Exemplo n.º 1
0
        // Try to create object code from source code
        // If error, just throw exception
        private ScriptObjCode TryToCompile()
        {
            m_CompilerErrors.Clear();

            /*
             * If object file exists, create ScriptObjCode directly from that.
             * Otherwise, compile the source to create object file then create
             * ScriptObjCode from that.
             */
            string assetID = m_Item.AssetID.ToString();

            m_CameFrom = "asset://" + assetID;
            ScriptObjCode objCode = Compile();

            if (m_CompilerErrors.Count != 0)
            {
                throw new Exception("compilation errors");
            }
            if (objCode == null)
            {
                throw new Exception("compilation failed");
            }

            return(objCode);
        }
Exemplo n.º 2
0
        /**
         * @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> ();
            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 = (ilGen != null) ? ilGen.ILOffset : 0;

                /*
                 * 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();

                    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;
                    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());
                }
            }
        }
Exemplo n.º 3
0
        /**
         * @brief Compile a script to produce a ScriptObjCode object
         * @returns object code pointer or null if compile error
         *          also can throw compile error exception
         */
        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))
            {
                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);
                }

                /*
                 * 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);
                    saveSource = File.CreateText(lslFileName);
                }

                /*
                 * Parse source string into tokens.
                 */
                TokenBegin tokenBegin;
                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);
                    return(null);
                }

                /*
                 * Create object file one way or another.
                 */
                try {
                    objFileStream = File.Create(tmpFileName);

                    /*
                     * Create abstract syntax tree from raw tokens.
                     */
                    TokenScript tokenScript = ScriptReduce.Reduce(tokenBegin);
                    if (tokenScript == null)
                    {
                        m_log.Warn("[XMREngine]: reduction errors on " + m_ScriptObjCodeKey + " (" + m_CameFrom + ")");
                        PrintCompilerErrors();
                        return(null);
                    }

                    /*
                     * 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 + ")");
                        PrintCompilerErrors();
                        objFileStream.Close();
                        return(null);
                    }
                    objFileStream.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.Replace(tmpFileName, objFileName, null);
                    }
                    else
                    {
                        File.Move(tmpFileName, objFileName);
                    }
                    objFileStream = File.OpenRead(objFileName);
                } finally {
                    /*
                     * In case something went wrong writing temp file, delete it.
                     */
                    try {
                        File.Delete(tmpFileName);
                    } 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);
                    asmFileWriter = File.CreateText(asmFileName);
                }
            }

            /*
             * 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 {
                scriptObjCode = new ScriptObjCode(objFileReader, asmFileWriter, null);
                if (scriptObjCode != null)
                {
                    scriptObjCode.fileDateUtc = File.GetLastWriteTimeUtc(objFileName);
                }
            } finally {
                objFileReader.Close();
                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);
        }