/// <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) { if (optimizationInfo.RootExpression == this) { // Return isn't in use. Do nothing. Left.GenerateCode(generator, optimizationInfo); Right.GenerateCode(generator, optimizationInfo); generator.Pop(); generator.Pop(); return; } // Dynamic resolve required (The 'Evaluate' method above diverts away otherwise). // Engine required: EmitHelpers.LoadEngine(generator); // Emit the object: Right.GenerateCode(generator, optimizationInfo); // Emit the left-hand side expression and convert it to a string. Left.GenerateCode(generator, optimizationInfo); EmitConversion.ToString(generator, Left.GetResultType(optimizationInfo)); // Property name is now on the stack too. // Emit the property test: generator.Call(ReflectionHelpers.Object_HasProperty); }
/// <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) { // This code is only used for untagged template literals. // Tagged template literals are handled by FunctionCallExpression. // Load the values array onto the stack. generator.LoadInt32(this.Strings.Count + this.Values.Count); generator.NewArray(typeof(string)); for (int i = 0; i < this.Strings.Count; i++) { // Operands for StoreArrayElement() are: an array (string[]), index (int), value (string). // Store the string. generator.Duplicate(); generator.LoadInt32(i * 2); generator.LoadString(this.Strings[i]); generator.StoreArrayElement(typeof(string)); if (i == this.Strings.Count - 1) { break; } // Store the value. generator.Duplicate(); generator.LoadInt32(i * 2 + 1); Values[i].GenerateCode(generator, optimizationInfo); EmitConversion.ToString(generator, Values[i].GetResultType(optimizationInfo)); generator.StoreArrayElement(typeof(string)); } // Call String.Concat(string[]) generator.CallStatic(ReflectionHelpers.String_Concat); }
/// <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> /// <param name="throwIfUnresolvable"> <c>true</c> to throw a ReferenceError exception if /// the name is unresolvable; <c>false</c> to create a new property instead. </param> public void GenerateSet(ILGenerator generator, OptimizationInfo optimizationInfo, bool rIU, Type valueType, SetValueMethod value, bool throwIfUnresolvable) { if (ResolvedProperty == null) { // Dynamic property access // ----------------------- // xxx = object.Set(x) // Load the left-hand side: var lhs = this.GetOperand(0); // -- Begin args for Prototype.SetPropertyValue -- // Script engine (engine): EmitHelpers.LoadEngine(generator); // Put LHS object onto stack now (thisObj): lhs.GenerateCode(generator, optimizationInfo); // What type have we now got on the stack? Typically expected to be 'object'. Type lhsType = lhs.GetResultType(optimizationInfo); // Ensure it's boxed (still thisObj): EmitConversion.ToAny(generator, lhsType); // Load the property name and convert to a string. var rhs = this.GetOperand(1); rhs.GenerateCode(generator, optimizationInfo); EmitConversion.ToString(generator, rhs.GetResultType(optimizationInfo)); if (rIU) { // Output the value now (twice): value(true); // We now have [obj][value][value] on the stack. // Calling the set method would fail (as it'll operate on the duplicated value). // So, we have to pop one off and re-add it after. // In order for SetValue to work, we need to shove the 2nd copy into a temp variable. ILLocalVariable localVar = generator.DeclareVariable(valueType); // Store into the local: generator.StoreVariable(localVar); // Set the value: generator.Call(ReflectionHelpers.Object_SetPropertyValue); // Load from the local: generator.LoadVariable(localVar); } else { // Output the value now: value(false); // Set the value: generator.Call(ReflectionHelpers.Object_SetPropertyValue); } } else if (isArrayIndex) { // Array indexer // ------------- // object[index] = x // Load the left-hand side and convert to an object instance. var lhs = this.GetOperand(0); lhs.GenerateCode(generator, optimizationInfo); // Load the right-hand side and convert to int32/uint32/whatever the indexer function wants. var rhs = this.GetOperand(1); rhs.GenerateCode(generator, optimizationInfo); // Convert the index: EmitConversion.Convert(generator, rhs.GetResultType(optimizationInfo), ResolvedProperty.FirstIndexType); // Call set: ResolvedProperty.Set(generator, optimizationInfo, rIU, valueType, value); } else { // Named property modification (e.g. x.property = y) // ------------------------------------------------- if (ResolvedProperty.HasEngine) { // Emit the engine ref: EmitHelpers.LoadEngine(generator); } if (ResolvedProperty.HasAccessor) { // Load the left-hand side: var lhs = GetOperand(0); lhs.GenerateCode(generator, optimizationInfo); } // Target object is now on the stack. // Set it: ResolvedProperty.Set(generator, optimizationInfo, rIU, valueType, value); } }
/// <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 (ResolvedProperty == null) { // Dynamic access. // optimizationInfo.TypeError("Attempted to get a property dynamically. Currently unsupported."); // Load the left-hand side: var lhs = this.GetOperand(0); // -- Begin args for Prototype.GetPropertyValue -- // Script engine (engine): EmitHelpers.LoadEngine(generator); // Emit LHS to the stack (thisObj): lhs.GenerateCode(generator, optimizationInfo); // What type have we now got on the stack? Expected to be just 'object'. Type lhsType = lhs.GetResultType(optimizationInfo); // Ensure it's boxed (still thisObj): EmitConversion.ToAny(generator, lhsType); // Load the property name and convert to a string (property). var rhs = this.GetOperand(1); rhs.GenerateCode(generator, optimizationInfo); EmitConversion.ToString(generator, rhs.GetResultType(optimizationInfo)); // Get the value: generator.Call(ReflectionHelpers.Object_GetPropertyValue); // Either it's now on the stack, or we threw a null ref. } else if (isArrayIndex) { // Array indexer // ------------- // xxx = object[index] // Load the left-hand side var lhs = this.GetOperand(0); lhs.GenerateCode(generator, optimizationInfo); // Load the right-hand side and convert to [theTypeHere] (typically int32). var rhs = this.GetOperand(1); rhs.GenerateCode(generator, optimizationInfo); // Convert the index: EmitConversion.Convert(generator, rhs.GetResultType(optimizationInfo), ResolvedProperty.FirstIndexType); // Emit a get for the indexer: ResolvedProperty.Get(generator); } else { // Load the left-hand side and convert to an object instance. var lhs = this.GetOperand(0); if (ResolvedProperty != null) { if (ResolvedProperty.HasEngine) { // Emit the engine ref: EmitHelpers.LoadEngine(generator); } if (ResolvedProperty.HasAccessor) { // Emit the 'this' obj: lhs.GenerateCode(generator, optimizationInfo); } // Emit a get: ResolvedProperty.Get(generator); } } }