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,65 +30,76 @@ using System.Collections.Generic;
using System.Reflection;
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 Type type; // resultant delegate type
private static Dictionary<string, DelegateCommon> delegateCommons = new Dictionary<string, DelegateCommon> ();
private static Dictionary<Type, DelegateCommon> delegateCommonsBySysType = new Dictionary<Type, DelegateCommon> ();
private static Dictionary<string, DelegateCommon> delegateCommons = new Dictionary<string, DelegateCommon>();
private static Dictionary<Type, DelegateCommon> delegateCommonsBySysType = new Dictionary<Type, DelegateCommon>();
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;
lock (delegateCommons) {
if (!delegateCommons.TryGetValue (sig, out dc)) {
dc = new DelegateCommon ();
dc.sig = sig;
dc.type = CreateDelegateType (sig, ret, args);
delegateCommons.Add (sig, dc);
delegateCommonsBySysType.Add (dc.type, dc);
lock(delegateCommons)
{
if(!delegateCommons.TryGetValue(sig, out dc))
{
dc = new DelegateCommon();
dc.sig = sig;
dc.type = CreateDelegateType(sig, ret, args);
delegateCommons.Add(sig, dc);
delegateCommonsBySysType.Add(dc.type, dc);
}
}
return dc.type;
}
public static Type TryGetType (string sig)
public static Type TryGetType(string sig)
{
DelegateCommon dc;
lock (delegateCommons) {
if (!delegateCommons.TryGetValue (sig, out dc)) dc = null;
lock(delegateCommons)
{
if(!delegateCommons.TryGetValue(sig, out dc))
dc = null;
}
return (dc == null) ? null : dc.type;
}
public static string TryGetName (Type t)
public static string TryGetName(Type t)
{
DelegateCommon dc;
lock (delegateCommons) {
if (!delegateCommonsBySysType.TryGetValue (t, out dc)) dc = null;
lock(delegateCommons)
{
if(!delegateCommonsBySysType.TryGetValue(t, out dc))
dc = null;
}
return (dc == null) ? null : dc.sig;
}
// 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();
assembly.Name = "CustomDelegateAssembly";
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assembly, AssemblyBuilderAccess.Run);
delegateModuleBuilder = assemblyBuilder.DefineDynamicModule("CustomDelegateModule");
}
TypeBuilder typeBuilder = delegateModuleBuilder.DefineType(name,
TypeBuilder typeBuilder = delegateModuleBuilder.DefineType(name,
TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.Class |
TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof (MulticastDelegate));
TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof(MulticastDelegate));
ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(
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_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine
namespace OpenSim.Region.ScriptEngine.Yengine
{
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 attach (string id);
void changed (int change);
void collision (int num_detected);
void collision_end (int num_detected);
void collision_start (int num_detected);
void control (string id, int held, int change);
void dataserver (string queryid, string data);
void email (string time, string address, string subj, string message, int num_left);
void http_request (string request_id, string method, string body);
void http_response (string request_id, int status, LSL_List metadata, string body);
void land_collision (LSL_Vector pos);
void land_collision_end (LSL_Vector pos);
void land_collision_start (LSL_Vector pos);
void link_message (int sender_num, int num, string str, string id);
void listen (int channel, string name, string id, string message);
void money (string id, int amount);
void moving_end ();
void moving_start ();
void no_sensor ();
void not_at_rot_target ();
void not_at_target ();
void object_rez (string id);
void on_rez (int start_param);
void remote_data (int event_type, string channel, string message_id, string sender, int idata, string sdata);
void run_time_permissions (int perm);
void sensor (int num_detected);
void state_entry ();
void state_exit ();
void timer ();
void touch (int num_detected);
void touch_start (int num_detected);
void touch_end (int num_detected);
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 attach(string id);
void changed(int change);
void collision(int num_detected);
void collision_end(int num_detected);
void collision_start(int num_detected);
void control(string id, int held, int change);
void dataserver(string queryid, string data);
void email(string time, string address, string subj, string message, int num_left);
void http_request(string request_id, string method, string body);
void http_response(string request_id, int status, LSL_List metadata, string body);
void land_collision(LSL_Vector pos);
void land_collision_end(LSL_Vector pos);
void land_collision_start(LSL_Vector pos);
void link_message(int sender_num, int num, string str, string id);
void listen(int channel, string name, string id, string message);
void money(string id, int amount);
void moving_end();
void moving_start();
void no_sensor();
void not_at_rot_target();
void not_at_target();
void object_rez(string id);
void on_rez(int start_param);
void remote_data(int event_type, string channel, string message_id, string sender, int idata, string sdata);
void run_time_permissions(int perm);
void sensor(int num_detected);
void state_entry();
void state_exit();
void timer();
void touch(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 path_update(int type, LSL_List data);
void region_cross(LSL_Vector newpos, LSL_Vector oldpos);

View File

@ -30,9 +30,11 @@ using System.Collections.Generic;
using System.IO;
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.
@ -41,50 +43,57 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
* false: catalog by simple name only, eg, state_entry
* @returns dictionary of function definition tokens
*/
public InternalFuncDict (Type iface, bool inclSig)
: base (false)
public InternalFuncDict(Type iface, bool inclSig)
: base(false)
{
/*
* Loop through list of all methods declared in the interface.
*/
System.Reflection.MethodInfo[] ifaceMethods = iface.GetMethods ();
foreach (System.Reflection.MethodInfo ifaceMethod in ifaceMethods) {
System.Reflection.MethodInfo[] ifaceMethods = iface.GetMethods();
foreach(System.Reflection.MethodInfo ifaceMethod in ifaceMethods)
{
string key = ifaceMethod.Name;
/*
* Only do ones that begin with lower-case letters...
* 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.
*/
System.Reflection.ParameterInfo[] parameters = ifaceMethod.GetParameters ();
TokenArgDecl argDecl = new TokenArgDecl (null);
for (int i = 0; i < parameters.Length; i++) {
System.Reflection.ParameterInfo[] parameters = ifaceMethod.GetParameters();
TokenArgDecl argDecl = new TokenArgDecl(null);
for(int i = 0; i < parameters.Length; i++)
{
System.Reflection.ParameterInfo param = parameters[i];
TokenType type = TokenType.FromSysType (null, param.ParameterType);
TokenName name = new TokenName (null, param.Name);
argDecl.AddArg (type, name);
TokenType type = TokenType.FromSysType(null, param.ParameterType);
TokenName name = new TokenName(null, param.Name);
argDecl.AddArg(type, name);
}
TokenDeclVar declFunc = new TokenDeclVar (null, null, null);
declFunc.name = new TokenName (null, key);
declFunc.retType = TokenType.FromSysType (null, ifaceMethod.ReturnType);
declFunc.argDecl = argDecl;
TokenDeclVar declFunc = new TokenDeclVar(null, null, null);
declFunc.name = new TokenName(null, key);
declFunc.retType = TokenType.FromSysType(null, ifaceMethod.ReturnType);
declFunc.argDecl = argDecl;
/*
* Add the TokenDeclVar struct to the dictionary.
*/
this.AddEntry (declFunc);
} catch (Exception except) {
this.AddEntry(declFunc);
}
catch(Exception except)
{
string msg = except.ToString ();
int i = msg.IndexOf ("\n");
if (i > 0) msg = msg.Substring (0, i);
Console.WriteLine ("InternalFuncDict*: {0}: {1}", key, msg);
string msg = except.ToString();
int i = msg.IndexOf("\n");
if(i > 0)
msg = msg.Substring(0, i);
Console.WriteLine("InternalFuncDict*: {0}: {1}", key, msg);
///??? 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.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
{
@ -45,155 +41,136 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @returns object code pointer or null if compile error
* also can throw compile error exception
*/
public ScriptObjCode Compile ()
public ScriptObjCode Compile()
{
bool oldObjFile = false;
Stream objFileStream = null;
StreamWriter asmFileWriter = null;
string envar = null;
string sourceHash = null;
TextWriter saveSource = null;
string asmFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrasm");
string lslFileName = GetScriptFileName (m_ScriptObjCodeKey + ".lsl");
string objFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrobj");
string tmpFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrtmp");
/*
* If we already have an object file, don't bother compiling.
*/
if (!m_ForceRecomp && File.Exists (objFileName)) {
// If we already have an object file, don't bother compiling.
if (!m_ForceRecomp && File.Exists(objFileName))
{
objFileStream = File.OpenRead (objFileName);
oldObjFile = true;
} else {
/*
* If source file empty, try to read from asset server.
*/
if (EmptySource (m_SourceCode)) {
}
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.
*/
envar = Environment.GetEnvironmentVariable ("MMRScriptCompileSaveSource");
if ((envar != null) && ((envar[0] & 1) != 0)) {
m_log.Debug ("[XMREngine]: MMRScriptCompileSaveSource: saving to " + lslFileName);
// Maybe write script source to a file for debugging.
if (m_Engine.m_ScriptDebugSaveSource)
{
string lslFileName = GetScriptFileName (m_ScriptObjCodeKey + ".lsl");
// m_log.Debug ("[YEngine]: MMRScriptCompileSaveSource: saving to " + lslFileName);
saveSource = File.CreateText (lslFileName);
}
/*
* Parse source string into tokens.
*/
// Parse source string into tokens.
TokenBegin tokenBegin;
try {
try
{
tokenBegin = TokenBegin.Construct(m_CameFrom, saveSource, ErrorHandler, m_SourceCode, out sourceHash);
} finally {
if (saveSource != null) saveSource.Close ();
}
if (tokenBegin == null) {
m_log.Debug ("[XMREngine]: parsing errors on " + m_ScriptObjCodeKey);
finally
{
if (saveSource != null)
saveSource.Close ();
}
if (tokenBegin == null)
{
m_log.Debug ("[YEngine]: parsing errors on " + m_ScriptObjCodeKey);
return null;
}
/*
* Create object file one way or another.
*/
try {
// Create object file one way or another.
try
{
objFileStream = File.Create (tmpFileName);
/*
* Create abstract syntax tree from raw tokens.
*/
// Create abstract syntax tree from raw tokens.
TokenScript tokenScript = ScriptReduce.Reduce(tokenBegin);
if (tokenScript == null) {
m_log.Warn ("[XMREngine]: reduction errors on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
PrintCompilerErrors ();
if (tokenScript == null)
{
m_log.Warn ("[YEngine]: reduction errors on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
PrintCompilerErrors();
objFileStream.Close();
return null;
}
/*
* Compile abstract syntax tree to write object file.
*/
// Compile abstract syntax tree to write object file.
BinaryWriter objFileWriter = new BinaryWriter (objFileStream);
bool ok = ScriptCodeGen.CodeGen(tokenScript, objFileWriter, sourceHash);
if (!ok) {
m_log.Warn ("[XMREngine]: compile error on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
if (!ok)
{
m_log.Warn ("[YEngine]: compile error on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
PrintCompilerErrors ();
objFileStream.Close ();
objFileWriter.Close ();
return null;
}
objFileStream.Close ();
objFileWriter.Close ();
/*
* File has been completely written.
* If there is an old one laying around, delete it now.
* Then re-open the new file for reading from the beginning.
*/
if (File.Exists (objFileName)) {
// File has been completely written.
// If there is an old one laying around, delete it now.
// Then re-open the new file for reading from the beginning.
if (File.Exists (objFileName))
File.Replace (tmpFileName, objFileName, null);
} else {
else
File.Move (tmpFileName, objFileName);
}
objFileStream = File.OpenRead (objFileName);
} finally {
/*
* In case something went wrong writing temp file, delete it.
*/
try {
objFileStream = File.OpenRead (objFileName);
}
finally
{
// In case something went wrong writing temp file, delete it.
try
{
File.Delete (tmpFileName);
} catch {
}
catch
{
}
}
/*
* Since we just wrote the .xmrobj file, maybe save disassembly.
*/
envar = Environment.GetEnvironmentVariable ("MMRScriptCompileSaveILGen");
if ((envar != null) && ((envar[0] & 1) != 0)) {
m_log.Debug ("[XMREngine]: MMRScriptCompileSaveILGen: saving to " + asmFileName);
// Since we just wrote the .xmrobj file, maybe save disassembly.
if (m_Engine.m_ScriptDebugSaveIL)
{
string asmFileName = GetScriptFileName (m_ScriptObjCodeKey + ".xmrasm");
// m_log.Debug ("[YEngine]: MMRScriptCompileSaveILGen: saving to " + asmFileName);
asmFileWriter = File.CreateText (asmFileName);
}
}
/*
* Read object file to create ScriptObjCode object.
* Maybe also write disassembly to a file for debugging.
*/
// Read object file to create ScriptObjCode object.
// Maybe also write disassembly to a file for debugging.
BinaryReader objFileReader = new BinaryReader (objFileStream);
ScriptObjCode scriptObjCode = null;
try {
try
{
scriptObjCode = new ScriptObjCode (objFileReader, asmFileWriter, null);
if (scriptObjCode != null) {
scriptObjCode.fileDateUtc = File.GetLastWriteTimeUtc (objFileName);
}
} finally {
}
finally
{
objFileReader.Close ();
if (asmFileWriter != null) {
if (asmFileWriter != null)
{
asmFileWriter.Flush ();
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;
}
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) {
m_log.Info ("[XMREngine]: - " + error);
m_log.Info ("[YEngine]: - " + error);
}
}
@ -204,11 +181,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{
int len = source.Length;
bool skipeol = false;
for (int i = 0; i < len; i ++) {
for (int i = 0; i < len; i ++)
{
char c = source[i];
skipeol &= c != '\n';
skipeol |= (c == '/') && (i + 1 < len) && (source[i+1] == '/');
if ((c > ' ') && !skipeol) return false;
if ((c > ' ') && !skipeol)
return false;
}
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.
*/
namespace OpenSim.Region.ScriptEngine.XMREngine {
namespace OpenSim.Region.ScriptEngine.Yengine
{
/**
* @brief List of event codes that can be passed to StartEventHandler().
@ -38,58 +39,59 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
* in range 0..63 that begin with a lower-case letter for scripts to
* reference.
*/
public enum ScriptEventCode : int {
public enum ScriptEventCode: int
{
// used by XMRInstance to indicate no event being processed
None = -1,
None = -1,
// must be bit numbers of equivalent values in ...
// OpenSim.Region.ScriptEngine.Shared.ScriptBase.scriptEvents
// ... so they can be passed to m_Part.SetScriptEvents().
attach = 0,
state_exit = 1,
timer = 2,
touch = 3,
collision = 4,
collision_end = 5,
collision_start = 6,
control = 7,
dataserver = 8,
email = 9,
http_response = 10,
land_collision = 11,
land_collision_end = 12,
attach = 0,
state_exit = 1,
timer = 2,
touch = 3,
collision = 4,
collision_end = 5,
collision_start = 6,
control = 7,
dataserver = 8,
email = 9,
http_response = 10,
land_collision = 11,
land_collision_end = 12,
land_collision_start = 13,
at_target = 14,
listen = 15,
money = 16,
moving_end = 17,
moving_start = 18,
not_at_rot_target = 19,
not_at_target = 20,
touch_start = 21,
object_rez = 22,
remote_data = 23,
at_rot_target = 24,
transaction_result = 25,
at_target = 14,
listen = 15,
money = 16,
moving_end = 17,
moving_start = 18,
not_at_rot_target = 19,
not_at_target = 20,
touch_start = 21,
object_rez = 22,
remote_data = 23,
at_rot_target = 24,
transaction_result = 25,
run_time_permissions = 28,
touch_end = 29,
state_entry = 30,
touch_end = 29,
state_entry = 30,
// events not passed to m_Part.SetScriptEvents().
changed = 33,
link_message = 34,
no_sensor = 35,
on_rez = 36,
sensor = 37,
http_request = 38,
changed = 33,
link_message = 34,
no_sensor = 35,
on_rez = 36,
sensor = 37,
http_request = 38,
path_update = 40,
path_update = 40,
// XMRE specific
region_cross = 63,
region_cross = 63,
// marks highest numbered event, ie, number of columns in seht.
Size = 64
Size = 64
}
}

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.Emit;
namespace OpenSim.Region.ScriptEngine.XMREngine
namespace OpenSim.Region.ScriptEngine.Yengine
{
public interface ScriptMyILGen
{
string methName { get; }
ScriptMyLocal DeclareLocal (Type type, string name);
ScriptMyLabel DefineLabel (string name);
void BeginExceptionBlock ();
void BeginCatchBlock (Type excType);
void BeginFinallyBlock ();
void EndExceptionBlock ();
void Emit (Token errorAt, OpCode opcode);
void Emit (Token errorAt, OpCode opcode, FieldInfo field);
void Emit (Token errorAt, OpCode opcode, ScriptMyLocal myLocal);
void Emit (Token errorAt, OpCode opcode, Type type);
void Emit (Token errorAt, OpCode opcode, ScriptMyLabel myLabel);
void Emit (Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels);
void Emit (Token errorAt, OpCode opcode, ScriptObjWriter method);
void Emit (Token errorAt, OpCode opcode, MethodInfo method);
void Emit (Token errorAt, OpCode opcode, ConstructorInfo ctor);
void Emit (Token errorAt, OpCode opcode, double value);
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);
string methName
{
get;
}
ScriptMyLocal DeclareLocal(Type type, string name);
ScriptMyLabel DefineLabel(string name);
void BeginExceptionBlock();
void BeginCatchBlock(Type excType);
void BeginFinallyBlock();
void EndExceptionBlock();
void Emit(Token errorAt, OpCode opcode);
void Emit(Token errorAt, OpCode opcode, FieldInfo field);
void Emit(Token errorAt, OpCode opcode, ScriptMyLocal myLocal);
void Emit(Token errorAt, OpCode opcode, Type type);
void Emit(Token errorAt, OpCode opcode, ScriptMyLabel myLabel);
void Emit(Token errorAt, OpCode opcode, ScriptMyLabel[] myLabels);
void Emit(Token errorAt, OpCode opcode, ScriptObjWriter method);
void Emit(Token errorAt, OpCode opcode, MethodInfo method);
void Emit(Token errorAt, OpCode opcode, ConstructorInfo ctor);
void Emit(Token errorAt, OpCode opcode, double value);
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.
*/
public class ScriptMyLabel {
public class ScriptMyLabel
{
public string name;
public int number;
@ -71,7 +75,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @brief One of these per local variable defined in the function.
*/
public class ScriptMyLocal {
public class ScriptMyLocal
{
public string name;
public Type type;
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
*/
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 TokenDeclSDTypeClass thisClass; // this VarDict is for members of thisClass
private struct ArgTypes {
private struct 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)) 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;
if((argTypes == null) && (calledBy == null))
return true;
if((argTypes == null) || (calledBy == null))
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;
}
public override bool Equals (Object that)
public override bool Equals(Object that)
{
if (that == null) return false;
if (that.GetType () != typeof (ArgTypes)) return false;
if(that == null)
return false;
if(that.GetType() != typeof(ArgTypes))
return false;
TokenType[] at = this.argTypes;
TokenType[] bt = ((ArgTypes)that).argTypes;
if ((at == null) && (bt == null)) return true;
if ((at == null) || (bt == null)) 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;
if((at == null) && (bt == null))
return true;
if((at == null) || (bt == null))
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;
}
public override int GetHashCode ()
public override int GetHashCode()
{
TokenType[] at = this.argTypes;
if (at == null) return -1;
if(at == null)
return -1;
int hc = 0;
for (int i = at.Length; -- i >= 0;) {
for(int i = at.Length; --i >= 0;)
{
int c = (hc < 0) ? 1 : 0;
hc = hc * 2 + c;
hc ^= at[i].ToString ().GetHashCode ();
hc = hc * 2 + c;
hc ^= at[i].ToString().GetHashCode();
}
return hc;
}
}
private struct TDVEntry {
private struct TDVEntry
{
public int count;
public TokenDeclVar var;
}
private bool isFrozen = false;
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 VarDict frozenLocals = null;
@ -98,7 +115,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @param locals = false: cannot be frozen, allows forward references
* true: can be frozen, thus forbidding forward references
*/
public VarDict (bool locals)
public VarDict(bool locals)
{
this.locals = locals;
}
@ -106,19 +123,21 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @brief Add new variable to the dictionary.
*/
public bool AddEntry (TokenDeclVar var)
public bool AddEntry(TokenDeclVar var)
{
if (isFrozen) {
throw new Exception ("var dict is frozen");
if(isFrozen)
{
throw new Exception("var dict is frozen");
}
/*
* Make sure we have a sub-dictionary based on the bare name (ie, no signature)
*/
Dictionary<ArgTypes, TDVEntry> typedic;
if (!master.TryGetValue (var.name.val, out typedic)) {
typedic = new Dictionary<ArgTypes, TDVEntry> ();
master.Add (var.name.val, typedic);
if(!master.TryGetValue(var.name.val, out 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.
*/
ArgTypes types;
types.argTypes = (var.argDecl == null) ? null : KeyTypesToStringTypes (var.argDecl.types);
if (typedic.ContainsKey (types)) return false;
types.argTypes = (var.argDecl == null) ? null : KeyTypesToStringTypes(var.argDecl.types);
if(typedic.ContainsKey(types))
return false;
/*
* It is unique, add to its name-specific sub-dictionary.
*/
TDVEntry entry;
entry.count = ++ count;
entry.var = var;
typedic.Add (types, entry);
entry.count = ++count;
entry.var = var;
typedic.Add(types, entry);
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.
* If this is a local variable frame, return a version that is frozen,
* 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.
* This will allow forward references as the future additions
* 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.
* This disallows forward referenes as those future additions
* 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.
@ -169,12 +197,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* contain additions made after this point, those additions
* will have a count .gt. frozen count and will be ignored.
*/
frozenLocals = new VarDict (true);
frozenLocals = new VarDict(true);
frozenLocals.outerVarDict = this.outerVarDict;
frozenLocals.thisClass = this.thisClass;
frozenLocals.master = this.master;
frozenLocals.count = this.count;
frozenLocals.thisClass = this.thisClass;
frozenLocals.master = this.master;
frozenLocals.count = this.count;
frozenLocals.frozenLocals = frozenLocals;
/*
@ -196,23 +224,27 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* else: list of matching functions/variables
* for variables, always of length 1
*/
private List<TokenDeclVar> found = new List<TokenDeclVar> ();
public TokenDeclVar[] FindCallables (string name, TokenType[] argTypes)
private List<TokenDeclVar> found = new List<TokenDeclVar>();
public TokenDeclVar[] FindCallables(string name, TokenType[] argTypes)
{
argTypes = KeyTypesToStringTypes (argTypes);
TokenDeclVar var = FindExact (name, argTypes);
if (var != null) return new TokenDeclVar[] { var };
argTypes = KeyTypesToStringTypes(argTypes);
TokenDeclVar var = FindExact(name, argTypes);
if(var != null)
return new TokenDeclVar[] { var };
Dictionary<ArgTypes, TDVEntry> typedic;
if (!master.TryGetValue (name, out typedic)) return null;
if(!master.TryGetValue(name, out typedic))
return null;
found.Clear ();
foreach (KeyValuePair<ArgTypes, TDVEntry> kvp in typedic) {
if ((kvp.Value.count <= this.count) && kvp.Key.CanBeCalledBy (argTypes)) {
found.Add (kvp.Value.var);
found.Clear();
foreach(KeyValuePair<ArgTypes, TDVEntry> kvp in typedic)
{
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
* 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.
*/
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.
*/
foreach (TDVEntry entry in typedic.Values) {
if (entry.count > this.count) continue;
foreach(TDVEntry entry in typedic.Values)
{
if(entry.count > this.count)
continue;
TokenDeclVar var = entry.var;
/*
@ -248,12 +283,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/*
* 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 ((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.
@ -261,29 +297,38 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* trying to cast the arguments to the delegate arg 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;
if (fieldType is TokenTypeSDTypeDelegate) return var;
if(fieldType is TokenTypeSDTypeDelegate)
return var;
}
/*
* 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.
*/
int i = declArgs.Length;
if (i != argTypes.Length) continue;
while (-- i >= 0) {
string da = declArgs[i].ToString ();
string ga = argTypes[i].ToString ();
if (da == "key") da = "string";
if (ga == "key") ga = "string";
if (da != ga) break;
if(i != argTypes.Length)
continue;
while(--i >= 0)
{
string da = declArgs[i].ToString();
string ga = argTypes[i].ToString();
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
* @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 nats = argTypes.Length;
for (i = nats; -- i >= 0;) {
if (argTypes[i] is TokenTypeKey) break;
for(i = nats; --i >= 0;)
{
if(argTypes[i] is TokenTypeKey)
break;
}
if (i >= 0) {
if(i >= 0)
{
TokenType[] at = new TokenType[nats];
for (i = nats; -- i >= 0;) {
for(i = nats; --i >= 0;)
{
at[i] = argTypes[i];
if (argTypes[i] is TokenTypeKey) {
at[i] = new TokenTypeStr (argTypes[i]);
if(argTypes[i] is TokenTypeKey)
{
at[i] = new TokenTypeStr(argTypes[i]);
}
}
return at;
@ -324,48 +375,60 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// foreach goes through all the TokenDeclVars that were added
// 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 typedicEnum;
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;
}
// IEnumerator
public void Reset ()
public void Reset()
{
masterEnum.Reset ();
masterEnum.Reset();
typedicEnum = null;
}
// IEnumerator
public bool MoveNext ()
public bool MoveNext()
{
while (true) {
if (typedicEnum != null) {
while (typedicEnum.MoveNext ()) {
if (((TDVEntry)typedicEnum.Current).count <= this.count) return true;
while(true)
{
if(typedicEnum != null)
{
while(typedicEnum.MoveNext())
{
if(((TDVEntry)typedicEnum.Current).count <= this.count)
return true;
}
typedicEnum = null;
}
if (!masterEnum.MoveNext ()) return false;
if(!masterEnum.MoveNext())
return false;
Dictionary<ArgTypes, TDVEntry> ctd;
ctd = (Dictionary<ArgTypes, TDVEntry>)masterEnum.Current;
typedicEnum = ctd.Values.GetEnumerator ();
typedicEnum = ctd.Values.GetEnumerator();
}
}
// 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
//
namespace OpenSim.Region.ScriptEngine.XMREngine
namespace OpenSim.Region.ScriptEngine.Yengine
{
/**
* @brief Array objects.
*/
public class XMR_Array {
public class XMR_Array
{
private const int EMPTYHEAP = 64;
private const int ENTRYHEAP = 24;
@ -53,36 +54,40 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// false: array[0..arrayValid-1] is all there is
private SortedDictionary<object, object> dnary;
private SortedDictionary<object, object>.Enumerator enumr;
// enumerator used to fill 'array' past arrayValid to end of dictionary
// enumerator used to fill 'array' past arrayValid to end of dictionary
private int arrayValid; // number of elements in 'array' that have been filled in
private KeyValuePair<object, object>[] array; // list of kvp's that have been returned by ForEach() since last modification
private XMRInstAbstract inst; // script instance debited with heap use
private int heapUse; // current heap use debit amount
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 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 countDelegate = new TokenTypeSDTypeDelegate(new TokenTypeInt(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 valueDelegate = new TokenTypeSDTypeDelegate(new TokenTypeObject(null), new TokenType[] { new TokenTypeInt(null) });
public XMR_Array (XMRInstAbstract inst)
public XMR_Array(XMRInstAbstract inst)
{
this.inst = inst;
dnary = new SortedDictionary<object, object> (XMRArrayKeyComparer.singleton);
heapUse = inst.UpdateHeapUse (0, EMPTYHEAP);
dnary = new SortedDictionary<object, object>(XMRArrayKeyComparer.singleton);
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 == "clear") return clearDelegate;
if (name.val == "index") return indexDelegate;
if (name.val == "value") return valueDelegate;
return new TokenTypeVoid (name);
if(name.val == "count")
return new TokenTypeInt(name);
if(name.val == "clear")
return clearDelegate;
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)
{
object val;
key = FixKey (key);
if (!dnary.TryGetValue (key, out val)) val = null;
key = FixKey(key);
if(!dnary.TryGetValue(key, out val))
val = null;
return val;
}
public void SetByKey(object key, object value)
{
key = FixKey (key);
key = FixKey(key);
/*
* Update heap use throwing an exception on failure
* before making any changes to the array.
*/
int keysize = HeapTrackerObject.Size (key);
int keysize = HeapTrackerObject.Size(key);
int newheapuse = heapUse;
object oldval;
if (dnary.TryGetValue (key, out oldval)) {
newheapuse -= keysize + HeapTrackerObject.Size (oldval);
if(dnary.TryGetValue(key, out oldval))
{
newheapuse -= keysize + HeapTrackerObject.Size(oldval);
}
if (value != null) {
newheapuse += keysize + HeapTrackerObject.Size (value);
if(value != null)
{
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.
* null means remove the value, ie, script did array[key] = undef.
*/
if (value != null) {
if(value != null)
{
dnary[key] = value;
} else {
dnary.Remove (key);
}
else
{
dnary.Remove(key);
/*
* Shrink the enumeration array, but always leave at least one element.
*/
if ((array != null) && (dnary.Count < array.Length / 2)) {
Array.Resize<KeyValuePair<object, object>> (ref array, array.Length / 2);
if((array != null) && (dnary.Count < array.Length / 2))
{
Array.Resize<KeyValuePair<object, object>>(ref array, array.Length / 2);
}
}
@ -148,44 +160,48 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* 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.
*/
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;
}
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;
}
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;
}
public static LSL_String Obj2String (object obj)
public static LSL_String Obj2String(object obj)
{
if (obj == null) throw new NullReferenceException ();
return obj.ToString ();
if(obj == null)
throw new NullReferenceException();
return obj.ToString();
}
/**
* @brief remove all elements from the array.
* sets everything to its 'just constructed' state.
*/
public void __pub_clear ()
public void __pub_clear()
{
heapUse = inst.UpdateHeapUse (heapUse, EMPTYHEAP);
dnary.Clear ();
heapUse = inst.UpdateHeapUse(heapUse, EMPTYHEAP);
dnary.Clear();
enumrValid = false;
arrayValid = 0;
array = null;
array = null;
}
/**
* @brief return number of elements in the array.
*/
public int __pub_count ()
public int __pub_count()
{
return dnary.Count;
}
@ -196,9 +212,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @returns null: array doesn't have that many elements
* 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
* 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
* 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
* any calls here before, so allocate an array big enough
* and set everything else to the beginning.
*/
if (array == null) {
if(array == null)
{
array = new KeyValuePair<object, object>[dnary.Count];
arrayValid = 0;
}
@ -233,17 +250,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/*
* If dictionary modified since last enumeration, get a new enumerator.
*/
if (arrayValid == 0) {
enumr = dnary.GetEnumerator ();
if(arrayValid == 0)
{
enumr = dnary.GetEnumerator();
enumrValid = true;
}
/*
* Make sure we have filled the array up enough for requested element.
*/
while ((arrayValid <= number) && enumrValid && enumr.MoveNext ()) {
if (arrayValid >= array.Length) {
Array.Resize<KeyValuePair<object, object>> (ref array, dnary.Count);
while((arrayValid <= number) && enumrValid && enumr.MoveNext())
{
if(arrayValid >= array.Length)
{
Array.Resize<KeyValuePair<object, object>>(ref array, dnary.Count);
}
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,
* including any in-progress ForEach() enumerations.
*/
public delegate void SendArrayObjDelegate (object graph);
public void SendArrayObj (SendArrayObjDelegate sendObj)
public delegate void SendArrayObjDelegate(object graph);
public void SendArrayObj(SendArrayObjDelegate sendObj)
{
/*
* Set the count then the elements themselves.
* UnfixKey() because sendObj doesn't handle XMRArrayListKeys.
*/
sendObj (dnary.Count);
foreach (KeyValuePair<object, object> kvp in dnary) {
sendObj (UnfixKey (kvp.Key));
sendObj (kvp.Value);
sendObj(dnary.Count);
foreach(KeyValuePair<object, object> kvp in dnary)
{
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
* were in on the sending side.
*/
public delegate object RecvArrayObjDelegate ();
public void RecvArrayObj (RecvArrayObjDelegate recvObj)
public delegate object RecvArrayObjDelegate();
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.
@ -294,14 +315,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/*
* Fill dictionary.
*/
dnary.Clear ();
int count = (int)recvObj ();
while (-- count >= 0) {
object key = FixKey (recvObj ());
object val = recvObj ();
int htuse = HeapTrackerObject.Size (key) + HeapTrackerObject.Size (val);
heapUse = inst.UpdateHeapUse (heapUse, heapUse + htuse);
dnary.Add (key, val);
dnary.Clear();
int count = (int)recvObj();
while(--count >= 0)
{
object key = FixKey(recvObj());
object val = recvObj();
int htuse = HeapTrackerObject.Size(key) + HeapTrackerObject.Size(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.
* 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;
if (data.Length == 1) return FixKey (data[0]);
return new XMRArrayListKey ((LSL_List)key);
if(data.Length == 1)
return FixKey(data[0]);
return new XMRArrayListKey((LSL_List)key);
}
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.
* 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;
}
}
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
*/
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.
*/
string xtn = x.GetType ().Name;
string ytn = y.GetType ().Name;
int ctn = String.CompareOrdinal (xtn, ytn);
if (ctn != 0) return ctn;
string xtn = x.GetType().Name;
string ytn = y.GetType().Name;
int ctn = String.CompareOrdinal(xtn, ytn);
if(ctn != 0)
return ctn;
ComparerDelegate cd;
if (!comparers.TryGetValue (xtn, out cd)) {
throw new Exception ("unsupported key type " + xtn);
if(!comparers.TryGetValue(xtn, out cd))
{
throw new Exception("unsupported key type " + xtn);
}
return cd (x, y);
return cd(x, y);
}
private delegate int ComparerDelegate (object a, object b);
private delegate int ComparerDelegate(object a, object b);
private static Dictionary<string, ComparerDelegate> comparers = BuildComparers ();
private static Dictionary<string, ComparerDelegate> comparers = BuildComparers();
private static Dictionary<string, ComparerDelegate> 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);
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;
}
private static int MyFloatComparer (object a, object b)
private static int MyFloatComparer(object a, object b)
{
double af = (double)a;
double bf = (double)b;
if (af < bf) return -1;
if (af > bf) return 1;
if(af < bf)
return -1;
if(af > bf)
return 1;
return 0;
}
private static int MyIntComparer (object a, object b)
private static int MyIntComparer(object a, object 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 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 br = (LSL_Rotation)b;
if (ar.x < br.x) return -1;
if (ar.x > br.x) return 1;
if (ar.y < br.y) return -1;
if (ar.y > br.y) 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;
if(ar.x < br.x)
return -1;
if(ar.x > br.x)
return 1;
if(ar.y < br.y)
return -1;
if(ar.y > br.y)
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;
}
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 bv = (LSL_Vector)b;
if (av.x < bv.x) return -1;
if (av.x > bv.x) return 1;
if (av.y < bv.y) return -1;
if (av.y > bv.y) return 1;
if (av.z < bv.z) return -1;
if (av.z > bv.z) return 1;
if(av.x < bv.x)
return -1;
if(av.x > bv.x)
return 1;
if(av.y < bv.y)
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;
}
}
@ -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
* the dictionary as they don't ever change.
*/
public class XMRArrayListKey {
public class XMRArrayListKey
{
private LSL_List original;
private object[] cleaned;
private int length;
@ -443,18 +492,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @brief Construct a sanitized object[] from a list.
* Also save the original list in case we need it later.
*/
public XMRArrayListKey (LSL_List key)
public XMRArrayListKey(LSL_List key)
{
original = key;
object[] given = key.Data;
int len = given.Length;
length = len;
cleaned = new object[len];
int hc = len;
for (int i = 0; i < len; i ++) {
object v = XMR_Array.FixKey (given[i]);
hc += hc + ((hc < 0) ? 1 : 0);
hc ^= v.GetHashCode ();
int len = given.Length;
length = len;
cleaned = new object[len];
int hc = len;
for(int i = 0; i < len; i++)
{
object v = XMR_Array.FixKey(given[i]);
hc += hc + ((hc < 0) ? 1 : 0);
hc ^= v.GetHashCode();
cleaned[i] = v;
}
hashCode = hc;
@ -463,8 +513,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @brief Get heap tracking size.
*/
public int Size {
get {
public int Size
{
get
{
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.
*/
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;
int len = a.length;
if (len != length) return false;
if (a.hashCode != hashCode) return false;
for (int i = 0; i < len; i ++) {
if (!cleaned[i].Equals (a.cleaned[i])) return false;
if(len != length)
return false;
if(a.hashCode != hashCode)
return false;
for(int i = 0; i < len; i++)
{
if(!cleaned[i].Equals(a.cleaned[i]))
return false;
}
return true;
}
@ -488,7 +545,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @brief Get an hash code.
*/
public override int GetHashCode ()
public override int GetHashCode()
{
return hashCode;
}
@ -496,15 +553,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @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;
if (j == 0) {
for (int i = 0; i < x.length; i ++) {
if(j == 0)
{
for(int i = 0; i < x.length; i++)
{
object xo = x.cleaned[i];
object yo = y.cleaned[i];
j = XMRArrayKeyComparer.singleton.Compare (xo, yo);
if (j != 0) break;
j = XMRArrayKeyComparer.singleton.Compare(xo, yo);
if(j != 0)
break;
}
}
return j;
@ -513,7 +573,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @brief Get the original LSL_List we were built from.
*/
public LSL_List GetOriginal ()
public LSL_List GetOriginal()
{
return original;
}
@ -521,14 +581,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @brief Debugging
*/
public override string ToString ()
public override string ToString()
{
StringBuilder sb = new StringBuilder ();
for (int i = 0; i < length; i ++) {
if (i > 0) sb.Append (',');
sb.Append (cleaned[i].ToString ());
StringBuilder sb = new StringBuilder();
for(int i = 0; i < length; i++)
{
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,41 +45,41 @@ 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
namespace OpenSim.Region.ScriptEngine.Yengine
{
/// <summary>
/// Prepares events so they can be directly executed upon a script by EventQueueManager, then queues it.
/// </summary>
public partial class XMREngine
public partial class Yengine
{
public static readonly object[] zeroObjectArray = new object[0];
public static readonly object[] oneObjectArrayOne = new object[1] { 1 };
private void InitEvents()
{
m_log.Info("[XMREngine] Hooking up to server events");
this.World.EventManager.OnAttach += attach;
this.World.EventManager.OnObjectGrab += touch_start;
this.World.EventManager.OnObjectGrabbing += touch;
this.World.EventManager.OnObjectDeGrab += touch_end;
this.World.EventManager.OnScriptChangedEvent += changed;
this.World.EventManager.OnScriptAtTargetEvent += at_target;
this.World.EventManager.OnScriptNotAtTargetEvent += not_at_target;
this.World.EventManager.OnScriptAtRotTargetEvent += at_rot_target;
m_log.Info("[YEngine] Hooking up to server events");
this.World.EventManager.OnAttach += attach;
this.World.EventManager.OnObjectGrab += touch_start;
this.World.EventManager.OnObjectGrabbing += touch;
this.World.EventManager.OnObjectDeGrab += touch_end;
this.World.EventManager.OnScriptChangedEvent += changed;
this.World.EventManager.OnScriptAtTargetEvent += at_target;
this.World.EventManager.OnScriptNotAtTargetEvent += not_at_target;
this.World.EventManager.OnScriptAtRotTargetEvent += at_rot_target;
this.World.EventManager.OnScriptNotAtRotTargetEvent += not_at_rot_target;
this.World.EventManager.OnScriptMovingStartEvent += moving_start;
this.World.EventManager.OnScriptMovingEndEvent += moving_end;
this.World.EventManager.OnScriptControlEvent += control;
this.World.EventManager.OnScriptColliderStart += collision_start;
this.World.EventManager.OnScriptColliding += collision;
this.World.EventManager.OnScriptCollidingEnd += collision_end;
this.World.EventManager.OnScriptLandColliderStart += land_collision_start;
this.World.EventManager.OnScriptLandColliding += land_collision;
this.World.EventManager.OnScriptLandColliderEnd += land_collision_end;
IMoneyModule money=this.World.RequestModuleInterface<IMoneyModule>();
if (money != null)
this.World.EventManager.OnScriptMovingStartEvent += moving_start;
this.World.EventManager.OnScriptMovingEndEvent += moving_end;
this.World.EventManager.OnScriptControlEvent += control;
this.World.EventManager.OnScriptColliderStart += collision_start;
this.World.EventManager.OnScriptColliding += collision;
this.World.EventManager.OnScriptCollidingEnd += collision_end;
this.World.EventManager.OnScriptLandColliderStart += land_collision_start;
this.World.EventManager.OnScriptLandColliding += land_collision;
this.World.EventManager.OnScriptLandColliderEnd += land_collision_end;
IMoneyModule money = this.World.RequestModuleInterface<IMoneyModule>();
if(money != null)
{
money.OnObjectPaid+=HandleObjectPaid;
money.OnObjectPaid += HandleObjectPaid;
}
}
@ -106,15 +106,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
SceneObjectPart part =
this.World.GetSceneObjectPart(objectID);
if (part == null)
if(part == null)
return;
if ((part.ScriptEvents & scriptEvents.money) == 0)
if((part.ScriptEvents & scriptEvents.money) == 0)
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);
}
@ -141,7 +141,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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,
SurfaceTouchEventArgs surfaceArgs)
{
@ -152,10 +152,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs, string eventname)
{
SceneObjectPart part;
if (originalID == 0) {
if(originalID == 0)
{
part = this.World.GetSceneObjectPart(localID);
if (part == null) return;
} else {
if(part == null)
return;
}
else
{
part = this.World.GetSceneObjectPart(originalID);
}
@ -167,7 +171,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
offsetPos.Z);
det.LinkNum = part.LinkNum;
if (surfaceArgs != null) {
if(surfaceArgs != null)
{
det.SurfaceTouchArgs = surfaceArgs;
}
@ -182,7 +187,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
int ch = (int)change;
// Add to queue for all scripts in localID, Object pass change.
this.PostObjectEvent(localID, new EventParams(
"changed",new object[] { ch },
"changed", new object[] { ch },
zeroDetectParams));
}
@ -216,15 +221,17 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private void collisions(uint localID, ColliderArgs col, string eventname)
{
int dc = col.Colliders.Count;
if (dc > 0) {
if(dc > 0)
{
DetectParams[] det = new DetectParams[dc];
int i = 0;
foreach (DetectedObject detobj in col.Colliders) {
foreach(DetectedObject detobj in col.Colliders)
{
DetectParams d = new DetectParams();
det[i++] = d;
d.Key = detobj.keyUUID;
d.Populate (this.World);
d.Populate(this.World);
/* not done by XEngine...
d.Position = detobj.posVector;
@ -257,12 +264,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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,
detobj.posVector.Y,
detobj.posVector.Z);
EventParams eps = new EventParams(eventname,
new Object[] { vec },
EventParams eps = new EventParams(eventname,
new Object[] { vec },
zeroDetectParams);
this.PostObjectEvent(localID, eps);
}
@ -274,7 +282,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public void control(UUID itemID, UUID agentID, uint held, uint change)
{
this.PostScriptEvent(itemID, new EventParams(
"control",new object[] {
"control", new object[] {
agentID.ToString(),
(int)held,
(int)change},
@ -285,7 +293,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
string address, string subject, string message, int numLeft)
{
this.PostObjectEvent(localID, new EventParams(
"email",new object[] {
"email", new object[] {
timeSent,
address,
subject,
@ -308,18 +316,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public void not_at_target(uint localID)
{
this.PostObjectEvent(localID, new EventParams(
"not_at_target",zeroObjectArray,
"not_at_target", zeroObjectArray,
zeroDetectParams));
}
public void at_rot_target(uint localID, uint handle, OpenMetaverse.Quaternion targetrot, OpenMetaverse.Quaternion atrot)
{
this.PostObjectEvent(
localID,
localID,
new EventParams(
"at_rot_target",
new object[] {
new LSL_Integer(handle),
new LSL_Integer(handle),
new LSL_Rotation(targetrot.X, targetrot.Y, targetrot.Z, targetrot.W),
new LSL_Rotation(atrot.X, atrot.Y, atrot.Z, atrot.W)
},
@ -331,7 +339,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public void not_at_rot_target(uint localID)
{
this.PostObjectEvent(localID, new EventParams(
"not_at_rot_target",zeroObjectArray,
"not_at_rot_target", zeroObjectArray,
zeroDetectParams));
}
@ -340,7 +348,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public void attach(uint localID, UUID itemID, UUID avatar)
{
this.PostObjectEvent(localID, new EventParams(
"attach",new object[] {
"attach", new object[] {
avatar.ToString() },
zeroDetectParams));
}
@ -351,14 +359,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public void moving_start(uint localID)
{
this.PostObjectEvent(localID, new EventParams(
"moving_start",zeroObjectArray,
"moving_start", zeroObjectArray,
zeroDetectParams));
}
public void moving_end(uint localID)
{
this.PostObjectEvent(localID, new EventParams(
"moving_end",zeroObjectArray,
"moving_end", zeroObjectArray,
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_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
@ -48,32 +48,35 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Note that the xmr arrays and script-defined objects have their own
* 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 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;
}
~HeapTrackerBase ()
~HeapTrackerBase()
{
usage = instance.UpdateHeapUse (usage, 0);
usage = instance.UpdateHeapUse(usage, 0);
}
}
/**
* Wrapper around lists to keep track of how much memory they use.
*/
public class HeapTrackerList : HeapTrackerBase {
private static FieldInfo listValueField = typeof (HeapTrackerList).GetField ("value");
private static MethodInfo listSaveMethod = typeof (HeapTrackerList).GetMethod ("Save");
public class HeapTrackerList: HeapTrackerBase
{
private static FieldInfo listValueField = typeof(HeapTrackerList).GetField("value");
private static MethodInfo listSaveMethod = typeof(HeapTrackerList).GetMethod("Save");
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
// input:
@ -83,7 +86,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 'this' pointer popped from stack
// new value popped from CIL stack
// 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);
}
@ -95,21 +98,21 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 'this' pointer popped from stack
// value pushed on CIL stack replacing 'this' pointer
// 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);
return typeof (LSL_List);
ilGen.Emit(errorAt, OpCodes.Ldfld, listValueField);
return typeof(LSL_List);
}
public void Save (LSL_List lis)
public void Save(LSL_List lis)
{
int newuse = Size (lis);
usage = instance.UpdateHeapUse (usage, newuse);
int newuse = Size(lis);
usage = instance.UpdateHeapUse(usage, newuse);
value = lis;
}
//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:
//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:
try {
try
{
return lis.Size;
} catch {
}
catch
{
return 0;
}
}
@ -131,22 +137,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* Wrapper around objects to keep track of how much memory they use.
*/
public class HeapTrackerObject : HeapTrackerBase {
private static FieldInfo objectValueField = typeof (HeapTrackerObject).GetField ("value");
private static MethodInfo objectSaveMethod = typeof (HeapTrackerObject).GetMethod ("Save");
public class HeapTrackerObject: HeapTrackerBase
{
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_DELE = 8;
public const int HT_DOUB = 8;
public const int HT_SING = 4;
public const int HT_SFLT = 4;
public const int HT_INT = 4;
public const int HT_VEC = HT_DOUB * 3;
public const int HT_ROT = HT_DOUB * 4;
public const int HT_INT = 4;
public const int HT_VEC = HT_DOUB * 3;
public const int HT_ROT = HT_DOUB * 4;
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
// input:
@ -156,7 +163,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 'this' pointer popped from stack
// new value popped from CIL stack
// 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);
}
@ -168,67 +175,88 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 'this' pointer popped from stack
// value pushed on CIL stack replacing 'this' pointer
// 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);
return typeof (object);
ilGen.Emit(errorAt, OpCodes.Ldfld, objectValueField);
return typeof(object);
}
public void Save (object obj)
public void Save(object obj)
{
int newuse = Size (obj);
usage = instance.UpdateHeapUse (usage, newuse);
int newuse = Size(obj);
usage = instance.UpdateHeapUse(usage, newuse);
value = obj;
}
// 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 Delegate) return HT_DELE;
if (obj is double) return HT_DOUB;
if (obj is float) return HT_SING;
if (obj is int) return HT_INT;
if (obj is LSL_Float) return HT_SFLT;
if (obj is LSL_Integer) return HT_INT;
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 char)
return HT_CHAR;
if(obj is Delegate)
return HT_DELE;
if(obj is double)
return HT_DOUB;
if(obj is float)
return HT_SING;
if(obj is int)
return HT_INT;
if(obj is LSL_Float)
return HT_SFLT;
if(obj is LSL_Integer)
return HT_INT;
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;
int len = ar.Length;
if (len == 0) return 0;
Type et = ar.GetType ().GetElementType ();
if (et.IsValueType) return Size (ar.GetValue (0)) * len;
if(len == 0)
return 0;
Type et = ar.GetType().GetElementType();
if(et.IsValueType)
return Size(ar.GetValue(0)) * len;
int size = 0;
for (int i = 0; i < len; i ++) {
size += Size (ar.GetValue (i));
for(int i = 0; i < len; i++)
{
size += Size(ar.GetValue(i));
}
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.
*/
public class HeapTrackerString : HeapTrackerBase {
private static FieldInfo stringValueField = typeof (HeapTrackerString).GetField ("value");
private static MethodInfo stringSaveMethod = typeof (HeapTrackerString).GetMethod ("Save");
public class HeapTrackerString: HeapTrackerBase
{
private static FieldInfo stringValueField = typeof(HeapTrackerString).GetField("value");
private static MethodInfo stringSaveMethod = typeof(HeapTrackerString).GetMethod("Save");
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
// input:
@ -238,9 +266,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 'this' pointer popped from stack
// new value popped from CIL stack
// 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
@ -250,20 +278,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 'this' pointer popped from stack
// value pushed on CIL stack replacing 'this' pointer
// 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);
return typeof (string);
ilGen.Emit(errorAt, OpCodes.Ldfld, stringValueField);
return typeof(string);
}
public void Save (string str)
public void Save(string str)
{
int newuse = Size (str);
usage = instance.UpdateHeapUse (usage, newuse);
int newuse = Size(str);
usage = instance.UpdateHeapUse(usage, newuse);
value = str;
}
public static int Size (string str)
public static int Size(string str)
{
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_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. *
\****************************************************/
public class XMRLSL_Api : LSL_Api
public class XMRLSL_Api: LSL_Api
{
public AsyncCommandManager acm;
private XMRInstance inst;
@ -83,38 +83,38 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* -2: no av granted perms
* -3: av not in region
*/
/* engines should not have own API
public int xmrSeatAvatar (bool owner)
{
// Get avatar to be seated and make sure they have given us ANIMATION permission
/* engines should not have own API
public int xmrSeatAvatar (bool owner)
{
// Get avatar to be seated and make sure they have given us ANIMATION permission
UUID avuuid;
if (owner) {
avuuid = inst.m_Part.OwnerID;
} else {
if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) == 0) {
return -1;
UUID avuuid;
if (owner) {
avuuid = inst.m_Part.OwnerID;
} else {
if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRIGGER_ANIMATION) == 0) {
return -1;
}
avuuid = m_item.PermsGranter;
}
if (avuuid == UUID.Zero) {
return -2;
}
ScenePresence presence = World.GetScenePresence (avuuid);
if (presence == null) {
return -3;
}
// remoteClient = not used by ScenePresence.HandleAgentRequestSit()
// agentID = not used by ScenePresence.HandleAgentRequestSit()
// targetID = UUID of prim to sit on
// offset = offset of sitting position
presence.HandleAgentRequestSit (null, UUID.Zero, m_host.UUID, OpenMetaverse.Vector3.Zero);
return 0;
}
avuuid = m_item.PermsGranter;
}
if (avuuid == UUID.Zero) {
return -2;
}
ScenePresence presence = World.GetScenePresence (avuuid);
if (presence == null) {
return -3;
}
// remoteClient = not used by ScenePresence.HandleAgentRequestSit()
// agentID = not used by ScenePresence.HandleAgentRequestSit()
// targetID = UUID of prim to sit on
// offset = offset of sitting position
presence.HandleAgentRequestSit (null, UUID.Zero, m_host.UUID, OpenMetaverse.Vector3.Zero);
return 0;
}
*/
*/
/**
* @brief llTeleportAgent() is broken in that if you pass it a landmark,
* it still subjects the position to spawn points, as it always
@ -125,80 +125,80 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @param landmark = inventory name or UUID of a landmark object
* @param lookat = looking direction after teleport
*/
/* engines should not have own API
public void xmrTeleportAgent2Landmark (string agent, string landmark, LSL_Vector lookat)
{
// find out about agent to be teleported
UUID agentId;
if (!UUID.TryParse (agent, out agentId)) throw new ApplicationException ("bad agent uuid");
/* engines should not have own API
public void xmrTeleportAgent2Landmark (string agent, string landmark, LSL_Vector lookat)
{
// find out about agent to be teleported
UUID agentId;
if (!UUID.TryParse (agent, out agentId)) throw new ApplicationException ("bad agent uuid");
ScenePresence presence = World.GetScenePresence (agentId);
if (presence == null) throw new ApplicationException ("agent not present in scene");
if (presence.IsNPC) throw new ApplicationException ("agent is an NPC");
if (presence.IsGod) throw new ApplicationException ("agent is a god");
ScenePresence presence = World.GetScenePresence (agentId);
if (presence == null) throw new ApplicationException ("agent not present in scene");
if (presence.IsNPC) throw new ApplicationException ("agent is an NPC");
if (presence.IsGod) throw new ApplicationException ("agent is a god");
// prim must be owned by land owner or prim must be attached to agent
if (m_host.ParentGroup.AttachmentPoint == 0) {
if (m_host.OwnerID != World.LandChannel.GetLandObject (presence.AbsolutePosition).LandData.OwnerID) {
throw new ApplicationException ("prim not owned by land's owner");
// prim must be owned by land owner or prim must be attached to agent
if (m_host.ParentGroup.AttachmentPoint == 0) {
if (m_host.OwnerID != World.LandChannel.GetLandObject (presence.AbsolutePosition).LandData.OwnerID) {
throw new ApplicationException ("prim not owned by land's owner");
}
} else {
if (m_host.OwnerID != presence.UUID) throw new ApplicationException ("prim not attached to agent");
}
// find landmark in inventory or by UUID
UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName (m_host, landmark);
if (assetID == UUID.Zero) throw new ApplicationException ("no such landmark");
// read it in and make sure it is a landmark
AssetBase lma = World.AssetService.Get (assetID.ToString ());
if ((lma == null) || (lma.Type != (sbyte)AssetType.Landmark)) throw new ApplicationException ("not a landmark");
// parse the record
AssetLandmark lm = new AssetLandmark (lma);
// the regionhandle (based on region's world X,Y) might be out of date
// re-read the handle so we can pass it to RequestTeleportLocation()
var region = World.GridService.GetRegionByUUID (World.RegionInfo.ScopeID, lm.RegionID);
if (region == null) throw new ApplicationException ("no such region");
// finally ready to teleport
World.RequestTeleportLocation (presence.ControllingClient,
region.RegionHandle,
lm.Position,
lookat,
(uint)TeleportFlags.ViaLandmark);
}
} else {
if (m_host.OwnerID != presence.UUID) throw new ApplicationException ("prim not attached to agent");
}
// find landmark in inventory or by UUID
UUID assetID = ScriptUtils.GetAssetIdFromKeyOrItemName (m_host, landmark);
if (assetID == UUID.Zero) throw new ApplicationException ("no such landmark");
// read it in and make sure it is a landmark
AssetBase lma = World.AssetService.Get (assetID.ToString ());
if ((lma == null) || (lma.Type != (sbyte)AssetType.Landmark)) throw new ApplicationException ("not a landmark");
// parse the record
AssetLandmark lm = new AssetLandmark (lma);
// the regionhandle (based on region's world X,Y) might be out of date
// re-read the handle so we can pass it to RequestTeleportLocation()
var region = World.GridService.GetRegionByUUID (World.RegionInfo.ScopeID, lm.RegionID);
if (region == null) throw new ApplicationException ("no such region");
// finally ready to teleport
World.RequestTeleportLocation (presence.ControllingClient,
region.RegionHandle,
lm.Position,
lookat,
(uint)TeleportFlags.ViaLandmark);
}
*/
*/
/**
* @brief Allow any member of group given by config SetParcelMusicURLGroup to set music URL.
* Code modelled after llSetParcelMusicURL().
* @param newurl = new URL to set (or "" to leave it alone)
* @returns previous URL string
*/
/* engines should not have own API
public string xmrSetParcelMusicURLGroup (string newurl)
{
string groupname = m_ScriptEngine.Config.GetString ("SetParcelMusicURLGroup", "");
if (groupname == "") throw new ApplicationException ("no SetParcelMusicURLGroup config param set");
/* engines should not have own API
public string xmrSetParcelMusicURLGroup (string newurl)
{
string groupname = m_ScriptEngine.Config.GetString ("SetParcelMusicURLGroup", "");
if (groupname == "") throw new ApplicationException ("no SetParcelMusicURLGroup config param set");
IGroupsModule igm = World.RequestModuleInterface<IGroupsModule> ();
if (igm == null) throw new ApplicationException ("no GroupsModule loaded");
IGroupsModule igm = World.RequestModuleInterface<IGroupsModule> ();
if (igm == null) throw new ApplicationException ("no GroupsModule loaded");
GroupRecord grouprec = igm.GetGroupRecord (groupname);
if (grouprec == null) throw new ApplicationException ("no such group " + groupname);
GroupRecord grouprec = igm.GetGroupRecord (groupname);
if (grouprec == null) throw new ApplicationException ("no such group " + groupname);
GroupMembershipData gmd = igm.GetMembershipData (grouprec.GroupID, m_host.OwnerID);
if (gmd == null) throw new ApplicationException ("not a member of group " + groupname);
GroupMembershipData gmd = igm.GetMembershipData (grouprec.GroupID, m_host.OwnerID);
if (gmd == null) throw new ApplicationException ("not a member of group " + groupname);
ILandObject land = World.LandChannel.GetLandObject (m_host.AbsolutePosition);
if (land == null) throw new ApplicationException ("no land at " + m_host.AbsolutePosition.ToString ());
string oldurl = land.GetMusicUrl ();
if (oldurl == null) oldurl = "";
if ((newurl != null) && (newurl != "")) land.SetMusicUrl (newurl);
return oldurl;
}
*/
ILandObject land = World.LandChannel.GetLandObject (m_host.AbsolutePosition);
if (land == null) throw new ApplicationException ("no land at " + m_host.AbsolutePosition.ToString ());
string oldurl = land.GetMusicUrl ();
if (oldurl == null) oldurl = "";
if ((newurl != null) && (newurl != "")) land.SetMusicUrl (newurl);
return oldurl;
}
*/
}
public partial class XMRInstance
@ -222,9 +222,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public DetectParams GetDetectParams(int number)
{
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];
}
return dp;
}
@ -236,7 +236,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public void Die()
{
// llDie doesn't work in attachments!
if (m_Part.ParentGroup.IsAttachment || m_DetachQuantum > 0)
if(m_Part.ParentGroup.IsAttachment || m_DetachQuantum > 0)
return;
throw new ScriptDieException();
@ -247,8 +247,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
public void Sleep(int ms)
{
lock (m_QueueLock) {
lock(m_QueueLock)
{
/*
* 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
* 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)
{
DateTime sleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds (timeout * 1000.0);
DateTime sleepUntil = DateTime.UtcNow + TimeSpan.FromMilliseconds(timeout * 1000.0);
EventParams evt = null;
int callNo, evc2;
int evc1 = 0;
@ -324,45 +324,47 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
callNo = -1;
try
{
if (callMode == CallMode_NORMAL) goto findevent;
if(callMode == CallMode_NORMAL)
goto findevent;
/*
* Stack frame is being restored as saved via CheckRun...().
* Restore necessary values then jump to __call<n> label to resume processing.
*/
sv = RestoreStackFrame ("xmrEventDequeue", out callNo);
sleepUntil = DateTime.Parse ((string)sv[0]);
sv = RestoreStackFrame("xmrEventDequeue", out callNo);
sleepUntil = DateTime.Parse((string)sv[0]);
returnMask1 = (int)sv[1];
returnMask2 = (int)sv[2];
mask1 = (int)sv[3];
mask2 = (int)sv[4];
switch (callNo)
mask1 = (int)sv[3];
mask2 = (int)sv[4];
switch(callNo)
{
case 0: goto __call0;
case 0:
goto __call0;
case 1:
{
evc1 = (int)sv[5];
evc = (ScriptEventCode)(int)sv[6];
DetectParams[] detprms = ObjArrToDetPrms ((object[])sv[7]);
object[] ehargs = (object[])sv[8];
evt = new EventParams (evc.ToString (), ehargs, detprms);
goto __call1;
}
{
evc1 = (int)sv[5];
evc = (ScriptEventCode)(int)sv[6];
DetectParams[] detprms = ObjArrToDetPrms((object[])sv[7]);
object[] ehargs = (object[])sv[8];
evt = new EventParams(evc.ToString(), ehargs, detprms);
goto __call1;
}
}
throw new ScriptBadCallNoException (callNo);
throw new ScriptBadCallNoException(callNo);
/*
* Find first event that matches either the return or background masks.
*/
findevent:
Monitor.Enter (m_QueueLock);
for (lln = m_EventQueue.First; lln != null; lln = lln.Next)
findevent:
Monitor.Enter(m_QueueLock);
for(lln = m_EventQueue.First; lln != null; lln = lln.Next)
{
evt = lln.Value;
evc = (ScriptEventCode)Enum.Parse (typeof (ScriptEventCode), evt.EventName);
evt = lln.Value;
evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode), evt.EventName);
evc1 = (int)evc;
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)))
goto remfromq;
}
@ -373,51 +375,50 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
m_SleepUntil = sleepUntil;
m_SleepEventMask1 = mask1;
m_SleepEventMask2 = mask2;
Monitor.Exit (m_QueueLock);
Monitor.Exit(m_QueueLock);
suspendOnCheckRunTemp = true;
callNo = 0;
__call0:
CheckRunQuick ();
__call0:
CheckRunQuick();
goto checktmo;
/*
* Found one, remove it from queue.
*/
remfromq:
m_EventQueue.Remove (lln);
if ((uint)evc1 < (uint)m_EventCounts.Length)
m_EventCounts[evc1] --;
remfromq:
m_EventQueue.Remove(lln);
if((uint)evc1 < (uint)m_EventCounts.Length)
m_EventCounts[evc1]--;
Monitor.Exit (m_QueueLock);
m_InstEHEvent ++;
Monitor.Exit(m_QueueLock);
m_InstEHEvent++;
/*
* 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)))
{
/*
* Returnable event, return its parameters in a list.
* Also set the detect parameters to what the event has.
*/
int plen = evt.Params.Length;
object[] plist = new object[plen+1];
object[] plist = new object[plen + 1];
plist[0] = (LSL_Integer)evc1;
for (int i = 0; i < plen;)
for(int i = 0; i < plen;)
{
object ob = evt.Params[i];
if (ob is int)
if(ob is int)
ob = (LSL_Integer)(int)ob;
else if (ob is double)
else if(ob is double)
ob = (LSL_Float)(double)ob;
else if (ob is string)
else if(ob is string)
ob = (LSL_String)(string)ob;
plist[++i] = ob;
}
m_DetectParams = evt.DetectParams;
return new LSL_List (plist);
return new LSL_List(plist);
}
/*
@ -425,35 +426,35 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* then check event queue again.
*/
callNo = 1;
__call1:
ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode,evc1];
if (seh == null)
__call1:
ScriptEventHandler seh = m_ObjCode.scriptEventHandlerTable[stateCode, evc1];
if(seh == null)
goto checktmo;
DetectParams[] saveDetParams = this.m_DetectParams;
object[] saveEHArgs = this.ehArgs;
DetectParams[] saveDetParams = this.m_DetectParams;
object[] saveEHArgs = this.ehArgs;
ScriptEventCode saveEventCode = this.eventCode;
this.m_DetectParams = evt.DetectParams;
this.ehArgs = evt.Params;
this.eventCode = evc;
this.ehArgs = evt.Params;
this.eventCode = evc;
try
{
seh (this);
seh(this);
}
finally
{
m_DetectParams = saveDetParams;
ehArgs = saveEHArgs;
eventCode = saveEventCode;
this.m_DetectParams = saveDetParams;
this.ehArgs = saveEHArgs;
this.eventCode = saveEventCode;
}
/*
* Keep waiting until we find a returnable event or timeout.
*/
checktmo:
if (DateTime.UtcNow < sleepUntil)
checktmo:
if(DateTime.UtcNow < sleepUntil)
goto findevent;
/*
@ -463,7 +464,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
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
* when we need to.
*/
sv = CaptureStackFrame ("xmrEventDequeue", callNo, 9);
sv[0] = sleepUntil.ToString (); // needed at __call0,__call1
sv = CaptureStackFrame("xmrEventDequeue", callNo, 9);
sv[0] = sleepUntil.ToString(); // needed at __call0,__call1
sv[1] = returnMask1; // needed at __call0,__call1
sv[2] = returnMask2; // needed at __call0,__call1
sv[3] = mask1; // needed at __call0,__call1
sv[4] = mask2; // needed at __call0,__call1
if (callNo == 1)
if(callNo == 1)
{
sv[5] = evc1; // 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
}
}
@ -495,16 +496,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* are as currently set for the script (use xmrEventLoadDets to set how
* you want them to be different).
*/
public override void xmrEventEnqueue (LSL_List ev)
public override void xmrEventEnqueue(LSL_List ev)
{
object[] data = ev.Data;
ScriptEventCode evc = (ScriptEventCode)ListInt (data[0]);
ScriptEventCode evc = (ScriptEventCode)ListInt(data[0]);
int nargs = data.Length - 1;
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;
public override LSL_List xmrEventSaveDets ()
public override LSL_List xmrEventSaveDets()
{
object[] obs = DetPrmsToObjArr (m_DetectParams);
return new LSL_List (obs);
object[] obs = DetPrmsToObjArr(m_DetectParams);
return new LSL_List(obs);
}
private static object[] DetPrmsToObjArr (DetectParams[] dps)
private static object[] DetPrmsToObjArr(DetectParams[] dps)
{
int len = dps.Length;
object[] obs = new object[len*16+1];
object[] obs = new object[len * 16 + 1];
int j = 0;
obs[j++] = (LSL_Integer)saveDPVer;
for (int i = 0; i < len; i ++)
for(int i = 0; i < len; i++)
{
DetectParams dp = dps[i];
obs[j++] = (LSL_String)dp.Key.ToString(); // UUID
@ -548,54 +549,52 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
return obs;
}
/**
* @brief Load current detect params from a list
* @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;
if ((objs.Length % 16 != 1) || (ListInt (objs[j++]) != saveDPVer))
throw new Exception ("invalid detect param format");
if((objs.Length % 16 != 1) || (ListInt(objs[j++]) != saveDPVer))
throw new Exception("invalid detect param format");
int len = objs.Length / 16;
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.OffsetPos = (LSL_Vector)objs[j++];
dp.LinkNum = ListInt (objs[j++]);
dp.Group = new UUID (ListStr (objs[j++]));
dp.Name = ListStr (objs[j++]);
dp.Owner = new UUID (ListStr (objs[j++]));
dp.Position = (LSL_Vector)objs[j++];
dp.Rotation = (LSL_Rotation)objs[j++];
dp.Type = ListInt (objs[j++]);
dp.Velocity = (LSL_Vector)objs[j++];
dp.Key = new UUID(ListStr(objs[j++]));
dp.OffsetPos = (LSL_Vector)objs[j++];
dp.LinkNum = ListInt(objs[j++]);
dp.Group = new UUID(ListStr(objs[j++]));
dp.Name = ListStr(objs[j++]);
dp.Owner = new UUID(ListStr(objs[j++]));
dp.Position = (LSL_Vector)objs[j++];
dp.Rotation = (LSL_Rotation)objs[j++];
dp.Type = ListInt(objs[j++]);
dp.Velocity = (LSL_Vector)objs[j++];
SurfaceTouchEventArgs stea = new SurfaceTouchEventArgs ();
SurfaceTouchEventArgs stea = new SurfaceTouchEventArgs();
stea.STCoord = LSLVec2OMVec ((LSL_Vector)objs[j++]);
stea.Normal = LSLVec2OMVec ((LSL_Vector)objs[j++]);
stea.Binormal = LSLVec2OMVec ((LSL_Vector)objs[j++]);
stea.Position = LSLVec2OMVec ((LSL_Vector)objs[j++]);
stea.UVCoord = LSLVec2OMVec ((LSL_Vector)objs[j++]);
stea.FaceIndex = ListInt (objs[j++]);
stea.STCoord = LSLVec2OMVec((LSL_Vector)objs[j++]);
stea.Normal = LSLVec2OMVec((LSL_Vector)objs[j++]);
stea.Binormal = LSLVec2OMVec((LSL_Vector)objs[j++]);
stea.Position = LSLVec2OMVec((LSL_Vector)objs[j++]);
stea.UVCoord = LSLVec2OMVec((LSL_Vector)objs[j++]);
stea.FaceIndex = ListInt(objs[j++]);
dp.SurfaceTouchArgs = stea;
dps[i] = dp;
}
return dps;
}
@ -623,21 +622,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/*
* Clear out any old events from the queue.
*/
lock (m_QueueLock)
lock(m_QueueLock)
{
m_EventQueue.Clear();
for (int i = m_EventCounts.Length; -- i >= 0;)
for(int i = m_EventCounts.Length; --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
* 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
* script. We don't want script-level try/catch to intercept
* 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.Threading;
using System.IO;
using System.Xml;
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_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine
namespace OpenSim.Region.ScriptEngine.Yengine
{
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.
* <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>
* <Running>m_Running</Running>
* <DetectArray ...
@ -71,23 +70,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// Change this to a 5 second timeout. If things do mess up,
// we don't want to be stuck forever.
//
m_DetachReady.WaitOne (5000, false);
m_DetachReady.WaitOne(5000, false);
XmlElement scriptStateN = doc.CreateElement("", "ScriptState", "");
scriptStateN.SetAttribute("Engine", m_Engine.ScriptEngineName);
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
// stable. Setting suspendOnCheckRun tells CheckRun() to suspend
// and return out so RunOne() will release the lock asap.
// Make sure we aren't executing part of the script so it stays
// stable. Setting suspendOnCheckRun tells CheckRun() to suspend
// and return out so RunOne() will release the lock asap.
suspendOnCheckRunHold = true;
lock (m_RunLock)
lock(m_RunLock)
{
m_RunOnePhase = "GetExecutionState enter";
CheckRunLockInvariants(true);
// Get copy of script globals and stack in relocateable form.
// Get copy of script globals and stack in relocateable form.
MemoryStream snapshotStream = new MemoryStream();
MigrateOutEventHandler(snapshotStream);
Byte[] snapshotBytes = snapshotStream.ToArray();
@ -96,21 +95,24 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
XmlElement snapshotN = doc.CreateElement("", "Snapshot", "");
snapshotN.AppendChild(doc.CreateTextNode(snapshotString));
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", "");
runningN.AppendChild(doc.CreateTextNode(m_Running.ToString()));
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", "");
doGblInitN.AppendChild(doc.CreateTextNode(doGblInit.ToString()));
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", "");
scriptStateN.AppendChild(permissionsN);
@ -121,30 +123,32 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
XmlAttribute maskA = doc.CreateAttribute("", "mask", "");
maskA.Value = m_Item.PermsMask.ToString();
permissionsN.Attributes.Append(maskA);
m_RunOnePhase = "GetExecutionState E"; CheckRunLockInvariants(true);
m_RunOnePhase = "GetExecutionState E";
CheckRunLockInvariants(true);
// "DetectParams" are returned by llDetected...() script functions
// for the currently active event, if any.
if (m_DetectParams != null)
// "DetectParams" are returned by llDetected...() script functions
// for the currently active event, if any.
if(m_DetectParams != null)
{
XmlElement detParArrayN = doc.CreateElement("", "DetectArray", "");
AppendXMLDetectArray(doc, detParArrayN, m_DetectParams);
scriptStateN.AppendChild(detParArrayN);
}
m_RunOnePhase = "GetExecutionState F"; CheckRunLockInvariants(true);
m_RunOnePhase = "GetExecutionState F";
CheckRunLockInvariants(true);
// Save any events we have in the queue.
// <EventQueue>
// <Event Name="...">
// <param>...</param> ...
// <DetectParams>...</DetectParams> ...
// </Event>
// ...
// </EventQueue>
// Save any events we have in the queue.
// <EventQueue>
// <Event Name="...">
// <param>...</param> ...
// <DetectParams>...</DetectParams> ...
// </Event>
// ...
// </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", "");
singleEventN.SetAttribute("Name", evt.EventName);
@ -154,26 +158,28 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
}
scriptStateN.AppendChild(queuedEventsN);
m_RunOnePhase = "GetExecutionState G"; CheckRunLockInvariants(true);
m_RunOnePhase = "GetExecutionState G";
CheckRunLockInvariants(true);
// "Plugins" indicate enabled timers and listens, etc.
Object[] pluginData =
// "Plugins" indicate enabled timers and listens, etc.
Object[] pluginData =
AsyncCommandManager.GetSerializationData(m_Engine, m_ItemID);
XmlNode plugins = doc.CreateElement("", "Plugins", "");
AppendXMLObjectArray(doc, plugins, pluginData, "plugin");
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;
m_RunOnePhase = "GetExecutionState leave";
CheckRunLockInvariants(true);
}
// scriptStateN represents the contents of the .state file so
// write the .state file while we are here.
// scriptStateN represents the contents of the .state file so
// write the .state file while we are here.
FileStream fs = File.Create(m_StateFileName);
StreamWriter sw = new StreamWriter(fs);
sw.Write(scriptStateN.OuterXml);
@ -185,116 +191,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @brief Write script state to output stream.
* The script microthread is at same state on return,
* ie, either inactive or suspended inside CheckRun().
*
* Input:
* 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.
// Does not change script state.
moehstream.WriteByte (migrationVersion);
moehstream.WriteByte ((byte)16);
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);
}
}
// Write script state out, frames and all, to the stream.
// Does not change script state.
stream.WriteByte(migrationVersion);
stream.WriteByte((byte)16);
this.MigrateOut(new BinaryWriter(stream));
}
/**
@ -304,7 +210,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
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);
parent.AppendChild(detectParamsN);
@ -367,7 +273,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
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);
parent.AppendChild(element);
@ -385,7 +291,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
XmlAttribute typ = doc.CreateAttribute("", "type", "");
XmlElement n = doc.CreateElement("", tag, "");
if (o is LSL_List)
if(o is LSL_List)
{
typ.Value = "list";
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.Api;
using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
using OpenSim.Region.ScriptEngine.XMREngine;
using OpenSim.Region.ScriptEngine.Yengine;
using OpenSim.Region.Framework.Scenes;
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_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine
namespace OpenSim.Region.ScriptEngine.Yengine
{
public partial class XMRInstance
{
@ -65,78 +65,82 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @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 stackSize = number of bytes to allocate for stacks
* @param errors = return compiler errors in this array
* @param forceRecomp = force recompile
* 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)
{
if (stackSize < 16384) stackSize = 16384;
if (heapSize < 16384) heapSize = 16384;
if(stackSize < 16384)
stackSize = 16384;
if(heapSize < 16384)
heapSize = 16384;
// Save all call parameters in instance vars for easy access.
m_Engine = engine;
// Save all call parameters in instance vars for easy access.
m_Engine = engine;
m_ScriptBasePath = scriptBasePath;
m_StackSize = stackSize;
m_HeapSize = heapSize;
m_StackSize = stackSize;
m_StackLeft = stackSize;
m_HeapSize = heapSize;
m_CompilerErrors = errors;
m_StateFileName = GetStateFileName(scriptBasePath, m_ItemID);
m_StateFileName = GetStateFileName(scriptBasePath, m_ItemID);
// Not in any XMRInstQueue.
// Not in any XMRInstQueue.
m_NextInst = this;
m_PrevInst = this;
// Set up list of API calls it has available.
// This also gets the API modules ready to accept setup data, such as
// active listeners being restored.
// Set up list of API calls it has available.
// This also gets the API modules ready to accept setup data, such as
// active listeners being restored.
IScriptApi scriptApi;
ApiManager am = new ApiManager();
foreach (string api in am.GetApis())
foreach(string api in am.GetApis())
{
// Instantiate the API for this script instance.
if (api != "LSL") {
// Instantiate the API for this script instance.
if(api != "LSL")
scriptApi = am.CreateApi(api);
} else {
else
scriptApi = m_XMRLSLApi = new XMRLSL_Api();
}
// Connect it up to the instance.
InitScriptApi (engine, api, scriptApi);
// Connect it up to the instance.
InitScriptApi(engine, api, scriptApi);
}
m_XMRLSLApi.InitXMRLSLApi(this);
// Get object loaded, compiling script and reading .state file as
// necessary to restore the state.
// Get object loaded, compiling script and reading .state file as
// necessary to restore the state.
suspendOnCheckRunHold = true;
InstantiateScript();
m_SourceCode = null;
if (m_ObjCode == null) throw new ArgumentNullException ("m_ObjCode");
if (m_ObjCode.scriptEventHandlerTable == null)
throw new ArgumentNullException ("m_ObjCode.scriptEventHandlerTable");
if(m_ObjCode == null)
throw new ArgumentNullException("m_ObjCode");
if(m_ObjCode.scriptEventHandlerTable == null)
throw new ArgumentNullException("m_ObjCode.scriptEventHandlerTable");
suspendOnCheckRunHold = false;
suspendOnCheckRunTemp = false;
// Declare which events the script's current state can handle.
// Declare which events the script's current state can handle.
int eventMask = GetStateEventFlags(stateCode);
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.
engine.m_XMRInstanceApiCtxFieldInfos[api].SetValue (this, scriptApi);
// Set up m_ApiManager_<APINAME> = instance pointer.
engine.m_XMRInstanceApiCtxFieldInfos[api].SetValue(this, scriptApi);
// Initialize the API instance.
// Initialize the API instance.
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,
* ready to resume it from where the .state file says it was last
@ -146,152 +150,151 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
bool compiledIt = false;
ScriptObjCode objCode;
// 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).
// 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).
int i, j, len;
if (m_SourceCode == null) m_SourceCode = String.Empty;
for (len = m_SourceCode.Length; len > 0; --len)
if(m_SourceCode == null)
m_SourceCode = String.Empty;
for(len = m_SourceCode.Length; len > 0; --len)
{
if (m_SourceCode[len-1] > ' ')
if(m_SourceCode[len - 1] > ' ')
break;
}
for (i = 0; i < len; i ++)
for(i = 0; i < len; i++)
{
char c = m_SourceCode[i];
if (c <= ' ')
if(c <= ' ')
continue;
if (c != '/')
if(c != '/')
break;
if ((i + 1 >= len) || (m_SourceCode[i+1] != '/'))
if((i + 1 >= len) || (m_SourceCode[i + 1] != '/'))
break;
i = m_SourceCode.IndexOf ('\n', i);
if (i < 0)
i = m_SourceCode.IndexOf('\n', i);
if(i < 0)
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,
// or we are being forced to use the asset-id as the key, to
// open an already existing object code file.
m_ScriptObjCodeKey = m_Item.AssetID.ToString ();
if (i >= len)
// Source consists of nothing but // comments and whitespace,
// or we are being forced to use the asset-id as the key, to
// open an already existing object code file.
m_ScriptObjCodeKey = m_Item.AssetID.ToString();
if(i >= len)
m_SourceCode = "";
}
else
{
// Make up dictionary key for the object code.
// Use the same object code for identical source code
// regardless of asset ID, so we don't care if they
// copy scripts or not.
byte[] scbytes = System.Text.Encoding.UTF8.GetBytes (m_SourceCode);
StringBuilder sb = new StringBuilder ((256 + 5) / 6);
ByteArrayToSixbitStr (sb, System.Security.Cryptography.SHA256.Create ().ComputeHash (scbytes));
m_ScriptObjCodeKey = sb.ToString ();
// Make up dictionary key for the object code.
// Use the same object code for identical source code
// regardless of asset ID, so we don't care if they
// copy scripts or not.
byte[] scbytes = System.Text.Encoding.UTF8.GetBytes(m_SourceCode);
StringBuilder sb = new StringBuilder((256 + 5) / 6);
ByteArrayToSixbitStr(sb, System.Security.Cryptography.SHA256.Create().ComputeHash(scbytes));
m_ScriptObjCodeKey = sb.ToString();
// But source code can be just a sixbit string itself
// that identifies an already existing object code file.
if (len - i == m_ScriptObjCodeKey.Length)
// But source code can be just a sixbit string itself
// that identifies an already existing object code file.
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;
}
if (j < i)
if(j < i)
{
m_ScriptObjCodeKey = m_SourceCode.Substring (i, len - i);
m_ScriptObjCodeKey = m_SourceCode.Substring(i, len - i);
m_SourceCode = "";
}
}
}
// There may already be an ScriptObjCode struct in memory that
// we can use. If not, try to compile it.
lock (m_CompileLock)
// There may already be an ScriptObjCode struct in memory that
// we can use. If not, try to compile it.
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;
}
// Loaded successfully, increment reference count.
// Loaded successfully, increment reference count.
// If we just compiled it though, reset count to 0 first as
// this is the one-and-only existance of this objCode struct,
// and we want any old ones for this source code to be garbage
// collected.
// If we just compiled it though, reset count to 0 first as
// this is the one-and-only existance of this objCode struct,
// and we want any old ones for this source code to be garbage
// collected.
if (compiledIt)
if(compiledIt)
{
m_CompiledScriptObjCode[m_ScriptObjCodeKey] = objCode;
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;
}
try
{
// Fill in script instance from object code
// Script instance is put in a "never-ever-has-run-before" state.
{
// Fill in script instance from object code
// Script instance is put in a "never-ever-has-run-before" state.
LoadObjCode();
// Fill in script intial state
// - either as loaded from a .state file
// - or initial default state_entry() event
// Fill in script intial state
// - either as loaded from a .state file
// - or initial default state_entry() event
LoadInitialState();
}
catch
{
// If any error loading, decrement object code reference count.
DecObjCodeRefCount ();
// If any error loading, decrement object code reference count.
DecObjCodeRefCount();
throw;
}
}
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 val = 0;
foreach (byte b in bytes)
foreach(byte b in bytes)
{
val |= (int)((uint)b << bit);
bit += 8;
while (bit >= 6)
while(bit >= 6)
{
sb.Append (sixbit[val&63]);
sb.Append(sixbit[val & 63]);
val >>= 6;
bit -= 6;
bit -= 6;
}
}
if (bit > 0)
sb.Append (sixbit[val&63]);
if(bit > 0)
sb.Append(sixbit[val & 63]);
}
/*
* Try to create object code from source code
* If error, just throw exception
*/
private ScriptObjCode TryToCompile ()
// Try to create object code from source code
// If error, just throw exception
private ScriptObjCode TryToCompile()
{
m_CompilerErrors.Clear();
// If object file exists, create ScriptObjCode directly from that.
// Otherwise, compile the source to create object file then create
// ScriptObjCode from that.
string assetID = m_Item.AssetID.ToString();
// If object file exists, create ScriptObjCode directly from that.
// Otherwise, compile the source to create object file then create
// ScriptObjCode from that.
string assetID = m_Item.AssetID.ToString();
m_CameFrom = "asset://" + assetID;
ScriptObjCode objCode = Compile ();
if (m_CompilerErrors.Count != 0)
throw new Exception ("compilation errors");
ScriptObjCode objCode = Compile();
if(m_CompilerErrors.Count != 0)
throw new Exception("compilation errors");
if (objCode == null)
throw new Exception ("compilation failed");
if(objCode == null)
throw new Exception("compilation failed");
return objCode;
}
@ -299,20 +302,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/*
* Retrieve source from asset server.
*/
private string FetchSource (string cameFrom)
private string FetchSource(string cameFrom)
{
m_log.Debug ("[XMREngine]: fetching source " + cameFrom);
if (!cameFrom.StartsWith ("asset://"))
throw new Exception ("unable to retrieve source from " + cameFrom);
m_log.Debug("[YEngine]: fetching source " + cameFrom);
if(!cameFrom.StartsWith("asset://"))
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);
if (asset == null)
throw new Exception ("source not found " + cameFrom);
if(asset == null)
throw new Exception("source not found " + cameFrom);
string source = Encoding.UTF8.GetString (asset.Data);
if (EmptySource (source))
throw new Exception ("fetched source empty " + cameFrom);
string source = Encoding.UTF8.GetString(asset.Data);
if(EmptySource(source))
throw new Exception("fetched source empty " + cameFrom);
return source;
}
@ -321,33 +324,29 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Fill in script object initial contents.
* 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 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;
// Allocate global variable arrays.
this.glblVars.AllocVarArrays (m_ObjCode.glblSizes);
// Allocate global variable arrays.
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)];
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;
}
}
}
// Set up microthread object which actually calls the script event handler functions.
this.microthread = (IScriptUThread)m_Engine.uThreadCtor.Invoke (new object[] { this });
}
/*
@ -360,9 +359,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
private void LoadInitialState()
{
// If no .state file exists, start from default state
// Otherwise, read initial state from the .state file
if (!File.Exists(m_StateFileName))
// If no .state file exists, start from default state
// Otherwise, read initial state from the .state file
if(!File.Exists(m_StateFileName))
{
m_Running = true; // event processing is enabled
eventCode = ScriptEventCode.None; // not processing any event
@ -371,14 +371,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
doGblInit = true;
stateCode = 0;
PostEvent(new EventParams("state_entry",
PostEvent(new EventParams("state_entry",
zeroObjectArray,
zeroDetectParams));
}
else
{
FileStream fs = File.Open(m_StateFileName,
FileMode.Open,
FileStream fs = File.Open(m_StateFileName,
FileMode.Open,
FileAccess.Read);
StreamReader ss = new StreamReader(fs);
string xml = ss.ReadToEnd();
@ -390,48 +390,51 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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",
new Object[] { m_StartParam },
new Object[] { m_StartParam },
zeroDetectParams));
}
switch (m_StateSource)
switch(m_StateSource)
{
case StateSource.AttachedRez:
// PostEvent(new EventParams("attach",
// new object[] { m_Part.ParentGroup.AttachedAvatar.ToString() },
// zeroDetectParams));
// PostEvent(new EventParams("attach",
// new object[] { m_Part.ParentGroup.AttachedAvatar.ToString() },
// zeroDetectParams));
break;
case StateSource.PrimCrossing:
PostEvent(new EventParams("changed",
sbcCR,
sbcCR,
zeroDetectParams));
break;
case StateSource.Teleporting:
PostEvent(new EventParams("changed",
sbcCR,
sbcCR,
zeroDetectParams));
PostEvent(new EventParams("changed",
sbcCT,
sbcCT,
zeroDetectParams));
break;
case StateSource.RegionStart:
PostEvent(new EventParams("changed",
sbcCRS,
sbcCRS,
zeroDetectParams));
break;
}
}
private static Object[] sbcCRS = new Object[] { ScriptBaseClass.CHANGED_REGION_START };
private static Object[] sbcCR = new Object[] { ScriptBaseClass.CHANGED_REGION };
private static Object[] sbcCT = new Object[] { ScriptBaseClass.CHANGED_TELEPORT };
private static Object[] sbcCR = new Object[] { ScriptBaseClass.CHANGED_REGION };
private static Object[] sbcCT = new Object[] { ScriptBaseClass.CHANGED_TELEPORT };
/**
* @brief Save compilation error messages for later retrieval
@ -439,24 +442,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
private void ErrorHandler(Token token, string message)
{
if (token != null)
if(token != null)
{
string srcloc = token.SrcLoc;
if (srcloc.StartsWith (m_CameFrom))
srcloc = srcloc.Substring (m_CameFrom.Length);
if(srcloc.StartsWith(m_CameFrom))
srcloc = srcloc.Substring(m_CameFrom.Length);
m_CompilerErrors.Add(srcloc + " Error: " + message);
}
else if (message != null)
else if(message != null)
m_CompilerErrors.Add("(0,0) Error: " + message);
else
m_CompilerErrors.Add("(0,0) Error compiling, see exception in log");
}
/**
* @brief Load script state from the given XML doc into the script memory
* <ScriptState Engine="XMREngine" Asset=...>
* <ScriptState Engine="YEngine" Asset=...>
* <Running>...</Running>
* <DoGblInit>...</DoGblInit>
* <Permissions granted=... mask=... />
@ -476,25 +478,24 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// Everything we know is enclosed in <ScriptState>...</ScriptState>
XmlElement scriptStateN = (XmlElement)doc.SelectSingleNode("ScriptState");
if (scriptStateN == null)
if(scriptStateN == null)
throw new Exception("no <ScriptState> tag");
string sen = scriptStateN.GetAttribute("Engine");
if ((sen == null) || (sen != m_Engine.ScriptEngineName))
throw new Exception("<ScriptState> missing Engine=\"XMREngine\" attribute");
if((sen == null) || (sen != m_Engine.ScriptEngineName))
throw new Exception("<ScriptState> missing Engine=\"YEngine\" attribute");
// AssetID is unique for the script source text so make sure the
// state file was written for that source file
string assetID = scriptStateN.GetAttribute("Asset");
if (assetID != m_Item.AssetID.ToString())
if(assetID != m_Item.AssetID.ToString())
throw new Exception("<ScriptState> assetID mismatch");
// Also match the sourceHash in case script was
// loaded via 'xmroption fetchsource' and has changed
string sourceHash = scriptStateN.GetAttribute ("SourceHash");
if ((sourceHash == null) || (sourceHash != m_ObjCode.sourceHash))
throw new Exception ("<ScriptState> SourceHash mismatch");
string sourceHash = scriptStateN.GetAttribute("SourceHash");
if((sourceHash == null) || (sourceHash != m_ObjCode.sourceHash))
throw new Exception("<ScriptState> SourceHash mismatch");
// Get various attributes
XmlElement runningN = (XmlElement)scriptStateN.SelectSingleNode("Running");
@ -519,7 +520,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
Object[] pluginData = ExtractXMLObjectArray(pluginN, "plugin");
// 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);
MemoryStream ms = new MemoryStream();
@ -530,17 +532,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// Restore event queues, preserving any events that queued
// whilst we were restoring the state
lock (m_QueueLock)
lock(m_QueueLock)
{
m_DetectParams = detParams;
foreach (EventParams evt in m_EventQueue)
eventQueue.AddLast (evt);
foreach(EventParams evt in m_EventQueue)
eventQueue.AddLast(evt);
m_EventQueue = eventQueue;
for (int i = m_EventCounts.Length; -- i >= 0;)
for(int i = m_EventCounts.Length; --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),
evt.EventName);
@ -566,17 +567,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private LinkedList<EventParams> RestoreEventQueue(XmlNode eventsN)
{
LinkedList<EventParams> eventQueue = new LinkedList<EventParams>();
if (eventsN != null)
if(eventsN != null)
{
XmlNodeList eventL = eventsN.SelectNodes("Event");
foreach (XmlNode evnt in eventL)
foreach(XmlNode evnt in eventL)
{
string name = ((XmlElement)evnt).GetAttribute("Name");
object[] parms = ExtractXMLObjectArray(evnt, "param");
string name = ((XmlElement)evnt).GetAttribute("Name");
object[] parms = ExtractXMLObjectArray(evnt, "param");
DetectParams[] detects = RestoreDetectParams(evnt);
if (parms == null) parms = zeroObjectArray;
if (detects == null) detects = zeroDetectParams;
if(parms == null)
parms = zeroObjectArray;
if(detects == null)
detects = zeroDetectParams;
EventParams evt = new EventParams(name, parms, detects);
eventQueue.AddLast(evt);
@ -596,38 +599,39 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
private DetectParams[] RestoreDetectParams(XmlNode detectedN)
{
if (detectedN == null) return null;
if(detectedN == null)
return null;
List<DetectParams> detected = new List<DetectParams>();
XmlNodeList detectL = detectedN.SelectNodes("DetectParams");
DetectParams detprm = new DetectParams();
foreach (XmlNode detxml in detectL)
foreach(XmlNode detxml in detectL)
{
try
{
detprm.Group = new UUID(detxml.Attributes.GetNamedItem("group").Value);
detprm.Key = new UUID(detxml.Attributes.GetNamedItem("key").Value);
detprm.Owner = new UUID(detxml.Attributes.GetNamedItem("owner").Value);
detprm.Group = new UUID(detxml.Attributes.GetNamedItem("group").Value);
detprm.Key = new UUID(detxml.Attributes.GetNamedItem("key").Value);
detprm.Owner = new UUID(detxml.Attributes.GetNamedItem("owner").Value);
detprm.LinkNum = Int32.Parse(detxml.Attributes.GetNamedItem("linkNum").Value);
detprm.Type = Int32.Parse(detxml.Attributes.GetNamedItem("type").Value);
detprm.LinkNum = Int32.Parse(detxml.Attributes.GetNamedItem("linkNum").Value);
detprm.Type = Int32.Parse(detxml.Attributes.GetNamedItem("type").Value);
detprm.Name = detxml.Attributes.GetNamedItem("name").Value;
detprm.Name = detxml.Attributes.GetNamedItem("name").Value;
detprm.OffsetPos = new LSL_Types.Vector3(detxml.Attributes.GetNamedItem("pos").Value);
detprm.Position = new LSL_Types.Vector3(detxml.Attributes.GetNamedItem("position").Value);
detprm.Velocity = new LSL_Types.Vector3(detxml.Attributes.GetNamedItem("velocity").Value);
detprm.Position = new LSL_Types.Vector3(detxml.Attributes.GetNamedItem("position").Value);
detprm.Velocity = new LSL_Types.Vector3(detxml.Attributes.GetNamedItem("velocity").Value);
detprm.Rotation = new LSL_Types.Quaternion(detxml.Attributes.GetNamedItem("rotation").Value);
detprm.Rotation = new LSL_Types.Quaternion(detxml.Attributes.GetNamedItem("rotation").Value);
detected.Add(detprm);
detprm = new DetectParams();
}
catch (Exception e)
catch(Exception e)
{
m_log.Warn("[XMREngine]: RestoreDetectParams bad XML: " + detxml.ToString());
m_log.Warn("[XMREngine]: ... " + e.ToString());
m_log.Warn("[YEngine]: RestoreDetectParams bad XML: " + detxml.ToString());
m_log.Warn("[YEngine]: ... " + e.ToString());
}
}
@ -646,8 +650,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
List<Object> olist = new List<Object>();
XmlNodeList itemL = parent.SelectNodes(tag);
foreach (XmlNode item in itemL)
foreach(XmlNode item in itemL)
{
olist.Add(ExtractXMLObjectValue(item));
}
return olist.ToArray();
}
@ -656,10 +662,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{
string itemType = item.Attributes.GetNamedItem("type").Value;
if (itemType == "list")
if(itemType == "list")
{
return new LSL_List(ExtractXMLObjectArray(item, "item"));
}
if (itemType == "OpenMetaverse.UUID")
if(itemType == "OpenMetaverse.UUID")
{
UUID val = new UUID();
UUID.TryParse(item.InnerText, out val);
@ -667,15 +675,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
Type itemT = Type.GetType(itemType);
if (itemT == null)
if(itemT == null)
{
Object[] args = new Object[] { item.InnerText };
string assembly = itemType + ", OpenSim.Region.ScriptEngine.Shared";
itemT = Type.GetType(assembly);
if (itemT == null)
if(itemT == null)
{
return null;
}
return Activator.CreateInstance(itemT, args);
}
@ -688,89 +697,27 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Input:
* 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
miehstream = stream;
stream.ReadByte(); // ignored
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
MigrateInEventHandlerThread ();
}
else
{
// some other thread, do migration via a script thread
m_Engine.QueueToTrunk(this.MigrateInEventHandlerThread);
BinaryReader br = new BinaryReader(stream);
this.MigrateIn(br);
// wait for it to complete
lock (miehdone)
{
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);
}
m_RunOnePhase = "MigrateInEventHandler finished";
CheckRunLockInvariants(true);
}
}
}

View File

@ -41,7 +41,7 @@ using OpenSim.Region.ScriptEngine.Interfaces;
using OpenSim.Region.ScriptEngine.Shared;
using OpenSim.Region.ScriptEngine.Shared.Api;
using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
using OpenSim.Region.ScriptEngine.XMREngine;
using OpenSim.Region.ScriptEngine.Yengine;
using OpenSim.Region.Framework.Scenes;
using log4net;
@ -55,7 +55,7 @@ using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
// 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,
@ -75,7 +75,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* 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
*/
public enum XMRInstState {
public enum XMRInstState
{
CONSTRUCT, // it is being constructed
IDLE, // nothing happening (finished last event and m_EventQueue is empty)
ONSTARTQ, // inserted on m_Engine.m_StartQueue
@ -89,7 +90,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
DISPOSED // has been disposed
}
public partial class XMRInstance : XMRInstAbstract, IDisposable
public partial class XMRInstance: XMRInstAbstract, IDisposable
{
/******************************************************************\
* This module contains the instance variables for XMRInstance. *
@ -103,44 +104,45 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public static readonly ILog m_log =
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
// is it?
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 SceneObjectPart m_Part = null;
public uint m_LocalID = 0;
public TaskInventoryItem m_Item = null;
public UUID m_ItemID;
public UUID m_PartUUID;
public bool m_ForceRecomp = false;
public SceneObjectPart m_Part = null;
public uint m_LocalID = 0;
public TaskInventoryItem m_Item = null;
public UUID m_ItemID;
public UUID m_PartUUID;
private string m_CameFrom;
private string m_ScriptObjCodeKey;
private XMREngine m_Engine = null;
private Yengine m_Engine = null;
private string m_ScriptBasePath;
private string m_StateFileName;
public string m_SourceCode;
public bool m_PostOnRez;
public string m_SourceCode;
public bool m_PostOnRez;
private DetectParams[] m_DetectParams = null;
public int m_StartParam = 0;
public StateSource m_StateSource;
public string m_DescName;
public int m_StartParam = 0;
public StateSource m_StateSource;
public string m_DescName;
private bool[] m_HaveEventHandlers;
public int m_StackSize;
public int m_HeapSize;
public int m_StackSize;
public int m_HeapSize;
private ArrayList m_CompilerErrors;
private DateTime m_LastRanAt = DateTime.MinValue;
private string m_RunOnePhase = "hasn't run";
private string m_CheckRunPhase = "hasn't checked";
public int m_InstEHEvent = 0; // number of events dequeued (StartEventHandler called)
public int m_InstEHSlice = 0; // number of times handler timesliced (ResumeEx called)
public double m_CPUTime = 0; // accumulated CPU time (milliseconds)
public double m_SliceStart = 0; // when did current exec start
public int m_InstEHEvent = 0; // number of events dequeued (StartEventHandler called)
public int m_InstEHSlice = 0; // number of times handler timesliced (ResumeEx called)
public double m_CPUTime = 0; // accumulated CPU time (milliseconds)
public double m_SliceStart = 0; // when did current exec start
// If code needs to have both m_QueueLock and m_RunLock,
// be sure to lock m_RunLock first then m_QueueLock, as
@ -156,7 +158,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public bool m_Running = true;
// 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.
private int[] m_EventCounts = new int[(int)ScriptEventCode.Size];
@ -175,20 +177,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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.
*/

View File

@ -42,7 +42,7 @@ using OpenSim.Region.ScriptEngine.Interfaces;
using OpenSim.Region.ScriptEngine.Shared;
using OpenSim.Region.ScriptEngine.Shared.Api;
using OpenSim.Region.ScriptEngine.Shared.ScriptBase;
using OpenSim.Region.ScriptEngine.XMREngine;
using OpenSim.Region.ScriptEngine.Yengine;
using OpenSim.Region.Framework.Scenes;
using log4net;
@ -56,7 +56,7 @@ using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
// This class exists in the main app domain
//
namespace OpenSim.Region.ScriptEngine.XMREngine
namespace OpenSim.Region.ScriptEngine.Yengine
{
public partial class XMRInstance
{
@ -79,58 +79,49 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
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.
*/
if (m_Part != null)
lock(m_RunLock)
{
xmrTrapRegionCrossing (0);
m_Part.RemoveScriptEvents(m_ItemID);
AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID);
m_Part = null;
if(m_Part != null)
{
m_Part.RemoveScriptEvents(m_ItemID);
AsyncCommandManager.RemoveScript(m_Engine, m_LocalID, m_ItemID);
m_Part = null;
}
}
/*
* Let script methods get garbage collected if no one else is using
* 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;
if (m_CompiledScriptObjCode.TryGetValue (m_ScriptObjCodeKey, out objCode) &&
if(m_CompiledScriptObjCode.TryGetValue(m_ScriptObjCodeKey, out objCode) &&
(objCode == m_ObjCode) &&
(-- objCode.refCount == 0)) {
m_CompiledScriptObjCode.Remove (m_ScriptObjCodeKey);
(--objCode.refCount == 0))
{
m_CompiledScriptObjCode.Remove(m_ScriptObjCodeKey);
}
}
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
@ -138,37 +129,39 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// Sacha
public void RunTestTop()
{
if (m_InstEHSlice > 0){
Console.WriteLine(m_DescName);
Console.WriteLine(" m_LocalID = " + m_LocalID);
Console.WriteLine(" m_ItemID = " + m_ItemID);
Console.WriteLine(" m_Item.AssetID = " + m_Item.AssetID);
Console.WriteLine(" m_StartParam = " + m_StartParam);
Console.WriteLine(" m_PostOnRez = " + m_PostOnRez);
Console.WriteLine(" m_StateSource = " + m_StateSource);
Console.WriteLine(" m_SuspendCount = " + m_SuspendCount);
Console.WriteLine(" m_SleepUntil = " + m_SleepUntil);
Console.WriteLine(" m_IState = " + m_IState.ToString());
Console.WriteLine(" m_StateCode = " + GetStateName(stateCode));
Console.WriteLine(" eventCode = " + eventCode.ToString());
Console.WriteLine(" m_LastRanAt = " + m_LastRanAt.ToString());
Console.WriteLine(" heapUsed/Limit = " + xmrHeapUsed () + "/" + heapLimit);
Console.WriteLine(" m_InstEHEvent = " + m_InstEHEvent.ToString());
Console.WriteLine(" m_InstEHSlice = " + m_InstEHSlice.ToString());
}
if(m_InstEHSlice > 0)
{
Console.WriteLine(m_DescName);
Console.WriteLine(" m_LocalID = " + m_LocalID);
Console.WriteLine(" m_ItemID = " + m_ItemID);
Console.WriteLine(" m_Item.AssetID = " + m_Item.AssetID);
Console.WriteLine(" m_StartParam = " + m_StartParam);
Console.WriteLine(" m_PostOnRez = " + m_PostOnRez);
Console.WriteLine(" m_StateSource = " + m_StateSource);
Console.WriteLine(" m_SuspendCount = " + m_SuspendCount);
Console.WriteLine(" m_SleepUntil = " + m_SleepUntil);
Console.WriteLine(" m_IState = " + m_IState.ToString());
Console.WriteLine(" m_StateCode = " + GetStateName(stateCode));
Console.WriteLine(" eventCode = " + eventCode.ToString());
Console.WriteLine(" m_LastRanAt = " + m_LastRanAt.ToString());
Console.WriteLine(" heapUsed/Limit = " + xmrHeapUsed() + "/" + heapLimit);
Console.WriteLine(" m_InstEHEvent = " + m_InstEHEvent.ToString());
Console.WriteLine(" m_InstEHSlice = " + m_InstEHSlice.ToString());
}
}
// Called by 'xmr ls' console command
// to dump this script's state to console
public string RunTestLs(bool flagFull)
{
if (flagFull) {
if(flagFull)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(m_DescName);
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_Part.WorldPosition = " + m_Part.GetWorldPosition ());
sb.AppendLine(" m_Part.WorldPosition = " + m_Part.GetWorldPosition());
sb.AppendLine(" m_ScriptObjCodeKey = " + m_ScriptObjCodeKey + " (source text)");
sb.AppendLine(" m_StartParam = " + m_StartParam);
sb.AppendLine(" m_PostOnRez = " + m_PostOnRez);
@ -185,28 +178,28 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
sb.AppendLine(" suspOnCkRunHold = " + suspendOnCheckRunHold);
sb.AppendLine(" suspOnCkRunTemp = " + suspendOnCheckRunTemp);
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_InstEHSlice = " + m_InstEHSlice.ToString());
sb.AppendLine(" m_CPUTime = " + m_CPUTime);
sb.AppendLine(" callMode = " + callMode);
sb.AppendLine(" captureStackFrames = " + captureStackFrames);
sb.AppendLine(" stackFramesRestored = " + stackFramesRestored);
lock (m_QueueLock)
lock(m_QueueLock)
{
sb.AppendLine(" m_Running = " + m_Running);
foreach (EventParams evt in m_EventQueue)
foreach(EventParams evt in m_EventQueue)
{
sb.AppendLine(" evt.EventName = " + evt.EventName);
}
}
return sb.ToString();
} else {
return String.Format("{0} {1} {2} {3} {4} {5}",
m_ItemID,
m_CPUTime.ToString("F3").PadLeft(9),
m_InstEHEvent.ToString().PadLeft(9),
m_IState.ToString().PadRight(10),
}
else
{
return String.Format("{0} {1} {2} {3} {4} {5}",
m_ItemID,
m_CPUTime.ToString("F3").PadLeft(9),
m_InstEHEvent.ToString().PadLeft(9),
m_IState.ToString().PadRight(10),
m_Part.GetWorldPosition().ToString().PadRight(32),
m_DescName);
}
@ -218,16 +211,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
public int GetStateEventFlags(int stateCode)
{
if ((stateCode < 0) ||
if((stateCode < 0) ||
(stateCode >= m_ObjCode.scriptEventHandlerTable.GetLength(0)))
{
return 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;
}
@ -239,41 +232,47 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @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.
*/
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.
*/
string subdir = filename.Substring (0, 2);
filename = filename.Substring (2);
scriptBasePath = Path.Combine (scriptBasePath, subdir);
Directory.CreateDirectory (scriptBasePath);
string newPath = Path.Combine (scriptBasePath, filename);
// string subdir = filename.Substring (0, 2);
// filename = filename.Substring (2);
string subdir = filename.Substring(0, 1);
filename = filename.Substring(1);
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 in both locations, delete old location.
*/
if (File.Exists (oldPath)) {
if (File.Exists (newPath)) {
File.Delete (oldPath);
} else {
File.Move (oldPath, newPath);
if(File.Exists(oldPath))
{
if(File.Exists(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).
*/
public string GetStateName (int stateCode)
public string GetStateName(int stateCode)
{
try {
try
{
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
{
get { return m_StartParam; }
set { m_StartParam = value; }
get
{
return m_StartParam;
}
set
{
m_StartParam = value;
}
}
public SceneObjectPart SceneObject
{
get { return m_Part; }
get
{
return m_Part;
}
}
public DetectParams[] DetectParams
{
get { return m_DetectParams; }
set { m_DetectParams = value; }
get
{
return m_DetectParams;
}
set
{
m_DetectParams = value;
}
}
public UUID ItemID
{
get { return m_ItemID; }
get
{
return m_ItemID;
}
}
public UUID AssetID
{
get { return m_Item.AssetID; }
get
{
return m_Item.AssetID;
}
}
public bool Running
{
get { return m_Running; }
get
{
return m_Running;
}
set
{
lock (m_QueueLock)
lock(m_QueueLock)
{
m_Running = value;
if (!value)
if(!value)
{
EmptyEventQueues ();
EmptyEventQueues();
}
}
}
@ -345,26 +371,28 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @brief Empty out the event queues.
* Assumes caller has the m_QueueLock locked.
*/
public void EmptyEventQueues ()
public void EmptyEventQueues()
{
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.
*/
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.
*/
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)element;
@ -373,9 +401,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @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)element;

View File

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

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_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine
namespace OpenSim.Region.ScriptEngine.Yengine
{
public class XMRSDTypeClObj
{
@ -56,7 +56,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Our VTable array, used for calling virtual functions.
* And ITable array, used for calling our implementation of interface functions.
*/
public Delegate[] sdtcVTable;
public Delegate[] sdtcVTable;
public Delegate[][] sdtcITable;
/*
@ -69,10 +69,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @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);
instVars.AllocVarArrays (sdtcClass.instSizes);
Construct(inst, classindex);
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
* @returns with the vtables filled in
*/
private void Construct (XMRInstAbstract inst, int classindex)
private void Construct(XMRInstAbstract inst, int classindex)
{
Delegate[] thisMid = null;
TokenDeclSDTypeClass clas = (TokenDeclSDTypeClass)inst.m_ObjCode.sdObjTypesIndx[classindex];
xmrInst = inst;
xmrInst = inst;
sdtcClass = clas;
instVars = new XMRInstArrays (inst);
instVars = new XMRInstArrays(inst);
/*
* VTable consists of delegates built from DynamicMethods and the 'this' pointer.
* Yes, yes, lots of shitty little mallocs.
*/
DynamicMethod[] vDynMeths = clas.vDynMeths;
if (vDynMeths != null) {
if(vDynMeths != null)
{
int n = vDynMeths.Length;
Type[] vMethTypes = clas.vMethTypes;
sdtcVTable = new Delegate[n];
for (int i = 0; i < n; i ++) {
sdtcVTable[i] = vDynMeths[i].CreateDelegate (vMethTypes[i], this);
for(int i = 0; i < n; i++)
{
sdtcVTable[i] = vDynMeths[i].CreateDelegate(vMethTypes[i], this);
}
}
@ -114,33 +116,40 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* So we end up with this:
* sdtcITable[interfacenumber][methodofintfnumber] = delegate of this.ourimplementationofinterfacesmethod
*/
if (clas.iDynMeths != null) {
if(clas.iDynMeths != null)
{
int nIFaces = clas.iDynMeths.Length;
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
DynamicMethod[] iDynMeths = clas.iDynMeths[i];
Type[] iMethTypes = clas.iMethTypes[i];
Type[] iMethTypes = clas.iMethTypes[i];
// allocate an array with a slot for each method the interface defines
int nMeths = iDynMeths.Length;
Delegate[] ivec;
if (nMeths > 0) {
if(nMeths > 0)
{
// fill in the array with delegates that reference back to this class instance
ivec = new Delegate[nMeths];
for (int j = 0; j < nMeths; j ++) {
ivec[j] = iDynMeths[j].CreateDelegate (iMethTypes[j], this);
for(int j = 0; j < nMeths; j++)
{
ivec[j] = iDynMeths[j].CreateDelegate(iMethTypes[j], this);
}
} else {
}
else
{
// just a marker interface with no methods,
// allocate a one-element array and fill
// with a dummy entry. this will allow casting
// back to the original class instance (this)
// by reading Target of entry 0.
if (thisMid == null) {
if(thisMid == null)
{
thisMid = new Delegate[1];
thisMid[0] = markerInterfaceDummy.CreateDelegate (typeof (MarkerInterfaceDummy), this);
thisMid[0] = markerInterfaceDummy.CreateDelegate(typeof(MarkerInterfaceDummy), this);
}
ivec = thisMid;
}
@ -151,13 +160,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
}
private delegate void MarkerInterfaceDummy ();
private static DynamicMethod markerInterfaceDummy = MakeMarkerInterfaceDummy ();
private static DynamicMethod MakeMarkerInterfaceDummy ()
private delegate void MarkerInterfaceDummy();
private static DynamicMethod markerInterfaceDummy = MakeMarkerInterfaceDummy();
private static DynamicMethod MakeMarkerInterfaceDummy()
{
DynamicMethod dm = new DynamicMethod ("XMRSDTypeClObj.MarkerInterfaceDummy", null, new Type[] { typeof (XMRSDTypeClObj) });
ILGenerator ilGen = dm.GetILGenerator ();
ilGen.Emit (OpCodes.Ret);
DynamicMethod dm = new DynamicMethod("XMRSDTypeClObj.MarkerInterfaceDummy", null, new Type[] { typeof(XMRSDTypeClObj) });
ILGenerator ilGen = dm.GetILGenerator();
ilGen.Emit(OpCodes.Ret);
return dm;
}
@ -168,9 +177,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @param classindex = what class those implementations are supposedly part of
* @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
* @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.
*/
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.
@ -197,9 +207,11 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* 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.
*/
for (TokenDeclSDTypeClass ac = ci.sdtcClass; ac != tc; ac = ac.extends) {
if (ac == null) throw new InvalidCastException ("invalid cast from " + ci.sdtcClass.longName.val +
" to " + tc.longName.val);
for(TokenDeclSDTypeClass ac = ci.sdtcClass; ac != tc; ac = ac.extends)
{
if(ac == null)
throw new InvalidCastException("invalid cast from " + ci.sdtcClass.longName.val +
" to " + tc.longName.val);
}
/*
@ -215,14 +227,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @param ob = object to be cast of unknown 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 (ob is Delegate[]) {
if(ob is Delegate[])
{
Delegate[] da = (Delegate[])ob;
ob = da[0].Target;
}
@ -239,21 +253,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @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);
this.instVars.SendArrays (sendValue);
sendValue(this.sdtcClass.sdTypeIndex);
this.instVars.SendArrays(sendValue);
}
/**
* @brief Read the whole thing in from a stream.
*/
public XMRSDTypeClObj () { }
public void Restore (XMRInstAbstract inst, XMRInstArrays.Recver recvValue)
public XMRSDTypeClObj()
{
int classindex = (int)recvValue ();
Construct (inst, classindex);
this.instVars.RecvArrays (recvValue);
}
public void Restore(XMRInstAbstract inst, XMRInstArrays.Recver 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"
;; ***DANGER***DANGER***
;; experimental engine
;; see section [XMREngine} below
; DefaultScriptEngine = "XMREngine"
;; see section [YEngine} below
; DefaultScriptEngine = "YEngine"
;# {HttpProxy} {} {Proxy URL for llHTTPRequest and dynamic texture loading} {} http://proxy.com:8080
;; Http proxy setting for llHTTPRequest and dynamic texture loading, if
@ -922,20 +922,19 @@
[XMREngine]
;; experimental engine
;; 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.
;; compiles LSL directly to IL, so only suports LSL scripting (no C# etc)
;; shares the Xengine APIs like LSL, OSSL, etc.
;; 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.
Enabled = false
UThreadModel = sys
ScriptStackSize = 256
ScriptHeapSize = 256
UseSourceHashCode = true
MinTimerInterval = 0.1
;ScriptBasePath="ScriptData"
;ScriptBasePath="ScriptEngines"
[XEngine]
;# {Enabled} {} {Enable the XEngine scripting engine?} {true false} true

View File

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