Hi Dan,
I've looked at your exploration of the Preload attribute. The LoaderTest
test loads class A but it doesn't link it. HotSpot looks at the PreLoad
attribute at class link time, not class load time (yes, the name is
misleading), this is why class B is not loaded.
Replacing the call to loadClass() with a call to Class.forName() to
force the linking of the class will trigger the processing of the
PreLoad attribute.
public static void main(String[] args) throws Throwable {
ARGS = args;
ClassLoader cl = new LoaderTest2();
Class<?> c = Class.forName(args[0], true, cl);
System.out.println(""+c+"::loader="+c.getClassLoader());
}
Fred
On 6/8/23 12:01 PM, Dan Heidinga wrote:
Thanks Dan and Fred for the clarification on the current spec and
Hotspot behaviour and John for suggesting we remove the attribute.
I think the problem with the current status quo for the preload
attribute is that we're trying to treat it like an optimization - a
"we can have our cake" (know which classes to load at some
indeterminate point) and "eat it too" (not promise users anything
about when or if those classes will be loaded).
As it stands, based just on the spec, it's hard for users to know what
the preload attribute will do for them. There's nothing they can
depend on in the spec and are at the mercy of whatever behaviour VM
implementers pick on a given day. Which means they will depend on the
current Hotspot behaviour (defacto standardization - yuck!) or expect
the behaviour to change all the time.
If we decouple the list of preloadable classes from the classfile, how
would non-jdk classes be handled? Many applications are a mix of
multiple jar files from different maintenance domains which would make
having a combined list difficult. We'd also need to think through the
classloader implications vs today's approach which attempts to load on
the same loader as the class with the preload attribute.
What if instead of ditching the attribute, or treating it like an
optimization, we firmed up the contract and treated it as a guarantee
similar to those of superclasses and superinterfaces as in the first
line in section 5.4 "Linking"? The new text would read something like:
> Linking a class or interface involves verifying and preparing
that class or interface, its direct superclass, its direct
superinterfaces, and its element type (if it is an array type), if
necessary. Any classes listed in the preload attribute will be loaded
at this point.
We don't need to say in the JVMS why the classes are in the attribute,
but we should be explicit about where the attempt to load them occurs
and that errors are ignored. This provides stability to the users and
allows for independent implementation while avoiding de
facto standardization of today's behaviour.
Before responding, I built the latest lworld branch of the Valhalla
repo and played with the preload attribute to try and force a
classloader-related deadlock. I was surprised to find that the
attribute doesn't seem to have an effect on user-defined loaders and
with the current spec, I can't even say if that's a bug or not.
Example classfiles for this exploration are in
https://github.com/DanHeidinga/valhalla-preload-example
--Dan
On Mon, Jun 5, 2023 at 9:52 PM John Rose <[email protected]> wrote:
Overall, as we look at Preload, it is looking more and more like a
no-op, as far as the JLS and JVMS is concerned. Perhaps that is a
signal that it should be placed somewhere outside of the JVMS,
such as in a Leyden-specific mechanism (a preload list) produced
in a way decoupled from any transactions between the JLS and JVMS.
On 1 Jun 2023, at 11:24, Dan Smith wrote:
On Jun 1, 2023, at 10:53 AM, Dan Heidinga
<[email protected]> wrote:
A couple of questions about the spec for the Preload
attribute[0]. The current spec says it indicates "certain
classes contain information that may be of interest during
linkage."
The Preload attribute removes one need for Q modifiers
while allowing calling convention optimizations and layout
decisions to be made early.
The current spec is quite vague on what classes should be
included in the attribute and on when / what the VM will
do with those classes (or even if it does anything).
FWIW, the JEP has more detail about when javac is expected to
include classes in Preload.
I think it's time to tighten up the spec for Preload
attribute and specify:
* what the VM will do with classes listed in the attribute
It is intentional that the VM may choose to do nothing. So
anything it does is purely an optimization.
Looks like a nop…
(In particular, it should not /reject/ any inputs, because that
would destabilize separate compilability in unpredictable ways.)
* when those classes will be loaded (ie: somewhere in JVMS
5.3)
If the VM chooses to load Preload classes, then our thinking
was that JVMS 5.4 already describes the details of timing:
https://docs.oracle.com/javase/specs/jvms/se20/html/jvms-5.html#jvms-5.4
So, for example, "Alternatively, an implementation may choose
an "eager" linkage strategy, where all symbolic references are
resolved at once when the class or interface is being
verified." That is, the Preload classes could all be loaded
during verification, or at some other stage of linking.
My expectation is that the natural point for processing
Preload is during preparation as vtables are set up, but
sometimes I get these things wrong. :-)
Sometimes you want them early (for instance layout) and sometimes
you need to wait (vtable layout or even just before <clinit>).
* how invalid cases are handled, including circularities
(Class A's Preload mentions B <: A)
Silent supression of errors, if any. Again, like a nop…
"Errors detected during linkage are thrown at a point in the
program where some action is taken by the program that might,
directly or indirectly, require linkage to the class or
interface involved in the error."
I've always found this rule super vague, but I think "require"
is the key word, and implies that errors caused by Preload
resolution should just be ignored. (Because Preload isn't
"required" to be processed at all.)
* what types of classes can be listed (any? only values?)
Definitely intend to support any classes of interest. Say a
future optimization wants to know about a sealed
superinterface, for example—it would be fine to tweak javac to
add that interface to Preload, and then use the information to
facilitate the optimization.
There's a lot of nondeterminism here—can a compliant system
trigger changes to class loading timing, but just on my
birthday?—but I think it's within the scope of JVMS 5.4, which
provides a lot of latitude for loading classes whenever it's
convenient.
It probably makes sense to start from the current Hotspot
handling of the attribute and fine tune that into the spec?
So I've outlined our hands-off stake in the ground above. The
spec would definitely benefit, at least, from a non-normative
cross-reference to 5.4 and short explanation. Beyond that, I
think we'd be open to specifying more if we can agree
something more is needed...
I think we could get the benefits in Fred’s prototype (as he
describes) with a list that is decoupled from any particular class
file, and Leyden could deliver this list.
As you see, I’m kind of sour on a Preload attribute these days.