/// <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> /// 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> /// 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) { // Deleting a variable is not allowed in strict mode. if (optimizationInfo.StrictMode == true) { throw new SyntaxErrorException($"Cannot delete {Name} because deleting a variable or argument is not allowed in strict mode", optimizationInfo.SourceSpan.StartLine, optimizationInfo.Source.Path, optimizationInfo.FunctionName); } // If we have allocated an IL variable, then always return false, as we don't support // optimizing deletable variables. var variableInfo = Scope.FindStaticVariable(Name); if (variableInfo != null && variableInfo.Store != null) { generator.LoadBoolean(false); return; } Scope.GenerateReference(generator, optimizationInfo); generator.LoadString(Name); generator.Call(ReflectionHelpers.RuntimeScope_Delete); }
/// <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); }