Beispiel #1
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());
        }
Beispiel #2
0
        /// <summary>
        /// Emits deserializing (SerializiationInfo, StreamingContext) constructor.
        /// </summary>
        private static void EmitDeserializingConstructor(PhpType /*!*/ phpType)
        {
            // (SerializationInfo, StreamingContext) constructor
            ConstructorBuilder ctor_builder = phpType.DeserializingConstructorBuilder;

            if (ctor_builder != null)
            {
                ILEmitter cil = new ILEmitter(ctor_builder);

                if (phpType.Base == null)
                {
                    EmitInvokePhpObjectDeserializingConstructor(cil);
                }
                else
                {
                    phpType.Base.EmitInvokeDeserializationConstructor(cil, phpType, null);
                }

                // [ __InitializeStaticFields(context) ]
                cil.Emit(OpCodes.Call, Methods.ScriptContext.GetCurrentContext);

                cil.EmitCall(OpCodes.Call, phpType.StaticFieldInitMethodInfo, null);
                cil.Emit(OpCodes.Ret);
            }
        }
Beispiel #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);
 }
Beispiel #4
0
        /// <summary>
        /// Implements all given abstract methods by using their p-invoke targets.
        /// </summary>
        /// <param name="typeBuilder">The type builder to use.</param>
        /// <param name="libraryName">The native library name.</param>
        /// <param name="methods">The methods to implement.</param>
        private static void ImplementImports(
            TypeBuilder typeBuilder,
            string libraryName,
            ImportMethod[] methods)
        {
            foreach (var importMethod in methods)
            {
                var method         = importMethod.Method;
                var parameters     = importMethod.GetParameters();
                var parameterTypes = importMethod.GetParameterTypes();

                // Define a new p-invoke compatible entry point method
                var pInvokeMethod = typeBuilder.DefineMethod(
                    importMethod.Attribute.GetEntryPoint(method),
                    MethodAttributes.Private |
                    MethodAttributes.Static |
                    MethodAttributes.HideBySig |
                    MethodAttributes.PinvokeImpl,
                    CallingConventions.Standard,
                    importMethod.ReturnType,
                    parameterTypes);
                pInvokeMethod.SetCustomAttribute(
                    SuppressCodeSecurityConstructor,
                    Array.Empty <byte>());
                pInvokeMethod.SetCustomAttribute(
                    importMethod.Attribute.ToImportAttributeBuilder(
                        libraryName,
                        method));
                DefineMarshalParameters(pInvokeMethod, parameters);

                // Define a new wrapper implementation that invokes the p-invoke target
                var wrapperMethod = importMethod.DefineImplementationMethod(typeBuilder);
                DefineWrapperParameters(wrapperMethod, parameters);

                // Define wrapper method body
                var generator = new ILEmitter(wrapperMethod.GetILGenerator());
                for (int i = 0, e = parameters.Length; i < e; ++i)
                {
                    generator.Emit(ArgumentOperation.Load, i + 1);
                }
                generator.EmitCall(pInvokeMethod);
                generator.Emit(OpCodes.Ret);

                // Define method override
                typeBuilder.DefineMethodOverride(wrapperMethod, method);
            }
        }
Beispiel #5
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);
            }
        }
Beispiel #6
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());
        }
Beispiel #7
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());
        }
Beispiel #8
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);
                }
            }
        }
Beispiel #9
0
        /// <summary> Implements property </summary>
        /// <remarks><code>
        /// class A : IDuck {
        ///   /*type*/ Prop {
        ///     get {
        ///             Operators.GetProperty(this._obj, "Foo", null, false);
        ///				return /* .. type conversion .. */
        ///     }
        ///     set {
        ///				Operators.SetProperty(
        ///					new PhpReference(PhpVariable.Copy(ClrObject.WrapDynamic(argument#i), CopyReason.PassedByCopy)),
        ///					ref this._obj, "Foo", null, ScriptContext.Current);
        ///			}
        ///   }
        /// }
        /// </code></remarks>
        private void ImplementProperty(TypeBuilder tb, PropertyInfo prop, FieldInfo fld)
        {
            if (prop.GetIndexParameters().Length > 0)
            {
                throw new NotImplementedException("Indexers are not supported!");
            }

            string propName = prop.Name;

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

            // define method
            PropertyBuilder pb = tb.DefineProperty(prop.Name, PropertyAttributes.HasDefault, prop.PropertyType, null);

            if (prop.CanRead)
            {
                MethodBuilder getter = tb.DefineMethod("get_" + prop.Name, MethodAttributes.Private | MethodAttributes.SpecialName |
                                                       MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
                                                       prop.PropertyType, Type.EmptyTypes);
                ILEmitter il = new ILEmitter(getter);

                // emit getter
                // Operators.GetProperty(this.obj, "Foo", null, false);
                il.Ldarg(0);
                il.Load(fld);
                il.LoadLiteral(propName);
                il.LoadLiteral(null);
                il.LoadLiteral(false);
                il.Emit(OpCodes.Call, Methods.Operators.GetProperty);

                EmitReturn(il, prop.PropertyType, false);
                pb.SetGetMethod(getter);
                tb.DefineMethodOverride(getter, prop.GetGetMethod());
            }

            if (prop.CanWrite)
            {
                MethodBuilder setter = tb.DefineMethod("set_" + prop.Name, MethodAttributes.Private | MethodAttributes.SpecialName |
                                                       MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final,
                                                       typeof(void), new Type[] { prop.PropertyType });
                ILEmitter il = new ILEmitter(setter);

                // emit setter
                // new PhpReference(PhpVariable.Copy(ClrObject.WrapDynamic(argument#i), CopyReason.PassedByCopy))
                il.Ldarg(1);
                if (prop.PropertyType.IsValueType)
                {
                    il.Emit(OpCodes.Box, prop.PropertyType);
                }

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

                // Operators.SetProperty( ... , ref this._obj, "Foo", null, ScriptContext.Current);
                il.Ldarg(0);
                il.LoadAddress(fld);
                il.LoadLiteral(propName);
                il.LoadLiteral(null);
                il.EmitCall(OpCodes.Call, Methods.ScriptContext.GetCurrentContext, Type.EmptyTypes);
                il.EmitCall(OpCodes.Call, Methods.Operators.SetProperty, Type.EmptyTypes);
                il.Emit(OpCodes.Ret);

                pb.SetSetMethod(setter);
                tb.DefineMethodOverride(setter, prop.GetSetMethod());
            }
        }
Beispiel #10
0
        /// <summary>
        /// Emits IL instructions that unset an instance field.
        /// </summary>
        /// <remarks>
        /// Nothing is expected on the evaluation stack. Nothing is left on the evaluation stack.
        /// </remarks>
        private void EmitUnsetField(CodeGenerator /*!*/ codeGenerator)
        {
            ILEmitter il = codeGenerator.IL;

            DirectVarUse direct_instance = isMemberOf as DirectVarUse;

            if (direct_instance != null && direct_instance.VarName.IsThisVariableName)
            {
                // $this->a
                switch (codeGenerator.LocationStack.LocationType)
                {
                case LocationTypes.GlobalCode:
                {
                    // load $this from one of Main's arguments and check for null
                    Label this_non_null = il.DefineLabel();

                    codeGenerator.EmitLoadSelf();
                    il.Emit(OpCodes.Brtrue_S, this_non_null);
                    codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
                    il.Emit(OpCodes.Br, codeGenerator.ChainBuilder.ErrorLabel);
                    il.MarkLabel(this_non_null, true);

                    // call UnsetProperty
                    codeGenerator.EmitLoadSelf();
                    il.Emit(OpCodes.Ldstr, varName.ToString());                                     // TODO
                    codeGenerator.EmitLoadClassContext();

                    il.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
                    return;
                }

                case LocationTypes.FunctionDecl:
                {
                    // always throws error
                    codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
                    il.Emit(OpCodes.Br, codeGenerator.ChainBuilder.ErrorLabel);
                    break;
                }

                case LocationTypes.MethodDecl:
                {
                    CompilerLocationStack.MethodDeclContext context = codeGenerator.LocationStack.PeekMethodDecl();
                    if (context.Method.IsStatic)
                    {
                        // always throws error
                        codeGenerator.EmitPhpException(Methods.PhpException.ThisUsedOutOfObjectContext);
                        il.Emit(OpCodes.Br, codeGenerator.ChainBuilder.ErrorLabel);
                    }
                    else
                    {
                        DProperty property;
                        if (context.Type.GetProperty(varName, context.Type, out property) == GetMemberResult.OK &&
                            !property.IsStatic)
                        {
                            // ask the DProperty to emit its unsetting code
                            property.EmitUnset(codeGenerator, IndexedPlace.ThisArg, null, false);
                        }
                        else
                        {
                            // unable to resolve the field -> call UnsetProperty
                            codeGenerator.EmitLoadSelf();
                            il.Emit(OpCodes.Ldstr, varName.ToString());
                            codeGenerator.EmitLoadClassContext();

                            il.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
                        }
                    }
                }
                break;
                }
            }
            else
            {
                // call UnsetProperty
                isMemberOf.Emit(codeGenerator);
                il.Emit(OpCodes.Ldstr, varName.ToString());
                codeGenerator.EmitLoadClassContext();

                il.EmitCall(OpCodes.Call, Methods.Operators.UnsetProperty, null);
            }
        }
Beispiel #11
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());
        }
Beispiel #12
0
        /// <summary>
        /// Emits (ScriptContext, bool) constructor.
        /// </summary>
        private static void EmitShortConstructor(PhpType /*!*/ phpType)
        {
            // (ScriptContext,bool) constructor
            ConstructorBuilder ctor_builder = phpType.ShortConstructorBuilder;

            ctor_builder.DefineParameter(1, ParameterAttributes.None, "context");
            ctor_builder.DefineParameter(2, ParameterAttributes.None, "newInstance");
            ILEmitter cil = new ILEmitter(ctor_builder);

            // invoke base constructor
            if (phpType.Base == null)
            {
                EmitInvokePhpObjectConstructor(cil);
            }
            else
            {
                phpType.Base.EmitInvokeConstructor(cil, phpType, null);
            }

            // perform fast DObject.<typeDesc> init if we are in its subclass
            if (phpType.Root is PhpType)
            {
                // [ if (GetType() == typeof(self)) this.typeDesc = self.<typeDesc> ]
                cil.Ldarg(FunctionBuilder.ArgThis);
                cil.Emit(OpCodes.Call, Methods.Object_GetType);
                cil.Emit(OpCodes.Ldtoken, phpType.RealTypeBuilder);
                cil.Emit(OpCodes.Call, Methods.GetTypeFromHandle);

                Label label = cil.DefineLabel();
                cil.Emit(OpCodes.Bne_Un_S, label);
                if (true)
                {
                    cil.Ldarg(FunctionBuilder.ArgThis);
                    cil.Emit(OpCodes.Ldsfld, phpType.TypeDescFieldInfo);
                    cil.Emit(OpCodes.Stfld, Fields.DObject_TypeDesc);
                    cil.MarkLabel(label);
                }
            }

            // register this instance for finalization if it introduced the __destruct method
            DRoutine destruct;

            if (phpType.TypeDesc.GetMethod(DObject.SpecialMethodNames.Destruct) != null && (phpType.Base == null ||
                                                                                            phpType.Base.GetMethod(DObject.SpecialMethodNames.Destruct, phpType, out destruct) == GetMemberResult.NotFound))
            {
                cil.Ldarg(FunctionBuilder.ArgContextInstance);
                cil.Ldarg(FunctionBuilder.ArgThis);

                if (phpType.ProxyFieldInfo != null)
                {
                    cil.Emit(OpCodes.Ldfld, phpType.ProxyFieldInfo);
                }

                cil.Emit(OpCodes.Call, Methods.ScriptContext.RegisterDObjectForFinalization);
            }

            // [ <InitializeInstanceFields>(arg1) ]
            cil.Ldarg(FunctionBuilder.ArgThis);
            cil.Ldarg(FunctionBuilder.ArgContextInstance);
            cil.EmitCall(OpCodes.Call, phpType.Builder.InstanceFieldInit, null);

            // [ __InitializeStaticFields(arg1) ]
            cil.Ldarg(FunctionBuilder.ArgContextInstance);
            cil.EmitCall(OpCodes.Call, phpType.StaticFieldInitMethodInfo, null);

            cil.Emit(OpCodes.Ret);
        }