/// <summary> /// Generates CIL for the expression. /// </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) { // Special-case the delete operator. if (this.OperatorType == OperatorType.Delete) { GenerateDelete(generator, optimizationInfo); return; } // Special-case the typeof operator. if (this.OperatorType == OperatorType.Typeof) { GenerateTypeof(generator, optimizationInfo); return; } // Load the operand onto the stack. this.Operand.GenerateCode(generator, optimizationInfo); // If we're not using the return value, pop and quit. if (optimizationInfo.RootExpression == this) { // Pop it and quit. generator.Pop(); return; } // Convert the operand to the correct type. switch (this.OperatorType) { case OperatorType.Plus: case OperatorType.Minus: EmitConversion.ToNumber(generator, this.Operand.GetResultType(optimizationInfo)); break; case OperatorType.BitwiseNot: EmitConversion.ToInt32(generator, this.Operand.GetResultType(optimizationInfo)); break; case OperatorType.LogicalNot: EmitConversion.ToBool(generator, this.Operand.GetResultType(optimizationInfo)); break; } // Apply the operator. switch (this.OperatorType) { case OperatorType.Plus: break; case OperatorType.Minus: generator.Negate(); break; case OperatorType.BitwiseNot: generator.BitwiseNot(); break; case OperatorType.LogicalNot: generator.LoadBoolean(false); generator.CompareEqual(); break; case OperatorType.Void: generator.Pop(); EmitHelpers.EmitUndefined(generator); break; default: throw new NotImplementedException(string.Format("Unsupported operator {0}", this.OperatorType)); } }
/// <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) { // Get the root: Expression prevRoot = optimizationInfo.RootExpression; // Is the condition constant? if (StaticResult != null) { // We have a compile-time constant (i.e. if(true) ) // Convert it to a bool: bool result = TypeConverter.ToBoolean(StaticResult); if (result) { // if(true) // Generate code for the if clause which is now the root: IfClause.SetRoot(optimizationInfo); IfClause.GenerateCode(generator, optimizationInfo); } else { // if(false) if (ElseClause != null) { // It's now the root: ElseClause.SetRoot(optimizationInfo); // Code for the else clause: ElseClause.GenerateCode(generator, optimizationInfo); } } // Restore root: optimizationInfo.RootExpression = prevRoot; return; } // Generate code for the condition and coerce to a boolean. this.Condition.GenerateCode(generator, optimizationInfo); EmitConversion.ToBool(generator, this.Condition.GetResultType(optimizationInfo)); // We will need a label at the end of the if statement. var endOfEverything = generator.CreateLabel(); if (this.ElseClause == null) { // Jump to the end if the condition is false. generator.BranchIfFalse(endOfEverything); // If clause is now the root: IfClause.SetRoot(optimizationInfo); // Generate code for the if clause. IfClause.GenerateCode(generator, optimizationInfo); } else { // Branch to the else clause if the condition is false. var startOfElseClause = generator.CreateLabel(); generator.BranchIfFalse(startOfElseClause); // If clause is now the root: IfClause.SetRoot(optimizationInfo); // Generate code for the if clause. IfClause.GenerateCode(generator, optimizationInfo); // Branch to the end of the if statement. generator.Branch(endOfEverything); // Else clause is now the root: ElseClause.SetRoot(optimizationInfo); // Generate code for the else clause. generator.DefineLabelPosition(startOfElseClause); ElseClause.GenerateCode(generator, optimizationInfo); } // Define the label at the end of the if statement. generator.DefineLabelPosition(endOfEverything); // Restore root: optimizationInfo.RootExpression = prevRoot; }
/// <summary> /// Generates CIL for the expression. /// </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) { // If our host is a root then we are also a root. Expression prevRoot = optimizationInfo.RootExpression; Expression operand2 = this.GetOperand(1); Expression operand3 = this.GetOperand(2); if (StaticResult != null) { // Going one way or the other statically! // Convert it to a bool: bool result = TypeConverter.ToBoolean(StaticResult); if (result) { // if(true) if (prevRoot == this) { // Host is a root therefore we are one now: optimizationInfo.RootExpression = operand2; } // Generate code for the if clause: operand2.GenerateCode(generator, optimizationInfo); } else { // if(false) if (prevRoot == this) { // Host is a root therefore we are one now: optimizationInfo.RootExpression = operand3; } // Code for the else clause: operand3.GenerateCode(generator, optimizationInfo); } // Restore root: optimizationInfo.RootExpression = prevRoot; return; } // Emit the condition. var condition = this.GetOperand(0); condition.GenerateCode(generator, optimizationInfo); // Convert the condition to a boolean. EmitConversion.ToBool(generator, condition.GetResultType(optimizationInfo)); // Branch if the condition is false. var startOfElse = generator.CreateLabel(); generator.BranchIfFalse(startOfElse); // Calculate the result type. var outputType = this.GetResultType(optimizationInfo); if (prevRoot == this) { // Host is a root therefore we are one now: optimizationInfo.RootExpression = operand2; } // Emit the second operand and convert it to the result type. operand2.GenerateCode(generator, optimizationInfo); EmitConversion.Convert(generator, operand2.GetResultType(optimizationInfo), outputType, optimizationInfo); // Branch to the end. var end = generator.CreateLabel(); generator.Branch(end); generator.DefineLabelPosition(startOfElse); if (prevRoot == this) { // Host is a root therefore we are one now: optimizationInfo.RootExpression = operand3; } // Emit the third operand and convert it to the result type. operand3.GenerateCode(generator, optimizationInfo); EmitConversion.Convert(generator, operand3.GetResultType(optimizationInfo), outputType, optimizationInfo); // Define the end label. generator.DefineLabelPosition(end); // Restore root: optimizationInfo.RootExpression = prevRoot; }
/// <summary> /// Generates CIL for the logical operators. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> private void GenerateLogical(ILGenerator generator, OptimizationInfo optimizationInfo) { // If either evaluates statically to 0 then we also know the correct return type. object leftEval = Left.Evaluate(); if (leftEval != null) { // RHS only. bool leftTrue = TypeConverter.ToBoolean(leftEval); // a && b // If a is false, don't do anything with b. // If a is true, emit b. // a || b // If a is false, emit b. If it's true, emit a. if (OperatorType == OperatorType.LogicalAnd && !leftTrue) { // Don't evaluate the RHS. Just emit a 'false' if one is needed. if (optimizationInfo.RootExpression != this) { // Emit the false: generator.LoadBoolean(false); } } else if (OperatorType == OperatorType.LogicalOr && leftTrue) { // Emit the left object only. if (optimizationInfo.RootExpression != this) { // Load it: EmitHelpers.EmitValue(generator, leftEval); } } else if (optimizationInfo.RootExpression == this) { // Emitting b (no return type required). // Right will be the root instead. optimizationInfo.RootExpression = Right; Right.GenerateCode(generator, optimizationInfo); optimizationInfo.RootExpression = this; } else { // Emitting b (return type required). // Output required. Right.GenerateCode(generator, optimizationInfo); } return; } // Evaluate B, just in case we're doing RHS only: object rightEval = Right.Evaluate(); // Get the statically-determined types of the left and right operands. Type leftType = this.Left.GetResultType(optimizationInfo); Type rightType = rightEval == null?this.Right.GetResultType(optimizationInfo) : rightEval.GetType(); // Load the left-hand side operand. this.Left.GenerateCode(generator, optimizationInfo); // Make sure the output type is consistant. if (leftType != rightType) { if (PrimitiveTypeUtilities.IsNumeric(leftType) == true && PrimitiveTypeUtilities.IsNumeric(rightType) == true) { EmitConversion.ToNumber(generator, leftType); leftType = typeof(double); } else { EmitConversion.ToAny(generator, leftType); leftType = typeof(object); } } // If this is an OR, we might be using the value currently on the stack if it's true. // So, duplicate: if (OperatorType == OperatorType.LogicalOr && optimizationInfo.RootExpression != this) { generator.Duplicate(); } // Convert to a boolean: EmitConversion.ToBool(generator, leftType); // If this is an AND, we might be using the value currently on the stack if it's false. // So, duplicate: if (OperatorType == OperatorType.LogicalAnd && optimizationInfo.RootExpression != this) { generator.Duplicate(); } // Stack contains: // OR: "left, (bool)left" // AND: "(bool)left, (bool)left" var endOfIf = generator.CreateLabel(); if (this.OperatorType == OperatorType.LogicalAnd) { generator.BranchIfFalse(endOfIf); } else { generator.BranchIfTrue(endOfIf); } if (optimizationInfo.RootExpression == this) { // Right hand side will now be the root (output is not in use). optimizationInfo.RootExpression = Right; Right.GenerateCode(generator, optimizationInfo); // Restore: optimizationInfo.RootExpression = this; } else { // Stack contains "left" which we don't need if we fall through here. Pop it off: generator.Pop(); // Output is in use. Right.GenerateCode(generator, optimizationInfo); // Make sure the output type is consistant. if (leftType != rightType) { if (PrimitiveTypeUtilities.IsNumeric(leftType) == true && PrimitiveTypeUtilities.IsNumeric(rightType) == true) { EmitConversion.ToNumber(generator, rightType); } else { EmitConversion.ToAny(generator, rightType); } } } // Define the label used above. generator.DefineLabelPosition(endOfIf); }
/// <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) { // Get the previous root - we'll be changing it: Expression prevRoot = optimizationInfo.RootExpression; List <string> labels = optimizationInfo.Labels; optimizationInfo.Labels = null; // Emit the initialization statement. if (InitStatement != null) { // Init isn't in use. Mark it as root: InitStatement.SetRoot(optimizationInfo); InitStatement.GenerateCode(generator, optimizationInfo); // Restore root: optimizationInfo.RootExpression = prevRoot; } var startOfLoop = generator.DefineLabelPosition(); var continueTarget = generator.CreateLabel(); var endOfLoop = generator.CreateLabel(); bool conditionAtEnd = CheckConditionAtEnd; // AT END.. // top: // <body statements> // continue: // <increment> // if(condition) // <goto top> // break: // top: // if(!condition) // <goto break> // <body statements> // continue: // <increment> // <goto top> // break: if (!conditionAtEnd) { if (ConditionStatement != null) { Condition.GenerateCode(generator, optimizationInfo); EmitConversion.ToBool(generator, Condition.GetResultType(optimizationInfo)); generator.BranchIfFalse(endOfLoop); } } // Emit the loop body. optimizationInfo.PushBreakOrContinueInfo(labels, endOfLoop, continueTarget, false); // Mark the body as root: Body.SetRoot(optimizationInfo); Body.GenerateCode(generator, optimizationInfo); optimizationInfo.PopBreakOrContinueInfo(); generator.DefineLabelPosition(continueTarget); // Increment the loop variable. if (IncrementStatement != null) { // Increment isn't in use. Mark it as root: IncrementStatement.SetRoot(optimizationInfo); IncrementStatement.GenerateCode(generator, optimizationInfo); } // Restore root: optimizationInfo.RootExpression = prevRoot; if (conditionAtEnd) { if (ConditionStatement != null) { // Emit now: Condition.GenerateCode(generator, optimizationInfo); EmitConversion.ToBool(generator, Condition.GetResultType(optimizationInfo)); generator.BranchIfTrue(startOfLoop); } } else { generator.Branch(startOfLoop); } generator.DefineLabelPosition(endOfLoop); }