RFR: 8194759: Support caching class mirror objects

mikhailo mikhailo.seledtsov at oracle.com
Wed Feb 14 19:47:53 UTC 2018


Hi Jiangli,

I reviewed tests only.

General comments:
   -   * @requires (vm.gc=="null")
      how about when vm.gc is set G1 ?
      @requires (vm.gc=="null") || (vm.gc==G1)

   - * @run main ClassFileInstaller <xyz>
     Please use "@run driver ClassFileInstaller <xyz>"
     Igor have updated most of the tests to do so. The reason is that 
@driver will use the "driver VM",
     as opposed to VM under test. Driver VM is usually product VM, and 
is much faster.

   - could you, please, add some details about what test does in the 
comments. It probably makes more
     sense to add these comments to the *App.java, as opposed to 
*Test.java, since this is where the actual
     test logic is recorder, where is *Test.java is more of a 'driver'.


CheckCachedMirrorApp.java
   -  65     static void checkMirror(Class c, boolean 
mirrorShouldArchived) {
      I recommend renaming 'mirrorShouldArchived' to 
'mirrorShouldBeArchived' for better clarity.

   - 65     static void checkMirror(Class c, boolean mirrorShouldArchived) {
      I like that you made this method verbose, provides more info when 
trouble shooting the test failure.
      I would also add a print statement for case where 
wb.isSharedClass(c) is false, something like
      ("Class" + c + "is not shared, skipping the check")

   The rest of the test looks good. Checking well known 'boot' classes, 
app class and class loaded by a user-defined loader.


CheckCachedMirrorTest.java
   Looks good

runtime/appcds/cacheObject/RedefineClassApp.java
   The new code snippets you added (2 in total) look identical. Does it 
make sense to factor them out
   into a method? Such as:
       int checkArchivedMirrorObject(Class klass, int failCount) // will 
return new failCount as an int


MirrorWithReferenceFieldsTest.java
   Looks good

MirrorWithReferenceFieldsApp.java
   Looks good

PrimitiveTypesTest.java
   Looks good

PrimitiveTypesApp.java
   - Why are you catching and re-throwing NoSuchFieldException and 
IllegalAccessException ?
     The CDS output analyzer logic or should be able to handle these 
exceptions (or any exception for that matter) directly.

   - also, this is a matter of preference, so I have no strong opinion: 
you could make a 'wb' variable static, and a bit simplify
     method signatures. The wb is inherently static, since it does not 
change during the execution of the test/program.
     However, if you choose to keep it as is, I am OK with that.


Thank you,
Misha

On 02/08/2018 03:59 PM, Jiangli Zhou wrote:
> Please review the change for caching class mirror objects in of CDS archive. Currently, CDS archive contains java.lang.String objects and constant pool resolved_references arrays with resolved string constants (when archiving java heap object is allowed). This change adds the mirror objects. Please see the description below for details.
>
> RFE: https://bugs.openjdk.java.net/browse/JDK-8194759 <https://bugs.openjdk.java.net/browse/JDK-8194759>
> webrev: http://cr.openjdk.java.net/~jiangli/8194759/webrev.00/ <http://cr.openjdk.java.net/~jiangli/8194759/webrev.00/>
>
> Tested with all CDS/AppCDS tests (including the new tests added as part of the webrev), hs tier1 - hs tier6 (some of the tiers are in progress).
>
>
> Goal
> ====
> Support caching the klass mirror objects (java.lang.Class instances) for archived classes from built-in class loaders at CDS dump time. Runtime can use the cached mirrors without recreating the objects in the java heap.
> Classes with cached mirrors are not pre-initialized at dump time. Pre-initialization is not a goal in current scope.
> Support G1 GC, 64-bit (non-Windows). Requires UseCompressedOops and UseCompressedClassPointers.
>
> Archiving Mirror Objects at CDS Dump Time
> ==================================
> Mirror objects are copied to the 'open archive' heap regions at CDS dump time after class metadata is relocated to the shared archive spaces. In JDK 11, mirrors for archived classes with the built-in loaders (boot, PlatformClassLoader, AppClassLoader) can be archived. Following class mirrors are not archived:
>   * Archived classes with user defined class loaders
>   * Classes with signers (loaded from signed JAR file)
> The _java_mirror in the archived Klass is reset to NULL if the mirror object is not archived.
> If archiving java heap objects cannot be supported at current dumping time (e.g. unsupported GC is used), all archived Klass' _java_mirror handles are cleared and set to NULL.
>
> Mirrors for InstanceKlasses and arrayKlasses
> ————————————————————
> Mirror objects are scrubbed to remove all unsharable field values, including fields updated due to the execution of class initializer or other java code when writing out to the archive file. The cached mirrors are in the state of "being just created" by java_lang_Class::create_mirror() without the unsharable parts (e.g. class_loader, protection_domain, and module, etc.).
> The process for archiving mirrors for InstanceKlass and arrayKlass:
> 	• Allocate and copy the mirror data to the open archive heap region. The oopDesc::_metadata._klass in the archived mirror is updated to point to the relocated java.lang.Class Klass.
> 	• Clear all non-static fields in the archived mirror
> 	• For arrayKlass only
> 		• Archive the component klass mirror object and update the comp_mirror field
> 	• For InstanceKlass only
> 		• Reload initial values for all local static final fields. If the initial value is a String object, the String object is archived. For any of the static fields without initial value, the field in the archived mirror is set to 0/NULL.
> 		• The init_lock object is not archived and the field in the archived mirror is reset to NULL
> 		• Clear the protection_domain field in the archived mirror
> 	• Clear the class_loader field in the archived mirror
> 	• Clear the module field in the archived mirror
> 	• Relocate the _klass reference in the archived mirror to point to the archived Klass
> 	• Relocate the _array_klass reference in the archived mirror to point to the archived arrayKlass if not NULL
> 	• Update the klass _java_mirror handle to point to the archived mirror
> 	• Set _has_raw_archived_mirror flag in the archived class
>
> Mirrors for Primitive Types
> ————————————
> The mirrors for primitive types are created differently (see java_lang_Class::create_basic_type_mirror). All primitive type mirrors except T_VOID mirror have the _array_klass field initialized to corresponding TypeArrayKlass. The 'module' fields in basic type mirrors point to the java.base Module, which is set by ModuleEntryTable::patch_javabase_entries() when java.base Module is known.
> At dump time, the primitive type mirrors are copied to the open archive heap region. The _array_klass field in the archived mirror is updated to point to the relocated TypeArrayKlass. The 'module' field is cleared and set to NULL.
> All primitive type mirrors do not have associated 'Klass' metadata. The roots to primitive type mirrors are maintained by the Universe. When writing out the archive, the pointers to the primitive type mirrors are written into the archive.
>
> Restoring Mirror Objects at Runtime
> ============================
>
> Restoring Primitive Type Mirrors
> ——————————————
> The archived primitive mirrors are used at runtime without recreating. No restoration is needed for the primitive type mirrors. The pointers to the archived primitive type mirrors are reloaded into Universe during VM initialization. GC Access API (RootAccess<IN_ARCHIVE_ROOT>::oop_store()) is used when installing the primitive type mirrors in Universe. The mirror 'module' field is set by ModuleEntryTable::patch_javabase_entries() when java.base Module becomes known.
>
> Restoring InstanceKlass and ArrayKlass Mirrors
> ——————————————————————
> Mirror objects for non-primitive types are restored when shared classes are loaded and restored at runtime.
> Mirror restoration process:
> 	• For InstanceKlass mirror only
> 		• Create init_lock
> 		• Set protection_domain domain in the mirror
> 	• Set class_loader filed in the mirror
> 	• Create a handle for the mirror and set _java_mirror in the shared klass
> 	• Clear the _has_raw_archived_mirror flag in the shared klass
> 	• Set the module field in the mirror
>
> Mirror Fixup and Module Fixup
> ——————————————
> java.lang.Class field offsets (used by JVM) are cached at CDS dump time and loaded from the archive at runtime time. Shared classes loaded before java.lang.Class are not pushed onto the fixup_mirror_list. For those shared classes, the archived mirrors are restored directly when the classes are loaded.
> The mirrors are added to the fixup_module_list before java.base is defined and patched later when the java.lang.Module for java.base is known.
>
> GC Considerations
> ===============
> When an archived mirror is installed (becomes 'in use') during shared class loading and restoration at runtime, the archived mirror is accessed via GC access API with barrier. The archived object is denoted with IN_ARCHIVE_ROOT and becomes a special root that handled differently by GC and enqueued in SATB implicitly in G1.
> Similar to the klass constant pool resolved_references array, the archived mirrors resides in the 'open archive' heap region. The mirror fields may be updated with references pointing to other non-archive heap regions during runtime execution. References within the archived mirrors are scanned and followed by GC.
> Shared classes from builtin loaders are never unloaded after they become 'in use' (loaded from the archive) at runtime, which keeps all 'used' archived mirrors alive after being installed.
>
> Class Redefinitiaon/Restransformation with Archived Mirrors
> ==============================================
> In VM_RedefineClasses::redefine_single_class(), the mirror from ‘scratch_class' is not copied to ‘the_class’. After redefinition/retransformation, the original mirror in 'the_class' is still used.
>
> During verification of the scratch class, the original mirror (handle) from ‘the_class’ is temporary copied into the ‘scratch_class’ to avoid issues. When verification is done, the ‘scratch_class’ is restored to point to the scratch mirror.
>
> Class redefinition/retransformation has no impact on the archived mirror from the original class.
>
> Thanks!
>
> Jiangli



More information about the hotspot-runtime-dev mailing list