On 9 Jun 2023, at 12:41, Dan Heidinga wrote:
On Thu, Jun 8, 2023 at 4:51 PM John Rose <[email protected]>
wrote:
On 8 Jun 2023, at 9:52, Dan Heidinga wrote:
On Thu, Jun 8, 2023 at 12:44 PM John Rose <[email protected]>
wrote:
On 8 Jun 2023, at 9:01, Dan Heidinga wrote:
If we decouple the list of preloadable classes from the classfile,
how
would non-jdk classes be handled?> What if instead of ditching the
attribute, or treating it like an
optimization, we firmed up the contract and treated it as a
guarantee…
If we go down this route, let’s consider putting the control
information
into a module file (only) for starters. (Maybe class file later if
needed.) There would be fewer states to document and test, since (by
definition) class files could not get out of sync.
A module would document, in one mplace, which types it would
“prefer” to
preload in order to optimize its APIs (internal or external).
This might lead to more class loading than intended. The current
approach
has each classfile register the list of classes it wants preloaded to
get
the best linkage which means we only have to load those classes if we
link
the original class. There's a natural trigger for the preload and a
limited set of classes to load.
There’s a spectrum of tradeoffs here: We could put preload
attributes on
every method and field, to get the maximum amount of fine-grained
lazy
(pre-)loading, or put them in a global file per JVM instance. The
more
fine-grained, the harder it will be to write compliance testing, I
think.
Agreed. There's a sweet spot between expressiveness and overheads
(testing, metadata, etc). Classfiles have historically been the place
where the JVM tracks this kind of information as that fits well with
separate compilation and avoids the "external metadata" problems of
ie:
GraalVM's extra-linguistic configuration files.
When compiling the current class, javac already requires directly
referenced classes to be findable and thus has the info required to
write a
preload attribute. Does javac necessarily have the same info when
compiling the module-info classfile? Maybe when finding the
non-exported
packages for the module javac (or jlink? or jmod?) could also find the
value classes that need preloading?
That is what I am assuming. The module file would be edited by those
guys. Or (maybe better) a plain flat textual list is put somewhere the
JVM can find it.
Moving it into a separate pass like this doesn't feel like quite the
right
fit though as it excludes the classpath and complicates the other
tools
processing of the modules.
I think it’s better than that. When we are assembling a program
(jlink or a Leyden condenser), the responsibility of publicizing value
classes (for Preload) surely belongs to the declaration, not
collectively on all the uses.
So every module (jmod or whatever) that declares 1 or more value classes
(if they are exported, at least) should list them on a publicized watch
list.
There is no need to replicate these watch lists across all potential API
clients of a value class. There are reasons *not* to do this, since the
clients have only partial, provisional information about the values.
Moving to a single per-module list loses the natural trigger and may
pre-load more classes than the application will use. If Module A has
classes {A, B, C} and each one preloads 5 separate classes, with a
per-module list that's forcing the loading of 15 additional classes
(plus
supers, etc). With a per-class list, we only preload the classes on a
per-use basis. More of a pay for what you use model.
Is there a natural trigger or way to limit the preloads to what I
might
use
with the per-module file?
That’s a very good question. I think what Preload *really is* is a
list
of “names that may require special handling before using in
APIs”. They
don’t need to be loaded when the preload attribute is parsed; they
are
simply put in a “watch list” to trigger additional loading *when
necessary*. (This is already true.) So I think if we move the preload
list to (say) the module level (if not a global file), then the JVM
will
have its watch list. (And, in fewer chunks than if we put all the
stuff all
the time redundantly in all class files that might need them: That
requires
frequent repetition.) The JVM can use its watch list as it does
today, with
watch lists populated separately for each class file.
I initially thought a global list would lead to issues if two
different
classloaders defined classes of the same name but since this is a "go
and
look" signal, early loading based on name should be fine even in that
case
as each loader that mentions the name would be asked to be asked to
load
their version of the named class. So I think a per-JVM list would be
OK
from that perspective (though I still don't like it).
Agreed.
To emphasize: A watch list does not require loading. It means, “if
you see
this name at a point where you could use extra class info, then I
encourage
you to load sooner rather than later”. The only reason it is “a
thing” at
all is that the default behavior (of loading either as late as
possible, or
as part of a CDS-like thingy) should be changed only on an explicit
signal.
While true for what the JVM needs, this is hard behaviour to explain
to
users and challenging for compliance test writers (or maybe not if we
continue to treat preload as an optimization).
I’m trying to reduce this to a pure optimization. In that case,
“watch lists” are just helpers, which are allowed to fail, and
allowed to be garbage.
Is this where we want to
spend our complexity budget?
(No, hence it should be an optimization.)
Part of why I'm circling back to treating
preload as a per-classfile attribute that forms a requirement on the
VM
rather than as an optimization is that the model becomes clearer for
users,
developers and testers.
I think it’s still going to be murky. Why is putting the watch list
on the API clients better than putting it on (or near) the value class
definitions?
And, hey, maybe CDS is all the primitive we need here: Just run
-Xdump
with all of your class path loaded. Et voila, no Preload at all.
Users may find this behaviour surprising - I ran with a CDS archive
and my
JVM loaded classes earlier than it would have otherwise?
CDS has the effect of making class loading in a more timely fashion, and
(under Leyden) will almost certainly trigger reordering of loading as
well. So promulgating a “watch list” has goals which align with
CDS.
I’m starting to think that the right “level” to pull for
optimizing value-based APIs is to put the value classes in a CDS
archive. That is a defacto watch list. The jlink guy should just make
a table of all value classes. That’s the best form of Preload I can
imagine, frankly.