On Oct 28, 2020, at 10:49 AM, Dan Smith <daniel.sm...@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.


Reply via email to