Skip to content
Closed
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 @@ -220,6 +220,20 @@ internal static RangeSection Find(Target target, Data.RangeSectionMap topRangeSe
return null;
}
}

private CodeBlock GetOrCreateCodeBlock(CodeBlockHandle codeInfoHandle)
{
if (_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make a decision whether we expect CodeBlockHandle (or other XyzHandle types) to remain valid across a flush operation. I'd propose no, all handles should become invalid on Flush. If the caller expected that there was still code in the same location before and after a flush then they would need to preserve the address or whatever other identity information created the handle and call into cDAC to re-create the handle (which would also repopulate any Dictionary backed cache at the same time).

This probably means instead of trying to repopulate the handle on the fly we should go modify other handles so they don't try to auto-repopulate if they are currently doing so. We could also add a flush cookie that updates on every Flush() call so that handles can be tagged with the cookie that was active when they were created and rejected if a caller tries to reuse a stale handle.

@rcj1 rcj1 Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question of whether we "expect" a CodeBlockHandle or other handle to stay valid depends on what we mean by "expect". We cannot prove yes or no without invoking more complex logic; we have to know where the object was allocated from, whether we are doing time-travel debugging, etc. However, I would assume it probably does more often than not, and that the same holds for the RuntimeTypeSystem caches.

The repopulation is a best-effort attempt at driving each individual DacDbi API to completion in the case that it is still valid. If it is no longer valid, then we return an error or invalid data, and that is a bug on the caller's side (for example in the DBI). We can wrap any error in the repopulation in a more descriptive error message. But at that point, it does not really matter what we do.

This is not intended to replace the process or stop-go locks that synchronize the DBI, more as a fail-safe to mostly produce a correct answer despite any locking bugs.

return info;

info = GetCodeBlock(new TargetCodePointer(codeInfoHandle.Address.Value));
if (info is null || !info.Valid)
throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}");

_codeInfos.TryAdd(codeInfoHandle.Address, info);
return info;
}

CodeBlockHandle? IExecutionManager.GetCodeBlockHandle(TargetCodePointer ip)
{
TargetPointer key = ip.AsTargetPointer; // FIXME: thumb bit. It's harmless (we potentialy have 2 cache entries per IP), but we should fix it
Expand All @@ -238,16 +252,14 @@ internal static RangeSection Find(Target target, Data.RangeSectionMap topRangeSe

TargetPointer IExecutionManager.GetMethodDesc(CodeBlockHandle codeInfoHandle)
{
if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info))
throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}");
CodeBlock info = GetOrCreateCodeBlock(codeInfoHandle);

return info.MethodDescAddress;
}

TargetPointer IExecutionManager.GetStartAddress(CodeBlockHandle codeInfoHandle)
{
if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info))
throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}");
CodeBlock info = GetOrCreateCodeBlock(codeInfoHandle);

return info.StartAddress;
}
Expand Down Expand Up @@ -338,8 +350,7 @@ bool IExecutionManager.IsFunclet(CodeBlockHandle codeInfoHandle)

bool IExecutionManager.IsFilterFunclet(CodeBlockHandle codeInfoHandle)
{
if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info))
throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}");
CodeBlock info = GetOrCreateCodeBlock(codeInfoHandle);

IExecutionManager eman = this;

Expand Down Expand Up @@ -406,8 +417,7 @@ void IExecutionManager.GetGCInfo(CodeBlockHandle codeInfoHandle, out TargetPoint

TargetNUInt IExecutionManager.GetRelativeOffset(CodeBlockHandle codeInfoHandle)
{
if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info))
throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}");
CodeBlock info = GetOrCreateCodeBlock(codeInfoHandle);

return info.RelativeOffset;
}
Expand Down Expand Up @@ -539,8 +549,7 @@ IReadOnlyList<TargetPointer> IExecutionManager.GetDynamicFunctionTableEntries(Ta

private RangeSection RangeSectionFromCodeBlockHandle(CodeBlockHandle codeInfoHandle)
{
if (!_codeInfos.TryGetValue(codeInfoHandle.Address, out CodeBlock? info))
throw new InvalidOperationException($"{nameof(CodeBlock)} not found for {codeInfoHandle.Address}");
_ = GetOrCreateCodeBlock(codeInfoHandle);

RangeSection range = RangeSection.Find(_target, _topRangeSectionMap, _rangeSectionMapLookup, codeInfoHandle.Address.Value);
return range;
Expand Down
Loading