Initialization at build time and run time (follow up) #764
Replies: 5 comments 13 replies
-
On a pragmatic note, I think that several run time initialization tasks should be handled using global constructors. Particularly, heap setup and deserialization, GC initialization, and any eager run-time tasks (such as thread starting) should be done from here. This allows us to support usage of program images as a dynamic library, which will surely be a future requirement. |
Beta Was this translation helpful? Give feedback.
-
Thanks for writing this up David. It's an important topic for us to get right.
Is this intended for both methods and fields? From the writeup, it definitely applies to methods (the new Moving from the specific to the general:One of the things this approach does is follow the existing JDK specification for The downside is it preserves the "soupy" nature of existing The runtime aspect class can then define multiple methods that each initialize one of the required fields. This lets us start to break the existing soupy clinit into finer grained operations. Hopefully helping explore where / how lazy final static fields could help with this problem. Not much needs to change from your proposal to make this happen - I think it's mostly in the patcher and in the placement of the runtime initialization operations. We can have the existing runtime class init model call each of the field initializers on the runtime aspect class so we don't need to add per-field init checks (though it may be an option in the future) |
Beta Was this translation helpful? Give feedback.
-
As much as I've wanted to avoid saying this - what we're building is the natural analogue to serialization and I think you're 100% right that we'll need the same kinds of mechanisms to support it as serialization has today. The more of this work we can do at build time - even if it's just building lists or tables of addresses needing to be patched at startup by the hooks - the better. We may be able to make these hooks efficient by doing the necessary heap walks to identify what needs to be replaced at build time. |
Beta Was this translation helpful? Give feedback.
-
Looking at the threading aspects:
I think this is a clever idea but I'm not sure it's workable. We may find that as we execute more code at runtime, we'll run into deadlocks or permanent waits due to delaying thread operations. The first As much as possible, we'll want to adapt existing I think we either need to adopt Graal's "threads must be exited" rule or come up with a model to quiesce the threads in way that we can restore (restart?) them at runtime. The CRIU efforts have been looking at a hooks api for this - maybe it's another place where we need to look at serialization read/write hooks? |
Beta Was this translation helpful? Give feedback.
-
I've written up the implemented design in a wiki page: https://github.com/qbicc/qbicc/wiki/Class-Initialization-in-qbicc |
Beta Was this translation helpful? Give feedback.
-
It is time to solve the initialization problem comprehensively.
I have created a PR (#760) to switch standard class initializers to be build time only. This is a pragmatic decision: having two different models is getting to be too difficult to maintain. But it does leave a largely unsolved problem in that we have no good solution for initializing things at run time.
I've re-listened to the virtual meeting we had in May (#523) where we discussed several aspects of initialization. Apart from things we discussed on that call which have since been completed, we identified some requirements:
And nice-to-haves:
The mechanisms that were discussed were:
Since then we've made quite a lot of progress of course. But despite floating a lot of ideas, we never answered the basic question of how to handle run time class initialization.
So in order to get something working that we can use ASAP, I'd like to propose an initial solution with multiple parts:
InitializerElement
which applies to run time initialization and call it a run time initializer, and develop a parallel set of initialization rules which apply to run time. I think there are some potentially creative things we can do with these rules but to start with we'd want to keep it as simple as possible; the existing run time initialization support code would likely be largely reusable for this (though in the near future we might want to reevaluate how we are inserting and using class init checks).invokedynamic
must still be computed during build time so that any generated lambda classes are properly constructed and availableWe may also need to consider some or all of the following capabilities in the future:
readObject
/readResolve
mechanism in serialization)writeObject
/writeReplace
in serialization)@dgrove-oss had a clever take on build time thread creation, wherein we enqueue the created threads and start them as part of a run time initialization sequence. This is in contrast to the GraalVM approach wherein one may generally start threads during build time, with the stipulation that all threads must be exited before the compiler can complete. Deferring thread start to run time might introduce some incompatibilities but overall I think it's a better approach.
Once we have a class initialization solution working, we have to address the next problem: OpenJDK initializes itself using a series of methods on
java.lang.System
. Since these methods are unaware of the separation between build time and run time, the tasks performed are generally a mix of tasks that can or should be done at build or run time. We can bodge around these issues to an extent - maybe enough to get things up and running - but we should consider creating two new proper initialization sequences for build and run time respectively using the mechanism we define for that purpose.Beta Was this translation helpful? Give feedback.
All reactions