diff --git a/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCodeGen.cs b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCodeGen.cs index 5219fa8674..3b0ba66a4d 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCodeGen.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCodeGen.cs @@ -141,9 +141,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine new Type[] { typeof (LSL_Vector) }); private static MethodInfo scriptRestoreCatchExceptionUnwrap = GetStaticMethod (typeof (ScriptRestoreCatchException), "Unwrap", new Type[] { typeof (Exception) }); private static MethodInfo thrownExceptionWrapMethodInfo = GetStaticMethod (typeof (ScriptThrownException), "Wrap", new Type[] { typeof (object) }); - private static MethodInfo heapTrackerListPush = typeof (HeapTrackerList). GetMethod ("Push", new Type[0]); - private static MethodInfo heapTrackerObjectPush = typeof (HeapTrackerObject).GetMethod ("Push", new Type[0]); - private static MethodInfo heapTrackerStringPush = typeof (HeapTrackerString).GetMethod ("Push", new Type[0]); private static MethodInfo catchExcToStrMethodInfo = GetStaticMethod (typeof (ScriptCodeGen), "CatchExcToStr", @@ -1510,16 +1507,13 @@ namespace OpenSim.Region.ScriptEngine.XMREngine ilGen.Emit (curDeclFunc, OpCodes.Ldloc, lcl); Type t = lcl.type; if (t == typeof (HeapTrackerList)) { - ilGen.Emit (curDeclFunc, OpCodes.Call, heapTrackerListPush); - t = typeof (LSL_List); + t = HeapTrackerList.GenPush (curDeclFunc, ilGen); } if (t == typeof (HeapTrackerObject)) { - ilGen.Emit (curDeclFunc, OpCodes.Call, heapTrackerObjectPush); - t = typeof (object); + t = HeapTrackerObject.GenPush (curDeclFunc, ilGen); } - if (t == typeof (HeapTrackerString)) { - ilGen.Emit (curDeclFunc, OpCodes.Call, heapTrackerStringPush); - t = typeof (string); + if (t == typeof(HeapTrackerString)) { + t = HeapTrackerString.GenPush (curDeclFunc, ilGen); } if (t.IsValueType) { ilGen.Emit (curDeclFunc, OpCodes.Box, t); @@ -1615,7 +1609,9 @@ namespace OpenSim.Region.ScriptEngine.XMREngine ilGen.Emit (curDeclFunc, OpCodes.Castclass, u); } if (u != t) { - ilGen.Emit (curDeclFunc, OpCodes.Call, t.GetMethod ("Pop", new Type[] { u })); + if (t == typeof (HeapTrackerList)) HeapTrackerList.GenPop (curDeclFunc, ilGen); + if (t == typeof (HeapTrackerObject)) HeapTrackerObject.GenPop (curDeclFunc, ilGen); + if (t == typeof (HeapTrackerString)) HeapTrackerString.GenPop (curDeclFunc, ilGen); } else { ilGen.Emit (curDeclFunc, OpCodes.Stloc, lcl); } diff --git a/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCompValu.cs b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCompValu.cs index fd3174d162..7263274ac5 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCompValu.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptCompValu.cs @@ -1313,7 +1313,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { scg.ilGen.Emit (errorAt, OpCodes.Ldloc, localBuilder); if (type.ToHeapTrackerType () != null) { - scg.ilGen.Emit (errorAt, OpCodes.Call, type.GetHeapTrackerPushMeth ()); + type.CallHeapTrackerPushMeth (errorAt, scg.ilGen); } } public override void PushRef (ScriptCodeGen scg, Token errorAt) @@ -1335,7 +1335,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine public override void PopPost (ScriptCodeGen scg, Token errorAt) { if (type.ToHeapTrackerType () != null) { - scg.ilGen.Emit (errorAt, OpCodes.Call, type.GetHeapTrackerPopMeth ()); + type.CallHeapTrackerPopMeth (errorAt, scg.ilGen); } else { scg.ilGen.Emit (errorAt, OpCodes.Stloc, localBuilder); } @@ -1352,7 +1352,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine scg.ilGen.Emit (errorAt, OpCodes.Stloc, htpop); scg.ilGen.Emit (errorAt, OpCodes.Ldloc, localBuilder); scg.ilGen.Emit (errorAt, OpCodes.Ldloc, htpop); - scg.ilGen.Emit (errorAt, OpCodes.Call, type.GetHeapTrackerPopMeth ()); + type.CallHeapTrackerPopMeth (errorAt, scg.ilGen); } else { /* diff --git a/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptTokenize.cs b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptTokenize.cs index a767dcf24e..1bdcc27dcd 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptTokenize.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/MMRScriptTokenize.cs @@ -1504,6 +1504,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { /** * @brief Get heap tracking type. + * null indicates there is no heap tracker for the type. */ public virtual Type ToHeapTrackerType () { @@ -1511,15 +1512,15 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { } public virtual ConstructorInfo GetHeapTrackerCtor () { - return null; + throw new ApplicationException("no GetHeapTrackerCtor for " + this.GetType()); } - public virtual MethodInfo GetHeapTrackerPopMeth () + public virtual void CallHeapTrackerPopMeth (Token errorAt, ScriptMyILGen ilGen) { - return null; + throw new ApplicationException("no CallHeapTrackerPopMeth for " + this.GetType()); } - public virtual MethodInfo GetHeapTrackerPushMeth () + public virtual void CallHeapTrackerPushMeth(Token errorAt, ScriptMyILGen ilGen) { - return null; + throw new ApplicationException("no CallHeapTrackerPushMeth for " + this.GetType()); } } @@ -1610,8 +1611,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { public class TokenTypeList : TokenType { private static readonly FieldInfo iarListsFieldInfo = typeof (XMRInstArrays).GetField ("iarLists"); private static readonly ConstructorInfo htListCtor = typeof (HeapTrackerList).GetConstructor (new Type [] { typeof (XMRInstAbstract) }); - private static readonly MethodInfo htListPopMeth = typeof (HeapTrackerList).GetMethod ("Pop", new Type[] { typeof (LSL_List) }); - private static readonly MethodInfo htListPushMeth = typeof (HeapTrackerList).GetMethod ("Push", new Type[0]); public TokenTypeList (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { } public TokenTypeList (Token original) : base (original) { } @@ -1624,14 +1623,12 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { } public override Type ToHeapTrackerType () { return typeof (HeapTrackerList); } public override ConstructorInfo GetHeapTrackerCtor () { return htListCtor; } - public override MethodInfo GetHeapTrackerPopMeth () { return htListPopMeth; } - public override MethodInfo GetHeapTrackerPushMeth () { return htListPushMeth; } + public override void CallHeapTrackerPopMeth (Token errorAt, ScriptMyILGen ilGen) { HeapTrackerList.GenPop(errorAt, ilGen); } + public override void CallHeapTrackerPushMeth (Token errorAt, ScriptMyILGen ilGen) { HeapTrackerList.GenPush(errorAt, ilGen); } } public class TokenTypeObject : TokenType { private static readonly FieldInfo iarObjectsFieldInfo = typeof (XMRInstArrays).GetField ("iarObjects"); private static readonly ConstructorInfo htObjectCtor = typeof (HeapTrackerObject).GetConstructor (new Type [] { typeof (XMRInstAbstract) }); - private static readonly MethodInfo htObjectPopMeth = typeof (HeapTrackerObject).GetMethod ("Pop", new Type[] { typeof (object) }); - private static readonly MethodInfo htObjectPushMeth = typeof (HeapTrackerObject).GetMethod ("Push", new Type[0]); public TokenTypeObject (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { } public TokenTypeObject (Token original) : base (original) { } @@ -1644,8 +1641,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { } public override Type ToHeapTrackerType () { return typeof (HeapTrackerObject); } public override ConstructorInfo GetHeapTrackerCtor () { return htObjectCtor; } - public override MethodInfo GetHeapTrackerPopMeth () { return htObjectPopMeth; } - public override MethodInfo GetHeapTrackerPushMeth () { return htObjectPushMeth; } + public override void CallHeapTrackerPopMeth(Token errorAt, ScriptMyILGen ilGen) { HeapTrackerObject.GenPop (errorAt, ilGen); } + public override void CallHeapTrackerPushMeth(Token errorAt, ScriptMyILGen ilGen) { HeapTrackerObject.GenPush(errorAt, ilGen); } } public class TokenTypeRot : TokenType { private static readonly FieldInfo iarRotationsFieldInfo = typeof (XMRInstArrays).GetField ("iarRotations"); @@ -1663,8 +1660,6 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { public class TokenTypeStr : TokenType { private static readonly FieldInfo iarStringsFieldInfo = typeof (XMRInstArrays).GetField ("iarStrings"); private static readonly ConstructorInfo htStringCtor = typeof (HeapTrackerString).GetConstructor (new Type [] { typeof (XMRInstAbstract) }); - private static readonly MethodInfo htStringPopMeth = typeof (HeapTrackerString).GetMethod ("Pop", new Type[] { typeof (string) }); - private static readonly MethodInfo htStringPushMeth = typeof (HeapTrackerString).GetMethod ("Push", new Type[0]); public TokenTypeStr (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { } public TokenTypeStr (Token original) : base (original) { } @@ -1677,8 +1672,8 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { } public override Type ToHeapTrackerType () { return typeof (HeapTrackerString); } public override ConstructorInfo GetHeapTrackerCtor () { return htStringCtor; } - public override MethodInfo GetHeapTrackerPopMeth () { return htStringPopMeth; } - public override MethodInfo GetHeapTrackerPushMeth () { return htStringPushMeth; } + public override void CallHeapTrackerPopMeth(Token errorAt, ScriptMyILGen ilGen) { HeapTrackerString.GenPop(errorAt, ilGen); } + public override void CallHeapTrackerPushMeth (Token errorAt, ScriptMyILGen ilGen) { HeapTrackerString.GenPush(errorAt, ilGen); } } public class TokenTypeUndef : TokenType { // for the 'undef' constant, ie, null object pointer public TokenTypeUndef (TokenErrorMessage emsg, string file, int line, int posn) : base (emsg, file, line, posn) { } diff --git a/OpenSim/Region/ScriptEngine/XMREngine/MMRWebRequest.cs b/OpenSim/Region/ScriptEngine/XMREngine/MMRWebRequest.cs index 3579332e1e..42865861c4 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/MMRWebRequest.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/MMRWebRequest.cs @@ -54,7 +54,7 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { } bool https = uri.Scheme == "https"; if (!https && (uri.Scheme != "http")) { - throw new WebException ("only support " + supported + ", not " + uri.Scheme); + throw new WebException ("only support " + supported + ", not " + uri.Scheme + " in " + requestUrl); } string host = uri.Host; int port = uri.Port; diff --git a/OpenSim/Region/ScriptEngine/XMREngine/XMRHeapTracker.cs b/OpenSim/Region/ScriptEngine/XMREngine/XMRHeapTracker.cs index c906f21aca..fdf65cfbbf 100644 --- a/OpenSim/Region/ScriptEngine/XMREngine/XMRHeapTracker.cs +++ b/OpenSim/Region/ScriptEngine/XMREngine/XMRHeapTracker.cs @@ -25,11 +25,7 @@ * 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.IO; using System.Reflection; using System.Reflection.Emit; @@ -43,9 +39,18 @@ using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; namespace OpenSim.Region.ScriptEngine.XMREngine { + /** + * One instance of this class for lsl base objects that take a variable + * amount of memory. They are what the script-visible list,object,string + * variables are declared as at the CIL level. Generally, temp vars used + * by the compiler get their basic type (list,object,string). + * + * 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 { - private int usage; - private XMRInstAbstract instance; + protected int usage; // num bytes used by object + protected XMRInstAbstract instance; // what script it is in public HeapTrackerBase (XMRInstAbstract inst) { @@ -57,36 +62,78 @@ namespace OpenSim.Region.ScriptEngine.XMREngine { usage = instance.UpdateHeapUse (usage, 0); } - - protected void NewUse (int newuse) - { - usage = instance.UpdateHeapUse (usage, newuse); - } } + /** + * Wrapper around lists to keep track of how much memory they use. + */ public class HeapTrackerList : HeapTrackerBase { - private LSL_List value; + private static FieldInfo listValueField = typeof (HeapTrackerList).GetField ("value"); + private static MethodInfo listSaveMethod = typeof (HeapTrackerList).GetMethod ("Save"); + + public LSL_List value; public HeapTrackerList (XMRInstAbstract inst) : base (inst) { } - public void Pop (LSL_List lis) + // generate CIL code to pop the value from the CIL stack + // input: + // 'this' pointer already pushed on CIL stack + // new value pushed on CIL stack + // output: + // 'this' pointer popped from stack + // new value popped from CIL stack + // heap usage updated + public static void GenPop (Token errorAt, ScriptMyILGen ilGen) { - NewUse (Size (lis)); + ilGen.Emit(errorAt, OpCodes.Call, listSaveMethod); + } + + // generate CIL code to push the value on the CIL stack + // input: + // 'this' pointer already pushed on CIL stack + // output: + // 'this' pointer popped from stack + // value pushed on CIL stack replacing 'this' pointer + // returns typeof value pushed on stack + public static Type GenPush (Token errorAt, ScriptMyILGen ilGen) + { + ilGen.Emit (errorAt, OpCodes.Ldfld, listValueField); + return typeof (LSL_List); + } + + public void Save (LSL_List lis) + { + int newuse = Size (lis); + usage = instance.UpdateHeapUse (usage, newuse); value = lis; } - public LSL_List Push () - { - return value; - } - + //private static int counter = 5; public static int Size (LSL_List lis) { - return (!typeof (LSL_List).IsValueType && (lis == null)) ? 0 : lis.Size; + // VS2017 in debug mode seems to have a problem running this statement quickly: + //SLOW: return (!typeof(LSL_List).IsValueType && (lis == null)) ? 0 : lis.Size; + + //FAST: return 33; + //SLOW: return (lis == null) ? 0 : 99; + //FAST: return ++ counter; + + // VS2017 in debug mode seems content to run this quickly though: + try { + return lis.Size; + } catch { + return 0; + } } } + /** + * Wrapper around objects to keep track of how much memory they use. + */ public class HeapTrackerObject : HeapTrackerBase { + private static FieldInfo objectValueField = typeof (HeapTrackerObject).GetField ("value"); + private static MethodInfo objectSaveMethod = typeof (HeapTrackerObject).GetMethod ("Save"); + public const int HT_CHAR = 2; public const int HT_DELE = 8; public const int HT_DOUB = 8; @@ -96,21 +143,44 @@ namespace OpenSim.Region.ScriptEngine.XMREngine public const int HT_VEC = HT_DOUB * 3; public const int HT_ROT = HT_DOUB * 4; - private object value; + public object value; public HeapTrackerObject (XMRInstAbstract inst) : base (inst) { } - public void Pop (object obj) + // generate CIL code to pop the value from the CIL stack + // input: + // 'this' pointer already pushed on CIL stack + // new value pushed on CIL stack + // output: + // 'this' pointer popped from stack + // new value popped from CIL stack + // heap usage updated + public static void GenPop (Token errorAt, ScriptMyILGen ilGen) { - NewUse (Size (obj)); + ilGen.Emit(errorAt, OpCodes.Call, objectSaveMethod); + } + + // generate CIL code to push the value on the CIL stack + // input: + // 'this' pointer already pushed on CIL stack + // output: + // 'this' pointer popped from stack + // value pushed on CIL stack replacing 'this' pointer + // returns typeof value pushed on stack + public static Type GenPush (Token errorAt, ScriptMyILGen ilGen) + { + ilGen.Emit (errorAt, OpCodes.Ldfld, objectValueField); + return typeof (object); + } + + public void Save (object obj) + { + int newuse = Size (obj); + usage = instance.UpdateHeapUse (usage, newuse); value = obj; } - public object Push () - { - return value; - } - + // public so it can be used by XMRArray public static int Size (object obj) { if (obj == null) return 0; @@ -148,20 +218,48 @@ namespace OpenSim.Region.ScriptEngine.XMREngine } } + /** + * Wrapper around strings to keep track of how much memory they use. + */ public class HeapTrackerString : HeapTrackerBase { - private string value; + private static FieldInfo stringValueField = typeof (HeapTrackerString).GetField ("value"); + private static MethodInfo stringSaveMethod = typeof (HeapTrackerString).GetMethod ("Save"); + + public string value; public HeapTrackerString (XMRInstAbstract inst) : base (inst) { } - public void Pop (string str) + // generate CIL code to pop the value from the CIL stack + // input: + // 'this' pointer already pushed on CIL stack + // new value pushed on CIL stack + // output: + // 'this' pointer popped from stack + // new value popped from CIL stack + // heap usage updated + public static void GenPop (Token errorAt, ScriptMyILGen ilGen) { - NewUse (Size (str)); - value = str; + ilGen.Emit (errorAt, OpCodes.Call, stringSaveMethod); } - public string Push () + // generate CIL code to push the value on the CIL stack + // input: + // 'this' pointer already pushed on CIL stack + // output: + // 'this' pointer popped from stack + // value pushed on CIL stack replacing 'this' pointer + // returns typeof value pushed on stack + public static Type GenPush (Token errorAt, ScriptMyILGen ilGen) { - return value; + ilGen.Emit (errorAt, OpCodes.Ldfld, stringValueField); + return typeof (string); + } + + public void Save (string str) + { + int newuse = Size (str); + usage = instance.UpdateHeapUse (usage, newuse); + value = str; } public static int Size (string str)