Пример #1
0
        /// <summary>
        /// Emits load of optional parameters array on the evaluation stack.
        /// </summary>
        /// <param name="builder">An overloads builder.</param>
        /// <param name="start">An index of the first optional parameter to be loaded into the array (indices start from 0).</param>
        /// <param name="param">
        /// A <see cref="ParameterInfo"/> of the formal parameter of the target method where the array will be passed.
        /// This information influences conversions all optional parameters.
        /// </param>
        /// <param name="optArgCount">Optional argument count (unused).</param>
        internal void EmitLibraryLoadOptArguments(OverloadsBuilder /*!*/ builder, int start, ParameterInfo /*!*/ param, IPlace optArgCount)
        {
            Debug.Assert(start >= 0 && builder != null && param != null && builder.Aux is CodeGenerator);

            ILEmitter il         = builder.IL;
            Type      elem_type  = param.ParameterType.GetElementType();
            Type      array_type = elem_type.MakeArrayType();

            LocalBuilder loc_array = il.DeclareLocal(array_type);
            LocalBuilder loc_item  = il.DeclareLocal(elem_type);

            // NEW <alem_type>[<parameters count - start>]
            il.LdcI4(parameters.Count - start);
            il.Emit(OpCodes.Newarr, elem_type);
            il.Stloc(loc_array);

            // loads each optional parameter into the appropriate bucket of the array:
            for (int i = start; i < parameters.Count; i++)
            {
                // item = <parameter value>;
                object type_or_value = EmitLibraryLoadArgument(il, i, builder.Aux);
                builder.EmitArgumentConversion(elem_type, type_or_value, false, param);
                il.Stloc(loc_item);

                // array[<i-start>] = item;
                il.Ldloc(loc_array);
                il.LdcI4(i - start);
                il.Ldloc(loc_item);
                il.Stelem(elem_type);
            }

            // loads the array:
            il.Ldloc(loc_array);
        }
Пример #2
0
        /// <summary cref="KernelAccelerator{TCompiledKernel, TKernel}
        /// .GenerateKernelLauncherMethod(TCompiledKernel, int)"/>
        protected override MethodInfo GenerateKernelLauncherMethod(
            CLCompiledKernel kernel,
            int customGroupSize)
        {
            var entryPoint = kernel.EntryPoint;

            AdjustAndVerifyKernelGroupSize(ref customGroupSize, entryPoint);

            // Add support for by ref parameters
            if (entryPoint.HasByRefParameters)
            {
                throw new NotSupportedException(
                          ErrorMessages.NotSupportedByRefKernelParameters);
            }

            var launcher = entryPoint.CreateLauncherMethod(Context);
            var emitter  = new ILEmitter(launcher.ILGenerator);

            // Load kernel instance
            var kernelLocal = emitter.DeclareLocal(typeof(CLKernel));

            KernelLauncherBuilder.EmitLoadKernelArgument <CLKernel, ILEmitter>(
                Kernel.KernelInstanceParamIdx,
                emitter);
            emitter.Emit(LocalOperation.Store, kernelLocal);

            // Map all kernel arguments
            var argumentMapper = Backend.ArgumentMapper;

            argumentMapper.Map(emitter, kernelLocal, entryPoint);

            // Load stream
            KernelLauncherBuilder.EmitLoadAcceleratorStream <CLStream, ILEmitter>(
                Kernel.KernelStreamParamIdx,
                emitter);

            // Load kernel
            emitter.Emit(LocalOperation.Load, kernelLocal);

            // Load dimensions
            KernelLauncherBuilder.EmitLoadRuntimeKernelConfig(
                entryPoint,
                emitter,
                Kernel.KernelParamDimensionIdx,
                customGroupSize);

            // Dispatch kernel
            emitter.EmitCall(LaunchKernelMethod);

            // Emit ThrowIfFailed
            emitter.EmitCall(ThrowIfFailedMethod);

            emitter.Emit(OpCodes.Ret);
            emitter.Finish();

            return(launcher.Finish());
        }
Пример #3
0
 /// <summary>
 /// Emits code that loads current <see cref="PHP.Core.ScriptContext"/> by calling
 /// <see cref="PHP.Core.ScriptContext.CurrentContext"/> and remembers it in a local.
 /// </summary>
 /// <param name="il"></param>
 public void EmitLoad(ILEmitter il)
 {
     if (localBuilder == null)
     {
         localBuilder = il.DeclareLocal(typeof(ScriptContext));
         il.EmitCall(OpCodes.Call, Methods.ScriptContext.GetCurrentContext, null);
         il.Stloc(localBuilder);
     }
     il.Ldloc(localBuilder);
 }
Пример #4
0
        /// <summary>
        /// Emits code that loads a specified parameter on the evaluation stack.
        /// </summary>
        /// <param name="paramInfo">The parameter to load.</param>
        /// <param name="requiredTypeCode">Specifies whether <see cref="PhpReference"/>
        /// (<see cref="PhpTypeCode.PhpReference"/>), <see cref="object"/> (<see cref="PhpTypeCode.Object"/>),
        /// or the most fitting of these two should be loaded.</param>
        public void EmitLoadClrParameter(ParameterInfo /*!*/ paramInfo, PhpTypeCode requiredTypeCode)
        {
            if (paramInfo.IsOut)
            {
                il.Emit(OpCodes.Ldnull);
            }
            else
            {
                il.Ldarg(paramInfo.Position + paramOffset);

                // dereference ref param
                Type param_type = paramInfo.ParameterType;
                if (param_type.IsByRef)
                {
                    param_type = param_type.GetElementType();

                    il.Ldind(param_type);
                }

                // convert the parameter to PHP type
                PhpTypeCode type_code = ClrOverloadBuilder.EmitConvertToPhp(
                    il,
                    param_type /*,
                                * scriptContextPlace*/);

                il.EmitBoxing(type_code);
            }

            // check whether we have to create a PhpReference
            if (requiredTypeCode == PhpTypeCode.Object ||
                (requiredTypeCode == PhpTypeCode.Unknown && !paramInfo.ParameterType.IsByRef))
            {
                return;
            }

            if (paramInfo.ParameterType.IsByRef)
            {
                LocalBuilder ref_local = il.DeclareLocal(Types.PhpReference[0]);

                // remember the PhpReference in a local
                il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
                il.Emit(OpCodes.Dup);
                il.Stloc(ref_local);

                referenceLocals[paramInfo.Position] = ref_local;
            }
            else
            {
                // no reference store-back is necessary
                il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);
            }
        }
Пример #5
0
        public void EmitNewLinqContext()
        {
            ILEmitter il = cg.IL;

            linqContextLocal = il.DeclareLocal(linqContextBuilder);

            // linq_context = NEW <linq context>(<this>, <variables>, <script context>, <type desc>)
            cg.SelfPlace.EmitLoad(il);
            cg.RTVariablesTablePlace.EmitLoad(il);
            cg.ScriptContextPlace.EmitLoad(il);
            cg.TypeContextPlace.EmitLoad(il);
            il.Emit(OpCodes.Newobj, linqContextCtor);
            il.Stloc(linqContextLocal);
        }
Пример #6
0
        private static void EmitExportedConstructor(PhpType /*!*/ phpType, ConstructorBuilder /*!*/ ctorStubBuilder,
                                                    PhpMethod phpCtor, ParameterInfo[] /*!*/ parameters)
        {
            // set parameter names and attributes
            if (phpCtor != null)
            {
                ClrStubBuilder.DefineStubParameters(
                    ctorStubBuilder,
                    phpCtor.Builder.Signature.FormalParams,
                    parameters);
            }

            // emit ctor body
            ILEmitter cil = new ILEmitter(ctorStubBuilder);

            // [ this(ScriptContext.CurrentContext ]
            cil.Ldarg(FunctionBuilder.ArgThis);
            cil.EmitCall(OpCodes.Call, Methods.ScriptContext.GetCurrentContext, null);

            LocalBuilder sc_local = cil.DeclareLocal(Types.ScriptContext[0]);

            cil.Stloc(sc_local);
            cil.Ldloc(sc_local);

            cil.LdcI4(1);
            cil.Emit(OpCodes.Call, phpType.ShortConstructorInfo);

            if (phpCtor != null)
            {
                // invoke the PHP ctor method
                ClrStubBuilder.EmitMethodStubBody(
                    cil,
                    new Place(sc_local),
                    parameters,
                    new GenericTypeParameterBuilder[0],
                    Types.Void,
                    phpCtor,
                    phpCtor.DeclaringType);
            }
            else
            {
                cil.Emit(OpCodes.Ret);
            }
        }
Пример #7
0
        public static void EmitArgFullPreCall(ILEmitter /*!*/ il, IPlace /*!*/ stack, bool argsAware,
                                              int formalParamCount, int formalTypeParamCount, out LocalBuilder locArgsCount)
        {
            if (argsAware)
            {
                locArgsCount = il.DeclareLocal(typeof(int));

                // locArgsCount = stack.MakeArgsAware(<formal tpye param count | formal param count>);
                stack.EmitLoad(il);
                il.LdcI4((formalTypeParamCount << 16) | formalParamCount);
                il.Emit(OpCodes.Call, Methods.PhpStack.MakeArgsAware);
                il.Stloc(locArgsCount);
            }
            else
            {
                locArgsCount = null;

                // CALL stack.RemoveFrame();
                stack.EmitLoad(il);
                il.Emit(OpCodes.Call, Methods.PhpStack.RemoveFrame);
            }
        }
Пример #8
0
        /// <summary>
        /// Emits IL instructions that transfer the control to the target label for <B>break</B> statement
        /// having parameter that cannot be evaluated at compile time.
        /// </summary>
        /// <remarks>This function is used to generate code for <B>break v;</B> where <i>v</i> is a variable.</remarks>
        public void EmitBreakRuntime()
        {
            int       i;
            ILEmitter il = codeGenerator.IL;

            Label[] jumpTable = new Label[stack.Count + 1];
            Label   exitLabel = il.DefineLabel();

            Debug.Assert(stack.Count != 0);

            for (i = 0; i <= stack.Count; i++)
            {
                jumpTable[i] = il.DefineLabel();
            }

            // The value according to we switch is already present on the evaluation stack
            LocalBuilder break_level_count = il.DeclareLocal(typeof(Int32));

            il.Emit(OpCodes.Dup);
            il.Stloc(break_level_count);
            il.Emit(OpCodes.Switch, jumpTable);

            // Default case
            il.Ldloc(break_level_count);
            codeGenerator.EmitPhpException(Methods.PhpException.InvalidBreakLevelCount);
            il.Emit(OpCodes.Br, exitLabel);

            il.MarkLabel(jumpTable[0]);
            EmitBranchToExit((StackItem)stack[stack.Count - 1]);

            for (i = 1; i <= stack.Count; i++)
            {
                il.MarkLabel(jumpTable[i]);
                EmitBranchToExit((StackItem)stack[stack.Count - i]);
            }

            il.MarkLabel(exitLabel);
        }
Пример #9
0
        /// <summary>
        /// Emits load of an array where all optional arguments are stored.
        /// Each optional argument is peeked from the PHP stack and converted before stored to the array.
        /// The resulting array is pushed on evaluation stack so it can be later passed as an argument to a method.
        /// </summary>
        /// <param name="builder">The builder.</param>
        /// <param name="start">The index of the first argument to be loaded.</param>
        /// <param name="param">The last parameter of the overload (should be an array).</param>
        /// <param name="optArgCount">The place where the number of optional arguments is stored.</param>
        /// <remarks>Assumes that the non-negative number of optional arguments has been stored to
        /// <paramref name="optArgCount"/> place.</remarks>
        public static void EmitPeekAllArguments(OverloadsBuilder /*!*/ builder, int start, ParameterInfo param, IPlace optArgCount)
        {
            Debug.Assert(start >= 0 && optArgCount != null && param != null);

            ILEmitter il         = builder.IL;
            Type      elem_type  = param.ParameterType.GetElementType();
            Type      array_type = Type.GetType(elem_type.FullName + "[]", true);
            Type      actual_type;

            // declares aux. variables:
            LocalBuilder loc_array = il.DeclareLocal(array_type);
            LocalBuilder loc_i     = il.DeclareLocal(typeof(int));
            LocalBuilder loc_elem  = il.DeclareLocal(elem_type);

            // creates an array for the arguments
            // array = new <elem_type>[opt_arg_count]:
            optArgCount.EmitLoad(il);
            il.Emit(OpCodes.Newarr, elem_type);
            il.Stloc(loc_array);

            Label for_end_label   = il.DefineLabel();
            Label condition_label = il.DefineLabel();

            // i = 0;
            il.Emit(OpCodes.Ldc_I4_0);
            il.Stloc(loc_i);

            // FOR (i = 0; i < opt_arg_count; i++)
            if (true)
            {
                il.MarkLabel(condition_label);

                // condition (i < opt_arg_count):
                il.Ldloc(loc_i);
                optArgCount.EmitLoad(il);
                il.Emit(OpCodes.Bge, for_end_label);

                // LOAD stack, i + start+1>:
                builder.Stack.EmitLoad(il);
                il.Ldloc(loc_i);
                il.LdcI4(start + 1);
                il.Emit(OpCodes.Add);

                if (elem_type == typeof(PhpReference))
                {
                    // CALL stack.PeekReferenceUnchecked(STACK);
                    il.Emit(OpCodes.Call, Methods.PhpStack.PeekReferenceUnchecked);
                    actual_type = typeof(PhpReference);
                }
                else
                {
                    // CALL stack.PeekValueUnchecked(STACK);
                    il.Emit(OpCodes.Call, Methods.PhpStack.PeekValueUnchecked);
                    actual_type = typeof(object);
                }

                // emits a conversion stuff (loads result into "elem" local variable):
                builder.EmitArgumentConversion(elem_type, actual_type, false, param);
                il.Stloc(loc_elem);

                // array[i] = elem;
                il.Ldloc(loc_array);
                il.Ldloc(loc_i);
                il.Ldloc(loc_elem);
                il.Stelem(elem_type);

                // i = i + 1;
                il.Ldloc(loc_i);
                il.Emit(OpCodes.Ldc_I4_1);
                il.Emit(OpCodes.Add);
                il.Stloc(loc_i);

                // GOTO condition;
                il.Emit(OpCodes.Br, condition_label);
            }
            // END FOR

            il.MarkLabel(for_end_label);

            // loads array to stack - consumed by the method call:
            il.Ldloc(loc_array);
        }
Пример #10
0
        /// <summary cref="KernelAccelerator{TCompiledKernel, TKernel}
        /// .GenerateKernelLauncherMethod(TCompiledKernel, int)"/>
        protected override MethodInfo GenerateKernelLauncherMethod(
            CLCompiledKernel kernel,
            int customGroupSize)
        {
            var entryPoint = kernel.EntryPoint;

            AdjustAndVerifyKernelGroupSize(ref customGroupSize, entryPoint);

            // Add support for by ref parameters
            if (entryPoint.HasByRefParameters)
            {
                throw new NotSupportedException(
                          ErrorMessages.NotSupportedByRefKernelParameters);
            }

            using var scopedLock = entryPoint.CreateLauncherMethod(
                      Context.RuntimeSystem,
                      out var launcher);
            var emitter = new ILEmitter(launcher.ILGenerator);

            // Load kernel instance
            var kernelLocal = emitter.DeclareLocal(typeof(CLKernel));

            KernelLauncherBuilder.EmitLoadKernelArgument <CLKernel, ILEmitter>(
                Kernel.KernelInstanceParamIdx,
                emitter);
            emitter.Emit(LocalOperation.Store, kernelLocal);

            // Map all kernel arguments
            var argumentMapper = Backend.ArgumentMapper;

            argumentMapper.Map(
                emitter,
                kernelLocal,
                Context.TypeContext,
                entryPoint);

            // Load current driver API
            emitter.EmitCall(GetCLAPIMethod);

            // Load stream
            KernelLauncherBuilder.EmitLoadAcceleratorStream <CLStream, ILEmitter>(
                Kernel.KernelStreamParamIdx,
                emitter);

            // Load kernel
            emitter.Emit(LocalOperation.Load, kernelLocal);

            // Load dimensions
            KernelLauncherBuilder.EmitLoadRuntimeKernelConfig(
                entryPoint,
                emitter,
                Kernel.KernelParamDimensionIdx,
                MaxGridSize,
                MaxGroupSize,
                customGroupSize);

            // Dispatch kernel
            var launchMethod = GenericLaunchKernelMethod.MakeGenericMethod(
                entryPoint.SharedMemory.HasDynamicMemory
                ? typeof(DynamicSharedMemoryHandler)
                : typeof(DefaultLaunchHandler));

            emitter.EmitCall(launchMethod);

            // Emit ThrowIfFailed
            emitter.EmitCall(ThrowIfFailedMethod);

            emitter.Emit(OpCodes.Ret);
            emitter.Finish();

            return(launcher.Finish());
        }
Пример #11
0
        private ArrayList refReferences = new ArrayList(3);           // GENERICS: <LocalBuilder>

        #endregion

        #region Call Switch Emitter

        /// <summary>
        /// Emits calls to specified overloads and a switch statement which calls appropriate overload
        /// according to the current value of <see cref="PhpStack.ArgCount"/> field of the current stack.
        /// </summary>
        /// <param name="thisRef">Reference to self.</param>
        /// <param name="script_context">Current script context.</param>
        /// <param name="rtVariables">
        /// Place where a run-time variables table can be loaded from.
        /// </param>
        /// <param name="namingContext">Naming context load-from place.</param>
        /// <param name="classContext">Class context load.</param>
        /// <param name="overloads">The overload list.</param>
        /// <remarks>
        /// Example: given overloads (2,5,7,9+), i.e. there are four overloads having 2, 5, 7 and 9 PHP parameters,
        /// respectively, and the last overload is marked as vararg,
        /// the method emits the following code:
        /// <code>
        /// switch(ArgCount - 2)                  // 2 = minimum { arg count of overload }
        /// {
        ///   case 0: return call #2;             // call to the 2nd overload with appropriate arg. and return value handling
        ///   case 1: goto case error;
        ///   case 2: goto case error;
        ///   case 3: return call #5;
        ///   case 4: goto case error;
        ///   case 5: return call #7;
        ///   case 6: goto case error;
        ///
        /// #if vararg
        ///   case 7: goto default;
        ///   default: return call #vararg (9 mandatory args,optional args);break;
        /// #elif
        ///   case 7: return call #9;
        ///   default: goto case error;
        /// #endif
        ///
        ///   case error: PhpException.InvalidArgumentCount(null, functionName); break;
        /// }
        /// </code>
        /// </remarks>
        public void EmitCallSwitch(IPlace /*!*/ thisRef, IPlace /*!*/ script_context, IPlace /*!*/ rtVariables, IPlace /*!*/ namingContext, IPlace /*!*/ classContext, List <PhpLibraryFunction.Overload> /*!!*/ overloads)
        {
            Debug.AssertAllNonNull(overloads);

            int last = overloads.Count - 1;
            int min  = overloads[0].ParamCount;
            int max  = overloads[last].ParamCount;

            var flags = overloads[last].Flags;

            // if function is not supported, just throw the warning:
            if ((flags & PhpLibraryFunction.OverloadFlags.NotSupported) != 0)
            {
                // stack.RemoveFrame();
                if (stack != null)
                {
                    stack.EmitLoad(il);
                    il.Emit(OpCodes.Call, Methods.PhpStack.RemoveFrame);
                }

                // PhpException.FunctionNotSupported( <FullName> );
                il.Emit(OpCodes.Ldstr, FunctionName.Value);
                il.Emit(OpCodes.Call, Methods.PhpException.FunctionNotSupported_String);
                if (debug)
                {
                    il.Emit(OpCodes.Nop);
                }

                // load methods default value
                il.EmitBoxing(OverloadsBuilder.EmitLoadDefault(il, overloads[last].Method));
                return;
            }

            bool is_vararg = (flags & PhpLibraryFunction.OverloadFlags.IsVararg) != 0;

            if ((flags & PhpLibraryFunction.OverloadFlags.NeedsScriptContext) == 0)
            {
                script_context = null;
            }

            if ((flags & PhpLibraryFunction.OverloadFlags.NeedsThisReference) == 0)
            {
                thisRef = null;
            }

            if ((flags & PhpLibraryFunction.OverloadFlags.NeedsVariables) == 0)
            {
                rtVariables = null;
            }

            if ((flags & PhpLibraryFunction.OverloadFlags.NeedsNamingContext) == 0)
            {
                namingContext = null;
            }

            if ((flags & (PhpLibraryFunction.OverloadFlags.NeedsClassContext | PhpLibraryFunction.OverloadFlags.NeedsLateStaticBind)) == 0)
            {
                classContext = null;
            }

            Label end_label   = il.DefineLabel();
            Label error_label = il.DefineLabel();

            Label[]    cases = new Label[max - min + 1];
            MethodInfo method;

            // fills cases with "goto case error":
            for (int i = 0; i < cases.Length; i++)
            {
                cases[i] = error_label;
            }

            // define labels for valid cases:
            for (int i = 0; i < overloads.Count; i++)
            {
                int count = overloads[i].ParamCount;
                cases[count - min] = il.DefineLabel();
            }

            // LOAD(stack.ArgCount - min);
            stack.EmitLoad(il);
            il.Emit(OpCodes.Ldfld, Fields.PhpStack_ArgCount);
            il.LdcI4(min);
            il.Emit(OpCodes.Sub);

            // SWITCH(tmp)
            il.Emit(OpCodes.Switch, cases);

            // CASE >=N or <0 (underflows);
            // if the last overload is vararg:
            if (is_vararg)
            {
                LocalBuilder opt_arg_count_local = il.DeclareLocal(typeof(int));

                // CASE N:
                il.MarkLabel(cases[cases.Length - 1]);

                // opt_arg_count = stack.ArgCount - max;
                stack.EmitLoad(il);
                il.Emit(OpCodes.Ldfld, Fields.PhpStack_ArgCount);
                il.LdcI4(max);
                il.Emit(OpCodes.Sub);
                il.Stloc(opt_arg_count_local);

                // IF(tmp<0) GOTO CASE error;
                il.Ldloc(opt_arg_count_local);
                il.Emit(OpCodes.Ldc_I4_0);
                il.Emit(OpCodes.Blt, error_label);

                // emits argument loading, stack frame removal, method call, return value conversion:
                method = overloads[last].Method;
                Type return_type = EmitOverloadCall(method, overloads[last].RealParameters, max, script_context,
                                                    rtVariables, namingContext, classContext, new Place(opt_arg_count_local), thisRef, false);

                // loads boxed return value:
                if (return_type != Types.Void)
                {
                    //il.LoadBoxed(return_value);
                    if (return_type.IsValueType)
                    {
                        il.Emit(OpCodes.Box, return_type);
                    }
                }
                else
                {
                    il.Emit(OpCodes.Ldnull);
                }

                // RETURN;
                il.Emit(OpCodes.Ret);                  //bug in Reflector: il.Emit(OpCodes.Br,end_label);
            }
            else
            {
                // GOTO CASE error;
                il.Emit(OpCodes.Br, error_label);
            }

            // emits all valid cases which are not vararg:
            int j = 0;

            for (int i = min; i <= max - (is_vararg ? 1 : 0); i++)
            {
                if (overloads[j].ParamCount == i)
                {
                    // CASE <i>;
                    il.MarkLabel(cases[i - min]);

                    // emits argument loading, stack frame removal, method call, return value conversion:
                    method = overloads[j].Method;
                    Type return_type = EmitOverloadCall(method, overloads[j].RealParameters, i, script_context, rtVariables, namingContext, classContext, null, thisRef, false);

                    // loads boxed return value:
                    if (return_type != Types.Void)
                    {
                        //il.LoadBoxed(return_value);
                        if (return_type.IsValueType)
                        {
                            il.Emit(OpCodes.Box, return_type);
                        }
                    }
                    else
                    {
                        il.Emit(OpCodes.Ldnull);
                    }

                    // RETURN;
                    il.Emit(OpCodes.Ret);                      //bug in Reflector: il.Emit(OpCodes.Br,end_label);

                    j++;
                }
            }
            Debug.Assert(j + (is_vararg ? 1 : 0) == overloads.Count);

            // ERROR:
            il.MarkLabel(error_label);
            il.Emit(OpCodes.Ldnull);
            il.Emit(OpCodes.Ldstr, this.functionName.ToString());
            il.Emit(OpCodes.Call, Methods.PhpException.InvalidArgumentCount);
            if (debug)
            {
                il.Emit(OpCodes.Nop);
            }

            // RETURN null:
            il.Emit(OpCodes.Ldnull);
            il.MarkLabel(end_label);
        }
Пример #12
0
        /// <summary> Emit PHP to CLR conversion </summary>
        /// <remarks>If the return type is interface marked using <seealso cref="DuckTypeAttribute"/>
        /// it is wrapped again.
        /// <code>
        /// // type is IDuckEnumerable&lt;T&gt;
        /// return new DuckEnumerableWrapper&lt;T&gt;(obj.GetForeachEnumerator(false, false, null))
        ///
        /// // type is IDuckKeyedEnumerable&lt;T&gt;
        /// return new DuckKeyedEnumerableWrapper&lt;T&gt;(obj.GetForeachEnumerator(true, false, null))
        ///
        /// // type is marked using [DuckType]
        /// return DuckTyping.Instance.ImplementDuckType&lt;T&gt;(obj);
        ///
        /// // otherwise uses standard ConvertToClr conversion method
        /// </code>
        /// </remarks>
        private static void EmitReturn(ILEmitter il, Type returnedType, bool isPhpRef)
        {
            Type[]   gargs = returnedType.GetGenericArguments();
            object[] attrs = returnedType.GetCustomAttributes(typeof(DuckTypeAttribute), false);

            bool isDuckEnumerable      = (gargs.Length == 1 && returnedType.Equals(typeof(IDuckEnumerable <>).MakeGenericType(gargs)));
            bool isDuckKeyedEnumerable = (gargs.Length == 2 && returnedType.Equals(typeof(IDuckKeyedEnumerable <,>).MakeGenericType(gargs)));
            bool isDuckType            = attrs != null && attrs.Length > 0;

            if (returnedType.Equals(typeof(void)))
            {
                il.Emit(OpCodes.Pop);
                il.Emit(OpCodes.Ret);
            }
            else if (isDuckType || isDuckEnumerable || isDuckKeyedEnumerable)
            {
                LocalBuilder tmp = il.DeclareLocal(typeof(object));

                //store the value local var (after unwrapping it from the reference)
                if (isPhpRef)
                {
                    il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
                }
                il.Stloc(tmp);

                Label lblTestMinusOne = il.DefineLabel();
                Label lblWrap         = il.DefineLabel();
                Label lblInvalidInt   = il.DefineLabel();

                // test whether the value is null
                il.Ldloc(tmp);
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ceq);
                il.Emit(OpCodes.Brfalse, lblTestMinusOne);
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ret);

                il.MarkLabel(lblTestMinusOne);

                // test whether value is -1
                il.Ldloc(tmp);
                il.Emit(OpCodes.Isinst, typeof(int));
                il.Emit(OpCodes.Brfalse, lblWrap);                 // value is not int, so we can wrap the value
                il.Ldloc(tmp);
                il.Emit(OpCodes.Unbox_Any, typeof(int));
                il.Emit(OpCodes.Ldc_I4, -1);
                il.Emit(OpCodes.Ceq);
                il.Emit(OpCodes.Brfalse, lblWrap);                 // value is int but not -1
                il.Emit(OpCodes.Ldnull);
                il.Emit(OpCodes.Ret);

                il.MarkLabel(lblWrap);

                // specific duck type wrapping
                if (isDuckEnumerable || isDuckKeyedEnumerable)
                {
                    il.Ldloc(tmp);
                    il.Emit(OpCodes.Dup);
                    // Standard: new DuckEnumerableWrapper<T>(obj.GetForeachEnumerator(false, false, null))
                    // Keyed:    new DuckKeyedEnumerableWrapper<T>(obj.GetForeachEnumerator(false, false, null))
                    il.LoadLiteral(gargs.Length == 2);                     // keyed?
                    il.LoadLiteral(false);
                    il.LoadLiteral(null);
                    il.Emit(OpCodes.Callvirt, Methods.IPhpEnumerable_GetForeachEnumerator);
                    if (isDuckEnumerable)
                    {
                        il.Emit(OpCodes.Newobj, typeof(DuckEnumerableWrapper <>).
                                MakeGenericType(gargs).GetConstructors()[0]);
                    }
                    else
                    {
                        il.Emit(OpCodes.Newobj, typeof(DuckKeyedEnumerableWrapper <,>).
                                MakeGenericType(gargs).GetConstructors()[0]);
                    }
                }
                else
                {
                    il.Emit(OpCodes.Call, typeof(DuckTyping).GetProperty("Instance", BindingFlags.Public | BindingFlags.Static).GetGetMethod());
                    il.Ldloc(tmp);
                    il.Emit(OpCodes.Call, typeof(DuckTyping).GetMethod("ImplementDuckType", BindingFlags.Public | BindingFlags.Instance).MakeGenericMethod(returnedType));
                }

                il.Emit(OpCodes.Ret);
            }
            else
            {
                if (returnedType == typeof(object))
                {
                    Label lbl = il.DefineLabel();

                    if (isPhpRef)
                    {
                        il.Emit(OpCodes.Ldfld, Fields.PhpReference_Value);
                    }

                    il.Emit(OpCodes.Dup);
                    il.Emit(OpCodes.Isinst, typeof(PhpBytes));
                    il.Emit(OpCodes.Brfalse, lbl);
                    il.EmitCall(OpCodes.Call, typeof(IPhpConvertible).GetMethod("ToString", Type.EmptyTypes), Type.EmptyTypes);
                    il.Emit(OpCodes.Ret);
                    il.MarkLabel(lbl);
                    ClrOverloadBuilder.EmitConvertToClr(il, PhpTypeCode.Object, returnedType);
                    il.Emit(OpCodes.Ret);
                }
                else
                {
                    ClrOverloadBuilder.EmitConvertToClr(il, isPhpRef ? PhpTypeCode.PhpReference : PhpTypeCode.Object, returnedType);
                    il.Emit(OpCodes.Ret);
                }
            }
        }
Пример #13
0
        /// <summary> Implements method </summary>
        /// <remarks><code>
        /// class A : IDuck {
        ///   /*type*/ Func(/*arguments*/) {
        ///     sc = ScriptContext.Current;
        ///			// temporary array is created only when arguments.Length > 8 (otherwise AddFrame overload exists)
        ///			object[] tmp = new object[arguments.Length];
        ///			tmp[#i] = new PhpReference(PhpVariable.Copy(ClrObject.WrapDynamic(argument#i), CopyReason.PassedByCopy));
        ///			sc.Stack.AddFrame(tmp);
        ///			return /* .. type conversion .. */
        ///   }
        /// }
        /// </code></remarks>
        private void ImplementMethod(TypeBuilder tb, MethodInfo method, FieldInfo fld, bool globalFuncs)
        {
            // get parameters (i want C# 3.0 NOW!!)
            ParameterInfo[] pinfo  = method.GetParameters();
            Type[]          ptypes = new Type[pinfo.Length];
            for (int i = 0; i < pinfo.Length; i++)
            {
                ptypes[i] = pinfo[i].ParameterType;
            }
            int argCount = pinfo.Length;

            string methName = method.Name;

            object[] attrs = method.GetCustomAttributes(typeof(DuckNameAttribute), false);
            if (attrs.Length > 0)
            {
                methName = ((DuckNameAttribute)attrs[0]).Name;
            }

            // define method
            MethodBuilder mb = tb.DefineMethod(method.Name, MethodAttributes.Private | MethodAttributes.HideBySig |
                                               MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
                                               method.ReturnType, ptypes);
            ILEmitter il = new ILEmitter(mb);

            // Wrap parameters
            // sc = ScriptContext.Current
            LocalBuilder sc = il.DeclareLocal(typeof(ScriptContext));

            il.Emit(OpCodes.Call, Methods.ScriptContext.GetCurrentContext);
            il.Stloc(sc);

            LocalBuilder ar = null;

            if (argCount > 8)
            {
                // tmp = new object[pinfo.Length];
                ar = il.DeclareLocal(typeof(object[]));
                il.Emit(OpCodes.Ldc_I4, pinfo.Length);
                il.Emit(OpCodes.Newarr, typeof(object));
                il.Stloc(ar);
            }

            // sc.Stack.AddFrame(...);
            il.Ldloc(sc);
            il.Load(Fields.ScriptContext_Stack);

            for (int i = 0; i < argCount; i++)
            {
                if (argCount > 8)
                {
                    // tmp[i]
                    il.Emit(OpCodes.Ldloc, ar);
                    il.Emit(OpCodes.Ldc_I4, i);
                }

                // if (param#i is IDuckType)
                //   param#i.OriginalObject
                // else
                //   new PhpReference(PhpVariable.Copy(ClrObject.WrapDynamic(param#i), CopyReason.PassedByCopy));

                Label lblDuckType = il.DefineLabel();
                Label lblEnd      = il.DefineLabel();

                if (!ptypes[i].IsValueType)
                {
                    il.Ldarg(i + 1);
                    il.Emit(OpCodes.Isinst, typeof(IDuckType));
                    il.Emit(OpCodes.Brtrue, lblDuckType);
                }

                il.Ldarg(i + 1);

                if (ptypes[i].IsValueType)
                {
                    il.Emit(OpCodes.Box, ptypes[i]);
                }

                il.Emit(OpCodes.Call, Methods.ClrObject_WrapDynamic);
                il.LdcI4((int)CopyReason.PassedByCopy);
                il.Emit(OpCodes.Call, Methods.PhpVariable.Copy);
                il.Emit(OpCodes.Newobj, Constructors.PhpReference_Object);

                if (!ptypes[i].IsValueType)
                {
                    il.Emit(OpCodes.Br, lblEnd);

                    il.MarkLabel(lblDuckType);

                    il.Ldarg(i + 1);
                    il.Emit(OpCodes.Call, typeof(IDuckType).GetProperty("OriginalObject").GetGetMethod());

                    il.MarkLabel(lblEnd);
                }

                if (argCount > 8)
                {
                    il.Emit(OpCodes.Stelem_Ref);
                }
            }
            if (argCount > 8)
            {
                il.Emit(OpCodes.Ldloc, ar);
            }
            il.Emit(OpCodes.Call, Methods.PhpStack.AddFrame.Overload(argCount));

            if (globalFuncs)
            {
                // localVariables = null, namingContext = null
                // ScriptContex.Call(null, null, "Foo", null, ScriptContext.Current).value;
                il.LoadLiteral(null);
                il.LoadLiteral(null);
                il.LoadLiteral(methName);
                il.LoadLiteral(null);
                il.Emit(OpCodes.Ldsflda, il.TypeBuilder.DefineField("<callHint>'lambda", typeof(PHP.Core.Reflection.DRoutineDesc), FieldAttributes.Static | FieldAttributes.Private));
                il.Ldloc(sc);
                il.Emit(OpCodes.Call, Methods.ScriptContext.Call);
            }
            else
            {
                // Operators.InvokeMethod(this.obj, "Foo", null, ScriptContext.Current).value;
                il.Ldarg(0);
                il.Load(fld);
                il.LoadLiteral(methName);
                il.LoadLiteral(null);
                il.Ldloc(sc);
                il.Emit(OpCodes.Call, Methods.Operators.InvokeMethodStr);
            }

            EmitReturn(il, method.ReturnType, true);
            tb.DefineMethodOverride(mb, method);
        }
Пример #14
0
        /// <include file='Doc/Nodes.xml' path='doc/method[@name="Emit"]/*'/>
        internal override void Emit(CodeGenerator /*!*/ codeGenerator)
        {
            Statistics.AST.AddNode("SwitchStmt");
            ILEmitter il = codeGenerator.IL;

            // Note:
            //  SwitchStmt is now implemented in the most general (and unefficient) way. The whole switch
            //  is understood as a series of if-elseif-else statements.

            Label        exit_label            = il.DefineLabel();
            bool         fall_through          = false;
            Label        fall_through_label    = il.DefineLabel();
            Label        last_default_label    = il.DefineLabel();
            DefaultItem  last_default          = GetLastDefaultItem();
            LocalBuilder branch_to_lastdefault = null;

            if (last_default != null)
            {
                branch_to_lastdefault = il.DeclareLocal(Types.Bool[0]);
                il.LdcI4(0);
                il.Stloc(branch_to_lastdefault);
            }

            codeGenerator.BranchingStack.BeginLoop(exit_label, exit_label,
                                                   codeGenerator.ExceptionBlockNestingLevel);

            // marks a sequence point containing the discriminator evaluation:
            codeGenerator.MarkSequencePoint(
                switchValue.Position.FirstLine,
                switchValue.Position.FirstColumn,
                switchValue.Position.LastLine,
                switchValue.Position.LastColumn + 1);

            // Evaluate condition value and store the result into local variable
            codeGenerator.EmitBoxing(switchValue.Emit(codeGenerator));
            LocalBuilder condition_value = il.DeclareLocal(Types.Object[0]);

            il.Stloc(condition_value);

            foreach (SwitchItem item in switchItems)
            {
                item.MarkSequencePoint(codeGenerator);

                // switch item is either CaseItem ("case xxx:") or DefaultItem ("default") item:
                CaseItem case_item = item as CaseItem;
                if (case_item != null)
                {
                    Label false_label = il.DefineLabel();

                    // PhpComparer.Default.CompareEq(<switch expr. value>,<case value>);
                    /*changed to static method*/ //il.Emit(OpCodes.Ldsfld, Fields.PhpComparer_Default);
                    codeGenerator.EmitCompareEq(
                        cg => { cg.IL.Ldloc(condition_value); return(PhpTypeCode.Object); },
                        cg => case_item.EmitCaseValue(cg));

                    // IF (!STACK) GOTO false_label;
                    il.Emit(OpCodes.Brfalse, false_label);
                    if (fall_through == true)
                    {
                        il.MarkLabel(fall_through_label, true);
                        fall_through = false;
                    }

                    case_item.EmitStatements(codeGenerator);

                    if (fall_through == false)
                    {
                        fall_through_label = il.DefineLabel();
                        fall_through       = true;
                    }

                    il.Emit(OpCodes.Br, fall_through_label);

                    il.MarkLabel(false_label, true);
                }
                else
                {
                    DefaultItem default_item = (DefaultItem)item;

                    // Only the last default branch defined in source code is used.
                    // So skip default while testing "case" items at runtime.
                    Label false_label = il.DefineLabel();
                    il.Emit(OpCodes.Br, false_label);

                    if (default_item == last_default)
                    {
                        il.MarkLabel(last_default_label, false);
                    }

                    if (fall_through == true)
                    {
                        il.MarkLabel(fall_through_label, true);
                        fall_through = false;
                    }

                    default_item.EmitStatements(codeGenerator);

                    if (fall_through == false)
                    {
                        fall_through_label = il.DefineLabel();
                        fall_through       = true;
                    }

                    il.Emit(OpCodes.Br, fall_through_label);
                    il.MarkLabel(false_label, true);
                }
            }

            // If no case branch matched, branch to last default case if any is defined
            if (last_default != null)
            {
                // marks a sequence point containing the condition evaluation or skip of the default case:
                codeGenerator.MarkSequencePoint(
                    last_default.Position.FirstLine,
                    last_default.Position.FirstColumn,
                    last_default.Position.LastLine,
                    last_default.Position.LastColumn + 1);

                Debug.Assert(branch_to_lastdefault != null);
                Label temp = il.DefineLabel();

                // IF (!branch_to_lastdefault) THEN
                il.Ldloc(branch_to_lastdefault);
                il.LdcI4(0);
                il.Emit(OpCodes.Bne_Un, temp);
                if (true)
                {
                    // branch_to_lastdefault = TRUE;
                    il.LdcI4(1);
                    il.Stloc(branch_to_lastdefault);

                    // GOTO last_default_label;
                    il.Emit(OpCodes.Br, last_default_label);
                }
                il.MarkLabel(temp, true);
                // END IF;

                il.ForgetLabel(last_default_label);
            }

            if (fall_through == true)
            {
                il.MarkLabel(fall_through_label, true);
            }

            il.MarkLabel(exit_label);
            codeGenerator.BranchingStack.EndLoop();
            il.ForgetLabel(exit_label);
        }
Пример #15
0
        /// <summary>
        /// Emits local variable switch and performs a specified operation on each case.
        /// </summary>
        /// <param name="codeGenerator">The code generator.</param>
        /// <param name="method">The operation performed in each case.</param>
        internal void EmitSwitch(CodeGenerator codeGenerator, SwitchMethod method)
        {
            ILEmitter il = codeGenerator.IL;

            Debug.Assert(method != null);

            Label          default_case       = il.DefineLabel();
            Label          end_label          = il.DefineLabel();
            LocalBuilder   ivar_local         = il.GetTemporaryLocal(Types.String[0], true);
            LocalBuilder   non_interned_local = il.DeclareLocal(Types.String[0]);
            VariablesTable variables          = codeGenerator.CurrentVariablesTable;

            Label[] labels = new Label[variables.Count];

            // non_interned_local = <name expression>;
            EmitName(codeGenerator);
            il.Stloc(non_interned_local);

            // ivar_local = String.IsInterned(non_interned_local)
            il.Ldloc(non_interned_local);
            il.Emit(OpCodes.Call, Methods.String_IsInterned);
            il.Stloc(ivar_local);

            // switch for every compile-time variable:
            int i = 0;

            foreach (VariablesTable.Entry variable in variables)
            {
                labels[i] = il.DefineLabel();

                // IF (ivar_local == <i-th variable name>) GOTO labels[i];
                il.Ldloc(ivar_local);
                il.Emit(OpCodes.Ldstr, variable.VariableName.ToString());
                il.Emit(OpCodes.Beq, labels[i]);
                i++;
            }

            // GOTO default_case:
            il.Emit(OpCodes.Br, default_case);

            // operation on each variable:
            i = 0;
            foreach (VariablesTable.Entry variable in variables)
            {
                // labels[i]:
                il.MarkLabel(labels[i]);

                // operation:
                method(codeGenerator, variable, null);

                // GOTO end;
                il.Emit(OpCodes.Br, end_label);
                i++;
            }

            // default case - new variable created at runtime:
            il.MarkLabel(default_case);
            method(codeGenerator, null, non_interned_local);

            // END:
            il.MarkLabel(end_label);
        }
Пример #16
0
        /// <summary>
        /// Generates a dynamic kernel-launcher method that will be just-in-time compiled
        /// during the first invocation. Using the generated launcher lowers the overhead
        /// for kernel launching dramatically, since unnecessary operations (like boxing)
        /// can be avoided.
        /// </summary>
        /// <param name="kernel">The kernel to generate a launcher for.</param>
        /// <param name="customGroupSize">The custom group size for the launching operation.</param>
        /// <returns>The generated launcher method.</returns>
        private MethodInfo GenerateKernelLauncherMethod(ILCompiledKernel kernel, int customGroupSize)
        {
            var entryPoint = kernel.EntryPoint;

            AdjustAndVerifyKernelGroupSize(ref customGroupSize, entryPoint);

            var launcher = entryPoint.CreateLauncherMethod(Context);
            var emitter  = new ILEmitter(launcher.ILGenerator);

            var cpuKernel = emitter.DeclareLocal(typeof(CPUKernel));

            KernelLauncherBuilder.EmitLoadKernelArgument <CPUKernel, ILEmitter>(
                Kernel.KernelInstanceParamIdx, emitter);
            emitter.Emit(LocalOperation.Store, cpuKernel);

            // Create an instance of the custom task type
            var task = emitter.DeclareLocal(kernel.TaskType);
            {
                var sharedMemSize = KernelLauncherBuilder.EmitSharedMemorySizeComputation(entryPoint, emitter);

                emitter.Emit(LocalOperation.Load, cpuKernel);
                emitter.EmitCall(
                    typeof(CPUKernel).GetProperty(
                        nameof(CPUKernel.KernelExecutionDelegate),
                        BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).GetGetMethod(true));

                // Load custom user dimension
                KernelLauncherBuilder.EmitLoadDimensions(
                    entryPoint,
                    emitter,
                    Kernel.KernelParamDimensionIdx,
                    () => emitter.EmitNewObject(
                        typeof(Index3).GetConstructor(
                            new Type[] { typeof(int), typeof(int), typeof(int) })));

                // Load dimensions as index3 arguments
                KernelLauncherBuilder.EmitLoadDimensions(
                    entryPoint,
                    emitter,
                    Kernel.KernelParamDimensionIdx,
                    () => emitter.EmitNewObject(
                        typeof(Index3).GetConstructor(
                            new Type[] { typeof(int), typeof(int), typeof(int) })),
                    customGroupSize);

                // Load shared-memory size
                emitter.Emit(LocalOperation.Load, sharedMemSize);

                // Create new task object
                emitter.EmitNewObject(kernel.TaskConstructor);

                // Store task
                emitter.Emit(LocalOperation.Store, task);
            }

            // Assign parameters
            var parameters = entryPoint.Parameters;

            for (int i = 0, e = parameters.NumParameters; i < e; ++i)
            {
                emitter.Emit(LocalOperation.Load, task);
                emitter.Emit(ArgumentOperation.Load, i + Kernel.KernelParameterOffset);
                if (parameters.IsByRef(i))
                {
                    emitter.Emit(OpCodes.Ldobj, parameters[i]);
                }
                emitter.Emit(OpCodes.Stfld, kernel.TaskArgumentMapping[i]);
            }

            // Launch task: ((CPUKernel)kernel).CPUAccelerator.Launch(task);
            emitter.Emit(LocalOperation.Load, cpuKernel);
            emitter.EmitCall(
                typeof(CPUKernel).GetProperty(
                    nameof(CPUKernel.CPUAccelerator)).GetGetMethod(false));
            emitter.Emit(LocalOperation.Load, task);
            emitter.EmitCall(
                typeof(CPUAccelerator).GetMethod(
                    nameof(CPUAccelerator.Launch),
                    BindingFlags.NonPublic | BindingFlags.Instance));

            // End of launch method
            emitter.Emit(OpCodes.Ret);
            emitter.Finish();

            return(launcher.Finish());
        }
Пример #17
0
        /// <summary>
        /// Generates a dynamic kernel-launcher method that will be just-in-time compiled
        /// during the first invocation. Using the generated launcher lowers the overhead
        /// for kernel launching dramatically, since unnecessary operations (like boxing)
        /// can be avoided.
        /// </summary>
        /// <param name="kernel">The kernel to generate a launcher for.</param>
        /// <param name="customGroupSize">
        /// The custom group size for the launching operation.
        /// </param>
        /// <returns>The generated launcher method.</returns>
        private MethodInfo GenerateKernelLauncherMethod(
            ILCompiledKernel kernel,
            int customGroupSize)
        {
            var entryPoint = kernel.EntryPoint;

            AdjustAndVerifyKernelGroupSize(ref customGroupSize, entryPoint);

            // Add support for by ref parameters
            if (entryPoint.HasByRefParameters)
            {
                throw new NotSupportedException(
                          ErrorMessages.NotSupportedByRefKernelParameters);
            }

            using var scopedLock = entryPoint.CreateLauncherMethod(
                      Context.RuntimeSystem,
                      out var launcher);
            var emitter = new ILEmitter(launcher.ILGenerator);

            // Pretend to map kernel arguments (like a GPU accelerator would perform).
            var argumentMapper = Backend.ArgumentMapper;

            argumentMapper.Map(entryPoint);

            var cpuKernel = emitter.DeclareLocal(typeof(CPUKernel));

            KernelLauncherBuilder.EmitLoadKernelArgument <CPUKernel, ILEmitter>(
                Kernel.KernelInstanceParamIdx, emitter);
            emitter.Emit(LocalOperation.Store, cpuKernel);

            // Create an instance of the custom task type
            var task = emitter.DeclareLocal(kernel.TaskType);
            {
                emitter.Emit(LocalOperation.Load, cpuKernel);
                emitter.EmitCall(CPUKernel.GetKernelExecutionDelegate);

                // Load custom user dimension
                KernelLauncherBuilder.EmitLoadKernelConfig(
                    entryPoint,
                    emitter,
                    Kernel.KernelParamDimensionIdx,
                    MaxGridSize,
                    MaxGroupSize);

                // Load dimensions
                KernelLauncherBuilder.EmitLoadRuntimeKernelConfig(
                    entryPoint,
                    emitter,
                    Kernel.KernelParamDimensionIdx,
                    MaxGridSize,
                    MaxGroupSize,
                    customGroupSize);

                // Create new task object
                emitter.EmitNewObject(kernel.TaskConstructor);

                // Store task
                emitter.Emit(LocalOperation.Store, task);
            }

            // Assign parameters
            var parameters = entryPoint.Parameters;

            for (int i = 0, e = parameters.Count; i < e; ++i)
            {
                emitter.Emit(LocalOperation.Load, task);
                emitter.Emit(ArgumentOperation.Load, i + Kernel.KernelParameterOffset);
                if (parameters.IsByRef(i))
                {
                    emitter.Emit(OpCodes.Ldobj, parameters[i]);
                }
                emitter.Emit(OpCodes.Stfld, kernel.TaskArgumentMapping[i]);
            }

            // Launch task: ((CPUKernel)kernel).CPUAccelerator.Launch(task);
            emitter.Emit(LocalOperation.Load, cpuKernel);
            emitter.EmitCall(
                typeof(CPUKernel).GetProperty(
                    nameof(CPUKernel.CPUAccelerator)).GetGetMethod(false));
            emitter.Emit(LocalOperation.Load, task);
            emitter.EmitCall(
                typeof(CPUAccelerator).GetMethod(
                    nameof(CPUAccelerator.Launch),
                    BindingFlags.NonPublic | BindingFlags.Instance));

            // End of launch method
            emitter.Emit(OpCodes.Ret);
            emitter.Finish();

            return(launcher.Finish());
        }