Ejemplo n.º 1
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);
     }
 }
        /// <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.º 3
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;
            }

            // Check if this is a super() call.
            if (this.Target is SuperExpression)
            {
                // executionContext.CallSuperClass(arguments)
                EmitHelpers.LoadExecutionContext(generator);
                GenerateArgumentsArray(generator, optimizationInfo);
                generator.Call(ReflectionHelpers.ExecutionContext_CallSuperClass);
                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. "my_func()").
                this.Target.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, this.Target.ResultType);
            }

            // Check the object really is a function - if not, throw an exception.
            generator.Duplicate();
            generator.IsInstance(typeof(FunctionInstance));
            var endOfTypeCheck = generator.CreateLabel();

            generator.BranchIfTrue(endOfTypeCheck);

            // Throw an nicely formatted exception.
            generator.Pop();
            EmitHelpers.EmitThrow(generator, ErrorType.TypeError, string.Format("'{0}' is not a function", this.Target.ToString()), optimizationInfo);
            generator.DefineLabelPosition(endOfTypeCheck);

            // Pass in the path, function name and line.
            generator.ReinterpretCast(typeof(FunctionInstance));
            generator.LoadStringOrNull(optimizationInfo.Source.Path);
            generator.LoadStringOrNull(optimizationInfo.FunctionName);
            generator.LoadInt32(optimizationInfo.SourceSpan.StartLine);

            // 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()").
                //    If we are inside a with() block, then there is an implicit 'this' value,
                //    otherwise 'this' is undefined.
                Scope.GenerateReference(generator, optimizationInfo);
                generator.Call(ReflectionHelpers.RuntimeScope_ImplicitThis);
            }
            else if (this.Target is MemberAccessExpression targetMemberAccessExpression)
            {
                // 2. The function is a member access expression (e.g. "Math.cos()").
                //    In this case this = Math.
                //    Unless it's a super call like super.blah().
                if (targetMemberAccessExpression.Base is SuperExpression)
                {
                    EmitHelpers.LoadThis(generator);
                }
                else
                {
                    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_CallWithStackTrace);

            // Allow reuse of the temporary variable.
            if (targetBase != null)
            {
                generator.ReleaseTemporaryVariable(targetBase);
            }
        }
Ejemplo n.º 4
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.º 5
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)
 {
     EmitHelpers.LoadExecutionContext(generator);
     generator.Call(ReflectionHelpers.ExecutionContext_GetSuperValue);
 }