Escape Analysis and Stack Allocation

Jeremy Manson jeremymanson at
Mon Jan 27 21:21:33 PST 2014

I tried implementing direct stack allocation in Hotspot a couple of years
ago.  It was a pain to try to allocate anything outside the heap - there
are a lot of checks to make sure that your objects live on the heap.

I ended up creating TLAB-like regions in the heap that could hold objects
allocated in a stack-like way.  It was a lot easier that way, and seemed to
give the kinds of performance benefits you would expect.

I never got around to trying to wire it up to Hotspot's escape analysis,
but it was a fairly obvious next step.


On Sun, Jan 26, 2014 at 12:26 PM, Aaron Grunthal <
aaron.grunthal at> wrote:

> There also is an issue with merge points [1] which prevents objects in
> loops with an accumulator (e.g. reduce operations on streams) to
> stack-allocate the intermediate values.
> [1]
> - Aaron
> On 26.01.2014 07:04, Benedict Elliott Smith wrote:
>> Hi,
>> I was digging into some (to me) unexpected behaviour of escape analysis,
>> namely that some references that clearly weren't escaping, and easily
>> determined to be so, were not being stack allocated.
>> So, after some digging through the hotspot code, I discovered some things
>> that were probably obvious to everyone on this list, but also some things
>> I'm still a little perplexed about. I was hoping somebody could enlighten
>> me about the latter.
>> 1) I cannot see a reason why stores to a primitive array, for instance,
>> should cause the argument to escape in bcEscapeAnalyser.cpp
>> *iterate_one_block()*; most interestingly, a store to an object array does
>> not result in this, which seems incongruous;
>> 2) An object array store *does* however result in *set_global_escape()*
>> for
>> the value being stored, which makes sense, except that this should only be
>> *set_method_escape()*, as per the paper, in the case where the target
>> array
>> is one of the method arguments. This seems to be missing, here and for
>> *putfield*.
>> Some other weird ones are *arraylength*, *getfield*, *ifnonnull*, etc. The
>> fact that these all result in *set_method_escape()*, and that
>> *putfield*and
>> *aastore* don't optimise *set_global_escape()* to
>> *set_method_escape()*where possible, seem to point to the conclusion
>> that *_is_arg_stack
>> / set_method_escape()* actually encode only *!is_scalar_replaceable*. Is
>> this the case? If so, why the confusing name?*
>> Which leads to a much trickier but more interesting question, which is:
>> what are the barriers to performing actual stack allocation of full
>> objects, instead of scalar replacement? It is something I would be keen to
>> investigate, but given my lack of familiarity with the codebase, it would
>> be immensely helpful to hear what the major difficulties / showstoppers
>> might be before trying to attack it.
>> Thanks in advance,
>> Benedict
>> *I do note that in escape.cpp *ArgEscape* is defined and is explicitly
>> overloaded to include some of the characteristics of
>> *is_scalar_replaceable*.
>> However the *is_arg_stack()* method is commented with "The given argument
>> escapes the callee, but does not become globally reachable." which seems
>> to
>> correspond to *ArgEscape* in the paper, but only *invoke()* seems to
>> follow
>> the spec, when invoking a method that cannot be analysed, and this would
>> also be true for *!is_scalar_replaceable.*

More information about the hotspot-dev mailing list