Exemple #1
0
        public virtual void Implement(CompilerState state, Instruction ins,
            CompileTimeValue[] staticArgv, int dynamicArgc)
        {
            if (dynamicArgc >= 2)
            {
                state.EmitIgnoreArguments(dynamicArgc - 2);
                state.EmitStoreLocal(state.PrimaryTempLocal);
                state.EmitLoadLocal(state.SctxLocal);
                state.EmitLoadLocal(state.PrimaryTempLocal);
            }
            else if (dynamicArgc == 1)
            {
                //we can load the second static arg just where we need it
                state.EmitLoadLocal(state.SctxLocal);
                staticArgv[0].EmitLoadAsPValue(state);
            }
            else
            {
                PValue left;
                PValue right;

                if (staticArgv[0].TryGetConstant(out left)
                    && staticArgv[1].TryGetConstant(out right))
                {
                    //Both operands are constants (remember: static args can also be references)
                    //=> Apply the operator at compile time.
                    var result = Run(state, new[] {left, right});
                    switch (result.Type.ToBuiltIn())
                    {
                        case PType.BuiltIn.Real:
                            state.EmitLoadRealAsPValue((double) result.Value);
                            break;
                        case PType.BuiltIn.Int:
                            state.EmitLoadIntAsPValue((int) result.Value);
                            break;
                        case PType.BuiltIn.String:
                            state.EmitLoadStringAsPValue((string) result.Value);
                            break;
                        case PType.BuiltIn.Null:
                            state.EmitLoadNullAsPValue();
                            break;
                        case PType.BuiltIn.Bool:
                            state.EmitLoadBoolAsPValue((bool) result.Value);
                            break;
                        default:
                            throw new PrexoniteException(
                                string.Format(
                                    "The operation {0} is no implemented correctly. Given {1} and {2} it results in the non-constant {3}",
                                    GetType().FullName, left, right, result));
                    }
                    return; //We've already emitted the result. 
                }
                else
                {
                    //Load the first operand now, then proceed like for just one static arg
                    staticArgv[0].EmitLoadAsPValue(state);
                    state.EmitLoadLocal(state.SctxLocal);
                    staticArgv[1].EmitLoadAsPValue(state);
                }
            }

            state.Il.EmitCall(OpCodes.Call, OperationMethod, null);
        }
Exemple #2
0
        private static void _createAndInitializeRemainingLocals(CompilerState state)
        {
            var nullLocals = new List<LocalBuilder>();

            //Create remaining local variables and initialize them
            foreach (var pair in state.Symbols)
            {
                var id = pair.Key;
                var sym = pair.Value;
                if (sym.Local != null)
                    continue;

                switch (sym.Kind)
                {
                    case SymbolKind.Local:
                        {
                            sym.Local = state.Il.DeclareLocal(typeof (PValue));
                            var initVal = _getVariableInitialization(state, id, false);
                            switch (initVal)
                            {
                                case VariableInitialization.ArgV:
                                    _emitLoadArgV(state);
                                    state.EmitStoreLocal(sym.Local);
                                    break;
                                case VariableInitialization.Null:
                                    nullLocals.Add(sym.Local); //defer assignment
                                    break;

                                    // ReSharper disable RedundantCaseLabel
                                case VariableInitialization.None:
                                    // ReSharper restore RedundantCaseLabel
                                default:
                                    break;
                            }
                        }
                        break;
                    case SymbolKind.LocalRef:
                        {
                            sym.Local = state.Il.DeclareLocal(typeof (PVariable));
                            var initVal = _getVariableInitialization(state, id, true);

                            var idx = sym.Local.LocalIndex;

                            state.Il.Emit(OpCodes.Newobj, NewPVariableCtor);

                            if (initVal != VariableInitialization.None)
                            {
                                state.Il.Emit(OpCodes.Dup);
                                state.EmitStoreLocal(idx);

                                switch (initVal)
                                {
                                    case VariableInitialization.ArgV:
                                        _emitLoadArgV(state);
                                        break;
                                    case VariableInitialization.Null:
                                        state.EmitLoadNullAsPValue();
                                        break;

                                    default:
                                        break;
                                }
                                state.Il.EmitCall(OpCodes.Call, SetValueMethod, null);
                            }
                            else
                            {
                                state.EmitStoreLocal(idx);
                            }
                        }
                        break;
                    case SymbolKind.LocalEnum:
                        {
                            sym.Local = state.Il.DeclareLocal(typeof (IEnumerator<PValue>));
                            //No initialization needed.
                        }
                        break;
                    default:
                        throw new PrexoniteException("Cannot initialize unknown symbol kind.");
                }
            }

            //Initialize null locals
            var nullCount = nullLocals.Count;
            if (nullCount > 0)
            {
                state.EmitLoadNullAsPValue();
                for (var i = 0; i < nullCount; i++)
                {
                    var local = nullLocals[i];
                    if (i + 1 != nullCount)
                        state.Il.Emit(OpCodes.Dup);
                    state.EmitStoreLocal(local);
                }
            }
        }
Exemple #3
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);
        }
Exemple #4
0
        private static void _parseParameters(CompilerState state)
        {
            for (var i = 0; i < state.Source.Parameters.Count; i++)
            {
                var id = state.Source.Parameters[i];
                var sym = state.Symbols[id];
                LocalBuilder local;

                //Determine whether local variables for parameters have already been created and create them if necessary
                switch (sym.Kind)
                {
                    case SymbolKind.Local:
                        local = sym.Local ?? state.Il.DeclareLocal(typeof (PValue));
                        break;
                    case SymbolKind.LocalRef:
                        if (sym.Local == null)
                        {
                            local = state.Il.DeclareLocal(typeof (PVariable));
                            state.Il.Emit(OpCodes.Newobj, NewPVariableCtor);
                            state.EmitStoreLocal(local);
                            //PVariable objects already contain PValue.Null and need not be initialized if no
                            //  argument has been passed.
                        }
                        else
                        {
                            local = sym.Local;
                        }
                        break;
                    default:
                        throw new PrexoniteException("Cannot create variable to represent symbol");
                }

                sym.Local = local;

                var hasArg = state.Il.DefineLabel();
                var end = state.Il.DefineLabel();

                if (sym.Kind == SymbolKind.Local) // var = idx < len ? args[idx] : null;
                {
                    //The closure below is only accessed once. The capture is therefore transparent.
                    // ReSharper disable AccessToModifiedClosure
                    state.EmitStorePValue
                        (
                            sym,
                            delegate
                                {
                                    //(idx < argc) ? args[idx] : null; 
                                    state.EmitLdcI4(i);
                                    state.EmitLoadLocal(state.ArgcLocal);
                                    state.Il.Emit(OpCodes.Blt_S, hasArg);
                                    state.EmitLoadNullAsPValue();
                                    state.Il.Emit(OpCodes.Br_S, end);
                                    state.Il.MarkLabel(hasArg);
                                    state.EmitLoadArg(CompilerState.ParamArgsIndex);
                                    state.EmitLdcI4(i);
                                    state.Il.Emit(OpCodes.Ldelem_Ref);
                                    state.Il.MarkLabel(end);
                                }
                        );
                    // ReSharper restore AccessToModifiedClosure
                }
                else // if(idx < len) var = args[idx];
                {
                    state.EmitLdcI4(i);
                    state.EmitLoadLocal(state.ArgcLocal);
                    state.Il.Emit(OpCodes.Bge_S, end);

                    //The following closure is only accessed once. The capture is therefore transparent.
                    // ReSharper disable AccessToModifiedClosure
                    state.EmitStorePValue
                        (
                            sym,
                            delegate
                                {
                                    state.EmitLoadArg(CompilerState.ParamArgsIndex);
                                    state.EmitLdcI4(i);
                                    state.Il.Emit(OpCodes.Ldelem_Ref);
                                });
                    // ReSharper restore AccessToModifiedClosure
                    state.Il.MarkLabel(end);
                }
            }
        }
Exemple #5
0
        private static void _analysisAndPreparation(CompilerState state)
        {
            var tempMaxOrder = 1; // 
            var needsSharedVariables = false;

            foreach (var ins in state.Source.Code.InReverse())
            {
                string toConvert;
                switch (ins.OpCode)
                {
                    case OpCode.ldr_loci:
                        //see ldr_loc
                        toConvert = state.IndexMap[ins.Arguments];
                        goto Convert;
                    case OpCode.ldr_loc:
                        toConvert = ins.Id;
                        Convert:

                        //Normal local variables are implemented as CIL locals.
                        // If the function uses variable references, they must be converted to reference variables.
                        state.Symbols[toConvert].Kind = SymbolKind.LocalRef;
                        break;
                    case OpCode.rot:
                        //Determine the maximum number of temporary variables for the implementation of rot[ate]
                        var order = (int) ins.GenericArgument;
                        if (order > tempMaxOrder)
                            tempMaxOrder = order;
                        break;
                    case OpCode.newclo:
                        MetaEntry[] entries;
                        var func = state.Source.ParentApplication.Functions[ins.Id];
                        MetaEntry entry;
                        if (func.Meta.ContainsKey(PFunction.SharedNamesKey) &&
                            (entry = func.Meta[PFunction.SharedNamesKey]).IsList)
                            entries = entry.List;
                        else
                            entries = new MetaEntry[] {};
                        foreach (var t in entries)
                        {
                            var symbolName = t.Text;
                            if (!state.Symbols.ContainsKey(symbolName))
                                throw new PrexoniteException
                                    (func + " does not contain a mapping for the symbol " +
                                        symbolName);

                            //In order for variables to be shared, they too, need to be converted to reference locals.
                            state.Symbols[symbolName].Kind = SymbolKind.LocalRef;
                        }

                        //Notify the compiler of the presence of closures with shared variables
                        needsSharedVariables = needsSharedVariables || entries.Length > 0;
                        break;
                }
            }

            //Create temporary variables for rotation
            state.TempLocals = new LocalBuilder[tempMaxOrder];
            for (var i = 0; i < tempMaxOrder; i++)
            {
                var rotTemp = state.Il.DeclareLocal(typeof (PValue));
                state.TempLocals[i] = rotTemp;
            }

            //Create temporary variable for argv and sharedVariables
            state.ArgvLocal = state.Il.DeclareLocal(typeof (PValue[]));
            state.SharedLocal = needsSharedVariables
                ? state.Il.DeclareLocal(typeof (PVariable[]))
                : null;

            //Create argc local variable and initialize it, if needed
            if (state.Source.Parameters.Count > 0)
            {
                state.ArgcLocal = state.Il.DeclareLocal(typeof (Int32));
                state.EmitLoadArg(CompilerState.ParamArgsIndex);
                state.Il.Emit(OpCodes.Ldlen);
                state.Il.Emit(OpCodes.Conv_I4);
                state.EmitStoreLocal(state.ArgcLocal);
            }

            //Determine stack size at every instruction
            _determineStackSize(state);
        }
Exemple #6
0
        private static void _buildSymbolTable(CompilerState state)
        {
            //Create local ref variables for shared names
            //  and populate them with the contents of the sharedVariables parameter
            if (state.Source.Meta.ContainsKey(PFunction.SharedNamesKey))
            {
                var sharedNames = state.Source.Meta[PFunction.SharedNamesKey].List;
                for (var i = 0; i < sharedNames.Length; i++)
                {
                    if (state.Source.Variables.Contains(sharedNames[i]))
                        continue; //Arguments are redeclarations.
                    var sym = new CilSymbol(SymbolKind.LocalRef)
                        {
                            Local = state.Il.DeclareLocal(typeof (PVariable))
                        };
                    var id = sharedNames[i].Text;

                    state.EmitLoadArg(CompilerState.ParamSharedVariablesIndex);
                    state.Il.Emit(OpCodes.Ldc_I4, i);
                    state.Il.Emit(OpCodes.Ldelem_Ref);
                    state.EmitStoreLocal(sym.Local.LocalIndex);

                    state.Symbols.Add(id, sym);
                }
            }

            //Create index -> id map
            foreach (var mapping in state.Source.LocalVariableMapping)
                state.IndexMap.Add(mapping.Value, mapping.Key);

            //Add entries for paramters
            foreach (var parameter in state.Source.Parameters)
                if (!state.Symbols.ContainsKey(parameter))
                    state.Symbols.Add(parameter, new CilSymbol(SymbolKind.Local));

            //Add entries for enumerator variables
            foreach (var hint in state._ForeachHints)
            {
                if (state.Symbols.ContainsKey(hint.EnumVar))
                    throw new PrexoniteException(
                        "Invalid foreach hint. Enumerator variable is shared.");
                state.Symbols.Add(hint.EnumVar, new CilSymbol(SymbolKind.LocalEnum));
            }

            //Add entries for non-shared local variables
            foreach (var variable in state.Source.Variables)
                if (!state.Symbols.ContainsKey(variable))
                    state.Symbols.Add(variable, new CilSymbol(SymbolKind.Local));
        }
Exemple #7
0
        private static void _emitCilImplementationHeader(CompilerState state)
        {
            //Create local cil function stack context
            //  CilFunctionContext cfctx = CilFunctionContext.New(sctx, source);
            state.SctxLocal = state.Il.DeclareLocal(typeof (CilFunctionContext));
            state.EmitLoadArg(CompilerState.ParamSctxIndex);
            state.EmitLoadArg(CompilerState.ParamSourceIndex);
            state.Il.EmitCall(OpCodes.Call, CilFunctionContext.NewMethod, null);
            state.EmitStoreLocal(state.SctxLocal.LocalIndex);

            //Initialize result and assign default return mode
            //  Result = null;
            state._EmitAssignReturnMode(ReturnMode.Exit);
            state.EmitLoadArg(CompilerState.ParamResultIndex);
            state.EmitLoadNullAsPValue();
            state.Il.Emit(OpCodes.Stind_Ref);
        }
Exemple #8
0
        void ICilExtension.Implement(CompilerState state, Instruction ins,
            CompileTimeValue[] staticArgv, int dynamicArgc)
        {
            foreach (var compileTimeValue in staticArgv)
            {
                EntityRef.Variable.Local local;
                if (!compileTimeValue.TryGetLocalVariableReference(out local))
                    throw new ArgumentException(
                        "CIL implementation of Core.Unbind command only accepts local variable references.",
                        "staticArgv");

                CilSymbol cilSymbol;
                if (!state.Symbols.TryGetValue(local.Id, out cilSymbol) ||
                    cilSymbol.Kind != SymbolKind.LocalRef)
                    throw new PrexoniteException(
                        string.Format("CIL implementation of {1} cannot find local explicit variable {0}", local.Id, GetType().FullName));

                //Create new PVariable
                state.Il.Emit(OpCodes.Newobj, Compiler.Cil.Compiler.NewPVariableCtor);
                state.Il.Emit(OpCodes.Dup);

                //Copy old value
                state.EmitLoadPValue(cilSymbol);
                state.EmitCall(Compiler.Cil.Compiler.SetValueMethod);

                //Override variable slot
                state.EmitStoreLocal(cilSymbol.Local);
            }

            if (!ins.JustEffect)
                state.EmitLoadNullAsPValue();
        }