BranchIfFalse() public method

Branches to the given label if the value on the top of the stack is zero, false or null.
public BranchIfFalse ( ILLabel label ) : void
label ILLabel The label to branch to.
return void
        /// <summary>
        /// Generates CIL for the logical operators.
        /// </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 GenerateLogical(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Get the statically-determined types of the left and right operands.
            PrimitiveType leftType  = this.Left.ResultType;
            PrimitiveType rightType = this.Right.ResultType;

            // Load the left-hand side operand.
            this.Left.GenerateCode(generator, optimizationInfo);

            // Make sure the output type is consistant.
            if (leftType != rightType)
            {
                if (PrimitiveTypeUtilities.IsNumeric(leftType) == true && PrimitiveTypeUtilities.IsNumeric(rightType) == true)
                {
                    EmitConversion.ToNumber(generator, leftType);
                    leftType = PrimitiveType.Number;
                }
                else
                {
                    EmitConversion.ToAny(generator, leftType);
                    leftType = PrimitiveType.Any;
                }
            }

            // Duplicate and convert to a Boolean.
            generator.Duplicate();
            EmitConversion.ToBool(generator, leftType);

            // Stack contains "left, (bool)left"
            var endOfIf = generator.CreateLabel();

            if (this.OperatorType == OperatorType.LogicalAnd)
            {
                generator.BranchIfFalse(endOfIf);
            }
            else
            {
                generator.BranchIfTrue(endOfIf);
            }

            // Stack contains "left".  Load the right-hand side operand.
            generator.Pop();
            this.Right.GenerateCode(generator, optimizationInfo);

            // Make sure the output type is consistant.
            if (leftType != rightType)
            {
                if (PrimitiveTypeUtilities.IsNumeric(leftType) == true && PrimitiveTypeUtilities.IsNumeric(rightType) == true)
                {
                    EmitConversion.ToNumber(generator, rightType);
                }
                else
                {
                    EmitConversion.ToAny(generator, rightType);
                }
            }

            // Define the label used above.
            generator.DefineLabelPosition(endOfIf);
        }
Esempio n. 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)
        {
            // Generate code for the start of the statement.
            var statementLocals = new StatementLocals();

            GenerateStartOfStatement(generator, optimizationInfo, statementLocals);

            // Generate code for the condition and coerce to a boolean.
            this.Condition.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToBool(generator, this.Condition.ResultType);

            // We will need a label at the end of the if statement.
            var endOfEverything = generator.CreateLabel();

            if (this.ElseClause == null)
            {
                // Jump to the end if the condition is false.
                generator.BranchIfFalse(endOfEverything);

                // Generate code for the if clause.
                this.IfClause.GenerateCode(generator, optimizationInfo);
            }
            else
            {
                // Branch to the else clause if the condition is false.
                var startOfElseClause = generator.CreateLabel();
                generator.BranchIfFalse(startOfElseClause);

                // Generate code for the if clause.
                this.IfClause.GenerateCode(generator, optimizationInfo);

                // Branch to the end of the if statement.
                generator.Branch(endOfEverything);

                // Generate code for the else clause.
                generator.DefineLabelPosition(startOfElseClause);
                this.ElseClause.GenerateCode(generator, optimizationInfo);
            }

            // Define the label at the end of the if statement.
            generator.DefineLabelPosition(endOfEverything);

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
Esempio n. 3
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);

            // Generate code for the condition and coerce to a boolean.
            this.Condition.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToBool(generator, this.Condition.ResultType);

            // We will need a label at the end of the if statement.
            var endOfEverything = generator.CreateLabel();

            if (this.ElseClause == null)
            {
                // Jump to the end if the condition is false.
                generator.BranchIfFalse(endOfEverything);

                // Generate code for the if clause.
                this.IfClause.GenerateCode(generator, optimizationInfo);
            }
            else
            {
                // Branch to the else clause if the condition is false.
                var startOfElseClause = generator.CreateLabel();
                generator.BranchIfFalse(startOfElseClause);

                // Generate code for the if clause.
                this.IfClause.GenerateCode(generator, optimizationInfo);

                // Branch to the end of the if statement.
                generator.Branch(endOfEverything);

                // Generate code for the else clause.
                generator.DefineLabelPosition(startOfElseClause);
                this.ElseClause.GenerateCode(generator, optimizationInfo);
                
            }

            // Define the label at the end of the if statement.
            generator.DefineLabelPosition(endOfEverything);

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
Esempio n. 4
0
        /// <summary>
        /// Pops the value on the stack, converts it to a string, then pushes the result onto the
        /// stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        public static void ToString(ILGenerator generator, PrimitiveType fromType)
        {
            // Check that a conversion is actually necessary.
            if (fromType == PrimitiveType.String)
            {
                return;
            }

            switch (fromType)
            {
            case PrimitiveType.Undefined:
                // Converting from undefined produces "undefined".
                generator.Pop();
                generator.LoadString("undefined");
                break;

            case PrimitiveType.Null:
                // Converting from null produces "null".
                generator.Pop();
                generator.LoadString("null");
                break;

            case PrimitiveType.Bool:
                // Converting from a boolean produces "false" if the boolean is false, or "true" if the boolean is true.
                var elseClause = generator.CreateLabel();
                var endOfIf    = generator.CreateLabel();
                generator.BranchIfFalse(elseClause);
                generator.LoadString("true");
                generator.Branch(endOfIf);
                generator.DefineLabelPosition(elseClause);
                generator.LoadString("false");
                generator.DefineLabelPosition(endOfIf);
                break;

            case PrimitiveType.ConcatenatedString:
                generator.Call(ReflectionHelpers.ConcatenatedString_ToString);
                break;

            case PrimitiveType.Int32:
            case PrimitiveType.UInt32:
            case PrimitiveType.Number:
            case PrimitiveType.Any:
            case PrimitiveType.Object:
                // Otherwise, fall back to calling TypeConverter.ToString()
                if (PrimitiveTypeUtilities.IsValueType(fromType))
                {
                    generator.Box(fromType);
                }
                generator.Call(ReflectionHelpers.TypeConverter_ToString);
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
Esempio 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)
        {
            // If a return value is not expected, generate only the side-effects.

            /*if (optimizationInfo.SuppressReturnValue == true)
             * {
             *  this.GenerateSideEffects(generator, optimizationInfo);
             *  return;
             * }*/

            // Emit the condition.
            var condition = this.GetOperand(0);

            condition.GenerateCode(generator, optimizationInfo);

            // Convert the condition to a boolean.
            EmitConversion.ToBool(generator, condition.ResultType);

            // Branch if the condition is false.
            var startOfElse = generator.CreateLabel();

            generator.BranchIfFalse(startOfElse);

            // Calculate the result type.
            var outputType = this.ResultType;

            // Emit the second operand and convert it to the result type.
            var operand2 = this.GetOperand(1);

            operand2.GenerateCode(generator, optimizationInfo);
            EmitConversion.Convert(generator, operand2.ResultType, outputType, optimizationInfo);

            // Branch to the end.
            var end = generator.CreateLabel();

            generator.Branch(end);
            generator.DefineLabelPosition(startOfElse);

            // Emit the third operand and convert it to the result type.
            var operand3 = this.GetOperand(2);

            operand3.GenerateCode(generator, optimizationInfo);
            EmitConversion.Convert(generator, operand3.ResultType, outputType, optimizationInfo);

            // Define the end label.
            generator.DefineLabelPosition(end);
        }
        /// <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)
        {
            // If a return value is not expected, generate only the side-effects.
            /*if (optimizationInfo.SuppressReturnValue == true)
            {
                this.GenerateSideEffects(generator, optimizationInfo);
                return;
            }*/

            // Emit the condition.
            var condition = this.GetOperand(0);
            condition.GenerateCode(generator, optimizationInfo);

            // Convert the condition to a boolean.
            EmitConversion.ToBool(generator, condition.ResultType);

            // Branch if the condition is false.
            var startOfElse = generator.CreateLabel();
            generator.BranchIfFalse(startOfElse);

            // Calculate the result type.
            var outputType = this.ResultType;

            // Emit the second operand and convert it to the result type.
            var operand2 = this.GetOperand(1);
            operand2.GenerateCode(generator, optimizationInfo);
            EmitConversion.Convert(generator, operand2.ResultType, outputType, optimizationInfo);

            // Branch to the end.
            var end = generator.CreateLabel();
            generator.Branch(end);
            generator.DefineLabelPosition(startOfElse);

            // Emit the third operand and convert it to the result type.
            var operand3 = this.GetOperand(2);
            operand3.GenerateCode(generator, optimizationInfo);
            EmitConversion.Convert(generator, operand3.ResultType, outputType, optimizationInfo);

            // Define the end label.
            generator.DefineLabelPosition(end);
        }
        /// <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);

                // }
                generator.DefineLabelPosition(endOfIf);
                EmitHelpers.StoreThis(generator);
            }

            // Transfer the function name into the scope.
            if (string.IsNullOrEmpty(this.Name) == false &&
                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();
        }
Esempio n. 8
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();
        }
Esempio n. 9
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();
        }
Esempio n. 10
0
        /// <summary>
        /// Stores the value on the top of the stack in the reference.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        /// <param name="valueType"> The primitive type of the value that is on the top of the stack. </param>
        /// <param name="throwIfUnresolvable"> <c>true</c> to throw a ReferenceError exception if
        /// the name is unresolvable; <c>false</c> to create a new property instead. </param>
        public void GenerateSet(ILGenerator generator, OptimizationInfo optimizationInfo, PrimitiveType valueType, bool throwIfUnresolvable)
        {
            // The value is initially on the top of the stack but is stored in this variable
            // at the last possible moment.
            ILLocalVariable value = null;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                        // else
                        generator.DefineLabelPosition(elseClause);

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

                        // End of the if statement
                        generator.DefineLabelPosition(endOfIf);
                    }
                    else
                    {
                        // Slow route.

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

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

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

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

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

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

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

            // Define a label at the end.
            generator.DefineLabelPosition(endOfSet);
        }
Esempio n. 11
0
        /// <summary>
        /// Pops the value on the stack, converts it from an object to the given type, then pushes
        /// the result onto the stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="toType"> The type to convert to. </param>
        /// <param name="convertToAddress"> <c>true</c> if the value is intended for use as an
        /// instance pointer; <c>false</c> otherwise. </param>
        internal static void EmitConversionToType(ILGenerator generator, Type toType, bool convertToAddress)
        {
            // Convert Null.Value to null if the target type is a reference type.
            ILLabel endOfNullCheck = null;

            if (toType.IsValueType == false)
            {
                var startOfElse = generator.CreateLabel();
                endOfNullCheck = generator.CreateLabel();
                generator.Duplicate();
                EmitHelpers.EmitNull(generator);
                generator.BranchIfNotEqual(startOfElse);
                generator.Pop();
                generator.LoadNull();
                generator.Branch(endOfNullCheck);
                generator.DefineLabelPosition(startOfElse);
            }

            switch (Type.GetTypeCode(toType))
            {
            case TypeCode.Boolean:
                EmitConversion.ToBool(generator, PrimitiveType.Any);
                break;

            case TypeCode.Byte:
                EmitConversion.ToInt32(generator, PrimitiveType.Any);
                break;

            case TypeCode.Char:
                EmitConversion.ToString(generator, PrimitiveType.Any);
                generator.Duplicate();
                generator.Call(ReflectionHelpers.String_Length);
                generator.LoadInt32(1);
                var endOfCharCheck = generator.CreateLabel();
                generator.BranchIfEqual(endOfCharCheck);
                EmitHelpers.EmitThrow(generator, ErrorType.TypeError, "Cannot convert string to char - the string must be exactly one character long");
                generator.DefineLabelPosition(endOfCharCheck);
                generator.LoadInt32(0);
                generator.Call(ReflectionHelpers.String_GetChars);
                break;

            case TypeCode.DBNull:
                throw new NotSupportedException("DBNull is not a supported parameter type.");

            case TypeCode.Decimal:
                EmitConversion.ToNumber(generator, PrimitiveType.Any);
                generator.NewObject(ReflectionHelpers.Decimal_Constructor_Double);
                break;

            case TypeCode.Double:
                EmitConversion.ToNumber(generator, PrimitiveType.Any);
                break;

            case TypeCode.Empty:
                throw new NotSupportedException("Empty is not a supported return type.");

            case TypeCode.Int16:
                EmitConversion.ToInt32(generator, PrimitiveType.Any);
                break;

            case TypeCode.Int32:
                EmitConversion.ToInt32(generator, PrimitiveType.Any);
                break;

            case TypeCode.Int64:
                EmitConversion.ToNumber(generator, PrimitiveType.Any);
                generator.ConvertToInt64();
                break;

            case TypeCode.DateTime:
            case TypeCode.Object:
                // Check if the type must be unwrapped.
                generator.Duplicate();
                generator.IsInstance(typeof(Jurassic.Library.ClrInstanceWrapper));
                var endOfUnwrapCheck = generator.CreateLabel();
                generator.BranchIfFalse(endOfUnwrapCheck);

                // Unwrap the wrapped instance.
                generator.Call(ReflectionHelpers.ClrInstanceWrapper_GetWrappedInstance);
                generator.DefineLabelPosition(endOfUnwrapCheck);

                // Value types must be unboxed.
                if (toType.IsValueType == true)
                {
                    if (convertToAddress == true)
                    {
                        // Unbox.
                        generator.Unbox(toType);
                    }
                    else
                    {
                        // Unbox and copy to the stack.
                        generator.UnboxAny(toType);
                    }

                    //// Calling methods on value required the address of the value type, not the value type itself.
                    //if (argument.Source == BinderArgumentSource.ThisValue && argument.Type.IsValueType == true)
                    //{
                    //    var temp = generator.CreateTemporaryVariable(argument.Type);
                    //    generator.StoreVariable(temp);
                    //    generator.LoadAddressOfVariable(temp);
                    //    generator.ReleaseTemporaryVariable(temp);
                    //}
                }


                break;

            case TypeCode.SByte:
                EmitConversion.ToInt32(generator, PrimitiveType.Any);
                break;

            case TypeCode.Single:
                EmitConversion.ToNumber(generator, PrimitiveType.Any);
                break;

            case TypeCode.String:
                EmitConversion.ToString(generator, PrimitiveType.Any);
                break;

            case TypeCode.UInt16:
                EmitConversion.ToInt32(generator, PrimitiveType.Any);
                break;

            case TypeCode.UInt32:
                EmitConversion.ToUInt32(generator, PrimitiveType.Any);
                break;

            case TypeCode.UInt64:
                EmitConversion.ToNumber(generator, PrimitiveType.Any);
                generator.ConvertToUnsignedInt64();
                break;
            }

            // Label the end of the null check.
            if (toType.IsValueType == false)
            {
                generator.DefineLabelPosition(endOfNullCheck);
            }
        }
Esempio n. 12
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()
            {
                NonDefaultBreakStatementBehavior = true, NonDefaultSourceSpanBehavior = true
            };

            GenerateStartOfStatement(generator, optimizationInfo, statementLocals);

            // Construct a loop expression.
            // var enumerator = TypeUtilities.EnumeratePropertyNames(rhs).GetEnumerator();
            // while (true) {
            //   continue-target:
            //   if (enumerator.MoveNext() == false)
            //     goto break-target;
            //   lhs = enumerator.Current;
            //
            //   <body statements>
            // }
            // break-target:

            // Call IEnumerable<string> EnumeratePropertyNames(ScriptEngine engine, object obj)
            optimizationInfo.MarkSequencePoint(generator, this.TargetObjectSourceSpan);
            EmitHelpers.LoadScriptEngine(generator);
            this.TargetObject.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.TargetObject.ResultType);
            generator.Call(ReflectionHelpers.TypeUtilities_EnumeratePropertyNames);

            // Call IEnumerable<string>.GetEnumerator()
            generator.Call(ReflectionHelpers.IEnumerable_String_GetEnumerator);

            // Store the enumerator in a temporary variable.
            var enumerator = generator.CreateTemporaryVariable(typeof(IEnumerator <string>));

            generator.StoreVariable(enumerator);

            var breakTarget    = generator.CreateLabel();
            var continueTarget = generator.DefineLabelPosition();

            // Generate the scope variable if necessary.
            this.Scope.GenerateScopeCreation(generator, optimizationInfo);

            //   if (enumerator.MoveNext() == false)
            //     goto break-target;
            generator.LoadVariable(enumerator);
            generator.Call(ReflectionHelpers.IEnumerator_MoveNext);
            generator.BranchIfFalse(breakTarget);

            // lhs = enumerator.Current;
            this.Variable.GenerateReference(generator, optimizationInfo);
            generator.LoadVariable(enumerator);
            generator.Call(ReflectionHelpers.IEnumerator_String_Current);
            this.Variable.GenerateSet(generator, optimizationInfo, PrimitiveType.String);

            // Emit the body statement(s).
            optimizationInfo.PushBreakOrContinueInfo(this.Labels, breakTarget, continueTarget, labelledOnly: false);
            this.Body.GenerateCode(generator, optimizationInfo);
            optimizationInfo.PopBreakOrContinueInfo();

            generator.Branch(continueTarget);
            generator.DefineLabelPosition(breakTarget);

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
Esempio n. 13
0
        /// <summary>
        /// Stores the value on the top of the stack in the reference.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        /// <param name="valueType"> The primitive type of the value that is on the top of the stack. </param>
        /// <param name="throwIfUnresolvable"> <c>true</c> to throw a ReferenceError exception if
        /// the name is unresolvable; <c>false</c> to create a new property instead. </param>
        public void GenerateSet(ILGenerator generator, OptimizationInfo optimizationInfo, PrimitiveType valueType, bool throwIfUnresolvable)
        {
            // The value is initially on the top of the stack but is stored in this variable
            // at the last possible moment.
            ILLocalVariable value = null;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                        // else
                        generator.DefineLabelPosition(elseClause);

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

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

                    }
                    else
                    {
                        // Slow route.

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

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

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

                    }
                }

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

            } while (scope != null);

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

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

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

            // Define a label at the end.
            generator.DefineLabelPosition(endOfSet);
        }
        /// <summary>
        /// Generates CIL for the logical operators.
        /// </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 GenerateLogical(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Get the statically-determined types of the left and right operands.
            PrimitiveType leftType = this.Left.ResultType;
            PrimitiveType rightType = this.Right.ResultType;

            // Load the left-hand side operand.
            this.Left.GenerateCode(generator, optimizationInfo);

            // Make sure the output type is consistant.
            if (leftType != rightType)
            {
                if (PrimitiveTypeUtilities.IsNumeric(leftType) == true && PrimitiveTypeUtilities.IsNumeric(rightType) == true)
                {
                    EmitConversion.ToNumber(generator, leftType);
                    leftType = PrimitiveType.Number;
                }
                else
                {
                    EmitConversion.ToAny(generator, leftType);
                    leftType = PrimitiveType.Any;
                }
            }

            // Duplicate and convert to a Boolean.
            generator.Duplicate();
            EmitConversion.ToBool(generator, leftType);

            // Stack contains "left, (bool)left"
            var endOfIf = generator.CreateLabel();
            if (this.OperatorType == OperatorType.LogicalAnd)
                generator.BranchIfFalse(endOfIf);
            else
                generator.BranchIfTrue(endOfIf);

            // Stack contains "left".  Load the right-hand side operand.
            generator.Pop();
            this.Right.GenerateCode(generator, optimizationInfo);

            // Make sure the output type is consistant.
            if (leftType != rightType)
            {
                if (PrimitiveTypeUtilities.IsNumeric(leftType) == true && PrimitiveTypeUtilities.IsNumeric(rightType) == true)
                    EmitConversion.ToNumber(generator, rightType);
                else
                    EmitConversion.ToAny(generator, rightType);
            }

            // Define the label used above.
            generator.DefineLabelPosition(endOfIf);
        }
Esempio n. 15
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() { NonDefaultBreakStatementBehavior = true, NonDefaultDebugInfoBehavior = true };
            GenerateStartOfStatement(generator, optimizationInfo, statementLocals);

            // Construct a loop expression.
            // var enumerator = TypeUtilities.EnumeratePropertyNames(rhs).GetEnumerator();
            // while (true) {
            //   continue-target:
            //   if (enumerator.MoveNext() == false)
            //     goto break-target;
            //   lhs = enumerator.Current;
            //
            //   <body statements>
            // }
            // break-target:

            // Call IEnumerable<string> EnumeratePropertyNames(ScriptEngine engine, object obj)
            EmitHelpers.LoadScriptEngine(generator);
            this.TargetObject.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.TargetObject.ResultType);
            generator.Call(ReflectionHelpers.TypeUtilities_EnumeratePropertyNames);

            // Call IEnumerable<string>.GetEnumerator()
            generator.Call(ReflectionHelpers.IEnumerable_GetEnumerator);

            // Store the enumerator in a temporary variable.
            var enumerator = generator.CreateTemporaryVariable(typeof(IEnumerator<string>));
            generator.StoreVariable(enumerator);

            var breakTarget = generator.CreateLabel();
            var continueTarget = generator.DefineLabelPosition();

            #if !XBOX
            // Emit debugging information.
            if (optimizationInfo.DebugDocument != null)
                generator.MarkSequencePoint(optimizationInfo.DebugDocument, this.VariableDebugInfo);
            #endif

            //   if (enumerator.MoveNext() == false)
            //     goto break-target;
            generator.LoadVariable(enumerator);
            generator.Call(ReflectionHelpers.IEnumerator_MoveNext);
            generator.BranchIfFalse(breakTarget);

            // lhs = enumerator.Current;
            generator.LoadVariable(enumerator);
            generator.Call(ReflectionHelpers.IEnumerator_Current);
            this.Variable.GenerateSet(generator, optimizationInfo, PrimitiveType.String, false);

            // Emit the body statement(s).
            optimizationInfo.PushBreakOrContinueInfo(this.Labels, breakTarget, continueTarget, labelledOnly: false);
            this.Body.GenerateCode(generator, optimizationInfo);
            optimizationInfo.PopBreakOrContinueInfo();

            generator.Branch(continueTarget);
            generator.DefineLabelPosition(breakTarget);

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
Esempio n. 16
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() { NonDefaultBreakStatementBehavior = true, NonDefaultSourceSpanBehavior = true };
            GenerateStartOfStatement(generator, optimizationInfo, statementLocals);

            // <initializer>
            // if (<condition>)
            // {
            // 	 <loop body>
            //   <increment>
            //   while (true) {
            //     if (<condition> == false)
            //       break;
            //
            //     <body statements>
            //
            //     continue-target:
            //     <increment>
            //   }
            // }
            // break-target:

            // Set up some labels.
            var continueTarget = generator.CreateLabel();
            var breakTarget1 = generator.CreateLabel();
            var breakTarget2 = generator.CreateLabel();

            // Emit the initialization statement.
            if (this.InitStatement != null)
                this.InitStatement.GenerateCode(generator, optimizationInfo);

            // Check the condition and jump to the end if it is false.
            if (this.CheckConditionAtEnd == false && this.ConditionStatement != null)
            {
                optimizationInfo.MarkSequencePoint(generator, this.ConditionStatement.SourceSpan);
                this.Condition.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToBool(generator, this.Condition.ResultType);
                generator.BranchIfFalse(breakTarget1);
            }

            // Emit the loop body.
            optimizationInfo.PushBreakOrContinueInfo(this.Labels, breakTarget1, continueTarget, false);
            this.Body.GenerateCode(generator, optimizationInfo);
            optimizationInfo.PopBreakOrContinueInfo();

            // Increment the loop variable.
            if (this.IncrementStatement != null)
                this.IncrementStatement.GenerateCode(generator, optimizationInfo);

            // Strengthen the variable types.
            List<KeyValuePair<Scope.DeclaredVariable, RevertInfo>> previousVariableTypes = null;
            var previousInsideTryCatchOrFinally = optimizationInfo.InsideTryCatchOrFinally;
            if (optimizationInfo.OptimizeInferredTypes == true)
            {
                // Keep a record of the variable types before strengthening.
                previousVariableTypes = new List<KeyValuePair<Scope.DeclaredVariable, RevertInfo>>();

                var typedVariables = FindTypedVariables();
                foreach (var variableAndType in typedVariables)
                {
                    var variable = variableAndType.Key;
                    var variableInfo = variableAndType.Value;
                    if (variableInfo.Conditional == false && variableInfo.Type != variable.Type)
                    {
                        // Save the previous type so we can restore it later.
                        var previousType = variable.Type;
                        previousVariableTypes.Add(new KeyValuePair<Scope.DeclaredVariable, RevertInfo>(variable, new RevertInfo() { Type = previousType, Variable = variable.Store }));

                        // Load the existing value.
                        var nameExpression = new NameExpression(variable.Scope, variable.Name);
                        nameExpression.GenerateGet(generator, optimizationInfo, false);

                        // Store the typed value.
                        variable.Store = generator.DeclareVariable(variableInfo.Type);
                        variable.Type = variableInfo.Type;
                        nameExpression.GenerateSet(generator, optimizationInfo, previousType, false);
                    }
                }

                // The variables must be reverted even in the presence of exceptions.
                if (previousVariableTypes.Count > 0)
                {
                    generator.BeginExceptionBlock();

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

            // The inner loop starts here.
            var startOfLoop = generator.DefineLabelPosition();

            // Check the condition and jump to the end if it is false.
            if (this.ConditionStatement != null)
            {
                optimizationInfo.MarkSequencePoint(generator, this.ConditionStatement.SourceSpan);
                this.Condition.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToBool(generator, this.Condition.ResultType);
                generator.BranchIfFalse(breakTarget2);
            }

            // Emit the loop body.
            optimizationInfo.PushBreakOrContinueInfo(this.Labels, breakTarget2, continueTarget, labelledOnly: false);
            this.Body.GenerateCode(generator, optimizationInfo);
            optimizationInfo.PopBreakOrContinueInfo();

            // The continue statement jumps here.
            generator.DefineLabelPosition(continueTarget);

            // Increment the loop variable.
            if (this.IncrementStatement != null)
                this.IncrementStatement.GenerateCode(generator, optimizationInfo);

            // Unconditionally branch back to the start of the loop.
            generator.Branch(startOfLoop);

            // Define the end of the loop (actually just after).
            generator.DefineLabelPosition(breakTarget2);

            // Revert the variable types.
            if (previousVariableTypes != null && previousVariableTypes.Count > 0)
            {
                // Revert the InsideTryCatchOrFinally flag.
                optimizationInfo.InsideTryCatchOrFinally = previousInsideTryCatchOrFinally;

                // Revert the variable types within a finally block.
                generator.BeginFinallyBlock();

                foreach (var previousVariableAndType in previousVariableTypes)
                {
                    var variable = previousVariableAndType.Key;
                    var variableRevertInfo = previousVariableAndType.Value;

                    // Load the existing value.
                    var nameExpression = new NameExpression(variable.Scope, variable.Name);
                    nameExpression.GenerateGet(generator, optimizationInfo, false);

                    // Store the typed value.
                    var previousType = variable.Type;
                    variable.Store = variableRevertInfo.Variable;
                    variable.Type = variableRevertInfo.Type;
                    nameExpression.GenerateSet(generator, optimizationInfo, previousType, false);
                }

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

            // Define the end of the loop (actually just after).
            generator.DefineLabelPosition(breakTarget1);

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
Esempio n. 17
0
        /// <summary>
        /// Pops the value on the stack, converts it from an object to the given type, then pushes
        /// the result onto the stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="toType"> The type to convert to. </param>
        /// <param name="convertToAddress"> <c>true</c> if the value is intended for use as an
        /// instance pointer; <c>false</c> otherwise. </param>
        internal static void EmitConversionToType(ILGenerator generator, Type toType, bool convertToAddress)
        {
            // Convert Null.Value to null if the target type is a reference type.
            ILLabel endOfNullCheck = null;
            if (toType.IsValueType == false)
            {
                var startOfElse = generator.CreateLabel();
                endOfNullCheck = generator.CreateLabel();
                generator.Duplicate();
                EmitHelpers.EmitNull(generator);
                generator.BranchIfNotEqual(startOfElse);
                generator.Pop();
                generator.LoadNull();
                generator.Branch(endOfNullCheck);
                generator.DefineLabelPosition(startOfElse);
            }

            switch (Type.GetTypeCode(toType))
            {
                case TypeCode.Boolean:
                    EmitConversion.ToBool(generator, PrimitiveType.Any);
                    break;
                case TypeCode.Byte:
                    EmitConversion.ToInt32(generator, PrimitiveType.Any);
                    break;
                case TypeCode.Char:
                    EmitConversion.ToString(generator, PrimitiveType.Any);
                    generator.Duplicate();
                    generator.Call(ReflectionHelpers.String_Length);
                    generator.LoadInt32(1);
                    var endOfCharCheck = generator.CreateLabel();
                    generator.BranchIfEqual(endOfCharCheck);
                    EmitHelpers.EmitThrow(generator, "TypeError", "Cannot convert string to char - the string must be exactly one character long");
                    generator.DefineLabelPosition(endOfCharCheck);
                    generator.LoadInt32(0);
                    generator.Call(ReflectionHelpers.String_GetChars);
                    break;
                case TypeCode.DBNull:
                    throw new NotSupportedException("DBNull is not a supported parameter type.");
                case TypeCode.Decimal:
                    EmitConversion.ToNumber(generator, PrimitiveType.Any);
                    generator.NewObject(ReflectionHelpers.Decimal_Constructor_Double);
                    break;
                case TypeCode.Double:
                    EmitConversion.ToNumber(generator, PrimitiveType.Any);
                    break;
                case TypeCode.Empty:
                    throw new NotSupportedException("Empty is not a supported return type.");
                case TypeCode.Int16:
                    EmitConversion.ToInt32(generator, PrimitiveType.Any);
                    break;
                case TypeCode.Int32:
                    EmitConversion.ToInt32(generator, PrimitiveType.Any);
                    break;
                case TypeCode.Int64:
                    EmitConversion.ToNumber(generator, PrimitiveType.Any);
                    generator.ConvertToInt64();
                    break;

                case TypeCode.DateTime:
                case TypeCode.Object:
                    // Check if the type must be unwrapped.
                    generator.Duplicate();
                    generator.IsInstance(typeof(Jurassic.Library.ClrInstanceWrapper));
                    var endOfUnwrapCheck = generator.CreateLabel();
                    generator.BranchIfFalse(endOfUnwrapCheck);

                    // Unwrap the wrapped instance.
                    generator.Call(ReflectionHelpers.ClrInstanceWrapper_GetWrappedInstance);
                    generator.DefineLabelPosition(endOfUnwrapCheck);

                    // Value types must be unboxed.
                    if (toType.IsValueType == true)
                    {
                        if (convertToAddress == true)
                            // Unbox.
                            generator.Unbox(toType);
                        else
                            // Unbox and copy to the stack.
                            generator.UnboxAny(toType);

                        //// Calling methods on value required the address of the value type, not the value type itself.
                        //if (argument.Source == BinderArgumentSource.ThisValue && argument.Type.IsValueType == true)
                        //{
                        //    var temp = generator.CreateTemporaryVariable(argument.Type);
                        //    generator.StoreVariable(temp);
                        //    generator.LoadAddressOfVariable(temp);
                        //    generator.ReleaseTemporaryVariable(temp);
                        //}
                    }


                    break;

                case TypeCode.SByte:
                    EmitConversion.ToInt32(generator, PrimitiveType.Any);
                    break;
                case TypeCode.Single:
                    EmitConversion.ToNumber(generator, PrimitiveType.Any);
                    break;
                case TypeCode.String:
                    EmitConversion.ToString(generator, PrimitiveType.Any);
                    break;
                case TypeCode.UInt16:
                    EmitConversion.ToInt32(generator, PrimitiveType.Any);
                    break;
                case TypeCode.UInt32:
                    EmitConversion.ToUInt32(generator, PrimitiveType.Any);
                    break;
                case TypeCode.UInt64:
                    EmitConversion.ToNumber(generator, PrimitiveType.Any);
                    generator.ConvertToUnsignedInt64();
                    break;
            }

            // Label the end of the null check.
            if (toType.IsValueType == false)
                generator.DefineLabelPosition(endOfNullCheck);
        }
Esempio n. 18
0
        /// <summary>
        /// Pops the value on the stack, converts it to a string, then pushes the result onto the
        /// stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        public static void ToString(ILGenerator generator, PrimitiveType fromType)
        {
            // Check that a conversion is actually necessary.
            if (fromType == PrimitiveType.String)
                return;

            switch (fromType)
            {
                case PrimitiveType.Undefined:
                    // Converting from undefined produces "undefined".
                    generator.Pop();
                    generator.LoadString("undefined");
                    break;

                case PrimitiveType.Null:
                    // Converting from null produces "null".
                    generator.Pop();
                    generator.LoadString("null");
                    break;

                case PrimitiveType.Bool:
                    // Converting from a boolean produces "false" if the boolean is false, or "true" if the boolean is true.
                    var elseClause = generator.CreateLabel();
                    var endOfIf = generator.CreateLabel();
                    generator.BranchIfFalse(elseClause);
                    generator.LoadString("true");
                    generator.Branch(endOfIf);
                    generator.DefineLabelPosition(elseClause);
                    generator.LoadString("false");
                    generator.DefineLabelPosition(endOfIf);
                    break;

                case PrimitiveType.ConcatenatedString:
                    generator.Call(ReflectionHelpers.ConcatenatedString_ToString);
                    break;

                case PrimitiveType.Int32:
                case PrimitiveType.UInt32:
                case PrimitiveType.Number:
                case PrimitiveType.Any:
                case PrimitiveType.Object:
                    // Otherwise, fall back to calling TypeConverter.ToString()
                    if (PrimitiveTypeUtilities.IsValueType(fromType))
                        generator.Box(fromType);
                    generator.Call(ReflectionHelpers.TypeConverter_ToString);
                    break;

                default:
                    throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
Esempio n. 19
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();
        }
Esempio n. 20
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()
            {
                NonDefaultBreakStatementBehavior = true, NonDefaultDebugInfoBehavior = true
            };

            GenerateStartOfStatement(generator, optimizationInfo, statementLocals);

            // <initializer>
            // if (<condition>)
            // {
            //   <loop body>
            //   <increment>
            //   while (true) {
            //     if (<condition> == false)
            //       break;
            //
            //     <body statements>
            //
            //     continue-target:
            //     <increment>
            //   }
            // }
            // break-target:

            // Set up some labels.
            var continueTarget = generator.CreateLabel();
            var breakTarget1   = generator.CreateLabel();
            var breakTarget2   = generator.CreateLabel();

            // Emit the initialization statement.
            if (this.InitStatement != null)
            {
                this.InitStatement.GenerateCode(generator, optimizationInfo);
            }

            // Check the condition and jump to the end if it is false.
            if (this.CheckConditionAtEnd == false && this.ConditionStatement != null)
            {
#if !XBOX
                if (optimizationInfo.DebugDocument != null)
                {
                    generator.MarkSequencePoint(optimizationInfo.DebugDocument, this.ConditionStatement.DebugInfo);
                }
#endif
                this.Condition.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToBool(generator, this.Condition.ResultType);
                generator.BranchIfFalse(breakTarget1);
            }

            // Emit the loop body.
            optimizationInfo.PushBreakOrContinueInfo(this.Labels, breakTarget1, continueTarget, false);
            this.Body.GenerateCode(generator, optimizationInfo);
            optimizationInfo.PopBreakOrContinueInfo();

            // Increment the loop variable.
            if (this.IncrementStatement != null)
            {
                this.IncrementStatement.GenerateCode(generator, optimizationInfo);
            }

            // Strengthen the variable types.
            List <KeyValuePair <Scope.DeclaredVariable, RevertInfo> > previousVariableTypes = null;
            var previousInsideTryCatchOrFinally = optimizationInfo.InsideTryCatchOrFinally;
            if (optimizationInfo.OptimizeInferredTypes == true)
            {
                // Keep a record of the variable types before strengthening.
                previousVariableTypes = new List <KeyValuePair <Scope.DeclaredVariable, RevertInfo> >();

                var typedVariables = FindTypedVariables();
                foreach (var variableAndType in typedVariables)
                {
                    var variable     = variableAndType.Key;
                    var variableInfo = variableAndType.Value;
                    if (variableInfo.Conditional == false && variableInfo.Type != variable.Type)
                    {
                        // Save the previous type so we can restore it later.
                        var previousType = variable.Type;
                        previousVariableTypes.Add(new KeyValuePair <Scope.DeclaredVariable, RevertInfo>(variable, new RevertInfo()
                        {
                            Type = previousType, Variable = variable.Store
                        }));

                        // Load the existing value.
                        var nameExpression = new NameExpression(variable.Scope, variable.Name);
                        nameExpression.GenerateGet(generator, optimizationInfo, false);

                        // Store the typed value.
                        variable.Store = generator.DeclareVariable(variableInfo.Type);
                        variable.Type  = variableInfo.Type;
                        nameExpression.GenerateSet(generator, optimizationInfo, previousType, false);
                    }
                }

                // The variables must be reverted even in the presence of exceptions.
                if (previousVariableTypes.Count > 0)
                {
                    generator.BeginExceptionBlock();

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

            // The inner loop starts here.
            var startOfLoop = generator.DefineLabelPosition();

            // Check the condition and jump to the end if it is false.
            if (this.ConditionStatement != null)
            {
#if !XBOX
                if (optimizationInfo.DebugDocument != null)
                {
                    generator.MarkSequencePoint(optimizationInfo.DebugDocument, this.ConditionStatement.DebugInfo);
                }
#endif
                this.Condition.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToBool(generator, this.Condition.ResultType);
                generator.BranchIfFalse(breakTarget2);
            }

            // Emit the loop body.
            optimizationInfo.PushBreakOrContinueInfo(this.Labels, breakTarget2, continueTarget, labelledOnly: false);
            this.Body.GenerateCode(generator, optimizationInfo);
            optimizationInfo.PopBreakOrContinueInfo();

            // The continue statement jumps here.
            generator.DefineLabelPosition(continueTarget);

            // Increment the loop variable.
            if (this.IncrementStatement != null)
            {
                this.IncrementStatement.GenerateCode(generator, optimizationInfo);
            }

            // Unconditionally branch back to the start of the loop.
            generator.Branch(startOfLoop);

            // Define the end of the loop (actually just after).
            generator.DefineLabelPosition(breakTarget2);

            // Revert the variable types.
            if (previousVariableTypes != null && previousVariableTypes.Count > 0)
            {
                // Revert the InsideTryCatchOrFinally flag.
                optimizationInfo.InsideTryCatchOrFinally = previousInsideTryCatchOrFinally;

                // Revert the variable types within a finally block.
                generator.BeginFinallyBlock();

                foreach (var previousVariableAndType in previousVariableTypes)
                {
                    var variable           = previousVariableAndType.Key;
                    var variableRevertInfo = previousVariableAndType.Value;

                    // Load the existing value.
                    var nameExpression = new NameExpression(variable.Scope, variable.Name);
                    nameExpression.GenerateGet(generator, optimizationInfo, false);

                    // Store the typed value.
                    var previousType = variable.Type;
                    variable.Store = variableRevertInfo.Variable;
                    variable.Type  = variableRevertInfo.Type;
                    nameExpression.GenerateSet(generator, optimizationInfo, previousType, false);
                }

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

            // Define the end of the loop (actually just after).
            generator.DefineLabelPosition(breakTarget1);

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
Esempio n. 21
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();
        }
Esempio n. 22
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()
            {
                NonDefaultBreakStatementBehavior = true, NonDefaultSourceSpanBehavior = true
            };

            GenerateStartOfStatement(generator, optimizationInfo, statementLocals);

            // Construct a loop expression.
            // var iterator = TypeUtilities.GetIterator(obj);
            // while (true) {
            //   continue-target:
            //   if (enumerator.MoveNext() == false)
            //     goto break-target;
            //   lhs = enumerator.Current;
            //
            //   <body statements>
            // }
            // break-target:

            // Call: ObjectInstance GetIterator(ScriptEngine engine, ObjectInstance iterable)
            // Then call: IEnumerable<object> Iterate(ScriptEngine engine, ObjectInstance iterator)
            optimizationInfo.MarkSequencePoint(generator, this.TargetObjectSourceSpan);
            EmitHelpers.LoadScriptEngine(generator);
            this.TargetObject.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.TargetObject.ResultType);
            generator.Call(ReflectionHelpers.TypeUtilities_ForOf);

            // Call IEnumerable<object>.GetEnumerator()
            generator.Call(ReflectionHelpers.IEnumerable_Object_GetEnumerator);

            // Store the enumerator in a temporary variable.
            var enumerator = generator.CreateTemporaryVariable(typeof(IEnumerator <object>));

            generator.StoreVariable(enumerator);

            var breakTarget    = generator.CreateLabel();
            var continueTarget = generator.DefineLabelPosition();

            // Emit debugging information.
            if (optimizationInfo.DebugDocument != null)
            {
                generator.MarkSequencePoint(optimizationInfo.DebugDocument, this.VariableSourceSpan);
            }

            //   if (enumerator.MoveNext() == false)
            //     goto break-target;
            generator.LoadVariable(enumerator);
            generator.Call(ReflectionHelpers.IEnumerator_MoveNext);
            generator.BranchIfFalse(breakTarget);

            // lhs = enumerator.Current;
            this.Variable.GenerateReference(generator, optimizationInfo);
            generator.LoadVariable(enumerator);
            generator.Call(ReflectionHelpers.IEnumerator_Object_Current);
            this.Variable.GenerateSet(generator, optimizationInfo, PrimitiveType.Any, false);

            // Emit the body statement(s).
            optimizationInfo.PushBreakOrContinueInfo(this.Labels, breakTarget, continueTarget, labelledOnly: false);
            this.Body.GenerateCode(generator, optimizationInfo);
            optimizationInfo.PopBreakOrContinueInfo();

            generator.Branch(continueTarget);
            generator.DefineLabelPosition(breakTarget);

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
        /// <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();
            }
        }
Esempio n. 24
0
        /// <summary>
        /// Stores the value on the top of the stack in the reference.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        /// <param name="valueType"> The primitive type of the value that is on the top of the stack. </param>
        /// <param name="throwIfUnresolvable"> <c>true</c> to throw a ReferenceError exception if
        /// the name is unresolvable; <c>false</c> to create a new property instead. </param>
        public void GenerateSet(ILGenerator generator, OptimizationInfo optimizationInfo, PrimitiveType valueType, bool throwIfUnresolvable)
        {
            // The value is initially on the top of the stack but is stored in this variable
            // at the last possible moment.
            ILLocalVariable value = null;

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

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

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

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

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

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

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

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

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

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

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

                    if (scopeVariable == null)
                    {
                        EmitHelpers.LoadScope(generator);
                    }
                    else
                    {
                        generator.LoadVariable(scopeVariable);
                    }
                    generator.CastClass(typeof(ObjectScope));
                    generator.Call(ReflectionHelpers.ObjectScope_ScopeObject);

                    if (scope.ParentScope == null && throwIfUnresolvable == false)
                    {
                        // Sets the value of a global variable.
                        // JS: object.property = value
                        // C# ==>
                        // if (propertyName == null)
                        //     propertyName = new PropertyName("property");
                        // object.SetPropertyValue(propertyName, value, strictMode);

                        ILLocalVariable propertyName = optimizationInfo.GetGlobalPropertyReferenceVariable(generator, this.Name);
                        generator.LoadVariable(propertyName);
                        generator.Duplicate();
                        var afterIf = generator.CreateLabel();
                        generator.BranchIfNotNull(afterIf);
                        generator.Pop();
                        generator.LoadString(this.Name);
                        generator.NewObject(ReflectionHelpers.PropertyName_Constructor);
                        generator.Duplicate();
                        generator.StoreVariable(propertyName);
                        generator.DefineLabelPosition(afterIf);

                        generator.LoadVariable(value);
                        generator.LoadBoolean(optimizationInfo.StrictMode);
                        generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_PropertyReference);
                    }
                    else
                    {
                        // Setting a variable within a "with" scope.
                        generator.LoadString(this.Name);
                        generator.LoadVariable(value);
                        generator.LoadBoolean(optimizationInfo.StrictMode);

                        // Set the property value if the property exists.
                        generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValueIfExists);

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

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

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

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

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

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