Esempio n. 1
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;
            }

            scope = this.Scope;

            do
            {
                DeclarativeScope dScope = scope as DeclarativeScope;

                if (dScope != null)
                {
                    if (dScope.HasDeclaredVariable(this.Name))
                    {
                        // The variable exists but declarative scopes always produce undefined for
                        // the "this" value.
                        EmitHelpers.EmitUndefined(generator);
                        break;
                    }
                }
                else
                {
                    // Object scope - what object type is it for?
                    Prototype proto = (scope as ObjectScope).ScopePrototype;

                    _Variable = proto.GetProperty(Name);

                    if (_Variable != null)
                    {
                        // Output a get now:
                        _Variable.Get(generator);

                        break;
                    }
                }

                scope = scope.ParentScope;
            } while (scope != null);
        }
Esempio n. 2
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)
        {
            // Parent root:
            Expression rootExpression = optimizationInfo.RootExpression;

            // Get an array of comma-delimited expressions.
            var items = this.Items;
            int max   = items.Count;

            if (max == 0)
            {
                if (rootExpression != this)
                {
                    // Some other expression is using '()' - emit an undefined:
                    EmitHelpers.EmitUndefined(generator);
                }

                return;
            }

            if (rootExpression != this)
            {
                // Some other expression is the root. Return the last one.
                max--;
            }

            for (int i = 0; i < max; i++)
            {
                // Generate the code for the item:
                Expression expr = items[i];

                // Update root - we don't want return values except for the last one:
                optimizationInfo.RootExpression = expr;

                // Generate the code:
                expr.GenerateCode(generator, optimizationInfo);
            }

            // Restore root:
            optimizationInfo.RootExpression = rootExpression;

            if (rootExpression != this)
            {
                // Return the last one

                // Generate code for the last item and return the value.
                items[items.Count - 1].GenerateCode(generator, optimizationInfo);
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Pushes the value of the reference onto the stack.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        /// <param name="throwIfUnresolvable"> <c>true</c> to throw a ReferenceError exception if
        /// the name is unresolvable; <c>false</c> to output <c>null</c> instead. </param>
        public void GenerateGet(ILGenerator generator, OptimizationInfo optimizationInfo, bool throwIfUnresolvable)
        {
            if (Variable == null)
            {
                // It's undefined:
                EmitHelpers.EmitUndefined(generator);

                return;
            }

            if (Variable.IsHoisted(Scope))
            {
                // Hoist the variable:
                Variable = (Scope as DeclarativeScope).Function.Hoist(Variable);
            }

            // Output a get now:
            Variable.Get(generator);
        }
Esempio n. 4
0
        /// <summary>
        /// Pops the value on the stack, converts it to the given type, then pushes the result
        /// onto the stack.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        /// <param name="toType"> The type to convert to. </param>
        /// <param name="path"> The path of the javascript source file that is currently executing. </param>
        /// <param name="function"> The name of the currently executing function. </param>
        public static void Convert(ILGenerator generator, Type fromType, Type toType, string path, string function)
        {
            // Check that a conversion is actually necessary.
            if (fromType == toType)
            {
                return;
            }

            if (toType == typeof(object))
            {
                ToAny(generator, fromType);
            }
            else if (toType == typeof(Nitrassic.Undefined))
            {
                generator.Pop();
                EmitHelpers.EmitUndefined(generator);
            }
            else if (toType == typeof(Nitrassic.Null))
            {
                generator.Pop();
                EmitHelpers.EmitNull(generator);
            }
            else if (toType == typeof(bool))
            {
                ToBool(generator, fromType);
            }
            else if (toType == typeof(long))
            {
                generator.ConvertToInt64();
            }
            else if (toType == typeof(ulong))
            {
                generator.ConvertToUnsignedInt64();
            }
            else if (toType == typeof(int))
            {
                generator.ConvertToInt32();
            }
            else if (toType == typeof(uint))
            {
                generator.ConvertToUnsignedInt32();
            }
            else if (toType == typeof(short))
            {
                generator.ConvertToInt16();
            }
            else if (toType == typeof(ushort))
            {
                generator.ConvertToUnsignedInt16();
            }
            else if (toType == typeof(sbyte))
            {
                generator.ConvertToInt8();
            }
            else if (toType == typeof(byte))
            {
                generator.ConvertToUnsignedInt8();
            }
            else if (toType == typeof(double))
            {
                ToNumber(generator, fromType);
            }
            else if (toType == typeof(string))
            {
                ToString(generator, fromType);
            }
            else if (toType == typeof(ConcatenatedString))
            {
                ToConcatenatedString(generator, fromType);
            }
            else
            {
                throw new NotImplementedException(string.Format("Unsupported primitive type: {0}", toType));
            }
        }
Esempio n. 5
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)
        {
            if (optimizationInfo.IsConstructor)
            {
                return;
            }

            // Emit the return value.
            Type returnType = ReturnType;

            // Determine if this is the last statement in the function.
            BlockStatement hostBlock = optimizationInfo.AbstractSyntaxTree as BlockStatement;

            bool lastStatement;

            if (hostBlock != null && hostBlock.Statements.Count > 0 &&
                hostBlock.Statements[hostBlock.Statements.Count - 1] == this)
            {
                lastStatement = true;
            }
            else
            {
                lastStatement = false;
            }

            // Current return var:
            var returnVar = optimizationInfo.ReturnVariable;

            if (Value != null)
            {
                // Emit the returned value:
                Value.GenerateCode(generator, optimizationInfo);

                // The first return statement initializes the variable that holds the return value.
                if (returnVar == null)
                {
                    if (!lastStatement)
                    {
                        returnVar = generator.DeclareVariable(returnType, "returnValue");
                        optimizationInfo.ReturnVariable = returnVar;
                    }
                }
            }
            else if (returnVar != null)
            {
                // We need to return undefined here, which will require changing the return type to object.

                // No value being set:
                EmitHelpers.EmitUndefined(generator);
            }

            if (returnVar != null)
            {
                // the return type here must be a child type of the return type.
                // If it isn't then this function returns different things.

                // Store the return value in a variable.
                generator.StoreVariable(returnVar);
            }

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

                // Branch to the end of the function.  Note: the return statement might be branching
                // from inside a try { } or finally { } block to outside.  EmitLongJump() handles this.
                optimizationInfo.EmitLongJump(generator, optimizationInfo.ReturnTarget);
            }
        }
Esempio n. 6
0
        /// <summary>
        /// Emits the given value.  Only possible for certain types.
        /// </summary>
        /// <param name="generator"> The IL generator. </param>
        /// <param name="value"> The value to emit. </param>
        public static void EmitValue(ILGenerator generator, object value)
        {
            if (value == null)
            {
                generator.LoadNull();
            }
            else if (value is Nitrassic.Undefined)
            {
                EmitHelpers.EmitUndefined(generator);
            }
            else if (value is System.Reflection.MethodBase)
            {
                generator.LoadToken(value as System.Reflection.MethodBase);
                generator.Call(ReflectionHelpers.MethodBase_GetMethod);
            }
            else if (value is MethodGroup)
            {
                throw new NotImplementedException("Can't emit methodGroups here");
            }
            else if (value is FunctionMethodGenerator)
            {
                // body
                generator.LoadInt64((value as FunctionMethodGenerator).MethodID);
                generator.Call(ReflectionHelpers.MethodLookup_Load);
            }
            else
            {
                switch (Type.GetTypeCode(value.GetType()))
                {
                case TypeCode.Boolean:
                    generator.LoadBoolean((bool)value);
                    break;

                case TypeCode.Byte:
                    generator.LoadInt32((byte)value);
                    break;

                case TypeCode.Char:
                    generator.LoadInt32((char)value);
                    break;

                case TypeCode.Double:
                    generator.LoadDouble((double)value);
                    break;

                case TypeCode.Int16:
                    generator.LoadInt32((short)value);
                    break;

                case TypeCode.Int32:
                    generator.LoadInt32((int)value);
                    break;

                case TypeCode.Int64:
                    generator.LoadInt64((long)value);
                    break;

                case TypeCode.SByte:
                    generator.LoadInt32((sbyte)value);
                    break;

                case TypeCode.Single:
                    generator.LoadDouble((float)value);
                    break;

                case TypeCode.String:
                    generator.LoadString((string)value);
                    break;

                case TypeCode.UInt16:
                    generator.LoadInt32((ushort)value);
                    break;

                case TypeCode.UInt32:
                    generator.LoadInt32((uint)value);
                    break;

                case TypeCode.UInt64:
                    generator.LoadInt64((ulong)value);
                    break;

                case TypeCode.Object:
                case TypeCode.Empty:
                case TypeCode.DateTime:
                case TypeCode.DBNull:
                case TypeCode.Decimal:
                    throw new NotImplementedException(string.Format("Cannot emit the value '{0}' (a " + value.GetType() + ")", value));
                }
            }
        }
Esempio n. 7
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)
        {
            // Special-case the delete operator.
            if (this.OperatorType == OperatorType.Delete)
            {
                GenerateDelete(generator, optimizationInfo);
                return;
            }

            // Special-case the typeof operator.
            if (this.OperatorType == OperatorType.Typeof)
            {
                GenerateTypeof(generator, optimizationInfo);
                return;
            }

            // Load the operand onto the stack.
            this.Operand.GenerateCode(generator, optimizationInfo);

            // If we're not using the return value, pop and quit.
            if (optimizationInfo.RootExpression == this)
            {
                // Pop it and quit.
                generator.Pop();
                return;
            }

            // Convert the operand to the correct type.
            switch (this.OperatorType)
            {
            case OperatorType.Plus:
            case OperatorType.Minus:
                EmitConversion.ToNumber(generator, this.Operand.GetResultType(optimizationInfo));
                break;

            case OperatorType.BitwiseNot:
                EmitConversion.ToInt32(generator, this.Operand.GetResultType(optimizationInfo));
                break;

            case OperatorType.LogicalNot:
                EmitConversion.ToBool(generator, this.Operand.GetResultType(optimizationInfo));
                break;
            }

            // Apply the operator.
            switch (this.OperatorType)
            {
            case OperatorType.Plus:
                break;

            case OperatorType.Minus:
                generator.Negate();
                break;

            case OperatorType.BitwiseNot:
                generator.BitwiseNot();
                break;

            case OperatorType.LogicalNot:
                generator.LoadBoolean(false);
                generator.CompareEqual();
                break;

            case OperatorType.Void:
                generator.Pop();
                EmitHelpers.EmitUndefined(generator);
                break;

            default:
                throw new NotImplementedException(string.Format("Unsupported operator {0}", this.OperatorType));
            }
        }
Esempio n. 8
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)
        {
            // Get the target as a name expression:
            NameExpression nameExpr = Target as NameExpression;

            // Grab if this is a 'new' call:
            bool isConstructor = optimizationInfo.IsConstructCall;

            optimizationInfo.IsConstructCall = false;

            if (ResolvedMethod != null)
            {
                // We have a known method!

                if (UserDefined != null)
                {
                    if (isConstructor)
                    {
                        // Generate code to produce the "this" value.
                        Library.Prototype proto = UserDefined.GetInstancePrototype(optimizationInfo.Engine);

                        // Create the object now:
                        generator.NewObject(proto.TypeConstructor);

                        // Duplicate (which will act as our return value):
                        if (optimizationInfo.RootExpression != this)
                        {
                            generator.Duplicate();
                        }
                    }
                    else
                    {
                        // There are three cases for non-constructor calls.
                        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.GetResultType(optimizationInfo));
                        }
                        else
                        {
                            // 3. Neither of the above (e.g. "(function() { return 5 })()")
                            //	In this case this = undefined.
                            EmitHelpers.EmitUndefined(generator);
                        }
                    }
                }

                // Emit the rest of the args:
                EmitArguments(generator, optimizationInfo);

                // Got a return type?
                Type returnType = GetResultType(optimizationInfo);

                // Then the call!
                if (typeof(System.Reflection.ConstructorInfo).IsAssignableFrom(ResolvedMethod.GetType()))
                {
                    // Actual constructor call:
                    generator.NewObject(ResolvedMethod as System.Reflection.ConstructorInfo);
                }
                else
                {
                    // Ordinary method:
                    generator.Call(ResolvedMethod);
                }

                if (isConstructor)
                {
                    // Always a returned value here. Needed?
                    if (optimizationInfo.RootExpression == this)
                    {
                        // Remove the return value:
                        generator.Pop();
                    }
                }
                else
                {
                    if (returnType == typeof(Nitrassic.Undefined))
                    {
                        if (optimizationInfo.RootExpression != this)
                        {
                            // Put undef on the stack:
                            EmitHelpers.EmitUndefined(generator);
                        }
                    }
                    else if (optimizationInfo.RootExpression == this)
                    {
                        // Remove the return value:
                        generator.Pop();
                    }
                }
            }
            else
            {
                // Either runtime resolve it or it's not actually a callable function
                throw new NotImplementedException("A function was called which was not supported (" + ToString() + ")");
            }
        }
Esempio n. 9
0
        /// <summary>
        /// Generates CIL for the expression.
        /// </summary>
        /// <param name="generator"> The generator to output the CIL to. </param>
        /// <param name="optimizationInfo"> Information about any optimizations that should be performed. </param>
        public override void GenerateCode(ILGenerator generator, OptimizationInfo optimizationInfo)
        {
            // Literals cannot have side-effects so if a return value is not expected then generate
            // nothing.
            if (optimizationInfo.RootExpression == this)
            {
                return;
            }

            if (this.Value is int)
            {
                generator.LoadInt32((int)this.Value);
            }
            else if (this.Value is double)
            {
                generator.LoadDouble((double)this.Value);
            }
            else if (this.Value is string)
            {
                generator.LoadString((string)this.Value);
            }
            else if (this.Value is bool)
            {
                generator.LoadBoolean((bool)this.Value);
            }
            else if (this.Value is RegularExpressionLiteral)
            {
                // RegExp
                var sharedRegExpVariable = optimizationInfo.GetRegExpVariable(generator, (RegularExpressionLiteral)this.Value);
                var label1 = generator.CreateLabel();
                var label2 = generator.CreateLabel();

                // if (sharedRegExp == null) {
                generator.LoadVariable(sharedRegExpVariable);
                generator.LoadNull();
                generator.BranchIfNotEqual(label1);

                // sharedRegExp = Global.RegExp.OnConstruct(source, flags)
                EmitHelpers.LoadPrototypes(generator);
                generator.LoadField(ReflectionHelpers.PrototypeLookup_RegExp);
                generator.LoadString(((RegularExpressionLiteral)this.Value).Pattern);
                generator.LoadString(((RegularExpressionLiteral)this.Value).Flags);
                generator.Call(ReflectionHelpers.RegExp_Construct);
                generator.Duplicate();
                generator.StoreVariable(sharedRegExpVariable);

                // } else {
                generator.Branch(label2);
                generator.DefineLabelPosition(label1);

                // Global.RegExp.OnConstruct(sharedRegExp, flags)
                EmitHelpers.LoadPrototypes(generator);
                generator.LoadField(ReflectionHelpers.PrototypeLookup_RegExp);
                generator.LoadVariable(sharedRegExpVariable);
                generator.LoadNull();
                generator.Call(ReflectionHelpers.RegExp_Construct);

                // }
                generator.DefineLabelPosition(label2);
            }
            else if (this.Value == Null.Value)
            {
                // Null.
                EmitHelpers.EmitNull(generator);
            }
            else if (this.Value == Undefined.Value)
            {
                // Undefined.
                EmitHelpers.EmitUndefined(generator);
            }
            else if (this.Value is List <Expression> )
            {
                // Construct an array literal.
                var arrayLiteral = (List <Expression>) this.Value;

                // Operands for ArrayConstructor.New() are: an ArrayConstructor instance (ArrayConstructor), an array (object[])
                // ArrayConstructor
                EmitHelpers.LoadEngine(generator);

                // object[]
                generator.LoadInt32(arrayLiteral.Count);
                generator.NewArray(typeof(object));

                for (int i = 0; i < arrayLiteral.Count; i++)
                {
                    // Operands for StoreArrayElement() are: an array (object[]), index (int), value (object).
                    // Array
                    generator.Duplicate();

                    // Index
                    generator.LoadInt32(i);

                    // Value
                    var elementExpression = arrayLiteral[i];
                    if (elementExpression == null)
                    {
                        generator.LoadNull();
                    }
                    else
                    {
                        elementExpression.GenerateCode(generator, optimizationInfo);
                        EmitConversion.ToAny(generator, elementExpression.GetResultType(optimizationInfo));
                    }

                    // Store the element value.
                    generator.StoreArrayElement(typeof(object));
                }

                // ArrayConstructor.New(object[])
                generator.Call(ReflectionHelpers.Array_New);
            }
            else if (this.Value is List <KeyValuePair <Expression, Expression> > )
            {
                // This is an object literal.
                var properties = (List <KeyValuePair <Expression, Expression> >) this.Value;

                // We'll generate a prototype and a custom object type for it:
                Library.Prototype proto = CreatedPrototype;

                // Create a new object.
                generator.NewObject(proto.TypeConstructor);

                foreach (var keyValuePair in properties)
                {
                    string     propertyName  = keyValuePair.Key.ToString();
                    Expression propertyValue = keyValuePair.Value;

                    // Duplicate the object ref:
                    generator.Duplicate();

                    // Add a new property to the object.

                    Type valueType = propertyValue.GetResultType(optimizationInfo);

                    // Get the property:
                    Library.PropertyVariable pv = proto.GetProperty(propertyName);

                    // Set it:
                    pv.Set(generator, optimizationInfo, false, valueType, delegate(bool two){
                        if (pv.IsConstant)
                        {
                            // Emit the constant:
                            EmitHelpers.EmitValue(generator, pv.ConstantValue);
                        }
                        else
                        {
                            // Write the value to set now:
                            propertyValue.GenerateCode(generator, optimizationInfo);
                        }

                        // Note: This one always ignores 'two'
                    });
                }
            }
            else
            {
                throw new NotImplementedException("Unknown literal type.");
            }
        }