I would like to propose an alternative strategy, one that would effectively provide the same consistency checks outlined in http://cr.openjdk.java.net/~acorn/value-types-consistency-checking-details.pdf 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.
This proposal makes use of the existing ValueTypes attribute. In addition, it requires that each classloader keeps a registry of ‘expected’ VTs. Proposal -------------------------- The following steps occur in the loading phase: 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). 2. Pre-loading of ACC_FLATTENABLE instance fields follow the same rules as the ones specified in Karen's proposal. 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. In link phase prior to preparation: - Same as Karen's static field rules, "static fields declared with the ACC_FLATTENABLE flag set have their type pre-loaded..." In preparation phase: - Same as Karen's method overriding rules, "any method overriding needs to perform value type consistency checking between declarer of the overridden method ..." At resolution time: - Same as Karen’s CONSTANT_Class, field and method resolution rules --------------------------- 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. > Some aspects of the implementation complexity that we have identified so far: > a) At method resolution time, if there is a mismatch in value type consistency > between the declaring class and the actual type in the signature, then there > is also a mismatch in all classes that have overridden the current method. > This is particularly painful with default methods in interfaces. With this proposal the only possible inconsistency here is: 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. > b) We need to ensure that we catch all method resolution, through all of the > alternate accessor paths, including MethodHandles, VarHandles, Reflection, JNI, > so that we catch both the specification and implementation changes. All these cases are covered with the class loading consistency checks (EVTR). > c) Our favorite, invokespecial ACC_SUPER, needs special handling, since it > performs selection which is not based on overriding, but based on virtually > re-resolving. same as above > e) If we modify the specification to allow eager loading, and save errors > to throw at method resolution, we need to work through the JVMS question > of which errors would be saved (e.g. OOME, SOE might be thrown as part of > the implementation vs. saving LinkageError), as well as designing a new > implementation mechanism to repeat exceptions relative to signatures used > for method resolution. This wouldn’t be required in this proposal > d) Pass by value calling convention optimizations depend on loading the > actual type. Loading of the parameter types on first method resolution > implies that if the caller is compiled, the caller method requires > deoptimization/recompilation to pass arguments by value for future calls, > which is a performance cost. 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. --Tobi > From: Karen Kinnear <[email protected]> > To: valhalla-spec-experts <[email protected]> > Date: 2018/06/26 10:32 AM > Subject: EG help please with getting to LW1 re: Value Types > Consistency Checking > Sent by: "valhalla-spec-experts" <valhalla-spec-experts- > [email protected]> > > Summary: Could we please allow eager loading for value types in the > locally declared method signatures > prior to preparation for LW1? > > Without that we seriously risk being able to offer an LW1 early > access binary for the JVMLS. > We believe it is more important to get this into people’s hands for > experimentation and feedback than > to delay the eager loading at this time. > > Details: > At our EG discussion on June 20, 2018, we discussed the proposal for > Value Types Consistency checking > at http://cr.openjdk.java.net/~acorn/value-types-consistency- > checking-details.pdf > > Part of the proposal for checking value type consistency relative to > the actual type > was for locally declared methods. The proposal was to check the > value types in arguments/return type > before preparation of the declaring class. > > During the meeting, there was a request to explore whether we could either: > 1) delay checking the value type consistency until an attempt to > resolve the method for invocation, or > 2) write the JVMS is such as way as to allow eager loading, but only > throw an error related to the eager loading at method resolution. > > My understanding is that the goals of this are two-fold: > 1) if the method is never called, the rest of the code will continue to run > 2) reduce eager loading > > We have started this investigation, and there is non-trivial > complexity in implementing either of these approaches, > and we would like more time to explore how to make this possible, > after making LW1 available. > > Some aspects of the implementation complexity that we have identified so far: > a) At method resolution time, if there is a mismatch in value type > consistency between the declaring class and the actual > type in the signature, then there is also a mismatch in all classes > that have overridden the current method. This is particularly > painful with default methods in interfaces. > b) We need to ensure that we catch all method resolution, through > all of the alternate accessor paths, including MethodHandles, VarHandles, > Reflection, JNI, so that we catch both the specification and > implementation changes. > c) Our favorite, invokespecial ACC_SUPER, needs special handling, > since it performs selection which is not based on overriding, but > based on virtually re-resolving. > d) Pass by value calling convention optimizations depend on loading > the actual type. Loading of the parameter types on first method > resolution implies that if the caller is compiled, the caller method > requires deoptimization/recompilation to pass arguments by value for > future calls, which is a performance cost. > e) If we modify the specification to allow eager loading, and save > errors to throw at method resolution, we need to work through the > JVMS question of which errors would be saved (e.g. OOME, SOE might > be thrown as part of the implementation vs. saving LinkageError), as > well as designing a new implementation mechanism to repeat > exceptions relative to signatures used for method resolution. > > thanks, > Karen
