null
/// <summary> /// Generates CIL for a call to eval(). /// </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 GenerateEval(ILGenerator generator, OptimizationInfo optimizationInfo) { // engine EmitHelpers.LoadScriptEngine(generator); // code if (this.OperandCount < 2) { // No arguments were supplied. generator.LoadNull(); } else { // Take the first argument and convert it to a string. GenerateArgumentsArray(generator, optimizationInfo); generator.LoadInt32(0); generator.LoadArrayElement(typeof(object)); } // scope EmitHelpers.LoadScope(generator); // thisObject EmitHelpers.LoadThis(generator); // strictMode generator.LoadBoolean(optimizationInfo.StrictMode); // Call Global.Eval(engine, code, scope, thisValue, strictMode) generator.Call(ReflectionHelpers.Global_Eval); }
/// <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 statement. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { // Generate code for the start of the statement. var statementLocals = new StatementLocals(); GenerateStartOfStatement(generator, optimizationInfo, statementLocals); // Emit code to throw the given value. this.Value.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, this.Value.ResultType); generator.LoadInt32(0); generator.LoadNull(); generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Object); generator.Throw(); // Generate code for the end of the statement. GenerateEndOfStatement(generator, optimizationInfo, statementLocals); }
/// <summary> /// Deletes the reference and pushes <c>true</c> if the delete succeeded, or <c>false</c> /// if the delete failed. /// </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 void GenerateDelete(ILGenerator generator, OptimizationInfo optimizationInfo) { // Load the left-hand side and convert to an object instance. var lhs = this.GetOperand(0); if (lhs is SuperExpression) { // Deleting a super reference is not allowed. EmitHelpers.EmitThrow(generator, ErrorType.ReferenceError, "Unsupported reference to 'super'."); generator.LoadNull(); // Extraneous, but helps with verification. return; } lhs.GenerateCode(generator, optimizationInfo); EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo); // Load the property name and convert to a string. var rhs = this.GetOperand(1); if (this.OperatorType == OperatorType.MemberAccess) { // delete a.b if (rhs is NameExpression nameExpession) { generator.LoadString(nameExpession.Name); } else { throw new SyntaxErrorException("Invalid member access", optimizationInfo.SourceSpan.StartLine, optimizationInfo.Source.Path, optimizationInfo.FunctionName); } } else { // delete a['1'] rhs.GenerateCode(generator, optimizationInfo); EmitConversion.ToPropertyKey(generator, rhs.ResultType); } // Call Delete() generator.LoadBoolean(optimizationInfo.StrictMode); generator.Call(ReflectionHelpers.ObjectInstance_Delete); // If the return value is not wanted then pop it from the stack. //if (optimizationInfo.SuppressReturnValue == true) // generator.Pop(); }
/// <summary> /// Generates IL for the script. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> protected override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { if (Context != GeneratorContext.Global) { // Declare a variable to store the eval result. optimizationInfo.EvalResult = generator.DeclareVariable(typeof(object)); } // Generate the main body of code. this.AbstractSyntaxTree.GenerateCode(generator, optimizationInfo); if (Context != GeneratorContext.Global) { // Make the return value from the method the eval result. generator.LoadVariable(optimizationInfo.EvalResult); } else { // Code in the global context always returns null. generator.LoadNull(); } }
/// <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) { // Operands for ArrayConstructor.New() are: an ArrayConstructor instance (ArrayConstructor), an array (object[]) // ArrayConstructor EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Array); // object[] generator.LoadInt32(Items.Count); generator.NewArray(typeof(object)); for (int i = 0; i < Items.Count; i++) { // Operands for StoreArrayElement() are: an array (object[]), index (int), value (object). // Array generator.Duplicate(); // Index generator.LoadInt32(i); // Value var elementExpression = Items[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); }
/// <summary> /// Generates code that creates a new scope. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> internal void GenerateScopeCreation(ILGenerator generator, OptimizationInfo optimizationInfo) { // Make sure we don't generate the scope twice. if (GenerateScopeCreationWasCalled) { return; } GenerateScopeCreationWasCalled = true; // We can optimize this away if there are zero variables declared in the scope, // UNLESS it's a with scope (as then we need something to bind to). if (this.variables.Count == 0 && Type != ScopeType.With) { return; } // If there is no eval(), no arguments usage and no nested functions, then we can use // IL variables instead of using RuntimeScope. if ((Type == ScopeType.TopLevelFunction || Type == ScopeType.Block) && optimizationInfo.OptimizeDeclarativeScopes) { foreach (var variable in this.variables.Values) { variable.Store = generator.DeclareVariable(variable.Type, variable.Name); if (variable.Type == PrimitiveType.Any) { generator.LoadNull(); generator.StoreVariable(variable.Store); } } return; } // The fallback: use RuntimeScope. EmitHelpers.LoadExecutionContext(generator); // parentScope if (ParentScope != null) { ParentScope.GenerateReference(generator, optimizationInfo); } else { generator.LoadNull(); } var varList = new List <DeclaredVariable>(); var letList = new List <DeclaredVariable>(); var constList = new List <DeclaredVariable>(); foreach (var variable in this.variables.Values) { if (variable.Keyword == KeywordToken.Var) { varList.Add(variable); } else if (variable.Keyword == KeywordToken.Const) { constList.Add(variable); } else { letList.Add(variable); } } varList.Sort((a, b) => a.Index - b.Index); letList.Sort((a, b) => a.Index - b.Index); constList.Sort((a, b) => a.Index - b.Index); int i; // scopeType generator.LoadEnumValue(Type); // varNames if (varList.Count == 0) { generator.LoadNull(); } else { generator.LoadInt32(varList.Count); generator.NewArray(typeof(string)); i = 0; foreach (var variable in varList) { generator.Duplicate(); generator.LoadInt32(i++); generator.LoadString(variable.Name); generator.StoreArrayElement(typeof(string)); } } // letNames if (letList.Count == 0) { generator.LoadNull(); } else { generator.LoadInt32(letList.Count); generator.NewArray(typeof(string)); i = 0; foreach (var variable in letList) { generator.Duplicate(); generator.LoadInt32(i++); generator.LoadString(variable.Name); generator.StoreArrayElement(typeof(string)); } } // constNames if (constList.Count == 0) { generator.LoadNull(); } else { generator.LoadInt32(constList.Count); generator.NewArray(typeof(string)); i = 0; foreach (var variable in constList) { generator.Duplicate(); generator.LoadInt32(i++); generator.LoadString(variable.Name); generator.StoreArrayElement(typeof(string)); } } // executionContext.CreateRuntimeScope(parentScope, varNames, letNames, constNames) generator.Call(ReflectionHelpers.ExecutionContext_CreateRuntimeScope); // Store the RuntimeScope instance in a variable. GeneratedRuntimeScope = generator.DeclareVariable(typeof(RuntimeScope), "scope"); generator.StoreVariable(GeneratedRuntimeScope); }
/// <summary> /// Pops the value on the stack, converts it from an object to the given type, then pushes /// the result onto the stack. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="toType"> The type to convert to. </param> /// <param name="convertToAddress"> <c>true</c> if the value is intended for use as an /// instance pointer; <c>false</c> otherwise. </param> internal static void EmitConversionToType(ILGenerator generator, Type toType, bool convertToAddress) { // Convert Null.Value to null if the target type is a reference type. ILLabel endOfNullCheck = null; if (toType.IsValueType == false) { var startOfElse = generator.CreateLabel(); endOfNullCheck = generator.CreateLabel(); generator.Duplicate(); EmitHelpers.EmitNull(generator); generator.BranchIfNotEqual(startOfElse); generator.Pop(); generator.LoadNull(); generator.Branch(endOfNullCheck); generator.DefineLabelPosition(startOfElse); } switch (Type.GetTypeCode(toType)) { case TypeCode.Boolean: EmitConversion.ToBool(generator, PrimitiveType.Any); break; case TypeCode.Byte: EmitConversion.ToInt32(generator, PrimitiveType.Any); break; case TypeCode.Char: EmitConversion.ToString(generator, PrimitiveType.Any); generator.Duplicate(); generator.Call(ReflectionHelpers.String_Length); generator.LoadInt32(1); var endOfCharCheck = generator.CreateLabel(); generator.BranchIfEqual(endOfCharCheck); EmitHelpers.EmitThrow(generator, ErrorType.TypeError, "Cannot convert string to char - the string must be exactly one character long"); generator.DefineLabelPosition(endOfCharCheck); generator.LoadInt32(0); generator.Call(ReflectionHelpers.String_GetChars); break; case TypeCode.DBNull: throw new NotSupportedException("DBNull is not a supported parameter type."); case TypeCode.Decimal: EmitConversion.ToNumber(generator, PrimitiveType.Any); generator.NewObject(ReflectionHelpers.Decimal_Constructor_Double); break; case TypeCode.Double: EmitConversion.ToNumber(generator, PrimitiveType.Any); break; case TypeCode.Empty: throw new NotSupportedException("Empty is not a supported return type."); case TypeCode.Int16: EmitConversion.ToInt32(generator, PrimitiveType.Any); break; case TypeCode.Int32: EmitConversion.ToInt32(generator, PrimitiveType.Any); break; case TypeCode.Int64: EmitConversion.ToNumber(generator, PrimitiveType.Any); generator.ConvertToInt64(); break; case TypeCode.DateTime: case TypeCode.Object: // Check if the type must be unwrapped. generator.Duplicate(); generator.IsInstance(typeof(Jurassic.Library.ClrInstanceWrapper)); var endOfUnwrapCheck = generator.CreateLabel(); generator.BranchIfFalse(endOfUnwrapCheck); // Unwrap the wrapped instance. generator.Call(ReflectionHelpers.ClrInstanceWrapper_GetWrappedInstance); generator.DefineLabelPosition(endOfUnwrapCheck); // Value types must be unboxed. if (toType.IsValueType == true) { if (convertToAddress == true) { // Unbox. generator.Unbox(toType); } else { // Unbox and copy to the stack. generator.UnboxAny(toType); } //// Calling methods on value required the address of the value type, not the value type itself. //if (argument.Source == BinderArgumentSource.ThisValue && argument.Type.IsValueType == true) //{ // var temp = generator.CreateTemporaryVariable(argument.Type); // generator.StoreVariable(temp); // generator.LoadAddressOfVariable(temp); // generator.ReleaseTemporaryVariable(temp); //} } break; case TypeCode.SByte: EmitConversion.ToInt32(generator, PrimitiveType.Any); break; case TypeCode.Single: EmitConversion.ToNumber(generator, PrimitiveType.Any); break; case TypeCode.String: EmitConversion.ToString(generator, PrimitiveType.Any); break; case TypeCode.UInt16: EmitConversion.ToInt32(generator, PrimitiveType.Any); break; case TypeCode.UInt32: EmitConversion.ToUInt32(generator, PrimitiveType.Any); break; case TypeCode.UInt64: EmitConversion.ToNumber(generator, PrimitiveType.Any); generator.ConvertToUnsignedInt64(); break; } // Label the end of the null check. if (toType.IsValueType == false) { generator.DefineLabelPosition(endOfNullCheck); } }
/// <summary> /// Generates IL for the script. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> protected override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { // Method signature: object FunctionDelegate(Compiler.Scope scope, object thisObject, Library.FunctionInstance functionObject, object[] arguments) // Initialize the scope (note: the initial scope for a function is always declarative). this.InitialScope.GenerateScopeCreation(generator, optimizationInfo); // Verify the scope is correct. VerifyScope(generator); // In ES3 the "this" value must be an object. See 10.4.3 in the spec. if (this.StrictMode == false && this.MethodOptimizationHints.HasThis == true) { // if (thisObject == null || thisObject == Null.Value || thisObject == Undefined.Value) EmitHelpers.LoadThis(generator); generator.LoadNull(); generator.CompareEqual(); EmitHelpers.LoadThis(generator); EmitHelpers.EmitNull(generator); generator.CompareEqual(); generator.BitwiseOr(); EmitHelpers.LoadThis(generator); EmitHelpers.EmitUndefined(generator); generator.CompareEqual(); generator.BitwiseOr(); // { var startOfFalse = generator.CreateLabel(); generator.BranchIfFalse(startOfFalse); // thisObject = engine.Global; EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Global); // } else { var endOfIf = generator.CreateLabel(); generator.Branch(endOfIf); generator.DefineLabelPosition(startOfFalse); // thisObject = TypeConverter.ToObject(thisObject); EmitHelpers.LoadThis(generator); EmitConversion.ToObject(generator, PrimitiveType.Any); // } generator.DefineLabelPosition(endOfIf); EmitHelpers.StoreThis(generator); } // Transfer the function name into the scope. if (string.IsNullOrEmpty(this.Name) == false && this.ArgumentNames.Contains(this.Name) == false && optimizationInfo.MethodOptimizationHints.HasVariable(this.Name)) { EmitHelpers.LoadFunction(generator); var functionName = new NameExpression(this.InitialScope, this.Name); functionName.GenerateSet(generator, optimizationInfo, PrimitiveType.Any, false); } // Transfer the arguments object into the scope. if (this.MethodOptimizationHints.HasArguments == true && this.ArgumentNames.Contains("arguments") == false) { // prototype EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Object); generator.Call(ReflectionHelpers.FunctionInstance_InstancePrototype); // callee EmitHelpers.LoadFunction(generator); generator.CastClass(typeof(Library.UserDefinedFunction)); // scope EmitHelpers.LoadScope(generator); generator.CastClass(typeof(DeclarativeScope)); // argumentValues EmitHelpers.LoadArgumentsArray(generator); generator.NewObject(ReflectionHelpers.Arguments_Constructor); var arguments = new NameExpression(this.InitialScope, "arguments"); arguments.GenerateSet(generator, optimizationInfo, PrimitiveType.Any, false); } // Transfer the argument values into the scope. // Note: the arguments array can be smaller than expected. if (this.ArgumentNames.Count > 0) { var endOfArguments = generator.CreateLabel(); for (int i = 0; i < this.ArgumentNames.Count; i++) { // Check if a duplicate argument name exists. bool duplicate = false; for (int j = i + 1; j < this.ArgumentNames.Count; j++) if (this.ArgumentNames[i] == this.ArgumentNames[j]) { duplicate = true; break; } if (duplicate == true) continue; // Check if an array element exists. EmitHelpers.LoadArgumentsArray(generator); generator.LoadArrayLength(); generator.LoadInt32(i); generator.BranchIfLessThanOrEqual(endOfArguments); // Store the array element in the scope. EmitHelpers.LoadArgumentsArray(generator); generator.LoadInt32(i); generator.LoadArrayElement(typeof(object)); var argument = new NameExpression(this.InitialScope, this.ArgumentNames[i]); argument.GenerateSet(generator, optimizationInfo, PrimitiveType.Any, false); } generator.DefineLabelPosition(endOfArguments); } // Initialize any declarations. this.InitialScope.GenerateDeclarations(generator, optimizationInfo); //EmitHelpers.LoadScope(generator); //EmitConversion.ToObject(generator, PrimitiveType.Any); //generator.Pop(); // Generate code for the body of the function. this.AbstractSyntaxTree.GenerateCode(generator, optimizationInfo); // Define the return target - this is where the return statement jumps to. // ReturnTarget can be null if there were no return statements. if (optimizationInfo.ReturnTarget != null) generator.DefineLabelPosition(optimizationInfo.ReturnTarget); // Load the return value. If the variable is null, there were no return statements. if (optimizationInfo.ReturnVariable != null) // Return the value stored in the variable. Will be null if execution hits the end // of the function without encountering any return statements. generator.LoadVariable(optimizationInfo.ReturnVariable); else // There were no return statements - return null. generator.LoadNull(); }
/// <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 object, then pushes the result onto the /// stack. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="fromType"> The type to convert from. </param> internal static void EmitConversionToObject(ILGenerator generator, Type fromType) { // If the from type is a reference type, check for null. ILLabel endOfNullCheck = null; if (fromType.IsValueType == false) { var startOfElse = generator.CreateLabel(); endOfNullCheck = generator.CreateLabel(); generator.Duplicate(); generator.BranchIfNotNull(startOfElse); generator.Pop(); EmitHelpers.EmitNull(generator); generator.Branch(endOfNullCheck); generator.DefineLabelPosition(startOfElse); } // Handle Nullable<>. var isNullable = fromType.IsGenericType && fromType.GetGenericTypeDefinition() == typeof(Nullable <>); if (isNullable) { endOfNullCheck = generator.CreateLabel(); var v = generator.CreateTemporaryVariable(fromType); generator.StoreVariable(v); generator.LoadAddressOfVariable(v); var hasValue = ReflectionHelpers.GetInstanceMethod(fromType, "get_HasValue"); generator.Call(hasValue); generator.BranchIfTrue(endOfNullCheck); // Return null. generator.LoadNull(); generator.Return(); // Jump here if it was NOT null. generator.DefineLabelPosition(endOfNullCheck); // Get the underlying value. generator.LoadAddressOfVariable(v); var getValue = ReflectionHelpers.GetInstanceMethod(fromType, "get_Value"); generator.Call(getValue); // Now let the normal conversion work. fromType = fromType.GenericTypeArguments[0]; } switch (Type.GetTypeCode(fromType)) { case TypeCode.Boolean: generator.Box(typeof(bool)); break; case TypeCode.Byte: generator.Box(typeof(int)); break; case TypeCode.Char: generator.LoadInt32(1); generator.NewObject(ReflectionHelpers.String_Constructor_Char_Int); break; case TypeCode.DBNull: throw new NotSupportedException("DBNull is not a supported return type."); case TypeCode.Decimal: generator.Call(ReflectionHelpers.Decimal_ToDouble); generator.Box(typeof(double)); break; case TypeCode.Double: generator.Box(typeof(double)); break; case TypeCode.Empty: throw new NotSupportedException("Empty is not a supported return type."); case TypeCode.Int16: generator.Box(typeof(int)); break; case TypeCode.Int32: generator.Box(typeof(int)); break; case TypeCode.Int64: generator.ConvertToDouble(); generator.Box(typeof(double)); break; case TypeCode.DateTime: case TypeCode.Object: // Check if the type must be wrapped with a ClrInstanceWrapper. // Note: if the type is a value type it cannot be a primitive or it would // have been handled elsewhere in the switch. ILLabel endOfWrapCheck = null; if (fromType.IsValueType == false) { generator.Duplicate(); generator.Call(ReflectionHelpers.TypeUtilities_IsPrimitiveOrObject); endOfWrapCheck = generator.CreateLabel(); generator.BranchIfTrue(endOfWrapCheck); } // The type must be wrapped. var temp = generator.CreateTemporaryVariable(fromType); generator.StoreVariable(temp); generator.LoadArgument(0); generator.LoadVariable(temp); if (fromType.IsValueType == true) { generator.Box(fromType); } generator.ReleaseTemporaryVariable(temp); generator.CallStatic(ReflectionHelpers.ClrInstanceWrapper_Create); // End of wrap check. if (fromType.IsValueType == false) { generator.DefineLabelPosition(endOfWrapCheck); } break; case TypeCode.SByte: generator.Box(typeof(int)); break; case TypeCode.Single: generator.Box(typeof(double)); break; case TypeCode.String: break; case TypeCode.UInt16: generator.Box(typeof(int)); break; case TypeCode.UInt32: generator.Box(typeof(uint)); break; case TypeCode.UInt64: generator.ConvertUnsignedToDouble(); generator.Box(typeof(double)); break; } // Label the end of the null check. if (fromType.IsValueType == false) { generator.DefineLabelPosition(endOfNullCheck); } }
/// <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) { // Generate a new method. this.context.GenerateCode(); // Add the generated method to the nested function list. if (optimizationInfo.NestedFunctions == null) { optimizationInfo.NestedFunctions = new List <GeneratedMethod>(); } optimizationInfo.NestedFunctions.Add(this.context.GeneratedMethod); // Add all the nested methods to the parent list. if (this.context.GeneratedMethod.Dependencies != null) { foreach (var nestedFunctionExpression in this.context.GeneratedMethod.Dependencies) { optimizationInfo.NestedFunctions.Add(nestedFunctionExpression); } } // Store the generated method in the cache. long generatedMethodID = GeneratedMethod.Save(this.context.GeneratedMethod); // Create a UserDefinedFunction. // prototype EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Function); generator.Call(ReflectionHelpers.FunctionInstance_InstancePrototype); // name string prefix = null; if (Name.IsGetter) { prefix = "get "; } else if (Name.IsSetter) { prefix = "set "; } if (Name.HasStaticName) { generator.LoadString(prefix + Name.StaticName); } else { // Compute the name at runtime. if (prefix != null) { generator.LoadString(prefix); } Name.ComputedName.GenerateCode(generator, optimizationInfo); EmitConversion.ToString(generator, Name.ComputedName.ResultType); if (prefix != null) { generator.CallStatic(ReflectionHelpers.String_Concat_String_String); } } // argumentNames generator.LoadInt32(this.Arguments.Count); generator.NewArray(typeof(string)); for (int i = 0; i < this.Arguments.Count; i++) { generator.Duplicate(); generator.LoadInt32(i); generator.LoadString(this.Arguments[i].Name); generator.StoreArrayElement(typeof(string)); } // scope Scope.GenerateReference(generator, optimizationInfo); // bodyText generator.LoadString(this.BodyText); // body generator.LoadInt64(generatedMethodID); generator.Call(ReflectionHelpers.GeneratedMethod_Load); // strictMode generator.LoadBoolean(this.context.StrictMode); // container if (ContainerVariable != null) { generator.LoadVariable(ContainerVariable); } else { generator.LoadNull(); } // CreateFunction(ObjectInstance prototype, string name, IList<string> argumentNames, // RuntimeScope scope, Func<Scope, object, object[], object> body, // bool strictMode, FunctionInstance container) generator.CallStatic(ReflectionHelpers.ReflectionHelpers_CreateFunction); }
/// <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.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> /// Pops the value on the stack, converts it from an object to the given type, then pushes /// the result onto the stack. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="toType"> The type to convert to. </param> /// <param name="convertToAddress"> <c>true</c> if the value is intended for use as an /// instance pointer; <c>false</c> otherwise. </param> internal static void EmitConversionToType(ILGenerator generator, Type toType, bool convertToAddress) { // Convert Null.Value to null if the target type is a reference type. ILLabel endOfNullCheck = null; if (toType.IsValueType == false) { var startOfElse = generator.CreateLabel(); endOfNullCheck = generator.CreateLabel(); generator.Duplicate(); EmitHelpers.EmitNull(generator); generator.BranchIfNotEqual(startOfElse); generator.Pop(); generator.LoadNull(); generator.Branch(endOfNullCheck); generator.DefineLabelPosition(startOfElse); } switch (Type.GetTypeCode(toType)) { case TypeCode.Boolean: EmitConversion.ToBool(generator, PrimitiveType.Any); break; case TypeCode.Byte: EmitConversion.ToInt32(generator, PrimitiveType.Any); break; case TypeCode.Char: EmitConversion.ToString(generator, PrimitiveType.Any); generator.Duplicate(); generator.Call(ReflectionHelpers.String_Length); generator.LoadInt32(1); var endOfCharCheck = generator.CreateLabel(); generator.BranchIfEqual(endOfCharCheck); EmitHelpers.EmitThrow(generator, "TypeError", "Cannot convert string to char - the string must be exactly one character long"); generator.DefineLabelPosition(endOfCharCheck); generator.LoadInt32(0); generator.Call(ReflectionHelpers.String_GetChars); break; case TypeCode.DBNull: throw new NotSupportedException("DBNull is not a supported parameter type."); case TypeCode.Decimal: EmitConversion.ToNumber(generator, PrimitiveType.Any); generator.NewObject(ReflectionHelpers.Decimal_Constructor_Double); break; case TypeCode.Double: EmitConversion.ToNumber(generator, PrimitiveType.Any); break; case TypeCode.Empty: throw new NotSupportedException("Empty is not a supported return type."); case TypeCode.Int16: EmitConversion.ToInt32(generator, PrimitiveType.Any); break; case TypeCode.Int32: EmitConversion.ToInt32(generator, PrimitiveType.Any); break; case TypeCode.Int64: EmitConversion.ToNumber(generator, PrimitiveType.Any); generator.ConvertToInt64(); break; case TypeCode.DateTime: case TypeCode.Object: // Check if the type must be unwrapped. generator.Duplicate(); generator.IsInstance(typeof(Jurassic.Library.ClrInstanceWrapper)); var endOfUnwrapCheck = generator.CreateLabel(); generator.BranchIfFalse(endOfUnwrapCheck); // Unwrap the wrapped instance. generator.Call(ReflectionHelpers.ClrInstanceWrapper_GetWrappedInstance); generator.DefineLabelPosition(endOfUnwrapCheck); // Value types must be unboxed. if (toType.IsValueType == true) { if (convertToAddress == true) // Unbox. generator.Unbox(toType); else // Unbox and copy to the stack. generator.UnboxAny(toType); //// Calling methods on value required the address of the value type, not the value type itself. //if (argument.Source == BinderArgumentSource.ThisValue && argument.Type.IsValueType == true) //{ // var temp = generator.CreateTemporaryVariable(argument.Type); // generator.StoreVariable(temp); // generator.LoadAddressOfVariable(temp); // generator.ReleaseTemporaryVariable(temp); //} } break; case TypeCode.SByte: EmitConversion.ToInt32(generator, PrimitiveType.Any); break; case TypeCode.Single: EmitConversion.ToNumber(generator, PrimitiveType.Any); break; case TypeCode.String: EmitConversion.ToString(generator, PrimitiveType.Any); break; case TypeCode.UInt16: EmitConversion.ToInt32(generator, PrimitiveType.Any); break; case TypeCode.UInt32: EmitConversion.ToUInt32(generator, PrimitiveType.Any); break; case TypeCode.UInt64: EmitConversion.ToNumber(generator, PrimitiveType.Any); generator.ConvertToUnsignedInt64(); break; } // Label the end of the null check. if (toType.IsValueType == false) generator.DefineLabelPosition(endOfNullCheck); }
/// <summary> /// Generates IL for the script. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> protected override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { // Method signature: object FunctionDelegate(Compiler.Scope scope, object thisObject, Library.FunctionInstance functionObject, object[] arguments) // Initialize the scope (note: the initial scope for a function is always declarative). this.BaseScope.GenerateScopeCreation(generator, optimizationInfo); // In ES3 the "this" value must be an object. See 10.4.3 in the spec. if (this.StrictMode == false && this.MethodOptimizationHints.HasThis == true) { // context.ConvertThisToObject(); EmitHelpers.LoadExecutionContext(generator); generator.Call(ReflectionHelpers.ExecutionContext_ConvertThisToObject); } // Transfer the function name into the scope. if (Name.HasStaticName && !Name.IsGetter && !Name.IsSetter && this.Arguments.Any(a => a.Name == Name.StaticName) == false && optimizationInfo.MethodOptimizationHints.HasVariable(Name.StaticName)) { EmitHelpers.LoadFunction(generator); var functionName = new NameExpression(this.BaseScope, Name.StaticName); functionName.GenerateSet(generator, optimizationInfo, PrimitiveType.Any); } // Transfer the arguments object into the scope. if (this.MethodOptimizationHints.HasArguments == true && this.Arguments.Any(a => a.Name == "arguments") == false) { // executionContext.CreateArgumentsInstance(object[] arguments) EmitHelpers.LoadExecutionContext(generator); this.BaseScope.GenerateReference(generator, optimizationInfo); EmitHelpers.LoadArgumentsArray(generator); generator.Call(ReflectionHelpers.ExecutionContext_CreateArgumentsInstance); var arguments = new NameExpression(this.BaseScope, "arguments"); arguments.GenerateSet(generator, optimizationInfo, PrimitiveType.Any); } // Transfer the argument values into the scope. // Note: the arguments array can be smaller than expected. if (this.Arguments.Count > 0) { for (int i = 0; i < this.Arguments.Count; i++) { // Check if a duplicate argument name exists. bool duplicate = false; for (int j = i + 1; j < this.Arguments.Count; j++) { if (this.Arguments[i].Name == this.Arguments[j].Name) { duplicate = true; break; } } if (duplicate == true) { continue; } var loadDefaultValue = generator.CreateLabel(); var storeValue = generator.CreateLabel(); // Check if an array element exists. EmitHelpers.LoadArgumentsArray(generator); generator.LoadArrayLength(); generator.LoadInt32(i); generator.BranchIfLessThanOrEqual(loadDefaultValue); // Load the parameter value from the parameters array. EmitHelpers.LoadArgumentsArray(generator); generator.LoadInt32(i); generator.LoadArrayElement(typeof(object)); if (this.Arguments[i].DefaultValue == null) { // Branch to the part where it stores the value. generator.Branch(storeValue); // Load undefined. generator.DefineLabelPosition(loadDefaultValue); EmitHelpers.EmitUndefined(generator); generator.ReinterpretCast(typeof(object)); } else { // Check if it's undefined. generator.Duplicate(); EmitHelpers.EmitUndefined(generator); generator.ReinterpretCast(typeof(object)); generator.BranchIfNotEqual(storeValue); generator.Pop(); // Load the default value. generator.DefineLabelPosition(loadDefaultValue); this.Arguments[i].DefaultValue.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, this.Arguments[i].DefaultValue.ResultType); } // Store the value in the scope. generator.DefineLabelPosition(storeValue); var argument = new NameExpression(this.BaseScope, this.Arguments[i].Name); argument.GenerateSet(generator, optimizationInfo, PrimitiveType.Any); } } // Initialize any declarations. this.BaseScope.GenerateHoistedDeclarations(generator, optimizationInfo); // Generate code for the body of the function. this.AbstractSyntaxTree.GenerateCode(generator, optimizationInfo); // Define the return target - this is where the return statement jumps to. // ReturnTarget can be null if there were no return statements. if (optimizationInfo.ReturnTarget != null) { generator.DefineLabelPosition(optimizationInfo.ReturnTarget); } // Load the return value. If the variable is null, there were no return statements. if (optimizationInfo.ReturnVariable != null) { // Return the value stored in the variable. Will be null if execution hits the end // of the function without encountering any return statements. generator.LoadVariable(optimizationInfo.ReturnVariable); } else { // There were no return statements - return null. generator.LoadNull(); } }
/// <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 the class was named, then we need to create a new scope to hold the name. if (Name != null) { Scope.GenerateScopeCreation(generator, optimizationInfo); } // engine EmitHelpers.LoadScriptEngine(generator); // name generator.LoadStringOrNull(this.Name); // extends if (Extends == null) { generator.LoadNull(); } else { Extends.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, Extends.ResultType); } // constructor if (Constructor == null) { generator.LoadNull(); } else { Constructor.GenerateCode(generator, optimizationInfo); } // ConstructClass(ScriptEngine engine, string name, object extends, FunctionInstance constructor) generator.CallStatic(ReflectionHelpers.ReflectionHelpers_ConstructClass); // Create a variable to hold the container instance value. var containerVariable = generator.CreateTemporaryVariable(typeof(ObjectInstance)); foreach (var member in this.Members) { // class.InstancePrototype generator.Duplicate(); if (!member.Name.IsStatic) { generator.Call(ReflectionHelpers.FunctionInstance_InstancePrototype); } // Store this in a variable so that FunctionExpression.GenerateCode can retrieve it. generator.Duplicate(); generator.StoreVariable(containerVariable); // The key can be a property name or an expression that evaluates to a name. if (member.Name.HasStaticName) { generator.LoadString(member.Name.StaticName); } else { member.Name.ComputedName.GenerateCode(generator, optimizationInfo); EmitConversion.ToPropertyKey(generator, member.Name.ComputedName.ResultType); } // Emit the function value. member.ContainerVariable = containerVariable; member.GenerateCode(generator, optimizationInfo); member.ContainerVariable = null; if (member.Name.IsGetter) { // Add a getter to the object. generator.Call(ReflectionHelpers.ReflectionHelpers_SetClassGetter); } else if (member.Name.IsSetter) { // Add a setter to the object. generator.Call(ReflectionHelpers.ReflectionHelpers_SetClassSetter); } else { // Add a new property to the object. generator.Call(ReflectionHelpers.ReflectionHelpers_SetClassValue); } } // Release the variable that we created above. generator.ReleaseTemporaryVariable(containerVariable); // Store the class name in the scope. if (Name != null) { generator.Duplicate(); new NameExpression(Scope, Name).GenerateSet(generator, optimizationInfo, PrimitiveType.Object); } }
/// <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> /// 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> /// Generates IL for the script. /// </summary> /// <param name="generator"> The generator to output the CIL to. </param> /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param> protected override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo) { // Method signature: object FunctionDelegate(Compiler.Scope scope, object thisObject, Library.FunctionInstance functionObject, object[] arguments) // Initialize the scope (note: the initial scope for a function is always declarative). this.InitialScope.GenerateScopeCreation(generator, optimizationInfo); // Verify the scope is correct. VerifyScope(generator); // In ES3 the "this" value must be an object. See 10.4.3 in the spec. if (this.StrictMode == false && this.MethodOptimizationHints.HasThis == true) { // if (thisObject == null || thisObject == Null.Value || thisObject == Undefined.Value) EmitHelpers.LoadThis(generator); generator.LoadNull(); generator.CompareEqual(); EmitHelpers.LoadThis(generator); EmitHelpers.EmitNull(generator); generator.CompareEqual(); generator.BitwiseOr(); EmitHelpers.LoadThis(generator); EmitHelpers.EmitUndefined(generator); generator.CompareEqual(); generator.BitwiseOr(); // { var startOfFalse = generator.CreateLabel(); generator.BranchIfFalse(startOfFalse); // thisObject = engine.Global; EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Global); // } else { var endOfIf = generator.CreateLabel(); generator.Branch(endOfIf); generator.DefineLabelPosition(startOfFalse); // thisObject = TypeConverter.ToObject(thisObject); EmitHelpers.LoadThis(generator); EmitConversion.ToObject(generator, PrimitiveType.Any, optimizationInfo); // } generator.DefineLabelPosition(endOfIf); EmitHelpers.StoreThis(generator); } // Transfer the function name into the scope. if (string.IsNullOrEmpty(this.Name) == false && this.IncludeNameInScope == true && this.ArgumentNames.Contains(this.Name) == false && optimizationInfo.MethodOptimizationHints.HasVariable(this.Name)) { EmitHelpers.LoadFunction(generator); var functionName = new NameExpression(this.InitialScope, this.Name); functionName.GenerateSet(generator, optimizationInfo, PrimitiveType.Any, false); } // Transfer the arguments object into the scope. if (this.MethodOptimizationHints.HasArguments == true && this.ArgumentNames.Contains("arguments") == false) { // prototype EmitHelpers.LoadScriptEngine(generator); generator.Call(ReflectionHelpers.ScriptEngine_Object); generator.Call(ReflectionHelpers.FunctionInstance_InstancePrototype); // callee EmitHelpers.LoadFunction(generator); generator.CastClass(typeof(Library.UserDefinedFunction)); // scope EmitHelpers.LoadScope(generator); generator.CastClass(typeof(DeclarativeScope)); // argumentValues EmitHelpers.LoadArgumentsArray(generator); generator.NewObject(ReflectionHelpers.Arguments_Constructor); var arguments = new NameExpression(this.InitialScope, "arguments"); arguments.GenerateSet(generator, optimizationInfo, PrimitiveType.Any, false); } // Transfer the argument values into the scope. // Note: the arguments array can be smaller than expected. if (this.ArgumentNames.Count > 0) { var endOfArguments = generator.CreateLabel(); for (int i = 0; i < this.ArgumentNames.Count; i++) { // Check if a duplicate argument name exists. bool duplicate = false; for (int j = i + 1; j < this.ArgumentNames.Count; j++) { if (this.ArgumentNames[i] == this.ArgumentNames[j]) { duplicate = true; break; } } if (duplicate == true) { continue; } // Check if an array element exists. EmitHelpers.LoadArgumentsArray(generator); generator.LoadArrayLength(); generator.LoadInt32(i); generator.BranchIfLessThanOrEqual(endOfArguments); // Store the array element in the scope. EmitHelpers.LoadArgumentsArray(generator); generator.LoadInt32(i); generator.LoadArrayElement(typeof(object)); var argument = new NameExpression(this.InitialScope, this.ArgumentNames[i]); argument.GenerateSet(generator, optimizationInfo, PrimitiveType.Any, false); } generator.DefineLabelPosition(endOfArguments); } // Initialize any declarations. this.InitialScope.GenerateDeclarations(generator, optimizationInfo); //EmitHelpers.LoadScope(generator); //EmitConversion.ToObject(generator, PrimitiveType.Any); //generator.Pop(); // Generate code for the body of the function. this.AbstractSyntaxTree.GenerateCode(generator, optimizationInfo); // Define the return target - this is where the return statement jumps to. // ReturnTarget can be null if there were no return statements. if (optimizationInfo.ReturnTarget != null) { generator.DefineLabelPosition(optimizationInfo.ReturnTarget); } // Load the return value. If the variable is null, there were no return statements. if (optimizationInfo.ReturnVariable != null) { // Return the value stored in the variable. Will be null if execution hits the end // of the function without encountering any return statements. generator.LoadVariable(optimizationInfo.ReturnVariable); } else { // There were no return statements - return null. generator.LoadNull(); } }
/// <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."); }