IsInstance() public abstract method

Pops an object off the stack, checks that the object inherits from or implements the given type, and pushes either the object (if the check was successful) or null (if the check failed) onto the stack.
public abstract IsInstance ( Type type ) : void
type System.Type The type of the class the object inherits from or the interface the /// object implements.
return void
Beispiel #1
0
        /// <summary>
        /// Pops the value on the stack, converts it from one type to another, then pushes the
        /// result onto the stack.
        /// </summary>
        /// <param name="il"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        /// <param name="toType"> The type to convert to. </param>
        private static void EmitTypeConversion(ILGenerator il, Type fromType, Type toType)
        {
            // If the source type equals the destination type, then there is nothing to do.
            if (fromType == toType)
            {
                return;
            }

            // Emit for each type of argument we support.
            if (toType == typeof(int))
            {
                EmitConversion.ToInteger(il, PrimitiveTypeUtilities.ToPrimitiveType(fromType));
            }
            else if (typeof(ObjectInstance).IsAssignableFrom(toType))
            {
                EmitConversion.Convert(il, PrimitiveTypeUtilities.ToPrimitiveType(fromType), PrimitiveType.Object);
                if (toType != typeof(ObjectInstance))
                {
                    // Convert to null if the from type isn't compatible with the to type.
                    // For example, if the target type is FunctionInstance and the from type is ArrayInstance, then pass null.
                    il.IsInstance(toType);
                }
            }
            else
            {
                EmitConversion.Convert(il, PrimitiveTypeUtilities.ToPrimitiveType(fromType), PrimitiveTypeUtilities.ToPrimitiveType(toType));
            }
        }
Beispiel #2
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);
        }
Beispiel #3
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);
        }
Beispiel #4
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);
            }
        }
        /// <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);
        }
        /// <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);
        }
Beispiel #7
0
        /// <summary>
        /// Pops the value on the stack, converts it from one type to another, then pushes the
        /// result onto the stack.
        /// </summary>
        /// <param name="il"> The IL generator. </param>
        /// <param name="fromType"> The type to convert from. </param>
        /// <param name="toType"> The type to convert to. </param>
        private static void EmitTypeConversion(ILGenerator il, Type fromType, Type toType)
        {
            // If the source type equals the destination type, then there is nothing to do.
            if (fromType == toType)
                return;

            // Emit for each type of argument we support.
            if (toType == typeof(int))
                EmitConversion.ToInteger(il, PrimitiveTypeUtilities.ToPrimitiveType(fromType));
            else if (typeof(ObjectInstance).IsAssignableFrom(toType))
            {
                EmitConversion.Convert(il, PrimitiveTypeUtilities.ToPrimitiveType(fromType), PrimitiveType.Object);
                if (toType != typeof(ObjectInstance))
                {
                    // Convert to null if the from type isn't compatible with the to type.
                    // For example, if the target type is FunctionInstance and the from type is ArrayInstance, then pass null.
                    il.IsInstance(toType);
                }
            }
            else
                EmitConversion.Convert(il, PrimitiveTypeUtilities.ToPrimitiveType(fromType), PrimitiveTypeUtilities.ToPrimitiveType(toType));
        }
        /// <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);
            }
        }
Beispiel #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)
        {
            // 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);
        }
Beispiel #11
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));

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

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

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

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

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

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


                    break;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


                break;

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

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

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

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

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

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

            // Label the end of the null check.
            if (toType.IsValueType == false)
            {
                generator.DefineLabelPosition(endOfNullCheck);
            }
        }
Beispiel #14
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));
            }

            // End the IL.
            generator.Complete();
        }