/// <summary> /// Pops the value on the stack, converts it to an integer, then pushes the integer result /// onto the stack. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="fromType"> The type to convert from. </param> public static void ToInteger(ILGenerator generator, PrimitiveType fromType) { // Check that a conversion is actually necessary. if (fromType == PrimitiveType.Int32 || fromType == PrimitiveType.UInt32 || fromType == PrimitiveType.Bool) { return; } switch (fromType) { case PrimitiveType.Undefined: case PrimitiveType.Null: // Converting from undefined or null produces 0. generator.Pop(); generator.LoadInt32(0); break; case PrimitiveType.Number: // Converting from a number produces the following: // Any number between -2147483648 and +2147483647 -> itself // Any number smaller than -2147483648 -> -2147483648 // Any number larger than +2147483647 -> +2147483647 // NaN -> 0 // bool isPositiveInfinity = input > 2147483647.0 var isPositiveInfinity = generator.CreateTemporaryVariable(typeof(bool)); generator.Duplicate(); generator.LoadDouble(2147483647.0); generator.CompareGreaterThan(); generator.StoreVariable(isPositiveInfinity); // bool notNaN = input == input var notNaN = generator.CreateTemporaryVariable(typeof(bool)); generator.Duplicate(); generator.Duplicate(); generator.CompareEqual(); generator.StoreVariable(notNaN); // input = (int)input // Infinity -> -2147483648 // -Infinity -> -2147483648 // NaN -> -2147483648 generator.ConvertToInteger(); // input = input & -((int)notNaN) generator.LoadVariable(notNaN); generator.Negate(); generator.BitwiseAnd(); // input = input - (int)isPositiveInfinity generator.LoadVariable(isPositiveInfinity); generator.Subtract(); // The temporary variables are no longer needed. generator.ReleaseTemporaryVariable(notNaN); generator.ReleaseTemporaryVariable(isPositiveInfinity); break; case PrimitiveType.String: case PrimitiveType.ConcatenatedString: case PrimitiveType.Any: case PrimitiveType.Object: // Otherwise, fall back to calling TypeConverter.ToInteger() generator.Call(ReflectionHelpers.TypeConverter_ToInteger); break; default: throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType)); } }
/// <summary> /// Pops the value on the stack, converts it to a boolean, then pushes the boolean result /// onto the stack. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="fromType"> The type to convert from. </param> public static void ToBool(ILGenerator generator, PrimitiveType fromType) { // Check that a conversion is actually necessary. if (fromType == PrimitiveType.Bool) { return; } switch (fromType) { case PrimitiveType.Undefined: case PrimitiveType.Null: // Converting from undefined or null produces false. generator.Pop(); generator.LoadInt32(0); break; case PrimitiveType.Int32: case PrimitiveType.UInt32: // Converting from an integer produces true if the integer is non-zero. generator.LoadInt32(0); generator.CompareGreaterThanUnsigned(); break; case PrimitiveType.Number: // Converting from a number produces true if the number is non-zero and not NaN. var temp = generator.CreateTemporaryVariable(fromType); generator.StoreVariable(temp); // input != 0 generator.LoadVariable(temp); generator.LoadDouble(0.0); generator.CompareEqual(); generator.LoadInt32(0); generator.CompareEqual(); // input == input generator.LoadVariable(temp); generator.Duplicate(); generator.CompareEqual(); // && generator.CompareEqual(); // The temporary variable is no longer needed. generator.ReleaseTemporaryVariable(temp); break; case PrimitiveType.String: // Converting from a string produces true if the string is not empty. generator.Call(ReflectionHelpers.String_Length); generator.LoadInt32(0); generator.CompareGreaterThan(); break; case PrimitiveType.ConcatenatedString: // Converting from a string produces true if the string is not empty. generator.Call(ReflectionHelpers.ConcatenatedString_Length); generator.LoadInt32(0); generator.CompareGreaterThan(); break; case PrimitiveType.Any: case PrimitiveType.Object: // Otherwise, fall back to calling TypeConverter.ToBoolean() generator.Call(ReflectionHelpers.TypeConverter_ToBoolean); break; default: throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType)); } }
/// <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. PrimitiveType leftType = this.Left.ResultType; PrimitiveType rightType = this.Right.ResultType; // The relational operators compare strings if both of the operands are strings. if (leftType == PrimitiveType.String && rightType == PrimitiveType.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); // 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 == PrimitiveType.Int32 && rightType == PrimitiveType.Int32) { // 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); // 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); // 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); 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 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. PrimitiveType leftType = this.Left.ResultType; PrimitiveType rightType = this.Right.ResultType; // The relational operators compare strings if both of the operands are strings. if (leftType == PrimitiveType.String && rightType == PrimitiveType.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); // 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 == PrimitiveType.Int32 && rightType == PrimitiveType.Int32) { // 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); // 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); // 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); 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> /// Pops the value on the stack, converts it to an integer, then pushes the integer result /// onto the stack. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="fromType"> The type to convert from. </param> public static void ToInteger(ILGenerator generator, PrimitiveType fromType) { // Check that a conversion is actually necessary. if (fromType == PrimitiveType.Int32 || fromType == PrimitiveType.UInt32 || fromType == PrimitiveType.Bool) return; switch (fromType) { case PrimitiveType.Undefined: case PrimitiveType.Null: // Converting from undefined or null produces 0. generator.Pop(); generator.LoadInt32(0); break; case PrimitiveType.Number: // Converting from a number produces the following: // Any number between -2147483648 and +2147483647 -> itself // Any number smaller than -2147483648 -> -2147483648 // Any number larger than +2147483647 -> +2147483647 // NaN -> 0 // bool isPositiveInfinity = input > 2147483647.0 var isPositiveInfinity = generator.CreateTemporaryVariable(typeof(bool)); generator.Duplicate(); generator.LoadDouble(2147483647.0); generator.CompareGreaterThan(); generator.StoreVariable(isPositiveInfinity); // bool notNaN = input == input var notNaN = generator.CreateTemporaryVariable(typeof(bool)); generator.Duplicate(); generator.Duplicate(); generator.CompareEqual(); generator.StoreVariable(notNaN); // input = (int)input // Infinity -> -2147483648 // -Infinity -> -2147483648 // NaN -> -2147483648 generator.ConvertToInteger(); // input = input & -((int)notNaN) generator.LoadVariable(notNaN); generator.Negate(); generator.BitwiseAnd(); // input = input - (int)isPositiveInfinity generator.LoadVariable(isPositiveInfinity); generator.Subtract(); // The temporary variables are no longer needed. generator.ReleaseTemporaryVariable(notNaN); generator.ReleaseTemporaryVariable(isPositiveInfinity); break; case PrimitiveType.String: case PrimitiveType.ConcatenatedString: case PrimitiveType.Any: case PrimitiveType.Object: // Otherwise, fall back to calling TypeConverter.ToInteger() generator.Call(ReflectionHelpers.TypeConverter_ToInteger); break; default: throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType)); } }
/// <summary> /// Pops the value on the stack, converts it to a boolean, then pushes the boolean result /// onto the stack. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="fromType"> The type to convert from. </param> public static void ToBool(ILGenerator generator, PrimitiveType fromType) { // Check that a conversion is actually necessary. if (fromType == PrimitiveType.Bool) return; switch (fromType) { case PrimitiveType.Undefined: case PrimitiveType.Null: // Converting from undefined or null produces false. generator.Pop(); generator.LoadInt32(0); break; case PrimitiveType.Int32: case PrimitiveType.UInt32: // Converting from an integer produces true if the integer is non-zero. generator.LoadInt32(0); generator.CompareGreaterThanUnsigned(); break; case PrimitiveType.Number: // Converting from a number produces true if the number is non-zero and not NaN. var temp = generator.CreateTemporaryVariable(fromType); generator.StoreVariable(temp); // input != 0 generator.LoadVariable(temp); generator.LoadDouble(0.0); generator.CompareEqual(); generator.LoadInt32(0); generator.CompareEqual(); // input == input generator.LoadVariable(temp); generator.Duplicate(); generator.CompareEqual(); // && generator.CompareEqual(); // The temporary variable is no longer needed. generator.ReleaseTemporaryVariable(temp); break; case PrimitiveType.String: // Converting from a string produces true if the string is not empty. generator.Call(ReflectionHelpers.String_Length); generator.LoadInt32(0); generator.CompareGreaterThan(); break; case PrimitiveType.ConcatenatedString: // Converting from a string produces true if the string is not empty. generator.Call(ReflectionHelpers.ConcatenatedString_Length); generator.LoadInt32(0); generator.CompareGreaterThan(); break; case PrimitiveType.Any: case PrimitiveType.Object: // Otherwise, fall back to calling TypeConverter.ToBoolean() generator.Call(ReflectionHelpers.TypeConverter_ToBoolean); break; default: throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType)); } }