/// <summary> /// Generates CIL for an increment or decrement 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> /// <param name="target"> The target to modify. </param> /// <param name="postfix"> <c>true</c> if this is the postfix version of the operator; /// <c>false</c> otherwise. </param> /// <param name="increment"> <c>true</c> if this is the increment operator; <c>false</c> if /// this is the decrement operator. </param> private void GenerateIncrementOrDecrement(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target, bool postfix, bool increment) { // Note: increment and decrement can produce a number that is out of range if the // target is of type Int32. The only time this should happen is for a loop variable // where the range has been carefully checked to make sure an out of range condition // cannot happen. // Store the value. target.GenerateSet(generator, optimizationInfo, optimizationInfo.RootExpression != this, target.GetResultType(optimizationInfo) == typeof(int) ? typeof(int) : typeof(double), delegate(bool two) { // Get the target value. target.GenerateGet(generator, optimizationInfo, true); // Convert it to a number. if (target.GetResultType(optimizationInfo) != typeof(int)) { EmitConversion.ToNumber(generator, target.GetResultType(optimizationInfo)); } // If this is PostIncrement or PostDecrement, duplicate the value so it can be produced as the return value. if (postfix && two) { generator.Duplicate(); } // Load the increment constant. if (target.GetResultType(optimizationInfo) == typeof(int)) { generator.LoadInt32(1); } else { generator.LoadDouble(1.0); } // Add or subtract the constant to the target value. if (increment == true) { generator.Add(); } else { generator.Subtract(); } // If this is PreIncrement or PreDecrement, duplicate the value so it can be produced as the return value. if (!postfix && two) { generator.Duplicate(); } }, optimizationInfo.StrictMode); }
/// <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 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 relational 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 GenerateRelational(ILGenerator generator, OptimizationInfo optimizationInfo) { // Get the statically-determined types of the left and right operands. Type leftType = this.Left.GetResultType(optimizationInfo); Type rightType = this.Right.GetResultType(optimizationInfo); // The relational operators compare strings if both of the operands are strings. if (leftType == typeof(string) && rightType == typeof(string)) { // Both of the operands are strings. // Load the left hand side operand onto the stack. this.Left.GenerateCode(generator, optimizationInfo); // Load the right hand side operand onto the stack. this.Right.GenerateCode(generator, optimizationInfo); if (optimizationInfo.RootExpression == this) { generator.Pop(); generator.Pop(); return; } // Compare the two strings. generator.Call(ReflectionHelpers.String_CompareOrdinal); switch (this.OperatorType) { case OperatorType.LessThan: generator.LoadInt32(0); generator.CompareLessThan(); break; case OperatorType.LessThanOrEqual: generator.LoadInt32(1); generator.CompareLessThan(); break; case OperatorType.GreaterThan: generator.LoadInt32(0); generator.CompareGreaterThan(); break; case OperatorType.GreaterThanOrEqual: generator.LoadInt32(-1); generator.CompareGreaterThan(); break; } } else if (leftType == typeof(int) && rightType == typeof(int)) { // Both of the operands are integers. // Load the left hand side operand onto the stack. this.Left.GenerateCode(generator, optimizationInfo); // Load the right hand side operand onto the stack. this.Right.GenerateCode(generator, optimizationInfo); if (optimizationInfo.RootExpression == this) { generator.Pop(); generator.Pop(); return; } // Compare the two numbers. switch (this.OperatorType) { case OperatorType.LessThan: generator.CompareLessThan(); break; case OperatorType.GreaterThan: generator.CompareGreaterThan(); break; case OperatorType.LessThanOrEqual: // a <= b <--> (a > b) == false generator.CompareGreaterThan(); generator.LoadBoolean(false); generator.CompareEqual(); break; case OperatorType.GreaterThanOrEqual: // a >= b <--> (a < b) == false generator.CompareLessThan(); generator.LoadBoolean(false); generator.CompareEqual(); break; } } else if (PrimitiveTypeUtilities.IsNumeric(leftType) || PrimitiveTypeUtilities.IsNumeric(rightType)) { // At least one of the operands is a number. // Load the left hand side operand onto the stack. this.Left.GenerateCode(generator, optimizationInfo); // Convert the operand to a number. EmitConversion.ToNumber(generator, leftType); // Load the right hand side operand onto the stack. this.Right.GenerateCode(generator, optimizationInfo); if (optimizationInfo.RootExpression == this) { generator.Pop(); generator.Pop(); return; } // Convert the operand to a number. EmitConversion.ToNumber(generator, rightType); // Compare the two numbers. switch (this.OperatorType) { case OperatorType.LessThan: generator.CompareLessThan(); break; case OperatorType.GreaterThan: generator.CompareGreaterThan(); break; case OperatorType.LessThanOrEqual: // a <= b <--> (a > b) == false generator.CompareGreaterThanUnsigned(); generator.LoadBoolean(false); generator.CompareEqual(); break; case OperatorType.GreaterThanOrEqual: // a >= b <--> (a < b) == false generator.CompareLessThanUnsigned(); generator.LoadBoolean(false); generator.CompareEqual(); break; } } else { // It is unknown whether one of the operands is a string. // Load the left hand side operand onto the stack. this.Left.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, leftType); // Load the right hand side operand onto the stack. this.Right.GenerateCode(generator, optimizationInfo); if (optimizationInfo.RootExpression == this) { generator.Pop(); generator.Pop(); return; } EmitConversion.ToAny(generator, rightType); switch (this.OperatorType) { case OperatorType.LessThan: generator.Call(ReflectionHelpers.TypeComparer_LessThan); break; case OperatorType.LessThanOrEqual: generator.Call(ReflectionHelpers.TypeComparer_LessThanOrEqual); break; case OperatorType.GreaterThan: generator.Call(ReflectionHelpers.TypeComparer_GreaterThan); break; case OperatorType.GreaterThanOrEqual: generator.Call(ReflectionHelpers.TypeComparer_GreaterThanOrEqual); break; } } }
/// <summary> /// Generates CIL for the addition operation. /// </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 GenerateAdd(ILGenerator generator, OptimizationInfo optimizationInfo) { // Get the statically-determined types of the left and right operands. Type leftType = this.Left.GetResultType(optimizationInfo); Type rightType = this.Right.GetResultType(optimizationInfo); // The add operator adds two strings together if at least one of the operands // is a string, otherwise it adds two numbers. if (PrimitiveTypeUtilities.IsString(leftType) || PrimitiveTypeUtilities.IsString(rightType)) { // If at least one of the operands is a string, then the add operator concatenates. // Load the left-hand side onto the stack. this.Left.GenerateCode(generator, optimizationInfo); // Convert the operand to a concatenated string. EmitConversion.ToPrimitive(generator, leftType, PrimitiveTypeHint.None); EmitConversion.ToConcatenatedString(generator, leftType); // Load the right-hand side onto the stack. this.Right.GenerateCode(generator, optimizationInfo); if (rightType == typeof(string)) { // Concatenate the two strings. generator.Call(ReflectionHelpers.ConcatenatedString_Concatenate_String); } else if (rightType == typeof(ConcatenatedString)) { // Concatenate the two strings. generator.Call(ReflectionHelpers.ConcatenatedString_Concatenate_ConcatenatedString); } else { // Convert the operand to an object. EmitConversion.ToPrimitive(generator, rightType, PrimitiveTypeHint.None); EmitConversion.ToAny(generator, rightType); // Concatenate the two strings. generator.Call(ReflectionHelpers.ConcatenatedString_Concatenate_Object); } } else if (leftType != typeof(object) && leftType != typeof(Library.ObjectInstance) && rightType != typeof(object) && rightType != typeof(Library.ObjectInstance)) { // Neither of the operands are strings. // If the two types are numeric integers, retain the one with the most accuracy. Type numeric = TypeConverter.MostAccurateInteger(leftType, rightType); if (numeric == null) { // Load the left hand side onto the stack. this.Left.GenerateCode(generator, optimizationInfo); // Convert the operand to a number. EmitConversion.ToNumber(generator, leftType); // Load the right hand side onto the stack. this.Right.GenerateCode(generator, optimizationInfo); // Convert the operand to a number. EmitConversion.ToNumber(generator, rightType); // Add the two numbers. generator.Add(); } else { // Use them both converted to 'numeric' // Load the left hand side onto the stack. this.Left.GenerateCode(generator, optimizationInfo); // Convert the operand to a number. EmitConversion.ToNumber(generator, leftType, numeric); // Load the right hand side onto the stack. this.Right.GenerateCode(generator, optimizationInfo); // Convert the operand to a number. EmitConversion.ToNumber(generator, rightType, numeric); // Add the two numbers. generator.Add(); } } else { // It is unknown whether the operands are strings. // Load the left hand side onto the stack. this.Left.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, leftType); // Load the right hand side onto the stack. this.Right.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, rightType); // Add the two objects. generator.Call(ReflectionHelpers.TypeUtilities_Add); } }
/// <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 a return value is not expected, generate only the side-effects. /*if (optimizationInfo.SuppressReturnValue == true) * { * this.GenerateSideEffects(generator, optimizationInfo); * return; * }*/ // Special case the addition operator. if (this.OperatorType == OperatorType.Add) { GenerateAdd(generator, optimizationInfo); return; } // Special case the instanceof operator. if (this.OperatorType == OperatorType.InstanceOf) { GenerateInstanceOf(generator, optimizationInfo); return; } // Special case the in operator. if (this.OperatorType == OperatorType.In) { GenerateIn(generator, optimizationInfo); return; } // Special case the relational operators. if (this.OperatorType == OperatorType.LessThan || this.OperatorType == OperatorType.LessThanOrEqual || this.OperatorType == OperatorType.GreaterThan || this.OperatorType == OperatorType.GreaterThanOrEqual) { GenerateRelational(generator, optimizationInfo); return; } // Special case the logical operators. if (this.OperatorType == OperatorType.LogicalAnd || this.OperatorType == OperatorType.LogicalOr) { GenerateLogical(generator, optimizationInfo); return; } // Load the left hand side onto the stack. this.Left.GenerateCode(generator, optimizationInfo); // Convert the left argument. switch (this.OperatorType) { // Arithmetic operations. case OperatorType.Subtract: case OperatorType.Multiply: case OperatorType.Divide: case OperatorType.Modulo: EmitConversion.ToNumber(generator, this.Left.GetResultType(optimizationInfo)); break; // Bitwise operations. case OperatorType.BitwiseAnd: case OperatorType.BitwiseOr: case OperatorType.BitwiseXor: case OperatorType.LeftShift: case OperatorType.SignedRightShift: case OperatorType.UnsignedRightShift: EmitConversion.ToInt32(generator, this.Left.GetResultType(optimizationInfo)); break; // Equality operations. case OperatorType.Equal: case OperatorType.StrictlyEqual: case OperatorType.NotEqual: case OperatorType.StrictlyNotEqual: EmitConversion.ToAny(generator, this.Left.GetResultType(optimizationInfo)); break; } // Load the right hand side onto the stack. this.Right.GenerateCode(generator, optimizationInfo); // If the return isn't in use, pop them both: if (optimizationInfo.RootExpression == this) { generator.Pop(); generator.Pop(); return; } // Convert the right argument. switch (this.OperatorType) { // Arithmetic operations. case OperatorType.Subtract: case OperatorType.Multiply: case OperatorType.Divide: case OperatorType.Modulo: EmitConversion.ToNumber(generator, this.Right.GetResultType(optimizationInfo)); break; // Bitwise operations. case OperatorType.BitwiseAnd: case OperatorType.BitwiseOr: case OperatorType.BitwiseXor: EmitConversion.ToInt32(generator, this.Right.GetResultType(optimizationInfo)); break; case OperatorType.LeftShift: case OperatorType.SignedRightShift: case OperatorType.UnsignedRightShift: EmitConversion.ToUInt32(generator, this.Right.GetResultType(optimizationInfo)); generator.LoadInt32(0x1F); generator.BitwiseAnd(); break; // Equality operations. case OperatorType.Equal: case OperatorType.StrictlyEqual: case OperatorType.NotEqual: case OperatorType.StrictlyNotEqual: EmitConversion.ToAny(generator, this.Right.GetResultType(optimizationInfo)); break; } // Apply the operator. switch (this.OperatorType) { // Arithmetic operations. case OperatorType.Subtract: generator.Subtract(); break; case OperatorType.Multiply: generator.Multiply(); break; case OperatorType.Divide: generator.Divide(); break; case OperatorType.Modulo: generator.Remainder(); break; // Bitwise operations. case OperatorType.BitwiseAnd: generator.BitwiseAnd(); break; case OperatorType.BitwiseOr: generator.BitwiseOr(); break; case OperatorType.BitwiseXor: generator.BitwiseXor(); break; // Shift operations. case OperatorType.LeftShift: generator.ShiftLeft(); break; case OperatorType.SignedRightShift: generator.ShiftRight(); break; case OperatorType.UnsignedRightShift: generator.ShiftRightUnsigned(); EmitConversion.ToNumber(generator, typeof(uint)); break; // Equality operations. case OperatorType.Equal: generator.Call(ReflectionHelpers.TypeComparer_Equals); break; case OperatorType.StrictlyEqual: generator.Call(ReflectionHelpers.TypeComparer_StrictEquals); break; case OperatorType.NotEqual: generator.Call(ReflectionHelpers.TypeComparer_Equals); generator.LoadBoolean(false); generator.CompareEqual(); break; case OperatorType.StrictlyNotEqual: generator.Call(ReflectionHelpers.TypeComparer_StrictEquals); generator.LoadBoolean(false); generator.CompareEqual(); break; default: throw new NotImplementedException(string.Format("Unsupported operator {0}", this.OperatorType)); } }