Skip to content

Commit 5649739

Browse files
UnsafeAccessorAttribute non-generic support (#86932)
* CoreCLR and NativeAOT * Add UnsafeAccessorAttribute API * Implement IL generation for all accessor paths * Implement static/instance field lookup - non-generic * Implement static/instance method lookup - non-generic * Defined ambiguity logic with respect to custom modifiers. - First pass ignore custom modifiers - If ambiguity detected, rerun algorithm but require precise matching of custom modifiers. - If there is no clear match throw AmbiguousImplementationException. * Cleanup memory management confusion with ILStubResolver. * Fix non-standard C++ * Remove CORINFO_MODULE_ALLACCESS scope * Remove enum METHOD_TYPE. * Update BOTR on TypeDesc
1 parent 4302b80 commit 5649739

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2567
-763
lines changed

docs/design/coreclr/botr/type-loader.md

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ If `MyClass` fails to load, for example because it's supposed to be defined in a
100100

101101
## Key Data Structures
102102

103-
The most universal type designation in the CLR is the `TypeHandle`. It's an abstract entity which encapsulates a pointer to either a `MethodTable` (representing "ordinary" types like `System.Object` or `List<string>`) or a `TypeDesc` (representing byrefs, pointers, function pointers, arrays, and generic variables). It constitutes the identity of a type in that two handles are equal if and only if they represent the same type. To save space, the fact that a `TypeHandle` contains a `TypeDesc` is indicated by setting the second lowest bit of the pointer to 1 (i.e. (ptr | 2)) instead of using additional flags<sup>2</sup>. `TypeDesc` is "abstract" and has the following inheritance hierarchy.
103+
The most universal type designation in the CLR is the `TypeHandle`. It's an abstract entity which encapsulates a pointer to either a `MethodTable` (representing "ordinary" types like `System.Object` or `List<string>`) or a `TypeDesc` (representing byrefs, pointers, function pointers and generic variables). It constitutes the identity of a type in that two handles are equal if and only if they represent the same type. To save space, the fact that a `TypeHandle` contains a `TypeDesc` is indicated by setting the second lowest bit of the pointer to 1 (i.e. (ptr | 2)) instead of using additional flags<sup>2</sup>. `TypeDesc` is "abstract" and has the following inheritance hierarchy.
104104

105105
![Figure 2](images/typeloader-fig2.png)
106106

@@ -122,10 +122,6 @@ Represents a function pointer, essentially a variable-length list of type handle
122122

123123
This descriptor represents a byref and pointer types. Byrefs are the results of the `ref` and `out` C# keywords applied to method parameters<sup>3</sup> whereas pointer types are unmanaged pointers to data used in unsafe C# and managed C++.
124124

125-
**`ArrayTypeDesc`**
126-
127-
Represents array types. It is derived from `ParamTypeDesc` because arrays are also parameterized by a single parameter (the type of their element). This is opposed to generic instantiations whose number of parameters is variable.
128-
129125
**`MethodTable`**
130126

131127
This is by far the central data structure of the runtime. It represents any type which does not fall into one of the categories above (this includes primitive types, and generic types, both "open" and "closed"). It contains everything about the type that needs to be looked up quickly, such as its parent type, implemented interfaces, and the v-table.

src/coreclr/debug/ee/controller.cpp

Lines changed: 64 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2373,7 +2373,7 @@ bool DebuggerController::PatchTrace(TraceDestination *trace,
23732373
// trace->address is actually a MethodDesc* of the method that we'll
23742374
// soon JIT, so put a relative bp at offset zero in.
23752375
LOG((LF_CORDB, LL_INFO10000,
2376-
"Setting unjitted method patch in MethodDesc 0x%p %s\n", trace->GetMethodDesc(), trace->GetMethodDesc() ? trace->GetMethodDesc()->m_pszDebugMethodName : ""));
2376+
"Setting unjitted method patch in MethodDesc %p %s\n", trace->GetMethodDesc(), trace->GetMethodDesc() ? trace->GetMethodDesc()->m_pszDebugMethodName : ""));
23772377

23782378
// Note: we have to make sure to bind here. If this function is prejitted, this may be our only chance to get a
23792379
// DebuggerJITInfo and thereby cause a JITComplete callback.
@@ -2484,7 +2484,7 @@ bool DebuggerController::MatchPatch(Thread *thread,
24842484
}
24852485
}
24862486

2487-
LOG((LF_CORDB, LL_INFO100000, "DC::MP: Returning true"));
2487+
LOG((LF_CORDB, LL_INFO100000, "DC::MP: Returning true\n"));
24882488

24892489
return true;
24902490
}
@@ -3317,11 +3317,11 @@ BOOL DebuggerController::DispatchExceptionHook(Thread *thread,
33173317
}
33183318
CONTRACTL_END;
33193319

3320-
LOG((LF_CORDB, LL_INFO1000, "DC:: DispatchExceptionHook\n"));
3320+
LOG((LF_CORDB, LL_INFO1000, "DC::DEH: DispatchExceptionHook\n"));
33213321

33223322
if (!g_patchTableValid)
33233323
{
3324-
LOG((LF_CORDB, LL_INFO1000, "DC::DEH returning, no patch table.\n"));
3324+
LOG((LF_CORDB, LL_INFO1000, "DC::DEH: returning, no patch table.\n"));
33253325
return (TRUE);
33263326
}
33273327

@@ -3339,24 +3339,24 @@ BOOL DebuggerController::DispatchExceptionHook(Thread *thread,
33393339
DebuggerController *pNext = p->m_next;
33403340

33413341
if (p->m_exceptionHook
3342-
&& (p->m_thread == NULL || p->m_thread == thread) &&
3343-
tpr != TPR_IGNORE_AND_STOP)
3342+
&& (p->m_thread == NULL || p->m_thread == thread)
3343+
&& tpr != TPR_IGNORE_AND_STOP)
33443344
{
3345-
LOG((LF_CORDB, LL_INFO1000, "DC::DEH calling TEH...\n"));
3345+
LOG((LF_CORDB, LL_INFO1000, "DC::DEH: calling TEH...\n"));
33463346
tpr = p->TriggerExceptionHook(thread, context , pException);
3347-
LOG((LF_CORDB, LL_INFO1000, "DC::DEH ... returned.\n"));
3347+
LOG((LF_CORDB, LL_INFO1000, "DC::DEH: ... returned.\n"));
33483348

33493349
if (tpr == TPR_IGNORE_AND_STOP)
33503350
{
3351-
LOG((LF_CORDB, LL_INFO1000, "DC:: DEH: leaving early!\n"));
3351+
LOG((LF_CORDB, LL_INFO1000, "DC::DEH: leaving early!\n"));
33523352
break;
33533353
}
33543354
}
33553355

33563356
p = pNext;
33573357
}
33583358

3359-
LOG((LF_CORDB, LL_INFO1000, "DC:: DEH: returning 0x%x!\n", tpr));
3359+
LOG((LF_CORDB, LL_INFO1000, "DC::DEH: returning 0x%x!\n", tpr));
33603360

33613361
return (tpr != TPR_IGNORE_AND_STOP);
33623362
}
@@ -4725,11 +4725,11 @@ TP_RESULT DebuggerPatchSkip::TriggerExceptionHook(Thread *thread, CONTEXT * cont
47254725
SIZE_T *sp = (SIZE_T *) GetSP(context);
47264726

47274727
LOG((LF_CORDB, LL_INFO10000,
4728-
"Bypass call return address redirected from 0x%p\n", *sp));
4728+
"Bypass call return address redirected from %p\n", *sp));
47294729

47304730
*sp -= patchBypass - (BYTE*)m_address;
47314731

4732-
LOG((LF_CORDB, LL_INFO10000, "to 0x%p\n", *sp));
4732+
LOG((LF_CORDB, LL_INFO10000, "to %p\n", *sp));
47334733
#else
47344734
PORTABILITY_ASSERT("DebuggerPatchSkip::TriggerExceptionHook -- return address fixup NYI");
47354735
#endif
@@ -4739,7 +4739,7 @@ TP_RESULT DebuggerPatchSkip::TriggerExceptionHook(Thread *thread, CONTEXT * cont
47394739
{
47404740
// Fixup IP
47414741

4742-
LOG((LF_CORDB, LL_INFO10000, "Bypass instruction redirected from 0x%p\n", GetIP(context)));
4742+
LOG((LF_CORDB, LL_INFO10000, "Bypass instruction redirected from %p\n", GetIP(context)));
47434743

47444744
if (IsSingleStep(exception->ExceptionCode))
47454745
{
@@ -4786,9 +4786,9 @@ TP_RESULT DebuggerPatchSkip::TriggerExceptionHook(Thread *thread, CONTEXT * cont
47864786
((size_t)GetIP(context) > (size_t)patchBypass &&
47874787
(size_t)GetIP(context) <= (size_t)(patchBypass + MAX_INSTRUCTION_LENGTH + 1)))
47884788
{
4789-
LOG((LF_CORDB, LL_INFO10000, "Bypass instruction redirected because still in skip area.\n"));
4790-
LOG((LF_CORDB, LL_INFO10000, "m_fIsCall = %d, patchBypass = 0x%x, m_address = 0x%x\n",
4791-
m_instrAttrib.m_fIsCall, patchBypass, m_address));
4789+
LOG((LF_CORDB, LL_INFO10000, "Bypass instruction redirected because still in skip area.\n"
4790+
"\tm_fIsCall = %s, patchBypass = %p, m_address = %p\n",
4791+
(m_instrAttrib.m_fIsCall ? "true" : "false"), patchBypass, m_address));
47924792
SetIP(context, (PCODE)((BYTE *)GetIP(context) - (patchBypass - (BYTE *)m_address)));
47934793
}
47944794
else
@@ -4822,8 +4822,7 @@ TP_RESULT DebuggerPatchSkip::TriggerExceptionHook(Thread *thread, CONTEXT * cont
48224822
SetIP(context, (PCODE)((BYTE *)GetIP(context) - (patchBypass - (BYTE *)m_address)));
48234823
}
48244824

4825-
LOG((LF_CORDB, LL_ALWAYS, "to 0x%x\n", GetIP(context)));
4826-
4825+
LOG((LF_CORDB, LL_ALWAYS, "DPS::TEH: IP now at %p\n", GetIP(context)));
48274826
}
48284827

48294828
#endif
@@ -5376,39 +5375,36 @@ bool DebuggerStepper::DetectHandleInterceptors(ControllerStackInfo *info)
53765375

53775376
BOOL DebuggerStepper::DetectHandleLCGMethods(const PCODE ip, MethodDesc * pMD, ControllerStackInfo * pInfo)
53785377
{
5378+
// If a MethodDesc is specified, it has to match the given IP.
5379+
_ASSERTE(pMD == NULL || pMD == g_pEEInterface->GetNativeCodeMethodDesc(ip));
5380+
53795381
// Look up the MethodDesc for the given IP.
53805382
if (pMD == NULL)
53815383
{
5382-
if (g_pEEInterface->IsManagedNativeCode((const BYTE *)ip))
5383-
{
5384-
pMD = g_pEEInterface->GetNativeCodeMethodDesc(ip);
5385-
_ASSERTE(pMD != NULL);
5386-
}
5387-
}
5388-
#if defined(_DEBUG)
5389-
else
5390-
{
5391-
// If a MethodDesc is specified, it has to match the given IP.
5392-
_ASSERTE(pMD == g_pEEInterface->GetNativeCodeMethodDesc(ip));
5384+
// If the given IP is in unmanaged code, then it isn't an LCG method
5385+
if (!g_pEEInterface->IsManagedNativeCode((const BYTE *)ip))
5386+
return FALSE;
5387+
5388+
pMD = g_pEEInterface->GetNativeCodeMethodDesc(ip);
53935389
}
5394-
#endif // _DEBUG
53955390

5396-
// If the given IP is in unmanaged code, then we won't have a MethodDesc by this point.
5397-
if (pMD != NULL)
5398-
{
5399-
if (pMD->IsLCGMethod())
5400-
{
5401-
// Enable all the traps to catch the thread.
5402-
EnableUnwind(m_fp);
5403-
EnableJMCBackStop(pMD);
5391+
_ASSERTE(pMD != NULL);
5392+
LOG((LF_CORDB, LL_INFO10000, "DS::DHLCGM: ip:%zx pMD:%p (%s::%s)\n",
5393+
ip,
5394+
pMD,
5395+
pMD->m_pszDebugClassName,
5396+
pMD->m_pszDebugMethodName));
54045397

5405-
pInfo->SetReturnFrameWithActiveFrame();
5406-
TrapStepOut(pInfo);
5407-
return TRUE;
5408-
}
5409-
}
5398+
if (!pMD->IsLCGMethod())
5399+
return FALSE;
54105400

5411-
return FALSE;
5401+
// Enable all the traps to catch the thread.
5402+
EnableUnwind(m_fp);
5403+
EnableJMCBackStop(pMD);
5404+
5405+
pInfo->SetReturnFrameWithActiveFrame();
5406+
TrapStepOut(pInfo);
5407+
return TRUE;
54125408
}
54135409

54145410

@@ -5523,19 +5519,19 @@ bool DebuggerStepper::TrapStepInto(ControllerStackInfo *info,
55235519
if (IsCloserToRoot(info->m_activeFrame.fp, m_fpStepInto))
55245520
m_fpStepInto = info->m_activeFrame.fp;
55255521

5526-
LOG((LF_CORDB, LL_INFO1000, "DS::TSI this:0x%p m_fpStepInto:0x%p\n",
5527-
this, m_fpStepInto.GetSPValue()));
5522+
LOG((LF_CORDB, LL_INFO1000, "DS::TSI this:%p m_fpStepInto:%p ip:%p\n",
5523+
this, m_fpStepInto.GetSPValue(), ip));
55285524

55295525
TraceDestination trace;
55305526

55315527
// Trace through the stubs.
55325528
// If we're calling from managed code, this should either succeed
5533-
// or become an ecall into mscorwks.
5534-
// @Todo - what about stubs in mscorwks.
5529+
// or become an ecall into coreclr.
55355530
// @todo - if this fails, we want to provide as much info as possible.
55365531
if (!g_pEEInterface->TraceStub(ip, &trace)
55375532
|| !g_pEEInterface->FollowTrace(&trace))
55385533
{
5534+
LOG((LF_CORDB, LL_INFO1000, "DS::TSI Failed to step into\n"));
55395535
return false;
55405536
}
55415537

@@ -5964,8 +5960,8 @@ bool DebuggerStepper::TrapStep(ControllerStackInfo *info, bool in)
59645960

59655961
case WALK_UNKNOWN:
59665962
LWALK_UNKNOWN:
5967-
LOG((LF_CORDB,LL_INFO10000,"DS::TS:WALK_UNKNOWN - curIP:0x%p "
5968-
"nextIP:0x%p skipIP:0x%p 1st byte of opcode:0x%x\n", (BYTE*)GetControlPC(&(info->m_activeFrame.
5963+
LOG((LF_CORDB,LL_INFO10000,"DS::TS:WALK_UNKNOWN - curIP:%p "
5964+
"nextIP:%p skipIP:%p 1st byte of opcode:0x%x\n", (BYTE*)GetControlPC(&(info->m_activeFrame.
59695965
registers)), walker.GetNextIP(),walker.GetSkipIP(),
59705966
*(BYTE*)GetControlPC(&(info->m_activeFrame.registers))));
59715967

@@ -6713,7 +6709,7 @@ bool DebuggerStepper::SetRangesFromIL(DebuggerJitInfo *dji, COR_DEBUG_STEP_RANGE
67136709
{
67146710
// {0...-1} means use the entire method as the range
67156711
// Code dup'd from below case.
6716-
LOG((LF_CORDB, LL_INFO10000, "DS:Step: Have DJI, special (0,-1) entry\n"));
6712+
LOG((LF_CORDB, LL_INFO10000, "DS::Step: Have DJI, special (0,-1) entry\n"));
67176713
rTo->startOffset = 0;
67186714
rTo->endOffset = (ULONG32)g_pEEInterface->GetFunctionSize(fd);
67196715
}
@@ -6777,7 +6773,7 @@ bool DebuggerStepper::SetRangesFromIL(DebuggerJitInfo *dji, COR_DEBUG_STEP_RANGE
67776773
}
67786774
}
67796775

6780-
LOG((LF_CORDB, LL_INFO10000, "DS:Step: nat off:0x%x to 0x%x\n", rTo->startOffset, rTo->endOffset));
6776+
LOG((LF_CORDB, LL_INFO10000, "DS::Step: nat off:0x%x to 0x%x\n", rTo->startOffset, rTo->endOffset));
67816777
}
67826778
}
67836779
}
@@ -6799,15 +6795,15 @@ bool DebuggerStepper::SetRangesFromIL(DebuggerJitInfo *dji, COR_DEBUG_STEP_RANGE
67996795
{
68006796
if (r->startOffset == 0 && r->endOffset == (ULONG) ~0)
68016797
{
6802-
LOG((LF_CORDB, LL_INFO10000, "DS:Step:No DJI, (0,-1) special entry\n"));
6798+
LOG((LF_CORDB, LL_INFO10000, "DS::Step:No DJI, (0,-1) special entry\n"));
68036799
// Code dup'd from above case.
68046800
// {0...-1} means use the entire method as the range
68056801
rTo->startOffset = 0;
68066802
rTo->endOffset = (ULONG32)functionSize;
68076803
}
68086804
else
68096805
{
6810-
LOG((LF_CORDB, LL_INFO10000, "DS:Step:No DJI, regular entry\n"));
6806+
LOG((LF_CORDB, LL_INFO10000, "DS::Step:No DJI, regular entry\n"));
68116807
// We can't just leave ths IL entry - we have to
68126808
// get rid of it.
68136809
// This will just be ignored
@@ -6949,12 +6945,12 @@ bool DebuggerStepper::Step(FramePointer fp, bool in,
69496945
}
69506946
m_eMode = m_stepIn ? cStepIn : cStepOver;
69516947

6952-
LOG((LF_CORDB,LL_INFO10000,"DS 0x%p Step: STEP_NORMAL\n",this));
6948+
LOG((LF_CORDB,LL_INFO10000,"DS::Step %p STEP_NORMAL\n",this));
69536949
m_reason = STEP_NORMAL; //assume it'll be a normal step & set it to
69546950
//something else if we walk over it
69556951
if (fIsILStub)
69566952
{
6957-
LOG((LF_CORDB, LL_INFO10000, "DS:Step: stepping in an IL stub\n"));
6953+
LOG((LF_CORDB, LL_INFO10000, "DS::Step: stepping in an IL stub\n"));
69586954

69596955
// Enable the right triggers if the user wants to step in.
69606956
if (in)
@@ -6978,12 +6974,12 @@ bool DebuggerStepper::Step(FramePointer fp, bool in,
69786974
}
69796975
else if (!TrapStep(&info, in))
69806976
{
6981-
LOG((LF_CORDB,LL_INFO10000,"DS:Step: Did TS\n"));
6977+
LOG((LF_CORDB,LL_INFO10000,"DS::Step: Did TS\n"));
69826978
m_stepIn = true;
69836979
TrapStepNext(&info);
69846980
}
69856981

6986-
LOG((LF_CORDB,LL_INFO10000,"DS:Step: Did TS,TSO\n"));
6982+
LOG((LF_CORDB,LL_INFO10000,"DS::Step: Did TS,TSO\n"));
69876983

69886984
EnableUnwind(m_fp);
69896985

@@ -7316,13 +7312,13 @@ void DebuggerStepper::TriggerMethodEnter(Thread * thread,
73167312
_ASSERTE(!IsFrozen());
73177313

73187314
MethodDesc * pDesc = dji->m_nativeCodeVersion.GetMethodDesc();
7319-
LOG((LF_CORDB, LL_INFO10000, "DebuggerStepper::TME, desc=%p, addr=%p\n",
7315+
LOG((LF_CORDB, LL_INFO10000, "DS::TME, desc=%p, addr=%p\n",
73207316
pDesc, ip));
73217317

73227318
// JMC steppers won't stop in Lightweight codegen (LCG). Just return & keep executing.
73237319
if (pDesc->IsNoMetadata())
73247320
{
7325-
LOG((LF_CORDB, LL_INFO100000, "DebuggerStepper::TME, skipping b/c it's dynamic code (LCG)\n"));
7321+
LOG((LF_CORDB, LL_INFO100000, "DS::TME, skipping b/c it's dynamic code (LCG)\n"));
73267322
return;
73277323
}
73287324

@@ -7382,9 +7378,7 @@ void DebuggerStepper::TriggerMethodEnter(Thread * thread,
73827378
}
73837379
#endif
73847380

7385-
7386-
7387-
// Place a patch to stopus.
7381+
// Place a patch to stop us.
73887382
// Don't bind to a particular AppDomain so that we can do a Cross-Appdomain step.
73897383
AddBindAndActivateNativeManagedPatch(pDesc,
73907384
dji,
@@ -7393,9 +7387,9 @@ void DebuggerStepper::TriggerMethodEnter(Thread * thread,
73937387
NULL // AppDomain
73947388
);
73957389

7396-
LOG((LF_CORDB, LL_INFO10000, "DJMCStepper::TME, after setting patch to stop\n"));
7390+
LOG((LF_CORDB, LL_INFO10000, "DS::TME, after setting patch to stop\n"));
73977391

7398-
// Once we resume, we'll go hit that patch (duh, we patched our return address)
7392+
// Once we resume, we'll go hit that patch since we patched our return address.
73997393
// Furthermore, we know the step will complete with reason = call, so set that now.
74007394
m_reason = STEP_CALL;
74017395
}
@@ -7406,7 +7400,7 @@ void DebuggerStepper::TriggerMethodEnter(Thread * thread,
74067400
// We never single-step into calls (we place a patch at the call destination).
74077401
bool DebuggerStepper::TriggerSingleStep(Thread *thread, const BYTE *ip)
74087402
{
7409-
LOG((LF_CORDB,LL_INFO10000,"DS:TSS this:0x%p, @ ip:0x%p\n", this, ip));
7403+
LOG((LF_CORDB,LL_INFO10000,"DS::TSS this:0x%p, @ ip:0x%p\n", this, ip));
74107404

74117405
_ASSERTE(!IsFrozen());
74127406

@@ -7507,12 +7501,12 @@ bool DebuggerStepper::TriggerSingleStep(Thread *thread, const BYTE *ip)
75077501

75087502
void DebuggerStepper::TriggerTraceCall(Thread *thread, const BYTE *ip)
75097503
{
7510-
LOG((LF_CORDB,LL_INFO10000,"DS:TTC this:0x%x, @ ip:0x%x\n",this,ip));
7504+
LOG((LF_CORDB,LL_INFO10000,"DS::TTC this:0x%x, @ ip:0x%x\n",this,ip));
75117505
TraceDestination trace;
75127506

75137507
if (IsFrozen())
75147508
{
7515-
LOG((LF_CORDB,LL_INFO10000,"DS:TTC exit b/c of Frozen\n"));
7509+
LOG((LF_CORDB,LL_INFO10000,"DS::TTC exit b/c of Frozen\n"));
75167510
return;
75177511
}
75187512

@@ -7573,7 +7567,7 @@ void DebuggerStepper::TriggerUnwind(Thread *thread,
75737567

75747568
if (IsFrozen())
75757569
{
7576-
LOG((LF_CORDB,LL_INFO10000,"DS:TTC exit b/c of Frozen\n"));
7570+
LOG((LF_CORDB,LL_INFO10000,"DS::TTC exit b/c of Frozen\n"));
75777571
return;
75787572
}
75797573

@@ -7853,7 +7847,7 @@ bool DebuggerJMCStepper::TrapStepInHelper(
78537847
SIZE_T offset = CodeRegionInfo::GetCodeRegionInfo(dji, pDesc).AddressToOffset(ipNext);
78547848

78557849

7856-
LOG((LF_CORDB, LL_INFO100000, "DJMCStepper::TSIH, at '%s::%s', calling=0x%p, next=0x%p, offset=%d\n",
7850+
LOG((LF_CORDB, LL_INFO100000, "DJMCStepper::TSIH, at '%s::%s', calling=%p, next=%p, offset=%d\n",
78577851
pDesc->m_pszDebugClassName,
78587852
pDesc->m_pszDebugMethodName,
78597853
ipCallTarget, ipNext,

0 commit comments

Comments
 (0)