Moving from VVT to the L-world value types (LWVT) (original) (raw)
Srikanth srikanth.adayapalam at oracle.com
Wed Feb 21 06:13:14 UTC 2018
- Previous message (by thread): Moving from VVT to the L-world value types (LWVT)
- Next message (by thread): Moving from VVT to the L-world value types (LWVT)
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On Wednesday 21 February 2018 08:18 AM, John Rose wrote:
On Feb 12, 2018, at 11:12 AM, John Rose <john.r.rose at oracle.com> wrote:
On Feb 12, 2018, at 8:53 AM, Srikanth <srikanth.adayapalam at oracle.com> wrote:
Hi Frederic,
A couple of follow up questions below: On Monday 12 February 2018 10:02 PM, Frederic Parain wrote: [...] The current design allows null references for value types, as long as they are not stored in a container (field or array) declared as flattenable. This is a significant change from previous design. So, casting null to a value class type is now legal. OK. This does not call for any change to the specification of checkcast in JVMS ? (I don't know that it does - Just double checking) There might be an option here: Maybe we could get away with having checkcast throw NPE if the target class is a value type. After all, the checkcast instruction resolves its class operand. Remember that we must allow polluting nulls in fields which are not explicitly marked as flat, but only because of binary compatibility requirements. We do not allow polluting nulls to be stored into arrays, because arrays must resolve their element types before the first array is constructed. I think we could put checkcast into either of these two categories: Allowing polluting nulls for compatibility, or forbidding them (throwing NPE). Hmm… The more aggressive choice (throwing NPE on checkcast) would make would prevent instances of generic code (such as List) from accepting nulls: List xs = new ArrayList<>(); xs.add(null); // to NPE or not to NPE? This is not really a JVM question, but a language question: Should the above code throw NPE if freshly recompiled? Yes, probably. What if it is inside a legacy classfile, and is not freshly recompiled? It would break if it threw NPE. This argues for two slightly different versions of checkcast. Argh: An option turns into a two-sided mandate. The checkcast might need a flat-bit. (Stay away, you Q-types.) Or the checkcast could throw NPE only in newer classfile versions. These considerations also apply to Class::cast. I thought about this some more, and talked briefly with Brian, and here's where I think we should come out: In new source code it will always be illegal to cast a null to a value type. The rule for values is, "codes like a class, works like an int". If you cast a null to (int) you get an NPE. That's what the language needs to do. It doesn't matter what the JVM does.
Thanks very much for your comments, John.
I have made the observation a couple of times in my past mails that javac should align with what the VM does and your observation that "It doesn't matter what the JVM does." made me pause and think. I understand your point better now.
You say: "In new source code it will always be illegal to cast a null to a value type."
Let me ask expressly: In new source code is it legal to assign null to a value typed variable as long as it is not annotated @Flattenable and as long as it is not an array element that is being assigned to ?
Or is this ACC_FLATTENABLE field flag bit only for the VM's jurisdiction
- something javac is supposed to ignore other than setting it where it should be set ?
Likewise what about null comparison against value instances in new source code ?
void foo() { ValueType v = null; v = (ValueType) null; if (v != null) {} }
In what is proposed, do the three operations shown above end up getting treated "regularly" - or is such regularity not required ?
I will require some time to digest all the observations - I have reopened JDK-8197791 so that suitable adjustments in behavior can be made.
Thanks again, Srikanth
There are two exceptions to this reasoning: Explicit nullability, or legacy compilation. If we were to add a new feature which allowed a type to be nullable, then types which had this nullable aspect could be the target of a cast, without a null check, and the JVM would process the null appropriately. It would have to use an L-type descriptor for the value, of course. But we are not doing this at present. If javac is compiling for legacy code (say, with the experimental features turned off) then it should not "notice" class files which are defined as value types (or non-nullable types, if we add this feature at some point). In that case, no null checks should be inserted, since that would be incompatible with old code. To summarize: javac should arrange a null check when it emits a cast to a type which is statically known to be a value type, if it is compiling at a source level which recognizes value types as such. Since reflective calls are used by both old and new bytecodes, adding a null checks for value-types is not an option for Class::cast. Probably we need a new API point, Class::castValue, which senses a value type and adds a null check in that case. For reference types, the behavior of Class::castValue would be the same as Class::cast. At the JVM level, we should consider making checkcast incorporate a null check, in the case where (a) the class resolves to a value type, and (b) the classfile version supports value types. In this way, legacy classfile code will continue to be sloppy with nulls, but new code will not. Users who need to cast to a value type without the null check can use Class::cast or some other API point which guarantees to allow "polluting" nulls to pass through. To be clear: If a classfile contains a checkcast that refers to a value type, and if the classfile's version number (or other markings) allows it to process value types (say, withfield is also allowed), then the semanatics of the checkcast should include a null check, even though (for compatibility reasons in old code) the JVM would allow a null under the same descriptor. I admit that giving checkcast a different behavior in different classfile versions is odd, and as a temporary fallback it might be better to ask javac to insert explicit null checks before such checkcasts.
- Previous message (by thread): Moving from VVT to the L-world value types (LWVT)
- Next message (by thread): Moving from VVT to the L-world value types (LWVT)
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]