Esempio n. 1
0
        /// <summary>
        /// Get a native function pointer for a given method. This matches an IL-level ldftn.
        /// </summary>
        /// <remarks>
        /// ldftn doesn't JIT-compile the method on mono, which thus keeps the class constructor untouched.
        /// On the other hand, its result thus doesn't always match that of MethodHandle.GetFunctionPointer().
        /// </remarks>
        /// <param name="m">The method to get a native function pointer for.</param>
        /// <returns>The native function pointer.</returns>
        public static IntPtr GetLdftnPointer(this MethodBase m) {
            if (_GetLdftnPointerCache.TryGetValue(m, out Func<IntPtr> func))
                return func();

            DynamicMethodDefinition dmd = new DynamicMethodDefinition(
                $"GetLdftnPointer<{m.GetID(simple: true)}>",
                typeof(int), Type.EmptyTypes
            );

            ILProcessor il = dmd.GetILProcessor();
            il.Emit(OpCodes.Ldftn, dmd.Definition.Module.ImportReference(m));
            il.Emit(OpCodes.Ret);

            lock (_GetLdftnPointerCache) {
                return (_GetLdftnPointerCache[m] = dmd.Generate().CreateDelegate<Func<IntPtr>>() as Func<IntPtr>)();
            }
        }
Esempio n. 2
0
        public static int GetManagedSize(this Type t)
        {
            if (_GetManagedSizeCache.TryGetValue(t, out int size))
            {
                return(size);
            }

            // Note: sizeof is more accurate for the "managed size" than Marshal.SizeOf (marshalled size)
            // It also returns a value for types of which the size cannot be determined otherwise.

            DynamicMethodDefinition dmd = new DynamicMethodDefinition(
                $"GetSize<{t.FullName}>",
                typeof(int), Type.EmptyTypes
                );

            ILProcessor il = dmd.GetILProcessor();

            il.Emit(OpCodes.Sizeof, dmd.Definition.Module.ImportReference(t));
            il.Emit(OpCodes.Ret);

            lock (_GetManagedSizeCache) {
                return(_GetManagedSizeCache[t] = (dmd.Generate().CreateDelegate(typeof(Func <int>)) as Func <int>)());
            }
        }
Esempio n. 3
0
        public static IntPtr GetLdftnPointer(this MethodBase m)
        {
            if (_GetLdftnPointerCache.TryGetValue(m, out Func <IntPtr> func))
            {
                return(func());
            }

            // Note: ldftn doesn't JIT the method on mono, keeping the class constructor untouched.
            // Its result thus doesn't always match MethodHandle.GetFunctionPointer().

            DynamicMethodDefinition dmd = new DynamicMethodDefinition(
                $"GetLdftnPointer<{m.GetFindableID(simple: true)}>",
                typeof(int), Type.EmptyTypes
                );

            ILProcessor il = dmd.GetILProcessor();

            il.Emit(OpCodes.Ldftn, dmd.Definition.Module.ImportReference(m));
            il.Emit(OpCodes.Ret);

            lock (_GetLdftnPointerCache) {
                return((_GetLdftnPointerCache[m] = dmd.Generate().CreateDelegate(typeof(Func <IntPtr>)) as Func <IntPtr>)());
            }
        }
Esempio n. 4
0
        private static FastReflectionDelegate _CreateFastDelegate(MethodBase method, bool directBoxValueAccess = true)
        {
            DynamicMethodDefinition dmd = new DynamicMethodDefinition($"FastReflection<{method.GetID(simple: true)}>", typeof(object), _DynamicMethodDelegateArgs);
            ILProcessor             il  = dmd.GetILProcessor();

            ParameterInfo[] args = method.GetParameters();

            bool generateLocalBoxValuePtr = true;

            if (!method.IsStatic)
            {
                il.Emit(OpCodes.Ldarg_0);
                if (method.DeclaringType.IsValueType)
                {
                    il.Emit(OpCodes.Unbox_Any, method.DeclaringType);
                }
            }

            for (int i = 0; i < args.Length; i++)
            {
                Type argType    = args[i].ParameterType;
                bool argIsByRef = argType.IsByRef;
                if (argIsByRef)
                {
                    argType = argType.GetElementType();
                }
                bool argIsValueType = argType.IsValueType;

                if (argIsByRef && argIsValueType && !directBoxValueAccess)
                {
                    // Used later when storing back the reference to the new box in the array.
                    il.Emit(OpCodes.Ldarg_1);
                    il.Emit(OpCodes.Ldc_I4, i);
                }

                il.Emit(OpCodes.Ldarg_1);
                il.Emit(OpCodes.Ldc_I4, i);

                if (argIsByRef && !argIsValueType)
                {
                    il.Emit(OpCodes.Ldelema, typeof(object));
                }
                else
                {
                    il.Emit(OpCodes.Ldelem_Ref);
                    if (argIsValueType)
                    {
                        if (!argIsByRef || !directBoxValueAccess)
                        {
                            // if !directBoxValueAccess, create a new box if required
                            il.Emit(OpCodes.Unbox_Any, argType);
                            if (argIsByRef)
                            {
                                // box back
                                il.Emit(OpCodes.Box, argType);

                                // store new box value address to local 0
                                il.Emit(OpCodes.Dup);
                                il.Emit(OpCodes.Unbox, argType);
                                if (generateLocalBoxValuePtr)
                                {
                                    generateLocalBoxValuePtr = false;
                                    dmd.Definition.Body.Variables.Add(new VariableDefinition(new PinnedType(new PointerType(dmd.Definition.Module.TypeSystem.Void))));
                                }
                                il.Emit(OpCodes.Stloc_0);

                                // arr and index set up already
                                il.Emit(OpCodes.Stelem_Ref);

                                // load address back to stack
                                il.Emit(OpCodes.Ldloc_0);
                            }
                        }
                        else
                        {
                            // if directBoxValueAccess, emit unbox (get value address)
                            il.Emit(OpCodes.Unbox, argType);
                        }
                    }
                }
            }

            if (method.IsConstructor)
            {
                il.Emit(OpCodes.Newobj, method as ConstructorInfo);
            }
            else if (method.IsFinal || !method.IsVirtual)
            {
                il.Emit(OpCodes.Call, method as MethodInfo);
            }
            else
            {
                il.Emit(OpCodes.Callvirt, method as MethodInfo);
            }

            Type returnType = method.IsConstructor ? method.DeclaringType : (method as MethodInfo).ReturnType;

            if (returnType != typeof(void))
            {
                if (returnType.IsValueType)
                {
                    il.Emit(OpCodes.Box, returnType);
                }
            }
            else
            {
                il.Emit(OpCodes.Ldnull);
            }

            il.Emit(OpCodes.Ret);

            return((FastReflectionDelegate)dmd.Generate().CreateDelegate(typeof(FastReflectionDelegate)));
        }