JDK-8366271 : Valhalla: verification adjustments for operations on 'uninitialized'
  • Type: Enhancement
  • Component: specification
  • Sub-Component: vm
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2025-08-28
  • Updated: 2025-09-06
  • Resolved: 2025-09-06
Related Reports
Blocks :  
Relates :  
Relates :  
Description
Some opcodes are allowed by the verifier to operate on 'uninitialized' types, of the forms 'uninitializedThis' and 'uninitialized(Address)'. In practice, doing so is rarely useful. For larval value objects, some of these operations do not make sense and should be restricted.

The following are important and useful:
astore
dup
pop
swap
invokespecial
putfield

----

if_acmp<cond>

In most cases, an 'uninitialized' input is == to itself and != to everything else. (Corner case: two identical 'uninitialized(Address)' types may refer to different uninitialized objects, produced by the same instruction.)

With value objects, we cannot allow larval fields to be observed by acmp. The verifier should disallow any 'uninitialized' input and only allow the operation on type 'Object'.

----

ifnull/ifnonnull

The null type is not a subtype of 'uninitialized' (4.10.1.2), so the value can never be null.

Value objects do not introduce any new behavior, but we should prevent this obvious bytecode bug, only allowing 'ifnull'/'ifnonnull' on type 'Object'.

----

monitorenter/monitorexit

These operations do have some practical use: do 'monitorenter' before calling 'super()' (or a 'new' object's '<init>' method), and the creating thread can guarantee that no other thread will get the monitor first.

A verifier change was considered a few years ago, but we opted not to (JDK-8180581). At the time, J9's verifier would reject the operation.

Value objects always throw, and can likely keep doing so even when larval. So no change necessary here.
Comments
Updated spec changes posted here: https://cr.openjdk.org/~dlsmith/jep401/jep401-20250905/specs/value-objects-jvms.html
06-09-2025

Concrete changes to verification rules: instructionIsTypeSafe(if_acmpeq(Target), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :- ~~canPop(StackFrame, [reference, reference], NextStackFrame),~~ **isBootstrapLoader(BL),** **canPop(StackFrame, [class('java/lang/Object', BL), class('java/lang/Object', BL)], NextStackFrame),** targetIsTypeSafe(Environment, NextStackFrame, Target), exceptionStackFrame(StackFrame, ExceptionStackFrame). instructionIsTypeSafe(ifnonnull(Target), Environment, _Offset, StackFrame, NextStackFrame, ExceptionStackFrame) :- ~~canPop(StackFrame, [reference], NextStackFrame),~~ **isBootstrapLoader(BL),** **canPop(StackFrame, [class('java/lang/Object', BL)], NextStackFrame),** targetIsTypeSafe(Environment, NextStackFrame, Target), exceptionStackFrame(StackFrame, ExceptionStackFrame).
28-08-2025