Hi Ioi,
Overall looks promising. I have some review comments below, but not a
complete review. I concentrated on the JVM side primarily how the
archived module graph is read in, how the ModuleEntry and PackageEntry
tables are created from the archive for the 3 builtin loaders and
potential timing issues during start up.
On 7/22/2020 3:36 PM, Ioi Lam wrote:
https://bugs.openjdk.java.net/browse/JDK-8244778
http://cr.openjdk.java.net/~iklam/jdk16/8244778-archive-full-module-graph.v01/
Please review this patch that stores the full module graph in the CDS
archive heap. This reduces the initialization time of the basic JVM by
about 22%:
$ perf stat -r 100 bin/java -version
before: 98,219,329 instructions 0.03971 secs elapsed (+- 0.44%)
after: 55,835,815 instructions 0.03109 secs elapsed (+- 0.65%)
[1] Start with ModuleBootstrap.java. The current implementation is
quite restrictive: the archived module graph is used only when no
module options are specified.
See ModuleBootstrap.mayUseArchivedBootLayer().
We can probably support options such as main module and module path
in a future RFE.
Yes, I noticed the restrictions. The JBS issue discusses the
possibility of using the dumped module graph in the event that the value
of the options are the same. I think for this implementation to be
viable and have a positive impact you should consider comparing at least
the options --add-modules, --add-exports and --add-reads.
[2] In the current JDK implementation, there is no single object
that represents "the module graph". Most of the information
is stored in the archive bootLayer object, but a few additional
restoration operations need to be performed:
+ See ModuleBootstrap.getArchivedBootLayer()
+ Some static fields need to be archived/restored in
Module.java, BuiltinClassLoader.java, ClassLoaders.java
and BootLoader.java
[3] I ran into a complication with two loader instances of
PlatformClassLoader and AppClassLoader. They are stored in
multiple tables inside the module graph (e.g.,
BuiltinClassLoader$LoadedModule) so I cannot easily recreate
them at runtime.
However, these two loaders contain information specific to the
dump time VM lifecycle (such as the classes that were loaded
during CDS dumping) that need to be scrubbed. I couldn't find an
elegant way of doing this, so I added a private "resetArchivedStates"
method to a few classes. They are called inside
HeapShared::reset_archived_object_states().
[4] Related native data structures (PackageEntry and ModuleEntry)
are also archived. Start with classLoaderData.cpp
Passes mach5 tiers 1-4. I will test with additional tiers.
Thanks
- Ioi
classfile/classLoader.cpp
- line #1644 pulling the javabase_moduleEntry() check outside of the
Module_lock maybe problematic if after you check it another
thread initializes in the time between the check and the obtaining of
the Module_lock on line #1645.
classfile/classLoader.hpp
- somewhere in ArchivedClassLoaderData there should be an assert to make
sure that the CLD, whose package entries and module entries are
being archived is not a "_has_class_mirror_holder" CLD for a weakly
defined hidden class. Those dedicated CLDs should never have
package entries or module entries.
classfile/moduleEntry.cpp
- line #400, typo "conver" --> "convert"
- line #500, maybe sort if n is greater than 1 instead of 0 (same
comment for packageEntry.cpp line #270)
classfile/systemDictionary.cpp
- It looks like the PackageEntry and ModuleEntry tables for the system
and platform class loaders are added within
SystemDictionary::compute_java_loaders() which is called from
Thread::create_vm() but after the call in Thread::create_vm() to
call_initPhase2 which is when Universe::_module_initialized is set to
true. Did I read this correctly? If yes, then I think you have to be
sure that Universe::_module_initialized is not set until the module
graph for the 3 builtin loaders is loaded from the archive.
memory/filemap.cpp
- line #237 typo "modue" --> "module"
oops/instanceKlass.cpp
- line #2545, comment "TO DO -- point it to the archived PackageEntry
(JDK-8249262)"
are you thinking that since the module graph is read in ahead of time
that it can be set when an InstanceKlass is created? There is a point
before java.base is defined that InstanceKlass::set_package takes into
account that could be a timing issue.
Clarification/timing questions:
- Since the CDS support for capturing the module graph does not archive
unnamed modules, I assume Modules::set_bootloader_unnamed_module() is
still called. Is this true or does the unnamed module for the boot
loader get archived?
- There are some checks in modules.cpp that are valuable to have during
bootstrapping. For example, packages that are encountered during
bootstrapping before java.base is defined are put into the java.base
module but then verified after java.base is defined via
verify_javabase_packages. So at what point in the bootstrapping process
does the boot loader's archived module's become known? Could classes
have been defined to the VM before this point? Then their packages will
have to be verified to be sure that they are indeed packages within
java.base. Consider looking at other checks that occur within
classfile/modules.cpp as well.
I may have more review comments as I continue to look at this!
Thanks,
Lois