Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -3220,8 +3220,12 @@ private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORIN
ModuleToken moduleToken = new ModuleToken(ecmaMethod.Module, ecmaMethod.Handle);
MethodWithToken methodWithToken = new MethodWithToken(ecmaMethod, moduleToken, constrainedType: null, unboxing: false, genericContextObject: null);

if ((ecmaMethod.GetPInvokeMethodCallingConventions() & UnmanagedCallingConventions.IsSuppressGcTransition) != 0)
if (((ecmaMethod.GetPInvokeMethodCallingConventions() & UnmanagedCallingConventions.IsSuppressGcTransition) != 0)
|| _compilation.NodeFactory.Target.IsWasm)
{
// Suppress GC transition pinvokes are called directly, since we can't do a gc transition at this point.
// On Wasm, we also call directly, as the runtime doesn't generate stubs for the pinvoke calls which can produce errors. Instead
// the error is produced as we fixup the method in the first place.
Comment on lines +3226 to +3228
pLookup.addr = (void*)ObjectToHandle(_compilation.SymbolNodeFactory.GetPInvokeTargetNode(methodWithToken));
pLookup.accessType = InfoAccessType.IAT_PVALUE;
}
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14313,6 +14313,7 @@ BOOL LoadDynamicInfoEntry(Module *currentModule,
}
break;

#ifdef HAS_PINVOKE_IMPORT_PRECODE
case READYTORUN_FIXUP_IndirectPInvokeTarget:
{
MethodDesc *pMethod = ZapSig::DecodeMethod(currentModule, pInfoModule, pBlob);
Expand All @@ -14322,6 +14323,7 @@ BOOL LoadDynamicInfoEntry(Module *currentModule,
result = (size_t)(LPVOID)&(pMD->m_pPInvokeTarget);
}
break;
#endif // HAS_PINVOKE_IMPORT_PRECODE

case READYTORUN_FIXUP_PInvokeTarget:
{
Expand Down
79 changes: 71 additions & 8 deletions src/coreclr/vm/wasm/helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#define WASM_STRINGIFY_HELPER(value) #value
#define WASM_STRINGIFY(value) WASM_STRINGIFY_HELPER(value)
#define INLINED_PINVOKE_FROM_R2R 0

void ExecuteInterpretedMethodWithArgs_PortableEntryPoint(PCODE portableEntrypoint, TransitionBlock* block, size_t argsSize, int8_t* retBuff);

Expand Down Expand Up @@ -491,12 +492,21 @@ void InlinedCallFrame::UpdateRegDisplay_Impl(const PREGDISPLAY pRD, bool updateF
return;
}

pRD->pCurrentContext->InterpreterIP = *(DWORD *)&m_pCallerReturnAddress;

pRD->IsCallerContextValid = FALSE;

pRD->pCurrentContext->InterpreterSP = *(DWORD *)&m_pCallSiteSP;
pRD->pCurrentContext->InterpreterFP = *(DWORD *)&m_pCalleeSavedFP;
if (m_CallerReturnAddress == INLINED_PINVOKE_FROM_R2R)
{
pRD->pCurrentContext->InterpreterSP = m_pCallSiteSP;
pRD->pCurrentContext->InterpreterIP = GetWasmVirtualIPFromStackPointer(m_pCallSiteSP);
_ASSERTE(pRD->pCurrentContext->InterpreterIP != 0); // We should be in RyuJit compiled code here
pRD->pCurrentContext->InterpreterFP = GetWasmFramePointerFromStackPointer(m_pCallSiteSP, pRD->pCurrentContext->InterpreterIP);
}
Comment on lines +499 to +503
else
{
pRD->pCurrentContext->InterpreterIP = *(DWORD *)&m_pCallerReturnAddress;
pRD->pCurrentContext->InterpreterSP = *(DWORD *)&m_pCallSiteSP;
pRD->pCurrentContext->InterpreterFP = *(DWORD *)&m_pCalleeSavedFP;
}

#define CALLEE_SAVED_REGISTER(regname) pRD->pCurrentContextPointers->regname = NULL;
ENUM_CALLEE_SAVED_REGISTERS();
Expand Down Expand Up @@ -687,16 +697,69 @@ extern "C" void STDCALL GenericPInvokeCalliHelper(void)
PORTABILITY_ASSERT("GenericPInvokeCalliHelper is not implemented on wasm");
}

EXTERN_C void JIT_PInvokeBegin(InlinedCallFrame* pFrame)
// Does the pinvoke frame transition; the naked wrappers below have already set the wasm
// __stack_pointer global to sp so it is safe to run native code here.
EXTERN_C void JIT_PInvokeBeginImpl(void* sp, InlinedCallFrame* pFrame)
{
PORTABILITY_ASSERT("JIT_PInvokeBegin is not implemented on wasm");
Thread* pThread = GetThread();

// Initialize the JIT-provided frame storage, deriving its state from sp/pep since wasm
// has no machine registers to read the caller SP / return address from.
::new ((void*)pFrame) InlinedCallFrame();
pFrame->m_pCallSiteSP = sp;
pFrame->m_pCallerReturnAddress = INLINED_PINVOKE_FROM_R2R; // When this is tru the UpdateRegisters function will do all work based on m_pCallerReturnAddress
pFrame->m_pCalleeSavedFP = 0;
pFrame->m_pThread = pThread;
Comment on lines +708 to +712

// Link the frame and transition to preemptive GC mode for the native call.
pFrame->Push();
pThread->EnablePreemptiveGC();
}

EXTERN_C void JIT_PInvokeEnd(InlinedCallFrame* pFrame)
// R2R keeps its shadow SP in a local and leaves the __stack_pointer global stale, so publish
// the incoming sp to __stack_pointer before any native code runs and leave it there so the
// subsequent native pinvoke target is also safe.
extern "C" __attribute__((naked)) void JIT_PInvokeBegin(void* sp, InlinedCallFrame* pFrame, PCODE pep)
{
Comment on lines +722 to 723
PORTABILITY_ASSERT("JIT_PInvokeEnd is not implemented on wasm");
asm("local.get 0\n" /* sp */
"global.set __stack_pointer\n" /* __stack_pointer = sp before any native code runs */
"local.get 0\n" /* sp */
"local.get 1\n" /* pFrame */
"call %0\n"
"return" ::"i"(JIT_PInvokeBeginImpl));
}

#ifdef DEBUG
// Debug variant of these apis tests that sp and __stack_pointer are in sync
EXTERN_C void* JIT_PInvokeEndImpl(TADDR sp, TADDR stack_pointer_global_value, InlinedCallFrame* pFrame)
{
_ASSERTE(sp == stack_pointer_global_value);
Thread* pThread = (Thread*)pFrame->m_pThread;

// Transition back to cooperative GC mode and unlink the frame.
pThread->DisablePreemptiveGC();
pFrame->Pop();
}
Comment on lines +734 to +742

extern "C" __attribute__((naked)) void JIT_PInvokeEnd(void* sp, InlinedCallFrame* pFrame, PCODE pep)
{
asm("local.get 0\n" /* sp */
"global.set __stack_pointer\n" /* __stack_pointer = sp before any native code runs */
"local.get 1\n" /* pFrame */
"call %0\n"
"return" ::"i"(JIT_PInvokeEndImpl));
Comment on lines +746 to +750
}
#else
extern "C" void JIT_PInvokeEnd(void* sp, InlinedCallFrame* pFrame, PCODE pep)
{
Thread* pThread = (Thread*)pFrame->m_pThread;
Comment on lines +753 to +755

// Transition back to cooperative GC mode and unlink the frame.
pThread->DisablePreemptiveGC();
pFrame->Pop();
}
#endif

extern "C" void STDCALL JIT_StackProbe()
{
PORTABILITY_ASSERT("JIT_StackProbe is not implemented on wasm");
Expand Down
Loading