hg: valhalla/valhalla: Scanner, parser, semantic analysis and attribution support for value types

Srikanth srikanth.adayapalam at oracle.com
Thu Feb 1 01:00:29 UTC 2018


Hi Karen,

(1) Regarding your question about the use of [v]withfield, here is what 
javac is doing in the VVT project:

      - A static method declared in a value class may be tagged with the 
modifier __ValueFactory.
      - The return type of such a static factory method must be 
identical to the value class of which the static factory is a member.
      - Value instances are created with the no-arg invocation 
of__MakeDefault ValueType().
      - yes, there needs to be at least one such factory - no factory at 
all means that there is no way to create value instances of that type.
      - __MakeDefault and new cannot be used for cross purposes.
      - Invoking __MakeDefault outside of the corresponding static value 
factory is an error.
      - The static factory method is also "privileged" in the sense that 
it is allowed to assign to blank final instance fields of the 
corresponding value class.
      - It is precisely such assignments are lowered into vwithfield 
instructions. *So you should never expect to see a vwithfield 
instruction outside of a static value factory. (likewise for 
vdefault/defaultvalue) in javac generated code*

The above holds for the VVT project.

I imagine that javac's use of withfield & defaultvalue in the LWorld 
would match the above (unless Frederic's draft changes to JVMS call for 
different behavior - I am still reading through these). In particular, 
there is no special provision for nestmates ATM.

You asked: "would it also make sense for an instance method that sets a 
field to create a new value instance using the current values of the 
starting instance fields and explicitly set a field (or set of fields)"

Ans: No. This is not supported in VVT and also not in Lworld: Assignment 
to blank finals cannot be allowed anywhere else (outside of constructors 
and static value factories) without calling into question the very 
meaning of finality.

(2) For javac treatment of null assignment to values, casting null to 
values and null comparison against values: I'll wait for minutes from 
the EG discussion.

(3) For == and != with at least one statically discernible value 
instance, this is what I think makes sense:
Given that jvm's planned implementation of acmp when at runtime at least 
one of the operands is found to be a value is to evaluate to false, we 
have three choices:

(a) mimic the runtime behavior and fold the == or != into false/true at 
compile time.
(b) forbid the operation as ill conceived operation
(c) lower it into acmp and let the vm handle it - this would be 
"sub-optimal" in some sense.

(b) is the present behavior. I will discuss this with the team to see if 
any change is called for and share what I hear.

(4) ATM, it does look like "exp" should not have been the branch for the 
commit, I will follow up as soon as there is clear confirmation.

Thanks!
Srikanth




On Wednesday 31 January 2018 08:35 PM, Karen Kinnear wrote:
> Srikanth,
>
> Thank you for the very helpful detailed feedback.
>
> In particular, 2,4,5 are all javac language questions - so I will 
> defer to your proposal. Your
> team can revisit if they disagree.
>
> More questions below
>
>
>> On Jan 31, 2018, at 12:43 AM, Srikanth 
>> <srikanth.adayapalam at oracle.com 
>> <mailto:srikanth.adayapalam at oracle.com>> wrote:
>>
>>
>> Hi Karen,
>>
>> Thanks for your comments - There is no need for apologizing and such 
>> ! I am not looking for a fully evolved specification and am happy to 
>> accommodate any changes you require or address any misunderstandings 
>> on my part that you call out :)
>>
>> Some of the issues you raise though require further discussion and I 
>> am pulling up and enumerating these below:
>>
>> (In summary ATM (1) through (6) below look as though they don't call 
>> for a change - But I will wait for any contrary opinions.
>>
>> I'll study (7) and (8) and follow up suitably.)
>>
>> (1) Branch to use:
>>
>> I have asked David Simms for clarification, but I based my decision 
>> to push to "exp"
>> on 
>> http://mail.openjdk.java.net/pipermail/valhalla-dev/2018-January/003663.html. 
>> After hearing from David, I'll take suitable follow up actions 
>> (including nothing)
>>
>> ----
>>
>> (2) Value types may not declare a super class not even j.l.O:
>>
>> Please note: In the commit I pushed, value classes *do* extend j.l.O, 
>> it is just that they can't explicitly
>> declare an extends clause even if that only mentions j.l.O
>>
>> This is consistent with
>>
>> (a) How in the original valhalla prototype, value types extend 
>> java.lang.__Value, but cannot mention
>> an explicit super type in the extends clause.
>>
>> (b) This is also consistent with how all annotation types 
>> automatically implement java.lang.annotation.Annotation but are not 
>> allowed to specify an implements clause in the annotation type 
>> declaration site.
>>
>> (c) This is also consistent with how all enum types implicitly 
>> automatically extend java.lang.Enum, but
>> cannot expressly extend it.
>>
>> (d) Also consistent with how all interfaces have j.l.O as a super 
>> type but this cannot be expressed in
>> source.
>>
>> For these reasons I am inclined to think we should leave this matter 
>> as is, but can be convinced if I am found to overlook some points.
>>
>> ------------
>>
>> (3) "Values have no instance lock and so may not be synchronized upon"
>>
>> Clarification:
>>
>> (a) A value type may not declare an instance method that has the 
>> modifier synchronized AND
>> (b) A value instance may not be used to furnish the mutual exclusion 
>> lock for a synchronized statement.
>>
>> (Already done in the prototype)
>>
>> -----
>>
>> (4) Values have no identity and consequently the method 
>> java.lang.System.identityHashCode may not be invoked on them:
>>
>> You wrote:
>>
>> I had assumed that java.lang.System.identityHashCode() would be 
>> revised to throw an exception at runtime for values, not that javac 
>> would catch this
>>
>> Certainly a runtime check and throw would be required at 
>> j.l.S.identityHashCode(), but it would feel very "unlike Java" to NOT 
>> catch this error statically where possible. I agree not all cases 
>> could be caught at compile time and so a second line defense would be 
>> required at runtime.
>>
>> ------
>>
>> (5) The following methods from j.l.O are not allowed on value 
>> receivers:  clone(), finalize(), wait(), wait(long), wait(long, int), 
>> notify, notifyAll
>>
>> You wrote:
>>
>>           Actually they all are - we will be rewriting the j.l.O 
>> methods to throw runtime errors if this happens,
>>           so we do not need javac to disallow this
>>           (we will run into this at runtime due to inheritance when 
>> passing an Object or interface and the
>>            receiver is a value instance - so we have to do a runtime 
>> check anyway)
>>
>> I understand how values may "leak" into places where they cannot be 
>> discerned to be values statically and hence the rationale for doing a 
>> runtime check anyway and rewriting j.l.O methods to throw runtime 
>> errors when the receiver happens to be a value instance - but not 
>> diagnosing this where it is possible to do so statically in javac 
>> would again similar to (4) above be very unlike Java - That is to 
>> defer errors to runtime where they can be caught and reported right 
>> away at compile time.
>>
>> (6) Clarification: I expect Javac would issue a withfield instruction 
>> only from the static value factory associated with the value type and 
>> nowhere else. As a matter of fact attempt to assign to an instance 
>> field of a value type anywhere else would trigger a compile time 
>> error about final field being modified,
> Can you help me with this one - I do not have a good sense of where 
> withfield would make sense to be used
> be represented in the language. Sounds like you would propose #1 below:
>
> 1) explicit value factory, e.g. methods marked in source/in a classfile
>    - for VVT I believe you used __MakeDefault
>
>    - your sentence above says “static value factory”
>      - I recognize that for bootstrapping you have to have at least 
> one static value factory
>      - would it also make sense for an instance method that sets a 
> field to create a new value instance
>         using the current values of the starting instance fields and 
> explicitly set a field (or set of fields)
>
> 2) in any methods in the current class
>    - for VVT I believe this is what the JVM implemented
>
> 3) also for nestmates - TBD
>
> Totally makes sense to me that javac would throw compile time errors
>>
>> ------
>>
>> (7) Null assignment to values, casting null to values and null 
>> comparison against values:
>>
>> Thanks for your comments and the pointer to recent discussion. I'll 
>> study these in detail and make suitable changes or follow up with 
>> requests for additional clarifications.
> We will be discussing this latest proposal today at both the Valhalla 
> vm meeting and at the expert group,
> so we should get initial feedback. I will be typing in the EG minutes.
>>
>> ---
>>
>> (8) Value instances may not be compared with == or !=
>>
>> You wrote:
>>
>> The proposal was that value instances MAY be compared with 
>> if_acmpeq/if_acmp_ne,
>>           and the bytecode will return FALSE if either argument is a 
>> value type
>>           This presupposes a model in which “most” code uses a check 
>> of ==/!=, null check, .equals() check
>>
>> Is this true for source code where it can be discerned by the 
>> compiler that one or both of the operands of == or != is a value type ???
>
>
>>
>> http://cr.openjdk.java.net/~jrose/values/values-0.html 
>> <http://cr.openjdk.java.net/%7Ejrose/values/values-0.html> does 
>> foresee different semantics for == and != on values, including 
>> component-wise == comparison or invoking equals method, but I am not 
>> sure where we stand.
> That is a very old proposal.
> John spoke with Guy Steele in Burlington in November and came away with
> his current proposal.
> See: http://cr.openjdk.java.net/~dlsmith/values-notes.html 
> <http://cr.openjdk.java.net/%7Edlsmith/values-notes.html>
> Dan’s write-up starts with variations in the RLQU world
> — the section on Operations is where the LWorld potential option 
> evolved to in November:
>
>   * |if_acmpeq| and |if_acmpne| always return |false| and |true|,
>     respectively, when invoked on a |Q| valu
>
> See John’s longer email on optimizing acmp below - based on the 
> assumption above:
> extract:
> Background:  The acmp operation, also known as reference
> comparison, is overloaded in L-World to handle values as well,
> with a specific semantics of returning false if either operand is
> a value (similar to NaN behavior for fcmp).  The rationale for
> this is that acmp is reference comparison, even in L-World,
> and since values have no references, they can never be
> equal as references.
>
> That does leave us with the question of what javac should do.
>
> Would it make sense to issue a warning if javac knows that one or both 
> operands is a value type
> if there is an “==“ or “!=“ not coupled with a .equals check (and 
> possibly a null check)?
> Would it make sense to do that even for reference types since any 
> Object or interface could at runtime
> be a value type?
> Brian says we have been “encouraging” folks to do this for 20 years - 
> I don’t know how we teach evolution
> in java - with a flag? with a warning? That is a language designers 
> call - I added it to our open issues -
> love it if you work it out with your team and let us jvm folks know 
> the answer :-)
>
>
>
>
> thanks,
> Karen
>
>>
>> Thanks!
>> Srikanth
>>
>>
>>
>> On Tuesday 30 January 2018 10:58 PM, Karen Kinnear wrote:
>>> Srikanth,
>>>   I have not yet had a time to look through the code, but I wanted 
>>> to get back to you right away.
>>>
>>> First - many many thanks for doing this so quickly and for asking 
>>> for feedback at this
>>> early phase.
>>>
>>> Some clarifications to the list below. My apologies if I incorrectly 
>>> specified some to you.
>>> Thank you for your understanding A we have been evolving some key 
>>> issues such as how to
>>> deal with signatures and nullability. So this is a good time to 
>>> touch base.
>>>
>>> Also - can you touch base with Mr Simms on the repos - my 
>>> understanding was that
>>> the “exp” branch was for independent performance experiments based 
>>> on JDK 11
>>> without value types support, and he was going to create a new branch 
>>> ?name TBD?  for our joint
>>> prototype.
>>>
>>>> On Jan 30, 2018, at 4:21 AM, Srikanth 
>>>> <srikanth.adayapalam at oracle.com 
>>>> <mailto:srikanth.adayapalam at oracle.com>> wrote:
>>>>
>>>>
>>>> Hello,
>>>>
>>>> The commit below is the record of the change set I pushed to 
>>>> valhalla "exp" branch
>>>> that contains the javac changes for scanner, parser, semantic 
>>>> analysis and attribution
>>>> support for value types. Most of this is leveraged from the 
>>>> existing prototype
>>>> and tweaked for the present work.
>>>>
>>>> No code generation support exists at the moment. I will look into 
>>>> it now.
>>>> See below for the summary of changes and a couple of questions.
>>>>
>>>> Summary of changes:
>>>>
>>>>     - Tag a type declaration as being a value type with __ByValue 
>>>> modifier (>= JDK11)
>>>           yes
>>>>     - Value types may not declare a super class not even j.l.O
>>>           current proposal is that a value type must explicitly 
>>> declare j.l.O as the super class
>>>>     - Value class declarations and their instance fields must be final.
>>>          yes
>>>>     - Value types may not declare fields of their own types either 
>>>> directly or indirectly.
>>>          yes
>>>>     - Null cannot be assigned to value types
>>>          This is a very new proposal - still in discussion
>>>
>>> http://mail.openjdk.java.net/pipermail/valhalla-dev/2018-January/003721.html
>>>
>>>           Proposal is to add in the classfile the ACC_NON_NULLABLE 
>>> flag for FieldInfo
>>>           — I do not know what the language support should be for a 
>>> prototype?
>>>           — keyword? annotation? Needs a langtools team discussion, 
>>> perhaps
>>>           before that all gets sorted out stick with the keywords 
>>> like the rest of the prototype,
>>>           e.g. __NonNullable
>>>
>>>          If the field is declared with the ACC_NON_NULLABLE, then 
>>> writing to this field
>>>          at runtime with throw and NPE.
>>>          Given that it is illegal to use this flag for an object 
>>> class (vs. a value class)
>>>          javac could catch both the use of this class for an object 
>>> class, and catch
>>>          assigning these fields to null.
>>>
>>>          Let us know if you see a problem with this approach for 
>>> prototyping
>>>
>>>>     - Null cannot be casted to or compared with value types.
>>>          Changed: null can be cast to a value type or compared with 
>>> a value type
>>>          (we left the semantics of checkcast and instanceof unchanged)
>>>          (see below for comparison discussion)
>>>
>>>>     - Support for static value factories and value instance 
>>>> creation via __MakeDefault()
>>>>     - Values have no instance lock and so may not be synchronized upon.
>>>           clarify: it is illegal to declare a non-static 
>>> synchronized method for a value class
>>>
>>>>     - Values have no identity and consequently the method 
>>>> java.lang.System.identityHashCode
>>>>       may not be invoked on them and
>>>           I had assumed that java.lang.System.identityHashCode() 
>>> would be revised to throw an exception at runtime for values, not 
>>> that javac would catch this
>>>>     - The following methods from j.l.O are not allowed on value 
>>>> receivers:
>>>>         - clone()
>>>>         - finalize()
>>>>         - wait()
>>>>         - wait(long),
>>>>         - wait(long, int)
>>>>         - notify
>>>>         - notifyAll
>>>            Actually they all are - we will be rewriting the j.l.O 
>>> methods to throw runtime errors if this happens,
>>>            so we do not need javac to disallow this
>>>            (we will run into this at runtime due to inheritance when 
>>> passing an Object or interface and the
>>>             receiver is a value instance - so we have to do a 
>>> runtime check anyway)
>>>>     - Value instances may not be compared with == or !=
>>>           The proposal was that value instances MAY be compared with 
>>> if_acmpeq/if_acmp_ne,
>>>            and the bytecode will return FALSE if either argument is 
>>> a value type
>>>            This presupposes a model in which “most” code uses a 
>>> check of ==/!=, null check, .equals() check
>>>
>>>>     - Tests for the above restrictions.
>>>>
>>>> Questions:
>>>>
>>>> 1.    ATM, javac forbids comparison of values using != or ==. This 
>>>> behavior is simply
>>>> brought forward from the original valhalla implementation. Is this 
>>>> what we want in
>>>> the present prototype ? (in the context of acmp performance 
>>>> characterization ?)
>>>> 2. The support in the parser allows inner class to be declared as 
>>>> __ByValue. Do we want
>>>> to restrict values to top level classes ? I seem to recall this 
>>>> being suggested a while
>>>> ago - but I am unable to dig up the context.
>>> I added this to the list of open design questions - I think that is 
>>> a language choice, I don’t
>>> know why the JVM would care since today it knows nothing really 
>>> about top level vs
>>> inner classes.
>>> Also brings up the question of withfield (renamed) and where it is 
>>> legal to call it -
>>> explicit factories, any method in the value class itself, nestmates?
>>>
>>> thanks so much,
>>> Karen
>>>
>>>
>>>> Thanks!
>>>> Srikanth
>>>>
>>>>
>>>> On Tuesday 30 January 2018 02:49 PM, srikanth.adayapalam at oracle.com 
>>>> wrote:
>>>>> Changeset: 8d76e47a91e7
>>>>> Author:    sadayapalam
>>>>> Date:      2018-01-30 14:45 +0530
>>>>> URL: http://hg.openjdk.java.net/valhalla/valhalla/rev/8d76e47a91e7
>>>>>
>>>>> Scanner, parser, semantic analysis and attribution support for 
>>>>> value types
>>>>>
>>>>> ! 
>>>>> src/java.compiler/share/classes/javax/lang/model/element/Modifier.java
>>>>> ! src/jdk.compiler/share/classes/com/sun/source/tree/NewClassTree.java
>>>>> ! src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java
>>>>> ! src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java
>>>>> ! src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java
>>>>> ! src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
>>>>> ! src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java
>>>>> ! src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
>>>>> ! 
>>>>> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java
>>>>> ! 
>>>>> src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java
>>>>> ! 
>>>>> src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
>>>>> ! 
>>>>> src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java
>>>>> ! 
>>>>> src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties
>>>>> ! src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java
>>>>> ! src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java
>>>>> ! 
>>>>> src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java
>>>>> ! src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java
>>>>> ! test/langtools/tools/javac/diags/examples.not-yet.txt
>>>>> + test/langtools/tools/javac/diags/examples/ValuesNotSupported.java
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/CheckClone.java
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/CheckClone.out
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckCyclicMembership.java
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckCyclicMembership.out
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/CheckEquals.java
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/CheckEquals.out
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/CheckExtends.java
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/CheckExtends.out
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/CheckFinal.java
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/CheckFinal.out
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/CheckFinalize.java
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/CheckFinalize.out
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckIdentityHash.java
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckIdentityHash.out
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckIdentityHash01.java
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckIdentityHash01.out
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckMakeDefault.java
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckMakeDefault.out
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckNullAssign.java
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckNullAssign.out
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckNullCastable.java
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckNullCastable.out
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckStaticValueFactory.java
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckStaticValueFactory.out
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckSuperCompileOnly.java
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/CheckSync.java
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/CheckSync.out
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckSynchronized.java
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckSynchronized.out
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckValueFactoryWithReference.java
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckValueFactoryWithReference.out
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckValueModifier.java
>>>>> + 
>>>>> test/langtools/tools/javac/valhalla/lworld-values/CheckValueModifier.out
>>>>> + test/langtools/tools/javac/valhalla/lworld-values/Point.java
>>>>>
>>>
>>
>



More information about the valhalla-dev mailing list