Skip to content

Commit 9d5c9cc

Browse files
committedOct 31, 2020
8254309: appcds GCDuringDump.java failed - class must exist
Reviewed-by: ccheung, iklam
1 parent 36c150b commit 9d5c9cc

File tree

8 files changed

+149
-14
lines changed

8 files changed

+149
-14
lines changed
 

‎src/hotspot/share/classfile/classListParser.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "interpreter/linkResolver.hpp"
3838
#include "logging/log.hpp"
3939
#include "logging/logTag.hpp"
40+
#include "memory/archiveUtils.hpp"
4041
#include "memory/metaspaceShared.hpp"
4142
#include "memory/resourceArea.hpp"
4243
#include "oops/constantPool.hpp"
@@ -572,6 +573,7 @@ Klass* ClassListParser::load_current_class(TRAPS) {
572573
klass = java_lang_Class::as_Klass(obj);
573574
} else { // load classes in bootclasspath/a
574575
if (HAS_PENDING_EXCEPTION) {
576+
ArchiveUtils::check_for_oom(PENDING_EXCEPTION); // exit on OOM
575577
CLEAR_PENDING_EXCEPTION;
576578
}
577579

@@ -582,6 +584,8 @@ Klass* ClassListParser::load_current_class(TRAPS) {
582584
} else {
583585
if (!HAS_PENDING_EXCEPTION) {
584586
THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());
587+
} else {
588+
ArchiveUtils::check_for_oom(PENDING_EXCEPTION); // exit on OOM
585589
}
586590
}
587591
}
@@ -590,6 +594,9 @@ Klass* ClassListParser::load_current_class(TRAPS) {
590594
// If "source:" tag is specified, all super class and super interfaces must be specified in the
591595
// class list file.
592596
klass = load_class_from_source(class_name_symbol, CHECK_NULL);
597+
if (HAS_PENDING_EXCEPTION) {
598+
ArchiveUtils::check_for_oom(PENDING_EXCEPTION); // exit on OOM
599+
}
593600
}
594601

595602
if (klass != NULL && klass->is_instance_klass() && is_id_specified()) {

‎src/hotspot/share/memory/archiveUtils.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,12 @@ void ArchiveUtils::log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) {
319319
}
320320
}
321321
}
322+
323+
void ArchiveUtils::check_for_oom(oop exception) {
324+
assert(exception != nullptr, "Sanity check");
325+
if (exception->is_a(SystemDictionary::OutOfMemoryError_klass())) {
326+
vm_exit_during_cds_dumping(
327+
err_msg("Out of memory. Please run with a larger Java heap, current MaxHeapSize = " SIZE_FORMAT "M",
328+
MaxHeapSize/M));
329+
}
330+
}

‎src/hotspot/share/memory/archiveUtils.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ class ReadClosure : public SerializeClosure {
243243
class ArchiveUtils {
244244
public:
245245
static void log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) NOT_CDS_RETURN;
246+
static void check_for_oom(oop exception) NOT_CDS_RETURN;
246247
};
247248

248249
#endif // SHARE_MEMORY_ARCHIVEUTILS_HPP

‎src/hotspot/share/memory/heapShared.cpp

+12-13
Original file line numberDiff line numberDiff line change
@@ -259,15 +259,6 @@ void HeapShared::run_full_gc_in_vm_thread() {
259259

260260
void HeapShared::archive_java_heap_objects(GrowableArray<MemRegion> *closed,
261261
GrowableArray<MemRegion> *open) {
262-
if (!is_heap_object_archiving_allowed()) {
263-
log_info(cds)(
264-
"Archived java heap is not supported as UseG1GC, "
265-
"UseCompressedOops and UseCompressedClassPointers are required."
266-
"Current settings: UseG1GC=%s, UseCompressedOops=%s, UseCompressedClassPointers=%s.",
267-
BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedOops),
268-
BOOL_TO_STR(UseCompressedClassPointers));
269-
return;
270-
}
271262

272263
G1HeapVerifier::verify_ready_for_archiving();
273264

@@ -1035,7 +1026,13 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
10351026
TempNewSymbol field_name = SymbolTable::new_symbol(info->field_name);
10361027

10371028
Klass* k = SystemDictionary::resolve_or_null(klass_name, THREAD);
1038-
assert(k != NULL && !HAS_PENDING_EXCEPTION, "class must exist");
1029+
if (HAS_PENDING_EXCEPTION) {
1030+
ResourceMark rm(THREAD);
1031+
ArchiveUtils::check_for_oom(PENDING_EXCEPTION); // exit on OOM
1032+
log_info(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),
1033+
java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION)));
1034+
vm_exit_during_initialization("VM exits due to exception, use -Xlog:cds,exceptions=trace for detail");
1035+
}
10391036
InstanceKlass* ik = InstanceKlass::cast(k);
10401037
assert(InstanceKlass::cast(ik)->is_shared_boot_class(),
10411038
"Only support boot classes");
@@ -1052,8 +1049,8 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[],
10521049
}
10531050

10541051
void HeapShared::init_subgraph_entry_fields(Thread* THREAD) {
1052+
assert(is_heap_object_archiving_allowed(), "Sanity check");
10551053
_dump_time_subgraph_info_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeKlassSubGraphInfoTable();
1056-
10571054
init_subgraph_entry_fields(closed_archive_subgraph_entry_fields,
10581055
num_closed_archive_subgraph_entry_fields,
10591056
THREAD);
@@ -1068,8 +1065,10 @@ void HeapShared::init_subgraph_entry_fields(Thread* THREAD) {
10681065
}
10691066

10701067
void HeapShared::init_for_dumping(Thread* THREAD) {
1071-
_dumped_interned_strings = new (ResourceObj::C_HEAP, mtClass)DumpedInternedStrings();
1072-
init_subgraph_entry_fields(THREAD);
1068+
if (is_heap_object_archiving_allowed()) {
1069+
_dumped_interned_strings = new (ResourceObj::C_HEAP, mtClass)DumpedInternedStrings();
1070+
init_subgraph_entry_fields(THREAD);
1071+
}
10731072
}
10741073

10751074
void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[],

‎src/hotspot/share/memory/metaspaceShared.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -1166,6 +1166,15 @@ bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) {
11661166

11671167
#if INCLUDE_CDS_JAVA_HEAP
11681168
void VM_PopulateDumpSharedSpace::dump_java_heap_objects() {
1169+
if(!HeapShared::is_heap_object_archiving_allowed()) {
1170+
log_info(cds)(
1171+
"Archived java heap is not supported as UseG1GC, "
1172+
"UseCompressedOops and UseCompressedClassPointers are required."
1173+
"Current settings: UseG1GC=%s, UseCompressedOops=%s, UseCompressedClassPointers=%s.",
1174+
BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedOops),
1175+
BOOL_TO_STR(UseCompressedClassPointers));
1176+
return;
1177+
}
11691178
// Find all the interned strings that should be dumped.
11701179
int i;
11711180
for (i = 0; i < _global_klass_objects->length(); i++) {

‎test/hotspot/jtreg/TEST.groups

+1
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ hotspot_appcds_dynamic = \
325325
-runtime/cds/appcds/dynamicArchive \
326326
-runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java \
327327
-runtime/cds/appcds/javaldr/ArrayTest.java \
328+
-runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java \
328329
-runtime/cds/appcds/javaldr/GCSharedStringsDuringDump.java \
329330
-runtime/cds/appcds/javaldr/HumongousDuringDump.java \
330331
-runtime/cds/appcds/javaldr/LockDuringDump.java \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*
23+
*/
24+
25+
/*
26+
* @test
27+
* @summary Out of memory When dumping the CDS archive
28+
* @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes
29+
* @requires vm.cds.archived.java.heap
30+
* @requires vm.jvmti
31+
* @run driver ExceptionDuringDumpAtObjectsInitPhase
32+
*/
33+
34+
import jdk.test.lib.cds.CDSOptions;
35+
import jdk.test.lib.process.OutputAnalyzer;
36+
import jdk.test.lib.process.ProcessTools;
37+
38+
public class ExceptionDuringDumpAtObjectsInitPhase {
39+
public static String appClasses[] = {
40+
Hello.class.getName(),
41+
};
42+
public static String agentClasses[] = {
43+
GCDuringDumpTransformer.class.getName(),
44+
GCDuringDumpTransformer.MyCleaner.class.getName(),
45+
};
46+
47+
public static void main(String[] args) throws Throwable {
48+
String agentJar =
49+
ClassFileInstaller.writeJar("GCDuringDumpTransformer.jar",
50+
ClassFileInstaller.Manifest.fromSourceFile("GCDuringDumpTransformer.mf"),
51+
agentClasses);
52+
53+
String appJar =
54+
ClassFileInstaller.writeJar("GCDuringDumpApp.jar", appClasses);
55+
56+
String gcLog = Boolean.getBoolean("test.cds.verbose.gc") ?
57+
"-Xlog:gc*=info,gc+region=trace,gc+alloc+region=debug" : "-showversion";
58+
59+
// 1. Test with exception
60+
System.out.println("1. Exception during dump");
61+
TestCommon.dump(appJar,
62+
TestCommon.list(Hello.class.getName()),
63+
"-XX:+UnlockDiagnosticVMOptions",
64+
"-XX:+AllowArchivingWithJavaAgent",
65+
"-javaagent:" + agentJar,
66+
"-Xlog:cds,class+load",
67+
"-Xmx32m",
68+
"-Dtest.with.exception=true",
69+
gcLog).shouldNotHaveExitValue(0)
70+
.shouldContain("Preload Error: Failed to load jdk/internal/math/FDBigInteger")
71+
.shouldContain("VM exits due to exception, use -Xlog:cds,exceptions=trace for detail");
72+
73+
// 2. Test with OOM
74+
System.out.println("2. OOM during dump");
75+
TestCommon.dump(appJar,
76+
TestCommon.list(Hello.class.getName()),
77+
"-XX:+UnlockDiagnosticVMOptions",
78+
"-XX:+AllowArchivingWithJavaAgent",
79+
"-javaagent:" + agentJar,
80+
"-Dtest.with.oom=true",
81+
"-Xlog:cds,class+load",
82+
"-Xmx12M",
83+
gcLog).shouldNotHaveExitValue(0)
84+
.shouldContain("Out of memory. Please run with a larger Java heap, current MaxHeapSize");
85+
}
86+
}

‎test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCDuringDumpTransformer.java

+24-1
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,16 @@
2626
import java.lang.instrument.Instrumentation;
2727
import java.lang.instrument.IllegalClassFormatException;
2828
import java.lang.ref.Cleaner;
29+
import java.util.ArrayList;
30+
import java.util.List;
2931
import java.security.ProtectionDomain;
3032

3133
public class GCDuringDumpTransformer implements ClassFileTransformer {
3234
static boolean TEST_WITH_CLEANER = Boolean.getBoolean("test.with.cleaner");
35+
static boolean TEST_WITH_EXCEPTION = Boolean.getBoolean("test.with.exception");
36+
static boolean TEST_WITH_OOM = Boolean.getBoolean("test.with.oom");
37+
static List<byte[]> waste = new ArrayList();
38+
3339
static Cleaner cleaner;
3440
static Thread thread;
3541
static Object garbage;
@@ -45,6 +51,22 @@ public class GCDuringDumpTransformer implements ClassFileTransformer {
4551

4652
public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRedefined,
4753
ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException {
54+
// jdk/internal/math/FDBigInteger is loaded as part of archived heap.
55+
if (name.equals("jdk/internal/math/FDBigInteger")) {
56+
System.out.println("Transforming class jdk/internal/math/FDBigInteger");
57+
if (TEST_WITH_EXCEPTION) {
58+
System.out.println("Return bad buffer for " + name);
59+
return new byte[] {1, 2, 3, 4, 5, 6, 7, 8};
60+
}
61+
if (TEST_WITH_OOM) {
62+
// fill until OOM
63+
System.out.println("Fill objects until OOM");
64+
for (;;) {
65+
waste.add(new byte[64*1024]);
66+
}
67+
}
68+
}
69+
4870
if (TEST_WITH_CLEANER) {
4971
if (name.equals("Hello")) {
5072
garbage = null;
@@ -60,14 +82,15 @@ public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRede
6082
} catch (Throwable t2) {}
6183
}
6284
}
63-
6485
return null;
6586
}
6687

6788
private static Instrumentation savedInstrumentation;
6889

6990
public static void premain(String agentArguments, Instrumentation instrumentation) {
7091
System.out.println("ClassFileTransformer.premain() is called: TEST_WITH_CLEANER = " + TEST_WITH_CLEANER);
92+
System.out.println("ClassFileTransformer.premain() is called: TEST_WITH_EXCEPTION = " + TEST_WITH_EXCEPTION);
93+
System.out.println("ClassFileTransformer.premain() is called: TEST_WITH_OOM = " + TEST_WITH_OOM);
7194
instrumentation.addTransformer(new GCDuringDumpTransformer(), /*canRetransform=*/true);
7295
savedInstrumentation = instrumentation;
7396
}

0 commit comments

Comments
 (0)
Please sign in to comment.