Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions src/coreclr/interpreter/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2163,10 +2163,14 @@ int32_t InterpCompiler::GetDataItemIndexForHelperFtn(CorInfoHelpFunc ftn)
CORINFO_CONST_LOOKUP ftnLookup;
m_compHnd->getHelperFtn(ftn, &ftnLookup);
void* addr = ftnLookup.addr;
if (ftnLookup.accessType == IAT_PVALUE)
if (ftnLookup.accessType == IAT_VALUE)
{
addr = (void*)((size_t)addr | INTERP_INDIRECT_HELPER_TAG);
// We can't use the 1 bit to mark indirect addresses because it is used for real code on arm32 (the thumb bit)
// So instead, we mark direct addresses with a 1 and then on the other end we will clear the 1 and re-set it as needed for thumb
addr = (void*)((size_t)addr | INTERP_DIRECT_HELPER_TAG);
}
else if (ftnLookup.accessType == IAT_PPVALUE)
NO_WAY("IAT_PPVALUE helpers not implemented in interpreter");

#ifdef DEBUG
if (!PointerInNameMap(addr))
Expand Down Expand Up @@ -2821,6 +2825,9 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
doCallInsteadOfNew = true;
}

bool isPInvoke = callInfo.methodFlags & CORINFO_FLG_PINVOKE;
bool isMarshaledPInvoke = isPInvoke && m_compHnd->pInvokeMarshalingRequired(callInfo.hMethod, &callInfo.sig);

// Process sVars
int numArgsFromStack = callInfo.sig.numArgs + (newObj ? 0 : callInfo.sig.hasThis());
int newObjThisArgLocation = newObj && !doCallInsteadOfNew ? 0 : INT_MAX;
Expand Down Expand Up @@ -3057,8 +3064,17 @@ void InterpCompiler::EmitCall(CORINFO_RESOLVED_TOKEN* pConstrainedToken, bool re
// before the call.
// TODO: Add null checking behavior somewhere here!
}
AddIns(INTOP_CALL);
AddIns((isPInvoke && !isMarshaledPInvoke) ? INTOP_CALL_PINVOKE : INTOP_CALL);
m_pLastNewIns->data[0] = GetMethodDataItemIndex(callInfo.hMethod);
if (isPInvoke && !isMarshaledPInvoke)
{
CORINFO_CONST_LOOKUP lookup;
m_compHnd->getAddressOfPInvokeTarget(callInfo.hMethod, &lookup);
m_pLastNewIns->data[1] = GetDataItemIndex(lookup.addr);
m_pLastNewIns->data[2] = lookup.accessType == IAT_PVALUE;
if (lookup.accessType == IAT_PPVALUE)
NO_WAY("IAT_PPVALUE pinvokes not implemented in interpreter");
}
}
break;

Expand Down Expand Up @@ -6296,13 +6312,15 @@ void InterpCompiler::PrintHelperFtn(void* helperDirectOrIndirect)
{
void* helperAddr = helperDirectOrIndirect;

if (((size_t)helperDirectOrIndirect) & INTERP_INDIRECT_HELPER_TAG)
if (((size_t)helperDirectOrIndirect) & INTERP_DIRECT_HELPER_TAG)
{
helperAddr = (void*)(((size_t)helperDirectOrIndirect) & ~INTERP_INDIRECT_HELPER_TAG);
printf(" (indirect)");
helperAddr = (void*)(((size_t)helperDirectOrIndirect) & ~INTERP_DIRECT_HELPER_TAG);
printf(" (direct)");
}
else
printf(" (direct)");
{
printf(" (indirect)");
}

PrintPointer(helperAddr);
}
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/interpreter/interpretershared.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#define INTERP_STACK_SLOT_SIZE 8 // Alignment of each var offset on the interpreter stack
#define INTERP_STACK_ALIGNMENT 16 // Alignment of interpreter stack at the start of a frame

#define INTERP_INDIRECT_HELPER_TAG 1 // When a helper ftn's address is indirect we tag it with this tag bit
#define INTERP_DIRECT_HELPER_TAG 1 // When a helper ftn's address is direct we tag it with this tag bit

struct CallStubHeader;

Expand Down Expand Up @@ -137,7 +137,7 @@ struct InterpGenericLookup
void* signature;

// Here is the helper you must call. It is one of CORINFO_HELP_RUNTIMEHANDLE_* helpers.

InterpGenericLookupType lookupType;

// Number of indirections to get there
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/interpreter/intops.def
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ OPDEF(INTOP_LDFLDA, "ldflda", 4, 1, 1, InterpOpInt)
OPDEF(INTOP_CALL, "call", 4, 1, 1, InterpOpMethodHandle)
OPDEF(INTOP_CALLI, "calli", 5, 1, 2, InterpOpLdPtr)
OPDEF(INTOP_CALLVIRT, "callvirt", 4, 1, 1, InterpOpMethodHandle)
OPDEF(INTOP_CALL_PINVOKE, "call.pinvoke", 6, 1, 1, InterpOpMethodHandle) // inlined (no marshaling wrapper) pinvokes only
OPDEF(INTOP_NEWOBJ, "newobj", 5, 1, 1, InterpOpMethodHandle)
OPDEF(INTOP_NEWOBJ_GENERIC, "newobj.generic", 6, 1, 2, InterpOpMethodHandle)
OPDEF(INTOP_NEWOBJ_VT, "newobj.vt", 5, 1, 1, InterpOpMethodHandle)
Expand Down
50 changes: 44 additions & 6 deletions src/coreclr/vm/interpexec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
#include "gcenv.h"
#include "interpexec.h"
#include "callstubgenerator.h"
#include "frames.h"

// for numeric_limits
#include <limits>

void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet)
void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet, PCODE target)
{
CONTRACTL
{
Expand Down Expand Up @@ -44,7 +45,8 @@ void InvokeCompiledMethod(MethodDesc *pMD, int8_t *pArgs, int8_t *pRet)
}
}

pHeader->SetTarget(pMD->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY)); // The method to call
// Interpreter-FIXME: Potential race condition if a single CallStubHeader is reused for multiple targets.
pHeader->SetTarget(target); // The method to call

pHeader->Invoke(pHeader->Routines, pArgs, pRet, pHeader->TotalStackSize);
}
Expand Down Expand Up @@ -163,10 +165,11 @@ static OBJECTREF CreateMultiDimArray(MethodTable* arrayClass, int8_t* stack, int
template <typename THelper> static THelper GetPossiblyIndirectHelper(void* dataItem)
{
size_t helperDirectOrIndirect = (size_t)dataItem;
if (helperDirectOrIndirect & INTERP_INDIRECT_HELPER_TAG)
return *(THelper *)(helperDirectOrIndirect & ~INTERP_INDIRECT_HELPER_TAG);
if (helperDirectOrIndirect & INTERP_DIRECT_HELPER_TAG)
// Clear the direct flag and then raise the thumb bit as needed
return (THelper)PINSTRToPCODE((TADDR)(helperDirectOrIndirect & ~INTERP_DIRECT_HELPER_TAG));
else
return (THelper)helperDirectOrIndirect;
return *(THelper *)helperDirectOrIndirect;
}

// At present our behavior for float to int conversions is to perform a saturating conversion down to either 32 or 64 bits
Expand Down Expand Up @@ -1827,6 +1830,41 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
break;
}

case INTOP_CALL_PINVOKE:
{
// This opcode handles p/invokes that don't use a managed wrapper for marshaling. These
// calls are special in that they need an InlinedCallFrame in order for proper EH to happen

returnOffset = ip[1];
callArgsOffset = ip[2];
methodSlot = ip[3];
int32_t targetAddrSlot = ip[4];
int32_t indirectFlag = ip[5];

ip += 6;
targetMethod = (MethodDesc*)pMethod->pDataItems[methodSlot];
PCODE callTarget = indirectFlag
? *(PCODE *)pMethod->pDataItems[targetAddrSlot]
: (PCODE)pMethod->pDataItems[targetAddrSlot];

InlinedCallFrame inlinedCallFrame;
inlinedCallFrame.m_pCallerReturnAddress = (TADDR)ip;
inlinedCallFrame.m_pCallSiteSP = pFrame;
inlinedCallFrame.m_pCalleeSavedFP = (TADDR)stack;
inlinedCallFrame.m_pThread = GetThread();
inlinedCallFrame.m_Datum = NULL;
inlinedCallFrame.Push();

{
GCX_PREEMP();
InvokeCompiledMethod(targetMethod, stack + callArgsOffset, stack + returnOffset, callTarget);
}

inlinedCallFrame.Pop();

break;
}

case INTOP_CALL:
{
returnOffset = ip[1];
Expand Down Expand Up @@ -1860,7 +1898,7 @@ void InterpExecMethod(InterpreterFrame *pInterpreterFrame, InterpMethodContextFr
if (targetIp == NULL)
{
// If we didn't get the interpreter code pointer setup, then this is a method we need to invoke as a compiled method.
InvokeCompiledMethod(targetMethod, stack + callArgsOffset, stack + returnOffset);
InvokeCompiledMethod(targetMethod, stack + callArgsOffset, stack + returnOffset, targetMethod->GetMultiCallableAddrOfCode(CORINFO_ACCESS_ANY));
break;
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/tests/JIT/interpreter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
project (pinvoke)

include_directories(${INC_PLATFORM_DIR})

set(SOURCES pinvoke.cpp)

# add the executable
add_library (pinvoke SHARED ${SOURCES})

# add the install targets
install (TARGETS pinvoke DESTINATION bin)
98 changes: 98 additions & 0 deletions src/tests/JIT/interpreter/Interpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -969,6 +969,11 @@ public static void RunInterpreterTests()

Console.WriteLine("IntPtr.Zero: {0}, UIntPtr.Zero: {1}", IntPtr.Zero, UIntPtr.Zero);

Console.WriteLine("TestPInvoke");
if (!TestPInvoke())
Environment.FailFast(null);

// For stackwalking validation
System.GC.Collect();

Console.WriteLine("All tests passed successfully!");
Expand Down Expand Up @@ -2383,6 +2388,99 @@ static object BoxedSubtraction(object lhs, object rhs)
return (int)lhs - (int)rhs;
}

[DllImport("pinvoke", CallingConvention = CallingConvention.Cdecl)]
public static extern int sumTwoInts(int x, int y);
[DllImport("pinvoke", CallingConvention = CallingConvention.Cdecl)]
public static extern double sumTwoDoubles(double x, double y);
[DllImport("pinvoke", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int writeToStdout(string s);
[DllImport("missingLibrary", CallingConvention = CallingConvention.Cdecl)]
public static extern void missingPInvoke();
[DllImport("missingLibrary", CallingConvention = CallingConvention.Cdecl)]
public static extern void missingPInvokeWithMarshaling(string s);

public static bool TestPInvoke()
{
if (sumTwoInts(1, 2) != 3)
return false;

double summed = sumTwoDoubles(1, 2);
if (summed != 3)
return false;

// Test marshaling wrappers
writeToStdout("Hello world from pinvoke.dll!writeToStdout\n");

/* fails, with output:
Assert failure(PID 32748 [0x00007fec], Thread: 24256 [0x5ec0]): pMD == codeInfo.GetMethodDesc()

CORECLR! AppendExceptionStackFrame + 0x331 (0x00007ff9`85879b71)
SYSTEM.PRIVATE.CORELIB! <no symbol> + 0x0 (0x00007ff9`80d91f30)
SYSTEM.PRIVATE.CORELIB! <no symbol> + 0x0 (0x00007ff9`80d926b7)
SYSTEM.PRIVATE.CORELIB! <no symbol> + 0x0 (0x00007ff9`80d92289)
CORECLR! CallDescrWorkerInternal + 0x83 (0x00007ff9`859811c3)
CORECLR! CallDescrWorkerWithHandler + 0x130 (0x00007ff9`854755c0)
CORECLR! DispatchCallSimple + 0x26C (0x00007ff9`8547655c)
CORECLR! DispatchManagedException + 0x388 (0x00007ff9`85872998)
CORECLR! DispatchManagedException + 0x67 (0x00007ff9`858725a7)
CORECLR! UnwindAndContinueRethrowHelperAfterCatch + 0x1F8 (0x00007ff9`851be5e8)
File: Z:\runtime\src\coreclr\vm\exceptionhandling.cpp:3032
Image: Z:\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\corerun.exe

pMD is TestPInvoke (correct) and codeInfo.GetMethodDesc() is Main (wrong)
*/
/*
bool caught = false;
try {
Console.WriteLine("calling missingPInvoke");
missingPInvoke();
return false;
} catch (DllNotFoundException) {
Console.WriteLine("caught #1");
caught = true;
}

if (!caught)
return false;
*/

/* fails, with output:
calling missingPInvokeWithMarshaling
caught #2

Assert failure(PID 59772 [0x0000e97c], Thread: 24864 [0x6120]): ohThrowable

CORECLR! PreStubWorker$catch$10 + 0x93 (0x00007ff9`580972b3)
CORECLR! CallSettingFrame_LookupContinuationIndex + 0x20 (0x00007ff9`57f32e70)
CORECLR! _FrameHandler4::CxxCallCatchBlock + 0x1DE (0x00007ff9`57f1e83e)
NTDLL! RtlCaptureContext2 + 0x4A6 (0x00007ffa`b7e46606)
CORECLR! PreStubWorker + 0x4F8 (0x00007ff9`5789dd78)
CORECLR! ThePreStub + 0x55 (0x00007ff9`57ec29c5)
CORECLR! CallJittedMethodRetVoid + 0x14 (0x00007ff9`57ec0f34)
CORECLR! InvokeCompiledMethod + 0x5D7 (0x00007ff9`57afaf67)
CORECLR! InterpExecMethod + 0x84BB (0x00007ff9`57af68cb)
CORECLR! ExecuteInterpretedMethod + 0x11B (0x00007ff9`5789c77b)
File: Z:\runtime\src\coreclr\vm\prestub.cpp:1965
Image: Z:\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\corerun.exe
*/
/*
bool caught2 = false;
try {
Console.WriteLine("calling missingPInvokeWithMarshaling");
missingPInvokeWithMarshaling("test");
return false;
} catch (DllNotFoundException) {
Console.WriteLine("caught #2");
caught2 = true;
}

if (!caught2)
return false;
*/

return true;
}

public static bool TestArray()
{
// sbyte
Expand Down
3 changes: 3 additions & 0 deletions src/tests/JIT/interpreter/Interpreter.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@
<ItemGroup>
<Compile Include="Interpreter.cs" />
</ItemGroup>
<ItemGroup>
<CMakeProjectReference Include="CMakeLists.txt" />
</ItemGroup>
</Project>
3 changes: 3 additions & 0 deletions src/tests/JIT/interpreter/InterpreterTester.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
<ItemGroup>
<Compile Include="InterpreterTester.cs" />
</ItemGroup>
<ItemGroup>
<CMakeProjectReference Include="CMakeLists.txt" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(TestSourceDir)Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)Interpreter.csproj">
Expand Down
23 changes: 23 additions & 0 deletions src/tests/JIT/interpreter/pinvoke.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#include "stdio.h"
#include <stdlib.h>
#include <platformdefines.h>

#define EXPORT_IT extern "C" DLL_EXPORT

EXPORT_IT void writeToStdout (const char *str)
{
puts(str);
}

EXPORT_IT int sumTwoInts (int x, int y)
{
return x + y;
}

EXPORT_IT double sumTwoDoubles (double x, double y)
{
return x + y;
}
Loading