Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

Implement NativeCallableMethods for CoreCLR #1566

Merged
merged 1 commit into from
Sep 19, 2015
Merged

Implement NativeCallableMethods for CoreCLR #1566

merged 1 commit into from
Sep 19, 2015

Conversation

tijoytom-zz
Copy link

Feature Description

Apply [NativeCallable] attribute to a managed method and then it can be called from native code.Typical use would be passing a managed method as callback to native , now it can be done by wrapping the method in a delegate or directly using Marshal.GetFunctionPointerForDelegate.This's fine as long as we make sure that delegate is not garbage collected.

[NativeCallable] introduce another way , where you can directly load the function pointer of a native callable method and use it as callback.This feature cannot be directly used from C# , but can be very useful in dynamic code generation scenarios where you want a callback to be passed to native.

Usage

Here's an example of how it can be used.
public static class NativeMethods
{
[DllImport("user32.dll")]
public static extern int EnumWindows(IntPtr enumProc, IntPtr lParam);
}

// Native callable callback method
[NativeCallable]
public static int CallbackMethod(IntPtr hWnd, IntPtr lParam)
{
return 1;
}
Now you can generate the below IL to load native callable function pointer ( LDFTN) and then pass it a native method.

               .locals init ([0] native int ptr)
               IL_0000:  nop  
               IL_0001:  ldftn      int32 CallbackMethod(native int,native int)
               IL_0002:  stloc.0
               IL_0003:  ldloc.0
               IL_0004:  ldsfld     native int [mscorlib]System.IntPtr::Zero
               IL_0005:  call       bool NativeMethods::EnumWindows(native int,native int)                                                                                  
               IL_0006:  pop
               IL_0007:  ret

Implementation

During JIT we treat method with [NativeCallable] attribute as special and create a reverse PInvoke thunk for it. Essentially it takes the same code path as reverse pinvoke.

Advantages and Limitations

Advantages of this method are , you don't have to create delegate matching the callback , and also you don't have to keep track of the delegates to make sure they are not collected.

Currently we require the native callable method to be
1.Static , Non Generic and no variable number of arguments.
2.Uses only blittable parameter types.

@dnfclas
Copy link

dnfclas commented Sep 16, 2015

Hi @tijoytom, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution!

In order for us to evaluate and accept your PR, we ask that you sign a contribution license agreement. It's all electronic and will take just minutes. I promise there's no faxing. https://cla2.dotnetfoundation.org.

TTYL, DNFBOT;

@dnfclas
Copy link

dnfclas commented Sep 16, 2015

@tijoytom, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR.

Thanks, DNFBOT;

@@ -153,6 +157,21 @@ LOCAL_LABEL(DoThreadSetup):
call C_FUNC(CreateThreadBlockThrow)
jmp LOCAL_LABEL(HaveThread)

LOCAL_LABEL(InvalidTransition):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not correct for Unix. There is no homing of argument registers and the argument registers are different from Windows. See the stack layout starting at line 44 in this file.

@dnfclas
Copy link

dnfclas commented Sep 16, 2015

@tijoytom, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR.

Thanks, DNFBOT;

@mmitche
Copy link
Member

mmitche commented Sep 16, 2015

@dotnet-bot test this please

@@ -279,6 +283,21 @@ DoThreadSetup:

jmp HaveThread

InvalidTransition:
mov [rbp + UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET + 0h], rcx
mov [rbp + UMThunkStubAMD64_ARGUMENTS_STACK_HOME_OFFSET + 8h], rdx
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please remove this setup as well - to match what you have done for Unix?

@jkotas
Copy link
Member

jkotas commented Sep 18, 2015

LGTM. Could you please squash everything into a single commit before merging?

Apply [NativeCallable] attribute to a managed method and then it can be
called from native code.Typical use would be passing a managed method as
callback to native, now it can be done by wrapping the method in a
delegate or directly using Marshal.GetFunctionPointerForDelegate.This's
fine as long as we make sure that delegate is not garbage
collected.[NativeCallable] introduce another way, where you can directly
load the function pointer of a native callable method and use it as
callback.This feature cannot be directly used from C#,but can be very
useful in dynamic code generation scenarios where you want a callback to
be passed to native.

Here's an example of how it can be used.

public static class NativeMethods {
 [DllImport("user32.dll")]
 public static extern int EnumWindows(IntPtr enumProc, IntPtr lParam);
}

//Method attributed with NativeCallable
[NativeCallable]
public static int CallbackMethod(IntPtr hWnd, IntPtr lParam){ return 1; }

Now you can generate the below IL to load native callable function pointer
( LDFTN) and then pass it a native method.
	.locals init ([0] native int ptr)
	nop
	ldftn      int32 CallbackMethod(native int,native int)
	stloc.0
	ldloc.0
	ldsfld     native int System.IntPtr::Zero
	call       bool NativeMethods::EnumWindows(native int,native int)
	pop
	ret

Encoding native callable methods as  ENCODE_METHOD_NATIVECALLABLE_HANDLE
so that we don't have to check for the custom attribute at runtime to
decode the method.Also fixing the remaining code review comments.

Adding runtime check to prevent Native Callable methods from being used as
calli target with an ldftn. Also adding some negative test cases , they
are disabled for now since the tests failfast and msbuild report it as
failure.
@tijoytom-zz
Copy link
Author

This's the test failing on FreeBSD , not sure if it has anything to with this change.
threading.WaitForMultipleObjectsEx.test2
Expected thread to wait for 1000 ms (and get interrupted). Interrupt Time: 500 ms, ThreadWaitDelta 499

@jkotas
Copy link
Member

jkotas commented Sep 18, 2015

Ignore the PAL failure. The PAL tests are known to fail once in a while because of the virtual machine that they are running on happen to be slow. We have fixed the worst offenders by raising the tolerances but there are still some left ...

@jkotas
Copy link
Member

jkotas commented Sep 18, 2015

@dotnet-bot test this please

jkotas added a commit that referenced this pull request Sep 19, 2015
Implement NativeCallableMethods for CoreCLR
@jkotas jkotas merged commit 9fa52c4 into dotnet:master Sep 19, 2015
picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
Implement NativeCallableMethods for CoreCLR

Commit migrated from dotnet/coreclr@9fa52c4
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants