예제 #1
0
        protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
        {
            var labelNs = @"Or\" + Guid.NewGuid().ToString("N");
            var trueLabel = @"True\" + labelNs;
            var falseLabel = @"False\" + labelNs;
            var evalLabel = @"Eval\" + labelNs;

            EmitCode(target, trueLabel, falseLabel);

            if (stackSemantics == StackSemantics.Value)
            {
                target.EmitLabel(Position, falseLabel);
                target.EmitConstant(Position, false);
                target.EmitJump(Position, evalLabel);
                target.EmitLabel(Position, trueLabel);
                target.EmitConstant(Position, true);
                target.EmitLabel(Position, evalLabel);
            }
            else
            {
                Debug.Assert(stackSemantics == StackSemantics.Effect);
                target.EmitLabel(Position, falseLabel);
                target.EmitLabel(Position, trueLabel);
            }
        }
예제 #2
0
        protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
        {
            if(stackSemantics == StackSemantics.Value)
                throw new NotSupportedException("While loops do not produce values and can thus not be used as expressions.");
            if (!IsInitialized)
                throw new PrexoniteException("AstWhileLoop requires Condition to be set.");

            //Optimize unary not condition
            _OptimizeNode(target, ref Condition);
            // Invert condition when unary logical not
            AstIndirectCall unaryCond;
            while (Condition.IsCommandCall(Commands.Core.Operators.LogicalNot.DefaultAlias, out unaryCond))
            {
                Condition = unaryCond.Arguments[0];
                IsPositive = !IsPositive;
            }

            //Constant conditions
            var conditionIsConstant = false;
            if (Condition is AstConstant)
            {
                var constCond = (AstConstant) Condition;
                PValue condValue;
                if (
                    !constCond.ToPValue(target).TryConvertTo(
                        target.Loader, PType.Bool, out condValue))
                    goto continueFull;
                else if ((bool) condValue.Value == IsPositive)
                    conditionIsConstant = true;
                else
                {
                    //Condition is always false
                    if (!IsPrecondition) //If do-while, emit the body without loop code
                    {
                        target.BeginBlock(Block);
                        Block.EmitEffectCode(target);
                        target.EndBlock();
                    }
                    return;
                }
            }
            continueFull:

            target.BeginBlock(Block);
            if (!Block.IsEmpty) //Body exists -> complete loop code?
            {
                if (conditionIsConstant) //Infinite, hopefully user managed, loop ->
                {
                    target.EmitLabel(Position, Block.ContinueLabel);
                    target.EmitLabel(Position, Block.BeginLabel);
                    Block.EmitEffectCode(target);
                    target.EmitJump(Position, Block.ContinueLabel);
                }
                else
                {
                    if (IsPrecondition)
                        target.EmitJump(Position, Block.ContinueLabel);

                    target.EmitLabel(Position, Block.BeginLabel);
                    Block.EmitEffectCode(target);

                    _emitCondition(target);
                }
            }
            else //Body does not exist -> Condition loop
            {
                target.EmitLabel(Position, Block.BeginLabel);
                _emitCondition(target);
            }

            target.EmitLabel(Position, Block.BreakLabel);
            target.EndBlock();
        }
예제 #3
0
 private void _emitCondition(CompilerTarget target)
 {
     target.EmitLabel(Position, Block.ContinueLabel);
     AstLazyLogical.EmitJumpCondition(target, Condition, Block.BeginLabel, IsPositive);
 }
예제 #4
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);
 }
예제 #5
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
        }
예제 #6
0
        protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
        {
            if(stackSemantics == StackSemantics.Value)
                throw new NotSupportedException("Try-catch-finally blocks cannot be used with value stack semantics (They don't produce values)");

            var prefix = "try\\" + Guid.NewGuid().ToString("N") + "\\";
            var beginTryLabel = prefix + "beginTry";
            var beginFinallyLabel = prefix + "beginFinally";
            var beginCatchLabel = prefix + "beginCatch";
            var endTry = prefix + "endTry";

            if (TryBlock.IsEmpty)
                if (FinallyBlock.IsEmpty)
                    return;
                else
                {
                    //The finally block is not protected
                    //  A trycatchfinally with just a finally block is equivalent to the contents of the finally block
                    //  " try {} finally { $code } " => " $code "
                    FinallyBlock.EmitEffectCode(target);
                    return;
                }

            //Emit try block
            target.EmitLabel(Position, beginTryLabel);
            target.Emit(Position,OpCode.@try);
            TryBlock.EmitEffectCode(target);

            //Emit finally block
            target.EmitLabel(FinallyBlock.Position, beginFinallyLabel);
            var beforeEmit = target.Code.Count;
            FinallyBlock.EmitEffectCode(target);
            if (FinallyBlock.Count > 0 && target.Code.Count == beforeEmit)
                target.Emit(FinallyBlock.Position, OpCode.nop);
            target.EmitLeave(FinallyBlock.Position, endTry);

            //Emit catch block
            target.EmitLabel(CatchBlock.Position, beginCatchLabel);
            var usesException = ExceptionVar != null;
            var justRethrow = CatchBlock.IsEmpty && !usesException;

            if (usesException)
            {
                //Assign exception
                ExceptionVar = _GetOptimizedNode(target, ExceptionVar) as AstGetSet ?? ExceptionVar;
                ExceptionVar.Arguments.Add(new AstGetException(File, Line, Column));
                ExceptionVar.Call = PCall.Set;
                ExceptionVar.EmitEffectCode(target);
            }

            if (!justRethrow)
            {
                //Exception handled
                CatchBlock.EmitEffectCode(target);
            }
            else
            {
                //Exception not handled => rethrow.
                // * Rethrow is implemented in the runtime *
                //AstThrow th = new AstThrow(File, Line, Column);
                //th.Expression = new AstGetException(File, Line, Column);
                //th.EmitCode(target);
            }

            target.EmitLabel(Position, endTry);
            target.Emit(Position,OpCode.nop);

            var block =
                new TryCatchFinallyBlock(
                    _getAddress(target, beginTryLabel), _getAddress(target, endTry))
                    {
                        BeginFinally =
                            (!FinallyBlock.IsEmpty ? _getAddress(target, beginFinallyLabel) : -1),
                        BeginCatch = (!justRethrow ? _getAddress(target, beginCatchLabel) : -1),
                        UsesException = usesException
                    };

            //Register try-catch-finally block
            target.Function.Meta.AddTo(TryCatchFinallyBlock.MetaKey, block);
            target.Function.InvalidateTryCatchFinallyBlocks();
        }
예제 #7
0
파일: AstForLoop.cs 프로젝트: SealedSun/prx
        protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
        {
             if(stackSemantics == StackSemantics.Value)
                throw new NotSupportedException("For loops don't produce values and can thus not be emitted with value semantics.");

            if (!IsInitialized)
                throw new PrexoniteException("AstForLoop requires Condition to be set.");

            //Optimize unary not condition
            var condition = Condition;

            _OptimizeNode(target, ref condition);
            // Invert condition when unary logical not
            AstIndirectCall unaryCond;
            while (Condition.IsCommandCall(Commands.Core.Operators.LogicalNot.DefaultAlias, out unaryCond))
            {
                Condition = unaryCond.Arguments[0];
                IsPositive = !IsPositive;
            }

            //Constant conditions
            var conditionIsConstant = false;
            var constCond = condition as AstConstant;
            if (constCond != null)
            {
                PValue condValue;
                if (
                    !constCond.ToPValue(target).TryConvertTo(
                        target.Loader, PType.Bool, out condValue))
                    goto continueFull;
                else if ((bool) condValue.Value == IsPositive)
                    conditionIsConstant = true;
                else
                {
                    //Condition is always false
                    return;
                }
            }
            continueFull:

            var conditionLabel = Block.CreateLabel("condition");

            if (!Block.IsEmpty) //Body exists -> complete loop code?
            {
                if (conditionIsConstant) //Infinite, hopefully user managed, loop ->
                {
                    /*  {init}
                     *  begin:
                     *  {block}
                     *  continue:
                     *  {next}
                     *  jump -> begin
                     */
                    target.BeginBlock(Initialize);
                    Initialize.EmitValueCode(target);
                    if (!IsPrecondition) //start with nextIteration
                        target.EmitJump(Position, Block.ContinueLabel);
                    target.EmitLabel(Position, Block.BeginLabel);
                    target.BeginBlock(NextIteration);
                    target.BeginBlock(Block);
                    Block.EmitEffectCode(target);
                    target.EndBlock();
                    target.EmitLabel(Position, Block.ContinueLabel);
                    NextIteration.EmitValueCode(target);
                    target.EndBlock();
                    target.EmitJump(Position, Block.BeginLabel);
                    target.EndBlock();
                }
                else //Variable condition and body -> full loop code
                {
                    /*  {init}
                     *  jump -> condition
                     *  begin:
                     *  {block}
                     *  continue:
                     *  {next}
                     *  condition:
                     *  {condition}
                     *  jump if true -> begin
                     */
                    target.BeginBlock(Initialize);
                    Initialize.EmitValueCode(target);
                    target.BeginBlock(NextIteration);
                    if (IsPrecondition)
                        target.EmitJump(Position, conditionLabel);
                    else
                        target.EmitJump(Position, Block.ContinueLabel);
                    target.EmitLabel(Position, Block.BeginLabel);
                    target.BeginBlock(Block);
                    Block.EmitEffectCode(target);
                    target.EndBlock();
                    target.EmitLabel(Position, Block.ContinueLabel);
                    NextIteration.EmitValueCode(target);
                    target.EndBlock();
                    target.EmitLabel(Position, conditionLabel);
                    AstLazyLogical.EmitJumpCondition(
                        target, condition, Block.BeginLabel, IsPositive);
                    target.EndBlock();
                }
            }
            else //Body does not exist -> Condition loop
            {
                /*  {init}
                 *  begin:
                 *  {cond}
                 *  jump if false -> break
                 *  continue:
                 *  {next}
                 *  jump -> begin
                 */
                target.BeginBlock(Block);
                Initialize.EmitValueCode(target);
                if (!IsPrecondition)
                    target.EmitJump(Position, Block.ContinueLabel);
                target.EmitLabel(Position, Block.BeginLabel);
                AstLazyLogical.EmitJumpCondition(target, condition, Block.BreakLabel, !IsPositive);
                if (IsPrecondition)
                    target.EmitLabel(Position, Block.ContinueLabel);
                NextIteration.EmitValueCode(target);
                target.EmitJump(Position, Block.BeginLabel);
                target.EndBlock();
            }

            target.EmitLabel(Position, Block.BreakLabel);
        }
예제 #8
0
 protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
 {
     target.EmitLabel(Position, Label);
 }
예제 #9
0
        protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
        {
            //Optimize condition
            _OptimizeNode(target, ref Condition);

            // Invert condition when unary logical not
            AstIndirectCall unaryCond;
            while (Condition.IsCommandCall(Commands.Core.Operators.LogicalNot.DefaultAlias, out unaryCond))
            {
                Condition = unaryCond.Arguments[0];
                IsNegative = !IsNegative;
            }

            //Constant conditions
            if (Condition is AstConstant)
            {
                var constCond = (AstConstant) Condition;
                PValue condValue;
                if (
                    !constCond.ToPValue(target).TryConvertTo(
                        target.Loader, PType.Bool, out condValue))
                    goto continueFull;
                else if (((bool) condValue.Value) ^ IsNegative)
                    IfBlock.EmitEffectCode(target);
                else
                    ElseBlock.EmitEffectCode(target);
                return;
            }
            //Conditions with empty blocks
            if (IfBlock.IsEmpty && ElseBlock.IsEmpty)
            {
                Condition.EmitEffectCode(target);
                return;
            }
            continueFull:
            ;

            //Switch If and Else block in case the if-block is empty
            if (IfBlock.IsEmpty)
            {
                IsNegative = !IsNegative;
                var tmp = IfBlock;
                IfBlock = ElseBlock;
                ElseBlock = tmp;
            }

            var elseLabel = "else\\" + _depth + "\\assembler";
            var endLabel = "endif\\" + _depth + "\\assembler";
            _depth++;

            //Emit
            var ifGoto = IfBlock.IsSingleStatement
                ? IfBlock[0] as AstExplicitGoTo
                : null;
            var elseGoto = ElseBlock.IsSingleStatement
                ? ElseBlock[0] as AstExplicitGoTo
                : null;
            ;

            var ifIsGoto = ifGoto != null;
            var elseIsGoto = elseGoto != null;

            if (ifIsGoto && elseIsGoto)
            {
                //only jumps
                AstLazyLogical.EmitJumpCondition(
                    target,
                    Condition,
                    ifGoto.Destination,
                    elseGoto.Destination,
                    !IsNegative);
            }
            else if (ifIsGoto)
            {
                //if => jump / else => block
                AstLazyLogical.EmitJumpCondition(target, Condition, ifGoto.Destination, !IsNegative);
                ElseBlock.EmitEffectCode(target);
            }
            else if (elseIsGoto)
            {
                //if => block / else => jump
                AstLazyLogical.EmitJumpCondition(
                    target, Condition, elseGoto.Destination, IsNegative); //inverted
                IfBlock.EmitEffectCode(target);
            }
            else
            {
                //if => block / else => block
                AstLazyLogical.EmitJumpCondition(target, Condition, elseLabel, IsNegative);
                IfBlock.EmitEffectCode(target);
                target.EmitJump(Position, endLabel);
                target.EmitLabel(Position, elseLabel);
                ElseBlock.EmitEffectCode(target);
                target.EmitLabel(Position, endLabel);
            }

            target.FreeLabel(elseLabel);
            target.FreeLabel(endLabel);
        }
예제 #10
0
 public static void EmitJumpUnlessCondition(
     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, continueLabel, targetLabel); //inverted
         target.EmitLabel(cond.Position, continueLabel);
     }
     else
     {
         cond.EmitValueCode(target);
         target.EmitJumpIfFalse(cond.Position, targetLabel);
     }
 }
예제 #11
0
        public void DoEmitPartialApplicationCode(CompilerTarget target)
        {
            AstPlaceholder.DeterminePlaceholderIndices(Expressions.OfType<AstPlaceholder>());

            var count = Expressions.Count;
            if (count == 0)
            {
                this.ConstFunc(null).EmitValueCode(target);
                return;
            }

            //only the very last condition may be a placeholder
            for (var i = 0; i < count; i++)
            {
                var value = Expressions[i];
                var isPlaceholder = value.IsPlaceholder();
                if (i == count - 1)
                {
                    if (!isPlaceholder)
                    {
                        //there is no placeholder at all, wrap expression in const
                        Debug.Assert(Expressions.All(e => !e.IsPlaceholder()));
                        DoEmitCode(target,StackSemantics.Value);
                        target.EmitCommandCall(Position, 1, Const.Alias);
                        return;
                    }
                }
                else
                {
                    if (isPlaceholder)
                    {
                        _reportInvalidPlaceholders(target);
                        return;
                    }
                }
            }

            if (count == 0)
            {
                this.ConstFunc().EmitValueCode(target);
            }
            else if (count == 1)
            {
                Debug.Assert(Expressions[0].IsPlaceholder(),
                    "Singleton ??-chain expected to consist of placeholder.");
                var placeholder = (AstPlaceholder) Expressions[0];
                placeholder.IdFunc().EmitValueCode(target);
            }
            else
            {
                Debug.Assert(Expressions[count - 1].IsPlaceholder(),
                    "Last expression in ??-chain expected to be placeholder.");
                var placeholder = (AstPlaceholder) Expressions[count - 1];
                var prefix = new AstCoalescence(File, Line, Column);
                prefix.Expressions.AddRange(Expressions.Take(count - 1));

                //check for null (keep a copy of prefix on stack)
                var constLabel = _generateEndLabel();
                var endLabel = _generateEndLabel();
                prefix._emitCode(target, constLabel, StackSemantics.Value);
                target.EmitDuplicate(Position);
                target.Emit(Position,OpCode.check_null);
                target.EmitJumpIfFalse(Position, constLabel);
                //prefix is null, identity function
                target.EmitPop(Position);
                placeholder.IdFunc().EmitValueCode(target);
                target.EmitJump(Position, endLabel);
                //prefix is not null, const function
                target.EmitLabel(Position, constLabel);
                target.EmitCommandCall(Position, 1, Const.Alias);
                target.EmitLabel(Position, endLabel);
            }
        }
예제 #12
0
 protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
 {
     //Expressions contains at least two expressions
     var endLabel = _generateEndLabel();
     _emitCode(target, endLabel, stackSemantics);
     target.EmitLabel(Position, endLabel);
 }
예제 #13
0
        protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics)
        {
            //Optimize condition
            _OptimizeNode(target, ref Condition);
            _OptimizeNode(target, ref IfExpression);
            _OptimizeNode(target, ref ElseExpression);

            var elseLabel = "elsei\\" + _depth + "\\assembler";
            var endLabel = "endifi\\" + _depth + "\\assembler";
            _depth++;

            //Emit
            //if => block / else => block
            AstLazyLogical.EmitJumpCondition(target, Condition, elseLabel, IsNegative);
            IfExpression.EmitCode(target, stackSemantics);
            target.EmitJump(Position, endLabel);
            target.EmitLabel(Position, elseLabel);
            ElseExpression.EmitCode(target, stackSemantics);
            target.EmitLabel(Position, endLabel);

            target.FreeLabel(elseLabel);
            target.FreeLabel(endLabel);
        }