Moving from VVT to the L-world value types (LWVT)

Srikanth srikanth.adayapalam at oracle.com
Wed Feb 21 06:13:14 UTC 2018



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<DoubleComplex>) from accepting
>> nulls:
>>
>>   List<DoubleComplex> 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.
>



More information about the valhalla-dev mailing list