示例#1
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)
        {
            // Check for the correct number of arguments.
            if (argumentCount != 0)
            {
                EmitHelpers.EmitThrow(generator, "TypeError", "Wrong number of arguments");
                EmitHelpers.EmitDefaultValue(generator, PrimitiveType.Any);
                generator.Complete();
                return;
            }

            if (this.Field.IsStatic == false)
            {
                generator.LoadArgument(1);
                ClrBinder.EmitConversionToType(generator, this.Field.DeclaringType, true);
            }
            generator.LoadField(this.Field);
            ClrBinder.EmitConversionToObject(generator, this.Field.FieldType);
            generator.Complete();
        }
示例#2
0
        /// <summary>
        /// Gets an enumerable list of argument objects, equal in size to
        /// <paramref name="argumentCount"/> while generating code to prepare those arguments for
        /// a method call.
        /// </summary>
        /// <param name="argumentCount"> The number of arguments to return. </param>
        /// <param name="generator"> The IL generator used to create an array if the method has a
        /// ParamArray parameter. </param>
        /// <returns> An enumerable list of argument objects. </returns>
        public IEnumerable <BinderArgument> GenerateArguments(ILGenerator generator, int argumentCount)
        {
            if (generator == null)
            {
                throw new ArgumentNullException("generator");
            }

            int paramArrayIndex = 0;

            foreach (var argument in this.GetArguments(argumentCount))
            {
                if (argument.IsParamArrayArgument)
                {
                    if (paramArrayIndex == 0)
                    {
                        // This is the start of the ParamArray arguments.
                        // Create an array.
                        int paramArraySize = Math.Max(0, argumentCount - this.OptionalParameterCount - this.RequiredParameterCount);
                        generator.LoadInt32(paramArraySize);
                        generator.NewArray(argument.Type);
                    }

                    // Load the array and index.
                    generator.Duplicate();
                    generator.LoadInt32(paramArrayIndex++);
                }

                // Yield will have the side effect of generating a value.
                yield return(argument);

                if (argument.IsParamArrayArgument)
                {
                    // Store the value in the ParamArray array.
                    generator.StoreArrayElement(argument.Type);
                }
            }

            // Populate any missing optional arguments with the default value.
            if (this.RequiredParameterCount + this.OptionalParameterCount - argumentCount > 0)
            {
                var parameters = this.GetParameters();
                for (int i = 0; i < this.RequiredParameterCount + this.OptionalParameterCount - argumentCount; i++)
                {
                    var optionalParameter = parameters[argumentCount + i];
                    if ((optionalParameter.Attributes & ParameterAttributes.HasDefault) == ParameterAttributes.HasDefault)
                    {
                        // Emit the default value.
                        EmitHelpers.EmitValue(generator, new BinderArgument(optionalParameter, 0).DefaultValue);
                    }
                    else
                    {
                        // Emit default(T).
                        EmitHelpers.EmitDefaultValue(generator, optionalParameter.ParameterType);
                    }
                }
            }

            // Create an empty array if a ParamArray argument exists but no arguments were provided.
            if (this.HasParamArray && paramArrayIndex == 0)
            {
                // Create an array.
                generator.LoadInt32(0);
                generator.NewArray(this.ParamArrayElementType);
            }
        }
示例#3
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)
        {
            // Determine the methods that have the correct number of arguments.
            var candidateMethods = this.m_targetMethods
                                   .Where(candidateMethod => candidateMethod.IsArgumentCountCompatible(argumentCount))
                                   .ToList();

            // Zero candidates means no overload had the correct number of arguments.
            if (candidateMethods.Count == 0)
            {
                EmitHelpers.EmitThrow(generator, "TypeError", string.Format("No overload for method '{0}' takes {1} arguments", this.Name, argumentCount));
                EmitHelpers.EmitDefaultValue(generator, PrimitiveType.Any);
                generator.Complete();
                return;
            }

            // Select the method to call at run time.
            generator.LoadInt32(candidateMethods.Count);
            generator.NewArray(typeof(RuntimeMethodHandle));
            for (int i = 0; i < candidateMethods.Count; i++)
            {
                generator.Duplicate();
                generator.LoadInt32(i);
                generator.LoadToken(candidateMethods[i]);
                generator.StoreArrayElement(typeof(RuntimeMethodHandle));
            }
            generator.LoadArgument(0);
            generator.LoadArgument(1);
            generator.LoadArgument(2);
            generator.Call(ReflectionHelpers.BinderUtilities_ResolveOverloads.Value);

            var endOfMethod = generator.CreateLabel();

            for (int i = 0; i < candidateMethods.Count; i++)
            {
                // Check if this is the selected method.
                ILLabel endOfIf = null;
                if (i < candidateMethods.Count - 1)
                {
                    generator.Duplicate();
                    generator.LoadInt32(i);
                    endOfIf = generator.CreateLabel();
                    generator.BranchIfNotEqual(endOfIf);
                }
                generator.Pop();

                var targetMethod = candidateMethods[i];

                // Convert the arguments.
                foreach (var argument in targetMethod.GenerateArguments(generator, argumentCount))
                {
                    // Load the input parameter value.
                    switch (argument.Source)
                    {
                    case BinderArgumentSource.ScriptEngine:
                        generator.LoadArgument(0);
                        break;

                    case BinderArgumentSource.ThisValue:
                        generator.LoadArgument(1);
                        break;

                    case BinderArgumentSource.InputParameter:
                        generator.LoadArgument(2);
                        generator.LoadInt32(argument.InputParameterIndex);
                        generator.LoadArrayElement(typeof(object));
                        break;
                    }

                    // Convert to the target type.
                    EmitConversionToType(generator, argument.Type, argument.Source == BinderArgumentSource.ThisValue);
                }

                // Call the target method.
                targetMethod.GenerateCall(generator);

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

                // Branch to the end of the method if this was the selected method.
                if (endOfIf != null)
                {
                    generator.Branch(endOfMethod);
                    generator.DefineLabelPosition(endOfIf);
                }
            }

            generator.DefineLabelPosition(endOfMethod);
            generator.Complete();
        }