8214388: CDS dumping fails with java heap fragmentation
authoriklam
Mon, 03 Dec 2018 22:27:24 -0800
changeset 52811 ff04b71bf6f1
parent 52810 a2500cf11ee5
child 52812 fc54d27e58d8
child 52844 de8be034dbd4
8214388: CDS dumping fails with java heap fragmentation Summary: Force a full GC with a single thread before writing heap archive regions Reviewed-by: sjohanss, jiangli
src/hotspot/share/classfile/compactHashtable.hpp
src/hotspot/share/gc/g1/g1Arguments.cpp
src/hotspot/share/gc/g1/g1HeapVerifier.cpp
src/hotspot/share/gc/g1/g1HeapVerifier.hpp
src/hotspot/share/gc/shared/gcCause.cpp
src/hotspot/share/gc/shared/gcCause.hpp
src/hotspot/share/memory/filemap.cpp
src/hotspot/share/memory/heapShared.cpp
src/hotspot/share/memory/metaspaceShared.cpp
test/hotspot/jtreg/runtime/appcds/LotsOfClasses.java
test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedIntegerCacheTest.java
test/hotspot/jtreg/runtime/appcds/javaldr/HumongousDuringDump.java
test/hotspot/jtreg/runtime/appcds/javaldr/HumongousDuringDumpTransformer.java
test/hotspot/jtreg/runtime/appcds/javaldr/HumongousDuringDumpTransformer.mf
test/hotspot/jtreg/runtime/appcds/sharedStrings/InvalidFileFormat.java
test/hotspot/jtreg/runtime/appcds/sharedStrings/SharedStringsHumongous.java
test/hotspot/jtreg/runtime/appcds/sharedStrings/SharedStringsStress.java
test/hotspot/jtreg/runtime/appcds/sharedStrings/invalidFormat/LengthOverflow.txt
test/hotspot/jtreg/runtime/appcds/sharedStrings/invalidFormat/TruncatedString.txt
--- a/src/hotspot/share/classfile/compactHashtable.hpp	Tue Dec 04 11:10:19 2018 +0530
+++ b/src/hotspot/share/classfile/compactHashtable.hpp	Mon Dec 03 22:27:24 2018 -0800
@@ -375,6 +375,9 @@
   inline int remain() {
     return (int)(_end - _p);
   }
+  int last_line_no() {
+    return _line_no - 1;
+  }
 
   void corrupted(const char *p, const char *msg);
 
--- a/src/hotspot/share/gc/g1/g1Arguments.cpp	Tue Dec 04 11:10:19 2018 +0530
+++ b/src/hotspot/share/gc/g1/g1Arguments.cpp	Mon Dec 03 22:27:24 2018 -0800
@@ -81,6 +81,13 @@
     vm_exit_during_initialization("The flag -XX:+UseG1GC can not be combined with -XX:ParallelGCThreads=0", NULL);
   }
 
+  // When dumping the CDS archive we want to reduce fragmentation by
+  // triggering a full collection. To get as low fragmentation as
+  // possible we only use one worker thread.
+  if (DumpSharedSpaces) {
+    FLAG_SET_ERGO(uint, ParallelGCThreads, 1);
+  }
+
   if (FLAG_IS_DEFAULT(G1ConcRefinementThreads)) {
     FLAG_SET_ERGO(uint, G1ConcRefinementThreads, ParallelGCThreads);
   }
--- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp	Tue Dec 04 11:10:19 2018 +0530
+++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp	Mon Dec 03 22:27:24 2018 -0800
@@ -273,6 +273,69 @@
 };
 
 // Should be only used at CDS dump time
+class VerifyReadyForArchivingRegionClosure : public HeapRegionClosure {
+  bool _seen_free;
+  bool _has_holes;
+  bool _has_unexpected_holes;
+  bool _has_humongous;
+public:
+  bool has_holes() {return _has_holes;}
+  bool has_unexpected_holes() {return _has_unexpected_holes;}
+  bool has_humongous() {return _has_humongous;}
+
+  VerifyReadyForArchivingRegionClosure() : HeapRegionClosure() {
+    _seen_free = false;
+    _has_holes = false;
+    _has_unexpected_holes = false;
+    _has_humongous = false;
+  }
+  virtual bool do_heap_region(HeapRegion* hr) {
+    const char* hole = "";
+
+    if (hr->is_free()) {
+      _seen_free = true;
+    } else {
+      if (_seen_free) {
+        _has_holes = true;
+        if (hr->is_humongous()) {
+          hole = " hole";
+        } else {
+          _has_unexpected_holes = true;
+          hole = " hole **** unexpected ****";
+        }
+      }
+    }
+    if (hr->is_humongous()) {
+      _has_humongous = true;
+    }
+    log_info(gc, region, cds)("HeapRegion " INTPTR_FORMAT " %s%s", p2i(hr->bottom()), hr->get_type_str(), hole);
+    return false;
+  }
+};
+
+// We want all used regions to be moved to the bottom-end of the heap, so we have
+// a contiguous range of free regions at the top end of the heap. This way, we can
+// avoid fragmentation while allocating the archive regions.
+//
+// Before calling this, a full GC should have been executed with a single worker thread,
+// so that no old regions would be moved to the middle of the heap.
+void G1HeapVerifier::verify_ready_for_archiving() {
+  VerifyReadyForArchivingRegionClosure cl;
+  G1CollectedHeap::heap()->heap_region_iterate(&cl);
+  if (cl.has_holes()) {
+    log_warning(gc, verify)("All free regions should be at the top end of the heap, but"
+                            " we found holes. This is probably caused by (unmovable) humongous"
+                            " allocations, and may lead to fragmentation while"
+                            " writing archive heap memory regions.");
+  }
+  if (cl.has_humongous()) {
+    log_warning(gc, verify)("(Unmovable) humongous regions have been found and"
+                            " may lead to fragmentation while"
+                            " writing archive heap memory regions.");
+  }
+  assert(!cl.has_unexpected_holes(), "all holes should have been caused by humongous regions");
+}
+
 class VerifyArchivePointerRegionClosure: public HeapRegionClosure {
 private:
   G1CollectedHeap* _g1h;
--- a/src/hotspot/share/gc/g1/g1HeapVerifier.hpp	Tue Dec 04 11:10:19 2018 +0530
+++ b/src/hotspot/share/gc/g1/g1HeapVerifier.hpp	Mon Dec 03 22:27:24 2018 -0800
@@ -115,6 +115,7 @@
   void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
   void verify_dirty_young_regions() PRODUCT_RETURN;
 
+  static void verify_ready_for_archiving();
   static void verify_archive_regions();
 };
 
--- a/src/hotspot/share/gc/shared/gcCause.cpp	Tue Dec 04 11:10:19 2018 +0530
+++ b/src/hotspot/share/gc/shared/gcCause.cpp	Mon Dec 03 22:27:24 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -60,6 +60,9 @@
     case _wb_full_gc:
       return "WhiteBox Initiated Full GC";
 
+    case _archive_time_gc:
+      return "Full GC for -Xshare:dump";
+
     case _no_gc:
       return "No GC";
 
--- a/src/hotspot/share/gc/shared/gcCause.hpp	Tue Dec 04 11:10:19 2018 +0530
+++ b/src/hotspot/share/gc/shared/gcCause.hpp	Mon Dec 03 22:27:24 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,6 +52,7 @@
     _wb_young_gc,
     _wb_conc_mark,
     _wb_full_gc,
+    _archive_time_gc,
 
     /* implementation independent, but reserved for GC use */
     _no_gc,
--- a/src/hotspot/share/memory/filemap.cpp	Tue Dec 04 11:10:19 2018 +0530
+++ b/src/hotspot/share/memory/filemap.cpp	Mon Dec 03 22:27:24 2018 -0800
@@ -683,7 +683,7 @@
   int arr_len = heap_mem == NULL ? 0 : heap_mem->length();
   if(arr_len > max_num_regions) {
     fail_stop("Unable to write archive heap memory regions: "
-              "number of memory regions exceeds maximum due to fragmentation."
+              "number of memory regions exceeds maximum due to fragmentation. "
               "Please increase java heap size "
               "(current MaxHeapSize is " SIZE_FORMAT ", InitialHeapSize is " SIZE_FORMAT ").",
               MaxHeapSize, InitialHeapSize);
--- a/src/hotspot/share/memory/heapShared.cpp	Tue Dec 04 11:10:19 2018 +0530
+++ b/src/hotspot/share/memory/heapShared.cpp	Mon Dec 03 22:27:24 2018 -0800
@@ -193,6 +193,8 @@
     return;
   }
 
+  G1HeapVerifier::verify_ready_for_archiving();
+
   {
     NoSafepointVerifier nsv;
 
--- a/src/hotspot/share/memory/metaspaceShared.cpp	Tue Dec 04 11:10:19 2018 +0530
+++ b/src/hotspot/share/memory/metaspaceShared.cpp	Mon Dec 03 22:27:24 2018 -0800
@@ -29,6 +29,7 @@
 #include "classfile/classLoaderExt.hpp"
 #include "classfile/dictionary.hpp"
 #include "classfile/loaderConstraints.hpp"
+#include "classfile/javaClasses.inline.hpp"
 #include "classfile/placeholders.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/stringTable.hpp"
@@ -350,7 +351,11 @@
   }
 }
 
+static GrowableArray<Handle>* _extra_interned_strings = NULL;
+
 void MetaspaceShared::read_extra_data(const char* filename, TRAPS) {
+  _extra_interned_strings = new (ResourceObj::C_HEAP, mtInternal)GrowableArray<Handle>(10000, true);
+
   HashtableTextDump reader(filename);
   reader.check_version("VERSION: 1.0");
 
@@ -358,15 +363,45 @@
     int utf8_length;
     int prefix_type = reader.scan_prefix(&utf8_length);
     ResourceMark rm(THREAD);
-    char* utf8_buffer = NEW_RESOURCE_ARRAY(char, utf8_length);
+    if (utf8_length == 0x7fffffff) {
+      // buf_len will overflown 32-bit value.
+      vm_exit_during_initialization(err_msg("string length too large: %d", utf8_length));
+    }
+    int buf_len = utf8_length+1;
+    char* utf8_buffer = NEW_RESOURCE_ARRAY(char, buf_len);
     reader.get_utf8(utf8_buffer, utf8_length);
+    utf8_buffer[utf8_length] = '\0';
 
     if (prefix_type == HashtableTextDump::SymbolPrefix) {
-      SymbolTable::new_symbol(utf8_buffer, utf8_length, THREAD);
+      SymbolTable::new_permanent_symbol(utf8_buffer, THREAD);
     } else{
       assert(prefix_type == HashtableTextDump::StringPrefix, "Sanity");
-      utf8_buffer[utf8_length] = '\0';
       oop s = StringTable::intern(utf8_buffer, THREAD);
+
+      if (HAS_PENDING_EXCEPTION) {
+        log_warning(cds, heap)("[line %d] extra interned string allocation failed; size too large: %d",
+                               reader.last_line_no(), utf8_length);
+        CLEAR_PENDING_EXCEPTION;
+      } else {
+#if INCLUDE_G1GC
+        if (UseG1GC) {
+          typeArrayOop body = java_lang_String::value(s);
+          const HeapRegion* hr = G1CollectedHeap::heap()->heap_region_containing(body);
+          if (hr->is_humongous()) {
+            // Don't keep it alive, so it will be GC'ed before we dump the strings, in order
+            // to maximize free heap space and minimize fragmentation.
+            log_warning(cds, heap)("[line %d] extra interned string ignored; size too large: %d",
+                                reader.last_line_no(), utf8_length);
+            continue;
+          }
+        }
+#endif
+        // Interned strings are GC'ed if there are no references to it, so let's
+        // add a reference to keep this string alive.
+        assert(s != NULL, "must succeed");
+        Handle h(THREAD, s);
+        _extra_interned_strings->append(h);
+      }
     }
   }
 }
@@ -451,8 +486,6 @@
   return _cds_i2i_entry_code_buffers;
 }
 
-// CDS code for dumping shared archive.
-
 // Global object for holding classes that have been loaded.  Since this
 // is run at a safepoint just before exit, this is the entire set of classes.
 static GrowableArray<Klass*>* _global_klass_objects;
@@ -1686,6 +1719,13 @@
     link_and_cleanup_shared_classes(CATCH);
     tty->print_cr("Rewriting and linking classes: done");
 
+    if (HeapShared::is_heap_object_archiving_allowed()) {
+      // Avoid fragmentation while archiving heap objects.
+      Universe::heap()->soft_ref_policy()->set_should_clear_all_soft_refs(true);
+      Universe::heap()->collect(GCCause::_archive_time_gc);
+      Universe::heap()->soft_ref_policy()->set_should_clear_all_soft_refs(false);
+    }
+
     VM_PopulateDumpSharedSpace op;
     VMThread::execute(&op);
   }
--- a/test/hotspot/jtreg/runtime/appcds/LotsOfClasses.java	Tue Dec 04 11:10:19 2018 +0530
+++ b/test/hotspot/jtreg/runtime/appcds/LotsOfClasses.java	Mon Dec 03 22:27:24 2018 -0800
@@ -57,16 +57,12 @@
         opts.addSuffix("--add-modules");
         opts.addSuffix("ALL-SYSTEM");
         opts.addSuffix("-Xlog:hashtables");
-        opts.addSuffix("-Xms500m");
         opts.addSuffix("-Xmx500m");
+        opts.addSuffix("-Xlog:gc+region+cds");
+        opts.addSuffix("-Xlog:gc+region=trace");
 
         OutputAnalyzer out = CDSTestUtils.createArchive(opts);
-        try {
-            CDSTestUtils.checkDump(out);
-        } catch (java.lang.RuntimeException re) {
-            out.shouldContain(
-                "number of memory regions exceeds maximum due to fragmentation");
-        }
+        CDSTestUtils.checkDump(out);
     }
 
     static void findAllClasses(ArrayList<String> list) throws Throwable {
--- a/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedIntegerCacheTest.java	Tue Dec 04 11:10:19 2018 +0530
+++ b/test/hotspot/jtreg/runtime/appcds/cacheObject/ArchivedIntegerCacheTest.java	Mon Dec 03 22:27:24 2018 -0800
@@ -146,8 +146,11 @@
                 "-Xmx1g",
                 "-XX:NewSize=1g",
                 "-Xlog:cds+heap=info",
+                "-Xlog:gc+region+cds",
+                "-Xlog:gc+region=trace",
                 use_whitebox_jar);
         TestCommon.checkDump(output,
-            "Cannot archive the sub-graph referenced from [Ljava.lang.Integer; object");
+            "Cannot archive the sub-graph referenced from [Ljava.lang.Integer; object",
+            "humongous regions have been found and may lead to fragmentation");
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/javaldr/HumongousDuringDump.java	Mon Dec 03 22:27:24 2018 -0800
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Test how CDS dumping handles the existence of humongous G1 regions.
+ * @library /test/lib /test/hotspot/jtreg/runtime/appcds /test/hotspot/jtreg/runtime/appcds/test-classes
+ * @requires vm.cds.archived.java.heap
+ * @requires vm.flavor != "minimal"
+ * @modules java.base/jdk.internal.misc
+ *          jdk.jartool/sun.tools.jar
+ *          java.management
+ * @build HumongousDuringDumpTransformer Hello
+ * @run main/othervm/timeout=240 HumongousDuringDump
+ */
+
+import jdk.test.lib.cds.CDSOptions;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+
+public class HumongousDuringDump {
+    public static String appClasses[] = {
+        "Hello",
+    };
+    public static String agentClasses[] = {
+        "HumongousDuringDumpTransformer",
+    };
+
+    public static void main(String[] args) throws Throwable {
+        String agentJar =
+            ClassFileInstaller.writeJar("HumongousDuringDumpTransformer.jar",
+                                        ClassFileInstaller.Manifest.fromSourceFile("HumongousDuringDumpTransformer.mf"),
+                                        agentClasses);
+
+        String appJar =
+            ClassFileInstaller.writeJar("HumongousDuringDumpApp.jar", appClasses);
+
+        String gcLog = Boolean.getBoolean("test.cds.verbose.gc") ?
+            "-Xlog:gc*=info,gc+region=trace,gc+alloc+region=debug" : "-showversion";
+
+        String extraArg = "-javaagent:" + agentJar;
+        String extraOption = "-XX:+AllowArchivingWithJavaAgent";
+
+        OutputAnalyzer out =
+          TestCommon.testDump(appJar, TestCommon.list("Hello"),
+                              "-XX:+UnlockDiagnosticVMOptions", extraOption,
+                              "-Xlog:gc+region+cds",
+                              "-Xlog:gc+region=trace",
+                              extraArg, "-Xmx64m", gcLog);
+        out.shouldContain("(Unmovable) humongous regions have been found and may lead to fragmentation");
+        out.shouldContain("All free regions should be at the top end of the heap, but we found holes.");
+        out.shouldMatch("gc,region,cds. HeapRegion .* HUM. hole");
+        String pattern = "gc,region,cds. HeapRegion .*hole";
+        out.shouldMatch(pattern);
+        out.shouldNotMatch(pattern + ".*unexpected");
+
+        TestCommon.run(
+                "-cp", appJar,
+                "-verbose",
+                "-Xmx64m",
+                "-XX:+PrintSharedSpaces",
+                "-XX:+UnlockDiagnosticVMOptions", extraOption,
+                gcLog,
+                "Hello")
+              .assertNormalExit();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/javaldr/HumongousDuringDumpTransformer.java	Mon Dec 03 22:27:24 2018 -0800
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import java.lang.instrument.ClassFileTransformer;
+import java.lang.instrument.Instrumentation;
+import java.lang.instrument.IllegalClassFormatException;
+import java.security.ProtectionDomain;
+
+// This test is sensitive to -Xmx. It must be run with -xmx64m.
+// Running with a different -Xmx requires changing the parameters and careful re-testing.
+public class HumongousDuringDumpTransformer implements ClassFileTransformer {
+    public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRedefined,
+                            ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException {
+        if (name.equals("Hello")) {
+            try {
+                makeHumongousRegions();
+            } catch (Throwable t) {
+                array = null;
+                humon = null;
+                System.out.println("Unexpected error: " + t);
+                t.printStackTrace();
+            }
+        }
+        array = null;
+        return null;
+    }
+
+    private static Instrumentation savedInstrumentation;
+
+    public static void premain(String agentArguments, Instrumentation instrumentation) {
+        long xmx = Runtime.getRuntime().maxMemory();
+        if (xmx < 60 * 1024 * 1024 || xmx > 80 * 1024 * 1024) {
+            System.out.println("Running with incorrect heap size: " + xmx);
+            System.exit(1);
+        }
+
+        System.out.println("ClassFileTransformer.premain() is called");
+        instrumentation.addTransformer(new HumongousDuringDumpTransformer(), /*canRetransform=*/true);
+        savedInstrumentation = instrumentation;
+    }
+
+    public static Instrumentation getInstrumentation() {
+        return savedInstrumentation;
+    }
+
+    public static void agentmain(String args, Instrumentation inst) throws Exception {
+        premain(args, inst);
+    }
+
+    Object[] array;
+
+    static final int DUMMY_SIZE = 4096 - 16 - 8;
+    static final int HUMON_SIZE = 4 * 1024 * 1024 - 16 - 8;
+    static final int SKIP = 13;
+
+    byte humon[] = null;
+    boolean first = true;
+
+    public synchronized void makeHumongousRegions() {
+        if (!first) {
+            return;
+        }
+        System.out.println("===============================================================================");
+        first = false;
+
+        int total = 0;
+        array = new Object[100000];
+        System.out.println(array);
+
+        // (1) Allocate about 8MB of old objects.
+        for (int n=0, i=0; total < 8 * 1024 * 1024; n++) {
+            // Make enough allocations to cause a GC (for 64MB heap) to create
+            // old regions.
+            //
+            // But don't completely fill up the heap. That would cause OOM and
+            // may not be handled gracefully inside class transformation!
+            Object x = new byte[DUMMY_SIZE];
+            if ((n  % SKIP) == 0) {
+                array[i++] = x;
+                total += DUMMY_SIZE;
+            }
+        }
+
+        System.gc();
+
+        // (2) Now allocate a humongous array. It will sit above the 8MB of old regions.
+        humon = new byte[HUMON_SIZE];
+        array = null;
+        System.gc();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/javaldr/HumongousDuringDumpTransformer.mf	Mon Dec 03 22:27:24 2018 -0800
@@ -0,0 +1,5 @@
+Manifest-Version: 1.0
+Premain-Class: HumongousDuringDumpTransformer
+Agent-Class: HumongousDuringDumpTransformer
+Can-Retransform-Classes: true
+Can-Redefine-Classes: true
--- a/test/hotspot/jtreg/runtime/appcds/sharedStrings/InvalidFileFormat.java	Tue Dec 04 11:10:19 2018 +0530
+++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/InvalidFileFormat.java	Mon Dec 03 22:27:24 2018 -0800
@@ -57,6 +57,7 @@
         test("OverflowPrefix.txt", "Num overflow. Corrupted at line 4");
         test("UnrecognizedPrefix.txt", "Unrecognized format. Corrupted at line 5");
         test("TruncatedString.txt", "Truncated. Corrupted at line 3");
+        test("LengthOverflow.txt", "string length too large: 2147483647");
     }
 
     private static void
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/SharedStringsHumongous.java	Mon Dec 03 22:27:24 2018 -0800
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * @test
+ * @summary Use a shared string allocated in a humongous G1 region.
+ * @comment -- the following implies that G1 is used (by command-line or by default)
+ * @requires vm.cds.archived.java.heap
+ *
+ * @library /test/hotspot/jtreg/runtime/appcds /test/lib
+ * @modules jdk.jartool/sun.tools.jar
+ * @build HelloString
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. SharedStringsHumongous
+ */
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import sun.hotspot.WhiteBox;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.Asserts;
+
+public class SharedStringsHumongous {
+    static String sharedArchiveConfigFile = System.getProperty("user.dir") + File.separator + "SharedStringsHumongous_gen.txt";
+
+    public static void main(String[] args) throws Exception {
+        WhiteBox wb = WhiteBox.getWhiteBox();
+
+        try (FileOutputStream fos = new FileOutputStream(sharedArchiveConfigFile)) {
+            PrintWriter out = new PrintWriter(new OutputStreamWriter(fos));
+            out.println("VERSION: 1.0");
+            out.println("@SECTION: String");
+            out.println("31: shared_test_string_unique_14325");
+            int region_size = wb.g1RegionSize();
+            char body[] = new char[region_size + region_size / 2];
+            for (int i = 0; i < body.length; i++) {
+              body[i] = 'x';
+            }
+            Asserts.assertTrue(wb.g1IsHumongous(body));
+            String prefix = "generated_string (followed by " + body.length + " 'x') ";
+
+            System.out.println("G1 region size: " + region_size);
+            System.out.println("Using a humongous string: " + prefix);
+
+            String s = prefix + new String(body);
+            out.println(s.length() + ": " + s);
+            out.close();
+        }
+
+        SharedStringsUtils.run(args, SharedStringsHumongous::test);
+    }
+
+    public static void test(String[] args) throws Exception {
+        String vmOptionsPrefix[] = SharedStringsUtils.getChildVMOptionsPrefix();
+        String appJar = JarBuilder.build("SharedStringsHumongous", "HelloString");
+
+        OutputAnalyzer dumpOutput = TestCommon.dump(appJar, TestCommon.list("HelloString"),
+                TestCommon.concat(vmOptionsPrefix,
+                    "-XX:SharedArchiveConfigFile=" + sharedArchiveConfigFile,
+                    "-Xlog:gc+region+cds",
+                    "-Xlog:gc+region=trace"));
+        TestCommon.checkDump(dumpOutput, "extra interned string ignored; size too large");
+        // Extra strings that are humongous are not kelp alive, so they should be GC'ed
+        // before dumping the string table. That means the heap should contain no
+        // humongous regions.
+        dumpOutput.shouldNotMatch("gc,region,cds. HeapRegion 0x[0-9a-f]* HUM");
+
+        OutputAnalyzer execOutput = TestCommon.exec(appJar,
+            TestCommon.concat(vmOptionsPrefix, "HelloString"));
+        TestCommon.checkExec(execOutput);
+    }
+}
--- a/test/hotspot/jtreg/runtime/appcds/sharedStrings/SharedStringsStress.java	Tue Dec 04 11:10:19 2018 +0530
+++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/SharedStringsStress.java	Mon Dec 03 22:27:24 2018 -0800
@@ -29,7 +29,7 @@
  * @library /test/hotspot/jtreg/runtime/appcds /test/lib
  * @modules jdk.jartool/sun.tools.jar
  * @build HelloString
- * @run driver SharedStringsStress
+ * @run driver/timeout=500 SharedStringsStress
  */
 import java.io.File;
 import java.io.FileOutputStream;
@@ -39,34 +39,56 @@
 import jdk.test.lib.process.ProcessTools;
 
 public class SharedStringsStress {
-    public static void main(String[] args) throws Exception {
-        SharedStringsUtils.run(args, SharedStringsStress::test);
-    }
+    static String sharedArchiveConfigFile = System.getProperty("user.dir") + File.separator + "SharedStringsStress_gen.txt";
 
-    public static void test(String[] args) throws Exception {
-        String vmOptionsPrefix[] = SharedStringsUtils.getChildVMOptionsPrefix();
-
-        String appJar = JarBuilder.build("SharedStringsStress", "HelloString");
-
-        String sharedArchiveConfigFile = System.getProperty("user.dir") + File.separator + "SharedStringsStress_gen.txt";
+    public static void main(String[] args) throws Exception {
         try (FileOutputStream fos = new FileOutputStream(sharedArchiveConfigFile)) {
             PrintWriter out = new PrintWriter(new OutputStreamWriter(fos));
             out.println("VERSION: 1.0");
             out.println("@SECTION: String");
             out.println("31: shared_test_string_unique_14325");
-            for (int i=0; i<100000; i++) {
+            for (int i=0; i<200000; i++) {
                 String s = "generated_string " + i;
                 out.println(s.length() + ": " + s);
             }
             out.close();
         }
 
-        OutputAnalyzer dumpOutput = TestCommon.dump(appJar, TestCommon.list("HelloString"),
-            TestCommon.concat(vmOptionsPrefix,
-                "-XX:SharedArchiveConfigFile=" + sharedArchiveConfigFile));
-        TestCommon.checkDump(dumpOutput);
-        OutputAnalyzer execOutput = TestCommon.exec(appJar,
-            TestCommon.concat(vmOptionsPrefix, "HelloString"));
-        TestCommon.checkExec(execOutput);
+        SharedStringsUtils.run(args, SharedStringsStress::test);
+    }
+
+    public static void test(String[] args) throws Exception {
+        String vmOptionsPrefix[] = SharedStringsUtils.getChildVMOptionsPrefix();
+        String appJar = JarBuilder.build("SharedStringsStress", "HelloString");
+
+        String test_cases[][] = {
+            // default heap size
+            {},
+
+            // Test for handling of heap fragmentation. With sharedArchiveConfigFile, we will dump about
+            // 18MB of shared objects on 64 bit VM (smaller on 32-bit).
+            //
+            // During dump time, an extra copy of these objects are allocated,
+            // so we need about 36MB, plus a few MB for other system data. So 64MB total heap
+            // should be enough.
+            //
+            // The VM should executed a full GC to maximize contiguous free space and
+            // avoid fragmentation.
+            {"-Xmx64m"},
+        };
+
+        for (String[] extra_opts: test_cases) {
+            vmOptionsPrefix = TestCommon.concat(vmOptionsPrefix, extra_opts);
+
+            OutputAnalyzer dumpOutput = TestCommon.dump(appJar, TestCommon.list("HelloString"),
+                TestCommon.concat(vmOptionsPrefix,
+                    "-XX:SharedArchiveConfigFile=" + sharedArchiveConfigFile,
+                    "-Xlog:gc+region+cds",
+                    "-Xlog:gc+region=trace"));
+            TestCommon.checkDump(dumpOutput);
+            OutputAnalyzer execOutput = TestCommon.exec(appJar,
+                TestCommon.concat(vmOptionsPrefix, "HelloString"));
+            TestCommon.checkExec(execOutput);
+        }
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/invalidFormat/LengthOverflow.txt	Mon Dec 03 22:27:24 2018 -0800
@@ -0,0 +1,10 @@
+VERSION: 1.0
+@SECTION: String
+2147483647: s
+5: cp819
+31: shared_test_string_intern_12345
+7: test123
+@SECTION: Symbol
+41 -1: (Ljava/util/Set<TE;>;Ljava/lang/Object;)V
+10 -1: linkMethod
+20 -1: isAlphaNumericString
--- a/test/hotspot/jtreg/runtime/appcds/sharedStrings/invalidFormat/TruncatedString.txt	Tue Dec 04 11:10:19 2018 +0530
+++ b/test/hotspot/jtreg/runtime/appcds/sharedStrings/invalidFormat/TruncatedString.txt	Mon Dec 03 22:27:24 2018 -0800
@@ -1,6 +1,6 @@
 VERSION: 1.0
 @SECTION: String
-2147483647: s
+40000: s
 5: cp819
 31: shared_test_string_intern_12345
 7: test123