Exemple #1
0
 public void EmitLoadAsPValue(CompilerState state)
 {
     switch (Interpretation)
     {
         case CompileTimeInterpretation.Null:
             state.EmitLoadNullAsPValue();
             break;
         case CompileTimeInterpretation.String:
             string stringValue;
             if (!TryGetString(out stringValue))
                 goto default;
             state.EmitLoadStringAsPValue(stringValue);
             break;
         case CompileTimeInterpretation.Int:
             int intValue;
             if (!TryGetInt(out intValue))
                 goto default;
             state.EmitLoadIntAsPValue(intValue);
             break;
         case CompileTimeInterpretation.Bool:
             bool boolValue;
             if (!TryGetBool(out boolValue))
                 goto default;
             state.EmitLoadBoolAsPValue(boolValue);
             break;
         case CompileTimeInterpretation.LocalVariableReference:
             EntityRef.Variable.Local localVariable;
             if (!TryGetLocalVariableReference(out localVariable))
                 goto default;
             state.EmitLoadLocalRefAsPValue(localVariable);
             break;
         case CompileTimeInterpretation.GlobalVariableReference:
             EntityRef.Variable.Global globalVariable;
             if (!TryGetGlobalVariableReference(out globalVariable))
                 goto default;
             state.EmitLoadGlobalRefAsPValue(globalVariable);
             break;
         case CompileTimeInterpretation.FunctionReference:
             EntityRef.Function func;
             if (!TryGetFunctionReference(out func))
                 goto default;
             state.EmitLoadFuncRefAsPValue(func);
             break;
         case CompileTimeInterpretation.CommandReference:
             EntityRef.Command command;
             if (!TryGetCommandReference(out command))
                 goto default;
             state.EmitLoadCmdRefAsPValue(command);
             break;
         default:
             throw new ArgumentOutOfRangeException();
     }
 }
Exemple #2
0
        private static void _emitInstructions(CompilerState state)
        {
            //Tables of foreach call hint hooks
            var foreachCasts = new Dictionary<int, ForeachHint>();
            var foreachGetCurrents = new Dictionary<int, ForeachHint>();
            var foreachMoveNexts = new Dictionary<int, ForeachHint>();
            var foreachDisposes = new Dictionary<int, ForeachHint>();

            foreach (var hint in state._ForeachHints)
            {
                foreachCasts.Add(hint.CastAddress, hint);
                foreachGetCurrents.Add(hint.GetCurrentAddress, hint);
                foreachMoveNexts.Add(hint.MoveNextAddress, hint);
                foreachDisposes.Add(hint.DisposeAddress, hint);
            }

            var sourceCode = state.Source.Code;

            //CIL Extension
            var cilExtensionMode = false;
            List<CompileTimeValue> staticArgv = null;

            for (var instructionIndex = 0; instructionIndex < sourceCode.Count; instructionIndex++)
            {
                #region Handling for try-finally-catch blocks

                //Handle try-finally-catch blocks
                //Push new blocks
                foreach (var block in state.Seh.GetOpeningTryBlocks(instructionIndex))
                {
                    state.TryBlocks.Push(block);
                    if (block.HasFinally)
                        state.Il.BeginExceptionBlock();
                    if (block.HasCatch)
                        state.Il.BeginExceptionBlock();
                }

                //Handle active blocks
                if (state.TryBlocks.Count > 0)
                {
                    CompiledTryCatchFinallyBlock block;
                    do
                    {
                        block = state.TryBlocks.Peek();
                        if (instructionIndex == block.BeginFinally)
                        {
                            if (block.SkipTry == instructionIndex)
                            {
                                //state.Il.MarkLabel(block.SkipTryLabel);
                                state.Il.Emit(OpCodes.Nop);
                            }
                            state.Il.BeginFinallyBlock();
                        }
                        else if (instructionIndex == block.BeginCatch)
                        {
                            if (block.HasFinally)
                                state.Il.EndExceptionBlock(); //end finally here
                            state.Il.BeginCatchBlock(typeof (Exception));
                            //parse the exception
                            state.EmitLoadLocal(state.SctxLocal);
                            state.Il.EmitCall(OpCodes.Call, Runtime.ParseExceptionMethod, null);
                            //user code will store it in a local variable
                        }
                        else if (instructionIndex == block.EndTry)
                        {
                            if (block.HasFinally || block.HasCatch)
                                state.Il.EndExceptionBlock();
                            if (block.SkipTry == instructionIndex)
                            {
                                //state.Il.MarkLabel(block.SkipTryLabel);
                                state.Il.Emit(OpCodes.Nop);
                            }
                            state.TryBlocks.Pop();
                            block = null; //signal another loop iteration
                        }
                    } while (block == null && state.TryBlocks.Count > 0);
                }

                #endregion

                state.MarkInstruction(instructionIndex);

                var ins = sourceCode[instructionIndex];

                #region CIL hints

                // **** CIL hints ****
                //  * CIL Extension *
                {
                    if (state._CilExtensionOffsets.Count > 0 &&
                        state._CilExtensionOffsets.Peek() == instructionIndex)
                    {
                        state._CilExtensionOffsets.Dequeue();
                        if (staticArgv == null)
                            staticArgv = new List<CompileTimeValue>(8);
                        else
                            staticArgv.Clear();
                        cilExtensionMode = true;
                    }
                    if (cilExtensionMode)
                    {
                        CompileTimeValue compileTimeValue;
                        if (CompileTimeValue.TryParse(ins, state.IndexMap, state.Cache, state.Source.ParentApplication.Module.Name, out compileTimeValue))
                        {
                            staticArgv.Add(compileTimeValue);
                        }
                        else
                        {
                            //found the actual invocation of the CIL extension
                            cilExtensionMode = false;

                            switch (ins.OpCode)
                            {
                                case OpCode.cmd:
                                    PCommand command;
                                    ICilExtension extension;
                                    if (
                                        !state.TargetEngine.Commands.TryGetValue(ins.Id, out command) ||
                                            (extension = command as ICilExtension) == null)
                                        goto default;

                                    extension.Implement(state, ins, staticArgv.ToArray(),
                                        ins.Arguments - staticArgv.Count);
                                    break;
                                default:
                                    throw new PrexoniteException(
                                        "The CIL compiler does not support CIL extensions for this opcode: " +
                                            ins);
                            }
                        }
                        continue;
                    }
                }
                //  * Foreach *
                {
                    ForeachHint hint;
                    if (foreachCasts.TryGetValue(instructionIndex, out hint))
                    {
                        //result of (expr).GetEnumerator on the stack
                        //cast IEnumerator
                        state.EmitLoadLocal(state.SctxLocal);
                        state.Il.EmitCall(OpCodes.Call, Runtime.ExtractEnumeratorMethod, null);
                        instructionIndex++;
                        //stloc enum
                        state.EmitStoreLocal(state.Symbols[hint.EnumVar].Local);
                        continue;
                    }
                    else if (foreachGetCurrents.TryGetValue(instructionIndex, out hint))
                    {
                        //ldloc enum
                        state.EmitLoadLocal(state.Symbols[hint.EnumVar].Local);
                        instructionIndex++;
                        //get.0 Current
                        state.Il.EmitCall(OpCodes.Callvirt, ForeachHint.GetCurrentMethod, null);
                        //result will be stored by user code
                        continue;
                    }
                    else if (foreachMoveNexts.TryGetValue(instructionIndex, out hint))
                    {
                        //ldloc enum
                        state.EmitLoadLocal(state.Symbols[hint.EnumVar].Local);
                        instructionIndex++;
                        //get.0 MoveNext
                        state.Il.EmitCall(OpCodes.Callvirt, ForeachHint.MoveNextMethod, null);
                        instructionIndex++;
                        //jump.t begin
                        var target = sourceCode[instructionIndex].Arguments; //read from user code
                        state.Il.Emit(OpCodes.Brtrue, state.InstructionLabels[target]);
                        continue;
                    }
                    else if (foreachDisposes.TryGetValue(instructionIndex, out hint))
                    {
                        //ldloc enum
                        state.EmitLoadLocal(state.Symbols[hint.EnumVar].Local);
                        instructionIndex++;
                        //@cmd.1 dispose
                        state.Il.EmitCall(OpCodes.Callvirt, ForeachHint.DisposeMethod, null);
                        continue;
                    }
                }

                #endregion

                //  * Normal code generation *
                //Decode instruction
                var argc = ins.Arguments;
                var justEffect = ins.JustEffect;
                var id = ins.Id;
                int idx;
                string methodId;
                string typeExpr;
                var moduleName = ins.ModuleName;

                //Emit code for the instruction
                switch (ins.OpCode)
                {
                        #region NOP

                        //NOP
                    case OpCode.nop:
                        //Do nothing
                        state.Il.Emit(OpCodes.Nop);
                        break;

                        #endregion

                        #region LOAD

                        #region LOAD CONSTANT

                        //LOAD CONSTANT
                    case OpCode.ldc_int:
                        state.EmitLoadIntAsPValue(argc);
                        break;
                    case OpCode.ldc_real:
                        state.EmitLoadRealAsPValue(ins);
                        break;
                    case OpCode.ldc_bool:
                        state.EmitLoadBoolAsPValue(argc != 0);
                        break;
                    case OpCode.ldc_string:
                        state.EmitLoadStringAsPValue(id);
                        break;

                    case OpCode.ldc_null:
                        state.EmitLoadNullAsPValue();
                        break;

                        #endregion LOAD CONSTANT

                        #region LOAD REFERENCE

                        //LOAD REFERENCE
                    case OpCode.ldr_loc:
                        state.EmitLoadLocalRefAsPValue(id);
                        break;
                    case OpCode.ldr_loci:
                        id = state.IndexMap[argc];
                        goto case OpCode.ldr_loc;
                    case OpCode.ldr_glob:
                        state.EmitLoadGlobalRefAsPValue(id, moduleName);
                        break;
                    case OpCode.ldr_func:
                        state.EmitLoadFuncRefAsPValue(id, moduleName);
                        break;
                    case OpCode.ldr_cmd:
                        state.EmitLoadCmdRefAsPValue(id);
                        break;
                    case OpCode.ldr_app:
                        CompilerState.EmitLoadAppRefAsPValue(state);
                        break;
                    case OpCode.ldr_eng:
                        state.EmitLoadEngRefAsPValue();
                        break;
                    case OpCode.ldr_type:
                        state.EmitPTypeAsPValue(id);
                        break;
                    case OpCode.ldr_mod:
                        state.EmitModuleNameAsPValue(moduleName);
                        break;

                        #endregion //LOAD REFERENCE

                        #endregion //LOAD

                        #region VARIABLES

                        #region LOCAL

                        //LOAD LOCAL VARIABLE
                    case OpCode.ldloc:
                        state.EmitLoadPValue(state.Symbols[id]);
                        break;
                    case OpCode.stloc:
                        //Don't use EmitStorePValue here, because this is a more efficient solution
                        var sym = state.Symbols[id];
                        if (sym.Kind == SymbolKind.Local)
                        {
                            state.EmitStoreLocal(sym.Local.LocalIndex);
                        }
                        else if (sym.Kind == SymbolKind.LocalRef)
                        {
                            state.EmitStoreLocal(state.PrimaryTempLocal.LocalIndex);
                            state.EmitLoadLocal(sym.Local.LocalIndex);
                            state.EmitLoadLocal(state.PrimaryTempLocal.LocalIndex);
                            state.Il.EmitCall(OpCodes.Call, SetValueMethod, null);
                        }
                        break;

                    case OpCode.ldloci:
                        id = state.IndexMap[argc];
                        goto case OpCode.ldloc;

                    case OpCode.stloci:
                        id = state.IndexMap[argc];
                        goto case OpCode.stloc;

                        #endregion

                        #region GLOBAL

                        //LOAD GLOBAL VARIABLE
                    case OpCode.ldglob:
                        state.EmitLoadGlobalValue(id, moduleName);
                        break;
                    case OpCode.stglob:
                        state.EmitStoreLocal(state.PrimaryTempLocal);
                        state.EmitLoadGlobalReference(id,moduleName);
                        state.EmitLoadLocal(state.PrimaryTempLocal);
                        state.Il.EmitCall(OpCodes.Call, SetValueMethod, null);
                        break;

                        #endregion

                        #endregion

                        #region CONSTRUCTION

                        //CONSTRUCTION
                    case OpCode.newobj:
                        state.EmitNewObj(id, argc);
                        break;
                    case OpCode.newtype:
                        state.FillArgv(argc);
                        state.EmitLoadLocal(state.SctxLocal);
                        state.ReadArgv(argc);
                        state.Il.Emit(OpCodes.Ldstr, id);
                        state.Il.EmitCall(OpCodes.Call, Runtime.NewTypeMethod, null);
                        break;

                    case OpCode.newclo:
                        //Collect shared variables
                        MetaEntry[] entries;
                        var func = state.Source.ParentApplication.Functions[id];
                        if (func.Meta.ContainsKey(PFunction.SharedNamesKey))
                            entries = func.Meta[PFunction.SharedNamesKey].List;
                        else
                            entries = new MetaEntry[] {};
                        var hasSharedVariables = entries.Length > 0;
                        if (hasSharedVariables)
                        {
                            state.EmitLdcI4(entries.Length);
                            state.Il.Emit(OpCodes.Newarr, typeof (PVariable));
                            state.EmitStoreLocal(state.SharedLocal);
                            for (var i = 0; i < entries.Length; i++)
                            {
                                state.EmitLoadLocal(state.SharedLocal);
                                state.EmitLdcI4(i);
                                state.EmitLoadLocal(state.Symbols[entries[i].Text].Local);
                                state.Il.Emit(OpCodes.Stelem_Ref);
                            }
                        }
                        state.EmitLoadLocal(state.SctxLocal);
                        if (hasSharedVariables)
                            state.EmitLoadLocal(state.SharedLocal);
                        else
                            state.Il.Emit(OpCodes.Ldnull);

                        state.EmitNewClo(id,moduleName);
                        break;

                    case OpCode.newcor:
                        state.FillArgv(argc);
                        state.EmitLoadLocal(state.SctxLocal);
                        state.ReadArgv(argc);
                        state.Il.EmitCall(OpCodes.Call, Runtime.NewCoroutineMethod, null);
                        break;

                        #endregion

                        #region OPERATORS

                        #region UNARY

                        //UNARY OPERATORS
                    case OpCode.incloc:
                        sym = state.Symbols[id];
                        if (sym.Kind == SymbolKind.Local)
                        {
                            state.EmitLoadLocal(sym.Local);
                            state.EmitLoadLocal(state.SctxLocal);
                            state.Il.EmitCall(OpCodes.Call, PVIncrementMethod, null);
                            state.EmitStoreLocal(sym.Local);
                        }
                        else if (sym.Kind == SymbolKind.LocalRef)
                        {
                            state.EmitLoadLocal(sym.Local);
                            state.Il.Emit(OpCodes.Dup);
                            state.Il.EmitCall(OpCodes.Call, GetValueMethod, null);
                            state.EmitLoadLocal(state.SctxLocal);
                            state.Il.EmitCall(OpCodes.Call, PVIncrementMethod, null);
                            state.Il.EmitCall(OpCodes.Call, SetValueMethod, null);
                        }
                        break;

                    case OpCode.incloci:
                        id = state.IndexMap[argc];
                        goto case OpCode.incloc;

                    case OpCode.incglob:
                        state.EmitLoadGlobalReference(id,moduleName);
                        state.Il.Emit(OpCodes.Dup);
                        state.Il.EmitCall(OpCodes.Call, GetValueMethod, null);
                        state.EmitLoadLocal(state.SctxLocal);
                        state.Il.EmitCall(OpCodes.Call, PVIncrementMethod, null);
                        state.Il.EmitCall(OpCodes.Call, SetValueMethod, null);
                        break;

                    case OpCode.decloc:
                        sym = state.Symbols[id];
                        if (sym.Kind == SymbolKind.Local)
                        {
                            state.EmitLoadLocal(sym.Local);
                            state.EmitLoadLocal(state.SctxLocal);
                            state.Il.EmitCall(OpCodes.Call, PVDecrementMethod, null);
                            state.EmitStoreLocal(sym.Local);
                        }
                        else if (sym.Kind == SymbolKind.LocalRef)
                        {
                            state.EmitLoadLocal(sym.Local);
                            state.Il.Emit(OpCodes.Dup);
                            state.Il.EmitCall(OpCodes.Call, GetValueMethod, null);
                            state.EmitLoadLocal(state.SctxLocal);
                            state.Il.EmitCall(OpCodes.Call, PVDecrementMethod, null);
                            state.Il.EmitCall(OpCodes.Call, SetValueMethod, null);
                        }
                        break;
                    case OpCode.decloci:
                        id = state.IndexMap[argc];
                        goto case OpCode.decloc;

                    case OpCode.decglob:
                        state.EmitLoadGlobalReference(id,moduleName);
                        state.Il.Emit(OpCodes.Dup);
                        state.Il.EmitCall(OpCodes.Call, GetValueMethod, null);
                        state.EmitLoadLocal(state.SctxLocal);
                        state.Il.EmitCall(OpCodes.Call, PVDecrementMethod, null);
                        state.Il.EmitCall(OpCodes.Call, SetValueMethod, null);
                        break;

                        #endregion

                        #region BINARY

                        // all binary operators are implemented as CIL extensions in
                        //  Prexonite.Commands.Core.Operators

                        #endregion //OPERATORS

                        #endregion

                        #region TYPE OPERATIONS

                        #region TYPE CHECK

                        //TYPE CHECK
                    case OpCode.check_const:
                        //Stack:
                        //  Obj
                        state.EmitLoadType(id);
                        //Stack:
                        //  Obj
                        //  Type
                        state.EmitCall(Runtime.CheckTypeConstMethod);
                        break;
                    case OpCode.check_arg:
                        //Stack: 
                        //  Obj
                        //  Type
                        state.Il.EmitCall(OpCodes.Call, Runtime.CheckTypeMethod, null);
                        break;

                    case OpCode.check_null:
                        state.Il.EmitCall(OpCodes.Call, PVIsNullMethod, null);
                        state.Il.Emit(OpCodes.Box, typeof (bool));
                        state.Il.EmitCall(OpCodes.Call, GetBoolPType, null);
                        state.Il.Emit(OpCodes.Newobj, NewPValue);
                        break;

                        #endregion

                        #region TYPE CAST

                    case OpCode.cast_const:
                        //Stack:
                        //  Obj
                        state.EmitLoadType(id);
                        //Stack:
                        //  Obj
                        //  Type
                        state.EmitLoadLocal(state.SctxLocal);
                        state.EmitCall(Runtime.CastConstMethod);

                        break;
                    case OpCode.cast_arg:
                        //Stack
                        //  Obj
                        //  Type
                        state.EmitLoadLocal(state.SctxLocal);
                        state.Il.EmitCall(OpCodes.Call, Runtime.CastMethod, null);
                        break;

                        #endregion

                        #endregion

                        #region OBJECT CALLS

                        #region DYNAMIC

                    case OpCode.get:
                        state.FillArgv(argc);
                        state.EmitLoadLocal(state.SctxLocal);
                        state.ReadArgv(argc);
                        state.EmitLdcI4((int) PCall.Get);
                        state.Il.Emit(OpCodes.Ldstr, id);
                        state.Il.EmitCall(OpCodes.Call, PVDynamicCallMethod, null);
                        if (justEffect)
                            state.Il.Emit(OpCodes.Pop);
                        break;

                    case OpCode.set:
                        state.FillArgv(argc);
                        state.EmitLoadLocal(state.SctxLocal);
                        state.ReadArgv(argc);
                        state.EmitLdcI4((int) PCall.Set);
                        state.Il.Emit(OpCodes.Ldstr, id);
                        state.Il.EmitCall(OpCodes.Call, PVDynamicCallMethod, null);
                        state.Il.Emit(OpCodes.Pop);
                        break;

                        #endregion

                        #region STATIC

                    case OpCode.sget:
                        //Stack:
                        //  arg
                        //   .
                        //   .
                        //   .
                        state.FillArgv(argc);
                        idx = id.LastIndexOf("::");
                        if (idx < 0)
                            throw new PrexoniteException
                                (
                                "Invalid sget instruction. Does not specify a method.");
                        methodId = id.Substring(idx + 2);
                        typeExpr = id.Substring(0, idx);
                        state.EmitLoadType(typeExpr);
                        state.EmitLoadLocal(state.SctxLocal);
                        state.ReadArgv(argc);
                        state.EmitLdcI4((int) PCall.Get);
                        state.Il.Emit(OpCodes.Ldstr, methodId);
                        state.EmitVirtualCall(Runtime.StaticCallMethod);
                        if (justEffect)
                            state.Il.Emit(OpCodes.Pop);
                        break;

                    case OpCode.sset:
                        state.FillArgv(argc);
                        idx = id.LastIndexOf("::");
                        if (idx < 0)
                            throw new PrexoniteException
                                (
                                "Invalid sset instruction. Does not specify a method.");
                        methodId = id.Substring(idx + 2);
                        typeExpr = id.Substring(0, idx);
                        state.EmitLoadType(typeExpr);
                        state.EmitLoadLocal(state.SctxLocal);
                        state.ReadArgv(argc);
                        state.EmitLdcI4((int) PCall.Set);
                        state.Il.Emit(OpCodes.Ldstr, methodId);
                        state.EmitVirtualCall(Runtime.StaticCallMethod);
                        state.Il.Emit(OpCodes.Pop);
                        break;

                        #endregion

                        #endregion

                        #region INDIRECT CALLS

                    case OpCode.indloc:
                        sym = state.Symbols[id];
                        if (sym == null)
                            throw new PrexoniteException(
                                "Internal CIL compiler error. Information about local entity " + id +
                                    " missing.");
                        state.FillArgv(argc);
                        sym.EmitLoad(state);
                        state.EmitIndirectCall(argc, justEffect);
                        break;

                    case OpCode.indloci:
                        idx = argc & ushort.MaxValue;
                        argc = (argc & (ushort.MaxValue << 16)) >> 16;
                        id = state.IndexMap[idx];
                        goto case OpCode.indloc;

                    case OpCode.indglob:
                        state.FillArgv(argc);
                        state.EmitLoadGlobalValue(id,moduleName);
                        state.EmitIndirectCall(argc, justEffect);
                        break;

                    case OpCode.indarg:
                        //Stack
                        //  obj
                        //  args
                        state.FillArgv(argc);
                        state.EmitIndirectCall(argc, justEffect);
                        break;

                    case OpCode.tail:
                        throw new PrexoniteException(
                            "Cannot compile tail instruction to CIL. Qualification should have failed.");

                        #endregion

                        #region ENGINE CALLS

                    case OpCode.func:
                        state.EmitFuncCall(argc, id, moduleName, justEffect);
                        break;
                    case OpCode.cmd:
                        state.EmitCommandCall(ins);
                        break;

                        #endregion

                        #region FLOW CONTROL

                        //FLOW CONTROL

                        #region JUMPS

                    case OpCode.jump:
                    case OpCode.jump_t:
                    case OpCode.jump_f:
                    case OpCode.ret_break:
                    case OpCode.ret_continue:
                        state.Seh.EmitJump(instructionIndex, ins);
                        break;

                        #endregion

                        #region RETURNS

                    case OpCode.ret_exit:
                        goto case OpCode.jump;

                    case OpCode.ret_value:
                        //return value is assigned by SEH
                        goto case OpCode.jump;

                    case OpCode.ret_set:
                        state.EmitSetReturnValue();
                        break;

                        #endregion

                        #region THROW

                    case OpCode.@throw:
                        state.EmitLoadLocal(state.SctxLocal);
                        state.Il.EmitCall(OpCodes.Call, Runtime.ThrowExceptionMethod, null);
                        break;

                        #endregion

                        #region LEAVE

                    case OpCode.@try:
                        //Is done via analysis of TryCatchFinally objects associated with the function
                        Debug.Assert(state.StackSize[instructionIndex] == 0,
                            "The stack should be empty when entering a try-block.",
                            "The stack is not empty when entering the try-block at instruction {0} in function {1}.",
                            instructionIndex, state.Source);
                        break;

                    case OpCode.leave:
                        //is handled by the CLR

                        #endregion

                        #region EXCEPTION

                    case OpCode.exc:
                        //is not implemented via Emit
                        // The exception is stored when the exception block is entered.
                        break;

                        #endregion

                        #endregion

                        #region STACK MANIPULATION

                        //STACK MANIPULATION
                    case OpCode.pop:
                        for (var i = 0; i < argc; i++)
                            state.Il.Emit(OpCodes.Pop);
                        break;
                    case OpCode.dup:
                        for (var i = 0; i < argc; i++)
                            state.Il.Emit(OpCodes.Dup);
                        break;
                    case OpCode.rot:
                        var values = (int) ins.GenericArgument;
                        var rotations = argc;
                        for (var i = 0; i < values; i++)
                            state.EmitStoreLocal
                                (
                                    state.TempLocals[(i + rotations)%values].LocalIndex);
                        for (var i = values - 1; i >= 0; i--)
                            state.EmitLoadLocal(state.TempLocals[i].LocalIndex);
                        break;

                        #endregion
                } //end of switch over opcode

                //DON'T ADD ANY CODE HERE, A LOT OF CASES USE `CONTINUE`
            } // end of loop over instructions

            //Close all pending try blocks, since the next instruction will never come
            //  (other closing try blocks are handled by the emitting the instruction immediately following 
            //  the try block)
            foreach (var block in state.TryBlocks)
            {
                if (block.HasCatch || block.HasFinally)
                    state.Il.EndExceptionBlock();
            }

            //Implicit return
            //Often instructions refer to a virtual instruction after the last real one.
            state.MarkInstruction(sourceCode.Count);
            state.Il.MarkLabel(state.ReturnLabel);
            state.Il.Emit(OpCodes.Ret);
        }