Repository navigation
Invoke debugger function evaluations through managed UCO - #133659
jkoritzinsky wants to merge 18 commits into
Conversation
|
Azure Pipelines: Successfully started running 3 pipeline(s). 13 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
|
Tagging subscribers to this area: @agocke |
08c8a1d to
2c9232c
Compare
2c9232c to
84969d7
Compare
84969d7 to
ce9480a
Compare
ce9480a to
10d25d9
Compare
|
@jkoritzinsky, please ask copilot to double check this review by my instance: I reviewed the managed entrypoint, the invoker emitter, the native func-eval changes, external-memory GC reporting, and the cDAC changes. The overall design holds up and CI has no failures caused by this PR, but I found two bugs and a mismatch between what the runtime and the cDAC report. Line numbers below refer to head commit Bugs1. Evals that return a struct leak their result buffer and a GC rootcontext.ppTemporaryResult = &temporaryResult;
2. A struct receiver held in a register is now always written back, which fails in caller frames
3. The runtime and the cDAC report different roots for overlapping byref fields
Possible issues4. A by-ref
|
Complete the third layer of #123864 on the shared invocation foundation from #126542. Use rooted receiver/argument/result storage and the common managed emitter instead of native ABI packing. Preserve raw byref and nullable results, in-place receivers, register/literal semantics, exception propagation and abort recovery. Correct native-helper abort contracts and true nullable backing-box copy-back. Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
WebAssembly does not build or link debug/ee even though DEBUGGING_SUPPORTED is defined. Guard both the debugger UCO MethodDesc declaration and its EH comparison with TARGET_WASM instead of referencing an unavailable definition. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Add an internal InvokeForDebugger facade on RuntimeConstructorInfo that forwards to its existing MethodBaseInvoker, so Debugger.InvokeFunction no longer needs direct access to the constructor's Invoker property once it is made private for encapsulation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
The writable copy is performed by PackArgumentStorage. The residual copy in GetFuncEvalArgStorage references parameters removed by the managed func-eval refactor. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use debugger-specific emitted thunks for managed argument preparation, invocation, and copy-back. Retain native GC-safe input capture and debugger state handling, protect result and snapshot storage with external memory handles, and preserve reference identity and fresh external-value inspection across collections. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Register known references in serialized non-leaf register slots with external memory handles before managed entry. Read register-only value types from those GC-updated slots, while preserving native snapshots for leaf and mixed homes and leaving numeric register contents unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Run preparation, invocation, and copy-back within a single managed UCO entry. Use GCFrameRegistration for call storage, and move primitive capture, result handle creation, and memory/literal copy-back into CoreLib while retaining native bootstrap, register, and completion responsibilities. Avoid the invalid cooperative-mode safe-point query uncovered by GCStress validation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace the debugger-specific allocator QCall with RuntimeTypeHandle.InternalAllocNoChecks after activating each type at its actual allocation site. Preserve COM, GCStress, logging, large/finalizable object, and profiler/ETW behavior by falling back to the existing slow allocator when required. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Treat RAK_MEMREG and RAK_REGMEM as scalar 64-bit integer or enum homes rather than hypothetical GC-containing structs. Remove their GC-layout rooting and address registrations, retain scalar snapshots and copy-back, reduce the external-handle bound, and assert the verified invariant. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Register DebuggerEval::m_result[0] directly as the persistent interior root for raw byref returns. Tie root ownership to DebuggerEval cleanup, remove the refresh/controller ownership path, and unregister before exception publication repurposes the slot. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Report the MethodTable loader allocator during external-memory root promotion and remove the redundant debugger typed-owner allocator handle. Preserve the separate raw-byref result lifetime root. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Represent external memory with the exact managed local type, including byrefs and unmanaged pointers. Update runtime callers, cDAC descriptors, root walking, tests, and contract documentation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: am11 <3840695+am11@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This reverts commit cc83a28cb5e01c0c58ff4b73bef5423681110560. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use InternalAlloc and GC-aware raw nullable copying while preserving heap-backed argument storage. Remove the dedicated EnsureInstanceActive QCall. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
22e799b to
ad5abd7
Compare
Fix temporary result ownership and external-field lifetimes, including helper-thread cleanup. Preserve receiver semantics, correct floating-register handling and restrict raw reference inputs to pointer-sized integers. Make cDAC root parity validation duplicate-safe, add targeted coverage, clarify argument storage, and restore the original unchecked allocation fast path. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
@am11 addressed the feedback from your agent. It found some legit problems, much appreciated! |
|
|
||
| extern MethodDesc* g_pThreadStartCallbackMethodDesc; | ||
| extern MethodDesc* g_pGCRunFinalizersMethodDesc; | ||
| // The debugger func-eval implementation is not linked on WebAssembly. |
There was a problem hiding this comment.
Why is that? The debugger - that is work in progress - is going to need it.
Summary
Layer 3 of the stack for #123864, following #133658. The prior func-eval-specific proposal is #126809.
This layer started as replacing the final native managed-call dispatch with a managed UnmanagedCallersOnly entrypoint. It now moves most debugger function-evaluation preparation, invocation, storage, and copy-back into managed CoreLib while retaining the debugger-specific control flow and GC-safe bootstrap in native code.
Managed invocation and storage
Debugger.FunctionEvaluation, a runtime-owned UCO entrypoint that resolves the exact target method from its declaringRuntimeTypeand rootedIRuntimeMethodInfo.newobjfor debugger object construction instead of preallocating an object and calling its constructor as an ordinary method. Existing-object constructor calls remain supported, and abstract/interface allocation is rejected.GCFrameRegistration, using exact typed locals for memory-backed by-value ref structs so their managed byrefs are reported by normal JIT GC info.Native debugger and GC integration
ExternalMemoryHandleregistrations so collections during managed preparation relocate their contents correctly.TypeHandle, allowing the runtime and cDAC to distinguish inline value types, object-reference slots, managed-byref slots, and unmanaged pointer/function-pointer locals.debug/ee.Correctness fixes included
ref structwith overlappingreffields is reported to the GC twice, so a compacting GC relocates the byref twice #135245).Validation
Validation used the existing internal MDbg/xUnit debugger-test harness with a private CoreRun and ProjectK/CoreCLR-only configuration:
GCStress=0x3: 1/1 passed.Coverage includes moving GC, overlapping and nested byrefs, memory and register homes, non-leaf registers, receiver mutation, constructors, primitive/native-endian copy-back, nullable memory homes, byref/byref-like/value-type results, collectible generics and layouts, nested and exception-time eval, safe/rude/exception-unwind aborts, and post-eval inspection. Runtime hashes and loaded modules were audited; each abort scenario completed the callback, successfully evaluated
Echo(42), detached, and exited MDbg with code 100. Test configurations were restored and no debugger/test processes survived the runs.These results were recorded on the validated pre-refresh candidate. The final stack rebase preserved the layer's net diff; builds and tests were not repeated after the history rewrite at the user's request.
The final native invocation cleanup layer is #133660.
Stack created with GitHub Stacks CLI • Give Feedback 💬
Resolves #135245
Resolves #135247
Resolves #135249
Resolves #135251
Resolves #135252
Note
This PR description and implementation were prepared with GitHub Copilot. Commits that reuse am11's code retain the requested co-author attribution.