Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hack DynamicMethod #351

Open
dadhi opened this issue Oct 3, 2022 · 9 comments
Open

Hack DynamicMethod #351

dadhi opened this issue Oct 3, 2022 · 9 comments

Comments

@dadhi
Copy link
Owner

dadhi commented Oct 3, 2022

  • Hack its construction
  • Hack CreateDelegate in order to reuse the method again.
@weichx
Copy link

weichx commented Oct 3, 2022

I've actually done some experiments with this before. By re-using DynamicMethod and IlGenerators I could reduce (on mono) allocations per delegate creation by 12. Performance wasn't directly impacted that much but since there's a lot of contention for the memory allocator (at least on the version of Mono inside Unity3d) I got some pretty big throughput increases while multi-threading compilation of many delegates.

@dadhi
Copy link
Owner Author

dadhi commented Oct 3, 2022

@weichx Wow, how did you do that, can you share?

At the moment, the most promising part for me is to reuse byte codes byte[] array here:

            internal void EnsureCapacity(int size)
            {
                if (m_length + size >= m_ILStream.Length)
                    IncreaseCapacity(size);
            }
            private void IncreaseCapacity(int size)
            {
                byte[] temp = new byte[Math.Max(m_ILStream.Length * 2, m_length + size)]; // todo: @perf how to reuse existing ILStream here
                Array.Copy(m_ILStream, temp, m_ILStream.Length);
                m_ILStream = temp;
            }

@weichx
Copy link

weichx commented Oct 3, 2022

That was just a little prototype so I unfortunately don't have the code anymore but the gist of it was directly calling the internal C# runtime methods via reflection (or compiled expression tree). This let me skip all the api overhead that the .NET library introduces.

// this is a method defined in DynamicMethod.cs in the runtime library
// You can find it via reflection.
// I called this via reflection after setting all the properties on `m` 
// which was reused across compilations
private static extern void create_dynamic_method (DynamicMethod m);

All of the C# -> C runtime methods have static extern C# methods that are marked private or internal. Its just a matter of finding them and calling them yourself. I did the same thing for finding fields/properties/methods via reflection without allocating. The code below won't compile for you since it uses some of my utilities but hopefully it illustrates the idea.

public static unsafe class MonoUtil {

        private static Action<IntPtr> s_DisposePtrFn;
        private static Func<MethodInfo, ParameterInfo[]> s_GetParametersFn;
        private static Func<Type, IntPtr, int, BindingFlags, IntPtr> s_GetMethodsByNameFn;
        private static Func<Type, RuntimeTypeHandle> s_CreateRuntimeTypeHandleFn;
        private static Func<IntPtr, RuntimeTypeHandle, MethodBase> s_CreateMethodInfo;
        private static Func<IntPtr, RuntimeTypeHandle, FieldInfo> s_CreateFieldInfo;
        private static Func<IntPtr, RuntimeTypeHandle, PropertyInfo> s_CreatePropertyInfo;

        private static Func<Type, IntPtr, int, BindingFlags, IntPtr> s_GetFieldsByNameFn;
        private static Func<Type, IntPtr, int, BindingFlags, IntPtr> s_GetPropertiesByNameFn;

        // mirrors mono definition
        private enum MemberListType {

            All,
            CaseSensitive,
            CaseInsensitive,
            HandleToInfo

        }

        public static void Initialize() {
            CreateUtilFunctions();
        }

        public static int GetFields(Type type, BindingFlags bindingFlags, IList<FieldInfo> result) {
            return GetFields(type, default(FixedCharacterSpan), bindingFlags, result);
        }

        public static int GetFields(Type type, string fieldName, BindingFlags bindingFlags, IList<FieldInfo> result) {

            if (string.IsNullOrEmpty(fieldName)) {
                return GetFields(type, default(FixedCharacterSpan), bindingFlags, result);
            }

            fixed (char* cbuffer = fieldName) {
                return GetFields(type, new FixedCharacterSpan(cbuffer, fieldName.Length), bindingFlags, result);
            }
        }

        internal struct GPtrArray {

            internal IntPtr* data;
            internal int len;

        }

        internal static int GetFields(Type type, FixedCharacterSpan fieldName, BindingFlags bindingFlags, IList<FieldInfo> result) {

            IntPtr ptr = default;
            if (fieldName.size != 0) {
                int utf8Size = (fieldName.size * 2) + 4; // buffer a bit extra just in case 
                byte* cbuffer = stackalloc byte[utf8Size];
                CopyError error = UTF8ArrayUnsafeUtility.Copy(cbuffer, out _, utf8Size, fieldName.ptr, fieldName.size);
                if (error == CopyError.Truncation) {
                    cbuffer = TypedUnsafe.Malloc<byte>(2 * utf8Size, Allocator.Temp);
                    UTF8ArrayUnsafeUtility.Copy(cbuffer, out _, 2 * utf8Size, fieldName.ptr, fieldName.size);
                }

                ptr = new IntPtr(cbuffer);
            }

            IntPtr nativeMethodHandle = GetFieldsByName(type, ptr, bindingFlags);
            RuntimeTypeHandle runtimeTypeHandle = CreateRuntimeTypeHandle(type);
            GPtrArray* ptrArray = (GPtrArray*)nativeMethodHandle;

            for (int i = 0; i < ptrArray->len; i++) {
                result.Add(s_CreateFieldInfo(ptrArray->data[i], runtimeTypeHandle));
            }

            int retn = ptrArray->len;
            DisposeMonoArray(nativeMethodHandle);
            return retn;
        }

        public static int GetProperties(Type type, BindingFlags bindingFlags, IList<PropertyInfo> result) {
            return GetProperties(type, default(FixedCharacterSpan), bindingFlags, result);
        }

        public static int GetProperties(Type type, string propertyName, BindingFlags bindingFlags, IList<PropertyInfo> result) {

            if (string.IsNullOrEmpty(propertyName)) {
                return GetProperties(type, default(FixedCharacterSpan), bindingFlags, result);
            }

            fixed (char* cbuffer = propertyName) {
                return GetProperties(type, new FixedCharacterSpan(cbuffer, propertyName.Length), bindingFlags, result);
            }
        }

        internal static int GetProperties(Type type, FixedCharacterSpan propertyName, BindingFlags bindingFlags, IList<PropertyInfo> result) {

            IntPtr ptr = default;
            if (propertyName.size != 0) {
                int utf8Size = (propertyName.size * 2) + 4; // buffer a bit extra just in case 
                byte* cbuffer = stackalloc byte[utf8Size];
                CopyError error = UTF8ArrayUnsafeUtility.Copy(cbuffer, out _, utf8Size, propertyName.ptr, propertyName.size);
                if (error == CopyError.Truncation) {
                    cbuffer = TypedUnsafe.Malloc<byte>(2 * utf8Size, Allocator.Temp);
                    UTF8ArrayUnsafeUtility.Copy(cbuffer, out _, 2 * utf8Size, propertyName.ptr, propertyName.size);
                }

                ptr = new IntPtr(cbuffer);
            }

            IntPtr nativeMethodHandle = GetPropertiesByName(type, ptr, bindingFlags);
            RuntimeTypeHandle runtimeTypeHandle = CreateRuntimeTypeHandle(type);
            GPtrArray* ptrArray = (GPtrArray*)nativeMethodHandle;

            for (int i = 0; i < ptrArray->len; i++) {
                result.Add(s_CreatePropertyInfo(ptrArray->data[i], runtimeTypeHandle));
            }

            int retn = ptrArray->len;
            DisposeMonoArray(nativeMethodHandle);
            return retn;
        }

        internal static int GetMethods(Type type, IList<MethodInfo> result, BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) {
            return GetMethods(type, default(FixedCharacterSpan), result, bindingFlags);
        }

        public static int GetMethods(Type type, string methodName, IList<MethodInfo> result, BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) {

            if (string.IsNullOrEmpty(methodName)) {
                return GetMethods(type, default(FixedCharacterSpan), result, bindingFlags);
            }

            fixed (char* cbuffer = methodName) {
                return GetMethods(type, new FixedCharacterSpan(cbuffer, methodName.Length), result, bindingFlags);
            }

        }

        internal static int GetMethods(Type type, FixedCharacterSpan methodName, IList<MethodInfo> result, BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static) {

            IntPtr ptr = default;
            if (methodName.size != 0) {
                int utf8Size = (methodName.size * 2) + 4; // buffer a bit extra just in case 
                byte* cbuffer = stackalloc byte[utf8Size];
                CopyError error = UTF8ArrayUnsafeUtility.Copy(cbuffer, out _, utf8Size, methodName.ptr, methodName.size);
                if (error == CopyError.Truncation) {
                    cbuffer = TypedUnsafe.Malloc<byte>(2 * utf8Size, Allocator.Temp);
                    UTF8ArrayUnsafeUtility.Copy(cbuffer, out _, 2 * utf8Size, methodName.ptr, methodName.size);
                }

                ptr = new IntPtr(cbuffer);
            }

            IntPtr nativeMethodHandle = GetMethodsByName(type, ptr, bindingFlags);
            RuntimeTypeHandle runtimeTypeHandle = CreateRuntimeTypeHandle(type);
            GPtrArray* ptrArray = (GPtrArray*)nativeMethodHandle;

            for (int i = 0; i < ptrArray->len; i++) {
                result.Add((MethodInfo)s_CreateMethodInfo(ptrArray->data[i], runtimeTypeHandle));
            }

            int retn = ptrArray->len;
            DisposeMonoArray(nativeMethodHandle);
            return retn;
        }

        private static MethodInfo CreateRuntimeMethodHandle(IntPtr ptr, RuntimeTypeHandle typeHandle) {
            return (MethodInfo)s_CreateMethodInfo(ptr, typeHandle);
        }

        private static void CreateUtilFunctions() {
            {
                Type monoMethodInfoType = typeof(MethodInfo).Assembly.GetType("System.Reflection.MonoMethodInfo");

                MethodInfo getparams = monoMethodInfoType.GetMethod("GetParametersInfo", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);

                ParameterExpression methodInfoParam = Expression.Parameter(typeof(MethodInfo));

                PropertyInfo methodHandle = typeof(MethodInfo).GetProperty(nameof(MethodInfo.MethodHandle));
                PropertyInfo value = methodHandle.PropertyType.GetProperty(nameof(MethodInfo.MethodHandle.Value));

                MemberExpression handleProp = Expression.Property(methodInfoParam, methodHandle);
                MemberExpression ptrValue = Expression.Property(handleProp, value);

                s_GetParametersFn = Expression.Lambda<Func<MethodInfo, ParameterInfo[]>>(Expression.Call(null, getparams, ptrValue, methodInfoParam), new[] { methodInfoParam }).Compile();
            }

            Type runtimeMethodInfoType = typeof(Action).Assembly.GetType("System.Reflection.RuntimeMethodInfo");
            Type runtimePropertyInfoType = typeof(Action).Assembly.GetType("System.Reflection.RuntimePropertyInfo");
            Type runtimePropertyHandleType = typeof(Action).Assembly.GetType("Mono.RuntimePropertyHandle");

            ConstructorInfo runtimeMethodHandleCtor = typeof(RuntimeMethodHandle).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];
            ConstructorInfo runtimeFieldHandleCtor = typeof(RuntimeFieldHandle).GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];
            ConstructorInfo runtimePropertyHandleCtor = runtimePropertyHandleType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];

            MethodInfo[] runtimeMethodInfoMethods = runtimeMethodInfoType.GetMethods(BindingFlags.NonPublic | BindingFlags.Static);
            MethodInfo[] fieldInfoMethods = typeof(FieldInfo).GetMethods(BindingFlags.Public | BindingFlags.Static);
            MethodInfo[] runtimePropertyInfoMethods = runtimePropertyInfoType.GetMethods(BindingFlags.NonPublic | BindingFlags.Static);

            MethodInfo methodInfoGetMethodFromHandle = null;
            MethodInfo fieldInfoGetFieldFromHandle = null;
            MethodInfo propertyInfoGetPropertyFromHandle = null;

            for (int i = 0; i < runtimeMethodInfoMethods.Length; i++) {
                if (runtimeMethodInfoMethods[i].Name == "GetMethodFromHandleNoGenericCheck" && GetImmutableParameters(runtimeMethodInfoMethods[i]).Length == 2) {
                    methodInfoGetMethodFromHandle = runtimeMethodInfoMethods[i];
                    break;
                }
            }

            for (int i = 0; i < fieldInfoMethods.Length; i++) {
                if (fieldInfoMethods[i].Name == "GetFieldFromHandle" && GetImmutableParameters(fieldInfoMethods[i]).Length == 2) {
                    fieldInfoGetFieldFromHandle = fieldInfoMethods[i];
                    break;
                }
            }

            for (int i = 0; i < runtimePropertyInfoMethods.Length; i++) {
                if (runtimePropertyInfoMethods[i].Name == "GetPropertyFromHandle" && GetImmutableParameters(runtimePropertyInfoMethods[i]).Length == 2) {
                    propertyInfoGetPropertyFromHandle = runtimePropertyInfoMethods[i];
                    break;
                }
            }

            ParameterExpression[] parameters = new[] {
                Expression.Parameter(typeof(IntPtr)),
                Expression.Parameter(typeof(RuntimeTypeHandle)),
            };

            s_CreateMethodInfo = Expression.Lambda<Func<IntPtr, RuntimeTypeHandle, MethodBase>>(Expression.Call(null, methodInfoGetMethodFromHandle, Expression.New(runtimeMethodHandleCtor, parameters[0]), parameters[1]), parameters).Compile();

            s_CreateFieldInfo = Expression.Lambda<Func<IntPtr, RuntimeTypeHandle, FieldInfo>>(Expression.Call(null, fieldInfoGetFieldFromHandle, Expression.New(runtimeFieldHandleCtor, parameters[0]), parameters[1]), parameters).Compile();

            s_CreatePropertyInfo = Expression.Lambda<Func<IntPtr, RuntimeTypeHandle, PropertyInfo>>(Expression.Call(null, propertyInfoGetPropertyFromHandle, Expression.New(runtimePropertyHandleCtor, parameters[0]), parameters[1]), parameters).Compile();

            Type safeGPtrArrayHandle = typeof(Action).Assembly.GetType("Mono.SafeGPtrArrayHandle");
            ParameterExpression intPtrParam = Expression.Parameter(typeof(IntPtr));
            ConstructorInfo safeHandleCtor = safeGPtrArrayHandle.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance)[0];
            // new SafeGPtrArrayHandle(ptr).Dispose();  this lets me invoke the dispose w/o dealing w/ pointers which I can't do via expr trees
            s_DisposePtrFn = Expression.Lambda<Action<IntPtr>>(Expression.Call(
                Expression.New(safeHandleCtor, intPtrParam),
                safeGPtrArrayHandle.GetMethod("Dispose", BindingFlags.Instance | BindingFlags.Public)
            ), intPtrParam).Compile();

            Type systemRuntimeType = typeof(Action).Assembly.GetType("System.RuntimeType");

            ConstructorInfo rtHandleCtor = typeof(RuntimeTypeHandle).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { systemRuntimeType }, null);
            ParameterExpression parameter = Expression.Parameter(typeof(Type), "type");

            s_CreateRuntimeTypeHandleFn = Expression.Lambda<Func<Type, RuntimeTypeHandle>>(
                Expression.New(rtHandleCtor, Expression.Convert(parameter, systemRuntimeType)),
                parameter
            ).Compile();

            MethodInfo getFields_native = systemRuntimeType.GetMethod("GetFields_native", BindingFlags.NonPublic | BindingFlags.Instance);
            MethodInfo getProperties_native = systemRuntimeType.GetMethod("GetPropertiesByName_native", BindingFlags.NonPublic | BindingFlags.Instance);
            MethodInfo getConstructors_native = systemRuntimeType.GetMethod("GetConstructors_native", BindingFlags.NonPublic | BindingFlags.Instance);

            MethodInfo getMethodsByName_native = systemRuntimeType.GetMethod("GetMethodsByName_native", BindingFlags.NonPublic | BindingFlags.Instance);
            Type memberListType = typeof(Action).Assembly.GetType("System.RuntimeType+MemberListType");

            ParameterExpression typeParameter = Expression.Parameter(typeof(Type));
            ParameterExpression nameParameter = Expression.Parameter(typeof(IntPtr));
            ParameterExpression memberTypeListVal = Expression.Parameter(typeof(int));
            ParameterExpression bindingFlags = Expression.Parameter(typeof(BindingFlags));

            // ConstantExpression bindingFlags = Expression.Constant(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

            ParameterExpression[] paramList3 = new[] { typeParameter, nameParameter, memberTypeListVal };
            ParameterExpression[] paramList4 = new[] { typeParameter, nameParameter, memberTypeListVal, bindingFlags };

            s_GetMethodsByNameFn = Expression.Lambda<Func<Type, IntPtr, int, BindingFlags, IntPtr>>(Expression.Call(
                Expression.Convert(typeParameter, systemRuntimeType),
                getMethodsByName_native,
                nameParameter,
                bindingFlags,
                Expression.Convert(memberTypeListVal, memberListType)
            ), paramList4).Compile();

            s_GetFieldsByNameFn = Expression.Lambda<Func<Type, IntPtr, int, BindingFlags, IntPtr>>(Expression.Call(
                Expression.Convert(typeParameter, systemRuntimeType),
                getFields_native,
                nameParameter,
                bindingFlags,
                Expression.Convert(memberTypeListVal, memberListType)
            ), paramList4).Compile();

            s_GetPropertiesByNameFn = Expression.Lambda<Func<Type, IntPtr, int, BindingFlags, IntPtr>>(Expression.Call(
                Expression.Convert(typeParameter, systemRuntimeType),
                getProperties_native,
                nameParameter,
                bindingFlags,
                Expression.Convert(memberTypeListVal, memberListType)
            ), paramList4).Compile();

        }

        public static void DisposeMonoArray(IntPtr ptr) {
            s_DisposePtrFn(ptr);
        }

        public static RuntimeTypeHandle CreateRuntimeTypeHandle(Type type) {
            return s_CreateRuntimeTypeHandleFn(type);
        }

        private static IntPtr GetMethodsByName(Type type, IntPtr methodName, BindingFlags bindingFlags) {
            return s_GetMethodsByNameFn(type, methodName, methodName.ToInt64() == 0 ? (int)MemberListType.All : (int)MemberListType.CaseSensitive, bindingFlags);
        }

        private static IntPtr GetFieldsByName(Type type, IntPtr fieldName, BindingFlags bindingFlags) {
            return s_GetFieldsByNameFn(type, fieldName, fieldName.ToInt64() == 0 ? (int)MemberListType.All : (int)MemberListType.CaseSensitive, bindingFlags);
        }

        private static IntPtr GetPropertiesByName(Type type, IntPtr fieldName, BindingFlags bindingFlags) {
            return s_GetPropertiesByNameFn(type, fieldName, fieldName.ToInt64() == 0 ? (int)MemberListType.All : (int)MemberListType.CaseSensitive, bindingFlags);
        }

        public static ParameterInfo[] GetImmutableParameters(MethodBase methodBase) {
            if (methodBase is ConstructorInfo ctor) {
                return GetImmutableParameters(ctor);
            }

            return GetImmutableParameters((MethodInfo)methodBase);
        }

        public static ParameterInfo[] GetImmutableParameters(MethodInfo methodInfo) {
            // this proooobablly needs a lock or the caller needs to be locked

            // this is calling directly into mono to get at the parameter list that it uses internally
            // which prevents an array allocation & copy. Because we use their direct copy we CANNOT
            // mutate that array or weird shit will start happening. 
            return s_GetParametersFn.Invoke(methodInfo);
        }

        internal static bool TryGetFieldByName(Type type, string fieldName, BindingFlags bindingFlags, out FieldInfo fieldInfo) {
            fixed (char* cbuffer = fieldName) {
                return TryGetFieldByName(type, new FixedCharacterSpan(cbuffer, fieldName.Length), bindingFlags, out fieldInfo);
            }
        }

        internal static bool TryGetFieldByName(Type type, FixedCharacterSpan fieldName, BindingFlags bindingFlags, out FieldInfo fieldInfo) {
            IntPtr ptr = default;
            if (fieldName.size != 0) {
                int utf8Size = (fieldName.size * 2) + 4; // buffer a bit extra just in case 
                byte* cbuffer = stackalloc byte[utf8Size];
                CopyError error = UTF8ArrayUnsafeUtility.Copy(cbuffer, out _, utf8Size, fieldName.ptr, fieldName.size);
                if (error == CopyError.Truncation) {
                    cbuffer = TypedUnsafe.Malloc<byte>(2 * utf8Size, Allocator.Temp);
                    UTF8ArrayUnsafeUtility.Copy(cbuffer, out _, 2 * utf8Size, fieldName.ptr, fieldName.size);
                }

                ptr = new IntPtr(cbuffer);
            }

            IntPtr nativeMethodHandle = GetFieldsByName(type, ptr, bindingFlags);
            RuntimeTypeHandle runtimeTypeHandle = CreateRuntimeTypeHandle(type);
            GPtrArray* ptrArray = (GPtrArray*)nativeMethodHandle;

            if (ptrArray->len >= 1) {
                // return first match, I don't know when there would ever be more than 1. Maybe w/ base types & shadowing?
                fieldInfo = s_CreateFieldInfo(ptrArray->data[0], runtimeTypeHandle);
                DisposeMonoArray(nativeMethodHandle);
                return true;
            }

            fieldInfo = default;
            DisposeMonoArray(nativeMethodHandle);
            return false;
        }

        internal static bool TryGetPropertyByName(Type type, string propertyName, BindingFlags bindingFlags, out PropertyInfo propertyInfo) {
            fixed (char* cbuffer = propertyName) {
                return TryGetPropertyByName(type, new FixedCharacterSpan(cbuffer, propertyName.Length), bindingFlags, out propertyInfo);
            }
        }

        internal static bool TryGetPropertyByName(Type type, FixedCharacterSpan propertyName, BindingFlags bindingFlags, out PropertyInfo propertyInfo) {
            IntPtr ptr = default;
            if (propertyName.size != 0) {
                int utf8Size = (propertyName.size * 2) + 4; // buffer a bit extra just in case 
                byte* cbuffer = stackalloc byte[utf8Size];
                CopyError error = UTF8ArrayUnsafeUtility.Copy(cbuffer, out _, utf8Size, propertyName.ptr, propertyName.size);
                if (error == CopyError.Truncation) {
                    cbuffer = TypedUnsafe.Malloc<byte>(2 * utf8Size, Allocator.Temp);
                    UTF8ArrayUnsafeUtility.Copy(cbuffer, out _, 2 * utf8Size, propertyName.ptr, propertyName.size);
                }

                ptr = new IntPtr(cbuffer);
            }

            IntPtr nativeMethodHandle = GetPropertiesByName(type, ptr, bindingFlags);
            RuntimeTypeHandle runtimeTypeHandle = CreateRuntimeTypeHandle(type);
            GPtrArray* ptrArray = (GPtrArray*)nativeMethodHandle;

            if (ptrArray->len >= 1) {
                // return first match, I don't know when there would ever be more than 1. Maybe w/ base types & shadowing?
                propertyInfo = s_CreatePropertyInfo(ptrArray->data[0], runtimeTypeHandle);
                DisposeMonoArray(nativeMethodHandle);
                return true;
            }

            propertyInfo = default;
            DisposeMonoArray(nativeMethodHandle);
            return false;
        }

     
        // This will return enumValues and enumNames sorted by the values.
        public static void GetEnumData(Type type, out string[] enumNames, out Array enumValues) {
            FieldInfo[] flds = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);

            object[] values = new object[flds.Length];
            string[] names = new string[flds.Length];

            for (int i = 0; i < flds.Length; i++) {
                names[i] = flds[i].Name;
                values[i] = flds[i].GetRawConstantValue();
            }

            enumNames = names;
            enumValues = values;
        }

    }

@dadhi
Copy link
Owner Author

dadhi commented Oct 3, 2022

@weichx Thanks for sharing.. will see what can I steal from it :)

dadhi added a commit that referenced this issue Oct 4, 2022
@dadhi
Copy link
Owner Author

dadhi commented Oct 5, 2022

@weichx May be you tried it?... I was thinking, what is the fastest route from the byte[] array to the method.
I am looking at something like https://source.dot.net/#System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs,901

@weichx
Copy link

weichx commented Oct 5, 2022

probably just getting the m_Code field yourself and not using the methods. Also be aware that the Mono implementation looks different, there is a very good chance you'll need two different implementations of this or one of the platforms won't work.

@jogibear9988
Copy link
Contributor

If you'd like to use private/internal methods without reflection, this maybe usefull: https://github.com/aelij/IgnoresAccessChecksToGenerator

@dadhi
Copy link
Owner Author

dadhi commented Nov 8, 2023

Use #375 in .NET 8

@dadhi
Copy link
Owner Author

dadhi commented Nov 8, 2023

Nope for the #375 until UnsafeAccessorTypeAttribute is supported (likely in .NET 9)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants