Skip to content

Commit

Permalink
Merge branch 'main' into user/sergiopedri/get-generic-type-definition…
Browse files Browse the repository at this point in the history
…-intrinsic
  • Loading branch information
EgorBo authored Jul 19, 2024
2 parents 78281de + 5fd965d commit 7f0594b
Show file tree
Hide file tree
Showing 32 changed files with 891 additions and 260 deletions.
53 changes: 53 additions & 0 deletions docs/design/datacontracts/Object.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Contract Object

This contract is for getting information about well-known managed objects

## APIs of contract

``` csharp
// Get the method table address for the object
TargetPointer GetMethodTableAddress(TargetPointer address);

// Get the string corresponding to a managed string object. Error if address does not represent a string.
string GetStringValue(TargetPointer address);
```

## Version 1

Data descriptors used:
| Data Descriptor Name | Field | Meaning |
| --- | --- | --- |
| `Object` | `m_pMethTab` | Method table for the object |
| `String` | `m_FirstChar` | First character of the string - `m_StringLength` can be used to read the full string (encoded in UTF-16) |
| `String` | `m_StringLength` | Length of the string in characters (encoded in UTF-16) |

Global variables used:
| Global Name | Type | Purpose |
| --- | --- | --- |
| `ObjectToMethodTableUnmask` | uint8 | Bits to clear for converting to a method table address |
| `StringMethodTable` | TargetPointer | The method table for System.String |

``` csharp
TargetPointer GetMethodTableAddress(TargetPointer address)
{
TargetPointer mt = _targetPointer.ReadPointer(address + /* Object::m_pMethTab offset */);
return mt.Value & ~target.ReadGlobal<byte>("ObjectToMethodTableUnmask");
}

string GetStringValue(TargetPointer address)
{
TargetPointer mt = GetMethodTableAddress(address);
TargetPointer stringMethodTable = target.ReadPointer(target.ReadGlobalPointer("StringMethodTable"));
if (mt != stringMethodTable)
throw new ArgumentException("Address does not represent a string object", nameof(address));

// Validates the method table
_ = target.Contracts.RuntimeTypeSystem.GetTypeHandle(mt);

Data.String str = _target.ProcessedData.GetOrAdd<Data.String>(address);
uint length = target.Read<uint>(address + /* String::m_StringLength offset */);
Span<byte> span = stackalloc byte[(int)length * sizeof(char)];
target.ReadBuffer(address + /* String::m_FirstChar offset */, span);
return new string(MemoryMarshal.Cast<byte, char>(span));
}
```
1 change: 1 addition & 0 deletions src/coreclr/debug/daccess/dacimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1241,6 +1241,7 @@ class ClrDataAccess
HRESULT GetMethodTableForEEClassImpl (CLRDATA_ADDRESS eeClassReallyMT, CLRDATA_ADDRESS *value);
HRESULT GetMethodTableNameImpl(CLRDATA_ADDRESS mt, unsigned int count, _Inout_updates_z_(count) WCHAR *mtName, unsigned int *pNeeded);
HRESULT GetObjectExceptionDataImpl(CLRDATA_ADDRESS objAddr, struct DacpExceptionObjectData *data);
HRESULT GetObjectStringDataImpl(CLRDATA_ADDRESS obj, unsigned int count, _Inout_updates_z_(count) WCHAR *stringData, unsigned int *pNeeded);

BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord);
#ifndef TARGET_UNIX
Expand Down
81 changes: 55 additions & 26 deletions src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1601,7 +1601,7 @@ ClrDataAccess::GetDomainFromContext(CLRDATA_ADDRESS contextAddr, CLRDATA_ADDRESS


HRESULT
ClrDataAccess::GetObjectStringData(CLRDATA_ADDRESS obj, unsigned int count, _Inout_updates_z_(count) WCHAR *stringData, unsigned int *pNeeded)
ClrDataAccess::GetObjectStringData(CLRDATA_ADDRESS obj, unsigned int count, _Inout_updates_z_(count) WCHAR* stringData, unsigned int* pNeeded)
{
if (obj == 0)
return E_INVALIDARG;
Expand All @@ -1611,44 +1611,73 @@ ClrDataAccess::GetObjectStringData(CLRDATA_ADDRESS obj, unsigned int count, _Ino

SOSDacEnter();

if (m_cdacSos != NULL)
{
hr = m_cdacSos->GetObjectStringData(obj, count, stringData, pNeeded);
if (FAILED(hr))
{
hr = GetObjectStringDataImpl(obj, count, stringData, pNeeded);
}
#ifdef _DEBUG
else
{
unsigned int neededLocal;
SString stringDataLocal;
HRESULT hrLocal = GetObjectStringDataImpl(obj, count, stringDataLocal.OpenUnicodeBuffer(count), &neededLocal);
_ASSERTE(hr == hrLocal);
_ASSERTE(pNeeded == NULL || *pNeeded == neededLocal);
_ASSERTE(u16_strncmp(stringData, stringDataLocal, count) == 0);
}
#endif
}
else
{
hr = GetObjectStringDataImpl(obj, count, stringData, pNeeded);
}

SOSDacLeave();
return hr;
}

HRESULT
ClrDataAccess::GetObjectStringDataImpl(CLRDATA_ADDRESS obj, unsigned int count, _Inout_updates_z_(count) WCHAR *stringData, unsigned int *pNeeded)
{
TADDR mtTADDR = DACGetMethodTableFromObjectPointer(TO_TADDR(obj), m_pTarget);
PTR_MethodTable mt = PTR_MethodTable(mtTADDR);

// Object must be a string
BOOL bFree = FALSE;
if (!DacValidateMethodTable(mt, bFree))
hr = E_INVALIDARG;
else if (HOST_CDADDR(mt) != HOST_CDADDR(g_pStringClass))
hr = E_INVALIDARG;
return E_INVALIDARG;

if (SUCCEEDED(hr))
{
PTR_StringObject str(TO_TADDR(obj));
ULONG32 needed = (ULONG32)str->GetStringLength() + 1;
if (HOST_CDADDR(mt) != HOST_CDADDR(g_pStringClass))
return E_INVALIDARG;

if (stringData && count > 0)
{
if (count > needed)
count = needed;
PTR_StringObject str(TO_TADDR(obj));
ULONG32 needed = (ULONG32)str->GetStringLength() + 1;

TADDR pszStr = TO_TADDR(obj)+offsetof(StringObject, m_FirstChar);
hr = m_pTarget->ReadVirtual(pszStr, (PBYTE)stringData, count * sizeof(WCHAR), &needed);
HRESULT hr;
if (stringData && count > 0)
{
if (count > needed)
count = needed;

if (SUCCEEDED(hr))
stringData[count - 1] = W('\0');
else
stringData[0] = W('\0');
}
else
{
hr = E_INVALIDARG;
}
TADDR pszStr = TO_TADDR(obj)+offsetof(StringObject, m_FirstChar);
hr = m_pTarget->ReadVirtual(pszStr, (PBYTE)stringData, count * sizeof(WCHAR), &needed);

if (pNeeded)
*pNeeded = needed;
if (SUCCEEDED(hr))
stringData[count - 1] = W('\0');
else
stringData[0] = W('\0');
}
else
{
hr = E_INVALIDARG;
}

SOSDacLeave();
if (pNeeded)
*pNeeded = needed;

return hr;
}

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/debug/runtimeinfo/contracts.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"DacStreams": 1,
"Exception": 1,
"Loader": 1,
"Object": 1,
"RuntimeTypeSystem": 1,
"Thread": 1
}
18 changes: 18 additions & 0 deletions src/coreclr/debug/runtimeinfo/datadescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,17 @@ CDAC_TYPE_BEGIN(GCHandle)
CDAC_TYPE_SIZE(sizeof(OBJECTHANDLE))
CDAC_TYPE_END(GCHandle)

CDAC_TYPE_BEGIN(Object)
CDAC_TYPE_INDETERMINATE(Object)
CDAC_TYPE_FIELD(Object, /*pointer*/, m_pMethTab, cdac_offsets<Object>::m_pMethTab)
CDAC_TYPE_END(Object)

CDAC_TYPE_BEGIN(String)
CDAC_TYPE_INDETERMINATE(String)
CDAC_TYPE_FIELD(String, /*pointer*/, m_FirstChar, cdac_offsets<StringObject>::m_FirstChar)
CDAC_TYPE_FIELD(String, /*uint32*/, m_StringLength, cdac_offsets<StringObject>::m_StringLength)
CDAC_TYPE_END(String)

// Loader

CDAC_TYPE_BEGIN(Module)
Expand Down Expand Up @@ -264,8 +275,15 @@ CDAC_GLOBAL(FeatureEHFunclets, uint8, 1)
#else
CDAC_GLOBAL(FeatureEHFunclets, uint8, 0)
#endif
// See Object::GetGCSafeMethodTable
#ifdef TARGET_64BIT
CDAC_GLOBAL(ObjectToMethodTableUnmask, uint8, 1 | 1 << 1 | 1 << 2)
#else
CDAC_GLOBAL(ObjectToMethodTableUnmask, uint8, 1 | 1 << 1)
#endif //TARGET_64BIT
CDAC_GLOBAL(SOSBreakingChangeVersion, uint8, SOS_BREAKING_CHANGE_VERSION)
CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable)
CDAC_GLOBAL_POINTER(StringMethodTable, &::g_pStringClass)
CDAC_GLOBAL_POINTER(MiniMetaDataBuffAddress, &::g_MiniMetaDataBuffAddress)
CDAC_GLOBAL_POINTER(MiniMetaDataBuffMaxSize, &::g_MiniMetaDataBuffMaxSize)
CDAC_GLOBALS_END()
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/jit/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -4514,6 +4514,7 @@ class Compiler

GenTree* impStoreNullableFields(CORINFO_CLASS_HANDLE nullableCls,
GenTree* value);
GenTree* impInlineUnboxNullable(CORINFO_CLASS_HANDLE nullableCls, GenTree* nullableClsNode, GenTree* obj);
void impLoadNullableFields(GenTree* nullableObj, CORINFO_CLASS_HANDLE nullableCls, GenTree** hasValueFld, GenTree** valueFld);

int impBoxPatternMatch(CORINFO_RESOLVED_TOKEN* pResolvedToken,
Expand Down Expand Up @@ -7649,6 +7650,8 @@ class Compiler
LoopLocalOccurrences* loopLocals);
bool optCanAndShouldChangeExitTest(GenTree* cond, bool dump);
bool optPrimaryIVHasNonLoopUses(unsigned lclNum, FlowGraphNaturalLoop* loop, LoopLocalOccurrences* loopLocals);

bool optWidenIVs(ScalarEvolutionContext& scevContext, FlowGraphNaturalLoop* loop, LoopLocalOccurrences* loopLocals);
bool optWidenPrimaryIV(FlowGraphNaturalLoop* loop,
unsigned lclNum,
ScevAddRec* addRec,
Expand All @@ -7665,6 +7668,9 @@ class Compiler
void optReplaceWidenedIV(unsigned lclNum, unsigned ssaNum, unsigned newLclNum, Statement* stmt);
void optSinkWidenedIV(unsigned lclNum, unsigned newLclNum, FlowGraphNaturalLoop* loop);

bool optRemoveUnusedIVs(FlowGraphNaturalLoop* loop, LoopLocalOccurrences* loopLocals);
bool optIsUpdateOfIVWithoutSideEffects(GenTree* tree, unsigned lclNum);

// Redundant branch opts
//
PhaseStatus optRedundantBranches();
Expand Down
Loading

0 comments on commit 7f0594b

Please sign in to comment.