Wasm: full-framework R2R generic dictionary lookup leaves thread in preemptive GC mode
arch-wasmarea-ReadyToRun
When the whole framework (not just System.Private.CoreLib) is ReadyToRun-compiled
for wasm, several tests in the JIT subtree fail with a checked assert:
```
!"OBJECTREF being accessed while thread is in preemptive GC mode."
src/coreclr/vm/object.cpp:514 Object::Validate
```
Affected tests: `ProfileCastClassAndIsInst` (+ `_random1/2/3`), `Methodical_d1`,
`Methodical_r1`, `UnrollEqualsStartsWith` -- all the same root cause.
These tests pass with interpreter or with only SPC R2R.
AI analysis below
----------------------------------
The falure is in the R2R generic dictionary lookup slow path:
- R2R generic code hits a delay-load fixup `READYTORUN_FIXUP_MethodDictionaryLookup`.
- `DynamicHelperFixup`/`DynamicHelperWorker` (prestub.cpp) resolves it and builds
`DynamicHelper_GenericDictionaryLookup_Method_UseHelper` (wasm stub,
dynamichelpers.S). Both run and return cooperative (verified).
- The stub `call_indirect`s `g_pMethodWithSlotAndModule` = managed
`GenericsHelpers.MethodWithSlotAndModule` (in the R2R SPC), which calls the
`GenericHandleWorker` `[LibraryImport(QCall)]` P/Invoke.
Instrumented trace (ProfileCastClassAndIsInst):
```
DynamicHelperWorker after-fixup: coopMode=1 (cooperative)
GenericHandleWorker enter: coopMode=0 (preemptive - correct for a QCALL)
GenericHandleWorker exit: coopMode=0 (still preemptive at C return)
ASSERT FAILED
```
The QCALL's `coop -> preempt -> coop` transition never restores COOPERATIVE on this
wasm path. After `GenericHandleWorker` returns, the R2R managed code resumes
PREEMPTIVE and asserts on the next OBJECTREF access.
With only the SPC R2R-compiled, the generic code runs interpreted and the
interpreter resolves dictionary lookups correctly.
> [!NOTE]
> Portions of this issue (the analysis below the line) were produced with GitHub Copilot.
1 条评论