Experimentation with build time and runtime class initialization in qbicc
Dan Heidinga
heidinga at redhat.com
Tue May 31 15:50:30 UTC 2022
On Fri, May 27, 2022 at 7:53 AM Kasper Nielsen <kasperni at gmail.com> wrote:
>
> Hi David,
>
> Thanks for the write-up.
>
> One thing that isn't completely clear to me after reading this is why
> language
> changes (<rtinit>) are needed?
The <rtinit> model was a convenient way for us to explore a model that
put all class initialization at build time, while allowing a small set
of fields to be reinitialized at runtime. It also minimized the
changes we had to make to the core JDK classes which makes maintaining
the changes much easier given the rate of JDK updates. SubstrateVM
uses a similar approach with their Substitutions for what I assume are
similar reasons.
Leyden will be able to update the JDK core classes directly and can
take a more direct approach to indicating in which phase a static
field should be initialized.
> It seems to me this could be entirely
> implemented via a standard API. Using ClassValue as the main inspiration you
> could have something like:
>
> abstract class RuntimeLocal<T> {
> protected RuntimeLocal() {
> checkBuildTime();
> VM.registerForRuntimeInitialization(this);
> }
> protected abstract T computeValue();
> public final T get(); // Calls to get are optimized by the vm
> }
>
>
> Usage would be something similar to:
>
> class Usage {
>
> static final LocalDateTime BUILD_TIME = LocalDateTime.now();
>
> static final RuntimeLocal<LocalDateTime> RUNTIME_TIME = new
> RuntimeLocal<>() {
> protected LocalDateTime computeValue() {
> return LocalDateTime.now();
> }
> };
> }
>
> I might be missing some details, but it seems to me that this approach would
> be strongly favorable to needing to change the language as well as adding
> new bytecodes.
This is a good starting point. I went a fair ways looking at how to
group static fields into different classes to decouple their lifetimes
and found that I couldn't cleanly split them into two groups. I used
the Initialization on demand holder pattern (IODH) rather than your
RuntimeLocal but the idea is very similar.
The problem is that while it's clear that some fields can be
initialized early (build time) and others must be initialized late
(runtime), there is a third group that needs to be reinitialized. I
list 3 buckets: early, late, and reinit, but that's a minimum number.
There may be more than 3. And due to the "soupy" nature of <clinit>,
it's not always easy to avoid depending on a field that's in a
different bucket. And values in that 3rd bucket - the fields that
need to be reinitialized - don't have a clear meaning when their value
propagates around the program. Does it need to be cleared everywhere
and force reinit of all consumers? Lots to figure out here.
We need a better model - whether that's library features or new
language features - that makes it easier to express when (which phase)
an operation should occur and some way to talk about the dependency
chain of that value (all the classes that have to be initialized,
values calculated, etc).
--Dan
>
> /Kasper
>
> On Thu, 26 May 2022 at 21:22, David P Grove <groved at us.ibm.com> wrote:
>
> > Hi,
> > I’ve appended the contents of the referenced wiki page in this email.
> > Apologies in advance if the formatting doesn’t come through as intended.
> >
> > There is a full implementation of this (GPLv2 + Classpath
> > exception) as part of the qbicc project on GitHub. There is also a GitHub
> > discussion in the qbicc project that links to various GitHub issues that
> > capture the history that led to the current design. I will not hyperlink
> > to those here so that if people have any IP concerns, they can avoid seeing
> > them. They are easily findable.
> >
> > Regards,
> >
> > --dave
> >
> >
>
More information about the leyden-dev
mailing list