Skip to content

Commit 8fcd3d1

Browse files
committed
Try a new approach
1 parent cb18670 commit 8fcd3d1

File tree

2 files changed

+60
-13
lines changed

2 files changed

+60
-13
lines changed

src/coreclr/vm/dllimportcallback.cpp

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,22 @@ UMEntryThunkData * GetMostRecentUMEntryThunkData()
221221
}
222222
#endif
223223

224+
static void PatchUMEntryPrecodeIfNecessary(UMEntryThunkData * pUMEntryThunkData, PCODE callTarget)
225+
{
226+
#ifdef FEATURE_INTERPRETER
227+
// HACK: We currently rely on the thread-local stash in TheUMEntryPrestubWorker for proper operation
228+
// of reverse p/invoke IL stubs in the interpreter, so we can't patch the precode in this scenario.
229+
// Instead, every reverse p/invoke will go through TheUMEntryPrestubWorker.
230+
MethodDesc *pMD = NonVirtualEntry2MethodDesc(callTarget);
231+
if (pMD && pMD->GetInterpreterCode())
232+
return;
233+
#endif
234+
235+
// NOTE: This may be run concurrently by multiple threads, but it should be safe since we will just be
236+
// setting the target of the precode to the same thing multiple times in a row.
237+
pUMEntryThunkData->PatchPrecode();
238+
}
239+
224240
PCODE TheUMEntryPrestubWorker(UMEntryThunkData * pUMEntryThunkData)
225241
{
226242
STATIC_CONTRACT_THROWS;
@@ -240,23 +256,36 @@ PCODE TheUMEntryPrestubWorker(UMEntryThunkData * pUMEntryThunkData)
240256
if (pUMEntryThunkData->IsCollectedDelegate())
241257
CallbackOnCollectedDelegate(pUMEntryThunkData);
242258

243-
INSTALL_MANAGED_EXCEPTION_DISPATCHER;
244-
// this method is called by stubs which are called by managed code,
245-
// so we need an unwind and continue handler so that our internal
246-
// exceptions don't leak out into managed code.
247-
INSTALL_UNWIND_AND_CONTINUE_HANDLER;
248-
259+
PCODE callTarget = (PCODE)0;
249260
#ifdef FEATURE_INTERPRETER
250261
// HACK: Stash the entry thunk data address so that the interpreter can recover it.
251262
// The InterpreterStub overwrites the register that normally would contain this address.
252263
t_MostRecentUMEntryThunkData = pUMEntryThunkData;
264+
265+
// See whether another thread has already prepared the IL stub for the reverse p/invoke.
266+
callTarget = pUMEntryThunkData->GetCachedCallTarget();
253267
#endif
254-
pUMEntryThunkData->RunTimeInit();
255268

256-
UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
257-
UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
269+
// We don't have a pre-prepared reverse p/invoke, and might be racing with another thread.
270+
if (!callTarget)
271+
{
272+
INSTALL_MANAGED_EXCEPTION_DISPATCHER;
273+
// this method is called by stubs which are called by managed code,
274+
// so we need an unwind and continue handler so that our internal
275+
// exceptions don't leak out into managed code.
276+
INSTALL_UNWIND_AND_CONTINUE_HANDLER;
277+
278+
pUMEntryThunkData->RunTimeInit();
279+
callTarget = pUMEntryThunkData->GetCachedCallTarget();
280+
// We're likely to be the first thread to have gotten here for this UM entry thunk, so make
281+
// sure that the precode is patched to point to the IL stub instead of us, if necessary.
282+
PatchUMEntryPrecodeIfNecessary(pUMEntryThunkData, callTarget);
283+
284+
UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
285+
UNINSTALL_MANAGED_EXCEPTION_DISPATCHER;
286+
}
258287

259-
return (PCODE)pUMEntryThunkData->GetCode();
288+
return callTarget;
260289
}
261290

262291
UMEntryThunkData* UMEntryThunkData::CreateUMEntryThunk()

src/coreclr/vm/dllimportcallback.h

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ class UMEntryThunk : private StubPrecode
134134
PTR_UMEntryThunkData GetData() const
135135
{
136136
LIMITED_METHOD_CONTRACT;
137-
137+
138138
return dac_cast<PTR_UMEntryThunkData>(GetSecretParam());
139139
}
140140
};
@@ -148,6 +148,9 @@ class UMEntryThunkData
148148
// if m_pObjectHandle is non-NULL, this field is still set to help with diagnostic of call on collected delegate crashes
149149
// but it may not have the correct value.
150150
PCODE m_pManagedTarget;
151+
// The native code to tailcall. May or may not match what the UM entry precode has been patched to call directly.
152+
// This is populated by RunTimeInit at the end of execution.
153+
PCODE m_pCachedCallTarget;
151154

152155
// This is used for debugging and profiling.
153156
PTR_MethodDesc m_pMD;
@@ -200,6 +203,7 @@ class UMEntryThunkData
200203
m_pManagedTarget = pManagedTarget;
201204
m_pObjectHandle = pObjectHandle;
202205
m_pUMThunkMarshInfo = pUMThunkMarshInfo;
206+
m_pCachedCallTarget = (PCODE)0;
203207

204208
m_pMD = pMD;
205209

@@ -214,7 +218,20 @@ class UMEntryThunkData
214218

215219
void Terminate();
216220

217-
VOID RunTimeInit()
221+
PCODE GetCachedCallTarget()
222+
{
223+
STANDARD_VM_CONTRACT;
224+
return m_pCachedCallTarget;
225+
}
226+
227+
void PatchPrecode()
228+
{
229+
STANDARD_VM_CONTRACT;
230+
231+
m_pUMEntryThunk->SetTargetUnconditional(m_pCachedCallTarget);
232+
}
233+
234+
void RunTimeInit()
218235
{
219236
STANDARD_VM_CONTRACT;
220237

@@ -227,7 +244,8 @@ class UMEntryThunkData
227244
if (m_pObjectHandle == NULL && m_pManagedTarget == (TADDR)0)
228245
m_pManagedTarget = m_pMD->GetMultiCallableAddrOfCode();
229246

230-
m_pUMEntryThunk->SetTargetUnconditional(m_pUMThunkMarshInfo->GetExecStubEntryPoint());
247+
// FIXME: Do we need to use atomics here?
248+
m_pCachedCallTarget = m_pUMThunkMarshInfo->GetExecStubEntryPoint();
231249

232250
#ifdef _DEBUG
233251
m_state = kRunTimeInited;

0 commit comments

Comments
 (0)