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,9 +30,11 @@ 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
@ -41,13 +43,17 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
private static ModuleBuilder delegateModuleBuilder = null;
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)
{
DelegateCommon dc;
lock (delegateCommons) {
if (!delegateCommons.TryGetValue (sig, out dc)) {
lock(delegateCommons)
{
if(!delegateCommons.TryGetValue(sig, out dc))
{
dc = new DelegateCommon();
dc.sig = sig;
dc.type = CreateDelegateType(sig, ret, args);
@ -61,8 +67,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
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;
}
@ -70,8 +78,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
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;
}
@ -79,7 +89,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
// http://blog.bittercoder.com/PermaLink,guid,a770377a-b1ad-4590-9145-36381757a52b.aspx
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);

View File

@ -33,9 +33,10 @@ 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
{
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);

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.
@ -48,23 +50,27 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
* Loop through list of all methods declared in the interface.
*/
System.Reflection.MethodInfo[] ifaceMethods = iface.GetMethods();
foreach (System.Reflection.MethodInfo ifaceMethod in ifaceMethods) {
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++) {
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);
@ -79,11 +85,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine {
* Add the TokenDeclVar struct to the dictionary.
*/
this.AddEntry(declFunc);
} catch (Exception except) {
}
catch(Exception except)
{
string msg = except.ToString();
int i = msg.IndexOf("\n");
if (i > 0) msg = msg.Substring (0, i);
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
{
@ -47,153 +43,134 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
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)) {
m_SourceCode = FetchSource (m_CameFrom);
}
else
{
// If source file empty, try to read from asset server.
if (EmptySource (m_SourceCode))
m_SourceCode = FetchSource (m_CameFrom);
/*
* Maybe write script source to a file for debugging.
*/
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 + ")");
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 {
}
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,7 +39,8 @@ 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,

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,11 +29,14 @@ 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; }
string methName
{
get;
}
ScriptMyLocal DeclareLocal(Type type, string name);
ScriptMyLabel DefineLabel(string name);
void BeginExceptionBlock();
@ -59,7 +62,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @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,37 +33,51 @@ 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)
{
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)
{
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;
}
@ -71,9 +85,11 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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();
@ -82,7 +98,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
}
private struct TDVEntry {
private struct TDVEntry
{
public int count;
public TokenDeclVar var;
}
@ -108,7 +125,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
public bool AddEntry(TokenDeclVar var)
{
if (isFrozen) {
if(isFrozen)
{
throw new Exception("var dict is frozen");
}
@ -116,7 +134,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* 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)) {
if(!master.TryGetValue(var.name.val, out typedic))
{
typedic = new Dictionary<ArgTypes, TDVEntry>();
master.Add(var.name.val, typedic);
}
@ -128,7 +147,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
ArgTypes types;
types.argTypes = (var.argDecl == null) ? null : KeyTypesToStringTypes(var.argDecl.types);
if (typedic.ContainsKey (types)) return false;
if(typedic.ContainsKey(types))
return false;
/*
* It is unique, add to its name-specific sub-dictionary.
@ -140,7 +160,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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.
@ -154,14 +180,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* 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.
@ -201,14 +229,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{
argTypes = KeyTypesToStringTypes(argTypes);
TokenDeclVar var = FindExact(name, argTypes);
if (var != null) return new TokenDeclVar[] { var };
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)) {
foreach(KeyValuePair<ArgTypes, TDVEntry> kvp in typedic)
{
if((kvp.Value.count <= this.count) && kvp.Key.CanBeCalledBy(argTypes))
{
found.Add(kvp.Value.var);
}
}
@ -229,13 +261,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* 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;
/*
@ -253,7 +288,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/*
* 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) {
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(da == "key")
da = "string";
if(ga == "key")
ga = "string";
if(da != ga)
break;
}
if (i < 0) return var;
if(i < 0)
return var;
}
/*
@ -301,17 +346,23 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
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) {
if(argTypes[i] is TokenTypeKey)
{
at[i] = new TokenTypeStr(argTypes[i]);
}
}
@ -329,7 +380,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
return new VarDictEnumerator(this.master, this.count);
}
private class VarDictEnumerator : IEnumerator {
private class VarDictEnumerator: IEnumerator
{
private IEnumerator masterEnum;
private IEnumerator typedicEnum;
private int count;
@ -350,14 +402,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// IEnumerator
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();
@ -365,7 +422,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
// 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;
@ -78,10 +79,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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;
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);
}
@ -94,7 +99,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{
object val;
key = FixKey(key);
if (!dnary.TryGetValue (key, out val)) val = null;
if(!dnary.TryGetValue(key, out val))
val = null;
return val;
}
@ -109,10 +115,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
int keysize = HeapTrackerObject.Size(key);
int newheapuse = heapUse;
object oldval;
if (dnary.TryGetValue (key, out oldval)) {
if(dnary.TryGetValue(key, out oldval))
{
newheapuse -= keysize + HeapTrackerObject.Size(oldval);
}
if (value != null) {
if(value != null)
{
newheapuse += keysize + HeapTrackerObject.Size(value);
}
heapUse = inst.UpdateHeapUse(heapUse, newheapuse);
@ -121,15 +129,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* 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 {
}
else
{
dnary.Remove(key);
/*
* Shrink the enumeration array, but always leave at least one element.
*/
if ((array != null) && (dnary.Count < array.Length / 2)) {
if((array != null) && (dnary.Count < array.Length / 2))
{
Array.Resize<KeyValuePair<object, object>>(ref array, array.Length / 2);
}
}
@ -150,22 +162,26 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
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)
{
if (obj == null) throw new NullReferenceException ();
if(obj == null)
throw new NullReferenceException();
return (LSL_Key)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)
{
if (obj == null) throw new NullReferenceException ();
if(obj == null)
throw new NullReferenceException();
return obj.ToString();
}
@ -225,7 +241,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* 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,7 +250,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/*
* If dictionary modified since last enumeration, get a new enumerator.
*/
if (arrayValid == 0) {
if(arrayValid == 0)
{
enumr = dnary.GetEnumerator();
enumrValid = true;
}
@ -241,8 +259,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/*
* Make sure we have filled the array up enough for requested element.
*/
while ((arrayValid <= number) && enumrValid && enumr.MoveNext ()) {
if (arrayValid >= array.Length) {
while((arrayValid <= number) && enumrValid && enumr.MoveNext())
{
if(arrayValid >= array.Length)
{
Array.Resize<KeyValuePair<object, object>>(ref array, dnary.Count);
}
array[arrayValid++] = enumr.Current;
@ -266,7 +286,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* UnfixKey() because sendObj doesn't handle XMRArrayListKeys.
*/
sendObj(dnary.Count);
foreach (KeyValuePair<object, object> kvp in dnary) {
foreach(KeyValuePair<object, object> kvp in dnary)
{
sendObj(UnfixKey(kvp.Key));
sendObj(kvp.Value);
}
@ -296,7 +317,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
dnary.Clear();
int count = (int)recvObj();
while (-- count >= 0) {
while(--count >= 0)
{
object key = FixKey(recvObj());
object val = recvObj();
int htuse = HeapTrackerObject.Size(key) + HeapTrackerObject.Size(val);
@ -312,13 +334,19 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
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]);
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
@ -331,12 +359,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
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();
@ -351,10 +381,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
string xtn = x.GetType().Name;
string ytn = y.GetType().Name;
int ctn = String.CompareOrdinal(xtn, ytn);
if (ctn != 0) return ctn;
if(ctn != 0)
return ctn;
ComparerDelegate cd;
if (!comparers.TryGetValue (xtn, out cd)) {
if(!comparers.TryGetValue(xtn, out cd))
{
throw new Exception("unsupported key type " + xtn);
}
return cd(x, y);
@ -380,8 +412,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{
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)
@ -398,14 +432,22 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{
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)
@ -416,12 +458,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{
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;
@ -451,7 +500,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
length = len;
cleaned = new object[len];
int hc = len;
for (int i = 0; i < len; i ++) {
for(int i = 0; i < len; i++)
{
object v = XMR_Array.FixKey(given[i]);
hc += hc + ((hc < 0) ? 1 : 0);
hc ^= v.GetHashCode();
@ -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;
}
}
@ -474,13 +526,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
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;
}
@ -499,12 +556,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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;
if(j != 0)
break;
}
}
return j;
@ -524,8 +584,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
public override string ToString()
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i ++) {
if (i > 0) sb.Append (',');
for(int i = 0; i < length; i++)
{
if(i > 0)
sb.Append(',');
sb.Append(cleaned[i].ToString());
}
return sb.ToString();

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -45,19 +45,19 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_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");
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;
@ -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;
}
@ -216,10 +221,12 @@ 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;
@ -257,7 +264,8 @@ 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);

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,13 +48,15 @@ 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)
{
if (inst == null) throw new ArgumentNullException ("inst");
if(inst == null)
throw new ArgumentNullException("inst");
instance = inst;
}
@ -67,7 +69,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* Wrapper around lists to keep track of how much memory they use.
*/
public class HeapTrackerList : HeapTrackerBase {
public class HeapTrackerList: HeapTrackerBase
{
private static FieldInfo listValueField = typeof(HeapTrackerList).GetField("value");
private static MethodInfo listSaveMethod = typeof(HeapTrackerList).GetMethod("Save");
@ -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,7 +137,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* Wrapper around objects to keep track of how much memory they use.
*/
public class HeapTrackerObject : HeapTrackerBase {
public class HeapTrackerObject: HeapTrackerBase
{
private static FieldInfo objectValueField = typeof(HeapTrackerObject).GetField("value");
private static MethodInfo objectSaveMethod = typeof(HeapTrackerObject).GetMethod("Save");
@ -184,32 +191,52 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// public so it can be used by XMRArray
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;
if(len == 0)
return 0;
Type et = ar.GetType().GetElementType();
if (et.IsValueType) return Size (ar.GetValue (0)) * len;
if(et.IsValueType)
return Size(ar.GetValue(0)) * len;
int size = 0;
for (int i = 0; i < len; i ++) {
for(int i = 0; i < len; i++)
{
size += Size(ar.GetValue(i));
}
return size;
@ -222,7 +249,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* Wrapper around strings to keep track of how much memory they use.
*/
public class HeapTrackerString : HeapTrackerBase {
public class HeapTrackerString: HeapTrackerBase
{
private static FieldInfo stringValueField = typeof(HeapTrackerString).GetField("value");
private static MethodInfo stringSaveMethod = typeof(HeapTrackerString).GetMethod("Save");

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,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
{
/****************************************************\
* This file contains routines called by scripts. *
@ -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;
}
@ -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.
*/
@ -324,7 +324,8 @@ 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...().
@ -338,7 +339,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
mask2 = (int)sv[4];
switch(callNo)
{
case 0: goto __call0;
case 0:
goto __call0;
case 1:
{
evc1 = (int)sv[5];
@ -397,7 +399,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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.
@ -444,9 +445,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
finally
{
m_DetectParams = saveDetParams;
ehArgs = saveEHArgs;
eventCode = saveEventCode;
this.m_DetectParams = saveDetParams;
this.ehArgs = saveEHArgs;
this.eventCode = saveEventCode;
}
/*
@ -548,7 +549,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
return obs;
}
/**
* @brief Load current detect params from a list
* @param dpList = as returned by xmrEventSaveDets()
@ -595,7 +595,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
dps[i] = dp;
}
return dps;
}
@ -630,14 +629,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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 ...
@ -96,19 +95,22 @@ 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.
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.
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.
XmlNode permissionsN = doc.CreateElement("", "Permissions", "");
@ -121,7 +123,8 @@ 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.
@ -131,7 +134,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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>
@ -154,7 +158,8 @@ 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 =
@ -163,7 +168,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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.
suspendOnCheckRunHold = false;
@ -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)
{
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);
}
}
stream.WriteByte(migrationVersion);
stream.WriteByte((byte)16);
this.MigrateOut(new BinaryWriter(stream));
}
/**

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,23 +65,26 @@ 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;
m_ScriptBasePath = scriptBasePath;
m_StackSize = stackSize;
m_StackLeft = stackSize;
m_HeapSize = heapSize;
m_CompilerErrors = errors;
m_StateFileName = GetStateFileName(scriptBasePath, m_ItemID);
@ -98,11 +101,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
foreach(string api in am.GetApis())
{
// Instantiate the API for this script instance.
if (api != "LSL") {
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);
@ -115,7 +117,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
suspendOnCheckRunHold = true;
InstantiateScript();
m_SourceCode = null;
if (m_ObjCode == null) throw new ArgumentNullException ("m_ObjCode");
if(m_ObjCode == null)
throw new ArgumentNullException("m_ObjCode");
if(m_ObjCode.scriptEventHandlerTable == null)
throw new ArgumentNullException("m_ObjCode.scriptEventHandlerTable");
@ -127,7 +130,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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);
@ -137,6 +140,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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
@ -149,7 +153,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 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;
if(m_SourceCode == null)
m_SourceCode = String.Empty;
for(len = m_SourceCode.Length; len > 0; --len)
{
if(m_SourceCode[len - 1] > ' ')
@ -216,7 +221,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
// 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
@ -235,6 +239,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
try
{
// Fill in script instance from object code
// Script instance is put in a "never-ever-has-run-before" state.
LoadObjCode();
@ -246,6 +251,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
catch
{
// If any error loading, decrement object code reference count.
DecObjCodeRefCount();
throw;
@ -272,10 +278,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
sb.Append(sixbit[val & 63]);
}
/*
* Try to create object code from source code
* If error, just throw exception
*/
// Try to create object code from source code
// If error, just throw exception
private ScriptObjCode TryToCompile()
{
m_CompilerErrors.Clear();
@ -283,7 +287,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 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();
@ -301,7 +304,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
private string FetchSource(string cameFrom)
{
m_log.Debug ("[XMREngine]: fetching source " + cameFrom);
m_log.Debug("[YEngine]: fetching source " + cameFrom);
if(!cameFrom.StartsWith("asset://"))
throw new Exception("unable to retrieve source from " + cameFrom);
@ -324,7 +327,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private void LoadObjCode()
{
// 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.
@ -345,9 +347,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
}
}
// Set up microthread object which actually calls the script event handler functions.
this.microthread = (IScriptUThread)m_Engine.uThreadCtor.Invoke (new object[] { this });
}
/*
@ -362,6 +361,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{
// 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
@ -390,7 +390,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
LoadScriptState(doc);
}
// Post event(s) saying what caused the script to start.
/*
* Post event(s) saying what caused the script to start.
*/
if(m_PostOnRez)
{
PostEvent(new EventParams("on_rez",
@ -412,6 +414,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
zeroDetectParams));
break;
case StateSource.Teleporting:
PostEvent(new EventParams("changed",
sbcCR,
@ -449,14 +452,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
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=... />
@ -481,8 +483,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
string sen = scriptStateN.GetAttribute("Engine");
if((sen == null) || (sen != m_Engine.ScriptEngineName))
throw new Exception("<ScriptState> missing Engine=\"XMREngine\" attribute");
throw new Exception("<ScriptState> missing Engine=\"YEngine\" attribute");
// AssetID is unique for the script source text so make sure the
// state file was written for that source file
@ -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();
@ -539,7 +541,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
m_EventQueue = eventQueue;
for(int i = m_EventCounts.Length; --i >= 0;)
m_EventCounts[i] = 0;
foreach(EventParams evt in m_EventQueue)
{
ScriptEventCode eventCode = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
@ -575,8 +576,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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,7 +599,8 @@ 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");
@ -626,8 +630,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
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());
}
}
@ -647,7 +651,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
XmlNodeList itemL = parent.SelectNodes(tag);
foreach(XmlNode item in itemL)
{
olist.Add(ExtractXMLObjectValue(item));
}
return olist.ToArray();
}
@ -657,7 +663,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
string itemType = item.Attributes.GetNamedItem("type").Value;
if(itemType == "list")
{
return new LSL_List(ExtractXMLObjectArray(item, "item"));
}
if(itemType == "OpenMetaverse.UUID")
{
@ -674,8 +682,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
string assembly = itemType + ", OpenSim.Region.ScriptEngine.Shared";
itemT = Type.GetType(assembly);
if(itemT == null)
{
return null;
}
return Activator.CreateInstance(itemT, args);
}
@ -690,87 +699,25 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
private void MigrateInEventHandler(Stream stream)
{
miehexcep = null;
// do all the work in the MigrateInEventHandlerThread() method below
miehstream = stream;
XMRScriptThread cst = m_Engine.CurrentScriptThread ();
if (cst != null)
{
// 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);
// 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 ();
int mv = stream.ReadByte();
if(mv != migrationVersion)
throw new Exception("incoming migration version " + mv + " but accept only " + migrationVersion);
miehstream.ReadByte (); // ignored
stream.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);
/*
* 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)
{
BinaryReader br = new BinaryReader(stream);
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
@ -103,13 +104,14 @@ 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>();
public XMRInstance m_NextInst; // used by XMRInstQueue
public XMRInstance m_PrevInst;
public XMRInstState m_IState;
public bool m_ForceRecomp = false;
@ -121,7 +123,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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;
@ -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
{
@ -80,30 +80,17 @@ 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.
* Don't send us any more events.
*/
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)
{
xmrTrapRegionCrossing (0);
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
@ -114,13 +101,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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) &&
(objCode == m_ObjCode) &&
(-- objCode.refCount == 0)) {
(--objCode.refCount == 0))
{
m_CompiledScriptObjCode.Remove(m_ScriptObjCodeKey);
}
}
@ -130,7 +120,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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,7 +129,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// Sacha
public void RunTestTop()
{
if (m_InstEHSlice > 0){
if(m_InstEHSlice > 0)
{
Console.WriteLine(m_DescName);
Console.WriteLine(" m_LocalID = " + m_LocalID);
Console.WriteLine(" m_ItemID = " + m_ItemID);
@ -162,7 +154,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 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);
@ -190,8 +183,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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)
{
sb.AppendLine(" m_Running = " + m_Running);
@ -201,7 +192,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
}
return sb.ToString();
} else {
}
else
{
return String.Format("{0} {1} {2} {3} {4} {5}",
m_ItemID,
m_CPUTime.ToString("F3").PadLeft(9),
@ -259,8 +252,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/*
* Get new path, ie, files split up based on first 2 chars of name.
*/
string subdir = filename.Substring (0, 2);
filename = filename.Substring (2);
// 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);
@ -269,10 +264,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* 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)) {
if(File.Exists(oldPath))
{
if(File.Exists(newPath))
{
File.Delete(oldPath);
} else {
}
else
{
File.Move(oldPath, newPath);
}
}
@ -288,9 +287,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
public string GetStateName(int stateCode)
{
try {
try
{
return m_ObjCode.stateNames[stateCode];
} catch {
}
catch
{
return stateCode.ToString();
}
}
@ -300,34 +302,58 @@ 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)
@ -348,7 +374,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
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;
}
/**
@ -364,7 +391,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
public static int ListInt(object element)
{
if (element is LSL_Integer) {
if(element is LSL_Integer)
{
return (int)(LSL_Integer)element;
}
return (int)element;
@ -375,7 +403,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
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;
}

View File

@ -32,11 +32,9 @@ using System.Text;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
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.Framework.Scenes;
using log4net;
@ -48,7 +46,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine
namespace OpenSim.Region.ScriptEngine.Yengine
{
public partial class XMRInstance
{
@ -84,28 +82,30 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
if(!construct && // make sure m_HaveEventHandlers is filled in
((uint)evc < (uint)m_HaveEventHandlers.Length) &&
!m_HaveEventHandlers[(int)evc]) { // don't bother if we don't have such a handler in any state
!m_HaveEventHandlers[(int)evc]) // don't bother if we don't have such a handler in any state
return;
}
/*
* Not running means we ignore any incoming events.
* But queue if still constructing because m_Running is not yet valid.
*/
if (!m_Running && !construct) {
if(!m_Running && !construct)
return;
}
/*
* Only so many of each event type allowed to queue.
*/
if ((uint)evc < (uint)m_EventCounts.Length) {
int maxAllowed = MAXEVENTQUEUE;
if (evc == ScriptEventCode.timer) maxAllowed = 1;
if (m_EventCounts[(int)evc] >= maxAllowed)
if((uint)evc < (uint)m_EventCounts.Length)
{
if(evc == ScriptEventCode.timer)
{
if(m_EventCounts[(int)evc] >= 1)
return;
}
else if(m_EventCounts[(int)evc] >= MAXEVENTQUEUE)
return;
m_EventCounts[(int)evc]++;
}
@ -113,18 +113,17 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Put event on end of instance's event queue.
*/
LinkedListNode<EventParams> lln = new LinkedListNode<EventParams>(evt);
switch (evc) {
switch(evc)
{
/*
* These need to go first. The only time we manually
* queue them is for the default state_entry() and we
* need to make sure they go before any attach() events
* so the heapLimit value gets properly initialized.
*/
case ScriptEventCode.state_entry: {
case ScriptEventCode.state_entry:
m_EventQueue.AddFirst(lln);
break;
}
/*
* The attach event sneaks to the front of the queue.
@ -134,7 +133,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* before attach(NULL_KEY) is executed.
*/
case ScriptEventCode.attach:
{
if(evt.Params[0].ToString() == UUID.Zero.ToString())
{
LinkedListNode<EventParams> lln2 = null;
@ -144,12 +142,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
ScriptEventCode evc2 = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
evt2.EventName);
if((evc2 != ScriptEventCode.state_entry) &&
(evc2 != ScriptEventCode.attach)) break;
(evc2 != ScriptEventCode.attach))
break;
}
if(lln2 == null)
m_EventQueue.AddLast(lln);
else
m_EventQueue.AddBefore(lln2, lln);
/* If we're detaching, limit the qantum. This will also
* cause the script to self-suspend after running this
* event
@ -160,18 +160,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
else
m_EventQueue.AddLast(lln);
break;
}
/*
* All others just go on end in the order queued.
*/
default:
{
m_EventQueue.AddLast(lln);
break;
}
}
/*
* If instance is idle (ie, not running or waiting to run),
@ -196,11 +194,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
int evc2 = evc1 - 32;
if((((uint)evc1 < (uint)32) && (((m_SleepEventMask1 >> evc1) & 1) != 0)) ||
(((uint)evc2 < (uint)32) && (((m_SleepEventMask2 >> evc2) & 1) != 0)))
{
wakeIt = true;
}
}
}
/*
* If transitioned from IDLE->ONSTARTQ, actually go insert it
@ -269,19 +265,18 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
Exception e = null;
/*
* Maybe we have been disposed.
* Maybe it has been Disposed()
*/
m_RunOnePhase = "check disposed";
if (microthread == null)
if(m_Part == null)
{
m_RunOnePhase = "return disposed";
m_RunOnePhase = "runone saw it disposed";
return XMRInstState.DISPOSED;
}
/*
* Do some more of the last event if it didn't finish.
*/
else if (eventCode != ScriptEventCode.None)
if(this.eventCode != ScriptEventCode.None)
{
lock(m_QueueLock)
{
@ -299,7 +294,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
m_LastRanAt = now;
m_InstEHSlice++;
callMode = CallMode_NORMAL;
e = microthread.ResumeEx ();
e = ResumeEx();
}
/*
@ -335,10 +330,10 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
if(m_EventQueue.First != null)
{
evt = m_EventQueue.First.Value;
evc = (ScriptEventCode)Enum.Parse (typeof (ScriptEventCode),
evt.EventName);
if(m_DetachQuantum > 0)
{
evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
evt.EventName);
if(evc != ScriptEventCode.attach)
{
/*
@ -355,7 +350,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
}
}
m_EventQueue.RemoveFirst();
if (evc >= 0)
evc = (ScriptEventCode)Enum.Parse(typeof(ScriptEventCode),
evt.EventName);
if((int)evc >= 0)
m_EventCounts[(int)evc]--;
}
@ -410,9 +407,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* If event handler completed, get rid of detect params.
*/
if(this.eventCode == ScriptEventCode.None)
{
m_DetectParams = null;
}
}
finally
{
@ -432,34 +428,31 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* @brief Immediately after taking m_RunLock or just before releasing it, check invariants.
*/
private ScriptEventCode lastEventCode = ScriptEventCode.None;
private int lastActive = 0;
private bool lastActive = false;
private string lastRunPhase = "";
public void CheckRunLockInvariants(bool throwIt)
{
/*
* If not executing any event handler, active should be 0 indicating the microthread stack is not in use.
* If executing an event handler, active should be -1 indicating stack is in use but suspended.
* If not executing any event handler, there shouldn't be any saved stack frames.
* If executing an event handler, there should be some saved stack frames.
*/
IScriptUThread uth = microthread;
if (uth != null) {
int active = uth.Active ();
bool active = (stackFrames != null);
ScriptEventCode ec = this.eventCode;
if (((ec == ScriptEventCode.None) && (active != 0)) ||
((ec != ScriptEventCode.None) && (active >= 0))) {
if(((ec == ScriptEventCode.None) && active) ||
((ec != ScriptEventCode.None) && !active))
{
Console.WriteLine("CheckRunLockInvariants: script=" + m_DescName);
Console.WriteLine("CheckRunLockInvariants: eventcode=" + ec.ToString() + ", active=" + active.ToString());
Console.WriteLine("CheckRunLockInvariants: m_RunOnePhase=" + m_RunOnePhase);
Console.WriteLine("CheckRunLockInvariants: lastec=" + lastEventCode + ", lastAct=" + lastActive + ", lastPhase=" + lastRunPhase);
if (throwIt) {
if(throwIt)
throw new Exception("CheckRunLockInvariants: eventcode=" + ec.ToString() + ", active=" + active.ToString());
}
}
lastEventCode = ec;
lastActive = active;
lastRunPhase = m_RunOnePhase;
}
}
/*
* Start event handler.
@ -487,7 +480,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/*
* Silly to even try if there is no handler defined for this event.
*/
if ((eventCode >= 0) && (m_ObjCode.scriptEventHandlerTable[this.stateCode,(int)eventCode] == null))
if(((int)eventCode >= 0) && (m_ObjCode.scriptEventHandlerTable[this.stateCode, (int)eventCode] == null))
return null;
/*
@ -497,10 +490,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
if(this.eventCode != ScriptEventCode.None)
throw new Exception("still processing event " + this.eventCode.ToString());
int active = microthread.Active ();
if (active != 0)
throw new Exception ("microthread is active " + active.ToString ());
/*
* Save eventCode so we know what event handler to run in the microthread.
* And it also marks us busy so we can't be started again and this event lost.
@ -515,9 +504,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* without doing any stack frame restores first.
*/
this.stackFrames = null;
Exception e;
e = microthread.StartEx ();
return e;
return StartEx();
}
@ -540,7 +527,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* ... to delete itself from the object.
*/
m_SleepUntil = DateTime.MaxValue;
Verbose ("[XMREngine]: script self-delete {0}", m_ItemID);
Verbose("[YEngine]: script self-delete {0}", m_ItemID);
m_Part.Inventory.RemoveInventoryItem(m_ItemID);
}
else if(e is ScriptDieException)
@ -579,7 +566,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{
StringBuilder msg = new StringBuilder();
msg.Append ("[XMREngine]: Exception while running ");
msg.Append("[YEngine]: Exception while running ");
msg.Append(m_ItemID);
msg.Append('\n');
@ -623,15 +610,20 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Suppress internal code stack trace lines.
*/
string msgst = msg.ToString();
if (!msgst.EndsWith ("\n")) msgst += '\n';
if(!msgst.EndsWith("\n"))
msgst += '\n';
int j = 0;
StringBuilder imstr = new StringBuilder();
for (int i = 0; (i = msgst.IndexOf ('\n', i)) >= 0; j = ++ i) {
for(int i = 0; (i = msgst.IndexOf('\n', i)) >= 0; j = ++i)
{
string line = msgst.Substring(j, i - j);
if (line.StartsWith ("at ")) {
if (line.StartsWith ("at (wrapper")) continue; // at (wrapper ...
if(line.StartsWith("at "))
{
if(line.StartsWith("at (wrapper"))
continue; // at (wrapper ...
int k = line.LastIndexOf(".cs:"); // ... .cs:linenumber
if (Int32.TryParse (line.Substring (k + 4), out k)) continue;
if(Int32.TryParse(line.Substring(k + 4), out k))
continue;
}
this.llOwnerSay(line);
imstr.Append(line);
@ -643,7 +635,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Code modelled from llInstantMessage().
*/
IMessageTransferModule transferModule = m_Engine.World.RequestModuleInterface<IMessageTransferModule>();
if (transferModule != null) {
if(transferModule != null)
{
UUID friendTransactionID = UUID.Random();
GridInstantMessage gim = new GridInstantMessage();
gim.fromAgentID = new Guid(m_Part.UUID.ToString());
@ -663,7 +656,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
(int)Math.Floor(pos.X),
(int)Math.Floor(pos.Y),
(int)Math.Floor(pos.Z));
transferModule.SendInstantMessage(gim, delegate(bool success) {});
transferModule.SendInstantMessage(gim, delegate (bool success)
{
});
}
/*
@ -681,14 +676,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
{
checkstate:
XMRInstState iState = m_IState;
switch (iState) {
switch(iState)
{
/*
* If it's really being constructed now, that's about as reset as we get.
*/
case XMRInstState.CONSTRUCT: {
case XMRInstState.CONSTRUCT:
return;
}
/*
* If it's idle, that means it is ready to receive a new event.
@ -696,15 +690,16 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* it out of idle, verify that it is still in idle then transition
* it to resetting so no other thread will touch it.
*/
case XMRInstState.IDLE: {
lock (m_QueueLock) {
if (m_IState == XMRInstState.IDLE) {
case XMRInstState.IDLE:
lock(m_QueueLock)
{
if(m_IState == XMRInstState.IDLE)
{
m_IState = XMRInstState.RESETTING;
break;
}
}
goto checkstate;
}
/*
* If it's on the start queue, that means it is about to dequeue an
@ -712,112 +707,108 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* can't be started and transition it to resetting so no other thread
* will touch it.
*/
case XMRInstState.ONSTARTQ: {
lock (m_Engine.m_StartQueue) {
if (m_IState == XMRInstState.ONSTARTQ) {
case XMRInstState.ONSTARTQ:
lock(m_Engine.m_StartQueue)
{
if(m_IState == XMRInstState.ONSTARTQ)
{
m_Engine.m_StartQueue.Remove(this);
m_IState = XMRInstState.RESETTING;
break;
}
}
goto checkstate;
}
/*
* If it's running, tell CheckRun() to suspend the thread then go back
* to see what it got transitioned to.
*/
case XMRInstState.RUNNING: {
case XMRInstState.RUNNING:
suspendOnCheckRunHold = true;
lock (m_QueueLock) { }
goto checkstate;
lock(m_QueueLock)
{
}
goto checkstate;
/*
* If it's sleeping, remove it from sleep queue and transition it to
* resetting so no other thread will touch it.
*/
case XMRInstState.ONSLEEPQ: {
lock (m_Engine.m_SleepQueue) {
if (m_IState == XMRInstState.ONSLEEPQ) {
case XMRInstState.ONSLEEPQ:
lock(m_Engine.m_SleepQueue)
{
if(m_IState == XMRInstState.ONSLEEPQ)
{
m_Engine.m_SleepQueue.Remove(this);
m_IState = XMRInstState.RESETTING;
break;
}
}
goto checkstate;
}
/*
* It was just removed from the sleep queue and is about to be put
* on the yield queue (ie, is being woken up).
* Let that thread complete transition and try again.
*/
case XMRInstState.REMDFROMSLPQ: {
case XMRInstState.REMDFROMSLPQ:
Sleep(10);
goto checkstate;
}
/*
* If it's yielding, remove it from yield queue and transition it to
* resetting so no other thread will touch it.
*/
case XMRInstState.ONYIELDQ: {
lock (m_Engine.m_YieldQueue) {
if (m_IState == XMRInstState.ONYIELDQ) {
case XMRInstState.ONYIELDQ:
lock(m_Engine.m_YieldQueue)
{
if(m_IState == XMRInstState.ONYIELDQ)
{
m_Engine.m_YieldQueue.Remove(this);
m_IState = XMRInstState.RESETTING;
break;
}
}
goto checkstate;
}
/*
* If it just finished running something, let that thread transition it
* to its next state then check again.
*/
case XMRInstState.FINISHED: {
case XMRInstState.FINISHED:
Sleep(10);
goto checkstate;
}
/*
* If it's disposed, that's about as reset as it gets.
*/
case XMRInstState.DISPOSED: {
case XMRInstState.DISPOSED:
return;
}
/*
* Some other thread is already resetting it, let it finish.
*/
case XMRInstState.RESETTING: {
case XMRInstState.RESETTING:
return;
}
default: throw new Exception("bad state");
default:
throw new Exception("bad state");
}
/*
* This thread transitioned the instance to RESETTING so reset it.
*/
lock (m_RunLock) {
lock(m_RunLock)
{
CheckRunLockInvariants(true);
/*
* No other thread should have transitioned it from RESETTING.
*/
if (m_IState != XMRInstState.RESETTING) throw new Exception("bad state");
/*
* If the microthread is active, that means it has call frame
* context that we don't want. Throw it out and get a fresh one.
*/
if (microthread.Active () < 0) {
microthread.Dispose ();
microthread = (IScriptUThread)m_Engine.uThreadCtor.Invoke (new object[] { this });
}
if(m_IState != XMRInstState.RESETTING)
throw new Exception("bad state");
/*
* Mark it idle now so it can get queued to process new stuff.
@ -836,21 +827,22 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
private void ClearQueueExceptLinkMessages()
{
lock (m_QueueLock) {
lock(m_QueueLock)
{
EventParams[] linkMessages = new EventParams[m_EventQueue.Count];
int n = 0;
foreach (EventParams evt2 in m_EventQueue) {
if (evt2.EventName == "link_message") {
foreach(EventParams evt2 in m_EventQueue)
{
if(evt2.EventName == "link_message")
linkMessages[n++] = evt2;
}
}
m_EventQueue.Clear();
for (int i = m_EventCounts.Length; -- i >= 0;) m_EventCounts[i] = 0;
for(int i = m_EventCounts.Length; --i >= 0;)
m_EventCounts[i] = 0;
for (int i = 0; i < n; i ++) {
for(int i = 0; i < n; i++)
m_EventQueue.AddLast(linkMessages[i]);
}
m_EventCounts[(int)ScriptEventCode.link_message] = n;
}
@ -861,7 +853,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
lock(m_QueueLock)
{
m_EventQueue.Clear(); // no events queued
for (int i = m_EventCounts.Length; -- i >= 0;) m_EventCounts[i] = 0;
for(int i = m_EventCounts.Length; --i >= 0;)
m_EventCounts[i] = 0;
}
}
@ -926,24 +919,27 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
int permsMask;
UUID permsGranter;
try {
try
{
permsGranter = m_Part.TaskInventory[m_ItemID].PermsGranter;
permsMask = m_Part.TaskInventory[m_ItemID].PermsMask;
found = true;
} catch {
}
catch
{
permsGranter = UUID.Zero;
permsMask = 0;
found = false;
}
if (found && ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0)) {
if(found && ((permsMask & ScriptBaseClass.PERMISSION_TAKE_CONTROLS) != 0))
{
ScenePresence presence = m_Engine.World.GetScenePresence(permsGranter);
if (presence != null) {
if(presence != null)
presence.UnRegisterControlEventsToScript(m_LocalID, m_ItemID);
}
}
}
}
/**
* @brief The script code should call this routine whenever it is
@ -957,7 +953,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
return;
suspendOnCheckRunTemp = true;
}
m_CheckRunPhase = "entered";
/*
@ -966,44 +961,37 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
while(suspendOnCheckRunHold || suspendOnCheckRunTemp)
{
m_CheckRunPhase = "top of while";
/*
* See if MigrateOutEventHandler() has been called.
* If so, dump our stack to stackFrames and unwind.
*/
if (this.captureStackFrames)
{
/*
* Puque our stack to the output stream.
* But otherwise, our state remains intact.
*/
m_CheckRunPhase = "saving";
this.callMode = CallMode_SAVE;
this.stackFrames = null;
throw new StackCaptureException ();
}
/*
* We get here when the script state has been read in by MigrateInEventHandler().
* Since the stack is completely restored at this point, any subsequent calls
* within the functions should do their normal processing instead of trying to
* restore their state.
*/
if (this.callMode == CallMode_RESTORE)
{
stackFramesRestored = true;
this.callMode = CallMode_NORMAL;
}
/*
* Now we are ready to suspend the microthread.
* This is like a longjmp() to the most recent StartEx() or ResumeEx()
* with a simultaneous setjmp() so ResumeEx() can longjmp() back here.
*/
m_CheckRunPhase = "suspending";
suspendOnCheckRunTemp = false;
microthread.Hiber ();
switch(this.callMode)
{
// Now we are ready to suspend the microthread.
// This is like a longjmp() to the most recent StartEx() or ResumeEx()
// with a simultaneous setjmp() so ResumeEx() can longjmp() back here.
// the script event handler wants to hibernate
// capture stack frames and unwind to Start() or Resume()
case CallMode_NORMAL:
m_CheckRunPhase = "suspending";
callMode = XMRInstance.CallMode_SAVE;
stackFrames = null;
throw new StackHibernateException();
// We get here when the script state has been read in by MigrateInEventHandler().
// Since the stack is completely restored at this point, any subsequent calls
// within the functions should do their normal processing instead of trying to
// restore their state.
// the stack has been restored as a result of calling ResumeEx()
// tell script code to process calls normally
case CallMode_RESTORE:
this.callMode = CallMode_NORMAL;
break;
default:
throw new Exception("callMode=" + callMode);
}
m_CheckRunPhase = "resumed";
}
@ -1013,7 +1001,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* Upon return from CheckRun() it should always be the case that the script is
* going to process calls normally, neither saving nor restoring stack frame state.
*/
if (callMode != CallMode_NORMAL) throw new Exception ("bad callMode " + callMode);
if(callMode != CallMode_NORMAL)
throw new Exception("bad callMode " + callMode);
}
/**
@ -1026,7 +1015,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
m_Suspended = false;
if((m_EventQueue != null) &&
(m_EventQueue.First != null) &&
(m_IState == XMRInstState.IDLE)) {
(m_IState == XMRInstState.IDLE))
{
m_IState = XMRInstState.ONSTARTQ;
m_Engine.QueueToStart(this);
}
@ -1052,5 +1042,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* to intercept this exception as it would block the stack capture
* functionality.
*/
public class StackCaptureException : Exception, IXMRUncatchable { }
public class StackCaptureException: Exception, IXMRUncatchable
{
}
}

File diff suppressed because it is too large Load Diff

View File

@ -36,7 +36,7 @@ using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
namespace OpenSim.Region.ScriptEngine.XMREngine
namespace OpenSim.Region.ScriptEngine.Yengine
{
public class XMRSDTypeClObj
{
@ -95,11 +95,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* 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 ++) {
for(int i = 0; i < n; i++)
{
sdtcVTable[i] = vDynMeths[i].CreateDelegate(vMethTypes[i], this);
}
}
@ -114,10 +116,12 @@ 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];
@ -126,19 +130,24 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
// 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 ++) {
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);
}
@ -185,7 +194,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
* 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,8 +207,10 @@ 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 +
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);
}
@ -217,12 +229,14 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
*/
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;
}
@ -248,7 +262,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine
/**
* @brief Read the whole thing in from a stream.
*/
public XMRSDTypeClObj () { }
public XMRSDTypeClObj()
{
}
public void Restore(XMRInstAbstract inst, XMRInstArrays.Recver recvValue)
{
int classindex = (int)recvValue();

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>