/// <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()); }
/// <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); } }
/// <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); }
/// <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); } }
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); } }
/// <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()); }
/// <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()); }
/// <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<T> /// return new DuckEnumerableWrapper<T>(obj.GetForeachEnumerator(false, false, null)) /// /// // type is IDuckKeyedEnumerable<T> /// return new DuckKeyedEnumerableWrapper<T>(obj.GetForeachEnumerator(true, false, null)) /// /// // type is marked using [DuckType] /// return DuckTyping.Instance.ImplementDuckType<T>(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); } } }
/// <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()); } }
/// <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); } }
/// <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()); }
/// <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); }