Outputs IL for misc tasks.
Ejemplo n.º 1
0
        /// <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)
        {
            // Declare a variable to store the eval result.
            optimizationInfo.EvalResult = generator.DeclareVariable(typeof(object));

            if (this.StrictMode == true)
            {
                // Create a new scope.
                this.InitialScope.GenerateScopeCreation(generator, optimizationInfo);
            }

            // Initialize any declarations.
            this.InitialScope.GenerateDeclarations(generator, optimizationInfo);

            // Generate the main body of code.
            this.AbstractSyntaxTree.GenerateCode(generator, optimizationInfo);

            // Make the return value from the method the eval result.
            generator.LoadVariable(optimizationInfo.EvalResult);

            // If the result is null, convert it to undefined.
            var end = generator.CreateLabel();

            generator.Duplicate();
            generator.BranchIfNotNull(end);
            generator.Pop();
            EmitHelpers.EmitUndefined(generator);
            generator.DefineLabelPosition(end);
        }
Ejemplo n.º 2
0
        /// <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);
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 4
0
 /// <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>
 public static void EmitThrow(ILGenerator generator, string name, string message)
 {
     EmitHelpers.LoadScriptEngine(generator);
     generator.LoadString(name);
     generator.LoadString(message);
     generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error);
     generator.Throw();
 }
Ejemplo n.º 5
0
        /// <summary>
        /// Pops the value on the stack, converts it to the given type, 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="toType"> The type to convert to. </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 Convert(ILGenerator generator, PrimitiveType fromType, PrimitiveType toType, string path, string function, int line)
        {
            // Check that a conversion is actually necessary.
            if (fromType == toType)
            {
                return;
            }

            switch (toType)
            {
            case PrimitiveType.Any:
                ToAny(generator, fromType);
                break;

            case PrimitiveType.Undefined:
                generator.Pop();
                EmitHelpers.EmitUndefined(generator);
                break;

            case PrimitiveType.Null:
                generator.Pop();
                EmitHelpers.EmitNull(generator);
                break;

            case PrimitiveType.Bool:
                ToBool(generator, fromType);
                break;

            case PrimitiveType.Int32:
                ToInt32(generator, fromType);
                break;

            case PrimitiveType.UInt32:
                ToUInt32(generator, fromType);
                break;

            case PrimitiveType.Number:
                ToNumber(generator, fromType);
                break;

            case PrimitiveType.String:
                ToString(generator, fromType);
                break;

            case PrimitiveType.ConcatenatedString:
                ToConcatenatedString(generator, fromType);
                break;

            case PrimitiveType.Object:
                ToObject(generator, fromType, path, function, line);
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", toType));
            }
        }
Ejemplo n.º 6
0
 /// <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();
 }
Ejemplo n.º 7
0
        /// <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(Library.ObjectInstance));
            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.LoadInt32((int)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);

            // 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);
        }
Ejemplo n.º 8
0
        /// <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)
        {
            // Initialize any function or variable declarations.
            this.InitialScope.GenerateDeclarations(generator, optimizationInfo);

            // Generate code for the source code.
            this.AbstractSyntaxTree.GenerateCode(generator, optimizationInfo);

            // Code in the global context always returns undefined.
            EmitHelpers.EmitUndefined(generator);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Generates code that restores the parent scope as the active 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 GenerateScopeDestruction(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            if (this.ExistsAtRuntime == false)
            {
                return;
            }

            // Modify the scope variable so it points at the parent scope.
            EmitHelpers.LoadScope(generator);
            generator.Call(ReflectionHelpers.Scope_ParentScope);
            EmitHelpers.StoreScope(generator);
        }
Ejemplo n.º 10
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);
                }
            }
        }
Ejemplo n.º 11
0
        /// <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 the return value.
            if (this.Value == null)
            {
                EmitHelpers.EmitUndefined(generator);
            }
            else
            {
                this.Value.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, this.Value.ResultType);
            }

            // Determine if this is the last statement in the function.
            bool lastStatement = optimizationInfo.AbstractSyntaxTree is BlockStatement &&
                                 ((BlockStatement)optimizationInfo.AbstractSyntaxTree).Statements.Count > 0 &&
                                 ((BlockStatement)optimizationInfo.AbstractSyntaxTree).Statements[((BlockStatement)optimizationInfo.AbstractSyntaxTree).Statements.Count - 1] == this;

            // The first return statement initializes the variable that holds the return value.
            if (optimizationInfo.ReturnVariable == null)
            {
                optimizationInfo.ReturnVariable = generator.DeclareVariable(typeof(object), "returnValue");
            }

            // Store the return value in a variable.
            generator.StoreVariable(optimizationInfo.ReturnVariable);

            // There is no need to jump to the end of the function if this is the last statement.
            if (lastStatement == false)
            {
                // The first return statement that needs to branch creates the return label.  This is
                // defined in FunctionmethodGenerator.GenerateCode() at the end of the function.
                if (optimizationInfo.ReturnTarget == null)
                {
                    optimizationInfo.ReturnTarget = generator.CreateLabel();
                }

                // Branch to the end of the function.  Note: the return statement might be branching
                // from inside a try { } or finally { } block to outside.  EmitLongJump() handles this.
                optimizationInfo.EmitLongJump(generator, optimizationInfo.ReturnTarget);
            }

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
Ejemplo n.º 12
0
 /// <summary>
 /// Pushes the result of converting <c>undefined</c> to the given type onto the stack.
 /// </summary>
 /// <param name="il"> The IL generator. </param>
 /// <param name="targetParameter"> The type to convert to, and optionally a default value. </param>
 private static void EmitUndefined(ILGenerator il, BinderArgument argument)
 {
     // Emit either the default value if there is one, otherwise emit "undefined".
     if (argument.HasDefaultValue == true)
     {
         // Emit the default value.
         EmitHelpers.EmitValue(il, argument.DefaultValue);
     }
     else
     {
         // Convert Undefined to the target type and emit.
         EmitHelpers.EmitUndefined(il);
         EmitTypeConversion(il, typeof(object), argument.Type);
     }
 }
Ejemplo n.º 13
0
        /// <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));
            }
        }
Ejemplo n.º 14
0
        /// <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();
        }
Ejemplo n.º 15
0
 /// <summary>
 /// Generates code that pushes a RuntimeScope instance to the top of 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>
 internal void GenerateReference(ILGenerator generator, OptimizationInfo optimizationInfo)
 {
     if (!GenerateScopeCreationWasCalled)
     {
         GenerateScopeCreation(generator, optimizationInfo);
     }
     if (GeneratedRuntimeScope != null)
     {
         generator.LoadVariable(GeneratedRuntimeScope);
     }
     else if (ParentScope != null)
     {
         ParentScope.GenerateReference(generator, optimizationInfo);
     }
     else
     {
         EmitHelpers.LoadExecutionContext(generator);
         generator.CallVirtual(ReflectionHelpers.ExecutionContext_ParentScope);
     }
 }
Ejemplo n.º 16
0
        /// <summary>
        /// Generates a method that does type conversion and calls the bound method.
        /// </summary>
        /// <param name="generator"> The ILGenerator used to output the body of the method. </param>
        /// <param name="argumentCount"> The number of arguments that will be passed to the delegate. </param>
        /// <returns> A delegate that does type conversion and calls the method represented by this
        /// object. </returns>
        protected override void GenerateStub(ILGenerator generator, int argumentCount)
        {
            // Check for the correct number of arguments.
            if (argumentCount != 0)
            {
                EmitHelpers.EmitThrow(generator, ErrorType.TypeError, "Wrong number of arguments");
                EmitHelpers.EmitDefaultValue(generator, PrimitiveType.Any);
                generator.Complete();
                return;
            }

            if (this.field.IsStatic == false)
            {
                generator.LoadArgument(1);
                ClrBinder.EmitConversionToType(generator, this.field.DeclaringType, convertToAddress: true);
            }
            generator.LoadField(this.field);
            ClrBinder.EmitConversionToObject(generator, this.field.FieldType);
            generator.Complete();
        }
Ejemplo n.º 17
0
        /// <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 override void GenerateScopeCreation(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Allocate storage for each variable if the declarative scope object has been optimized away.
            if (optimizationInfo.OptimizeDeclarativeScopes == false)
            {
                // Create a new declarative scope.

                // parentScope
                EmitHelpers.LoadScope(generator);

                // declaredVariableNames
                generator.LoadInt32(this.DeclaredVariableCount);
                generator.NewArray(typeof(string));
                int i = 0;
                foreach (string variableName in this.DeclaredVariableNames)
                {
                    generator.Duplicate();
                    generator.LoadInt32(i++);
                    generator.LoadString(variableName);
                    generator.StoreArrayElement(typeof(string));
                }

                // DeclarativeScope.CreateRuntimeScope(parentScope, declaredVariableNames)
                generator.Call(ReflectionHelpers.DeclarativeScope_CreateRuntimeScope);

                // Save the new scope.
                EmitHelpers.StoreScope(generator);
            }
            else
            {
                // The declarative scope can be optimized away entirely.
                foreach (var variable in this.DeclaredVariables)
                {
                    variable.Store = null;
                    variable.Type  = PrimitiveType.Any;
                }

                // Indicate the scope was not created.
                this.ExistsAtRuntime = false;
            }
        }
Ejemplo n.º 18
0
        /// <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 override void GenerateScopeCreation(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Create a new runtime object scope.
            EmitHelpers.LoadScope(generator);  // parent scope
            if (this.ScopeObjectExpression == null)
            {
                EmitHelpers.LoadScriptEngine(generator);
                generator.Call(ReflectionHelpers.ScriptEngine_Global);
            }
            else
            {
                this.ScopeObjectExpression.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToObject(generator, this.ScopeObjectExpression.ResultType, optimizationInfo);
            }
            generator.LoadBoolean(this.ProvidesImplicitThisValue);
            generator.LoadBoolean(this.CanDeclareVariables);
            generator.Call(ReflectionHelpers.ObjectScope_CreateRuntimeScope);

            // Save the new scope.
            EmitHelpers.StoreScope(generator);
        }
Ejemplo n.º 19
0
        /// <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);
        }
Ejemplo n.º 20
0
 /// <summary>
 /// Generates a method that does type conversion and calls the bound method.
 /// </summary>
 /// <param name="generator"> The ILGenerator used to output the body of the method. </param>
 /// <param name="argumentCount"> The number of arguments that will be passed to the delegate. </param>
 /// <returns> A delegate that does type conversion and calls the method represented by this
 /// object. </returns>
 protected override void GenerateStub(ILGenerator generator, int argumentCount)
 {
     // Check for the correct number of arguments.
     if (argumentCount != 1)
     {
         EmitHelpers.EmitThrow(generator, "TypeError", "Wrong number of arguments");
         EmitHelpers.EmitDefaultValue(generator, PrimitiveType.Any);
         generator.Complete();
         return;
     }
     if (this.field.IsStatic == false)
     {
         generator.LoadArgument(1);
         ClrBinder.EmitConversionToType(generator, this.field.DeclaringType, convertToAddress: true);
     }
     generator.LoadArgument(2);
     generator.LoadInt32(0);
     generator.LoadArrayElement(typeof(object));
     ClrBinder.EmitConversionToType(generator, this.field.FieldType, convertToAddress: false);
     generator.StoreField(this.field);
     EmitHelpers.EmitUndefined(generator);
     generator.Complete();
 }
        /// <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();
            }
        }
Ejemplo n.º 22
0
        /// <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)
        {
            // The left hand side needs to be a variable reference or member access.
            var target = this.GetOperand(0) as IReferenceExpression;

            if (target == null)
            {
                // Emit an error message.
                switch (this.OperatorType)
                {
                case OperatorType.PostIncrement:
                case OperatorType.PostDecrement:
                    EmitHelpers.EmitThrow(generator, "ReferenceError", "Invalid left-hand side in postfix operation", optimizationInfo);
                    break;

                case OperatorType.PreIncrement:
                case OperatorType.PreDecrement:
                    EmitHelpers.EmitThrow(generator, "ReferenceError", "Invalid left-hand side in prefix operation", optimizationInfo);
                    break;

                case OperatorType.Assignment:
                default:
                    EmitHelpers.EmitThrow(generator, "ReferenceError", "Invalid left-hand side in assignment", optimizationInfo);
                    break;
                }
                //if (optimizationInfo.SuppressReturnValue == false)
                EmitHelpers.EmitDefaultValue(generator, this.ResultType);
                return;
            }

            // The left hand side cannot be "arguments" or "eval" in strict mode.
            if (optimizationInfo.StrictMode == true && target is NameExpression)
            {
                if (((NameExpression)target).Name == "eval")
                {
                    throw new JavaScriptException(optimizationInfo.Engine, "SyntaxError", "The variable 'eval' cannot be modified in strict mode.", optimizationInfo.SourceSpan.StartLine, optimizationInfo.Source.Path, optimizationInfo.FunctionName);
                }
                if (((NameExpression)target).Name == "arguments")
                {
                    throw new JavaScriptException(optimizationInfo.Engine, "SyntaxError", "The variable 'arguments' cannot be modified in strict mode.", optimizationInfo.SourceSpan.StartLine, optimizationInfo.Source.Path, optimizationInfo.FunctionName);
                }
            }

            switch (this.OperatorType)
            {
            case OperatorType.Assignment:
                // Standard assignment operator.
                GenerateAssignment(generator, optimizationInfo, target);
                break;

            case OperatorType.PostIncrement:
                GenerateIncrementOrDecrement(generator, optimizationInfo, target, postfix: true, increment: true);
                break;

            case OperatorType.PostDecrement:
                GenerateIncrementOrDecrement(generator, optimizationInfo, target, postfix: true, increment: false);
                break;

            case OperatorType.PreIncrement:
                GenerateIncrementOrDecrement(generator, optimizationInfo, target, postfix: false, increment: true);
                break;

            case OperatorType.PreDecrement:
                GenerateIncrementOrDecrement(generator, optimizationInfo, target, postfix: false, increment: false);
                break;

            case OperatorType.CompoundAdd:
                // Special case +=
                GenerateCompoundAddAssignment(generator, optimizationInfo, target);
                break;

            default:
                // All other compound operators.
                GenerateCompoundAssignment(generator, optimizationInfo, target);
                break;
            }
        }
Ejemplo n.º 23
0
        /// <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);

            // 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_CallLateBound);

            // Allow reuse of the temporary variable.
            if (targetBase != null)
            {
                generator.ReleaseTemporaryVariable(targetBase);
            }
        }
Ejemplo n.º 24
0
        /// <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.");
            }
        }
Ejemplo n.º 25
0
        /// <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() { NonDefaultSourceSpanBehavior = true };
            GenerateStartOfStatement(generator, optimizationInfo, statementLocals);

            // Unlike in .NET, in javascript there are no restrictions on what can appear inside
            // try, catch and finally blocks.  The one restriction which causes problems is the
            // inability to jump out of .NET finally blocks.  This is required when break, continue
            // or return statements appear inside of a finally block.  To work around this, when
            // inside a finally block these instructions throw an exception instead.

            // Setting the InsideTryCatchOrFinally flag converts BR instructions into LEAVE
            // instructions so that the finally block is executed correctly.
            var previousInsideTryCatchOrFinally = optimizationInfo.InsideTryCatchOrFinally;
            optimizationInfo.InsideTryCatchOrFinally = true;

            // Finally requires two exception nested blocks.
            if (this.FinallyBlock != null)
                generator.BeginExceptionBlock();

            // Begin the exception block.
            generator.BeginExceptionBlock();

            // Generate code for the try block.
            this.TryBlock.GenerateCode(generator, optimizationInfo);

            // Generate code for the catch block.
            ILLocalVariable skipFinallyBlock = null;
           
            
            // Begin a catch block.  The exception is on the top of the stack.
            generator.BeginCatchBlock(typeof(Exception));

            // Check the exception is catchable by calling CanCatchException(ex).
            // We need to handle the case where JS code calls into .NET code which then throws
            // a JavaScriptException from a different ScriptEngine.
            // If CatchBlock is null, we need to rethrow the exception in every case.
            var endOfIfLabel = generator.CreateLabel();
            generator.Duplicate();  // ex
            var exceptionTemporary = generator.CreateTemporaryVariable(typeof(Exception));
            generator.StoreVariable(exceptionTemporary);
            EmitHelpers.LoadScriptEngine(generator);
            generator.LoadVariable(exceptionTemporary);
            generator.ReleaseTemporaryVariable(exceptionTemporary);
            generator.Call(ReflectionHelpers.ScriptEngine_CanCatchException);
            generator.BranchIfTrue(endOfIfLabel);
            if (this.FinallyBlock != null)
            {
                generator.LoadBoolean(true);
                skipFinallyBlock = generator.DeclareVariable(typeof(bool), "skipFinallyBlock");
                generator.StoreVariable(skipFinallyBlock);
            }
            if (this.CatchBlock == null)
                generator.DefineLabelPosition(endOfIfLabel);
            generator.Rethrow();
            if (this.CatchBlock != null)
                generator.DefineLabelPosition(endOfIfLabel);

            if (this.CatchBlock != null) {
                // Create a new DeclarativeScope.
                this.CatchScope.GenerateScopeCreation(generator, optimizationInfo);

                // Store the error object in the variable provided.
                generator.Call(ReflectionHelpers.JavaScriptException_ErrorObject);
                var catchVariable = new NameExpression(this.CatchScope, this.CatchVariableName);
                catchVariable.GenerateSet(generator, optimizationInfo, PrimitiveType.Any, false);

                // Make sure the scope is reverted even if an exception is thrown.
                generator.BeginExceptionBlock();

                // Emit code for the statements within the catch block.
                this.CatchBlock.GenerateCode(generator, optimizationInfo);

                // Revert the scope.
                generator.BeginFinallyBlock();
                this.CatchScope.GenerateScopeDestruction(generator, optimizationInfo);
                generator.EndExceptionBlock();
            }

            // Generate code for the finally block.
            if (this.FinallyBlock != null)
            {
                generator.BeginFinallyBlock();

                // If an exception was thrown that wasn't handled by the catch block, then don't
                // run the finally block either.  This prevents user code from being run when a
                // ThreadAbortException is thrown.
                var endOfFinallyBlock = generator.CreateLabel();                
                generator.LoadVariable(skipFinallyBlock);
                generator.BranchIfTrue(endOfFinallyBlock);

                var branches = new List<ILLabel>();
                var previousStackSize = optimizationInfo.LongJumpStackSizeThreshold;
                optimizationInfo.LongJumpStackSizeThreshold = optimizationInfo.BreakOrContinueStackSize;
                var previousCallback = optimizationInfo.LongJumpCallback;
                optimizationInfo.LongJumpCallback = (generator2, label) =>
                    {
                        // It is not possible to branch out of a finally block - therefore instead of
                        // generating LEAVE instructions we throw an exception then catch it to transfer
                        // control out of the finally block.
                        generator2.LoadInt32(branches.Count);
                        generator2.NewObject(ReflectionHelpers.LongJumpException_Constructor);
                        generator2.Throw();

                        // Record any branches that are made within the finally code.
                        branches.Add(label);
                    };

                // Emit code for the finally block.
                this.FinallyBlock.GenerateCode(generator, optimizationInfo);

                // Define the position at the end of the finally block.
                generator.DefineLabelPosition(endOfFinallyBlock);

                // End the main exception block.
                generator.EndExceptionBlock();

                // Begin a catch block to catch any LongJumpExceptions. The exception object is on
                // the top of the stack.
                generator.BeginCatchBlock(typeof(LongJumpException));

                if (branches.Count > 0)
                {
                    // switch (exception.RouteID)
                    // {
                    //    case 0: goto label1;
                    //    case 1: goto label2;
                    // }
                    ILLabel[] switchLabels = new ILLabel[branches.Count];
                    for (int i = 0; i < branches.Count; i++)
                        switchLabels[i] = generator.CreateLabel();
                    generator.Call(ReflectionHelpers.LongJumpException_RouteID);
                    generator.Switch(switchLabels);
                    for (int i = 0; i < branches.Count; i++)
                    {
                        generator.DefineLabelPosition(switchLabels[i]);
                        generator.Leave(branches[i]);
                    }
                }

                // Reset the state we clobbered.
                optimizationInfo.LongJumpStackSizeThreshold = previousStackSize;
                optimizationInfo.LongJumpCallback = previousCallback;
            }

            // End the exception block.
            generator.EndExceptionBlock();

            // Reset the InsideTryCatchOrFinally flag.
            optimizationInfo.InsideTryCatchOrFinally = previousInsideTryCatchOrFinally;

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
Ejemplo n.º 26
0
        /// <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();
            }
        }
Ejemplo n.º 27
0
        /// <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);
        }
Ejemplo n.º 28
0
        /// <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)
        {
            // This method generates code to retrieve the value of a variable, given the name of
            // variable and scope in which the variable is being referenced.  The variable was
            // not necessary declared in this scope - it might be declared in any of the parent
            // scopes (together called a scope chain).  The general algorithm is to start at the
            // head of the chain and search backwards until the variable is found.  There are
            // two types of scopes: declarative scopes and object scopes.  Object scopes are hard -
            // it cannot be known at compile time whether the variable exists or not so runtime
            // checks have to be inserted.  Declarative scopes are easier - variables have to be
            // declared and cannot be deleted.  There is one tricky bit: new variables can be
            // introduced into a declarative scope at runtime by a non-strict eval() statement.
            // Even worse, variables that were introduced by means of an eval() *can* be deleted.

            var             scope         = this.Scope;
            ILLocalVariable scopeVariable = null;
            var             endOfGet      = generator.CreateLabel();

            do
            {
                if (scope is DeclarativeScope)
                {
                    // The variable was declared in this scope.
                    var variable = scope.GetDeclaredVariable(this.Name);

                    if (variable != null)
                    {
                        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);
                            }

                            // Load the value from the variable.
                            generator.LoadVariable(variable.Store);

                            // Ensure that we match ResultType.
                            EmitConversion.Convert(generator, variable.Type, this.ResultType, optimizationInfo);
                        }
                        else
                        {
                            // scope.Values[index]
                            if (scopeVariable == null)
                            {
                                EmitHelpers.LoadScope(generator);
                            }
                            else
                            {
                                generator.LoadVariable(scopeVariable);
                            }
                            generator.CastClass(typeof(DeclarativeScope));
                            generator.Call(ReflectionHelpers.DeclarativeScope_Values);
                            generator.LoadInt32(variable.Index);
                            generator.LoadArrayElement(typeof(object));
                        }

                        // 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)
                        {
                            // 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);

                            // Load the value of the variable.
                            if (scopeVariable == null)
                            {
                                EmitHelpers.LoadScope(generator);
                            }
                            else
                            {
                                generator.LoadVariable(scopeVariable);
                            }
                            generator.CastClass(typeof(DeclarativeScope));
                            generator.LoadString(this.Name);
                            generator.Call(ReflectionHelpers.Scope_GetValue);
                            generator.Branch(endOfGet);

                            // }
                            generator.DefineLabelPosition(hasValueClause);
                        }
                    }
                }
                else
                {
                    if (scope.ParentScope == null)
                    {
                        // Global variable access
                        // -------------------------------------------
                        // __object_cacheKey = null;
                        // __object_property_cachedIndex = 0;
                        // ...
                        // if (__object_cacheKey != object.InlineCacheKey)
                        //     xxx = object.InlineGetPropertyValue("variable", out __object_property_cachedIndex, out __object_cacheKey)
                        // else
                        //     xxx = object.InlinePropertyValues[__object_property_cachedIndex];

                        // 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);

                        // value = object.InlineGetProperty("property", out __object_property_cachedIndex, out __object_cacheKey)
                        generator.LoadVariable(objectInstance);
                        generator.LoadString(this.Name);
                        generator.LoadAddressOfVariable(cachedIndex);
                        generator.LoadAddressOfVariable(cacheKey);
                        generator.Call(ReflectionHelpers.ObjectInstance_InlineGetPropertyValue);

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

                        // else
                        generator.DefineLabelPosition(elseClause);

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

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

                        // Check if the value is null.
                        generator.Duplicate();
                        generator.BranchIfNotNull(endOfGet);
                        if (scope.ParentScope != null)
                        {
                            generator.Pop();
                        }
                    }
                    else
                    {
                        // Gets the value of a variable in an object scope.
                        if (scopeVariable == null)
                        {
                            EmitHelpers.LoadScope(generator);
                        }
                        else
                        {
                            generator.LoadVariable(scopeVariable);
                        }
                        generator.CastClass(typeof(ObjectScope));
                        generator.Call(ReflectionHelpers.ObjectScope_ScopeObject);
                        generator.LoadString(this.Name);
                        generator.Call(ReflectionHelpers.ObjectInstance_GetPropertyValue_Object);

                        // Check if the value is null.
                        generator.Duplicate();
                        generator.BranchIfNotNull(endOfGet);
                        if (scope.ParentScope != null)
                        {
                            generator.Pop();
                        }
                    }
                }

                // 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);

            // 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 variable.
            if (scopeVariable != null)
            {
                generator.ReleaseTemporaryVariable(scopeVariable);
            }

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

            // Object scope references may have side-effects (because of getters) so if the value
            // is to be ignored we evaluate the value then pop the value from the stack.
            //if (optimizationInfo.SuppressReturnValue == true)
            //    generator.Pop();
        }
Ejemplo n.º 29
0
        /// <summary>
        /// Generates code to push the "this" value for a function call.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        public void GenerateThis(ILGenerator generator)
        {
            // Optimization: if there are no with scopes, simply emit undefined.
            bool scopeChainHasWithScope = false;
            var  scope = this.Scope;

            do
            {
                if (scope is ObjectScope && ((ObjectScope)scope).ProvidesImplicitThisValue == true)
                {
                    scopeChainHasWithScope = true;
                    break;
                }
                scope = scope.ParentScope;
            } while (scope != null);

            if (scopeChainHasWithScope == false)
            {
                // No with scopes in the scope chain, use undefined as the "this" value.
                EmitHelpers.EmitUndefined(generator);
                return;
            }

            var end = generator.CreateLabel();

            scope = this.Scope;
            ILLocalVariable scopeVariable = generator.CreateTemporaryVariable(typeof(Scope));

            EmitHelpers.LoadScope(generator);
            generator.StoreVariable(scopeVariable);

            do
            {
                if (scope is DeclarativeScope)
                {
                    if (scope.HasDeclaredVariable(this.Name))
                    {
                        // The variable exists but declarative scopes always produce undefined for
                        // the "this" value.
                        EmitHelpers.EmitUndefined(generator);
                        break;
                    }
                }
                else
                {
                    var objectScope = (ObjectScope)scope;

                    // Check if the property exists by calling scope.ScopeObject.HasProperty(propertyName)
                    if (objectScope.ProvidesImplicitThisValue == false)
                    {
                        EmitHelpers.EmitUndefined(generator);
                    }
                    generator.LoadVariable(scopeVariable);
                    generator.CastClass(typeof(ObjectScope));
                    generator.Call(ReflectionHelpers.ObjectScope_ScopeObject);
                    if (objectScope.ProvidesImplicitThisValue == true)
                    {
                        generator.Duplicate();
                    }
                    generator.LoadString(this.Name);
                    generator.Call(ReflectionHelpers.ObjectInstance_HasProperty);
                    generator.BranchIfTrue(end);
                    generator.Pop();

                    // If the name is not defined, use undefined for the "this" value.
                    if (scope.ParentScope == null)
                    {
                        EmitHelpers.EmitUndefined(generator);
                    }
                }

                // Try the parent scope.
                if (scope.ParentScope != null && scope.ExistsAtRuntime == true)
                {
                    generator.LoadVariable(scopeVariable);
                    generator.Call(ReflectionHelpers.Scope_ParentScope);
                    generator.StoreVariable(scopeVariable);
                }
                scope = scope.ParentScope;
            } while (scope != null);

            // Release the temporary variable.
            generator.ReleaseTemporaryVariable(scopeVariable);

            // Define a label at the end.
            generator.DefineLabelPosition(end);
        }
Ejemplo n.º 30
0
        /// <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 JavaScriptException(optimizationInfo.Engine, ErrorType.SyntaxError, string.Format("Cannot delete {0} because deleting a variable or argument is not allowed in strict mode", this.Name), optimizationInfo.SourceSpan.StartLine, optimizationInfo.Source.Path, optimizationInfo.FunctionName);
            }

            var             endOfDelete   = generator.CreateLabel();
            var             scope         = this.Scope;
            ILLocalVariable scopeVariable = generator.CreateTemporaryVariable(typeof(Scope));

            EmitHelpers.LoadScope(generator);
            generator.StoreVariable(scopeVariable);
            do
            {
                if (scope is DeclarativeScope)
                {
                    var variable = scope.GetDeclaredVariable(this.Name);
                    if (variable != null)
                    {
                        // The variable is known at compile-time.
                        if (variable.Deletable == false)
                        {
                            // The variable cannot be deleted - return false.
                            generator.LoadBoolean(false);
                        }
                        else
                        {
                            // The variable can be deleted (it was declared inside an eval()).
                            // Delete the variable.
                            generator.LoadVariable(scopeVariable);
                            generator.CastClass(typeof(DeclarativeScope));
                            generator.LoadString(this.Name);
                            generator.Call(ReflectionHelpers.Scope_Delete);
                        }
                        break;
                    }
                    else
                    {
                        // The variable was not defined at compile time, but may have been
                        // introduced by an eval() statement.
                        if (optimizationInfo.MethodOptimizationHints.HasEval == true)
                        {
                            // Check the variable exists: if (scope.HasValue(variableName) == true) {
                            generator.LoadVariable(scopeVariable);
                            generator.CastClass(typeof(DeclarativeScope));
                            generator.LoadString(this.Name);
                            generator.Call(ReflectionHelpers.Scope_HasValue);
                            var hasValueClause = generator.CreateLabel();
                            generator.BranchIfFalse(hasValueClause);

                            // If the variable does exist, return true.
                            generator.LoadVariable(scopeVariable);
                            generator.CastClass(typeof(DeclarativeScope));
                            generator.LoadString(this.Name);
                            generator.Call(ReflectionHelpers.Scope_Delete);
                            generator.Branch(endOfDelete);

                            // }
                            generator.DefineLabelPosition(hasValueClause);
                        }
                    }
                }
                else
                {
                    // Check if the property exists by calling scope.ScopeObject.HasProperty(propertyName)
                    generator.LoadVariable(scopeVariable);
                    generator.CastClass(typeof(ObjectScope));
                    generator.Call(ReflectionHelpers.ObjectScope_ScopeObject);
                    generator.Duplicate();
                    generator.LoadString(this.Name);
                    generator.Call(ReflectionHelpers.ObjectInstance_HasProperty);

                    // Jump past the delete if the property doesn't exist.
                    var endOfExistsCheck = generator.CreateLabel();
                    generator.BranchIfFalse(endOfExistsCheck);

                    // Call scope.ScopeObject.Delete(key, false)
                    generator.LoadString(this.Name);
                    generator.LoadBoolean(false);
                    generator.Call(ReflectionHelpers.ObjectInstance_Delete);
                    generator.Branch(endOfDelete);

                    generator.DefineLabelPosition(endOfExistsCheck);
                    generator.Pop();

                    // If the name is not defined, return true.
                    if (scope.ParentScope == null)
                    {
                        generator.LoadBoolean(true);
                    }
                }

                // Try the parent scope.
                if (scope.ParentScope != null && scope.ExistsAtRuntime == true)
                {
                    generator.LoadVariable(scopeVariable);
                    generator.Call(ReflectionHelpers.Scope_ParentScope);
                    generator.StoreVariable(scopeVariable);
                }
                scope = scope.ParentScope;
            } while (scope != null);

            // Release the temporary variable.
            generator.ReleaseTemporaryVariable(scopeVariable);

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

            // Delete obviously has side-effects so we evaluate the return value then pop it from
            // the stack.
            //if (optimizationInfo.SuppressReturnValue == true)
            //    generator.Pop();
        }