Source code analysis: calls to wrapper class constructors

forax at univ-mlv.fr forax at univ-mlv.fr
Wed Oct 28 20:05:15 UTC 2020


> De: "John Rose" <john.r.rose at oracle.com>
> À: "Remi Forax" <forax at univ-mlv.fr>
> Cc: "Valhalla Expert Group Observers"
> <valhalla-spec-observers at openjdk.java.net>, "daniel smith"
> <daniel.smith at oracle.com>, "valhalla-spec-experts"
> <valhalla-spec-experts at openjdk.java.net>
> Envoyé: Mercredi 28 Octobre 2020 20:08:30
> Objet: Re: Source code analysis: calls to wrapper class constructors

> Please accept the Tiger Woods Code Golf award for that one!
Did i win something, a free t-shirt :) 

> It only works if the “dup” output (after “new”) is still contiguous
> on the stack. That won’t be true if javac for some reason spilled
> the result of “new” to a local instead of holding it on stack.

> IIRC one reason to spill from stack to locals during expression
> evaluation is if there is some kind of complicated control flow
> inside the expression. Different javac’s historically have
> different policies about stuff like that.

I've never seen such bytecode shapes but I don't think i've ever seen a classfile compiled with a version which was less that Java 1.2. 

Rémi 

>> On Oct 28, 2020, at 4:25 AM, Remi Forax < [ mailto:forax at univ-mlv.fr |
>> forax at univ-mlv.fr ] > wrote:

>> ----- Mail original -----

>>> De: "John Rose" < [ mailto:john.r.rose at oracle.com | john.r.rose at oracle.com ] >
>>> À: "daniel smith" < [ mailto:daniel.smith at oracle.com | daniel.smith at oracle.com ]
>>> >
>>> Cc: "valhalla-spec-experts" < [ mailto:valhalla-spec-experts at openjdk.java.net |
>>> valhalla-spec-experts at openjdk.java.net ] >
>>> Envoyé: Mercredi 28 Octobre 2020 05:56:29
>>> Objet: Re: Source code analysis: calls to wrapper class constructors

>>> On Oct 27, 2020, at 12:27 PM, Dan Smith < [ mailto:daniel.smith at oracle.com |
>>> daniel.smith at oracle.com ] > wrote:

>>>> This tooling will support common bytecode patterns like 'new Foo; dup; ...;
>>>> invokespecial Foo.<init>;', but will not be a comprehensive solution.
>>>> (Mimicking the behavior of instance initialization method invocation in full
>>>> generality would be a very difficult task.)

>>> One of the reasons it’s not going to be comprehensive
>>> is code like new Integer(complicatedExpr()), in which
>>> the `new` and `invokespecial <init>` are separated
>>> by (almost) arbitrarily complex bytecode. The two
>>> instructions don’t even have to be in the same basic
>>> block (at the bytecode level):

>>> new Integer(foo() ? bar() : baz())
>>> // compiles to 4 BB’s in a diamond

>>> If we add switch expressions with large sub-blocks,
>>> I think we get peak separation of the start and
>>> end parts of the new/init dance:

>>> new Integer(switch (x) {
>>> case 1 -> { complicatedBlock: try { … } catch ... ; return 0;
>>> default -> { for (;;) … }} )

>>> All of this gives me yet one more reason we would have
>>> been better off with factory methods instead of
>>> open-coding the new/init dance. It was, in hindsight,
>>> a false economy to open code the object creation “guts”
>>> instead of putting them in factory API points.

>>> And with an eye toward future evolutions of legacy code
>>> (legacy code not yet in existence!), and uniformity with
>>> the factory methods of inline classes, let’s try harder
>>> to get rid of the new/init dance for identity objects.

>> I believe there is a quick and dirty trick,
>> replace new java/lang/Integer by 3 NOPs and replace INVOKESPECIAL
>> java/lang/Integer <init> (I)V by INVOKESTATIC java/lang/Integer valueOf
>> (I)Ljava/lang/Integer;

>> It has to be done after the code is verified because the new execution doesn't
>> push java/lang/Integer on the stack anymore before calling the arbitrary init
>> expression thus any StackMapTables in between the NOPs and INVOKESTATIC are
>> invalid.

>>> — John

>> Rémi


More information about the valhalla-spec-observers mailing list