Skip to content

[cDAC] Implement SetJITCompilerFlags for cDAC#126595

Draft
barosiak wants to merge 4 commits intodotnet:mainfrom
barosiak:barosiak/SetJITCompilerFlags
Draft

[cDAC] Implement SetJITCompilerFlags for cDAC#126595
barosiak wants to merge 4 commits intodotnet:mainfrom
barosiak:barosiak/SetJITCompilerFlags

Conversation

@barosiak
Copy link
Copy Markdown
Member

@barosiak barosiak commented Apr 7, 2026

 Summary

Implement SetJITCompilerFlags on IXCLRDataModule2 in the cDAC.

 Changes

  • ClrDataModule.cs - SetJITCompilerFlags implementation
  • ILoader.cs / Loader_1.cs - added GetDebuggerInfoBits and SetDebuggerInfoBits contract methods with direct target memory read/write
  • IXCLRData.cs - added DebuggerAssemblyControlFlags enum mirroring cordbpriv.h
  • Tests - new tests covering get/set/flag-preservation

@barosiak barosiak requested review from max-charlamb and rcj1 April 7, 2026 01:20
@barosiak barosiak self-assigned this Apr 7, 2026
Copilot AI review requested due to automatic review settings April 7, 2026 01:20
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Implements IXCLRDataModule2.SetJITCompilerFlags for the managed cDAC by wiring it to the Loader contract’s module transient-flag debugger bits, adding the necessary contract surface and tests to validate read/write behavior.

Changes:

  • Implement IXCLRDataModule2.SetJITCompilerFlags in ClrDataModule by updating module debugger control bits via ILoader.
  • Extend ILoader/Loader_1 with GetDebuggerInfoBits and SetDebuggerInfoBits, and document the new contract surface/constants.
  • Update cDAC test infrastructure to support target-memory writes and add Loader tests for debugger-bit get/set and flag preservation.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/ClrDataModule.cs Implements SetJITCompilerFlags using Loader debugger-info bits.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/IXCLRData.cs Adds managed DebuggerAssemblyControlFlags enum mirroring cordbpriv.h.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/ILoader.cs Adds GetDebuggerInfoBits / SetDebuggerInfoBits to the Loader contract.
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Loader_1.cs Implements debugger-info bit get/set by reading/writing Module::Flags.
src/native/managed/cdac/tests/TestPlaceholderTarget.cs Adds write-capable target support for tests.
src/native/managed/cdac/tests/MockDescriptors/MockDescriptors.Loader.cs Allows initializing module transient flags in mocks.
src/native/managed/cdac/tests/LoaderTests.cs Adds new tests for debugger-info bit behavior.
docs/design/datacontracts/Loader.md Documents new Loader contract methods and constants.
src/coreclr/vm/ceeload.h Notes cDAC Loader contract dependency on debugger-info mask/shift constants.
src/coreclr/inc/cordbpriv.h Adds explicit comment that cDAC depends on flag values.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 7, 2026 17:53
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Comment on lines +482 to +487
int hr = HResults.S_OK;
try
{
if ((flags != CORDEBUG_JIT_DEFAULT) && (flags != CORDEBUG_JIT_DISABLE_OPTIMIZATION))
throw new ArgumentException();

Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

IXCLRDataModule2.SetJITCompilerFlags is now implemented, but there doesn’t appear to be any unit/integration test that exercises this COM entrypoint (argument validation and the expected updates to Module::m_dwTransientFlags via Loader.Get/SetDebuggerInfoBits). Adding a focused test that constructs a ClrDataModule over a mock Module, calls SetJITCompilerFlags with both supported values (and an invalid value), and then asserts the shifted debugger bits in target memory would help prevent regressions.

Suggested change
int hr = HResults.S_OK;
try
{
if ((flags != CORDEBUG_JIT_DEFAULT) && (flags != CORDEBUG_JIT_DISABLE_OPTIMIZATION))
throw new ArgumentException();
if ((flags != CORDEBUG_JIT_DEFAULT) && (flags != CORDEBUG_JIT_DISABLE_OPTIMIZATION))
{
return HResults.E_INVALIDARG;
}
int hr = HResults.S_OK;
try
{

Copilot uses AI. Check for mistakes.
void SetDebuggerInfoBits(ModuleHandle handle, uint newBits)
{
uint currentFlags = // read Module::Flags (uint32) at handle.Address + Flags offset
uint updated = (currentFlags & ~DebuggerInfoMask) | (newBits << DebuggerInfoShift);
Copy link

Copilot AI Apr 7, 2026

Choose a reason for hiding this comment

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

The SetDebuggerInfoBits pseudocode writes (newBits << DebuggerInfoShift) without masking to the available bit-range, but the contract implementation masks newBits to (DebuggerInfoMask >> DebuggerInfoShift) before shifting. Please update the documentation snippet to reflect the masking behavior so callers don’t assume higher bits will be preserved/written.

Suggested change
uint updated = (currentFlags & ~DebuggerInfoMask) | (newBits << DebuggerInfoShift);
uint updated = (currentFlags & ~DebuggerInfoMask) | ((newBits & (DebuggerInfoMask >> DebuggerInfoShift)) << DebuggerInfoShift);

Copilot uses AI. Check for mistakes.
IReadOnlyDictionary<string, TargetPointer> GetLoaderAllocatorHeaps(TargetPointer loaderAllocatorPointer);

uint GetDebuggerInfoBits(ModuleHandle handle);
void SetDebuggerInfoBits(ModuleHandle handle, uint newBits);
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.

Rather than expose all the bits I'd suggest only exposing DACF_ALLOW_JIT_OPTS and DACF_ENC_ENABLED for now. Later I think we might need to add read-only for DACF_IGNORE_PDBS as part of DBI ENC support.

DACF_USER_OVERRIDE doesn't look like it serves any purpose and could be removed from the runtime. The one place I see in the runtime that reads it is unreachable.

}

[Flags]
public enum DebuggerAssemblyControlFlags : uint
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.

I'd treat this enum as part of the contract (document it in the markdown, define it in DataContractReader, and use it as the input/output type for the Get/SetDebuggerBits functions).

Comment on lines +384 to +386
Target.TypeInfo type = _target.GetTypeInfo(DataType.Module);
ulong flagsAddr = handle.Address + (ulong)type.Fields[nameof(Data.Module.Flags)].Offset;
uint flags = _target.Read<uint>(flagsAddr);
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.

Can use Data.Module.Flags to get this value.

Comment on lines +393 to +398
Target.TypeInfo type = _target.GetTypeInfo(DataType.Module);
ulong flagsAddr = handle.Address + (ulong)type.Fields[nameof(Data.Module.Flags)].Offset;
uint currentFlags = _target.Read<uint>(flagsAddr);
uint debuggerInfoBitsMask = DebuggerInfoMask >> DebuggerInfoShift;
uint updated = (currentFlags & ~DebuggerInfoMask) | ((newBits & debuggerInfoBitsMask) << DebuggerInfoShift);
_target.Write<uint>(flagsAddr, updated);
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 sure to update the in memory Data.Module class. Otherwise anyone else that looks at the Module.Flags field will get outdated data (IData classes are cached). Not sure if we have an existing pattern for this, but I wouldn't be opposed to adding support for writing back in the Module class directly.

DACF_ENC_ENABLED = 0x08,
DACF_IGNORE_PDBS = 0x20,
DACF_CONTROL_FLAGS_MASK = 0x2F,
DACF_CONTROL_FLAGS_MASK = 0x2E,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

unintentional?

}

Target.TypeInfo type = _target.GetTypeInfo(DataType.Module);
ulong flagsAddr = handle.Address + (ulong)type.Fields[nameof(Data.Module.Flags)].Offset;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

belongs in Module IData

| `MaxWebcilSections` | ushort | Maximum number of COFF sections supported in a Webcil image (must stay in sync with native `WEBCIL_MAX_SECTIONS`) | `16` |
| `DebuggerInfoMask` | uint | Mask for the debugger info bits within the Module's transient flags | `0x0000Fc00` |
| `DebuggerInfoShift` | int | Bit shift for the debugger info bits within the Module's transient flags | `10` |
| `IS_JIT_OPTIMIZATION_DISABLED` | uint | Cached flag: JIT optimizations are disabled | `0x00000002` |
Copy link
Copy Markdown
Contributor

@rcj1 rcj1 Apr 10, 2026

Choose a reason for hiding this comment

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

These four that are on the module flags belong in the module flags enum

Copilot AI review requested due to automatic review settings April 10, 2026 21:53
@barosiak barosiak marked this pull request as draft April 10, 2026 21:53
@dotnet-policy-service dotnet-policy-service bot added the linkable-framework Issues associated with delivering a linker friendly framework label Apr 10, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 293 out of 664 changed files in this pull request and generated 6 comments.

Comment on lines 482 to 494
Comment on lines +397 to +400
Data.Module module = _target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
uint currentFlags = module.Flags;
uint debuggerInfoBitsMask = DebuggerInfoMask >> DebuggerInfoShift;
uint updatedFlags = (currentFlags & ~DebuggerInfoMask) | (((uint)newBits & debuggerInfoBitsMask) << DebuggerInfoShift);
Comment on lines +408 to +423
if ((updatedFlags & IS_ENC_CAPABLE) != 0)
{
TargetPointer configPtr = _target.ReadGlobalPointer(Constants.Globals.EEConfig);
Data.EEConfig config = _target.ProcessedData.GetOrAdd<Data.EEConfig>(configPtr);
ClrModifiableAssemblies modifiableAssemblies = (ClrModifiableAssemblies)config.ModifiableAssemblies;

if (modifiableAssemblies != ClrModifiableAssemblies.None)
{
bool encRequested = (newBits & DebuggerAssemblyControlFlags.DACF_ENC_ENABLED) != 0;
bool jitOptsDisabledForEnc = (updatedFlags & IS_JIT_OPTIMIZATION_DISABLED) != 0;
bool setEnC = encRequested || (modifiableAssemblies == ClrModifiableAssemblies.Debug && jitOptsDisabledForEnc);

if (setEnC)
updatedFlags |= IS_EDIT_AND_CONTINUE;
}
}
Comment on lines +27 to +34
[Flags]
public enum DebuggerAssemblyControlFlags : uint
{
DACF_NONE = 0x00,
DACF_ALLOW_JIT_OPTS = 0x02,
DACF_ENC_ENABLED = 0x08,
DACF_CONTROL_FLAGS_MASK = 0x2E,
}
Comment on lines +104 to +105
DACF_ALLOW_JIT_OPTS = 0x02,
DACF_ENC_ENABLED = 0x08,
Comment on lines +171 to +172
if (_dataWriter(address, buffer) < 0)
throw new InvalidOperationException($"Failed to write {buffer.Length} bytes at 0x{address:x8}.");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-Diagnostics-coreclr linkable-framework Issues associated with delivering a linker friendly framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants