internal override void Generate(CodeGenerator cg) { Contract.ThrowIfNull(Condition); if (IsLoop) // perf { cg.Builder.EmitBranch(ILOpCode.Br, this.Condition); // { cg.GenerateScope(TrueTarget, NextBlock.Ordinal); // } // if (Condition) cg.EmitSequencePoint(this.Condition.PhpSyntax); cg.Builder.MarkLabel(this.Condition); cg.EmitConvert(this.Condition, cg.CoreTypes.Boolean); cg.Builder.EmitBranch(ILOpCode.Brtrue, TrueTarget); } else { // if (Condition) cg.EmitSequencePoint(this.Condition.PhpSyntax); cg.EmitConvert(this.Condition, cg.CoreTypes.Boolean); cg.Builder.EmitBranch(ILOpCode.Brfalse, FalseTarget); // { cg.GenerateScope(TrueTarget, NextBlock.Ordinal); // } } cg.Scope.ContinueWith(FalseTarget); }
void EmitTryStatement(CodeGenerator cg, bool emitCatchesOnly = false) { // Stack must be empty at beginning of try block. cg.Builder.AssertStackEmpty(); // IL requires catches and finally block to be distinct try // blocks so if the source contained both a catch and // a finally, nested scopes are emitted. bool emitNestedScopes = (!emitCatchesOnly && //(_catchBlocks.Length != 0) && (_finallyBlock != null)); cg.Builder.OpenLocalScope(ScopeType.TryCatchFinally); cg.Builder.OpenLocalScope(ScopeType.Try); // IL requires catches and finally block to be distinct try // blocks so if the source contained both a catch and // a finally, nested scopes are emitted. //_tryNestingLevel++; if (emitNestedScopes) { EmitTryStatement(cg, emitCatchesOnly: true); } else { cg.GenerateScope(_body, (_finallyBlock ?? NextBlock).Ordinal); } //_tryNestingLevel--; // Close the Try scope cg.Builder.CloseLocalScope(); if (!emitNestedScopes) { EmitScriptDiedBlock(cg); // foreach (var catchBlock in _catchBlocks) { EmitCatchBlock(cg, catchBlock); } } if (!emitCatchesOnly && _finallyBlock != null) { cg.Builder.OpenLocalScope(ScopeType.Finally); cg.GenerateScope(_finallyBlock, NextBlock.Ordinal); // close Finally scope cg.Builder.CloseLocalScope(); } // close the whole try statement scope cg.Builder.CloseLocalScope(); if (!emitCatchesOnly) { // cg.Scope.ContinueWith(NextBlock); } }
internal override void Generate(CodeGenerator cg) { // four cases: // 1. just single or none case label that can be replaced with single IF // 2. switch over integers, using native CIL switch // 3. switch over strings, using C# static Dictionary and CIL switch // 4. PHP style switch which is just a bunch of IFs if (this.CaseBlocks.Length == 0 || this.CaseBlocks[0].IsDefault) { Debug.Assert(this.CaseBlocks.Length <= 1); // no SWITCH or IF needed cg.EmitPop(this.SwitchValue.WithAccess(BoundAccess.None).Emit(cg)); // None Access, also using BoundExpression.Emit directly to avoid CodeGenerator type specialization which is not needed if (this.CaseBlocks.Length == 1) { cg.GenerateScope(this.CaseBlocks[0], NextBlock.Ordinal); } } else { // CIL Switch: bool allconsts = this.CaseBlocks.All(c => c.IsDefault || c.CaseValue.ConstantValue.HasValue); bool allconstints = allconsts && this.CaseBlocks.All(c => c.IsDefault || IsInt32(c.CaseValue.ConstantValue.Value)); //bool allconststrings = allconsts && this.CaseBlocks.All(c => c.IsDefault || IsString(c.CaseValue.ConstantValue.Value)); var default_block = this.DefaultBlock; // <switch_loc> = <SwitchValue>; TypeSymbol switch_type; LocalDefinition switch_loc; // Switch Header if (allconstints) { switch_type = cg.CoreTypes.Int32; cg.EmitSequencePoint(this.SwitchValue.PhpSyntax); cg.EmitConvert(this.SwitchValue, switch_type); switch_loc = cg.GetTemporaryLocal(switch_type); cg.Builder.EmitLocalStore(switch_loc); // switch (labels) cg.Builder.EmitIntegerSwitchJumpTable(GetSwitchCaseLabels(CaseBlocks), default_block ?? NextBlock, switch_loc, switch_type.PrimitiveTypeCode); } //else if (allconststrings) //{ //} else { // legacy jump table // IF (case_i) GOTO label_i; cg.EmitSequencePoint(this.SwitchValue.PhpSyntax); switch_type = cg.Emit(this.SwitchValue); switch_loc = cg.GetTemporaryLocal(switch_type); cg.Builder.EmitLocalStore(switch_loc); // for (int i = 0; i < this.CaseBlocks.Length; i++) { var this_block = this.CaseBlocks[i]; if (this_block.CaseValue != null) { // <CaseValue>: cg.EmitSequencePoint(this_block.CaseValue.PhpSyntax); // if (<switch_loc> == c.CaseValue) goto this_block; cg.Builder.EmitLocalLoad(switch_loc); BoundBinaryEx.EmitEquality(cg, switch_type, this_block.CaseValue); cg.Builder.EmitBranch(ILOpCode.Brtrue, this_block); } } // default: cg.Builder.EmitBranch(ILOpCode.Br, default_block ?? NextBlock); } // FREE <switch_loc> cg.ReturnTemporaryLocal(switch_loc); // Switch Body this.CaseBlocks.ForEach((i, this_block) => { var next_case = (i + 1 < this.CaseBlocks.Length) ? this.CaseBlocks[i + 1] : null; // { cg.GenerateScope(this_block, (next_case ?? NextBlock).Ordinal); // } }); } // cg.Scope.ContinueWith(NextBlock); }
internal override void Generate(CodeGenerator cg) { /* Template: * for (;MoveNext(enumerator);) * $value = CurrentValue(enumerator); * $key = CurrentKey(enumerator); * {body} * } */ var lblMoveNext = new object(); var lblBody = new object(); // cg.Builder.EmitBranch(ILOpCode.Br, lblMoveNext); cg.Builder.MarkLabel(lblBody); // $value, $key this.EnumereeEdge.EmitGetCurrent(cg, this.ValueVariable, this.KeyVariable); // { cg.GenerateScope(this.BodyBlock, NextBlock.Ordinal); // } // if (enumerator.MoveNext()) //cg.EmitSequencePoint(this.Condition.PhpSyntax); cg.Builder.MarkLabel(lblMoveNext); this.EnumereeEdge.EmitMoveNext(cg); // bool cg.Builder.EmitBranch(ILOpCode.Brtrue, lblBody); // cg.Scope.ContinueWith(NextBlock); }
void EmitBody(CodeGenerator cg) { Debug.Assert(NextBlock.NextEdge is ForeachMoveNextEdge); cg.GenerateScope(NextBlock, NextBlock.NextEdge.NextBlock.Ordinal); }
void EmitCatchBlock(CodeGenerator cg, CatchBlock catchBlock) { Debug.Assert(catchBlock.Variable.Variable != null); if (catchBlock.TypeRef.ResolvedType == null) { throw new NotImplementedException("handle exception type dynamically"); // TODO: if (ex is ctx.ResolveType(ExceptionTypeName)) { ... } } var extype = catchBlock.TypeRef.ResolvedType; cg.Builder.AdjustStack(1); // Account for exception on the stack. cg.Builder.OpenLocalScope(ScopeType.Catch, (Microsoft.Cci.ITypeReference)extype); // <tmp> = <ex> var tmploc = cg.GetTemporaryLocal(extype); cg.Builder.EmitLocalStore(tmploc); var varplace = catchBlock.Variable.BindPlace(cg); Debug.Assert(varplace != null); // $x = <tmp> varplace.EmitStorePrepare(cg); cg.Builder.EmitLocalLoad(tmploc); varplace.EmitStore(cg, (TypeSymbol)tmploc.Type); // cg.ReturnTemporaryLocal(tmploc); tmploc = null; // cg.GenerateScope(catchBlock, NextBlock.Ordinal); // cg.Builder.CloseLocalScope(); }