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

Karen Kinnear karen.kinnear at oracle.com
Fri Feb 2 15:00:14 UTC 2018


Srikanth,

Thank you for the thoughtful discussion.
Had a long chat with Brian and it sounds like he is in agreement with the model of having javac
perform compile time checks.

> On Jan 31, 2018, at 8:00 PM, Srikanth <srikanth.adayapalam at oracle.com> wrote:
> 
> 
> 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.
From a JVM perspective, creation of a default value is also performed when
 - initializing value type array entries
 - initializing non-nullable value type fields
That said, that is not the same as the use of the defaultvalue bytecode
> 
> 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. 
So how would set a value instance’s fields to other than default?
I presume by having factories with arguments?
Is there a way to take a value type with two fields, one initialized, and create a new value type containing the
values of an existing value type and adding one more? I think that is the model John is looking for.
So perhaps that would be another static factory that takes an existing value instance and sets a specific field,
so might be called ValueType = setField1(starterValueType ,field1contents)
That is what I meant by a setter.

> 
> (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.
I updated the wiki page based on the discussion at the EG, John’s emails and discussion with Brian. I am
sure there will be additional discussion, for now folks have voice support for this approach.
> 
> (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.
Due to separate compilation, it is not clear to me that you will always know if a type is a value type or not
(that said, it is forbidden to go from value type to object type, so if you do know value type you know that can’t change).
> (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.
Love to hear the results of the discussion
> 
> (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.
Mr Simms created the “lworld” repo - populated from MVT - so you might have to clean out some change
you don’t want there.

many thanks,
Karen
> 
> 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 <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 <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 <mailto: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 <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