<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi Ioi,<div class=""><br class=""></div><div class="">Thanks for looking again.</div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Aug 4, 2017, at 2:22 PM, Ioi Lam <<a href="mailto:ioi.lam@oracle.com" class="">ioi.lam@oracle.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">
  
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type" class="">
  
  <div bgcolor="#FFFFFF" text="#000000" class="">
    <tt class="">Hi Jiangli,</tt><tt class=""><br class="">
    </tt><tt class=""><br class="">
      The code looks good in general. I just have a few pet peeves for
      readability:<br class="">
      <br class="">
      <br class="">
    </tt><tt class="">(1) stringTable.cpp and metaspaceShared.cpp have the same
      asserts</tt><tt class=""><br class="">
    </tt><tt class=""><br class="">
    </tt><tt class=""> 704   assert(UseG1GC, "Only support G1 GC");</tt><tt class=""><br class="">
    </tt><tt class=""> 705   assert(UseCompressedOops &&
      UseCompressedClassPointers,</tt><tt class=""><br class="">
    </tt><tt class=""> 706          "Only support UseCompressedOops and
      UseCompressedClassPointers enabled");</tt><tt class=""><br class="">
    </tt><tt class=""><br class="">
    </tt><tt class="">1615   assert(UseG1GC, "Only support G1 GC");</tt><tt class=""><br class="">
    </tt><tt class="">1616   assert(UseCompressedOops &&
      UseCompressedClassPointers,</tt><tt class=""><br class="">
    </tt><tt class="">1617          "Only support UseCompressedOops and
      UseCompressedClassPointers enabled");</tt><tt class=""><br class="">
    </tt><tt class=""><br class="">
    </tt><tt class="">Maybe it's better to combine them into a single function
      like MetaspaceShared::assert_vm_flags() so they don't get out of
      sync?</tt><tt class=""><br class=""></tt></div></div></blockquote><div><br class=""></div>There is a MetaspaceShared::allow_archive_heap_object(), which checks for UseG1GC, UseCompressedOops and UseCompressedClassPointers combined. It does not seem to worth add another separate API for asserting the required flags. I’ll use that in the assert. </div><div><br class=""></div><div><blockquote type="cite" class=""><div class=""><div bgcolor="#FFFFFF" text="#000000" class=""><tt class="">
    </tt><tt class=""><br class="">
      <br class="">
      <br class="">
    </tt><tt class="">(2) FileMapInfo::write_archive_heap_regions()</tt><tt class=""><br class="">
    </tt><tt class=""><br class="">
    </tt><tt class="">I still find this code very hard to read, especially due to
      the loop.<br class="">
      <br class="">
      First, the comments are not consistent with the code:</tt><tt class=""><br class="">
    </tt><tt class=""><br class="">
    </tt><tt class="">    498   assert(arr_len <= max_num_regions, "number of
      memory regions exceeds maximum");</tt><tt class=""><br class="">
      <br class="">
    </tt><tt class="">but the comments says: "The rest are consecutive full GC
      regions" which means there's a chance for max_num_regions to be
      more than 2 (which will be the case with Calvin's java-loader
      dumping changes using very small heap size).</tt><tt class=""> So the code
      is actually wrong.<br class=""></tt></div></div></blockquote><div><br class=""></div><div>The max_num_regions is the maximum number of region for each archived heap space (the string space, or open archive space). We only run into the case where the MemRegion array size is larger than max_num_regions with Calvin’s pending change. As part of Calvin’s change, he will change the assert into a check and bail out if the number of MemRegions are larger than max_num_regions due to heap fragmentation.</div><div><br class=""></div><div><br class=""></div><blockquote type="cite" class=""><div class=""><div bgcolor="#FFFFFF" text="#000000" class=""><tt class="">
    </tt><tt class=""><br class="">
    </tt><tt class="">The word "region" is used in these parameters, but they
      don't mean the same thing.<br class="">
      <br class="">
    </tt><tt class="">              GrowableArray<MemRegion> *regions</tt><tt class=""><br class="">
    </tt><tt class="">              int first_region, int max_num_regions,</tt><tt class=""><br class="">
    </tt><tt class=""><br class="">
      <br class="">
      How about regions      -> g1_regions_list<br class="">
                first_region -> first_region_in_archive<br class=""></tt></div></div></blockquote><div><br class=""></div><div>The GrowableArray above is the MemRegions that GC code gives back to us. The GC code combines multiple G1 regions. The comments probably are over-explaining the details, which are hidden in the GC code. Probably that’s the confusing source. I’ll make the comment more clear. </div><div><br class=""></div><div>Using g1_regions_list would also be confusing, since <span style="font-family: Menlo;" class="">write_archive_heap_regions</span> does not handle G1 regions directly. It processes the MemRegion array that GC code returns. How about changing ‘regions’ to ‘mem_regions’ or ‘archive_regions'?</div><br class=""><blockquote type="cite" class=""><div class=""><div bgcolor="#FFFFFF" text="#000000" class=""><tt class="">
      <br class="">
      <br class="">
      In the comments, I find the phrase 'the current archive heap
      region' ambiguous. It could be (erroneously) interpreted as "a
      region from the currently mapped archive”</tt></div></div></blockquote></div><div><blockquote type="cite" class=""><div class=""><div bgcolor="#FFFFFF" text="#000000" class=""><tt class=""><br class="">
      To make it unambiguous, how about changing<br class="">
      <br class="">
      <br class="">
       464 // Write the current archive heap region, which contains one
      or multiple GC(G1) regions.<br class="">
      <br class="">
      <br class="">
      to<br class="">
      <br class="">
          // Write the given list of G1 memory regions into the archive,
      starting at </tt><br class="">
    <tt class=""><tt class="">    // first_region_in_archive</tt>.<br class=""></tt></div></div></blockquote><div><br class=""></div><div><br class=""></div><div>Ok. How about the following:</div><div><br class=""></div><div>// Write the given list of java heap memory regions into the archive, starting at </div><div><tt class="">// first_region_in_archive</tt>.</div><br class=""><blockquote type="cite" class=""><div class=""><div bgcolor="#FFFFFF" text="#000000" class=""><tt class="">
      <br class="">
      <br class="">
      Also, for the explanation of how the G1 regions are written into
      the archive, how about:<br class="">
      <br class="">
         // The G1 regions in the list are sorted in ascending address
      order. When there are more objects<br class="">
         // than the capacity of a single G1 region, the bottom-most G1
      region may be partially filled, and the<br class="">
         // remaining G1 region(s) are consecutively allocated and fully
      filled.<br class="">
         //<br class="">
         // Thus, the bottom-most G1 region (if not empty) is written
      into </tt><tt class=""><tt class="">first_region_in_archive</tt>.<br class="">
         // The remaining G1 regions (if exist) are coalesced and
      written as a single block<br class="">
         // into (</tt><tt class=""><tt class=""><tt class="">first_region_in_archive </tt>+ 1)</tt>
      <br class="">
      <br class="">
         // Here's the mapping from (g1 regions) -> (archive
      regions).<br class="">
      <br class="">
      <br class="">
    </tt><tt class="">All this function needs to do is to decide the values for </tt><tt class=""><br class="">
    </tt><tt class=""><br class="">
    </tt><tt class="">     r0_start, r0_top</tt><tt class=""><br class="">
    </tt><tt class="">     r1_start, r1_top</tt><tt class=""><br class="">
    </tt><tt class="">
    </tt><tt class=""><br class="">
    </tt><tt class="">I think it would be much better to not use the loop, and
      not use the max_num_regions parameter (it's always 2 anyway).</tt><tt class=""><br class="">
    </tt><tt class=""><br class="">
           *r0_start = *r0_top = NULL;<br class="">
           *r1_start = *r1_top = NULL;<br class="">
      <br class="">
    </tt><tt class="">     if (arr_len >= 1) {</tt><tt class=""><br class="">
    </tt><tt class="">         *r0_start = regions->at(0).start();</tt><tt class=""><br class="">
    </tt><tt class="">         *r0_end = *r0_start +
      regions->at(0).byte_size();</tt><tt class=""><br class="">
    </tt><tt class="">     }</tt><tt class=""><br class="">
    </tt><tt class="">     if (arr_len >= 2) {</tt><tt class=""><br class="">
    </tt><tt class="">         int last = arr_len - 1;</tt><tt class=""><br class="">
    </tt><tt class="">
               *r1_start = regions->at(1).start();</tt><tt class=""><br class="">
    </tt><tt class="">
               *r1_end = regions->at(last).start() +
      regions->at(last).byte_size();</tt><tt class=""><br class="">
    </tt><tt class="">     
      }<br class="">
      <br class="">
      what do you think?<br class=""></tt></div></div></blockquote><div><br class=""></div><div>We need to write out all archive regions including the empty ones. The loop using max_num_regions is the easiest way. I’d like to remove the code that deals with r0_* and r1_ explicitly. Let me try that.</div><br class=""><blockquote type="cite" class=""><div class=""><div bgcolor="#FFFFFF" text="#000000" class=""><tt class="">
      <br class="">
      <br class="">
      <br class="">
      (3) metaspace.cpp<br class="">
      <br class="">
      3350         // Map the archived heap regions after compressed
      pointers<br class="">
      3351         // because it relies on compressed class pointers
      setting to work<br class="">
      <br class="">
      do you mean this?<br class="">
      <br class="">
          // Archived heap regions depend on the parameters of
      compressed class pointers, so<br class="">
          // they must be mapped after such parameters have been decided
      in the above call.<br class=""></tt></div></div></blockquote><div><br class=""></div>Hmmm, maybe use ‘arguments’ instead of ‘parameters’?</div><div> <br class=""><blockquote type="cite" class=""><div class=""><div bgcolor="#FFFFFF" text="#000000" class=""><tt class="">
      <br class="">
      <br class="">
      (4) I found this name not strictly grammatical. How about this:<br class="">
      <br class="">
           allow_archive_heap_object ->
      is_heap_object_archiving_allowed<br class=""></tt></div></div></blockquote><div><br class=""></div>Ok.</div><div><br class=""><blockquote type="cite" class=""><div class=""><div bgcolor="#FFFFFF" text="#000000" class=""><tt class="">
      <br class="">
      (5) in most of your code, 'archive' is used as a noun, except in
      StringTable::archive_string() where it's used as a verb.<br class="">
      <br class="">
      archive_string could also be interpreted erroneously as "return a
      string that's already in the archive". So to be consistent and unambiguous,
      I think it's better to rename it to
      StringTable::create_archived_string()<br class=""></tt></div></div></blockquote><div><br class=""></div>Ok.</div><div><br class=""></div><div>Thanks,</div><div>Jiangli</div><div><br class=""><blockquote type="cite" class=""><div class=""><div bgcolor="#FFFFFF" text="#000000" class=""><tt class="">
      <br class="">
      <br class="">
      Thanks<br class="">
      - Ioi<br class="">
    </tt><tt class=""></tt><tt class="">
    </tt><tt class=""><br class="">
    </tt><br class="">
    <div class="moz-cite-prefix">On 8/3/17 5:15 PM, Jiangli Zhou wrote:<br class="">
    </div>
    <blockquote cite="mid:98EF8CF9-FD28-46BC-8D3D-52DEA205EBD5@oracle.com" type="cite" class="">Here are the updated webrevs.<br class="">
      <br class="">
      <a moz-do-not-send="true" href="http://cr.openjdk.java.net/%7Ejiangli/8179302/webrev.hotspot.02/" class="">http://cr.openjdk.java.net/~jiangli/8179302/webrev.hotspot.02/</a><br class="">
      <a class="moz-txt-link-freetext" href="http://cr.openjdk.java.net/~jiangli/8179302/webrev.whitebox.02/">http://cr.openjdk.java.net/~jiangli/8179302/webrev.whitebox.02/</a>
      <div class=""><br class="">
      </div>
      <div class="">Changes in the updated webrevs include:</div>
      <div class="">
        <ul class="MailOutline">
          <li class="">Merge with Ioi’s recent shared space auto-sizing
            change (<span style="font-family: 'Helvetica Neue';" class="">8072061)</span></li>
          <li class=""><span style="font-family: 'Helvetica Neue';" class="">Addressed all feedbacks from Ioi and Coleen
              (Thanks for detailed review!)</span></li>
        </ul>
        <div class=""><font class="" face="Helvetica Neue"><br class="">
          </font></div>
        <div class=""><font class="" face="Helvetica Neue">Thanks,</font></div>
        <div class=""><font class="" face="Helvetica Neue">Jiangli</font></div>
        <br class="">
        <br class="">
        <blockquote type="cite" class="">On Aug 1, 2017, at 5:29 PM,
          Jiangli Zhou <a class="moz-txt-link-rfc2396E" href="mailto:jiangli.zhou@Oracle.COM"><jiangli.zhou@Oracle.COM></a> wrote:<br class="">
          <br class="">
          Hi Ioi,<br class="">
          <br class="">
          Thank you so much for reviewing this. I’ve addressed all your
          feedbacks. Please see details below. I’ll updated the webrev
          after addressing Coleen’s comments.<br class="">
          <br class="">
          <blockquote type="cite" class="">On Jul 30, 2017, at 9:07 PM,
            Ioi Lam <a class="moz-txt-link-rfc2396E" href="mailto:ioi.lam@oracle.com"><ioi.lam@oracle.com></a> wrote:<br class="">
            <br class="">
            Hi Jiangli,<br class="">
            <br class="">
            Here are my comments. I've not reviewed the GC code and I'll
            leave that to the GC experts :-)<br class="">
            <br class="">
            stringTable.cpp: StringTable::archive_string<br class="">
            <br class="">
               add assert for DumpSharedSpaces only<br class="">
          </blockquote>
          <br class="">
          Ok.<br class="">
          <br class="">
          <blockquote type="cite" class=""><br class="">
            filemap.cpp<br class="">
            <br class="">
            525 void
            FileMapInfo::write_archive_heap_regions(GrowableArray<MemRegion>
            *regions,<br class="">
            526                                              int
            first_region, int num_regions) {<br class="">
            <br class="">
            When I first read this function, I found it hard to follow,
            especially this part that coalesces the trailing regions:<br class="">
            <br class="">
            537         int len = regions->length();<br class="">
            538         if (len > 1) {<br class="">
            539           start = (char*)regions->at(1).start();<br class="">
            540           size = (char*)regions->at(len - 1).end() -
            start;<br class="">
            541         }<br class="">
            542       }<br class="">
            <br class="">
            The rest of filemap.cpp always perform identical operations
            on MemRegion arrays, which are either 1 or 2 in size.
            However, this function doesn't follow that pattern; it also
            has a very different notion of "region", and the confusing
            part is regions->size() is not the same as num_regions.<br class="">
            <br class="">
            How about we change the API to something like the following?
            Before calling this API, the caller needs to coalesce the
            trailing G1 regions into a single MemRegion.<br class="">
            <br class="">
                FileMapInfo::write_archive_heap_regions(MemRegion
            *regions, int first, int num_regions) {<br class="">
                   if (first == MetaspaceShared::first_string) {<br class="">
                      assert(num_regons <=
             MetaspaceShared::max_strings, "...");<br class="">
                   } else {<br class="">
                      assert(first ==
            MetaspaceShared::first_open_archive_heap_region, "...");<br class="">
                      assert(num_regons <=
            MetaspaceShared::max_open_archive_heap_region, "...");<br class="">
            }<br class="">
                   ....<br class="">
            <br class="">
            <br class="">
          </blockquote>
          <br class="">
          I’ve reworked the function and simplified the code. <br class="">
          <br class="">
          <blockquote type="cite" class=""><br class="">
            756   if (!string_data_mapped) {<br class="">
            757     StringTable::ignore_shared_strings(true);<br class="">
            758     assert(string_ranges == NULL &&
            num_string_ranges == 0, "sanity");<br class="">
            759   }<br class="">
            760<br class="">
            761   if (open_archive_heap_data_mapped) {<br class="">
            762    
            MetaspaceShared::set_open_archive_heap_region_mapped();<br class="">
            763   } else {<br class="">
            764     assert(open_archive_heap_ranges == NULL &&
            num_open_archive_heap_ranges == 0, "sanity");<br class="">
            765   }<br class="">
            <br class="">
            Maybe the two "if" statements should be more consistent?
            Instead of StringTable::ignore_shared_strings, how
            about StringTable::set_shared_strings_region_mapped()?<br class="">
          </blockquote>
          <br class="">
          Fixed.<br class="">
          <br class="">
          <blockquote type="cite" class=""><br class="">
            FileMapInfo::map_heap_data() --<br class="">
            <br class="">
            818     char* addr = (char*)regions[i].start();<br class="">
            819     char* base = os::map_memory(_fd, _full_path,
            si->_file_offset,<br class="">
            820                                 addr,
            regions[i].byte_size(), si->_read_only,<br class="">
            821                                 si->_allow_exec);<br class="">
            <br class="">
            What happens when the first region succeeds to map but the
            second region fails to map? Will both regions be unmapped? I
            don't see where you store the return value (base) from
            os::map_memory(). Does it mean the code assumes that (addr
            == base). If so, we need an assert here.<br class="">
          </blockquote>
          <br class="">
          If any of the region fails to map, we bail out and call
          dealloc_archive_heap_regions(), which handles the deallocation
          of any regions specified. If second region fails to map, all
          memory ranges specified by ‘regions’ array are deallocated. We
          don’t unmap the memory here since it is part of the java heap.
          Unmapping of heap memory are handled by GC code. The ‘if’
          check below makes sure base == addr.<br class="">
          <br class="">
              if (base == NULL || base != addr) {<br class="">
                // dealloc the regions from java heap<br class="">
                dealloc_archive_heap_regions(regions, region_num);<br class="">
                if (log_is_enabled(Info, cds)) {<br class="">
                  log_info(cds)("UseSharedSpaces: Unable to map at
          required address in java heap.");<br class="">
                }<br class="">
                return false;<br class="">
              }<br class="">
          <br class="">
          <br class="">
          <blockquote type="cite" class=""><br class="">
            constantPool.cpp<br class="">
            <br class="">
                Handle refs_handle;<br class="">
                ...<br class="">
                refs_handle = Handle(THREAD, (oop)archived);<br class="">
            <br class="">
            This will first create a NULL handle, then construct a
            temporary handle, and then assign the temp handle back to
            the null handle. This means two handles will be pushed onto
            THREAD->metadata_handles()<br class="">
            <br class="">
            I think it's more efficient if you merge these into a single
            statement<br class="">
            <br class="">
                Handle refs_handle(THREAD, (oop)archived);<br class="">
          </blockquote>
          <br class="">
          Fixed.<br class="">
          <br class="">
          <blockquote type="cite" class=""><br class="">
            Is this experimental code? Maybe it should be removed?<br class="">
            <br class="">
            664     if (tag_at(index).is_unresolved_klass()) {<br class="">
            665 #if 0<br class="">
            666       CPSlot entry = cp->slot_at(index);<br class="">
            667       Symbol* name = entry.get_symbol();<br class="">
            668       Klass* k = SystemDictionary::find(name, NULL,
            NULL, THREAD);<br class="">
            669       if (k != NULL) {<br class="">
            670         klass_at_put(index, k);<br class="">
            671       }<br class="">
            672 #endif<br class="">
            673     } else<br class="">
          </blockquote>
          <br class="">
          Removed.<br class="">
          <br class="">
          <blockquote type="cite" class=""><br class="">
            cpCache.hpp:<br class="">
            <br class="">
                u8   _archived_references<br class="">
            <br class="">
            shouldn't this be declared as an narrowOop to avoid the type
            casts when it's used?<br class="">
          </blockquote>
          <br class="">
          Ok. <br class="">
          <br class="">
          <blockquote type="cite" class=""><br class="">
            cpCache.cpp:<br class="">
            <br class="">
               add assert so that one of these is used only at dump time
            and the other only at run time?<br class="">
            <br class="">
            610 oop ConstantPoolCache::archived_references() {<br class="">
            611   return
            oopDesc::decode_heap_oop((narrowOop)_archived_references);<br class="">
            612 }<br class="">
            613<br class="">
            614 void ConstantPoolCache::set_archived_references(oop o) {<br class="">
            615   _archived_references =
            (u8)oopDesc::encode_heap_oop(o);<br class="">
            616 }<br class="">
          </blockquote>
          <br class="">
          Ok.<br class="">
          <br class="">
          Thanks!<br class="">
          <br class="">
          Jiangli<br class="">
          <br class="">
          <blockquote type="cite" class=""><br class="">
            Thanks!<br class="">
            - Ioi<br class="">
            <br class="">
            On 7/27/17 1:37 PM, Jiangli Zhou wrote:<br class="">
            <blockquote type="cite" class="">Sorry, the mail didn’t
              handle the rich text well. I fixed the format below.<br class="">
              <br class="">
              Please help review the changes for JDK-8179302
              (Pre-resolve constant pool string entries and cache
              resolved_reference arrays in CDS archive). Currently, the
              CDS archive can contain cached class metadata, interned
              java.lang.String objects. This RFE adds the constant pool
              ‘resolved_references’ arrays (hotspot specific) to the
              archive for startup/runtime performance enhancement.
              The ‘resolved_references' arrays are used to hold
              references of resolved constant pool entries including
              Strings, mirrors, etc. With the 'resolved_references’
              being cached, string constants in shared classes can now
              be resolved to existing interned java.lang.Strings at CDS
              dump time. G1 and 64-bit platforms are required.<br class="">
              <br class="">
              The GC changes in the RFE were discussed and guided by
              Thomas Schatzl and GC team. Part of the changes were
              contributed by Thomas himself.<br class="">
              RFE:      
               <a class="moz-txt-link-freetext" href="https://bugs.openjdk.java.net/browse/JDK-8179302">https://bugs.openjdk.java.net/browse/JDK-8179302</a><br class="">
              hotspot:
                <a class="moz-txt-link-freetext" href="http://cr.openjdk.java.net/~jiangli/8179302/webrev.hotspot.01/">http://cr.openjdk.java.net/~jiangli/8179302/webrev.hotspot.01/</a><br class="">
whitebox: <a class="moz-txt-link-freetext" href="http://cr.openjdk.java.net/~jiangli/8179302/webrev.whitebox.01/">http://cr.openjdk.java.net/~jiangli/8179302/webrev.whitebox.01/</a><br class="">
              <br class="">
              Please see below for details of supporting cached
              ‘resolved_references’ and pre-resolving string constants.<br class="">
              <br class="">
              Types of Pinned G1 Heap Regions<br class="">
              <br class="">
              The pinned region type is a super type of all archive
              region types, which include the open archive type and the
              closed archive type.<br class="">
              <br class="">
              00100 0 [ 8] Pinned Mask<br class="">
              01000 0 [16] Old Mask<br class="">
              10000 0 [32] Archive Mask<br class="">
              11100 0 [56] Open Archive:   ArchiveMask | PinnedMask |
              OldMask<br class="">
              11100 1 [57] Closed Archive: ArchiveMask | PinnedMask |
              OldMask + 1<br class="">
              <br class="">
              <br class="">
              Pinned Regions<br class="">
              <br class="">
              Objects within the region are 'pinned', which means GC
              does not move any live objects. GC scans and marks objects
              in the pinned region as normal, but skips forwarding live
              objects. Pointers in live objects are updated. Dead
              objects (unreachable) can be collected and freed.<br class="">
              <br class="">
              Archive Regions<br class="">
              <br class="">
              The archive types are sub-types of 'pinned'. There are two
              types of archive region currently, open archive and closed
              archive. Both can support caching java heap objects via
              the CDS archive.<br class="">
              <br class="">
              An archive region is also an old region by design.<br class="">
              <br class="">
              Open Archive (GC-RW) Regions<br class="">
              <br class="">
              Open archive region is GC writable. GC scans & marks
              objects within the region and adjusts (updates) pointers
              in live objects the same way as a pinned region. Live
              objects (reachable) are pinned and not forwarded by GC.<br class="">
              Open archive region does not have 'dead' objects.
              Unreachable objects are 'dormant' objects. Dormant objects
              are not collected and freed by GC.<br class="">
              <br class="">
              Adjustable Outgoing Pointers<br class="">
              <br class="">
              As GC can adjust pointers within the live objects in open
              archive heap region, objects can have outgoing pointers to
              another java heap region, including closed archive region,
              open archive region, pinned (or humongous) region, and
              normal generational region. When a referenced object is
              moved by GC, the pointer within the open archive region is
              updated accordingly.<br class="">
              <br class="">
              Closed Archive (GC-RO) Regions<br class="">
              <br class="">
              The closed archive region is GC read-only region. GC
              cannot write into the region. Objects are not scanned and
              marked by GC. Objects are pinned and not forwarded.
              Pointers are not updated by GC either. Hence, objects
              within the archive region cannot have any outgoing
              pointers to another java heap region. Objects however can
              still have pointers to other objects within the
              closed archive regions (we might allow pointers to open
              archive regions in the future). That restricts the type of
              java objects that can be supported by the archive region.<br class="">
              In JDK 9 we support archive Strings with the archive
              regions.<br class="">
              <br class="">
              The GC-readonly archive region makes java heap memory
              sharable among different JVM processes. NOTE:
              synchronization on the objects within the archive heap
              region can still cause writes to the memory page.<br class="">
              <br class="">
              Dormant Objects<br class="">
              <br class="">
              Dormant objects are unreachable java objects within the
              open archive heap region.<br class="">
              A java object in the open archive heap region is a live
              object if it can be reached during scanning. Some of the
              java objects in the region may not be reachable during
              scanning. Those objects are considered as dormant, but not
              dead. For example, a constant pool 'resolved_references'
              array is reachable via the klass root if its container
              klass (shared) is already loaded at the time during GC
              scanning. If a shared klass is not yet loaded, the klass
              root is not scanned and it's constant pool
              'resolved_reference' array (A) in the open archive region
              is not reachable. Then A is a dormant object.<br class="">
              <br class="">
              Object State Transition<br class="">
              <br class="">
              All java objects are initially dormant objects when open
              archive heap regions are mapped to the runtime java heap.
              A dormant object becomes live object when the associated
              shared class is loaded at runtime. Explicit call
              to G1SATBCardTableModRefBS::enqueue() needs to be made
              when a dormant object becomes live. That should be the
              case for cached objects with strong roots as well, since
              strong roots are only scanned at the start of GC marking
              (the initial marking) but not during Remarking/Final
              marking. If a cached object becomes live during concurrent
              marking phase, G1 may not find it and mark it live unless
              a call to G1SATBCardTableModRefBS::enqueue() is made for
              the object.<br class="">
              <br class="">
              Currently, a live object in the open archive heap region
              cannot become dormant again. This restriction simplifies
              GC requirement and guarantees all outgoing pointers are
              updated by GC correctly. Only objects for shared classes
              from the builtin class loaders (boot,
              PlatformClassLoaders, and AppClassLoaders) are supported
              for caching.<br class="">
              <br class="">
              Caching Java Objects at Archive Dump Time<br class="">
              <br class="">
              The closed archive and open archive regions are allocated
              near the top of the dump time java heap. Archived java
              objects are copied into the designated archive heap
              regions. For example, String objects and the underlying
              'value' arrays are copied into the closed archive regions.
              All references to the archived objects (from shared class
              metadata, string table, etc) are set to the new heap
              locations. A hash table is used to keep track of all
              archived java objects during the copying process to make
              sure java object is not archived more than once if reached
              from different roots. It also makes sure references to the
              same archived object are updated using the same new
              address location.<br class="">
              <br class="">
              Caching Constant Pool resolved_references Array<br class="">
              <br class="">
              The 'resolved_references' is an array that holds
              references of resolved constant pool entries including
              Strings, mirrors and methodTypes, etc. Each loaded class
              has one 'resolved_references' array (in
              ConstantPoolCache). The 'resolved_references' arrays are
              copied into the open archive regions during dump process.
              Prior to copying the 'resolved_references' arrays,
              JVM iterates through constant pool entries and resolves
              all JVM_CONSTANT_String entries to existing interned
              Strings for all archived classes. When resolving, JVM only
              looks up the string table and finds existing interned
              Strings without inserting new ones. If a string entry
              cannot be resolved to an existing interned String, the
              constant pool entry remain as unresolved. That prevents
              memory waste if a constant pool string entry is never used
              at runtime.<br class="">
              <br class="">
              All String objects referenced by the string table are
              copied first into the closed archive regions. The string
              table entry is updated with the new location when each
              String object is archived. The JVM updates the resolved
              constant pool string entries with the new object locations
              when copying the 'resolved_references' arrays to the open
              archive regions. References to the 'resolved_references'
              arrays in the ConstantPoolCache are also updated.<br class="">
              At runtime as part of
              ConstantPool::restore_unshareable_info() work, call
              G1SATBCardTableModRefBS::enqueue() to let GC know the
              'resolved_references' is becoming live. A handle is
              created for the cached object and added to the
              loader_data's handles.<br class="">
              <br class="">
              Runtime Java Heap With Cached Java Objects<br class="">
              <br class="">
              <br class="">
              The closed archive regions (the string regions) and open
              archive regions are mapped to the runtime java heap at the
              same offsets as the dump time offsets from the runtime
              java heap base.<br class="">
              <br class="">
              Preliminary test execution and status:<br class="">
              <br class="">
              JPRT: passed<br class="">
              Tier2-rt: passed<br class="">
              Tier2-gc: passed<br class="">
              Tier2-comp: passed<br class="">
              Tier3-rt: passed<br class="">
              Tier3-gc: passed<br class="">
              Tier3-comp: passed<br class="">
              Tier4-rt: passed<br class="">
              Tier4-gc: passed<br class="">
              Tier4-comp:6 jobs timed out, all other tests passed<br class="">
              Tier5-rt: one test failed but passed when running locally,
              all other tests passed<br class="">
              Tier5-gc: passed<br class="">
              Tier5-comp: running<br class="">
              hotspot_gc: two jobs timed out, all other tests passed<br class="">
              hotspot_gc in CDS mode: two jobs timed out, all other
              tests passed<br class="">
              vm.gc: passed<br class="">
              vm.gc in CDS mode: passed<br class="">
              Kichensink: passed<br class="">
              Kichensink in CDS mode: passed<br class="">
              <br class="">
              Thanks,<br class="">
              Jiangli<br class="">
            </blockquote>
            <br class="">
          </blockquote>
          <br class="">
        </blockquote>
        <br class="">
      </div>
    </blockquote>
    <br class="">
  </div>

</div></blockquote></div><br class=""></div></body></html>