public LoadStringOrNull ( string value ) : void | ||
value | string | The string to push onto the stack. Can be |
return | void |
/// <summary> /// Emits a JavaScriptException. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="type"> The type of error to generate, e.g. Error, RangeError, etc. </param> /// <param name="message"> The error message. </param> /// <param name="path"> The path of the javascript source file that is currently executing. </param> /// <param name="function"> The name of the currently executing function. </param> /// <param name="line"> The line number of the statement that is currently executing. </param> public static void EmitThrow(ILGenerator generator, ErrorType type, string message, string path, string function, int line) { generator.LoadEnumValue(type); generator.LoadString(message); generator.LoadInt32(line); generator.LoadStringOrNull(path); generator.LoadStringOrNull(function); generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error); generator.Throw(); }
/// <summary> /// Generates CIL for the in operator. /// </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 GenerateIn(ILGenerator generator, OptimizationInfo optimizationInfo) { // Emit the left-hand side expression and convert it to a string. this.Left.GenerateCode(generator, optimizationInfo); EmitConversion.ToString(generator, this.Left.ResultType); // Store the left-hand side expression in a temporary variable. var temp = generator.CreateTemporaryVariable(typeof(string)); generator.StoreVariable(temp); // Emit the right-hand side expression. this.Right.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, this.Right.ResultType); // Check the right-hand side is a javascript object - if not, throw an exception. generator.Duplicate(); generator.IsInstance(typeof(ObjectInstance)); var endOfTypeCheck = generator.CreateLabel(); generator.BranchIfTrue(endOfTypeCheck); // Throw an nicely formatted exception. var rightValue = generator.CreateTemporaryVariable(typeof(object)); generator.StoreVariable(rightValue); generator.LoadEnumValue(ErrorType.TypeError); generator.LoadString("The in operator expected an object, but found '{0}' instead"); generator.LoadInt32(1); generator.NewArray(typeof(object)); generator.Duplicate(); generator.LoadInt32(0); generator.LoadVariable(rightValue); generator.Call(ReflectionHelpers.TypeUtilities_TypeOf); generator.StoreArrayElement(typeof(object)); generator.Call(ReflectionHelpers.String_Format); generator.LoadInt32(optimizationInfo.SourceSpan.StartLine); generator.LoadStringOrNull(optimizationInfo.Source.Path); generator.LoadStringOrNull(optimizationInfo.FunctionName); generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error); generator.Throw(); generator.DefineLabelPosition(endOfTypeCheck); generator.ReleaseTemporaryVariable(rightValue); generator.ReinterpretCast(typeof(ObjectInstance)); // Load the left-hand side expression from the temporary variable. generator.LoadVariable(temp); // Call ObjectInstance.HasProperty(object) generator.Call(ReflectionHelpers.ObjectInstance_HasProperty); // Allow the temporary variable to be reused. generator.ReleaseTemporaryVariable(temp); }
/// <summary> /// Emits a JavaScriptException. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="type"> The type of error to generate, e.g. Error, RangeError, etc. </param> /// <param name="message"> The error message. </param> /// <param name="path"> The path of the javascript source file that is currently executing. </param> /// <param name="function"> The name of the currently executing function. </param> /// <param name="line"> The line number of the statement that is currently executing. </param> public static void EmitThrow(ILGenerator generator, ErrorType type, string message, string path, string function, int line) { EmitHelpers.LoadScriptEngine(generator); generator.LoadInt32((int)type); generator.LoadString(message); generator.LoadInt32(line); generator.LoadStringOrNull(path); generator.LoadStringOrNull(function); generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error); generator.Throw(); }
/// <summary> /// Emits a JavaScriptException. /// </summary> /// <param name="generator"> The IL generator. </param> /// <param name="name"> The type of error to generate. </param> /// <param name="message"> The error message. </param> /// <param name="path"> The path of the javascript source file that is currently executing. </param> /// <param name="function"> The name of the currently executing function. </param> /// <param name="line"> The line number of the statement that is currently executing. </param> public static void EmitThrow(ILGenerator generator, string name, string message, string path, string function, int line) { EmitHelpers.LoadScriptEngine(generator); generator.LoadString(name); generator.LoadString(message); generator.LoadInt32(line); generator.LoadStringOrNull(path); generator.LoadStringOrNull(function); generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error); generator.Throw(); }
/// <summary> /// Pushes the value of the reference onto the stack. /// </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="throwIfUnresolvable"> <c>true</c> to throw a ReferenceError exception if /// the name is unresolvable; <c>false</c> to output <c>null</c> instead. </param> public void GenerateGet(ILGenerator generator, OptimizationInfo optimizationInfo, bool throwIfUnresolvable) { // If we have allocated an IL variable, use it. var variableInfo = Scope.FindStaticVariable(Name); if (variableInfo != null && variableInfo.Store != null) { generator.LoadVariable(variableInfo.Store); if (variableInfo.Keyword != KeywordToken.Var) { var afterIf = generator.CreateLabel(); generator.Duplicate(); generator.BranchIfNotNull(afterIf); EmitHelpers.EmitThrow(generator, ErrorType.ReferenceError, $"Cannot access '{Name}' before initialization."); generator.DefineLabelPosition(afterIf); } return; } // Fallback: call RuntimeScope.GetValue() or RuntimeScope.GetValueNoThrow(). Scope.GenerateReference(generator, optimizationInfo); generator.LoadString(Name); generator.LoadInt32(optimizationInfo.SourceSpan.StartLine); generator.LoadStringOrNull(optimizationInfo.Source.Path); generator.Call(throwIfUnresolvable ? ReflectionHelpers.RuntimeScope_GetValue : ReflectionHelpers.RuntimeScope_GetValueNoThrow); }
/// <summary> /// Pops the value on the stack, converts it to a javascript 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> /// <param name="path"> The path of the javascript source file that is currently executing. </param> /// <param name="function"> The name of the currently executing function. </param> /// <param name="line"> The line number of the statement that is currently executing. </param> public static void ToObject(ILGenerator generator, PrimitiveType fromType, string path, string function, int line) { // Check that a conversion is actually necessary. if (fromType == PrimitiveType.Object) { generator.ReinterpretCast(typeof(ObjectInstance)); return; } switch (fromType) { case PrimitiveType.Undefined: // Converting from undefined always throws an exception. EmitHelpers.EmitThrow(generator, ErrorType.TypeError, "Undefined cannot be converted to an object", path, function, line); generator.ReinterpretCast(typeof(ObjectInstance)); break; case PrimitiveType.Null: // Converting from null always throws an exception. EmitHelpers.EmitThrow(generator, ErrorType.TypeError, "Null cannot be converted to an object", path, function, line); generator.ReinterpretCast(typeof(ObjectInstance)); break; case PrimitiveType.Bool: case PrimitiveType.Int32: case PrimitiveType.UInt32: case PrimitiveType.Number: case PrimitiveType.String: case PrimitiveType.ConcatenatedString: case PrimitiveType.Any: // Otherwise, fall back to calling TypeConverter.ToObject() ToAny(generator, fromType); var temp = generator.CreateTemporaryVariable(typeof(object)); generator.StoreVariable(temp); EmitHelpers.LoadScriptEngine(generator); generator.LoadVariable(temp); generator.ReleaseTemporaryVariable(temp); generator.LoadInt32(line); generator.LoadStringOrNull(path); generator.LoadStringOrNull(function); generator.Call(ReflectionHelpers.TypeConverter_ToObject); break; default: throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType)); } }
/// <summary> /// Stores the value on the top of the stack in the reference. /// </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="valueType"> The primitive type of the value that is on the top of the stack. </param> public void GenerateSet(ILGenerator generator, OptimizationInfo optimizationInfo, PrimitiveType valueType) { // TODO: Optimize this. // // ++ or -- // GenerateReference // DuplicateReference // GenerateGet // ToNumber // if (postfix) Dup/Store in variable // Increment/Decrement // if (prefix) Dup/Store in variable // GenerateSet // Load variable // // += // GenerateReference // DuplicateReference // GenerateGet // Dup/Store in variable // GenerateSet // Load variable // // for (in/of) // GenerateReference // LoadVariable(enumerator) // GenerateGet // GenerateSet // // = // GenerateReference // target.GenerateGet // Dup/Store in variable // GenerateSet // Load variable // If we have allocated an IL variable, use it. var variableInfo = Scope.FindStaticVariable(Name); if (variableInfo != null && variableInfo.Store != null) { EmitConversion.Convert(generator, valueType, variableInfo.Type); generator.StoreVariable(variableInfo.Store); return; } // Fallback: call RuntimeScope.SetValue() or RuntimeScope.SetValueStrict(). var temp = generator.CreateTemporaryVariable(valueType); generator.StoreVariable(temp); Scope.GenerateReference(generator, optimizationInfo); generator.LoadString(Name); generator.LoadVariable(temp); EmitConversion.ToAny(generator, valueType); generator.LoadInt32(optimizationInfo.SourceSpan.StartLine); generator.LoadStringOrNull(optimizationInfo.Source.Path); generator.Call(optimizationInfo.StrictMode ? ReflectionHelpers.RuntimeScope_SetValueStrict : ReflectionHelpers.RuntimeScope_SetValue); generator.ReleaseTemporaryVariable(temp); }
/// <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(optimizationInfo.SourceSpan.StartLine); generator.LoadStringOrNull(optimizationInfo.Source.Path); generator.LoadStringOrNull(optimizationInfo.FunctionName); generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Object); generator.Throw(); // Generate code for the end of the statement. GenerateEndOfStatement(generator, optimizationInfo, statementLocals); }
/// <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(optimizationInfo.SourceSpan.StartLine); generator.LoadStringOrNull(optimizationInfo.Source.Path); generator.LoadStringOrNull(optimizationInfo.FunctionName); generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Object); generator.Throw(); // Generate code for the end of the statement. GenerateEndOfStatement(generator, optimizationInfo, statementLocals); }
/// <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) { // Note: we use GetRawOperand() so that grouping operators are not ignored. var operand = this.GetRawOperand(0); // There is only one operand, and it can be either a reference or a function call. // We need to split the operand into a function and some arguments. // If the operand is a reference, it is equivalent to a function call with no arguments. if (operand is FunctionCallExpression) { // Emit the function instance first. var function = ((FunctionCallExpression)operand).Target; function.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, function.ResultType); } else { // Emit the function instance first. operand.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, operand.ResultType); } // Check the object really is a function - if not, throw an exception. generator.IsInstance(typeof(Library.FunctionInstance)); generator.Duplicate(); var endOfTypeCheck = generator.CreateLabel(); generator.BranchIfNotNull(endOfTypeCheck); // Throw an nicely formatted exception. var targetValue = generator.CreateTemporaryVariable(typeof(object)); generator.StoreVariable(targetValue); EmitHelpers.LoadScriptEngine(generator); generator.LoadString("TypeError"); generator.LoadString("The new operator requires a function, found a '{0}' instead"); generator.LoadInt32(1); generator.NewArray(typeof(object)); generator.Duplicate(); generator.LoadInt32(0); generator.LoadVariable(targetValue); generator.Call(ReflectionHelpers.TypeUtilities_TypeOf); generator.StoreArrayElement(typeof(object)); generator.Call(ReflectionHelpers.String_Format); generator.LoadInt32(optimizationInfo.SourceSpan.StartLine); generator.LoadStringOrNull(optimizationInfo.Source.Path); generator.LoadStringOrNull(optimizationInfo.FunctionName); generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error); generator.Throw(); generator.DefineLabelPosition(endOfTypeCheck); generator.ReleaseTemporaryVariable(targetValue); if (operand is FunctionCallExpression) { // Emit an array containing the function arguments. ((FunctionCallExpression)operand).GenerateArgumentsArray(generator, optimizationInfo); } else { // Emit an empty array. generator.LoadInt32(0); generator.NewArray(typeof(object)); } // Call FunctionInstance.ConstructLateBound(argumentValues) generator.Call(ReflectionHelpers.FunctionInstance_ConstructLateBound); }
/// <summary> /// Generates CIL for the in operator. /// </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 GenerateIn(ILGenerator generator, OptimizationInfo optimizationInfo) { // Emit the left-hand side expression and convert it to a string. this.Left.GenerateCode(generator, optimizationInfo); EmitConversion.ToString(generator, this.Left.ResultType); // Store the left-hand side expression in a temporary variable. var temp = generator.CreateTemporaryVariable(typeof(string)); generator.StoreVariable(temp); // Emit the right-hand side expression. this.Right.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, this.Right.ResultType); // Check the right-hand side is a javascript object - if not, throw an exception. generator.IsInstance(typeof(Library.ObjectInstance)); generator.Duplicate(); var endOfTypeCheck = generator.CreateLabel(); generator.BranchIfNotNull(endOfTypeCheck); // Throw an nicely formatted exception. var rightValue = generator.CreateTemporaryVariable(typeof(object)); generator.StoreVariable(rightValue); EmitHelpers.LoadScriptEngine(generator); generator.LoadString("TypeError"); generator.LoadString("The in operator expected an object, but found '{0}' instead"); generator.LoadInt32(1); generator.NewArray(typeof(object)); generator.Duplicate(); generator.LoadInt32(0); generator.LoadVariable(rightValue); generator.Call(ReflectionHelpers.TypeUtilities_TypeOf); generator.StoreArrayElement(typeof(object)); generator.Call(ReflectionHelpers.String_Format); generator.LoadInt32(optimizationInfo.SourceSpan.StartLine); generator.LoadStringOrNull(optimizationInfo.Source.Path); generator.LoadStringOrNull(optimizationInfo.FunctionName); generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error); generator.Throw(); generator.DefineLabelPosition(endOfTypeCheck); generator.ReleaseTemporaryVariable(rightValue); // Load the left-hand side expression from the temporary variable. generator.LoadVariable(temp); // Call ObjectInstance.HasProperty(object) generator.Call(ReflectionHelpers.ObjectInstance_HasProperty); // Allow the temporary variable to be reused. generator.ReleaseTemporaryVariable(temp); }
/// <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) { // Check if this is a direct call to eval(). if (this.Target is NameExpression && ((NameExpression)this.Target).Name == "eval") { GenerateEval(generator, optimizationInfo); return; } // Check if this is a super() call. if (this.Target is SuperExpression) { // executionContext.CallSuperClass(arguments) EmitHelpers.LoadExecutionContext(generator); GenerateArgumentsArray(generator, optimizationInfo); generator.Call(ReflectionHelpers.ExecutionContext_CallSuperClass); return; } // Emit the function instance first. ILLocalVariable targetBase = null; if (this.Target is MemberAccessExpression) { // The function is a member access expression (e.g. "Math.cos()"). // Evaluate the left part of the member access expression. var baseExpression = ((MemberAccessExpression)this.Target).Base; baseExpression.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, baseExpression.ResultType); targetBase = generator.CreateTemporaryVariable(typeof(object)); generator.StoreVariable(targetBase); // Evaluate the right part of the member access expression. var memberAccessExpression = new MemberAccessExpression(((MemberAccessExpression)this.Target).Operator); memberAccessExpression.Push(new TemporaryVariableExpression(targetBase)); memberAccessExpression.Push(((MemberAccessExpression)this.Target).GetOperand(1)); memberAccessExpression.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, this.Target.ResultType); } else { // Something else (e.g. "my_func()"). this.Target.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, this.Target.ResultType); } // Check the object really is a function - if not, throw an exception. generator.Duplicate(); generator.IsInstance(typeof(FunctionInstance)); var endOfTypeCheck = generator.CreateLabel(); generator.BranchIfTrue(endOfTypeCheck); // Throw an nicely formatted exception. generator.Pop(); EmitHelpers.EmitThrow(generator, ErrorType.TypeError, string.Format("'{0}' is not a function", this.Target.ToString()), optimizationInfo); generator.DefineLabelPosition(endOfTypeCheck); // Pass in the path, function name and line. generator.ReinterpretCast(typeof(FunctionInstance)); generator.LoadStringOrNull(optimizationInfo.Source.Path); generator.LoadStringOrNull(optimizationInfo.FunctionName); generator.LoadInt32(optimizationInfo.SourceSpan.StartLine); // Generate code to produce the "this" value. There are three cases. if (this.Target is NameExpression) { // 1. The function is a name expression (e.g. "parseInt()"). // If we are inside a with() block, then there is an implicit 'this' value, // otherwise 'this' is undefined. Scope.GenerateReference(generator, optimizationInfo); generator.Call(ReflectionHelpers.RuntimeScope_ImplicitThis); } else if (this.Target is MemberAccessExpression targetMemberAccessExpression) { // 2. The function is a member access expression (e.g. "Math.cos()"). // In this case this = Math. // Unless it's a super call like super.blah(). if (targetMemberAccessExpression.Base is SuperExpression) { EmitHelpers.LoadThis(generator); } else { generator.LoadVariable(targetBase); } } else { // 3. Neither of the above (e.g. "(function() { return 5 })()") // In this case this = undefined. EmitHelpers.EmitUndefined(generator); } // Emit an array containing the function arguments. GenerateArgumentsArray(generator, optimizationInfo); // Call FunctionInstance.CallLateBound(thisValue, argumentValues) generator.Call(ReflectionHelpers.FunctionInstance_CallWithStackTrace); // Allow reuse of the temporary variable. if (targetBase != null) { generator.ReleaseTemporaryVariable(targetBase); } }
/// <summary> /// Pops the value on the stack, converts it to a javascript 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> /// <param name="path"> The path of the javascript source file that is currently executing. </param> /// <param name="function"> The name of the currently executing function. </param> /// <param name="line"> The line number of the statement that is currently executing. </param> public static void ToObject(ILGenerator generator, PrimitiveType fromType, string path, string function, int line) { // Check that a conversion is actually necessary. if (fromType == PrimitiveType.Object) return; switch (fromType) { case PrimitiveType.Undefined: // Converting from undefined always throws an exception. EmitHelpers.EmitThrow(generator, ErrorType.TypeError, "Undefined cannot be converted to an object", path, function, line); break; case PrimitiveType.Null: // Converting from null always throws an exception. EmitHelpers.EmitThrow(generator, ErrorType.TypeError, "Null cannot be converted to an object", path, function, line); break; case PrimitiveType.Bool: case PrimitiveType.Int32: case PrimitiveType.UInt32: case PrimitiveType.Number: case PrimitiveType.String: case PrimitiveType.ConcatenatedString: case PrimitiveType.Any: // Otherwise, fall back to calling TypeConverter.ToObject() ToAny(generator, fromType); var temp = generator.CreateTemporaryVariable(typeof(object)); generator.StoreVariable(temp); EmitHelpers.LoadScriptEngine(generator); generator.LoadVariable(temp); generator.ReleaseTemporaryVariable(temp); generator.LoadInt32(line); generator.LoadStringOrNull(path); generator.LoadStringOrNull(function); generator.Call(ReflectionHelpers.TypeConverter_ToObject); 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) { // Check if this is a direct call to eval(). if (this.Target is NameExpression && ((NameExpression)this.Target).Name == "eval") { GenerateEval(generator, optimizationInfo); return; } // Emit the function instance first. ILLocalVariable targetBase = null; if (this.Target is MemberAccessExpression) { // The function is a member access expression (e.g. "Math.cos()"). // Evaluate the left part of the member access expression. var baseExpression = ((MemberAccessExpression)this.Target).Base; baseExpression.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, baseExpression.ResultType); targetBase = generator.CreateTemporaryVariable(typeof(object)); generator.StoreVariable(targetBase); // Evaluate the right part of the member access expression. var memberAccessExpression = new MemberAccessExpression(((MemberAccessExpression)this.Target).Operator); memberAccessExpression.Push(new TemporaryVariableExpression(targetBase)); memberAccessExpression.Push(((MemberAccessExpression)this.Target).GetOperand(1)); memberAccessExpression.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, this.Target.ResultType); } else { // Something else (e.g. "eval()"). this.Target.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, this.Target.ResultType); } // Check the object really is a function - if not, throw an exception. generator.IsInstance(typeof(Library.FunctionInstance)); generator.Duplicate(); var endOfTypeCheck = generator.CreateLabel(); generator.BranchIfNotNull(endOfTypeCheck); // Throw an nicely formatted exception. generator.Pop(); EmitHelpers.EmitThrow(generator, "TypeError", string.Format("'{0}' is not a function", this.Target.ToString())); generator.DefineLabelPosition(endOfTypeCheck); // Pass in the path, function name and line. generator.LoadStringOrNull(optimizationInfo.Source.Path); generator.LoadStringOrNull(optimizationInfo.FunctionName); generator.LoadInt32(optimizationInfo.SourceSpan.StartLine); // Generate code to produce the "this" value. There are three cases. if (this.Target is NameExpression) { // 1. The function is a name expression (e.g. "parseInt()"). // In this case this = scope.ImplicitThisValue, if there is one, otherwise undefined. ((NameExpression)this.Target).GenerateThis(generator); } else if (this.Target is MemberAccessExpression) { // 2. The function is a member access expression (e.g. "Math.cos()"). // In this case this = Math. //var baseExpression = ((MemberAccessExpression)this.Target).Base; //baseExpression.GenerateCode(generator, optimizationInfo); //EmitConversion.ToAny(generator, baseExpression.ResultType); generator.LoadVariable(targetBase); } else { // 3. Neither of the above (e.g. "(function() { return 5 })()") // In this case this = undefined. EmitHelpers.EmitUndefined(generator); } // Emit an array containing the function arguments. GenerateArgumentsArray(generator, optimizationInfo); // Call FunctionInstance.CallLateBound(thisValue, argumentValues) generator.Call(ReflectionHelpers.FunctionInstance_CallWithStackTrace); // Allow reuse of the temporary variable. if (targetBase != null) generator.ReleaseTemporaryVariable(targetBase); }
/// <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) { // Note: we use GetRawOperand() so that grouping operators are not ignored. var operand = this.GetRawOperand(0); // There is only one operand, and it can be either a reference or a function call. // We need to split the operand into a function and some arguments. // If the operand is a reference, it is equivalent to a function call with no arguments. if (operand is FunctionCallExpression) { // Emit the function instance first. var function = ((FunctionCallExpression)operand).Target; function.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, function.ResultType); } else { // Emit the function instance first. operand.GenerateCode(generator, optimizationInfo); EmitConversion.ToAny(generator, operand.ResultType); } // Check the object really is a function - if not, throw an exception. generator.IsInstance(typeof(Library.FunctionInstance)); generator.Duplicate(); var endOfTypeCheck = generator.CreateLabel(); generator.BranchIfNotNull(endOfTypeCheck); // Throw an nicely formatted exception. var targetValue = generator.CreateTemporaryVariable(typeof(object)); generator.StoreVariable(targetValue); EmitHelpers.LoadScriptEngine(generator); generator.LoadString("TypeError"); generator.LoadString("The new operator requires a function, found a '{0}' instead"); generator.LoadInt32(1); generator.NewArray(typeof(object)); generator.Duplicate(); generator.LoadInt32(0); generator.LoadVariable(targetValue); generator.Call(ReflectionHelpers.TypeUtilities_TypeOf); generator.StoreArrayElement(typeof(object)); generator.Call(ReflectionHelpers.String_Format); generator.LoadInt32(optimizationInfo.SourceSpan.StartLine); generator.LoadStringOrNull(optimizationInfo.Source.Path); generator.LoadStringOrNull(optimizationInfo.FunctionName); generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error); generator.Throw(); generator.DefineLabelPosition(endOfTypeCheck); generator.ReleaseTemporaryVariable(targetValue); if (operand is FunctionCallExpression) { // Emit an array containing the function arguments. ((FunctionCallExpression)operand).GenerateArgumentsArray(generator, optimizationInfo); } else { // Emit an empty array. generator.LoadInt32(0); generator.NewArray(typeof(object)); } // Call FunctionInstance.ConstructLateBound(argumentValues) generator.Call(ReflectionHelpers.FunctionInstance_ConstructLateBound); }