public abstract LoadDouble ( double value ) : void | ||
value | double | The number to push onto the stack. |
Résultat | void |
/// <summary> /// Pops the value on the stack, converts it to a double, then pushes the double result /// onto the stack. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="fromType"> The type to convert from. </param> public static void ToNumber(ILGenerator generator, PrimitiveType fromType) { // Check that a conversion is actually necessary. if (fromType == PrimitiveType.Number) { return; } switch (fromType) { case PrimitiveType.Undefined: // Converting from undefined produces NaN. generator.Pop(); generator.LoadDouble(double.NaN); break; case PrimitiveType.Null: // Converting from null produces 0. generator.Pop(); generator.LoadDouble(0.0); break; case PrimitiveType.Bool: // Converting from a boolean produces 0 if the boolean is false, or 1 if the boolean is true. generator.ConvertToDouble(); break; case PrimitiveType.Int32: // Converting from int32 produces the same number. generator.ConvertToDouble(); break; case PrimitiveType.UInt32: // Converting from a number produces the following: generator.ConvertUnsignedToDouble(); break; case PrimitiveType.String: case PrimitiveType.ConcatenatedString: case PrimitiveType.Any: case PrimitiveType.Object: // Otherwise, fall back to calling TypeConverter.ToNumber() generator.Call(ReflectionHelpers.TypeConverter_ToNumber); break; default: throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType)); } }
/// <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. // Get the target value. target.GenerateGet(generator, optimizationInfo, true); // Convert it to a number. if (target.Type != PrimitiveType.Int32) { EmitConversion.ToNumber(generator, target.Type); } // If this is PostIncrement or PostDecrement, duplicate the value so it can be produced as the return value. if (postfix == true) { generator.Duplicate(); } // Load the increment constant. if (target.Type == PrimitiveType.Int32) { 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 == false) { generator.Duplicate(); } // Store the value. target.GenerateSet(generator, optimizationInfo, target.Type == PrimitiveType.Int32 ? PrimitiveType.Int32 : PrimitiveType.Number, 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) { // Literals cannot have side-effects so if a return value is not expected then generate // nothing. //if (optimizationInfo.SuppressReturnValue == true) // return; if (this.Value is int) { generator.LoadInt32((int)this.Value); } else if (this.Value is double) { generator.LoadDouble((double)this.Value); } else if (this.Value is string) { generator.LoadString((string)this.Value); } else if (this.Value is bool) { generator.LoadBoolean((bool)this.Value); } else if (this.Value is RegularExpressionLiteral) { // RegExp var sharedRegExpVariable = optimizationInfo.GetRegExpVariable(generator, (RegularExpressionLiteral)this.Value); var label1 = generator.CreateLabel(); var label2 = generator.CreateLabel(); // if (sharedRegExp == null) { generator.LoadVariable(sharedRegExpVariable); generator.LoadNull(); generator.BranchIfNotEqual(label1); // sharedRegExp = Global.RegExp.Construct(source, flags) EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_RegExp); generator.LoadString(((RegularExpressionLiteral)this.Value).Pattern); generator.LoadString(((RegularExpressionLiteral)this.Value).Flags); generator.Call(ReflectionHelpers.RegExp_Construct); generator.Duplicate(); generator.StoreVariable(sharedRegExpVariable); // } else { generator.Branch(label2); generator.DefineLabelPosition(label1); // Global.RegExp.Construct(sharedRegExp, flags) EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_RegExp); generator.LoadVariable(sharedRegExpVariable); generator.LoadNull(); generator.Call(ReflectionHelpers.RegExp_Construct); // } generator.DefineLabelPosition(label2); } else if (this.Value == Null.Value) { // Null. EmitHelpers.EmitNull(generator); } else if (this.Value == Undefined.Value) { // Undefined. EmitHelpers.EmitUndefined(generator); } else if (this.Value is List <Expression> ) { // Construct an array literal. var arrayLiteral = (List <Expression>) this.Value; // Operands for ArrayConstructor.New() are: an ArrayConstructor instance (ArrayConstructor), an array (object[]) // ArrayConstructor EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Array); // object[] generator.LoadInt32(arrayLiteral.Count); generator.NewArray(typeof(object)); for (int i = 0; i < arrayLiteral.Count; i++) { // Operands for StoreArrayElement() are: an array (object[]), index (int), value (object). // Array generator.Duplicate(); // Index generator.LoadInt32(i); // Value var elementExpression = arrayLiteral[i]; if (elementExpression == null) { generator.LoadNull(); } else { elementExpression.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, elementExpression.ResultType); } // Store the element value. generator.StoreArrayElement(typeof(object)); } // ArrayConstructor.New(object[]) generator.Call(ReflectionHelpers.Array_New); } else if (this.Value is List <KeyValuePair <Expression, Expression> > ) { // This is an object literal. var properties = (List <KeyValuePair <Expression, Expression> >) this.Value; // Create a new object. EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Object); generator.Call(ReflectionHelpers.Object_Construct); foreach (var keyValuePair in properties) { Expression propertyName = keyValuePair.Key; Expression propertyValue = keyValuePair.Value; generator.Duplicate(); // The key can be a property name or an expression that evaluates to a name. propertyName.GenerateCode(generator, optimizationInfo); EmitConversion.ToPropertyKey(generator, propertyName.ResultType); var functionValue = propertyValue as FunctionExpression; if (functionValue != null && functionValue.DeclarationType == FunctionDeclarationType.Getter) { // Add a getter to the object. functionValue.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. if (propertyName is LiteralExpression && ((LiteralExpression)propertyName).Value is string) { functionValue.GenerateDisplayName(generator, optimizationInfo, "get " + (string)((LiteralExpression)propertyName).Value, true); } generator.Call(ReflectionHelpers.ReflectionHelpers_SetObjectLiteralGetter); } else if (functionValue != null && functionValue.DeclarationType == FunctionDeclarationType.Setter) { // Add a setter to the object. functionValue.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. if (propertyName is LiteralExpression && ((LiteralExpression)propertyName).Value is string) { functionValue.GenerateDisplayName(generator, optimizationInfo, "set " + (string)((LiteralExpression)propertyName).Value, true); } generator.Call(ReflectionHelpers.ReflectionHelpers_SetObjectLiteralSetter); } else { // Add a new property to the object. propertyValue.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. if (propertyValue is FunctionExpression && propertyName is LiteralExpression && ((LiteralExpression)propertyName).Value is string) { ((FunctionExpression)propertyValue).GenerateDisplayName(generator, optimizationInfo, (string)((LiteralExpression)propertyName).Value, false); } EmitConversion.ToAny(generator, propertyValue.ResultType); generator.Call(ReflectionHelpers.ReflectionHelpers_SetObjectLiteralValue); } } } else { throw new NotImplementedException("Unknown literal type."); } }
/// <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> /// 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> /// Emits the given value. Only possible for certain types. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="value"> The value to emit. </param> public static void EmitValue(ILGenerator generator, object value) { if (value == null) { generator.LoadNull(); } else { switch (Type.GetTypeCode(value.GetType())) { case TypeCode.Boolean: generator.LoadBoolean((bool)value); break; case TypeCode.Byte: generator.LoadInt32((byte)value); break; case TypeCode.Char: generator.LoadInt32((char)value); break; case TypeCode.Double: generator.LoadDouble((double)value); break; case TypeCode.Int16: generator.LoadInt32((short)value); break; case TypeCode.Int32: generator.LoadInt32((int)value); break; case TypeCode.Int64: generator.LoadInt64((long)value); break; case TypeCode.SByte: generator.LoadInt32((sbyte)value); break; case TypeCode.Single: generator.LoadDouble((float)value); break; case TypeCode.String: generator.LoadString((string)value); break; case TypeCode.UInt16: generator.LoadInt32((ushort)value); break; case TypeCode.UInt32: generator.LoadInt32((uint)value); break; case TypeCode.UInt64: generator.LoadInt64((ulong)value); break; case TypeCode.Object: case TypeCode.Empty: case TypeCode.DateTime: case TypeCode.DBNull: case TypeCode.Decimal: throw new NotImplementedException(string.Format("Cannot emit the value '{0}'", value)); } } }
/// <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) { // Literals cannot have side-effects so if a return value is not expected then generate // nothing. //if (optimizationInfo.SuppressReturnValue == true) // return; if (this.Value is int) { generator.LoadInt32((int)this.Value); } else if (this.Value is double) { generator.LoadDouble((double)this.Value); } else if (this.Value is string) { generator.LoadString((string)this.Value); } else if (this.Value is bool) { generator.LoadBoolean((bool)this.Value); } else if (this.Value is RegularExpressionLiteral) { // RegExp var sharedRegExpVariable = optimizationInfo.GetRegExpVariable(generator, (RegularExpressionLiteral)this.Value); var label1 = generator.CreateLabel(); var label2 = generator.CreateLabel(); // if (sharedRegExp == null) { generator.LoadVariable(sharedRegExpVariable); generator.LoadNull(); generator.BranchIfNotEqual(label1); // sharedRegExp = Global.RegExp.Construct(source, flags) EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_RegExp); generator.LoadString(((RegularExpressionLiteral)this.Value).Pattern); generator.LoadString(((RegularExpressionLiteral)this.Value).Flags); generator.Call(ReflectionHelpers.RegExp_Construct); generator.Duplicate(); generator.StoreVariable(sharedRegExpVariable); // } else { generator.Branch(label2); generator.DefineLabelPosition(label1); // Global.RegExp.Construct(sharedRegExp, flags) EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_RegExp); generator.LoadVariable(sharedRegExpVariable); generator.LoadNull(); generator.Call(ReflectionHelpers.RegExp_Construct); // } generator.DefineLabelPosition(label2); } else if (this.Value == Null.Value) { // Null. EmitHelpers.EmitNull(generator); } else if (this.Value == Undefined.Value) { // Undefined. EmitHelpers.EmitUndefined(generator); } else if (this.Value is List <Expression> ) { // Construct an array literal. var arrayLiteral = (List <Expression>) this.Value; // Operands for ArrayConstructor.New() are: an ArrayConstructor instance (ArrayConstructor), an array (object[]) // ArrayConstructor EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Array); // object[] generator.LoadInt32(arrayLiteral.Count); generator.NewArray(typeof(object)); for (int i = 0; i < arrayLiteral.Count; i++) { // Operands for StoreArrayElement() are: an array (object[]), index (int), value (object). // Array generator.Duplicate(); // Index generator.LoadInt32(i); // Value var elementExpression = arrayLiteral[i]; if (elementExpression == null) { generator.LoadNull(); } else { elementExpression.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, elementExpression.ResultType); } // Store the element value. generator.StoreArrayElement(typeof(object)); } // ArrayConstructor.New(object[]) generator.Call(ReflectionHelpers.Array_New); } else if (this.Value is Dictionary <string, object> ) { // This is an object literal. var properties = (Dictionary <string, object>) this.Value; // Create a new object. EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Object); generator.Call(ReflectionHelpers.Object_Construct); foreach (var keyValuePair in properties) { string propertyName = keyValuePair.Key; object propertyValue = keyValuePair.Value; generator.Duplicate(); generator.LoadString(propertyName); if (propertyValue is Expression) { // Add a new property to the object. var dataPropertyValue = (Expression)propertyValue; dataPropertyValue.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. if (dataPropertyValue is FunctionExpression) { ((FunctionExpression)dataPropertyValue).GenerateDisplayName(generator, optimizationInfo, propertyName, false); } EmitConversion.ToAny(generator, dataPropertyValue.ResultType); generator.LoadBoolean(optimizationInfo.StrictMode); generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_String); } else if (propertyValue is Parser.ObjectLiteralAccessor) { // Add a new getter/setter to the object. var accessorValue = (Parser.ObjectLiteralAccessor)propertyValue; if (accessorValue.Getter != null) { accessorValue.Getter.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. accessorValue.Getter.GenerateDisplayName(generator, optimizationInfo, "get " + propertyName, true); EmitConversion.ToAny(generator, accessorValue.Getter.ResultType); } else { generator.LoadNull(); } if (accessorValue.Setter != null) { accessorValue.Setter.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. accessorValue.Setter.GenerateDisplayName(generator, optimizationInfo, "set " + propertyName, true); EmitConversion.ToAny(generator, accessorValue.Setter.ResultType); } else { generator.LoadNull(); } generator.LoadInt32((int)Library.PropertyAttributes.FullAccess); generator.NewObject(ReflectionHelpers.PropertyDescriptor_Constructor3); generator.LoadBoolean(false); generator.Call(ReflectionHelpers.ObjectInstance_DefineProperty); generator.Pop(); } else { throw new InvalidOperationException("Invalid property value type in object literal."); } } } else { throw new NotImplementedException("Unknown literal type."); } }
/// <summary> /// Emits the given value. Only possible for certain types. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="value"> The value to emit. </param> public static void EmitValue(ILGenerator generator, object value) { if (value == null) generator.LoadNull(); else { switch (Type.GetTypeCode(value.GetType())) { case TypeCode.Boolean: generator.LoadBoolean((bool)value); break; case TypeCode.Byte: generator.LoadInt32((byte)value); break; case TypeCode.Char: generator.LoadInt32((char)value); break; case TypeCode.Double: generator.LoadDouble((double)value); break; case TypeCode.Int16: generator.LoadInt32((short)value); break; case TypeCode.Int32: generator.LoadInt32((int)value); break; case TypeCode.Int64: generator.LoadInt64((long)value); break; case TypeCode.SByte: generator.LoadInt32((sbyte)value); break; case TypeCode.Single: generator.LoadDouble((float)value); break; case TypeCode.String: generator.LoadString((string)value); break; case TypeCode.UInt16: generator.LoadInt32((ushort)value); break; case TypeCode.UInt32: generator.LoadInt32((uint)value); break; case TypeCode.UInt64: generator.LoadInt64((ulong)value); break; case TypeCode.Object: case TypeCode.Empty: case TypeCode.DateTime: case TypeCode.DBNull: case TypeCode.Decimal: throw new NotImplementedException(string.Format("Cannot emit the value '{0}'", value)); } } }
/// <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. // Evaluate the left hand side only once. target.GenerateReference(generator, optimizationInfo); target.DuplicateReference(generator, optimizationInfo); // For the GenerateSet, later on. // Get the target value. target.GenerateGet(generator, optimizationInfo, true); // Convert it to a number. if (target.Type != PrimitiveType.Int32) EmitConversion.ToNumber(generator, target.Type); // If this is PostIncrement or PostDecrement, store the value so it can be returned later. var result = generator.CreateTemporaryVariable(target.Type == PrimitiveType.Int32 ? PrimitiveType.Int32 : PrimitiveType.Number); if (postfix == true) { generator.Duplicate(); generator.StoreVariable(result); } // Load the increment constant. if (target.Type == PrimitiveType.Int32) 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, store the value so it can be returned later. if (postfix == false) { generator.Duplicate(); generator.StoreVariable(result); } // Store the value. target.GenerateSet(generator, optimizationInfo, target.Type == PrimitiveType.Int32 ? PrimitiveType.Int32 : PrimitiveType.Number, optimizationInfo.StrictMode); // Restore the expression result. generator.LoadVariable(result); generator.ReleaseTemporaryVariable(result); }
/// <summary> /// Pops the value on the stack, converts it to a double, then pushes the double result /// onto the stack. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="fromType"> The type to convert from. </param> public static void ToNumber(ILGenerator generator, PrimitiveType fromType) { // Check that a conversion is actually necessary. if (fromType == PrimitiveType.Number) return; switch (fromType) { case PrimitiveType.Undefined: // Converting from undefined produces NaN. generator.Pop(); generator.LoadDouble(double.NaN); break; case PrimitiveType.Null: // Converting from null produces 0. generator.Pop(); generator.LoadDouble(0.0); break; case PrimitiveType.Bool: // Converting from a boolean produces 0 if the boolean is false, or 1 if the boolean is true. generator.ConvertToDouble(); break; case PrimitiveType.Int32: // Converting from int32 produces the same number. generator.ConvertToDouble(); break; case PrimitiveType.UInt32: // Converting from a number produces the following: generator.ConvertUnsignedToDouble(); break; case PrimitiveType.String: case PrimitiveType.ConcatenatedString: case PrimitiveType.Any: case PrimitiveType.Object: // Otherwise, fall back to calling TypeConverter.ToNumber() generator.Call(ReflectionHelpers.TypeConverter_ToNumber); 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) { // Literals cannot have side-effects so if a return value is not expected then generate // nothing. //if (optimizationInfo.SuppressReturnValue == true) // return; if (this.Value is int) generator.LoadInt32((int)this.Value); else if (this.Value is double) generator.LoadDouble((double)this.Value); else if (this.Value is string) generator.LoadString((string)this.Value); else if (this.Value is bool) generator.LoadBoolean((bool)this.Value); else if (this.Value is RegularExpressionLiteral) { // RegExp var sharedRegExpVariable = optimizationInfo.GetRegExpVariable(generator, (RegularExpressionLiteral)this.Value); var label1 = generator.CreateLabel(); var label2 = generator.CreateLabel(); // if (sharedRegExp == null) { generator.LoadVariable(sharedRegExpVariable); generator.LoadNull(); generator.BranchIfNotEqual(label1); // sharedRegExp = Global.RegExp.Construct(source, flags) EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_RegExp); generator.LoadString(((RegularExpressionLiteral)this.Value).Pattern); generator.LoadString(((RegularExpressionLiteral)this.Value).Flags); generator.Call(ReflectionHelpers.RegExp_Construct); generator.Duplicate(); generator.StoreVariable(sharedRegExpVariable); // } else { generator.Branch(label2); generator.DefineLabelPosition(label1); // Global.RegExp.Construct(sharedRegExp, flags) EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_RegExp); generator.LoadVariable(sharedRegExpVariable); generator.LoadNull(); generator.Call(ReflectionHelpers.RegExp_Construct); // } generator.DefineLabelPosition(label2); } else if (this.Value == Null.Value) { // Null. EmitHelpers.EmitNull(generator); } else if (this.Value == Undefined.Value) { // Undefined. EmitHelpers.EmitUndefined(generator); } else if (this.Value is List<Expression>) { // Construct an array literal. var arrayLiteral = (List<Expression>)this.Value; // Operands for ArrayConstructor.New() are: an ArrayConstructor instance (ArrayConstructor), an array (object[]) // ArrayConstructor EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Array); // object[] generator.LoadInt32(arrayLiteral.Count); generator.NewArray(typeof(object)); for (int i = 0; i < arrayLiteral.Count; i ++) { // Operands for StoreArrayElement() are: an array (object[]), index (int), value (object). // Array generator.Duplicate(); // Index generator.LoadInt32(i); // Value var elementExpression = arrayLiteral[i]; if (elementExpression == null) generator.LoadNull(); else { elementExpression.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, elementExpression.ResultType); } // Store the element value. generator.StoreArrayElement(typeof(object)); } // ArrayConstructor.New(object[]) generator.Call(ReflectionHelpers.Array_New); } else if (this.Value is Dictionary<string, object>) { // This is an object literal. var properties = (Dictionary<string, object>)this.Value; // Create a new object. EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Object); generator.Call(ReflectionHelpers.Object_Construct); foreach (var keyValuePair in properties) { string propertyName = keyValuePair.Key; object propertyValue = keyValuePair.Value; generator.Duplicate(); generator.LoadString(propertyName); if (propertyValue is Expression) { // Add a new property to the object. var dataPropertyValue = (Expression)propertyValue; dataPropertyValue.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. if (dataPropertyValue is FunctionExpression) ((FunctionExpression)dataPropertyValue).GenerateDisplayName(generator, optimizationInfo, propertyName, false); EmitConversion.ToAny(generator, dataPropertyValue.ResultType); generator.LoadBoolean(optimizationInfo.StrictMode); generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_String); } else if (propertyValue is Parser.ObjectLiteralAccessor) { // Add a new getter/setter to the object. var accessorValue = (Parser.ObjectLiteralAccessor)propertyValue; if (accessorValue.Getter != null) { accessorValue.Getter.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. accessorValue.Getter.GenerateDisplayName(generator, optimizationInfo, "get " + propertyName, true); EmitConversion.ToAny(generator, accessorValue.Getter.ResultType); } else generator.LoadNull(); if (accessorValue.Setter != null) { accessorValue.Setter.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. accessorValue.Setter.GenerateDisplayName(generator, optimizationInfo, "set " + propertyName, true); EmitConversion.ToAny(generator, accessorValue.Setter.ResultType); } else generator.LoadNull(); generator.LoadInt32((int)Library.PropertyAttributes.FullAccess); generator.NewObject(ReflectionHelpers.PropertyDescriptor_Constructor3); generator.LoadBoolean(false); generator.Call(ReflectionHelpers.ObjectInstance_DefineProperty); generator.Pop(); } else throw new InvalidOperationException("Invalid property value type in object literal."); } } else throw new NotImplementedException("Unknown literal type."); }
/// <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 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. // Evaluate the left hand side only once. target.GenerateReference(generator, optimizationInfo); target.DuplicateReference(generator, optimizationInfo); // For the GenerateSet, later on. // Get the target value. target.GenerateGet(generator, optimizationInfo, true); // Convert it to a number. if (target.Type != PrimitiveType.Int32) { EmitConversion.ToNumber(generator, target.Type); } ILLocalVariable result = null; if (optimizationInfo.IgnoreReturnValue != this && postfix == true) { // If this is PostIncrement or PostDecrement, store the value so it can be returned later. result = generator.CreateTemporaryVariable(target.Type == PrimitiveType.Int32 ? PrimitiveType.Int32 : PrimitiveType.Number); generator.Duplicate(); generator.StoreVariable(result); } // Load the increment constant. if (target.Type == PrimitiveType.Int32) { 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 (optimizationInfo.IgnoreReturnValue != this && postfix == false) { // If this is PreIncrement or PreDecrement, store the value so it can be returned later. result = generator.CreateTemporaryVariable(target.Type == PrimitiveType.Int32 ? PrimitiveType.Int32 : PrimitiveType.Number); generator.Duplicate(); generator.StoreVariable(result); } // Store the value. target.GenerateSet(generator, optimizationInfo, target.Type == PrimitiveType.Int32 ? PrimitiveType.Int32 : PrimitiveType.Number); if (optimizationInfo.IgnoreReturnValue != this) { // Restore the expression result. generator.LoadVariable(result); generator.ReleaseTemporaryVariable(result); } else { optimizationInfo.ReturnValueWasNotGenerated = true; } }
/// <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) { // Literals cannot have side-effects so if a return value is not expected then generate // nothing. //if (optimizationInfo.SuppressReturnValue == true) // return; if (this.Value is int) { generator.LoadInt32((int)this.Value); } else if (this.Value is double) { generator.LoadDouble((double)this.Value); } else if (this.Value is string) { generator.LoadString((string)this.Value); } else if (this.Value is bool) { generator.LoadBoolean((bool)this.Value); } else if (this.Value is RegularExpressionLiteral) { // RegExp var sharedRegExpVariable = optimizationInfo.GetRegExpVariable(generator, (RegularExpressionLiteral)this.Value); var label1 = generator.CreateLabel(); var label2 = generator.CreateLabel(); // if (sharedRegExp == null) { generator.LoadVariable(sharedRegExpVariable); generator.BranchIfNotNull(label1); // sharedRegExp = Global.RegExp.Construct(source, flags) EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_RegExp); generator.LoadString(((RegularExpressionLiteral)this.Value).Pattern); generator.LoadString(((RegularExpressionLiteral)this.Value).Flags); generator.Call(ReflectionHelpers.RegExp_Construct); generator.Duplicate(); generator.StoreVariable(sharedRegExpVariable); // } else { generator.Branch(label2); generator.DefineLabelPosition(label1); // Global.RegExp.Construct(sharedRegExp, flags) EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_RegExp); generator.LoadVariable(sharedRegExpVariable); generator.LoadNull(); generator.Call(ReflectionHelpers.RegExp_Construct); // } generator.DefineLabelPosition(label2); } else if (this.Value == Null.Value) { // Null. EmitHelpers.EmitNull(generator); } else if (this.Value == Undefined.Value) { // Undefined. EmitHelpers.EmitUndefined(generator); } else { throw new NotImplementedException("Unknown literal type."); } }
/// <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) { // Literals cannot have side-effects so if a return value is not expected then generate // nothing. //if (optimizationInfo.SuppressReturnValue == true) // return; if (this.Value is int) generator.LoadInt32((int)this.Value); else if (this.Value is double) generator.LoadDouble((double)this.Value); else if (this.Value is string) generator.LoadString((string)this.Value); else if (this.Value is bool) generator.LoadBoolean((bool)this.Value); else if (this.Value is RegularExpressionLiteral) { // RegExp var sharedRegExpVariable = optimizationInfo.GetRegExpVariable(generator, (RegularExpressionLiteral)this.Value); var label1 = generator.CreateLabel(); var label2 = generator.CreateLabel(); // if (sharedRegExp == null) { generator.LoadVariable(sharedRegExpVariable); generator.LoadNull(); generator.BranchIfNotEqual(label1); // sharedRegExp = Global.RegExp.Construct(source, flags) EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_RegExp); generator.LoadString(((RegularExpressionLiteral)this.Value).Pattern); generator.LoadString(((RegularExpressionLiteral)this.Value).Flags); generator.Call(ReflectionHelpers.RegExp_Construct); generator.Duplicate(); generator.StoreVariable(sharedRegExpVariable); // } else { generator.Branch(label2); generator.DefineLabelPosition(label1); // Global.RegExp.Construct(sharedRegExp, flags) EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_RegExp); generator.LoadVariable(sharedRegExpVariable); generator.LoadNull(); generator.Call(ReflectionHelpers.RegExp_Construct); // } generator.DefineLabelPosition(label2); } else if (this.Value == Null.Value) { // Null. EmitHelpers.EmitNull(generator); } else if (this.Value == Undefined.Value) { // Undefined. EmitHelpers.EmitUndefined(generator); } else if (this.Value is List<Expression>) { // Construct an array literal. var arrayLiteral = (List<Expression>)this.Value; // Operands for ArrayConstructor.New() are: an ArrayConstructor instance (ArrayConstructor), an array (object[]) // ArrayConstructor EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Array); // object[] generator.LoadInt32(arrayLiteral.Count); generator.NewArray(typeof(object)); for (int i = 0; i < arrayLiteral.Count; i ++) { // Operands for StoreArrayElement() are: an array (object[]), index (int), value (object). // Array generator.Duplicate(); // Index generator.LoadInt32(i); // Value var elementExpression = arrayLiteral[i]; if (elementExpression == null) generator.LoadNull(); else { elementExpression.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, elementExpression.ResultType); } // Store the element value. generator.StoreArrayElement(typeof(object)); } // ArrayConstructor.New(object[]) generator.Call(ReflectionHelpers.Array_New); } else if (this.Value is List<KeyValuePair<Expression, Expression>>) { // This is an object literal. var properties = (List<KeyValuePair<Expression, Expression>>)this.Value; // Create a new object. EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Object); generator.Call(ReflectionHelpers.Object_Construct); foreach (var keyValuePair in properties) { Expression propertyName = keyValuePair.Key; Expression propertyValue = keyValuePair.Value; generator.Duplicate(); // The key can be a property name or an expression that evaluates to a name. propertyName.GenerateCode(generator, optimizationInfo); EmitConversion.ToPropertyKey(generator, propertyName.ResultType); var functionValue = propertyValue as FunctionExpression; if (functionValue != null && functionValue.DeclarationType == FunctionDeclarationType.Getter) { // Add a getter to the object. functionValue.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. if (propertyName is LiteralExpression && ((LiteralExpression)propertyName).Value is string) functionValue.GenerateDisplayName(generator, optimizationInfo, "get " + (string)((LiteralExpression)propertyName).Value, true); generator.Call(ReflectionHelpers.ReflectionHelpers_SetObjectLiteralGetter); } else if(functionValue != null && functionValue.DeclarationType == FunctionDeclarationType.Setter) { // Add a setter to the object. functionValue.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. if (propertyName is LiteralExpression && ((LiteralExpression)propertyName).Value is string) functionValue.GenerateDisplayName(generator, optimizationInfo, "set " + (string)((LiteralExpression)propertyName).Value, true); generator.Call(ReflectionHelpers.ReflectionHelpers_SetObjectLiteralSetter); } else { // Add a new property to the object. propertyValue.GenerateCode(generator, optimizationInfo); // Support the inferred function displayName property. if (propertyValue is FunctionExpression && propertyName is LiteralExpression && ((LiteralExpression)propertyName).Value is string) ((FunctionExpression)propertyValue).GenerateDisplayName(generator, optimizationInfo, (string)((LiteralExpression)propertyName).Value, false); EmitConversion.ToAny(generator, propertyValue.ResultType); generator.Call(ReflectionHelpers.ReflectionHelpers_SetObjectLiteralValue); } } } else throw new NotImplementedException("Unknown literal type."); }