Valhalla EG notes March 14, 2018
karen.kinnear at oracle.com
Mon Mar 26 21:33:33 UTC 2018
attendees: David Simms, John, Frederic, Dan S, Tobi, Dan H, Remi, Karen
apologies for not noting the meeting time change in US/Canada relative to Europe - should be all set now
Corrections as always - welcome
John: Check Nashorn usage of BSM with Object as 1st parameter
John: email proposal about usage of MethdHandle for ldc including usage examples
All: review https://bugs.openjdk.java.net/browse/JDK-8171335- - dynamic nestmates (+) proposal
- read it through - comments have updated the proposal from the initial description
All: John issued a challenge - non-vacuous meaning of final for Value Types
Dan S - are folks ok with the BSM descriptor change - distinguishing with Lookup as 1st parameter, and throwing error if not to allow this as a future differentiator?
Karen: Lois, Karen ok
Dan H: decreases ability to use BSM with Object today - expect this is vanishingly small use case - so OK
What about Nashorn usage?
John : AI: check
Dan H: believe JRuby started with Lookup
John: in practice - this could be an unambiguous distinguisher for condy - since it is new
for indy - if we adopt the restriction they can be similar
alternative: we could add a new combinator in front of a new BSM with a new protocol to get the new capability
Dan S: condy is often simpler to create, creating a CallSite is more complex
John: today: condy is adding an invocation to do what we wanted the VM to do for us
Brian has an example in Amber handling symbolic expressions creating syntax trees, with an BSM per level of expression, all named “invoke” - which is a “smell”
A bigger cleanup would combine all three invokes into one, i.e. a multi invoke BSM with args
perhaps 1 multiinvoke BSM with constants and delimiters in the right order which invokes an expression tree
no longer 1:1 CP entry to function call
we may not need the VM to cache the intermediate steps
Dan S: the natural way to express syntax trees in the the CP is to have each node with its own constant and BSM map
John: need ways to deal with sub-expressions
John: another future idea
invoke dynamic constants to be LDC able - i.e. to return a MethodHandle rather than a CallSite
completes a matrix:
constants have 2 forms: 1 field type, 1 method type
indy constant: MethodType type (actually MethodHandle)
if indy constant mentions a MethodType give me a MethodHandle with signature
ldc - invoke exact or ldc -> MethodHandle behavior
want JVM to ensure signature is an exact match
Dan H: Is the MethodHandle a dynamic invoker invoked through the CallSite or a 1 time?
John: dynamic invoker as if a free floating CallSite
as a forward compatibility direction
- allow indy BSM to return a MethodHandle as well as CallSites
if need a CallSite and get MethodHandle - wrap a constant CallSite around it
note: Mutable CallSites - used by dynamic languages - only work for indy and are not in the CP
[ed. note - is that accurate? an indy BSM can not return a Mutable CallSite?]
Dan H: If VM creates the CallSite - no one could change it if no references leak
Karen: indy BSM today is not shareable, ldc has 1:1 CP entry and resolved value
would a BSM for ldc MH be shareable?
John: [ed. note - missed the answer?]
Karen: who creates the CallSite if ldc resolves to a MethodHandle?
John: Not the VM
Dan H: already have condy, struggling to find use case
John: get MH w/signature w/out creating asType and MH constant
Dan S: Lambda produces a MH
John: we can do this with condy today but it neds an extra layer - could reduce noise in CP
Karen: is there a write up?
John: AI: email a proposal
Dan S: With BSCI, one of the goals is to move the complexity to the library
John: concept of a “butterfly network”
Allow any use case to use any constants - relative to field and method types. Move the type mixups to low levels of
Dan H: does this negate the need for condy?
John: VM has a natural type system - with separate field types and method types represented in the CP and bootstrap level
combinators, pattern matchers, lambdas - still work with j.l.Class and j.l.MethodType which are the reflected field and method types
where possible, nice to have a low level approach that works for both
one doesn’t reduce to the other except for simulators
Dan H: aware we can do this easily, where do users see this?
John: users are classfile translation strategy designers, currently using lots of MH
want to create expression trees out of field types and invocation
Karen: can you provide examples?
Dan H: yes please
Remi: concerns: not want two different ways to do the same thing - will send comments in reply to the minutes
Karen : Sealed classes will not make JDK 11
Dynamic nestmates - exploring - possibly part for JDK 11
Proposed approach: extend MethodHandles.Lookup
1. Create dynamic nestmates
For static nestmates, explicitly designed so that the NestHost “authorizes” NestMembers.
For dynamic nestmates, propose using providing a Lookup with appropriate mode on the NestHost as authorization to create a NestMate
John pointed out we need to distinguish between a Private Lookup and a Full Power Lookup and we need to
have that conversation for appropriate mode here.
In JDK9 we added a Lookup.defineClass with Package mode which allows defining a class within a package.
Intention is to extend this to allow defining a dynamic Nestmate with the same capabilities as a static nestmate,
with the exception that the java.lang.Class.getNestMembers()” will only return the statically declared members.
Dan H pointed out: we will need an API to get the dynamic members
2. evolve unsafe.DefineAnonymousClass to a supported mechanism
Proposal is to extend Lookup.defineClass with the appropriate mode to allow
- defining an UNNAMED class - i.e. not findable in the SystemDictionary
- defining a TEMPORARY class - which must also be UNNAMED - allowing class unloading on a different lifecycle than the creator or host
See RFE: https://bugs.openjdk.java.net/browse/JDK-8171335
The intention is that the three flags/enums: NESTMATE, UNNAMED, TEMPORARY are independent,
so you can use this to create non-nestmates. Need to look at the required Lookup modes and make a matrix.
In addition, there is a proposal to replace the constant pool patching with the ability to pass in a single live type which is as if you had a pre-initialized static, not in the constant pool, which can only be retrieved via an API on the Lookup.
Dan H: is this live type necessary given condy?
John: yes - you need at least one object reference which you can inject in a class to associate with user data so that you have this when you run the static initializer
Dan H: note: never implemented the constant pool patching for unsafe.DefineAnonymousClass - never found a use for it.
John: relates to condy
condy does symbolic resolution from the current class’ context
this mechanism can have a different context
Dan H: users could have a condy BSM which they write themselves
John: only via symbolic references - if the class is temporary, i.e. has no name - they would need a local namespace shared between the definer and the defined class itself
Dan H: or a common named class to communicate through
John: concerns about race conditions and privacy problems, this is not a class loader isolation model which is considered less safe today
Dan H: how look up live data?
John: method call on Lookup on your own class - no one else can get to it
as if injected class has an extra static variable pre-initialized
library API: getUserData, not getStatic
if you can think of another way to initialize a private static final variable with a value that is unnamed and unknown to the definer (and not trust thread locals)
Dan H: sounds similar to ClassValue
John: alternative trick? Can’t print if it is not yet loaded
Remi: or thread local
John: assume initiating loader
Karen: intentional - not required to be seen by initiating loader?
John: this is a live class, avoid name/symbolic reference, not required to be in a shared namespace
Remi: want to ensure that when the class’ lifecycle is over, the live type is not kept alive
John: for class lifecycle - ensure UserData can be acted. UserData lifecycle should not keep the class alive.
[ed. note - I added that note to the RFE]
John: computed before class is defined as if set static before class initializer is run
Remi: use case - AST - want to pass in with bytecode
John: could serialize AST into CP of the new class
Remi: would have to reconstruct and lose profile data
Karen: you are using the CP patching today, right?
John: Remi - ok with you to replace with UserData?
JohnL not expect <init> to play a big role with value types, it is a Object initializer, moving toward factory methods
Remi: need to test Srikanth’s changes for withfield syntax
John: repurpose constructor syntax
Remi: could use static methods
Karen: checked with verifier - ok to reuse name <init> if helpful
“final” value type fields:
John: can we skip marking value type fields as “final” - no benefit - might want to have meaning in future
Dan H: expected the other way - preserve final now so semantics don’t change if future more options
Remi: javac use final to detect changing a field of VT
John: benefit of final bit?
Remi: vm - no, javac -yes
Dan H: if we take it away in future, it will need to be meaningful
John: potential future option:
not stateful values
final for Object means can only be set in a constructor (write once)
westfield means withfield
state changes only in constructor
Dan H: that is a discussion of the scope of withfield
John: constructor or nest?
if final means restrict setting - nonfatal could allow setting based on access controls
always do Copy-on-Write
who is allowed to replace single fields?
Remi: that is a class level, not a field level decision
John: final - want smaller than class, maybe just constructors?
Remi: that would change the meaning of final - change all reflection and all tools that process bytecodes
Dan H: VM would require a known factory?
John: codes like a class - marker for all classe - final allows limited writers
use cases - e.g. serialization - that need to set final fields outside of a constructor
Remi: they could call a constructor
John: simulation of “new” bytecode
- e.g. Cloneable - no way to clone all final fields
writing up Reconstructor/Deconstructor
Reconstructor - like a constructor - acts as a factory
secretly temporarily cloning object
and patch new fields even if final
Remi: how to create factories on VT - see if they will apply to Object
rather than changing semantics of final
base this on withfield access
John: if final means access to withfield - maybe another modifier bit for new tricks
Question: if final in VT fields now - what would be the meaning if unset in future?
Dan S: bar higher if unset by default
precedent: classfile has redundant info for consistency
Remi: clone - is a class level decision, not a field decision
look at the class semantics for the new modifier
John: final-withdraw set operation: objects: putfield, values: withfield
Dan S: final bit for VT: default put final - i.e. not mutable
John: can be mutated? what about a field initializer? Create a constant for a field? No.
Dan S: sort out with VT how to interpret nonfinal vs. final
John: challenge - find non-vacuous meaning for final for VT - which have different physics
Remi: plenty of modifiers can use - at the class level, not the field level e.g. volatile
John: volatile - need atomic marking - use ACC_VOLATILE?
Remi: use a different bit if you want a different semantic - first get a clear design of a factory
John: another model:
withfield allows setting with no side effects
nesmates can use withfield - not confined to factories/constructors/reconstructors
final means can’t use withfield outside nest
RemiL VM vs. Reflection & JDK: can’t call set on it
DanH: putfield will not verify on a value type
John: link time will throw ICCE
More information about the valhalla-spec-observers