-
Notifications
You must be signed in to change notification settings - Fork 153
GC: reporting for GC references from non-SSA references #33
Comments
Precise GC using statepoints cannot handle aggregates that contain managed pointers yet. (Issue dotnet#33) So, this change adds a check to the reader-postpass, which scans the generated IR if it contains values of managed-aggregate type. If so, the compilation fails gracefully by throwing a NYI exception. This check in ReaderIr.cpp is based on the assertion checks in RewriteStatepointsForGC.cpp. [Issue dotnet#32]
Precise GC using statepoints cannot handle aggregates that contain managed pointers yet. (Issue dotnet#33) So, this change adds a check to the reader-postpass, which scans the generated IR if it contains values of managed-aggregate type. If so, the compilation fails gracefully by throwing a NYI exception. This check in ReaderIr.cpp is based on the assertion checks in RewriteStatepointsForGC.cpp. [Issue dotnet#32]
Here's a summary of the discussion with @AndyAyersMS, @preames and @sanjoy on this topic: Supporting aggregates containing GC-pointers Philip Reams wrote: Option 1 - Extend the stackmap format to encode an object map for the on stack aggregate. Stackmap contains only the pointer to the alloca and a pointer to the appropriate object map. The runtime can translate the object map + alloca entry into specific stack offsets for individual fields if desired. Option 2 - Report each field within the object directly in the stackmap. No format extensions needed. For option 2, we could extend the lowering code to distinguish a GEP from an alloca from a "normal" SSA GEP. We already have this distinction for alloca pointers themselves. We might want to introduce a new argument section (for explicit slots?), but this could be prototyped quickly today. I do have some concerns about distinguishing values reliably - i.e. consider a transform which adds a 100 nop GEPs - but in practice, I suspect this would work fine. For option 1, we could reuse the metadata argument to gc.root. We could interpret a pointer to a alloca with a gc_root marker as being an explicit stack slot (i.e. no mem2reg performed), and use the metadata field to describe the object map. We would need to either define a metadata format for the object map or find a generic way to serialize a metadata encoding into the stack map. In either case, we probably need to extend Mem2Reg to not treat a statepoint gc arg use as an escaping reference. We want allocas to still become SSA in most cases. Anyone else have another approach? Or thoughts on these? I mildly tempted to take option 2 out of simple expediency, but I'm mildly concerned some GC might expect to be able to get object maps for the structs on the stack. Swaroop wrote: My preference is also for option 2 – reporting each GC-pointer field individually in the stackmap – since it is closer to the CLR stackmap format. Andy Ayers Wrote: Value types on the stack are what we (sometimes jokingly) refer to as “non self-describing aggregates”. (As opposed to value types on the heap [boxed types] which have a vtable which links to gc info to describe layout, or ref types which always have a vtable which likewise links to gc layout, and currently never live on the stack). So there’s no way to convey to the runtime that a range of stack locations corresponds to some value type. Instead we must report each stack slot that contains a gc reference. There’s a bunch of code in our jit to ensure that the LLVM type accurately captures this information, so presumably we can either feed GEPs for each GC ref slot in the aggregate or just feed the base address of the aggregate (which would be the alloca) to the statepoint instruction with the right type obtainable (I hope), and from that reconstruct the right info. Since the latter is just one extra arg per live value type with GC refs it seems preferable and gives us a bit of factorization. Sanjoy Das wrote: Andy Ayers wrote: If not, we can just report all the slots one by one, but there can be lots of them. Luckily we don't have inplace allocated arrays yet. The other aspect of this is that we need to ensure that those GC ref slots in the value types are seen as updatable by the calls at statepoints. I think this is covered by escape semantics, which is tolerable. It means we'll think the non-GC fields may change at the call as well, which is unfortunate, but we can live with that for a while. |
In Reader's post-process phase, add an additional check to detect allocation of managed aggregates on the stack (alloca). Conservatively defer to the default Jit for functions containing such instructions. Without this check, LLVM silently generated bad code (until Issue dotnet#33 is fixed). This change also clarifies a comment in GcInfo.cpp.
In Reader's post-process phase, add an additional check to detect allocation of managed aggregates on the stack (alloca). Conservatively defer to the default Jit for functions containing such instructions. Without this check, LLVM silently generated bad code (until Issue dotnet#33 is fixed). This change also clarifies a comment in GcInfo.cpp.
In Reader's post-process phase, add an additional check to detect allocation of managed aggregates on the stack (alloca). Conservatively defer to the default Jit for functions containing such instructions. Without this check, LLVM silently generated bad code (until Issue dotnet#33 is fixed). This change also clarifies a comment in GcInfo.cpp.
In Reader's post-process phase, add an additional check to detect allocation of managed aggregates on the stack (alloca). Conservatively defer to the default Jit for functions containing such instructions. Without this check, LLVM silently generated bad code (until Issue dotnet#33 is fixed). This change also clarifies a comment in GcInfo.cpp.
Notes from an earlier discussion: In MSIL code, the use of gc-aggregates is fairly common. (1) The common case is that a pointer to the gc-aggregate is live at a call-site. For example:
Here, we silently generate bad code (StackMap) for Main() today -- only a pointer to Pair P is reported as a root, and not the constituent fields.
If I understand correctly, the proposal from last meeting is to modify ReWriteStatepointsForGC phase such that the GC-pointer fields of gc-aggregates are made explicit at statepoints.
We’ll have something like
Here, The main concerns with this approach is throughput: large number of arguments on statepoint instructions and associated relocations can degrade throughput. |
Report GcInfo for GcAggregates, Pinned pointers, GS Cookie Security Object, and Generics Context. The stackmap generated via Statepoints only handles SSA values, and therefore does not track pointers contained within GC-aggregates. To circumvent this problem, (1) Gc-aggregate stack allocations are marked frame-escaped to keep the allocation live throughout the function. (2) We report all pointers within GC-aggregates as untracked. Pinned pointers and other special symbols are handled similarly. Testing: NGEN of MsCorlib pass when built for precise GC. All CoreCLR tests passed when built for Precise GC (Statepoints inserted and GcInfo generated) but run with Conservative GC. dotnet-ci.cloudapp.net/job/dotnet_llilc_release_win64_prtest/1111/ Previously passing CoreCLR tests pass with Precise GC (108 tests failed). http://dotnet-ci.cloudapp.net/job/dotnet_llilc_release_win64_prtest/1112/ Notes: 1) GcInfo, Emitter and Recorder should be separated to different files. Will do in a separate checkin (to help view diffs for review) 2) DoInsertStatepoints can be enabled by default (while running with Conservative GC). Will do this in a separate change. Fixes dotnet#33, dotnet#29, dotnet#766, dotnet#767, dotnet#768
Issue dotnet#33 The stackmap generated via Statepoints only handles SSA values, and therefore does not track pointers contained within GC-aggregates. To circumvent this problem, (1) Gc-aggregate stack allocations are marked frame-escaped to keep the allocation live throughout the function. (2) We report all pointers within GC-aggregates as untracked. Issue dotnet#29 Pinned pointers are handled similarly. Issues dotnet#766, dotnet#767, dotnet#768 GS Cookie, Security Object, and Generics Context are tracked in the GcInfo and escaped. They are not reported in the encoder because we need some additional information. Testing: NGEN of MsCorlib pass when built for precise GC. All CoreCLR tests passed when built for Precise GC (Statepoints inserted and GcInfo generated) but run with Conservative GC. http://dotnet-ci.cloudapp.net/job/dotnet_llilc_release_win64_prtest/1111/ Previously passing CoreCLR tests pass with Precise GC (108 tests failed). http://dotnet-ci.cloudapp.net/job/dotnet_llilc_release_win64_prtest/1112/ Notes: 1) GcInfo, Emitter and Recorder should be separated to different files. Will do in a separate checkin (to help view diffs for review) 2) DoInsertStatepoints can be enabled by default (while running with Conservative GC). Will do this in a separate change. Fixes dotnet#33, dotnet#29
Value type GC fields need reporting, but don't naturally fit into SSA. Find a way to report them.
The text was updated successfully, but these errors were encountered: