merge latest from master branch

This commit is contained in:
Jaikiran Pai 2026-01-27 13:01:32 +05:30
commit b57b088ec9
71 changed files with 1217 additions and 937 deletions

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 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.
*
*/
#include "cds/aotGrowableArray.hpp"
#include "cds/aotMetaspace.hpp"
#include "memory/allocation.inline.hpp"
#include "utilities/growableArray.hpp"
void AOTGrowableArrayHelper::deallocate(void* mem) {
if (!AOTMetaspace::in_aot_cache(mem)) {
GrowableArrayCHeapAllocator::deallocate(mem);
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 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.
*
*/
#ifndef SHARE_AOT_AOTGROWABLEARRAY_HPP
#define SHARE_AOT_AOTGROWABLEARRAY_HPP
#include <memory/metaspaceClosureType.hpp>
#include <utilities/growableArray.hpp>
class AOTGrowableArrayHelper {
public:
static void deallocate(void* mem);
};
// An AOTGrowableArray<T> provides the same functionality as a GrowableArray<T> that
// uses the C heap allocator. In addition, AOTGrowableArray<T> can be iterated with
// MetaspaceClosure. This type should be used for growable arrays that need to be
// stored in the AOT cache. See ModuleEntry::_reads for an example.
template <typename E>
class AOTGrowableArray : public GrowableArrayWithAllocator<E, AOTGrowableArray<E>> {
friend class VMStructs;
friend class GrowableArrayWithAllocator<E, AOTGrowableArray>;
static E* allocate(int max, MemTag mem_tag) {
return (E*)GrowableArrayCHeapAllocator::allocate(max, sizeof(E), mem_tag);
}
E* allocate() {
return allocate(this->_capacity, mtClass);
}
void deallocate(E* mem) {
#if INCLUDE_CDS
AOTGrowableArrayHelper::deallocate(mem);
#else
GrowableArrayCHeapAllocator::deallocate(mem);
#endif
}
public:
AOTGrowableArray(int initial_capacity, MemTag mem_tag) :
GrowableArrayWithAllocator<E, AOTGrowableArray>(
allocate(initial_capacity, mem_tag),
initial_capacity) {}
AOTGrowableArray() : AOTGrowableArray(0, mtClassShared) {}
// methods required by MetaspaceClosure
void metaspace_pointers_do(MetaspaceClosure* it);
int size_in_heapwords() const { return (int)heap_word_size(sizeof(*this)); }
MetaspaceClosureType type() const { return MetaspaceClosureType::GrowableArrayType; }
static bool is_read_only_by_default() { return false; }
};
#endif // SHARE_AOT_AOTGROWABLEARRAY_HPP

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 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.
*
*/
#ifndef SHARE_CDS_AOTGROWABLEARRAY_INLINE_HPP
#define SHARE_CDS_AOTGROWABLEARRAY_INLINE_HPP
#include "cds/aotGrowableArray.hpp"
#include "memory/metaspaceClosure.hpp"
template <typename E>
void AOTGrowableArray<E>::metaspace_pointers_do(MetaspaceClosure* it) {
it->push_c_array(AOTGrowableArray<E>::data_addr(), AOTGrowableArray<E>::capacity());
}
#endif // SHARE_CDS_AOTGROWABLEARRAY_INLINE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* 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
@ -29,6 +29,8 @@
#include "cds/aotStreamedHeapWriter.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/filemap.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/packageEntry.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/vmClasses.hpp"
#include "logging/log.hpp"
@ -141,7 +143,7 @@ public:
info._buffered_addr = ref->obj();
info._requested_addr = ref->obj();
info._bytes = ref->size() * BytesPerWord;
info._type = ref->msotype();
info._type = ref->type();
_objs.append(info);
}
@ -214,7 +216,7 @@ void AOTMapLogger::dumptime_log_metaspace_region(const char* name, DumpRegion* r
info._buffered_addr = src_info->buffered_addr();
info._requested_addr = info._buffered_addr + _buffer_to_requested_delta;
info._bytes = src_info->size_in_bytes();
info._type = src_info->msotype();
info._type = src_info->type();
objs.append(info);
}
@ -332,43 +334,52 @@ void AOTMapLogger::log_metaspace_objects_impl(address region_base, address regio
address buffered_addr = info._buffered_addr;
address requested_addr = info._requested_addr;
int bytes = info._bytes;
MetaspaceObj::Type type = info._type;
const char* type_name = MetaspaceObj::type_name(type);
MetaspaceClosureType type = info._type;
const char* type_name = MetaspaceClosure::type_name(type);
log_as_hex(last_obj_base, buffered_addr, last_obj_base + _buffer_to_requested_delta);
switch (type) {
case MetaspaceObj::ClassType:
case MetaspaceClosureType::ClassType:
log_klass((Klass*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceObj::ConstantPoolType:
case MetaspaceClosureType::ConstantPoolType:
log_constant_pool((ConstantPool*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceObj::ConstantPoolCacheType:
case MetaspaceClosureType::ConstantPoolCacheType:
log_constant_pool_cache((ConstantPoolCache*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceObj::ConstMethodType:
case MetaspaceClosureType::ConstMethodType:
log_const_method((ConstMethod*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceObj::MethodType:
case MetaspaceClosureType::MethodType:
log_method((Method*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceObj::MethodCountersType:
case MetaspaceClosureType::MethodCountersType:
log_method_counters((MethodCounters*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceObj::MethodDataType:
case MetaspaceClosureType::MethodDataType:
log_method_data((MethodData*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceObj::SymbolType:
case MetaspaceClosureType::ModuleEntryType:
log_module_entry((ModuleEntry*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceClosureType::PackageEntryType:
log_package_entry((PackageEntry*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceClosureType::GrowableArrayType:
log_growable_array((GrowableArrayBase*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceClosureType::SymbolType:
log_symbol((Symbol*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceObj::KlassTrainingDataType:
case MetaspaceClosureType::KlassTrainingDataType:
log_klass_training_data((KlassTrainingData*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceObj::MethodTrainingDataType:
case MetaspaceClosureType::MethodTrainingDataType:
log_method_training_data((MethodTrainingData*)src, requested_addr, type_name, bytes, current);
break;
case MetaspaceObj::CompileTrainingDataType:
case MetaspaceClosureType::CompileTrainingDataType:
log_compile_training_data((CompileTrainingData*)src, requested_addr, type_name, bytes, current);
break;
default:
@ -421,6 +432,27 @@ void AOTMapLogger::log_method_data(MethodData* md, address requested_addr, const
log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, md->method()->external_name());
}
void AOTMapLogger::log_module_entry(ModuleEntry* mod, address requested_addr, const char* type_name,
int bytes, Thread* current) {
ResourceMark rm(current);
log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes,
mod->name_as_C_string());
}
void AOTMapLogger::log_package_entry(PackageEntry* pkg, address requested_addr, const char* type_name,
int bytes, Thread* current) {
ResourceMark rm(current);
log_debug(aot, map)(_LOG_PREFIX " %s - %s", p2i(requested_addr), type_name, bytes,
pkg->module()->name_as_C_string(), pkg->name_as_C_string());
}
void AOTMapLogger::log_growable_array(GrowableArrayBase* arr, address requested_addr, const char* type_name,
int bytes, Thread* current) {
ResourceMark rm(current);
log_debug(aot, map)(_LOG_PREFIX " %d (%d)", p2i(requested_addr), type_name, bytes,
arr->length(), arr->capacity());
}
void AOTMapLogger::log_klass(Klass* k, address requested_addr, const char* type_name,
int bytes, Thread* current) {
ResourceMark rm(current);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* 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
@ -28,6 +28,7 @@
#include "cds/archiveBuilder.hpp"
#include "memory/allocation.hpp"
#include "memory/allStatic.hpp"
#include "memory/metaspaceClosureType.hpp"
#include "oops/oopsHierarchy.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/growableArray.hpp"
@ -37,9 +38,13 @@ class ArchiveStreamedHeapInfo;
class CompileTrainingData;
class DumpRegion;
class FileMapInfo;
class GrowableArrayBase;
class KlassTrainingData;
class MethodCounters;
class MethodTrainingData;
class ModuleEntry;
class outputStream;
class PackageEntry;
// Write detailed info to a mapfile to analyze contents of the AOT cache/CDS archive.
// -Xlog:aot+map* can be used both when creating an AOT cache, or when using an AOT cache.
@ -62,7 +67,7 @@ class AOTMapLogger : AllStatic {
address _buffered_addr;
address _requested_addr;
int _bytes;
MetaspaceObj::Type _type;
MetaspaceClosureType _type;
};
public:
@ -142,6 +147,9 @@ private:
Thread* current);
static void log_klass(Klass* k, address requested_addr, const char* type_name, int bytes, Thread* current);
static void log_method(Method* m, address requested_addr, const char* type_name, int bytes, Thread* current);
static void log_module_entry(ModuleEntry* mod, address requested_addr, const char* type_name, int bytes, Thread* current);
static void log_package_entry(PackageEntry* pkg, address requested_addr, const char* type_name, int bytes, Thread* current);
static void log_growable_array(GrowableArrayBase* arr, address requested_addr, const char* type_name, int bytes, Thread* current);
static void log_symbol(Symbol* s, address requested_addr, const char* type_name, int bytes, Thread* current);
static void log_klass_training_data(KlassTrainingData* ktd, address requested_addr, const char* type_name, int bytes, Thread* current);
static void log_method_training_data(MethodTrainingData* mtd, address requested_addr, const char* type_name, int bytes, Thread* current);

View File

@ -698,6 +698,9 @@ public:
Universe::metaspace_pointers_do(it);
vmSymbols::metaspace_pointers_do(it);
TrainingData::iterate_roots(it);
if (CDSConfig::is_dumping_full_module_graph()) {
ClassLoaderDataShared::iterate_roots(it);
}
// The above code should find all the symbols that are referenced by the
// archived classes. We just need to add the extra symbols which
@ -795,6 +798,10 @@ void VM_PopulateDumpSharedSpace::doit() {
_builder.make_klasses_shareable();
AOTMetaspace::make_method_handle_intrinsics_shareable();
if (CDSConfig::is_dumping_full_module_graph()) {
ClassLoaderDataShared::remove_unshareable_info();
}
dump_java_heap_objects();
dump_shared_symbol_table(_builder.symbols());
@ -1135,6 +1142,7 @@ void AOTMetaspace::dump_static_archive_impl(StaticArchiveBuilder& builder, TRAPS
HeapShared::init_heap_writer();
if (CDSConfig::is_dumping_full_module_graph()) {
ClassLoaderDataShared::ensure_module_entry_tables_exist();
ClassLoaderDataShared::build_tables(CHECK);
HeapShared::reset_archived_object_states(CHECK);
}

View File

@ -243,7 +243,7 @@ bool ArchiveBuilder::gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool re
if (get_follow_mode(ref) != make_a_copy) {
return false;
}
if (ref->msotype() == MetaspaceObj::ClassType) {
if (ref->type() == MetaspaceClosureType::ClassType) {
Klass* klass = (Klass*)ref->obj();
assert(klass->is_klass(), "must be");
if (!is_excluded(klass)) {
@ -252,7 +252,7 @@ bool ArchiveBuilder::gather_klass_and_symbol(MetaspaceClosure::Ref* ref, bool re
assert(klass->is_instance_klass(), "must be");
}
}
} else if (ref->msotype() == MetaspaceObj::SymbolType) {
} else if (ref->type() == MetaspaceClosureType::SymbolType) {
// Make sure the symbol won't be GC'ed while we are dumping the archive.
Symbol* sym = (Symbol*)ref->obj();
sym->increment_refcount();
@ -271,11 +271,6 @@ void ArchiveBuilder::gather_klasses_and_symbols() {
aot_log_info(aot)("Gathering classes and symbols ... ");
GatherKlassesAndSymbols doit(this);
iterate_roots(&doit);
#if INCLUDE_CDS_JAVA_HEAP
if (CDSConfig::is_dumping_full_module_graph()) {
ClassLoaderDataShared::iterate_symbols(&doit);
}
#endif
doit.finish();
if (CDSConfig::is_dumping_static_archive()) {
@ -446,14 +441,14 @@ bool ArchiveBuilder::gather_one_source_obj(MetaspaceClosure::Ref* ref, bool read
}
#ifdef ASSERT
if (ref->msotype() == MetaspaceObj::MethodType) {
if (ref->type() == MetaspaceClosureType::MethodType) {
Method* m = (Method*)ref->obj();
assert(!RegeneratedClasses::has_been_regenerated((address)m->method_holder()),
"Should not archive methods in a class that has been regenerated");
}
#endif
if (ref->msotype() == MetaspaceObj::MethodDataType) {
if (ref->type() == MetaspaceClosureType::MethodDataType) {
MethodData* md = (MethodData*)ref->obj();
md->clean_method_data(false /* always_clean */);
}
@ -554,16 +549,16 @@ ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref
if (CDSConfig::is_dumping_dynamic_archive() && AOTMetaspace::in_aot_cache(obj)) {
// Don't dump existing shared metadata again.
return point_to_it;
} else if (ref->msotype() == MetaspaceObj::MethodDataType ||
ref->msotype() == MetaspaceObj::MethodCountersType ||
ref->msotype() == MetaspaceObj::KlassTrainingDataType ||
ref->msotype() == MetaspaceObj::MethodTrainingDataType ||
ref->msotype() == MetaspaceObj::CompileTrainingDataType) {
} else if (ref->type() == MetaspaceClosureType::MethodDataType ||
ref->type() == MetaspaceClosureType::MethodCountersType ||
ref->type() == MetaspaceClosureType::KlassTrainingDataType ||
ref->type() == MetaspaceClosureType::MethodTrainingDataType ||
ref->type() == MetaspaceClosureType::CompileTrainingDataType) {
return (TrainingData::need_data() || TrainingData::assembling_data()) ? make_a_copy : set_to_null;
} else if (ref->msotype() == MetaspaceObj::AdapterHandlerEntryType) {
} else if (ref->type() == MetaspaceClosureType::AdapterHandlerEntryType) {
return CDSConfig::is_dumping_adapters() ? make_a_copy : set_to_null;
} else {
if (ref->msotype() == MetaspaceObj::ClassType) {
if (ref->type() == MetaspaceClosureType::ClassType) {
Klass* klass = (Klass*)ref->obj();
assert(klass->is_klass(), "must be");
if (RegeneratedClasses::has_been_regenerated(klass)) {
@ -620,15 +615,6 @@ void ArchiveBuilder::dump_rw_metadata() {
ResourceMark rm;
aot_log_info(aot)("Allocating RW objects ... ");
make_shallow_copies(&_rw_region, &_rw_src_objs);
#if INCLUDE_CDS_JAVA_HEAP
if (CDSConfig::is_dumping_full_module_graph()) {
// Archive the ModuleEntry's and PackageEntry's of the 3 built-in loaders
char* start = rw_region()->top();
ClassLoaderDataShared::allocate_archived_tables();
alloc_stats()->record_modules(rw_region()->top() - start, /*read_only*/false);
}
#endif
}
void ArchiveBuilder::dump_ro_metadata() {
@ -637,15 +623,6 @@ void ArchiveBuilder::dump_ro_metadata() {
start_dump_region(&_ro_region);
make_shallow_copies(&_ro_region, &_ro_src_objs);
#if INCLUDE_CDS_JAVA_HEAP
if (CDSConfig::is_dumping_full_module_graph()) {
char* start = ro_region()->top();
ClassLoaderDataShared::init_archived_tables();
alloc_stats()->record_modules(ro_region()->top() - start, /*read_only*/true);
}
#endif
RegeneratedClasses::record_regenerated_objects();
}
@ -663,7 +640,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s
size_t alignment = SharedSpaceObjectAlignment; // alignment for the dest pointer
char* oldtop = dump_region->top();
if (src_info->msotype() == MetaspaceObj::ClassType) {
if (src_info->type() == MetaspaceClosureType::ClassType) {
// Allocate space for a pointer directly in front of the future InstanceKlass, so
// we can do a quick lookup from InstanceKlass* -> RunTimeClassInfo*
// without building another hashtable. See RunTimeClassInfo::get_for()
@ -679,7 +656,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s
alignment = nth_bit(ArchiveBuilder::precomputed_narrow_klass_shift());
}
#endif
} else if (src_info->msotype() == MetaspaceObj::SymbolType) {
} else if (src_info->type() == MetaspaceClosureType::SymbolType) {
// Symbols may be allocated by using AllocateHeap, so their sizes
// may be less than size_in_bytes() indicates.
bytes = ((Symbol*)src)->byte_size();
@ -689,7 +666,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s
memcpy(dest, src, bytes);
// Update the hash of buffered sorted symbols for static dump so that the symbols have deterministic contents
if (CDSConfig::is_dumping_static_archive() && (src_info->msotype() == MetaspaceObj::SymbolType)) {
if (CDSConfig::is_dumping_static_archive() && (src_info->type() == MetaspaceClosureType::SymbolType)) {
Symbol* buffered_symbol = (Symbol*)dest;
assert(((Symbol*)src)->is_permanent(), "archived symbols must be permanent");
buffered_symbol->update_identity_hash();
@ -704,7 +681,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s
}
}
intptr_t* archived_vtable = CppVtables::get_archived_vtable(src_info->msotype(), (address)dest);
intptr_t* archived_vtable = CppVtables::get_archived_vtable(src_info->type(), (address)dest);
if (archived_vtable != nullptr) {
*(address*)dest = (address)archived_vtable;
ArchivePtrMarker::mark_pointer((address*)dest);
@ -714,7 +691,7 @@ void ArchiveBuilder::make_shallow_copy(DumpRegion *dump_region, SourceObjInfo* s
src_info->set_buffered_addr((address)dest);
char* newtop = dump_region->top();
_alloc_stats.record(src_info->msotype(), int(newtop - oldtop), src_info->read_only());
_alloc_stats.record(src_info->type(), int(newtop - oldtop), src_info->read_only());
DEBUG_ONLY(_alloc_stats.verify((int)dump_region->used(), src_info->read_only()));
}
@ -997,15 +974,15 @@ void ArchiveBuilder::make_training_data_shareable() {
return;
}
if (info.msotype() == MetaspaceObj::KlassTrainingDataType ||
info.msotype() == MetaspaceObj::MethodTrainingDataType ||
info.msotype() == MetaspaceObj::CompileTrainingDataType) {
if (info.type() == MetaspaceClosureType::KlassTrainingDataType ||
info.type() == MetaspaceClosureType::MethodTrainingDataType ||
info.type() == MetaspaceClosureType::CompileTrainingDataType) {
TrainingData* buffered_td = (TrainingData*)info.buffered_addr();
buffered_td->remove_unshareable_info();
} else if (info.msotype() == MetaspaceObj::MethodDataType) {
} else if (info.type() == MetaspaceClosureType::MethodDataType) {
MethodData* buffered_mdo = (MethodData*)info.buffered_addr();
buffered_mdo->remove_unshareable_info();
} else if (info.msotype() == MetaspaceObj::MethodCountersType) {
} else if (info.type() == MetaspaceClosureType::MethodCountersType) {
MethodCounters* buffered_mc = (MethodCounters*)info.buffered_addr();
buffered_mc->remove_unshareable_info();
}

View File

@ -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
@ -134,13 +134,13 @@ private:
int _size_in_bytes;
int _id; // Each object has a unique serial ID, starting from zero. The ID is assigned
// when the object is added into _source_objs.
MetaspaceObj::Type _msotype;
MetaspaceClosureType _type;
address _source_addr; // The source object to be copied.
address _buffered_addr; // The copy of this object insider the buffer.
public:
SourceObjInfo(MetaspaceClosure::Ref* ref, bool read_only, FollowMode follow_mode) :
_ptrmap_start(0), _ptrmap_end(0), _read_only(read_only), _has_embedded_pointer(false), _follow_mode(follow_mode),
_size_in_bytes(ref->size() * BytesPerWord), _id(0), _msotype(ref->msotype()),
_size_in_bytes(ref->size() * BytesPerWord), _id(0), _type(ref->type()),
_source_addr(ref->obj()) {
if (follow_mode == point_to_it) {
_buffered_addr = ref->obj();
@ -155,7 +155,7 @@ private:
SourceObjInfo(address src, SourceObjInfo* renegerated_obj_info) :
_ptrmap_start(0), _ptrmap_end(0), _read_only(false),
_follow_mode(renegerated_obj_info->_follow_mode),
_size_in_bytes(0), _msotype(renegerated_obj_info->_msotype),
_size_in_bytes(0), _type(renegerated_obj_info->_type),
_source_addr(src), _buffered_addr(renegerated_obj_info->_buffered_addr) {}
bool should_copy() const { return _follow_mode == make_a_copy; }
@ -182,7 +182,7 @@ private:
}
return _buffered_addr;
}
MetaspaceObj::Type msotype() const { return _msotype; }
MetaspaceClosureType type() const { return _type; }
FollowMode follow_mode() const { return _follow_mode; }
};

View File

@ -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
@ -22,12 +22,14 @@
*
*/
#include "cds/aotGrowableArray.hpp"
#include "cds/aotMetaspace.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/archiveUtils.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/cppVtables.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "oops/instanceClassLoaderKlass.hpp"
#include "oops/instanceMirrorKlass.hpp"
#include "oops/instanceRefKlass.hpp"
@ -53,6 +55,19 @@
// + at run time: we clone the actual contents of the vtables from libjvm.so
// into our own tables.
#ifndef PRODUCT
// AOTGrowableArray has a vtable only when in non-product builds (due to
// the virtual printing functions in AnyObj).
using GrowableArray_ModuleEntry_ptr = AOTGrowableArray<ModuleEntry*>;
#define DEBUG_CPP_VTABLE_TYPES_DO(f) \
f(GrowableArray_ModuleEntry_ptr) \
#endif
// Currently, the archive contains ONLY the following types of objects that have C++ vtables.
#define CPP_VTABLE_TYPES_DO(f) \
f(ConstantPool) \
@ -68,7 +83,8 @@
f(TypeArrayKlass) \
f(KlassTrainingData) \
f(MethodTrainingData) \
f(CompileTrainingData)
f(CompileTrainingData) \
NOT_PRODUCT(DEBUG_CPP_VTABLE_TYPES_DO(f))
class CppVtableInfo {
intptr_t _vtable_size;
@ -86,7 +102,7 @@ public:
}
};
static inline intptr_t* vtable_of(const Metadata* m) {
static inline intptr_t* vtable_of(const void* m) {
return *((intptr_t**)m);
}
@ -116,6 +132,7 @@ CppVtableInfo* CppVtableCloner<T>::allocate_and_initialize(const char* name) {
template <class T>
void CppVtableCloner<T>::initialize(const char* name, CppVtableInfo* info) {
ResourceMark rm;
T tmp; // Allocate temporary dummy metadata object to get to the original vtable.
int n = info->vtable_size();
intptr_t* srcvtable = vtable_of(&tmp);
@ -268,7 +285,7 @@ void CppVtables::serialize(SerializeClosure* soc) {
}
}
intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address obj) {
intptr_t* CppVtables::get_archived_vtable(MetaspaceClosureType type, address obj) {
if (!_orig_cpp_vtptrs_inited) {
CPP_VTABLE_TYPES_DO(INIT_ORIG_CPP_VTPTRS);
_orig_cpp_vtptrs_inited = true;
@ -276,19 +293,23 @@ intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address ob
assert(CDSConfig::is_dumping_archive(), "sanity");
int kind = -1;
switch (msotype) {
case MetaspaceObj::SymbolType:
case MetaspaceObj::TypeArrayU1Type:
case MetaspaceObj::TypeArrayU2Type:
case MetaspaceObj::TypeArrayU4Type:
case MetaspaceObj::TypeArrayU8Type:
case MetaspaceObj::TypeArrayOtherType:
case MetaspaceObj::ConstMethodType:
case MetaspaceObj::ConstantPoolCacheType:
case MetaspaceObj::AnnotationsType:
case MetaspaceObj::RecordComponentType:
case MetaspaceObj::AdapterHandlerEntryType:
case MetaspaceObj::AdapterFingerPrintType:
switch (type) {
case MetaspaceClosureType::SymbolType:
case MetaspaceClosureType::TypeArrayU1Type:
case MetaspaceClosureType::TypeArrayU2Type:
case MetaspaceClosureType::TypeArrayU4Type:
case MetaspaceClosureType::TypeArrayU8Type:
case MetaspaceClosureType::TypeArrayOtherType:
case MetaspaceClosureType::CArrayType:
case MetaspaceClosureType::ConstMethodType:
case MetaspaceClosureType::ConstantPoolCacheType:
case MetaspaceClosureType::AnnotationsType:
case MetaspaceClosureType::ModuleEntryType:
case MetaspaceClosureType::PackageEntryType:
case MetaspaceClosureType::RecordComponentType:
case MetaspaceClosureType::AdapterHandlerEntryType:
case MetaspaceClosureType::AdapterFingerPrintType:
PRODUCT_ONLY(case MetaspaceClosureType::GrowableArrayType:)
// These have no vtables.
break;
default:

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2024, 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
@ -27,6 +27,7 @@
#include "memory/allocation.hpp"
#include "memory/allStatic.hpp"
#include "memory/metaspaceClosureType.hpp"
#include "utilities/globalDefinitions.hpp"
class ArchiveBuilder;
@ -40,7 +41,7 @@ class CppVtables : AllStatic {
public:
static void dumptime_init(ArchiveBuilder* builder);
static void zero_archived_vtables();
static intptr_t* get_archived_vtable(MetaspaceObj::Type msotype, address obj);
static intptr_t* get_archived_vtable(MetaspaceClosureType type, address obj);
static void serialize(SerializeClosure* sc);
static bool is_valid_shared_method(const Method* m) NOT_CDS_RETURN_(false);
static char* vtables_serialized_base() { return _vtables_serialized_base; }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2024, 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
@ -27,32 +27,34 @@
#include "classfile/compactHashtable.hpp"
#include "memory/allocation.hpp"
#include "memory/metaspaceClosureType.hpp"
// This is for dumping detailed statistics for the allocations
// in the shared spaces.
class DumpAllocStats : public StackObj {
public:
// Here's poor man's enum inheritance
#define SHAREDSPACE_OBJ_TYPES_DO(f) \
METASPACE_OBJ_TYPES_DO(f) \
#define DUMPED_OBJ_TYPES_DO(f) \
METASPACE_CLOSURE_TYPES_DO(f) \
f(SymbolHashentry) \
f(SymbolBucket) \
f(StringHashentry) \
f(StringBucket) \
f(ModulesNatives) \
f(CppVTables) \
f(Other)
#define DUMPED_TYPE_DECLARE(name) name ## Type,
#define DUMPED_TYPE_NAME_CASE(name) case name ## Type: return #name;
enum Type {
// Types are MetaspaceObj::ClassType, MetaspaceObj::SymbolType, etc
SHAREDSPACE_OBJ_TYPES_DO(METASPACE_OBJ_TYPE_DECLARE)
DUMPED_OBJ_TYPES_DO(DUMPED_TYPE_DECLARE)
_number_of_types
};
static const char* type_name(Type type) {
switch(type) {
SHAREDSPACE_OBJ_TYPES_DO(METASPACE_OBJ_TYPE_NAME_CASE)
DUMPED_OBJ_TYPES_DO(DUMPED_TYPE_NAME_CASE)
default:
ShouldNotReachHere();
return nullptr;
@ -101,16 +103,12 @@ public:
CompactHashtableStats* symbol_stats() { return &_symbol_stats; }
CompactHashtableStats* string_stats() { return &_string_stats; }
void record(MetaspaceObj::Type type, int byte_size, bool read_only) {
assert(int(type) >= 0 && type < MetaspaceObj::_number_of_types, "sanity");
void record(MetaspaceClosureType type, int byte_size, bool read_only) {
int t = (int)type;
assert(t >= 0 && t < (int)MetaspaceClosureType::_number_of_types, "sanity");
int which = (read_only) ? RO : RW;
_counts[which][type] ++;
_bytes [which][type] += byte_size;
}
void record_modules(int byte_size, bool read_only) {
int which = (read_only) ? RO : RW;
_bytes [which][ModulesNativesType] += byte_size;
_counts[which][t] ++;
_bytes [which][t] += byte_size;
}
void record_other_type(int byte_size, bool read_only) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 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
@ -948,10 +948,6 @@ void HeapShared::archive_subgraphs() {
true /* is_full_module_graph */);
}
}
if (CDSConfig::is_dumping_full_module_graph()) {
Modules::verify_archived_modules();
}
}
//

View File

@ -216,6 +216,10 @@ ciField::ciField(fieldDescriptor *fd) :
static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
if (holder == nullptr)
return false;
if (holder->trust_final_fields()) {
// Explicit opt-in from system classes
return true;
}
// Even if general trusting is disabled, trust system-built closures in these packages.
if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke") ||
holder->is_in_package("java/lang/reflect") || holder->is_in_package("jdk/internal/reflect") ||
@ -230,14 +234,6 @@ static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
// Trust final fields in records
if (holder->is_record())
return true;
// Trust Atomic*FieldUpdaters: they are very important for performance, and make up one
// more reason not to use Unsafe, if their final fields are trusted. See more in JDK-8140483.
if (holder->name() == ciSymbols::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl() ||
holder->name() == ciSymbols::java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater() ||
holder->name() == ciSymbols::java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater() ||
holder->name() == ciSymbols::java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl()) {
return true;
}
return TrustFinalNonStaticFields;
}

View File

@ -65,6 +65,7 @@ ciInstanceKlass::ciInstanceKlass(Klass* k) :
_has_nonstatic_concrete_methods = ik->has_nonstatic_concrete_methods();
_is_hidden = ik->is_hidden();
_is_record = ik->is_record();
_trust_final_fields = ik->trust_final_fields();
_nonstatic_fields = nullptr; // initialized lazily by compute_nonstatic_fields:
_has_injected_fields = -1;
_implementor = nullptr; // we will fill these lazily

View File

@ -59,6 +59,7 @@ private:
bool _has_nonstatic_concrete_methods;
bool _is_hidden;
bool _is_record;
bool _trust_final_fields;
bool _has_trusted_loader;
ciFlags _flags;
@ -207,6 +208,10 @@ public:
return _is_record;
}
bool trust_final_fields() const {
return _trust_final_fields;
}
ciInstanceKlass* get_canonical_holder(int offset);
ciField* get_field_by_offset(int field_offset, bool is_static);
ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static);

View File

@ -943,6 +943,7 @@ public:
_java_lang_Deprecated_for_removal,
_jdk_internal_vm_annotation_AOTSafeClassInitializer,
_method_AOTRuntimeSetup,
_jdk_internal_vm_annotation_TrustFinalFields,
_annotation_LIMIT
};
const Location _location;
@ -1878,6 +1879,11 @@ AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
if (!privileged) break; // only allow in privileged code
return _field_Stable;
}
case VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_TrustFinalFields_signature): {
if (_location != _in_class) break; // only allow for classes
if (!privileged) break; // only allow in privileged code
return _jdk_internal_vm_annotation_TrustFinalFields;
}
case VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Contended_signature): {
if (_location != _in_field && _location != _in_class) {
break; // only allow for fields and classes
@ -1992,6 +1998,9 @@ void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) {
if (has_annotation(_jdk_internal_vm_annotation_AOTSafeClassInitializer)) {
ik->set_has_aot_safe_initializer();
}
if (has_annotation(_jdk_internal_vm_annotation_TrustFinalFields)) {
ik->set_trust_final_fields(true);
}
}
#define MAX_ARGS_SIZE 255

View File

@ -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
@ -33,6 +33,7 @@
#include "classfile/packageEntry.hpp"
#include "classfile/systemDictionary.hpp"
#include "logging/log.hpp"
#include "memory/metaspaceClosure.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/safepoint.hpp"
@ -56,9 +57,9 @@ class ArchivedClassLoaderData {
public:
ArchivedClassLoaderData() : _packages(nullptr), _modules(nullptr), _unnamed_module(nullptr) {}
void iterate_symbols(ClassLoaderData* loader_data, MetaspaceClosure* closure);
void allocate(ClassLoaderData* loader_data);
void init_archived_entries(ClassLoaderData* loader_data);
void iterate_roots(MetaspaceClosure* closure);
void build_tables(ClassLoaderData* loader_data, TRAPS);
void remove_unshareable_info();
ModuleEntry* unnamed_module() {
return _unnamed_module;
}
@ -80,17 +81,14 @@ static ModuleEntry* _archived_javabase_moduleEntry = nullptr;
static int _platform_loader_root_index = -1;
static int _system_loader_root_index = -1;
void ArchivedClassLoaderData::iterate_symbols(ClassLoaderData* loader_data, MetaspaceClosure* closure) {
void ArchivedClassLoaderData::iterate_roots(MetaspaceClosure* it) {
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
assert_valid(loader_data);
if (loader_data != nullptr) {
loader_data->packages()->iterate_symbols(closure);
loader_data->modules() ->iterate_symbols(closure);
loader_data->unnamed_module()->iterate_symbols(closure);
}
it->push(&_packages);
it->push(&_modules);
it->push(&_unnamed_module);
}
void ArchivedClassLoaderData::allocate(ClassLoaderData* loader_data) {
void ArchivedClassLoaderData::build_tables(ClassLoaderData* loader_data, TRAPS) {
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
assert_valid(loader_data);
if (loader_data != nullptr) {
@ -98,19 +96,28 @@ void ArchivedClassLoaderData::allocate(ClassLoaderData* loader_data) {
// address of the Symbols, which may be relocated at runtime due to ASLR.
// So we store the packages/modules in Arrays. At runtime, we create
// the hashtables using these arrays.
_packages = loader_data->packages()->allocate_archived_entries();
_modules = loader_data->modules() ->allocate_archived_entries();
_unnamed_module = loader_data->unnamed_module()->allocate_archived_entry();
_packages = loader_data->packages()->build_aot_table(loader_data, CHECK);
_modules = loader_data->modules()->build_aot_table(loader_data, CHECK);
_unnamed_module = loader_data->unnamed_module();
}
}
void ArchivedClassLoaderData::init_archived_entries(ClassLoaderData* loader_data) {
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
assert_valid(loader_data);
if (loader_data != nullptr) {
loader_data->packages()->init_archived_entries(_packages);
loader_data->modules() ->init_archived_entries(_modules);
_unnamed_module->init_as_archived_entry();
void ArchivedClassLoaderData::remove_unshareable_info() {
if (_packages != nullptr) {
_packages = ArchiveBuilder::current()->get_buffered_addr(_packages);
for (int i = 0; i < _packages->length(); i++) {
_packages->at(i)->remove_unshareable_info();
}
}
if (_modules != nullptr) {
_modules = ArchiveBuilder::current()->get_buffered_addr(_modules);
for (int i = 0; i < _modules->length(); i++) {
_modules->at(i)->remove_unshareable_info();
}
}
if (_unnamed_module != nullptr) {
_unnamed_module = ArchiveBuilder::current()->get_buffered_addr(_unnamed_module);
_unnamed_module->remove_unshareable_info();
}
}
@ -153,7 +160,6 @@ void ArchivedClassLoaderData::clear_archived_oops() {
// ------------------------------
void ClassLoaderDataShared::load_archived_platform_and_system_class_loaders() {
#if INCLUDE_CDS_JAVA_HEAP
// The streaming object loader prefers loading the class loader related objects before
// the CLD constructor which has a NoSafepointVerifier.
if (!HeapShared::is_loading_streaming_mode()) {
@ -178,7 +184,6 @@ void ClassLoaderDataShared::load_archived_platform_and_system_class_loaders() {
if (system_loader_module_entry != nullptr) {
system_loader_module_entry->preload_archived_oops();
}
#endif
}
static ClassLoaderData* null_class_loader_data() {
@ -210,28 +215,27 @@ void ClassLoaderDataShared::ensure_module_entry_table_exists(oop class_loader) {
assert(met != nullptr, "sanity");
}
void ClassLoaderDataShared::iterate_symbols(MetaspaceClosure* closure) {
void ClassLoaderDataShared::build_tables(TRAPS) {
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
_archived_boot_loader_data.iterate_symbols (null_class_loader_data(), closure);
_archived_platform_loader_data.iterate_symbols(java_platform_loader_data_or_null(), closure);
_archived_system_loader_data.iterate_symbols (java_system_loader_data_or_null(), closure);
_archived_boot_loader_data.build_tables(null_class_loader_data(), CHECK);
_archived_platform_loader_data.build_tables(java_platform_loader_data_or_null(), CHECK);
_archived_system_loader_data.build_tables(java_system_loader_data_or_null(), CHECK);
}
void ClassLoaderDataShared::allocate_archived_tables() {
void ClassLoaderDataShared::iterate_roots(MetaspaceClosure* it) {
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
_archived_boot_loader_data.allocate (null_class_loader_data());
_archived_platform_loader_data.allocate(java_platform_loader_data_or_null());
_archived_system_loader_data.allocate (java_system_loader_data_or_null());
_archived_boot_loader_data.iterate_roots(it);
_archived_platform_loader_data.iterate_roots(it);
_archived_system_loader_data.iterate_roots(it);
}
void ClassLoaderDataShared::init_archived_tables() {
void ClassLoaderDataShared::remove_unshareable_info() {
assert(CDSConfig::is_dumping_full_module_graph(), "must be");
_archived_boot_loader_data.remove_unshareable_info();
_archived_platform_loader_data.remove_unshareable_info();
_archived_system_loader_data.remove_unshareable_info();
_archived_boot_loader_data.init_archived_entries (null_class_loader_data());
_archived_platform_loader_data.init_archived_entries(java_platform_loader_data_or_null());
_archived_system_loader_data.init_archived_entries (java_system_loader_data_or_null());
_archived_javabase_moduleEntry = ModuleEntry::get_archived_entry(ModuleEntryTable::javabase_moduleEntry());
_archived_javabase_moduleEntry = ArchiveBuilder::current()->get_buffered_addr(ModuleEntryTable::javabase_moduleEntry());
_platform_loader_root_index = HeapShared::append_root(SystemDictionary::java_platform_loader());
_system_loader_root_index = HeapShared::append_root(SystemDictionary::java_system_loader());
@ -271,7 +275,6 @@ ModuleEntry* ClassLoaderDataShared::archived_unnamed_module(ClassLoaderData* loa
return archived_module;
}
void ClassLoaderDataShared::clear_archived_oops() {
assert(!CDSConfig::is_using_full_module_graph(), "must be");
_archived_boot_loader_data.clear_archived_oops();

View File

@ -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
@ -40,11 +40,11 @@ class ClassLoaderDataShared : AllStatic {
public:
static void load_archived_platform_and_system_class_loaders() NOT_CDS_JAVA_HEAP_RETURN;
static void restore_archived_modules_for_preloading_classes(JavaThread* current) NOT_CDS_JAVA_HEAP_RETURN;
static void build_tables(TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
static void iterate_roots(MetaspaceClosure* closure) NOT_CDS_JAVA_HEAP_RETURN;
static void remove_unshareable_info() NOT_CDS_JAVA_HEAP_RETURN;
#if INCLUDE_CDS_JAVA_HEAP
static void ensure_module_entry_tables_exist();
static void allocate_archived_tables();
static void iterate_symbols(MetaspaceClosure* closure);
static void init_archived_tables();
static void serialize(SerializeClosure* f);
static void clear_archived_oops();
static void restore_archived_entries_for_null_class_loader_data();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@ -23,6 +23,7 @@
*/
#include "cds/aotClassLocation.hpp"
#include "cds/aotGrowableArray.inline.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/archiveUtils.hpp"
#include "cds/cdsConfig.hpp"
@ -37,6 +38,7 @@
#include "jni.h"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/oopHandle.inline.hpp"
@ -44,7 +46,6 @@
#include "runtime/handles.inline.hpp"
#include "runtime/safepoint.hpp"
#include "utilities/events.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashTable.hpp"
#include "utilities/ostream.hpp"
#include "utilities/quickSort.hpp"
@ -167,7 +168,7 @@ void ModuleEntry::add_read(ModuleEntry* m) {
} else {
if (reads() == nullptr) {
// Lazily create a module's reads list
GrowableArray<ModuleEntry*>* new_reads = new (mtModule) GrowableArray<ModuleEntry*>(MODULE_READS_SIZE, mtModule);
AOTGrowableArray<ModuleEntry*>* new_reads = new (mtModule) AOTGrowableArray<ModuleEntry*>(MODULE_READS_SIZE, mtModule);
set_reads(new_reads);
}
@ -274,8 +275,7 @@ ModuleEntry::ModuleEntry(Handle module_handle,
_has_default_read_edges(false),
_must_walk_reads(false),
_is_open(is_open),
_is_patched(false)
DEBUG_ONLY(COMMA _reads_is_archived(false)) {
_is_patched(false) {
// Initialize fields specific to a ModuleEntry
if (_name == nullptr) {
@ -394,7 +394,6 @@ ModuleEntryTable::~ModuleEntryTable() {
ModuleEntryTableDeleter deleter;
_table.unlink(&deleter);
assert(_table.number_of_entries() == 0, "should have removed all entries");
}
void ModuleEntry::set_loader_data(ClassLoaderData* cld) {
@ -402,147 +401,51 @@ void ModuleEntry::set_loader_data(ClassLoaderData* cld) {
_loader_data = cld;
}
void ModuleEntry::metaspace_pointers_do(MetaspaceClosure* it) {
it->push(&_name);
it->push(&_reads);
it->push(&_version);
it->push(&_location);
}
#if INCLUDE_CDS_JAVA_HEAP
typedef HashTable<
const ModuleEntry*,
ModuleEntry*,
557, // prime number
AnyObj::C_HEAP> ArchivedModuleEntries;
static ArchivedModuleEntries* _archive_modules_entries = nullptr;
#ifndef PRODUCT
static int _num_archived_module_entries = 0;
static int _num_inited_module_entries = 0;
#endif
bool ModuleEntry::should_be_archived() const {
return SystemDictionaryShared::is_builtin_loader(loader_data());
}
ModuleEntry* ModuleEntry::allocate_archived_entry() const {
precond(should_be_archived());
precond(CDSConfig::is_dumping_full_module_graph());
ModuleEntry* archived_entry = (ModuleEntry*)ArchiveBuilder::rw_region_alloc(sizeof(ModuleEntry));
memcpy((void*)archived_entry, (void*)this, sizeof(ModuleEntry));
void ModuleEntry::remove_unshareable_info() {
_archived_module_index = HeapShared::append_root(module_oop());
archived_entry->_archived_module_index = HeapShared::append_root(module_oop());
if (_archive_modules_entries == nullptr) {
_archive_modules_entries = new (mtClass)ArchivedModuleEntries();
}
assert(_archive_modules_entries->get(this) == nullptr, "Each ModuleEntry must not be shared across ModuleEntryTables");
_archive_modules_entries->put(this, archived_entry);
DEBUG_ONLY(_num_archived_module_entries++);
if (CDSConfig::is_dumping_final_static_archive()) {
OopHandle null_handle;
archived_entry->_shared_pd = null_handle;
} else {
assert(archived_entry->shared_protection_domain() == nullptr, "never set during -Xshare:dump");
if (_reads != nullptr) {
_reads->set_in_aot_cache();
}
// Clear handles and restore at run time. Handles cannot be archived.
if (CDSConfig::is_dumping_final_static_archive()) {
OopHandle null_handle;
_shared_pd = null_handle;
} else {
assert(shared_protection_domain() == nullptr, "never set during -Xshare:dump");
}
OopHandle null_handle;
archived_entry->_module_handle = null_handle;
// For verify_archived_module_entries()
DEBUG_ONLY(_num_inited_module_entries++);
if (log_is_enabled(Info, aot, module)) {
ResourceMark rm;
LogStream ls(Log(aot, module)::info());
ls.print("Stored in archive: ");
archived_entry->print(&ls);
}
return archived_entry;
}
bool ModuleEntry::has_been_archived() {
assert(!ArchiveBuilder::current()->is_in_buffer_space(this), "must be called on original ModuleEntry");
return _archive_modules_entries->contains(this);
}
ModuleEntry* ModuleEntry::get_archived_entry(ModuleEntry* orig_entry) {
ModuleEntry** ptr = _archive_modules_entries->get(orig_entry);
assert(ptr != nullptr && *ptr != nullptr, "must have been allocated");
return *ptr;
}
// This function is used to archive ModuleEntry::_reads and PackageEntry::_qualified_exports.
// GrowableArray cannot be directly archived, as it needs to be expandable at runtime.
// Write it out as an Array, and convert it back to GrowableArray at runtime.
Array<ModuleEntry*>* ModuleEntry::write_growable_array(GrowableArray<ModuleEntry*>* array) {
Array<ModuleEntry*>* archived_array = nullptr;
int length = (array == nullptr) ? 0 : array->length();
if (length > 0) {
archived_array = ArchiveBuilder::new_ro_array<ModuleEntry*>(length);
for (int i = 0; i < length; i++) {
ModuleEntry* archived_entry = get_archived_entry(array->at(i));
archived_array->at_put(i, archived_entry);
ArchivePtrMarker::mark_pointer((address*)archived_array->adr_at(i));
}
}
return archived_array;
}
GrowableArray<ModuleEntry*>* ModuleEntry::restore_growable_array(Array<ModuleEntry*>* archived_array) {
GrowableArray<ModuleEntry*>* array = nullptr;
int length = (archived_array == nullptr) ? 0 : archived_array->length();
if (length > 0) {
array = new (mtModule) GrowableArray<ModuleEntry*>(length, mtModule);
for (int i = 0; i < length; i++) {
ModuleEntry* archived_entry = archived_array->at(i);
array->append(archived_entry);
}
}
return array;
}
void ModuleEntry::iterate_symbols(MetaspaceClosure* closure) {
closure->push(&_name);
closure->push(&_version);
closure->push(&_location);
}
void ModuleEntry::init_as_archived_entry() {
set_archived_reads(write_growable_array(reads()));
_module_handle = null_handle;
_loader_data = nullptr; // re-init at runtime
if (name() != nullptr) {
_shared_path_index = AOTClassLocationConfig::dumptime()->get_module_shared_path_index(_location);
_name = ArchiveBuilder::get_buffered_symbol(_name);
ArchivePtrMarker::mark_pointer((address*)&_name);
Symbol* src_location = ArchiveBuilder::current()->get_source_addr(_location);
_shared_path_index = AOTClassLocationConfig::dumptime()->get_module_shared_path_index(src_location);
} else {
// _shared_path_index is used only by SystemDictionary::is_shared_class_visible_impl()
// for checking classes in named modules.
_shared_path_index = -1;
}
if (_version != nullptr) {
_version = ArchiveBuilder::get_buffered_symbol(_version);
}
if (_location != nullptr) {
_location = ArchiveBuilder::get_buffered_symbol(_location);
}
JFR_ONLY(set_trace_id(0);) // re-init at runtime
ArchivePtrMarker::mark_pointer((address*)&_reads);
ArchivePtrMarker::mark_pointer((address*)&_version);
ArchivePtrMarker::mark_pointer((address*)&_location);
}
#ifndef PRODUCT
void ModuleEntry::verify_archived_module_entries() {
assert(_num_archived_module_entries == _num_inited_module_entries,
"%d ModuleEntries have been archived but %d of them have been properly initialized with archived java.lang.Module objects",
_num_archived_module_entries, _num_inited_module_entries);
}
#endif // PRODUCT
void ModuleEntry::load_from_archive(ClassLoaderData* loader_data) {
assert(CDSConfig::is_using_archive(), "runtime only");
set_loader_data(loader_data);
set_reads(restore_growable_array(archived_reads()));
JFR_ONLY(INIT_ID(this);)
}
@ -581,38 +484,28 @@ static int compare_module_by_name(ModuleEntry* a, ModuleEntry* b) {
return a->name()->fast_compare(b->name());
}
void ModuleEntryTable::iterate_symbols(MetaspaceClosure* closure) {
auto syms = [&] (const SymbolHandle& key, ModuleEntry*& m) {
m->iterate_symbols(closure);
};
_table.iterate_all(syms);
}
Array<ModuleEntry*>* ModuleEntryTable::allocate_archived_entries() {
Array<ModuleEntry*>* archived_modules = ArchiveBuilder::new_rw_array<ModuleEntry*>(_table.number_of_entries());
Array<ModuleEntry*>* ModuleEntryTable::build_aot_table(ClassLoaderData* loader_data, TRAPS) {
Array<ModuleEntry*>* aot_table =
MetadataFactory::new_array<ModuleEntry*>(loader_data, _table.number_of_entries(), nullptr, CHECK_NULL);
int n = 0;
auto grab = [&] (const SymbolHandle& key, ModuleEntry*& m) {
archived_modules->at_put(n++, m);
m->pack_reads();
aot_table->at_put(n++, m);
if (log_is_enabled(Info, aot, module)) {
ResourceMark rm;
LogStream ls(Log(aot, module)::info());
ls.print("Stored in archive: ");
m->print(&ls);
}
};
_table.iterate_all(grab);
if (n > 1) {
// Always allocate in the same order to produce deterministic archive.
QuickSort::sort(archived_modules->data(), n, compare_module_by_name);
QuickSort::sort(aot_table->data(), n, compare_module_by_name);
}
for (int i = 0; i < n; i++) {
archived_modules->at_put(i, archived_modules->at(i)->allocate_archived_entry());
ArchivePtrMarker::mark_pointer((address*)archived_modules->adr_at(i));
}
return archived_modules;
}
void ModuleEntryTable::init_archived_entries(Array<ModuleEntry*>* archived_modules) {
assert(CDSConfig::is_dumping_full_module_graph(), "sanity");
for (int i = 0; i < archived_modules->length(); i++) {
ModuleEntry* archived_entry = archived_modules->at(i);
archived_entry->init_as_archived_entry();
}
return aot_table;
}
void ModuleEntryTable::load_archived_entries(ClassLoaderData* loader_data,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@ -25,7 +25,9 @@
#ifndef SHARE_CLASSFILE_MODULEENTRY_HPP
#define SHARE_CLASSFILE_MODULEENTRY_HPP
#include "cds/aotGrowableArray.hpp"
#include "jni.h"
#include "memory/metaspaceClosureType.hpp"
#include "oops/oopHandle.hpp"
#include "oops/symbol.hpp"
#include "oops/symbolHandle.hpp"
@ -68,11 +70,8 @@ private:
// for shared classes from this module
Symbol* _name; // name of this module
ClassLoaderData* _loader_data;
AOTGrowableArray<ModuleEntry*>* _reads; // list of modules that are readable by this module
union {
GrowableArray<ModuleEntry*>* _reads; // list of modules that are readable by this module
Array<ModuleEntry*>* _archived_reads; // List of readable modules stored in the CDS archive
};
Symbol* _version; // module version number
Symbol* _location; // module location
CDS_ONLY(int _shared_path_index;) // >=0 if classes in this module are in CDS archive
@ -81,7 +80,6 @@ private:
bool _must_walk_reads; // walk module's reads list at GC safepoints to purge out dead modules
bool _is_open; // whether the packages in the module are all unqualifiedly exported
bool _is_patched; // whether the module is patched via --patch-module
DEBUG_ONLY(bool _reads_is_archived);
CDS_JAVA_HEAP_ONLY(int _archived_module_index;)
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
@ -120,22 +118,18 @@ public:
bool can_read(ModuleEntry* m) const;
bool has_reads_list() const;
GrowableArray<ModuleEntry*>* reads() const {
assert(!_reads_is_archived, "sanity");
AOTGrowableArray<ModuleEntry*>* reads() const {
return _reads;
}
void set_reads(GrowableArray<ModuleEntry*>* r) {
void set_reads(AOTGrowableArray<ModuleEntry*>* r) {
_reads = r;
DEBUG_ONLY(_reads_is_archived = false);
}
Array<ModuleEntry*>* archived_reads() const {
assert(_reads_is_archived, "sanity");
return _archived_reads;
}
void set_archived_reads(Array<ModuleEntry*>* r) {
_archived_reads = r;
DEBUG_ONLY(_reads_is_archived = true);
void pack_reads() {
if (_reads != nullptr) {
_reads->shrink_to_fit();
}
}
void add_read(ModuleEntry* m);
void set_read_walk_required(ClassLoaderData* m_loader_data);
@ -189,6 +183,13 @@ public:
const char* name_as_C_string() const {
return is_named() ? name()->as_C_string() : UNNAMED_MODULE;
}
// methods required by MetaspaceClosure
void metaspace_pointers_do(MetaspaceClosure* it);
int size_in_heapwords() const { return (int)heap_word_size(sizeof(ModuleEntry)); }
MetaspaceClosureType type() const { return MetaspaceClosureType::ModuleEntryType; }
static bool is_read_only_by_default() { return false; }
void print(outputStream* st = tty) const;
void verify();
@ -198,18 +199,11 @@ public:
#if INCLUDE_CDS_JAVA_HEAP
bool should_be_archived() const;
void iterate_symbols(MetaspaceClosure* closure);
ModuleEntry* allocate_archived_entry() const;
void init_as_archived_entry();
static ModuleEntry* get_archived_entry(ModuleEntry* orig_entry);
bool has_been_archived();
static Array<ModuleEntry*>* write_growable_array(GrowableArray<ModuleEntry*>* array);
static GrowableArray<ModuleEntry*>* restore_growable_array(Array<ModuleEntry*>* archived_array);
void remove_unshareable_info();
void load_from_archive(ClassLoaderData* loader_data);
void preload_archived_oops();
void restore_archived_oops(ClassLoaderData* loader_data);
void clear_archived_oops();
static void verify_archived_module_entries() PRODUCT_RETURN;
#endif
};
@ -275,9 +269,7 @@ public:
void verify();
#if INCLUDE_CDS_JAVA_HEAP
void iterate_symbols(MetaspaceClosure* closure);
Array<ModuleEntry*>* allocate_archived_entries();
void init_archived_entries(Array<ModuleEntry*>* archived_modules);
Array<ModuleEntry*>* build_aot_table(ClassLoaderData* loader_data, TRAPS);
void load_archived_entries(ClassLoaderData* loader_data,
Array<ModuleEntry*>* archived_modules);
void restore_archived_oops(ClassLoaderData* loader_data,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@ -505,13 +505,10 @@ void Modules::check_archived_module_oop(oop orig_module_obj) {
ClassLoaderData* loader_data = orig_module_ent->loader_data();
assert(loader_data->is_builtin_class_loader_data(), "must be");
if (orig_module_ent->name() != nullptr) {
// For each named module, we archive both the java.lang.Module oop and the ModuleEntry.
assert(orig_module_ent->has_been_archived(), "sanity");
} else {
precond(ArchiveBuilder::current()->has_been_archived(orig_module_ent));
if (orig_module_ent->name() == nullptr) {
// We always archive unnamed module oop for boot, platform, and system loaders.
precond(orig_module_ent->should_be_archived());
precond(orig_module_ent->has_been_archived());
if (loader_data->is_boot_class_loader_data()) {
assert(!_seen_boot_unnamed_module, "only once");
@ -529,10 +526,6 @@ void Modules::check_archived_module_oop(oop orig_module_obj) {
}
}
void Modules::verify_archived_modules() {
ModuleEntry::verify_archived_module_entries();
}
class Modules::ArchivedProperty {
const char* _prop;
const bool _numbered;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@ -59,7 +59,6 @@ public:
TRAPS) NOT_CDS_JAVA_HEAP_RETURN;
static void init_archived_modules(JavaThread* current, Handle h_platform_loader, Handle h_system_loader)
NOT_CDS_JAVA_HEAP_RETURN;
static void verify_archived_modules() NOT_CDS_JAVA_HEAP_RETURN;
static void dump_archived_module_info() NOT_CDS_JAVA_HEAP_RETURN;
static void serialize_archived_module_info(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@ -22,6 +22,8 @@
*
*/
#include "cds/aotGrowableArray.inline.hpp"
#include "cds/aotMetaspace.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/archiveUtils.hpp"
#include "cds/cdsConfig.hpp"
@ -31,13 +33,13 @@
#include "classfile/vmSymbols.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/resourceArea.hpp"
#include "oops/array.hpp"
#include "oops/symbol.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
#include "utilities/events.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashTable.hpp"
#include "utilities/ostream.hpp"
#include "utilities/quickSort.hpp"
@ -51,7 +53,7 @@ PackageEntry::PackageEntry(Symbol* name, ModuleEntry* module) :
_qualified_exports(nullptr),
_defined_by_cds_in_class_path(0)
{
// name can't be null
// name can't be null -- a class in the default package gets a PackageEntry of nullptr.
_name->increment_refcount();
JFR_ONLY(INIT_ID(this);)
@ -81,7 +83,7 @@ void PackageEntry::add_qexport(ModuleEntry* m) {
if (!has_qual_exports_list()) {
// Lazily create a package's qualified exports list.
// Initial size is small, do not anticipate export lists to be large.
_qualified_exports = new (mtModule) GrowableArray<ModuleEntry*>(QUAL_EXP_SIZE, mtModule);
_qualified_exports = new (mtModule) AOTGrowableArray<ModuleEntry*>(QUAL_EXP_SIZE, mtModule);
}
// Determine, based on this newly established export to module m,
@ -183,12 +185,24 @@ void PackageEntry::purge_qualified_exports() {
}
void PackageEntry::delete_qualified_exports() {
if (_qualified_exports != nullptr) {
if (_qualified_exports != nullptr && !AOTMetaspace::in_aot_cache(_qualified_exports)) {
delete _qualified_exports;
}
_qualified_exports = nullptr;
}
void PackageEntry::pack_qualified_exports() {
if (_qualified_exports != nullptr) {
_qualified_exports->shrink_to_fit();
}
}
void PackageEntry::metaspace_pointers_do(MetaspaceClosure* it) {
it->push(&_name);
it->push(&_module);
it->push(&_qualified_exports);
}
PackageEntryTable::PackageEntryTable() { }
PackageEntryTable::~PackageEntryTable() {
@ -212,66 +226,19 @@ PackageEntryTable::~PackageEntryTable() {
}
#if INCLUDE_CDS_JAVA_HEAP
typedef HashTable<
const PackageEntry*,
PackageEntry*,
557, // prime number
AnyObj::C_HEAP> ArchivedPackageEntries;
static ArchivedPackageEntries* _archived_packages_entries = nullptr;
bool PackageEntry::should_be_archived() const {
return module()->should_be_archived();
}
PackageEntry* PackageEntry::allocate_archived_entry() const {
precond(should_be_archived());
PackageEntry* archived_entry = (PackageEntry*)ArchiveBuilder::rw_region_alloc(sizeof(PackageEntry));
memcpy((void*)archived_entry, (void*)this, sizeof(PackageEntry));
if (_archived_packages_entries == nullptr) {
_archived_packages_entries = new (mtClass)ArchivedPackageEntries();
void PackageEntry::remove_unshareable_info() {
if (_qualified_exports != nullptr) {
_qualified_exports->set_in_aot_cache();
}
assert(_archived_packages_entries->get(this) == nullptr, "Each PackageEntry must not be shared across PackageEntryTables");
_archived_packages_entries->put(this, archived_entry);
return archived_entry;
}
PackageEntry* PackageEntry::get_archived_entry(PackageEntry* orig_entry) {
PackageEntry** ptr = _archived_packages_entries->get(orig_entry);
if (ptr != nullptr) {
return *ptr;
} else {
return nullptr;
}
}
void PackageEntry::iterate_symbols(MetaspaceClosure* closure) {
closure->push(&_name);
}
void PackageEntry::init_as_archived_entry() {
Array<ModuleEntry*>* archived_qualified_exports = ModuleEntry::write_growable_array(_qualified_exports);
_name = ArchiveBuilder::get_buffered_symbol(_name);
_module = ModuleEntry::get_archived_entry(_module);
_qualified_exports = (GrowableArray<ModuleEntry*>*)archived_qualified_exports;
_defined_by_cds_in_class_path = 0;
JFR_ONLY(set_trace_id(0);) // re-init at runtime
ArchivePtrMarker::mark_pointer((address*)&_name);
ArchivePtrMarker::mark_pointer((address*)&_module);
ArchivePtrMarker::mark_pointer((address*)&_qualified_exports);
LogStreamHandle(Info, aot, package) st;
if (st.is_enabled()) {
st.print("archived ");
print(&st);
}
}
void PackageEntry::load_from_archive() {
_qualified_exports = ModuleEntry::restore_growable_array((Array<ModuleEntry*>*)_qualified_exports);
JFR_ONLY(INIT_ID(this);)
}
@ -280,14 +247,7 @@ static int compare_package_by_name(PackageEntry* a, PackageEntry* b) {
return a->name()->fast_compare(b->name());
}
void PackageEntryTable::iterate_symbols(MetaspaceClosure* closure) {
auto syms = [&] (const SymbolHandle& key, PackageEntry*& p) {
p->iterate_symbols(closure);
};
_table.iterate_all(syms);
}
Array<PackageEntry*>* PackageEntryTable::allocate_archived_entries() {
Array<PackageEntry*>* PackageEntryTable::build_aot_table(ClassLoaderData* loader_data, TRAPS) {
// First count the packages in named modules
int n = 0;
auto count = [&] (const SymbolHandle& key, PackageEntry*& p) {
@ -297,12 +257,19 @@ Array<PackageEntry*>* PackageEntryTable::allocate_archived_entries() {
};
_table.iterate_all(count);
Array<PackageEntry*>* archived_packages = ArchiveBuilder::new_rw_array<PackageEntry*>(n);
Array<PackageEntry*>* archived_packages = MetadataFactory::new_array<PackageEntry*>(loader_data, n, nullptr, CHECK_NULL);
// reset n
n = 0;
auto grab = [&] (const SymbolHandle& key, PackageEntry*& p) {
if (p->should_be_archived()) {
p->pack_qualified_exports();
archived_packages->at_put(n++, p);
LogStreamHandle(Info, aot, package) st;
if (st.is_enabled()) {
st.print("archived ");
p->print(&st);
}
}
};
_table.iterate_all(grab);
@ -311,18 +278,8 @@ Array<PackageEntry*>* PackageEntryTable::allocate_archived_entries() {
// Always allocate in the same order to produce deterministic archive.
QuickSort::sort(archived_packages->data(), n, compare_package_by_name);
}
for (int i = 0; i < n; i++) {
archived_packages->at_put(i, archived_packages->at(i)->allocate_archived_entry());
ArchivePtrMarker::mark_pointer((address*)archived_packages->adr_at(i));
}
return archived_packages;
}
void PackageEntryTable::init_archived_entries(Array<PackageEntry*>* archived_packages) {
for (int i = 0; i < archived_packages->length(); i++) {
PackageEntry* archived_entry = archived_packages->at(i);
archived_entry->init_as_archived_entry();
}
return archived_packages;
}
void PackageEntryTable::load_archived_entries(Array<PackageEntry*>* archived_packages) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@ -25,7 +25,9 @@
#ifndef SHARE_CLASSFILE_PACKAGEENTRY_HPP
#define SHARE_CLASSFILE_PACKAGEENTRY_HPP
#include "cds/aotGrowableArray.hpp"
#include "classfile/moduleEntry.hpp"
#include "memory/metaspaceClosureType.hpp"
#include "oops/symbol.hpp"
#include "oops/symbolHandle.hpp"
#include "runtime/atomicAccess.hpp"
@ -114,7 +116,7 @@ private:
bool _must_walk_exports;
// Contains list of modules this package is qualifiedly exported to. Access
// to this list is protected by the Module_lock.
GrowableArray<ModuleEntry*>* _qualified_exports;
AOTGrowableArray<ModuleEntry*>* _qualified_exports;
JFR_ONLY(DEFINE_TRACE_ID_FIELD;)
// Initial size of a package entry's list of qualified exports.
@ -205,14 +207,24 @@ public:
void purge_qualified_exports();
void delete_qualified_exports();
void pack_qualified_exports(); // used by AOT
// methods required by MetaspaceClosure
void metaspace_pointers_do(MetaspaceClosure* it);
int size_in_heapwords() const { return (int)heap_word_size(sizeof(PackageEntry)); }
MetaspaceClosureType type() const { return MetaspaceClosureType::PackageEntryType; }
static bool is_read_only_by_default() { return false; }
void print(outputStream* st = tty);
char* name_as_C_string() const {
assert(_name != nullptr, "name can't be null");
return name()->as_C_string();
}
#if INCLUDE_CDS_JAVA_HEAP
bool should_be_archived() const;
void iterate_symbols(MetaspaceClosure* closure);
PackageEntry* allocate_archived_entry() const;
void init_as_archived_entry();
static PackageEntry* get_archived_entry(PackageEntry* orig_entry);
void remove_unshareable_info();
void load_from_archive();
#endif
@ -271,9 +283,7 @@ public:
void print(outputStream* st = tty);
#if INCLUDE_CDS_JAVA_HEAP
void iterate_symbols(MetaspaceClosure* closure);
Array<PackageEntry*>* allocate_archived_entries();
void init_archived_entries(Array<PackageEntry*>* archived_packages);
Array<PackageEntry*>* build_aot_table(ClassLoaderData* loader_data, TRAPS);
void load_archived_entries(Array<PackageEntry*>* archived_packages);
#endif
};

View File

@ -245,10 +245,6 @@ class SerializeClosure;
\
/* Concurrency support */ \
template(java_util_concurrent_locks_AbstractOwnableSynchronizer, "java/util/concurrent/locks/AbstractOwnableSynchronizer") \
template(java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicIntegerFieldUpdater$AtomicIntegerFieldUpdaterImpl") \
template(java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$CASUpdater") \
template(java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater, "java/util/concurrent/atomic/AtomicLongFieldUpdater$LockedUpdater") \
template(java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl, "java/util/concurrent/atomic/AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl") \
template(jdk_internal_vm_annotation_Contended_signature, "Ljdk/internal/vm/annotation/Contended;") \
template(jdk_internal_vm_annotation_ReservedStackAccess_signature, "Ljdk/internal/vm/annotation/ReservedStackAccess;") \
template(jdk_internal_ValueBased_signature, "Ljdk/internal/ValueBased;") \
@ -302,6 +298,7 @@ class SerializeClosure;
template(jdk_internal_misc_Scoped_signature, "Ljdk/internal/misc/ScopedMemoryAccess$Scoped;") \
template(jdk_internal_vm_annotation_IntrinsicCandidate_signature, "Ljdk/internal/vm/annotation/IntrinsicCandidate;") \
template(jdk_internal_vm_annotation_Stable_signature, "Ljdk/internal/vm/annotation/Stable;") \
template(jdk_internal_vm_annotation_TrustFinalFields_signature, "Ljdk/internal/vm/annotation/TrustFinalFields;") \
\
template(jdk_internal_vm_annotation_ChangesCurrentThread_signature, "Ljdk/internal/vm/annotation/ChangesCurrentThread;") \
template(jdk_internal_vm_annotation_JvmtiHideEvents_signature, "Ljdk/internal/vm/annotation/JvmtiHideEvents;") \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -22,6 +22,7 @@
*
*/
#include "cds/aotMetaspace.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/arena.hpp"
#include "memory/metaspace.hpp"
@ -161,12 +162,33 @@ void AnyObj::set_allocation_type(address res, allocation_type type) {
}
}
void AnyObj::set_in_aot_cache() {
_allocation_t[0] = 0;
_allocation_t[1] = 0;
}
bool AnyObj::in_aot_cache() const {
if (AOTMetaspace::in_aot_cache(this)) {
precond(_allocation_t[0] == 0);
precond(_allocation_t[1] == 0);
return true;
} else {
return false;
}
}
AnyObj::allocation_type AnyObj::get_allocation_type() const {
if (in_aot_cache()) {
return STACK_OR_EMBEDDED;
}
assert(~(_allocation_t[0] | allocation_mask) == (uintptr_t)this, "lost resource object");
return (allocation_type)((~_allocation_t[0]) & allocation_mask);
}
bool AnyObj::is_type_set() const {
if (in_aot_cache()) {
return true;
}
allocation_type type = (allocation_type)(_allocation_t[1] & allocation_mask);
return get_allocation_type() == type &&
(_allocation_t[1] - type) == (uintptr_t)(&_allocation_t[1]);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -420,6 +420,7 @@ class AnyObj {
public:
enum allocation_type { STACK_OR_EMBEDDED = 0, RESOURCE_AREA, C_HEAP, ARENA, allocation_mask = 0x3 };
static void set_allocation_type(address res, allocation_type type) NOT_DEBUG_RETURN;
void set_in_aot_cache() NOT_DEBUG_RETURN;
#ifdef ASSERT
private:
// When this object is allocated on stack the new() operator is not
@ -429,6 +430,7 @@ class AnyObj {
uintptr_t _allocation_t[2];
bool is_type_set() const;
void initialize_allocation_info();
bool in_aot_cache() const;
public:
allocation_type get_allocation_type() const;
bool allocated_on_stack_or_embedded() const { return get_allocation_type() == STACK_OR_EMBEDDED; }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -22,7 +22,21 @@
*
*/
#include "cds/aotGrowableArray.hpp"
#include "classfile/packageEntry.hpp"
#include "memory/metaspaceClosure.hpp"
#include "oops/array.hpp"
#include "oops/instanceKlass.hpp"
// Sanity checks
static_assert(!HAS_METASPACE_POINTERS_DO(int));
static_assert(HAS_METASPACE_POINTERS_DO(Array<int>));
static_assert(HAS_METASPACE_POINTERS_DO(Array<InstanceKlass*>));
static_assert(HAS_METASPACE_POINTERS_DO(InstanceKlass));
static_assert(HAS_METASPACE_POINTERS_DO(PackageEntry));
static_assert(HAS_METASPACE_POINTERS_DO(AOTGrowableArray<int>));
static_assert(HAS_METASPACE_POINTERS_DO(AOTGrowableArray<PackageEntry*>));
void MetaspaceClosure::push_impl(MetaspaceClosure::Ref* ref) {
if (_enclosing_ref != nullptr) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 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
@ -25,9 +25,11 @@
#ifndef SHARE_MEMORY_METASPACECLOSURE_HPP
#define SHARE_MEMORY_METASPACECLOSURE_HPP
#include "cds/aotGrowableArray.hpp"
#include "cppstdlib/type_traits.hpp"
#include "logging/log.hpp"
#include "memory/allocation.hpp"
#include "memory/metaspaceClosureType.hpp"
#include "metaprogramming/enableIf.hpp"
#include "oops/array.hpp"
#include "utilities/debug.hpp"
@ -36,41 +38,27 @@
#include "utilities/macros.hpp"
#include "utilities/resizableHashTable.hpp"
// The metadata hierarchy is separate from the oop hierarchy
class MetaspaceObj; // no C++ vtable
//class Array; // no C++ vtable
class Annotations; // no C++ vtable
class ConstantPoolCache; // no C++ vtable
class ConstMethod; // no C++ vtable
class MethodCounters; // no C++ vtable
class Symbol; // no C++ vtable
class Metadata; // has C++ vtable (so do all subclasses)
class ConstantPool;
class MethodData;
class Method;
class Klass;
class InstanceKlass;
class InstanceMirrorKlass;
class InstanceClassLoaderKlass;
class InstanceRefKlass;
class ArrayKlass;
class ObjArrayKlass;
class TypeArrayKlass;
// This macro just check for the existence of a member with the name "metaspace_pointers_do". If the
// parameter list is not (MetaspaceClosure* it), you will get a compilation error.
#define HAS_METASPACE_POINTERS_DO(T) HasMetaspacePointersDo<T>::value
template<typename T>
class HasMetaspacePointersDo {
template<typename U> static void* test(decltype(&U::metaspace_pointers_do));
template<typename> static int test(...);
using test_type = decltype(test<T>(nullptr));
public:
static constexpr bool value = std::is_pointer_v<test_type>;
};
// class MetaspaceClosure --
//
// This class is used for iterating the objects in the HotSpot Metaspaces. It
// This class is used for iterating the class metadata objects. It
// provides an API to walk all the reachable objects starting from a set of
// root references (such as all Klass'es in the SystemDictionary).
//
// Currently it is used for compacting the CDS archive by eliminate temporary
// objects allocated during archive creation time. See ArchiveBuilder for an example.
//
// To support MetaspaceClosure, each subclass of MetaspaceObj must provide
// a method of the type void metaspace_pointers_do(MetaspaceClosure*). This method
// should call MetaspaceClosure::push() on every pointer fields of this
// class that points to a MetaspaceObj. See Annotations::metaspace_pointers_do()
// for an example.
// Currently it is used to copy class metadata into the AOT cache.
// See ArchiveBuilder for an example.
class MetaspaceClosure {
public:
enum Writability {
@ -79,16 +67,32 @@ public:
_default
};
#define METASPACE_CLOSURE_TYPE_NAME_CASE(name) case MetaspaceClosureType::name ## Type: return #name;
static const char* type_name(MetaspaceClosureType type) {
switch(type) {
METASPACE_CLOSURE_TYPES_DO(METASPACE_CLOSURE_TYPE_NAME_CASE)
default:
ShouldNotReachHere();
return nullptr;
}
}
// class MetaspaceClosure::Ref --
//
// MetaspaceClosure can be viewed as a very simple type of copying garbage
// collector. For it to function properly, it requires each subclass of
// MetaspaceObj to provide two methods:
// For type X to be iterable by MetaspaceClosure, X (or one of X's supertypes) must have
// the following public functions:
// void metaspace_pointers_do(MetaspaceClosure* it);
// static bool is_read_only_by_default() { return true; }
//
// size_t size(); -- to determine how much data to copy
// void metaspace_pointers_do(MetaspaceClosure*); -- to locate all the embedded pointers
// In addition, if X is not a subtype of MetaspaceObj, it must have the following function:
// MetaspaceClosureType type() const;
// int size_in_heapwords() const;
//
// Calling these methods would be trivial if these two were virtual methods.
// Currently, the iterable types include all subtypes of MetsapceObj, as well
// as GrowableArray, ModuleEntry and PackageEntry.
//
// Calling these functions would be trivial if these were virtual functions.
// However, to save space, MetaspaceObj has NO vtable. The vtable is introduced
// only in the Metadata class.
//
@ -97,7 +101,7 @@ public:
// so that we can statically discover the type of a object. The use of Ref
// depends on the fact that:
//
// [1] We don't use polymorphic pointers for MetaspaceObj's that are not subclasses
// [1] We don't use polymorphic pointers to MetaspaceObj's that are not subclasses
// of Metadata. I.e., we don't do this:
// class Klass {
// MetaspaceObj *_obj;
@ -130,8 +134,7 @@ public:
virtual bool not_null() const = 0;
virtual int size() const = 0;
virtual void metaspace_pointers_do(MetaspaceClosure *it) const = 0;
virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const = 0;
virtual MetaspaceObj::Type msotype() const = 0;
virtual MetaspaceClosureType type() const = 0;
virtual bool is_read_only_by_default() const = 0;
virtual ~Ref() {}
@ -180,7 +183,26 @@ public:
}
private:
// MSORef -- iterate an instance of MetaspaceObj
template <typename T, ENABLE_IF(std::is_base_of<MetaspaceObj, T>::value)>
static int get_size(T* obj) {
return obj->size();
}
template <typename T, ENABLE_IF(!std::is_base_of<MetaspaceObj, T>::value)>
static int get_size(T* obj) {
return obj->size_in_heapwords();
}
static MetaspaceClosureType as_type(MetaspaceClosureType t) {
return t;
}
static MetaspaceClosureType as_type(MetaspaceObj::Type msotype) {
precond(msotype < MetaspaceObj::_number_of_types);
return (MetaspaceClosureType)msotype;
}
// MSORef -- iterate an instance of T, where T::metaspace_pointers_do() exists.
template <class T> class MSORef : public Ref {
T** _mpp;
T* dereference() const {
@ -196,18 +218,20 @@ private:
virtual bool is_read_only_by_default() const { return T::is_read_only_by_default(); }
virtual bool not_null() const { return dereference() != nullptr; }
virtual int size() const { return dereference()->size(); }
virtual MetaspaceObj::Type msotype() const { return dereference()->type(); }
virtual int size() const { return get_size(dereference()); }
virtual MetaspaceClosureType type() const { return as_type(dereference()->type()); }
virtual void metaspace_pointers_do(MetaspaceClosure *it) const {
dereference()->metaspace_pointers_do(it);
}
virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const {
((T*)new_loc)->metaspace_pointers_do(it);
}
};
// abstract base class for MSOArrayRef, MSOPointerArrayRef and OtherArrayRef
//---------------------
// Support for Array<T>
//---------------------
// Abstract base class for MSOArrayRef, MSOPointerArrayRef and OtherArrayRef.
// These are used for iterating Array<T>.
template <class T> class ArrayRef : public Ref {
Array<T>** _mpp;
protected:
@ -224,10 +248,10 @@ private:
virtual bool is_read_only_by_default() const { return true; }
virtual bool not_null() const { return dereference() != nullptr; }
virtual int size() const { return dereference()->size(); }
virtual MetaspaceObj::Type msotype() const { return MetaspaceObj::array_type(sizeof(T)); }
virtual MetaspaceClosureType type() const { return as_type(MetaspaceObj::array_type(sizeof(T))); }
};
// OtherArrayRef -- iterate an instance of Array<T>, where T is NOT a subtype of MetaspaceObj.
// OtherArrayRef -- iterate an instance of Array<T>, where T does NOT have metaspace_pointer_do().
// T can be a primitive type, such as int, or a structure. However, we do not scan
// the fields inside T, so you should not embed any pointers inside T.
template <class T> class OtherArrayRef : public ArrayRef<T> {
@ -238,13 +262,9 @@ private:
Array<T>* array = ArrayRef<T>::dereference();
log_trace(aot)("Iter(OtherArray): %p [%d]", array, array->length());
}
virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const {
Array<T>* array = (Array<T>*)new_loc;
log_trace(aot)("Iter(OtherArray): %p [%d]", array, array->length());
}
};
// MSOArrayRef -- iterate an instance of Array<T>, where T is a subtype of MetaspaceObj.
// MSOArrayRef -- iterate an instance of Array<T>, where T has metaspace_pointer_do().
// We recursively call T::metaspace_pointers_do() for each element in this array.
template <class T> class MSOArrayRef : public ArrayRef<T> {
public:
@ -253,9 +273,6 @@ private:
virtual void metaspace_pointers_do(MetaspaceClosure *it) const {
metaspace_pointers_do_at_impl(it, ArrayRef<T>::dereference());
}
virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const {
metaspace_pointers_do_at_impl(it, (Array<T>*)new_loc);
}
private:
void metaspace_pointers_do_at_impl(MetaspaceClosure *it, Array<T>* array) const {
log_trace(aot)("Iter(MSOArray): %p [%d]", array, array->length());
@ -266,7 +283,7 @@ private:
}
};
// MSOPointerArrayRef -- iterate an instance of Array<T*>, where T is a subtype of MetaspaceObj.
// MSOPointerArrayRef -- iterate an instance of Array<T*>, where T has metaspace_pointer_do().
// We recursively call MetaspaceClosure::push() for each pointer in this array.
template <class T> class MSOPointerArrayRef : public ArrayRef<T*> {
public:
@ -275,9 +292,6 @@ private:
virtual void metaspace_pointers_do(MetaspaceClosure *it) const {
metaspace_pointers_do_at_impl(it, ArrayRef<T*>::dereference());
}
virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const {
metaspace_pointers_do_at_impl(it, (Array<T*>*)new_loc);
}
private:
void metaspace_pointers_do_at_impl(MetaspaceClosure *it, Array<T*>* array) const {
log_trace(aot)("Iter(MSOPointerArray): %p [%d]", array, array->length());
@ -288,6 +302,102 @@ private:
}
};
//--------------------------------
// Support for AOTGrowableArray<T>
//--------------------------------
// Abstract base class for MSOCArrayRef, MSOPointerCArrayRef and OtherCArrayRef.
// These are used for iterating the buffer held by AOTGrowableArray<T>.
template <class T> class CArrayRef : public Ref {
T** _mpp;
int _num_elems; // Number of elements
int byte_size() const {
return _num_elems * sizeof(T);
}
protected:
// C pointer arrays don't support tagged pointers.
T* dereference() const {
return *_mpp;
}
virtual void** mpp() const {
return (void**)_mpp;
}
int num_elems() const {
return _num_elems;
}
public:
CArrayRef(T** mpp, int num_elems, Writability w)
: Ref(w), _mpp(mpp), _num_elems(num_elems) {
assert(is_aligned(byte_size(), BytesPerWord), "must be");
}
virtual bool is_read_only_by_default() const { return false; }
virtual bool not_null() const { return dereference() != nullptr; }
virtual int size() const { return (int)heap_word_size(byte_size()); }
virtual MetaspaceClosureType type() const { return MetaspaceClosureType::CArrayType; }
};
// OtherCArrayRef -- iterate a C array of type T, where T does NOT have metaspace_pointer_do().
// T can be a primitive type, such as int, or a structure. However, we do not scan
// the fields inside T, so you should not embed any pointers inside T.
template <class T> class OtherCArrayRef : public CArrayRef<T> {
public:
OtherCArrayRef(T** mpp, int num_elems, Writability w) : CArrayRef<T>(mpp, num_elems, w) {}
virtual void metaspace_pointers_do(MetaspaceClosure *it) const {
T* array = CArrayRef<T>::dereference();
log_trace(aot)("Iter(OtherCArray): %p [%d]", array, CArrayRef<T>::num_elems());
}
};
// MSOCArrayRef<T> -- iterate a C array of type T, where T has metaspace_pointer_do().
// We recursively call T::metaspace_pointers_do() for each element in this array.
// This is for supporting AOTGrowableArray<T>.
//
// E.g., PackageEntry* _pkg_entry_pointers[2]; // a buffer that has 2 PackageEntry objects
// ...
// it->push(&_pkg_entry_pointers, 2);
// /* calls _pkg_entry_pointers[0].metaspace_pointers_do(it); */
// /* calls _pkg_entry_pointers[1].metaspace_pointers_do(it); */
template <class T> class MSOCArrayRef : public CArrayRef<T> {
public:
MSOCArrayRef(T** mpp, int num_elems, Writability w) : CArrayRef<T>(mpp, num_elems, w) {}
virtual void metaspace_pointers_do(MetaspaceClosure *it) const {
T* array = CArrayRef<T>::dereference();
log_trace(aot)("Iter(MSOCArray): %p [%d]", array, CArrayRef<T>::num_elems());
for (int i = 0; i < CArrayRef<T>::num_elems(); i++) {
T* elm = array + i;
elm->metaspace_pointers_do(it);
}
}
};
// MSOPointerCArrayRef<T> -- iterate a C array of type T*, where T has metaspace_pointer_do().
// We recursively call MetaspaceClosure::push() for each pointer in this array.
// This is for supporting AOTGrowableArray<T*>.
//
// E.g., PackageEntry** _pkg_entry_pointers[2]; // a buffer that has 2 PackageEntry pointers
// ...
// it->push(&_pkg_entry_pointers, 2);
// /* calls _pkg_entry_pointers[0]->metaspace_pointers_do(it); */
// /* calls _pkg_entry_pointers[1]->metaspace_pointers_do(it); */
template <class T> class MSOPointerCArrayRef : public CArrayRef<T*> {
public:
MSOPointerCArrayRef(T*** mpp, int num_elems, Writability w) : CArrayRef<T*>(mpp, num_elems, w) {}
virtual void metaspace_pointers_do(MetaspaceClosure *it) const {
T** array = CArrayRef<T*>::dereference();
log_trace(aot)("Iter(MSOPointerCArray): %p [%d]", array, CArrayRef<T*>::num_elems());
for (int i = 0; i < CArrayRef<T*>::num_elems(); i++) {
T** mpp = array + i;
it->push(mpp);
}
}
};
// Normally, chains of references like a->b->c->d are iterated recursively. However,
// if recursion is too deep, we save the Refs in _pending_refs, and push them later in
// MetaspaceClosure::finish(). This avoids overflowing the C stack.
@ -330,37 +440,61 @@ public:
// Array<Array<Klass*>*>* a4 = ...; it->push(&a4); => MSOPointerArrayRef
// Array<Annotation*>* a5 = ...; it->push(&a5); => MSOPointerArrayRef
//
// Note that the following will fail to compile (to prevent you from adding new fields
// into the MetaspaceObj subtypes that cannot be properly copied by CDS):
// AOTGrowableArrays have a separate "C array" buffer, so they are scanned in two steps:
//
// MemoryPool* p = ...; it->push(&p); => MemoryPool is not a subclass of MetaspaceObj
// Array<MemoryPool*>* a6 = ...; it->push(&a6); => MemoryPool is not a subclass of MetaspaceObj
// Array<int*>* a7 = ...; it->push(&a7); => int is not a subclass of MetaspaceObj
// AOTGrowableArray<jlong>* ga1 = ...; it->push(&ga1); => MSORef => OtherCArrayRef
// AOTGrowableArray<Annotation>* ga2 = ...; it->push(&ga2); => MSORef => MSOCArrayRef
// AOTGrowableArray<Klass*>* ga3 = ...; it->push(&ga3); => MSORef => MSOPointerCArrayRef
//
// Note that the following will fail to compile:
//
// MemoryPool* p = ...; it->push(&p); => MemoryPool doesn't have metaspace_pointers_do
// Array<MemoryPool*>* a6 = ...; it->push(&a6); => MemoryPool doesn't have metaspace_pointers_do
// Array<int*>* a7 = ...; it->push(&a7); => int doesn't have metaspace_pointers_do
// --- Regular iterable objects
template <typename T>
void push(T** mpp, Writability w = _default) {
static_assert(std::is_base_of<MetaspaceObj, T>::value, "Do not push pointers of arbitrary types");
static_assert(HAS_METASPACE_POINTERS_DO(T), "Do not push pointers of arbitrary types");
push_with_ref<MSORef<T>>(mpp, w);
}
template <typename T, ENABLE_IF(!std::is_base_of<MetaspaceObj, T>::value)>
// --- Array<T>
template <typename T, ENABLE_IF(!HAS_METASPACE_POINTERS_DO(T))>
void push(Array<T>** mpp, Writability w = _default) {
push_with_ref<OtherArrayRef<T>>(mpp, w);
}
template <typename T, ENABLE_IF(std::is_base_of<MetaspaceObj, T>::value)>
template <typename T, ENABLE_IF(HAS_METASPACE_POINTERS_DO(T))>
void push(Array<T>** mpp, Writability w = _default) {
push_with_ref<MSOArrayRef<T>>(mpp, w);
}
template <typename T>
void push(Array<T*>** mpp, Writability w = _default) {
static_assert(std::is_base_of<MetaspaceObj, T>::value, "Do not push Arrays of arbitrary pointer types");
static_assert(HAS_METASPACE_POINTERS_DO(T), "Do not push Arrays of arbitrary pointer types");
push_with_ref<MSOPointerArrayRef<T>>(mpp, w);
}
// --- The buffer of AOTGrowableArray<T>
template <typename T, ENABLE_IF(!HAS_METASPACE_POINTERS_DO(T))>
void push_c_array(T** mpp, int num_elems, Writability w = _default) {
push_impl(new OtherCArrayRef<T>(mpp, num_elems, w));
}
template <typename T, ENABLE_IF(HAS_METASPACE_POINTERS_DO(T))>
void push_c_array(T** mpp, int num_elems, Writability w = _default) {
push_impl(new MSOCArrayRef<T>(mpp, num_elems, w));
}
template <typename T>
void push_c_array(T*** mpp, int num_elems, Writability w = _default) {
static_assert(HAS_METASPACE_POINTERS_DO(T), "Do not push C arrays of arbitrary pointer types");
push_impl(new MSOPointerCArrayRef<T>(mpp, num_elems, w));
}
};
// This is a special MetaspaceClosure that visits each unique MetaspaceObj once.
// This is a special MetaspaceClosure that visits each unique object once.
class UniqueMetaspaceClosure : public MetaspaceClosure {
static const int INITIAL_TABLE_SIZE = 15889;
static const int MAX_TABLE_SIZE = 1000000;

View File

@ -0,0 +1,46 @@
/*
* Copyright (c) 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.
*
*/
#ifndef SHARE_MEMORY_METASPACECLOSURETYPE_HPP
#define SHARE_MEMORY_METASPACECLOSURETYPE_HPP
#include "memory/allocation.hpp"
// MetaspaceClosure is able to iterate on MetaspaceObjs, plus the following classes
#define METASPACE_CLOSURE_TYPES_DO(f) \
METASPACE_OBJ_TYPES_DO(f) \
f(CArray) \
f(GrowableArray) \
f(ModuleEntry) \
f(PackageEntry) \
#define METASPACE_CLOSURE_TYPE_DECLARE(name) name ## Type,
enum class MetaspaceClosureType : int {
METASPACE_CLOSURE_TYPES_DO(METASPACE_CLOSURE_TYPE_DECLARE)
_number_of_types
};
#endif // SHARE_MEMORY_METASPACECLOSURETYPE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 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
@ -33,6 +33,8 @@
// Array for metadata allocation
class MetaspaceClosure;
template <typename T>
class Array: public MetaspaceObj {
friend class ArchiveBuilder;
@ -157,6 +159,9 @@ protected:
st->print("Array<T>(" PTR_FORMAT ")", p2i(this));
}
// This function does nothing. The iteration of the elements are done inside metaspaceClosure.hpp
void metaspace_pointers_do(MetaspaceClosure* it) {}
#ifndef PRODUCT
void print(outputStream* st) {
for (int i = 0; i< _length; i++) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -2693,6 +2693,10 @@ void InstanceKlass::metaspace_pointers_do(MetaspaceClosure* it) {
it->push(&_nest_members);
it->push(&_permitted_subclasses);
it->push(&_record_components);
if (CDSConfig::is_dumping_full_module_graph() && !defined_by_other_loaders()) {
it->push(&_package_entry);
}
}
#if INCLUDE_CDS
@ -2791,24 +2795,9 @@ void InstanceKlass::remove_java_mirror() {
void InstanceKlass::init_shared_package_entry() {
assert(CDSConfig::is_dumping_archive(), "must be");
#if !INCLUDE_CDS_JAVA_HEAP
_package_entry = nullptr;
#else
if (CDSConfig::is_dumping_full_module_graph()) {
if (defined_by_other_loaders()) {
_package_entry = nullptr;
} else {
_package_entry = PackageEntry::get_archived_entry(_package_entry);
}
} else if (CDSConfig::is_dumping_dynamic_archive() &&
CDSConfig::is_using_full_module_graph() &&
AOTMetaspace::in_aot_cache(_package_entry)) {
// _package_entry is an archived package in the base archive. Leave it as is.
} else {
if (!CDSConfig::is_dumping_full_module_graph() || defined_by_other_loaders()) {
_package_entry = nullptr;
}
ArchivePtrMarker::mark_pointer((address**)&_package_entry);
#endif
}
void InstanceKlass::compute_has_loops_flag_for_methods() {

View File

@ -353,6 +353,9 @@ class InstanceKlass: public Klass {
int static_oop_field_count() const { return (int)_static_oop_field_count; }
void set_static_oop_field_count(u2 size) { _static_oop_field_count = size; }
bool trust_final_fields() { return _misc_flags.trust_final_fields(); }
void set_trust_final_fields(bool value) { _misc_flags.set_trust_final_fields(value); }
// Java itable
int itable_length() const { return _itable_len; }
void set_itable_length(int len) { _itable_len = len; }

View File

@ -54,6 +54,7 @@ class InstanceKlassFlags {
flag(has_localvariable_table , 1 << 11) /* has localvariable information */ \
flag(has_miranda_methods , 1 << 12) /* True if this class has miranda methods in it's vtable */ \
flag(has_final_method , 1 << 13) /* True if klass has final method */ \
flag(trust_final_fields , 1 << 14) /* All instance final fields in this class should be trusted */ \
/* end of list */
#define IK_FLAGS_ENUM_NAME(name, value) _misc_##name = value,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -581,7 +581,7 @@ void Compile::print_phase(const char* phase_name) {
tty->print_cr("%u.\t%s", ++_phase_counter, phase_name);
}
void Compile::print_ideal_ir(const char* phase_name) {
void Compile::print_ideal_ir(const char* compile_phase_name) const {
// keep the following output all in one block
// This output goes directly to the tty, not the compiler log.
// To enable tools to match it up with the compilation activity,
@ -593,7 +593,7 @@ void Compile::print_ideal_ir(const char* phase_name) {
stringStream ss;
if (_output == nullptr) {
ss.print_cr("AFTER: %s", phase_name);
ss.print_cr("AFTER: %s", compile_phase_name);
// Print out all nodes in ascending order of index.
// It is important that we traverse both inputs and outputs of nodes,
// so that we reach all nodes that are connected to Root.
@ -610,7 +610,7 @@ void Compile::print_ideal_ir(const char* phase_name) {
xtty->head("ideal compile_id='%d'%s compile_phase='%s'",
compile_id(),
is_osr_compilation() ? " compile_kind='osr'" : "",
phase_name);
compile_phase_name);
}
tty->print("%s", ss.as_string());
@ -671,7 +671,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci,
_coarsened_locks(comp_arena(), 8, 0, nullptr),
_congraph(nullptr),
NOT_PRODUCT(_igv_printer(nullptr) COMMA)
_unique(0),
_unique(0),
_dead_node_count(0),
_dead_node_list(comp_arena()),
_node_arena_one(mtCompiler, Arena::Tag::tag_node),
@ -865,7 +865,7 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci,
#ifndef PRODUCT
if (should_print_ideal()) {
print_ideal_ir("print_ideal");
print_ideal_ir("PrintIdeal");
}
#endif
@ -938,7 +938,7 @@ Compile::Compile(ciEnv* ci_env,
_for_merge_stores_igvn(comp_arena(), 8, 0, nullptr),
_congraph(nullptr),
NOT_PRODUCT(_igv_printer(nullptr) COMMA)
_unique(0),
_unique(0),
_dead_node_count(0),
_dead_node_list(comp_arena()),
_node_arena_one(mtCompiler, Arena::Tag::tag_node),
@ -5165,17 +5165,17 @@ void Compile::sort_macro_nodes() {
}
}
void Compile::print_method(CompilerPhaseType cpt, int level, Node* n) {
void Compile::print_method(CompilerPhaseType compile_phase, int level, Node* n) {
if (failing_internal()) { return; } // failing_internal to not stress bailouts from printing code.
EventCompilerPhase event(UNTIMED);
if (event.should_commit()) {
CompilerEvent::PhaseEvent::post(event, C->_latest_stage_start_counter, cpt, C->_compile_id, level);
CompilerEvent::PhaseEvent::post(event, C->_latest_stage_start_counter, compile_phase, C->_compile_id, level);
}
#ifndef PRODUCT
ResourceMark rm;
stringStream ss;
ss.print_raw(CompilerPhaseTypeHelper::to_description(cpt));
int iter = ++_igv_phase_iter[cpt];
ss.print_raw(CompilerPhaseTypeHelper::to_description(compile_phase));
int iter = ++_igv_phase_iter[compile_phase];
if (iter > 1) {
ss.print(" %d", iter);
}
@ -5203,8 +5203,8 @@ void Compile::print_method(CompilerPhaseType cpt, int level, Node* n) {
if (should_print_phase(level)) {
print_phase(name);
}
if (should_print_ideal_phase(cpt)) {
print_ideal_ir(CompilerPhaseTypeHelper::to_name(cpt));
if (should_print_ideal_phase(compile_phase)) {
print_ideal_ir(CompilerPhaseTypeHelper::to_name(compile_phase));
}
#endif
C->_latest_stage_start_counter.stamp();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -666,7 +666,7 @@ public:
uint next_igv_idx() { return _igv_idx++; }
bool trace_opto_output() const { return _trace_opto_output; }
void print_phase(const char* phase_name);
void print_ideal_ir(const char* phase_name);
void print_ideal_ir(const char* compile_phase_name) const;
bool should_print_ideal() const { return _directive->PrintIdealOption; }
bool parsed_irreducible_loop() const { return _parsed_irreducible_loop; }
void set_parsed_irreducible_loop(bool z) { _parsed_irreducible_loop = z; }
@ -680,7 +680,7 @@ public:
void begin_method();
void end_method();
void print_method(CompilerPhaseType cpt, int level, Node* n = nullptr);
void print_method(CompilerPhaseType compile_phase, int level, Node* n = nullptr);
#ifndef PRODUCT
bool should_print_igv(int level);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -30,7 +30,6 @@
#include "code/vmreg.hpp"
#include "interpreter/linkResolver.hpp"
#include "memory/allStatic.hpp"
#include "memory/metaspaceClosure.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "runtime/stubInfo.hpp"
@ -38,6 +37,7 @@
class AdapterHandlerEntry;
class AdapterFingerPrint;
class MetaspaceClosure;
class vframeStream;
// Runtime is the base class for various runtime interfaces

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@ -116,6 +116,12 @@ protected:
~GrowableArrayView() {}
protected:
// Used by AOTGrowableArray for MetaspaceClosure support.
E** data_addr() {
return &_data;
}
public:
bool operator==(const GrowableArrayView& rhs) const {
if (_len != rhs._len)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 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
@ -4826,7 +4826,9 @@ assert((int)twice.invokeExact(21) == 42);
* Before the method handle is returned, the passed-in value is converted to the requested type.
* If the requested type is primitive, widening primitive conversions are attempted,
* else reference conversions are attempted.
* <p>The returned method handle is equivalent to {@code identity(type).bindTo(value)}.
* <p>The returned method handle is equivalent to {@code identity(type).bindTo(value)},
* for reference types. For all types it is equivalent to
* {@code insertArguments(identity(type), 0, value)}.
* @param type the return type of the desired method handle
* @param value the value to return
* @return a method handle of the given return type and no arguments, which always returns the given value

View File

@ -25,7 +25,7 @@
package java.util;
import jdk.internal.vm.annotation.Stable;
import jdk.internal.vm.annotation.TrustFinalFields;
import java.util.function.Consumer;
import java.util.function.Function;
@ -62,6 +62,7 @@ import java.util.stream.Stream;
* @since 1.8
*/
@jdk.internal.ValueBased
@TrustFinalFields
public final class Optional<T> {
/**
* Common instance for {@code empty()}.
@ -71,7 +72,6 @@ public final class Optional<T> {
/**
* If non-null, the value; if null, indicates no value is present
*/
@Stable
private final T value;
/**

View File

@ -42,6 +42,8 @@ import java.util.function.IntUnaryOperator;
import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.TrustFinalFields;
import java.lang.invoke.VarHandle;
/**
@ -371,6 +373,7 @@ public abstract class AtomicIntegerFieldUpdater<T> {
/**
* Standard hotspot implementation using intrinsics.
*/
@TrustFinalFields
private static final class AtomicIntegerFieldUpdaterImpl<T>
extends AtomicIntegerFieldUpdater<T> {
private static final Unsafe U = Unsafe.getUnsafe();

View File

@ -42,6 +42,8 @@ import java.util.function.LongUnaryOperator;
import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.TrustFinalFields;
import java.lang.invoke.VarHandle;
/**
@ -368,6 +370,7 @@ public abstract class AtomicLongFieldUpdater<T> {
return next;
}
@TrustFinalFields
private static final class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
private static final Unsafe U = Unsafe.getUnsafe();
private final long offset;

View File

@ -42,6 +42,8 @@ import java.util.function.UnaryOperator;
import jdk.internal.misc.Unsafe;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.vm.annotation.TrustFinalFields;
import java.lang.invoke.VarHandle;
/**
@ -312,6 +314,7 @@ public abstract class AtomicReferenceFieldUpdater<T,V> {
return next;
}
@TrustFinalFields
private static final class AtomicReferenceFieldUpdaterImpl<T,V>
extends AtomicReferenceFieldUpdater<T,V> {
private static final Unsafe U = Unsafe.getUnsafe();

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2025, 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. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
package jdk.internal.vm.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/// Indicates all instance final fields declared in the annotated class should
/// be trusted as constants by compilers in `ciField::is_constant`.
///
/// The compiler already treats static final fields and instance final fields in
/// record classes and hidden classes as constant. All classes in select
/// packages (Defined in `trust_final_non_static_fields` in `ciField.cpp`) in
/// the boot class loader also have their instance final fields trusted. This
/// annotation is not necessary in these cases.
///
/// The [Stable] annotation treats fields as constants once they are not the
/// zero or null value. In comparison, a non-stable final instance field
/// trusted by this annotation can treat zero and null values as constants.
///
/// This annotation is suitable when constant treatment of final fields is
/// performance sensitive, yet package-wide final field constant treatment may
/// be at risk from final field modifications such as serialization.
///
/// This annotation is only recognized on classes from the boot and platform
/// class loaders and is ignored elsewhere.
///
/// @since 26
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TrustFinalFields {
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -85,10 +85,6 @@ void ImageDecompressor::image_decompressor_init() {
}
}
void ImageDecompressor::image_decompressor_close() {
delete[] _decompressors;
}
/*
* Locate decompressor.
*/

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -105,6 +105,7 @@ private:
protected:
ImageDecompressor(const char* name) : _name(name) {
}
virtual void decompress_resource(u1* data, u1* uncompressed,
ResourceHeader* header, const ImageStrings* strings) = 0;
@ -166,6 +167,6 @@ private:
public:
SharedStringDecompressor(const char* sym) : ImageDecompressor(sym){}
void decompress_resource(u1* data, u1* uncompressed, ResourceHeader* header,
const ImageStrings* strings);
const ImageStrings* strings);
};
#endif // LIBJIMAGE_IMAGEDECOMPRESSOR_HPP

View File

@ -32,7 +32,6 @@ import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.synth.*;
import sun.awt.AppContext;
import sun.awt.UNIXToolkit;
import sun.swing.SwingUtilities2;
import javax.swing.plaf.synth.SynthIcon;
@ -961,11 +960,11 @@ class GTKStyle extends SynthStyle implements GTKConstants {
static class GTKStockIconInfo {
private static Map<String,Integer> ICON_TYPE_MAP;
private static final Object ICON_SIZE_KEY = new StringBuffer("IconSize");
private static Dimension[] iconSizesMap;
private static Dimension[] getIconSizesMap() {
AppContext appContext = AppContext.getAppContext();
Dimension[] iconSizes = (Dimension[])appContext.get(ICON_SIZE_KEY);
Dimension[] iconSizes = iconSizesMap;
if (iconSizes == null) {
iconSizes = new Dimension[7];
@ -976,7 +975,7 @@ class GTKStyle extends SynthStyle implements GTKConstants {
iconSizes[4] = new Dimension(20, 20); // GTK_ICON_SIZE_BUTTON
iconSizes[5] = new Dimension(32, 32); // GTK_ICON_SIZE_DND
iconSizes[6] = new Dimension(48, 48); // GTK_ICON_SIZE_DIALOG
appContext.put(ICON_SIZE_KEY, iconSizes);
iconSizesMap = iconSizes;
}
return iconSizes;
}

View File

@ -24,8 +24,6 @@
*/
package javax.swing.plaf.nimbus;
import sun.awt.AppContext;
import java.awt.image.BufferedImage;
import java.lang.ref.SoftReference;
@ -81,13 +79,10 @@ abstract class Effect {
// =================================================================================================================
// Static data cache
private static final ArrayCache ARRAY_CACHE = new ArrayCache();
protected static ArrayCache getArrayCache() {
ArrayCache cache = (ArrayCache)AppContext.getAppContext().get(ArrayCache.class);
if (cache == null){
cache = new ArrayCache();
AppContext.getAppContext().put(ArrayCache.class,cache);
}
return cache;
return ARRAY_CACHE;
}
protected static class ArrayCache {

View File

@ -28,7 +28,6 @@ import java.awt.*;
import java.lang.ref.WeakReference;
import java.net.*;
import javax.swing.*;
import sun.awt.AppContext;
import sun.swing.plaf.synth.Paint9Painter;
/**
@ -41,8 +40,6 @@ import sun.swing.plaf.synth.Paint9Painter;
* @author Scott Violet
*/
class ImagePainter extends SynthPainter {
private static final StringBuffer CACHE_KEY =
new StringBuffer("SynthCacheKey");
private Image image;
private Insets sInsets;
@ -53,22 +50,17 @@ class ImagePainter extends SynthPainter {
private Paint9Painter imageCache;
private boolean center;
private static volatile WeakReference<Paint9Painter> cacheRef;
private static Paint9Painter getPaint9Painter() {
// A SynthPainter is created per <imagePainter>. We want the
// cache to be shared by all, and we don't use a static because we
// don't want it to persist between look and feels. For that reason
// we use a AppContext specific Paint9Painter. It's backed via
// cache to be shared by all. It's held via
// a WeakRef so that it can go away if the look and feel changes.
synchronized(CACHE_KEY) {
@SuppressWarnings("unchecked")
WeakReference<Paint9Painter> cacheRef =
(WeakReference<Paint9Painter>)AppContext.getAppContext().
get(CACHE_KEY);
synchronized(ImagePainter.class) {
Paint9Painter painter;
if (cacheRef == null || (painter = cacheRef.get()) == null) {
painter = new Paint9Painter(30);
cacheRef = new WeakReference<Paint9Painter>(painter);
AppContext.getAppContext().put(CACHE_KEY, cacheRef);
}
return painter;
}

View File

@ -24,8 +24,6 @@
*/
package javax.swing.plaf.synth;
import sun.awt.AppContext;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@ -72,8 +70,6 @@ import javax.swing.UIDefaults;
* @author Scott Violet
*/
public class Region {
private static final Object UI_TO_REGION_MAP_KEY = new Object();
private static final Object LOWER_CASE_NAME_MAP_KEY = new Object();
/**
* ArrowButton's are special types of buttons that also render a
@ -425,10 +421,10 @@ public class Region {
*/
public static final Region VIEWPORT = new Region("Viewport", false);
private static Map<String, Region> getUItoRegionMap() {
AppContext context = AppContext.getAppContext();
@SuppressWarnings("unchecked")
Map<String, Region> map = (Map<String, Region>) context.get(UI_TO_REGION_MAP_KEY);
private static Map<String, Region> regionMap;
private static synchronized Map<String, Region> getUItoRegionMap() {
Map<String, Region> map = regionMap;
if (map == null) {
map = new HashMap<String, Region>();
map.put("ArrowButtonUI", ARROW_BUTTON);
@ -476,18 +472,18 @@ public class Region {
map.put("ToolBarSeparatorUI", TOOL_BAR_SEPARATOR);
map.put("TreeUI", TREE);
map.put("ViewportUI", VIEWPORT);
context.put(UI_TO_REGION_MAP_KEY, map);
regionMap = map;
}
return map;
}
private static Map<Region, String> getLowerCaseNameMap() {
AppContext context = AppContext.getAppContext();
@SuppressWarnings("unchecked")
Map<Region, String> map = (Map<Region, String>) context.get(LOWER_CASE_NAME_MAP_KEY);
private static Map<Region, String> lcRegionMap;
private static synchronized Map<Region, String> getLowerCaseNameMap() {
Map<Region, String> map = lcRegionMap;
if (map == null) {
map = new HashMap<Region, String>();
context.put(LOWER_CASE_NAME_MAP_KEY, map);
lcRegionMap = map;
}
return map;
}

View File

@ -25,8 +25,6 @@
package javax.swing.plaf.synth;
import sun.awt.AppContext;
import javax.swing.*;
import java.awt.*;
import java.beans.*;

View File

@ -60,7 +60,6 @@ import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.InsetsUIResource;
import javax.swing.plaf.basic.BasicLookAndFeel;
import sun.awt.AppContext;
import sun.awt.SunToolkit;
import sun.swing.DefaultLookup;
import sun.swing.SwingAccessor;
@ -101,31 +100,13 @@ public class SynthLookAndFeel extends BasicLookAndFeel {
static final Insets EMPTY_UIRESOURCE_INSETS = new InsetsUIResource(
0, 0, 0, 0);
/**
* AppContext key to get the current SynthStyleFactory.
*/
private static final Object STYLE_FACTORY_KEY =
new StringBuffer("com.sun.java.swing.plaf.gtk.StyleCache");
private static ComponentUI selectedUI;
private static int selectedUIStateValue;
/**
* AppContext key to get selectedUI.
*/
private static final Object SELECTED_UI_KEY = new StringBuilder("selectedUI");
/**
* AppContext key to get selectedUIState.
*/
private static final Object SELECTED_UI_STATE_KEY = new StringBuilder("selectedUIState");
/**
* The last SynthStyleFactory that was asked for from AppContext
* <code>lastContext</code>.
* The last SynthStyleFactory that was set.
*/
private static SynthStyleFactory lastFactory;
/**
* AppContext lastLAF came from.
*/
private static AppContext lastContext;
/**
* SynthStyleFactory for the this SynthLookAndFeel.
@ -141,7 +122,7 @@ public class SynthLookAndFeel extends BasicLookAndFeel {
private Handler _handler;
static ComponentUI getSelectedUI() {
return (ComponentUI) AppContext.getAppContext().get(SELECTED_UI_KEY);
return selectedUI;
}
/**
@ -182,23 +163,20 @@ public class SynthLookAndFeel extends BasicLookAndFeel {
}
}
AppContext context = AppContext.getAppContext();
context.put(SELECTED_UI_KEY, uix);
context.put(SELECTED_UI_STATE_KEY, Integer.valueOf(selectedUIState));
selectedUI = uix;
selectedUIStateValue = selectedUIState;
}
static int getSelectedUIState() {
Integer result = (Integer) AppContext.getAppContext().get(SELECTED_UI_STATE_KEY);
return result == null ? 0 : result.intValue();
return selectedUIStateValue;
}
/**
* Clears out the selected UI that was last set in setSelectedUI.
*/
static void resetSelectedUI() {
AppContext.getAppContext().remove(SELECTED_UI_KEY);
selectedUI = null;
selectedUIStateValue = 0;
}
@ -210,12 +188,8 @@ public class SynthLookAndFeel extends BasicLookAndFeel {
*/
public static void setStyleFactory(SynthStyleFactory cache) {
// We assume the setter is called BEFORE the getter has been invoked
// for a particular AppContext.
synchronized(SynthLookAndFeel.class) {
AppContext context = AppContext.getAppContext();
lastFactory = cache;
lastContext = context;
context.put(STYLE_FACTORY_KEY, cache);
}
}
@ -226,13 +200,6 @@ public class SynthLookAndFeel extends BasicLookAndFeel {
*/
public static SynthStyleFactory getStyleFactory() {
synchronized(SynthLookAndFeel.class) {
AppContext context = AppContext.getAppContext();
if (lastContext == context) {
return lastFactory;
}
lastContext = context;
lastFactory = (SynthStyleFactory) context.get(STYLE_FACTORY_KEY);
return lastFactory;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -248,8 +248,8 @@ public class JlinkTask {
* Read the release.txt from the module.
*/
private static Optional<String> getReleaseInfo(ModuleReference mref) {
try {
Optional<InputStream> release = mref.open().open(JDK_RELEASE_RESOURCE);
try (var moduleReader = mref.open()) {
Optional<InputStream> release = moduleReader.open(JDK_RELEASE_RESOURCE);
if (release.isEmpty()) {
return Optional.empty();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -21,6 +21,7 @@
* questions.
*/
#include "cds/aotGrowableArray.inline.hpp"
#include "memory/allocation.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/metaspaceClosure.hpp"
@ -58,7 +59,7 @@ public:
class MyUniqueMetaspaceClosure : public MetaspaceClosure {
static constexpr int SIZE = 10;
MyMetaData* _visited[SIZE];
void* _visited[SIZE];
int _count;
public:
MyUniqueMetaspaceClosure() {
@ -71,11 +72,22 @@ public:
virtual bool do_ref(Ref* ref, bool read_only) {
MyMetaData* ptr = (MyMetaData*)ref->obj();
assert(_count < SIZE, "out of bounds");
_visited[_count++] = ptr;
for (int i = 0; i < _count; i++) {
if (_visited[i] == (void*)ptr) {
// We have walked this before.
return false;
}
}
// Found a new pointer. Let's walk it
_visited[_count++] = (void*)ptr;
return true; // recurse
}
bool has_visited(MyMetaData* p) {
return has_visited((void*)p);
}
bool has_visited(void* p) {
for (int i = 0; i < SIZE; i++) {
if (_visited[i] == p) {
return true;
@ -83,6 +95,9 @@ public:
}
return false;
}
int visited_count() {
return _count;
}
};
// iterate an Array<MyMetaData*>
@ -104,7 +119,9 @@ TEST_VM(MetaspaceClosure, MSOPointerArrayRef) {
MyUniqueMetaspaceClosure closure;
closure.push(&array);
closure.finish();
EXPECT_TRUE(closure.has_visited(array)) << "must be";
EXPECT_TRUE(closure.has_visited(&x)) << "must be";
EXPECT_TRUE(closure.has_visited(&y)) << "must be";
EXPECT_TRUE(closure.has_visited(&z)) << "must be";
@ -130,8 +147,85 @@ TEST_VM(MetaspaceClosure, MSOArrayRef) {
MyUniqueMetaspaceClosure closure;
closure.push(&array);
closure.finish();
EXPECT_TRUE(closure.has_visited(array)) << "must be";
EXPECT_TRUE(closure.has_visited(&x)) << "must be";
EXPECT_TRUE(closure.has_visited(&y)) << "must be";
EXPECT_TRUE(closure.has_visited(&z)) << "must be";
}
// iterate an Array<int>
TEST_VM(MetaspaceClosure, OtherArrayRef) {
JavaThread* THREAD = JavaThread::current();
ClassLoaderData* cld = ClassLoaderData::the_null_class_loader_data();
Array<int>* array = MetadataFactory::new_array<int>(cld, 4, THREAD);
MyUniqueMetaspaceClosure closure;
closure.push(&array);
closure.finish();
EXPECT_TRUE(closure.has_visited(array)) << "must be";
}
// iterate an AOTGrowableArray<MyMetaData*>
TEST_VM(MetaspaceClosure, GrowableArray_MSOPointer) {
AOTGrowableArray<MyMetaData*>* array = new(mtClass) AOTGrowableArray<MyMetaData*>(2, mtClass);
MyMetaData x;
MyMetaData y;
MyMetaData z;
array->push(&x);
array->push(&y);
y._a = &z;
MyUniqueMetaspaceClosure closure;
closure.push(&array);
closure.finish();
EXPECT_TRUE(closure.has_visited(array)) << "must be";
EXPECT_TRUE(closure.has_visited(&x)) << "must be";
EXPECT_TRUE(closure.has_visited(&y)) << "must be";
EXPECT_TRUE(closure.has_visited(&z)) << "must be";
}
// iterate an AOTGrowableArray<MyMetaData>
TEST_VM(MetaspaceClosure, GrowableArray_MSO) {
AOTGrowableArray<MyMetaData>* array = new(mtClass) AOTGrowableArray<MyMetaData>(4, mtClass);
for (int i = 0; i < array->length(); i++) {
EXPECT_TRUE(array->at(i)._a == nullptr) << "should be initialized to null";
EXPECT_TRUE(array->at(i)._b == nullptr) << "should be initialized to null";
}
MyMetaData x;
MyMetaData y;
MyMetaData z;
z._a = &x;
z._b = &y;
y._a = &z;
array->push(z);
MyUniqueMetaspaceClosure closure;
closure.push(&array);
closure.finish();
EXPECT_TRUE(closure.has_visited(array)) << "must be";
EXPECT_TRUE(closure.has_visited(&x)) << "must be";
EXPECT_TRUE(closure.has_visited(&y)) << "must be";
EXPECT_TRUE(closure.has_visited(&z)) << "must be";
}
// iterate an AOTGrowableArray<jlong>
TEST_VM(MetaspaceClosure, GrowableArray_jlong) {
AOTGrowableArray<jlong>* array = new(mtClass) AOTGrowableArray<jlong>(4, mtClass);
MyUniqueMetaspaceClosure closure;
closure.push(&array);
closure.finish();
EXPECT_TRUE(closure.has_visited(array)) << "must be";
EXPECT_TRUE(closure.visited_count() == 2) << "must visit buffer inside GrowableArray";
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) 2025, 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.
*/
package compiler.corelibs;
import java.util.Optional;
import compiler.lib.ir_framework.Check;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.IRNode;
import compiler.lib.ir_framework.Test;
import compiler.lib.ir_framework.TestFramework;
/*
* @test
* @bug 8372696
* @summary Verify constant folding for Optional, both present and absent
* @library /test/lib /
* @run driver ${test.main.class}
*/
public class OptionalFold {
public static void main(String[] args) {
// Somehow fails with -XX:-TieredCompilation
TestFramework.runWithFlags("-XX:+TieredCompilation");
}
// Ensure both present and empty values can fold
static final Optional<Integer> ONE = Optional.of(5), TWO = Optional.empty();
@Test
@IR(failOn = {IRNode.ADD_I})
public int testSum() {
return ONE.orElse(7) + TWO.orElse(12);
}
@Check(test = "testSum")
public void checkTestSum(int res) {
if (res != 5 + 12) {
throw new RuntimeException("incorrect result: " + res);
}
}
}

View File

@ -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
@ -161,7 +161,7 @@ public enum CompilePhase {
static {
for (CompilePhase phase : CompilePhase.values()) {
if (phase == PRINT_IDEAL) {
PHASES_BY_PARSED_NAME.put("print_ideal", phase);
PHASES_BY_PARSED_NAME.put("PrintIdeal", phase);
} else {
PHASES_BY_PARSED_NAME.put(phase.name(), phase);
}

View File

@ -183,7 +183,7 @@ public class TestFramework {
private List<String> flags;
private int defaultWarmup = -1;
private boolean testClassesOnBootClassPath;
private boolean isAllowNotCompilable = false;
private boolean allowNotCompilable = false;
/*
* Public interface methods
@ -498,7 +498,7 @@ public class TestFramework {
* and else it is ignored silently.
*/
public TestFramework allowNotCompilable() {
this.isAllowNotCompilable = true;
this.allowNotCompilable = true;
return this;
}
@ -721,7 +721,7 @@ public class TestFramework {
nonWhiteListedFlags.forEach((f) -> System.out.println(" - " + f));
}
System.out.println("");
System.out.println();
}
/**
@ -860,8 +860,8 @@ public class TestFramework {
private List<String> anyNonWhitelistedJTregVMAndJavaOptsFlags() {
List<String> flags = Arrays.stream(Utils.getTestJavaOpts())
.map(s -> s.replaceFirst("-XX:[+|-]?|-(?=[^D|^e])", ""))
.collect(Collectors.toList());
List<String> nonWhiteListedFlags = new ArrayList();
.toList();
List<String> nonWhiteListedFlags = new ArrayList<>();
for (String flag : flags) {
if (flag.contains("agentpath")) {
throw new SkippedException("Can't run test with -javaagent");
@ -877,10 +877,10 @@ public class TestFramework {
private void runTestVM(List<String> additionalFlags) {
TestVMProcess testVMProcess = new TestVMProcess(additionalFlags, testClass, helperClasses, defaultWarmup,
isAllowNotCompilable, testClassesOnBootClassPath);
allowNotCompilable, testClassesOnBootClassPath);
if (shouldVerifyIR) {
try {
TestClassParser testClassParser = new TestClassParser(testClass, isAllowNotCompilable);
TestClassParser testClassParser = new TestClassParser(testClass, allowNotCompilable);
Matchable testClassMatchable = testClassParser.parse(testVMProcess.getHotspotPidFileName(),
testVMProcess.getApplicableIRRules());
IRMatcher matcher = new IRMatcher(testClassMatchable);

View File

@ -38,7 +38,6 @@ import java.io.File;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* This class prepares, creates, and runs the Test VM with verification of proper termination. The class also stores
@ -108,7 +107,7 @@ public class TestVMProcess {
cmds.add("-XX:+UnlockDiagnosticVMOptions");
cmds.add("-XX:+WhiteBoxAPI");
// Ignore CompileCommand flags which have an impact on the profiling information.
List<String> jtregVMFlags = Arrays.stream(Utils.getTestJavaOpts()).filter(s -> !s.contains("CompileThreshold")).collect(Collectors.toList());
List<String> jtregVMFlags = Arrays.stream(Utils.getTestJavaOpts()).filter(s -> !s.contains("CompileThreshold")).toList();
if (!PREFER_COMMAND_LINE_FLAGS) {
cmds.addAll(jtregVMFlags);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -32,6 +32,7 @@ import compiler.lib.ir_framework.driver.irmatching.Matchable;
import compiler.lib.ir_framework.driver.irmatching.MatchableMatcher;
import compiler.lib.ir_framework.driver.irmatching.irrule.IRRule;
import compiler.lib.ir_framework.driver.irmatching.parser.VMInfo;
import compiler.lib.ir_framework.driver.network.testvm.java.IRRuleIds;
import compiler.lib.ir_framework.shared.TestFormat;
import compiler.lib.ir_framework.shared.TestFormatException;
@ -53,14 +54,14 @@ public class IRMethod implements IRMethodMatchable {
private final Method method;
private final MatchableMatcher matcher;
public IRMethod(Method method, int[] ruleIds, IR[] irAnnos, Compilation compilation, VMInfo vmInfo) {
public IRMethod(Method method, IRRuleIds irRuleIds, IR[] irAnnos, Compilation compilation, VMInfo vmInfo) {
this.method = method;
this.matcher = new MatchableMatcher(createIRRules(method, ruleIds, irAnnos, compilation, vmInfo));
this.matcher = new MatchableMatcher(createIRRules(method, irRuleIds, irAnnos, compilation, vmInfo));
}
private List<Matchable> createIRRules(Method method, int[] ruleIds, IR[] irAnnos, Compilation compilation, VMInfo vmInfo) {
private List<Matchable> createIRRules(Method method, IRRuleIds irRuleIds, IR[] irAnnos, Compilation compilation, VMInfo vmInfo) {
List<Matchable> irRules = new ArrayList<>();
for (int ruleId : ruleIds) {
for (int ruleId : irRuleIds) {
try {
irRules.add(new IRRule(ruleId, irAnnos[ruleId - 1], compilation, vmInfo));
} catch (TestFormatException e) {
@ -89,13 +90,12 @@ public class IRMethod implements IRMethodMatchable {
return new IRMethodMatchResult(method, matcher.match());
}
List<MatchResult> match;
for (int i = 0; i < 10; i++) { // warm up
match = matcher.match();
matcher.match();
}
long startTime = System.nanoTime();
match = matcher.match();
List<MatchResult> match = matcher.match();
long endTime = System.nanoTime();
long duration = (endTime - startTime);
System.out.println("Verifying IR rules for " + name() + ": " + duration + " ns = " + (duration / 1000000) + " ms");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* 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
@ -24,8 +24,7 @@
package compiler.lib.ir_framework.driver.irmatching.irmethod;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.Run;
import compiler.lib.ir_framework.RunMode;
import compiler.lib.ir_framework.Test;
import java.lang.reflect.Method;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* 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
@ -23,8 +23,7 @@
package compiler.lib.ir_framework.driver.irmatching.irmethod;
import compiler.lib.ir_framework.Run;
import compiler.lib.ir_framework.RunMode;
import compiler.lib.ir_framework.Test;
import compiler.lib.ir_framework.driver.irmatching.MatchResult;
import compiler.lib.ir_framework.driver.irmatching.visitor.MatchResultVisitor;

View File

@ -26,12 +26,15 @@ package compiler.lib.ir_framework.driver.irmatching.parser;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.TestFramework;
import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.HotSpotPidFileParser;
import compiler.lib.ir_framework.driver.network.testvm.java.IRRuleIds;
import compiler.lib.ir_framework.shared.TestFormat;
import compiler.lib.ir_framework.shared.TestFrameworkException;
import compiler.lib.ir_framework.test.ApplicableIRRulesPrinter;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -75,15 +78,15 @@ public class ApplicableIRRulesParser {
* assembly output in {@link HotSpotPidFileParser}.
*/
private void createTestMethodMap(String applicableIRRules, Class<?> testClass) {
Map<String, int[]> irRulesMap = parseApplicableIRRules(applicableIRRules);
Map<String, IRRuleIds> irRulesMap = parseApplicableIRRules(applicableIRRules);
createTestMethodsWithApplicableIRRules(testClass, irRulesMap);
}
/**
* Read the Applicable IR Rules emitted by the Test VM to decide if an @IR rule must be checked for a method.
*/
private Map<String, int[]> parseApplicableIRRules(String applicableIRRules) {
Map<String, int[]> irRulesMap = new HashMap<>();
private Map<String, IRRuleIds> parseApplicableIRRules(String applicableIRRules) {
Map<String, IRRuleIds> irRulesMap = new HashMap<>();
String[] applicableIRRulesLines = getApplicableIRRulesLines(applicableIRRules);
for (String s : applicableIRRulesLines) {
String line = s.trim();
@ -92,8 +95,8 @@ public class ApplicableIRRulesParser {
throw new TestFrameworkException("Invalid Applicable IR Rules format. No comma found: " + splitLine[0]);
}
String testName = splitLine[0];
int[] irRulesIdx = getRuleIndexes(splitLine);
irRulesMap.put(testName, irRulesIdx);
IRRuleIds irRuleIds = parseIrRulesIds(splitLine);
irRulesMap.put(testName, irRuleIds);
}
return irRulesMap;
}
@ -116,24 +119,24 @@ public class ApplicableIRRulesParser {
/**
* Parse rule indexes from a single line of the Applicable IR Rules in the format: <method,idx1,idx2,...>
*/
private int[] getRuleIndexes(String[] splitLine) {
int[] irRulesIdx = new int[splitLine.length - 1];
private IRRuleIds parseIrRulesIds(String[] splitLine) {
List<Integer> irRuleIds = new ArrayList<>();
for (int i = 1; i < splitLine.length; i++) {
try {
irRulesIdx[i - 1] = Integer.parseInt(splitLine[i]);
irRuleIds.add(Integer.parseInt(splitLine[i]));
} catch (NumberFormatException e) {
throw new TestFrameworkException("Invalid Applicable IR Rules format. No number found: " + splitLine[i]);
}
}
return irRulesIdx;
return new IRRuleIds(irRuleIds);
}
private void createTestMethodsWithApplicableIRRules(Class<?> testClass, Map<String, int[]> irRulesMap) {
private void createTestMethodsWithApplicableIRRules(Class<?> testClass, Map<String, IRRuleIds> irRulesMap) {
for (Method m : testClass.getDeclaredMethods()) {
IR[] irAnnos = m.getAnnotationsByType(IR.class);
if (irAnnos.length > 0) {
// Validation of legal @IR attributes and placement of the annotation was already done in Test VM.
int[] irRuleIds = irRulesMap.get(m.getName());
IRRuleIds irRuleIds = irRulesMap.get(m.getName());
validateIRRuleIds(m, irAnnos, irRuleIds);
if (hasAnyApplicableIRRules(irRuleIds)) {
testMethods.put(m.getName(), new TestMethod(m, irAnnos, irRuleIds));
@ -142,18 +145,18 @@ public class ApplicableIRRulesParser {
}
}
private void validateIRRuleIds(Method m, IR[] irAnnos, int[] ids) {
TestFramework.check(ids != null, "Should find method name in validIrRulesMap for " + m);
TestFramework.check(ids.length > 0, "Did not find any rule indices for " + m);
TestFramework.check((ids[0] >= 1 || ids[0] == ApplicableIRRulesPrinter.NO_RULE_APPLIED)
&& ids[ids.length - 1] <= irAnnos.length,
private void validateIRRuleIds(Method m, IR[] irAnnos, IRRuleIds irRuleIds) {
TestFramework.check(irRuleIds != null, "Should find method name in validIrRulesMap for " + m);
TestFramework.check(!irRuleIds.isEmpty(), "Did not find any rule indices for " + m);
TestFramework.check((irRuleIds.first() >= 1 || irRuleIds.first() == ApplicableIRRulesPrinter.NO_RULE_APPLIED)
&& irRuleIds.last() <= irAnnos.length,
"Invalid IR rule index found in validIrRulesMap for " + m);
}
/**
* Does the list of IR rules contain any applicable IR rules for the given conditions?
*/
private boolean hasAnyApplicableIRRules(int[] irRuleIds) {
return irRuleIds[0] != ApplicableIRRulesPrinter.NO_RULE_APPLIED;
private boolean hasAnyApplicableIRRules(IRRuleIds irRuleIds) {
return irRuleIds.first() != ApplicableIRRulesPrinter.NO_RULE_APPLIED;
}
}

View File

@ -71,9 +71,9 @@ class IRMethodBuilder {
Test[] testAnnos = testMethod.method().getAnnotationsByType(Test.class);
boolean allowMethodNotCompilable = allowNotCompilable || testAnnos[0].allowNotCompilable();
if (allowMethodNotCompilable) {
return new NotCompilableIRMethod(testMethod.method(), testMethod.irRuleIds().length);
return new NotCompilableIRMethod(testMethod.method(), testMethod.irRuleIds().count());
} else {
return new NotCompiledIRMethod(testMethod.method(), testMethod.irRuleIds().length);
return new NotCompiledIRMethod(testMethod.method(), testMethod.irRuleIds().count());
}
}
}

View File

@ -26,6 +26,7 @@ package compiler.lib.ir_framework.driver.irmatching.parser;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod;
import compiler.lib.ir_framework.driver.irmatching.parser.hotspot.LoggedMethod;
import compiler.lib.ir_framework.driver.network.testvm.java.IRRuleIds;
import java.lang.reflect.Method;
@ -40,9 +41,9 @@ import java.lang.reflect.Method;
public class TestMethod {
private final Method method;
private final IR[] irAnnos;
private final int[] irRuleIds;
private final IRRuleIds irRuleIds;
public TestMethod(Method m, IR[] irAnnos, int[] irRuleIds) {
public TestMethod(Method m, IR[] irAnnos, IRRuleIds irRuleIds) {
this.method = m;
this.irAnnos = irAnnos;
this.irRuleIds = irRuleIds;
@ -56,7 +57,7 @@ public class TestMethod {
return irAnnos;
}
public int[] irRuleIds() {
public IRRuleIds irRuleIds() {
return irRuleIds;
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright (c) 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.
*/
package compiler.lib.ir_framework.driver.network.testvm.java;
import compiler.lib.ir_framework.IR;
import compiler.lib.ir_framework.driver.irmatching.irmethod.IRMethod;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;
/**
* Class to hold the indices of the applicable {@link IR @IR} rules of an {@link IRMethod}.
*/
public class IRRuleIds implements Iterable<Integer> {
private final List<Integer> ruleIds;
public IRRuleIds(List<Integer> ruleIds) {
this.ruleIds = ruleIds;
}
public int first() {
return ruleIds.getFirst();
}
public int last() {
return ruleIds.getLast();
}
public boolean isEmpty() {
return ruleIds.isEmpty();
}
public int count() {
return ruleIds.size();
}
@Override
public Iterator<Integer> iterator() {
return ruleIds.iterator();
}
public Stream<Integer> stream() {
return ruleIds.stream();
}
}

View File

@ -92,7 +92,7 @@ public class TestVM {
static final boolean XCOMP = Platform.isComp();
static final boolean VERBOSE = Boolean.getBoolean("Verbose");
private static final boolean PRINT_TIMES = Boolean.getBoolean("PrintTimes");
private static final boolean PRINT_TIMES = Boolean.getBoolean("PrintTimes") || VERBOSE;
public static final boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
static final boolean EXCLUDE_RANDOM = Boolean.getBoolean("ExcludeRandom");
private static final String TESTLIST = System.getProperty("Test", "");
@ -823,14 +823,14 @@ public class TestVM {
forceCompileMap.forEach((key, value) -> builder.append("- ").append(key).append(" at CompLevel.").append(value)
.append(System.lineSeparator()));
throw new TestRunException("Could not force compile the following @ForceCompile methods:"
+ System.lineSeparator() + builder.toString());
+ System.lineSeparator() + builder);
}
/**
* Once all framework tests are collected, they are run in this method.
*/
private void runTests() {
TreeMap<Long, String> durations = (PRINT_TIMES || VERBOSE) ? new TreeMap<>() : null;
TreeMap<Long, String> durations = PRINT_TIMES ? new TreeMap<>() : null;
long startTime = System.nanoTime();
List<AbstractTest> testList;
boolean testFilterPresent = testFilterPresent();
@ -867,11 +867,11 @@ public class TestVM {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
builder.append(test.toString()).append(":").append(System.lineSeparator()).append(sw.toString())
builder.append(test).append(":").append(System.lineSeparator()).append(sw)
.append(System.lineSeparator()).append(System.lineSeparator());
failures++;
}
if (PRINT_TIMES || VERBOSE) {
if (PRINT_TIMES) {
long endTime = System.nanoTime();
long duration = (endTime - startTime);
durations.put(duration, test.getName());
@ -886,7 +886,7 @@ public class TestVM {
}
// Print execution times
if (VERBOSE || PRINT_TIMES) {
if (PRINT_TIMES) {
TestFrameworkSocket.write("Test execution times:", PRINT_TIMES_TAG, true);
for (Map.Entry<Long, String> entry : durations.entrySet()) {
TestFrameworkSocket.write(String.format("%-25s%15d ns%n", entry.getValue() + ":", entry.getKey()),
@ -898,7 +898,7 @@ public class TestVM {
// Finally, report all occurred exceptions in a nice format.
String msg = System.lineSeparator() + System.lineSeparator() + "Test Failures (" + failures + ")"
+ System.lineSeparator() + "----------------" + "-".repeat(String.valueOf(failures).length());
throw new TestRunException(msg + System.lineSeparator() + builder.toString());
throw new TestRunException(msg + System.lineSeparator() + builder);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -180,6 +180,12 @@ class BadIRAndRuntimeCheckedTests {
throw new BadCheckedTestException("expected");
}
}
static class BadCheckedTestException extends RuntimeException {
BadCheckedTestException(String s) {
super(s);
}
}
}
class BadIRCheckedTests {
@ -224,9 +230,3 @@ class BadIRCheckedTests {
}
}
}
class BadCheckedTestException extends RuntimeException {
BadCheckedTestException(String s) {
super(s);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, 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
@ -25,7 +25,6 @@ package ir_framework.tests;
import compiler.lib.ir_framework.*;
import compiler.lib.ir_framework.driver.TestVMException;
import compiler.lib.ir_framework.shared.TestRunException;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
@ -360,10 +359,11 @@ class TestSetupTestsWithExpectedExceptions {
public void checkThrowInCheck(int x) {
throw new BadCheckedTestException("expected check");
}
}
class BadCheckedTestException extends RuntimeException {
BadCheckedTestException(String s) {
super(s);
static class BadCheckedTestException extends RuntimeException {
BadCheckedTestException(String s) {
super(s);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
@ -50,8 +50,8 @@ public final class bug4966171 {
}
private static void test() {
// Will run the test no more than 10 seconds per L&F
long endtime = System.nanoTime() + TimeUnit.SECONDS.toNanos(10);
// Will run the test no more than 5 seconds per L&F
long endtime = System.nanoTime() + TimeUnit.SECONDS.toNanos(5);
while (System.nanoTime() < endtime) {
try {
var byteOut = new ByteArrayOutputStream();

View File

@ -1,99 +0,0 @@
/*
* Copyright (c) 2012, 2015, 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 7143614
* @summary Issues with Synth Look&Feel
* @author Pavel Porvatov
* @modules java.desktop/javax.swing.plaf.synth:open
* @modules java.desktop/sun.awt
*/
import sun.awt.SunToolkit;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicButtonUI;
import javax.swing.plaf.synth.SynthConstants;
import javax.swing.plaf.synth.SynthLookAndFeel;
import java.lang.reflect.Method;
public class bug7143614 {
private static Method setSelectedUIMethod;
private static ComponentUI componentUI = new BasicButtonUI();
public static void main(String[] args) throws Exception {
setSelectedUIMethod = SynthLookAndFeel.class.getDeclaredMethod("setSelectedUI", ComponentUI.class,
boolean.class, boolean.class, boolean.class, boolean.class);
setSelectedUIMethod.setAccessible(true);
setSelectedUIMethod.invoke(null, componentUI, true, true, true, true);
validate();
Thread thread = new ThreadInAnotherAppContext();
thread.start();
thread.join();
validate();
System.out.println("Test bug7143614 passed.");
}
private static void validate() throws Exception {
Method getSelectedUIMethod = SynthLookAndFeel.class.getDeclaredMethod("getSelectedUI");
getSelectedUIMethod.setAccessible(true);
Method getSelectedUIStateMethod = SynthLookAndFeel.class.getDeclaredMethod("getSelectedUIState");
getSelectedUIStateMethod.setAccessible(true);
if (getSelectedUIMethod.invoke(null) != componentUI) {
throw new RuntimeException("getSelectedUI returns invalid value");
}
if (((Integer) getSelectedUIStateMethod.invoke(null)).intValue() !=
(SynthConstants.SELECTED | SynthConstants.FOCUSED)) {
throw new RuntimeException("getSelectedUIState returns invalid value");
}
}
private static class ThreadInAnotherAppContext extends Thread {
public ThreadInAnotherAppContext() {
super(new ThreadGroup("7143614"), "ThreadInAnotherAppContext");
}
public void run() {
SunToolkit.createNewAppContext();
try {
setSelectedUIMethod.invoke(null, null, false, false, false, false);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}

View File

@ -1,125 +0,0 @@
/*
* Copyright (c) 2009, 2016, 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
* @key headful
* @bug 6660049 6849518
* @summary Tests the Region initialization
* @author Sergey Malenkov
* @modules java.desktop/sun.awt
*/
import sun.awt.SunToolkit;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import javax.swing.plaf.synth.Region;
import javax.swing.plaf.synth.SynthLookAndFeel;
public class Test6660049 implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Test6660049(
javax.swing.JButton.class,
javax.swing.JCheckBox.class,
javax.swing.JCheckBoxMenuItem.class,
javax.swing.JColorChooser.class,
javax.swing.JComboBox.class,
javax.swing.JDesktopPane.class,
javax.swing.JEditorPane.class,
javax.swing.JFileChooser.class,
javax.swing.JFormattedTextField.class,
javax.swing.JInternalFrame.class,
javax.swing.JLabel.class,
javax.swing.JList.class,
javax.swing.JMenu.class,
javax.swing.JMenuBar.class,
javax.swing.JMenuItem.class,
javax.swing.JOptionPane.class,
javax.swing.JPanel.class,
javax.swing.JPasswordField.class,
javax.swing.JPopupMenu.class,
javax.swing.JProgressBar.class,
javax.swing.JRadioButton.class,
javax.swing.JRadioButtonMenuItem.class,
javax.swing.JRootPane.class,
javax.swing.JScrollBar.class,
javax.swing.JScrollPane.class,
javax.swing.JSeparator.class,
javax.swing.JSlider.class,
javax.swing.JSpinner.class,
javax.swing.JSplitPane.class,
javax.swing.JTabbedPane.class,
javax.swing.JTable.class,
javax.swing.JTextArea.class,
javax.swing.JTextField.class,
javax.swing.JTextPane.class,
javax.swing.JToggleButton.class,
javax.swing.JToolBar.class,
javax.swing.JToolTip.class,
javax.swing.JTree.class,
javax.swing.JViewport.class,
javax.swing.table.JTableHeader.class));
}
private final Class<? extends JComponent>[] types;
private final Region region;
private Test6660049(Class<? extends JComponent>... types) {
this.types = types;
run();
this.region = new Region("Button", "ButtonUI", true) {
@Override
public String getName() {
throw new Error("6660049: exploit is available");
}
};
}
public void run() {
if (this.region != null) {
SunToolkit.createNewAppContext();
}
for (Class<? extends JComponent> type : this.types) {
Region region = getRegion(type);
if (region == null) {
throw new Error("6849518: region is not initialized");
}
}
getRegion(JButton.class).getName();
}
private static Region getRegion(Class<? extends JComponent> type) {
try {
return SynthLookAndFeel.getRegion(type.newInstance());
}
catch (IllegalAccessException exception) {
throw new Error("unexpected exception", exception);
}
catch (InstantiationException exception) {
throw new Error("unexpected exception", exception);
}
}
}