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

John Rose john.r.rose at oracle.com
Sat Jan 20 04:22:46 UTC 2018


On Jan 16, 2018, at 12:56 PM, Frederic Parain <frederic.parain at oracle.com> wrote:

Here’s an attempt to bootstrap the L-world exploration, where java.lang.Object is the top type of all value classes (as discussed during the November meetings in Burlington).

This is excellent work, Frederic; thank you. I'm really hopeful that we are on the right track.

... Here’s a quick summary of the changes with some consequences on the HotSpot code: - all v-bytecodes are removed except vdefault and vwithfield

At some point we may want to strip the v-prefix from those survivors. No hurry.

- all bytecodes operating on an object receiver are updated to support values as well, except putfield and new

Yep.

- single carrier type for both instances of object classes and instances of value classes - this carrier type maps to the TOBJECT BasicType - TVALUETYPE still exists but its usage is limited (same purpose as TARRAY)

T_ARRAY can be a confusing source of bugs. I've always wondered if it was worth it.

- qtos TosState is removed - JNI: the jobject type can be used to carry either a reference to an object or an array or a value. The type jvaluetype, sub-type of jobject, is used when only a value class instance is expected - Q…; remains the way to encode value classes in signature (fields and methods)

I'd like to move towards an ACC_VALUE bit on both fields and classes. Again, no hurry, but (as in my previous message) I'd like to retire Q-descriptors.

- In the constant pool, the CONSTANTCLASSinfo entry type is used to store a symbolic reference to either an object class or a value class - the ;Q escape sequence is not used anymore in value class names

One important point of this exercise is to ensure that the migration of Value Based Classes into Value Classes is possible, and doable with a reasonable complexity and costs. In addition to the JVMS update (and consistent with the JVMS modifications), here’s a set of proposals on how to deal with the VBC migration.

I'm glad you are doing this analysis, not only because VBC migration is a wonderful goal, but also because I think the same analysis is necessary just to manage separate recompilation, even if we never decided to migrate a single class.

In short, I see you are leaning hard on Q-descriptors, but I don't think you are getting enough value out of them, and they cause serious problems. More comments below…

Migration of Value Based Classes into Value Classes: - challenges: - signature mismatch

Goes away when/if we retire Q-descriptors!

- null

Can be dealt with by assuming non-null and throwing dynamic NPEs as needed where Q types are in play. Also, we tolerate "polluting nulls" along paths where the Q/R distinction is not available, even if (at some point later on) we realize that it was a Q all along. Eventually, the polluting null will cause an NPE.

(In my view, the NPE should happen later than one might prefer if it were a true coding error rather than a recompilation artifact. Catching polluting nulls early in the presence of recompilation requires too many heroics.)

- change in behavior

Yes, that's the tricky part.

- proposal for signature mismatch: - with LWVT, value class types in signatures are using the Q…; format - legacy code is using signature with L…; format (because VBC are object classes) - methods will have two signatures: - true signature, which could include Q…; elements - a L-ified signature where all Q…; elements are re-written with the L…; format - method lookup still works by signature string comparisons - the signature of the method being looked up will compared against both the true and the L-ified signatures, if the looked up signature matches the L-ified signature but not the true signature, it means a situation where legacy code is trying to invoke migrated code has been detected, and additional work might be required for the invocation (actions to be taken have to be defined) - signature mismatch can also occur for fields, this is still being investigating, the proposal will be updated as soon as we have a solution ready to be published

This sort of thing is, for me, a rich argument against keeping Q-descriptors.

- proposal for null references leaking to migrated code - having a null reference for a Value Based Class variable or field is valid in legacy code but it becomes invalid when the Value Based Class has been migrated to a Value Class - trying to prevent all references with a value class type to get a null value would be very expensive (it would require to look at the stackmap for each assignment to a local variable)

Yes. We have to tolerate polluting nulls where the Q/R distinction is unavailable.

- the proposed solution is to allow null references for local variable and expression stack slots, but forbid them for fields or array elements (bytecodes operating on fields and array have to be updated to throw a NPE whenever a null reference is provided instead of a value class instance)

Yes, I think this is on the right track. On paths where a Q-type is needed we do a null check. That's the Java way.

- null references are likely to be an issue for JIT optimizations like passing values in registers when a method is invoked. The proposed solution is to only allow null references for value classes in legacy code, by detecting them and blocking them when leaking to migrated code. The detection can be done at invocation time, when a mismatch between the signature expected by the caller and the real signature of the callee is detected (see signature mismatch proposal above)

At some point, a polluting null might reach code that "knows" there is a Q type (and may even "know" that it goes in an xmm register). That's the point where an NPE should be thrown. In some cases, a deopt might be appropriate, to correctly order the NPE by executing interpreter code.

Note that this combination of techniques does not Q-descriptors. The lack of Q-descriptors doesn't totally destroy the Q/R distinction; it just means you have to execute a little further before you get to code which "knows" that the null is illegal.

- the null reference should also be detected and blocked when it is used as a return value and the type of the value to be returned is a value class type

Doing this requires (a) Q-descriptors in method returns, (b) Remi's ValueTypes table, or (c) toleration of nulls in the interpreter. (The JIT doesn't have to tolerate nulls: It can deopt if it hits a surprise null, or perhaps throw an early NPE.) So, I am arguing for (c).

In addition to the JVMS update, here’s a chart trying to summarize the new checks that will have to be added to existing bytecode when moving the vbytecodes semantic in to a* bytecodes. The categories in the chart are not very precise, but we can use it as a starting point for our discussions. The chart can also help defining which experiments could be done to estimate the costs of the different additional checks needed to be added to existing bytecodes.

The chart is really helpful, thanks. More comments later.

Onward!

— John



More information about the valhalla-dev mailing list