Reference favoring primitive class heap allocations

forax at univ-mlv.fr forax at univ-mlv.fr
Thu Sep 2 08:52:49 UTC 2021


> From: "Stig Rohde Døssing" <stigdoessing at gmail.com>
> To: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "valhalla-dev" <valhalla-dev at openjdk.java.net>
> Sent: Jeudi 2 Septembre 2021 00:23:29
> Subject: Re: Reference favoring primitive class heap allocations

> Thanks Rémi, I think it mostly does. I'll admit that the bit about optimizing
> local T.ref goes a bit over my head.

My point was that T.ref declared as a local variable can be optimized by the JIT avoiding heap allocation. 

Just today Tobias submit a PR that shows how c2 try to avoid T.ref allocation on heap for local variables even when there is no inlining 
[ https://github.com/openjdk/valhalla/pull/543 | https://github.com/openjdk/valhalla/pull/543 ] 

> What about method return values? If I declare a method as

> T.val someMethod()
> vs
> T.ref someMethod()

> and do

> T.val someLocal = someMethod()

> would the two methods have different behavior for how the value is returned from
> the call (Return the value in registers/put it on the caller's stack vs.put the
> object on heap and return a pointer to that), or is this determined by whether
> "someLocal" is a val or a ref and doesn't have anything to do with the return
> type of "someMethod"?

The two methods have almost the same behavior, apart from the fact that T.ref allows null while T.val does not. 
But they do not have the same "performance model". If you return T.val you ask to flatten T so it works even without inlining while if you return T.ref, the performance depend on the JIT being able to inline/optimize (so you may get the same performance or not). 

Rémi 

> Den ons. 1. sep. 2021 kl. 23.06 skrev Remi Forax < [ mailto:forax at univ-mlv.fr |
> forax at univ-mlv.fr ] >:

>> ----- Original Message -----
>>> From: "Stig Rohde Døssing" < [ mailto:stigdoessing at gmail.com |
>> > stigdoessing at gmail.com ] >
>>> To: "valhalla-dev" < [ mailto:valhalla-dev at openjdk.java.net |
>> > valhalla-dev at openjdk.java.net ] >
>> > Sent: Mercredi 1 Septembre 2021 12:43:46
>> > Subject: Reference favoring primitive class heap allocations

>> > Hi,


>> Hi,

>> > JEP 401 describes that current value-based classes will be made reference
>> > favoring to avoid breaking existing code. Optional is one of these. I'm
>> > trying to understand the impact this will have on existing APIs with
>> > respect to heap allocation.

>> > Please assume for the following code snippets that ordinary scalar
>> > replacement does not apply.

>> > As I understand it, code like

>> > Optional.val of(T item) { new Optional.val(item) }
>> > Optional.val<String> s = of("Hello")

>> > would tell the JVM that the Optional does not necessarily have to go on the
>> > heap, but could maybe go on the stack or in registers instead.

>> > When "of" is instead defined with the reference type, as in

>> > Optional of(T item) { new Optional(item) }
>> > Optional.val<String> s = of("Hello")

>> > will the Optional always go on the heap?

>> > Also is the plan to be able to avoid the heap for return values, or will
>> > the return value of

>> > Optional.val of(T item)

>> > always go on the heap unless "of" happens to be inlined?

>> > Thanks for reading.

>> Nope, there is only one way to create an object which is a primitive class.

>> Let's use an analogy, an ArrayList<String> at runtime can be typed as List<?> or
>> as List<String>, but it's the same ArrayList at runtime.

>> With primitive classes, it works the same way, a primitive class is always a
>> primitive class at runtime,
>> there is no two different ways to create a primitive class, there is only one
>> way (to call the factory method named <new> of Optional).
>> What is different, is that a primitive class can be typed in two different ways,
>> as an Optional.val or as an Optional.ref,
>> those two types mean different things in term of storage for a field, an array
>> element or a local variable.

>> T.val:
>> For fields and array elements, all the fields (if there are not too many) of
>> T.val are stored in the container of the T.val (the class or the array
>> containing the T.val)
>> For a local variable, T.val means that the VM will use registers (or spill the
>> values on stack due to the register allocator) independently of the inlining
>> algorithm.

>> T.ref:
>> For fields and array elements, a T.ref is stored as a reference (on heap).
>> For a local variable, T.ref means that inside the inlining horizon, the VM can
>> optimize the code using escape inlining with late rematerialization, so better
>> than a classical reference because a primitive class has no identity (in
>> practice it's a little more complicated because you don't want to
>> inflate/deflate the same object inside the inlining horizon).

>> I hope it answers to your questions.

>> regards,
>> Rémi


More information about the valhalla-dev mailing list