ReleaseTemporaryVariable() public method

Indicates that the given temporary variable is no longer needed.
public ReleaseTemporaryVariable ( ILLocalVariable temporaryVariable ) : void
temporaryVariable ILLocalVariable The temporary variable created using CreateTemporaryVariable().
return void
Exemplo n.º 1
0
        /// <summary>
        /// Generates CIL for the in operator.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        private void GenerateIn(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Emit the left-hand side expression and convert it to a string.
            this.Left.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToString(generator, this.Left.ResultType);

            // Store the left-hand side expression in a temporary variable.
            var temp = generator.CreateTemporaryVariable(typeof(string));

            generator.StoreVariable(temp);

            // Emit the right-hand side expression.
            this.Right.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.Right.ResultType);

            // Check the right-hand side is a javascript object - if not, throw an exception.
            generator.Duplicate();
            generator.IsInstance(typeof(ObjectInstance));
            var endOfTypeCheck = generator.CreateLabel();

            generator.BranchIfTrue(endOfTypeCheck);

            // Throw an nicely formatted exception.
            var rightValue = generator.CreateTemporaryVariable(typeof(object));

            generator.StoreVariable(rightValue);
            generator.LoadEnumValue(ErrorType.TypeError);
            generator.LoadString("The in operator expected an object, but found '{0}' instead");
            generator.LoadInt32(1);
            generator.NewArray(typeof(object));
            generator.Duplicate();
            generator.LoadInt32(0);
            generator.LoadVariable(rightValue);
            generator.Call(ReflectionHelpers.TypeUtilities_TypeOf);
            generator.StoreArrayElement(typeof(object));
            generator.Call(ReflectionHelpers.String_Format);
            generator.LoadInt32(optimizationInfo.SourceSpan.StartLine);
            generator.LoadStringOrNull(optimizationInfo.Source.Path);
            generator.LoadStringOrNull(optimizationInfo.FunctionName);
            generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error);
            generator.Throw();
            generator.DefineLabelPosition(endOfTypeCheck);
            generator.ReleaseTemporaryVariable(rightValue);
            generator.ReinterpretCast(typeof(ObjectInstance));

            // Load the left-hand side expression from the temporary variable.
            generator.LoadVariable(temp);

            // Call ObjectInstance.HasProperty(object)
            generator.Call(ReflectionHelpers.ObjectInstance_HasProperty);

            // Allow the temporary variable to be reused.
            generator.ReleaseTemporaryVariable(temp);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Generates CIL for the instanceof operator.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        private void GenerateInstanceOf(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Emit the left-hand side expression and convert it to an object.
            this.Left.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.Left.ResultType);

            // Store the left-hand side expression in a temporary variable.
            var temp = generator.CreateTemporaryVariable(typeof(object));

            generator.StoreVariable(temp);

            // Emit the right-hand side expression.
            this.Right.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.Right.ResultType);

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

            generator.BranchIfNotNull(endOfTypeCheck);

            // Throw an nicely formatted exception.
            var rightValue = generator.CreateTemporaryVariable(typeof(object));

            generator.StoreVariable(rightValue);
            EmitHelpers.LoadScriptEngine(generator);
            generator.LoadString("TypeError");
            generator.LoadString("The instanceof operator expected a function, but found '{0}' instead");
            generator.LoadInt32(1);
            generator.NewArray(typeof(object));
            generator.Duplicate();
            generator.LoadInt32(0);
            generator.LoadVariable(rightValue);
            generator.Call(ReflectionHelpers.TypeUtilities_TypeOf);
            generator.StoreArrayElement(typeof(object));
            generator.Call(ReflectionHelpers.String_Format);
            generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error);
            generator.Throw();
            generator.DefineLabelPosition(endOfTypeCheck);
            generator.ReleaseTemporaryVariable(rightValue);

            // Load the left-hand side expression from the temporary variable.
            generator.LoadVariable(temp);

            // Call FunctionInstance.HasInstance(object)
            generator.Call(ReflectionHelpers.FunctionInstance_HasInstance);

            // Allow the temporary variable to be reused.
            generator.ReleaseTemporaryVariable(temp);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Generates CIL for an assignment 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>
        /// <param name="target"> The target to modify. </param>
        private void GenerateAssignment(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target)
        {
            // Evaluate the left hand side first!
            target.GenerateReference(generator, optimizationInfo);

            // Load the value to assign.
            var rhs = this.GetOperand(1);

            rhs.GenerateCode(generator, optimizationInfo);

            // Support the inferred function displayName property.
            if (rhs is FunctionExpression)
            {
                ((FunctionExpression)rhs).GenerateDisplayName(generator, optimizationInfo, target.ToString(), false);
            }

            // Store the RHS value so we can return it as the result of the expression.
            var result = generator.CreateTemporaryVariable(rhs.ResultType);

            generator.Duplicate();
            generator.StoreVariable(result);

            // Store the value.
            target.GenerateSet(generator, optimizationInfo, rhs.ResultType, optimizationInfo.StrictMode);

            // Restore the RHS value.
            generator.LoadVariable(result);
            generator.ReleaseTemporaryVariable(result);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Generates CIL for a compound assignment 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>
        /// <param name="target"> The target to modify. </param>
        private void GenerateCompoundAssignment(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target)
        {
            // Evaluate the left hand side only once.
            target.GenerateReference(generator, optimizationInfo);
            target.DuplicateReference(generator, optimizationInfo); // For the GenerateSet, later on.

            // Load the value to assign.
            var compoundOperator = new BinaryExpression(GetCompoundBaseOperator(this.OperatorType), new ReferenceGetExpression(target), this.GetOperand(1));

            compoundOperator.GenerateCode(generator, optimizationInfo);

            ILLocalVariable result = null;

            if (optimizationInfo.IgnoreReturnValue != this)
            {
                // Store the resulting value so we can return it as the result of the expression.
                result = generator.CreateTemporaryVariable(compoundOperator.ResultType);
                generator.Duplicate();
                generator.StoreVariable(result);
            }

            // Store the value.
            target.GenerateSet(generator, optimizationInfo, compoundOperator.ResultType);

            if (optimizationInfo.IgnoreReturnValue != this)
            {
                // Restore the expression result.
                generator.LoadVariable(result);
                generator.ReleaseTemporaryVariable(result);
            }
            else
            {
                optimizationInfo.ReturnValueWasNotGenerated = true;
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// Generates CIL for an assignment 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>
        /// <param name="target"> The target to modify. </param>
        private void GenerateAssignment(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target)
        {
            // Evaluate the left hand side first!
            target.GenerateReference(generator, optimizationInfo);

            // Load the value to assign.
            var rhs = this.GetOperand(1);

            rhs.GenerateCode(generator, optimizationInfo);

            ILLocalVariable result = null;

            if (optimizationInfo.IgnoreReturnValue != this)
            {
                // Store the RHS value so we can return it as the result of the expression.
                result = generator.CreateTemporaryVariable(rhs.ResultType);
                generator.Duplicate();
                generator.StoreVariable(result);
            }

            // Store the value.
            target.GenerateSet(generator, optimizationInfo, rhs.ResultType);

            if (optimizationInfo.IgnoreReturnValue != this)
            {
                // Restore the RHS value.
                generator.LoadVariable(result);
                generator.ReleaseTemporaryVariable(result);
            }
            else
            {
                optimizationInfo.ReturnValueWasNotGenerated = true;
            }
        }
Exemplo n.º 6
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>
        public void GenerateSet(ILGenerator generator, OptimizationInfo optimizationInfo, PrimitiveType valueType)
        {
            // TODO: Optimize this.
            //
            // ++ or --
            // GenerateReference
            // DuplicateReference
            // GenerateGet
            // ToNumber
            // if (postfix) Dup/Store in variable
            // Increment/Decrement
            // if (prefix) Dup/Store in variable
            // GenerateSet
            // Load variable
            //
            // +=
            // GenerateReference
            // DuplicateReference
            // GenerateGet
            // Dup/Store in variable
            // GenerateSet
            // Load variable
            //
            // for (in/of)
            // GenerateReference
            // LoadVariable(enumerator)
            // GenerateGet
            // GenerateSet
            //
            // =
            // GenerateReference
            // target.GenerateGet
            // Dup/Store in variable
            // GenerateSet
            // Load variable

            // If we have allocated an IL variable, use it.
            var variableInfo = Scope.FindStaticVariable(Name);

            if (variableInfo != null && variableInfo.Store != null)
            {
                EmitConversion.Convert(generator, valueType, variableInfo.Type);
                generator.StoreVariable(variableInfo.Store);
                return;
            }

            // Fallback: call RuntimeScope.SetValue() or RuntimeScope.SetValueStrict().
            var temp = generator.CreateTemporaryVariable(valueType);

            generator.StoreVariable(temp);
            Scope.GenerateReference(generator, optimizationInfo);
            generator.LoadString(Name);
            generator.LoadVariable(temp);
            EmitConversion.ToAny(generator, valueType);
            generator.LoadInt32(optimizationInfo.SourceSpan.StartLine);
            generator.LoadStringOrNull(optimizationInfo.Source.Path);
            generator.Call(optimizationInfo.StrictMode ? ReflectionHelpers.RuntimeScope_SetValueStrict : ReflectionHelpers.RuntimeScope_SetValue);
            generator.ReleaseTemporaryVariable(temp);
        }
Exemplo n.º 7
0
 /// <summary>
 /// Emits a default value of the given type.
 /// </summary>
 /// <param name="generator"> The IL generator. </param>
 /// <param name="type"> The type of value to generate. </param>
 public static void EmitDefaultValue(ILGenerator generator, Type type)
 {
     var temp = generator.CreateTemporaryVariable(type);
     generator.LoadAddressOfVariable(temp);
     generator.InitObject(temp.Type);
     generator.LoadVariable(temp);
     generator.ReleaseTemporaryVariable(temp);
 }
Exemplo n.º 8
0
        /// <summary>
        /// Emits a default value of the given type.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="type"> The type of value to generate. </param>
        public static void EmitDefaultValue(ILGenerator generator, Type type)
        {
            var temp = generator.CreateTemporaryVariable(type);

            generator.LoadAddressOfVariable(temp);
            generator.InitObject(temp.Type);
            generator.LoadVariable(temp);
            generator.ReleaseTemporaryVariable(temp);
        }
Exemplo n.º 9
0
        /// <summary>
        /// Outputs the values needed to get or set this 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>
        public void DuplicateReference(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            string             propertyName     = null;
            TypeOfMemberAccess memberAccessType = DetermineTypeOfMemberAccess(optimizationInfo, out propertyName);

            if (memberAccessType == TypeOfMemberAccess.ArrayIndex)
            {
                // Array indexer
                var arg1 = generator.CreateTemporaryVariable(typeof(object));
                var arg2 = generator.CreateTemporaryVariable(typeof(uint));
                generator.StoreVariable(arg2);
                generator.StoreVariable(arg1);
                generator.LoadVariable(arg1);
                generator.LoadVariable(arg2);
                generator.LoadVariable(arg1);
                generator.LoadVariable(arg2);
                generator.ReleaseTemporaryVariable(arg1);
                generator.ReleaseTemporaryVariable(arg2);
            }
            else if (memberAccessType == TypeOfMemberAccess.Static)
            {
                // Named property access
                generator.Duplicate();
            }
            else
            {
                // Dynamic property access
                var arg1 = generator.CreateTemporaryVariable(typeof(object));
                var arg2 = generator.CreateTemporaryVariable(typeof(object));
                generator.StoreVariable(arg2);
                generator.StoreVariable(arg1);
                generator.LoadVariable(arg1);
                generator.LoadVariable(arg2);
                generator.LoadVariable(arg1);
                generator.LoadVariable(arg2);
                generator.ReleaseTemporaryVariable(arg1);
                generator.ReleaseTemporaryVariable(arg2);
            }
        }
Exemplo n.º 10
0
        /// <summary>
        /// Pops the value on the stack, converts it to a javascript object, then pushes the result
        /// onto the stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        /// <param name="path"> The path of the javascript source file that is currently executing. </param>
        /// <param name="function"> The name of the currently executing function. </param>
        /// <param name="line"> The line number of the statement that is currently executing. </param>
        public static void ToObject(ILGenerator generator, PrimitiveType fromType, string path, string function, int line)
        {
            // Check that a conversion is actually necessary.
            if (fromType == PrimitiveType.Object)
            {
                generator.ReinterpretCast(typeof(ObjectInstance));
                return;
            }

            switch (fromType)
            {
            case PrimitiveType.Undefined:
                // Converting from undefined always throws an exception.
                EmitHelpers.EmitThrow(generator, ErrorType.TypeError, "Undefined cannot be converted to an object", path, function, line);
                generator.ReinterpretCast(typeof(ObjectInstance));
                break;

            case PrimitiveType.Null:
                // Converting from null always throws an exception.
                EmitHelpers.EmitThrow(generator, ErrorType.TypeError, "Null cannot be converted to an object", path, function, line);
                generator.ReinterpretCast(typeof(ObjectInstance));
                break;

            case PrimitiveType.Bool:
            case PrimitiveType.Int32:
            case PrimitiveType.UInt32:
            case PrimitiveType.Number:
            case PrimitiveType.String:
            case PrimitiveType.ConcatenatedString:
            case PrimitiveType.Any:
                // Otherwise, fall back to calling TypeConverter.ToObject()
                ToAny(generator, fromType);
                var temp = generator.CreateTemporaryVariable(typeof(object));
                generator.StoreVariable(temp);
                EmitHelpers.LoadScriptEngine(generator);
                generator.LoadVariable(temp);
                generator.ReleaseTemporaryVariable(temp);
                generator.LoadInt32(line);
                generator.LoadStringOrNull(path);
                generator.LoadStringOrNull(function);
                generator.Call(ReflectionHelpers.TypeConverter_ToObject);
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
Exemplo n.º 11
0
        /// <summary>
        /// Pops the value on the stack, converts it to an object, then pushes the result onto the
        /// stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        internal static void EmitConversionToObject(ILGenerator generator, Type fromType)
        {
            // If the from type is a reference type, check for null.
            ILLabel endOfNullCheck = null;

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

            // Handle Nullable<>.
            var isNullable = fromType.IsGenericType && fromType.GetGenericTypeDefinition() == typeof(Nullable <>);

            if (isNullable)
            {
                endOfNullCheck = generator.CreateLabel();

                var v = generator.CreateTemporaryVariable(fromType);
                generator.StoreVariable(v);
                generator.LoadAddressOfVariable(v);

                var hasValue = ReflectionHelpers.GetInstanceMethod(fromType, "get_HasValue");
                generator.Call(hasValue);
                generator.BranchIfTrue(endOfNullCheck);

                // Return null.
                generator.LoadNull();
                generator.Return();

                // Jump here if it was NOT null.
                generator.DefineLabelPosition(endOfNullCheck);

                // Get the underlying value.
                generator.LoadAddressOfVariable(v);
                var getValue = ReflectionHelpers.GetInstanceMethod(fromType, "get_Value");
                generator.Call(getValue);

                // Now let the normal conversion work.
                fromType = fromType.GenericTypeArguments[0];
            }

            switch (Type.GetTypeCode(fromType))
            {
            case TypeCode.Boolean:
                generator.Box(typeof(bool));
                break;

            case TypeCode.Byte:
                generator.Box(typeof(int));
                break;

            case TypeCode.Char:
                generator.LoadInt32(1);
                generator.NewObject(ReflectionHelpers.String_Constructor_Char_Int);
                break;

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

            case TypeCode.Decimal:
                generator.Call(ReflectionHelpers.Decimal_ToDouble);
                generator.Box(typeof(double));
                break;

            case TypeCode.Double:
                generator.Box(typeof(double));
                break;

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

            case TypeCode.Int16:
                generator.Box(typeof(int));
                break;

            case TypeCode.Int32:
                generator.Box(typeof(int));
                break;

            case TypeCode.Int64:
                generator.ConvertToDouble();
                generator.Box(typeof(double));
                break;

            case TypeCode.DateTime:
            case TypeCode.Object:
                // Check if the type must be wrapped with a ClrInstanceWrapper.
                // Note: if the type is a value type it cannot be a primitive or it would
                // have been handled elsewhere in the switch.
                ILLabel endOfWrapCheck = null;
                if (fromType.IsValueType == false)
                {
                    generator.Duplicate();
                    generator.Call(ReflectionHelpers.TypeUtilities_IsPrimitiveOrObject);
                    endOfWrapCheck = generator.CreateLabel();
                    generator.BranchIfTrue(endOfWrapCheck);
                }

                // The type must be wrapped.
                var temp = generator.CreateTemporaryVariable(fromType);
                generator.StoreVariable(temp);
                generator.LoadArgument(0);
                generator.LoadVariable(temp);
                if (fromType.IsValueType == true)
                {
                    generator.Box(fromType);
                }
                generator.ReleaseTemporaryVariable(temp);
                generator.CallStatic(ReflectionHelpers.ClrInstanceWrapper_Create);

                // End of wrap check.
                if (fromType.IsValueType == false)
                {
                    generator.DefineLabelPosition(endOfWrapCheck);
                }
                break;

            case TypeCode.SByte:
                generator.Box(typeof(int));
                break;

            case TypeCode.Single:
                generator.Box(typeof(double));
                break;

            case TypeCode.String:
                break;

            case TypeCode.UInt16:
                generator.Box(typeof(int));
                break;

            case TypeCode.UInt32:
                generator.Box(typeof(uint));
                break;

            case TypeCode.UInt64:
                generator.ConvertUnsignedToDouble();
                generator.Box(typeof(double));
                break;
            }

            // Label the end of the null check.
            if (fromType.IsValueType == false)
            {
                generator.DefineLabelPosition(endOfNullCheck);
            }
        }
Exemplo n.º 12
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)
        {
            string propertyName = null;
            TypeOfMemberAccess memberAccessType = DetermineTypeOfMemberAccess(optimizationInfo, out propertyName);

            if (memberAccessType == TypeOfMemberAccess.ArrayIndex)
            {
                // Array indexer
                // -------------
                // xxx = object[index]

                // Call the indexer.
                EmitConversion.ToAny(generator, valueType);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_Int);
            }
            else if (memberAccessType == TypeOfMemberAccess.Static)
            {
                // Named property modification (e.g. x.property = y)
                // -------------------------------------------------
                // __object_cacheKey = null;
                // __object_property_cachedIndex = 0;
                // ...
                // if (__object_cacheKey != object.InlineCacheKey)
                //     object.InlineSetPropertyValue("property", value, strictMode, out __object_property_cachedIndex, out __object_cacheKey)
                // else
                //     object.InlinePropertyValues[__object_property_cachedIndex] = value;

                // Convert the value to an object and store it in a temporary variable.
                var value = generator.CreateTemporaryVariable(typeof(object));
                EmitConversion.ToAny(generator, valueType);
                generator.StoreVariable(value);

                // 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.InlineSetPropertyValue("property", value, strictMode, out __object_property_cachedIndex, out __object_cacheKey)
                generator.LoadVariable(objectInstance);
                generator.LoadString(propertyName);
                generator.LoadVariable(value);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.LoadAddressOfVariable(cachedIndex);
                generator.LoadAddressOfVariable(cacheKey);
                generator.Call(ReflectionHelpers.ObjectInstance_InlineSetPropertyValue);

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

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

                // The temporary variable is no longer needed.
                generator.ReleaseTemporaryVariable(value);
            }
            else
            {
                // Dynamic property access
                // -----------------------
                // xxx = object.Get(x)

                // Call the indexer.
                EmitConversion.ToAny(generator, valueType);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_Object);
            }
        }
Exemplo 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 (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);
        }
Exemplo n.º 14
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);
        }
Exemplo 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 };
            GenerateStartOfStatement(generator, optimizationInfo, statementLocals);

            // We need a label for each case clause and one for the default case.
            var jumpTargets = new ILLabel[this.CaseClauses.Count];
            int defaultIndex = -1;
            ILLabel endOfSwitch = generator.CreateLabel();

            // Generate code for the switch value.
            var startOfSwitch = generator.CreateLabel();
            this.Value.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.Value.ResultType);

            // Save the switch value in a variable.
            var switchValue = generator.CreateTemporaryVariable(typeof(object));
            generator.StoreVariable(switchValue);

            for (int i = 0; i < this.CaseClauses.Count; i ++)
            {
                var caseClause = this.CaseClauses[i];

                // Create a label for each clause.
                jumpTargets[i] = generator.CreateLabel();

                if (caseClause.Value == null)
                {
                    // This is a default clause.
                    defaultIndex = i;
                    continue;
                }

                // TypeComparer.StrictEquals(switchValue, caseValue)
                generator.LoadVariable(switchValue);
                caseClause.Value.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, caseClause.Value.ResultType);
                generator.Call(ReflectionHelpers.TypeComparer_StrictEquals);

                // if (TypeComparer.StrictEquals(switchValue, caseValue) == true)
                //     goto case i
                generator.BranchIfTrue(jumpTargets[i]);
            }
            
            // None of the cases matched, jump to the default clause or the end of the switch.
            if (defaultIndex >= 0)
                generator.Branch(jumpTargets[defaultIndex]);
            else
                generator.Branch(endOfSwitch);

            for (int i = 0; i < this.CaseClauses.Count; i++)
            {
                // Define a label at the start of the case clause.
                generator.DefineLabelPosition(jumpTargets[i]);

                // Set up the information needed by the break statement.
                optimizationInfo.PushBreakOrContinueInfo(this.Labels, endOfSwitch, null, labelledOnly: false);

                // Emit the case clause statements.
                foreach (var statement in this.CaseClauses[i].BodyStatements)
                    statement.GenerateCode(generator, optimizationInfo);

                // Revert the information needed by the break statement.
                optimizationInfo.PopBreakOrContinueInfo();
            }

            // Define a label for the end of the switch statement.
            generator.DefineLabelPosition(endOfSwitch);

            // Release the switch value variable for use elsewhere.
            generator.ReleaseTemporaryVariable(switchValue);

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
Exemplo n.º 16
0
        /// <summary>
        /// Generates a method that does type conversion and calls the bound method.
        /// </summary>
        /// <param name="generator"> The ILGenerator used to output the body of the method. </param>
        /// <param name="argumentCount"> The number of arguments that will be passed to the delegate. </param>
        /// <returns> A delegate that does type conversion and calls the method represented by this
        /// object. </returns>
        protected override void GenerateStub(ILGenerator generator, int argumentCount)
        {
            // Here is what we are going to generate.
            //private static object SampleBinder(ScriptEngine engine, object thisObject, object[] arguments)
            //{
            //    // Target function signature: int (bool, int, string, object).
            //    bool param1;
            //    int param2;
            //    string param3;
            //    object param4;
            //    param1 = arguments[0] != 0;
            //    param2 = TypeConverter.ToInt32(arguments[1]);
            //    param3 = TypeConverter.ToString(arguments[2]);
            //    param4 = Undefined.Value;
            //    return thisObject.targetMethod(param1, param2, param3, param4);
            //}

            // Find the target method.
            var binderMethod = this.buckets[Math.Min(argumentCount, this.buckets.Length - 1)];

            // Constrain the number of apparent arguments to within the required bounds.
            int minArgumentCount = binderMethod.RequiredParameterCount;
            int maxArgumentCount = binderMethod.RequiredParameterCount + binderMethod.OptionalParameterCount;

            if (binderMethod.HasParamArray == true)
            {
                maxArgumentCount = int.MaxValue;
            }

            foreach (var argument in binderMethod.GenerateArguments(generator, Math.Min(Math.Max(argumentCount, minArgumentCount), maxArgumentCount)))
            {
                switch (argument.Source)
                {
                case BinderArgumentSource.ScriptEngine:
                    // Load the "engine" parameter passed by the client.
                    generator.LoadArgument(0);
                    break;

                case BinderArgumentSource.ThisValue:
                    // Load the "this" parameter passed by the client.
                    generator.LoadArgument(1);

                    bool inheritsFromObjectInstance = typeof(ObjectInstance).IsAssignableFrom(argument.Type);
                    if (argument.Type.IsClass == true && inheritsFromObjectInstance == false &&
                        argument.Type != typeof(string) && argument.Type != typeof(object))
                    {
                        // If the "this" object is an unsupported class, pass it through unmodified.
                        generator.CastClass(argument.Type);
                    }
                    else
                    {
                        if (argument.Type != typeof(object))
                        {
                            // If the target "this" object type is not of type object, throw an error if
                            // the value is undefined or null.
                            generator.Duplicate();
                            var temp = generator.CreateTemporaryVariable(typeof(object));
                            generator.StoreVariable(temp);
                            generator.LoadArgument(0);
                            generator.LoadVariable(temp);
                            generator.LoadString(binderMethod.Name);
                            generator.Call(ReflectionHelpers.TypeUtilities_VerifyThisObject);
                            generator.ReleaseTemporaryVariable(temp);
                        }

                        // Convert to the target type.
                        EmitTypeConversion(generator, typeof(object), argument.Type);

                        if (argument.Type != typeof(ObjectInstance) && inheritsFromObjectInstance == true)
                        {
                            // EmitConversionToObjectInstance can emit null if the toType is derived from ObjectInstance.
                            // Therefore, if the value emitted is null it means that the "thisObject" is a type derived
                            // from ObjectInstance (e.g. FunctionInstance) and the value provided is a different type
                            // (e.g. ArrayInstance).  In this case, throw an exception explaining that the function is
                            // not generic.
                            var endOfThrowLabel = generator.CreateLabel();
                            generator.Duplicate();
                            generator.BranchIfNotNull(endOfThrowLabel);
                            generator.LoadArgument(0);
                            EmitHelpers.EmitThrow(generator, "TypeError", string.Format("The method '{0}' is not generic", binderMethod.Name));
                            generator.DefineLabelPosition(endOfThrowLabel);
                        }
                    }
                    break;

                case BinderArgumentSource.InputParameter:
                    if (argument.InputParameterIndex < argumentCount)
                    {
                        // Load the argument onto the stack.
                        generator.LoadArgument(2);
                        generator.LoadInt32(argument.InputParameterIndex);
                        generator.LoadArrayElement(typeof(object));

                        // Get some flags that apply to the parameter.
                        var parameterFlags     = JSParameterFlags.None;
                        var parameterAttribute = argument.GetCustomAttribute <JSParameterAttribute>();
                        if (parameterAttribute != null)
                        {
                            if (argument.Type != typeof(ObjectInstance))
                            {
                                throw new NotImplementedException("[JSParameter] is only supported for arguments of type ObjectInstance.");
                            }
                            parameterFlags = parameterAttribute.Flags;
                        }

                        if ((parameterFlags & JSParameterFlags.DoNotConvert) == 0)
                        {
                            // Convert the input parameter to the correct type.
                            EmitTypeConversion(generator, typeof(object), argument);
                        }
                        else
                        {
                            // Don't do argument conversion.

                            /*var endOfThrowLabel = generator.CreateLabel();
                             * generator.IsInstance(typeof(ObjectInstance));
                             * generator.Duplicate();
                             * generator.BranchIfNotNull(endOfThrowLabel);
                             * EmitHelpers.EmitThrow(generator, "TypeError", string.Format("Parameter {1} parameter of '{0}' must be an object", binderMethod.Name, argument.InputParameterIndex));
                             * generator.DefineLabelPosition(endOfThrowLabel);*/
                        }
                    }
                    else
                    {
                        // The target method has more parameters than we have input values.
                        EmitUndefined(generator, argument);
                    }
                    break;
                }
            }

            // Emit the call.
            binderMethod.GenerateCall(generator);

            // Convert the return value.
            if (binderMethod.ReturnType == typeof(void))
            {
                EmitHelpers.EmitUndefined(generator);
            }
            else
            {
                EmitTypeConversion(generator, binderMethod.ReturnType, typeof(object));

                // Convert a null return value to Null.Value or Undefined.Value.
                var endOfSpecialCaseLabel = generator.CreateLabel();
                generator.Duplicate();
                generator.BranchIfNotNull(endOfSpecialCaseLabel);
                generator.Pop();
                if ((binderMethod.Flags & JSFunctionFlags.ConvertNullReturnValueToUndefined) != 0)
                {
                    EmitHelpers.EmitUndefined(generator);
                }
                else
                {
                    EmitHelpers.EmitNull(generator);
                }
                generator.DefineLabelPosition(endOfSpecialCaseLabel);
            }

            // End the IL.
            generator.Complete();
        }
Exemplo n.º 17
0
        /// <summary>
        /// Generates CIL for the expression.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Check if this is a direct call to eval().
            if (this.Target is NameExpression && ((NameExpression)this.Target).Name == "eval")
            {
                GenerateEval(generator, optimizationInfo);
                return;
            }

            // Check if this is a super() call.
            if (this.Target is SuperExpression)
            {
                // executionContext.CallSuperClass(arguments)
                EmitHelpers.LoadExecutionContext(generator);
                GenerateArgumentsArray(generator, optimizationInfo);
                generator.Call(ReflectionHelpers.ExecutionContext_CallSuperClass);
                return;
            }

            // Emit the function instance first.
            ILLocalVariable targetBase = null;

            if (this.Target is MemberAccessExpression)
            {
                // The function is a member access expression (e.g. "Math.cos()").

                // Evaluate the left part of the member access expression.
                var baseExpression = ((MemberAccessExpression)this.Target).Base;
                baseExpression.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, baseExpression.ResultType);
                targetBase = generator.CreateTemporaryVariable(typeof(object));
                generator.StoreVariable(targetBase);

                // Evaluate the right part of the member access expression.
                var memberAccessExpression = new MemberAccessExpression(((MemberAccessExpression)this.Target).Operator);
                memberAccessExpression.Push(new TemporaryVariableExpression(targetBase));
                memberAccessExpression.Push(((MemberAccessExpression)this.Target).GetOperand(1));
                memberAccessExpression.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, this.Target.ResultType);
            }
            else
            {
                // Something else (e.g. "my_func()").
                this.Target.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, this.Target.ResultType);
            }

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

            generator.BranchIfTrue(endOfTypeCheck);

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

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

            // Generate code to produce the "this" value.  There are three cases.
            if (this.Target is NameExpression)
            {
                // 1. The function is a name expression (e.g. "parseInt()").
                //    If we are inside a with() block, then there is an implicit 'this' value,
                //    otherwise 'this' is undefined.
                Scope.GenerateReference(generator, optimizationInfo);
                generator.Call(ReflectionHelpers.RuntimeScope_ImplicitThis);
            }
            else if (this.Target is MemberAccessExpression targetMemberAccessExpression)
            {
                // 2. The function is a member access expression (e.g. "Math.cos()").
                //    In this case this = Math.
                //    Unless it's a super call like super.blah().
                if (targetMemberAccessExpression.Base is SuperExpression)
                {
                    EmitHelpers.LoadThis(generator);
                }
                else
                {
                    generator.LoadVariable(targetBase);
                }
            }
            else
            {
                // 3. Neither of the above (e.g. "(function() { return 5 })()")
                //    In this case this = undefined.
                EmitHelpers.EmitUndefined(generator);
            }

            // Emit an array containing the function arguments.
            GenerateArgumentsArray(generator, optimizationInfo);

            // Call FunctionInstance.CallLateBound(thisValue, argumentValues)
            generator.Call(ReflectionHelpers.FunctionInstance_CallWithStackTrace);

            // Allow reuse of the temporary variable.
            if (targetBase != null)
            {
                generator.ReleaseTemporaryVariable(targetBase);
            }
        }
Exemplo n.º 18
0
        /// <summary>
        /// Pops the value on the stack, converts it to an object, then pushes the result onto the
        /// stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        internal static void EmitConversionToObject(ILGenerator generator, Type fromType)
        {
            // If the from type is a reference type, check for null.
            ILLabel endOfNullCheck = null;
            if (fromType.IsValueType == false)
            {
                var startOfElse = generator.CreateLabel();
                endOfNullCheck = generator.CreateLabel();
                generator.Duplicate();
                generator.BranchIfNotNull(startOfElse);
                generator.Pop();
                EmitHelpers.EmitNull(generator);
                generator.Branch(endOfNullCheck);
                generator.DefineLabelPosition(startOfElse);
            }

            switch (Type.GetTypeCode(fromType))
            {
                case TypeCode.Boolean:
                    generator.Box(typeof(bool));
                    break;
                case TypeCode.Byte:
                    generator.Box(typeof(int));
                    break;
                case TypeCode.Char:
                    generator.LoadInt32(1);
                    generator.NewObject(ReflectionHelpers.String_Constructor_Char_Int);
                    break;
                
                case TypeCode.DBNull:
                    throw new NotSupportedException("DBNull is not a supported return type.");
                case TypeCode.Decimal:
                    generator.Call(ReflectionHelpers.Decimal_ToDouble);
                    generator.Box(typeof(double));
                    break;
                case TypeCode.Double:
                    generator.Box(typeof(double));
                    break;
                case TypeCode.Empty:
                    throw new NotSupportedException("Empty is not a supported return type.");
                case TypeCode.Int16:
                    generator.Box(typeof(int));
                    break;
                case TypeCode.Int32:
                    generator.Box(typeof(int));
                    break;
                case TypeCode.Int64:
                    generator.ConvertToDouble();
                    generator.Box(typeof(double));
                    break;

                case TypeCode.DateTime:
                case TypeCode.Object:
                    // Check if the type must be wrapped with a ClrInstanceWrapper.
                    // Note: if the type is a value type it cannot be a primitive or it would
                    // have been handled elsewhere in the switch.
                    ILLabel endOfWrapCheck = null;
                    if (fromType.IsValueType == false)
                    {
                        generator.Duplicate();
                        generator.Call(ReflectionHelpers.TypeUtilities_IsPrimitiveOrObject);
                        endOfWrapCheck = generator.CreateLabel();
                        generator.BranchIfTrue(endOfWrapCheck);
                    }

                    // The type must be wrapped.
                    var temp = generator.CreateTemporaryVariable(fromType);
                    generator.StoreVariable(temp);
                    generator.LoadArgument(0);
                    generator.LoadVariable(temp);
                    if (fromType.IsValueType == true)
                        generator.Box(fromType);
                    generator.ReleaseTemporaryVariable(temp);
                    generator.NewObject(ReflectionHelpers.ClrInstanceWrapper_Constructor);
                    
                    // End of wrap check.
                    if (fromType.IsValueType == false)
                        generator.DefineLabelPosition(endOfWrapCheck);
                    break;

                case TypeCode.SByte:
                    generator.Box(typeof(int));
                    break;
                case TypeCode.Single:
                    generator.Box(typeof(double));
                    break;
                case TypeCode.String:
                    break;
                case TypeCode.UInt16:
                    generator.Box(typeof(int));
                    break;
                case TypeCode.UInt32:
                    generator.Box(typeof(uint));
                    break;
                case TypeCode.UInt64:
                    generator.ConvertUnsignedToDouble();
                    generator.Box(typeof(double));
                    break;
            }

            // Label the end of the null check.
            if (fromType.IsValueType == false)
                generator.DefineLabelPosition(endOfNullCheck);
        }
Exemplo n.º 19
0
        /// <summary>
        /// Pops the value on the stack, converts it to an integer, then pushes the integer result
        /// onto the stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        public static void ToInteger(ILGenerator generator, PrimitiveType fromType)
        {
            // Check that a conversion is actually necessary.
            if (fromType == PrimitiveType.Int32 || fromType == PrimitiveType.UInt32 || fromType == PrimitiveType.Bool)
                return;

            switch (fromType)
            {
                case PrimitiveType.Undefined:
                case PrimitiveType.Null:
                    // Converting from undefined or null produces 0.
                    generator.Pop();
                    generator.LoadInt32(0);
                    break;

                case PrimitiveType.Number:
                    // Converting from a number produces the following:
                    // Any number between -2147483648 and +2147483647 -> itself
                    // Any number smaller than -2147483648 -> -2147483648
                    // Any number larger than +2147483647 -> +2147483647
                    // NaN -> 0

                    // bool isPositiveInfinity = input > 2147483647.0
                    var isPositiveInfinity = generator.CreateTemporaryVariable(typeof(bool));
                    generator.Duplicate();
                    generator.LoadDouble(2147483647.0);
                    generator.CompareGreaterThan();
                    generator.StoreVariable(isPositiveInfinity);

                    // bool notNaN = input == input
                    var notNaN = generator.CreateTemporaryVariable(typeof(bool));
                    generator.Duplicate();
                    generator.Duplicate();
                    generator.CompareEqual();
                    generator.StoreVariable(notNaN);

                    // input = (int)input
                    // Infinity -> -2147483648
                    // -Infinity -> -2147483648
                    // NaN -> -2147483648
                    generator.ConvertToInteger();

                    // input = input & -((int)notNaN)
                    generator.LoadVariable(notNaN);
                    generator.Negate();
                    generator.BitwiseAnd();

                    // input = input - (int)isPositiveInfinity
                    generator.LoadVariable(isPositiveInfinity);
                    generator.Subtract();

                    // The temporary variables are no longer needed.
                    generator.ReleaseTemporaryVariable(notNaN);
                    generator.ReleaseTemporaryVariable(isPositiveInfinity);
                    break;

                case PrimitiveType.String:
                case PrimitiveType.ConcatenatedString:
                case PrimitiveType.Any:
                case PrimitiveType.Object:
                    // Otherwise, fall back to calling TypeConverter.ToInteger()
                    generator.Call(ReflectionHelpers.TypeConverter_ToInteger);
                    break;

                default:
                    throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
Exemplo n.º 20
0
        /// <summary>
        /// Pops the value on the stack, converts it to a javascript object, then pushes the result
        /// onto the stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        /// <param name="path"> The path of the javascript source file that is currently executing. </param>
        /// <param name="function"> The name of the currently executing function. </param>
        /// <param name="line"> The line number of the statement that is currently executing. </param>
        public static void ToObject(ILGenerator generator, PrimitiveType fromType, string path, string function, int line)
        {
            // Check that a conversion is actually necessary.
            if (fromType == PrimitiveType.Object)
                return;

            switch (fromType)
            {
                case PrimitiveType.Undefined:
                    // Converting from undefined always throws an exception.
                    EmitHelpers.EmitThrow(generator, ErrorType.TypeError, "Undefined cannot be converted to an object", path, function, line);
                    break;

                case PrimitiveType.Null:
                    // Converting from null always throws an exception.
                    EmitHelpers.EmitThrow(generator, ErrorType.TypeError, "Null cannot be converted to an object", path, function, line);
                    break;

                case PrimitiveType.Bool:
                case PrimitiveType.Int32:
                case PrimitiveType.UInt32:
                case PrimitiveType.Number:
                case PrimitiveType.String:
                case PrimitiveType.ConcatenatedString:
                case PrimitiveType.Any:
                    // Otherwise, fall back to calling TypeConverter.ToObject()
                    ToAny(generator, fromType);
                    var temp = generator.CreateTemporaryVariable(typeof(object));
                    generator.StoreVariable(temp);
                    EmitHelpers.LoadScriptEngine(generator);
                    generator.LoadVariable(temp);
                    generator.ReleaseTemporaryVariable(temp);
                    generator.LoadInt32(line);
                    generator.LoadStringOrNull(path);
                    generator.LoadStringOrNull(function);
                    generator.Call(ReflectionHelpers.TypeConverter_ToObject);
                    break;

                default:
                    throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
Exemplo n.º 21
0
        /// <summary>
        /// Pops the value on the stack, converts it to a boolean, then pushes the boolean result
        /// onto the stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        public static void ToBool(ILGenerator generator, PrimitiveType fromType)
        {
            // Check that a conversion is actually necessary.
            if (fromType == PrimitiveType.Bool)
                return;

            switch (fromType)
            {
                case PrimitiveType.Undefined:
                case PrimitiveType.Null:
                    // Converting from undefined or null produces false.
                    generator.Pop();
                    generator.LoadInt32(0);
                    break;

                case PrimitiveType.Int32:
                case PrimitiveType.UInt32:
                    // Converting from an integer produces true if the integer is non-zero.
                    generator.LoadInt32(0);
                    generator.CompareGreaterThanUnsigned();
                    break;

                case PrimitiveType.Number:
                    // Converting from a number produces true if the number is non-zero and not NaN.
                    var temp = generator.CreateTemporaryVariable(fromType);
                    generator.StoreVariable(temp);

                    // input != 0
                    generator.LoadVariable(temp);
                    generator.LoadDouble(0.0);
                    generator.CompareEqual();
                    generator.LoadInt32(0);
                    generator.CompareEqual();

                    // input == input
                    generator.LoadVariable(temp);
                    generator.Duplicate();
                    generator.CompareEqual();

                    // &&
                    generator.CompareEqual();

                    // The temporary variable is no longer needed.
                    generator.ReleaseTemporaryVariable(temp);
                    break;

                case PrimitiveType.String:
                    // Converting from a string produces true if the string is not empty.
                    generator.Call(ReflectionHelpers.String_Length);
                    generator.LoadInt32(0);
                    generator.CompareGreaterThan();
                    break;

                case PrimitiveType.ConcatenatedString:
                    // Converting from a string produces true if the string is not empty.
                    generator.Call(ReflectionHelpers.ConcatenatedString_Length);
                    generator.LoadInt32(0);
                    generator.CompareGreaterThan();
                    break;

                case PrimitiveType.Any:
                case PrimitiveType.Object:
                    // Otherwise, fall back to calling TypeConverter.ToBoolean()
                    generator.Call(ReflectionHelpers.TypeConverter_ToBoolean);
                    break;

                default:
                    throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
Exemplo n.º 22
0
        /// <summary>
        /// Generates CIL for the expression.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Note: we use GetRawOperand() so that grouping operators are not ignored.
            var operand = this.GetRawOperand(0);

            // There is only one operand, and it can be either a reference or a function call.
            // We need to split the operand into a function and some arguments.
            // If the operand is a reference, it is equivalent to a function call with no arguments.
            if (operand is FunctionCallExpression)
            {
                // Emit the function instance first.
                var function = ((FunctionCallExpression)operand).Target;
                function.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, function.ResultType);
            }
            else
            {
                // Emit the function instance first.
                operand.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, operand.ResultType);
            }

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

            generator.BranchIfNotNull(endOfTypeCheck);

            // Throw an nicely formatted exception.
            var targetValue = generator.CreateTemporaryVariable(typeof(object));

            generator.StoreVariable(targetValue);
            EmitHelpers.LoadScriptEngine(generator);
            generator.LoadString("TypeError");
            generator.LoadString("The new operator requires a function, found a '{0}' instead");
            generator.LoadInt32(1);
            generator.NewArray(typeof(object));
            generator.Duplicate();
            generator.LoadInt32(0);
            generator.LoadVariable(targetValue);
            generator.Call(ReflectionHelpers.TypeUtilities_TypeOf);
            generator.StoreArrayElement(typeof(object));
            generator.Call(ReflectionHelpers.String_Format);
            generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error);
            generator.Throw();
            generator.DefineLabelPosition(endOfTypeCheck);
            generator.ReleaseTemporaryVariable(targetValue);

            if (operand is FunctionCallExpression)
            {
                // Emit an array containing the function arguments.
                ((FunctionCallExpression)operand).GenerateArgumentsArray(generator, optimizationInfo);
            }
            else
            {
                // Emit an empty array.
                generator.LoadInt32(0);
                generator.NewArray(typeof(object));
            }

            // Call FunctionInstance.ConstructLateBound(argumentValues)
            generator.Call(ReflectionHelpers.FunctionInstance_ConstructLateBound);
        }
        /// <summary>
        /// Generates CIL for the expression.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Check if this is a direct call to eval().
            if (this.Target is NameExpression && ((NameExpression)this.Target).Name == "eval")
            {
                GenerateEval(generator, optimizationInfo);
                return;
            }

            // Emit the function instance first.
            ILLocalVariable targetBase = null;
            if (this.Target is MemberAccessExpression)
            {
                // The function is a member access expression (e.g. "Math.cos()").

                // Evaluate the left part of the member access expression.
                var baseExpression = ((MemberAccessExpression)this.Target).Base;
                baseExpression.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, baseExpression.ResultType);
                targetBase = generator.CreateTemporaryVariable(typeof(object));
                generator.StoreVariable(targetBase);

                // Evaluate the right part of the member access expression.
                var memberAccessExpression = new MemberAccessExpression(((MemberAccessExpression)this.Target).Operator);
                memberAccessExpression.Push(new TemporaryVariableExpression(targetBase));
                memberAccessExpression.Push(((MemberAccessExpression)this.Target).GetOperand(1));
                memberAccessExpression.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, this.Target.ResultType);
            }
            else
            {
                // Something else (e.g. "eval()").
                this.Target.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, this.Target.ResultType);
            }

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

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

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

            // Generate code to produce the "this" value.  There are three cases.
            if (this.Target is NameExpression)
            {
                // 1. The function is a name expression (e.g. "parseInt()").
                //    In this case this = scope.ImplicitThisValue, if there is one, otherwise undefined.
                ((NameExpression)this.Target).GenerateThis(generator);
            }
            else if (this.Target is MemberAccessExpression)
            {
                // 2. The function is a member access expression (e.g. "Math.cos()").
                //    In this case this = Math.
                //var baseExpression = ((MemberAccessExpression)this.Target).Base;
                //baseExpression.GenerateCode(generator, optimizationInfo);
                //EmitConversion.ToAny(generator, baseExpression.ResultType);
                generator.LoadVariable(targetBase);
            }
            else
            {
                // 3. Neither of the above (e.g. "(function() { return 5 })()")
                //    In this case this = undefined.
                EmitHelpers.EmitUndefined(generator);
            }

            // Emit an array containing the function arguments.
            GenerateArgumentsArray(generator, optimizationInfo);

            // Call FunctionInstance.CallLateBound(thisValue, argumentValues)
            generator.Call(ReflectionHelpers.FunctionInstance_CallWithStackTrace);

            // Allow reuse of the temporary variable.
            if (targetBase != null)
                generator.ReleaseTemporaryVariable(targetBase);
        }
Exemplo n.º 24
0
        /// <summary>
        /// Generates CIL for a compound assignment 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>
        /// <param name="target"> The target to modify. </param>
        private void GenerateCompoundAssignment(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target)
        {
            // Evaluate the left hand side only once.
            target.GenerateReference(generator, optimizationInfo);
            target.DuplicateReference(generator, optimizationInfo); // For the GenerateSet, later on.

            // Load the value to assign.
            var compoundOperator = new BinaryExpression(GetCompoundBaseOperator(this.OperatorType), new ReferenceGetExpression(target), this.GetOperand(1));
            compoundOperator.GenerateCode(generator, optimizationInfo);

            // Store the resulting value so we can return it as the result of the expression.
            var result = generator.CreateTemporaryVariable(compoundOperator.ResultType);
            generator.Duplicate();
            generator.StoreVariable(result);

            // Store the value.
            target.GenerateSet(generator, optimizationInfo, compoundOperator.ResultType, optimizationInfo.StrictMode);

            // Restore the expression result.
            generator.LoadVariable(result);
            generator.ReleaseTemporaryVariable(result);
        }
Exemplo n.º 25
0
        /// <summary>
        /// Generates a method that does type conversion and calls the bound method.
        /// </summary>
        /// <param name="generator"> The ILGenerator used to output the body of the method. </param>
        /// <param name="argumentCount"> The number of arguments that will be passed to the delegate. </param>
        /// <returns> A delegate that does type conversion and calls the method represented by this
        /// object. </returns>
        protected override void GenerateStub(ILGenerator generator, int argumentCount)
        {
            // Here is what we are going to generate.
            //private static object SampleBinder(ScriptEngine engine, object thisObject, object[] arguments)
            //{
            //    // Target function signature: int (bool, int, string, object).
            //    bool param1;
            //    int param2;
            //    string param3;
            //    object param4;
            //    param1 = arguments[0] != 0;
            //    param2 = TypeConverter.ToInt32(arguments[1]);
            //    param3 = TypeConverter.ToString(arguments[2]);
            //    param4 = Undefined.Value;
            //    return thisObject.targetMethod(param1, param2, param3, param4);
            //}

            // Find the target method.
            var binderMethod = this.buckets[Math.Min(argumentCount, this.buckets.Length - 1)];

            // Constrain the number of apparent arguments to within the required bounds.
            int minArgumentCount = binderMethod.RequiredParameterCount;
            int maxArgumentCount = binderMethod.RequiredParameterCount + binderMethod.OptionalParameterCount;
            if (binderMethod.HasParamArray == true)
                maxArgumentCount = int.MaxValue;

            foreach (var argument in binderMethod.GenerateArguments(generator, Math.Min(Math.Max(argumentCount, minArgumentCount), maxArgumentCount)))
            {
                switch (argument.Source)
                {
                    case BinderArgumentSource.ScriptEngine:
                        // Load the "engine" parameter passed by the client.
                        generator.LoadArgument(0);
                        break;

                    case BinderArgumentSource.ThisValue:
                        // Load the "this" parameter passed by the client.
                        generator.LoadArgument(1);

                        bool inheritsFromObjectInstance = typeof(ObjectInstance).IsAssignableFrom(argument.Type);
                        if (argument.Type.IsClass == true && inheritsFromObjectInstance == false &&
                            argument.Type != typeof(string) && argument.Type != typeof(object))
                        {
                            // If the "this" object is an unsupported class, pass it through unmodified.
                            generator.CastClass(argument.Type);
                        }
                        else
                        {
                            if (argument.Type != typeof(object))
                            {
                                // If the target "this" object type is not of type object, throw an error if
                                // the value is undefined or null.
                                generator.Duplicate();
                                var temp = generator.CreateTemporaryVariable(typeof(object));
                                generator.StoreVariable(temp);
                                generator.LoadArgument(0);
                                generator.LoadVariable(temp);
                                generator.LoadString(binderMethod.Name);
                                generator.Call(ReflectionHelpers.TypeUtilities_VerifyThisObject);
                                generator.ReleaseTemporaryVariable(temp);
                            }

                            // Convert to the target type.
                            EmitTypeConversion(generator, typeof(object), argument.Type);

                            if (argument.Type != typeof(ObjectInstance) && inheritsFromObjectInstance == true)
                            {
                                // EmitConversionToObjectInstance can emit null if the toType is derived from ObjectInstance.
                                // Therefore, if the value emitted is null it means that the "thisObject" is a type derived
                                // from ObjectInstance (e.g. FunctionInstance) and the value provided is a different type
                                // (e.g. ArrayInstance).  In this case, throw an exception explaining that the function is
                                // not generic.
                                var endOfThrowLabel = generator.CreateLabel();
                                generator.Duplicate();
                                generator.BranchIfNotNull(endOfThrowLabel);
                                generator.LoadArgument(0);
                                EmitHelpers.EmitThrow(generator, "TypeError", string.Format("The method '{0}' is not generic", binderMethod.Name));
                                generator.DefineLabelPosition(endOfThrowLabel);
                            }
                        }
                        break;

                    case BinderArgumentSource.InputParameter:
                        if (argument.InputParameterIndex < argumentCount)
                        {
                            // Load the argument onto the stack.
                            generator.LoadArgument(2);
                            generator.LoadInt32(argument.InputParameterIndex);
                            generator.LoadArrayElement(typeof(object));

                            // Get some flags that apply to the parameter.
                            var parameterFlags = JSParameterFlags.None;
                            var parameterAttribute = argument.GetCustomAttribute<JSParameterAttribute>();
                            if (parameterAttribute != null)
                            {
                                if (argument.Type != typeof(ObjectInstance))
                                    throw new NotImplementedException("[JSParameter] is only supported for arguments of type ObjectInstance.");
                                parameterFlags = parameterAttribute.Flags;
                            }

                            if ((parameterFlags & JSParameterFlags.DoNotConvert) == 0)
                            {
                                // Convert the input parameter to the correct type.
                                EmitTypeConversion(generator, typeof(object), argument);
                            }
                            else
                            {
                                // Don't do argument conversion.
                                /*var endOfThrowLabel = generator.CreateLabel();
                                generator.IsInstance(typeof(ObjectInstance));
                                generator.Duplicate();
                                generator.BranchIfNotNull(endOfThrowLabel);
                                EmitHelpers.EmitThrow(generator, "TypeError", string.Format("Parameter {1} parameter of '{0}' must be an object", binderMethod.Name, argument.InputParameterIndex));
                                generator.DefineLabelPosition(endOfThrowLabel);*/
                            }
                        }
                        else
                        {
                            // The target method has more parameters than we have input values.
                            EmitUndefined(generator, argument);
                        }
                        break;
                }
            }

            // Emit the call.
            binderMethod.GenerateCall(generator);

            // Convert the return value.
            if (binderMethod.ReturnType == typeof(void))
                EmitHelpers.EmitUndefined(generator);
            else
            {
                EmitTypeConversion(generator, binderMethod.ReturnType, typeof(object));

                // Convert a null return value to Null.Value or Undefined.Value.
                var endOfSpecialCaseLabel = generator.CreateLabel();
                generator.Duplicate();
                generator.BranchIfNotNull(endOfSpecialCaseLabel);
                generator.Pop();
                if ((binderMethod.Flags & JSFunctionFlags.ConvertNullReturnValueToUndefined) != 0)
                    EmitHelpers.EmitUndefined(generator);
                else
                    EmitHelpers.EmitNull(generator);
                generator.DefineLabelPosition(endOfSpecialCaseLabel);
            }

            // End the IL.
            generator.Complete();
        }
Exemplo n.º 26
0
        /// <summary>
        /// Generates CIL for an increment or decrement 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>
        /// <param name="target"> The target to modify. </param>
        /// <param name="postfix"> <c>true</c> if this is the postfix version of the operator;
        /// <c>false</c> otherwise. </param>
        /// <param name="increment"> <c>true</c> if this is the increment operator; <c>false</c> if
        /// this is the decrement operator. </param>
        private void GenerateIncrementOrDecrement(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target, bool postfix, bool increment)
        {
            // Note: increment and decrement can produce a number that is out of range if the
            // target is of type Int32.  The only time this should happen is for a loop variable
            // where the range has been carefully checked to make sure an out of range condition
            // cannot happen.

            // Evaluate the left hand side only once.
            target.GenerateReference(generator, optimizationInfo);
            target.DuplicateReference(generator, optimizationInfo); // For the GenerateSet, later on.

            // Get the target value.
            target.GenerateGet(generator, optimizationInfo, true);

            // Convert it to a number.
            if (target.Type != PrimitiveType.Int32)
                EmitConversion.ToNumber(generator, target.Type);

            // If this is PostIncrement or PostDecrement, store the value so it can be returned later.
            var result = generator.CreateTemporaryVariable(target.Type == PrimitiveType.Int32 ? PrimitiveType.Int32 : PrimitiveType.Number);
            if (postfix == true)
            {
                generator.Duplicate();
                generator.StoreVariable(result);
            }

            // Load the increment constant.
            if (target.Type == PrimitiveType.Int32)
                generator.LoadInt32(1);
            else
                generator.LoadDouble(1.0);

            // Add or subtract the constant to the target value.
            if (increment == true)
                generator.Add();
            else
                generator.Subtract();

            // If this is PreIncrement or PreDecrement, store the value so it can be returned later.
            if (postfix == false)
            {
                generator.Duplicate();
                generator.StoreVariable(result);
            }

            // Store the value.
            target.GenerateSet(generator, optimizationInfo, target.Type == PrimitiveType.Int32 ? PrimitiveType.Int32 : PrimitiveType.Number, optimizationInfo.StrictMode);

            // Restore the expression result.
            generator.LoadVariable(result);
            generator.ReleaseTemporaryVariable(result);
        }
Exemplo n.º 27
0
        /// <summary>
        /// Generates code to push the "this" value for a function call.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        public void GenerateThis(ILGenerator generator)
        {
            // Optimization: if there are no with scopes, simply emit undefined.
            bool scopeChainHasWithScope = false;
            var  scope = this.Scope;

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

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

            var end = generator.CreateLabel();

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

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

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

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

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

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

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

            // Define a label at the end.
            generator.DefineLabelPosition(end);
        }
Exemplo n.º 28
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)
        {
            // Note: we use GetRawOperand() so that grouping operators are not ignored.
            var operand = this.GetRawOperand(0);

            // There is only one operand, and it can be either a reference or a function call.
            // We need to split the operand into a function and some arguments.
            // If the operand is a reference, it is equivalent to a function call with no arguments.
            if (operand is FunctionCallExpression)
            {
                // Emit the function instance first.
                var function = ((FunctionCallExpression)operand).Target;
                function.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, function.ResultType);
            }
            else
            {
                // Emit the function instance first.
                operand.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, operand.ResultType);
            }

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

            // Throw an nicely formatted exception.
            var targetValue = generator.CreateTemporaryVariable(typeof(object));
            generator.StoreVariable(targetValue);
            EmitHelpers.LoadScriptEngine(generator);
            generator.LoadString("TypeError");
            generator.LoadString("The new operator requires a function, found a '{0}' instead");
            generator.LoadInt32(1);
            generator.NewArray(typeof(object));
            generator.Duplicate();
            generator.LoadInt32(0);
            generator.LoadVariable(targetValue);
            generator.Call(ReflectionHelpers.TypeUtilities_TypeOf);
            generator.StoreArrayElement(typeof(object));
            generator.Call(ReflectionHelpers.String_Format);
            generator.LoadInt32(optimizationInfo.SourceSpan.StartLine);
            generator.LoadStringOrNull(optimizationInfo.Source.Path);
            generator.LoadStringOrNull(optimizationInfo.FunctionName);
            generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error);
            generator.Throw();
            generator.DefineLabelPosition(endOfTypeCheck);
            generator.ReleaseTemporaryVariable(targetValue);

            if (operand is FunctionCallExpression)
            {
                // Emit an array containing the function arguments.
                ((FunctionCallExpression)operand).GenerateArgumentsArray(generator, optimizationInfo);
            }
            else
            {
                // Emit an empty array.
                generator.LoadInt32(0);
                generator.NewArray(typeof(object));
            }

            // Call FunctionInstance.ConstructLateBound(argumentValues)
            generator.Call(ReflectionHelpers.FunctionInstance_ConstructLateBound);
        }
Exemplo n.º 29
0
        /// <summary>
        /// Generates CIL for an increment or decrement 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>
        /// <param name="target"> The target to modify. </param>
        /// <param name="postfix"> <c>true</c> if this is the postfix version of the operator;
        /// <c>false</c> otherwise. </param>
        /// <param name="increment"> <c>true</c> if this is the increment operator; <c>false</c> if
        /// this is the decrement operator. </param>
        private void GenerateIncrementOrDecrement(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target, bool postfix, bool increment)
        {
            // Note: increment and decrement can produce a number that is out of range if the
            // target is of type Int32.  The only time this should happen is for a loop variable
            // where the range has been carefully checked to make sure an out of range condition
            // cannot happen.

            // Evaluate the left hand side only once.
            target.GenerateReference(generator, optimizationInfo);
            target.DuplicateReference(generator, optimizationInfo); // For the GenerateSet, later on.

            // Get the target value.
            target.GenerateGet(generator, optimizationInfo, true);

            // Convert it to a number.
            if (target.Type != PrimitiveType.Int32)
            {
                EmitConversion.ToNumber(generator, target.Type);
            }

            // If this is PostIncrement or PostDecrement, store the value so it can be returned later.
            var result = generator.CreateTemporaryVariable(target.Type == PrimitiveType.Int32 ? PrimitiveType.Int32 : PrimitiveType.Number);

            if (postfix == true)
            {
                generator.Duplicate();
                generator.StoreVariable(result);
            }

            // Load the increment constant.
            if (target.Type == PrimitiveType.Int32)
            {
                generator.LoadInt32(1);
            }
            else
            {
                generator.LoadDouble(1.0);
            }

            // Add or subtract the constant to the target value.
            if (increment == true)
            {
                generator.Add();
            }
            else
            {
                generator.Subtract();
            }

            // If this is PreIncrement or PreDecrement, store the value so it can be returned later.
            if (postfix == false)
            {
                generator.Duplicate();
                generator.StoreVariable(result);
            }

            // Store the value.
            target.GenerateSet(generator, optimizationInfo, target.Type == PrimitiveType.Int32 ? PrimitiveType.Int32 : PrimitiveType.Number, optimizationInfo.StrictMode);

            // Restore the expression result.
            generator.LoadVariable(result);
            generator.ReleaseTemporaryVariable(result);
        }
Exemplo n.º 30
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)
        {
            string propertyName = null;
            bool   isArrayIndex = false;

            //optimizationInfo = optimizationInfo.RemoveFlags(OptimizationFlags.SuppressReturnValue);

            // Right-hand-side can be a property name (a.b)
            if (this.OperatorType == OperatorType.MemberAccess)
            {
                var rhs = this.GetOperand(1) as NameExpression;
                if (rhs == null)
                {
                    throw new JavaScriptException(optimizationInfo.Engine, "SyntaxError", "Invalid member access", optimizationInfo.SourceSpan.StartLine, optimizationInfo.Source.Path, optimizationInfo.FunctionName);
                }
                propertyName = rhs.Name;
            }

            // Or a constant indexer (a['b'])
            if (this.OperatorType == OperatorType.Index)
            {
                var rhs = this.GetOperand(1) as LiteralExpression;
                if (rhs != null)
                {
                    propertyName = TypeConverter.ToString(rhs.Value);

                    // Or a array index (a[0])
                    if (rhs.ResultType == PrimitiveType.Int32 || (propertyName != null && Library.ArrayInstance.ParseArrayIndex(propertyName) != uint.MaxValue))
                    {
                        isArrayIndex = true;
                    }
                }
            }

            // Convert the value to an object and store it in a temporary variable.
            var value = generator.CreateTemporaryVariable(typeof(object));

            EmitConversion.ToAny(generator, valueType);
            generator.StoreVariable(value);

            if (isArrayIndex == true)
            {
                // Array indexer
                // -------------
                // xxx = object[index]

                // Load the left-hand side and convert to an object instance.
                var lhs = this.GetOperand(0);
                lhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo);

                // Load the right-hand side and convert to a uint32.
                var rhs = this.GetOperand(1);
                rhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToUInt32(generator, rhs.ResultType);

                // Call the indexer.
                generator.LoadVariable(value);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_Int);
            }
            else if (propertyName != null)
            {
                //// Load the left-hand side and convert to an object instance.
                //var lhs = this.GetOperand(0);
                //lhs.GenerateCode(generator, optimizationInfo);
                //EmitConversion.ToObject(generator, lhs.ResultType);

                //// Call the indexer.
                //generator.LoadString(propertyName);
                //generator.LoadVariable(value);
                //generator.LoadBoolean(optimizationInfo.StrictMode);
                //generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_String);



                // Named property modification (e.g. x.property = y)
                // -------------------------------------------------
                // __object_cacheKey = null;
                // __object_property_cachedIndex = 0;
                // ...
                // if (__object_cacheKey != object.InlineCacheKey)
                //     object.InlineSetPropertyValue("property", value, strictMode, out __object_property_cachedIndex, out __object_cacheKey)
                // else
                //     object.InlinePropertyValues[__object_property_cachedIndex] = value;

                // Load the left-hand side and convert to an object instance.
                var lhs = this.GetOperand(0);
                lhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo);

                // 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.InlineSetPropertyValue("property", value, strictMode, out __object_property_cachedIndex, out __object_cacheKey)
                generator.LoadVariable(objectInstance);
                generator.LoadString(propertyName);
                generator.LoadVariable(value);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.LoadAddressOfVariable(cachedIndex);
                generator.LoadAddressOfVariable(cacheKey);
                generator.Call(ReflectionHelpers.ObjectInstance_InlineSetPropertyValue);

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

                // End of the if statement
                generator.DefineLabelPosition(endOfIf);
            }
            else
            {
                // Dynamic property access
                // -----------------------
                // xxx = object.Get(x)

                // Load the left-hand side and convert to an object instance.
                var lhs = this.GetOperand(0);
                lhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo);

                // Load the property name and convert to a string.
                var rhs = this.GetOperand(1);
                rhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToString(generator, rhs.ResultType);

                // Call the indexer.
                generator.LoadVariable(value);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_String);
            }

            // The temporary variable is no longer needed.
            generator.ReleaseTemporaryVariable(value);
        }
Exemplo n.º 31
0
        /// <summary>
        /// Pops the value on the stack, converts it to a boolean, then pushes the boolean result
        /// onto the stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        public static void ToBool(ILGenerator generator, PrimitiveType fromType)
        {
            // Check that a conversion is actually necessary.
            if (fromType == PrimitiveType.Bool)
            {
                return;
            }

            switch (fromType)
            {
            case PrimitiveType.Undefined:
            case PrimitiveType.Null:
                // Converting from undefined or null produces false.
                generator.Pop();
                generator.LoadInt32(0);
                break;

            case PrimitiveType.Int32:
            case PrimitiveType.UInt32:
                // Converting from an integer produces true if the integer is non-zero.
                generator.LoadInt32(0);
                generator.CompareGreaterThanUnsigned();
                break;

            case PrimitiveType.Number:
                // Converting from a number produces true if the number is non-zero and not NaN.
                var temp = generator.CreateTemporaryVariable(fromType);
                generator.StoreVariable(temp);

                // input != 0
                generator.LoadVariable(temp);
                generator.LoadDouble(0.0);
                generator.CompareEqual();
                generator.LoadInt32(0);
                generator.CompareEqual();

                // input == input
                generator.LoadVariable(temp);
                generator.Duplicate();
                generator.CompareEqual();

                // &&
                generator.CompareEqual();

                // The temporary variable is no longer needed.
                generator.ReleaseTemporaryVariable(temp);
                break;

            case PrimitiveType.String:
                // Converting from a string produces true if the string is not empty.
                generator.Call(ReflectionHelpers.String_Length);
                generator.LoadInt32(0);
                generator.CompareGreaterThan();
                break;

            case PrimitiveType.ConcatenatedString:
                // Converting from a string produces true if the string is not empty.
                generator.Call(ReflectionHelpers.ConcatenatedString_Length);
                generator.LoadInt32(0);
                generator.CompareGreaterThan();
                break;

            case PrimitiveType.Any:
            case PrimitiveType.Object:
                // Otherwise, fall back to calling TypeConverter.ToBoolean()
                generator.Call(ReflectionHelpers.TypeConverter_ToBoolean);
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
Exemplo n.º 32
0
        /// <summary>
        /// Generates CIL for the statement.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Generate code for the start of the statement.
            var statementLocals = new StatementLocals() { NonDefaultSourceSpanBehavior = true };
            GenerateStartOfStatement(generator, optimizationInfo, statementLocals);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
Exemplo n.º 33
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 the class was named, then we need to create a new scope to hold the name.
            if (Name != null)
            {
                Scope.GenerateScopeCreation(generator, optimizationInfo);
            }

            // engine
            EmitHelpers.LoadScriptEngine(generator);

            // name
            generator.LoadStringOrNull(this.Name);

            // extends
            if (Extends == null)
            {
                generator.LoadNull();
            }
            else
            {
                Extends.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, Extends.ResultType);
            }

            // constructor
            if (Constructor == null)
            {
                generator.LoadNull();
            }
            else
            {
                Constructor.GenerateCode(generator, optimizationInfo);
            }

            // ConstructClass(ScriptEngine engine, string name, object extends, FunctionInstance constructor)
            generator.CallStatic(ReflectionHelpers.ReflectionHelpers_ConstructClass);

            // Create a variable to hold the container instance value.
            var containerVariable = generator.CreateTemporaryVariable(typeof(ObjectInstance));

            foreach (var member in this.Members)
            {
                // class.InstancePrototype
                generator.Duplicate();
                if (!member.Name.IsStatic)
                {
                    generator.Call(ReflectionHelpers.FunctionInstance_InstancePrototype);
                }

                // Store this in a variable so that FunctionExpression.GenerateCode can retrieve it.
                generator.Duplicate();
                generator.StoreVariable(containerVariable);

                // The key can be a property name or an expression that evaluates to a name.
                if (member.Name.HasStaticName)
                {
                    generator.LoadString(member.Name.StaticName);
                }
                else
                {
                    member.Name.ComputedName.GenerateCode(generator, optimizationInfo);
                    EmitConversion.ToPropertyKey(generator, member.Name.ComputedName.ResultType);
                }

                // Emit the function value.
                member.ContainerVariable = containerVariable;
                member.GenerateCode(generator, optimizationInfo);
                member.ContainerVariable = null;

                if (member.Name.IsGetter)
                {
                    // Add a getter to the object.
                    generator.Call(ReflectionHelpers.ReflectionHelpers_SetClassGetter);
                }
                else if (member.Name.IsSetter)
                {
                    // Add a setter to the object.
                    generator.Call(ReflectionHelpers.ReflectionHelpers_SetClassSetter);
                }
                else
                {
                    // Add a new property to the object.
                    generator.Call(ReflectionHelpers.ReflectionHelpers_SetClassValue);
                }
            }

            // Release the variable that we created above.
            generator.ReleaseTemporaryVariable(containerVariable);

            // Store the class name in the scope.
            if (Name != null)
            {
                generator.Duplicate();
                new NameExpression(Scope, Name).GenerateSet(generator, optimizationInfo, PrimitiveType.Object);
            }
        }
Exemplo n.º 34
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
            };

            GenerateStartOfStatement(generator, optimizationInfo, statementLocals);

            // We need a label for each case clause and one for the default case.
            var     jumpTargets  = new ILLabel[this.CaseClauses.Count];
            int     defaultIndex = -1;
            ILLabel endOfSwitch  = generator.CreateLabel();

            // Generate code for the switch value.
            var startOfSwitch = generator.CreateLabel();

            this.Value.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.Value.ResultType);

            // Save the switch value in a variable.
            var switchValue = generator.CreateTemporaryVariable(typeof(object));

            generator.StoreVariable(switchValue);

            for (int i = 0; i < this.CaseClauses.Count; i++)
            {
                var caseClause = this.CaseClauses[i];

                // Create a label for each clause.
                jumpTargets[i] = generator.CreateLabel();

                if (caseClause.Value == null)
                {
                    // This is a default clause.
                    defaultIndex = i;
                    continue;
                }

                // TypeComparer.StrictEquals(switchValue, caseValue)
                generator.LoadVariable(switchValue);
                caseClause.Value.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, caseClause.Value.ResultType);
                generator.Call(ReflectionHelpers.TypeComparer_StrictEquals);

                // if (TypeComparer.StrictEquals(switchValue, caseValue) == true)
                //     goto case i
                generator.BranchIfTrue(jumpTargets[i]);
            }

            // None of the cases matched, jump to the default clause or the end of the switch.
            if (defaultIndex >= 0)
            {
                generator.Branch(jumpTargets[defaultIndex]);
            }
            else
            {
                generator.Branch(endOfSwitch);
            }

            for (int i = 0; i < this.CaseClauses.Count; i++)
            {
                // Define a label at the start of the case clause.
                generator.DefineLabelPosition(jumpTargets[i]);

                // Set up the information needed by the break statement.
                optimizationInfo.PushBreakOrContinueInfo(this.Labels, endOfSwitch, null, labelledOnly: false);

                // Emit the case clause statements.
                foreach (var statement in this.CaseClauses[i].BodyStatements)
                {
                    statement.GenerateCode(generator, optimizationInfo);
                }

                // Revert the information needed by the break statement.
                optimizationInfo.PopBreakOrContinueInfo();
            }

            // Define a label for the end of the switch statement.
            generator.DefineLabelPosition(endOfSwitch);

            // Release the switch value variable for use elsewhere.
            generator.ReleaseTemporaryVariable(switchValue);

            // Generate code for the end of the statement.
            GenerateEndOfStatement(generator, optimizationInfo, statementLocals);
        }
Exemplo n.º 35
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();
        }
Exemplo n.º 36
0
        /// <summary>
        /// Pops the value on the stack, converts it to an integer, then pushes the integer result
        /// onto the stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        public static void ToInteger(ILGenerator generator, PrimitiveType fromType)
        {
            // Check that a conversion is actually necessary.
            if (fromType == PrimitiveType.Int32 || fromType == PrimitiveType.UInt32 || fromType == PrimitiveType.Bool)
            {
                return;
            }

            switch (fromType)
            {
            case PrimitiveType.Undefined:
            case PrimitiveType.Null:
                // Converting from undefined or null produces 0.
                generator.Pop();
                generator.LoadInt32(0);
                break;

            case PrimitiveType.Number:
                // Converting from a number produces the following:
                // Any number between -2147483648 and +2147483647 -> itself
                // Any number smaller than -2147483648 -> -2147483648
                // Any number larger than +2147483647 -> +2147483647
                // NaN -> 0

                // bool isPositiveInfinity = input > 2147483647.0
                var isPositiveInfinity = generator.CreateTemporaryVariable(typeof(bool));
                generator.Duplicate();
                generator.LoadDouble(2147483647.0);
                generator.CompareGreaterThan();
                generator.StoreVariable(isPositiveInfinity);

                // bool notNaN = input == input
                var notNaN = generator.CreateTemporaryVariable(typeof(bool));
                generator.Duplicate();
                generator.Duplicate();
                generator.CompareEqual();
                generator.StoreVariable(notNaN);

                // input = (int)input
                // Infinity -> -2147483648
                // -Infinity -> -2147483648
                // NaN -> -2147483648
                generator.ConvertToInteger();

                // input = input & -((int)notNaN)
                generator.LoadVariable(notNaN);
                generator.Negate();
                generator.BitwiseAnd();

                // input = input - (int)isPositiveInfinity
                generator.LoadVariable(isPositiveInfinity);
                generator.Subtract();

                // The temporary variables are no longer needed.
                generator.ReleaseTemporaryVariable(notNaN);
                generator.ReleaseTemporaryVariable(isPositiveInfinity);
                break;

            case PrimitiveType.String:
            case PrimitiveType.ConcatenatedString:
            case PrimitiveType.Any:
            case PrimitiveType.Object:
                // Otherwise, fall back to calling TypeConverter.ToInteger()
                generator.Call(ReflectionHelpers.TypeConverter_ToInteger);
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", fromType));
            }
        }
Exemplo n.º 37
0
        /// <summary>
        /// Generates code to push the "this" value for a function call.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        public void GenerateThis(ILGenerator generator)
        {
            // Optimization: if there are no with scopes, simply emit undefined.
            bool scopeChainHasWithScope = false;
            var scope = this.Scope;
            do
            {
                if (scope is ObjectScope && ((ObjectScope)scope).ProvidesImplicitThisValue == true)
                {
                    scopeChainHasWithScope = true;
                    break;
                }
                scope = scope.ParentScope;
            } while (scope != null);

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

            var end = generator.CreateLabel();

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

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

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

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

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

            } while (scope != null);

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

            // Define a label at the end.
            generator.DefineLabelPosition(end);
        }
Exemplo n.º 38
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();
        }
Exemplo n.º 39
0
        /// <summary>
        /// Outputs the values needed to get or set this 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>
        public void DuplicateReference(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            string propertyName = null;
            TypeOfMemberAccess memberAccessType = DetermineTypeOfMemberAccess(optimizationInfo, out propertyName);

            if (memberAccessType == TypeOfMemberAccess.ArrayIndex)
            {
                // Array indexer
                var arg1 = generator.CreateTemporaryVariable(typeof(object));
                var arg2 = generator.CreateTemporaryVariable(typeof(uint));
                generator.StoreVariable(arg2);
                generator.StoreVariable(arg1);
                generator.LoadVariable(arg1);
                generator.LoadVariable(arg2);
                generator.LoadVariable(arg1);
                generator.LoadVariable(arg2);
                generator.ReleaseTemporaryVariable(arg1);
                generator.ReleaseTemporaryVariable(arg2);
            }
            else if (memberAccessType == TypeOfMemberAccess.Static)
            {
                // Named property access
                generator.Duplicate();
            }
            else
            {
                // Dynamic property access
                var arg1 = generator.CreateTemporaryVariable(typeof(object));
                var arg2 = generator.CreateTemporaryVariable(typeof(object));
                generator.StoreVariable(arg2);
                generator.StoreVariable(arg1);
                generator.LoadVariable(arg1);
                generator.LoadVariable(arg2);
                generator.LoadVariable(arg1);
                generator.LoadVariable(arg2);
                generator.ReleaseTemporaryVariable(arg1);
                generator.ReleaseTemporaryVariable(arg2);
            }
        }
Exemplo n.º 40
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();
        }
        /// <summary>
        /// Generates CIL for the in operator.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        private void GenerateIn(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Emit the left-hand side expression and convert it to a string.
            this.Left.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToString(generator, this.Left.ResultType);

            // Store the left-hand side expression in a temporary variable.
            var temp = generator.CreateTemporaryVariable(typeof(string));
            generator.StoreVariable(temp);

            // Emit the right-hand side expression.
            this.Right.GenerateCode(generator, optimizationInfo);
            EmitConversion.ToAny(generator, this.Right.ResultType);

            // Check the right-hand side is a javascript object - if not, throw an exception.
            generator.IsInstance(typeof(Library.ObjectInstance));
            generator.Duplicate();
            var endOfTypeCheck = generator.CreateLabel();
            generator.BranchIfNotNull(endOfTypeCheck);

            // Throw an nicely formatted exception.
            var rightValue = generator.CreateTemporaryVariable(typeof(object));
            generator.StoreVariable(rightValue);
            EmitHelpers.LoadScriptEngine(generator);
            generator.LoadString("TypeError");
            generator.LoadString("The in operator expected an object, but found '{0}' instead");
            generator.LoadInt32(1);
            generator.NewArray(typeof(object));
            generator.Duplicate();
            generator.LoadInt32(0);
            generator.LoadVariable(rightValue);
            generator.Call(ReflectionHelpers.TypeUtilities_TypeOf);
            generator.StoreArrayElement(typeof(object));
            generator.Call(ReflectionHelpers.String_Format);
            generator.LoadInt32(optimizationInfo.SourceSpan.StartLine);
            generator.LoadStringOrNull(optimizationInfo.Source.Path);
            generator.LoadStringOrNull(optimizationInfo.FunctionName);
            generator.NewObject(ReflectionHelpers.JavaScriptException_Constructor_Error);
            generator.Throw();
            generator.DefineLabelPosition(endOfTypeCheck);
            generator.ReleaseTemporaryVariable(rightValue);

            // Load the left-hand side expression from the temporary variable.
            generator.LoadVariable(temp);

            // Call ObjectInstance.HasProperty(object)
            generator.Call(ReflectionHelpers.ObjectInstance_HasProperty);

            // Allow the temporary variable to be reused.
            generator.ReleaseTemporaryVariable(temp);
        }
Exemplo n.º 42
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)
        {
            string             propertyName     = null;
            TypeOfMemberAccess memberAccessType = DetermineTypeOfMemberAccess(optimizationInfo, out propertyName);

            if (memberAccessType == TypeOfMemberAccess.ArrayIndex)
            {
                // Array indexer
                // -------------
                // xxx = object[index]

                // Call the indexer.
                EmitConversion.ToAny(generator, valueType);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_Int);
            }
            else if (memberAccessType == TypeOfMemberAccess.Static)
            {
                // Named property modification (e.g. x.property = y)
                // -------------------------------------------------
                // __object_cacheKey = null;
                // __object_property_cachedIndex = 0;
                // ...
                // if (__object_cacheKey != object.InlineCacheKey)
                //     object.InlineSetPropertyValue("property", value, strictMode, out __object_property_cachedIndex, out __object_cacheKey)
                // else
                //     object.InlinePropertyValues[__object_property_cachedIndex] = value;

                // Convert the value to an object and store it in a temporary variable.
                var value = generator.CreateTemporaryVariable(typeof(object));
                EmitConversion.ToAny(generator, valueType);
                generator.StoreVariable(value);

                // 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.InlineSetPropertyValue("property", value, strictMode, out __object_property_cachedIndex, out __object_cacheKey)
                generator.LoadVariable(objectInstance);
                generator.LoadString(propertyName);
                generator.LoadVariable(value);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.LoadAddressOfVariable(cachedIndex);
                generator.LoadAddressOfVariable(cacheKey);
                generator.Call(ReflectionHelpers.ObjectInstance_InlineSetPropertyValue);

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

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

                // The temporary variable is no longer needed.
                generator.ReleaseTemporaryVariable(value);
            }
            else
            {
                // Dynamic property access
                // -----------------------
                // xxx = object.Get(x)

                // Call the indexer.
                EmitConversion.ToAny(generator, valueType);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_String);
            }
        }
Exemplo n.º 43
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>
        public void GenerateSet(ILGenerator generator, OptimizationInfo optimizationInfo, PrimitiveType valueType)
        {
            string             propertyName     = null;
            TypeOfMemberAccess memberAccessType = DetermineTypeOfMemberAccess(optimizationInfo, out propertyName);

            if (memberAccessType == TypeOfMemberAccess.ArrayIndex)
            {
                // Array indexer
                // -------------
                // xxx = object[index]

                // Call the indexer.
                EmitConversion.ToAny(generator, valueType);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_Int);
                generator.Pop();
            }
            else if (memberAccessType == TypeOfMemberAccess.Static)
            {
                // Named property modification (e.g. object.property = value)
                // ----------------------------------------------------------
                // object.SetPropertyValue(property, value, strictMode)

                // Convert the value to an object and store it in a temporary variable.
                var value = generator.CreateTemporaryVariable(typeof(object));
                EmitConversion.ToAny(generator, valueType);
                generator.StoreVariable(value);

                // Use a PropertyReference to speed up access if we are inside a loop.
                if (optimizationInfo.InsideLoop)
                {
                    ILLocalVariable propertyReference = optimizationInfo.GetPropertyReferenceVariable(generator, propertyName);
                    generator.LoadVariable(propertyReference);
                    generator.Duplicate();
                    var afterIf = generator.CreateLabel();
                    generator.BranchIfNotNull(afterIf);
                    generator.Pop();
                    generator.LoadString(propertyName);
                    generator.NewObject(ReflectionHelpers.PropertyName_Constructor);
                    generator.Duplicate();
                    generator.StoreVariable(propertyReference);
                    generator.DefineLabelPosition(afterIf);

                    generator.LoadVariable(value);
                    generator.LoadBoolean(optimizationInfo.StrictMode);
                    generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_PropertyReference);
                    generator.Pop();
                }
                else
                {
                    generator.LoadString(propertyName);
                    generator.LoadVariable(value);
                    generator.LoadBoolean(optimizationInfo.StrictMode);
                    generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_Object);
                    generator.Pop();
                }

                generator.ReleaseTemporaryVariable(value);
            }
            else
            {
                // Dynamic property access
                // -----------------------
                // object.SetPropertyValue(property, value, strictMode)

                EmitConversion.ToAny(generator, valueType);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_Object);
                generator.Pop();
            }
        }
Exemplo n.º 44
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();
        }
        /// <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)
        {
            string propertyName = null;
            bool isArrayIndex = false;
            //optimizationInfo = optimizationInfo.RemoveFlags(OptimizationFlags.SuppressReturnValue);

            // Right-hand-side can be a property name (a.b)
            if (this.OperatorType == OperatorType.MemberAccess)
            {
                var rhs = this.GetOperand(1) as NameExpression;
                if (rhs == null)
                    throw new JavaScriptException(optimizationInfo.Engine, "SyntaxError", "Invalid member access", optimizationInfo.SourceSpan.StartLine, optimizationInfo.Source.Path, optimizationInfo.FunctionName);
                propertyName = rhs.Name;
            }

            // Or a constant indexer (a['b'])
            if (this.OperatorType == OperatorType.Index)
            {
                var rhs = this.GetOperand(1) as LiteralExpression;
                if (rhs != null)
                {
                    propertyName = TypeConverter.ToString(rhs.Value);

                    // Or a array index (a[0])
                    if (rhs.ResultType == PrimitiveType.Int32 || (propertyName != null && Library.ArrayInstance.ParseArrayIndex(propertyName) != uint.MaxValue))
                        isArrayIndex = true;
                }
            }

            // Convert the value to an object and store it in a temporary variable.
            var value = generator.CreateTemporaryVariable(typeof(object));
            EmitConversion.ToAny(generator, valueType);
            generator.StoreVariable(value);

            if (isArrayIndex == true)
            {
                // Array indexer
                // -------------
                // xxx = object[index]

                // Load the left-hand side and convert to an object instance.
                var lhs = this.GetOperand(0);
                lhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo);

                // Load the right-hand side and convert to a uint32.
                var rhs = this.GetOperand(1);
                rhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToUInt32(generator, rhs.ResultType);

                // Call the indexer.
                generator.LoadVariable(value);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_Int);
            }
            else if (propertyName != null)
            {
                //// Load the left-hand side and convert to an object instance.
                //var lhs = this.GetOperand(0);
                //lhs.GenerateCode(generator, optimizationInfo);
                //EmitConversion.ToObject(generator, lhs.ResultType);

                //// Call the indexer.
                //generator.LoadString(propertyName);
                //generator.LoadVariable(value);
                //generator.LoadBoolean(optimizationInfo.StrictMode);
                //generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_String);



                // Named property modification (e.g. x.property = y)
                // -------------------------------------------------
                // __object_cacheKey = null;
                // __object_property_cachedIndex = 0;
                // ...
                // if (__object_cacheKey != object.InlineCacheKey)
                //     object.InlineSetPropertyValue("property", value, strictMode, out __object_property_cachedIndex, out __object_cacheKey)
                // else
                //     object.InlinePropertyValues[__object_property_cachedIndex] = value;

                // Load the left-hand side and convert to an object instance.
                var lhs = this.GetOperand(0);
                lhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo);

                // 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.InlineSetPropertyValue("property", value, strictMode, out __object_property_cachedIndex, out __object_cacheKey)
                generator.LoadVariable(objectInstance);
                generator.LoadString(propertyName);
                generator.LoadVariable(value);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.LoadAddressOfVariable(cachedIndex);
                generator.LoadAddressOfVariable(cacheKey);
                generator.Call(ReflectionHelpers.ObjectInstance_InlineSetPropertyValue);

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

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

            }
            else
            {
                // Dynamic property access
                // -----------------------
                // xxx = object.Get(x)

                // Load the left-hand side and convert to an object instance.
                var lhs = this.GetOperand(0);
                lhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToObject(generator, lhs.ResultType, optimizationInfo);

                // Load the property name and convert to a string.
                var rhs = this.GetOperand(1);
                rhs.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToString(generator, rhs.ResultType);

                // Call the indexer.
                generator.LoadVariable(value);
                generator.LoadBoolean(optimizationInfo.StrictMode);
                generator.Call(ReflectionHelpers.ObjectInstance_SetPropertyValue_String);
            }

            // The temporary variable is no longer needed.
            generator.ReleaseTemporaryVariable(value);
        }
Exemplo n.º 46
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);
        }
Exemplo n.º 47
0
        /// <summary>
        /// Generates CIL for an assignment 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>
        /// <param name="target"> The target to modify. </param>
        private void GenerateAssignment(ILGenerator generator, OptimizationInfo optimizationInfo, IReferenceExpression target)
        {
            // Evaluate the left hand side first!
            target.GenerateReference(generator, optimizationInfo);

            // Load the value to assign.
            var rhs = this.GetOperand(1);
            rhs.GenerateCode(generator, optimizationInfo);

            // Support the inferred function displayName property.
            if (rhs is FunctionExpression)
                ((FunctionExpression)rhs).GenerateDisplayName(generator, optimizationInfo, target.ToString(), false);

            // Store the RHS value so we can return it as the result of the expression.
            var result = generator.CreateTemporaryVariable(rhs.ResultType);
            generator.Duplicate();
            generator.StoreVariable(result);

            // Store the value.
            target.GenerateSet(generator, optimizationInfo, rhs.ResultType, optimizationInfo.StrictMode);

            // Restore the RHS value.
            generator.LoadVariable(result);
            generator.ReleaseTemporaryVariable(result);
        }
Exemplo n.º 48
0
        /// <summary>
        /// Generates CIL for the expression.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Check if this is a direct call to eval().
            if (this.Target is NameExpression && ((NameExpression)this.Target).Name == "eval")
            {
                GenerateEval(generator, optimizationInfo);
                return;
            }

            // Emit the function instance first.
            ILLocalVariable targetBase = null;

            if (this.Target is MemberAccessExpression)
            {
                // The function is a member access expression (e.g. "Math.cos()").

                // Evaluate the left part of the member access expression.
                var baseExpression = ((MemberAccessExpression)this.Target).Base;
                baseExpression.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, baseExpression.ResultType);
                targetBase = generator.CreateTemporaryVariable(typeof(object));
                generator.StoreVariable(targetBase);

                // Evaluate the right part of the member access expression.
                var memberAccessExpression = new MemberAccessExpression(((MemberAccessExpression)this.Target).Operator);
                memberAccessExpression.Push(new TemporaryVariableExpression(targetBase));
                memberAccessExpression.Push(((MemberAccessExpression)this.Target).GetOperand(1));
                memberAccessExpression.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, this.Target.ResultType);
            }
            else
            {
                // Something else (e.g. "eval()").
                this.Target.GenerateCode(generator, optimizationInfo);
                EmitConversion.ToAny(generator, this.Target.ResultType);
            }

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

            generator.BranchIfNotNull(endOfTypeCheck);

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

            // Generate code to produce the "this" value.  There are three cases.
            if (this.Target is NameExpression)
            {
                // 1. The function is a name expression (e.g. "parseInt()").
                //    In this case this = scope.ImplicitThisValue, if there is one, otherwise undefined.
                ((NameExpression)this.Target).GenerateThis(generator);
            }
            else if (this.Target is MemberAccessExpression)
            {
                // 2. The function is a member access expression (e.g. "Math.cos()").
                //    In this case this = Math.
                //var baseExpression = ((MemberAccessExpression)this.Target).Base;
                //baseExpression.GenerateCode(generator, optimizationInfo);
                //EmitConversion.ToAny(generator, baseExpression.ResultType);
                generator.LoadVariable(targetBase);
            }
            else
            {
                // 3. Neither of the above (e.g. "(function() { return 5 })()")
                //    In this case this = undefined.
                EmitHelpers.EmitUndefined(generator);
            }

            // Emit an array containing the function arguments.
            GenerateArgumentsArray(generator, optimizationInfo);

            // Call FunctionInstance.CallLateBound(thisValue, argumentValues)
            generator.Call(ReflectionHelpers.FunctionInstance_CallLateBound);

            // Allow reuse of the temporary variable.
            if (targetBase != null)
            {
                generator.ReleaseTemporaryVariable(targetBase);
            }
        }
Exemplo n.º 49
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)
        {
            // Create a new object.
            EmitHelpers.LoadScriptEngine(generator);
            generator.Call(ReflectionHelpers.ScriptEngine_Object);
            generator.Call(ReflectionHelpers.Object_Construct);

            // Create a variable to hold the container instance value.
            var containerVariable = generator.CreateTemporaryVariable(typeof(ObjectInstance));

            generator.Duplicate();
            generator.StoreVariable(containerVariable);

            foreach (var property in this.Properties)
            {
                generator.Duplicate();

                // The key can be a property name or an expression that evaluates to a name.
                if (property.Name.HasStaticName)
                {
                    generator.LoadString(property.Name.StaticName);
                }
                else
                {
                    property.Name.ComputedName.GenerateCode(generator, optimizationInfo);
                    EmitConversion.ToPropertyKey(generator, property.Name.ComputedName.ResultType);
                }

                // Emit the property value.
                if (property.Value is FunctionExpression functionExpression)
                {
                    functionExpression.ContainerVariable = containerVariable;
                    property.Value.GenerateCode(generator, optimizationInfo);
                    generator.ReinterpretCast(typeof(UserDefinedFunction));
                    functionExpression.ContainerVariable = null;
                }
                else
                {
                    property.Value.GenerateCode(generator, optimizationInfo);
                    EmitConversion.ToAny(generator, property.Value.ResultType);
                }

                if (property.Name.IsGetter)
                {
                    // Add a getter to the object.
                    generator.Call(ReflectionHelpers.ReflectionHelpers_SetObjectLiteralGetter);
                }
                else if (property.Name.IsSetter)
                {
                    // Add a setter to the object.
                    generator.Call(ReflectionHelpers.ReflectionHelpers_SetObjectLiteralSetter);
                }
                else
                {
                    // Add a new property to the object.
                    generator.Call(ReflectionHelpers.ReflectionHelpers_SetObjectLiteralValue);
                }
            }

            // Release the variable that we created above.
            generator.ReleaseTemporaryVariable(containerVariable);
        }