Skip to content

Commit

Permalink
Add test for inlined P/Invokes into an UnmanagedCallersOnly callback. (
Browse files Browse the repository at this point in the history
  • Loading branch information
AaronRobinsonMSFT authored Jun 20, 2020
1 parent 531ebcd commit b8632bb
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,25 @@

#include <thread>

extern "C" DLL_EXPORT int STDMETHODCALLTYPE DoubleImplNative(int n)
{
return 2 * n;
}

typedef int (STDMETHODCALLTYPE *CALLBACKPROC)(int n);

extern "C" DLL_EXPORT int STDMETHODCALLTYPE CallManagedProcMultipleTimes(int m, CALLBACKPROC pCallbackProc, int n)
{
int acc = 0;
for (int i = 0; i < m; ++i)
acc += pCallbackProc(n);

return acc;
}

extern "C" DLL_EXPORT int STDMETHODCALLTYPE CallManagedProc(CALLBACKPROC pCallbackProc, int n)
{
return pCallbackProc(n);
return CallManagedProcMultipleTimes(1, pCallbackProc, n);
}

namespace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ public class Program
{
public static class UnmanagedCallersOnlyDll
{
[DllImport(nameof(UnmanagedCallersOnlyDll))]
public static extern int DoubleImplNative(int n);

[DllImport(nameof(UnmanagedCallersOnlyDll))]
public static extern int CallManagedProc(IntPtr callbackProc, int n);

[DllImport(nameof(UnmanagedCallersOnlyDll))]
public static extern int CallManagedProcMultipleTimes(int m, IntPtr callbackProc, int n);

[DllImport(nameof(UnmanagedCallersOnlyDll))]
public static extern int CallManagedProcOnNewThread(IntPtr callbackProc, int n);

Expand All @@ -36,6 +42,8 @@ public static int Main(string[] args)
TestUnmanagedCallersOnlyValid();
TestUnmanagedCallersOnlyValid_OnNewNativeThread();
TestUnmanagedCallersOnlyValid_PrepareMethod();
// Fails due to https://github.com/dotnet/runtime/issues/38192
//TestUnmanagedCallersOnlyMultipleTimesValid();
NegativeTest_NonStaticMethod();
NegativeTest_ViaDelegate();
NegativeTest_NonBlittable();
Expand Down Expand Up @@ -207,6 +215,64 @@ .locals init ([0] native int ptr)
}
}

[UnmanagedCallersOnly]
public static int ManagedDoubleInNativeCallback(int n)
{
// This callback is designed to test if the JIT handles
// cases where a P/Invoke is inlined into a function
// marked with UnmanagedCallersOnly.
return UnmanagedCallersOnlyDll.DoubleImplNative(n);
}

public static void TestUnmanagedCallersOnlyMultipleTimesValid()
{
Console.WriteLine($"Running {nameof(TestUnmanagedCallersOnlyMultipleTimesValid)}...");

/*
void UnmanagedCallersOnly()
{
.locals init ([0] native int ptr)
nop
ldftn int32 ManagedDoubleInNativeCallback(int32)
stloc.0
ldc.i4 <m> call count
ldloc.0
ldc.i4 <n> local
call bool UnmanagedCallersOnlyDll::CallManagedProcMultipleTimes(int, native int, int)
ret
}
*/
DynamicMethod testUnmanagedCallersOnly = new DynamicMethod("UnmanagedCallersOnly", typeof(int), null, typeof(Program).Module);
ILGenerator il = testUnmanagedCallersOnly.GetILGenerator();
il.DeclareLocal(typeof(IntPtr));
il.Emit(OpCodes.Nop);

// Get native function pointer of the callback
il.Emit(OpCodes.Ldftn, typeof(Program).GetMethod(nameof(ManagedDoubleInNativeCallback)));
il.Emit(OpCodes.Stloc_0);

int callCount = 7;
il.Emit(OpCodes.Ldc_I4, callCount);

il.Emit(OpCodes.Ldloc_0);

int n = 12345;
il.Emit(OpCodes.Ldc_I4, n);
il.Emit(OpCodes.Call, typeof(UnmanagedCallersOnlyDll).GetMethod("CallManagedProcMultipleTimes"));
il.Emit(OpCodes.Ret);
var testNativeMethod = (IntNativeMethodInvoker)testUnmanagedCallersOnly.CreateDelegate(typeof(IntNativeMethodInvoker));

int expected = 0;
for (int i = 0; i < callCount; ++i)
{
expected += DoubleImpl(n);
}
Assert.AreEqual(expected, testNativeMethod());
}

private const int CallbackThrowsErrorCode = 27;

[UnmanagedCallersOnly]
Expand Down

0 comments on commit b8632bb

Please sign in to comment.