<html><body><p><tt><font size="2">I would like to propose an alternative strategy, one that would effectively provide the same consistency checks outlined in </font></tt><a href="http://cr.openjdk.java.net/~acorn/value-types-consistency-checking-details.pdf"><tt><font size="2">http://cr.openjdk.java.net/~acorn/value-types-consistency-checking-details.pdf</font></tt></a><tt><font size="2"> without requiring eager loading of value types (VT) in the return/args of methods during the preparation phase. This is born out of our experience with PackedObjects which took a very similar approach to the ValueTypes attribute.   </font></tt><br><br><tt><font size="2">This proposal makes use of the existing ValueTypes attribute. In addition, it requires that each classloader keeps a registry of ‘expected’ VTs.  </font></tt><br><br><tt><font size="2">Proposal</font></tt><br><tt><font size="2">--------------------------</font></tt><br><tt><font size="2">The following steps occur in the loading phase:</font></tt><br><br><tt><font size="2">1. Prior to loading the current class each type in the ValueTypes attribute is checked see if it is loaded. If it is, the type must be a VT or ICCE is thrown. Otherwise, the type is registered with the initiating classloaders expected VT registry (EVTR).</font></tt><br><br><tt><font size="2">2. Pre-loading of ACC_FLATTENABLE instance fields follow the same rules as the ones specified in Karen's proposal.</font></tt><br><br><tt><font size="2">3. Prior to loading the current class, if the current class is a VT it must be in the classloader's EVTR or ICCE is thrown. If the current class is not a VT and does appear in the EVTR, ICCE is thrown.</font></tt><br><br><tt><font size="2">In link phase prior to preparation:</font></tt><br><tt><font size="2">- Same as Karen's static field rules, "static fields declared with the ACC_FLATTENABLE flag set have their type pre-loaded..."</font></tt><br><br><tt><font size="2">In preparation phase:</font></tt><br><tt><font size="2">- Same as Karen's method overriding rules, "any method overriding needs to perform value type consistency checking between declarer of the overridden method ..."</font></tt><br><br><tt><font size="2">At resolution time:</font></tt><br><tt><font size="2">- Same as Karen’s CONSTANT_Class, field and method resolution rules</font></tt><br><tt><font size="2">---------------------------</font></tt><br><br><tt><font size="2">The benefit of this approach is that as soon as anyone believes a class is a VT, it must be loaded as a VT or it fails. As a result, there is no inconsistency of loaded VTs. This proposal doesn't guard against cases where a class was not expecting a method return/arg type to be a VT but then later on turned out to be a VT when it was resolved. However, I think don’t think Karen’s proposal offered these guarantees either. </font></tt><br><br><tt><font size="2">> Some aspects of the implementation complexity that we have identified so far:</font></tt><br><tt><font size="2">> a) At method resolution time, if there is a mismatch in value type consistency </font></tt><br><tt><font size="2">> between the declaring class and the actual type in the signature, then there </font></tt><br><tt><font size="2">> is also a mismatch in all classes that have overridden the current method. </font></tt><br><tt><font size="2">> This is particularly painful with default methods in interfaces.</font></tt><br><br><tt><font size="2">With this proposal the only possible inconsistency here is: </font></tt><br><tt><font size="2">Method has a return/arg type that is believed to not be a VT but turns out to be a VT. In this case any compiled code is doing pass by reference calling convention which works for both VT and non-VT types. </font></tt><br><br><tt><font size="2">> b) We need to ensure that we catch all method resolution, through all of the </font></tt><br><tt><font size="2">> alternate accessor paths, including MethodHandles, VarHandles, Reflection, JNI,</font></tt><br><tt><font size="2">> so that we catch both the specification and implementation changes.</font></tt><br><br><tt><font size="2">All these cases are covered with the class loading consistency checks (EVTR).</font></tt><br><br><tt><font size="2">> c) Our favorite, invokespecial ACC_SUPER, needs special handling, since it </font></tt><br><tt><font size="2">> performs selection which is not based on overriding, but based on virtually </font></tt><br><tt><font size="2">> re-resolving.</font></tt><br><br><tt><font size="2">same as above</font></tt><br><br><tt><font size="2">> e) If we modify the specification to allow eager loading, and save errors </font></tt><br><tt><font size="2">> to throw at method resolution, we need to work through the JVMS question </font></tt><br><tt><font size="2">> of which errors would be saved (e.g. OOME, SOE might be thrown as part of </font></tt><br><tt><font size="2">> the implementation vs. saving LinkageError), as well as designing a new </font></tt><br><tt><font size="2">> implementation mechanism to repeat exceptions relative to signatures used </font></tt><br><tt><font size="2">> for method resolution.</font></tt><br><br><tt><font size="2">This wouldn’t be required in this proposal</font></tt><br><br><tt><font size="2">> d) Pass by value calling convention optimizations depend on loading the </font></tt><br><tt><font size="2">> actual type. Loading of the parameter types on first method resolution </font></tt><br><tt><font size="2">> implies that if the caller is compiled, the caller method requires </font></tt><br><tt><font size="2">> deoptimization/recompilation to pass arguments by value for future calls, </font></tt><br><tt><font size="2">> which is a performance cost.</font></tt><br><br><tt><font size="2">Typically, a method is run a few times before it is compiled (perhaps I’m making implementation assumptions?). At this stage, the return/arg types are either loaded or they are always null. This seems to suggest that deoptimization/recompilation scenario would not be a common occurrence. </font></tt><br><br><br><tt><font size="2">--Tobi<br><br>> From: Karen Kinnear <karen.kinnear@oracle.com></font></tt><br><tt><font size="2">> To: valhalla-spec-experts <valhalla-spec-experts@openjdk.java.net></font></tt><br><tt><font size="2">> Date: 2018/06/26 10:32 AM</font></tt><br><tt><font size="2">> Subject: EG help please with getting to LW1 re: Value Types <br>> Consistency Checking</font></tt><br><tt><font size="2">> Sent by: "valhalla-spec-experts" <valhalla-spec-experts-<br>> bounces@openjdk.java.net></font></tt><br><tt><font size="2">> <br>> Summary: Could we please allow eager loading for value types in the <br>> locally declared method signatures<br>> prior to preparation  for LW1? <br>> <br>> Without that we seriously risk being able to offer an LW1 early <br>> access binary for the JVMLS.<br>> We believe it is more important to get this into people’s hands for <br>> experimentation and feedback than<br>> to delay the eager loading at this time.<br>> <br>> Details:<br>> At our EG discussion on June 20, 2018, we discussed the proposal for<br>> Value Types Consistency checking<br>> at <a href="http://cr.openjdk.java.net/~acorn/value-types-consistency-">http://cr.openjdk.java.net/~acorn/value-types-consistency-</a><br>> checking-details.pdf<br>> <br>> Part of the proposal for checking value type consistency relative to<br>> the actual type<br>> was for locally declared methods. The proposal was to check the <br>> value types in arguments/return type<br>> before preparation of the declaring class.<br>> <br>> During the meeting, there was a request to explore whether we could either:<br>> 1)  delay checking the value type consistency until an attempt to <br>> resolve the method for invocation, or <br>> 2) write the JVMS is such as way as to allow eager loading, but only<br>> throw an error related to the eager loading at method resolution.<br>> <br>> My understanding is that the goals of this are two-fold:<br>> 1) if the method is never called, the rest of the code will continue to run<br>> 2) reduce eager loading<br>> <br>> We have started this investigation, and there is non-trivial <br>> complexity in implementing either of these approaches,<br>> and we would like more time to explore how to make this possible, <br>> after making LW1 available.<br>> <br>> Some aspects of the implementation complexity that we have identified so far:<br>> a) At method resolution time, if there is a mismatch in value type <br>> consistency between the declaring class and the actual<br>> type in the signature, then there is also a mismatch in all classes <br>> that have overridden the current method. This is particularly<br>> painful with default methods in interfaces.<br>> b) We need to ensure that we catch all method resolution, through <br>> all of the alternate accessor paths, including MethodHandles, VarHandles,<br>> Reflection, JNI, so that we catch both the specification and <br>> implementation changes.<br>> c) Our favorite, invokespecial ACC_SUPER, needs special handling, <br>> since it performs selection which is not based on overriding, but <br>> based on virtually re-resolving.<br>> d) Pass by value calling convention optimizations depend on loading <br>> the actual type. Loading of the parameter types on first method <br>> resolution implies that if the caller is compiled, the caller method<br>> requires deoptimization/recompilation to pass arguments by value for<br>> future calls, which is a performance cost.<br>> e) If we modify the specification to allow eager loading, and save <br>> errors to throw at method resolution, we need to work through the <br>> JVMS question of which errors would be saved (e.g. OOME, SOE might <br>> be thrown as part of the implementation vs. saving LinkageError), as<br>> well as designing a new implementation mechanism to repeat <br>> exceptions relative to signatures used for method resolution.<br>> <br>> thanks,<br>> Karen</font></tt><BR>
</body></html>