Jurassic.Compiler.NameExpression.GenerateSet C# (CSharp) Method

GenerateSet() public method

Stores the value on the top of the stack in the reference.
public GenerateSet ( ILGenerator generator, OptimizationInfo optimizationInfo, PrimitiveType valueType, bool throwIfUnresolvable ) : void
generator ILGenerator The generator to output the CIL to.
optimizationInfo OptimizationInfo Information about any optimizations that should be performed.
valueType PrimitiveType The primitive type of the value that is on the top of the stack.
throwIfUnresolvable bool true to throw a ReferenceError exception if /// the name is unresolvable; false to create a new property instead.
return void
        public void GenerateSet(ILGenerator generator, OptimizationInfo optimizationInfo, PrimitiveType valueType, bool throwIfUnresolvable)
        {
            // The value is initially on the top of the stack but is stored in this variable
            // at the last possible moment.
            ILLocalVariable value = null;

            var scope = this.Scope;
            ILLocalVariable scopeVariable = null;
            var endOfSet = generator.CreateLabel();
            do
            {
                if (scope is DeclarativeScope)
                {
                    // Get information about the variable.
                    var variable = scope.GetDeclaredVariable(this.Name);
                    if (variable != null)
                    {
                        // The variable was declared in this scope.

                        if (scope.ExistsAtRuntime == false)
                        {
                            // The scope has been optimized away.  The value of the variable is stored
                            // in an ILVariable.

                            // Declare an IL local variable if no storage location has been allocated yet.
                            if (variable.Store == null)
                                variable.Store = generator.DeclareVariable(typeof(object), variable.Name);

                            if (value == null)
                            {
                                // The value to store is on the top of the stack - convert it to the
                                // storage type of the variable.
                                EmitConversion.Convert(generator, valueType, variable.Type, optimizationInfo);
                            }
                            else
                            {
                                // The value to store is in a temporary variable.
                                generator.LoadVariable(value);
                                EmitConversion.Convert(generator, PrimitiveType.Any, variable.Type, optimizationInfo);
                            }

                            // Store the value in the variable.
                            generator.StoreVariable(variable.Store);
                        }
                        else if (variable.Writable == true)
                        {
                            if (value == null)
                            {
                                // The value to store is on the top of the stack - convert it to an
                                // object and store it in a temporary variable.
                                EmitConversion.Convert(generator, valueType, PrimitiveType.Any, optimizationInfo);
                                value = generator.CreateTemporaryVariable(typeof(object));
                                generator.StoreVariable(value);
                            }

                            // scope.Values[index] = value
                            if (scopeVariable == null)
                                EmitHelpers.LoadScope(generator);
                            else
                                generator.LoadVariable(scopeVariable);
                            generator.CastClass(typeof(DeclarativeScope));
                            generator.Call(ReflectionHelpers.DeclarativeScope_Values);
                            generator.LoadInt32(variable.Index);
                            generator.LoadVariable(value);
                            generator.StoreArrayElement(typeof(object));
                        }
                        else
                        {
                            // The variable exists, but is read-only.
                            // Pop the value off the stack (if it is still there).
                            if (value == null)
                                generator.Pop();
                        }

                        // The variable was found - no need to search any more parent scopes.
                        break;
                    }
                    else
                    {
                        // The variable was not defined at compile time, but may have been
                        // introduced by an eval() statement.
                        if (optimizationInfo.MethodOptimizationHints.HasEval == true)
                        {
                            if (value == null)
                            {
                                // The value to store is on the top of the stack - convert it to an
                                // object and store it in a temporary variable.
                                EmitConversion.Convert(generator, valueType, PrimitiveType.Any, optimizationInfo);
                                value = generator.CreateTemporaryVariable(typeof(object));
                                generator.StoreVariable(value);
                            }

                            // Check the variable exists: if (scope.HasValue(variableName) == true) {
                            if (scopeVariable == null)
                                EmitHelpers.LoadScope(generator);
                            else
                                generator.LoadVariable(scopeVariable);
                            generator.CastClass(typeof(DeclarativeScope));
                            generator.LoadString(this.Name);
                            generator.Call(ReflectionHelpers.Scope_HasValue);
                            var hasValueClause = generator.CreateLabel();
                            generator.BranchIfFalse(hasValueClause);

                            // Set the value of the variable.
                            if (scopeVariable == null)
                                EmitHelpers.LoadScope(generator);
                            else
                                generator.LoadVariable(scopeVariable);
                            generator.CastClass(typeof(DeclarativeScope));
                            generator.LoadString(this.Name);
                            generator.LoadVariable(value);
                            generator.Call(ReflectionHelpers.Scope_SetValue);
                            generator.Branch(endOfSet);

                            // }
                            generator.DefineLabelPosition(hasValueClause);
                        }
                    }
                }
                else
                {
                    if (value == null)
                    {
                        // The value to store is on the top of the stack - convert it to an
                        // object and store it in a temporary variable.
                        EmitConversion.Convert(generator, valueType, PrimitiveType.Any, optimizationInfo);
                        value = generator.CreateTemporaryVariable(typeof(object));
                        generator.StoreVariable(value);
                    }

                    if (scope.ParentScope == null)
                    {
                        // Optimization: if this is the global scope, use hidden classes to
                        // optimize variable access.

                        // Global variable modification
                        // ----------------------------
                        // __object_cacheKey = null;
                        // __object_property_cachedIndex = 0;
                        // ...
                        // if (__object_cacheKey != object.InlineCacheKey)
                        //     object.InlineSetPropertyValueIfExists("property", value, strictMode, out __object_property_cachedIndex, out __object_cacheKey)
                        // else
                        //     object.InlinePropertyValues[__object_property_cachedIndex] = value;

                        // Get a reference to the global object.
                        if (scopeVariable == null)
                            EmitHelpers.LoadScope(generator);
                        else
                            generator.LoadVariable(scopeVariable);
                        generator.CastClass(typeof(ObjectScope));
                        generator.Call(ReflectionHelpers.ObjectScope_ScopeObject);

                        // TODO: share these variables somehow.
                        var cacheKey = generator.DeclareVariable(typeof(object));
                        var cachedIndex = generator.DeclareVariable(typeof(int));

                        // Store the object into a temp variable.
                        var objectInstance = generator.DeclareVariable(PrimitiveType.Object);
                        generator.StoreVariable(objectInstance);

                        // if (__object_cacheKey != object.InlineCacheKey)
                        generator.LoadVariable(cacheKey);
                        generator.LoadVariable(objectInstance);
                        generator.Call(ReflectionHelpers.ObjectInstance_InlineCacheKey);
                        var elseClause = generator.CreateLabel();
                        generator.BranchIfEqual(elseClause);

                        // xxx = object.InlineSetPropertyValueIfExists("property", value, strictMode, out __object_property_cachedIndex, out __object_cacheKey)
                        generator.LoadVariable(objectInstance);
                        generator.LoadString(this.Name);
                        generator.LoadVariable(value);
                        generator.LoadBoolean(optimizationInfo.StrictMode);
                        generator.LoadAddressOfVariable(cachedIndex);
                        generator.LoadAddressOfVariable(cacheKey);
                        if (throwIfUnresolvable == false)
                        {
                            // Set the property value unconditionally.
                            generator.Call(ReflectionHelpers.ObjectInstance_InlineSetPropertyValue);
                        }
                        else
                        {
                            // Set the property value if the property exists.
                            generator.Call(ReflectionHelpers.ObjectInstance_InlineSetPropertyValueIfExists);

                            // The return value is true if the property was defined, and false if it wasn't.
                            generator.BranchIfTrue(endOfSet);
                        }

                        var endOfIf = generator.CreateLabel();
                        generator.Branch(endOfIf);

                        // else
                        generator.DefineLabelPosition(elseClause);

                        // object.InlinePropertyValues[__object_property_cachedIndex] = value;
                        generator.LoadVariable(objectInstance);
                        generator.Call(ReflectionHelpers.ObjectInstance_InlinePropertyValues);
                        generator.LoadVariable(cachedIndex);
                        generator.LoadVariable(value);
                        generator.StoreArrayElement(typeof(object));
                        generator.Branch(endOfSet);

                        // End of the if statement
                        generator.DefineLabelPosition(endOfIf);

                    }
                    else
                    {
                        // Slow route.

                        if (scopeVariable == null)
                            EmitHelpers.LoadScope(generator);
                        else
                            generator.LoadVariable(scopeVariable);
                        generator.CastClass(typeof(ObjectScope));
                        generator.Call(ReflectionHelpers.ObjectScope_ScopeObject);
                        generator.LoadString(this.Name);
                        generator.LoadVariable(value);
                        generator.LoadBoolean(optimizationInfo.StrictMode);

                        if (scope.ParentScope == null && throwIfUnresolvable == false)
                        {
                            // Set the property value unconditionally.
                            generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_Object);
                        }
                        else
                        {
                            // Set the property value if the property exists.
                            generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValueIfExists);

                            // The return value is true if the property was defined, and false if it wasn't.
                            generator.BranchIfTrue(endOfSet);
                        }

                    }
                }

                // Try the parent scope.
                if (scope.ParentScope != null && scope.ExistsAtRuntime == true)
                {
                    if (scopeVariable == null)
                    {
                        scopeVariable = generator.CreateTemporaryVariable(typeof(Scope));
                        EmitHelpers.LoadScope(generator);
                    }
                    else
                    {
                        generator.LoadVariable(scopeVariable);
                    }
                    generator.Call(ReflectionHelpers.Scope_ParentScope);
                    generator.StoreVariable(scopeVariable);
                }
                scope = scope.ParentScope;

            } while (scope != null);

            // The value might be still on top of the stack.
            if (value == null && scope == null)
                generator.Pop();

            // Throw an error if the name does not exist and throwIfUnresolvable is true.
            if (scope == null && throwIfUnresolvable == true)
                EmitHelpers.EmitThrow(generator, ErrorType.ReferenceError, this.Name + " is not defined", optimizationInfo);

            // Release the temporary variables.
            if (value != null)
                generator.ReleaseTemporaryVariable(value);
            if (scopeVariable != null)
                generator.ReleaseTemporaryVariable(scopeVariable);

            // Define a label at the end.
            generator.DefineLabelPosition(endOfSet);
        }

Usage Example

Beispiel #1
0
        /// <summary>
        /// Generates code that initializes the variable and function declarations.
        /// </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 virtual void GenerateDeclarations(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Initialize the declared variables and functions.
            foreach (var variable in this.variables.Values)
            {
                // Emit the initialization code.
                if (this is ObjectScope)
                {
                    // Determine the property attributes.
                    var attributes = Library.PropertyAttributes.Enumerable;
                    if (variable.Writable == true)
                    {
                        attributes |= Library.PropertyAttributes.Writable;
                    }
                    if (variable.Deletable == true)
                    {
                        attributes |= Library.PropertyAttributes.Configurable;
                    }

                    if (variable.ValueAtTopOfScope == null)
                    {
                        // void InitializeMissingProperty(object key, PropertyAttributes attributes)
                        EmitHelpers.LoadScope(generator);
                        generator.CastClass(typeof(ObjectScope));
                        generator.Call(ReflectionHelpers.ObjectScope_ScopeObject);
                        generator.LoadString(variable.Name);
                        generator.LoadInt32((int)attributes);
                        generator.Call(ReflectionHelpers.ObjectInstance_InitializeMissingProperty);
                    }
                    else
                    {
                        // bool DefineProperty(string propertyName, PropertyDescriptor descriptor, bool throwOnError)
                        EmitHelpers.LoadScope(generator);
                        generator.CastClass(typeof(ObjectScope));
                        generator.Call(ReflectionHelpers.ObjectScope_ScopeObject);
                        generator.LoadString(variable.Name);
                        variable.ValueAtTopOfScope.GenerateCode(generator, optimizationInfo);
                        EmitConversion.Convert(generator, variable.ValueAtTopOfScope.ResultType, PrimitiveType.Any, optimizationInfo);
                        generator.LoadInt32((int)attributes);
                        generator.NewObject(ReflectionHelpers.PropertyDescriptor_Constructor2);
                        generator.LoadBoolean(false);
                        generator.Call(ReflectionHelpers.ObjectInstance_DefineProperty);
                        generator.Pop();
                    }
                }
                else if (variable.ValueAtTopOfScope != null)
                {
                    variable.ValueAtTopOfScope.GenerateCode(generator, optimizationInfo);
                    var name = new NameExpression(this, variable.Name);
                    name.GenerateSet(generator, optimizationInfo, variable.ValueAtTopOfScope.ResultType, false);
                }
            }
        }
All Usage Examples Of Jurassic.Compiler.NameExpression::GenerateSet