LWorld1 initial phase proposal

Karen Kinnear karen.kinnear at oracle.com
Wed Dec 13 19:58:01 UTC 2017


Folks,

Based on Dan Smith’s write-up: http://cr.openjdk.java.net/~dlsmith/values-notes.html of a possible
LWorld direction, we’ve written a proposal for a potential initial LWorld1 prototype and would appreciate review.
We can walk through at our next meeting Dec 20th.

                           JVM Lworld Value Types Phase I

http://cr.openjdk.java.net/~dlsmith/values-notes.html

I. New terminology: for LWorld
 L-Type as reference or value type
 Q-Type as value type
 R-Type as reference only - open question - do we need this?

II. Assumptions:
1. New root: LObject - for all references and value types

2. Value Type characteristics:
  immutable (not all the way down)
  not nullable
  no identity
  flattenable when contained in reference, value type or array
  no default box (buffer, not box)
     - if you want identity, create a reference storing a value type field
  support interfaces

III. goals:
   existing interfaces should be implementable by both references and value types
    - without requiring recompilation
   existing code should be able to handle both references and value type arguments
    - without requiring recompilation

   Migration:
     LType -> QType migration
       author must opt-in: by declaring in source (language policy)
          - requires recompilation
     Any existing class that meets the requirements could become a value type
     ValueBasedClasses are candidates

     LWorld Value Type Static restrictions (for javac)
        j.l.Object as the only superclass
        no use of identity:
           no use of Object methods invalid for value types: wait/notify*/finalize
        no assumptions of nullability
        no non-private constructors
        no use of reference-only bytecodes: new, putfield, monitorenter/exit, aconst_null

      LWorld Static restrictions (for verifier) TBD
        no use of reference-only bytecodes: new, putfield, monitorenter/exit, aconst_null

      LWorld new Dynamic restrictions (based on dynamic type)
        for Value Types: no use of reference-only bytecodes: new, putfield, monitorenter/exit, aconst_null
        for Reference Types: no use of value-type-only bytecodes: vdefault, withfield
        no use of if_acmpeq/ne without following .equals call

IV: Non-goals:
    Primitives as value types - future phase

V. Expected Behaviors:

1. Object methods
  wait/notify/etc: if QType: throw ICCE (IncompatibleClassChangeError)
  getClass: normal behavior (no ambiguity with no default box)
  toString: nothing special
  clone: nothing special (must implement cloneable)
  finalize: ICCE
  equals: if QType - component-wise equals (ucmp API? ucmp bytecode?) (overridable)
  hashcode: TBD - needs to be based on equals

2. Java level APIs
  isValue
  isFlattened (for a reflection Field or array)
  isElementValue (for an array - not the same as is the array a Value)
  ucmp - substitutability check (not overridable)

3. Support beyond MVT
   Allow Value Types in static fields (not flattened)
   Method and method invocation support
   Interface support: default methods - must handle both L-types and Q-types

4. LWorld bytecodes vs. JVMS 9
Key Challenge: can we apply the same bytecodes to QTypes and RTypes? can they check dynamically without loss of performance?
  special handling:
     if_acmpeq/if_acmpne: false/true if either is a Qtype. They should fall back to .equals
     ifnull/ifnonnull: as if acmp vs. Null: false/true if QType

  needs dynamic different handling:
     aaload/aastore: handle LType or QType dynamically
     aload/astore: handle LType or QType dynamically
     areturn: handle LType or QType dynamically

  exception if wrong kind: ICCE
     putfield: QType exception: ICCE
     monitorenter/exit: exception for QType: ICCE
     new: exception for QType: ICCE (expects uninitialized state)
     aconst_null: exception for QType: ICCE

     vdefault: exception for LType: ICCE
     withfield: exception for LType: ICCE

  unchanged or already implemented (in MVT) or should fall out:
     getfield: handle LType or QType dynamically (already implemented)
     newarray/etc.: handle LType or QType dynamically (already implemented)
     athrow: always LType (subtype of Error)  - unchanged
     invoke*: handle LType or QType dynamically (should fall out)
     checkcast/instanceof: should fall out
     ldc: should fall out

V. Implementation use of explicit QType
1. Field descriptors
  Goal: not require verifier or class file parser to load all fields.
     ICCE if misclaimed, at first runtime mismatch (kind constraints)
     To allow flattening, want field and arrays to explicitly use QTypes at language level

2. Array descriptors: propose - yes
     Remi: not needed - at array creation you know the element type
     Propsal: uniformity
       - confusing to explain inconsistency
       - javac already knows the information and has done the work, why slow down?
       - safety - kind constraints - could be checked by verifier
3. Method descriptors : propose - no
   1) No indication of receiver type
   2) method descriptor parameters/return type - all use LTypes
   Propose: do NOT support QTypes in Method Descriptors
    challenge: descriptor mismatches based on migration
        - for client inheritance/overriding, caller/callee matching

Resolved Questions for LWorld1
1. Q: support other superclasses?
   A: QType has no subclasses
   A. for now - QType has only jlO as superclass, may be extended in future
      (see if any that would break any optimizations)

2. Q:acmp behavior options:
   a) failing: return false <- propose for try 1
   b) throw exception
   c) field-equality using ucmp as "substitutable" - field-wise comparison
     general bit equality including floating point
     may need to recurse on values buffereed
   A: LWorld1: if >= one operand is a QType: if_acmpeq -> false, if_acmpne -> true
   A: null handling: as if acmp vs. NULL
      if operand is a QType: ifnull -> false, ifnonnull->true

3. Q: Do we need to know if an LType is an old L-Type or a new LType?
   A: be on the lookout - we have not yet identified any cases
      - note: If we do, we have ClassFileVersion

4. Q: Any issues with argument passing/argument return handling if we have
      runtime mismatches of kind?
   A: If we have kind constraints then we should not get runtime mismatches
   A: advanced error handling - check implications if verification is skipped

5. Q: Do we need a new carrier type?
   A: TBD - so far requirement not identified.

6. Q: What does it mean for LObject to be more like an interface?
   A: TBD (TODO - ask Dan?)
      A1. disallow adding fields
      A2. superclass of references and value types (with modified methods)

7. Q: Do we need a fast way to distinguish an LType from a QType? in the JVM itself?
   A. Initial prototype can work with instancKlass vs. valueKlass
      Later - look at potential optimizations

8. Q: What does updated Object.hashcode do?
    - field equality based hashcode
    - assume cache in header optimization ?
  A: Dan: call hashcode or identity hashcode (throw) - performance tradeoff

9. Q: Do we need a fast way for Java to determine ValueType (isValue call?)
    A: Frederic proposed: e.g. give all value types a common super interface
        e.g. ValueMarker
  - verifier or class file format checking at class loading
    - ensure that this can't be a superinterface if not a value type
    - this is probably temporary, but useful

10. Q: Migration QType->LType support?
  Customers will try this
  A: Need to ensure we catch failures
  challenges:
    instance creation:
      value type - must have a private constructor - so new will fail IAE
        - except for nestmates (dynamically added which are not same compilation)
        - except Reflection.setAccessible

11. Q: Circularity handling for Field types?
    A: today we get StackOverflowError - hotspot folks propose we leave that alone
       to avoid complexity and costly testing

12. Q: Class.forName() and internal loaded class cache
    A: NO L vs. Q type naming here, there is no ambiguity

Unresolved Questions for LWorld1
1. Q: Reflection requirements/plans?

2. Q. What can the verifier check, what do we want to check later to avoid early class loading?
   A. Expect to create kind constraints, if we have bytecodes that require a value type
      which would be checked when we load that value type and throw ICCE
   A. Verifier can still check primitive vs. LType - leave those checks in
   A. note: for loaded classes such as supertypes, value type fields or isAssignable checks, some classes are already loaded, so may not need a kind constraint
   Q: Do we also need to do this for references - e.g. "new" bytecode?
   Q: Is there a concern that by loading a class that uses the wrong bytecodes for someone else's kind - that could prevent a class from successfully loading?

===================
Early experiment:
Add to JDK 11 (not MVT specific)
 add dynamic checks for ValueBasedClasses
    follow LWorld dynamic restrictions
 add checks for ifacmp_eq/ne NOT followed by a call to .equals?
 (todo: find Dan's corpus search results email)
 todo: consider using JFR? This will be open in jdk11

Experimental steps:
1. new repo - remove MVT parts, just include -XX:+EnableValhalla tests (already split)

2. LangTools:
2.1 test bytecode generator
    - generate LWorld bytecodes (from simp

2.2 Javac:
  __ByValue for class declaration (for simplified JVMS bytecode changes document)
     request:
       super as java.lang.Object
       generate LWorld bytecodes
       LWorld restrictions checking
         - e.g. allow superinterfaces , allow value types in static fields

2.2 new static utility class for new bytecodes
   isValue
   isElementValue (for array)
   isFlattened (for field or array)
   ucmp

2.3 java.lang.Object methods
   Using isValue - rewrite

2.4 real JVMS LWorld1 proposal - Dan

3. Runtime
a. write up simplified JVMS bytecode changes document (not verifier yet)
b. interpreter bytecode changes - see list above
c. migrate VVT tests to LVT1
d. verifier -
   propose JVMS verifier changes
   propose kind constraint handling - to not add any additional
     class loading
     - note: value type fields, supertypes and isAssignable checks already perform loading
e. method handle support

4. JIT:
a. bytecodes
b. migrate VVT tests to LVT1
c. adaptor generation
d. optimizations


5. Core libraries:
a. methodhandle support - e.g. changes to LambdaForms
   - (simplified from MVT with no __Value)
   - no boxing
b. Reflection/new reflection?
   TODO - what are the requirements here?

6. Migration testing:
Try VBC -> value type -- run tests and see what breaks






More information about the valhalla-spec-observers mailing list