Пример #1
0
        protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
        {
            //Jumps need special treatment for label resolution

            if (Instruction.Arguments == -1)
            {
                switch (Instruction.OpCode)
                {
                    case OpCode.jump:
                        target.EmitJump(Position, Instruction.Id);
                        break;
                    case OpCode.jump_t:
                        target.EmitJumpIfTrue(Position, Instruction.Id);
                        break;
                    case OpCode.jump_f:
                        target.EmitJumpIfFalse(Position, Instruction.Id);
                        break;
                    case OpCode.leave:
                        target.EmitLeave(Position, Instruction.Id);
                        break;
                    default:
                        goto emitNormally;
                }
            }
            else
                goto emitNormally;

            return;
            emitNormally:
            target.Emit(Position, Instruction);
        }
Пример #2
0
 protected override void DoEmitCode(CompilerTarget target, string trueLabel,
     string falseLabel)
 {
     var labelNs = @"Or\" + Guid.NewGuid().ToString("N");
     var nextLabel = @"Next\" + labelNs;
     foreach (var expr in Conditions)
     {
         var and = expr as AstLogicalAnd;
         if (and != null)
         {
             and.EmitCode(target, trueLabel, nextLabel);
             //ResolveOperator pending jumps to Next
             target.EmitLabel(Position, nextLabel);
             target.FreeLabel(nextLabel);
             //Future references of to nextLabel will be resolved in the next iteration
         }
         else
         {
             expr.EmitValueCode(target);
             target.EmitJumpIfTrue(Position, trueLabel);
         }
     }
     target.EmitJump(Position, falseLabel);
 }
Пример #3
0
 public static void EmitJumpCondition(
     CompilerTarget target,
     AstExpr cond,
     string targetLabel,
     string alternativeLabel,
     bool isPositive)
 {
     if (cond == null)
         throw new ArgumentNullException("cond", Resources.AstLazyLogical__Condition_must_not_be_null);
     if (target == null)
         throw new ArgumentNullException("target", Resources.AstNode_Compiler_target_must_not_be_null);
     if (String.IsNullOrEmpty(targetLabel))
         throw new ArgumentException(
             Resources.AstLazyLogical__targetLabel_must_neither_be_null_nor_empty, "targetLabel");
     if (String.IsNullOrEmpty(alternativeLabel))
         throw new ArgumentException(
             Resources.AstLazyLogical_alternativeLabel_may_neither_be_null_nor_empty, "alternativeLabel");
     var logical = cond as AstLazyLogical;
     if (!isPositive)
     {
         //Invert if needed
         var tmpLabel = alternativeLabel;
         alternativeLabel = targetLabel;
         targetLabel = tmpLabel;
     }
     if (logical != null)
     {
         logical.EmitCode(target, targetLabel, alternativeLabel);
     }
     else
     {
         cond.EmitValueCode(target);
         target.EmitJumpIfTrue(cond.Position, targetLabel);
         target.EmitJump(cond.Position, alternativeLabel);
     }
 }
Пример #4
0
        protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
        {
            if(stackSemantics == StackSemantics.Value)
                throw new NotSupportedException("Foreach loops don't produce values and can thus not be emitted with value semantics.");

            if (!IsInitialized)
                throw new PrexoniteException("AstForeachLoop requires List and Element to be set.");

            //Optimize expression
            _OptimizeNode(target, ref List);

            //Create the enumerator variable
            var enumVar = Block.CreateLabel("enumerator");
            target.Function.Variables.Add(enumVar);

            //Create the element assignment statement
            var element = Element.GetCopy();
            AstExpr optElem;
            if (element.TryOptimize(target, out optElem))
            {
                element = optElem as AstGetSet;
                if (element == null)
                {
                    target.Loader.ReportMessage(Message.Error(Resources.AstForeachLoop_DoEmitCode_ElementTooComplicated,Position,MessageClasses.ForeachElementTooComplicated));
                    return;
                }
            }
            var ldEnumVar = target.Factory.Call(Position, EntityRef.Variable.Local.Create(enumVar));
            var getCurrent =
                new AstGetSetMemberAccess(File, Line, Column, ldEnumVar, "Current");
            element.Arguments.Add(getCurrent);
            element.Call = PCall.Set;

            //Actual Code Generation
            var moveNextAddr = -1;
            var getCurrentAddr = -1;
            var disposeAddr = -1;

            //Get the enumerator
            target.BeginBlock(Block);

            List.EmitValueCode(target);
            target.EmitGetCall(List.Position, 0, "GetEnumerator");
            var castAddr = target.Code.Count;
            target.Emit(List.Position, OpCode.cast_const, "Object(\"System.Collections.IEnumerator\")");
            target.EmitStoreLocal(List.Position, enumVar);

            //check whether an enhanced CIL implementation is possible
            bool emitHint;
            if (element.DefaultAdditionalArguments + element.Arguments.Count > 1)
                //has additional arguments
                emitHint = false;
            else
                emitHint = true;

            var @try = new AstTryCatchFinally(Position, Block);

            @try.TryBlock = new AstActionBlock
                (
                Position, @try,
                delegate
                    {
                        target.EmitJump(Position, Block.ContinueLabel);

                        //Assignment (begin)
                        target.EmitLabel(Position, Block.BeginLabel);
                        getCurrentAddr = target.Code.Count;
                        element.EmitEffectCode(target);

                        //Code block
                        Block.EmitEffectCode(target);

                        //Condition (continue)
                        target.EmitLabel(Position, Block.ContinueLabel);
                        moveNextAddr = target.Code.Count;
                        target.EmitLoadLocal(List.Position, enumVar);
                        target.EmitGetCall(List.Position, 0, "MoveNext");
                        target.EmitJumpIfTrue(Position, Block.BeginLabel);

                        //Break
                        target.EmitLabel(Position, Block.BreakLabel);
                    });
            @try.FinallyBlock = new AstActionBlock
                (
                Position, @try,
                delegate
                    {
                        disposeAddr = target.Code.Count;
                        target.EmitLoadLocal(List.Position, enumVar);
                        target.EmitCommandCall(List.Position, 1, Engine.DisposeAlias, true);
                    });
                

            @try.EmitEffectCode(target);

            target.EndBlock();

            if (getCurrentAddr < 0 || moveNextAddr < 0 || disposeAddr < 0)
                throw new PrexoniteException(
                    "Could not capture addresses within foreach construct for CIL compiler hint.");
            else if (emitHint)
            {
                var hint = new ForeachHint(enumVar, castAddr, getCurrentAddr, moveNextAddr,
                    disposeAddr);
                Cil.Compiler.AddCilHint(target, hint);

                Action<int, int> mkHook =
                    (index, original) =>
                        {
                            AddressChangeHook hook = null;
                            hook = new AddressChangeHook(
                                original,
                                newAddr =>
                                    {
                                        foreach (
                                            var hintEntry in target.Meta[Loader.CilHintsKey].List)
                                        {
                                            var entry = hintEntry.List;
                                            if (entry[0] == ForeachHint.Key &&
                                                entry[index].Text == original.ToString(CultureInfo.InvariantCulture))
                                            {
                                                entry[index] = newAddr.ToString(CultureInfo.InvariantCulture);
                                                // AddressChangeHook.ctor can be trusted not to call the closure.
                                                // ReSharper disable PossibleNullReferenceException
                                                // ReSharper disable AccessToModifiedClosure
                                                hook.InstructionIndex = newAddr;
                                                // ReSharper restore AccessToModifiedClosure
                                                // ReSharper restore PossibleNullReferenceException
                                                original = newAddr;
                                            }
                                        }
                                    });
                            target.AddressChangeHooks.Add(hook);
                        };

                mkHook(ForeachHint.CastAddressIndex + 1, castAddr);
                mkHook(ForeachHint.GetCurrentAddressIndex + 1, getCurrentAddr);
                mkHook(ForeachHint.MoveNextAddressIndex + 1, moveNextAddr);
                mkHook(ForeachHint.DisposeAddressIndex + 1, disposeAddr);
            } // else nothing
        }
Пример #5
0
 /// <summary>
 ///     Emit the jump code for an if-like condition (jump if true). Recognizes and takes advantage of lazy logical expressions.
 /// </summary>
 /// <param name = "target">The compiler target to emit code to.</param>
 /// <param name = "cond">The condition of the jump.</param>
 /// <param name = "targetLabel">The target of the conditional jump.</param>
 public static void EmitJumpIfCondition(
     CompilerTarget target, AstExpr cond, string targetLabel)
 {
     if (cond == null)
         throw new ArgumentNullException("cond", Resources.AstLazyLogical__Condition_must_not_be_null);
     if (target == null)
         throw new ArgumentNullException("target", Resources.AstNode_Compiler_target_must_not_be_null);
     if (String.IsNullOrEmpty(targetLabel))
         throw new ArgumentException(
             Resources.AstLazyLogical__targetLabel_must_neither_be_null_nor_empty, "targetLabel");
     var logical = cond as AstLazyLogical;
     if (logical != null)
     {
         var continueLabel = "Continue\\Lazy\\" + Guid.NewGuid().ToString("N");
         logical.EmitCode(target, targetLabel, continueLabel);
         target.EmitLabel(cond.Position, continueLabel);
     }
     else
     {
         cond.EmitValueCode(target);
         target.EmitJumpIfTrue(cond.Position, targetLabel);
     }
 }