[PATCH] Statepoint infrastructure for garbage collection

Philip Reames listmail at philipreames.com
Thu Oct 16 14:51:58 PDT 2014


On 10/15/2014 02:52 PM, Philip Reames wrote:
> Kevin,
>
> Let me try to answer the point you're getting at.  In doing so, I want 
> to explicitly separate the statepoint intrinsics which are currently 
> up for review, and the future late safepoint placement. The statepoint 
> intrinsics have value separate from the late safepoint placement 
> approach, and I want to justify them on their own merits.
>
> The basic problem we're trying to solve with these intrinsics is 
> supporting fully relocating collectors.  By definition, such a 
> collector needs to be precise w.r.t. root tracking.  Even worse, we 
> need to ensure that *all copies* of a pointer are updated.  It is not 
> acceptable to make two copies of a pointer, update one of them, then 
> use the other for a memory access.
>
> If the compiler is allowed to introduce derived pointers (i.e. pointer 
> valued temporaries created by the compiler which point somewhere 
> within an object, or outside it, but associated with it), we also need 
> to track which *object* each *pointer* to be updated is associated 
> with.  This is required to safely update the pointers.
>
> For the sake of argument, let's say our frontend does safepoint 
> insertion.
>
> There's a couple of approaches which seem like they might work, let's 
> explore each in turn:
> - We could use patchpoints to record all the values needed for the GC 
> stack map.  This mostly works, but requires that the patchpoint not be 
> marked readonly or readnone (to prevent illegal reorderings).  That 
> could be a usage convention.  The real problem is that the compiler is 
> still free to introduce multiple *copies* of an SSA value over the 
> patchpoint.  (This is completely legal under SSA semantics.)  When it 
> does so, it creates a situation where the gc could fail to update a 
> pointer which will then be dereferenced. That's a bug.  Worth stating 
> explicitly, I believe the patchpoint scheme would be sufficient *if 
> you do not every relocate a root*.
> - We could use the gc.root.  gc.root defines the allocs, but does not 
> define the call format, or any of the mechanisms to ensure proper 
> relocation.  As such, it *by itself* is not viable.  Also, gc.root 
> inherently assumes every value will have a stack slot. Without *heavy* 
> reengineering, there's no way to have a gc pointer in a callee saved 
> register over a call site.  This is an unfortunate limitation.  Any 
> call representation without explicit relocation suffers from the same 
> bug as the patchpoint scheme.
> - We could combine gc.root allocas and patchpoints.  This essentially 
> combines the flaws (no gc pointers in callee saved registers over 
> calls, and missed copies), with no benefit.
>
> The statepoint intrinsics are basically the patchpoint option above, 
> but with relocation made explicit in the IR.  While it's still legal 
> for the optimizer to create a copy of the value feeding a statepoint, 
> that's now okay.  By construction, there can be no use of the original 
> SSA value (and thus the copy) after the statepoint. Instead, the 
> explicitly relocated value is used.
>
> To summarize: We need (something like) statepoints for correctness of 
> fully relocating collectors.
>
> (The points I'm making here are somewhat subtle.  If it would help to 
> have IR examples here, ask.  I'm deferring writing them because it's 
> time consuming.)
I need to withdraw this part of my comments.  After further reflection 
and discussion offline, I was reminded that you can implement full 
relocation semantics with gcroot.  The parts about patchpoints stands, 
but the gcroot comments are inaccurate.

I need to leave early today, but I plan to respond tomorrow with a more 
complete analysis of the tradeoffs between gcroots and statepoints.  
Sorry for the confusion.
>
>
> Other advantages of the statepoint approach:
>
> The gc.relocate intrinsics (part of the statepoint proposal) also 
> makes it explicit in the IR what the base object of each pointer to be 
> relocated is.  This isn't *required* (you could encode the same 
> information in the arguments of the statepoint), but making it 
> explicit is much cleaner.
>
> The explicit relocation notation has the potential to be extended in 
> to the backend.  With some register allocator changes (not part of 
> this patch!), we could support gc pointers in callee saved registers.  
> This is possible with the (incorrect) patchpoint scheme.  It is 
> possible, but *hard*, with the gc.root scheme.
>
> The posted patch includes a couple of small optimizations (i.e. null 
> forwarding) that help performance, but could (probably) be implemented 
> on top of another scheme.  We have a number of planned optimizations 
> on the statepoint mechanism.
>
>
> Now, let me finally bring up late safepoint placement. The only real 
> impact on this patch is that, to date, we have only focused on the 
> *correctness* of a statepoint passing through the optimizer.  We have 
> not attempted to teach the optimizer about how to leverage one or 
> perform optimizations over one.  There's room for improvement here 
> (i.e. not completely blocking inlining), but we prefer to approach 
> this problem by simply inserting them late.   You could instead choose 
> to insert them at generation time, and teach the optimizer about their 
> semantics.  That *strategy choice* is independent of the 
> representation choosen provided that representation is *correct*.
>
> Yours,
> Philip
>
> On 10/14/2014 07:01 PM, Kevin Modzelewski wrote:
>> I think a change like this might be more compelling if you could give 
>> more detail on how it would actually help (I can't find the detail 
>> I'm looking for in your blog posts).  It seems like the value of this 
>> patch is that it will work with late safepoint placement, but it'd be 
>> nice to see some examples of cases where late safepoint placement 
>> gives you something that early safepoint placement (ie by the 
>> frontend) doesn't.  It kind of feels like either approach will work 
>> well with only non-gc values, and neither approach will be able to do 
>> much optimization when you do function calls.  I'm not trying to 
>> claim that that's necessarily true, but it'd be easier to understand 
>> your point if there was some example IR.
>>
>> http://reviews.llvm.org/D5683
>>
>>
>




More information about the llvm-commits mailing list