
HotSpot compiler: Stack allocation prototype for C2 - The_rationalist
https://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/2020-June/038779.html
======
chrisseaton
I'm anticipating a lot of confusion and people talking past each other in this
thread.

C2 already does escape analysis, and scalar-replacement-of-aggregates to turn
objects that don't escape a compilation unit into dataflow edges, which if
possible is far better than the stack-allocation in this article because you'd
rather not write out to the stack if you don't have to, and you'd like unused
parts of the object to disappear. Graal then adds partial-escape-analysis to
float reification of an object to the last-safe-moment.

What _this_ does on top of that is then to cover the corner case where an
object would be safe for SRA, except something requires the object to have the
same layout as on the heap. I think a concrete example of this is some
intrinsics and merges where an object needs to be heap-allocated on just one
branch, so that code following the merge can have a full object in both cases
and not care that one has been allocated on the stack.

The key to avoiding confusion - 'allocating on the stack' in this case means
literally allocating the full reified object in stack memory, whereas in C2 at
the moment when people say 'stack allocation' informally they mean SRA.

C2 already removes reference type allocations when they don't escape a
compilation unit, which is something I think C# doesn't yet do at all for some
reason I don't really understand.

~~~
noblethrasher
It appears that the .NET Core CLR does perform some rudimentary escape
analysis:
[https://github.com/dotnet/coreclr/pull/6653](https://github.com/dotnet/coreclr/pull/6653)

~~~
chrisseaton
Right - and that supports the stack-allocation, not SRA, which is what I think
C# doesn't have - possibly because they prefer explicit value types over
trying to do it automatically through SRA.

------
eggsnbacon1
I wonder what Oracle will think about this. Isn't this one of the "big"
optimizations you only get with Graal EE $$$ right now? Its going to be ironic
if external contributors keep C2 as on par with Graal EE.

~~~
chrisseaton
No I don't believe this is in Graal EE. I think you may be mistaking it with
partial escape analysis, which can float reification of an object on the heap
to the branch where it is needed and let it stay virtualised on other
branches. This post is about actually allocating the reified object on the
stack. I don't believe Graal does that in any configuration.

------
The_rationalist
Those are the first results of the renewed interest from Microsoft to
contributing to the JVM cf
[https://news.ycombinator.com/item?id=21837508](https://news.ycombinator.com/item?id=21837508)

I wonder what others lovely optimizations/improvements they will bring :}
Especially which optimizations from the C# world will they transpose to the
JVM world. According to the benchmarckgame C# is the fastest on earth JITed
language

~~~
wokkel
The benchmarkgame result are comparing apples to oranges. I stopped after
seeing them tests Java regexes tot c# regexes which uses the native pcre
library. In my professional experience, the .net jit is nearly always slower
than the jvm one.

~~~
ygra
With .NET 5 the fastest non-PCRE C# regexredux implementation there completes
in five seconds on my machine, as opposed to 8 seconds for the Java
implementation. Still quite a bit away from C, but I'd say respectable for a
purely managed implementation.

It helps that the team has done a lot of optimizations for regex and other
parts of the standard lib in the past few months.

------
paavohtl
I don't understand the "and C#" part. C# has had stack allocation support (for
primitives, structs and fixed size arrays) since the very first release.

~~~
shellac
You'll find the detail in [https://github.com/microsoft/openjdk-
proposals/blob/master/s...](https://github.com/microsoft/openjdk-
proposals/blob/master/stack_allocation/Stack_Allocation_JEP.md)

This is about stack allocation of objects where safe (i.e. when you can prove
they don't escape the local scope) for Hotspot, something that already exists
in J9 (IBM's JVM) I think.

There is equivalent work for .net core here:
[https://github.com/dotnet/runtime/blob/master/docs/design/co...](https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/jit/object-
stack-allocation.md)

(So the title is somewhat accurate, but you have to do some digging)

------
divs1210
Cheney on the MTA and its various implementations (like Chicken Scheme [0])
have been allocating objects on the stack for ages. Would like to know how
this compares.

[0] [https://www.more-magic.net/posts/internals-gc.html](https://www.more-
magic.net/posts/internals-gc.html)

~~~
chrisseaton
This is a bit different. My understanding (but I'm not an expert) is that
Chicken uses the stack effectively as the thread allocation buffer, which is
clever because it's already thread-local using an existing register, and it's
already in cache. They then evacuate from the stack to the old generation (or
a separate young generation? I'm not sure). This isn't what is being done in
the work referenced in this article, as objects are known in this case to be
long-term safe to allocate on the stack - it's not using it as an allocation
buffer.

But my understanding of Chicken is limited - maybe you were asking
rhetorically and you knew more?

------
kasajian
I don't understand. we've always been able to allocate value types on the
stack in C#.

~~~
didibus
What I understand is that this is stack allocating reference types, when the
compiler can infer that it is safe to do so. Which I think is an optimization
.net Core desktop doesn't yet do.

Also worth noting, I believe .net Core doesn't necessarily stack allocate
value types either, seems a lot of conditions can make it unsafe as well, like
a closed over value type that could escape the local scope, so value types
arn't always stack allocated either. Only done when it is safe to do so.

~~~
entha_saava
> like a closed over value type that could escape the local scope

You mean, captured in closure?

~~~
ygra
I guess that's what they meant. However, that's a bit misleading, since the
runtime doesn't care about that that's a value type captured in a closure, as
it's a class field in IL already. And those are always allocated like their
containing type.

------
pjmlp
Please fix the heading, C# has had stack allocation since version 1.0 (value
allocation to be more precise).

The linked content is only about Java.

~~~
sz4kerto
Stack allocation and value allocation are different. In C#, value types can be
allocated on the stack, but reference types are always allocated on the heap.
The OP describes an approach where reference types are stored on the stack.

~~~
littlecranky67
But doesn't the 'stackalloc' keyword in C# allow you to express to
intentionally allocate value types on the stack?

~~~
giulianob
I'd say ref structs are more explicitly stack allocated since they're not
allowed to be boxed. Stackalloc is used to allocate arrays on the stack (or
rather a block of memory).

