Source code analysis: calls to wrapper class constructors
John Rose
john.r.rose at oracle.com
Wed Oct 28 19:32:46 UTC 2020
On Oct 28, 2020, at 10:49 AM, Dan Smith <daniel.smith at oracle.com> wrote:
>
> You're right that this disrupts verification; I think we can address this pre-verification by rewriting the StackMapTable, eliminating all references to 'uninitialized(Offset)' and shrinking the stack by two.
Or we can try to keep the verification as-is by emulating the stack effects.
This requires inserting instructions, I think, but avoids reshaping the stack.
Maybe:
new Integer; dup; …(stuff that pushes int)…; invokespecial Integer.<init>(int)V
⇒
ldc_w (String)dummy; dup; …(stuff that pushes int)…; invokestatic Integer.valueOf(int)Integer; swap; pop; swap; pop
Maybe use a helper which can “gobble up” the stack junk in one go:
invokestatic Integer.valueOf(int)Integer; swap; pop; swap; pop
⇒
invokestatic Integer.$pop2$valueOf(String,String,int)Integer
If the dummy value has migrated somewhere random, it could be picked up and popped:
new Integer; astore L42; …(stuff that pushes int)…; aload L42; invokespecial Integer.<init>(int)V
⇒
ldc_w (String)dummy; astore L42; …(stuff that pushes int)…; invokestatic Integer.valueOf(int)Integer; swap; pop; aload L42; pop
As a further improvement on this theme, note that the dummy always has two copies, one to feed to invokespecial <init> and one to return to the user. The one to return to the user might be at TOS, or it might be elsewhere (in L42 or deeper on stack). We could do a peephole transform which finds the bytecodes that pull up the dummy value, move them *before* the $pop2$valueOf helper, and the net size change of bytecodes is zero. The location of the invokespecial <init> might move a byte or two later.
So:
new Integer; …(stuff like dup that stores a duplicate ref)…; …(stuff that leaves the new ref on stack, then pushes the int)…; invokespecial Integer.<init>(int)V; …(unrelated stuff)… …(stuff that ensures the replicate ref is now at TOS)…
⇒
ldc_w (String)dummy; …(same stuff like dup that stores a duplicate ref)…; …(same stuff that leaves the new ref on stack, then pushes the int)…; …(same stuff that ensures the replicate ref is now at TOS, but moved before the invoke)…; invokestatic Integer.$pop2$valueOf(Object,int)V; …(same unrelated stuff)…
This more elaborate scheme works for both the simple “dup” case and for the more complicated “astore L42” case. I don’t think it requires changing stack maps.
Hours of educational play for nerds 14 and up!
> The bigger limitation, which I don't think you run into in any javac-generated code, is that you can put a copy of the uninitialized object reference anywhere you want—in locals, duplicated 15 times on the stack, etc. That's the point where I'm guessing we give up.
More information about the valhalla-spec-observers
mailing list