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