/// <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> /// 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.ResultType); 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.ResultType); break; // Equality operations. case OperatorType.Equal: case OperatorType.StrictlyEqual: case OperatorType.NotEqual: case OperatorType.StrictlyNotEqual: EmitConversion.ToAny(generator, this.Left.ResultType); break; } // Load the right hand side onto the stack. this.Right.GenerateCode(generator, optimizationInfo); // 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.ResultType); break; // Bitwise operations. case OperatorType.BitwiseAnd: case OperatorType.BitwiseOr: case OperatorType.BitwiseXor: EmitConversion.ToInt32(generator, this.Right.ResultType); break; case OperatorType.LeftShift: case OperatorType.SignedRightShift: case OperatorType.UnsignedRightShift: EmitConversion.ToUInt32(generator, this.Right.ResultType); 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.ResultType); 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, PrimitiveType.UInt32); 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)); } }
/// <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: case OperatorType.Exponentiation: EmitConversion.ToNumber(generator, this.Left.ResultType); 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.ResultType); break; // Equality operations. case OperatorType.Equal: case OperatorType.StrictlyEqual: case OperatorType.NotEqual: case OperatorType.StrictlyNotEqual: EmitConversion.ToAny(generator, this.Left.ResultType); break; } // Load the right hand side onto the stack. this.Right.GenerateCode(generator, optimizationInfo); // Convert the right argument. switch (this.OperatorType) { // Arithmetic operations. case OperatorType.Subtract: case OperatorType.Multiply: case OperatorType.Divide: case OperatorType.Modulo: case OperatorType.Exponentiation: EmitConversion.ToNumber(generator, this.Right.ResultType); break; // Bitwise operations. case OperatorType.BitwiseAnd: case OperatorType.BitwiseOr: case OperatorType.BitwiseXor: EmitConversion.ToInt32(generator, this.Right.ResultType); break; case OperatorType.LeftShift: case OperatorType.SignedRightShift: case OperatorType.UnsignedRightShift: EmitConversion.ToUInt32(generator, this.Right.ResultType); 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.ResultType); 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; case OperatorType.Exponentiation: generator.CallStatic(ReflectionHelpers.Math_Pow); 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, PrimitiveType.UInt32); 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)); } }
/// <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)); } }