/* * 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 opCodes = PopulateOpCodes (); private static Dictionary string2Type = PopulateS2T (); private static Dictionary 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 sdTypesRev = new Dictionary (); 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. (); * 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 sdTypes, BinaryReader objReader, ScriptObjCode scriptObjCode, ObjectTokens objectTokens) { Dictionary methods = new Dictionary (); DynamicMethod method = null; ILGenerator ilGen = null; Dictionary labels = new Dictionary (); Dictionary locals = new Dictionary (); Dictionary labelNames = new Dictionary (); Dictionary localNames = new Dictionary (); object[] ilGenArg = new object[1]; int offset = 0; Dictionary 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 (); 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 PopulateOpCodes () { Dictionary opCodeDict = new Dictionary (); 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 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 PopulateS2T () { Dictionary s2t = new Dictionary (); 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 PopulateT2S () { Dictionary s2t = PopulateS2T (); Dictionary t2s = new Dictionary (); foreach (KeyValuePair 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 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; } }