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); } }
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(); }
private void _emitCondition(CompilerTarget target) { target.EmitLabel(Position, Block.ContinueLabel); AstLazyLogical.EmitJumpCondition(target, Condition, Block.BeginLabel, IsPositive); }
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); }
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 }
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(); }
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); }
protected override void DoEmitCode(CompilerTarget target, StackSemantics stackSemantics) { target.EmitLabel(Position, Label); }
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); }
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); } }
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); } }
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); }
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); }