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

How to Obtain a Method Pointer Without Reflection in NativeAOT? #100103

Closed
dadavadd opened this issue Mar 21, 2024 · 18 comments
Closed

How to Obtain a Method Pointer Without Reflection in NativeAOT? #100103

dadavadd opened this issue Mar 21, 2024 · 18 comments
Labels
area-NativeAOT-coreclr question Answer questions and provide assistance, not an issue with source code or documentation.

Comments

@dadavadd
Copy link

Hi!

I am currently exploring NativeAOT for a project that requires high performance and direct method calls without the overhead of reflection. My goal is to obtain a pointer to a specific method in C# to use in an unsafe context, ensuring the most efficient execution possible.

In the traditional .NET runtime, we typically rely on reflection (e.g., MethodInfo.MethodHandle.GetFunctionPointer()) to achieve this, but I understand that reflection might not be fully supported or recommended in NativeAOT for performance and runtime efficiency reasons.

Could you provide guidance or recommendations on how we can obtain a method pointer without relying on reflection within the NativeAOT environment? Are there any specific patterns, practices, or API calls in NativeAOT that facilitate this kind of direct method access?

Any examples or documentation you could point me to would be greatly appreciated.

Thank you for your time and assistance.

Copy link
Contributor

Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas
See info in area-owners.md if you want to be subscribed.

@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Mar 21, 2024
@jkotas jkotas added the question Answer questions and provide assistance, not an issue with source code or documentation. label Mar 21, 2024
@MichalStrehovsky
Copy link
Member

The C# function pointers (delegate*) work. If you go to IL level, ldftn works (delegate* is limited to static methods, ldftn isn't).

MethodInfo.MethodHandle.GetFunctionPointer() also works. The only problems with it are trimmability problems - i.e. if you can obtain the MethodInfo in a way that can be statically analyzed, it's not a problem. The trimming can analyze things like typeof(SomeType).GetMethod("Foo"). If you don't see any warnings at publish time (or in IDE when writing the code and the analyzer is enabled either by setting the IsTrimmable or PublishTrimmed property), it's fine.

@dadavadd
Copy link
Author

The C# function pointers (delegate*) work. If you go to IL level, ldftn works (delegate* is limited to static methods, ldftn isn't).

MethodInfo.MethodHandle.GetFunctionPointer() also works. The only problems with it are trimmability problems - i.e. if you can obtain the MethodInfo in a way that can be statically analyzed, it's not a problem. The trimming can analyze things like typeof(SomeType).GetMethod("Foo"). If you don't see any warnings at publish time (or in IDE when writing the code and the analyzer is enabled either by setting the IsTrimmable or PublishTrimmed property), it's fine.

I'm trying to port my code to Unity Il2CPP, but reflection is ruining everything. Is it possible to get a pointer to a method without reflection and without necessarily specifying "static"?

@dadavadd
Copy link
Author

The C# function pointers (delegate*) work. If you go to IL level, ldftn works (delegate* is limited to static methods, ldftn isn't).

MethodInfo.MethodHandle.GetFunctionPointer() also works. The only problems with it are trimmability problems - i.e. if you can obtain the MethodInfo in a way that can be statically analyzed, it's not a problem. The trimming can analyze things like typeof(SomeType).GetMethod("Foo"). If you don't see any warnings at publish time (or in IDE when writing the code and the analyzer is enabled either by setting the IsTrimmable or PublishTrimmed property), it's fine.

image

At the moment my code looks like this. But it only accepts static functions. Is there a way to get a pointer to more than just static methods without reflection?

@MichalStrehovsky
Copy link
Member

Stepping back - once you obtain the function pointer to an instance method, how are you going to invoke it?

@dadavadd
Copy link
Author

Stepping back - once you obtain the function pointer to an instance method, how are you going to invoke it?

You are not the first person to ask me about this :). I'm not going to call her. I will store the function instructions into a variable as a byte array :). Is there any way to get a pointer to a non-static method? I just need his address. I'm not trying to call him :)

@MichalStrehovsky
Copy link
Member

typeof(TestProtectMethods).GetMethod("SetHealth").MethodHandle.GetFunctionPointer() should work in that case. If the type and method name is visible in the typeof(TestProtectMethods).GetMethod("SetHealth") sequence, there should be no publish-time warnings and therefore no runtime problem.

@dadavadd
Copy link
Author

typeof(TestProtectMethods).GetMethod("SetHealth").MethodHandle.GetFunctionPointer()должно работать в этом случае. Если имя типа и метода отображается в typeof(TestProtectMethods).GetMethod("SetHealth")последовательности, не должно быть никаких предупреждений во время публикации и, следовательно, проблем во время выполнения.

THANK YOU!!

@dadavadd
Copy link
Author

dadavadd commented Mar 21, 2024

typeof(TestProtectMethods).GetMethod("SetHealth").MethodHandle.GetFunctionPointer() should work in that case. If the type and method name is visible in the typeof(TestProtectMethods).GetMethod("SetHealth") sequence, there should be no publish-time warnings and therefore no runtime problem.

image
image

🤔

@MichalStrehovsky
Copy link
Member

Remove the unsupported IlcDisableReflection switch from your project file.

@huoyaoyuan
Copy link
Member

I am currently exploring NativeAOT for a project that requires high performance and direct method calls without the overhead of reflection. My goal is to obtain a pointer to a specific method in C# to use in an unsafe context, ensuring the most efficient execution possible.

I'm also curious about this statement. How do you benefit from NativeAOT for your goal?

@MichalPetryka
Copy link
Contributor

How do you benefit from NativeAOT for your goal?

FYI calls on NativeAOT are faster cause they don't go through tiering stubs and such and are just always direct, they're also noticeably faster for indirect calls.

@am11
Copy link
Member

am11 commented Mar 22, 2024

I'm also curious about this statement. How do you benefit from NativeAOT for your goal?

They are porting their code from Il2CPP (Unity's AOT) to .NET NativeAOT backend, so it fits the bill.

@dadavadd
Copy link
Author

dadavadd commented Mar 22, 2024

Remove the unsupported IlcDisableReflection switch from your project file.

I want to check the instructions of given methods and therefore I need pointers without reflection. Because of this, my code doesn't work.

I already know how to get pointers to static methods without reflection. How do I get a pointer to a non-static method without reflection? Sorry for my English, I translate everything through Google Translator

@agocke
Copy link
Member

agocke commented Mar 23, 2024

I don't know of any way to do this today without reflection. #94975 is one proposal to do so.

@agocke
Copy link
Member

agocke commented Mar 23, 2024

Actually, this seems to work fine right now:

unsafe
{
    delegate*<C, void> func = &Accessor.M;
    func(c);
}

static class Accessor
{
    [UnsafeAccessor(UnsafeAccessorKind.Method)]
    public extern static void M(C c);
}

public class C {
    public void M() {
        Console.WriteLine("Hello");
    }
}

@MichalPetryka
Copy link
Contributor

Actually, this seems to work fine right now

Worth noting that this returns a pointer to a wrapper static method, not the method itself.

@MichalStrehovsky
Copy link
Member

I want to check the instructions of given methods and therefore I need pointers without reflection. Because of this, my code doesn't work.

You have to use reflection or write IL code by hand. The ldftn IL instruction returns an address of instance methods. Otherwise just remove the unsupported IlcDisableReflection and use reflection.

Worth noting that this returns a pointer to a wrapper static method, not the method itself.

Yes, that example returns the address of Accessor.M instead of C.M

I think with this we exhausted the list of options.

@dotnet-policy-service dotnet-policy-service bot removed the untriaged New issue has not been triaged by the area owner label Mar 25, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Apr 24, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-NativeAOT-coreclr question Answer questions and provide assistance, not an issue with source code or documentation.
Projects
Archived in project
Development

No branches or pull requests

7 participants