예제 #1
0
        /// <summary>
        /// Generates code that initializes the variable and function declarations.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        internal void GenerateDeclarations(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Parent root:
            Expression rootExpression = optimizationInfo.RootExpression;

            // Initialize the declared variables and functions.
            foreach (var variable in this.variables.Values)
            {
                DeclaredVariable dVariable = variable as DeclaredVariable;

                // When a scope is reused, i.e. with an eval(), do not reinitialize the variables.
                if (dVariable == null || dVariable.Initialized)
                {
                    continue;
                }

                if (dVariable.ValueAtTopOfScope != null)
                {
                    // Emit the initialization code.

                    var name = new NameExpression(this, dVariable.Name);

                    Type rType = dVariable.ValueAtTopOfScope.GetResultType(optimizationInfo);

                    name.ApplyType(optimizationInfo, rType);

                    name.GenerateSet(generator, optimizationInfo, false, rType, delegate(bool two)
                    {
                        optimizationInfo.RootExpression = dVariable.ValueAtTopOfScope;

                        dVariable.ValueAtTopOfScope.GenerateCode(generator, optimizationInfo);

                        if (two)
                        {
                            // Dupe it:
                            generator.Duplicate();
                        }
                    }, false);

                    // Mark the variable as having been initialized.
                    dVariable.Initialized = true;
                }
            }

            // Restore root:
            optimizationInfo.RootExpression = rootExpression;
        }
예제 #2
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)
        {
            // Get the previous root - we'll be changing it:
            Expression prevRoot = optimizationInfo.RootExpression;

            // 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. It's now the root.
            TryBlock.SetRoot(optimizationInfo);
            TryBlock.GenerateCode(generator, optimizationInfo);

            // Generate code for the catch block.
            if (this.CatchBlock != null)
            {
                // Begin a catch block.  The exception is on the top of the stack.
                generator.BeginCatchBlock(typeof(Exception));

                var catchVariable = new NameExpression(this.CatchScope, this.CatchVariableName);

                catchVariable.ApplyType(optimizationInfo, typeof(Exception));

                catchVariable.GenerateSet(generator, optimizationInfo, false, typeof(Exception), delegate(bool two){
                    // Note that we always do nothing here. The value is already on the stack.
                }, false);

                // Emit code for the statements within the catch block. It's now the root.
                CatchBlock.SetRoot(optimizationInfo);
                CatchBlock.GenerateCode(generator, optimizationInfo);
            }

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

                var branches          = new List <ILLabel>();
                var previousStackSize = optimizationInfo.LongJumpStackSizeThreshold;
                optimizationInfo.LongJumpStackSizeThreshold = optimizationInfo.BreakOrContinueStackSize;
                var previousCallback = optimizationInfo.LongJumpCallback;
                optimizationInfo.LongJumpCallback = delegate(ILGenerator generator2, ILLabel 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. It's now the root.
                FinallyBlock.SetRoot(optimizationInfo);
                this.FinallyBlock.GenerateCode(generator, optimizationInfo);

                // 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.LoadField(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;

            // Restore root:
            optimizationInfo.RootExpression = prevRoot;
        }
        /// <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(ArgVariable[] arguments, ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Method signature: object FunctionDelegate(object thisObj, object[] arguments)

            // Transfer the function name into the scope.
            if (!string.IsNullOrEmpty(Name) &&
                IncludeNameInScope &&
                !HasArgument(Name) &&
                optimizationInfo.MethodOptimizationHints.HasVariable(Name))
            {
                var functionName = new NameExpression(InitialScope, Name);

                functionName.ApplyType(optimizationInfo, typeof(object));

                functionName.GenerateSet(generator, optimizationInfo, false, typeof(object), delegate(bool two)
                {
                    generator.LoadInt64(MethodID);
                    generator.Call(ReflectionHelpers.MethodLookup_Load);

                    if (two)
                    {
                        // Duplicate it:
                        generator.Duplicate();
                    }
                }, false);
            }

            // Transfer the arguments object into the scope.
            if (MethodOptimizationHints.HasArguments && !HasArgument("arguments"))
            {
                var argsSet = new NameExpression(this.InitialScope, "arguments");

                argsSet.ApplyType(optimizationInfo, typeof(object));

                argsSet.GenerateSet(generator, optimizationInfo, false, typeof(object), delegate(bool two)
                {
                    // argumentValues

                    // Build an object[] from the arg values.

                    // Define an array:
                    int argCount = (arguments == null)?0 : arguments.Length;

                    generator.LoadInt32(argCount);
                    generator.NewArray(typeof(object));

                    for (int a = 0; a < argCount; a++)
                    {
                        // One of many args:
                        ArgVariable currentArg = arguments[a];

                        generator.Duplicate();
                        generator.LoadInt32(a);
                        currentArg.Get(generator);
                        EmitConversion.ToAny(generator, currentArg.Type);
                        generator.StoreArrayElement(typeof(object));
                    }


                    generator.NewObject(ReflectionHelpers.Arguments_Constructor);

                    if (two)
                    {
                        generator.Duplicate();
                    }
                }, false);
            }

            // Temp cache return var/target:
            var retVar  = optimizationInfo.ReturnVariable;
            var retTarg = optimizationInfo.ReturnTarget;

            optimizationInfo.ReturnVariable = null;
            optimizationInfo.ReturnTarget   = null;

            // Initialize any declarations.
            (this.InitialScope as DeclarativeScope).GenerateDeclarations(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);
            }

            // Restore:
            optimizationInfo.ReturnVariable = retVar;
            optimizationInfo.ReturnTarget   = retTarg;
        }