123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949 |
- /*
- * 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.Yengine
- {
- 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 readonly Dictionary<short, OpCode> opCodes = PopulateOpCodes();
- private static readonly Dictionary<string, Type> string2Type = PopulateS2T();
- private static readonly Dictionary<Type, string> type2String = PopulateT2S();
- 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 readonly Dictionary<Type, string> sdTypesRev = new ();
- public int labelNumber = 0;
- public int localNumber = 0;
- public string methName { get; private set;}
- 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 ()
- {
- type = type,
- name = name,
- number = localNumber++,
- 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()
- {
- name = name,
- 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(nameof(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 ();
- DynamicMethod method = null;
- ILGenerator ilGen = null;
- Dictionary<int, Label> labels = new ();
- Dictionary<int, LocalBuilder> locals = new ();
- Dictionary<int, string> labelNames = new ();
- Dictionary<int, string> localNames = new ();
- object[] ilGenArg = new object[1];
- int offset;
- Dictionary<int, ScriptSrcLoc> srcLocs = null;
- string srcFile = "";
- int srcLine = 0;
- int srcPosn = 0;
- while(true)
- {
- // Get IL instruction offset at beginning of instruction.
- offset = ilGen is null ? 0 : ilGen.ILOffset;
- // 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>();
- 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;
- 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());
- 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());
- 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));
- 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]);
- objectTokens?.MarkLabel(offset, number);
- break;
- }
- // Try/Catch blocks.
- case ScriptObjWriterCode.BegExcBlk:
- {
- ilGen.BeginExceptionBlock();
- objectTokens?.BegExcBlk(offset);
- break;
- }
- case ScriptObjWriterCode.BegCatBlk:
- {
- Type excType = GetTypeFromStr(sdTypes, objReader.ReadString());
- ilGen.BeginCatchBlock(excType);
- objectTokens?.BegCatBlk(offset, excType);
- break;
- }
- case ScriptObjWriterCode.BegFinBlk:
- {
- ilGen.BeginFinallyBlock();
- objectTokens?.BegFinBlk(offset);
- break;
- }
- case ScriptObjWriterCode.EndExcBlk:
- {
- ilGen.EndExceptionBlock();
- 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);
- 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);
- 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]);
- 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);
- 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]);
- 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);
- 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);
- 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);
- 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);
- 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);
- 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);
- 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);
- 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:
- 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);
- 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 ();
- 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)
- {
- srcLocs[offset] = new ScriptSrcLoc()
- {
- file = srcFile,
- line = srcLine,
- posn = srcPosn
- };
- }
- /**
- * @brief Create type<->string conversions.
- * Using Type.AssemblyQualifiedName is horribly inefficient
- * and all our types should be known.
- */
- private static Dictionary<string, Type> PopulateS2T()
- {
- return new Dictionary<string, Type>
- {
- { "badcallx", typeof(ScriptBadCallNoException) },
- { "binopstr", typeof(BinOpStr) },
- { "bool", typeof(bool) },
- { "char", typeof(char) },
- { "delegate", typeof(Delegate) },
- { "delarr[]", typeof(Delegate[]) },
- { "double", typeof(double) },
- { "exceptn", typeof(Exception) },
- { "float", typeof(float) },
- { "htlist", typeof(HeapTrackerList) },
- { "htobject", typeof(HeapTrackerObject) },
- { "htstring", typeof(HeapTrackerString) },
- { "inlfunc", typeof(CompValuInline) },
- { "int", typeof(int) },
- { "int*", typeof(int).MakeByRefType() },
- { "intrlokd", typeof(System.Threading.Interlocked) },
- { "lslfloat", typeof(LSL_Float) },
- { "lslint", typeof(LSL_Integer) },
- { "lsllist", typeof(LSL_List) },
- { "lslrot", typeof(LSL_Rotation) },
- { "lslstr", typeof(LSL_String) },
- { "lslvec", typeof(LSL_Vector) },
- { "math", typeof(Math) },
- { "midround", typeof(MidpointRounding) },
- { "object", typeof(object) },
- { "object*", typeof(object).MakeByRefType() },
- { "object[]", typeof(object[]) },
- { "scrbase", typeof(ScriptBaseClass) },
- { "scrcode", typeof(ScriptCodeGen) },
- { "sdtclobj", typeof(XMRSDTypeClObj) },
- { "string", typeof(string) },
- { "typecast", typeof(TypeCast) },
- { "undstatx", typeof(ScriptUndefinedStateException) },
- { "void", typeof(void) },
- { "xmrarray", typeof(XMR_Array) },
- { "xmrinst", typeof(XMRInstAbstract) }
- };
- }
- private static Dictionary<Type, string> PopulateT2S()
- {
- Dictionary<string, Type> s2t = PopulateS2T();
- Dictionary<Type, string> t2s = new ();
- 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)
- {
- // internal fixed types like int and xmrarray etc
- if (type2String.TryGetValue(t, out string 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)
- {
- // internal fixed types like int and xmrarray etc
- if (string2Type.TryGetValue(s, out Type t))
- return t;
- // script-defined types
- if (s.StartsWith("sdt$"))
- return sdTypes[s[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;
- }
- }
|