rename XMREngine as Yengine (still not all done), big mess source formating changes, move state files to proper folder, fix a source file locking on errors, more changes for cross platform including from Mike,... yes yes i know a messy commit

httptests
UbitUmarov 2018-02-23 14:52:34 +00:00
parent 756fbf324a
commit 2129d941ac
55 changed files with 36917 additions and 32055 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,250 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine {
public class ScriptConst {
public static Dictionary<string, ScriptConst> scriptConstants = Init ();
/**
* @brief look up the value of a given built-in constant.
* @param name = name of constant
* @returns null: no constant by that name defined
* else: pointer to ScriptConst struct
*/
public static ScriptConst Lookup (string name)
{
ScriptConst sc;
if (!scriptConstants.TryGetValue (name, out sc)) sc = null;
return sc;
}
private static Dictionary<string, ScriptConst> Init ()
{
Dictionary<string, ScriptConst> sc = new Dictionary<string, ScriptConst> ();
/*
* For every event code, define XMREVENTCODE_<eventname> and XMREVENTMASKn_<eventname> symbols.
*/
for (int i = 0; i < 64; i ++) {
try {
string s = ((ScriptEventCode)i).ToString ();
if ((s.Length > 0) && (s[0] >= 'a') && (s[0] <= 'z')) {
new ScriptConst (sc,
"XMREVENTCODE_" + s,
new CompValuInteger (new TokenTypeInt (null), i));
int n = i / 32 + 1;
int m = 1 << (i % 32);
new ScriptConst (sc,
"XMREVENTMASK" + n + "_" + s,
new CompValuInteger (new TokenTypeInt (null), m));
}
} catch { }
}
/*
* Also get all the constants from XMRInstAbstract and ScriptBaseClass etc as well.
*/
for (Type t = typeof (XMRInstAbstract); t != typeof (object); t = t.BaseType) {
AddInterfaceConstants (sc, t.GetFields ());
}
return sc;
}
/**
* @brief Add all constants defined by the given interface.
*/
// this one accepts only upper-case named fields
public static void AddInterfaceConstants (Dictionary<string, ScriptConst> sc, FieldInfo[] allFields)
{
List<FieldInfo> ucfs = new List<FieldInfo> (allFields.Length);
foreach (FieldInfo f in allFields) {
string fieldName = f.Name;
int i;
for (i = fieldName.Length; -- i >= 0;) {
if ("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_".IndexOf (fieldName[i]) < 0) break;
}
if (i < 0) ucfs.Add (f);
}
AddInterfaceConstants (sc, ucfs.GetEnumerator ());
}
// this one accepts all fields given to it
public static void AddInterfaceConstants (Dictionary<string, ScriptConst> sc, IEnumerator<FieldInfo> fields)
{
if (sc == null) sc = scriptConstants;
for (fields.Reset (); fields.MoveNext ();) {
FieldInfo constField = fields.Current;
Type fieldType = constField.FieldType;
CompValu cv;
/*
* The location of a simple number is the number itself.
* Access to the value gets compiled as an ldc instruction.
*/
if (fieldType == typeof (double)) {
cv = new CompValuFloat (new TokenTypeFloat (null),
(double)(double)constField.GetValue (null));
} else if (fieldType == typeof (int)) {
cv = new CompValuInteger (new TokenTypeInt (null),
(int)constField.GetValue (null));
} else if (fieldType == typeof (LSL_Integer)) {
cv = new CompValuInteger (new TokenTypeInt (null),
((LSL_Integer)constField.GetValue (null)).value);
}
/*
* The location of a string is the string itself.
* Access to the value gets compiled as an ldstr instruction.
*/
else if (fieldType == typeof (string)) {
cv = new CompValuString (new TokenTypeStr (null),
(string)constField.GetValue (null));
} else if (fieldType == typeof (LSL_String)) {
cv = new CompValuString (new TokenTypeStr (null),
(string)(LSL_String)constField.GetValue (null));
}
/*
* The location of everything else (objects) is the static field in the interface definition.
* Access to the value gets compiled as an ldsfld instruction.
*/
else {
cv = new CompValuSField (TokenType.FromSysType (null, fieldType), constField);
}
/*
* Add to dictionary.
*/
new ScriptConst (sc, constField.Name, cv);
}
}
/**
* @brief Add arbitrary constant available to script compilation.
* CAUTION: These values get compiled-in to a script and must not
* change over time as previously compiled scripts will
* still have the old values.
*/
public static ScriptConst AddConstant (string name, object value)
{
CompValu cv = null;
if (value is char) {
cv = new CompValuChar (new TokenTypeChar (null), (char)value);
}
if (value is double) {
cv = new CompValuFloat (new TokenTypeFloat (null), (double)(double)value);
}
if (value is float) {
cv = new CompValuFloat (new TokenTypeFloat (null), (double)(float)value);
}
if (value is int) {
cv = new CompValuInteger (new TokenTypeInt (null), (int)value);
}
if (value is string) {
cv = new CompValuString (new TokenTypeStr (null), (string)value);
}
if (value is LSL_Float) {
cv = new CompValuFloat (new TokenTypeFloat (null), (double)((LSL_Float)value).value);
}
if (value is LSL_Integer) {
cv = new CompValuInteger (new TokenTypeInt (null), ((LSL_Integer)value).value);
}
if (value is LSL_Rotation) {
LSL_Rotation r = (LSL_Rotation)value;
CompValu x = new CompValuFloat (new TokenTypeFloat (null), r.x);
CompValu y = new CompValuFloat (new TokenTypeFloat (null), r.y);
CompValu z = new CompValuFloat (new TokenTypeFloat (null), r.z);
CompValu s = new CompValuFloat (new TokenTypeFloat (null), r.s);
cv = new CompValuRot (new TokenTypeRot (null), x, y, z, s);
}
if (value is LSL_String) {
cv = new CompValuString (new TokenTypeStr (null), (string)(LSL_String)value);
}
if (value is LSL_Vector) {
LSL_Vector v = (LSL_Vector)value;
CompValu x = new CompValuFloat (new TokenTypeFloat (null), v.x);
CompValu y = new CompValuFloat (new TokenTypeFloat (null), v.y);
CompValu z = new CompValuFloat (new TokenTypeFloat (null), v.z);
cv = new CompValuVec (new TokenTypeVec (null), x, y, z);
}
if (value is OpenMetaverse.Quaternion) {
OpenMetaverse.Quaternion r = (OpenMetaverse.Quaternion)value;
CompValu x = new CompValuFloat (new TokenTypeFloat (null), r.X);
CompValu y = new CompValuFloat (new TokenTypeFloat (null), r.Y);
CompValu z = new CompValuFloat (new TokenTypeFloat (null), r.Z);
CompValu s = new CompValuFloat (new TokenTypeFloat (null), r.W);
cv = new CompValuRot (new TokenTypeRot (null), x, y, z, s);
}
if (value is OpenMetaverse.UUID) {
cv = new CompValuString (new TokenTypeKey (null), value.ToString ());
}
if (value is OpenMetaverse.Vector3) {
OpenMetaverse.Vector3 v = (OpenMetaverse.Vector3)value;
CompValu x = new CompValuFloat (new TokenTypeFloat (null), v.X);
CompValu y = new CompValuFloat (new TokenTypeFloat (null), v.Y);
CompValu z = new CompValuFloat (new TokenTypeFloat (null), v.Z);
cv = new CompValuVec (new TokenTypeVec (null), x, y, z);
}
if (cv == null) throw new Exception ("bad type " + value.GetType ().Name);
return new ScriptConst (scriptConstants, name, cv);
}
/*
* Instance variables
*/
public string name;
public CompValu rVal;
private ScriptConst (Dictionary<string, ScriptConst> lc, string name, CompValu rVal)
{
lc.Add (name, this);
this.name = name;
this.rVal = rVal;
}
}
}

View File

@ -1,666 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
/**
* @brief Generate code for the backend API calls.
*/
namespace OpenSim.Region.ScriptEngine.XMREngine
{
public abstract class TokenDeclInline : TokenDeclVar {
public static VarDict inlineFunctions = CreateDictionary ();
public abstract void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args);
private static string[] noCheckRuns;
private static string[] keyReturns;
protected bool isTaggedCallsCheckRun;
/**
* @brief Create a dictionary of inline backend API functions.
*/
private static VarDict CreateDictionary ()
{
/*
* For those listed in noCheckRun, we just generate the call (simple computations).
* For all others, we generate the call then a call to CheckRun().
*/
noCheckRuns = new string[] {
"llBase64ToString",
"llCSV2List",
"llDeleteSubList",
"llDeleteSubString",
"llDumpList2String",
"llEscapeURL",
"llEuler2Rot",
"llGetListEntryType",
"llGetListLength",
"llGetSubString",
"llGetUnixTime",
"llInsertString",
"llList2CSV",
"llList2Float",
"llList2Integer",
"llList2Key",
"llList2List",
"llList2ListStrided",
"llList2Rot",
"llList2String",
"llList2Vector",
"llListFindList",
"llListInsertList",
"llListRandomize",
"llListReplaceList",
"llListSort",
"llListStatistics",
"llMD5String",
"llParseString2List",
"llParseStringKeepNulls",
"llRot2Euler",
"llStringLength",
"llStringToBase64",
"llStringTrim",
"llSubStringIndex",
"llUnescapeURL"
};
/*
* These functions really return a 'key' even though we see them as
* returning 'string' because OpenSim has key and string as same type.
*/
keyReturns = new string[] {
"llAvatarOnLinkSitTarget",
"llAvatarOnSitTarget",
"llDetectedKey",
"llDetectedOwner",
"llGenerateKey",
"llGetCreator",
"llGetInventoryCreator",
"llGetInventoryKey",
"llGetKey",
"llGetLandOwnerAt",
"llGetLinkKey",
"llGetNotecardLine",
"llGetNumberOfNotecardLines",
"llGetOwner",
"llGetOwnerKey",
"llGetPermissionsKey",
"llHTTPRequest",
"llList2Key",
"llRequestAgentData",
"llRequestDisplayName",
"llRequestInventoryData",
"llRequestSecureURL",
"llRequestSimulatorData",
"llRequestURL",
"llRequestUsername",
"llSendRemoteData",
"llTransferLindenDollars"
};
VarDict ifd = new VarDict (false);
Type[] oneDoub = new Type[] { typeof (double) };
Type[] twoDoubs = new Type[] { typeof (double), typeof (double) };
/*
* Mono generates an FPU instruction for many math calls.
*/
new TokenDeclInline_LLAbs (ifd);
new TokenDeclInline_Math (ifd, "llAcos(float)", "Acos", oneDoub);
new TokenDeclInline_Math (ifd, "llAsin(float)", "Asin", oneDoub);
new TokenDeclInline_Math (ifd, "llAtan2(float,float)", "Atan2", twoDoubs);
new TokenDeclInline_Math (ifd, "llCos(float)", "Cos", oneDoub);
new TokenDeclInline_Math (ifd, "llFabs(float)", "Abs", oneDoub);
new TokenDeclInline_Math (ifd, "llLog(float)", "Log", oneDoub);
new TokenDeclInline_Math (ifd, "llLog10(float)", "Log10", oneDoub);
new TokenDeclInline_Math (ifd, "llPow(float,float)", "Pow", twoDoubs);
new TokenDeclInline_LLRound (ifd);
new TokenDeclInline_Math (ifd, "llSin(float)", "Sin", oneDoub);
new TokenDeclInline_Math (ifd, "llSqrt(float)", "Sqrt", oneDoub);
new TokenDeclInline_Math (ifd, "llTan(float)", "Tan", oneDoub);
/*
* Something weird about the code generation for these calls, so they all have their own handwritten code generators.
*/
new TokenDeclInline_GetFreeMemory (ifd);
new TokenDeclInline_GetUsedMemory (ifd);
/*
* These are all the xmr...() calls directly in XMRInstAbstract.
* Includes the calls from ScriptBaseClass that has all the stubs
* which convert XMRInstAbstract to the various <NAME>_Api contexts.
*/
MethodInfo[] absmeths = typeof (XMRInstAbstract).GetMethods ();
AddInterfaceMethods (ifd, absmeths, null);
return ifd;
}
/**
* @brief Add API functions from the given interface to list of built-in functions.
* Only functions beginning with a lower-case letter are entered, all others ignored.
* @param ifd = internal function dictionary to add them to
* @param ifaceMethods = list of API functions
* @param acf = which field in XMRInstanceSuperType holds method's 'this' pointer
*/
// this one accepts only names beginning with a lower-case letter
public static void AddInterfaceMethods (VarDict ifd, MethodInfo[] ifaceMethods, FieldInfo acf)
{
List<MethodInfo> lcms = new List<MethodInfo> (ifaceMethods.Length);
foreach (MethodInfo meth in ifaceMethods)
{
string name = meth.Name;
if ((name[0] >= 'a') && (name[0] <= 'z')) {
lcms.Add (meth);
}
}
AddInterfaceMethods (ifd, lcms.GetEnumerator (), acf);
}
// this one accepts all methods given to it
public static void AddInterfaceMethods (VarDict ifd, IEnumerator<MethodInfo> ifaceMethods, FieldInfo acf)
{
if (ifd == null) ifd = inlineFunctions;
for (ifaceMethods.Reset (); ifaceMethods.MoveNext ();) {
MethodInfo ifaceMethod = ifaceMethods.Current;
string key = ifaceMethod.Name;
try {
/*
* See if we will generate a call to CheckRun() right
* after we generate a call to the function.
* If function begins with xmr, assume we will not call CheckRun()
* Otherwise, assume we will call CheckRun()
*/
bool dcr = !key.StartsWith ("xmr");
foreach (string ncr in noCheckRuns) {
if (ncr == key) {
dcr = false;
break;
}
}
/*
* Add function to dictionary.
*/
new TokenDeclInline_BEApi (ifd, dcr, ifaceMethod, acf);
} catch {
///??? IGNORE ANY THAT FAIL - LIKE UNRECOGNIZED TYPE ???///
///??? and OVERLOADED NAMES ???///
}
}
}
/**
* @brief Add an inline function definition to the dictionary.
* @param ifd = dictionary to add inline definition to
* @param doCheckRun = true iff the generated code or the function itself can possibly call CheckRun()
* @param nameArgSig = inline function signature string, in form <name>(<arglsltypes>,...)
* @param retType = return type, use TokenTypeVoid if no return value
*/
protected TokenDeclInline (VarDict ifd,
bool doCheckRun,
string nameArgSig,
TokenType retType)
: base (null, null, null)
{
this.retType = retType;
this.triviality = doCheckRun ? Triviality.complex : Triviality.trivial;
int j = nameArgSig.IndexOf ('(');
this.name = new TokenName (null, nameArgSig.Substring (0, j ++));
this.argDecl = new TokenArgDecl (null);
if (nameArgSig[j] != ')') {
int i;
TokenName name;
TokenType type;
for (i = j; nameArgSig[i] != ')'; i ++) {
if (nameArgSig[i] == ',') {
type = TokenType.FromLSLType (null, nameArgSig.Substring (j, i - j));
name = new TokenName (null, "arg" + this.argDecl.varDict.Count);
this.argDecl.AddArg (type, name);
j = i + 1;
}
}
type = TokenType.FromLSLType (null, nameArgSig.Substring (j, i - j));
name = new TokenName (null, "arg" + this.argDecl.varDict.Count);
this.argDecl.AddArg (type, name);
}
this.location = new CompValuInline (this);
if (ifd == null) ifd = inlineFunctions;
ifd.AddEntry (this);
}
protected TokenDeclInline (VarDict ifd,
bool doCheckRun,
MethodInfo methInfo)
: base (null, null, null)
{
TokenType retType = TokenType.FromSysType (null, methInfo.ReturnType);
this.isTaggedCallsCheckRun = IsTaggedCallsCheckRun (methInfo);
this.name = new TokenName (null, methInfo.Name);
this.retType = GetRetType (methInfo, retType);
this.argDecl = GetArgDecl (methInfo.GetParameters ());
this.triviality = (doCheckRun || this.isTaggedCallsCheckRun) ? Triviality.complex : Triviality.trivial;
this.location = new CompValuInline (this);
if (ifd == null) ifd = inlineFunctions;
ifd.AddEntry (this);
}
private static TokenArgDecl GetArgDecl (ParameterInfo[] parameters)
{
TokenArgDecl argDecl = new TokenArgDecl (null);
foreach (ParameterInfo pi in parameters) {
TokenType type = TokenType.FromSysType (null, pi.ParameterType);
TokenName name = new TokenName (null, pi.Name);
argDecl.AddArg (type, name);
}
return argDecl;
}
/**
* @brief The above code assumes all methods beginning with 'xmr' are trivial, ie,
* they do not call CheckRun() and also we do not generate a CheckRun()
* call after they return. So if an 'xmr' method does call CheckRun(), it
* must be tagged with attribute 'xmrMethodCallsCheckRunAttribute' so we know
* the method is not trivial. But in neither case do we emit our own call
* to CheckRun(), the 'xmr' method must do its own. We do however set up a
* call label before the call to the non-trivial 'xmr' method so when we are
* restoring the call stack, the restore will call directly in to the 'xmr'
* method without re-executing any code before the call to the 'xmr' method.
*/
private static bool IsTaggedCallsCheckRun (MethodInfo methInfo)
{
return (methInfo != null) &&
Attribute.IsDefined (methInfo, typeof (xmrMethodCallsCheckRunAttribute));
}
/**
* @brief The dumbass OpenSim has key and string as the same type so non-ll
* methods must be tagged with xmrMethodReturnsKeyAttribute if we
* are to think they return a key type, otherwise we will think they
* return string.
*/
private static TokenType GetRetType (MethodInfo methInfo, TokenType retType)
{
if ((methInfo != null) && (retType != null) && (retType is TokenTypeStr)) {
if (Attribute.IsDefined (methInfo, typeof (xmrMethodReturnsKeyAttribute))) {
return ChangeToKeyType (retType);
}
string mn = methInfo.Name;
foreach (string kr in keyReturns) {
if (kr == mn) return ChangeToKeyType (retType);
}
}
return retType;
}
private static TokenType ChangeToKeyType (TokenType retType)
{
if (retType is TokenTypeLSLString) {
retType = new TokenTypeLSLKey (null);
} else {
retType = new TokenTypeKey (null);
}
return retType;
}
public virtual MethodInfo GetMethodInfo ()
{
return null;
}
/**
* @brief Print out a list of all the built-in functions and constants.
*/
public delegate void WriteLine (string str);
public static void PrintBuiltins (bool inclNoisyTag, WriteLine writeLine)
{
writeLine ("\nBuilt-in functions:\n");
SortedDictionary<string, TokenDeclInline> bifs = new SortedDictionary<string, TokenDeclInline> ();
foreach (TokenDeclVar bif in TokenDeclInline.inlineFunctions) {
bifs.Add (bif.fullName, (TokenDeclInline)bif);
}
foreach (TokenDeclInline bif in bifs.Values) {
char noisy = (!inclNoisyTag || !IsTaggedNoisy (bif.GetMethodInfo ())) ? ' ' : (bif.retType is TokenTypeVoid) ? 'N' : 'R';
writeLine (noisy + " " + bif.retType.ToString ().PadLeft (8) + " " + bif.fullName);
}
if (inclNoisyTag) {
writeLine ("\nN - stub that writes name and arguments to stdout");
writeLine ("R - stub that writes name and arguments to stdout then reads return value from stdin");
writeLine (" format is: function_name : return_value");
writeLine (" example: llKey2Name:\"Kunta Kinte\"");
}
writeLine ("\nBuilt-in constants:\n");
SortedDictionary<string, ScriptConst> scs = new SortedDictionary<string, ScriptConst> ();
int widest = 0;
foreach (ScriptConst sc in ScriptConst.scriptConstants.Values) {
if (widest < sc.name.Length) widest = sc.name.Length;
scs.Add (sc.name, sc);
}
foreach (ScriptConst sc in scs.Values) {
writeLine (" " + sc.rVal.type.ToString ().PadLeft (8) + " " + sc.name.PadRight (widest) + " = " + BuiltInConstVal (sc.rVal));
}
}
public static bool IsTaggedNoisy (MethodInfo methInfo)
{
return (methInfo != null) && Attribute.IsDefined (methInfo, typeof (xmrMethodIsNoisyAttribute));
}
public static string BuiltInConstVal (CompValu rVal)
{
if (rVal is CompValuInteger) {
int x = ((CompValuInteger)rVal).x;
return "0x" + x.ToString ("X8") + " = " + x.ToString ().PadLeft (11);
}
if (rVal is CompValuFloat) return ((CompValuFloat)rVal).x.ToString ();
if (rVal is CompValuString) {
StringBuilder sb = new StringBuilder ();
PrintParam (sb, ((CompValuString)rVal).x);
return sb.ToString ();
}
if (rVal is CompValuSField) {
FieldInfo fi = ((CompValuSField)rVal).field;
StringBuilder sb = new StringBuilder ();
PrintParam (sb, fi.GetValue (null));
return sb.ToString ();
}
return rVal.ToString (); // just prints the type
}
public static void PrintParam (StringBuilder sb, object p)
{
if (p == null) {
sb.Append ("null");
} else if (p is LSL_List) {
sb.Append ('[');
object[] d = ((LSL_List)p).Data;
for (int i = 0; i < d.Length; i ++) {
if (i > 0) sb.Append (',');
PrintParam (sb, d[i]);
}
sb.Append (']');
} else if (p is LSL_Rotation) {
LSL_Rotation r = (LSL_Rotation)p;
sb.Append ('<');
sb.Append (r.x);
sb.Append (',');
sb.Append (r.y);
sb.Append (',');
sb.Append (r.z);
sb.Append (',');
sb.Append (r.s);
sb.Append ('>');
} else if (p is LSL_String) {
PrintParamString (sb, (string)(LSL_String)p);
} else if (p is LSL_Vector) {
LSL_Vector v = (LSL_Vector)p;
sb.Append ('<');
sb.Append (v.x);
sb.Append (',');
sb.Append (v.y);
sb.Append (',');
sb.Append (v.z);
sb.Append ('>');
} else if (p is string) {
PrintParamString (sb, (string)p);
} else {
sb.Append (p.ToString ());
}
}
public static void PrintParamString (StringBuilder sb, string p)
{
sb.Append ('"');
foreach (char c in p) {
if (c == '\b') {
sb.Append ("\\b");
continue;
}
if (c == '\n') {
sb.Append ("\\n");
continue;
}
if (c == '\r') {
sb.Append ("\\r");
continue;
}
if (c == '\t') {
sb.Append ("\\t");
continue;
}
if (c == '"') {
sb.Append ("\\\"");
continue;
}
if (c == '\\') {
sb.Append ("\\\\");
continue;
}
sb.Append (c);
}
sb.Append ('"');
}
}
/**
* @brief Code generators...
* @param scg = script we are generating code for
* @param result = type/location for result (type matches function definition)
* @param args = type/location of arguments (types match function definition)
*/
public class TokenDeclInline_LLAbs : TokenDeclInline {
public TokenDeclInline_LLAbs (VarDict ifd)
: base (ifd, false, "llAbs(integer)", new TokenTypeInt (null)) { }
public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
{
ScriptMyLabel itsPosLabel = scg.ilGen.DefineLabel ("llAbstemp");
args[0].PushVal (scg, errorAt);
scg.ilGen.Emit (errorAt, OpCodes.Dup);
scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_0);
scg.ilGen.Emit (errorAt, OpCodes.Bge_S, itsPosLabel);
scg.ilGen.Emit (errorAt, OpCodes.Neg);
scg.ilGen.MarkLabel (itsPosLabel);
result.Pop (scg, errorAt, retType);
}
}
public class TokenDeclInline_Math : TokenDeclInline {
private MethodInfo methInfo;
public TokenDeclInline_Math (VarDict ifd, string sig, string name, Type[] args)
: base (ifd, false, sig, new TokenTypeFloat (null))
{
methInfo = ScriptCodeGen.GetStaticMethod (typeof (System.Math), name, args);
}
public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
{
for (int i = 0; i < args.Length; i ++) {
args[i].PushVal (scg, errorAt, argDecl.types[i]);
}
scg.ilGen.Emit (errorAt, OpCodes.Call, methInfo);
result.Pop (scg, errorAt, retType);
}
}
public class TokenDeclInline_LLRound : TokenDeclInline {
private static MethodInfo roundMethInfo = ScriptCodeGen.GetStaticMethod (typeof (System.Math), "Round",
new Type[] { typeof (double), typeof (MidpointRounding) });
public TokenDeclInline_LLRound (VarDict ifd)
: base (ifd, false, "llRound(float)", new TokenTypeInt (null)) { }
public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
{
args[0].PushVal (scg, errorAt, new TokenTypeFloat (null));
scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, (int)System.MidpointRounding.AwayFromZero);
scg.ilGen.Emit (errorAt, OpCodes.Call, roundMethInfo);
result.Pop (scg, errorAt, new TokenTypeFloat (null));
}
}
public class TokenDeclInline_GetFreeMemory : TokenDeclInline {
private static readonly MethodInfo getFreeMemMethInfo = typeof (XMRInstAbstract).GetMethod ("xmrHeapLeft", new Type[] { });
public TokenDeclInline_GetFreeMemory (VarDict ifd)
: base (ifd, false, "llGetFreeMemory()", new TokenTypeInt (null)) { }
// appears as llGetFreeMemory() in script source code
// but actually calls xmrHeapLeft()
public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
{
scg.PushXMRInst ();
scg.ilGen.Emit (errorAt, OpCodes.Call, getFreeMemMethInfo);
result.Pop (scg, errorAt, new TokenTypeInt (null));
}
}
public class TokenDeclInline_GetUsedMemory : TokenDeclInline {
private static readonly MethodInfo getUsedMemMethInfo = typeof (XMRInstAbstract).GetMethod ("xmrHeapUsed", new Type[] { });
public TokenDeclInline_GetUsedMemory (VarDict ifd)
: base (ifd, false, "llGetUsedMemory()", new TokenTypeInt (null)) { }
// appears as llGetUsedMemory() in script source code
// but actually calls xmrHeapUsed()
public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
{
scg.PushXMRInst ();
scg.ilGen.Emit (errorAt, OpCodes.Call, getUsedMemMethInfo);
result.Pop (scg, errorAt, new TokenTypeInt (null));
}
}
/**
* @brief Generate code for the usual ll...() functions.
*/
public class TokenDeclInline_BEApi : TokenDeclInline {
// private static readonly MethodInfo fixLLParcelMediaQuery = ScriptCodeGen.GetStaticMethod
// (typeof (XMRInstAbstract), "FixLLParcelMediaQuery", new Type[] { typeof (LSL_List) });
// private static readonly MethodInfo fixLLParcelMediaCommandList = ScriptCodeGen.GetStaticMethod
// (typeof (XMRInstAbstract), "FixLLParcelMediaCommandList", new Type[] { typeof (LSL_List) });
public bool doCheckRun;
private FieldInfo apiContextField;
private MethodInfo methInfo;
/**
* @brief Constructor
* @param ifd = dictionary to add the function to
* @param dcr = append a call to CheckRun()
* @param methInfo = ll...() method to be called
*/
public TokenDeclInline_BEApi (VarDict ifd, bool dcr, MethodInfo methInfo, FieldInfo acf)
: base (ifd, dcr, methInfo)
{
this.methInfo = methInfo;
doCheckRun = dcr;
apiContextField = acf;
}
public override MethodInfo GetMethodInfo ()
{
return methInfo;
}
/**
* @brief Generate call to backend API function (eg llSay()) maybe followed by a call to CheckRun().
* @param scg = script being compiled
* @param result = where to place result (might be void)
* @param args = script-visible arguments to pass to API function
*/
public override void CodeGen (ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
{
if (isTaggedCallsCheckRun)
{ // see if 'xmr' method that calls CheckRun() internally
new ScriptCodeGen.CallLabel (scg, errorAt); // if so, put a call label immediately before it
// .. so restoring the frame will jump immediately to the
// .. call without re-executing any code before this
}
if (!methInfo.IsStatic)
{
scg.PushXMRInst (); // XMRInstanceSuperType pointer
if (apiContextField != null) // 'this' pointer for API function
scg.ilGen.Emit (errorAt, OpCodes.Ldfld, apiContextField);
}
for (int i = 0; i < args.Length; i ++) // push arguments, boxing/unboxing as needed
args[i].PushVal (scg, errorAt, argDecl.types[i]);
// this should not be needed
// if (methInfo.Name == "llParcelMediaQuery") {
// scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaQuery);
// }
// this should not be needed
// if (methInfo.Name == "llParcelMediaCommandList") {
// scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaCommandList);
// }
if (methInfo.IsVirtual) // call API function
scg.ilGen.Emit (errorAt, OpCodes.Callvirt, methInfo);
else
scg.ilGen.Emit (errorAt, OpCodes.Call, methInfo);
result.Pop (scg, errorAt, retType); // pop result, boxing/unboxing as needed
if (isTaggedCallsCheckRun)
scg.openCallLabel = null;
if (doCheckRun)
scg.EmitCallCheckRun (errorAt, false); // maybe call CheckRun()
}
}
}

View File

@ -1,256 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using OpenSim.Region.ScriptEngine.XMREngine;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
namespace OpenSim.Region.ScriptEngine.XMREngine
{
public delegate void ScriptEventHandler (XMRInstAbstract instance);
/*
* This object represents the output of the compilation.
* Once the compilation is complete, its contents should be
* considered 'read-only', so it can be shared among multiple
* instances of the script.
*
* It gets created by ScriptCodeGen.
* It gets used by XMRInstance to create script instances.
*/
public class ScriptObjCode
{
public string sourceHash; // source text hash code
public XMRInstArSizes glblSizes = new XMRInstArSizes ();
// number of global variables of various types
public string[] stateNames; // convert state number to corresponding string
public ScriptEventHandler[,] scriptEventHandlerTable;
// entrypoints to all event handler functions
// 1st subscript = state code number (0=default)
// 2nd subscript = event code number
// null entry means no handler defined for that state,event
public Dictionary<string, TokenDeclSDType> sdObjTypesName;
// all script-defined types by name
public TokenDeclSDType[] sdObjTypesIndx;
// all script-defined types by sdTypeIndex
public Dictionary<Type, string> sdDelTypes;
// all script-defined delegates (including anonymous)
public Dictionary<string, DynamicMethod> dynamicMethods;
// all dyanmic methods
public Dictionary<string, KeyValuePair<int, ScriptSrcLoc>[]> scriptSrcLocss;
// method,iloffset -> source file,line,posn
public int refCount; // used by engine to keep track of number of
// instances that are using this object code
public Dictionary<string,Dictionary<int,string>> globalVarNames = new Dictionary<string,Dictionary<int,string>> ();
public DateTime fileDateUtc;
public int expiryDays = Int32.MaxValue;
public bool IsExpired ()
{
return (DateTime.UtcNow.Ticks - fileDateUtc.Ticks) / 10000000 / 86400 >= expiryDays;
}
/**
* @brief Fill in ScriptObjCode from an XMREngine object file.
* 'objFileReader' is a serialized form of the CIL code we generated
* 'asmFileWriter' is where we write the disassembly to (or null if not wanted)
* 'srcFileWriter' is where we write the decompilation to (or null if not wanted)
* Throws an exception if there is any error (theoretically).
*/
public ScriptObjCode (BinaryReader objFileReader, TextWriter asmFileWriter, TextWriter srcFileWriter)
{
/*
* Check version number to make sure we know how to process file contents.
*/
char[] ocm = objFileReader.ReadChars (ScriptCodeGen.OBJECT_CODE_MAGIC.Length);
if (new String (ocm) != ScriptCodeGen.OBJECT_CODE_MAGIC) {
throw new Exception ("not an XMR object file (bad magic)");
}
int cvv = objFileReader.ReadInt32 ();
if (cvv != ScriptCodeGen.COMPILED_VERSION_VALUE) {
throw new CVVMismatchException (cvv, ScriptCodeGen.COMPILED_VERSION_VALUE);
}
/*
* Fill in simple parts of scriptObjCode object.
*/
sourceHash = objFileReader.ReadString ();
expiryDays = objFileReader.ReadInt32 ();
glblSizes.ReadFromFile (objFileReader);
int nStates = objFileReader.ReadInt32 ();
stateNames = new string[nStates];
for (int i = 0; i < nStates; i ++) {
stateNames[i] = objFileReader.ReadString ();
if (asmFileWriter != null) {
asmFileWriter.WriteLine (" state[{0}] = {1}", i, stateNames[i]);
}
}
if (asmFileWriter != null) {
glblSizes.WriteAsmFile (asmFileWriter, "numGbl");
}
string gblName;
while ((gblName = objFileReader.ReadString ()) != "") {
string gblType = objFileReader.ReadString ();
int gblIndex = objFileReader.ReadInt32 ();
Dictionary<int,string> names;
if (!globalVarNames.TryGetValue (gblType, out names)) {
names = new Dictionary<int,string> ();
globalVarNames.Add (gblType, names);
}
names.Add (gblIndex, gblName);
if (asmFileWriter != null) {
asmFileWriter.WriteLine (" {0} = {1}[{2}]", gblName, gblType, gblIndex);
}
}
/*
* Read in script-defined types.
*/
sdObjTypesName = new Dictionary<string, TokenDeclSDType> ();
sdDelTypes = new Dictionary<Type, string> ();
int maxIndex = -1;
while ((gblName = objFileReader.ReadString ()) != "") {
TokenDeclSDType sdt = TokenDeclSDType.ReadFromFile (sdObjTypesName,
gblName, objFileReader, asmFileWriter);
sdObjTypesName.Add (gblName, sdt);
if (maxIndex < sdt.sdTypeIndex) maxIndex = sdt.sdTypeIndex;
if (sdt is TokenDeclSDTypeDelegate) {
sdDelTypes.Add (sdt.GetSysType (), gblName);
}
}
sdObjTypesIndx = new TokenDeclSDType[maxIndex+1];
foreach (TokenDeclSDType sdt in sdObjTypesName.Values) {
sdObjTypesIndx[sdt.sdTypeIndex] = sdt;
}
/*
* Now fill in the methods (the hard part).
*/
scriptEventHandlerTable = new ScriptEventHandler[nStates,(int)ScriptEventCode.Size];
dynamicMethods = new Dictionary<string, DynamicMethod> ();
scriptSrcLocss = new Dictionary<string, KeyValuePair<int, ScriptSrcLoc>[]> ();
ObjectTokens objectTokens = null;
if (asmFileWriter != null) {
objectTokens = new OTDisassemble (this, asmFileWriter);
} else if (srcFileWriter != null) {
objectTokens = new OTDecompile (this, srcFileWriter);
}
try {
ScriptObjWriter.CreateObjCode (sdObjTypesName, objFileReader, this, objectTokens);
} finally {
if (objectTokens != null) objectTokens.Close ();
}
/*
* We enter all script event handler methods in the ScriptEventHandler table.
* They are named: <statename> <eventname>
*/
foreach (KeyValuePair<string, DynamicMethod> kvp in dynamicMethods) {
string methName = kvp.Key;
int i = methName.IndexOf (' ');
if (i < 0) continue;
string stateName = methName.Substring (0, i);
string eventName = methName.Substring (++ i);
int stateCode;
for (stateCode = stateNames.Length; -- stateCode >= 0;) {
if (stateNames[stateCode] == stateName) break;
}
int eventCode = (int)Enum.Parse (typeof (ScriptEventCode), eventName);
scriptEventHandlerTable[stateCode,eventCode] =
(ScriptEventHandler)kvp.Value.CreateDelegate (typeof (ScriptEventHandler));
}
/*
* Fill in all script-defined class vtables.
*/
foreach (TokenDeclSDType sdt in sdObjTypesIndx) {
if ((sdt != null) && (sdt is TokenDeclSDTypeClass)) {
TokenDeclSDTypeClass sdtc = (TokenDeclSDTypeClass)sdt;
sdtc.FillVTables (this);
}
}
}
/**
* @brief Called once for every method found in objFileReader file.
* It enters the method in the ScriptObjCode object table so it can be called.
*/
public void EndMethod (DynamicMethod method, Dictionary<int, ScriptSrcLoc> srcLocs)
{
/*
* Save method object code pointer.
*/
dynamicMethods.Add (method.Name, method);
/*
* Build and sort iloffset -> source code location array.
*/
int n = srcLocs.Count;
KeyValuePair<int, ScriptSrcLoc>[] srcLocArray = new KeyValuePair<int, ScriptSrcLoc>[n];
n = 0;
foreach (KeyValuePair<int, ScriptSrcLoc> kvp in srcLocs) srcLocArray[n++] = kvp;
Array.Sort (srcLocArray, endMethodWrapper);
/*
* Save sorted array.
*/
scriptSrcLocss.Add (method.Name, srcLocArray);
}
/**
* @brief Called once for every method found in objFileReader file.
* It enters the method in the ScriptObjCode object table so it can be called.
*/
private static EndMethodWrapper endMethodWrapper = new EndMethodWrapper ();
private class EndMethodWrapper : System.Collections.IComparer {
public int Compare (object x, object y)
{
KeyValuePair<int, ScriptSrcLoc> kvpx = (KeyValuePair<int, ScriptSrcLoc>)x;
KeyValuePair<int, ScriptSrcLoc> kvpy = (KeyValuePair<int, ScriptSrcLoc>)y;
return kvpx.Key - kvpy.Key;
}
}
}
}

View File

@ -1,947 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
/**
* @brief Wrapper class for ILGenerator.
* It writes the object code to a file and can then make real ILGenerator calls
* based on the file's contents.
*/
namespace OpenSim.Region.ScriptEngine.XMREngine
{
public enum ScriptObjWriterCode : byte {
BegMethod, EndMethod, TheEnd,
DclLabel, DclLocal, DclMethod, MarkLabel,
EmitNull, EmitField, EmitLocal, EmitType, EmitLabel, EmitMethodExt,
EmitMethodInt, EmitCtor, EmitDouble, EmitFloat, EmitInteger, EmitString,
EmitLabels,
BegExcBlk, BegCatBlk, BegFinBlk, EndExcBlk
}
public class ScriptObjWriter : ScriptMyILGen
{
private static Dictionary<short, OpCode> opCodes = PopulateOpCodes ();
private static Dictionary<string, Type> string2Type = PopulateS2T ();
private static Dictionary<Type, string> type2String = PopulateT2S ();
private static MethodInfo monoGetCurrentOffset = typeof (ILGenerator).GetMethod ("Mono_GetCurrentOffset",
BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic, null,
new Type[] { typeof (ILGenerator) }, null);
private static readonly OpCode[] opCodesLdcI4M1P8 = new OpCode[] {
OpCodes.Ldc_I4_M1, OpCodes.Ldc_I4_0, OpCodes.Ldc_I4_1, OpCodes.Ldc_I4_2, OpCodes.Ldc_I4_3,
OpCodes.Ldc_I4_4, OpCodes.Ldc_I4_5, OpCodes.Ldc_I4_6, OpCodes.Ldc_I4_7, OpCodes.Ldc_I4_8
};
private BinaryWriter objFileWriter;
private string lastErrorAtFile = "";
private int lastErrorAtLine = 0;
private int lastErrorAtPosn = 0;
private Dictionary<Type, string> sdTypesRev = new Dictionary<Type, string> ();
public int labelNumber = 0;
public int localNumber = 0;
private string _methName;
public string methName { get { return _methName; } }
public Type retType;
public Type[] argTypes;
/**
* @brief Begin function declaration
* @param sdTypes = script-defined types
* @param methName = name of the method being declared, eg, "Verify(array,list,string)"
* @param retType = its return value type
* @param argTypes[] = its argument types
* @param objFileWriter = file to write its object code to
*
* After calling this function, the following functions should be called:
* this.BegMethod ();
* this.<as required> ();
* this.EndMethod ();
*
* The design of this object is such that many constructors may be called,
* but once a BegMethod() is called for one of the objects, no method may
* called for any of the other objects until EndMethod() is called (or it
* would break up the object stream for that method). But we need to have
* many constructors possible so we get function headers at the beginning
* of the object file in case there are forward references to the functions.
*/
public ScriptObjWriter (TokenScript tokenScript, string methName, Type retType, Type[] argTypes, string[] argNames, BinaryWriter objFileWriter)
{
this._methName = methName;
this.retType = retType;
this.argTypes = argTypes;
this.objFileWriter = objFileWriter;
/*
* Build list that translates system-defined types to script defined types.
*/
foreach (TokenDeclSDType sdt in tokenScript.sdSrcTypesValues) {
Type sys = sdt.GetSysType();
if (sys != null) sdTypesRev[sys] = sdt.longName.val;
}
/*
* This tells the reader to call 'new DynamicMethod()' to create
* the function header. Then any forward reference calls to this
* method will have a MethodInfo struct to call.
*/
objFileWriter.Write ((byte)ScriptObjWriterCode.DclMethod);
objFileWriter.Write (methName);
objFileWriter.Write (GetStrFromType (retType));
int nArgs = argTypes.Length;
objFileWriter.Write (nArgs);
for (int i = 0; i < nArgs; i ++) {
objFileWriter.Write (GetStrFromType (argTypes[i]));
objFileWriter.Write (argNames[i]);
}
}
/**
* @brief Begin outputting object code for the function
*/
public void BegMethod ()
{
/*
* This tells the reader to call methodInfo.GetILGenerator()
* so it can start writing CIL code for the method.
*/
objFileWriter.Write ((byte)ScriptObjWriterCode.BegMethod);
objFileWriter.Write (methName);
}
/**
* @brief End of object code for the function
*/
public void EndMethod ()
{
/*
* This tells the reader that all code for the method has
* been written and so it will typically call CreateDelegate()
* to finalize the method and create an entrypoint.
*/
objFileWriter.Write ((byte)ScriptObjWriterCode.EndMethod);
objFileWriter = null;
}
/**
* @brief Declare a local variable for use by the function
*/
public ScriptMyLocal DeclareLocal (Type type, string name)
{
ScriptMyLocal myLocal = new ScriptMyLocal ();
myLocal.type = type;
myLocal.name = name;
myLocal.number = localNumber ++;
myLocal.isReferenced = true; // so ScriptCollector won't optimize references away
return DeclareLocal (myLocal);
}
public ScriptMyLocal DeclareLocal (ScriptMyLocal myLocal)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.DclLocal);
objFileWriter.Write (myLocal.number);
objFileWriter.Write (myLocal.name);
objFileWriter.Write (GetStrFromType (myLocal.type));
return myLocal;
}
/**
* @brief Define a label for use by the function
*/
public ScriptMyLabel DefineLabel (string name)
{
ScriptMyLabel myLabel = new ScriptMyLabel ();
myLabel.name = name;
myLabel.number = labelNumber ++;
return DefineLabel (myLabel);
}
public ScriptMyLabel DefineLabel (ScriptMyLabel myLabel)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.DclLabel);
objFileWriter.Write (myLabel.number);
objFileWriter.Write (myLabel.name);
return myLabel;
}
/**
* @brief try/catch blocks.
*/
public void BeginExceptionBlock ()
{
objFileWriter.Write ((byte)ScriptObjWriterCode.BegExcBlk);
}
public void BeginCatchBlock (Type excType)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.BegCatBlk);
objFileWriter.Write (GetStrFromType (excType));
}
public void BeginFinallyBlock ()
{
objFileWriter.Write ((byte)ScriptObjWriterCode.BegFinBlk);
}
public void EndExceptionBlock ()
{
objFileWriter.Write ((byte)ScriptObjWriterCode.EndExcBlk);
}
public void Emit (Token errorAt, OpCode opcode)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitNull);
WriteOpCode (errorAt, opcode);
}
public void Emit (Token errorAt, OpCode opcode, FieldInfo field)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitField);
WriteOpCode (errorAt, opcode);
objFileWriter.Write (GetStrFromType (field.ReflectedType));
objFileWriter.Write (field.Name);
}
public void Emit (Token errorAt, OpCode opcode, ScriptMyLocal myLocal)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitLocal);
WriteOpCode (errorAt, opcode);
objFileWriter.Write (myLocal.number);
}
public void Emit (Token errorAt, OpCode opcode, Type type)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitType);
WriteOpCode (errorAt, opcode);
objFileWriter.Write (GetStrFromType (type));
}
public void Emit (Token errorAt, OpCode opcode, ScriptMyLabel myLabel)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitLabel);
WriteOpCode (errorAt, opcode);
objFileWriter.Write (myLabel.number);
}
public void Emit (Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitLabels);
WriteOpCode (errorAt, opcode);
int nLabels = myLabels.Length;
objFileWriter.Write (nLabels);
for (int i = 0; i < nLabels; i ++) {
objFileWriter.Write (myLabels[i].number);
}
}
public void Emit (Token errorAt, OpCode opcode, ScriptObjWriter method)
{
if (method == null) throw new ArgumentNullException ("method");
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitMethodInt);
WriteOpCode (errorAt, opcode);
objFileWriter.Write (method.methName);
}
public void Emit (Token errorAt, OpCode opcode, MethodInfo method)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitMethodExt);
WriteOpCode (errorAt, opcode);
objFileWriter.Write (method.Name);
objFileWriter.Write (GetStrFromType (method.ReflectedType));
ParameterInfo[] parms = method.GetParameters ();
int nArgs = parms.Length;
objFileWriter.Write (nArgs);
for (int i = 0; i < nArgs; i ++) {
objFileWriter.Write (GetStrFromType (parms[i].ParameterType));
}
}
public void Emit (Token errorAt, OpCode opcode, ConstructorInfo ctor)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitCtor);
WriteOpCode (errorAt, opcode);
objFileWriter.Write (GetStrFromType (ctor.ReflectedType));
ParameterInfo[] parms = ctor.GetParameters ();
int nArgs = parms.Length;
objFileWriter.Write (nArgs);
for (int i = 0; i < nArgs; i ++) {
objFileWriter.Write (GetStrFromType (parms[i].ParameterType));
}
}
public void Emit (Token errorAt, OpCode opcode, double value)
{
if (opcode != OpCodes.Ldc_R8) {
throw new Exception ("bad opcode " + opcode.ToString ());
}
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitDouble);
WriteOpCode (errorAt, opcode);
objFileWriter.Write (value);
}
public void Emit (Token errorAt, OpCode opcode, float value)
{
if (opcode != OpCodes.Ldc_R4) {
throw new Exception ("bad opcode " + opcode.ToString ());
}
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitFloat);
WriteOpCode (errorAt, opcode);
objFileWriter.Write (value);
}
public void Emit (Token errorAt, OpCode opcode, int value)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitInteger);
WriteOpCode (errorAt, opcode);
objFileWriter.Write (value);
}
public void Emit (Token errorAt, OpCode opcode, string value)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.EmitString);
WriteOpCode (errorAt, opcode);
objFileWriter.Write (value);
}
/**
* @brief Declare that the target of a label is the next instruction.
*/
public void MarkLabel (ScriptMyLabel myLabel)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.MarkLabel);
objFileWriter.Write (myLabel.number);
}
/**
* @brief Write end-of-file marker to binary file.
*/
public static void TheEnd (BinaryWriter objFileWriter)
{
objFileWriter.Write ((byte)ScriptObjWriterCode.TheEnd);
}
/**
* @brief Take an object file created by ScriptObjWriter() and convert it to a series of dynamic methods.
* @param sdTypes = script-defined types
* @param objReader = where to read object file from (as written by ScriptObjWriter above).
* @param scriptObjCode.EndMethod = called for each method defined at the end of the methods definition
* @param objectTokens = write disassemble/decompile data (or null if not wanted)
*/
public static void CreateObjCode (Dictionary<string, TokenDeclSDType> sdTypes, BinaryReader objReader,
ScriptObjCode scriptObjCode, ObjectTokens objectTokens)
{
Dictionary<string, DynamicMethod> methods = new Dictionary<string, DynamicMethod> ();
DynamicMethod method = null;
ILGenerator ilGen = null;
Dictionary<int, Label> labels = new Dictionary<int, Label> ();
Dictionary<int, LocalBuilder> locals = new Dictionary<int, LocalBuilder> ();
Dictionary<int, string> labelNames = new Dictionary<int, string> ();
Dictionary<int, string> localNames = new Dictionary<int, string> ();
object[] ilGenArg = new object[1];
int offset = 0;
Dictionary<int, ScriptSrcLoc> srcLocs = null;
string srcFile = "";
int srcLine = 0;
int srcPosn = 0;
while (true) {
/*
* Get IL instruction offset at beginning of instruction.
*/
offset = 0;
if ((ilGen != null) && (monoGetCurrentOffset != null)) {
offset = (int)monoGetCurrentOffset.Invoke (null, ilGenArg);
}
/*
* Read and decode next internal format code from input file (.xmrobj file).
*/
ScriptObjWriterCode code = (ScriptObjWriterCode)objReader.ReadByte ();
switch (code) {
/*
* Reached end-of-file so we are all done.
*/
case ScriptObjWriterCode.TheEnd: {
return;
}
/*
* Beginning of method's contents.
* Method must have already been declared via DclMethod
* so all we need is its name to retrieve from methods[].
*/
case ScriptObjWriterCode.BegMethod: {
string methName = objReader.ReadString ();
method = methods[methName];
ilGen = method.GetILGenerator ();
ilGenArg[0] = ilGen;
labels.Clear ();
locals.Clear ();
labelNames.Clear ();
localNames.Clear ();
srcLocs = new Dictionary<int, ScriptSrcLoc> ();
if (objectTokens != null) objectTokens.BegMethod (method);
break;
}
/*
* End of method's contents (ie, an OpCodes.Ret was probably just output).
* Call the callback to tell it the method is complete, and it can do whatever
* it wants with the method.
*/
case ScriptObjWriterCode.EndMethod: {
ilGen = null;
ilGenArg[0] = null;
scriptObjCode.EndMethod (method, srcLocs);
srcLocs = null;
if (objectTokens != null) objectTokens.EndMethod ();
break;
}
/*
* Declare a label for branching to.
*/
case ScriptObjWriterCode.DclLabel: {
int number = objReader.ReadInt32 ();
string name = objReader.ReadString ();
labels.Add (number, ilGen.DefineLabel ());
labelNames.Add (number, name + "_" + number.ToString ());
if (objectTokens != null) objectTokens.DefineLabel (number, name);
break;
}
/*
* Declare a local variable to store into.
*/
case ScriptObjWriterCode.DclLocal: {
int number = objReader.ReadInt32 ();
string name = objReader.ReadString ();
string type = objReader.ReadString ();
Type syType = GetTypeFromStr (sdTypes, type);
locals.Add (number, ilGen.DeclareLocal (syType));
localNames.Add (number, name + "_" + number.ToString ());
if (objectTokens != null) objectTokens.DefineLocal (number, name, type, syType);
break;
}
/*
* Declare a method that will subsequently be defined.
* We create the DynamicMethod object at this point in case there
* are forward references from other method bodies.
*/
case ScriptObjWriterCode.DclMethod: {
string methName = objReader.ReadString ();
Type retType = GetTypeFromStr (sdTypes, objReader.ReadString ());
int nArgs = objReader.ReadInt32 ();
Type[] argTypes = new Type[nArgs];
string[] argNames = new string[nArgs];
for (int i = 0; i < nArgs; i ++) {
argTypes[i] = GetTypeFromStr (sdTypes, objReader.ReadString ());
argNames[i] = objReader.ReadString ();
}
methods.Add (methName, new DynamicMethod (methName, retType, argTypes));
if (objectTokens != null) objectTokens.DefineMethod (methName, retType, argTypes, argNames);
break;
}
/*
* Mark a previously declared label at this spot.
*/
case ScriptObjWriterCode.MarkLabel: {
int number = objReader.ReadInt32 ();
ilGen.MarkLabel (labels[number]);
if (objectTokens != null) objectTokens.MarkLabel (offset, number);
break;
}
/*
* Try/Catch blocks.
*/
case ScriptObjWriterCode.BegExcBlk: {
ilGen.BeginExceptionBlock ();
if (objectTokens != null) objectTokens.BegExcBlk (offset);
break;
}
case ScriptObjWriterCode.BegCatBlk: {
Type excType = GetTypeFromStr (sdTypes, objReader.ReadString ());
ilGen.BeginCatchBlock (excType);
if (objectTokens != null) objectTokens.BegCatBlk (offset, excType);
break;
}
case ScriptObjWriterCode.BegFinBlk: {
ilGen.BeginFinallyBlock ();
if (objectTokens != null) objectTokens.BegFinBlk (offset);
break;
}
case ScriptObjWriterCode.EndExcBlk: {
ilGen.EndExceptionBlock ();
if (objectTokens != null) objectTokens.EndExcBlk (offset);
break;
}
/*
* Emit an opcode with no operand.
*/
case ScriptObjWriterCode.EmitNull: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
ilGen.Emit (opCode);
if (objectTokens != null) objectTokens.EmitNull (offset, opCode);
break;
}
/*
* Emit an opcode with a FieldInfo operand.
*/
case ScriptObjWriterCode.EmitField: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
Type reflectedType = GetTypeFromStr (sdTypes, objReader.ReadString ());
string fieldName = objReader.ReadString ();
FieldInfo field = reflectedType.GetField (fieldName);
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
ilGen.Emit (opCode, field);
if (objectTokens != null) objectTokens.EmitField (offset, opCode, field);
break;
}
/*
* Emit an opcode with a LocalBuilder operand.
*/
case ScriptObjWriterCode.EmitLocal: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
int number = objReader.ReadInt32 ();
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
ilGen.Emit (opCode, locals[number]);
if (objectTokens != null) objectTokens.EmitLocal (offset, opCode, number);
break;
}
/*
* Emit an opcode with a Type operand.
*/
case ScriptObjWriterCode.EmitType: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
string name = objReader.ReadString ();
Type type = GetTypeFromStr (sdTypes, name);
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
ilGen.Emit (opCode, type);
if (objectTokens != null) objectTokens.EmitType (offset, opCode, type);
break;
}
/*
* Emit an opcode with a Label operand.
*/
case ScriptObjWriterCode.EmitLabel: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
int number = objReader.ReadInt32 ();
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
ilGen.Emit (opCode, labels[number]);
if (objectTokens != null) objectTokens.EmitLabel (offset, opCode, number);
break;
}
/*
* Emit an opcode with a Label array operand.
*/
case ScriptObjWriterCode.EmitLabels: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
int nLabels = objReader.ReadInt32 ();
Label[] lbls = new Label[nLabels];
int[] nums = new int[nLabels];
for (int i = 0; i < nLabels; i ++) {
nums[i] = objReader.ReadInt32 ();
lbls[i] = labels[nums[i]];
}
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
ilGen.Emit (opCode, lbls);
if (objectTokens != null) objectTokens.EmitLabels (offset, opCode, nums);
break;
}
/*
* Emit an opcode with a MethodInfo operand (such as a call) of an external function.
*/
case ScriptObjWriterCode.EmitMethodExt: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
string methName = objReader.ReadString ();
Type methType = GetTypeFromStr (sdTypes, objReader.ReadString ());
int nArgs = objReader.ReadInt32 ();
Type[] argTypes = new Type[nArgs];
for (int i = 0; i < nArgs; i ++) {
argTypes[i] = GetTypeFromStr (sdTypes, objReader.ReadString ());
}
MethodInfo methInfo = methType.GetMethod (methName, argTypes);
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
ilGen.Emit (opCode, methInfo);
if (objectTokens != null) objectTokens.EmitMethod (offset, opCode, methInfo);
break;
}
/*
* Emit an opcode with a MethodInfo operand of an internal function
* (previously declared via DclMethod).
*/
case ScriptObjWriterCode.EmitMethodInt: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
string methName = objReader.ReadString ();
MethodInfo methInfo = methods[methName];
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
ilGen.Emit (opCode, methInfo);
if (objectTokens != null) objectTokens.EmitMethod (offset, opCode, methInfo);
break;
}
/*
* Emit an opcode with a ConstructorInfo operand.
*/
case ScriptObjWriterCode.EmitCtor: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
Type ctorType = GetTypeFromStr (sdTypes, objReader.ReadString ());
int nArgs = objReader.ReadInt32 ();
Type[] argTypes = new Type[nArgs];
for (int i = 0; i < nArgs; i ++) {
argTypes[i] = GetTypeFromStr (sdTypes, objReader.ReadString ());
}
ConstructorInfo ctorInfo = ctorType.GetConstructor (argTypes);
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
ilGen.Emit (opCode, ctorInfo);
if (objectTokens != null) objectTokens.EmitCtor (offset, opCode, ctorInfo);
break;
}
/*
* Emit an opcode with a constant operand of various types.
*/
case ScriptObjWriterCode.EmitDouble: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
double value = objReader.ReadDouble ();
if (opCode != OpCodes.Ldc_R8) {
throw new Exception ("bad opcode " + opCode.ToString ());
}
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
ilGen.Emit (opCode, value);
if (objectTokens != null) objectTokens.EmitDouble (offset, opCode, value);
break;
}
case ScriptObjWriterCode.EmitFloat: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
float value = objReader.ReadSingle ();
if (opCode != OpCodes.Ldc_R4) {
throw new Exception ("bad opcode " + opCode.ToString ());
}
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
ilGen.Emit (opCode, value);
if (objectTokens != null) objectTokens.EmitFloat (offset, opCode, value);
break;
}
case ScriptObjWriterCode.EmitInteger: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
int value = objReader.ReadInt32 ();
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
if (opCode == OpCodes.Ldc_I4) {
if ((value >= -1) && (value <= 8)) {
opCode = opCodesLdcI4M1P8[value+1];
ilGen.Emit (opCode);
if (objectTokens != null) objectTokens.EmitNull (offset, opCode);
break;
}
if ((value >= 0) && (value <= 127)) {
opCode = OpCodes.Ldc_I4_S;
ilGen.Emit (OpCodes.Ldc_I4_S, (sbyte)value);
goto pemitint;
}
}
ilGen.Emit (opCode, value);
pemitint:
if (objectTokens != null) objectTokens.EmitInteger (offset, opCode, value);
break;
}
case ScriptObjWriterCode.EmitString: {
OpCode opCode = ReadOpCode (objReader, ref srcFile, ref srcLine, ref srcPosn);
string value = objReader.ReadString ();
SaveSrcLoc (srcLocs, offset, srcFile, srcLine, srcPosn);
ilGen.Emit (opCode, value);
if (objectTokens != null) objectTokens.EmitString (offset, opCode, value);
break;
}
/*
* Who knows what?
*/
default: throw new Exception ("bad ScriptObjWriterCode " + ((byte)code).ToString ());
}
}
}
/**
* @brief Generate array to quickly translate OpCode.Value to full OpCode struct.
*/
private static Dictionary<short, OpCode> PopulateOpCodes ()
{
Dictionary<short, OpCode> opCodeDict = new Dictionary<short, OpCode> ();
FieldInfo[] fields = typeof (OpCodes).GetFields ();
for (int i = 0; i < fields.Length; i ++) {
OpCode opcode = (OpCode)fields[i].GetValue (null);
opCodeDict.Add (opcode.Value, opcode);
}
return opCodeDict;
}
/**
* @brief Write opcode out to file.
*/
private void WriteOpCode (Token errorAt, OpCode opcode)
{
if (errorAt == null) {
objFileWriter.Write ("");
objFileWriter.Write (lastErrorAtLine);
objFileWriter.Write (lastErrorAtPosn);
} else {
if (errorAt.file != lastErrorAtFile) {
objFileWriter.Write (errorAt.file);
lastErrorAtFile = errorAt.file;
} else {
objFileWriter.Write ("");
}
objFileWriter.Write (errorAt.line);
objFileWriter.Write (errorAt.posn);
lastErrorAtLine = errorAt.line;
lastErrorAtPosn = errorAt.posn;
}
objFileWriter.Write (opcode.Value);
}
/**
* @brief Read opcode in from file.
*/
private static OpCode ReadOpCode (BinaryReader objReader, ref string srcFile, ref int srcLine, ref int srcPosn)
{
string f = objReader.ReadString ();
if (f != "") srcFile = f;
srcLine = objReader.ReadInt32 ();
srcPosn = objReader.ReadInt32 ();
short value = objReader.ReadInt16 ();
return opCodes[value];
}
/**
* @brief Save an IL_offset -> source location translation entry
* @param srcLocs = saved entries for the current function
* @param offset = offset in IL object code for next instruction
* @param src{File,Line,Posn} = location in source file corresponding to opcode
* @returns with entry added to srcLocs
*/
private static void SaveSrcLoc (Dictionary<int, ScriptSrcLoc> srcLocs, int offset, string srcFile, int srcLine, int srcPosn)
{
ScriptSrcLoc srcLoc = new ScriptSrcLoc ();
srcLoc.file = srcFile;
srcLoc.line = srcLine;
srcLoc.posn = srcPosn;
srcLocs[offset] = srcLoc;
}
/**
* @brief Create type<->string conversions.
* Using Type.AssemblyQualifiedName is horribly inefficient
* and all our types should be known.
*/
private static Dictionary<string, Type> PopulateS2T ()
{
Dictionary<string, Type> s2t = new Dictionary<string, Type> ();
s2t.Add ("badcallx", typeof (ScriptBadCallNoException));
s2t.Add ("binopstr", typeof (BinOpStr));
s2t.Add ("bool", typeof (bool));
s2t.Add ("char", typeof (char));
s2t.Add ("delegate", typeof (Delegate));
s2t.Add ("delarr[]", typeof (Delegate[]));
s2t.Add ("double", typeof (double));
s2t.Add ("exceptn", typeof (Exception));
s2t.Add ("float", typeof (float));
s2t.Add ("htlist", typeof (HeapTrackerList));
s2t.Add ("htobject", typeof (HeapTrackerObject));
s2t.Add ("htstring", typeof (HeapTrackerString));
s2t.Add ("inlfunc", typeof (CompValuInline));
s2t.Add ("int", typeof (int));
s2t.Add ("int*", typeof (int).MakeByRefType ());
s2t.Add ("intrlokd", typeof (System.Threading.Interlocked));
s2t.Add ("lslfloat", typeof (LSL_Float));
s2t.Add ("lslint", typeof (LSL_Integer));
s2t.Add ("lsllist", typeof (LSL_List));
s2t.Add ("lslrot", typeof (LSL_Rotation));
s2t.Add ("lslstr", typeof (LSL_String));
s2t.Add ("lslvec", typeof (LSL_Vector));
s2t.Add ("math", typeof (Math));
s2t.Add ("midround", typeof (MidpointRounding));
s2t.Add ("object", typeof (object));
s2t.Add ("object*", typeof (object).MakeByRefType ());
s2t.Add ("object[]", typeof (object[]));
s2t.Add ("scrbase", typeof (ScriptBaseClass));
s2t.Add ("scrcode", typeof (ScriptCodeGen));
s2t.Add ("sdtclobj", typeof (XMRSDTypeClObj));
s2t.Add ("string", typeof (string));
s2t.Add ("typecast", typeof (TypeCast));
s2t.Add ("undstatx", typeof (ScriptUndefinedStateException));
s2t.Add ("void", typeof (void));
s2t.Add ("xmrarray", typeof (XMR_Array));
s2t.Add ("xmrinst", typeof (XMRInstAbstract));
return s2t;
}
private static Dictionary<Type, string> PopulateT2S ()
{
Dictionary<string, Type> s2t = PopulateS2T ();
Dictionary<Type, string> t2s = new Dictionary<Type, string> ();
foreach (KeyValuePair<string, Type> kvp in s2t) {
t2s.Add (kvp.Value, kvp.Key);
}
return t2s;
}
/**
* @brief Add to list of internally recognized types.
*/
public static void DefineInternalType (string name, Type type)
{
if (!string2Type.ContainsKey(name))
{
string2Type.Add (name, type);
type2String.Add (type, name);
}
}
private string GetStrFromType (Type t)
{
string s = GetStrFromTypeWork (t);
return s;
}
private string GetStrFromTypeWork (Type t)
{
string s;
// internal fixed types like int and xmrarray etc
if (type2String.TryGetValue (t, out s)) return s;
// script-defined types
if (sdTypesRev.TryGetValue (t, out s)) return "sdt$" + s;
// inline function types
s = TokenDeclSDTypeDelegate.TryGetInlineName (t);
if (s != null) return s;
// last resort
return t.AssemblyQualifiedName;
}
private static Type GetTypeFromStr (Dictionary<string, TokenDeclSDType> sdTypes, string s)
{
Type t;
// internal fixed types like int and xmrarray etc
if (string2Type.TryGetValue (s, out t)) return t;
// script-defined types
if (s.StartsWith ("sdt$")) return sdTypes[s.Substring(4)].GetSysType ();
// inline function types
t = TokenDeclSDTypeDelegate.TryGetInlineSysType (s);
if (t != null) return t;
// last resort
return Type.GetType (s, true);
}
}
public class ScriptSrcLoc {
public string file;
public int line;
public int posn;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,819 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
using OpenSim.Region.ScriptEngine.XMREngine;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
/**
* @brief Generate script object code to perform type casting
*/
namespace OpenSim.Region.ScriptEngine.XMREngine
{
public class TypeCast {
private delegate void CastDelegate (IScriptCodeGen scg, Token errorAt);
private static ConstructorInfo floatConstructorStringInfo = typeof (LSL_Float).GetConstructor (new Type[] { typeof (string) });
private static ConstructorInfo integerConstructorStringInfo = typeof (LSL_Integer).GetConstructor (new Type[] { typeof (string) });
private static ConstructorInfo lslFloatConstructorInfo = typeof (LSL_Float).GetConstructor (new Type[] { typeof (double) });
private static ConstructorInfo lslIntegerConstructorInfo = typeof (LSL_Integer).GetConstructor (new Type[] { typeof (int) });
private static ConstructorInfo lslStringConstructorInfo = typeof (LSL_String).GetConstructor (new Type[] { typeof (string) });
private static ConstructorInfo rotationConstrucorStringInfo = typeof (LSL_Rotation).GetConstructor (new Type[] { typeof (string) });
private static ConstructorInfo vectorConstrucorStringInfo = typeof (LSL_Vector).GetConstructor (new Type[] { typeof (string) });
private static FieldInfo lslFloatValueFieldInfo = typeof (LSL_Float).GetField ("value");
private static FieldInfo lslIntegerValueFieldInfo = typeof (LSL_Integer).GetField ("value");
private static FieldInfo lslStringValueFieldInfo = typeof (LSL_String).GetField ("m_string");
private static FieldInfo sdtcITableFieldInfo = typeof (XMRSDTypeClObj).GetField ("sdtcITable");
private static MethodInfo boolToListMethodInfo = typeof (TypeCast).GetMethod ("BoolToList", new Type[] { typeof (bool) });
private static MethodInfo boolToStringMethodInfo = typeof (TypeCast).GetMethod ("BoolToString", new Type[] { typeof (bool) });
private static MethodInfo charToStringMethodInfo = typeof (TypeCast).GetMethod ("CharToString", new Type[] { typeof (char) });
private static MethodInfo excToStringMethodInfo = typeof (TypeCast).GetMethod ("ExceptionToString", new Type[] { typeof (Exception), typeof (XMRInstAbstract) });
private static MethodInfo floatToStringMethodInfo = typeof (TypeCast).GetMethod ("FloatToString", new Type[] { typeof (double) });
private static MethodInfo intToStringMethodInfo = typeof (TypeCast).GetMethod ("IntegerToString", new Type[] { typeof (int) });
private static MethodInfo keyToBoolMethodInfo = typeof (TypeCast).GetMethod ("KeyToBool", new Type[] { typeof (string) });
private static MethodInfo listToBoolMethodInfo = typeof (TypeCast).GetMethod ("ListToBool", new Type[] { typeof (LSL_List) });
private static MethodInfo listToStringMethodInfo = typeof (TypeCast).GetMethod ("ListToString", new Type[] { typeof (LSL_List) });
private static MethodInfo objectToFloatMethodInfo = typeof (TypeCast).GetMethod ("ObjectToFloat", new Type[] { typeof (object) });
private static MethodInfo objectToIntegerMethodInfo = typeof (TypeCast).GetMethod ("ObjectToInteger", new Type[] { typeof (object) });
private static MethodInfo objectToListMethodInfo = typeof (TypeCast).GetMethod ("ObjectToList", new Type[] { typeof (object) });
private static MethodInfo objectToRotationMethodInfo = typeof (TypeCast).GetMethod ("ObjectToRotation", new Type[] { typeof (object) });
private static MethodInfo objectToStringMethodInfo = typeof (TypeCast).GetMethod ("ObjectToString", new Type[] { typeof (object) });
private static MethodInfo objectToVectorMethodInfo = typeof (TypeCast).GetMethod ("ObjectToVector", new Type[] { typeof (object) });
private static MethodInfo rotationToBoolMethodInfo = typeof (TypeCast).GetMethod ("RotationToBool", new Type[] { typeof (LSL_Rotation) });
private static MethodInfo rotationToStringMethodInfo = typeof (TypeCast).GetMethod ("RotationToString", new Type[] { typeof (LSL_Rotation) });
private static MethodInfo stringToBoolMethodInfo = typeof (TypeCast).GetMethod ("StringToBool", new Type[] { typeof (string) });
private static MethodInfo vectorToBoolMethodInfo = typeof (TypeCast).GetMethod ("VectorToBool", new Type[] { typeof (LSL_Vector) });
private static MethodInfo vectorToStringMethodInfo = typeof (TypeCast).GetMethod ("VectorToString", new Type[] { typeof (LSL_Vector) });
private static MethodInfo sdTypeClassCastClass2ClassMethodInfo = typeof (XMRSDTypeClObj).GetMethod ("CastClass2Class", new Type[] { typeof (object), typeof (int) });
private static MethodInfo sdTypeClassCastIFace2ClassMethodInfo = typeof (XMRSDTypeClObj).GetMethod ("CastIFace2Class", new Type[] { typeof (Delegate[]), typeof (int) });
private static MethodInfo sdTypeClassCastObj2IFaceMethodInfo = typeof (XMRSDTypeClObj).GetMethod ("CastObj2IFace", new Type[] { typeof (object), typeof (string) });
private static MethodInfo charToListMethodInfo = typeof (TypeCast).GetMethod ("CharToList", new Type[] { typeof (char) });
private static MethodInfo excToListMethodInfo = typeof (TypeCast).GetMethod ("ExcToList", new Type[] { typeof (Exception) });
private static MethodInfo vectorToListMethodInfo = typeof (TypeCast).GetMethod ("VectorToList", new Type[] { typeof (LSL_Vector) });
private static MethodInfo floatToListMethodInfo = typeof (TypeCast).GetMethod ("FloatToList", new Type[] { typeof (double) });
private static MethodInfo integerToListMethodInfo = typeof (TypeCast).GetMethod ("IntegerToList", new Type[] { typeof (int) });
private static MethodInfo rotationToListMethodInfo = typeof (TypeCast).GetMethod ("RotationToList", new Type[] { typeof (LSL_Rotation) });
private static MethodInfo stringToListMethodInfo = typeof (TypeCast).GetMethod ("StringToList", new Type[] { typeof (string) });
/*
* List of all allowed type casts and how to perform the casting.
*/
private static Dictionary<string, CastDelegate> legalTypeCasts = CreateLegalTypeCasts ();
/**
* @brief create a dictionary of legal type casts.
* Defines what EXPLICIT type casts are allowed in addition to the IMPLICIT ones.
* Key is of the form <oldtype> <newtype> for IMPLICIT casting.
* Key is of the form <oldtype>*<newtype> for EXPLICIT casting.
* Value is a delegate that generates code to perform the type cast.
*/
private static Dictionary<string, CastDelegate> CreateLegalTypeCasts ()
{
Dictionary<string, CastDelegate> ltc = new Dictionary<string, CastDelegate> ();
// IMPLICIT type casts (a space is in middle of the key)
// EXPLICIT type casts (an * is in middle of the key)
// In general, only mark explicit if it might throw an exception
ltc.Add ("array object", TypeCastArray2Object);
ltc.Add ("bool float", TypeCastBool2Float);
ltc.Add ("bool integer", TypeCastBool2Integer);
ltc.Add ("bool list", TypeCastBool2List);
ltc.Add ("bool object", TypeCastBool2Object);
ltc.Add ("bool string", TypeCastBool2String);
ltc.Add ("char integer", TypeCastChar2Integer);
ltc.Add ("char list", TypeCastChar2List);
ltc.Add ("char object", TypeCastChar2Object);
ltc.Add ("char string", TypeCastChar2String);
ltc.Add ("exception list", TypeCastExc2List);
ltc.Add ("exception object", TypeCastExc2Object);
ltc.Add ("exception string", TypeCastExc2String);
ltc.Add ("float bool", TypeCastFloat2Bool);
ltc.Add ("float integer", TypeCastFloat2Integer);
ltc.Add ("float list", TypeCastFloat2List);
ltc.Add ("float object", TypeCastFloat2Object);
ltc.Add ("float string", TypeCastFloat2String);
ltc.Add ("integer bool", TypeCastInteger2Bool);
ltc.Add ("integer char", TypeCastInteger2Char);
ltc.Add ("integer float", TypeCastInteger2Float);
ltc.Add ("integer list", TypeCastInteger2List);
ltc.Add ("integer object", TypeCastInteger2Object);
ltc.Add ("integer string", TypeCastInteger2String);
ltc.Add ("list bool", TypeCastList2Bool);
ltc.Add ("list object", TypeCastList2Object);
ltc.Add ("list string", TypeCastList2String);
ltc.Add ("object*array", TypeCastObject2Array);
ltc.Add ("object*bool", TypeCastObject2Bool);
ltc.Add ("object*char", TypeCastObject2Char);
ltc.Add ("object*exception", TypeCastObject2Exc);
ltc.Add ("object*float", TypeCastObject2Float);
ltc.Add ("object*integer", TypeCastObject2Integer);
ltc.Add ("object*list", TypeCastObject2List);
ltc.Add ("object*rotation", TypeCastObject2Rotation);
ltc.Add ("object string", TypeCastObject2String);
ltc.Add ("object*vector", TypeCastObject2Vector);
ltc.Add ("rotation bool", TypeCastRotation2Bool);
ltc.Add ("rotation list", TypeCastRotation2List);
ltc.Add ("rotation object", TypeCastRotation2Object);
ltc.Add ("rotation string", TypeCastRotation2String);
ltc.Add ("string bool", TypeCastString2Bool);
ltc.Add ("string float", TypeCastString2Float);
ltc.Add ("string integer", TypeCastString2Integer);
ltc.Add ("string list", TypeCastString2List);
ltc.Add ("string object", TypeCastString2Object);
ltc.Add ("string rotation", TypeCastString2Rotation);
ltc.Add ("string vector", TypeCastString2Vector);
ltc.Add ("vector bool", TypeCastVector2Bool);
ltc.Add ("vector list", TypeCastVector2List);
ltc.Add ("vector object", TypeCastVector2Object);
ltc.Add ("vector string", TypeCastVector2String);
return ltc;
}
/**
* @brief See if the given type can be cast to the other implicitly.
* @param dstType = type being cast to
* @param srcType = type being cast from
* @returns false: implicit cast not allowed
* true: implicit cast allowed
*/
public static bool IsAssignableFrom (TokenType dstType, TokenType srcType)
{
/*
* Do a 'dry run' of the casting operation, discarding any emits and not printing any errors.
* But if the casting tries to print error(s), return false.
* Otherwise assume the cast is allowed and return true.
*/
SCGIAF scg = new SCGIAF ();
scg.ok = true;
scg._ilGen = migiaf;
CastTopOfStack (scg, null, srcType, dstType, false);
return scg.ok;
}
private struct SCGIAF : IScriptCodeGen {
public bool ok;
public ScriptMyILGen _ilGen;
// IScriptCodeGen
public ScriptMyILGen ilGen { get { return _ilGen; } }
public void ErrorMsg (Token token, string message) { ok = false; }
public void PushDefaultValue (TokenType type) { }
public void PushXMRInst () { }
}
private static readonly MIGIAF migiaf = new MIGIAF ();
private struct MIGIAF : ScriptMyILGen {
// ScriptMyILGen
public string methName { get { return null; } }
public ScriptMyLocal DeclareLocal (Type type, string name) { return null; }
public ScriptMyLabel DefineLabel (string name) { return null; }
public void BeginExceptionBlock () { }
public void BeginCatchBlock (Type excType) { }
public void BeginFinallyBlock () { }
public void EndExceptionBlock () { }
public void Emit (Token errorAt, OpCode opcode) { }
public void Emit (Token errorAt, OpCode opcode, FieldInfo field) { }
public void Emit (Token errorAt, OpCode opcode, ScriptMyLocal myLocal) { }
public void Emit (Token errorAt, OpCode opcode, Type type) { }
public void Emit (Token errorAt, OpCode opcode, ScriptMyLabel myLabel) { }
public void Emit (Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels) { }
public void Emit (Token errorAt, OpCode opcode, ScriptObjWriter method) { }
public void Emit (Token errorAt, OpCode opcode, MethodInfo method) { }
public void Emit (Token errorAt, OpCode opcode, ConstructorInfo ctor) { }
public void Emit (Token errorAt, OpCode opcode, double value) { }
public void Emit (Token errorAt, OpCode opcode, float value) { }
public void Emit (Token errorAt, OpCode opcode, int value) { }
public void Emit (Token errorAt, OpCode opcode, string value) { }
public void MarkLabel (ScriptMyLabel myLabel) { }
}
/**
* @brief Emit code that converts the top stack item from 'oldType' to 'newType'
* @param scg = what script we are compiling
* @param errorAt = token used for source location for error messages
* @param oldType = type of item currently on the stack
* @param newType = type to convert it to
* @param explicitAllowed = false: only consider implicit casts
* true: consider both implicit and explicit casts
* @returns with code emitted for conversion (or error message output if not allowed, and stack left unchanged)
*/
public static void CastTopOfStack (IScriptCodeGen scg, Token errorAt, TokenType oldType, TokenType newType, bool explicitAllowed)
{
CastDelegate castDelegate;
string oldString = oldType.ToString ();
string newString = newType.ToString ();
/*
* 'key' -> 'bool' is the only time we care about key being different than string.
*/
if ((oldString == "key") && (newString == "bool")) {
LSLUnwrap (scg, errorAt, oldType);
scg.ilGen.Emit (errorAt, OpCodes.Call, keyToBoolMethodInfo);
LSLWrap (scg, errorAt, newType);
return;
}
/*
* Treat key and string as same type for all other type casts.
*/
if (oldString == "key") oldString = "string";
if (newString == "key") newString = "string";
/*
* If the types are the same, there is no conceptual casting needed.
* However, there may be wraping/unwraping to/from the LSL wrappers.
*/
if (oldString == newString) {
if (oldType.ToLSLWrapType () != newType.ToLSLWrapType ()) {
LSLUnwrap (scg, errorAt, oldType);
LSLWrap (scg, errorAt, newType);
}
return;
}
/*
* Script-defined classes can be cast up and down the tree.
*/
if ((oldType is TokenTypeSDTypeClass) && (newType is TokenTypeSDTypeClass)) {
TokenDeclSDTypeClass oldSDTC = ((TokenTypeSDTypeClass)oldType).decl;
TokenDeclSDTypeClass newSDTC = ((TokenTypeSDTypeClass)newType).decl;
// implicit cast allowed from leaf toward root
for (TokenDeclSDTypeClass sdtc = oldSDTC; sdtc != null; sdtc = sdtc.extends) {
if (sdtc == newSDTC) return;
}
// explicit cast allowed from root toward leaf
for (TokenDeclSDTypeClass sdtc = newSDTC; sdtc != null; sdtc = sdtc.extends) {
if (sdtc == oldSDTC) {
ExplCheck (scg, errorAt, explicitAllowed, oldString, newString);
scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, newSDTC.sdTypeIndex);
scg.ilGen.Emit (errorAt, OpCodes.Call, sdTypeClassCastClass2ClassMethodInfo);
return;
}
}
// not on same branch
goto illcast;
}
/*
* One script-defined interface type cannot be cast to another script-defined interface type,
* unless the old interface declares that it implements the new interface. That proves that
* the underlying object, no matter what type, implements the new interface.
*/
if ((oldType is TokenTypeSDTypeInterface) && (newType is TokenTypeSDTypeInterface)) {
TokenDeclSDTypeInterface oldDecl = ((TokenTypeSDTypeInterface)oldType).decl;
TokenDeclSDTypeInterface newDecl = ((TokenTypeSDTypeInterface)newType).decl;
if (!oldDecl.Implements (newDecl)) goto illcast;
scg.ilGen.Emit (errorAt, OpCodes.Ldstr, newType.ToString ());
scg.ilGen.Emit (errorAt, OpCodes.Call, sdTypeClassCastObj2IFaceMethodInfo);
return;
}
/*
* A script-defined class type can be implicitly cast to a script-defined interface type that it
* implements. The result is an array of delegates that give the class's implementation of the
* various methods defined by the interface.
*/
if ((oldType is TokenTypeSDTypeClass) && (newType is TokenTypeSDTypeInterface)) {
TokenDeclSDTypeClass oldSDTC = ((TokenTypeSDTypeClass)oldType).decl;
int intfIndex;
if (!oldSDTC.intfIndices.TryGetValue (newType.ToString (), out intfIndex)) goto illcast;
scg.ilGen.Emit (errorAt, OpCodes.Ldfld, sdtcITableFieldInfo);
scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, intfIndex);
scg.ilGen.Emit (errorAt, OpCodes.Ldelem, typeof (Delegate[]));
return;
}
/*
* A script-defined interface type can be explicitly cast to a script-defined class type by
* extracting the Target property from element 0 of the delegate array that is the interface
* object and making sure it casts to the correct script-defined class type.
*
* But then only if the class type implements the interface type.
*/
if ((oldType is TokenTypeSDTypeInterface) && (newType is TokenTypeSDTypeClass)) {
TokenTypeSDTypeInterface oldSDTI = (TokenTypeSDTypeInterface)oldType;
TokenTypeSDTypeClass newSDTC = (TokenTypeSDTypeClass) newType;
if (!newSDTC.decl.CanCastToIntf (oldSDTI.decl)) goto illcast;
ExplCheck (scg, errorAt, explicitAllowed, oldString, newString);
scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, newSDTC.decl.sdTypeIndex);
scg.ilGen.Emit (errorAt, OpCodes.Call, sdTypeClassCastIFace2ClassMethodInfo);
return;
}
/*
* A script-defined interface type can be implicitly cast to object.
*/
if ((oldType is TokenTypeSDTypeInterface) && (newType is TokenTypeObject)) {
return;
}
/*
* An object can be explicitly cast to a script-defined interface.
*/
if ((oldType is TokenTypeObject) && (newType is TokenTypeSDTypeInterface)) {
ExplCheck (scg, errorAt, explicitAllowed, oldString, newString);
scg.ilGen.Emit (errorAt, OpCodes.Ldstr, newString);
scg.ilGen.Emit (errorAt, OpCodes.Call, sdTypeClassCastObj2IFaceMethodInfo);
return;
}
/*
* Cast to void is always allowed, such as discarding value from 'i++' or function return value.
*/
if (newType is TokenTypeVoid) {
scg.ilGen.Emit (errorAt, OpCodes.Pop);
return;
}
/*
* Cast from undef to object or script-defined type is always allowed.
*/
if ((oldType is TokenTypeUndef) &&
((newType is TokenTypeObject) ||
(newType is TokenTypeSDTypeClass) ||
(newType is TokenTypeSDTypeInterface))) {
return;
}
/*
* Script-defined classes can be implicitly cast to objects.
*/
if ((oldType is TokenTypeSDTypeClass) && (newType is TokenTypeObject)) {
return;
}
/*
* Script-defined classes can be explicitly cast from objects and other script-defined classes.
* Note that we must manually check that it is the correct SDTypeClass however because as far as
* mono is concerned, all SDTypeClass's are the same.
*/
if ((oldType is TokenTypeObject) && (newType is TokenTypeSDTypeClass)) {
ExplCheck (scg, errorAt, explicitAllowed, oldString, newString);
scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4, ((TokenTypeSDTypeClass)newType).decl.sdTypeIndex);
scg.ilGen.Emit (errorAt, OpCodes.Call, sdTypeClassCastClass2ClassMethodInfo);
return;
}
/*
* Delegates can be implicitly cast to/from objects.
*/
if ((oldType is TokenTypeSDTypeDelegate) && (newType is TokenTypeObject)) {
return;
}
if ((oldType is TokenTypeObject) && (newType is TokenTypeSDTypeDelegate)) {
scg.ilGen.Emit (errorAt, OpCodes.Castclass, newType.ToSysType ());
return;
}
/*
* Some actual conversion is needed, see if it is in table of legal casts.
*/
string key = oldString + " " + newString;
if (!legalTypeCasts.TryGetValue (key, out castDelegate)) {
key = oldString + "*" + newString;
if (!legalTypeCasts.TryGetValue (key, out castDelegate)) goto illcast;
ExplCheck (scg, errorAt, explicitAllowed, oldString, newString);
}
/*
* Ok, output cast. But make sure it is in native form without any LSL wrapping
* before passing to our casting routine. Then if caller is expecting an LSL-
* wrapped value on the stack upon return, wrap it up after our casting.
*/
LSLUnwrap (scg, errorAt, oldType);
castDelegate (scg, errorAt);
LSLWrap (scg, errorAt, newType);
return;
illcast:
scg.ErrorMsg (errorAt, "illegal to cast from " + oldString + " to " + newString);
if (!(oldType is TokenTypeVoid)) scg.ilGen.Emit (errorAt, OpCodes.Pop);
scg.PushDefaultValue (newType);
}
private static void ExplCheck (IScriptCodeGen scg, Token errorAt, bool explicitAllowed, string oldString, string newString)
{
if (!explicitAllowed) {
scg.ErrorMsg (errorAt, "must explicitly cast from " + oldString + " to " + newString);
}
}
/**
* @brief If value on the stack is an LSL-style wrapped value, unwrap it.
*/
public static void LSLUnwrap (IScriptCodeGen scg, Token errorAt, TokenType type)
{
if (type.ToLSLWrapType () == typeof (LSL_Float)) {
scg.ilGen.Emit (errorAt, OpCodes.Ldfld, lslFloatValueFieldInfo);
}
if (type.ToLSLWrapType () == typeof (LSL_Integer)) {
scg.ilGen.Emit (errorAt, OpCodes.Ldfld, lslIntegerValueFieldInfo);
}
if (type.ToLSLWrapType () == typeof (LSL_String)) {
scg.ilGen.Emit (errorAt, OpCodes.Ldfld, lslStringValueFieldInfo);
}
}
/**
* @brief If caller wants the unwrapped value on stack wrapped LSL-style, wrap it.
*/
private static void LSLWrap (IScriptCodeGen scg, Token errorAt, TokenType type)
{
if (type.ToLSLWrapType () == typeof (LSL_Float)) {
scg.ilGen.Emit (errorAt, OpCodes.Newobj, lslFloatConstructorInfo);
}
if (type.ToLSLWrapType () == typeof (LSL_Integer)) {
scg.ilGen.Emit (errorAt, OpCodes.Newobj, lslIntegerConstructorInfo);
}
if (type.ToLSLWrapType () == typeof (LSL_String)) {
scg.ilGen.Emit (errorAt, OpCodes.Newobj, lslStringConstructorInfo);
}
}
/**
* @brief These routines output code to perform casting.
* They can assume there are no LSL wrapped values on input
* and they should not output an LSL wrapped value.
*/
private static void TypeCastArray2Object (IScriptCodeGen scg, Token errorAt)
{
}
private static void TypeCastBool2Float (IScriptCodeGen scg, Token errorAt)
{
if (typeof (double) == typeof (float)) {
scg.ilGen.Emit (errorAt, OpCodes.Conv_R4);
} else if (typeof (double) == typeof (double)) {
scg.ilGen.Emit (errorAt, OpCodes.Conv_R8);
} else {
throw new Exception ("unknown type");
}
}
private static void TypeCastBool2Integer (IScriptCodeGen scg, Token errorAt)
{
}
private static void TypeCastBool2Object (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (bool));
}
private static void TypeCastChar2Integer (IScriptCodeGen scg, Token errorAt)
{
}
private static void TypeCastChar2List (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, charToListMethodInfo);
}
private static void TypeCastChar2Object (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (char));
}
private static void TypeCastChar2String (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, charToStringMethodInfo);
}
private static void TypeCastExc2List (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, excToListMethodInfo);
}
private static void TypeCastExc2Object (IScriptCodeGen scg, Token errorAt)
{
}
private static void TypeCastExc2String (IScriptCodeGen scg, Token errorAt)
{
scg.PushXMRInst ();
scg.ilGen.Emit (errorAt, OpCodes.Call, excToStringMethodInfo);
}
private static void TypeCastFloat2Bool (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Ldc_R4, 0.0f);
scg.ilGen.Emit (errorAt, OpCodes.Ceq);
scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
scg.ilGen.Emit (errorAt, OpCodes.Xor);
}
private static void TypeCastFloat2Integer (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Conv_I4);
}
private static void TypeCastFloat2Object (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (double));
}
private static void TypeCastInteger2Bool (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_0);
scg.ilGen.Emit (errorAt, OpCodes.Ceq);
scg.ilGen.Emit (errorAt, OpCodes.Ldc_I4_1);
scg.ilGen.Emit (errorAt, OpCodes.Xor);
}
private static void TypeCastInteger2Char (IScriptCodeGen scg, Token errorAt)
{
}
private static void TypeCastInteger2Float (IScriptCodeGen scg, Token errorAt)
{
if (typeof (double) == typeof (float)) {
scg.ilGen.Emit (errorAt, OpCodes.Conv_R4);
} else if (typeof (double) == typeof (double)) {
scg.ilGen.Emit (errorAt, OpCodes.Conv_R8);
} else {
throw new Exception ("unknown type");
}
}
private static void TypeCastInteger2Object (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (int));
}
private static void TypeCastList2Bool (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, listToBoolMethodInfo);
}
private static void TypeCastList2Object (IScriptCodeGen scg, Token errorAt)
{
if (typeof (LSL_List).IsValueType) {
scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (LSL_List));
}
}
private static void TypeCastObject2Array (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Castclass, typeof (XMR_Array));
}
private static void TypeCastObject2Bool (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Unbox_Any, typeof (bool));
}
private static void TypeCastObject2Char (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Unbox_Any, typeof (char));
}
private static void TypeCastObject2Exc (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Castclass, typeof (Exception));
}
private static void TypeCastObject2Float (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, objectToFloatMethodInfo);
}
private static void TypeCastObject2Integer (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, objectToIntegerMethodInfo);
}
private static void TypeCastObject2List (IScriptCodeGen scg, Token errorAt)
{
if (typeof (LSL_List).IsValueType) {
scg.ilGen.Emit (errorAt, OpCodes.Call, objectToListMethodInfo);
} else {
scg.ilGen.Emit (errorAt, OpCodes.Castclass, typeof (LSL_List));
}
}
private static void TypeCastObject2Rotation (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, objectToRotationMethodInfo);
}
private static void TypeCastObject2Vector (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, objectToVectorMethodInfo);
}
private static void TypeCastRotation2Bool (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, rotationToBoolMethodInfo);
}
private static void TypeCastRotation2Object (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (LSL_Rotation));
}
private static void TypeCastString2Bool (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, stringToBoolMethodInfo);
}
private static void TypeCastString2Object (IScriptCodeGen scg, Token errorAt)
{
}
private static void TypeCastString2Rotation (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Newobj, rotationConstrucorStringInfo);
}
private static void TypeCastString2Vector (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Newobj, vectorConstrucorStringInfo);
}
private static void TypeCastVector2Bool (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, vectorToBoolMethodInfo);
}
private static void TypeCastVector2List (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, vectorToListMethodInfo);
}
private static void TypeCastVector2Object (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Box, typeof (LSL_Vector));
}
private static void TypeCastBool2List (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, boolToListMethodInfo);
}
private static void TypeCastBool2String (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, boolToStringMethodInfo);
}
private static void TypeCastFloat2List (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, floatToListMethodInfo);
}
private static void TypeCastFloat2String (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, floatToStringMethodInfo);
}
private static void TypeCastInteger2List (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, integerToListMethodInfo);
}
private static void TypeCastInteger2String (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, intToStringMethodInfo);
}
private static void TypeCastList2String (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, listToStringMethodInfo);
}
private static void TypeCastObject2String (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, objectToStringMethodInfo);
}
private static void TypeCastRotation2List (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, rotationToListMethodInfo);
}
private static void TypeCastRotation2String (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, rotationToStringMethodInfo);
}
private static void TypeCastString2Float (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Newobj, floatConstructorStringInfo);
scg.ilGen.Emit (errorAt, OpCodes.Ldfld, lslFloatValueFieldInfo);
}
private static void TypeCastString2Integer (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Newobj, integerConstructorStringInfo);
scg.ilGen.Emit (errorAt, OpCodes.Ldfld, lslIntegerValueFieldInfo);
}
private static void TypeCastString2List (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, stringToListMethodInfo);
}
private static void TypeCastVector2String (IScriptCodeGen scg, Token errorAt)
{
scg.ilGen.Emit (errorAt, OpCodes.Call, vectorToStringMethodInfo);
}
/*
* Because the calls are funky, let the compiler handle them.
*/
public static bool RotationToBool (LSL_Rotation x) { return !x.Equals (ScriptBaseClass.ZERO_ROTATION); }
public static bool StringToBool (string x) { return x.Length > 0; }
public static bool VectorToBool (LSL_Vector x) { return !x.Equals (ScriptBaseClass.ZERO_VECTOR); }
public static string BoolToString (bool x) { return x ? "1" : "0"; }
public static string CharToString (char x) { return x.ToString (); }
public static string FloatToString (double x) { return x.ToString ("0.000000"); }
public static string IntegerToString (int x) { return x.ToString (); }
public static bool KeyToBool (string x) { return (x != "") && (x != ScriptBaseClass.NULL_KEY); }
public static bool ListToBool (LSL_List x) { return x.Length != 0; }
public static string ListToString (LSL_List x) { return x.ToString (); }
public static string ObjectToString (object x) { return (x == null) ? null : x.ToString (); }
public static string RotationToString (LSL_Rotation x) { return x.ToString (); }
public static string VectorToString (LSL_Vector x) { return x.ToString (); }
public static LSL_List BoolToList (bool b) { return new LSL_List (new object[] { new LSL_Integer (b ? 1 : 0) }); }
public static LSL_List CharToList (char c) { return new LSL_List (new object[] { new LSL_Integer (c) }); }
public static LSL_List ExcToList (Exception e) { return new LSL_List (new object[] { e }); }
public static LSL_List VectorToList (LSL_Vector v) { return new LSL_List (new object[] { v }); }
public static LSL_List FloatToList (double f) { return new LSL_List (new object[] { new LSL_Float (f) }); }
public static LSL_List IntegerToList (int i) { return new LSL_List (new object[] { new LSL_Integer (i) }); }
public static LSL_List RotationToList (LSL_Rotation r) { return new LSL_List (new object[] { r }); }
public static LSL_List StringToList (string s) { return new LSL_List (new object[] { new LSL_String (s) }); }
public static double ObjectToFloat (object x)
{
if (x is LSL_String) return double.Parse (((LSL_String)x).m_string);
if (x is string) return double.Parse ((string)x);
if (x is LSL_Float) return (double)(LSL_Float)x;
if (x is LSL_Integer) return (double)(int)(LSL_Integer)x;
if (x is int) return (double)(int)x;
return (double)x;
}
public static int ObjectToInteger (object x)
{
if (x is LSL_String) return int.Parse (((LSL_String)x).m_string);
if (x is string) return int.Parse ((string)x);
if (x is LSL_Integer) return (int)(LSL_Integer)x;
return (int)x;
}
public static LSL_List ObjectToList (object x)
{
return (LSL_List)x;
}
public static LSL_Rotation ObjectToRotation (object x)
{
if (x is LSL_String) return new LSL_Rotation (((LSL_String)x).m_string);
if (x is string) return new LSL_Rotation ((string)x);
return (LSL_Rotation)x;
}
public static LSL_Vector ObjectToVector (object x)
{
if (x is LSL_String) return new LSL_Vector (((LSL_String)x).m_string);
if (x is string) return new LSL_Vector ((string)x);
return (LSL_Vector)x;
}
public static string ExceptionToString (Exception x, XMRInstAbstract inst)
{
return XMRInstAbstract.xmrExceptionTypeName (x) + ": " + XMRInstAbstract.xmrExceptionMessage (x) +
"\n" + inst.xmrExceptionStackTrace (x);
}
/*
* These are used by event handler entrypoints to remove any LSL wrapping
* from the argument list and return the unboxed/unwrapped value.
*/
public static double EHArgUnwrapFloat (object x)
{
if (x is LSL_Float) return (double)(LSL_Float)x;
return (double)x;
}
public static int EHArgUnwrapInteger (object x)
{
if (x is LSL_Integer) return (int)(LSL_Integer)x;
return (int)x;
}
public static LSL_Rotation EHArgUnwrapRotation (object x)
{
if (x is OpenMetaverse.Quaternion) {
OpenMetaverse.Quaternion q = (OpenMetaverse.Quaternion)x;
return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
}
return (LSL_Rotation)x;
}
public static string EHArgUnwrapString (object x)
{
if (x is LSL_Key) return (string)(LSL_Key)x;
if (x is LSL_String) return (string)(LSL_String)x;
return (string)x;
}
public static LSL_Vector EHArgUnwrapVector (object x)
{
if (x is OpenMetaverse.Vector3) {
OpenMetaverse.Vector3 v = (OpenMetaverse.Vector3)x;
return new LSL_Vector(v.X, v.Y, v.Z);
}
return (LSL_Vector)x;
}
}
}

View File

@ -1,269 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @brief Perform web request
*/
using System;
using System.IO;
using System.Net;
using System.Text;
namespace OpenSim.Region.ScriptEngine.XMREngine {
public class MMRWebRequest {
public static bool allowFileURL = false;
public static Stream MakeRequest (string verb, string requestUrl, string obj, int timeoutms)
{
/*
* Pick apart the given URL and make sure we support it.
* For file:// URLs, just return a read-only stream of the file.
*/
Uri uri = new Uri (requestUrl);
string supported = "http and https";
if (allowFileURL && (verb == "GET")) {
supported = "file, http and https";
if (uri.Scheme == "file") {
return File.OpenRead (requestUrl.Substring (7));
}
}
bool https = uri.Scheme == "https";
if (!https && (uri.Scheme != "http")) {
throw new WebException ("only support " + supported + ", not " + uri.Scheme + " in " + requestUrl);
}
string host = uri.Host;
int port = uri.Port;
if (port < 0) port = https ? 443 : 80;
string path = uri.AbsolutePath;
/*
* Connect to the web server.
*/
System.Net.Sockets.TcpClient tcpconnection = new System.Net.Sockets.TcpClient (host, port);
if (timeoutms > 0) {
tcpconnection.SendTimeout = timeoutms;
tcpconnection.ReceiveTimeout = timeoutms;
}
try {
/*
* Get TCP stream to/from web server.
* If HTTPS, wrap stream with SSL encryption.
*/
Stream tcpstream = tcpconnection.GetStream ();
if (https) {
System.Net.Security.SslStream sslstream = new System.Net.Security.SslStream (tcpstream, false);
sslstream.AuthenticateAsClient (host);
tcpstream = sslstream;
}
/*
* Write request header to the web server.
* There might be some POST data as well to write to web server.
*/
WriteStream (tcpstream, verb + " " + path + " HTTP/1.1\r\n");
WriteStream (tcpstream, "Host: " + host + "\r\n");
if (obj != null) {
byte[] bytes = Encoding.UTF8.GetBytes (obj);
WriteStream (tcpstream, "Content-Length: " + bytes.Length + "\r\n");
WriteStream (tcpstream, "Content-Type: application/x-www-form-urlencoded\r\n");
WriteStream (tcpstream, "\r\n");
tcpstream.Write (bytes, 0, bytes.Length);
} else {
WriteStream (tcpstream, "\r\n");
}
tcpstream.Flush ();
/*
* Check for successful reply status line.
*/
string headerline = ReadStreamLine (tcpstream).Trim ();
if (headerline != "HTTP/1.1 200 OK") throw new WebException ("status line " + headerline);
/*
* Scan through header lines.
* The only ones we care about are Content-Length and Transfer-Encoding.
*/
bool chunked = false;
int contentlength = -1;
while ((headerline = ReadStreamLine (tcpstream).Trim ().ToLowerInvariant ()) != "") {
if (headerline.StartsWith ("content-length:")) {
contentlength = int.Parse (headerline.Substring (15));
}
if (headerline.StartsWith ("transfer-encoding:") && (headerline.Substring (18).Trim () == "chunked")) {
chunked = true;
}
}
/*
* Read response byte array as a series of chunks.
*/
if (chunked) {
return new ChunkedStreamReader (tcpstream);
}
/*
* Read response byte array with the exact length given by Content-Length.
*/
if (contentlength >= 0) {
return new LengthStreamReader (tcpstream, contentlength);
}
/*
* Don't know how it is being transferred.
*/
throw new WebException ("header missing content-length or transfer-encoding: chunked");
} catch {
tcpconnection.Close ();
throw;
}
}
/**
* @brief Write the string out as ASCII bytes.
*/
private static void WriteStream (Stream stream, string line)
{
byte[] bytes = Encoding.ASCII.GetBytes (line);
stream.Write (bytes, 0, bytes.Length);
}
/**
* @brief Read the next text line from a stream.
* @returns string with \r\n trimmed off
*/
private static string ReadStreamLine (Stream stream)
{
StringBuilder sb = new StringBuilder ();
while (true) {
int b = stream.ReadByte ();
if (b < 0) break;
if (b == '\n') break;
if (b == '\r') continue;
sb.Append ((char)b);
}
return sb.ToString ();
}
private class ChunkedStreamReader : Stream {
private int chunklen;
private Stream tcpstream;
public ChunkedStreamReader (Stream tcpstream)
{
this.tcpstream = tcpstream;
}
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return false; } }
public override bool CanTimeout { get { return false; } }
public override bool CanWrite { get { return false; } }
public override long Length { get { return 0; } }
public override long Position { get { return 0; } set { } }
public override void Flush () { }
public override long Seek (long offset, SeekOrigin origin) { return 0; }
public override void SetLength (long length) { }
public override void Write (byte[] buffer, int offset, int length) { }
public override int Read (byte[] buffer, int offset, int length)
{
if (length <= 0) return 0;
if (chunklen == 0) {
chunklen = int.Parse (ReadStreamLine (tcpstream), System.Globalization.NumberStyles.HexNumber);
if (chunklen < 0) throw new WebException ("negative chunk length");
if (chunklen == 0) chunklen = -1;
}
if (chunklen < 0) return 0;
int maxread = (length < chunklen) ? length : chunklen;
int lenread = tcpstream.Read (buffer, offset, maxread);
chunklen -= lenread;
if (chunklen == 0) {
int b = tcpstream.ReadByte ();
if (b == '\r') b = tcpstream.ReadByte ();
if (b != '\n') throw new WebException ("chunk not followed by \\r\\n");
}
return lenread;
}
public override void Close ()
{
chunklen = -1;
if (tcpstream != null) {
tcpstream.Close ();
tcpstream = null;
}
}
}
private class LengthStreamReader : Stream {
private int contentlength;
private Stream tcpstream;
public LengthStreamReader (Stream tcpstream, int contentlength)
{
this.tcpstream = tcpstream;
this.contentlength = contentlength;
}
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return false; } }
public override bool CanTimeout { get { return false; } }
public override bool CanWrite { get { return false; } }
public override long Length { get { return 0; } }
public override long Position { get { return 0; } set { } }
public override void Flush () { }
public override long Seek (long offset, SeekOrigin origin) { return 0; }
public override void SetLength (long length) { }
public override void Write (byte[] buffer, int offset, int length) { }
public override int Read (byte[] buffer, int offset, int length)
{
if (length <= 0) return 0;
if (contentlength <= 0) return 0;
int maxread = (length < contentlength) ? length : contentlength;
int lenread = tcpstream.Read (buffer, offset, maxread);
contentlength -= lenread;
return lenread;
}
public override void Close ()
{
contentlength = -1;
if (tcpstream != null) {
tcpstream.Close ();
tcpstream = null;
}
}
}
}
}

View File

@ -1,491 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using log4net;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine
{
public partial class XMREngine {
private void XmrTestLs (string[] args, int indx)
{
bool flagFull = false;
bool flagQueues = false;
bool flagTopCPU = false;
int maxScripts = 0x7FFFFFFF;
int numScripts = 0;
string outName = null;
XMRInstance[] instances;
/*
* Decode command line options.
*/
for (int i = indx; i < args.Length; i ++) {
if (args[i] == "-full") {
flagFull = true;
continue;
}
if (args[i] == "-help") {
m_log.Info ("[XMREngine]: xmr ls -full -max=<number> -out=<filename> -queues -topcpu");
return;
}
if (args[i].StartsWith("-max=")) {
try {
maxScripts = Convert.ToInt32(args[i].Substring(5));
} catch (Exception e) {
m_log.Error("[XMREngine]: bad max " + args[i].Substring(5) + ": " + e.Message);
return;
}
continue;
}
if (args[i].StartsWith("-out=")) {
outName = args[i].Substring(5);
continue;
}
if (args[i] == "-queues") {
flagQueues = true;
continue;
}
if (args[i] == "-topcpu") {
flagTopCPU = true;
continue;
}
if (args[i][0] == '-') {
m_log.Error("[XMREngine]: unknown option " + args[i] + ", try 'xmr ls -help'");
return;
}
}
TextWriter outFile = null;
if (outName != null) {
try {
outFile = File.CreateText(outName);
} catch (Exception e) {
m_log.Error("[XMREngine]: error creating " + outName + ": " + e.Message);
return;
}
} else {
outFile = new LogInfoTextWriter(m_log);
}
try {
for (int i = 0; i < numThreadScriptWorkers; i ++) {
XMRScriptThread th = m_ScriptThreads[i];
outFile.WriteLine("Script thread ID: " + th.m_ScriptThreadTID);
long execTime = th.m_ScriptExecTime;
if (execTime < 0) {
execTime += (long)(DateTime.UtcNow - DateTime.MinValue).TotalMilliseconds;
}
outFile.WriteLine(" execution time: " + execTime + " mS");
outFile.WriteLine(" last ran at: " + th.m_LastRanAt.ToString());
XMRInstance rins = th.m_RunInstance;
if (rins != null) {
outFile.WriteLine(" running: " + rins.ItemID.ToString() + " " + rins.m_DescName);
if (flagFull) {
outFile.WriteLine (rins.RunTestLs (true));
}
}
}
/*
* Scan instance list to find those that match selection criteria.
*/
if (!Monitor.TryEnter(m_InstancesDict, 100)) {
m_log.Error("[XMREngine]: deadlock m_LockedDict=" + m_LockedDict);
return;
}
try
{
instances = new XMRInstance[m_InstancesDict.Count];
foreach (XMRInstance ins in m_InstancesDict.Values)
{
if (InstanceMatchesArgs(ins, args, indx)) {
instances[numScripts++] = ins;
}
}
} finally {
Monitor.Exit(m_InstancesDict);
}
/*
* Maybe sort by descending CPU time.
*/
if (flagTopCPU) {
Array.Sort<XMRInstance>(instances, CompareInstancesByCPUTime);
}
/*
* Print the entries.
*/
if (!flagFull) {
outFile.WriteLine(" ItemID" +
" CPU(ms)" +
" NumEvents" +
" Status " +
" World Position " +
" <Part>:<Item>");
}
for (int i = 0; (i < numScripts) && (i < maxScripts); i ++) {
outFile.WriteLine(instances[i].RunTestLs(flagFull));
}
/*
* Print number of scripts that match selection criteria,
* even if we were told to print fewer.
*/
outFile.WriteLine("total of {0} script(s)", numScripts);
/*
* If -queues given, print out queue contents too.
*/
if (flagQueues) {
LsQueue(outFile, "start", m_StartQueue, args, indx);
LsQueue(outFile, "sleep", m_SleepQueue, args, indx);
LsQueue(outFile, "yield", m_YieldQueue, args, indx);
}
} finally {
outFile.Close();
}
}
private void XmrTestPev (string[] args, int indx)
{
bool flagAll = false;
int numScripts = 0;
XMRInstance[] instances;
/*
* Decode command line options.
*/
int i, j;
List<string> selargs = new List<string> (args.Length);
MethodInfo[] eventmethods = typeof (IEventHandlers).GetMethods ();
MethodInfo eventmethod;
for (i = indx; i < args.Length; i ++) {
string arg = args[i];
if (arg == "-all") {
flagAll = true;
continue;
}
if (arg == "-help") {
m_log.Info ("[XMREngine]: xmr pev -all | <part-of-script-name> <event-name> <params...>");
return;
}
if (arg[0] == '-') {
m_log.Error ("[XMREngine]: unknown option " + arg + ", try 'xmr pev -help'");
return;
}
for (j = 0; j < eventmethods.Length; j ++) {
eventmethod = eventmethods[j];
if (eventmethod.Name == arg) goto gotevent;
}
selargs.Add (arg);
}
m_log.Error ("[XMREngine]: missing <event-name> <params...>, try 'xmr pev -help'");
return;
gotevent:
string eventname = eventmethod.Name;
StringBuilder sourcesb = new StringBuilder ();
while (++ i < args.Length) {
sourcesb.Append (' ');
sourcesb.Append (args[i]);
}
string sourcest = sourcesb.ToString ();
string sourcehash;
youveanerror = false;
Token t = TokenBegin.Construct ("", null, ErrorMsg, sourcest, out sourcehash);
if (youveanerror) return;
ParameterInfo[] paraminfos = eventmethod.GetParameters ();
object[] paramvalues = new object[paraminfos.Length];
i = 0;
while (!((t = t.nextToken) is TokenEnd)) {
if (i >= paramvalues.Length) {
ErrorMsg (t, "extra parameter(s)");
return;
}
paramvalues[i] = ParseParamValue (ref t);
if (paramvalues[i] == null) return;
i ++;
}
OpenSim.Region.ScriptEngine.Shared.EventParams eps =
new OpenSim.Region.ScriptEngine.Shared.EventParams (eventname, paramvalues, zeroDetectParams);
/*
* Scan instance list to find those that match selection criteria.
*/
if (!Monitor.TryEnter(m_InstancesDict, 100)) {
m_log.Error("[XMREngine]: deadlock m_LockedDict=" + m_LockedDict);
return;
}
try {
instances = new XMRInstance[m_InstancesDict.Count];
foreach (XMRInstance ins in m_InstancesDict.Values) {
if (flagAll || InstanceMatchesArgs (ins, selargs.ToArray (), 0)) {
instances[numScripts++] = ins;
}
}
} finally {
Monitor.Exit(m_InstancesDict);
}
/*
* Post event to the matching instances.
*/
for (i = 0; i < numScripts; i ++) {
XMRInstance inst = instances[i];
m_log.Info ("[XMREngine]: post " + eventname + " to " + inst.m_DescName);
inst.PostEvent (eps);
}
}
private object ParseParamValue (ref Token token)
{
if (token is TokenFloat) {
return new LSL_Float (((TokenFloat)token).val);
}
if (token is TokenInt) {
return new LSL_Integer (((TokenInt)token).val);
}
if (token is TokenStr) {
return new LSL_String (((TokenStr)token).val);
}
if (token is TokenKwCmpLT) {
List<double> valuelist = new List<double> ();
while (!((token = token.nextToken) is TokenKwCmpGT)) {
if (!(token is TokenKwComma)) {
object value = ParseParamValue (ref token);
if (value == null) return null;
if (value is int) value = (double)(int)value;
if (!(value is double)) {
ErrorMsg (token, "must be float or integer constant");
return null;
}
valuelist.Add ((double)value);
} else if (token.prevToken is TokenKwComma) {
ErrorMsg (token, "missing constant");
return null;
}
}
double[] values = valuelist.ToArray ();
switch (values.Length) {
case 3: {
return new LSL_Vector (values[0], values[1], values[2]);
}
case 4: {
return new LSL_Rotation (values[0], values[1], values[2], values[3]);
}
default: {
ErrorMsg (token, "not rotation or vector");
return null;
}
}
}
if (token is TokenKwBrkOpen) {
List<object> valuelist = new List<object> ();
while (!((token = token.nextToken) is TokenKwBrkClose)) {
if (!(token is TokenKwComma)) {
object value = ParseParamValue (ref token);
if (value == null) return null;
valuelist.Add (value);
} else if (token.prevToken is TokenKwComma) {
ErrorMsg (token, "missing constant");
return null;
}
}
return new LSL_List (valuelist.ToArray ());
}
if (token is TokenName) {
FieldInfo field = typeof (OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass).GetField (((TokenName)token).val);
if ((field != null) && field.IsPublic && (field.IsLiteral || (field.IsStatic && field.IsInitOnly))) {
return field.GetValue (null);
}
}
ErrorMsg (token, "invalid constant");
return null;
}
private bool youveanerror;
private void ErrorMsg (Token token, string message)
{
youveanerror = true;
m_log.Info ("[XMREngine]: " + token.posn + " " + message);
}
private void XmrTestReset (string[] args, int indx)
{
bool flagAll = false;
int numScripts = 0;
XMRInstance[] instances;
if (args.Length <= indx) {
m_log.Error("[XMREngine]: must specify part of script name or -all for all scripts");
return;
}
/*
* Decode command line options.
*/
for (int i = indx; i < args.Length; i ++) {
if (args[i] == "-all") {
flagAll = true;
continue;
}
if (args[i] == "-help") {
m_log.Info ("[XMREngine]: xmr reset -all | <part-of-script-name>");
return;
}
if (args[i][0] == '-') {
m_log.Error ("[XMREngine]: unknown option " + args[i] + ", try 'xmr reset -help'");
return;
}
}
/*
* Scan instance list to find those that match selection criteria.
*/
if (!Monitor.TryEnter(m_InstancesDict, 100)) {
m_log.Error("[XMREngine]: deadlock m_LockedDict=" + m_LockedDict);
return;
}
try {
instances = new XMRInstance[m_InstancesDict.Count];
foreach (XMRInstance ins in m_InstancesDict.Values) {
if (flagAll || InstanceMatchesArgs (ins, args, indx)) {
instances[numScripts++] = ins;
}
}
} finally {
Monitor.Exit(m_InstancesDict);
}
/*
* Reset the instances as if someone clicked their "Reset" button.
*/
for (int i = 0; i < numScripts; i ++) {
XMRInstance inst = instances[i];
m_log.Info ("[XMREngine]: resetting " + inst.m_DescName);
inst.Reset();
}
}
private static int CompareInstancesByCPUTime(XMRInstance a, XMRInstance b)
{
if (a == null) {
return (b == null) ? 0 : 1;
}
if (b == null) {
return -1;
}
if (b.m_CPUTime < a.m_CPUTime) return -1;
if (b.m_CPUTime > a.m_CPUTime) return 1;
return 0;
}
private void LsQueue(TextWriter outFile, string name, XMRInstQueue queue, string[] args, int indx)
{
outFile.WriteLine("Queue " + name + ":");
lock (queue) {
for (XMRInstance inst = queue.PeekHead(); inst != null; inst = inst.m_NextInst) {
try {
/*
* Try to print instance name.
*/
if (InstanceMatchesArgs(inst, args, indx)) {
outFile.WriteLine(" " + inst.ItemID.ToString() + " " + inst.m_DescName);
}
} catch (Exception e) {
/*
* Sometimes there are instances in the queue that are disposed.
*/
outFile.WriteLine(" " + inst.ItemID.ToString() + " " + inst.m_DescName + ": " + e.Message);
}
}
}
}
private bool InstanceMatchesArgs(XMRInstance ins, string[] args, int indx)
{
bool hadSomethingToCompare = false;
for (int i = indx; i < args.Length; i ++)
{
if (args[i][0] != '-') {
hadSomethingToCompare = true;
if (ins.m_DescName.Contains(args[i])) return true;
if (ins.ItemID.ToString().Contains(args[i])) return true;
if (ins.AssetID.ToString().Contains(args[i])) return true;
}
}
return !hadSomethingToCompare;
}
}
/**
* @brief Make m_log.Info look like a text writer.
*/
public class LogInfoTextWriter : TextWriter {
private StringBuilder sb = new StringBuilder();
private ILog m_log;
public LogInfoTextWriter (ILog m_log)
{
this.m_log = m_log;
}
public override void Write (char c)
{
if (c == '\n') {
m_log.Info("[XMREngine]: " + sb.ToString());
sb.Remove(0, sb.Length);
} else {
sb.Append(c);
}
}
public override void Close () { }
public override Encoding Encoding {
get {
return Encoding.UTF8;
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,76 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.ScriptEngine.Shared;
using System;
using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine
{
public partial class XMRInstance
{
/**
* @brief If RegionCrossing trapping is enabled, any attempt to move the object
* outside its current region will cause the event to fire and the object
* will remain in its current region.
*/
public override void xmrTrapRegionCrossing (int en)
{ }
/**
* @brief Move object to new position and rotation asynchronously.
* Can move object across region boundary.
* @param pos = new position within current region (same coords as llGetPos())
* @param rot = new rotation within current region (same coords as llGetRot())
* @param options = not used
* @param evcode = not used
* @param evargs = arguments to pass to event handler
* @returns false: completed synchronously, no event will be queued
*/
public const double Sorpra_MIN_CROSS = 1.0 / 512.0; // ie, ~2mm
public const int Sorpra_TIMEOUT_MS = 30000; // ie, 30sec
public override bool xmrSetObjRegPosRotAsync (LSL_Vector pos, LSL_Rotation rot, int options, int evcode, LSL_List evargs)
{
// do the move
SceneObjectGroup sog = m_Part.ParentGroup;
sog.UpdateGroupRotationPR (pos, rot);
// it is always synchronous
return false;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,102 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using OpenSim.Framework.Monitoring;
using System;
using System.Collections.Generic;
using System.Threading;
namespace OpenSim.Region.ScriptEngine.XMREngine
{
/**
* @brief There are NUMSCRIPTHREADWKRS of these.
* Each sits in a loop checking the Start and Yield queues for
* a script to run and calls the script as a microthread.
*/
public class XMRScriptThread
{
public bool m_WakeUpThis = false;
public DateTime m_LastRanAt = DateTime.MinValue;
public int m_ScriptThreadTID = 0;
public long m_ScriptExecTime = 0;
private Thread thd;
private XMREngine engine;
public XMRInstance m_RunInstance = null;
public XMRScriptThread(XMREngine eng, int i)
{
engine = eng;
if(i < 0)
thd = XMREngine.StartMyThread(RunScriptThread, "xmrengine script", ThreadPriority.Normal);
else
thd = XMREngine.StartMyThread(RunScriptThread, "xmrengineExec" + i.ToString(), ThreadPriority.Normal);
engine.AddThread(thd, this);
m_ScriptThreadTID = thd.ManagedThreadId;
}
public void Terminate()
{
m_WakeUpThis = true;
if(!thd.Join(250))
thd.Abort();
engine.RemoveThread(thd);
thd = null;
}
/**
* @brief Wake up this XMRScriptThread instance.
*/
public void WakeUpScriptThread()
{
m_WakeUpThis = true;
}
/**
* @brief A script instance was just removed from the Start or Yield Queue.
* So run it for a little bit then stick in whatever queue it should go in.
*/
private void RunScriptThread()
{
engine.RunScriptThread(this);
}
public void RunInstance (XMRInstance inst)
{
m_LastRanAt = DateTime.UtcNow;
m_ScriptExecTime -= (long)(m_LastRanAt - DateTime.MinValue).TotalMilliseconds;
inst.m_IState = XMRInstState.RUNNING;
m_RunInstance = inst;
XMRInstState newIState = inst.RunOne();
m_RunInstance = null;
engine.HandleNewIState(inst, newIState);
m_ScriptExecTime += (long)(DateTime.UtcNow - DateTime.MinValue).TotalMilliseconds;
}
}
}

View File

@ -1,196 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
/***************************\
* Use standard C# code *
* - uses stack smashing *
\***************************/
namespace OpenSim.Region.ScriptEngine.XMREngine
{
public class ScriptUThread_Nul : IScriptUThread, IDisposable
{
private int active; // -1: hibernating
// 0: exited
// 1: running
private XMRInstance instance;
public ScriptUThread_Nul (XMRInstance instance)
{
this.instance = instance;
}
/**
* @brief Start script event handler from the beginning.
* Return when either the script event handler completes
* or the script calls Hiber().
* @returns null: script did not throw any exception so far
* else: script threw an exception
*/
public Exception StartEx ()
{
// We should only be called when no event handler running.
if (active != 0)
throw new Exception ("active=" + active);
// Start script event handler from very beginning.
active = 1;
Exception except = null;
instance.callMode = XMRInstance.CallMode_NORMAL;
try
{
instance.CallSEH (); // run script event handler
active = 0;
}
catch (StackHibernateException)
{
if (instance.callMode != XMRInstance.CallMode_SAVE)
{
throw new Exception ("callMode=" + instance.callMode);
}
active = -1; // it is hibernating, can be resumed
}
catch (Exception e)
{
active = 0;
except = e; // threw exception, save for Start()/Resume()
}
// Return whether or not script threw an exception.
return except;
}
/**
* @brief We now want to run some more script code from where it last hibernated
* until it either finishes the script event handler or until the script
* calls Hiber() again.
*/
public Exception ResumeEx ()
{
// We should only be called when script is hibernating.
if (active >= 0)
throw new Exception ("active=" + active);
// Resume script from captured stack.
instance.callMode = XMRInstance.CallMode_RESTORE;
instance.suspendOnCheckRunTemp = true;
Exception except = null;
try
{
instance.CallSEH (); // run script event handler
active = 0;
}
catch (StackHibernateException)
{
if (instance.callMode != XMRInstance.CallMode_SAVE)
{
throw new Exception ("callMode=" + instance.callMode);
}
active = -1;
}
catch (Exception e)
{
active = 0;
except = e; // threw exception, save for Start()/Resume()
}
// Return whether or not script threw an exception.
return except;
}
/**
* @brief Script is being closed out.
* Terminate thread asap.
*/
public void Dispose ()
{ }
/**
* @brief Determine if script is active.
* Returns: 0: nothing started or has returned
* Resume() must not be called
* Start() may be called
* Hiber() must not be called
* -1: thread has called Hiber()
* Resume() may be called
* Start() may be called
* Hiber() must not be called
* 1: thread is running
* Resume() must not be called
* Start() must not be called
* Hiber() may be called
*/
public int Active ()
{
return active;
}
/**
* @brief Called by the script event handler whenever it wants to hibernate.
*/
public void Hiber ()
{
if (instance.callMode != XMRInstance.CallMode_NORMAL) {
throw new Exception ("callMode=" + instance.callMode);
}
switch (active) {
// the stack has been restored as a result of calling ResumeEx()
// say the microthread is now active and resume processing
case -1: {
active = 1;
return;
}
// the script event handler wants to hibernate
// capture stack frames and unwind to Start() or Resume()
case 1: {
instance.callMode = XMRInstance.CallMode_SAVE;
instance.stackFrames = null;
throw new StackHibernateException ();
}
default: throw new Exception ("active=" + active);
}
}
/**
* @brief Number of remaining stack bytes.
*/
public int StackLeft ()
{
return 0x7FFFFFFF;
}
public class StackHibernateException : Exception, IXMRUncatchable { }
}
}

View File

@ -30,56 +30,67 @@ using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
namespace OpenSim.Region.ScriptEngine.XMREngine { namespace OpenSim.Region.ScriptEngine.Yengine
{
public class DelegateCommon { public class DelegateCommon
{
private string sig; // rettype(arg1type,arg2type,...), eg, "void(list,string,integer)" private string sig; // rettype(arg1type,arg2type,...), eg, "void(list,string,integer)"
private Type type; // resultant delegate type private Type type; // resultant delegate type
private static Dictionary<string, DelegateCommon> delegateCommons = new Dictionary<string, DelegateCommon> (); private static Dictionary<string, DelegateCommon> delegateCommons = new Dictionary<string, DelegateCommon>();
private static Dictionary<Type, DelegateCommon> delegateCommonsBySysType = new Dictionary<Type, DelegateCommon> (); private static Dictionary<Type, DelegateCommon> delegateCommonsBySysType = new Dictionary<Type, DelegateCommon>();
private static ModuleBuilder delegateModuleBuilder = null; private static ModuleBuilder delegateModuleBuilder = null;
public static Type[] constructorArgTypes = new Type[] { typeof (object), typeof (IntPtr) }; public static Type[] constructorArgTypes = new Type[] { typeof(object), typeof(IntPtr) };
private DelegateCommon () { } private DelegateCommon()
{
}
public static Type GetType (System.Type ret, System.Type[] args, string sig) public static Type GetType(System.Type ret, System.Type[] args, string sig)
{ {
DelegateCommon dc; DelegateCommon dc;
lock (delegateCommons) { lock(delegateCommons)
if (!delegateCommons.TryGetValue (sig, out dc)) { {
dc = new DelegateCommon (); if(!delegateCommons.TryGetValue(sig, out dc))
{
dc = new DelegateCommon();
dc.sig = sig; dc.sig = sig;
dc.type = CreateDelegateType (sig, ret, args); dc.type = CreateDelegateType(sig, ret, args);
delegateCommons.Add (sig, dc); delegateCommons.Add(sig, dc);
delegateCommonsBySysType.Add (dc.type, dc); delegateCommonsBySysType.Add(dc.type, dc);
} }
} }
return dc.type; return dc.type;
} }
public static Type TryGetType (string sig) public static Type TryGetType(string sig)
{ {
DelegateCommon dc; DelegateCommon dc;
lock (delegateCommons) { lock(delegateCommons)
if (!delegateCommons.TryGetValue (sig, out dc)) dc = null; {
if(!delegateCommons.TryGetValue(sig, out dc))
dc = null;
} }
return (dc == null) ? null : dc.type; return (dc == null) ? null : dc.type;
} }
public static string TryGetName (Type t) public static string TryGetName(Type t)
{ {
DelegateCommon dc; DelegateCommon dc;
lock (delegateCommons) { lock(delegateCommons)
if (!delegateCommonsBySysType.TryGetValue (t, out dc)) dc = null; {
if(!delegateCommonsBySysType.TryGetValue(t, out dc))
dc = null;
} }
return (dc == null) ? null : dc.sig; return (dc == null) ? null : dc.sig;
} }
// http://blog.bittercoder.com/PermaLink,guid,a770377a-b1ad-4590-9145-36381757a52b.aspx // http://blog.bittercoder.com/PermaLink,guid,a770377a-b1ad-4590-9145-36381757a52b.aspx
private static Type CreateDelegateType (string name, Type retType, Type[] argTypes) private static Type CreateDelegateType(string name, Type retType, Type[] argTypes)
{
if(delegateModuleBuilder == null)
{ {
if (delegateModuleBuilder == null) {
AssemblyName assembly = new AssemblyName(); AssemblyName assembly = new AssemblyName();
assembly.Name = "CustomDelegateAssembly"; assembly.Name = "CustomDelegateAssembly";
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.Run); AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.Run);
@ -88,7 +99,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
TypeBuilder typeBuilder = delegateModuleBuilder.DefineType(name, TypeBuilder typeBuilder = delegateModuleBuilder.DefineType(name,
TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class |
TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof (MulticastDelegate)); TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof(MulticastDelegate));
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor( ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public, MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public,

View File

@ -33,43 +33,44 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
public interface IEventHandlers { public interface IEventHandlers
void at_rot_target (int tnum, LSL_Rotation targetrot, LSL_Rotation ourrot); {
void at_target (int tnum, LSL_Vector targetpos, LSL_Vector ourpos); void at_rot_target(int tnum, LSL_Rotation targetrot, LSL_Rotation ourrot);
void attach (string id); void at_target(int tnum, LSL_Vector targetpos, LSL_Vector ourpos);
void changed (int change); void attach(string id);
void collision (int num_detected); void changed(int change);
void collision_end (int num_detected); void collision(int num_detected);
void collision_start (int num_detected); void collision_end(int num_detected);
void control (string id, int held, int change); void collision_start(int num_detected);
void dataserver (string queryid, string data); void control(string id, int held, int change);
void email (string time, string address, string subj, string message, int num_left); void dataserver(string queryid, string data);
void http_request (string request_id, string method, string body); void email(string time, string address, string subj, string message, int num_left);
void http_response (string request_id, int status, LSL_List metadata, string body); void http_request(string request_id, string method, string body);
void land_collision (LSL_Vector pos); void http_response(string request_id, int status, LSL_List metadata, string body);
void land_collision_end (LSL_Vector pos); void land_collision(LSL_Vector pos);
void land_collision_start (LSL_Vector pos); void land_collision_end(LSL_Vector pos);
void link_message (int sender_num, int num, string str, string id); void land_collision_start(LSL_Vector pos);
void listen (int channel, string name, string id, string message); void link_message(int sender_num, int num, string str, string id);
void money (string id, int amount); void listen(int channel, string name, string id, string message);
void moving_end (); void money(string id, int amount);
void moving_start (); void moving_end();
void no_sensor (); void moving_start();
void not_at_rot_target (); void no_sensor();
void not_at_target (); void not_at_rot_target();
void object_rez (string id); void not_at_target();
void on_rez (int start_param); void object_rez(string id);
void remote_data (int event_type, string channel, string message_id, string sender, int idata, string sdata); void on_rez(int start_param);
void run_time_permissions (int perm); void remote_data(int event_type, string channel, string message_id, string sender, int idata, string sdata);
void sensor (int num_detected); void run_time_permissions(int perm);
void state_entry (); void sensor(int num_detected);
void state_exit (); void state_entry();
void timer (); void state_exit();
void touch (int num_detected); void timer();
void touch_start (int num_detected); void touch(int num_detected);
void touch_end (int num_detected); void touch_start(int num_detected);
void touch_end(int num_detected);
void transaction_result(string id, int success, string data); void transaction_result(string id, int success, string data);
void path_update(int type, LSL_List data); void path_update(int type, LSL_List data);
void region_cross(LSL_Vector newpos, LSL_Vector oldpos); void region_cross(LSL_Vector newpos, LSL_Vector oldpos);

View File

@ -30,9 +30,11 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
namespace OpenSim.Region.ScriptEngine.XMREngine { namespace OpenSim.Region.ScriptEngine.Yengine
{
public class InternalFuncDict : VarDict { public class InternalFuncDict: VarDict
{
/** /**
* @brief build dictionary of internal functions from an interface. * @brief build dictionary of internal functions from an interface.
@ -41,50 +43,57 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
* false: catalog by simple name only, eg, state_entry * false: catalog by simple name only, eg, state_entry
* @returns dictionary of function definition tokens * @returns dictionary of function definition tokens
*/ */
public InternalFuncDict (Type iface, bool inclSig) public InternalFuncDict(Type iface, bool inclSig)
: base (false) : base(false)
{ {
/* /*
* Loop through list of all methods declared in the interface. * Loop through list of all methods declared in the interface.
*/ */
System.Reflection.MethodInfo[] ifaceMethods = iface.GetMethods (); System.Reflection.MethodInfo[] ifaceMethods = iface.GetMethods();
foreach (System.Reflection.MethodInfo ifaceMethod in ifaceMethods) { foreach(System.Reflection.MethodInfo ifaceMethod in ifaceMethods)
{
string key = ifaceMethod.Name; string key = ifaceMethod.Name;
/* /*
* Only do ones that begin with lower-case letters... * Only do ones that begin with lower-case letters...
* as any others can't be referenced by scripts * as any others can't be referenced by scripts
*/ */
if ((key[0] < 'a') || (key[0] > 'z')) continue; if((key[0] < 'a') || (key[0] > 'z'))
continue;
try { try
{
/* /*
* Create a corresponding TokenDeclVar struct. * Create a corresponding TokenDeclVar struct.
*/ */
System.Reflection.ParameterInfo[] parameters = ifaceMethod.GetParameters (); System.Reflection.ParameterInfo[] parameters = ifaceMethod.GetParameters();
TokenArgDecl argDecl = new TokenArgDecl (null); TokenArgDecl argDecl = new TokenArgDecl(null);
for (int i = 0; i < parameters.Length; i++) { for(int i = 0; i < parameters.Length; i++)
{
System.Reflection.ParameterInfo param = parameters[i]; System.Reflection.ParameterInfo param = parameters[i];
TokenType type = TokenType.FromSysType (null, param.ParameterType); TokenType type = TokenType.FromSysType(null, param.ParameterType);
TokenName name = new TokenName (null, param.Name); TokenName name = new TokenName(null, param.Name);
argDecl.AddArg (type, name); argDecl.AddArg(type, name);
} }
TokenDeclVar declFunc = new TokenDeclVar (null, null, null); TokenDeclVar declFunc = new TokenDeclVar(null, null, null);
declFunc.name = new TokenName (null, key); declFunc.name = new TokenName(null, key);
declFunc.retType = TokenType.FromSysType (null, ifaceMethod.ReturnType); declFunc.retType = TokenType.FromSysType(null, ifaceMethod.ReturnType);
declFunc.argDecl = argDecl; declFunc.argDecl = argDecl;
/* /*
* Add the TokenDeclVar struct to the dictionary. * Add the TokenDeclVar struct to the dictionary.
*/ */
this.AddEntry (declFunc); this.AddEntry(declFunc);
} catch (Exception except) { }
catch(Exception except)
{
string msg = except.ToString (); string msg = except.ToString();
int i = msg.IndexOf ("\n"); int i = msg.IndexOf("\n");
if (i > 0) msg = msg.Substring (0, i); if(i > 0)
Console.WriteLine ("InternalFuncDict*: {0}: {1}", key, msg); msg = msg.Substring(0, i);
Console.WriteLine("InternalFuncDict*: {0}: {1}", key, msg);
///??? IGNORE ANY THAT FAIL - LIKE UNRECOGNIZED TYPE ???/// ///??? IGNORE ANY THAT FAIL - LIKE UNRECOGNIZED TYPE ???///
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -31,12 +31,8 @@
using System; using System;
using System.IO; using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
public partial class XMRInstance public partial class XMRInstance
{ {
@ -45,155 +41,136 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @returns object code pointer or null if compile error * @returns object code pointer or null if compile error
* also can throw compile error exception * also can throw compile error exception
*/ */
public ScriptObjCode Compile () public ScriptObjCode Compile()
{ {
bool oldObjFile = false;
Stream objFileStream = null; Stream objFileStream = null;
StreamWriter asmFileWriter = null; StreamWriter asmFileWriter = null;
string envar = null;
string sourceHash = null; string sourceHash = null;
TextWriter saveSource = null; TextWriter saveSource = null;
string asmFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrasm");
string lslFileName = GetScriptFileName (m_ScriptObjCodeKey + ".lsl");
string objFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrobj"); string objFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrobj");
string tmpFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrtmp"); string tmpFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrtmp");
/* // If we already have an object file, don't bother compiling.
* If we already have an object file, don't bother compiling. if (!m_ForceRecomp && File.Exists(objFileName))
*/ {
if (!m_ForceRecomp && File.Exists (objFileName)) {
objFileStream = File.OpenRead (objFileName); objFileStream = File.OpenRead (objFileName);
oldObjFile = true;
} else {
/*
* If source file empty, try to read from asset server.
*/
if (EmptySource (m_SourceCode)) {
m_SourceCode = FetchSource (m_CameFrom);
} }
else
{
// If source file empty, try to read from asset server.
if (EmptySource (m_SourceCode))
m_SourceCode = FetchSource (m_CameFrom);
/* // Maybe write script source to a file for debugging.
* Maybe write script source to a file for debugging. if (m_Engine.m_ScriptDebugSaveSource)
*/ {
envar = Environment.GetEnvironmentVariable ("MMRScriptCompileSaveSource"); string lslFileName = GetScriptFileName (m_ScriptObjCodeKey + ".lsl");
if ((envar != null) && ((envar[0] & 1) != 0)) { // m_log.Debug ("[YEngine]: MMRScriptCompileSaveSource: saving to " + lslFileName);
m_log.Debug ("[XMREngine]: MMRScriptCompileSaveSource: saving to " + lslFileName);
saveSource = File.CreateText (lslFileName); saveSource = File.CreateText (lslFileName);
} }
/* // Parse source string into tokens.
* Parse source string into tokens.
*/
TokenBegin tokenBegin; TokenBegin tokenBegin;
try { try
{
tokenBegin = TokenBegin.Construct(m_CameFrom, saveSource, ErrorHandler, m_SourceCode, out sourceHash); tokenBegin = TokenBegin.Construct(m_CameFrom, saveSource, ErrorHandler, m_SourceCode, out sourceHash);
} finally {
if (saveSource != null) saveSource.Close ();
} }
if (tokenBegin == null) { finally
m_log.Debug ("[XMREngine]: parsing errors on " + m_ScriptObjCodeKey); {
if (saveSource != null)
saveSource.Close ();
}
if (tokenBegin == null)
{
m_log.Debug ("[YEngine]: parsing errors on " + m_ScriptObjCodeKey);
return null; return null;
} }
/* // Create object file one way or another.
* Create object file one way or another. try
*/ {
try {
objFileStream = File.Create (tmpFileName); objFileStream = File.Create (tmpFileName);
/* // Create abstract syntax tree from raw tokens.
* Create abstract syntax tree from raw tokens.
*/
TokenScript tokenScript = ScriptReduce.Reduce(tokenBegin); TokenScript tokenScript = ScriptReduce.Reduce(tokenBegin);
if (tokenScript == null) { if (tokenScript == null)
m_log.Warn ("[XMREngine]: reduction errors on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")"); {
PrintCompilerErrors (); m_log.Warn ("[YEngine]: reduction errors on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
PrintCompilerErrors();
objFileStream.Close();
return null; return null;
} }
/* // Compile abstract syntax tree to write object file.
* Compile abstract syntax tree to write object file.
*/
BinaryWriter objFileWriter = new BinaryWriter (objFileStream); BinaryWriter objFileWriter = new BinaryWriter (objFileStream);
bool ok = ScriptCodeGen.CodeGen(tokenScript, objFileWriter, sourceHash); bool ok = ScriptCodeGen.CodeGen(tokenScript, objFileWriter, sourceHash);
if (!ok) { if (!ok)
m_log.Warn ("[XMREngine]: compile error on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")"); {
m_log.Warn ("[YEngine]: compile error on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
PrintCompilerErrors (); PrintCompilerErrors ();
objFileStream.Close (); objFileWriter.Close ();
return null; return null;
} }
objFileStream.Close (); objFileWriter.Close ();
/* // File has been completely written.
* File has been completely written. // If there is an old one laying around, delete it now.
* If there is an old one laying around, delete it now. // Then re-open the new file for reading from the beginning.
* Then re-open the new file for reading from the beginning. if (File.Exists (objFileName))
*/
if (File.Exists (objFileName)) {
File.Replace (tmpFileName, objFileName, null); File.Replace (tmpFileName, objFileName, null);
} else { else
File.Move (tmpFileName, objFileName); File.Move (tmpFileName, objFileName);
}
objFileStream = File.OpenRead (objFileName); objFileStream = File.OpenRead (objFileName);
} finally { }
finally
/* {
* In case something went wrong writing temp file, delete it. // In case something went wrong writing temp file, delete it.
*/ try
try { {
File.Delete (tmpFileName); File.Delete (tmpFileName);
} catch { }
catch
{
} }
} }
/* // Since we just wrote the .xmrobj file, maybe save disassembly.
* Since we just wrote the .xmrobj file, maybe save disassembly. if (m_Engine.m_ScriptDebugSaveIL)
*/ {
envar = Environment.GetEnvironmentVariable ("MMRScriptCompileSaveILGen"); string asmFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrasm");
if ((envar != null) && ((envar[0] & 1) != 0)) { // m_log.Debug ("[YEngine]: MMRScriptCompileSaveILGen: saving to " + asmFileName);
m_log.Debug ("[XMREngine]: MMRScriptCompileSaveILGen: saving to " + asmFileName);
asmFileWriter = File.CreateText (asmFileName); asmFileWriter = File.CreateText (asmFileName);
} }
} }
/* // Read object file to create ScriptObjCode object.
* Read object file to create ScriptObjCode object. // Maybe also write disassembly to a file for debugging.
* Maybe also write disassembly to a file for debugging.
*/
BinaryReader objFileReader = new BinaryReader (objFileStream); BinaryReader objFileReader = new BinaryReader (objFileStream);
ScriptObjCode scriptObjCode = null; ScriptObjCode scriptObjCode = null;
try { try
{
scriptObjCode = new ScriptObjCode (objFileReader, asmFileWriter, null); scriptObjCode = new ScriptObjCode (objFileReader, asmFileWriter, null);
if (scriptObjCode != null) {
scriptObjCode.fileDateUtc = File.GetLastWriteTimeUtc (objFileName);
} }
} finally { finally
{
objFileReader.Close (); objFileReader.Close ();
if (asmFileWriter != null) { if (asmFileWriter != null)
{
asmFileWriter.Flush (); asmFileWriter.Flush ();
asmFileWriter.Close (); asmFileWriter.Close ();
} }
} }
/*
* Maybe an old object file has reached its expiration date.
*/
if (oldObjFile && (scriptObjCode != null) && scriptObjCode.IsExpired ()) {
m_log.Debug ("[XMREngine]: expiration reached on " + m_ScriptObjCodeKey + ", reloading");
m_ForceRecomp = true;
scriptObjCode = Compile ();
}
return scriptObjCode; return scriptObjCode;
} }
private void PrintCompilerErrors () private void PrintCompilerErrors ()
{ {
m_log.Info ("[XMREngine]: - " + m_Part.GetWorldPosition () + " " + m_DescName); m_log.Info ("[YEngine]: - " + m_Part.GetWorldPosition () + " " + m_DescName);
foreach (string error in m_CompilerErrors) { foreach (string error in m_CompilerErrors) {
m_log.Info ("[XMREngine]: - " + error); m_log.Info ("[YEngine]: - " + error);
} }
} }
@ -204,11 +181,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{ {
int len = source.Length; int len = source.Length;
bool skipeol = false; bool skipeol = false;
for (int i = 0; i < len; i ++) { for (int i = 0; i < len; i ++)
{
char c = source[i]; char c = source[i];
skipeol &= c != '\n'; skipeol &= c != '\n';
skipeol |= (c == '/') && (i + 1 < len) && (source[i+1] == '/'); skipeol |= (c == '/') && (i + 1 < len) && (source[i+1] == '/');
if ((c > ' ') && !skipeol) return false; if ((c > ' ') && !skipeol)
return false;
} }
return true; return true;
} }

View File

@ -0,0 +1,287 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.Yengine
{
public class ScriptConst
{
public static Dictionary<string, ScriptConst> scriptConstants = Init();
/**
* @brief look up the value of a given built-in constant.
* @param name = name of constant
* @returns null: no constant by that name defined
* else: pointer to ScriptConst struct
*/
public static ScriptConst Lookup(string name)
{
ScriptConst sc;
if(!scriptConstants.TryGetValue(name, out sc))
sc = null;
return sc;
}
private static Dictionary<string, ScriptConst> Init()
{
Dictionary<string, ScriptConst> sc = new Dictionary<string, ScriptConst>();
/*
* For every event code, define XMREVENTCODE_<eventname> and XMREVENTMASKn_<eventname> symbols.
*/
for(int i = 0; i < 64; i++)
{
try
{
string s = ((ScriptEventCode)i).ToString();
if((s.Length > 0) && (s[0] >= 'a') && (s[0] <= 'z'))
{
new ScriptConst(sc,
"XMREVENTCODE_" + s,
new CompValuInteger(new TokenTypeInt(null), i));
int n = i / 32 + 1;
int m = 1 << (i % 32);
new ScriptConst(sc,
"XMREVENTMASK" + n + "_" + s,
new CompValuInteger(new TokenTypeInt(null), m));
}
}
catch { }
}
/*
* Also get all the constants from XMRInstAbstract and ScriptBaseClass etc as well.
*/
for(Type t = typeof(XMRInstAbstract); t != typeof(object); t = t.BaseType)
{
AddInterfaceConstants(sc, t.GetFields());
}
return sc;
}
/**
* @brief Add all constants defined by the given interface.
*/
// this one accepts only upper-case named fields
public static void AddInterfaceConstants(Dictionary<string, ScriptConst> sc, FieldInfo[] allFields)
{
List<FieldInfo> ucfs = new List<FieldInfo>(allFields.Length);
foreach(FieldInfo f in allFields)
{
string fieldName = f.Name;
int i;
for(i = fieldName.Length; --i >= 0;)
{
if("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_".IndexOf(fieldName[i]) < 0)
break;
}
if(i < 0)
ucfs.Add(f);
}
AddInterfaceConstants(sc, ucfs.GetEnumerator());
}
// this one accepts all fields given to it
public static void AddInterfaceConstants(Dictionary<string, ScriptConst> sc, IEnumerator<FieldInfo> fields)
{
if(sc == null)
sc = scriptConstants;
for(fields.Reset(); fields.MoveNext();)
{
FieldInfo constField = fields.Current;
Type fieldType = constField.FieldType;
CompValu cv;
/*
* The location of a simple number is the number itself.
* Access to the value gets compiled as an ldc instruction.
*/
if(fieldType == typeof(double))
{
cv = new CompValuFloat(new TokenTypeFloat(null),
(double)(double)constField.GetValue(null));
}
else if(fieldType == typeof(int))
{
cv = new CompValuInteger(new TokenTypeInt(null),
(int)constField.GetValue(null));
}
else if(fieldType == typeof(LSL_Integer))
{
cv = new CompValuInteger(new TokenTypeInt(null),
((LSL_Integer)constField.GetValue(null)).value);
}
/*
* The location of a string is the string itself.
* Access to the value gets compiled as an ldstr instruction.
*/
else if(fieldType == typeof(string))
{
cv = new CompValuString(new TokenTypeStr(null),
(string)constField.GetValue(null));
}
else if(fieldType == typeof(LSL_String))
{
cv = new CompValuString(new TokenTypeStr(null),
(string)(LSL_String)constField.GetValue(null));
}
/*
* The location of everything else (objects) is the static field in the interface definition.
* Access to the value gets compiled as an ldsfld instruction.
*/
else
{
cv = new CompValuSField(TokenType.FromSysType(null, fieldType), constField);
}
/*
* Add to dictionary.
*/
new ScriptConst(sc, constField.Name, cv);
}
}
/**
* @brief Add arbitrary constant available to script compilation.
* CAUTION: These values get compiled-in to a script and must not
* change over time as previously compiled scripts will
* still have the old values.
*/
public static ScriptConst AddConstant(string name, object value)
{
CompValu cv = null;
if(value is char)
{
cv = new CompValuChar(new TokenTypeChar(null), (char)value);
}
if(value is double)
{
cv = new CompValuFloat(new TokenTypeFloat(null), (double)(double)value);
}
if(value is float)
{
cv = new CompValuFloat(new TokenTypeFloat(null), (double)(float)value);
}
if(value is int)
{
cv = new CompValuInteger(new TokenTypeInt(null), (int)value);
}
if(value is string)
{
cv = new CompValuString(new TokenTypeStr(null), (string)value);
}
if(value is LSL_Float)
{
cv = new CompValuFloat(new TokenTypeFloat(null), (double)((LSL_Float)value).value);
}
if(value is LSL_Integer)
{
cv = new CompValuInteger(new TokenTypeInt(null), ((LSL_Integer)value).value);
}
if(value is LSL_Rotation)
{
LSL_Rotation r = (LSL_Rotation)value;
CompValu x = new CompValuFloat(new TokenTypeFloat(null), r.x);
CompValu y = new CompValuFloat(new TokenTypeFloat(null), r.y);
CompValu z = new CompValuFloat(new TokenTypeFloat(null), r.z);
CompValu s = new CompValuFloat(new TokenTypeFloat(null), r.s);
cv = new CompValuRot(new TokenTypeRot(null), x, y, z, s);
}
if(value is LSL_String)
{
cv = new CompValuString(new TokenTypeStr(null), (string)(LSL_String)value);
}
if(value is LSL_Vector)
{
LSL_Vector v = (LSL_Vector)value;
CompValu x = new CompValuFloat(new TokenTypeFloat(null), v.x);
CompValu y = new CompValuFloat(new TokenTypeFloat(null), v.y);
CompValu z = new CompValuFloat(new TokenTypeFloat(null), v.z);
cv = new CompValuVec(new TokenTypeVec(null), x, y, z);
}
if(value is OpenMetaverse.Quaternion)
{
OpenMetaverse.Quaternion r = (OpenMetaverse.Quaternion)value;
CompValu x = new CompValuFloat(new TokenTypeFloat(null), r.X);
CompValu y = new CompValuFloat(new TokenTypeFloat(null), r.Y);
CompValu z = new CompValuFloat(new TokenTypeFloat(null), r.Z);
CompValu s = new CompValuFloat(new TokenTypeFloat(null), r.W);
cv = new CompValuRot(new TokenTypeRot(null), x, y, z, s);
}
if(value is OpenMetaverse.UUID)
{
cv = new CompValuString(new TokenTypeKey(null), value.ToString());
}
if(value is OpenMetaverse.Vector3)
{
OpenMetaverse.Vector3 v = (OpenMetaverse.Vector3)value;
CompValu x = new CompValuFloat(new TokenTypeFloat(null), v.X);
CompValu y = new CompValuFloat(new TokenTypeFloat(null), v.Y);
CompValu z = new CompValuFloat(new TokenTypeFloat(null), v.Z);
cv = new CompValuVec(new TokenTypeVec(null), x, y, z);
}
if(cv == null)
throw new Exception("bad type " + value.GetType().Name);
return new ScriptConst(scriptConstants, name, cv);
}
/*
* Instance variables
*/
public string name;
public CompValu rVal;
private ScriptConst(Dictionary<string, ScriptConst> lc, string name, CompValu rVal)
{
lc.Add(name, this);
this.name = name;
this.rVal = rVal;
}
}
}

View File

@ -25,7 +25,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
namespace OpenSim.Region.ScriptEngine.XMREngine { namespace OpenSim.Region.ScriptEngine.Yengine
{
/** /**
* @brief List of event codes that can be passed to StartEventHandler(). * @brief List of event codes that can be passed to StartEventHandler().
@ -38,7 +39,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
* in range 0..63 that begin with a lower-case letter for scripts to * in range 0..63 that begin with a lower-case letter for scripts to
* reference. * reference.
*/ */
public enum ScriptEventCode : int { public enum ScriptEventCode: int
{
// used by XMRInstance to indicate no event being processed // used by XMRInstance to indicate no event being processed
None = -1, None = -1,

View File

@ -0,0 +1,727 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
/**
* @brief Generate code for the backend API calls.
*/
namespace OpenSim.Region.ScriptEngine.Yengine
{
public abstract class TokenDeclInline: TokenDeclVar
{
public static VarDict inlineFunctions = CreateDictionary();
public abstract void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args);
private static string[] noCheckRuns;
private static string[] keyReturns;
protected bool isTaggedCallsCheckRun;
/**
* @brief Create a dictionary of inline backend API functions.
*/
private static VarDict CreateDictionary()
{
/*
* For those listed in noCheckRun, we just generate the call (simple computations).
* For all others, we generate the call then a call to CheckRun().
*/
noCheckRuns = new string[] {
"llBase64ToString",
"llCSV2List",
"llDeleteSubList",
"llDeleteSubString",
"llDumpList2String",
"llEscapeURL",
"llEuler2Rot",
"llGetListEntryType",
"llGetListLength",
"llGetSubString",
"llGetUnixTime",
"llInsertString",
"llList2CSV",
"llList2Float",
"llList2Integer",
"llList2Key",
"llList2List",
"llList2ListStrided",
"llList2Rot",
"llList2String",
"llList2Vector",
"llListFindList",
"llListInsertList",
"llListRandomize",
"llListReplaceList",
"llListSort",
"llListStatistics",
"llMD5String",
"llParseString2List",
"llParseStringKeepNulls",
"llRot2Euler",
"llStringLength",
"llStringToBase64",
"llStringTrim",
"llSubStringIndex",
"llUnescapeURL"
};
/*
* These functions really return a 'key' even though we see them as
* returning 'string' because OpenSim has key and string as same type.
*/
keyReturns = new string[] {
"llAvatarOnLinkSitTarget",
"llAvatarOnSitTarget",
"llDetectedKey",
"llDetectedOwner",
"llGenerateKey",
"llGetCreator",
"llGetInventoryCreator",
"llGetInventoryKey",
"llGetKey",
"llGetLandOwnerAt",
"llGetLinkKey",
"llGetNotecardLine",
"llGetNumberOfNotecardLines",
"llGetOwner",
"llGetOwnerKey",
"llGetPermissionsKey",
"llHTTPRequest",
"llList2Key",
"llRequestAgentData",
"llRequestDisplayName",
"llRequestInventoryData",
"llRequestSecureURL",
"llRequestSimulatorData",
"llRequestURL",
"llRequestUsername",
"llSendRemoteData",
"llTransferLindenDollars"
};
VarDict ifd = new VarDict(false);
Type[] oneDoub = new Type[] { typeof(double) };
Type[] twoDoubs = new Type[] { typeof(double), typeof(double) };
/*
* Mono generates an FPU instruction for many math calls.
*/
new TokenDeclInline_LLAbs(ifd);
new TokenDeclInline_Math(ifd, "llAcos(float)", "Acos", oneDoub);
new TokenDeclInline_Math(ifd, "llAsin(float)", "Asin", oneDoub);
new TokenDeclInline_Math(ifd, "llAtan2(float,float)", "Atan2", twoDoubs);
new TokenDeclInline_Math(ifd, "llCos(float)", "Cos", oneDoub);
new TokenDeclInline_Math(ifd, "llFabs(float)", "Abs", oneDoub);
new TokenDeclInline_Math(ifd, "llLog(float)", "Log", oneDoub);
new TokenDeclInline_Math(ifd, "llLog10(float)", "Log10", oneDoub);
new TokenDeclInline_Math(ifd, "llPow(float,float)", "Pow", twoDoubs);
new TokenDeclInline_LLRound(ifd);
new TokenDeclInline_Math(ifd, "llSin(float)", "Sin", oneDoub);
new TokenDeclInline_Math(ifd, "llSqrt(float)", "Sqrt", oneDoub);
new TokenDeclInline_Math(ifd, "llTan(float)", "Tan", oneDoub);
/*
* Something weird about the code generation for these calls, so they all have their own handwritten code generators.
*/
new TokenDeclInline_GetFreeMemory(ifd);
new TokenDeclInline_GetUsedMemory(ifd);
/*
* These are all the xmr...() calls directly in XMRInstAbstract.
* Includes the calls from ScriptBaseClass that has all the stubs
* which convert XMRInstAbstract to the various <NAME>_Api contexts.
*/
MethodInfo[] absmeths = typeof(XMRInstAbstract).GetMethods();
AddInterfaceMethods(ifd, absmeths, null);
return ifd;
}
/**
* @brief Add API functions from the given interface to list of built-in functions.
* Only functions beginning with a lower-case letter are entered, all others ignored.
* @param ifd = internal function dictionary to add them to
* @param ifaceMethods = list of API functions
* @param acf = which field in XMRInstanceSuperType holds method's 'this' pointer
*/
// this one accepts only names beginning with a lower-case letter
public static void AddInterfaceMethods(VarDict ifd, MethodInfo[] ifaceMethods, FieldInfo acf)
{
List<MethodInfo> lcms = new List<MethodInfo>(ifaceMethods.Length);
foreach(MethodInfo meth in ifaceMethods)
{
string name = meth.Name;
if((name[0] >= 'a') && (name[0] <= 'z'))
{
lcms.Add(meth);
}
}
AddInterfaceMethods(ifd, lcms.GetEnumerator(), acf);
}
// this one accepts all methods given to it
public static void AddInterfaceMethods(VarDict ifd, IEnumerator<MethodInfo> ifaceMethods, FieldInfo acf)
{
if(ifd == null)
ifd = inlineFunctions;
for(ifaceMethods.Reset(); ifaceMethods.MoveNext();)
{
MethodInfo ifaceMethod = ifaceMethods.Current;
string key = ifaceMethod.Name;
try
{
/*
* See if we will generate a call to CheckRun() right
* after we generate a call to the function.
* If function begins with xmr, assume we will not call CheckRun()
* Otherwise, assume we will call CheckRun()
*/
bool dcr = !key.StartsWith("xmr");
foreach(string ncr in noCheckRuns)
{
if(ncr == key)
{
dcr = false;
break;
}
}
/*
* Add function to dictionary.
*/
new TokenDeclInline_BEApi(ifd, dcr, ifaceMethod, acf);
}
catch
{
///??? IGNORE ANY THAT FAIL - LIKE UNRECOGNIZED TYPE ???///
///??? and OVERLOADED NAMES ???///
}
}
}
/**
* @brief Add an inline function definition to the dictionary.
* @param ifd = dictionary to add inline definition to
* @param doCheckRun = true iff the generated code or the function itself can possibly call CheckRun()
* @param nameArgSig = inline function signature string, in form <name>(<arglsltypes>,...)
* @param retType = return type, use TokenTypeVoid if no return value
*/
protected TokenDeclInline(VarDict ifd,
bool doCheckRun,
string nameArgSig,
TokenType retType)
: base(null, null, null)
{
this.retType = retType;
this.triviality = doCheckRun ? Triviality.complex : Triviality.trivial;
int j = nameArgSig.IndexOf('(');
this.name = new TokenName(null, nameArgSig.Substring(0, j++));
this.argDecl = new TokenArgDecl(null);
if(nameArgSig[j] != ')')
{
int i;
TokenName name;
TokenType type;
for(i = j; nameArgSig[i] != ')'; i++)
{
if(nameArgSig[i] == ',')
{
type = TokenType.FromLSLType(null, nameArgSig.Substring(j, i - j));
name = new TokenName(null, "arg" + this.argDecl.varDict.Count);
this.argDecl.AddArg(type, name);
j = i + 1;
}
}
type = TokenType.FromLSLType(null, nameArgSig.Substring(j, i - j));
name = new TokenName(null, "arg" + this.argDecl.varDict.Count);
this.argDecl.AddArg(type, name);
}
this.location = new CompValuInline(this);
if(ifd == null)
ifd = inlineFunctions;
ifd.AddEntry(this);
}
protected TokenDeclInline(VarDict ifd,
bool doCheckRun,
MethodInfo methInfo)
: base(null, null, null)
{
TokenType retType = TokenType.FromSysType(null, methInfo.ReturnType);
this.isTaggedCallsCheckRun = IsTaggedCallsCheckRun(methInfo);
this.name = new TokenName(null, methInfo.Name);
this.retType = GetRetType(methInfo, retType);
this.argDecl = GetArgDecl(methInfo.GetParameters());
this.triviality = (doCheckRun || this.isTaggedCallsCheckRun) ? Triviality.complex : Triviality.trivial;
this.location = new CompValuInline(this);
if(ifd == null)
ifd = inlineFunctions;
ifd.AddEntry(this);
}
private static TokenArgDecl GetArgDecl(ParameterInfo[] parameters)
{
TokenArgDecl argDecl = new TokenArgDecl(null);
foreach(ParameterInfo pi in parameters)
{
TokenType type = TokenType.FromSysType(null, pi.ParameterType);
TokenName name = new TokenName(null, pi.Name);
argDecl.AddArg(type, name);
}
return argDecl;
}
/**
* @brief The above code assumes all methods beginning with 'xmr' are trivial, ie,
* they do not call CheckRun() and also we do not generate a CheckRun()
* call after they return. So if an 'xmr' method does call CheckRun(), it
* must be tagged with attribute 'xmrMethodCallsCheckRunAttribute' so we know
* the method is not trivial. But in neither case do we emit our own call
* to CheckRun(), the 'xmr' method must do its own. We do however set up a
* call label before the call to the non-trivial 'xmr' method so when we are
* restoring the call stack, the restore will call directly in to the 'xmr'
* method without re-executing any code before the call to the 'xmr' method.
*/
private static bool IsTaggedCallsCheckRun(MethodInfo methInfo)
{
return (methInfo != null) &&
Attribute.IsDefined(methInfo, typeof(xmrMethodCallsCheckRunAttribute));
}
/**
* @brief The dumbass OpenSim has key and string as the same type so non-ll
* methods must be tagged with xmrMethodReturnsKeyAttribute if we
* are to think they return a key type, otherwise we will think they
* return string.
*/
private static TokenType GetRetType(MethodInfo methInfo, TokenType retType)
{
if((methInfo != null) && (retType != null) && (retType is TokenTypeStr))
{
if(Attribute.IsDefined(methInfo, typeof(xmrMethodReturnsKeyAttribute)))
{
return ChangeToKeyType(retType);
}
string mn = methInfo.Name;
foreach(string kr in keyReturns)
{
if(kr == mn)
return ChangeToKeyType(retType);
}
}
return retType;
}
private static TokenType ChangeToKeyType(TokenType retType)
{
if(retType is TokenTypeLSLString)
{
retType = new TokenTypeLSLKey(null);
}
else
{
retType = new TokenTypeKey(null);
}
return retType;
}
public virtual MethodInfo GetMethodInfo()
{
return null;
}
/**
* @brief Print out a list of all the built-in functions and constants.
*/
public delegate void WriteLine(string str);
public static void PrintBuiltins(bool inclNoisyTag, WriteLine writeLine)
{
writeLine("\nBuilt-in functions:\n");
SortedDictionary<string, TokenDeclInline> bifs = new SortedDictionary<string, TokenDeclInline>();
foreach(TokenDeclVar bif in TokenDeclInline.inlineFunctions)
{
bifs.Add(bif.fullName, (TokenDeclInline)bif);
}
foreach(TokenDeclInline bif in bifs.Values)
{
char noisy = (!inclNoisyTag || !IsTaggedNoisy(bif.GetMethodInfo())) ? ' ' : (bif.retType is TokenTypeVoid) ? 'N' : 'R';
writeLine(noisy + " " + bif.retType.ToString().PadLeft(8) + " " + bif.fullName);
}
if(inclNoisyTag)
{
writeLine("\nN - stub that writes name and arguments to stdout");
writeLine("R - stub that writes name and arguments to stdout then reads return value from stdin");
writeLine(" format is: function_name : return_value");
writeLine(" example: llKey2Name:\"Kunta Kinte\"");
}
writeLine("\nBuilt-in constants:\n");
SortedDictionary<string, ScriptConst> scs = new SortedDictionary<string, ScriptConst>();
int widest = 0;
foreach(ScriptConst sc in ScriptConst.scriptConstants.Values)
{
if(widest < sc.name.Length)
widest = sc.name.Length;
scs.Add(sc.name, sc);
}
foreach(ScriptConst sc in scs.Values)
{
writeLine(" " + sc.rVal.type.ToString().PadLeft(8) + " " + sc.name.PadRight(widest) + " = " + BuiltInConstVal(sc.rVal));
}
}
public static bool IsTaggedNoisy(MethodInfo methInfo)
{
return (methInfo != null) && Attribute.IsDefined(methInfo, typeof(xmrMethodIsNoisyAttribute));
}
public static string BuiltInConstVal(CompValu rVal)
{
if(rVal is CompValuInteger)
{
int x = ((CompValuInteger)rVal).x;
return "0x" + x.ToString("X8") + " = " + x.ToString().PadLeft(11);
}
if(rVal is CompValuFloat)
return ((CompValuFloat)rVal).x.ToString();
if(rVal is CompValuString)
{
StringBuilder sb = new StringBuilder();
PrintParam(sb, ((CompValuString)rVal).x);
return sb.ToString();
}
if(rVal is CompValuSField)
{
FieldInfo fi = ((CompValuSField)rVal).field;
StringBuilder sb = new StringBuilder();
PrintParam(sb, fi.GetValue(null));
return sb.ToString();
}
return rVal.ToString(); // just prints the type
}
public static void PrintParam(StringBuilder sb, object p)
{
if(p == null)
{
sb.Append("null");
}
else if(p is LSL_List)
{
sb.Append('[');
object[] d = ((LSL_List)p).Data;
for(int i = 0; i < d.Length; i++)
{
if(i > 0)
sb.Append(',');
PrintParam(sb, d[i]);
}
sb.Append(']');
}
else if(p is LSL_Rotation)
{
LSL_Rotation r = (LSL_Rotation)p;
sb.Append('<');
sb.Append(r.x);
sb.Append(',');
sb.Append(r.y);
sb.Append(',');
sb.Append(r.z);
sb.Append(',');
sb.Append(r.s);
sb.Append('>');
}
else if(p is LSL_String)
{
PrintParamString(sb, (string)(LSL_String)p);
}
else if(p is LSL_Vector)
{
LSL_Vector v = (LSL_Vector)p;
sb.Append('<');
sb.Append(v.x);
sb.Append(',');
sb.Append(v.y);
sb.Append(',');
sb.Append(v.z);
sb.Append('>');
}
else if(p is string)
{
PrintParamString(sb, (string)p);
}
else
{
sb.Append(p.ToString());
}
}
public static void PrintParamString(StringBuilder sb, string p)
{
sb.Append('"');
foreach(char c in p)
{
if(c == '\b')
{
sb.Append("\\b");
continue;
}
if(c == '\n')
{
sb.Append("\\n");
continue;
}
if(c == '\r')
{
sb.Append("\\r");
continue;
}
if(c == '\t')
{
sb.Append("\\t");
continue;
}
if(c == '"')
{
sb.Append("\\\"");
continue;
}
if(c == '\\')
{
sb.Append("\\\\");
continue;
}
sb.Append(c);
}
sb.Append('"');
}
}
/**
* @brief Code generators...
* @param scg = script we are generating code for
* @param result = type/location for result (type matches function definition)
* @param args = type/location of arguments (types match function definition)
*/
public class TokenDeclInline_LLAbs: TokenDeclInline
{
public TokenDeclInline_LLAbs(VarDict ifd)
: base(ifd, false, "llAbs(integer)", new TokenTypeInt(null)) { }
public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
{
ScriptMyLabel itsPosLabel = scg.ilGen.DefineLabel("llAbstemp");
args[0].PushVal(scg, errorAt);
scg.ilGen.Emit(errorAt, OpCodes.Dup);
scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4_0);
scg.ilGen.Emit(errorAt, OpCodes.Bge_S, itsPosLabel);
scg.ilGen.Emit(errorAt, OpCodes.Neg);
scg.ilGen.MarkLabel(itsPosLabel);
result.Pop(scg, errorAt, retType);
}
}
public class TokenDeclInline_Math: TokenDeclInline
{
private MethodInfo methInfo;
public TokenDeclInline_Math(VarDict ifd, string sig, string name, Type[] args)
: base(ifd, false, sig, new TokenTypeFloat(null))
{
methInfo = ScriptCodeGen.GetStaticMethod(typeof(System.Math), name, args);
}
public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
{
for(int i = 0; i < args.Length; i++)
{
args[i].PushVal(scg, errorAt, argDecl.types[i]);
}
scg.ilGen.Emit(errorAt, OpCodes.Call, methInfo);
result.Pop(scg, errorAt, retType);
}
}
public class TokenDeclInline_LLRound: TokenDeclInline
{
private static MethodInfo roundMethInfo = ScriptCodeGen.GetStaticMethod(typeof(System.Math), "Round",
new Type[] { typeof(double), typeof(MidpointRounding) });
public TokenDeclInline_LLRound(VarDict ifd)
: base(ifd, false, "llRound(float)", new TokenTypeInt(null)) { }
public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
{
args[0].PushVal(scg, errorAt, new TokenTypeFloat(null));
scg.ilGen.Emit(errorAt, OpCodes.Ldc_I4, (int)System.MidpointRounding.AwayFromZero);
scg.ilGen.Emit(errorAt, OpCodes.Call, roundMethInfo);
result.Pop(scg, errorAt, new TokenTypeFloat(null));
}
}
public class TokenDeclInline_GetFreeMemory: TokenDeclInline
{
private static readonly MethodInfo getFreeMemMethInfo = typeof(XMRInstAbstract).GetMethod("xmrHeapLeft", new Type[] { });
public TokenDeclInline_GetFreeMemory(VarDict ifd)
: base(ifd, false, "llGetFreeMemory()", new TokenTypeInt(null)) { }
// appears as llGetFreeMemory() in script source code
// but actually calls xmrHeapLeft()
public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
{
scg.PushXMRInst();
scg.ilGen.Emit(errorAt, OpCodes.Call, getFreeMemMethInfo);
result.Pop(scg, errorAt, new TokenTypeInt(null));
}
}
public class TokenDeclInline_GetUsedMemory: TokenDeclInline
{
private static readonly MethodInfo getUsedMemMethInfo = typeof(XMRInstAbstract).GetMethod("xmrHeapUsed", new Type[] { });
public TokenDeclInline_GetUsedMemory(VarDict ifd)
: base(ifd, false, "llGetUsedMemory()", new TokenTypeInt(null)) { }
// appears as llGetUsedMemory() in script source code
// but actually calls xmrHeapUsed()
public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
{
scg.PushXMRInst();
scg.ilGen.Emit(errorAt, OpCodes.Call, getUsedMemMethInfo);
result.Pop(scg, errorAt, new TokenTypeInt(null));
}
}
/**
* @brief Generate code for the usual ll...() functions.
*/
public class TokenDeclInline_BEApi: TokenDeclInline
{
// private static readonly MethodInfo fixLLParcelMediaQuery = ScriptCodeGen.GetStaticMethod
// (typeof (XMRInstAbstract), "FixLLParcelMediaQuery", new Type[] { typeof (LSL_List) });
// private static readonly MethodInfo fixLLParcelMediaCommandList = ScriptCodeGen.GetStaticMethod
// (typeof (XMRInstAbstract), "FixLLParcelMediaCommandList", new Type[] { typeof (LSL_List) });
public bool doCheckRun;
private FieldInfo apiContextField;
private MethodInfo methInfo;
/**
* @brief Constructor
* @param ifd = dictionary to add the function to
* @param dcr = append a call to CheckRun()
* @param methInfo = ll...() method to be called
*/
public TokenDeclInline_BEApi(VarDict ifd, bool dcr, MethodInfo methInfo, FieldInfo acf)
: base(ifd, dcr, methInfo)
{
this.methInfo = methInfo;
doCheckRun = dcr;
apiContextField = acf;
}
public override MethodInfo GetMethodInfo()
{
return methInfo;
}
/**
* @brief Generate call to backend API function (eg llSay()) maybe followed by a call to CheckRun().
* @param scg = script being compiled
* @param result = where to place result (might be void)
* @param args = script-visible arguments to pass to API function
*/
public override void CodeGen(ScriptCodeGen scg, Token errorAt, CompValuTemp result, CompValu[] args)
{
if(isTaggedCallsCheckRun)
{ // see if 'xmr' method that calls CheckRun() internally
new ScriptCodeGen.CallLabel(scg, errorAt); // if so, put a call label immediately before it
// .. so restoring the frame will jump immediately to the
// .. call without re-executing any code before this
}
if(!methInfo.IsStatic)
{
scg.PushXMRInst(); // XMRInstanceSuperType pointer
if(apiContextField != null) // 'this' pointer for API function
scg.ilGen.Emit(errorAt, OpCodes.Ldfld, apiContextField);
}
for(int i = 0; i < args.Length; i++) // push arguments, boxing/unboxing as needed
args[i].PushVal(scg, errorAt, argDecl.types[i]);
// this should not be needed
// if (methInfo.Name == "llParcelMediaQuery") {
// scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaQuery);
// }
// this should not be needed
// if (methInfo.Name == "llParcelMediaCommandList") {
// scg.ilGen.Emit (errorAt, OpCodes.Call, fixLLParcelMediaCommandList);
// }
if(methInfo.IsVirtual) // call API function
scg.ilGen.Emit(errorAt, OpCodes.Callvirt, methInfo);
else
scg.ilGen.Emit(errorAt, OpCodes.Call, methInfo);
result.Pop(scg, errorAt, retType); // pop result, boxing/unboxing as needed
if(isTaggedCallsCheckRun)
scg.openCallLabel = null;
if(doCheckRun)
scg.EmitCallCheckRun(errorAt, false); // maybe call CheckRun()
}
}
}

View File

@ -29,37 +29,41 @@ using System;
using System.Reflection; using System.Reflection;
using System.Reflection.Emit; using System.Reflection.Emit;
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
public interface ScriptMyILGen public interface ScriptMyILGen
{ {
string methName { get; } string methName
ScriptMyLocal DeclareLocal (Type type, string name); {
ScriptMyLabel DefineLabel (string name); get;
void BeginExceptionBlock (); }
void BeginCatchBlock (Type excType); ScriptMyLocal DeclareLocal(Type type, string name);
void BeginFinallyBlock (); ScriptMyLabel DefineLabel(string name);
void EndExceptionBlock (); void BeginExceptionBlock();
void Emit (Token errorAt, OpCode opcode); void BeginCatchBlock(Type excType);
void Emit (Token errorAt, OpCode opcode, FieldInfo field); void BeginFinallyBlock();
void Emit (Token errorAt, OpCode opcode, ScriptMyLocal myLocal); void EndExceptionBlock();
void Emit (Token errorAt, OpCode opcode, Type type); void Emit(Token errorAt, OpCode opcode);
void Emit (Token errorAt, OpCode opcode, ScriptMyLabel myLabel); void Emit(Token errorAt, OpCode opcode, FieldInfo field);
void Emit (Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels); void Emit(Token errorAt, OpCode opcode, ScriptMyLocal myLocal);
void Emit (Token errorAt, OpCode opcode, ScriptObjWriter method); void Emit(Token errorAt, OpCode opcode, Type type);
void Emit (Token errorAt, OpCode opcode, MethodInfo method); void Emit(Token errorAt, OpCode opcode, ScriptMyLabel myLabel);
void Emit (Token errorAt, OpCode opcode, ConstructorInfo ctor); void Emit(Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels);
void Emit (Token errorAt, OpCode opcode, double value); void Emit(Token errorAt, OpCode opcode, ScriptObjWriter method);
void Emit (Token errorAt, OpCode opcode, float value); void Emit(Token errorAt, OpCode opcode, MethodInfo method);
void Emit (Token errorAt, OpCode opcode, int value); void Emit(Token errorAt, OpCode opcode, ConstructorInfo ctor);
void Emit (Token errorAt, OpCode opcode, string value); void Emit(Token errorAt, OpCode opcode, double value);
void MarkLabel (ScriptMyLabel myLabel); void Emit(Token errorAt, OpCode opcode, float value);
void Emit(Token errorAt, OpCode opcode, int value);
void Emit(Token errorAt, OpCode opcode, string value);
void MarkLabel(ScriptMyLabel myLabel);
} }
/** /**
* @brief One of these per label defined in the function. * @brief One of these per label defined in the function.
*/ */
public class ScriptMyLabel { public class ScriptMyLabel
{
public string name; public string name;
public int number; public int number;
@ -71,7 +75,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief One of these per local variable defined in the function. * @brief One of these per local variable defined in the function.
*/ */
public class ScriptMyLocal { public class ScriptMyLocal
{
public string name; public string name;
public Type type; public Type type;
public int number; public int number;

View File

@ -0,0 +1,245 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using OpenSim.Region.ScriptEngine.Yengine;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Reflection.Emit;
namespace OpenSim.Region.ScriptEngine.Yengine
{
public delegate void ScriptEventHandler(XMRInstAbstract instance);
/*
* This object represents the output of the compilation.
* Once the compilation is complete, its contents should be
* considered 'read-only', so it can be shared among multiple
* instances of the script.
*
* It gets created by ScriptCodeGen.
* It gets used by XMRInstance to create script instances.
*/
public class ScriptObjCode
{
public string sourceHash; // source text hash code
public XMRInstArSizes glblSizes = new XMRInstArSizes();
// number of global variables of various types
public string[] stateNames; // convert state number to corresponding string
public ScriptEventHandler[,] scriptEventHandlerTable;
// entrypoints to all event handler functions
// 1st subscript = state code number (0=default)
// 2nd subscript = event code number
// null entry means no handler defined for that state,event
public Dictionary<string, TokenDeclSDType> sdObjTypesName;
// all script-defined types by name
public TokenDeclSDType[] sdObjTypesIndx;
// all script-defined types by sdTypeIndex
public Dictionary<Type, string> sdDelTypes;
// all script-defined delegates (including anonymous)
public Dictionary<string, DynamicMethod> dynamicMethods;
// all dyanmic methods
public Dictionary<string, KeyValuePair<int, ScriptSrcLoc>[]> scriptSrcLocss;
// method,iloffset -> source file,line,posn
public int refCount; // used by engine to keep track of number of
// instances that are using this object code
public Dictionary<string, Dictionary<int, string>> globalVarNames = new Dictionary<string, Dictionary<int, string>>();
/**
* @brief Fill in ScriptObjCode from an YEngine object file.
* 'objFileReader' is a serialized form of the CIL code we generated
* 'asmFileWriter' is where we write the disassembly to (or null if not wanted)
* 'srcFileWriter' is where we write the decompilation to (or null if not wanted)
* Throws an exception if there is any error (theoretically).
*/
public ScriptObjCode(BinaryReader objFileReader, TextWriter asmFileWriter, TextWriter srcFileWriter)
{
/*
* Check version number to make sure we know how to process file contents.
*/
char[] ocm = objFileReader.ReadChars(ScriptCodeGen.OBJECT_CODE_MAGIC.Length);
if(new String(ocm) != ScriptCodeGen.OBJECT_CODE_MAGIC)
throw new Exception("not an XMR object file (bad magic)");
int cvv = objFileReader.ReadInt32();
if(cvv != ScriptCodeGen.COMPILED_VERSION_VALUE)
throw new CVVMismatchException(cvv, ScriptCodeGen.COMPILED_VERSION_VALUE);
// Fill in simple parts of scriptObjCode object.
sourceHash = objFileReader.ReadString();
glblSizes.ReadFromFile(objFileReader);
int nStates = objFileReader.ReadInt32();
stateNames = new string[nStates];
for(int i = 0; i < nStates; i++)
{
stateNames[i] = objFileReader.ReadString();
if(asmFileWriter != null)
asmFileWriter.WriteLine(" state[{0}] = {1}", i, stateNames[i]);
}
if(asmFileWriter != null)
glblSizes.WriteAsmFile(asmFileWriter, "numGbl");
string gblName;
while((gblName = objFileReader.ReadString()) != "")
{
string gblType = objFileReader.ReadString();
int gblIndex = objFileReader.ReadInt32();
Dictionary<int, string> names;
if(!globalVarNames.TryGetValue(gblType, out names))
{
names = new Dictionary<int, string>();
globalVarNames.Add(gblType, names);
}
names.Add(gblIndex, gblName);
if(asmFileWriter != null)
asmFileWriter.WriteLine(" {0} = {1}[{2}]", gblName, gblType, gblIndex);
}
// Read in script-defined types.
sdObjTypesName = new Dictionary<string, TokenDeclSDType>();
sdDelTypes = new Dictionary<Type, string>();
int maxIndex = -1;
while((gblName = objFileReader.ReadString()) != "")
{
TokenDeclSDType sdt = TokenDeclSDType.ReadFromFile(sdObjTypesName,
gblName, objFileReader, asmFileWriter);
sdObjTypesName.Add(gblName, sdt);
if(maxIndex < sdt.sdTypeIndex)
maxIndex = sdt.sdTypeIndex;
if(sdt is TokenDeclSDTypeDelegate)
sdDelTypes.Add(sdt.GetSysType(), gblName);
}
sdObjTypesIndx = new TokenDeclSDType[maxIndex + 1];
foreach(TokenDeclSDType sdt in sdObjTypesName.Values)
sdObjTypesIndx[sdt.sdTypeIndex] = sdt;
// Now fill in the methods (the hard part).
scriptEventHandlerTable = new ScriptEventHandler[nStates, (int)ScriptEventCode.Size];
dynamicMethods = new Dictionary<string, DynamicMethod>();
scriptSrcLocss = new Dictionary<string, KeyValuePair<int, ScriptSrcLoc>[]>();
ObjectTokens objectTokens = null;
if(asmFileWriter != null)
objectTokens = new OTDisassemble(this, asmFileWriter);
else if(srcFileWriter != null)
objectTokens = new OTDecompile(this, srcFileWriter);
try
{
ScriptObjWriter.CreateObjCode(sdObjTypesName, objFileReader, this, objectTokens);
}
finally
{
if(objectTokens != null)
objectTokens.Close();
}
// We enter all script event handler methods in the ScriptEventHandler table.
// They are named: <statename> <eventname>
foreach(KeyValuePair<string, DynamicMethod> kvp in dynamicMethods)
{
string methName = kvp.Key;
int i = methName.IndexOf(' ');
if(i < 0)
continue;
string stateName = methName.Substring(0, i);
string eventName = methName.Substring(++i);
int stateCode;
for(stateCode = stateNames.Length; --stateCode >= 0;)
if(stateNames[stateCode] == stateName)
break;
int eventCode = (int)Enum.Parse(typeof(ScriptEventCode), eventName);
scriptEventHandlerTable[stateCode, eventCode] =
(ScriptEventHandler)kvp.Value.CreateDelegate(typeof(ScriptEventHandler));
}
// Fill in all script-defined class vtables.
foreach(TokenDeclSDType sdt in sdObjTypesIndx)
{
if((sdt != null) && (sdt is TokenDeclSDTypeClass))
{
TokenDeclSDTypeClass sdtc = (TokenDeclSDTypeClass)sdt;
sdtc.FillVTables(this);
}
}
}
/**
* @brief Called once for every method found in objFileReader file.
* It enters the method in the ScriptObjCode object table so it can be called.
*/
public void EndMethod(DynamicMethod method, Dictionary<int, ScriptSrcLoc> srcLocs)
{
/*
* Save method object code pointer.
*/
dynamicMethods.Add(method.Name, method);
/*
* Build and sort iloffset -> source code location array.
*/
int n = srcLocs.Count;
KeyValuePair<int, ScriptSrcLoc>[] srcLocArray = new KeyValuePair<int, ScriptSrcLoc>[n];
n = 0;
foreach(KeyValuePair<int, ScriptSrcLoc> kvp in srcLocs)
srcLocArray[n++] = kvp;
Array.Sort(srcLocArray, endMethodWrapper);
/*
* Save sorted array.
*/
scriptSrcLocss.Add(method.Name, srcLocArray);
}
/**
* @brief Called once for every method found in objFileReader file.
* It enters the method in the ScriptObjCode object table so it can be called.
*/
private static EndMethodWrapper endMethodWrapper = new EndMethodWrapper();
private class EndMethodWrapper: System.Collections.IComparer
{
public int Compare(object x, object y)
{
KeyValuePair<int, ScriptSrcLoc> kvpx = (KeyValuePair<int, ScriptSrcLoc>)x;
KeyValuePair<int, ScriptSrcLoc> kvpy = (KeyValuePair<int, ScriptSrcLoc>)y;
return kvpx.Key - kvpy.Key;
}
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -33,63 +33,80 @@ using System.Collections.Generic;
* @brief Collection of variable/function/method definitions * @brief Collection of variable/function/method definitions
*/ */
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
public class VarDict : IEnumerable { public class VarDict: IEnumerable
{
public VarDict outerVarDict; // next outer VarDict to search public VarDict outerVarDict; // next outer VarDict to search
public TokenDeclSDTypeClass thisClass; // this VarDict is for members of thisClass public TokenDeclSDTypeClass thisClass; // this VarDict is for members of thisClass
private struct ArgTypes { private struct ArgTypes
{
public TokenType[] argTypes; public TokenType[] argTypes;
public bool CanBeCalledBy (TokenType[] calledBy) public bool CanBeCalledBy(TokenType[] calledBy)
{ {
if ((argTypes == null) && (calledBy == null)) return true; if((argTypes == null) && (calledBy == null))
if ((argTypes == null) || (calledBy == null)) return false; return true;
if (argTypes.Length != calledBy.Length) return false; if((argTypes == null) || (calledBy == null))
for (int i = argTypes.Length; -- i >= 0;) { return false;
if (!TypeCast.IsAssignableFrom (argTypes[i], calledBy[i])) return false; if(argTypes.Length != calledBy.Length)
return false;
for(int i = argTypes.Length; --i >= 0;)
{
if(!TypeCast.IsAssignableFrom(argTypes[i], calledBy[i]))
return false;
} }
return true; return true;
} }
public override bool Equals (Object that) public override bool Equals(Object that)
{ {
if (that == null) return false; if(that == null)
if (that.GetType () != typeof (ArgTypes)) return false; return false;
if(that.GetType() != typeof(ArgTypes))
return false;
TokenType[] at = this.argTypes; TokenType[] at = this.argTypes;
TokenType[] bt = ((ArgTypes)that).argTypes; TokenType[] bt = ((ArgTypes)that).argTypes;
if ((at == null) && (bt == null)) return true; if((at == null) && (bt == null))
if ((at == null) || (bt == null)) return false; return true;
if (at.Length != bt.Length) return false; if((at == null) || (bt == null))
for (int i = at.Length; -- i >= 0;) { return false;
if (at[i].ToString () != bt[i].ToString ()) return false; if(at.Length != bt.Length)
return false;
for(int i = at.Length; --i >= 0;)
{
if(at[i].ToString() != bt[i].ToString())
return false;
} }
return true; return true;
} }
public override int GetHashCode () public override int GetHashCode()
{ {
TokenType[] at = this.argTypes; TokenType[] at = this.argTypes;
if (at == null) return -1; if(at == null)
return -1;
int hc = 0; int hc = 0;
for (int i = at.Length; -- i >= 0;) { for(int i = at.Length; --i >= 0;)
{
int c = (hc < 0) ? 1 : 0; int c = (hc < 0) ? 1 : 0;
hc = hc * 2 + c; hc = hc * 2 + c;
hc ^= at[i].ToString ().GetHashCode (); hc ^= at[i].ToString().GetHashCode();
} }
return hc; return hc;
} }
} }
private struct TDVEntry { private struct TDVEntry
{
public int count; public int count;
public TokenDeclVar var; public TokenDeclVar var;
} }
private bool isFrozen = false; private bool isFrozen = false;
private bool locals; private bool locals;
private Dictionary<string, Dictionary<ArgTypes, TDVEntry>> master = new Dictionary<string, Dictionary<ArgTypes, TDVEntry>> (); private Dictionary<string, Dictionary<ArgTypes, TDVEntry>> master = new Dictionary<string, Dictionary<ArgTypes, TDVEntry>>();
private int count = 0; private int count = 0;
private VarDict frozenLocals = null; private VarDict frozenLocals = null;
@ -98,7 +115,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @param locals = false: cannot be frozen, allows forward references * @param locals = false: cannot be frozen, allows forward references
* true: can be frozen, thus forbidding forward references * true: can be frozen, thus forbidding forward references
*/ */
public VarDict (bool locals) public VarDict(bool locals)
{ {
this.locals = locals; this.locals = locals;
} }
@ -106,19 +123,21 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Add new variable to the dictionary. * @brief Add new variable to the dictionary.
*/ */
public bool AddEntry (TokenDeclVar var) public bool AddEntry(TokenDeclVar var)
{ {
if (isFrozen) { if(isFrozen)
throw new Exception ("var dict is frozen"); {
throw new Exception("var dict is frozen");
} }
/* /*
* Make sure we have a sub-dictionary based on the bare name (ie, no signature) * Make sure we have a sub-dictionary based on the bare name (ie, no signature)
*/ */
Dictionary<ArgTypes, TDVEntry> typedic; Dictionary<ArgTypes, TDVEntry> typedic;
if (!master.TryGetValue (var.name.val, out typedic)) { if(!master.TryGetValue(var.name.val, out typedic))
typedic = new Dictionary<ArgTypes, TDVEntry> (); {
master.Add (var.name.val, typedic); typedic = new Dictionary<ArgTypes, TDVEntry>();
master.Add(var.name.val, typedic);
} }
/* /*
@ -127,41 +146,50 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Methods always have a non-null argument list, even if only 0 entries long. * Methods always have a non-null argument list, even if only 0 entries long.
*/ */
ArgTypes types; ArgTypes types;
types.argTypes = (var.argDecl == null) ? null : KeyTypesToStringTypes (var.argDecl.types); types.argTypes = (var.argDecl == null) ? null : KeyTypesToStringTypes(var.argDecl.types);
if (typedic.ContainsKey (types)) return false; if(typedic.ContainsKey(types))
return false;
/* /*
* It is unique, add to its name-specific sub-dictionary. * It is unique, add to its name-specific sub-dictionary.
*/ */
TDVEntry entry; TDVEntry entry;
entry.count = ++ count; entry.count = ++count;
entry.var = var; entry.var = var;
typedic.Add (types, entry); typedic.Add(types, entry);
return true; return true;
} }
public int Count { get { return count; } } public int Count
{
get
{
return count;
}
}
/** /**
* @brief If this is not a local variable frame, just return the frame as is. * @brief If this is not a local variable frame, just return the frame as is.
* If this is a local variable frame, return a version that is frozen, * If this is a local variable frame, return a version that is frozen,
* ie, one that does not contain any future additions. * ie, one that does not contain any future additions.
*/ */
public VarDict FreezeLocals () public VarDict FreezeLocals()
{ {
/* /*
* If not local var frame, return original frame as is. * If not local var frame, return original frame as is.
* This will allow forward references as the future additions * This will allow forward references as the future additions
* will be seen by lookups done in this dictionary. * will be seen by lookups done in this dictionary.
*/ */
if (!locals) return this; if(!locals)
return this;
/* /*
* If local var frame, return a copy frozen at this point. * If local var frame, return a copy frozen at this point.
* This disallows forward referenes as those future additions * This disallows forward referenes as those future additions
* will not be seen by lookups done in the frozen dictionary. * will not be seen by lookups done in the frozen dictionary.
*/ */
if ((frozenLocals == null) || (frozenLocals.count != this.count)) { if((frozenLocals == null) || (frozenLocals.count != this.count))
{
/* /*
* Make a copy of the current var dictionary frame. * Make a copy of the current var dictionary frame.
@ -169,7 +197,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* contain additions made after this point, those additions * contain additions made after this point, those additions
* will have a count .gt. frozen count and will be ignored. * will have a count .gt. frozen count and will be ignored.
*/ */
frozenLocals = new VarDict (true); frozenLocals = new VarDict(true);
frozenLocals.outerVarDict = this.outerVarDict; frozenLocals.outerVarDict = this.outerVarDict;
frozenLocals.thisClass = this.thisClass; frozenLocals.thisClass = this.thisClass;
@ -196,23 +224,27 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* else: list of matching functions/variables * else: list of matching functions/variables
* for variables, always of length 1 * for variables, always of length 1
*/ */
private List<TokenDeclVar> found = new List<TokenDeclVar> (); private List<TokenDeclVar> found = new List<TokenDeclVar>();
public TokenDeclVar[] FindCallables (string name, TokenType[] argTypes) public TokenDeclVar[] FindCallables(string name, TokenType[] argTypes)
{ {
argTypes = KeyTypesToStringTypes (argTypes); argTypes = KeyTypesToStringTypes(argTypes);
TokenDeclVar var = FindExact (name, argTypes); TokenDeclVar var = FindExact(name, argTypes);
if (var != null) return new TokenDeclVar[] { var }; if(var != null)
return new TokenDeclVar[] { var };
Dictionary<ArgTypes, TDVEntry> typedic; Dictionary<ArgTypes, TDVEntry> typedic;
if (!master.TryGetValue (name, out typedic)) return null; if(!master.TryGetValue(name, out typedic))
return null;
found.Clear (); found.Clear();
foreach (KeyValuePair<ArgTypes, TDVEntry> kvp in typedic) { foreach(KeyValuePair<ArgTypes, TDVEntry> kvp in typedic)
if ((kvp.Value.count <= this.count) && kvp.Key.CanBeCalledBy (argTypes)) { {
found.Add (kvp.Value.var); if((kvp.Value.count <= this.count) && kvp.Key.CanBeCalledBy(argTypes))
{
found.Add(kvp.Value.var);
} }
} }
return (found.Count > 0) ? found.ToArray () : null; return (found.Count > 0) ? found.ToArray() : null;
} }
/** /**
@ -223,19 +255,22 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @returns null: no matching function/variable found * @returns null: no matching function/variable found
* else: the matching function/variable * else: the matching function/variable
*/ */
public TokenDeclVar FindExact (string name, TokenType[] argTypes) public TokenDeclVar FindExact(string name, TokenType[] argTypes)
{ {
/* /*
* Look for list of stuff that matches the given name. * Look for list of stuff that matches the given name.
*/ */
Dictionary<ArgTypes, TDVEntry> typedic; Dictionary<ArgTypes, TDVEntry> typedic;
if (!master.TryGetValue (name, out typedic)) return null; if(!master.TryGetValue(name, out typedic))
return null;
/* /*
* Loop through all fields/methods declared by that name, regardless of arg signature. * Loop through all fields/methods declared by that name, regardless of arg signature.
*/ */
foreach (TDVEntry entry in typedic.Values) { foreach(TDVEntry entry in typedic.Values)
if (entry.count > this.count) continue; {
if(entry.count > this.count)
continue;
TokenDeclVar var = entry.var; TokenDeclVar var = entry.var;
/* /*
@ -248,12 +283,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/* /*
* Convert any key args to string args. * Convert any key args to string args.
*/ */
declArgs = KeyTypesToStringTypes (declArgs); declArgs = KeyTypesToStringTypes(declArgs);
/* /*
* If both are null, they are signature-less (ie, both are fields), and so match. * If both are null, they are signature-less (ie, both are fields), and so match.
*/ */
if ((declArgs == null) && (argTypes == null)) return var; if((declArgs == null) && (argTypes == null))
return var;
/* /*
* If calling a delegate, it is a match, regardless of delegate arg types. * If calling a delegate, it is a match, regardless of delegate arg types.
@ -261,29 +297,38 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* trying to cast the arguments to the delegate arg types. * trying to cast the arguments to the delegate arg types.
* We don't allow overloading same field name with different delegate types. * We don't allow overloading same field name with different delegate types.
*/ */
if ((declArgs == null) && (argTypes != null)) { if((declArgs == null) && (argTypes != null))
{
TokenType fieldType = var.type; TokenType fieldType = var.type;
if (fieldType is TokenTypeSDTypeDelegate) return var; if(fieldType is TokenTypeSDTypeDelegate)
return var;
} }
/* /*
* If not both null, no match, keep looking. * If not both null, no match, keep looking.
*/ */
if ((declArgs == null) || (argTypes == null)) continue; if((declArgs == null) || (argTypes == null))
continue;
/* /*
* Both not null, match argument types to make sure we have correct overload. * Both not null, match argument types to make sure we have correct overload.
*/ */
int i = declArgs.Length; int i = declArgs.Length;
if (i != argTypes.Length) continue; if(i != argTypes.Length)
while (-- i >= 0) { continue;
string da = declArgs[i].ToString (); while(--i >= 0)
string ga = argTypes[i].ToString (); {
if (da == "key") da = "string"; string da = declArgs[i].ToString();
if (ga == "key") ga = "string"; string ga = argTypes[i].ToString();
if (da != ga) break; if(da == "key")
da = "string";
if(ga == "key")
ga = "string";
if(da != ga)
break;
} }
if (i < 0) return var; if(i < 0)
return var;
} }
/* /*
@ -299,20 +344,26 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @param argTypes = argument types as declared in source code * @param argTypes = argument types as declared in source code
* @returns argTypes with any key replaced by string * @returns argTypes with any key replaced by string
*/ */
private static TokenType[] KeyTypesToStringTypes (TokenType[] argTypes) private static TokenType[] KeyTypesToStringTypes(TokenType[] argTypes)
{
if(argTypes != null)
{ {
if (argTypes != null) {
int i; int i;
int nats = argTypes.Length; int nats = argTypes.Length;
for (i = nats; -- i >= 0;) { for(i = nats; --i >= 0;)
if (argTypes[i] is TokenTypeKey) break; {
if(argTypes[i] is TokenTypeKey)
break;
} }
if (i >= 0) { if(i >= 0)
{
TokenType[] at = new TokenType[nats]; TokenType[] at = new TokenType[nats];
for (i = nats; -- i >= 0;) { for(i = nats; --i >= 0;)
{
at[i] = argTypes[i]; at[i] = argTypes[i];
if (argTypes[i] is TokenTypeKey) { if(argTypes[i] is TokenTypeKey)
at[i] = new TokenTypeStr (argTypes[i]); {
at[i] = new TokenTypeStr(argTypes[i]);
} }
} }
return at; return at;
@ -324,48 +375,60 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// foreach goes through all the TokenDeclVars that were added // foreach goes through all the TokenDeclVars that were added
// IEnumerable // IEnumerable
public IEnumerator GetEnumerator () public IEnumerator GetEnumerator()
{ {
return new VarDictEnumerator (this.master, this.count); return new VarDictEnumerator(this.master, this.count);
} }
private class VarDictEnumerator : IEnumerator { private class VarDictEnumerator: IEnumerator
{
private IEnumerator masterEnum; private IEnumerator masterEnum;
private IEnumerator typedicEnum; private IEnumerator typedicEnum;
private int count; private int count;
public VarDictEnumerator (Dictionary<string, Dictionary<ArgTypes, TDVEntry>> master, int count) public VarDictEnumerator(Dictionary<string, Dictionary<ArgTypes, TDVEntry>> master, int count)
{ {
masterEnum = master.Values.GetEnumerator (); masterEnum = master.Values.GetEnumerator();
this.count = count; this.count = count;
} }
// IEnumerator // IEnumerator
public void Reset () public void Reset()
{ {
masterEnum.Reset (); masterEnum.Reset();
typedicEnum = null; typedicEnum = null;
} }
// IEnumerator // IEnumerator
public bool MoveNext () public bool MoveNext()
{ {
while (true) { while(true)
if (typedicEnum != null) { {
while (typedicEnum.MoveNext ()) { if(typedicEnum != null)
if (((TDVEntry)typedicEnum.Current).count <= this.count) return true; {
while(typedicEnum.MoveNext())
{
if(((TDVEntry)typedicEnum.Current).count <= this.count)
return true;
} }
typedicEnum = null; typedicEnum = null;
} }
if (!masterEnum.MoveNext ()) return false; if(!masterEnum.MoveNext())
return false;
Dictionary<ArgTypes, TDVEntry> ctd; Dictionary<ArgTypes, TDVEntry> ctd;
ctd = (Dictionary<ArgTypes, TDVEntry>)masterEnum.Current; ctd = (Dictionary<ArgTypes, TDVEntry>)masterEnum.Current;
typedicEnum = ctd.Values.GetEnumerator (); typedicEnum = ctd.Values.GetEnumerator();
} }
} }
// IEnumerator // IEnumerator
public object Current { get { return ((TDVEntry)typedicEnum.Current).var; } } public object Current
{
get
{
return ((TDVEntry)typedicEnum.Current).var;
}
}
} }
} }
} }

View File

@ -40,12 +40,13 @@ using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
// This class exists in the main app domain // This class exists in the main app domain
// //
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
/** /**
* @brief Array objects. * @brief Array objects.
*/ */
public class XMR_Array { public class XMR_Array
{
private const int EMPTYHEAP = 64; private const int EMPTYHEAP = 64;
private const int ENTRYHEAP = 24; private const int ENTRYHEAP = 24;
@ -59,30 +60,34 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private XMRInstAbstract inst; // script instance debited with heap use private XMRInstAbstract inst; // script instance debited with heap use
private int heapUse; // current heap use debit amount private int heapUse; // current heap use debit amount
public static TokenTypeSDTypeDelegate countDelegate = new TokenTypeSDTypeDelegate (new TokenTypeInt (null), new TokenType[0]); public static TokenTypeSDTypeDelegate countDelegate = new TokenTypeSDTypeDelegate(new TokenTypeInt(null), new TokenType[0]);
public static TokenTypeSDTypeDelegate clearDelegate = new TokenTypeSDTypeDelegate (new TokenTypeVoid (null), new TokenType[0]); public static TokenTypeSDTypeDelegate clearDelegate = new TokenTypeSDTypeDelegate(new TokenTypeVoid(null), new TokenType[0]);
public static TokenTypeSDTypeDelegate indexDelegate = new TokenTypeSDTypeDelegate (new TokenTypeObject (null), new TokenType[] { new TokenTypeInt (null) }); public static TokenTypeSDTypeDelegate indexDelegate = new TokenTypeSDTypeDelegate(new TokenTypeObject(null), new TokenType[] { new TokenTypeInt(null) });
public static TokenTypeSDTypeDelegate valueDelegate = new TokenTypeSDTypeDelegate (new TokenTypeObject (null), new TokenType[] { new TokenTypeInt (null) }); public static TokenTypeSDTypeDelegate valueDelegate = new TokenTypeSDTypeDelegate(new TokenTypeObject(null), new TokenType[] { new TokenTypeInt(null) });
public XMR_Array (XMRInstAbstract inst) public XMR_Array(XMRInstAbstract inst)
{ {
this.inst = inst; this.inst = inst;
dnary = new SortedDictionary<object, object> (XMRArrayKeyComparer.singleton); dnary = new SortedDictionary<object, object>(XMRArrayKeyComparer.singleton);
heapUse = inst.UpdateHeapUse (0, EMPTYHEAP); heapUse = inst.UpdateHeapUse(0, EMPTYHEAP);
} }
~XMR_Array () ~XMR_Array()
{ {
heapUse = inst.UpdateHeapUse (heapUse, 0); heapUse = inst.UpdateHeapUse(heapUse, 0);
} }
public static TokenType GetRValType (TokenName name) public static TokenType GetRValType(TokenName name)
{ {
if (name.val == "count") return new TokenTypeInt (name); if(name.val == "count")
if (name.val == "clear") return clearDelegate; return new TokenTypeInt(name);
if (name.val == "index") return indexDelegate; if(name.val == "clear")
if (name.val == "value") return valueDelegate; return clearDelegate;
return new TokenTypeVoid (name); if(name.val == "index")
return indexDelegate;
if(name.val == "value")
return valueDelegate;
return new TokenTypeVoid(name);
} }
/** /**
@ -93,44 +98,51 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public object GetByKey(object key) public object GetByKey(object key)
{ {
object val; object val;
key = FixKey (key); key = FixKey(key);
if (!dnary.TryGetValue (key, out val)) val = null; if(!dnary.TryGetValue(key, out val))
val = null;
return val; return val;
} }
public void SetByKey(object key, object value) public void SetByKey(object key, object value)
{ {
key = FixKey (key); key = FixKey(key);
/* /*
* Update heap use throwing an exception on failure * Update heap use throwing an exception on failure
* before making any changes to the array. * before making any changes to the array.
*/ */
int keysize = HeapTrackerObject.Size (key); int keysize = HeapTrackerObject.Size(key);
int newheapuse = heapUse; int newheapuse = heapUse;
object oldval; object oldval;
if (dnary.TryGetValue (key, out oldval)) { if(dnary.TryGetValue(key, out oldval))
newheapuse -= keysize + HeapTrackerObject.Size (oldval); {
newheapuse -= keysize + HeapTrackerObject.Size(oldval);
} }
if (value != null) { if(value != null)
newheapuse += keysize + HeapTrackerObject.Size (value); {
newheapuse += keysize + HeapTrackerObject.Size(value);
} }
heapUse = inst.UpdateHeapUse (heapUse, newheapuse); heapUse = inst.UpdateHeapUse(heapUse, newheapuse);
/* /*
* Save new value in array, replacing one of same key if there. * Save new value in array, replacing one of same key if there.
* null means remove the value, ie, script did array[key] = undef. * null means remove the value, ie, script did array[key] = undef.
*/ */
if (value != null) { if(value != null)
{
dnary[key] = value; dnary[key] = value;
} else { }
dnary.Remove (key); else
{
dnary.Remove(key);
/* /*
* Shrink the enumeration array, but always leave at least one element. * Shrink the enumeration array, but always leave at least one element.
*/ */
if ((array != null) && (dnary.Count < array.Length / 2)) { if((array != null) && (dnary.Count < array.Length / 2))
Array.Resize<KeyValuePair<object, object>> (ref array, array.Length / 2); {
Array.Resize<KeyValuePair<object, object>>(ref array, array.Length / 2);
} }
} }
@ -148,35 +160,39 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* the C# runtime can't convert a null to a value type, and throws an exception. * the C# runtime can't convert a null to a value type, and throws an exception.
* But for any reference type (array, key, etc) we must manually check for null. * But for any reference type (array, key, etc) we must manually check for null.
*/ */
public static XMR_Array Obj2Array (object obj) public static XMR_Array Obj2Array(object obj)
{ {
if (obj == null) throw new NullReferenceException (); if(obj == null)
throw new NullReferenceException();
return (XMR_Array)obj; return (XMR_Array)obj;
} }
public static LSL_Key Obj2Key (object obj) public static LSL_Key Obj2Key(object obj)
{ {
if (obj == null) throw new NullReferenceException (); if(obj == null)
throw new NullReferenceException();
return (LSL_Key)obj; return (LSL_Key)obj;
} }
public static LSL_List Obj2List (object obj) public static LSL_List Obj2List(object obj)
{ {
if (obj == null) throw new NullReferenceException (); if(obj == null)
throw new NullReferenceException();
return (LSL_List)obj; return (LSL_List)obj;
} }
public static LSL_String Obj2String (object obj) public static LSL_String Obj2String(object obj)
{ {
if (obj == null) throw new NullReferenceException (); if(obj == null)
return obj.ToString (); throw new NullReferenceException();
return obj.ToString();
} }
/** /**
* @brief remove all elements from the array. * @brief remove all elements from the array.
* sets everything to its 'just constructed' state. * sets everything to its 'just constructed' state.
*/ */
public void __pub_clear () public void __pub_clear()
{ {
heapUse = inst.UpdateHeapUse (heapUse, EMPTYHEAP); heapUse = inst.UpdateHeapUse(heapUse, EMPTYHEAP);
dnary.Clear (); dnary.Clear();
enumrValid = false; enumrValid = false;
arrayValid = 0; arrayValid = 0;
array = null; array = null;
@ -185,7 +201,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief return number of elements in the array. * @brief return number of elements in the array.
*/ */
public int __pub_count () public int __pub_count()
{ {
return dnary.Count; return dnary.Count;
} }
@ -196,9 +212,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @returns null: array doesn't have that many elements * @returns null: array doesn't have that many elements
* else: index (key) for that element * else: index (key) for that element
*/ */
public object __pub_index (int number) public object __pub_index(int number)
{ {
return ForEach (number) ? UnfixKey (array[number].Key) : null; return ForEach(number) ? UnfixKey(array[number].Key) : null;
} }
/** /**
@ -207,9 +223,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @returns null: array doesn't have that many elements * @returns null: array doesn't have that many elements
* else: value for that element * else: value for that element
*/ */
public object __pub_value (int number) public object __pub_value(int number)
{ {
return ForEach (number) ? array[number].Value : null; return ForEach(number) ? array[number].Value : null;
} }
/** /**
@ -218,14 +234,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @returns false: element does not exist * @returns false: element does not exist
* true: element exists * true: element exists
*/ */
private bool ForEach (int number) private bool ForEach(int number)
{ {
/* /*
* If we don't have any array, we can't have ever done * If we don't have any array, we can't have ever done
* any calls here before, so allocate an array big enough * any calls here before, so allocate an array big enough
* and set everything else to the beginning. * and set everything else to the beginning.
*/ */
if (array == null) { if(array == null)
{
array = new KeyValuePair<object, object>[dnary.Count]; array = new KeyValuePair<object, object>[dnary.Count];
arrayValid = 0; arrayValid = 0;
} }
@ -233,17 +250,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/* /*
* If dictionary modified since last enumeration, get a new enumerator. * If dictionary modified since last enumeration, get a new enumerator.
*/ */
if (arrayValid == 0) { if(arrayValid == 0)
enumr = dnary.GetEnumerator (); {
enumr = dnary.GetEnumerator();
enumrValid = true; enumrValid = true;
} }
/* /*
* Make sure we have filled the array up enough for requested element. * Make sure we have filled the array up enough for requested element.
*/ */
while ((arrayValid <= number) && enumrValid && enumr.MoveNext ()) { while((arrayValid <= number) && enumrValid && enumr.MoveNext())
if (arrayValid >= array.Length) { {
Array.Resize<KeyValuePair<object, object>> (ref array, dnary.Count); if(arrayValid >= array.Length)
{
Array.Resize<KeyValuePair<object, object>>(ref array, dnary.Count);
} }
array[arrayValid++] = enumr.Current; array[arrayValid++] = enumr.Current;
} }
@ -258,17 +278,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @brief Transmit array out in such a way that it can be reconstructed, * @brief Transmit array out in such a way that it can be reconstructed,
* including any in-progress ForEach() enumerations. * including any in-progress ForEach() enumerations.
*/ */
public delegate void SendArrayObjDelegate (object graph); public delegate void SendArrayObjDelegate(object graph);
public void SendArrayObj (SendArrayObjDelegate sendObj) public void SendArrayObj(SendArrayObjDelegate sendObj)
{ {
/* /*
* Set the count then the elements themselves. * Set the count then the elements themselves.
* UnfixKey() because sendObj doesn't handle XMRArrayListKeys. * UnfixKey() because sendObj doesn't handle XMRArrayListKeys.
*/ */
sendObj (dnary.Count); sendObj(dnary.Count);
foreach (KeyValuePair<object, object> kvp in dnary) { foreach(KeyValuePair<object, object> kvp in dnary)
sendObj (UnfixKey (kvp.Key)); {
sendObj (kvp.Value); sendObj(UnfixKey(kvp.Key));
sendObj(kvp.Value);
} }
} }
@ -278,10 +299,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* at the exact spot and in the exact same order as they * at the exact spot and in the exact same order as they
* were in on the sending side. * were in on the sending side.
*/ */
public delegate object RecvArrayObjDelegate (); public delegate object RecvArrayObjDelegate();
public void RecvArrayObj (RecvArrayObjDelegate recvObj) public void RecvArrayObj(RecvArrayObjDelegate recvObj)
{ {
heapUse = inst.UpdateHeapUse (heapUse, EMPTYHEAP); heapUse = inst.UpdateHeapUse(heapUse, EMPTYHEAP);
/* /*
* Cause any enumeration to refill the array from the sorted dictionary. * Cause any enumeration to refill the array from the sorted dictionary.
@ -294,14 +315,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/* /*
* Fill dictionary. * Fill dictionary.
*/ */
dnary.Clear (); dnary.Clear();
int count = (int)recvObj (); int count = (int)recvObj();
while (-- count >= 0) { while(--count >= 0)
object key = FixKey (recvObj ()); {
object val = recvObj (); object key = FixKey(recvObj());
int htuse = HeapTrackerObject.Size (key) + HeapTrackerObject.Size (val); object val = recvObj();
heapUse = inst.UpdateHeapUse (heapUse, heapUse + htuse); int htuse = HeapTrackerObject.Size(key) + HeapTrackerObject.Size(val);
dnary.Add (key, val); heapUse = inst.UpdateHeapUse(heapUse, heapUse + htuse);
dnary.Add(key, val);
} }
} }
@ -310,16 +332,22 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* So strip off any LSL-ness from the types. * So strip off any LSL-ness from the types.
* We also deep-strip any given lists used as keys (multi-dimensional arrays). * We also deep-strip any given lists used as keys (multi-dimensional arrays).
*/ */
public static object FixKey (object key) public static object FixKey(object key)
{
if(key is LSL_Integer)
return (int)(LSL_Integer)key;
if(key is LSL_Float)
return (double)(LSL_Float)key;
if(key is LSL_Key)
return (string)(LSL_Key)key;
if(key is LSL_String)
return (string)(LSL_String)key;
if(key is LSL_List)
{ {
if (key is LSL_Integer) return (int)(LSL_Integer)key;
if (key is LSL_Float) return (double)(LSL_Float)key;
if (key is LSL_Key) return (string)(LSL_Key)key;
if (key is LSL_String) return (string)(LSL_String)key;
if (key is LSL_List) {
object[] data = ((LSL_List)key).Data; object[] data = ((LSL_List)key).Data;
if (data.Length == 1) return FixKey (data[0]); if(data.Length == 1)
return new XMRArrayListKey ((LSL_List)key); return FixKey(data[0]);
return new XMRArrayListKey((LSL_List)key);
} }
return key; // int, double, string, LSL_Vector, LSL_Rotation, etc are ok as is return key; // int, double, string, LSL_Vector, LSL_Rotation, etc are ok as is
} }
@ -329,99 +357,119 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* LSL_List, not the sanitized one, as the script compiler expects an LSL_List. * LSL_List, not the sanitized one, as the script compiler expects an LSL_List.
* Any other sanitized types can remain as is (int, string, etc). * Any other sanitized types can remain as is (int, string, etc).
*/ */
private static object UnfixKey (object key) private static object UnfixKey(object key)
{ {
if (key is XMRArrayListKey) key = ((XMRArrayListKey)key).GetOriginal (); if(key is XMRArrayListKey)
key = ((XMRArrayListKey)key).GetOriginal();
return key; return key;
} }
} }
public class XMRArrayKeyComparer : IComparer<object> { public class XMRArrayKeyComparer: IComparer<object>
{
public static XMRArrayKeyComparer singleton = new XMRArrayKeyComparer (); public static XMRArrayKeyComparer singleton = new XMRArrayKeyComparer();
/** /**
* @brief Compare two keys * @brief Compare two keys
*/ */
public int Compare (object x, object y) // IComparer<object> public int Compare(object x, object y) // IComparer<object>
{ {
/* /*
* Use short type name (eg, String, Int32, XMRArrayListKey) as most significant part of key. * Use short type name (eg, String, Int32, XMRArrayListKey) as most significant part of key.
*/ */
string xtn = x.GetType ().Name; string xtn = x.GetType().Name;
string ytn = y.GetType ().Name; string ytn = y.GetType().Name;
int ctn = String.CompareOrdinal (xtn, ytn); int ctn = String.CompareOrdinal(xtn, ytn);
if (ctn != 0) return ctn; if(ctn != 0)
return ctn;
ComparerDelegate cd; ComparerDelegate cd;
if (!comparers.TryGetValue (xtn, out cd)) { if(!comparers.TryGetValue(xtn, out cd))
throw new Exception ("unsupported key type " + xtn);
}
return cd (x, y);
}
private delegate int ComparerDelegate (object a, object b);
private static Dictionary<string, ComparerDelegate> comparers = BuildComparers ();
private static Dictionary<string, ComparerDelegate> BuildComparers ()
{ {
Dictionary<string, ComparerDelegate> cmps = new Dictionary<string, ComparerDelegate> (); throw new Exception("unsupported key type " + xtn);
cmps.Add (typeof (double).Name, MyFloatComparer); }
cmps.Add (typeof (int).Name, MyIntComparer); return cd(x, y);
cmps.Add (typeof (XMRArrayListKey).Name, MyListKeyComparer); }
cmps.Add (typeof (LSL_Rotation).Name, MyRotationComparer);
cmps.Add (typeof (string).Name, MyStringComparer); private delegate int ComparerDelegate(object a, object b);
cmps.Add (typeof (LSL_Vector).Name, MyVectorComparer);
private static Dictionary<string, ComparerDelegate> comparers = BuildComparers();
private static Dictionary<string, ComparerDelegate> BuildComparers()
{
Dictionary<string, ComparerDelegate> cmps = new Dictionary<string, ComparerDelegate>();
cmps.Add(typeof(double).Name, MyFloatComparer);
cmps.Add(typeof(int).Name, MyIntComparer);
cmps.Add(typeof(XMRArrayListKey).Name, MyListKeyComparer);
cmps.Add(typeof(LSL_Rotation).Name, MyRotationComparer);
cmps.Add(typeof(string).Name, MyStringComparer);
cmps.Add(typeof(LSL_Vector).Name, MyVectorComparer);
return cmps; return cmps;
} }
private static int MyFloatComparer (object a, object b) private static int MyFloatComparer(object a, object b)
{ {
double af = (double)a; double af = (double)a;
double bf = (double)b; double bf = (double)b;
if (af < bf) return -1; if(af < bf)
if (af > bf) return 1; return -1;
if(af > bf)
return 1;
return 0; return 0;
} }
private static int MyIntComparer (object a, object b) private static int MyIntComparer(object a, object b)
{ {
return (int)a - (int)b; return (int)a - (int)b;
} }
private static int MyListKeyComparer (object a, object b) private static int MyListKeyComparer(object a, object b)
{ {
XMRArrayListKey alk = (XMRArrayListKey)a; XMRArrayListKey alk = (XMRArrayListKey)a;
XMRArrayListKey blk = (XMRArrayListKey)b; XMRArrayListKey blk = (XMRArrayListKey)b;
return XMRArrayListKey.Compare (alk, blk); return XMRArrayListKey.Compare(alk, blk);
} }
private static int MyRotationComparer (object a, object b) private static int MyRotationComparer(object a, object b)
{ {
LSL_Rotation ar = (LSL_Rotation)a; LSL_Rotation ar = (LSL_Rotation)a;
LSL_Rotation br = (LSL_Rotation)b; LSL_Rotation br = (LSL_Rotation)b;
if (ar.x < br.x) return -1; if(ar.x < br.x)
if (ar.x > br.x) return 1; return -1;
if (ar.y < br.y) return -1; if(ar.x > br.x)
if (ar.y > br.y) return 1; return 1;
if (ar.z < br.z) return -1; if(ar.y < br.y)
if (ar.z > br.z) return 1; return -1;
if (ar.s < br.s) return -1; if(ar.y > br.y)
if (ar.s > br.s) return 1; return 1;
if(ar.z < br.z)
return -1;
if(ar.z > br.z)
return 1;
if(ar.s < br.s)
return -1;
if(ar.s > br.s)
return 1;
return 0; return 0;
} }
private static int MyStringComparer (object a, object b) private static int MyStringComparer(object a, object b)
{ {
return String.CompareOrdinal ((string)a, (string)b); return String.CompareOrdinal((string)a, (string)b);
} }
private static int MyVectorComparer (object a, object b) private static int MyVectorComparer(object a, object b)
{ {
LSL_Vector av = (LSL_Vector)a; LSL_Vector av = (LSL_Vector)a;
LSL_Vector bv = (LSL_Vector)b; LSL_Vector bv = (LSL_Vector)b;
if (av.x < bv.x) return -1; if(av.x < bv.x)
if (av.x > bv.x) return 1; return -1;
if (av.y < bv.y) return -1; if(av.x > bv.x)
if (av.y > bv.y) return 1; return 1;
if (av.z < bv.z) return -1; if(av.y < bv.y)
if (av.z > bv.z) return 1; return -1;
if(av.y > bv.y)
return 1;
if(av.z < bv.z)
return -1;
if(av.z > bv.z)
return 1;
return 0; return 0;
} }
} }
@ -433,7 +481,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Note that just like LSL_Lists, we consider these objects to be immutable, so they can be directly used as keys in * Note that just like LSL_Lists, we consider these objects to be immutable, so they can be directly used as keys in
* the dictionary as they don't ever change. * the dictionary as they don't ever change.
*/ */
public class XMRArrayListKey { public class XMRArrayListKey
{
private LSL_List original; private LSL_List original;
private object[] cleaned; private object[] cleaned;
private int length; private int length;
@ -443,7 +492,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @brief Construct a sanitized object[] from a list. * @brief Construct a sanitized object[] from a list.
* Also save the original list in case we need it later. * Also save the original list in case we need it later.
*/ */
public XMRArrayListKey (LSL_List key) public XMRArrayListKey(LSL_List key)
{ {
original = key; original = key;
object[] given = key.Data; object[] given = key.Data;
@ -451,10 +500,11 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
length = len; length = len;
cleaned = new object[len]; cleaned = new object[len];
int hc = len; int hc = len;
for (int i = 0; i < len; i ++) { for(int i = 0; i < len; i++)
object v = XMR_Array.FixKey (given[i]); {
object v = XMR_Array.FixKey(given[i]);
hc += hc + ((hc < 0) ? 1 : 0); hc += hc + ((hc < 0) ? 1 : 0);
hc ^= v.GetHashCode (); hc ^= v.GetHashCode();
cleaned[i] = v; cleaned[i] = v;
} }
hashCode = hc; hashCode = hc;
@ -463,8 +513,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Get heap tracking size. * @brief Get heap tracking size.
*/ */
public int Size { public int Size
get { {
get
{
return original.Size; return original.Size;
} }
} }
@ -472,15 +524,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief See if the given object is an XMRArrayListKey and every value is equal to our own. * @brief See if the given object is an XMRArrayListKey and every value is equal to our own.
*/ */
public override bool Equals (object o) public override bool Equals(object o)
{ {
if (!(o is XMRArrayListKey)) return false; if(!(o is XMRArrayListKey))
return false;
XMRArrayListKey a = (XMRArrayListKey)o; XMRArrayListKey a = (XMRArrayListKey)o;
int len = a.length; int len = a.length;
if (len != length) return false; if(len != length)
if (a.hashCode != hashCode) return false; return false;
for (int i = 0; i < len; i ++) { if(a.hashCode != hashCode)
if (!cleaned[i].Equals (a.cleaned[i])) return false; return false;
for(int i = 0; i < len; i++)
{
if(!cleaned[i].Equals(a.cleaned[i]))
return false;
} }
return true; return true;
} }
@ -488,7 +545,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Get an hash code. * @brief Get an hash code.
*/ */
public override int GetHashCode () public override int GetHashCode()
{ {
return hashCode; return hashCode;
} }
@ -496,15 +553,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Compare for key sorting. * @brief Compare for key sorting.
*/ */
public static int Compare (XMRArrayListKey x, XMRArrayListKey y) public static int Compare(XMRArrayListKey x, XMRArrayListKey y)
{ {
int j = x.length - y.length; int j = x.length - y.length;
if (j == 0) { if(j == 0)
for (int i = 0; i < x.length; i ++) { {
for(int i = 0; i < x.length; i++)
{
object xo = x.cleaned[i]; object xo = x.cleaned[i];
object yo = y.cleaned[i]; object yo = y.cleaned[i];
j = XMRArrayKeyComparer.singleton.Compare (xo, yo); j = XMRArrayKeyComparer.singleton.Compare(xo, yo);
if (j != 0) break; if(j != 0)
break;
} }
} }
return j; return j;
@ -513,7 +573,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Get the original LSL_List we were built from. * @brief Get the original LSL_List we were built from.
*/ */
public LSL_List GetOriginal () public LSL_List GetOriginal()
{ {
return original; return original;
} }
@ -521,14 +581,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Debugging * @brief Debugging
*/ */
public override string ToString () public override string ToString()
{ {
StringBuilder sb = new StringBuilder (); StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i ++) { for(int i = 0; i < length; i++)
if (i > 0) sb.Append (','); {
sb.Append (cleaned[i].ToString ()); if(i > 0)
sb.Append(',');
sb.Append(cleaned[i].ToString());
} }
return sb.ToString (); return sb.ToString();
} }
} }
} }

View File

@ -0,0 +1,578 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using log4net;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.Yengine
{
public partial class Yengine
{
private void XmrTestLs(string[] args, int indx)
{
bool flagFull = false;
bool flagQueues = false;
bool flagTopCPU = false;
int maxScripts = 0x7FFFFFFF;
int numScripts = 0;
string outName = null;
XMRInstance[] instances;
/*
* Decode command line options.
*/
for(int i = indx; i < args.Length; i++)
{
if(args[i] == "-full")
{
flagFull = true;
continue;
}
if(args[i] == "-help")
{
m_log.Info("[YEngine]: xmr ls -full -max=<number> -out=<filename> -queues -topcpu");
return;
}
if(args[i].StartsWith("-max="))
{
try
{
maxScripts = Convert.ToInt32(args[i].Substring(5));
}
catch(Exception e)
{
m_log.Error("[YEngine]: bad max " + args[i].Substring(5) + ": " + e.Message);
return;
}
continue;
}
if(args[i].StartsWith("-out="))
{
outName = args[i].Substring(5);
continue;
}
if(args[i] == "-queues")
{
flagQueues = true;
continue;
}
if(args[i] == "-topcpu")
{
flagTopCPU = true;
continue;
}
if(args[i][0] == '-')
{
m_log.Error("[YEngine]: unknown option " + args[i] + ", try 'xmr ls -help'");
return;
}
}
TextWriter outFile = null;
if(outName != null)
{
try
{
outFile = File.CreateText(outName);
}
catch(Exception e)
{
m_log.Error("[YEngine]: error creating " + outName + ": " + e.Message);
return;
}
}
else
{
outFile = new LogInfoTextWriter(m_log);
}
try
{
/*
* Scan instance list to find those that match selection criteria.
*/
if(!Monitor.TryEnter(m_InstancesDict, 100))
{
m_log.Error("[YEngine]: deadlock m_LockedDict=" + m_LockedDict);
return;
}
try
{
instances = new XMRInstance[m_InstancesDict.Count];
foreach(XMRInstance ins in m_InstancesDict.Values)
{
if(InstanceMatchesArgs(ins, args, indx))
{
instances[numScripts++] = ins;
}
}
}
finally
{
Monitor.Exit(m_InstancesDict);
}
/*
* Maybe sort by descending CPU time.
*/
if(flagTopCPU)
{
Array.Sort<XMRInstance>(instances, CompareInstancesByCPUTime);
}
/*
* Print the entries.
*/
if(!flagFull)
{
outFile.WriteLine(" ItemID" +
" CPU(ms)" +
" NumEvents" +
" Status " +
" World Position " +
" <Part>:<Item>");
}
for(int i = 0; (i < numScripts) && (i < maxScripts); i++)
{
outFile.WriteLine(instances[i].RunTestLs(flagFull));
}
/*
* Print number of scripts that match selection criteria,
* even if we were told to print fewer.
*/
outFile.WriteLine("total of {0} script(s)", numScripts);
/*
* If -queues given, print out queue contents too.
*/
if(flagQueues)
{
LsQueue(outFile, "start", m_StartQueue, args, indx);
LsQueue(outFile, "sleep", m_SleepQueue, args, indx);
LsQueue(outFile, "yield", m_YieldQueue, args, indx);
}
}
finally
{
outFile.Close();
}
}
private void XmrTestPev(string[] args, int indx)
{
bool flagAll = false;
int numScripts = 0;
XMRInstance[] instances;
/*
* Decode command line options.
*/
int i, j;
List<string> selargs = new List<string>(args.Length);
MethodInfo[] eventmethods = typeof(IEventHandlers).GetMethods();
MethodInfo eventmethod;
for(i = indx; i < args.Length; i++)
{
string arg = args[i];
if(arg == "-all")
{
flagAll = true;
continue;
}
if(arg == "-help")
{
m_log.Info("[YEngine]: xmr pev -all | <part-of-script-name> <event-name> <params...>");
return;
}
if(arg[0] == '-')
{
m_log.Error("[YEngine]: unknown option " + arg + ", try 'xmr pev -help'");
return;
}
for(j = 0; j < eventmethods.Length; j++)
{
eventmethod = eventmethods[j];
if(eventmethod.Name == arg)
goto gotevent;
}
selargs.Add(arg);
}
m_log.Error("[YEngine]: missing <event-name> <params...>, try 'xmr pev -help'");
return;
gotevent:
string eventname = eventmethod.Name;
StringBuilder sourcesb = new StringBuilder();
while(++i < args.Length)
{
sourcesb.Append(' ');
sourcesb.Append(args[i]);
}
string sourcest = sourcesb.ToString();
string sourcehash;
youveanerror = false;
Token t = TokenBegin.Construct("", null, ErrorMsg, sourcest, out sourcehash);
if(youveanerror)
return;
ParameterInfo[] paraminfos = eventmethod.GetParameters();
object[] paramvalues = new object[paraminfos.Length];
i = 0;
while(!((t = t.nextToken) is TokenEnd))
{
if(i >= paramvalues.Length)
{
ErrorMsg(t, "extra parameter(s)");
return;
}
paramvalues[i] = ParseParamValue(ref t);
if(paramvalues[i] == null)
return;
i++;
}
OpenSim.Region.ScriptEngine.Shared.EventParams eps =
new OpenSim.Region.ScriptEngine.Shared.EventParams(eventname, paramvalues, zeroDetectParams);
/*
* Scan instance list to find those that match selection criteria.
*/
if(!Monitor.TryEnter(m_InstancesDict, 100))
{
m_log.Error("[YEngine]: deadlock m_LockedDict=" + m_LockedDict);
return;
}
try
{
instances = new XMRInstance[m_InstancesDict.Count];
foreach(XMRInstance ins in m_InstancesDict.Values)
{
if(flagAll || InstanceMatchesArgs(ins, selargs.ToArray(), 0))
{
instances[numScripts++] = ins;
}
}
}
finally
{
Monitor.Exit(m_InstancesDict);
}
/*
* Post event to the matching instances.
*/
for(i = 0; i < numScripts; i++)
{
XMRInstance inst = instances[i];
m_log.Info("[YEngine]: post " + eventname + " to " + inst.m_DescName);
inst.PostEvent(eps);
}
}
private object ParseParamValue(ref Token token)
{
if(token is TokenFloat)
{
return new LSL_Float(((TokenFloat)token).val);
}
if(token is TokenInt)
{
return new LSL_Integer(((TokenInt)token).val);
}
if(token is TokenStr)
{
return new LSL_String(((TokenStr)token).val);
}
if(token is TokenKwCmpLT)
{
List<double> valuelist = new List<double>();
while(!((token = token.nextToken) is TokenKwCmpGT))
{
if(!(token is TokenKwComma))
{
object value = ParseParamValue(ref token);
if(value == null)
return null;
if(value is int)
value = (double)(int)value;
if(!(value is double))
{
ErrorMsg(token, "must be float or integer constant");
return null;
}
valuelist.Add((double)value);
}
else if(token.prevToken is TokenKwComma)
{
ErrorMsg(token, "missing constant");
return null;
}
}
double[] values = valuelist.ToArray();
switch(values.Length)
{
case 3:
{
return new LSL_Vector(values[0], values[1], values[2]);
}
case 4:
{
return new LSL_Rotation(values[0], values[1], values[2], values[3]);
}
default:
{
ErrorMsg(token, "not rotation or vector");
return null;
}
}
}
if(token is TokenKwBrkOpen)
{
List<object> valuelist = new List<object>();
while(!((token = token.nextToken) is TokenKwBrkClose))
{
if(!(token is TokenKwComma))
{
object value = ParseParamValue(ref token);
if(value == null)
return null;
valuelist.Add(value);
}
else if(token.prevToken is TokenKwComma)
{
ErrorMsg(token, "missing constant");
return null;
}
}
return new LSL_List(valuelist.ToArray());
}
if(token is TokenName)
{
FieldInfo field = typeof(OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass).GetField(((TokenName)token).val);
if((field != null) && field.IsPublic && (field.IsLiteral || (field.IsStatic && field.IsInitOnly)))
{
return field.GetValue(null);
}
}
ErrorMsg(token, "invalid constant");
return null;
}
private bool youveanerror;
private void ErrorMsg(Token token, string message)
{
youveanerror = true;
m_log.Info("[YEngine]: " + token.posn + " " + message);
}
private void XmrTestReset(string[] args, int indx)
{
bool flagAll = false;
int numScripts = 0;
XMRInstance[] instances;
if(args.Length <= indx)
{
m_log.Error("[YEngine]: must specify part of script name or -all for all scripts");
return;
}
/*
* Decode command line options.
*/
for(int i = indx; i < args.Length; i++)
{
if(args[i] == "-all")
{
flagAll = true;
continue;
}
if(args[i] == "-help")
{
m_log.Info("[YEngine]: xmr reset -all | <part-of-script-name>");
return;
}
if(args[i][0] == '-')
{
m_log.Error("[YEngine]: unknown option " + args[i] + ", try 'xmr reset -help'");
return;
}
}
/*
* Scan instance list to find those that match selection criteria.
*/
if(!Monitor.TryEnter(m_InstancesDict, 100))
{
m_log.Error("[YEngine]: deadlock m_LockedDict=" + m_LockedDict);
return;
}
try
{
instances = new XMRInstance[m_InstancesDict.Count];
foreach(XMRInstance ins in m_InstancesDict.Values)
{
if(flagAll || InstanceMatchesArgs(ins, args, indx))
{
instances[numScripts++] = ins;
}
}
}
finally
{
Monitor.Exit(m_InstancesDict);
}
/*
* Reset the instances as if someone clicked their "Reset" button.
*/
for(int i = 0; i < numScripts; i++)
{
XMRInstance inst = instances[i];
m_log.Info("[YEngine]: resetting " + inst.m_DescName);
inst.Reset();
}
}
private static int CompareInstancesByCPUTime(XMRInstance a, XMRInstance b)
{
if(a == null)
{
return (b == null) ? 0 : 1;
}
if(b == null)
{
return -1;
}
if(b.m_CPUTime < a.m_CPUTime)
return -1;
if(b.m_CPUTime > a.m_CPUTime)
return 1;
return 0;
}
private void LsQueue(TextWriter outFile, string name, XMRInstQueue queue, string[] args, int indx)
{
outFile.WriteLine("Queue " + name + ":");
lock(queue)
{
for(XMRInstance inst = queue.PeekHead(); inst != null; inst = inst.m_NextInst)
{
try
{
/*
* Try to print instance name.
*/
if(InstanceMatchesArgs(inst, args, indx))
{
outFile.WriteLine(" " + inst.ItemID.ToString() + " " + inst.m_DescName);
}
}
catch(Exception e)
{
/*
* Sometimes there are instances in the queue that are disposed.
*/
outFile.WriteLine(" " + inst.ItemID.ToString() + " " + inst.m_DescName + ": " + e.Message);
}
}
}
}
private bool InstanceMatchesArgs(XMRInstance ins, string[] args, int indx)
{
bool hadSomethingToCompare = false;
for(int i = indx; i < args.Length; i++)
{
if(args[i][0] != '-')
{
hadSomethingToCompare = true;
if(ins.m_DescName.Contains(args[i]))
return true;
if(ins.ItemID.ToString().Contains(args[i]))
return true;
if(ins.AssetID.ToString().Contains(args[i]))
return true;
}
}
return !hadSomethingToCompare;
}
}
/**
* @brief Make m_log.Info look like a text writer.
*/
public class LogInfoTextWriter: TextWriter
{
private StringBuilder sb = new StringBuilder();
private ILog m_log;
public LogInfoTextWriter(ILog m_log)
{
this.m_log = m_log;
}
public override void Write(char c)
{
if(c == '\n')
{
m_log.Info("[YEngine]: " + sb.ToString());
sb.Remove(0, sb.Length);
}
else
{
sb.Append(c);
}
}
public override void Close()
{
}
public override Encoding Encoding
{
get
{
return Encoding.UTF8;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -45,19 +45,19 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
/// <summary> /// <summary>
/// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it. /// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it.
/// </summary> /// </summary>
public partial class XMREngine public partial class Yengine
{ {
public static readonly object[] zeroObjectArray = new object[0]; public static readonly object[] zeroObjectArray = new object[0];
public static readonly object[] oneObjectArrayOne = new object[1] { 1 }; public static readonly object[] oneObjectArrayOne = new object[1] { 1 };
private void InitEvents() private void InitEvents()
{ {
m_log.Info("[XMREngine] Hooking up to server events"); m_log.Info("[YEngine] Hooking up to server events");
this.World.EventManager.OnAttach += attach; this.World.EventManager.OnAttach += attach;
this.World.EventManager.OnObjectGrab += touch_start; this.World.EventManager.OnObjectGrab += touch_start;
this.World.EventManager.OnObjectGrabbing += touch; this.World.EventManager.OnObjectGrabbing += touch;
@ -76,10 +76,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
this.World.EventManager.OnScriptLandColliderStart += land_collision_start; this.World.EventManager.OnScriptLandColliderStart += land_collision_start;
this.World.EventManager.OnScriptLandColliding += land_collision; this.World.EventManager.OnScriptLandColliding += land_collision;
this.World.EventManager.OnScriptLandColliderEnd += land_collision_end; this.World.EventManager.OnScriptLandColliderEnd += land_collision_end;
IMoneyModule money=this.World.RequestModuleInterface<IMoneyModule>(); IMoneyModule money = this.World.RequestModuleInterface<IMoneyModule>();
if (money != null) if(money != null)
{ {
money.OnObjectPaid+=HandleObjectPaid; money.OnObjectPaid += HandleObjectPaid;
} }
} }
@ -106,15 +106,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
SceneObjectPart part = SceneObjectPart part =
this.World.GetSceneObjectPart(objectID); this.World.GetSceneObjectPart(objectID);
if (part == null) if(part == null)
return; return;
if ((part.ScriptEvents & scriptEvents.money) == 0) if((part.ScriptEvents & scriptEvents.money) == 0)
part = part.ParentGroup.RootPart; part = part.ParentGroup.RootPart;
Verbose ("Paid: " + objectID + " from " + agentID + ", amount " + amount); Verbose("Paid: " + objectID + " from " + agentID + ", amount " + amount);
if (part != null) if(part != null)
{ {
money(part.LocalId, agentID, amount, det); money(part.LocalId, agentID, amount, det);
} }
@ -141,7 +141,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
touches(localID, originalID, offsetPos, remoteClient, surfaceArgs, "touch"); touches(localID, originalID, offsetPos, remoteClient, surfaceArgs, "touch");
} }
private static Vector3 zeroVec3 = new Vector3(0,0,0); private static Vector3 zeroVec3 = new Vector3(0, 0, 0);
public void touch_end(uint localID, uint originalID, IClientAPI remoteClient, public void touch_end(uint localID, uint originalID, IClientAPI remoteClient,
SurfaceTouchEventArgs surfaceArgs) SurfaceTouchEventArgs surfaceArgs)
{ {
@ -152,10 +152,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs, string eventname) IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs, string eventname)
{ {
SceneObjectPart part; SceneObjectPart part;
if (originalID == 0) { if(originalID == 0)
{
part = this.World.GetSceneObjectPart(localID); part = this.World.GetSceneObjectPart(localID);
if (part == null) return; if(part == null)
} else { return;
}
else
{
part = this.World.GetSceneObjectPart(originalID); part = this.World.GetSceneObjectPart(originalID);
} }
@ -167,7 +171,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
offsetPos.Z); offsetPos.Z);
det.LinkNum = part.LinkNum; det.LinkNum = part.LinkNum;
if (surfaceArgs != null) { if(surfaceArgs != null)
{
det.SurfaceTouchArgs = surfaceArgs; det.SurfaceTouchArgs = surfaceArgs;
} }
@ -182,7 +187,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
int ch = (int)change; int ch = (int)change;
// Add to queue for all scripts in localID, Object pass change. // Add to queue for all scripts in localID, Object pass change.
this.PostObjectEvent(localID, new EventParams( this.PostObjectEvent(localID, new EventParams(
"changed",new object[] { ch }, "changed", new object[] { ch },
zeroDetectParams)); zeroDetectParams));
} }
@ -216,15 +221,17 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private void collisions(uint localID, ColliderArgs col, string eventname) private void collisions(uint localID, ColliderArgs col, string eventname)
{ {
int dc = col.Colliders.Count; int dc = col.Colliders.Count;
if (dc > 0) { if(dc > 0)
{
DetectParams[] det = new DetectParams[dc]; DetectParams[] det = new DetectParams[dc];
int i = 0; int i = 0;
foreach (DetectedObject detobj in col.Colliders) { foreach(DetectedObject detobj in col.Colliders)
{
DetectParams d = new DetectParams(); DetectParams d = new DetectParams();
det[i++] = d; det[i++] = d;
d.Key = detobj.keyUUID; d.Key = detobj.keyUUID;
d.Populate (this.World); d.Populate(this.World);
/* not done by XEngine... /* not done by XEngine...
d.Position = detobj.posVector; d.Position = detobj.posVector;
@ -257,7 +264,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private void land_collisions(uint localID, ColliderArgs col, string eventname) private void land_collisions(uint localID, ColliderArgs col, string eventname)
{ {
foreach (DetectedObject detobj in col.Colliders) { foreach(DetectedObject detobj in col.Colliders)
{
LSL_Vector vec = new LSL_Vector(detobj.posVector.X, LSL_Vector vec = new LSL_Vector(detobj.posVector.X,
detobj.posVector.Y, detobj.posVector.Y,
detobj.posVector.Z); detobj.posVector.Z);
@ -274,7 +282,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public void control(UUID itemID, UUID agentID, uint held, uint change) public void control(UUID itemID, UUID agentID, uint held, uint change)
{ {
this.PostScriptEvent(itemID, new EventParams( this.PostScriptEvent(itemID, new EventParams(
"control",new object[] { "control", new object[] {
agentID.ToString(), agentID.ToString(),
(int)held, (int)held,
(int)change}, (int)change},
@ -285,7 +293,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
string address, string subject, string message, int numLeft) string address, string subject, string message, int numLeft)
{ {
this.PostObjectEvent(localID, new EventParams( this.PostObjectEvent(localID, new EventParams(
"email",new object[] { "email", new object[] {
timeSent, timeSent,
address, address,
subject, subject,
@ -308,7 +316,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public void not_at_target(uint localID) public void not_at_target(uint localID)
{ {
this.PostObjectEvent(localID, new EventParams( this.PostObjectEvent(localID, new EventParams(
"not_at_target",zeroObjectArray, "not_at_target", zeroObjectArray,
zeroDetectParams)); zeroDetectParams));
} }
@ -331,7 +339,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public void not_at_rot_target(uint localID) public void not_at_rot_target(uint localID)
{ {
this.PostObjectEvent(localID, new EventParams( this.PostObjectEvent(localID, new EventParams(
"not_at_rot_target",zeroObjectArray, "not_at_rot_target", zeroObjectArray,
zeroDetectParams)); zeroDetectParams));
} }
@ -340,7 +348,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public void attach(uint localID, UUID itemID, UUID avatar) public void attach(uint localID, UUID itemID, UUID avatar)
{ {
this.PostObjectEvent(localID, new EventParams( this.PostObjectEvent(localID, new EventParams(
"attach",new object[] { "attach", new object[] {
avatar.ToString() }, avatar.ToString() },
zeroDetectParams)); zeroDetectParams));
} }
@ -351,14 +359,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public void moving_start(uint localID) public void moving_start(uint localID)
{ {
this.PostObjectEvent(localID, new EventParams( this.PostObjectEvent(localID, new EventParams(
"moving_start",zeroObjectArray, "moving_start", zeroObjectArray,
zeroDetectParams)); zeroDetectParams));
} }
public void moving_end(uint localID) public void moving_end(uint localID)
{ {
this.PostObjectEvent(localID, new EventParams( this.PostObjectEvent(localID, new EventParams(
"moving_end",zeroObjectArray, "moving_end", zeroObjectArray,
zeroDetectParams)); zeroDetectParams));
} }

View File

@ -37,7 +37,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
/** /**
* One instance of this class for lsl base objects that take a variable * One instance of this class for lsl base objects that take a variable
@ -48,32 +48,35 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Note that the xmr arrays and script-defined objects have their own * Note that the xmr arrays and script-defined objects have their own
* heap tracking built in so do not need any of this stuff. * heap tracking built in so do not need any of this stuff.
*/ */
public class HeapTrackerBase { public class HeapTrackerBase
{
protected int usage; // num bytes used by object protected int usage; // num bytes used by object
protected XMRInstAbstract instance; // what script it is in protected XMRInstAbstract instance; // what script it is in
public HeapTrackerBase (XMRInstAbstract inst) public HeapTrackerBase(XMRInstAbstract inst)
{ {
if (inst == null) throw new ArgumentNullException ("inst"); if(inst == null)
throw new ArgumentNullException("inst");
instance = inst; instance = inst;
} }
~HeapTrackerBase () ~HeapTrackerBase()
{ {
usage = instance.UpdateHeapUse (usage, 0); usage = instance.UpdateHeapUse(usage, 0);
} }
} }
/** /**
* Wrapper around lists to keep track of how much memory they use. * Wrapper around lists to keep track of how much memory they use.
*/ */
public class HeapTrackerList : HeapTrackerBase { public class HeapTrackerList: HeapTrackerBase
private static FieldInfo listValueField = typeof (HeapTrackerList).GetField ("value"); {
private static MethodInfo listSaveMethod = typeof (HeapTrackerList).GetMethod ("Save"); private static FieldInfo listValueField = typeof(HeapTrackerList).GetField("value");
private static MethodInfo listSaveMethod = typeof(HeapTrackerList).GetMethod("Save");
public LSL_List value; public LSL_List value;
public HeapTrackerList (XMRInstAbstract inst) : base (inst) { } public HeapTrackerList(XMRInstAbstract inst) : base(inst) { }
// generate CIL code to pop the value from the CIL stack // generate CIL code to pop the value from the CIL stack
// input: // input:
@ -83,7 +86,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 'this' pointer popped from stack // 'this' pointer popped from stack
// new value popped from CIL stack // new value popped from CIL stack
// heap usage updated // heap usage updated
public static void GenPop (Token errorAt, ScriptMyILGen ilGen) public static void GenPop(Token errorAt, ScriptMyILGen ilGen)
{ {
ilGen.Emit(errorAt, OpCodes.Call, listSaveMethod); ilGen.Emit(errorAt, OpCodes.Call, listSaveMethod);
} }
@ -95,21 +98,21 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 'this' pointer popped from stack // 'this' pointer popped from stack
// value pushed on CIL stack replacing 'this' pointer // value pushed on CIL stack replacing 'this' pointer
// returns typeof value pushed on stack // returns typeof value pushed on stack
public static Type GenPush (Token errorAt, ScriptMyILGen ilGen) public static Type GenPush(Token errorAt, ScriptMyILGen ilGen)
{ {
ilGen.Emit (errorAt, OpCodes.Ldfld, listValueField); ilGen.Emit(errorAt, OpCodes.Ldfld, listValueField);
return typeof (LSL_List); return typeof(LSL_List);
} }
public void Save (LSL_List lis) public void Save(LSL_List lis)
{ {
int newuse = Size (lis); int newuse = Size(lis);
usage = instance.UpdateHeapUse (usage, newuse); usage = instance.UpdateHeapUse(usage, newuse);
value = lis; value = lis;
} }
//private static int counter = 5; //private static int counter = 5;
public static int Size (LSL_List lis) public static int Size(LSL_List lis)
{ {
// VS2017 in debug mode seems to have a problem running this statement quickly: // VS2017 in debug mode seems to have a problem running this statement quickly:
//SLOW: return (!typeof(LSL_List).IsValueType && (lis == null)) ? 0 : lis.Size; //SLOW: return (!typeof(LSL_List).IsValueType && (lis == null)) ? 0 : lis.Size;
@ -120,9 +123,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// VS2017 in debug mode seems content to run this quickly though: // VS2017 in debug mode seems content to run this quickly though:
try { try
{
return lis.Size; return lis.Size;
} catch { }
catch
{
return 0; return 0;
} }
} }
@ -131,9 +137,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* Wrapper around objects to keep track of how much memory they use. * Wrapper around objects to keep track of how much memory they use.
*/ */
public class HeapTrackerObject : HeapTrackerBase { public class HeapTrackerObject: HeapTrackerBase
private static FieldInfo objectValueField = typeof (HeapTrackerObject).GetField ("value"); {
private static MethodInfo objectSaveMethod = typeof (HeapTrackerObject).GetMethod ("Save"); private static FieldInfo objectValueField = typeof(HeapTrackerObject).GetField("value");
private static MethodInfo objectSaveMethod = typeof(HeapTrackerObject).GetMethod("Save");
public const int HT_CHAR = 2; public const int HT_CHAR = 2;
public const int HT_DELE = 8; public const int HT_DELE = 8;
@ -146,7 +153,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public object value; public object value;
public HeapTrackerObject (XMRInstAbstract inst) : base (inst) { } public HeapTrackerObject(XMRInstAbstract inst) : base(inst) { }
// generate CIL code to pop the value from the CIL stack // generate CIL code to pop the value from the CIL stack
// input: // input:
@ -156,7 +163,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 'this' pointer popped from stack // 'this' pointer popped from stack
// new value popped from CIL stack // new value popped from CIL stack
// heap usage updated // heap usage updated
public static void GenPop (Token errorAt, ScriptMyILGen ilGen) public static void GenPop(Token errorAt, ScriptMyILGen ilGen)
{ {
ilGen.Emit(errorAt, OpCodes.Call, objectSaveMethod); ilGen.Emit(errorAt, OpCodes.Call, objectSaveMethod);
} }
@ -168,67 +175,88 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 'this' pointer popped from stack // 'this' pointer popped from stack
// value pushed on CIL stack replacing 'this' pointer // value pushed on CIL stack replacing 'this' pointer
// returns typeof value pushed on stack // returns typeof value pushed on stack
public static Type GenPush (Token errorAt, ScriptMyILGen ilGen) public static Type GenPush(Token errorAt, ScriptMyILGen ilGen)
{ {
ilGen.Emit (errorAt, OpCodes.Ldfld, objectValueField); ilGen.Emit(errorAt, OpCodes.Ldfld, objectValueField);
return typeof (object); return typeof(object);
} }
public void Save (object obj) public void Save(object obj)
{ {
int newuse = Size (obj); int newuse = Size(obj);
usage = instance.UpdateHeapUse (usage, newuse); usage = instance.UpdateHeapUse(usage, newuse);
value = obj; value = obj;
} }
// public so it can be used by XMRArray // public so it can be used by XMRArray
public static int Size (object obj) public static int Size(object obj)
{ {
if (obj == null) return 0; if(obj == null)
return 0;
if (obj is char) return HT_CHAR; if(obj is char)
if (obj is Delegate) return HT_DELE; return HT_CHAR;
if (obj is double) return HT_DOUB; if(obj is Delegate)
if (obj is float) return HT_SING; return HT_DELE;
if (obj is int) return HT_INT; if(obj is double)
if (obj is LSL_Float) return HT_SFLT; return HT_DOUB;
if (obj is LSL_Integer) return HT_INT; if(obj is float)
if (obj is LSL_List) return ((LSL_List)obj).Size; return HT_SING;
if (obj is LSL_Rotation) return HT_ROT; if(obj is int)
if (obj is LSL_String) return ((LSL_String)obj).m_string.Length * HT_CHAR; return HT_INT;
if (obj is LSL_Vector) return HT_VEC; if(obj is LSL_Float)
if (obj is string) return ((string)obj).Length * HT_CHAR; return HT_SFLT;
if (obj is XMR_Array) return 0; if(obj is LSL_Integer)
if (obj is XMRArrayListKey) return ((XMRArrayListKey)obj).Size; return HT_INT;
if (obj is XMRSDTypeClObj) return 0; if(obj is LSL_List)
return ((LSL_List)obj).Size;
if(obj is LSL_Rotation)
return HT_ROT;
if(obj is LSL_String)
return ((LSL_String)obj).m_string.Length * HT_CHAR;
if(obj is LSL_Vector)
return HT_VEC;
if(obj is string)
return ((string)obj).Length * HT_CHAR;
if(obj is XMR_Array)
return 0;
if(obj is XMRArrayListKey)
return ((XMRArrayListKey)obj).Size;
if(obj is XMRSDTypeClObj)
return 0;
if (obj is Array) { if(obj is Array)
{
Array ar = (Array)obj; Array ar = (Array)obj;
int len = ar.Length; int len = ar.Length;
if (len == 0) return 0; if(len == 0)
Type et = ar.GetType ().GetElementType (); return 0;
if (et.IsValueType) return Size (ar.GetValue (0)) * len; Type et = ar.GetType().GetElementType();
if(et.IsValueType)
return Size(ar.GetValue(0)) * len;
int size = 0; int size = 0;
for (int i = 0; i < len; i ++) { for(int i = 0; i < len; i++)
size += Size (ar.GetValue (i)); {
size += Size(ar.GetValue(i));
} }
return size; return size;
} }
throw new Exception ("unknown size of type " + obj.GetType ().Name); throw new Exception("unknown size of type " + obj.GetType().Name);
} }
} }
/** /**
* Wrapper around strings to keep track of how much memory they use. * Wrapper around strings to keep track of how much memory they use.
*/ */
public class HeapTrackerString : HeapTrackerBase { public class HeapTrackerString: HeapTrackerBase
private static FieldInfo stringValueField = typeof (HeapTrackerString).GetField ("value"); {
private static MethodInfo stringSaveMethod = typeof (HeapTrackerString).GetMethod ("Save"); private static FieldInfo stringValueField = typeof(HeapTrackerString).GetField("value");
private static MethodInfo stringSaveMethod = typeof(HeapTrackerString).GetMethod("Save");
public string value; public string value;
public HeapTrackerString (XMRInstAbstract inst) : base (inst) { } public HeapTrackerString(XMRInstAbstract inst) : base(inst) { }
// generate CIL code to pop the value from the CIL stack // generate CIL code to pop the value from the CIL stack
// input: // input:
@ -238,9 +266,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 'this' pointer popped from stack // 'this' pointer popped from stack
// new value popped from CIL stack // new value popped from CIL stack
// heap usage updated // heap usage updated
public static void GenPop (Token errorAt, ScriptMyILGen ilGen) public static void GenPop(Token errorAt, ScriptMyILGen ilGen)
{ {
ilGen.Emit (errorAt, OpCodes.Call, stringSaveMethod); ilGen.Emit(errorAt, OpCodes.Call, stringSaveMethod);
} }
// generate CIL code to push the value on the CIL stack // generate CIL code to push the value on the CIL stack
@ -250,20 +278,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 'this' pointer popped from stack // 'this' pointer popped from stack
// value pushed on CIL stack replacing 'this' pointer // value pushed on CIL stack replacing 'this' pointer
// returns typeof value pushed on stack // returns typeof value pushed on stack
public static Type GenPush (Token errorAt, ScriptMyILGen ilGen) public static Type GenPush(Token errorAt, ScriptMyILGen ilGen)
{ {
ilGen.Emit (errorAt, OpCodes.Ldfld, stringValueField); ilGen.Emit(errorAt, OpCodes.Ldfld, stringValueField);
return typeof (string); return typeof(string);
} }
public void Save (string str) public void Save(string str)
{ {
int newuse = Size (str); int newuse = Size(str);
usage = instance.UpdateHeapUse (usage, newuse); usage = instance.UpdateHeapUse(usage, newuse);
value = str; value = str;
} }
public static int Size (string str) public static int Size(string str)
{ {
return (str == null) ? 0 : str.Length * HeapTrackerObject.HT_CHAR; return (str == null) ? 0 : str.Length * HeapTrackerObject.HT_CHAR;
} }

File diff suppressed because it is too large Load Diff

View File

@ -42,13 +42,13 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
/****************************************************\ /****************************************************\
* This file contains routines called by scripts. * * This file contains routines called by scripts. *
\****************************************************/ \****************************************************/
public class XMRLSL_Api : LSL_Api public class XMRLSL_Api: LSL_Api
{ {
public AsyncCommandManager acm; public AsyncCommandManager acm;
private XMRInstance inst; private XMRInstance inst;
@ -83,7 +83,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* -2: no av granted perms * -2: no av granted perms
* -3: av not in region * -3: av not in region
*/ */
/* engines should not have own API /* engines should not have own API
public int xmrSeatAvatar (bool owner) public int xmrSeatAvatar (bool owner)
{ {
// Get avatar to be seated and make sure they have given us ANIMATION permission // Get avatar to be seated and make sure they have given us ANIMATION permission
@ -114,7 +114,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
presence.HandleAgentRequestSit (null, UUID.Zero, m_host.UUID, OpenMetaverse.Vector3.Zero); presence.HandleAgentRequestSit (null, UUID.Zero, m_host.UUID, OpenMetaverse.Vector3.Zero);
return 0; return 0;
} }
*/ */
/** /**
* @brief llTeleportAgent() is broken in that if you pass it a landmark, * @brief llTeleportAgent() is broken in that if you pass it a landmark,
* it still subjects the position to spawn points, as it always * it still subjects the position to spawn points, as it always
@ -125,7 +125,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @param landmark = inventory name or UUID of a landmark object * @param landmark = inventory name or UUID of a landmark object
* @param lookat = looking direction after teleport * @param lookat = looking direction after teleport
*/ */
/* engines should not have own API /* engines should not have own API
public void xmrTeleportAgent2Landmark (string agent, string landmark, LSL_Vector lookat) public void xmrTeleportAgent2Landmark (string agent, string landmark, LSL_Vector lookat)
{ {
// find out about agent to be teleported // find out about agent to be teleported
@ -169,14 +169,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
lookat, lookat,
(uint)TeleportFlags.ViaLandmark); (uint)TeleportFlags.ViaLandmark);
} }
*/ */
/** /**
* @brief Allow any member of group given by config SetParcelMusicURLGroup to set music URL. * @brief Allow any member of group given by config SetParcelMusicURLGroup to set music URL.
* Code modelled after llSetParcelMusicURL(). * Code modelled after llSetParcelMusicURL().
* @param newurl = new URL to set (or "" to leave it alone) * @param newurl = new URL to set (or "" to leave it alone)
* @returns previous URL string * @returns previous URL string
*/ */
/* engines should not have own API /* engines should not have own API
public string xmrSetParcelMusicURLGroup (string newurl) public string xmrSetParcelMusicURLGroup (string newurl)
{ {
string groupname = m_ScriptEngine.Config.GetString ("SetParcelMusicURLGroup", ""); string groupname = m_ScriptEngine.Config.GetString ("SetParcelMusicURLGroup", "");
@ -198,7 +198,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
if ((newurl != null) && (newurl != "")) land.SetMusicUrl (newurl); if ((newurl != null) && (newurl != "")) land.SetMusicUrl (newurl);
return oldurl; return oldurl;
} }
*/ */
} }
public partial class XMRInstance public partial class XMRInstance
@ -222,9 +222,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public DetectParams GetDetectParams(int number) public DetectParams GetDetectParams(int number)
{ {
DetectParams dp = null; DetectParams dp = null;
if ((number >= 0) && (m_DetectParams != null) && (number < m_DetectParams.Length)) { if((number >= 0) && (m_DetectParams != null) && (number < m_DetectParams.Length))
dp = m_DetectParams[number]; dp = m_DetectParams[number];
}
return dp; return dp;
} }
@ -236,7 +236,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public void Die() public void Die()
{ {
// llDie doesn't work in attachments! // llDie doesn't work in attachments!
if (m_Part.ParentGroup.IsAttachment || m_DetachQuantum > 0) if(m_Part.ParentGroup.IsAttachment || m_DetachQuantum > 0)
return; return;
throw new ScriptDieException(); throw new ScriptDieException();
@ -247,8 +247,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
public void Sleep(int ms) public void Sleep(int ms)
{ {
lock (m_QueueLock) { lock(m_QueueLock)
{
/* /*
* Say how long to sleep. * Say how long to sleep.
*/ */
@ -306,12 +306,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* be returned by xmrEventDequeue, to let the runtime know that the script is capable * be returned by xmrEventDequeue, to let the runtime know that the script is capable
* of processing that event type. Otherwise, the event may not be queued to the script. * of processing that event type. Otherwise, the event may not be queued to the script.
*/ */
private static LSL_List emptyList = new LSL_List (new object[0]); private static LSL_List emptyList = new LSL_List(new object[0]);
public override LSL_List xmrEventDequeue (double timeout, int returnMask1, int returnMask2, public override LSL_List xmrEventDequeue(double timeout, int returnMask1, int returnMask2,
int backgroundMask1, int backgroundMask2) int backgroundMask1, int backgroundMask2)
{ {
DateTime sleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds (timeout * 1000.0); DateTime sleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds(timeout * 1000.0);
EventParams evt = null; EventParams evt = null;
int callNo, evc2; int callNo, evc2;
int evc1 = 0; int evc1 = 0;
@ -324,45 +324,47 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
callNo = -1; callNo = -1;
try try
{ {
if (callMode == CallMode_NORMAL) goto findevent; if(callMode == CallMode_NORMAL)
goto findevent;
/* /*
* Stack frame is being restored as saved via CheckRun...(). * Stack frame is being restored as saved via CheckRun...().
* Restore necessary values then jump to __call<n> label to resume processing. * Restore necessary values then jump to __call<n> label to resume processing.
*/ */
sv = RestoreStackFrame ("xmrEventDequeue", out callNo); sv = RestoreStackFrame("xmrEventDequeue", out callNo);
sleepUntil = DateTime.Parse ((string)sv[0]); sleepUntil = DateTime.Parse((string)sv[0]);
returnMask1 = (int)sv[1]; returnMask1 = (int)sv[1];
returnMask2 = (int)sv[2]; returnMask2 = (int)sv[2];
mask1 = (int)sv[3]; mask1 = (int)sv[3];
mask2 = (int)sv[4]; mask2 = (int)sv[4];
switch (callNo) switch(callNo)
{ {
case 0: goto __call0; case 0:
goto __call0;
case 1: case 1:
{ {
evc1 = (int)sv[5]; evc1 = (int)sv[5];
evc = (ScriptEventCode)(int)sv[6]; evc = (ScriptEventCode)(int)sv[6];
DetectParams[] detprms = ObjArrToDetPrms ((object[])sv[7]); DetectParams[] detprms = ObjArrToDetPrms((object[])sv[7]);
object[] ehargs = (object[])sv[8]; object[] ehargs = (object[])sv[8];
evt = new EventParams (evc.ToString (), ehargs, detprms); evt = new EventParams(evc.ToString(), ehargs, detprms);
goto __call1; goto __call1;
} }
} }
throw new ScriptBadCallNoException (callNo); throw new ScriptBadCallNoException(callNo);
/* /*
* Find first event that matches either the return or background masks. * Find first event that matches either the return or background masks.
*/ */
findevent: findevent:
Monitor.Enter (m_QueueLock); Monitor.Enter(m_QueueLock);
for (lln = m_EventQueue.First; lln != null; lln = lln.Next) for(lln = m_EventQueue.First; lln != null; lln = lln.Next)
{ {
evt = lln.Value; evt = lln.Value;
evc = (ScriptEventCode)Enum.Parse (typeof (ScriptEventCode), evt.EventName); evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), evt.EventName);
evc1 = (int)evc; evc1 = (int)evc;
evc2 = evc1 - 32; evc2 = evc1 - 32;
if ((((uint)evc1 < (uint)32) && (((mask1 >> evc1) & 1) != 0)) || if((((uint)evc1 < (uint)32) && (((mask1 >> evc1) & 1) != 0)) ||
(((uint)evc2 < (uint)32) && (((mask2 >> evc2) & 1) != 0))) (((uint)evc2 < (uint)32) && (((mask2 >> evc2) & 1) != 0)))
goto remfromq; goto remfromq;
} }
@ -373,51 +375,50 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
m_SleepUntil = sleepUntil; m_SleepUntil = sleepUntil;
m_SleepEventMask1 = mask1; m_SleepEventMask1 = mask1;
m_SleepEventMask2 = mask2; m_SleepEventMask2 = mask2;
Monitor.Exit (m_QueueLock); Monitor.Exit(m_QueueLock);
suspendOnCheckRunTemp = true; suspendOnCheckRunTemp = true;
callNo = 0; callNo = 0;
__call0: __call0:
CheckRunQuick (); CheckRunQuick();
goto checktmo; goto checktmo;
/* /*
* Found one, remove it from queue. * Found one, remove it from queue.
*/ */
remfromq: remfromq:
m_EventQueue.Remove (lln); m_EventQueue.Remove(lln);
if ((uint)evc1 < (uint)m_EventCounts.Length) if((uint)evc1 < (uint)m_EventCounts.Length)
m_EventCounts[evc1] --; m_EventCounts[evc1]--;
Monitor.Exit (m_QueueLock); Monitor.Exit(m_QueueLock);
m_InstEHEvent ++; m_InstEHEvent++;
/* /*
* See if returnable or background event. * See if returnable or background event.
*/ */
if ((((uint)evc1 < (uint)32) && (((returnMask1 >> evc1) & 1) != 0)) || if((((uint)evc1 < (uint)32) && (((returnMask1 >> evc1) & 1) != 0)) ||
(((uint)evc2 < (uint)32) && (((returnMask2 >> evc2) & 1) != 0))) (((uint)evc2 < (uint)32) && (((returnMask2 >> evc2) & 1) != 0)))
{ {
/* /*
* Returnable event, return its parameters in a list. * Returnable event, return its parameters in a list.
* Also set the detect parameters to what the event has. * Also set the detect parameters to what the event has.
*/ */
int plen = evt.Params.Length; int plen = evt.Params.Length;
object[] plist = new object[plen+1]; object[] plist = new object[plen + 1];
plist[0] = (LSL_Integer)evc1; plist[0] = (LSL_Integer)evc1;
for (int i = 0; i < plen;) for(int i = 0; i < plen;)
{ {
object ob = evt.Params[i]; object ob = evt.Params[i];
if (ob is int) if(ob is int)
ob = (LSL_Integer)(int)ob; ob = (LSL_Integer)(int)ob;
else if (ob is double) else if(ob is double)
ob = (LSL_Float)(double)ob; ob = (LSL_Float)(double)ob;
else if (ob is string) else if(ob is string)
ob = (LSL_String)(string)ob; ob = (LSL_String)(string)ob;
plist[++i] = ob; plist[++i] = ob;
} }
m_DetectParams = evt.DetectParams; m_DetectParams = evt.DetectParams;
return new LSL_List (plist); return new LSL_List(plist);
} }
/* /*
@ -426,8 +427,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
callNo = 1; callNo = 1;
__call1: __call1:
ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode,evc1]; ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode, evc1];
if (seh == null) if(seh == null)
goto checktmo; goto checktmo;
DetectParams[] saveDetParams = this.m_DetectParams; DetectParams[] saveDetParams = this.m_DetectParams;
@ -440,20 +441,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
try try
{ {
seh (this); seh(this);
} }
finally finally
{ {
m_DetectParams = saveDetParams; this.m_DetectParams = saveDetParams;
ehArgs = saveEHArgs; this.ehArgs = saveEHArgs;
eventCode = saveEventCode; this.eventCode = saveEventCode;
} }
/* /*
* Keep waiting until we find a returnable event or timeout. * Keep waiting until we find a returnable event or timeout.
*/ */
checktmo: checktmo:
if (DateTime.UtcNow < sleepUntil) if(DateTime.UtcNow < sleepUntil)
goto findevent; goto findevent;
/* /*
@ -463,7 +464,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
} }
finally finally
{ {
if (callMode != CallMode_NORMAL) if(callMode != CallMode_NORMAL)
{ {
/* /*
@ -471,17 +472,17 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Save everything we need at the __call<n> labels so we can restore it * Save everything we need at the __call<n> labels so we can restore it
* when we need to. * when we need to.
*/ */
sv = CaptureStackFrame ("xmrEventDequeue", callNo, 9); sv = CaptureStackFrame("xmrEventDequeue", callNo, 9);
sv[0] = sleepUntil.ToString (); // needed at __call0,__call1 sv[0] = sleepUntil.ToString(); // needed at __call0,__call1
sv[1] = returnMask1; // needed at __call0,__call1 sv[1] = returnMask1; // needed at __call0,__call1
sv[2] = returnMask2; // needed at __call0,__call1 sv[2] = returnMask2; // needed at __call0,__call1
sv[3] = mask1; // needed at __call0,__call1 sv[3] = mask1; // needed at __call0,__call1
sv[4] = mask2; // needed at __call0,__call1 sv[4] = mask2; // needed at __call0,__call1
if (callNo == 1) if(callNo == 1)
{ {
sv[5] = evc1; // needed at __call1 sv[5] = evc1; // needed at __call1
sv[6] = (int)evc; // needed at __call1 sv[6] = (int)evc; // needed at __call1
sv[7] = DetPrmsToObjArr (evt.DetectParams); // needed at __call1 sv[7] = DetPrmsToObjArr(evt.DetectParams); // needed at __call1
sv[8] = evt.Params; // needed at __call1 sv[8] = evt.Params; // needed at __call1
} }
} }
@ -495,16 +496,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* are as currently set for the script (use xmrEventLoadDets to set how * are as currently set for the script (use xmrEventLoadDets to set how
* you want them to be different). * you want them to be different).
*/ */
public override void xmrEventEnqueue (LSL_List ev) public override void xmrEventEnqueue(LSL_List ev)
{ {
object[] data = ev.Data; object[] data = ev.Data;
ScriptEventCode evc = (ScriptEventCode)ListInt (data[0]); ScriptEventCode evc = (ScriptEventCode)ListInt(data[0]);
int nargs = data.Length - 1; int nargs = data.Length - 1;
object[] args = new object[nargs]; object[] args = new object[nargs];
Array.Copy (data, 1, args, 0, nargs); Array.Copy(data, 1, args, 0, nargs);
PostEvent (new EventParams (evc.ToString (), args, m_DetectParams)); PostEvent(new EventParams(evc.ToString(), args, m_DetectParams));
} }
/** /**
@ -513,19 +514,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
private const int saveDPVer = 1; private const int saveDPVer = 1;
public override LSL_List xmrEventSaveDets () public override LSL_List xmrEventSaveDets()
{ {
object[] obs = DetPrmsToObjArr (m_DetectParams); object[] obs = DetPrmsToObjArr(m_DetectParams);
return new LSL_List (obs); return new LSL_List(obs);
} }
private static object[] DetPrmsToObjArr (DetectParams[] dps) private static object[] DetPrmsToObjArr(DetectParams[] dps)
{ {
int len = dps.Length; int len = dps.Length;
object[] obs = new object[len*16+1]; object[] obs = new object[len * 16 + 1];
int j = 0; int j = 0;
obs[j++] = (LSL_Integer)saveDPVer; obs[j++] = (LSL_Integer)saveDPVer;
for (int i = 0; i < len; i ++) for(int i = 0; i < len; i++)
{ {
DetectParams dp = dps[i]; DetectParams dp = dps[i];
obs[j++] = (LSL_String)dp.Key.ToString(); // UUID obs[j++] = (LSL_String)dp.Key.ToString(); // UUID
@ -548,54 +549,52 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
return obs; return obs;
} }
/** /**
* @brief Load current detect params from a list * @brief Load current detect params from a list
* @param dpList = as returned by xmrEventSaveDets() * @param dpList = as returned by xmrEventSaveDets()
*/ */
public override void xmrEventLoadDets (LSL_List dpList) public override void xmrEventLoadDets(LSL_List dpList)
{ {
m_DetectParams = ObjArrToDetPrms (dpList.Data); m_DetectParams = ObjArrToDetPrms(dpList.Data);
} }
private static DetectParams[] ObjArrToDetPrms (object[] objs) private static DetectParams[] ObjArrToDetPrms(object[] objs)
{ {
int j = 0; int j = 0;
if ((objs.Length % 16 != 1) || (ListInt (objs[j++]) != saveDPVer)) if((objs.Length % 16 != 1) || (ListInt(objs[j++]) != saveDPVer))
throw new Exception ("invalid detect param format"); throw new Exception("invalid detect param format");
int len = objs.Length / 16; int len = objs.Length / 16;
DetectParams[] dps = new DetectParams[len]; DetectParams[] dps = new DetectParams[len];
for (int i = 0; i < len; i ++) for(int i = 0; i < len; i++)
{ {
DetectParams dp = new DetectParams (); DetectParams dp = new DetectParams();
dp.Key = new UUID (ListStr (objs[j++])); dp.Key = new UUID(ListStr(objs[j++]));
dp.OffsetPos = (LSL_Vector)objs[j++]; dp.OffsetPos = (LSL_Vector)objs[j++];
dp.LinkNum = ListInt (objs[j++]); dp.LinkNum = ListInt(objs[j++]);
dp.Group = new UUID (ListStr (objs[j++])); dp.Group = new UUID(ListStr(objs[j++]));
dp.Name = ListStr (objs[j++]); dp.Name = ListStr(objs[j++]);
dp.Owner = new UUID (ListStr (objs[j++])); dp.Owner = new UUID(ListStr(objs[j++]));
dp.Position = (LSL_Vector)objs[j++]; dp.Position = (LSL_Vector)objs[j++];
dp.Rotation = (LSL_Rotation)objs[j++]; dp.Rotation = (LSL_Rotation)objs[j++];
dp.Type = ListInt (objs[j++]); dp.Type = ListInt(objs[j++]);
dp.Velocity = (LSL_Vector)objs[j++]; dp.Velocity = (LSL_Vector)objs[j++];
SurfaceTouchEventArgs stea = new SurfaceTouchEventArgs (); SurfaceTouchEventArgs stea = new SurfaceTouchEventArgs();
stea.STCoord = LSLVec2OMVec ((LSL_Vector)objs[j++]); stea.STCoord = LSLVec2OMVec((LSL_Vector)objs[j++]);
stea.Normal = LSLVec2OMVec ((LSL_Vector)objs[j++]); stea.Normal = LSLVec2OMVec((LSL_Vector)objs[j++]);
stea.Binormal = LSLVec2OMVec ((LSL_Vector)objs[j++]); stea.Binormal = LSLVec2OMVec((LSL_Vector)objs[j++]);
stea.Position = LSLVec2OMVec ((LSL_Vector)objs[j++]); stea.Position = LSLVec2OMVec((LSL_Vector)objs[j++]);
stea.UVCoord = LSLVec2OMVec ((LSL_Vector)objs[j++]); stea.UVCoord = LSLVec2OMVec((LSL_Vector)objs[j++]);
stea.FaceIndex = ListInt (objs[j++]); stea.FaceIndex = ListInt(objs[j++]);
dp.SurfaceTouchArgs = stea; dp.SurfaceTouchArgs = stea;
dps[i] = dp; dps[i] = dp;
} }
return dps; return dps;
} }
@ -623,21 +622,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/* /*
* Clear out any old events from the queue. * Clear out any old events from the queue.
*/ */
lock (m_QueueLock) lock(m_QueueLock)
{ {
m_EventQueue.Clear(); m_EventQueue.Clear();
for (int i = m_EventCounts.Length; -- i >= 0;) for(int i = m_EventCounts.Length; --i >= 0;)
m_EventCounts[i] = 0; m_EventCounts[i] = 0;
} }
} }
/**
* @brief Script is calling xmrStackLeft().
*/
public override int xmrStackLeft ()
{
return microthread.StackLeft ();
}
} }
/** /**
@ -646,12 +637,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* handler. We don't want script-level try/catch to intercept * handler. We don't want script-level try/catch to intercept
* these so scripts can't interfere with the behavior. * these so scripts can't interfere with the behavior.
*/ */
public class ScriptResetException : Exception, IXMRUncatchable { } public class ScriptResetException: Exception, IXMRUncatchable
{
}
/** /**
* @brief Thrown by things like llDie() to unconditionally unwind as * @brief Thrown by things like llDie() to unconditionally unwind as
* script. We don't want script-level try/catch to intercept * script. We don't want script-level try/catch to intercept
* these so scripts can't interfere with the behavior. * these so scripts can't interfere with the behavior.
*/ */
public class ScriptDieException : Exception, IXMRUncatchable { } public class ScriptDieException: Exception, IXMRUncatchable
{
}
} }

View File

@ -26,7 +26,6 @@
*/ */
using System; using System;
using System.Threading;
using System.IO; using System.IO;
using System.Xml; using System.Xml;
using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared;
@ -41,7 +40,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
public partial class XMRInstance public partial class XMRInstance
{ {
@ -54,7 +53,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Create an XML element that gives the current state of the script. * @brief Create an XML element that gives the current state of the script.
* <ScriptState Engine="XMREngine" SourceHash=m_ObjCode.sourceHash Asset=m_Item.AssetID> * <ScriptState Engine="YEngine" SourceHash=m_ObjCode.sourceHash Asset=m_Item.AssetID>
* <Snapshot>globalsandstackdump</Snapshot> * <Snapshot>globalsandstackdump</Snapshot>
* <Running>m_Running</Running> * <Running>m_Running</Running>
* <DetectArray ... * <DetectArray ...
@ -71,18 +70,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// Change this to a 5 second timeout. If things do mess up, // Change this to a 5 second timeout. If things do mess up,
// we don't want to be stuck forever. // we don't want to be stuck forever.
// //
m_DetachReady.WaitOne (5000, false); m_DetachReady.WaitOne(5000, false);
XmlElement scriptStateN = doc.CreateElement("", "ScriptState", ""); XmlElement scriptStateN = doc.CreateElement("", "ScriptState", "");
scriptStateN.SetAttribute("Engine", m_Engine.ScriptEngineName); scriptStateN.SetAttribute("Engine", m_Engine.ScriptEngineName);
scriptStateN.SetAttribute("Asset", m_Item.AssetID.ToString()); scriptStateN.SetAttribute("Asset", m_Item.AssetID.ToString());
scriptStateN.SetAttribute ("SourceHash", m_ObjCode.sourceHash); scriptStateN.SetAttribute("SourceHash", m_ObjCode.sourceHash);
// Make sure we aren't executing part of the script so it stays // Make sure we aren't executing part of the script so it stays
// stable. Setting suspendOnCheckRun tells CheckRun() to suspend // stable. Setting suspendOnCheckRun tells CheckRun() to suspend
// and return out so RunOne() will release the lock asap. // and return out so RunOne() will release the lock asap.
suspendOnCheckRunHold = true; suspendOnCheckRunHold = true;
lock (m_RunLock) lock(m_RunLock)
{ {
m_RunOnePhase = "GetExecutionState enter"; m_RunOnePhase = "GetExecutionState enter";
CheckRunLockInvariants(true); CheckRunLockInvariants(true);
@ -96,19 +95,22 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
XmlElement snapshotN = doc.CreateElement("", "Snapshot", ""); XmlElement snapshotN = doc.CreateElement("", "Snapshot", "");
snapshotN.AppendChild(doc.CreateTextNode(snapshotString)); snapshotN.AppendChild(doc.CreateTextNode(snapshotString));
scriptStateN.AppendChild(snapshotN); scriptStateN.AppendChild(snapshotN);
m_RunOnePhase = "GetExecutionState B"; CheckRunLockInvariants(true); m_RunOnePhase = "GetExecutionState B";
CheckRunLockInvariants(true);
// "Running" says whether or not we are accepting new events. // "Running" says whether or not we are accepting new events.
XmlElement runningN = doc.CreateElement("", "Running", ""); XmlElement runningN = doc.CreateElement("", "Running", "");
runningN.AppendChild(doc.CreateTextNode(m_Running.ToString())); runningN.AppendChild(doc.CreateTextNode(m_Running.ToString()));
scriptStateN.AppendChild(runningN); scriptStateN.AppendChild(runningN);
m_RunOnePhase = "GetExecutionState C"; CheckRunLockInvariants(true); m_RunOnePhase = "GetExecutionState C";
CheckRunLockInvariants(true);
// "DoGblInit" says whether or not default:state_entry() will init global vars. // "DoGblInit" says whether or not default:state_entry() will init global vars.
XmlElement doGblInitN = doc.CreateElement("", "DoGblInit", ""); XmlElement doGblInitN = doc.CreateElement("", "DoGblInit", "");
doGblInitN.AppendChild(doc.CreateTextNode(doGblInit.ToString())); doGblInitN.AppendChild(doc.CreateTextNode(doGblInit.ToString()));
scriptStateN.AppendChild(doGblInitN); scriptStateN.AppendChild(doGblInitN);
m_RunOnePhase = "GetExecutionState D"; CheckRunLockInvariants(true); m_RunOnePhase = "GetExecutionState D";
CheckRunLockInvariants(true);
// More misc data. // More misc data.
XmlNode permissionsN = doc.CreateElement("", "Permissions", ""); XmlNode permissionsN = doc.CreateElement("", "Permissions", "");
@ -121,17 +123,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
XmlAttribute maskA = doc.CreateAttribute("", "mask", ""); XmlAttribute maskA = doc.CreateAttribute("", "mask", "");
maskA.Value = m_Item.PermsMask.ToString(); maskA.Value = m_Item.PermsMask.ToString();
permissionsN.Attributes.Append(maskA); permissionsN.Attributes.Append(maskA);
m_RunOnePhase = "GetExecutionState E"; CheckRunLockInvariants(true); m_RunOnePhase = "GetExecutionState E";
CheckRunLockInvariants(true);
// "DetectParams" are returned by llDetected...() script functions // "DetectParams" are returned by llDetected...() script functions
// for the currently active event, if any. // for the currently active event, if any.
if (m_DetectParams != null) if(m_DetectParams != null)
{ {
XmlElement detParArrayN = doc.CreateElement("", "DetectArray", ""); XmlElement detParArrayN = doc.CreateElement("", "DetectArray", "");
AppendXMLDetectArray(doc, detParArrayN, m_DetectParams); AppendXMLDetectArray(doc, detParArrayN, m_DetectParams);
scriptStateN.AppendChild(detParArrayN); scriptStateN.AppendChild(detParArrayN);
} }
m_RunOnePhase = "GetExecutionState F"; CheckRunLockInvariants(true); m_RunOnePhase = "GetExecutionState F";
CheckRunLockInvariants(true);
// Save any events we have in the queue. // Save any events we have in the queue.
// <EventQueue> // <EventQueue>
@ -142,9 +146,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// ... // ...
// </EventQueue> // </EventQueue>
XmlElement queuedEventsN = doc.CreateElement("", "EventQueue", ""); XmlElement queuedEventsN = doc.CreateElement("", "EventQueue", "");
lock (m_QueueLock) lock(m_QueueLock)
{ {
foreach (EventParams evt in m_EventQueue) foreach(EventParams evt in m_EventQueue)
{ {
XmlElement singleEventN = doc.CreateElement("", "Event", ""); XmlElement singleEventN = doc.CreateElement("", "Event", "");
singleEventN.SetAttribute("Name", evt.EventName); singleEventN.SetAttribute("Name", evt.EventName);
@ -154,7 +158,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
} }
} }
scriptStateN.AppendChild(queuedEventsN); scriptStateN.AppendChild(queuedEventsN);
m_RunOnePhase = "GetExecutionState G"; CheckRunLockInvariants(true); m_RunOnePhase = "GetExecutionState G";
CheckRunLockInvariants(true);
// "Plugins" indicate enabled timers and listens, etc. // "Plugins" indicate enabled timers and listens, etc.
Object[] pluginData = Object[] pluginData =
@ -163,7 +168,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
XmlNode plugins = doc.CreateElement("", "Plugins", ""); XmlNode plugins = doc.CreateElement("", "Plugins", "");
AppendXMLObjectArray(doc, plugins, pluginData, "plugin"); AppendXMLObjectArray(doc, plugins, pluginData, "plugin");
scriptStateN.AppendChild(plugins); scriptStateN.AppendChild(plugins);
m_RunOnePhase = "GetExecutionState H"; CheckRunLockInvariants(true); m_RunOnePhase = "GetExecutionState H";
CheckRunLockInvariants(true);
// Let script run again. // Let script run again.
suspendOnCheckRunHold = false; suspendOnCheckRunHold = false;
@ -185,116 +191,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Write script state to output stream. * @brief Write script state to output stream.
* The script microthread is at same state on return,
* ie, either inactive or suspended inside CheckRun().
*
* Input: * Input:
* stream = stream to write event handler state information to * stream = stream to write event handler state information to
*/ */
private void MigrateOutEventHandler (Stream stream) private void MigrateOutEventHandler(Stream stream)
{ {
moehexcep = null;
// do all the work in the MigrateOutEventHandlerThread() method below
moehstream = stream;
XMRScriptThread cst = m_Engine.CurrentScriptThread ();
if (cst != null)
{
// we might be getting called inside some LSL Api function
// so we are already in script thread and thus must do
// migration directly
MigrateOutEventHandlerThread ();
}
else
{
// some other thread, do migration via a script thread
m_Engine.QueueToTrunk(this.MigrateOutEventHandlerThread);
// wait for it to complete
lock (moehdone)
{
while (moehstream != null)
Monitor.Wait (moehdone);
}
}
// maybe it threw up
if (moehexcep != null)
throw moehexcep;
}
private Exception moehexcep;
private object moehdone = new object ();
private Stream moehstream;
private void MigrateOutEventHandlerThread ()
{
Exception except;
try
{
// Resume the microthread and it will throw a StackCaptureException()
// with the stack frames saved to this.stackFrames.
// Then write the saved stack frames to the output stream.
//
// There is a stack only if the event code is not None.
if (this.eventCode != ScriptEventCode.None)
{
// tell microthread to continue
// it should see captureStackFrames and throw StackCaptureException()
// ...generating XMRStackFrames as it unwinds
this.captureStackFrames = true;
// this.suspendOnCheckRunTemp = true;
except = this.microthread.ResumeEx ();
this.captureStackFrames = false;
if (except == null)
throw new Exception ("stack save did not complete");
if (!(except is StackCaptureException))
throw except;
}
// Write script state out, frames and all, to the stream. // Write script state out, frames and all, to the stream.
// Does not change script state. // Does not change script state.
stream.WriteByte(migrationVersion);
moehstream.WriteByte (migrationVersion); stream.WriteByte((byte)16);
moehstream.WriteByte ((byte)16); this.MigrateOut(new BinaryWriter(stream));
this.MigrateOut (new BinaryWriter (moehstream));
// Now restore script stack.
// Microthread will suspend inside CheckRun() when restore is complete.
if (this.eventCode != ScriptEventCode.None)
{
this.stackFramesRestored = false;
except = this.microthread.StartEx ();
if (except != null)
throw except;
if (!this.stackFramesRestored)
throw new Exception ("restore after save did not complete");
}
}
catch (Exception e)
{
moehexcep = e;
}
finally
{
// make sure CheckRunLockInvariants() won't puque
if (this.microthread.Active () == 0)
this.eventCode = ScriptEventCode.None;
// wake the MigrateOutEventHandler() method above
lock (moehdone)
{
moehstream = null;
Monitor.Pulse (moehdone);
}
}
} }
/** /**
@ -304,7 +210,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
private static void AppendXMLDetectArray(XmlDocument doc, XmlElement parent, DetectParams[] detect) private static void AppendXMLDetectArray(XmlDocument doc, XmlElement parent, DetectParams[] detect)
{ {
foreach (DetectParams d in detect) foreach(DetectParams d in detect)
{ {
XmlElement detectParamsN = GetXMLDetect(doc, d); XmlElement detectParamsN = GetXMLDetect(doc, d);
parent.AppendChild(detectParamsN); parent.AppendChild(detectParamsN);
@ -367,7 +273,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
private static void AppendXMLObjectArray(XmlDocument doc, XmlNode parent, object[] array, string tag) private static void AppendXMLObjectArray(XmlDocument doc, XmlNode parent, object[] array, string tag)
{ {
foreach (object o in array) foreach(object o in array)
{ {
XmlElement element = GetXMLObject(doc, o, tag); XmlElement element = GetXMLObject(doc, o, tag);
parent.AppendChild(element); parent.AppendChild(element);
@ -385,7 +291,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
XmlAttribute typ = doc.CreateAttribute("", "type", ""); XmlAttribute typ = doc.CreateAttribute("", "type", "");
XmlElement n = doc.CreateElement("", tag, ""); XmlElement n = doc.CreateElement("", tag, "");
if (o is LSL_List) if(o is LSL_List)
{ {
typ.Value = "list"; typ.Value = "list";
n.Attributes.Append(typ); n.Attributes.Append(typ);

View File

@ -41,7 +41,7 @@ using OpenSim.Region.ScriptEngine.Interfaces;
using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared;
using OpenSim.Region.ScriptEngine.Shared.Api; using OpenSim.Region.ScriptEngine.Shared.Api;
using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
using OpenSim.Region.ScriptEngine.XMREngine; using OpenSim.Region.ScriptEngine.Yengine;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using log4net; using log4net;
@ -53,7 +53,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
public partial class XMRInstance public partial class XMRInstance
{ {
@ -65,23 +65,26 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Initializer, loads script in memory and all ready for running. * @brief Initializer, loads script in memory and all ready for running.
* @param engine = XMREngine instance this is part of * @param engine = YEngine instance this is part of
* @param scriptBasePath = directory name where files are * @param scriptBasePath = directory name where files are
* @param stackSize = number of bytes to allocate for stacks * @param stackSize = number of bytes to allocate for stacks
* @param errors = return compiler errors in this array * @param errors = return compiler errors in this array
* @param forceRecomp = force recompile * @param forceRecomp = force recompile
* Throws exception if any error, so it was successful if it returns. * Throws exception if any error, so it was successful if it returns.
*/ */
public void Initialize(XMREngine engine, string scriptBasePath, public void Initialize(Yengine engine, string scriptBasePath,
int stackSize, int heapSize, ArrayList errors) int stackSize, int heapSize, ArrayList errors)
{ {
if (stackSize < 16384) stackSize = 16384; if(stackSize < 16384)
if (heapSize < 16384) heapSize = 16384; stackSize = 16384;
if(heapSize < 16384)
heapSize = 16384;
// Save all call parameters in instance vars for easy access. // Save all call parameters in instance vars for easy access.
m_Engine = engine; m_Engine = engine;
m_ScriptBasePath = scriptBasePath; m_ScriptBasePath = scriptBasePath;
m_StackSize = stackSize; m_StackSize = stackSize;
m_StackLeft = stackSize;
m_HeapSize = heapSize; m_HeapSize = heapSize;
m_CompilerErrors = errors; m_CompilerErrors = errors;
m_StateFileName = GetStateFileName(scriptBasePath, m_ItemID); m_StateFileName = GetStateFileName(scriptBasePath, m_ItemID);
@ -95,17 +98,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// active listeners being restored. // active listeners being restored.
IScriptApi scriptApi; IScriptApi scriptApi;
ApiManager am = new ApiManager(); ApiManager am = new ApiManager();
foreach (string api in am.GetApis()) foreach(string api in am.GetApis())
{ {
// Instantiate the API for this script instance. // Instantiate the API for this script instance.
if (api != "LSL") { if(api != "LSL")
scriptApi = am.CreateApi(api); scriptApi = am.CreateApi(api);
} else { else
scriptApi = m_XMRLSLApi = new XMRLSL_Api(); scriptApi = m_XMRLSLApi = new XMRLSL_Api();
}
// Connect it up to the instance. // Connect it up to the instance.
InitScriptApi (engine, api, scriptApi); InitScriptApi(engine, api, scriptApi);
} }
m_XMRLSLApi.InitXMRLSLApi(this); m_XMRLSLApi.InitXMRLSLApi(this);
@ -115,9 +117,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
suspendOnCheckRunHold = true; suspendOnCheckRunHold = true;
InstantiateScript(); InstantiateScript();
m_SourceCode = null; m_SourceCode = null;
if (m_ObjCode == null) throw new ArgumentNullException ("m_ObjCode"); if(m_ObjCode == null)
if (m_ObjCode.scriptEventHandlerTable == null) throw new ArgumentNullException("m_ObjCode");
throw new ArgumentNullException ("m_ObjCode.scriptEventHandlerTable"); if(m_ObjCode.scriptEventHandlerTable == null)
throw new ArgumentNullException("m_ObjCode.scriptEventHandlerTable");
suspendOnCheckRunHold = false; suspendOnCheckRunHold = false;
suspendOnCheckRunTemp = false; suspendOnCheckRunTemp = false;
@ -127,16 +130,17 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
m_Part.SetScriptEvents(m_ItemID, eventMask); m_Part.SetScriptEvents(m_ItemID, eventMask);
} }
private void InitScriptApi (XMREngine engine, string api, IScriptApi scriptApi) private void InitScriptApi(Yengine engine, string api, IScriptApi scriptApi)
{ {
// Set up m_ApiManager_<APINAME> = instance pointer. // Set up m_ApiManager_<APINAME> = instance pointer.
engine.m_XMRInstanceApiCtxFieldInfos[api].SetValue (this, scriptApi); engine.m_XMRInstanceApiCtxFieldInfos[api].SetValue(this, scriptApi);
// Initialize the API instance. // Initialize the API instance.
scriptApi.Initialize(m_Engine, m_Part, m_Item); scriptApi.Initialize(m_Engine, m_Part, m_Item);
this.InitApi (api, scriptApi); this.InitApi(api, scriptApi);
} }
/* /*
* Get script object code loaded in memory and all ready to run, * Get script object code loaded in memory and all ready to run,
* ready to resume it from where the .state file says it was last * ready to resume it from where the .state file says it was last
@ -149,32 +153,33 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// If source code string is empty, use the asset ID as the object file name. // If source code string is empty, use the asset ID as the object file name.
// Allow lines of // comments at the beginning (for such as engine selection). // Allow lines of // comments at the beginning (for such as engine selection).
int i, j, len; int i, j, len;
if (m_SourceCode == null) m_SourceCode = String.Empty; if(m_SourceCode == null)
for (len = m_SourceCode.Length; len > 0; --len) m_SourceCode = String.Empty;
for(len = m_SourceCode.Length; len > 0; --len)
{ {
if (m_SourceCode[len-1] > ' ') if(m_SourceCode[len - 1] > ' ')
break; break;
} }
for (i = 0; i < len; i ++) for(i = 0; i < len; i++)
{ {
char c = m_SourceCode[i]; char c = m_SourceCode[i];
if (c <= ' ') if(c <= ' ')
continue; continue;
if (c != '/') if(c != '/')
break; break;
if ((i + 1 >= len) || (m_SourceCode[i+1] != '/')) if((i + 1 >= len) || (m_SourceCode[i + 1] != '/'))
break; break;
i = m_SourceCode.IndexOf ('\n', i); i = m_SourceCode.IndexOf('\n', i);
if (i < 0) if(i < 0)
i = len - 1; i = len - 1;
} }
if ((i >= len) || !m_Engine.m_UseSourceHashCode) if((i >= len) || !m_Engine.m_UseSourceHashCode)
{ {
// Source consists of nothing but // comments and whitespace, // Source consists of nothing but // comments and whitespace,
// or we are being forced to use the asset-id as the key, to // or we are being forced to use the asset-id as the key, to
// open an already existing object code file. // open an already existing object code file.
m_ScriptObjCodeKey = m_Item.AssetID.ToString (); m_ScriptObjCodeKey = m_Item.AssetID.ToString();
if (i >= len) if(i >= len)
m_SourceCode = ""; m_SourceCode = "";
} }
else else
@ -183,23 +188,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// Use the same object code for identical source code // Use the same object code for identical source code
// regardless of asset ID, so we don't care if they // regardless of asset ID, so we don't care if they
// copy scripts or not. // copy scripts or not.
byte[] scbytes = System.Text.Encoding.UTF8.GetBytes (m_SourceCode); byte[] scbytes = System.Text.Encoding.UTF8.GetBytes(m_SourceCode);
StringBuilder sb = new StringBuilder ((256 + 5) / 6); StringBuilder sb = new StringBuilder((256 + 5) / 6);
ByteArrayToSixbitStr (sb, System.Security.Cryptography.SHA256.Create ().ComputeHash (scbytes)); ByteArrayToSixbitStr(sb, System.Security.Cryptography.SHA256.Create().ComputeHash(scbytes));
m_ScriptObjCodeKey = sb.ToString (); m_ScriptObjCodeKey = sb.ToString();
// But source code can be just a sixbit string itself // But source code can be just a sixbit string itself
// that identifies an already existing object code file. // that identifies an already existing object code file.
if (len - i == m_ScriptObjCodeKey.Length) if(len - i == m_ScriptObjCodeKey.Length)
{ {
for (j = len; -- j >= i;) for(j = len; --j >= i;)
{ {
if (sixbit.IndexOf (m_SourceCode[j]) < 0) if(sixbit.IndexOf(m_SourceCode[j]) < 0)
break; break;
} }
if (j < i) if(j < i)
{ {
m_ScriptObjCodeKey = m_SourceCode.Substring (i, len - i); m_ScriptObjCodeKey = m_SourceCode.Substring(i, len - i);
m_SourceCode = ""; m_SourceCode = "";
} }
} }
@ -207,27 +212,26 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// There may already be an ScriptObjCode struct in memory that // There may already be an ScriptObjCode struct in memory that
// we can use. If not, try to compile it. // we can use. If not, try to compile it.
lock (m_CompileLock) lock(m_CompileLock)
{ {
if (!m_CompiledScriptObjCode.TryGetValue (m_ScriptObjCodeKey, out objCode) || m_ForceRecomp) if(!m_CompiledScriptObjCode.TryGetValue(m_ScriptObjCodeKey, out objCode) || m_ForceRecomp)
{ {
objCode = TryToCompile (); objCode = TryToCompile();
compiledIt = true; compiledIt = true;
} }
// Loaded successfully, increment reference count. // Loaded successfully, increment reference count.
// If we just compiled it though, reset count to 0 first as // If we just compiled it though, reset count to 0 first as
// this is the one-and-only existance of this objCode struct, // this is the one-and-only existance of this objCode struct,
// and we want any old ones for this source code to be garbage // and we want any old ones for this source code to be garbage
// collected. // collected.
if (compiledIt) if(compiledIt)
{ {
m_CompiledScriptObjCode[m_ScriptObjCodeKey] = objCode; m_CompiledScriptObjCode[m_ScriptObjCodeKey] = objCode;
objCode.refCount = 0; objCode.refCount = 0;
} }
objCode.refCount ++; objCode.refCount++;
// Now set up to decrement ref count on dispose. // Now set up to decrement ref count on dispose.
m_ObjCode = objCode; m_ObjCode = objCode;
@ -235,6 +239,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
try try
{ {
// Fill in script instance from object code // Fill in script instance from object code
// Script instance is put in a "never-ever-has-run-before" state. // Script instance is put in a "never-ever-has-run-before" state.
LoadObjCode(); LoadObjCode();
@ -246,52 +251,50 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
} }
catch catch
{ {
// If any error loading, decrement object code reference count. // If any error loading, decrement object code reference count.
DecObjCodeRefCount (); DecObjCodeRefCount();
throw; throw;
} }
} }
private const string sixbit = "0123456789_abcdefghijklmnopqrstuvwxyz@ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private const string sixbit = "0123456789_abcdefghijklmnopqrstuvwxyz@ABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static void ByteArrayToSixbitStr (StringBuilder sb, byte[] bytes) private static void ByteArrayToSixbitStr(StringBuilder sb, byte[] bytes)
{ {
int bit = 0; int bit = 0;
int val = 0; int val = 0;
foreach (byte b in bytes) foreach(byte b in bytes)
{ {
val |= (int)((uint)b << bit); val |= (int)((uint)b << bit);
bit += 8; bit += 8;
while (bit >= 6) while(bit >= 6)
{ {
sb.Append (sixbit[val&63]); sb.Append(sixbit[val & 63]);
val >>= 6; val >>= 6;
bit -= 6; bit -= 6;
} }
} }
if (bit > 0) if(bit > 0)
sb.Append (sixbit[val&63]); sb.Append(sixbit[val & 63]);
} }
/* // Try to create object code from source code
* Try to create object code from source code // If error, just throw exception
* If error, just throw exception private ScriptObjCode TryToCompile()
*/
private ScriptObjCode TryToCompile ()
{ {
m_CompilerErrors.Clear(); m_CompilerErrors.Clear();
// If object file exists, create ScriptObjCode directly from that. // If object file exists, create ScriptObjCode directly from that.
// Otherwise, compile the source to create object file then create // Otherwise, compile the source to create object file then create
// ScriptObjCode from that. // ScriptObjCode from that.
string assetID = m_Item.AssetID.ToString(); string assetID = m_Item.AssetID.ToString();
m_CameFrom = "asset://" + assetID; m_CameFrom = "asset://" + assetID;
ScriptObjCode objCode = Compile (); ScriptObjCode objCode = Compile();
if (m_CompilerErrors.Count != 0) if(m_CompilerErrors.Count != 0)
throw new Exception ("compilation errors"); throw new Exception("compilation errors");
if (objCode == null) if(objCode == null)
throw new Exception ("compilation failed"); throw new Exception("compilation failed");
return objCode; return objCode;
} }
@ -299,20 +302,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/* /*
* Retrieve source from asset server. * Retrieve source from asset server.
*/ */
private string FetchSource (string cameFrom) private string FetchSource(string cameFrom)
{ {
m_log.Debug ("[XMREngine]: fetching source " + cameFrom); m_log.Debug("[YEngine]: fetching source " + cameFrom);
if (!cameFrom.StartsWith ("asset://")) if(!cameFrom.StartsWith("asset://"))
throw new Exception ("unable to retrieve source from " + cameFrom); throw new Exception("unable to retrieve source from " + cameFrom);
string assetID = cameFrom.Substring (8); string assetID = cameFrom.Substring(8);
AssetBase asset = m_Engine.World.AssetService.Get(assetID); AssetBase asset = m_Engine.World.AssetService.Get(assetID);
if (asset == null) if(asset == null)
throw new Exception ("source not found " + cameFrom); throw new Exception("source not found " + cameFrom);
string source = Encoding.UTF8.GetString (asset.Data); string source = Encoding.UTF8.GetString(asset.Data);
if (EmptySource (source)) if(EmptySource(source))
throw new Exception ("fetched source empty " + cameFrom); throw new Exception("fetched source empty " + cameFrom);
return source; return source;
} }
@ -321,33 +324,29 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Fill in script object initial contents. * Fill in script object initial contents.
* Set the initial state to "default". * Set the initial state to "default".
*/ */
private void LoadObjCode () private void LoadObjCode()
{ {
// Script must leave this much stack remaining on calls to CheckRun(). // Script must leave this much stack remaining on calls to CheckRun().
this.stackLimit = m_StackSize / 2; this.stackLimit = m_StackSize / 2;
// This is how many total heap bytes script is allowed to use. // This is how many total heap bytes script is allowed to use.
this.heapLimit = m_HeapSize; this.heapLimit = m_HeapSize;
// Allocate global variable arrays. // Allocate global variable arrays.
this.glblVars.AllocVarArrays (m_ObjCode.glblSizes); this.glblVars.AllocVarArrays(m_ObjCode.glblSizes);
// Script can handle these event codes. // Script can handle these event codes.
m_HaveEventHandlers = new bool[m_ObjCode.scriptEventHandlerTable.GetLength(1)]; m_HaveEventHandlers = new bool[m_ObjCode.scriptEventHandlerTable.GetLength(1)];
for (int i = m_ObjCode.scriptEventHandlerTable.GetLength(0); -- i >= 0;) for(int i = m_ObjCode.scriptEventHandlerTable.GetLength(0); --i >= 0;)
{ {
for (int j = m_ObjCode.scriptEventHandlerTable.GetLength(1); -- j >= 0;) for(int j = m_ObjCode.scriptEventHandlerTable.GetLength(1); --j >= 0;)
{ {
if (m_ObjCode.scriptEventHandlerTable[i,j] != null) if(m_ObjCode.scriptEventHandlerTable[i, j] != null)
{ {
m_HaveEventHandlers[j] = true; m_HaveEventHandlers[j] = true;
} }
} }
} }
// Set up microthread object which actually calls the script event handler functions.
this.microthread = (IScriptUThread)m_Engine.uThreadCtor.Invoke (new object[] { this });
} }
/* /*
@ -362,7 +361,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{ {
// If no .state file exists, start from default state // If no .state file exists, start from default state
// Otherwise, read initial state from the .state file // Otherwise, read initial state from the .state file
if (!File.Exists(m_StateFileName))
if(!File.Exists(m_StateFileName))
{ {
m_Running = true; // event processing is enabled m_Running = true; // event processing is enabled
eventCode = ScriptEventCode.None; // not processing any event eventCode = ScriptEventCode.None; // not processing any event
@ -390,20 +390,22 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
LoadScriptState(doc); LoadScriptState(doc);
} }
// Post event(s) saying what caused the script to start. /*
if (m_PostOnRez) * Post event(s) saying what caused the script to start.
*/
if(m_PostOnRez)
{ {
PostEvent(new EventParams("on_rez", PostEvent(new EventParams("on_rez",
new Object[] { m_StartParam }, new Object[] { m_StartParam },
zeroDetectParams)); zeroDetectParams));
} }
switch (m_StateSource) switch(m_StateSource)
{ {
case StateSource.AttachedRez: case StateSource.AttachedRez:
// PostEvent(new EventParams("attach", // PostEvent(new EventParams("attach",
// new object[] { m_Part.ParentGroup.AttachedAvatar.ToString() }, // new object[] { m_Part.ParentGroup.AttachedAvatar.ToString() },
// zeroDetectParams)); // zeroDetectParams));
break; break;
case StateSource.PrimCrossing: case StateSource.PrimCrossing:
@ -412,6 +414,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
zeroDetectParams)); zeroDetectParams));
break; break;
case StateSource.Teleporting: case StateSource.Teleporting:
PostEvent(new EventParams("changed", PostEvent(new EventParams("changed",
sbcCR, sbcCR,
@ -439,24 +442,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
private void ErrorHandler(Token token, string message) private void ErrorHandler(Token token, string message)
{ {
if (token != null) if(token != null)
{ {
string srcloc = token.SrcLoc; string srcloc = token.SrcLoc;
if (srcloc.StartsWith (m_CameFrom)) if(srcloc.StartsWith(m_CameFrom))
srcloc = srcloc.Substring (m_CameFrom.Length); srcloc = srcloc.Substring(m_CameFrom.Length);
m_CompilerErrors.Add(srcloc + " Error: " + message); m_CompilerErrors.Add(srcloc + " Error: " + message);
} }
else if (message != null) else if(message != null)
m_CompilerErrors.Add("(0,0) Error: " + message); m_CompilerErrors.Add("(0,0) Error: " + message);
else else
m_CompilerErrors.Add("(0,0) Error compiling, see exception in log"); m_CompilerErrors.Add("(0,0) Error compiling, see exception in log");
} }
/** /**
* @brief Load script state from the given XML doc into the script memory * @brief Load script state from the given XML doc into the script memory
* <ScriptState Engine="XMREngine" Asset=...> * <ScriptState Engine="YEngine" Asset=...>
* <Running>...</Running> * <Running>...</Running>
* <DoGblInit>...</DoGblInit> * <DoGblInit>...</DoGblInit>
* <Permissions granted=... mask=... /> * <Permissions granted=... mask=... />
@ -476,25 +478,24 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// Everything we know is enclosed in <ScriptState>...</ScriptState> // Everything we know is enclosed in <ScriptState>...</ScriptState>
XmlElement scriptStateN = (XmlElement)doc.SelectSingleNode("ScriptState"); XmlElement scriptStateN = (XmlElement)doc.SelectSingleNode("ScriptState");
if (scriptStateN == null) if(scriptStateN == null)
throw new Exception("no <ScriptState> tag"); throw new Exception("no <ScriptState> tag");
string sen = scriptStateN.GetAttribute("Engine"); string sen = scriptStateN.GetAttribute("Engine");
if ((sen == null) || (sen != m_Engine.ScriptEngineName)) if((sen == null) || (sen != m_Engine.ScriptEngineName))
throw new Exception("<ScriptState> missing Engine=\"XMREngine\" attribute"); throw new Exception("<ScriptState> missing Engine=\"YEngine\" attribute");
// AssetID is unique for the script source text so make sure the // AssetID is unique for the script source text so make sure the
// state file was written for that source file // state file was written for that source file
string assetID = scriptStateN.GetAttribute("Asset"); string assetID = scriptStateN.GetAttribute("Asset");
if (assetID != m_Item.AssetID.ToString()) if(assetID != m_Item.AssetID.ToString())
throw new Exception("<ScriptState> assetID mismatch"); throw new Exception("<ScriptState> assetID mismatch");
// Also match the sourceHash in case script was // Also match the sourceHash in case script was
// loaded via 'xmroption fetchsource' and has changed // loaded via 'xmroption fetchsource' and has changed
string sourceHash = scriptStateN.GetAttribute ("SourceHash"); string sourceHash = scriptStateN.GetAttribute("SourceHash");
if ((sourceHash == null) || (sourceHash != m_ObjCode.sourceHash)) if((sourceHash == null) || (sourceHash != m_ObjCode.sourceHash))
throw new Exception ("<ScriptState> SourceHash mismatch"); throw new Exception("<ScriptState> SourceHash mismatch");
// Get various attributes // Get various attributes
XmlElement runningN = (XmlElement)scriptStateN.SelectSingleNode("Running"); XmlElement runningN = (XmlElement)scriptStateN.SelectSingleNode("Running");
@ -519,7 +520,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
Object[] pluginData = ExtractXMLObjectArray(pluginN, "plugin"); Object[] pluginData = ExtractXMLObjectArray(pluginN, "plugin");
// Script's global variables and stack contents // Script's global variables and stack contents
XmlElement snapshotN = (XmlElement)scriptStateN.SelectSingleNode("Snapshot"); XmlElement snapshotN =
(XmlElement)scriptStateN.SelectSingleNode("Snapshot");
Byte[] data = Convert.FromBase64String(snapshotN.InnerText); Byte[] data = Convert.FromBase64String(snapshotN.InnerText);
MemoryStream ms = new MemoryStream(); MemoryStream ms = new MemoryStream();
@ -530,17 +532,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// Restore event queues, preserving any events that queued // Restore event queues, preserving any events that queued
// whilst we were restoring the state // whilst we were restoring the state
lock (m_QueueLock) lock(m_QueueLock)
{ {
m_DetectParams = detParams; m_DetectParams = detParams;
foreach (EventParams evt in m_EventQueue) foreach(EventParams evt in m_EventQueue)
eventQueue.AddLast (evt); eventQueue.AddLast(evt);
m_EventQueue = eventQueue; m_EventQueue = eventQueue;
for (int i = m_EventCounts.Length; -- i >= 0;) for(int i = m_EventCounts.Length; --i >= 0;)
m_EventCounts[i] = 0; m_EventCounts[i] = 0;
foreach(EventParams evt in m_EventQueue)
foreach (EventParams evt in m_EventQueue)
{ {
ScriptEventCode eventCode = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), ScriptEventCode eventCode = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
evt.EventName); evt.EventName);
@ -566,17 +567,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private LinkedList<EventParams> RestoreEventQueue(XmlNode eventsN) private LinkedList<EventParams> RestoreEventQueue(XmlNode eventsN)
{ {
LinkedList<EventParams> eventQueue = new LinkedList<EventParams>(); LinkedList<EventParams> eventQueue = new LinkedList<EventParams>();
if (eventsN != null) if(eventsN != null)
{ {
XmlNodeList eventL = eventsN.SelectNodes("Event"); XmlNodeList eventL = eventsN.SelectNodes("Event");
foreach (XmlNode evnt in eventL) foreach(XmlNode evnt in eventL)
{ {
string name = ((XmlElement)evnt).GetAttribute("Name"); string name = ((XmlElement)evnt).GetAttribute("Name");
object[] parms = ExtractXMLObjectArray(evnt, "param"); object[] parms = ExtractXMLObjectArray(evnt, "param");
DetectParams[] detects = RestoreDetectParams(evnt); DetectParams[] detects = RestoreDetectParams(evnt);
if (parms == null) parms = zeroObjectArray; if(parms == null)
if (detects == null) detects = zeroDetectParams; parms = zeroObjectArray;
if(detects == null)
detects = zeroDetectParams;
EventParams evt = new EventParams(name, parms, detects); EventParams evt = new EventParams(name, parms, detects);
eventQueue.AddLast(evt); eventQueue.AddLast(evt);
@ -596,13 +599,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
private DetectParams[] RestoreDetectParams(XmlNode detectedN) private DetectParams[] RestoreDetectParams(XmlNode detectedN)
{ {
if (detectedN == null) return null; if(detectedN == null)
return null;
List<DetectParams> detected = new List<DetectParams>(); List<DetectParams> detected = new List<DetectParams>();
XmlNodeList detectL = detectedN.SelectNodes("DetectParams"); XmlNodeList detectL = detectedN.SelectNodes("DetectParams");
DetectParams detprm = new DetectParams(); DetectParams detprm = new DetectParams();
foreach (XmlNode detxml in detectL) foreach(XmlNode detxml in detectL)
{ {
try try
{ {
@ -624,10 +628,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
detected.Add(detprm); detected.Add(detprm);
detprm = new DetectParams(); detprm = new DetectParams();
} }
catch (Exception e) catch(Exception e)
{ {
m_log.Warn("[XMREngine]: RestoreDetectParams bad XML: " + detxml.ToString()); m_log.Warn("[YEngine]: RestoreDetectParams bad XML: " + detxml.ToString());
m_log.Warn("[XMREngine]: ... " + e.ToString()); m_log.Warn("[YEngine]: ... " + e.ToString());
} }
} }
@ -646,8 +650,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
List<Object> olist = new List<Object>(); List<Object> olist = new List<Object>();
XmlNodeList itemL = parent.SelectNodes(tag); XmlNodeList itemL = parent.SelectNodes(tag);
foreach (XmlNode item in itemL) foreach(XmlNode item in itemL)
{
olist.Add(ExtractXMLObjectValue(item)); olist.Add(ExtractXMLObjectValue(item));
}
return olist.ToArray(); return olist.ToArray();
} }
@ -656,10 +662,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{ {
string itemType = item.Attributes.GetNamedItem("type").Value; string itemType = item.Attributes.GetNamedItem("type").Value;
if (itemType == "list") if(itemType == "list")
{
return new LSL_List(ExtractXMLObjectArray(item, "item")); return new LSL_List(ExtractXMLObjectArray(item, "item"));
}
if (itemType == "OpenMetaverse.UUID") if(itemType == "OpenMetaverse.UUID")
{ {
UUID val = new UUID(); UUID val = new UUID();
UUID.TryParse(item.InnerText, out val); UUID.TryParse(item.InnerText, out val);
@ -667,15 +675,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
} }
Type itemT = Type.GetType(itemType); Type itemT = Type.GetType(itemType);
if (itemT == null) if(itemT == null)
{ {
Object[] args = new Object[] { item.InnerText }; Object[] args = new Object[] { item.InnerText };
string assembly = itemType + ", OpenSim.Region.ScriptEngine.Shared"; string assembly = itemType + ", OpenSim.Region.ScriptEngine.Shared";
itemT = Type.GetType(assembly); itemT = Type.GetType(assembly);
if (itemT == null) if(itemT == null)
{
return null; return null;
}
return Activator.CreateInstance(itemT, args); return Activator.CreateInstance(itemT, args);
} }
@ -688,89 +697,27 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Input: * Input:
* stream = as generated by MigrateOutEventHandler() * stream = as generated by MigrateOutEventHandler()
*/ */
private void MigrateInEventHandler (Stream stream) private void MigrateInEventHandler(Stream stream)
{ {
miehexcep = null; int mv = stream.ReadByte();
if(mv != migrationVersion)
throw new Exception("incoming migration version " + mv + " but accept only " + migrationVersion);
// do all the work in the MigrateInEventHandlerThread() method below stream.ReadByte(); // ignored
miehstream = stream;
XMRScriptThread cst = m_Engine.CurrentScriptThread (); /*
if (cst != null) * Restore script variables and stack and other state from stream.
* And it also marks us busy (by setting this.eventCode) so we can't be
* started again and this event lost. If it restores this.eventCode =
* None, the the script was idle.
*/
lock(m_RunLock)
{ {
// in case we are getting called inside some LSL Api function BinaryReader br = new BinaryReader(stream);
MigrateInEventHandlerThread (); this.MigrateIn(br);
}
else
{
// some other thread, do migration via a script thread
m_Engine.QueueToTrunk(this.MigrateInEventHandlerThread);
// wait for it to complete m_RunOnePhase = "MigrateInEventHandler finished";
lock (miehdone) CheckRunLockInvariants(true);
{
while (miehstream != null)
Monitor.Wait(miehdone);
}
}
// maybe it threw up
if (miehexcep != null)
throw miehexcep;
}
private Exception miehexcep;
private object miehdone = new object ();
private Stream miehstream;
private void MigrateInEventHandlerThread ()
{
try
{
int mv = miehstream.ReadByte ();
if (mv != migrationVersion)
throw new Exception ("incoming migration version " + mv + " but accept only " + migrationVersion);
miehstream.ReadByte (); // ignored
// Restore script variables and stack and other state from stream.
// And it also marks us busy (by setting this.eventCode) so we can't be
// started again and this event lost.
BinaryReader br = new BinaryReader (miehstream);
this.MigrateIn (br);
// If eventCode is None, it means the script was idle when migrated.
if (this.eventCode != ScriptEventCode.None)
{
// So microthread.Start() calls XMRScriptUThread.Main() which calls the
// event handler function. The event handler function sees the stack
// frames in this.stackFrames and restores its args and locals, then calls
// whatever it was calling when the snapshot was taken. That function also
// sees this.stackFrames and restores its args and locals, and so on...
// Eventually it gets to the point of calling CheckRun() which sees we are
// doing a restore and it suspends, returning here with the microthread
// stack all restored. It shouldn't ever throw an exception.
this.stackFramesRestored = false;
Exception te = microthread.StartEx ();
if (te != null) throw te;
if (!this.stackFramesRestored)
throw new Exception ("migrate in did not complete");
}
}
catch (Exception e)
{
miehexcep = e;
}
finally
{
// Wake the MigrateInEventHandler() method above.
lock (miehdone)
{
miehstream = null;
Monitor.Pulse (miehdone);
}
} }
} }
} }

View File

@ -41,7 +41,7 @@ using OpenSim.Region.ScriptEngine.Interfaces;
using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared;
using OpenSim.Region.ScriptEngine.Shared.Api; using OpenSim.Region.ScriptEngine.Shared.Api;
using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
using OpenSim.Region.ScriptEngine.XMREngine; using OpenSim.Region.ScriptEngine.Yengine;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using log4net; using log4net;
@ -55,7 +55,7 @@ using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
// This class exists in the main app domain // This class exists in the main app domain
// //
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
/** /**
* @brief Which queue it is in as far as running is concerned, * @brief Which queue it is in as far as running is concerned,
@ -75,7 +75,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* SUSPENDED->ONSTARTQ : by any thread (NOT YET IMPLEMENTED, should be under some kind of lock?) * SUSPENDED->ONSTARTQ : by any thread (NOT YET IMPLEMENTED, should be under some kind of lock?)
* RESETTING->ONSTARTQ : only by the thread that transitioned it to RESETTING * RESETTING->ONSTARTQ : only by the thread that transitioned it to RESETTING
*/ */
public enum XMRInstState { public enum XMRInstState
{
CONSTRUCT, // it is being constructed CONSTRUCT, // it is being constructed
IDLE, // nothing happening (finished last event and m_EventQueue is empty) IDLE, // nothing happening (finished last event and m_EventQueue is empty)
ONSTARTQ, // inserted on m_Engine.m_StartQueue ONSTARTQ, // inserted on m_Engine.m_StartQueue
@ -89,7 +90,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
DISPOSED // has been disposed DISPOSED // has been disposed
} }
public partial class XMRInstance : XMRInstAbstract, IDisposable public partial class XMRInstance: XMRInstAbstract, IDisposable
{ {
/******************************************************************\ /******************************************************************\
* This module contains the instance variables for XMRInstance. * * This module contains the instance variables for XMRInstance. *
@ -103,13 +104,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public static readonly ILog m_log = public static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public XMRInstance m_NextInst; // used by XMRInstQueue
public XMRInstance m_PrevInst;
// For a given m_Item.AssetID, do we have the compiled object code and where // For a given m_Item.AssetID, do we have the compiled object code and where
// is it? // is it?
public static object m_CompileLock = new object(); public static object m_CompileLock = new object();
private static Dictionary<string,ScriptObjCode> m_CompiledScriptObjCode = new Dictionary<string,ScriptObjCode>(); private static Dictionary<string, ScriptObjCode> m_CompiledScriptObjCode = new Dictionary<string, ScriptObjCode>();
public XMRInstance m_NextInst; // used by XMRInstQueue
public XMRInstance m_PrevInst;
public XMRInstState m_IState; public XMRInstState m_IState;
public bool m_ForceRecomp = false; public bool m_ForceRecomp = false;
@ -121,7 +123,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private string m_CameFrom; private string m_CameFrom;
private string m_ScriptObjCodeKey; private string m_ScriptObjCodeKey;
private XMREngine m_Engine = null; private Yengine m_Engine = null;
private string m_ScriptBasePath; private string m_ScriptBasePath;
private string m_StateFileName; private string m_StateFileName;
public string m_SourceCode; public string m_SourceCode;
@ -156,7 +158,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public bool m_Running = true; public bool m_Running = true;
// queue of events that haven't been acted upon yet // queue of events that haven't been acted upon yet
public LinkedList<EventParams> m_EventQueue = new LinkedList<EventParams> (); public LinkedList<EventParams> m_EventQueue = new LinkedList<EventParams>();
// number of events of each code currently in m_EventQueue. // number of events of each code currently in m_EventQueue.
private int[] m_EventCounts = new int[(int)ScriptEventCode.Size]; private int[] m_EventCounts = new int[(int)ScriptEventCode.Size];
@ -175,20 +177,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private XMRLSL_Api m_XMRLSLApi; private XMRLSL_Api m_XMRLSLApi;
/*
* We will use this microthread to run the scripts event handlers.
*/
private IScriptUThread microthread;
/*
* Set to perform migration.
*/
public bool stackFramesRestored; // set true by CheckRun() when stack has been
// restored and is about to suspend the microthread
public bool captureStackFrames; // set true to tell CheckRun() to throw a
// StackCaptureException() causing it to capture a
// snapshot of the script's stack
/* /*
* Makes sure migration data version is same on both ends. * Makes sure migration data version is same on both ends.
*/ */

View File

@ -42,7 +42,7 @@ using OpenSim.Region.ScriptEngine.Interfaces;
using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared;
using OpenSim.Region.ScriptEngine.Shared.Api; using OpenSim.Region.ScriptEngine.Shared.Api;
using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
using OpenSim.Region.ScriptEngine.XMREngine; using OpenSim.Region.ScriptEngine.Yengine;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using log4net; using log4net;
@ -56,7 +56,7 @@ using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
// This class exists in the main app domain // This class exists in the main app domain
// //
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
public partial class XMRInstance public partial class XMRInstance
{ {
@ -79,58 +79,49 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
suspendOnCheckRunHold = true; suspendOnCheckRunHold = true;
/*
* Wait for it to stop executing and prevent it from starting again
* as it can't run without a microthread.
*/
lock (m_RunLock)
{
if (microthread != null)
{
m_RunOnePhase = "disposing";
CheckRunLockInvariants(true);
microthread.Dispose ();
microthread = null;
}
}
/* /*
* Don't send us any more events. * Don't send us any more events.
*/ */
if (m_Part != null) lock(m_RunLock)
{
if(m_Part != null)
{ {
xmrTrapRegionCrossing (0);
m_Part.RemoveScriptEvents(m_ItemID); m_Part.RemoveScriptEvents(m_ItemID);
AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID); AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID);
m_Part = null; m_Part = null;
} }
}
/* /*
* Let script methods get garbage collected if no one else is using * Let script methods get garbage collected if no one else is using
* them. * them.
*/ */
DecObjCodeRefCount (); DecObjCodeRefCount();
} }
private void DecObjCodeRefCount () private void DecObjCodeRefCount()
{
if(m_ObjCode != null)
{
lock(m_CompileLock)
{ {
if (m_ObjCode != null) {
lock (m_CompileLock) {
ScriptObjCode objCode; ScriptObjCode objCode;
if (m_CompiledScriptObjCode.TryGetValue (m_ScriptObjCodeKey, out objCode) && if(m_CompiledScriptObjCode.TryGetValue(m_ScriptObjCodeKey, out objCode) &&
(objCode == m_ObjCode) && (objCode == m_ObjCode) &&
(-- objCode.refCount == 0)) { (--objCode.refCount == 0))
m_CompiledScriptObjCode.Remove (m_ScriptObjCodeKey); {
m_CompiledScriptObjCode.Remove(m_ScriptObjCodeKey);
} }
} }
m_ObjCode = null; m_ObjCode = null;
} }
} }
public void Verbose (string format, params object[] args) public void Verbose(string format, params object[] args)
{ {
if (m_Engine.m_Verbose) m_log.DebugFormat (format, args); if(m_Engine.m_Verbose)
m_log.DebugFormat(format, args);
} }
// Called by 'xmr top' console command // Called by 'xmr top' console command
@ -138,7 +129,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// Sacha // Sacha
public void RunTestTop() public void RunTestTop()
{ {
if (m_InstEHSlice > 0){ if(m_InstEHSlice > 0)
{
Console.WriteLine(m_DescName); Console.WriteLine(m_DescName);
Console.WriteLine(" m_LocalID = " + m_LocalID); Console.WriteLine(" m_LocalID = " + m_LocalID);
Console.WriteLine(" m_ItemID = " + m_ItemID); Console.WriteLine(" m_ItemID = " + m_ItemID);
@ -152,7 +144,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
Console.WriteLine(" m_StateCode = " + GetStateName(stateCode)); Console.WriteLine(" m_StateCode = " + GetStateName(stateCode));
Console.WriteLine(" eventCode = " + eventCode.ToString()); Console.WriteLine(" eventCode = " + eventCode.ToString());
Console.WriteLine(" m_LastRanAt = " + m_LastRanAt.ToString()); Console.WriteLine(" m_LastRanAt = " + m_LastRanAt.ToString());
Console.WriteLine(" heapUsed/Limit = " + xmrHeapUsed () + "/" + heapLimit); Console.WriteLine(" heapUsed/Limit = " + xmrHeapUsed() + "/" + heapLimit);
Console.WriteLine(" m_InstEHEvent = " + m_InstEHEvent.ToString()); Console.WriteLine(" m_InstEHEvent = " + m_InstEHEvent.ToString());
Console.WriteLine(" m_InstEHSlice = " + m_InstEHSlice.ToString()); Console.WriteLine(" m_InstEHSlice = " + m_InstEHSlice.ToString());
} }
@ -162,13 +154,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// to dump this script's state to console // to dump this script's state to console
public string RunTestLs(bool flagFull) public string RunTestLs(bool flagFull)
{ {
if (flagFull) { if(flagFull)
{
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.AppendLine(m_DescName); sb.AppendLine(m_DescName);
sb.AppendLine(" m_LocalID = " + m_LocalID); sb.AppendLine(" m_LocalID = " + m_LocalID);
sb.AppendLine(" m_ItemID = " + m_ItemID + " (.state file)"); sb.AppendLine(" m_ItemID = " + m_ItemID + " (.state file)");
sb.AppendLine(" m_Item.AssetID = " + m_Item.AssetID); sb.AppendLine(" m_Item.AssetID = " + m_Item.AssetID);
sb.AppendLine(" m_Part.WorldPosition = " + m_Part.GetWorldPosition ()); sb.AppendLine(" m_Part.WorldPosition = " + m_Part.GetWorldPosition());
sb.AppendLine(" m_ScriptObjCodeKey = " + m_ScriptObjCodeKey + " (source text)"); sb.AppendLine(" m_ScriptObjCodeKey = " + m_ScriptObjCodeKey + " (source text)");
sb.AppendLine(" m_StartParam = " + m_StartParam); sb.AppendLine(" m_StartParam = " + m_StartParam);
sb.AppendLine(" m_PostOnRez = " + m_PostOnRez); sb.AppendLine(" m_PostOnRez = " + m_PostOnRez);
@ -185,23 +178,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
sb.AppendLine(" suspOnCkRunHold = " + suspendOnCheckRunHold); sb.AppendLine(" suspOnCkRunHold = " + suspendOnCheckRunHold);
sb.AppendLine(" suspOnCkRunTemp = " + suspendOnCheckRunTemp); sb.AppendLine(" suspOnCkRunTemp = " + suspendOnCheckRunTemp);
sb.AppendLine(" m_CheckRunPhase = " + m_CheckRunPhase); sb.AppendLine(" m_CheckRunPhase = " + m_CheckRunPhase);
sb.AppendLine(" heapUsed/Limit = " + xmrHeapUsed () + "/" + heapLimit); sb.AppendLine(" heapUsed/Limit = " + xmrHeapUsed() + "/" + heapLimit);
sb.AppendLine(" m_InstEHEvent = " + m_InstEHEvent.ToString()); sb.AppendLine(" m_InstEHEvent = " + m_InstEHEvent.ToString());
sb.AppendLine(" m_InstEHSlice = " + m_InstEHSlice.ToString()); sb.AppendLine(" m_InstEHSlice = " + m_InstEHSlice.ToString());
sb.AppendLine(" m_CPUTime = " + m_CPUTime); sb.AppendLine(" m_CPUTime = " + m_CPUTime);
sb.AppendLine(" callMode = " + callMode); sb.AppendLine(" callMode = " + callMode);
sb.AppendLine(" captureStackFrames = " + captureStackFrames); lock(m_QueueLock)
sb.AppendLine(" stackFramesRestored = " + stackFramesRestored);
lock (m_QueueLock)
{ {
sb.AppendLine(" m_Running = " + m_Running); sb.AppendLine(" m_Running = " + m_Running);
foreach (EventParams evt in m_EventQueue) foreach(EventParams evt in m_EventQueue)
{ {
sb.AppendLine(" evt.EventName = " + evt.EventName); sb.AppendLine(" evt.EventName = " + evt.EventName);
} }
} }
return sb.ToString(); return sb.ToString();
} else { }
else
{
return String.Format("{0} {1} {2} {3} {4} {5}", return String.Format("{0} {1} {2} {3} {4} {5}",
m_ItemID, m_ItemID,
m_CPUTime.ToString("F3").PadLeft(9), m_CPUTime.ToString("F3").PadLeft(9),
@ -218,16 +211,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
public int GetStateEventFlags(int stateCode) public int GetStateEventFlags(int stateCode)
{ {
if ((stateCode < 0) || if((stateCode < 0) ||
(stateCode >= m_ObjCode.scriptEventHandlerTable.GetLength(0))) (stateCode >= m_ObjCode.scriptEventHandlerTable.GetLength(0)))
{ {
return 0; return 0;
} }
int code = 0; int code = 0;
for (int i = 0 ; i < 32; i ++) for(int i = 0; i < 32; i++)
{ {
if (m_ObjCode.scriptEventHandlerTable[stateCode, i] != null) if(m_ObjCode.scriptEventHandlerTable[stateCode, i] != null)
{ {
code |= 1 << i; code |= 1 << i;
} }
@ -239,41 +232,47 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Get the .state file name. * @brief Get the .state file name.
*/ */
public static string GetStateFileName (string scriptBasePath, UUID itemID) public static string GetStateFileName(string scriptBasePath, UUID itemID)
{ {
return GetScriptFileName (scriptBasePath, itemID.ToString() + ".state"); return GetScriptFileName(scriptBasePath, itemID.ToString() + ".state");
} }
public string GetScriptFileName (string filename) public string GetScriptFileName(string filename)
{ {
return GetScriptFileName (m_ScriptBasePath, filename); return GetScriptFileName(m_ScriptBasePath, filename);
} }
public static string GetScriptFileName (string scriptBasePath, string filename) public static string GetScriptFileName(string scriptBasePath, string filename)
{ {
/* /*
* Get old path, ie, all files lumped in a single huge directory. * Get old path, ie, all files lumped in a single huge directory.
*/ */
string oldPath = Path.Combine (scriptBasePath, filename); string oldPath = Path.Combine(scriptBasePath, filename);
/* /*
* Get new path, ie, files split up based on first 2 chars of name. * Get new path, ie, files split up based on first 2 chars of name.
*/ */
string subdir = filename.Substring (0, 2); // string subdir = filename.Substring (0, 2);
filename = filename.Substring (2); // filename = filename.Substring (2);
scriptBasePath = Path.Combine (scriptBasePath, subdir); string subdir = filename.Substring(0, 1);
Directory.CreateDirectory (scriptBasePath); filename = filename.Substring(1);
string newPath = Path.Combine (scriptBasePath, filename); scriptBasePath = Path.Combine(scriptBasePath, subdir);
Directory.CreateDirectory(scriptBasePath);
string newPath = Path.Combine(scriptBasePath, filename);
/* /*
* If file exists only in old location, move to new location. * If file exists only in old location, move to new location.
* If file exists in both locations, delete old location. * If file exists in both locations, delete old location.
*/ */
if (File.Exists (oldPath)) { if(File.Exists(oldPath))
if (File.Exists (newPath)) { {
File.Delete (oldPath); if(File.Exists(newPath))
} else { {
File.Move (oldPath, newPath); File.Delete(oldPath);
}
else
{
File.Move(oldPath, newPath);
} }
} }
@ -286,12 +285,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Decode state code (int) to state name (string). * @brief Decode state code (int) to state name (string).
*/ */
public string GetStateName (int stateCode) public string GetStateName(int stateCode)
{
try
{ {
try {
return m_ObjCode.stateNames[stateCode]; return m_ObjCode.stateNames[stateCode];
} catch { }
return stateCode.ToString (); catch
{
return stateCode.ToString();
} }
} }
@ -300,42 +302,66 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
public int StartParam public int StartParam
{ {
get { return m_StartParam; } get
set { m_StartParam = value; } {
return m_StartParam;
}
set
{
m_StartParam = value;
}
} }
public SceneObjectPart SceneObject public SceneObjectPart SceneObject
{ {
get { return m_Part; } get
{
return m_Part;
}
} }
public DetectParams[] DetectParams public DetectParams[] DetectParams
{ {
get { return m_DetectParams; } get
set { m_DetectParams = value; } {
return m_DetectParams;
}
set
{
m_DetectParams = value;
}
} }
public UUID ItemID public UUID ItemID
{ {
get { return m_ItemID; } get
{
return m_ItemID;
}
} }
public UUID AssetID public UUID AssetID
{ {
get { return m_Item.AssetID; } get
{
return m_Item.AssetID;
}
} }
public bool Running public bool Running
{ {
get { return m_Running; } get
{
return m_Running;
}
set set
{ {
lock (m_QueueLock) lock(m_QueueLock)
{ {
m_Running = value; m_Running = value;
if (!value) if(!value)
{ {
EmptyEventQueues (); EmptyEventQueues();
} }
} }
} }
@ -345,26 +371,28 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @brief Empty out the event queues. * @brief Empty out the event queues.
* Assumes caller has the m_QueueLock locked. * Assumes caller has the m_QueueLock locked.
*/ */
public void EmptyEventQueues () public void EmptyEventQueues()
{ {
m_EventQueue.Clear(); m_EventQueue.Clear();
for (int i = m_EventCounts.Length; -- i >= 0;) m_EventCounts[i] = 0; for(int i = m_EventCounts.Length; --i >= 0;)
m_EventCounts[i] = 0;
} }
/** /**
* @brief Convert an LSL vector to an Openmetaverse vector. * @brief Convert an LSL vector to an Openmetaverse vector.
*/ */
public static OpenMetaverse.Vector3 LSLVec2OMVec (LSL_Vector lslVec) public static OpenMetaverse.Vector3 LSLVec2OMVec(LSL_Vector lslVec)
{ {
return new OpenMetaverse.Vector3 ((float)lslVec.x, (float)lslVec.y, (float)lslVec.z); return new OpenMetaverse.Vector3((float)lslVec.x, (float)lslVec.y, (float)lslVec.z);
} }
/** /**
* @brief Extract an integer from an element of an LSL_List. * @brief Extract an integer from an element of an LSL_List.
*/ */
public static int ListInt (object element) public static int ListInt(object element)
{
if(element is LSL_Integer)
{ {
if (element is LSL_Integer) {
return (int)(LSL_Integer)element; return (int)(LSL_Integer)element;
} }
return (int)element; return (int)element;
@ -373,9 +401,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Extract a string from an element of an LSL_List. * @brief Extract a string from an element of an LSL_List.
*/ */
public static string ListStr (object element) public static string ListStr(object element)
{
if(element is LSL_String)
{ {
if (element is LSL_String) {
return (string)(LSL_String)element; return (string)(LSL_String)element;
} }
return (string)element; return (string)element;

View File

@ -27,7 +27,7 @@
using System; using System;
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
/** /**
* @brief Implements a queue of XMRInstance's. * @brief Implements a queue of XMRInstance's.
@ -47,15 +47,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
public void InsertHead(XMRInstance inst) public void InsertHead(XMRInstance inst)
{ {
if ((inst.m_PrevInst != inst) || (inst.m_NextInst != inst)) { if((inst.m_PrevInst != inst) || (inst.m_NextInst != inst))
throw new Exception("already in list"); throw new Exception("already in list");
}
inst.m_PrevInst = null; inst.m_PrevInst = null;
if ((inst.m_NextInst = m_Head) == null) { if((inst.m_NextInst = m_Head) == null)
m_Tail = inst; m_Tail = inst;
} else { else
m_Head.m_PrevInst = inst; m_Head.m_PrevInst = inst;
}
m_Head = inst; m_Head = inst;
} }
@ -65,15 +65,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
public void InsertTail(XMRInstance inst) public void InsertTail(XMRInstance inst)
{ {
if ((inst.m_PrevInst != inst) || (inst.m_NextInst != inst)) { if((inst.m_PrevInst != inst) || (inst.m_NextInst != inst))
throw new Exception("already in list"); throw new Exception("already in list");
}
inst.m_NextInst = null; inst.m_NextInst = null;
if ((inst.m_PrevInst = m_Tail) == null) { if((inst.m_PrevInst = m_Tail) == null)
m_Head = inst; m_Head = inst;
} else { else
m_Tail.m_NextInst = inst; m_Tail.m_NextInst = inst;
}
m_Tail = inst; m_Tail = inst;
} }
@ -84,19 +84,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
public void InsertBefore(XMRInstance inst, XMRInstance after) public void InsertBefore(XMRInstance inst, XMRInstance after)
{ {
if ((inst.m_PrevInst != inst) || (inst.m_NextInst != inst)) { if((inst.m_PrevInst != inst) || (inst.m_NextInst != inst))
throw new Exception("already in list"); throw new Exception("already in list");
}
if (after == null) { if(after == null)
InsertTail(inst); InsertTail(inst);
} else { else
{
inst.m_NextInst = after; inst.m_NextInst = after;
inst.m_PrevInst = after.m_PrevInst; inst.m_PrevInst = after.m_PrevInst;
if (inst.m_PrevInst == null) { if(inst.m_PrevInst == null)
m_Head = inst; m_Head = inst;
} else { else
inst.m_PrevInst.m_NextInst = inst; inst.m_PrevInst.m_NextInst = inst;
}
after.m_PrevInst = inst; after.m_PrevInst = inst;
} }
} }
@ -119,12 +119,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public XMRInstance RemoveHead() public XMRInstance RemoveHead()
{ {
XMRInstance inst = m_Head; XMRInstance inst = m_Head;
if (inst != null) { if(inst != null)
if ((m_Head = inst.m_NextInst) == null) { {
if((m_Head = inst.m_NextInst) == null)
m_Tail = null; m_Tail = null;
} else { else
m_Head.m_PrevInst = null; m_Head.m_PrevInst = null;
}
inst.m_NextInst = inst; inst.m_NextInst = inst;
inst.m_PrevInst = inst; inst.m_PrevInst = inst;
} }
@ -139,12 +140,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public XMRInstance RemoveTail() public XMRInstance RemoveTail()
{ {
XMRInstance inst = m_Tail; XMRInstance inst = m_Tail;
if (inst != null) { if(inst != null)
if ((m_Tail = inst.m_PrevInst) == null) { {
if((m_Tail = inst.m_PrevInst) == null)
m_Head = null; m_Head = null;
} else { else
m_Tail.m_NextInst = null; m_Tail.m_NextInst = null;
}
inst.m_NextInst = inst; inst.m_NextInst = inst;
inst.m_PrevInst = inst; inst.m_PrevInst = inst;
} }
@ -160,25 +162,29 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{ {
XMRInstance next = inst.m_NextInst; XMRInstance next = inst.m_NextInst;
XMRInstance prev = inst.m_PrevInst; XMRInstance prev = inst.m_PrevInst;
if ((prev == inst) || (next == inst)) { if((prev == inst) || (next == inst))
throw new Exception("not in a list"); throw new Exception("not in a list");
}
if (next == null) { if(next == null)
if (m_Tail != inst) { {
if(m_Tail != inst)
throw new Exception("not in this list"); throw new Exception("not in this list");
}
m_Tail = prev; m_Tail = prev;
} else { }
else
next.m_PrevInst = prev; next.m_PrevInst = prev;
}
if (prev == null) { if(prev == null)
if (m_Head != inst) { {
if(m_Head != inst)
throw new Exception("not in this list"); throw new Exception("not in this list");
}
m_Head = next; m_Head = next;
} else {
prev.m_NextInst = next;
} }
else
prev.m_NextInst = next;
inst.m_NextInst = inst; inst.m_NextInst = inst;
inst.m_PrevInst = inst; inst.m_PrevInst = inst;
} }

View File

@ -32,11 +32,9 @@ using System.Text;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.ScriptEngine.Interfaces;
using OpenSim.Region.ScriptEngine.Shared; using OpenSim.Region.ScriptEngine.Shared;
using OpenSim.Region.ScriptEngine.Shared.Api; using OpenSim.Region.ScriptEngine.Shared.Api;
using OpenSim.Region.ScriptEngine.Shared.ScriptBase; using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
using OpenSim.Region.ScriptEngine.XMREngine;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
using log4net; using log4net;
@ -48,7 +46,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
public partial class XMRInstance public partial class XMRInstance
{ {
@ -65,7 +63,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
public void PostEvent(EventParams evt) public void PostEvent(EventParams evt)
{ {
ScriptEventCode evc = (ScriptEventCode)Enum.Parse (typeof (ScriptEventCode), ScriptEventCode evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
evt.EventName); evt.EventName);
/* /*
@ -73,7 +71,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
bool startIt = false; bool startIt = false;
bool wakeIt = false; bool wakeIt = false;
lock (m_QueueLock) lock(m_QueueLock)
{ {
bool construct = (m_IState == XMRInstState.CONSTRUCT); bool construct = (m_IState == XMRInstState.CONSTRUCT);
@ -82,49 +80,50 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* We can't be state-specific here because state might be different * We can't be state-specific here because state might be different
* by the time this event is dequeued and delivered to the script. * by the time this event is dequeued and delivered to the script.
*/ */
if (!construct && // make sure m_HaveEventHandlers is filled in if(!construct && // make sure m_HaveEventHandlers is filled in
((uint)evc < (uint)m_HaveEventHandlers.Length) && ((uint)evc < (uint)m_HaveEventHandlers.Length) &&
!m_HaveEventHandlers[(int)evc]) { // don't bother if we don't have such a handler in any state !m_HaveEventHandlers[(int)evc]) // don't bother if we don't have such a handler in any state
return; return;
}
/* /*
* Not running means we ignore any incoming events. * Not running means we ignore any incoming events.
* But queue if still constructing because m_Running is not yet valid. * But queue if still constructing because m_Running is not yet valid.
*/ */
if (!m_Running && !construct) { if(!m_Running && !construct)
return; return;
}
/* /*
* Only so many of each event type allowed to queue. * Only so many of each event type allowed to queue.
*/ */
if ((uint)evc < (uint)m_EventCounts.Length) { if((uint)evc < (uint)m_EventCounts.Length)
int maxAllowed = MAXEVENTQUEUE;
if (evc == ScriptEventCode.timer) maxAllowed = 1;
if (m_EventCounts[(int)evc] >= maxAllowed)
{ {
if(evc == ScriptEventCode.timer)
{
if(m_EventCounts[(int)evc] >= 1)
return; return;
} }
m_EventCounts[(int)evc] ++; else if(m_EventCounts[(int)evc] >= MAXEVENTQUEUE)
return;
m_EventCounts[(int)evc]++;
} }
/* /*
* Put event on end of instance's event queue. * Put event on end of instance's event queue.
*/ */
LinkedListNode<EventParams> lln = new LinkedListNode<EventParams>(evt); LinkedListNode<EventParams> lln = new LinkedListNode<EventParams>(evt);
switch (evc) { switch(evc)
{
/* /*
* These need to go first. The only time we manually * These need to go first. The only time we manually
* queue them is for the default state_entry() and we * queue them is for the default state_entry() and we
* need to make sure they go before any attach() events * need to make sure they go before any attach() events
* so the heapLimit value gets properly initialized. * so the heapLimit value gets properly initialized.
*/ */
case ScriptEventCode.state_entry: { case ScriptEventCode.state_entry:
m_EventQueue.AddFirst(lln); m_EventQueue.AddFirst(lln);
break; break;
}
/* /*
* The attach event sneaks to the front of the queue. * The attach event sneaks to the front of the queue.
@ -134,22 +133,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* before attach(NULL_KEY) is executed. * before attach(NULL_KEY) is executed.
*/ */
case ScriptEventCode.attach: case ScriptEventCode.attach:
{ if(evt.Params[0].ToString() == UUID.Zero.ToString())
if (evt.Params[0].ToString() == UUID.Zero.ToString())
{ {
LinkedListNode<EventParams> lln2 = null; LinkedListNode<EventParams> lln2 = null;
for (lln2 = m_EventQueue.First; lln2 != null; lln2 = lln2.Next) for(lln2 = m_EventQueue.First; lln2 != null; lln2 = lln2.Next)
{ {
EventParams evt2 = lln2.Value; EventParams evt2 = lln2.Value;
ScriptEventCode evc2 = (ScriptEventCode)Enum.Parse (typeof (ScriptEventCode), ScriptEventCode evc2 = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
evt2.EventName); evt2.EventName);
if ((evc2 != ScriptEventCode.state_entry) && if((evc2 != ScriptEventCode.state_entry) &&
(evc2 != ScriptEventCode.attach)) break; (evc2 != ScriptEventCode.attach))
break;
} }
if (lln2 == null) if(lln2 == null)
m_EventQueue.AddLast(lln); m_EventQueue.AddLast(lln);
else else
m_EventQueue.AddBefore(lln2, lln); m_EventQueue.AddBefore(lln2, lln);
/* If we're detaching, limit the qantum. This will also /* If we're detaching, limit the qantum. This will also
* cause the script to self-suspend after running this * cause the script to self-suspend after running this
* event * event
@ -160,18 +160,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
} }
else else
m_EventQueue.AddLast(lln); m_EventQueue.AddLast(lln);
break; break;
}
/* /*
* All others just go on end in the order queued. * All others just go on end in the order queued.
*/ */
default: default:
{
m_EventQueue.AddLast(lln); m_EventQueue.AddLast(lln);
break; break;
} }
}
/* /*
* If instance is idle (ie, not running or waiting to run), * If instance is idle (ie, not running or waiting to run),
@ -180,7 +178,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* to do the same thing right now. * to do the same thing right now.
* Dont' flag it if it's still suspended! * Dont' flag it if it's still suspended!
*/ */
if ((m_IState == XMRInstState.IDLE) && !m_Suspended) if((m_IState == XMRInstState.IDLE) && !m_Suspended)
{ {
m_IState = XMRInstState.ONSTARTQ; m_IState = XMRInstState.ONSTARTQ;
startIt = true; startIt = true;
@ -190,29 +188,27 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* If instance is sleeping (ie, possibly in xmrEventDequeue), * If instance is sleeping (ie, possibly in xmrEventDequeue),
* wake it up if event is in the mask. * wake it up if event is in the mask.
*/ */
if ((m_SleepUntil > DateTime.UtcNow) && !m_Suspended) if((m_SleepUntil > DateTime.UtcNow) && !m_Suspended)
{ {
int evc1 = (int)evc; int evc1 = (int)evc;
int evc2 = evc1 - 32; int evc2 = evc1 - 32;
if ((((uint)evc1 < (uint)32) && (((m_SleepEventMask1 >> evc1) & 1) != 0)) || if((((uint)evc1 < (uint)32) && (((m_SleepEventMask1 >> evc1) & 1) != 0)) ||
(((uint)evc2 < (uint)32) && (((m_SleepEventMask2 >> evc2) & 1) != 0))) (((uint)evc2 < (uint)32) && (((m_SleepEventMask2 >> evc2) & 1) != 0)))
{
wakeIt = true; wakeIt = true;
} }
} }
}
/* /*
* If transitioned from IDLE->ONSTARTQ, actually go insert it * If transitioned from IDLE->ONSTARTQ, actually go insert it
* on m_StartQueue and give the RunScriptThread() a wake-up. * on m_StartQueue and give the RunScriptThread() a wake-up.
*/ */
if (startIt) if(startIt)
m_Engine.QueueToStart(this); m_Engine.QueueToStart(this);
/* /*
* Likewise, if the event mask triggered a wake, wake it up. * Likewise, if the event mask triggered a wake, wake it up.
*/ */
if (wakeIt) if(wakeIt)
{ {
m_SleepUntil = DateTime.MinValue; m_SleepUntil = DateTime.MinValue;
m_Engine.WakeFromSleep(this); m_Engine.WakeFromSleep(this);
@ -234,7 +230,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* up. * up.
*/ */
m_RunOnePhase = "check m_SleepUntil"; m_RunOnePhase = "check m_SleepUntil";
if (m_SleepUntil > now) if(m_SleepUntil > now)
{ {
m_RunOnePhase = "return is sleeping"; m_RunOnePhase = "return is sleeping";
return XMRInstState.ONSLEEPQ; return XMRInstState.ONSLEEPQ;
@ -244,7 +240,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Also, someone may have called Suspend(). * Also, someone may have called Suspend().
*/ */
m_RunOnePhase = "check m_SuspendCount"; m_RunOnePhase = "check m_SuspendCount";
if (m_SuspendCount > 0) if(m_SuspendCount > 0)
{ {
m_RunOnePhase = "return is suspended"; m_RunOnePhase = "return is suspended";
return XMRInstState.SUSPENDED; return XMRInstState.SUSPENDED;
@ -256,7 +252,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* back right away, delay a bit so we don't get in infinite loop. * back right away, delay a bit so we don't get in infinite loop.
*/ */
m_RunOnePhase = "lock m_RunLock"; m_RunOnePhase = "lock m_RunLock";
if (!Monitor.TryEnter (m_RunLock)) if(!Monitor.TryEnter(m_RunLock))
{ {
m_SleepUntil = now.AddMilliseconds(3); m_SleepUntil = now.AddMilliseconds(3);
m_RunOnePhase = "return was locked"; m_RunOnePhase = "return was locked";
@ -269,23 +265,22 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
Exception e = null; Exception e = null;
/* /*
* Maybe we have been disposed. * Maybe it has been Disposed()
*/ */
m_RunOnePhase = "check disposed"; if(m_Part == null)
if (microthread == null)
{ {
m_RunOnePhase = "return disposed"; m_RunOnePhase = "runone saw it disposed";
return XMRInstState.DISPOSED; return XMRInstState.DISPOSED;
} }
/* /*
* Do some more of the last event if it didn't finish. * Do some more of the last event if it didn't finish.
*/ */
else if (eventCode != ScriptEventCode.None) if(this.eventCode != ScriptEventCode.None)
{ {
lock (m_QueueLock) lock(m_QueueLock)
{ {
if (m_DetachQuantum > 0 && --m_DetachQuantum == 0) if(m_DetachQuantum > 0 && --m_DetachQuantum == 0)
{ {
m_Suspended = true; m_Suspended = true;
m_DetachReady.Set(); m_DetachReady.Set();
@ -297,9 +292,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
m_RunOnePhase = "resume old event handler"; m_RunOnePhase = "resume old event handler";
m_LastRanAt = now; m_LastRanAt = now;
m_InstEHSlice ++; m_InstEHSlice++;
callMode = CallMode_NORMAL; callMode = CallMode_NORMAL;
e = microthread.ResumeEx (); e = ResumeEx();
} }
/* /*
@ -312,7 +307,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
EventParams evt = null; EventParams evt = null;
ScriptEventCode evc = ScriptEventCode.None; ScriptEventCode evc = ScriptEventCode.None;
lock (m_QueueLock) lock(m_QueueLock)
{ {
/* We can't get here unless the script has been resumed /* We can't get here unless the script has been resumed
@ -324,7 +319,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* out and may be improved in the future. * out and may be improved in the future.
*/ */
if (m_Suspended) if(m_Suspended)
{ {
m_RunOnePhase = "m_Suspended is set"; m_RunOnePhase = "m_Suspended is set";
CheckRunLockInvariants(true); CheckRunLockInvariants(true);
@ -332,14 +327,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
} }
m_RunOnePhase = "dequeue event"; m_RunOnePhase = "dequeue event";
if (m_EventQueue.First != null) if(m_EventQueue.First != null)
{ {
evt = m_EventQueue.First.Value; evt = m_EventQueue.First.Value;
evc = (ScriptEventCode)Enum.Parse (typeof (ScriptEventCode), if(m_DetachQuantum > 0)
evt.EventName);
if (m_DetachQuantum > 0)
{ {
if (evc != ScriptEventCode.attach) evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
evt.EventName);
if(evc != ScriptEventCode.attach)
{ {
/* /*
* This is the case where the attach event * This is the case where the attach event
@ -355,17 +350,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
} }
} }
m_EventQueue.RemoveFirst(); m_EventQueue.RemoveFirst();
if (evc >= 0) evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
m_EventCounts[(int)evc] --; evt.EventName);
if((int)evc >= 0)
m_EventCounts[(int)evc]--;
} }
/* /*
* If there is no event to dequeue, don't run this script * If there is no event to dequeue, don't run this script
* until another event gets queued. * until another event gets queued.
*/ */
if (evt == null) if(evt == null)
{ {
if (m_DetachQuantum > 0) if(m_DetachQuantum > 0)
{ {
/* /*
* This will happen if the attach event has run * This will happen if the attach event has run
@ -388,8 +385,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
m_RunOnePhase = "start event handler"; m_RunOnePhase = "start event handler";
m_DetectParams = evt.DetectParams; m_DetectParams = evt.DetectParams;
m_LastRanAt = now; m_LastRanAt = now;
m_InstEHEvent ++; m_InstEHEvent++;
e = StartEventHandler (evc, evt.Params); e = StartEventHandler(evc, evt.Params);
} }
m_RunOnePhase = "done running"; m_RunOnePhase = "done running";
m_CPUTime += DateTime.UtcNow.Subtract(now).TotalMilliseconds; m_CPUTime += DateTime.UtcNow.Subtract(now).TotalMilliseconds;
@ -397,7 +394,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/* /*
* Maybe it puqued. * Maybe it puqued.
*/ */
if (e != null) if(e != null)
{ {
m_RunOnePhase = "handling exception " + e.Message; m_RunOnePhase = "handling exception " + e.Message;
HandleScriptException(e); HandleScriptException(e);
@ -409,10 +406,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/* /*
* If event handler completed, get rid of detect params. * If event handler completed, get rid of detect params.
*/ */
if (this.eventCode == ScriptEventCode.None) if(this.eventCode == ScriptEventCode.None)
{
m_DetectParams = null; m_DetectParams = null;
}
} }
finally finally
{ {
@ -432,34 +428,31 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @brief Immediately after taking m_RunLock or just before releasing it, check invariants. * @brief Immediately after taking m_RunLock or just before releasing it, check invariants.
*/ */
private ScriptEventCode lastEventCode = ScriptEventCode.None; private ScriptEventCode lastEventCode = ScriptEventCode.None;
private int lastActive = 0; private bool lastActive = false;
private string lastRunPhase = ""; private string lastRunPhase = "";
public void CheckRunLockInvariants(bool throwIt) public void CheckRunLockInvariants(bool throwIt)
{ {
/* /*
* If not executing any event handler, active should be 0 indicating the microthread stack is not in use. * If not executing any event handler, there shouldn't be any saved stack frames.
* If executing an event handler, active should be -1 indicating stack is in use but suspended. * If executing an event handler, there should be some saved stack frames.
*/ */
IScriptUThread uth = microthread; bool active = (stackFrames != null);
if (uth != null) {
int active = uth.Active ();
ScriptEventCode ec = this.eventCode; ScriptEventCode ec = this.eventCode;
if (((ec == ScriptEventCode.None) && (active != 0)) || if(((ec == ScriptEventCode.None) && active) ||
((ec != ScriptEventCode.None) && (active >= 0))) { ((ec != ScriptEventCode.None) && !active))
{
Console.WriteLine("CheckRunLockInvariants: script=" + m_DescName); Console.WriteLine("CheckRunLockInvariants: script=" + m_DescName);
Console.WriteLine("CheckRunLockInvariants: eventcode=" + ec.ToString() + ", active=" + active.ToString()); Console.WriteLine("CheckRunLockInvariants: eventcode=" + ec.ToString() + ", active=" + active.ToString());
Console.WriteLine("CheckRunLockInvariants: m_RunOnePhase=" + m_RunOnePhase); Console.WriteLine("CheckRunLockInvariants: m_RunOnePhase=" + m_RunOnePhase);
Console.WriteLine("CheckRunLockInvariants: lastec=" + lastEventCode + ", lastAct=" + lastActive + ", lastPhase=" + lastRunPhase); Console.WriteLine("CheckRunLockInvariants: lastec=" + lastEventCode + ", lastAct=" + lastActive + ", lastPhase=" + lastRunPhase);
if (throwIt) { if(throwIt)
throw new Exception("CheckRunLockInvariants: eventcode=" + ec.ToString() + ", active=" + active.ToString()); throw new Exception("CheckRunLockInvariants: eventcode=" + ec.ToString() + ", active=" + active.ToString());
} }
}
lastEventCode = ec; lastEventCode = ec;
lastActive = active; lastActive = active;
lastRunPhase = m_RunOnePhase; lastRunPhase = m_RunOnePhase;
} }
}
/* /*
* Start event handler. * Start event handler.
@ -475,31 +468,27 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* from ehArgs[] and will throw an array bounds or cast exception * from ehArgs[] and will throw an array bounds or cast exception
* if it can't. * if it can't.
*/ */
private Exception StartEventHandler (ScriptEventCode eventCode, object[] ehArgs) private Exception StartEventHandler(ScriptEventCode eventCode, object[] ehArgs)
{ {
/* /*
* We use this.eventCode == ScriptEventCode.None to indicate we are idle. * We use this.eventCode == ScriptEventCode.None to indicate we are idle.
* So trying to execute ScriptEventCode.None might make a mess. * So trying to execute ScriptEventCode.None might make a mess.
*/ */
if (eventCode == ScriptEventCode.None) if(eventCode == ScriptEventCode.None)
return new Exception ("Can't process ScriptEventCode.None"); return new Exception("Can't process ScriptEventCode.None");
/* /*
* Silly to even try if there is no handler defined for this event. * Silly to even try if there is no handler defined for this event.
*/ */
if ((eventCode >= 0) && (m_ObjCode.scriptEventHandlerTable[this.stateCode,(int)eventCode] == null)) if(((int)eventCode >= 0) && (m_ObjCode.scriptEventHandlerTable[this.stateCode, (int)eventCode] == null))
return null; return null;
/* /*
* The microthread shouldn't be processing any event code. * The microthread shouldn't be processing any event code.
* These are assert checks so we throw them directly as exceptions. * These are assert checks so we throw them directly as exceptions.
*/ */
if (this.eventCode != ScriptEventCode.None) if(this.eventCode != ScriptEventCode.None)
throw new Exception ("still processing event " + this.eventCode.ToString ()); throw new Exception("still processing event " + this.eventCode.ToString());
int active = microthread.Active ();
if (active != 0)
throw new Exception ("microthread is active " + active.ToString ());
/* /*
* Save eventCode so we know what event handler to run in the microthread. * Save eventCode so we know what event handler to run in the microthread.
@ -515,9 +504,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* without doing any stack frame restores first. * without doing any stack frame restores first.
*/ */
this.stackFrames = null; this.stackFrames = null;
Exception e; return StartEx();
e = microthread.StartEx ();
return e;
} }
@ -533,17 +520,17 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
eventCode = ScriptEventCode.None; eventCode = ScriptEventCode.None;
if (e is ScriptDeleteException) if(e is ScriptDeleteException)
{ {
/* /*
* Script did something like llRemoveInventory(llGetScriptName()); * Script did something like llRemoveInventory(llGetScriptName());
* ... to delete itself from the object. * ... to delete itself from the object.
*/ */
m_SleepUntil = DateTime.MaxValue; m_SleepUntil = DateTime.MaxValue;
Verbose ("[XMREngine]: script self-delete {0}", m_ItemID); Verbose("[YEngine]: script self-delete {0}", m_ItemID);
m_Part.Inventory.RemoveInventoryItem(m_ItemID); m_Part.Inventory.RemoveInventoryItem(m_ItemID);
} }
else if (e is ScriptDieException) else if(e is ScriptDieException)
{ {
/* /*
* Script did an llDie() * Script did an llDie()
@ -552,7 +539,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
m_SleepUntil = DateTime.MaxValue; m_SleepUntil = DateTime.MaxValue;
m_Engine.World.DeleteSceneObject(m_Part.ParentGroup, false); m_Engine.World.DeleteSceneObject(m_Part.ParentGroup, false);
} }
else if (e is ScriptResetException) else if(e is ScriptResetException)
{ {
/* /*
* Script did an llResetScript(). * Script did an llResetScript().
@ -579,63 +566,68 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{ {
StringBuilder msg = new StringBuilder(); StringBuilder msg = new StringBuilder();
msg.Append ("[XMREngine]: Exception while running "); msg.Append("[YEngine]: Exception while running ");
msg.Append (m_ItemID); msg.Append(m_ItemID);
msg.Append ('\n'); msg.Append('\n');
/* /*
* Add exception message. * Add exception message.
*/ */
string des = e.Message; string des = e.Message;
des = (des == null) ? "" : (": " + des); des = (des == null) ? "" : (": " + des);
msg.Append (e.GetType ().Name + des + "\n"); msg.Append(e.GetType().Name + des + "\n");
/* /*
* Tell script owner what to do. * Tell script owner what to do.
*/ */
msg.Append ("Prim: <"); msg.Append("Prim: <");
msg.Append (m_Part.Name); msg.Append(m_Part.Name);
msg.Append (">, Script: <"); msg.Append(">, Script: <");
msg.Append (m_Item.Name); msg.Append(m_Item.Name);
msg.Append (">, Location: "); msg.Append(">, Location: ");
msg.Append (m_Engine.World.RegionInfo.RegionName); msg.Append(m_Engine.World.RegionInfo.RegionName);
msg.Append (" <"); msg.Append(" <");
Vector3 pos = m_Part.AbsolutePosition; Vector3 pos = m_Part.AbsolutePosition;
msg.Append ((int) Math.Floor (pos.X)); msg.Append((int)Math.Floor(pos.X));
msg.Append (','); msg.Append(',');
msg.Append ((int) Math.Floor (pos.Y)); msg.Append((int)Math.Floor(pos.Y));
msg.Append (','); msg.Append(',');
msg.Append ((int) Math.Floor (pos.Z)); msg.Append((int)Math.Floor(pos.Z));
msg.Append (">\nScript must be Reset to re-enable.\n"); msg.Append(">\nScript must be Reset to re-enable.\n");
/* /*
* Display full exception message in log. * Display full exception message in log.
*/ */
m_log.Info (msg.ToString() + XMRExceptionStackString (e), e); m_log.Info(msg.ToString() + XMRExceptionStackString(e), e);
/* /*
* Give script owner the stack dump. * Give script owner the stack dump.
*/ */
msg.Append (XMRExceptionStackString (e)); msg.Append(XMRExceptionStackString(e));
/* /*
* Send error message to owner. * Send error message to owner.
* Suppress internal code stack trace lines. * Suppress internal code stack trace lines.
*/ */
string msgst = msg.ToString(); string msgst = msg.ToString();
if (!msgst.EndsWith ("\n")) msgst += '\n'; if(!msgst.EndsWith("\n"))
msgst += '\n';
int j = 0; int j = 0;
StringBuilder imstr = new StringBuilder (); StringBuilder imstr = new StringBuilder();
for (int i = 0; (i = msgst.IndexOf ('\n', i)) >= 0; j = ++ i) { for(int i = 0; (i = msgst.IndexOf('\n', i)) >= 0; j = ++i)
string line = msgst.Substring (j, i - j); {
if (line.StartsWith ("at ")) { string line = msgst.Substring(j, i - j);
if (line.StartsWith ("at (wrapper")) continue; // at (wrapper ... if(line.StartsWith("at "))
int k = line.LastIndexOf (".cs:"); // ... .cs:linenumber {
if (Int32.TryParse (line.Substring (k + 4), out k)) continue; if(line.StartsWith("at (wrapper"))
continue; // at (wrapper ...
int k = line.LastIndexOf(".cs:"); // ... .cs:linenumber
if(Int32.TryParse(line.Substring(k + 4), out k))
continue;
} }
this.llOwnerSay (line); this.llOwnerSay(line);
imstr.Append (line); imstr.Append(line);
imstr.Append ('\n'); imstr.Append('\n');
} }
/* /*
@ -643,14 +635,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Code modelled from llInstantMessage(). * Code modelled from llInstantMessage().
*/ */
IMessageTransferModule transferModule = m_Engine.World.RequestModuleInterface<IMessageTransferModule>(); IMessageTransferModule transferModule = m_Engine.World.RequestModuleInterface<IMessageTransferModule>();
if (transferModule != null) { if(transferModule != null)
{
UUID friendTransactionID = UUID.Random(); UUID friendTransactionID = UUID.Random();
GridInstantMessage gim = new GridInstantMessage(); GridInstantMessage gim = new GridInstantMessage();
gim.fromAgentID = new Guid (m_Part.UUID.ToString()); gim.fromAgentID = new Guid(m_Part.UUID.ToString());
gim.toAgentID = new Guid (m_Part.OwnerID.ToString ()); gim.toAgentID = new Guid(m_Part.OwnerID.ToString());
gim.imSessionID = new Guid(friendTransactionID.ToString()); gim.imSessionID = new Guid(friendTransactionID.ToString());
gim.timestamp = (uint)Util.UnixTimeSinceEpoch(); gim.timestamp = (uint)Util.UnixTimeSinceEpoch();
gim.message = imstr.ToString (); gim.message = imstr.ToString();
gim.dialog = (byte)19; // messgage from script gim.dialog = (byte)19; // messgage from script
gim.fromGroup = false; gim.fromGroup = false;
gim.offline = (byte)0; gim.offline = (byte)0;
@ -663,7 +656,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
(int)Math.Floor(pos.X), (int)Math.Floor(pos.X),
(int)Math.Floor(pos.Y), (int)Math.Floor(pos.Y),
(int)Math.Floor(pos.Z)); (int)Math.Floor(pos.Z));
transferModule.SendInstantMessage(gim, delegate(bool success) {}); transferModule.SendInstantMessage(gim, delegate (bool success)
{
});
} }
/* /*
@ -681,14 +676,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{ {
checkstate: checkstate:
XMRInstState iState = m_IState; XMRInstState iState = m_IState;
switch (iState) { switch(iState)
{
/* /*
* If it's really being constructed now, that's about as reset as we get. * If it's really being constructed now, that's about as reset as we get.
*/ */
case XMRInstState.CONSTRUCT: { case XMRInstState.CONSTRUCT:
return; return;
}
/* /*
* If it's idle, that means it is ready to receive a new event. * If it's idle, that means it is ready to receive a new event.
@ -696,15 +690,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* it out of idle, verify that it is still in idle then transition * it out of idle, verify that it is still in idle then transition
* it to resetting so no other thread will touch it. * it to resetting so no other thread will touch it.
*/ */
case XMRInstState.IDLE: { case XMRInstState.IDLE:
lock (m_QueueLock) { lock(m_QueueLock)
if (m_IState == XMRInstState.IDLE) { {
if(m_IState == XMRInstState.IDLE)
{
m_IState = XMRInstState.RESETTING; m_IState = XMRInstState.RESETTING;
break; break;
} }
} }
goto checkstate; goto checkstate;
}
/* /*
* If it's on the start queue, that means it is about to dequeue an * If it's on the start queue, that means it is about to dequeue an
@ -712,112 +707,108 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* can't be started and transition it to resetting so no other thread * can't be started and transition it to resetting so no other thread
* will touch it. * will touch it.
*/ */
case XMRInstState.ONSTARTQ: { case XMRInstState.ONSTARTQ:
lock (m_Engine.m_StartQueue) { lock(m_Engine.m_StartQueue)
if (m_IState == XMRInstState.ONSTARTQ) { {
if(m_IState == XMRInstState.ONSTARTQ)
{
m_Engine.m_StartQueue.Remove(this); m_Engine.m_StartQueue.Remove(this);
m_IState = XMRInstState.RESETTING; m_IState = XMRInstState.RESETTING;
break; break;
} }
} }
goto checkstate; goto checkstate;
}
/* /*
* If it's running, tell CheckRun() to suspend the thread then go back * If it's running, tell CheckRun() to suspend the thread then go back
* to see what it got transitioned to. * to see what it got transitioned to.
*/ */
case XMRInstState.RUNNING: { case XMRInstState.RUNNING:
suspendOnCheckRunHold = true; suspendOnCheckRunHold = true;
lock (m_QueueLock) { } lock(m_QueueLock)
goto checkstate; {
} }
goto checkstate;
/* /*
* If it's sleeping, remove it from sleep queue and transition it to * If it's sleeping, remove it from sleep queue and transition it to
* resetting so no other thread will touch it. * resetting so no other thread will touch it.
*/ */
case XMRInstState.ONSLEEPQ: { case XMRInstState.ONSLEEPQ:
lock (m_Engine.m_SleepQueue) { lock(m_Engine.m_SleepQueue)
if (m_IState == XMRInstState.ONSLEEPQ) { {
if(m_IState == XMRInstState.ONSLEEPQ)
{
m_Engine.m_SleepQueue.Remove(this); m_Engine.m_SleepQueue.Remove(this);
m_IState = XMRInstState.RESETTING; m_IState = XMRInstState.RESETTING;
break; break;
} }
} }
goto checkstate; goto checkstate;
}
/* /*
* It was just removed from the sleep queue and is about to be put * It was just removed from the sleep queue and is about to be put
* on the yield queue (ie, is being woken up). * on the yield queue (ie, is being woken up).
* Let that thread complete transition and try again. * Let that thread complete transition and try again.
*/ */
case XMRInstState.REMDFROMSLPQ: { case XMRInstState.REMDFROMSLPQ:
Sleep (10); Sleep(10);
goto checkstate; goto checkstate;
}
/* /*
* If it's yielding, remove it from yield queue and transition it to * If it's yielding, remove it from yield queue and transition it to
* resetting so no other thread will touch it. * resetting so no other thread will touch it.
*/ */
case XMRInstState.ONYIELDQ: { case XMRInstState.ONYIELDQ:
lock (m_Engine.m_YieldQueue) { lock(m_Engine.m_YieldQueue)
if (m_IState == XMRInstState.ONYIELDQ) { {
if(m_IState == XMRInstState.ONYIELDQ)
{
m_Engine.m_YieldQueue.Remove(this); m_Engine.m_YieldQueue.Remove(this);
m_IState = XMRInstState.RESETTING; m_IState = XMRInstState.RESETTING;
break; break;
} }
} }
goto checkstate; goto checkstate;
}
/* /*
* If it just finished running something, let that thread transition it * If it just finished running something, let that thread transition it
* to its next state then check again. * to its next state then check again.
*/ */
case XMRInstState.FINISHED: { case XMRInstState.FINISHED:
Sleep (10); Sleep(10);
goto checkstate; goto checkstate;
}
/* /*
* If it's disposed, that's about as reset as it gets. * If it's disposed, that's about as reset as it gets.
*/ */
case XMRInstState.DISPOSED: { case XMRInstState.DISPOSED:
return; return;
}
/* /*
* Some other thread is already resetting it, let it finish. * Some other thread is already resetting it, let it finish.
*/ */
case XMRInstState.RESETTING: { case XMRInstState.RESETTING:
return; return;
}
default: throw new Exception("bad state");
default:
throw new Exception("bad state");
} }
/* /*
* This thread transitioned the instance to RESETTING so reset it. * This thread transitioned the instance to RESETTING so reset it.
*/ */
lock (m_RunLock) { lock(m_RunLock)
{
CheckRunLockInvariants(true); CheckRunLockInvariants(true);
/* /*
* No other thread should have transitioned it from RESETTING. * No other thread should have transitioned it from RESETTING.
*/ */
if (m_IState != XMRInstState.RESETTING) throw new Exception("bad state"); if(m_IState != XMRInstState.RESETTING)
throw new Exception("bad state");
/*
* If the microthread is active, that means it has call frame
* context that we don't want. Throw it out and get a fresh one.
*/
if (microthread.Active () < 0) {
microthread.Dispose ();
microthread = (IScriptUThread)m_Engine.uThreadCtor.Invoke (new object[] { this });
}
/* /*
* Mark it idle now so it can get queued to process new stuff. * Mark it idle now so it can get queued to process new stuff.
@ -836,21 +827,22 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private void ClearQueueExceptLinkMessages() private void ClearQueueExceptLinkMessages()
{ {
lock (m_QueueLock) { lock(m_QueueLock)
{
EventParams[] linkMessages = new EventParams[m_EventQueue.Count]; EventParams[] linkMessages = new EventParams[m_EventQueue.Count];
int n = 0; int n = 0;
foreach (EventParams evt2 in m_EventQueue) { foreach(EventParams evt2 in m_EventQueue)
if (evt2.EventName == "link_message") { {
if(evt2.EventName == "link_message")
linkMessages[n++] = evt2; linkMessages[n++] = evt2;
} }
}
m_EventQueue.Clear(); m_EventQueue.Clear();
for (int i = m_EventCounts.Length; -- i >= 0;) m_EventCounts[i] = 0; for(int i = m_EventCounts.Length; --i >= 0;)
m_EventCounts[i] = 0;
for (int i = 0; i < n; i ++) { for(int i = 0; i < n; i++)
m_EventQueue.AddLast(linkMessages[i]); m_EventQueue.AddLast(linkMessages[i]);
}
m_EventCounts[(int)ScriptEventCode.link_message] = n; m_EventCounts[(int)ScriptEventCode.link_message] = n;
} }
@ -858,10 +850,11 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private void ClearQueue() private void ClearQueue()
{ {
lock (m_QueueLock) lock(m_QueueLock)
{ {
m_EventQueue.Clear(); // no events queued m_EventQueue.Clear(); // no events queued
for (int i = m_EventCounts.Length; -- i >= 0;) m_EventCounts[i] = 0; for(int i = m_EventCounts.Length; --i >= 0;)
m_EventCounts[i] = 0;
} }
} }
@ -882,7 +875,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
m_Part.Inventory.GetInventoryItem(m_ItemID).PermsMask = 0; m_Part.Inventory.GetInventoryItem(m_ItemID).PermsMask = 0;
m_Part.Inventory.GetInventoryItem(m_ItemID).PermsGranter = UUID.Zero; m_Part.Inventory.GetInventoryItem(m_ItemID).PermsGranter = UUID.Zero;
IUrlModule urlModule = m_Engine.World.RequestModuleInterface<IUrlModule>(); IUrlModule urlModule = m_Engine.World.RequestModuleInterface<IUrlModule>();
if (urlModule != null) if(urlModule != null)
urlModule.ScriptRemoved(m_ItemID); urlModule.ScriptRemoved(m_ItemID);
AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID); AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID);
@ -891,7 +884,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
this.eventCode = ScriptEventCode.None; // not processing an event this.eventCode = ScriptEventCode.None; // not processing an event
m_DetectParams = null; // not processing an event m_DetectParams = null; // not processing an event
m_SleepUntil = DateTime.MinValue; // not doing llSleep() m_SleepUntil = DateTime.MinValue; // not doing llSleep()
m_ResetCount ++; // has been reset once more m_ResetCount++; // has been reset once more
/* /*
* Tell next call to 'default state_entry()' to reset all global * Tell next call to 'default state_entry()' to reset all global
@ -920,90 +913,85 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private void ReleaseControls() private void ReleaseControls()
{ {
if (m_Part != null) if(m_Part != null)
{ {
bool found; bool found;
int permsMask; int permsMask;
UUID permsGranter; UUID permsGranter;
try { try
{
permsGranter = m_Part.TaskInventory[m_ItemID].PermsGranter; permsGranter = m_Part.TaskInventory[m_ItemID].PermsGranter;
permsMask = m_Part.TaskInventory[m_ItemID].PermsMask; permsMask = m_Part.TaskInventory[m_ItemID].PermsMask;
found = true; found = true;
} catch { }
catch
{
permsGranter = UUID.Zero; permsGranter = UUID.Zero;
permsMask = 0; permsMask = 0;
found = false; found = false;
} }
if (found && ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)) { if(found && ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0))
{
ScenePresence presence = m_Engine.World.GetScenePresence(permsGranter); ScenePresence presence = m_Engine.World.GetScenePresence(permsGranter);
if (presence != null) { if(presence != null)
presence.UnRegisterControlEventsToScript(m_LocalID, m_ItemID); presence.UnRegisterControlEventsToScript(m_LocalID, m_ItemID);
} }
} }
} }
}
/** /**
* @brief The script code should call this routine whenever it is * @brief The script code should call this routine whenever it is
* convenient to perform a migation or switch microthreads. * convenient to perform a migation or switch microthreads.
*/ */
public override void CheckRunWork () public override void CheckRunWork()
{ {
if(!suspendOnCheckRunHold && ! suspendOnCheckRunTemp) if(!suspendOnCheckRunHold && !suspendOnCheckRunTemp)
{ {
if(Util.GetTimeStampMS() - m_SliceStart < 60.0) if(Util.GetTimeStampMS() - m_SliceStart < 60.0)
return; return;
suspendOnCheckRunTemp = true; suspendOnCheckRunTemp = true;
} }
m_CheckRunPhase = "entered"; m_CheckRunPhase = "entered";
/* /*
* Stay stuck in this loop as long as something wants us suspended. * Stay stuck in this loop as long as something wants us suspended.
*/ */
while (suspendOnCheckRunHold || suspendOnCheckRunTemp) while(suspendOnCheckRunHold || suspendOnCheckRunTemp)
{ {
m_CheckRunPhase = "top of while"; m_CheckRunPhase = "top of while";
/*
* See if MigrateOutEventHandler() has been called.
* If so, dump our stack to stackFrames and unwind.
*/
if (this.captureStackFrames)
{
/*
* Puque our stack to the output stream.
* But otherwise, our state remains intact.
*/
m_CheckRunPhase = "saving";
this.callMode = CallMode_SAVE;
this.stackFrames = null;
throw new StackCaptureException ();
}
/*
* We get here when the script state has been read in by MigrateInEventHandler().
* Since the stack is completely restored at this point, any subsequent calls
* within the functions should do their normal processing instead of trying to
* restore their state.
*/
if (this.callMode == CallMode_RESTORE)
{
stackFramesRestored = true;
this.callMode = CallMode_NORMAL;
}
/*
* Now we are ready to suspend the microthread.
* This is like a longjmp() to the most recent StartEx() or ResumeEx()
* with a simultaneous setjmp() so ResumeEx() can longjmp() back here.
*/
m_CheckRunPhase = "suspending";
suspendOnCheckRunTemp = false; suspendOnCheckRunTemp = false;
microthread.Hiber ();
switch(this.callMode)
{
// Now we are ready to suspend the microthread.
// This is like a longjmp() to the most recent StartEx() or ResumeEx()
// with a simultaneous setjmp() so ResumeEx() can longjmp() back here.
// the script event handler wants to hibernate
// capture stack frames and unwind to Start() or Resume()
case CallMode_NORMAL:
m_CheckRunPhase = "suspending";
callMode = XMRInstance.CallMode_SAVE;
stackFrames = null;
throw new StackHibernateException();
// We get here when the script state has been read in by MigrateInEventHandler().
// Since the stack is completely restored at this point, any subsequent calls
// within the functions should do their normal processing instead of trying to
// restore their state.
// the stack has been restored as a result of calling ResumeEx()
// tell script code to process calls normally
case CallMode_RESTORE:
this.callMode = CallMode_NORMAL;
break;
default:
throw new Exception("callMode=" + callMode);
}
m_CheckRunPhase = "resumed"; m_CheckRunPhase = "resumed";
} }
@ -1013,7 +1001,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Upon return from CheckRun() it should always be the case that the script is * Upon return from CheckRun() it should always be the case that the script is
* going to process calls normally, neither saving nor restoring stack frame state. * going to process calls normally, neither saving nor restoring stack frame state.
*/ */
if (callMode != CallMode_NORMAL) throw new Exception ("bad callMode " + callMode); if(callMode != CallMode_NORMAL)
throw new Exception("bad callMode " + callMode);
} }
/** /**
@ -1021,12 +1010,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
public void ResumeIt() public void ResumeIt()
{ {
lock (m_QueueLock) lock(m_QueueLock)
{ {
m_Suspended = false; m_Suspended = false;
if ((m_EventQueue != null) && if((m_EventQueue != null) &&
(m_EventQueue.First != null) && (m_EventQueue.First != null) &&
(m_IState == XMRInstState.IDLE)) { (m_IState == XMRInstState.IDLE))
{
m_IState = XMRInstState.ONSTARTQ; m_IState = XMRInstState.ONSTARTQ;
m_Engine.QueueToStart(this); m_Engine.QueueToStart(this);
} }
@ -1039,7 +1029,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/ */
public void SuspendIt() public void SuspendIt()
{ {
lock (m_QueueLock) lock(m_QueueLock)
{ {
m_Suspended = true; m_Suspended = true;
} }
@ -1052,5 +1042,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* to intercept this exception as it would block the stack capture * to intercept this exception as it would block the stack capture
* functionality. * functionality.
*/ */
public class StackCaptureException : Exception, IXMRUncatchable { } public class StackCaptureException: Exception, IXMRUncatchable
{
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine namespace OpenSim.Region.ScriptEngine.Yengine
{ {
public class XMRSDTypeClObj public class XMRSDTypeClObj
{ {
@ -69,10 +69,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Called by script's $new() to initialize a new object. * @brief Called by script's $new() to initialize a new object.
*/ */
public XMRSDTypeClObj (XMRInstAbstract inst, int classindex) public XMRSDTypeClObj(XMRInstAbstract inst, int classindex)
{ {
Construct (inst, classindex); Construct(inst, classindex);
instVars.AllocVarArrays (sdtcClass.instSizes); instVars.AllocVarArrays(sdtcClass.instSizes);
} }
/** /**
@ -81,26 +81,28 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @param classindex = which script-defined type class this object is an onstance of * @param classindex = which script-defined type class this object is an onstance of
* @returns with the vtables filled in * @returns with the vtables filled in
*/ */
private void Construct (XMRInstAbstract inst, int classindex) private void Construct(XMRInstAbstract inst, int classindex)
{ {
Delegate[] thisMid = null; Delegate[] thisMid = null;
TokenDeclSDTypeClass clas = (TokenDeclSDTypeClass)inst.m_ObjCode.sdObjTypesIndx[classindex]; TokenDeclSDTypeClass clas = (TokenDeclSDTypeClass)inst.m_ObjCode.sdObjTypesIndx[classindex];
xmrInst = inst; xmrInst = inst;
sdtcClass = clas; sdtcClass = clas;
instVars = new XMRInstArrays (inst); instVars = new XMRInstArrays(inst);
/* /*
* VTable consists of delegates built from DynamicMethods and the 'this' pointer. * VTable consists of delegates built from DynamicMethods and the 'this' pointer.
* Yes, yes, lots of shitty little mallocs. * Yes, yes, lots of shitty little mallocs.
*/ */
DynamicMethod[] vDynMeths = clas.vDynMeths; DynamicMethod[] vDynMeths = clas.vDynMeths;
if (vDynMeths != null) { if(vDynMeths != null)
{
int n = vDynMeths.Length; int n = vDynMeths.Length;
Type[] vMethTypes = clas.vMethTypes; Type[] vMethTypes = clas.vMethTypes;
sdtcVTable = new Delegate[n]; sdtcVTable = new Delegate[n];
for (int i = 0; i < n; i ++) { for(int i = 0; i < n; i++)
sdtcVTable[i] = vDynMeths[i].CreateDelegate (vMethTypes[i], this); {
sdtcVTable[i] = vDynMeths[i].CreateDelegate(vMethTypes[i], this);
} }
} }
@ -114,10 +116,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* So we end up with this: * So we end up with this:
* sdtcITable[interfacenumber][methodofintfnumber] = delegate of this.ourimplementationofinterfacesmethod * sdtcITable[interfacenumber][methodofintfnumber] = delegate of this.ourimplementationofinterfacesmethod
*/ */
if (clas.iDynMeths != null) { if(clas.iDynMeths != null)
{
int nIFaces = clas.iDynMeths.Length; int nIFaces = clas.iDynMeths.Length;
sdtcITable = new Delegate[nIFaces][]; sdtcITable = new Delegate[nIFaces][];
for (int i = 0; i < nIFaces; i ++) { for(int i = 0; i < nIFaces; i++)
{
// get vector of entrypoints of our instance methods that implement that interface // get vector of entrypoints of our instance methods that implement that interface
DynamicMethod[] iDynMeths = clas.iDynMeths[i]; DynamicMethod[] iDynMeths = clas.iDynMeths[i];
@ -126,21 +130,26 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// allocate an array with a slot for each method the interface defines // allocate an array with a slot for each method the interface defines
int nMeths = iDynMeths.Length; int nMeths = iDynMeths.Length;
Delegate[] ivec; Delegate[] ivec;
if (nMeths > 0) { if(nMeths > 0)
{
// fill in the array with delegates that reference back to this class instance // fill in the array with delegates that reference back to this class instance
ivec = new Delegate[nMeths]; ivec = new Delegate[nMeths];
for (int j = 0; j < nMeths; j ++) { for(int j = 0; j < nMeths; j++)
ivec[j] = iDynMeths[j].CreateDelegate (iMethTypes[j], this); {
ivec[j] = iDynMeths[j].CreateDelegate(iMethTypes[j], this);
} }
} else { }
else
{
// just a marker interface with no methods, // just a marker interface with no methods,
// allocate a one-element array and fill // allocate a one-element array and fill
// with a dummy entry. this will allow casting // with a dummy entry. this will allow casting
// back to the original class instance (this) // back to the original class instance (this)
// by reading Target of entry 0. // by reading Target of entry 0.
if (thisMid == null) { if(thisMid == null)
{
thisMid = new Delegate[1]; thisMid = new Delegate[1];
thisMid[0] = markerInterfaceDummy.CreateDelegate (typeof (MarkerInterfaceDummy), this); thisMid[0] = markerInterfaceDummy.CreateDelegate(typeof(MarkerInterfaceDummy), this);
} }
ivec = thisMid; ivec = thisMid;
} }
@ -151,13 +160,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
} }
} }
private delegate void MarkerInterfaceDummy (); private delegate void MarkerInterfaceDummy();
private static DynamicMethod markerInterfaceDummy = MakeMarkerInterfaceDummy (); private static DynamicMethod markerInterfaceDummy = MakeMarkerInterfaceDummy();
private static DynamicMethod MakeMarkerInterfaceDummy () private static DynamicMethod MakeMarkerInterfaceDummy()
{ {
DynamicMethod dm = new DynamicMethod ("XMRSDTypeClObj.MarkerInterfaceDummy", null, new Type[] { typeof (XMRSDTypeClObj) }); DynamicMethod dm = new DynamicMethod("XMRSDTypeClObj.MarkerInterfaceDummy", null, new Type[] { typeof(XMRSDTypeClObj) });
ILGenerator ilGen = dm.GetILGenerator (); ILGenerator ilGen = dm.GetILGenerator();
ilGen.Emit (OpCodes.Ret); ilGen.Emit(OpCodes.Ret);
return dm; return dm;
} }
@ -168,9 +177,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @param classindex = what class those implementations are supposedly part of * @param classindex = what class those implementations are supposedly part of
* @returns original script-defined class object * @returns original script-defined class object
*/ */
public static XMRSDTypeClObj CastIFace2Class (Delegate[] da, int classindex) public static XMRSDTypeClObj CastIFace2Class(Delegate[] da, int classindex)
{ {
return CastClass2Class (da[0].Target, classindex); return CastClass2Class(da[0].Target, classindex);
} }
/** /**
@ -179,13 +188,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @param classindex = script-defined class to cast it to * @param classindex = script-defined class to cast it to
* @returns ob is a valid instance of classindex; else exception thrown * @returns ob is a valid instance of classindex; else exception thrown
*/ */
public static XMRSDTypeClObj CastClass2Class (object ob, int classindex) public static XMRSDTypeClObj CastClass2Class(object ob, int classindex)
{ {
/* /*
* Let mono check to see if we at least have an XMRSDTypeClObj. * Let mono check to see if we at least have an XMRSDTypeClObj.
*/ */
XMRSDTypeClObj ci = (XMRSDTypeClObj)ob; XMRSDTypeClObj ci = (XMRSDTypeClObj)ob;
if (ci != null) { if(ci != null)
{
/* /*
* This is the target class, ie, what we are hoping the object can cast to. * This is the target class, ie, what we are hoping the object can cast to.
@ -197,8 +207,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* If we find the target class along the way, the cast is valid. * If we find the target class along the way, the cast is valid.
* If we run off the end of the root, the cast is not valid. * If we run off the end of the root, the cast is not valid.
*/ */
for (TokenDeclSDTypeClass ac = ci.sdtcClass; ac != tc; ac = ac.extends) { for(TokenDeclSDTypeClass ac = ci.sdtcClass; ac != tc; ac = ac.extends)
if (ac == null) throw new InvalidCastException ("invalid cast from " + ci.sdtcClass.longName.val + {
if(ac == null)
throw new InvalidCastException("invalid cast from " + ci.sdtcClass.longName.val +
" to " + tc.longName.val); " to " + tc.longName.val);
} }
@ -215,14 +227,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @param ob = object to be cast of unknown type * @param ob = object to be cast of unknown type
* @returns ob cast to the interface type * @returns ob cast to the interface type
*/ */
public static Delegate[] CastObj2IFace (object ob, string ifacename) public static Delegate[] CastObj2IFace(object ob, string ifacename)
{ {
if (ob == null) return null; if(ob == null)
return null;
/* /*
* If it is already one of our interfaces, extract the script-defined class object from it. * If it is already one of our interfaces, extract the script-defined class object from it.
*/ */
if (ob is Delegate[]) { if(ob is Delegate[])
{
Delegate[] da = (Delegate[])ob; Delegate[] da = (Delegate[])ob;
ob = da[0].Target; ob = da[0].Target;
} }
@ -239,21 +253,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/** /**
* @brief Write the whole thing out to a stream. * @brief Write the whole thing out to a stream.
*/ */
public void Capture (XMRInstArrays.Sender sendValue) public void Capture(XMRInstArrays.Sender sendValue)
{ {
sendValue (this.sdtcClass.sdTypeIndex); sendValue(this.sdtcClass.sdTypeIndex);
this.instVars.SendArrays (sendValue); this.instVars.SendArrays(sendValue);
} }
/** /**
* @brief Read the whole thing in from a stream. * @brief Read the whole thing in from a stream.
*/ */
public XMRSDTypeClObj () { } public XMRSDTypeClObj()
public void Restore (XMRInstAbstract inst, XMRInstArrays.Recver recvValue)
{ {
int classindex = (int)recvValue (); }
Construct (inst, classindex); public void Restore(XMRInstAbstract inst, XMRInstArrays.Recver recvValue)
this.instVars.RecvArrays (recvValue); {
int classindex = (int)recvValue();
Construct(inst, classindex);
this.instVars.RecvArrays(recvValue);
} }
} }
} }

View File

@ -0,0 +1,240 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using OpenSim.Framework.Monitoring;
using System;
using System.Collections.Generic;
using System.Threading;
namespace OpenSim.Region.ScriptEngine.Yengine
{
public partial class Yengine
{
private int m_WakeUpOne = 0;
public object m_WakeUpLock = new object();
private Dictionary<int, XMRInstance> m_RunningInstances = new Dictionary<int, XMRInstance>();
private bool m_SuspendScriptThreadFlag = false;
private bool m_WakeUpThis = false;
public DateTime m_LastRanAt = DateTime.MinValue;
public long m_ScriptExecTime = 0;
[ThreadStatic]
private static int m_ScriptThreadTID;
public static bool IsScriptThread
{
get
{
return m_ScriptThreadTID != 0;
}
}
public void StartThreadWorker(int i)
{
Thread thd;
if(i >= 0)
thd = Yengine.StartMyThread(RunScriptThread, "YScript" + i.ToString(), ThreadPriority.BelowNormal);
else
thd = Yengine.StartMyThread(RunScriptThread, "YScript", ThreadPriority.BelowNormal);
lock(m_WakeUpLock)
m_RunningInstances.Add(thd.ManagedThreadId, null);
}
public void StopThreadWorkers()
{
lock(m_WakeUpLock)
{
while(m_RunningInstances.Count != 0)
{
Monitor.PulseAll(m_WakeUpLock);
Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
}
}
}
/**
* @brief Something was just added to the Start or Yield queue so
* wake one of the RunScriptThread() instances to run it.
*/
public void WakeUpOne()
{
lock(m_WakeUpLock)
{
m_WakeUpOne++;
Monitor.Pulse(m_WakeUpLock);
}
}
public void SuspendThreads()
{
lock(m_WakeUpLock)
{
m_SuspendScriptThreadFlag = true;
Monitor.PulseAll(m_WakeUpLock);
}
}
public void ResumeThreads()
{
lock(m_WakeUpLock)
{
m_SuspendScriptThreadFlag = false;
Monitor.PulseAll(m_WakeUpLock);
}
}
/**
* @brief Thread that runs the scripts.
*
* There are NUMSCRIPTHREADWKRS of these.
* Each sits in a loop checking the Start and Yield queues for
* a script to run and calls the script as a microthread.
*/
private void RunScriptThread()
{
int tid = System.Threading.Thread.CurrentThread.ManagedThreadId;
ThreadStart thunk;
XMRInstance inst;
bool didevent;
m_ScriptThreadTID = tid;
while(!m_Exiting)
{
Yengine.UpdateMyThread();
lock(m_WakeUpLock)
{
// Maybe there are some scripts waiting to be migrated in or out.
thunk = null;
if(m_ThunkQueue.Count > 0)
thunk = m_ThunkQueue.Dequeue();
// Handle 'xmr resume/suspend' commands.
else if(m_SuspendScriptThreadFlag && !m_Exiting)
{
Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
Yengine.UpdateMyThread();
continue;
}
}
if(thunk != null)
{
thunk();
continue;
}
if(m_StartProcessing)
{
// If event just queued to any idle scripts
// start them right away. But only start so
// many so we can make some progress on yield
// queue.
int numStarts;
didevent = false;
for(numStarts = 5; numStarts >= 0; --numStarts)
{
lock(m_StartQueue)
inst = m_StartQueue.RemoveHead();
if(inst == null)
break;
if(inst.m_IState != XMRInstState.ONSTARTQ)
throw new Exception("bad state");
RunInstance(inst, tid);
if(m_SuspendScriptThreadFlag || m_Exiting)
continue;
didevent = true;
}
// If there is something to run, run it
// then rescan from the beginning in case
// a lot of things have changed meanwhile.
//
// These are considered lower priority than
// m_StartQueue as they have been taking at
// least one quantum of CPU time and event
// handlers are supposed to be quick.
lock(m_YieldQueue)
inst = m_YieldQueue.RemoveHead();
if(inst != null)
{
if(inst.m_IState != XMRInstState.ONYIELDQ)
throw new Exception("bad state");
RunInstance(inst, tid);
continue;
}
// If we left something dangling in the m_StartQueue or m_YieldQueue, go back to check it.
if(didevent)
continue;
}
// Nothing to do, sleep.
lock(m_WakeUpLock)
{
if(!m_WakeUpThis && (m_WakeUpOne <= 0) && !m_Exiting)
Monitor.Wait(m_WakeUpLock, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS / 2);
m_WakeUpThis = false;
if((m_WakeUpOne > 0) && (--m_WakeUpOne > 0))
Monitor.Pulse(m_WakeUpLock);
}
}
lock(m_WakeUpLock)
m_RunningInstances.Remove(tid);
Yengine.MyThreadExiting();
}
/**
* @brief A script instance was just removed from the Start or Yield Queue.
* So run it for a little bit then stick in whatever queue it should go in.
*/
private void RunInstance(XMRInstance inst, int tid)
{
m_LastRanAt = DateTime.UtcNow;
m_ScriptExecTime -= (long)(m_LastRanAt - DateTime.MinValue).TotalMilliseconds;
inst.m_IState = XMRInstState.RUNNING;
lock(m_WakeUpLock)
m_RunningInstances[tid] = inst;
XMRInstState newIState = inst.RunOne();
lock(m_WakeUpLock)
m_RunningInstances[tid] = null;
HandleNewIState(inst, newIState);
m_ScriptExecTime += (long)(DateTime.UtcNow - DateTime.MinValue).TotalMilliseconds;
}
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
namespace OpenSim.Region.ScriptEngine.Yengine
{
public partial class XMRInstance
{
/**
* @brief Start script event handler from the beginning.
* Return when either the script event handler completes
* or the script calls Hiber().
* @returns null: script did not throw any exception so far
* else: script threw an exception
*/
public Exception StartEx()
{
// Start script event handler from very beginning.
callMode = XMRInstance.CallMode_NORMAL;
try
{
CallSEH(); // run script event handler
}
catch(StackHibernateException)
{
if(callMode != XMRInstance.CallMode_SAVE)
throw new Exception("callMode=" + callMode);
}
catch(Exception e)
{
return e;
}
return null;
}
/**
* @brief We now want to run some more script code from where it last hibernated
* until it either finishes the script event handler or until the script
* calls Hiber() again.
*/
public Exception ResumeEx()
{
// Resume script from captured stack.
callMode = XMRInstance.CallMode_RESTORE;
suspendOnCheckRunTemp = true;
try
{
CallSEH(); // run script event handler
}
catch(StackHibernateException)
{
if(callMode != XMRInstance.CallMode_SAVE)
throw new Exception("callMode=" + callMode);
}
catch(Exception e)
{
return e;
}
return null;
}
public class StackHibernateException: Exception, IXMRUncatchable
{
}
}
}

View File

@ -265,8 +265,8 @@
; DefaultScriptEngine = "XEngine" ; DefaultScriptEngine = "XEngine"
;; ***DANGER***DANGER*** ;; ***DANGER***DANGER***
;; experimental engine ;; experimental engine
;; see section [XMREngine} below ;; see section [YEngine} below
; DefaultScriptEngine = "XMREngine" ; DefaultScriptEngine = "YEngine"
;# {HttpProxy} {} {Proxy URL for llHTTPRequest and dynamic texture loading} {} http://proxy.com:8080 ;# {HttpProxy} {} {Proxy URL for llHTTPRequest and dynamic texture loading} {} http://proxy.com:8080
;; Http proxy setting for llHTTPRequest and dynamic texture loading, if ;; Http proxy setting for llHTTPRequest and dynamic texture loading, if
@ -922,20 +922,19 @@
[XMREngine] [XMREngine]
;; experimental engine ;; experimental engine
;; ONLY SUPORTS ONE REGION PER INSTANCE at this point ;; ONLY SUPORTS ONE REGION PER INSTANCE at this point
;; implements microthreading, so fixing problems like llSleep or long events handlers ;; implements non preemptive microthreading, so fixing problems like llSleep or long events handlers
;; but those will suffer from timeslicing, so will be slower. ;; but those will suffer from timeslicing, so will be slower.
;; compiles LSL directly to IL, so only suports LSL scripting (no C# etc) ;; compiles LSL directly to IL, so only suports LSL scripting (no C# etc)
;; shares the Xengine APIs like LSL, OSSL, etc. ;; shares the Xengine APIs like LSL, OSSL, etc.
;; DANGER, do not use with HG, don't leave regions running alone with it. ;; DANGER, do not use with HG, don't leave regions running alone with it.
;; TPs or crossings to/from Xengine will recompile scripts losing state. ;; TPs or crossings to/from Xengine will full recompile scripts losing state.
;; attachment scripts may misbehave, cars will stop on crossings, etc. ;; attachment scripts may misbehave, cars will stop on crossings, etc.
Enabled = false Enabled = false
UThreadModel = sys
ScriptStackSize = 256 ScriptStackSize = 256
ScriptHeapSize = 256 ScriptHeapSize = 256
UseSourceHashCode = true UseSourceHashCode = true
MinTimerInterval = 0.1 MinTimerInterval = 0.1
;ScriptBasePath="ScriptData" ;ScriptBasePath="ScriptEngines"
[XEngine] [XEngine]
;# {Enabled} {} {Enable the XEngine scripting engine?} {true false} true ;# {Enabled} {} {Enable the XEngine scripting engine?} {true false} true

View File

@ -2418,8 +2418,8 @@
</Files> </Files>
</Project> </Project>
<!-- XMRengine --> <!-- YEngine/core XMRengine -->
<Project frameworkVersion="v4_6" name="OpenSim.Region.ScriptEngine.XMREngine" path="OpenSim/Region/ScriptEngine/XMREngine" type="Library"> <Project frameworkVersion="v4_6" name="OpenSim.Region.ScriptEngine.YEngine" path="OpenSim/Region/ScriptEngine/YEngine" type="Library">
<Configuration name="Debug"> <Configuration name="Debug">
<Options> <Options>
<OutputPath>../../../../bin/</OutputPath> <OutputPath>../../../../bin/</OutputPath>