Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/hotspot/share/cds/aotConstantPoolResolver.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2026, 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
Expand Down Expand Up @@ -116,6 +116,10 @@ bool AOTConstantPoolResolver::is_class_resolution_deterministic(InstanceKlass* c
return false;
}
} else if (resolved_class->is_objArray_klass()) {
if (CDSConfig::is_dumping_dynamic_archive()) {
// This is difficult to handle. See JDK-8374639
return false;
}
Klass* elem = ObjArrayKlass::cast(resolved_class)->bottom_klass();
if (elem->is_instance_klass()) {
return is_class_resolution_deterministic(cp_holder, InstanceKlass::cast(elem));
Expand Down
3 changes: 1 addition & 2 deletions src/hotspot/share/cds/aotMetaspace.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2026, 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
Expand Down Expand Up @@ -2159,7 +2159,6 @@ void AOTMetaspace::initialize_shared_spaces() {
intptr_t* buffer = (intptr_t*)dynamic_mapinfo->serialized_data();
ReadClosure rc(&buffer, (intptr_t)SharedBaseAddress);
DynamicArchive::serialize(&rc);
DynamicArchive::setup_array_klasses();
}

LogStreamHandle(Info, aot) lsh;
Expand Down
4 changes: 1 addition & 3 deletions src/hotspot/share/cds/archiveBuilder.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2026, 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
Expand Down Expand Up @@ -984,8 +984,6 @@ void ArchiveBuilder::make_klasses_shareable() {

#undef STATS_FORMAT
#undef STATS_PARAMS

DynamicArchive::make_array_klasses_shareable();
}

void ArchiveBuilder::make_training_data_shareable() {
Expand Down
119 changes: 2 additions & 117 deletions src/hotspot/share/cds/dynamicArchive.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2026, 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
Expand Down Expand Up @@ -48,6 +48,7 @@
#include "logging/log.hpp"
#include "memory/metaspaceClosure.hpp"
#include "memory/resourceArea.hpp"
#include "oops/array.hpp"
#include "oops/klass.inline.hpp"
#include "runtime/arguments.hpp"
#include "runtime/os.hpp"
Expand Down Expand Up @@ -95,7 +96,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder {
void sort_methods(InstanceKlass* ik) const;
void remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const;
void write_archive(char* serialized_data, AOTClassLocationConfig* cl_config);
void gather_array_klasses();

public:
// Do this before and after the archive dump to see if any corruption
Expand Down Expand Up @@ -132,7 +132,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder {

init_header();
gather_source_objs();
gather_array_klasses();
reserve_buffer();

log_info(cds, dynamic)("Copying %d klasses and %d symbols",
Expand All @@ -159,7 +158,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder {
ArchiveBuilder::OtherROAllocMark mark;
SystemDictionaryShared::write_to_archive(false);
cl_config = AOTClassLocationConfig::dumptime()->write_to_archive();
DynamicArchive::dump_array_klasses();

serialized_data = ro_region()->top();
WriteClosure wc(ro_region());
Expand All @@ -175,8 +173,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder {

write_archive(serialized_data, cl_config);
release_header();
DynamicArchive::post_dump();

post_dump();

verify_universe("After CDS dynamic dump");
Expand All @@ -185,30 +181,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder {
virtual void iterate_roots(MetaspaceClosure* it) {
AOTArtifactFinder::all_cached_classes_do(it);
SystemDictionaryShared::dumptime_classes_do(it);
iterate_primitive_array_klasses(it);
}

void iterate_primitive_array_klasses(MetaspaceClosure* it) {
for (int i = T_BOOLEAN; i <= T_LONG; i++) {
assert(is_java_primitive((BasicType)i), "sanity");
Klass* k = Universe::typeArrayKlass((BasicType)i); // this give you "[I", etc
assert(AOTMetaspace::in_aot_cache_static_region((void*)k),
"one-dimensional primitive array should be in static archive");
ArrayKlass* ak = ArrayKlass::cast(k);
while (ak != nullptr && ak->in_aot_cache()) {
Klass* next_k = ak->array_klass_or_null();
if (next_k != nullptr) {
ak = ArrayKlass::cast(next_k);
} else {
ak = nullptr;
}
}
if (ak != nullptr) {
assert(ak->dimension() > 1, "sanity");
// this is the lowest dimension that's not in the static archive
it->push(&ak);
}
}
}
};

Expand Down Expand Up @@ -367,26 +339,6 @@ void DynamicArchiveBuilder::write_archive(char* serialized_data, AOTClassLocatio
log_info(cds, dynamic)("%d klasses; %d symbols", klasses()->length(), symbols()->length());
}

void DynamicArchiveBuilder::gather_array_klasses() {
for (int i = 0; i < klasses()->length(); i++) {
if (klasses()->at(i)->is_objArray_klass()) {
ObjArrayKlass* oak = ObjArrayKlass::cast(klasses()->at(i));
Klass* elem = oak->element_klass();
if (AOTMetaspace::in_aot_cache_static_region(elem)) {
// Only capture the array klass whose element_klass is in the static archive.
// During run time, setup (see DynamicArchive::setup_array_klasses()) is needed
// so that the element_klass can find its array klasses from the dynamic archive.
DynamicArchive::append_array_klass(oak);
} else {
// The element_klass and its array klasses are in the same archive.
assert(!AOTMetaspace::in_aot_cache_static_region(oak),
"we should not gather klasses that are already in the static archive");
}
}
}
log_debug(aot)("Total array klasses gathered for dynamic archive: %d", DynamicArchive::num_array_klasses());
}

class VM_PopulateDynamicDumpSharedSpace: public VM_Heap_Sync_Operation {
DynamicArchiveBuilder _builder;
public:
Expand All @@ -403,76 +355,9 @@ class VM_PopulateDynamicDumpSharedSpace: public VM_Heap_Sync_Operation {
}
};

// _array_klasses and _dynamic_archive_array_klasses only hold the array klasses
// which have element klass in the static archive.
GrowableArray<ObjArrayKlass*>* DynamicArchive::_array_klasses = nullptr;
Array<ObjArrayKlass*>* DynamicArchive::_dynamic_archive_array_klasses = nullptr;

void DynamicArchive::serialize(SerializeClosure* soc) {
SymbolTable::serialize_shared_table_header(soc, false);
SystemDictionaryShared::serialize_dictionary_headers(soc, false);
soc->do_ptr(&_dynamic_archive_array_klasses);
}

void DynamicArchive::append_array_klass(ObjArrayKlass* ak) {
if (_array_klasses == nullptr) {
_array_klasses = new (mtClassShared) GrowableArray<ObjArrayKlass*>(50, mtClassShared);
}
_array_klasses->append(ak);
}

void DynamicArchive::dump_array_klasses() {
assert(CDSConfig::is_dumping_dynamic_archive(), "sanity");
if (_array_klasses != nullptr) {
ArchiveBuilder* builder = ArchiveBuilder::current();
int num_array_klasses = _array_klasses->length();
_dynamic_archive_array_klasses =
ArchiveBuilder::new_ro_array<ObjArrayKlass*>(num_array_klasses);
for (int i = 0; i < num_array_klasses; i++) {
builder->write_pointer_in_buffer(_dynamic_archive_array_klasses->adr_at(i), _array_klasses->at(i));
}
}
}

void DynamicArchive::setup_array_klasses() {
if (_dynamic_archive_array_klasses != nullptr) {
for (int i = 0; i < _dynamic_archive_array_klasses->length(); i++) {
ObjArrayKlass* oak = _dynamic_archive_array_klasses->at(i);
Klass* elm = oak->element_klass();
assert(AOTMetaspace::in_aot_cache_static_region((void*)elm), "must be");

if (elm->is_instance_klass()) {
assert(InstanceKlass::cast(elm)->array_klasses() == nullptr, "must be");
InstanceKlass::cast(elm)->set_array_klasses(oak);
} else {
assert(elm->is_array_klass(), "sanity");
assert(ArrayKlass::cast(elm)->higher_dimension() == nullptr, "must be");
ArrayKlass::cast(elm)->set_higher_dimension(oak);
}
}
log_debug(aot)("Total array klasses read from dynamic archive: %d", _dynamic_archive_array_klasses->length());
}
}

void DynamicArchive::make_array_klasses_shareable() {
if (_array_klasses != nullptr) {
int num_array_klasses = _array_klasses->length();
for (int i = 0; i < num_array_klasses; i++) {
ObjArrayKlass* k = ArchiveBuilder::current()->get_buffered_addr(_array_klasses->at(i));
k->remove_unshareable_info();
}
}
}

void DynamicArchive::post_dump() {
if (_array_klasses != nullptr) {
delete _array_klasses;
_array_klasses = nullptr;
}
}

int DynamicArchive::num_array_klasses() {
return _array_klasses != nullptr ? _array_klasses->length() : 0;
}

void DynamicArchive::dump_impl(bool jcmd_request, const char* archive_name, TRAPS) {
Expand Down
16 changes: 1 addition & 15 deletions src/hotspot/share/cds/dynamicArchive.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2026, 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
Expand All @@ -26,13 +26,8 @@
#define SHARE_CDS_DYNAMICARCHIVE_HPP

#include "cds/filemap.hpp"
#include "classfile/compactHashtable.hpp"
#include "memory/allStatic.hpp"
#include "memory/memRegion.hpp"
#include "oops/array.hpp"
#include "oops/oop.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/macros.hpp"

#if INCLUDE_CDS
Expand All @@ -59,22 +54,13 @@ class DynamicArchiveHeader : public FileMapHeader {
};

class DynamicArchive : AllStatic {
private:
static GrowableArray<ObjArrayKlass*>* _array_klasses;
static Array<ObjArrayKlass*>* _dynamic_archive_array_klasses;
public:
static void dump_for_jcmd(const char* archive_name, TRAPS);
static void dump_at_exit(JavaThread* current);
static void dump_impl(bool jcmd_request, const char* archive_name, TRAPS);
static bool is_mapped() { return FileMapInfo::dynamic_info() != nullptr; }
static bool validate(FileMapInfo* dynamic_info);
static void dump_array_klasses();
static void setup_array_klasses();
static void append_array_klass(ObjArrayKlass* oak);
static void serialize(SerializeClosure* soc);
static void make_array_klasses_shareable();
static void post_dump();
static int num_array_klasses();
};
#endif // INCLUDE_CDS
#endif // SHARE_CDS_DYNAMICARCHIVE_HPP
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2025, 2026, 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
* @bug 8374639
* @requires vm.cds.supports.aot.class.linking
* @library /test/lib
* @build DynamicDumpWithAOTLinkedStaticArchive jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar TestApp
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. DynamicDumpWithAOTLinkedStaticArchive
*/

import jdk.test.lib.cds.SimpleCDSAppTester;
import jdk.test.lib.process.OutputAnalyzer;

public class DynamicDumpWithAOTLinkedStaticArchive {
public static void main(String... args) throws Exception {
SimpleCDSAppTester.of("DynamicDumpWithAOTLinkedStaticArchive")
.classpath("app.jar")
.appCommandLine("TestApp")
.setGenerateBaseArchive(true)
.setBaseArchiveOptions("-XX:+AOTClassLinking")
.setProductionChecker((OutputAnalyzer out) -> {
out.shouldContain("HelloWorld");
})
.runDynamicWorkflow();
}
}

class TestApp {
public static void main(String[] args) {
System.out.println("HelloWorld");
System[][][] x = new System[0][0][0];
System.out.println(x);
}
}
Loading