/// <summary> /// Generates CIL for the start of every statement. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> /// <param name="locals"> Variables common to both GenerateStartOfStatement() and GenerateEndOfStatement(). </param> public void GenerateStartOfStatement(ILGenerator generator, OptimizationInfo optimizationInfo, StatementLocals locals) { #if DEBUG && !SILVERLIGHT // Statements must not produce or consume any values on the stack. if (generator is DynamicILGenerator) { locals.OriginalStackSize = ((DynamicILGenerator)generator).StackSize; } #endif if (locals.NonDefaultBreakStatementBehavior == false && this.HasLabels) { // Set up the information needed by the break statement. locals.EndOfStatement = generator.CreateLabel(); optimizationInfo.PushBreakOrContinueInfo(this.Labels, locals.EndOfStatement, null, true); } // Emit debugging information. if (locals.NonDefaultSourceSpanBehavior == false) { optimizationInfo.MarkSequencePoint(generator, this.SourceSpan); } }
/// <summary> /// Generates CIL for the statement. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { // Generate code for the start of the statement. var statementLocals = new StatementLocals { NonDefaultBreakStatementBehavior = true }; GenerateStartOfStatement(generator, optimizationInfo, statementLocals); // We need a label for each case clause and one for the default case. var jumpTargets = new ILLabel[this.CaseClauses.Count]; int defaultIndex = -1; ILLabel endOfSwitch = generator.CreateLabel(); // Generate code for the switch value. // ReSharper disable UnusedVariable var startOfSwitch = generator.CreateLabel(); // ReSharper restore UnusedVariable this.Value.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, this.Value.ResultType); // Save the switch value in a variable. var switchValue = generator.CreateTemporaryVariable(typeof(object)); generator.StoreVariable(switchValue); for (int i = 0; i < this.CaseClauses.Count; i++) { var caseClause = this.CaseClauses[i]; // Create a label for each clause. jumpTargets[i] = generator.CreateLabel(); if (caseClause.Value == null) { // This is a default clause. defaultIndex = i; continue; } // TypeComparer.StrictEquals(switchValue, caseValue) generator.LoadVariable(switchValue); caseClause.Value.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, caseClause.Value.ResultType); generator.Call(ReflectionHelpers.TypeComparer_StrictEquals.Value); // if (TypeComparer.StrictEquals(switchValue, caseValue) == true) // goto case i generator.BranchIfTrue(jumpTargets[i]); } // None of the cases matched, jump to the default clause or the end of the switch. generator.Branch(defaultIndex >= 0 ? jumpTargets[defaultIndex] : endOfSwitch); for (int i = 0; i < this.CaseClauses.Count; i++) { // Define a label at the start of the case clause. generator.DefineLabelPosition(jumpTargets[i]); // Set up the information needed by the break statement. optimizationInfo.PushBreakOrContinueInfo(this.Labels, endOfSwitch, null, false); // Emit the case clause statements. foreach (var statement in this.CaseClauses[i].BodyStatements) { statement.GenerateCode(generator, optimizationInfo); } // Revert the information needed by the break statement. optimizationInfo.PopBreakOrContinueInfo(); } // Define a label for the end of the switch statement. generator.DefineLabelPosition(endOfSwitch); // Release the switch value variable for use elsewhere. generator.ReleaseTemporaryVariable(switchValue); // Generate code for the end of the statement. GenerateEndOfStatement(generator, optimizationInfo, statementLocals); }
/// <summary> /// Generates CIL for the statement. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { // Generate code for the start of the statement. var statementLocals = new StatementLocals { NonDefaultBreakStatementBehavior = true, NonDefaultSourceSpanBehavior = true }; GenerateStartOfStatement(generator, optimizationInfo, statementLocals); // <initializer> // if (<condition>) // { // <loop body> // <increment> // while (true) { // if (<condition> == false) // break; // // <body statements> // // continue-target: // <increment> // } // } // break-target: // Set up some labels. var continueTarget = generator.CreateLabel(); var breakTarget1 = generator.CreateLabel(); var breakTarget2 = generator.CreateLabel(); // Emit the initialization statement. if (this.InitStatement != null) { this.InitStatement.GenerateCode(generator, optimizationInfo); } // Check the condition and jump to the end if it is false. if (this.CheckConditionAtEnd == false && this.ConditionStatement != null) { optimizationInfo.MarkSequencePoint(generator, this.ConditionStatement.SourceSpan); this.Condition.GenerateCode(generator, optimizationInfo); EmitConversion.ToBool(generator, this.Condition.ResultType); generator.BranchIfFalse(breakTarget1); } // Emit the loop body. optimizationInfo.PushBreakOrContinueInfo(this.Labels, breakTarget1, continueTarget, false); this.Body.GenerateCode(generator, optimizationInfo); optimizationInfo.PopBreakOrContinueInfo(); // Increment the loop variable. if (this.IncrementStatement != null) { this.IncrementStatement.GenerateCode(generator, optimizationInfo); } // Strengthen the variable types. List <KeyValuePair <Scope.DeclaredVariable, RevertInfo> > previousVariableTypes = null; var previousInsideTryCatchOrFinally = optimizationInfo.InsideTryCatchOrFinally; if (optimizationInfo.OptimizeInferredTypes) { // Keep a record of the variable types before strengthening. previousVariableTypes = new List <KeyValuePair <Scope.DeclaredVariable, RevertInfo> >(); var typedVariables = FindTypedVariables(); foreach (var variableAndType in typedVariables) { var variable = variableAndType.Key; var variableInfo = variableAndType.Value; if (variableInfo.Conditional == false && variableInfo.Type != variable.Type) { // Save the previous type so we can restore it later. var previousType = variable.Type; previousVariableTypes.Add(new KeyValuePair <Scope.DeclaredVariable, RevertInfo>(variable, new RevertInfo { Type = previousType, Variable = variable.Store })); // Load the existing value. var nameExpression = new NameExpression(variable.Scope, variable.Name); nameExpression.GenerateGet(generator, optimizationInfo, false); // Store the typed value. variable.Store = generator.DeclareVariable(variableInfo.Type, null); variable.Type = variableInfo.Type; nameExpression.GenerateSet(generator, optimizationInfo, previousType, false); } } // The variables must be reverted even in the presence of exceptions. if (previousVariableTypes.Count > 0) { generator.BeginExceptionBlock(); // Setting the InsideTryCatchOrFinally flag converts BR instructions into LEAVE // instructions so that the finally block is executed correctly. optimizationInfo.InsideTryCatchOrFinally = true; } } // The inner loop starts here. var startOfLoop = generator.DefineLabelPosition(); // Check the condition and jump to the end if it is false. if (this.ConditionStatement != null) { optimizationInfo.MarkSequencePoint(generator, this.ConditionStatement.SourceSpan); this.Condition.GenerateCode(generator, optimizationInfo); EmitConversion.ToBool(generator, this.Condition.ResultType); generator.BranchIfFalse(breakTarget2); } // Emit the loop body. optimizationInfo.PushBreakOrContinueInfo(this.Labels, breakTarget2, continueTarget, false); this.Body.GenerateCode(generator, optimizationInfo); optimizationInfo.PopBreakOrContinueInfo(); // The continue statement jumps here. generator.DefineLabelPosition(continueTarget); // Increment the loop variable. if (this.IncrementStatement != null) { this.IncrementStatement.GenerateCode(generator, optimizationInfo); } // Unconditionally branch back to the start of the loop. generator.Branch(startOfLoop); // Define the end of the loop (actually just after). generator.DefineLabelPosition(breakTarget2); // Revert the variable types. if (previousVariableTypes != null && previousVariableTypes.Count > 0) { // Revert the InsideTryCatchOrFinally flag. optimizationInfo.InsideTryCatchOrFinally = previousInsideTryCatchOrFinally; // Revert the variable types within a finally block. generator.BeginFinallyBlock(); foreach (var previousVariableAndType in previousVariableTypes) { var variable = previousVariableAndType.Key; var variableRevertInfo = previousVariableAndType.Value; // Load the existing value. var nameExpression = new NameExpression(variable.Scope, variable.Name); nameExpression.GenerateGet(generator, optimizationInfo, false); // Store the typed value. var previousType = variable.Type; variable.Store = variableRevertInfo.Variable; variable.Type = variableRevertInfo.Type; nameExpression.GenerateSet(generator, optimizationInfo, previousType, false); } // End the exception block. generator.EndExceptionBlock(); } // Define the end of the loop (actually just after). generator.DefineLabelPosition(breakTarget1); // Generate code for the end of the statement. GenerateEndOfStatement(generator, optimizationInfo, statementLocals); }
/// <summary> /// Generates CIL for the statement. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { // Generate code for the start of the statement. var statementLocals = new StatementLocals { NonDefaultBreakStatementBehavior = true, NonDefaultSourceSpanBehavior = true }; GenerateStartOfStatement(generator, optimizationInfo, statementLocals); // Construct a loop expression. // var enumerator = TypeUtilities.EnumeratePropertyNames(rhs).GetEnumerator(); // while (true) { // continue-target: // if (enumerator.MoveNext() == false) // goto break-target; // lhs = enumerator.Current; // // <body statements> // } // break-target: // Call IEnumerable<string> EnumeratePropertyNames(ScriptEngine engine, object obj) optimizationInfo.MarkSequencePoint(generator, this.TargetObjectSourceSpan); EmitHelpers.LoadScriptEngine(generator); this.TargetObject.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, this.TargetObject.ResultType); generator.Call(ReflectionHelpers.TypeUtilities_EnumeratePropertyNames.Value); // Call IEnumerable<string>.GetEnumerator() generator.Call(ReflectionHelpers.IEnumerable_GetEnumerator.Value); // Store the enumerator in a temporary variable. var enumerator = generator.CreateTemporaryVariable(typeof(IEnumerator <string>)); generator.StoreVariable(enumerator); var breakTarget = generator.CreateLabel(); var continueTarget = generator.DefineLabelPosition(); // Emit debugging information. if (optimizationInfo.DebugDocument != null) { generator.MarkSequencePoint(optimizationInfo.DebugDocument, this.VariableSourceSpan); } // if (enumerator.MoveNext() == false) // goto break-target; generator.LoadVariable(enumerator); generator.Call(ReflectionHelpers.IEnumerator_MoveNext.Value); generator.BranchIfFalse(breakTarget); // lhs = enumerator.Current; generator.LoadVariable(enumerator); generator.Call(ReflectionHelpers.IEnumerator_Current.Value); this.Variable.GenerateSet(generator, optimizationInfo, PrimitiveType.String, false); // Emit the body statement(s). optimizationInfo.PushBreakOrContinueInfo(this.Labels, breakTarget, continueTarget, false); this.Body.GenerateCode(generator, optimizationInfo); optimizationInfo.PopBreakOrContinueInfo(); generator.Branch(continueTarget); generator.DefineLabelPosition(breakTarget); // Generate code for the end of the statement. GenerateEndOfStatement(generator, optimizationInfo, statementLocals); }