mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-14 18:03:44 +00:00
merge latest from master branch
This commit is contained in:
commit
b57b088ec9
34
src/hotspot/share/cds/aotGrowableArray.cpp
Normal file
34
src/hotspot/share/cds/aotGrowableArray.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
76
src/hotspot/share/cds/aotGrowableArray.hpp
Normal file
76
src/hotspot/share/cds/aotGrowableArray.hpp
Normal 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
|
||||
37
src/hotspot/share/cds/aotGrowableArray.inline.hpp
Normal file
37
src/hotspot/share/cds/aotGrowableArray.inline.hpp
Normal 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
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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; }
|
||||
};
|
||||
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
@ -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;") \
|
||||
|
||||
@ -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]);
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
46
src/hotspot/share/memory/metaspaceClosureType.hpp
Normal file
46
src/hotspot/share/memory/metaspaceClosureType.hpp
Normal 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
|
||||
@ -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++) {
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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; }
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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 {
|
||||
}
|
||||
@ -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.
|
||||
*/
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -25,8 +25,6 @@
|
||||
|
||||
package javax.swing.plaf.synth;
|
||||
|
||||
import sun.awt.AppContext;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.beans.*;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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";
|
||||
}
|
||||
|
||||
64
test/hotspot/jtreg/compiler/corelibs/OptionalFold.java
Normal file
64
test/hotspot/jtreg/compiler/corelibs/OptionalFold.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user