Skip to content

Commit 3c94cde

Browse files
authored
win-x86: Replace "ret n" thunks with assembly code (dotnet#115089)
Replace x86 COM "ret n" thunks with assembly code that emulates "ret <n>" for an "<n>" specified using a variable value stored in register.
1 parent 29e3af6 commit 3c94cde

File tree

10 files changed

+46
-172
lines changed

10 files changed

+46
-172
lines changed

src/coreclr/inc/CrstTypes.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,6 @@ Crst MethodTableExposedObject
208208
Unordered
209209
End
210210

211-
Crst RetThunkCache
212-
AcquiredBefore LoaderHeap
213-
End
214-
215211
Crst FuncPtrStubs
216212
AcquiredBefore IbcProfile LoaderHeap UniqueStack CodeFragmentHeap JumpStubCache
217213
End

src/coreclr/inc/crsttypes_generated.h

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -96,30 +96,29 @@ enum CrstType
9696
CrstReadyToRunEntryPointToMethodDescMap = 78,
9797
CrstReflection = 79,
9898
CrstReJITGlobalRequest = 80,
99-
CrstRetThunkCache = 81,
100-
CrstSigConvert = 82,
101-
CrstSingleUseLock = 83,
102-
CrstStressLog = 84,
103-
CrstStubCache = 85,
104-
CrstStubDispatchCache = 86,
105-
CrstSyncBlockCache = 87,
106-
CrstSyncHashLock = 88,
107-
CrstSystemDomain = 89,
108-
CrstSystemDomainDelayedUnloadList = 90,
109-
CrstThreadIdDispenser = 91,
110-
CrstThreadLocalStorageLock = 92,
111-
CrstThreadStore = 93,
112-
CrstTieredCompilation = 94,
113-
CrstTypeEquivalenceMap = 95,
114-
CrstTypeIDMap = 96,
115-
CrstUMEntryThunkCache = 97,
116-
CrstUMEntryThunkFreeListLock = 98,
117-
CrstUniqueStack = 99,
118-
CrstUnresolvedClassLock = 100,
119-
CrstUnwindInfoTableLock = 101,
120-
CrstVSDIndirectionCellLock = 102,
121-
CrstWrapperTemplate = 103,
122-
kNumberOfCrstTypes = 104
99+
CrstSigConvert = 81,
100+
CrstSingleUseLock = 82,
101+
CrstStressLog = 83,
102+
CrstStubCache = 84,
103+
CrstStubDispatchCache = 85,
104+
CrstSyncBlockCache = 86,
105+
CrstSyncHashLock = 87,
106+
CrstSystemDomain = 88,
107+
CrstSystemDomainDelayedUnloadList = 89,
108+
CrstThreadIdDispenser = 90,
109+
CrstThreadLocalStorageLock = 91,
110+
CrstThreadStore = 92,
111+
CrstTieredCompilation = 93,
112+
CrstTypeEquivalenceMap = 94,
113+
CrstTypeIDMap = 95,
114+
CrstUMEntryThunkCache = 96,
115+
CrstUMEntryThunkFreeListLock = 97,
116+
CrstUniqueStack = 98,
117+
CrstUnresolvedClassLock = 99,
118+
CrstUnwindInfoTableLock = 100,
119+
CrstVSDIndirectionCellLock = 101,
120+
CrstWrapperTemplate = 102,
121+
kNumberOfCrstTypes = 103
123122
};
124123

125124
#endif // __CRST_TYPES_INCLUDED
@@ -211,7 +210,6 @@ int g_rgCrstLevelMap[] =
211210
9, // CrstReadyToRunEntryPointToMethodDescMap
212211
7, // CrstReflection
213212
15, // CrstReJITGlobalRequest
214-
3, // CrstRetThunkCache
215213
3, // CrstSigConvert
216214
4, // CrstSingleUseLock
217215
-1, // CrstStressLog
@@ -320,7 +318,6 @@ LPCSTR g_rgCrstNameMap[] =
320318
"CrstReadyToRunEntryPointToMethodDescMap",
321319
"CrstReflection",
322320
"CrstReJITGlobalRequest",
323-
"CrstRetThunkCache",
324321
"CrstSigConvert",
325322
"CrstSingleUseLock",
326323
"CrstStressLog",

src/coreclr/vm/clrtocomcall.cpp

Lines changed: 0 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -950,76 +950,3 @@ BOOL CLRToCOMMethodFrame::TraceFrame_Impl(Thread *thread, BOOL fromPatch,
950950

951951
return TRUE;
952952
}
953-
954-
#ifdef TARGET_X86
955-
956-
#ifndef DACCESS_COMPILE
957-
958-
CrstStatic CLRToCOMCall::s_RetThunkCacheCrst;
959-
SHash<CLRToCOMCall::RetThunkSHashTraits> *CLRToCOMCall::s_pRetThunkCache = NULL;
960-
961-
// One time init.
962-
void CLRToCOMCall::Init()
963-
{
964-
CONTRACTL
965-
{
966-
THROWS;
967-
GC_NOTRIGGER;
968-
MODE_ANY;
969-
}
970-
CONTRACTL_END;
971-
972-
s_RetThunkCacheCrst.Init(CrstRetThunkCache);
973-
}
974-
975-
LPVOID CLRToCOMCall::GetRetThunk(UINT numStackBytes)
976-
{
977-
STANDARD_VM_CONTRACT;
978-
979-
LPVOID pRetThunk = NULL;
980-
CrstHolder crst(&s_RetThunkCacheCrst);
981-
982-
// Lazily allocate the ret thunk cache.
983-
if (s_pRetThunkCache == NULL)
984-
s_pRetThunkCache = new SHash<RetThunkSHashTraits>();
985-
986-
const RetThunkCacheElement *pElement = s_pRetThunkCache->LookupPtr(numStackBytes);
987-
if (pElement != NULL)
988-
{
989-
pRetThunk = pElement->m_pRetThunk;
990-
}
991-
else
992-
{
993-
// cache miss -> create a new thunk
994-
AllocMemTracker dummyAmTracker;
995-
size_t thunkSize = (numStackBytes == 0) ? 1 : 3;
996-
pRetThunk = (LPVOID)dummyAmTracker.Track(SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->AllocMem(S_SIZE_T(thunkSize)));
997-
998-
ExecutableWriterHolder<BYTE> thunkWriterHolder((BYTE *)pRetThunk, thunkSize);
999-
BYTE *pThunkRW = thunkWriterHolder.GetRW();
1000-
1001-
if (numStackBytes == 0)
1002-
{
1003-
pThunkRW[0] = 0xc3;
1004-
}
1005-
else
1006-
{
1007-
pThunkRW[0] = 0xc2;
1008-
*(USHORT *)&pThunkRW[1] = (USHORT)numStackBytes;
1009-
}
1010-
1011-
// add it to the cache
1012-
RetThunkCacheElement element;
1013-
element.m_cbStack = numStackBytes;
1014-
element.m_pRetThunk = pRetThunk;
1015-
s_pRetThunkCache->Add(element);
1016-
1017-
dummyAmTracker.SuppressRelease();
1018-
}
1019-
1020-
return pRetThunk;
1021-
}
1022-
1023-
#endif // !DACCESS_COMPILE
1024-
1025-
#endif // TARGET_X86

src/coreclr/vm/clrtocomcall.h

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -30,42 +30,8 @@ class CLRToCOMCall
3030
static PCODE GetStubForILStub(MethodDesc* pMD, MethodDesc** ppStubMD);
3131

3232
static CLRToCOMCallInfo *PopulateCLRToCOMCallMethodDesc(MethodDesc* pMD, DWORD* pdwStubFlags);
33-
34-
#ifdef TARGET_X86
35-
static void Init();
36-
static LPVOID GetRetThunk(UINT numStackBytes);
37-
#endif // TARGET_X86
3833
private:
3934
CLRToCOMCall(); // prevent "new"'s on this class
40-
41-
#ifdef TARGET_X86
42-
struct RetThunkCacheElement
43-
{
44-
RetThunkCacheElement()
45-
{
46-
LIMITED_METHOD_CONTRACT;
47-
m_cbStack = 0;
48-
m_pRetThunk = NULL;
49-
}
50-
51-
UINT m_cbStack;
52-
LPVOID m_pRetThunk;
53-
};
54-
55-
class RetThunkSHashTraits : public NoRemoveSHashTraits< DefaultSHashTraits<RetThunkCacheElement> >
56-
{
57-
public:
58-
typedef UINT key_t;
59-
static key_t GetKey(element_t e) { LIMITED_METHOD_CONTRACT; return e.m_cbStack; }
60-
static BOOL Equals(key_t k1, key_t k2) { LIMITED_METHOD_CONTRACT; return (k1 == k2); }
61-
static count_t Hash(key_t k) { LIMITED_METHOD_CONTRACT; return (count_t)(size_t)k; }
62-
static const element_t Null() { LIMITED_METHOD_CONTRACT; return RetThunkCacheElement(); }
63-
static bool IsNull(const element_t &e) { LIMITED_METHOD_CONTRACT; return (e.m_pRetThunk == NULL); }
64-
};
65-
66-
static SHash<RetThunkSHashTraits> *s_pRetThunkCache;
67-
static CrstStatic s_RetThunkCacheCrst;
68-
#endif // TARGET_X86
6935
};
7036

7137
#endif // __CLRTOCOMCALL_H__

src/coreclr/vm/dllimport.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5783,9 +5783,11 @@ void CreateCLRToDispatchCOMStub(
57835783
iLCIDArg);
57845784

57855785
_ASSERTE(pMD->IsCLRToCOMCall()); // no generic disp-calls
5786-
((CLRToCOMCallMethodDesc *)pMD)->InitRetThunk();
5787-
}
57885786

5787+
#ifdef TARGET_X86
5788+
((CLRToCOMCallMethodDesc *)pMD)->InitStackPop();
5789+
#endif
5790+
}
57895791

57905792
#endif // FEATURE_COMINTEROP
57915793

src/coreclr/vm/i386/asmconstants.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,8 +227,8 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__FrameHandlerExRecord__m_pEntryFrame == offsetof(
227227
#define CLRToCOMCallMethodDesc__m_pCLRToCOMCallInfo DBG_FRE(0x20, 0xC)
228228
ASMCONSTANTS_C_ASSERT(CLRToCOMCallMethodDesc__m_pCLRToCOMCallInfo == offsetof(CLRToCOMCallMethodDesc, m_pCLRToCOMCallInfo))
229229

230-
#define CLRToCOMCallInfo__m_pRetThunk 0x10
231-
ASMCONSTANTS_C_ASSERT(CLRToCOMCallInfo__m_pRetThunk == offsetof(CLRToCOMCallInfo, m_pRetThunk))
230+
#define CLRToCOMCallInfo__m_cbStackPop 0x0e
231+
ASMCONSTANTS_C_ASSERT(CLRToCOMCallInfo__m_cbStackPop == offsetof(CLRToCOMCallInfo, m_cbStackPop))
232232

233233
#define COMMETHOD_PREPAD_ASM 8
234234
ASMCONSTANTS_C_ASSERT(COMMETHOD_PREPAD_ASM == COMMETHOD_PREPAD)

src/coreclr/vm/i386/asmhelpers.asm

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1291,14 +1291,19 @@ _GenericCLRToCOMCallStub@0 proc public
12911291

12921292
; Get pCLRToCOMCallInfo for return thunk
12931293
mov ecx, [ebx + CLRToCOMCallMethodDesc__m_pCLRToCOMCallInfo]
1294+
; Get size of arguments to pop
1295+
movzx ecx, word ptr [ecx + CLRToCOMCallInfo__m_cbStackPop]
1296+
; Get the return address, pushed registers on stack are 24 bytes big
1297+
mov ebx, [esp + 24]
1298+
; Set the return address on stack at the last stack slot
1299+
mov [esp + ecx + 24], ebx
12941300

12951301
STUB_EPILOG_RETURN
12961302

1297-
; Tailcall return thunk
1298-
jmp [ecx + CLRToCOMCallInfo__m_pRetThunk]
1303+
; Move esp to point to the last stack slot where we put the return
1304+
; address earlier
1305+
lea esp, [esp + ecx]
12991306

1300-
; This will never be executed. It is just to help out stack-walking logic
1301-
; which disassembles the epilog to unwind the stack.
13021307
ret
13031308

13041309
_GenericCLRToCOMCallStub@0 endp

src/coreclr/vm/interoputil.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3681,9 +3681,6 @@ void InitializeComInterop()
36813681

36823682
InitializeSListHead(&RCW::s_RCWStandbyList);
36833683
ComCall::Init();
3684-
#ifdef TARGET_X86
3685-
CLRToCOMCall::Init();
3686-
#endif
36873684
CtxEntryCache::Init();
36883685
ComCallWrapperTemplate::Init();
36893686
#ifdef _DEBUG

src/coreclr/vm/method.cpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3964,26 +3964,6 @@ PrecodeType MethodDesc::GetPrecodeType()
39643964

39653965
#endif // !DACCESS_COMPILE
39663966

3967-
#ifdef FEATURE_COMINTEROP
3968-
#ifndef DACCESS_COMPILE
3969-
void CLRToCOMCallMethodDesc::InitRetThunk()
3970-
{
3971-
WRAPPER_NO_CONTRACT;
3972-
3973-
#ifdef TARGET_X86
3974-
if (m_pCLRToCOMCallInfo->m_pRetThunk != NULL)
3975-
return;
3976-
3977-
UINT numStackBytes = CbStackPop();
3978-
3979-
LPVOID pRetThunk = CLRToCOMCall::GetRetThunk(numStackBytes);
3980-
3981-
InterlockedCompareExchangeT<void *>(&m_pCLRToCOMCallInfo->m_pRetThunk, pRetThunk, NULL);
3982-
#endif // TARGET_X86
3983-
}
3984-
#endif //!DACCESS_COMPILE
3985-
#endif // FEATURE_COMINTEROP
3986-
39873967
#ifndef DACCESS_COMPILE
39883968
void MethodDesc::PrepareForUseAsADependencyOfANativeImageWorker()
39893969
{

src/coreclr/vm/method.hpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3342,6 +3342,8 @@ struct CLRToCOMCallInfo
33423342
// Size of outgoing arguments (on stack). This is currently used only
33433343
// on x86 when we have an InlinedCallFrame representing a CLR->COM call.
33443344
WORD m_cbStackArgumentSize;
3345+
// Size of incoming arguments (on stack).
3346+
WORD m_cbStackPop;
33453347

33463348
void InitStackArgumentSize()
33473349
{
@@ -3369,9 +3371,6 @@ struct CLRToCOMCallInfo
33693371
_ASSERTE(m_cbStackArgumentSize != 0xFFFF);
33703372
return m_cbStackArgumentSize;
33713373
}
3372-
3373-
LPVOID m_pRetThunk;
3374-
33753374
#else // TARGET_X86
33763375
void InitStackArgumentSize()
33773376
{
@@ -3396,7 +3395,6 @@ class CLRToCOMCallMethodDesc : public MethodDesc
33963395
public:
33973396
CLRToCOMCallInfo *m_pCLRToCOMCallInfo; // initialized in code:CLRToCOMCall.PopulateCLRToCOMCallMethodDesc
33983397

3399-
void InitRetThunk();
34003398
void InitComEventCallInfo();
34013399

34023400
PCODE * GetAddrOfILStubField()
@@ -3446,6 +3444,12 @@ class CLRToCOMCallMethodDesc : public MethodDesc
34463444
LIMITED_METHOD_CONTRACT;
34473445
m_pCLRToCOMCallInfo->SetStackArgumentSize(cbDstBuffer);
34483446
}
3447+
3448+
void InitStackPop()
3449+
{
3450+
LIMITED_METHOD_CONTRACT;
3451+
m_pCLRToCOMCallInfo->m_cbStackPop = (WORD)CbStackPop();
3452+
}
34493453
#else // TARGET_X86
34503454
void SetStackArgumentSize(WORD cbDstBuffer)
34513455
{

0 commit comments

Comments
 (0)