diff --git a/src/hotspot/share/memory/metaspaceClosure.hpp b/src/hotspot/share/memory/metaspaceClosure.hpp index ac42dd13c6c..20e5528e9bc 100644 --- a/src/hotspot/share/memory/metaspaceClosure.hpp +++ b/src/hotspot/share/memory/metaspaceClosure.hpp @@ -37,19 +37,6 @@ #include "utilities/macros.hpp" #include "utilities/resizableHashTable.hpp" -// 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::value - -template -class HasMetaspacePointersDo { - template static void* test(decltype(&U::metaspace_pointers_do)); - template static int test(...); - using test_type = decltype(test(nullptr)); -public: - static constexpr bool value = std::is_pointer_v; -}; - // class MetaspaceClosure -- // // This class is used for iterating the class metadata objects. It @@ -98,7 +85,6 @@ public: // only in the Metadata class. // // To work around the lack of a vtable, we use the Ref class with templates - // (see MSORef, OtherArrayRef, MSOArrayRef, and MSOPointerArrayRef) // so that we can statically discover the type of a object. The use of Ref // depends on the fact that: // @@ -194,15 +180,6 @@ private: 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 MSORef : public Ref { T** _mpp; @@ -210,99 +187,22 @@ private: return strip_tags(*_mpp); } protected: - virtual void** mpp() const { + virtual void** mpp() const override { return (void**)_mpp; } public: MSORef(T** mpp, Writability w) : Ref(w), _mpp(mpp) {} - 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 get_size(dereference()); } - virtual MetaspaceClosureType type() const { return as_type(dereference()->type()); } - - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { + virtual bool is_read_only_by_default() const override { return T::is_read_only_by_default(); } + virtual bool not_null() const override { return dereference() != nullptr; } + virtual int size() const override { return get_size(dereference()); } + virtual MetaspaceClosureType type() const override { return as_type(dereference()->type()); } + virtual void metaspace_pointers_do(MetaspaceClosure *it) const override { dereference()->metaspace_pointers_do(it); } }; - //--------------------- - // Support for Array - //--------------------- - - // Abstract base class for MSOArrayRef, MSOPointerArrayRef and OtherArrayRef. - // These are used for iterating Array. - template class ArrayRef : public Ref { - Array** _mpp; - protected: - Array* dereference() const { - return strip_tags(*_mpp); - } - virtual void** mpp() const { - return (void**)_mpp; - } - - ArrayRef(Array** mpp, Writability w) : Ref(w), _mpp(mpp) {} - - // all Arrays are read-only by default - 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 MetaspaceClosureType type() const { return as_type(MetaspaceObj::array_type(sizeof(T))); } - }; - - // OtherArrayRef -- iterate an instance of Array, 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 OtherArrayRef : public ArrayRef { - public: - OtherArrayRef(Array** mpp, Writability w) : ArrayRef(mpp, w) {} - - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { - Array* array = ArrayRef::dereference(); - log_trace(aot)("Iter(OtherArray): %p [%d]", array, array->length()); - } - }; - - // MSOArrayRef -- iterate an instance of Array, where T has metaspace_pointer_do(). - // We recursively call T::metaspace_pointers_do() for each element in this array. - template class MSOArrayRef : public ArrayRef { - public: - MSOArrayRef(Array** mpp, Writability w) : ArrayRef(mpp, w) {} - - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { - metaspace_pointers_do_at_impl(it, ArrayRef::dereference()); - } - private: - void metaspace_pointers_do_at_impl(MetaspaceClosure *it, Array* array) const { - log_trace(aot)("Iter(MSOArray): %p [%d]", array, array->length()); - for (int i = 0; i < array->length(); i++) { - T* elm = array->adr_at(i); - elm->metaspace_pointers_do(it); - } - } - }; - - // MSOPointerArrayRef -- iterate an instance of Array, where T has metaspace_pointer_do(). - // We recursively call MetaspaceClosure::push() for each pointer in this array. - template class MSOPointerArrayRef : public ArrayRef { - public: - MSOPointerArrayRef(Array** mpp, Writability w) : ArrayRef(mpp, w) {} - - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { - metaspace_pointers_do_at_impl(it, ArrayRef::dereference()); - } - private: - void metaspace_pointers_do_at_impl(MetaspaceClosure *it, Array* array) const { - log_trace(aot)("Iter(MSOPointerArray): %p [%d]", array, array->length()); - for (int i = 0; i < array->length(); i++) { - T** mpp = array->adr_at(i); - it->push(mpp); - } - } - }; - //-------------------------------- // Support for GrowableArray //-------------------------------- @@ -314,28 +214,27 @@ private: return *_mpp; } - public: - GrowableArrayRef(GrowableArray** mpp, Writability w) : Ref(w), _mpp(mpp) {} - - virtual void** mpp() const { + protected: + virtual void** mpp() const override { return (void**)_mpp; } - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { + public: + GrowableArrayRef(GrowableArray** mpp, Writability w) : Ref(w), _mpp(mpp) {} + + virtual bool is_read_only_by_default() const override { return false; } + virtual bool not_null() const override { return dereference() != nullptr; } + virtual int size() const override { return (int)heap_word_size(sizeof(*dereference())); } + virtual MetaspaceClosureType type() const override { return MetaspaceClosureType::GrowableArrayType; } + virtual void metaspace_pointers_do(MetaspaceClosure *it) const override { GrowableArray* array = dereference(); log_trace(aot)("Iter(GrowableArray): %p [%d]", array, array->length()); array->assert_on_C_heap(); it->push_c_array(array->data_addr(), array->capacity()); } - - 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(sizeof(*dereference())); } - virtual MetaspaceClosureType type() const { return MetaspaceClosureType::GrowableArrayType; } }; - // Abstract base class for MSOCArrayRef, MSOPointerCArrayRef and OtherCArrayRef. - // These are used for iterating the buffer held by GrowableArray. + // For iterating the buffer held by GrowableArray. template class CArrayRef : public Ref { T** _mpp; int _num_elems; // Number of elements @@ -344,83 +243,57 @@ private: return _num_elems * sizeof(T); } - protected: - // C pointer arrays don't support tagged pointers. + // Gives you back the GrowableArray::_data T* dereference() const { return *_mpp; } - virtual void** mpp() const { - return (void**)_mpp; - } + int num_elems() const { return _num_elems; } + + protected: + virtual void** mpp() const override { + return (void**)_mpp; + } + 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 OtherCArrayRef : public CArrayRef { - public: - OtherCArrayRef(T** mpp, int num_elems, Writability w) : CArrayRef(mpp, num_elems, w) {} - - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { - T* array = CArrayRef::dereference(); - log_trace(aot)("Iter(OtherCArray): %p [%d]", array, CArrayRef::num_elems()); + virtual bool is_read_only_by_default() const override { return false; } + virtual bool not_null() const override { precond(dereference() != nullptr); return true; } + virtual int size() const override { return (int)heap_word_size(byte_size()); } + virtual MetaspaceClosureType type() const override { return MetaspaceClosureType::CArrayType; } + virtual void metaspace_pointers_do(MetaspaceClosure *it) const override { + metaspace_pointers_do_impl(it, dereference()); } - }; - // MSOCArrayRef -- 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 GrowableArray. - // - // 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 MSOCArrayRef : public CArrayRef { - public: - MSOCArrayRef(T** mpp, int num_elems, Writability w) : CArrayRef(mpp, num_elems, w) {} + private: + // E.g., GrowableArray + template ::value && !HAS_METASPACE_POINTERS_DO(U))> + void metaspace_pointers_do_impl(MetaspaceClosure* it, T* array) const { + log_trace(aot)("Iter(OtherCArray): %p [%d]", array, num_elems()); + } - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { - T* array = CArrayRef::dereference(); - log_trace(aot)("Iter(MSOCArray): %p [%d]", array, CArrayRef::num_elems()); - for (int i = 0; i < CArrayRef::num_elems(); i++) { + // E.g., GrowableArray + template ::value && HAS_METASPACE_POINTERS_DO(U))> + void metaspace_pointers_do_impl(MetaspaceClosure* it, T* array) const { + log_trace(aot)("Iter(MSOCArray): %p [%d]", array, num_elems()); + for (int i = 0; i < num_elems(); i++) { T* elm = array + i; elm->metaspace_pointers_do(it); } } - }; - // MSOPointerCArrayRef -- 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 GrowableArray. - // - // 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 MSOPointerCArrayRef : public CArrayRef { - public: - MSOPointerCArrayRef(T*** mpp, int num_elems, Writability w) : CArrayRef(mpp, num_elems, w) {} - - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { - T** array = CArrayRef::dereference(); - log_trace(aot)("Iter(MSOPointerCArray): %p [%d]", array, CArrayRef::num_elems()); - for (int i = 0; i < CArrayRef::num_elems(); i++) { - T** mpp = array + i; + // E.g., GrowableArray + template ::value && HAS_METASPACE_POINTERS_DO(typename std::remove_pointer::type))> + void metaspace_pointers_do_impl(MetaspaceClosure* it, T* array) const { + log_trace(aot)("Iter(MSOPointerCArray): %p [%d]", array, num_elems()); + for (int i = 0; i < num_elems(); i++) { + T* mpp = array + i; it->push(mpp); } } @@ -462,17 +335,12 @@ public: // // MetaspaceClosure* it = ...; // Klass* o = ...; it->push(&o); => MSORef - // Array* a1 = ...; it->push(&a1); => OtherArrayRef - // Array* a2 = ...; it->push(&a2); => MSOArrayRef - // Array* a3 = ...; it->push(&a3); => MSOPointerArrayRef - // Array*>* a4 = ...; it->push(&a4); => MSOPointerArrayRef - // Array* a5 = ...; it->push(&a5); => MSOPointerArrayRef // // GrowableArrays have a separate "C array" buffer, so they are scanned in two steps: // - // GrowableArray* ga1 = ...; it->push(&ga1); => GrowableArrayRef => OtherCArrayRef - // GrowableArray* ga2 = ...; it->push(&ga2); => GrowableArrayRef => MSOCArrayRef - // GrowableArray* ga3 = ...; it->push(&ga3); => GrowableArrayRef => MSOPointerCArrayRef + // GrowableArray* ga1 = ...; it->push(&ga1); => GrowableArrayRef => CArrayRef + // GrowableArray* ga2 = ...; it->push(&ga2); => GrowableArrayRef => CArrayRef + // GrowableArray* ga3 = ...; it->push(&ga3); => GrowableArrayRef => CArrayRef // // Note that the following will fail to compile: // @@ -487,43 +355,15 @@ public: push_with_ref>(mpp, w); } - // --- Array - template - void push(Array** mpp, Writability w = _default) { - push_with_ref>(mpp, w); - } - - template - void push(Array** mpp, Writability w = _default) { - push_with_ref>(mpp, w); - } - - template - void push(Array** mpp, Writability w = _default) { - static_assert(HAS_METASPACE_POINTERS_DO(T), "Do not push Arrays of arbitrary pointer types"); - push_with_ref>(mpp, w); - } - template void push(GrowableArray** mpp, Writability w = _default) { push_with_ref>(mpp, w); } // --- The buffer of GrowableArray - template - void push_c_array(T** mpp, int num_elems, Writability w = _default) { - push_impl(new OtherCArrayRef(mpp, num_elems, w)); - } - - template - void push_c_array(T** mpp, int num_elems, Writability w = _default) { - push_impl(new MSOCArrayRef(mpp, num_elems, w)); - } - template - 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(mpp, num_elems, w)); + void push_c_array(T** mpp, int num_elems, Writability w = _default) { + push_impl(new CArrayRef(mpp, num_elems, w)); } }; diff --git a/src/hotspot/share/memory/metaspaceClosureType.hpp b/src/hotspot/share/memory/metaspaceClosureType.hpp index adf6805521b..2dbba34ab67 100644 --- a/src/hotspot/share/memory/metaspaceClosureType.hpp +++ b/src/hotspot/share/memory/metaspaceClosureType.hpp @@ -26,6 +26,7 @@ #define SHARE_MEMORY_METASPACECLOSURETYPE_HPP #include "memory/allocation.hpp" +#include "metaprogramming/enableIf.hpp" // MetaspaceClosure is able to iterate on MetaspaceObjs, plus the following classes #define METASPACE_CLOSURE_TYPES_DO(f) \ @@ -42,5 +43,29 @@ enum class MetaspaceClosureType : int { _number_of_types }; +inline MetaspaceClosureType as_type(MetaspaceClosureType t) { + return t; +} + +inline MetaspaceClosureType as_type(MetaspaceObj::Type msotype) { + precond(msotype < MetaspaceObj::_number_of_types); + return (MetaspaceClosureType)msotype; +} + +// This macro checks for the existence of a member with the name metaspace_pointers_do +#define HAS_METASPACE_POINTERS_DO(T) HasMetaspacePointersDo::value + +template +class HasMetaspacePointersDo { + template static void* test(decltype(&U::metaspace_pointers_do)); + template static int test(...); + + // - If the first template matches, test_type will be void* + // - If the first template doesn't match, test will match second template, + // and test_type will be int + using test_type = decltype(test(nullptr)); +public: + static constexpr bool value = std::is_pointer_v; +}; #endif // SHARE_MEMORY_METASPACECLOSURETYPE_HPP diff --git a/src/hotspot/share/oops/array.hpp b/src/hotspot/share/oops/array.hpp index 82067e007ea..0c720c85478 100644 --- a/src/hotspot/share/oops/array.hpp +++ b/src/hotspot/share/oops/array.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_OOPS_ARRAY_HPP #define SHARE_OOPS_ARRAY_HPP +#include "memory/metaspaceClosureType.hpp" #include "runtime/atomicAccess.hpp" #include "utilities/align.hpp" #include "utilities/exceptions.hpp" @@ -159,8 +160,48 @@ protected: st->print("Array(" PTR_FORMAT ")", p2i(this)); } - // This function does nothing. The iteration of the elements are done inside metaspaceClosure.hpp - void metaspace_pointers_do(MetaspaceClosure* it) {} + MetaspaceClosureType type() const { return as_type(MetaspaceObj::array_type(sizeof(T))); } + + static bool is_read_only_by_default() { + return is_read_only_by_default_impl(); + } + +private: + // Elements are neither pointers nor metadata objects => no need to relocate, so put the array + // in read-only region by default. + template ::value && !HAS_METASPACE_POINTERS_DO(U))> + static bool is_read_only_by_default_impl() { + return true; + } + + // The opposite of the above => the array may contain relocatable pointers, so put it + // in read-write region by default. + template ::value || HAS_METASPACE_POINTERS_DO(U))> + static bool is_read_only_by_default_impl() { + return false; + } + +public: + void metaspace_pointers_do(MetaspaceClosure* it) { + metaspace_pointers_do_impl(it); + } + +private: + // E.g., Array + template ::value && !HAS_METASPACE_POINTERS_DO(U))> + void metaspace_pointers_do_impl(MetaspaceClosure* it) { + // No pointers to follow + } + + // E.g., Array + template ::value && HAS_METASPACE_POINTERS_DO(U))> + void metaspace_pointers_do_impl(MetaspaceClosure* it); + + // E.g., Array + template ::value && HAS_METASPACE_POINTERS_DO(typename std::remove_pointer::type))> + void metaspace_pointers_do_impl(MetaspaceClosure* it); + +public: #ifndef PRODUCT void print(outputStream* st) { diff --git a/src/hotspot/share/oops/array.inline.hpp b/src/hotspot/share/oops/array.inline.hpp index 30cf2e38f77..e6c8ef94a12 100644 --- a/src/hotspot/share/oops/array.inline.hpp +++ b/src/hotspot/share/oops/array.inline.hpp @@ -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 @@ -29,6 +29,7 @@ #include "memory/allocation.hpp" #include "memory/metaspace.hpp" +#include "memory/metaspaceClosure.hpp" template inline void* Array::operator new(size_t size, ClassLoaderData* loader_data, int length, TRAPS) throw() { @@ -52,4 +53,26 @@ inline void* Array::operator new(size_t size, int length, MemTag flags) throw return p; } +// E.g., Array +template +template ::value && HAS_METASPACE_POINTERS_DO(U))> +void Array::metaspace_pointers_do_impl(MetaspaceClosure* it) { + log_trace(aot)("Iter(MSOArray): %p [%d]", this, length()); + for (int i = 0; i < length(); i++) { + T* elm = adr_at(i); + elm->metaspace_pointers_do(it); + } +} + +// E.g., Array +template +template ::value && HAS_METASPACE_POINTERS_DO(typename std::remove_pointer::type))> +void Array::metaspace_pointers_do_impl(MetaspaceClosure* it) { + log_trace(aot)("Iter(MSOPtrArray): %p [%d]", this, length()); + for (int i = 0; i < length(); i++) { + T* mpp = adr_at(i); + it->push(mpp); + } +} + #endif // SHARE_OOPS_ARRAY_INLINE_HPP diff --git a/src/hotspot/share/oops/trainingData.hpp b/src/hotspot/share/oops/trainingData.hpp index a6decdce7f0..50f97153d8c 100644 --- a/src/hotspot/share/oops/trainingData.hpp +++ b/src/hotspot/share/oops/trainingData.hpp @@ -31,6 +31,7 @@ #include "compiler/compilerDefinitions.hpp" #include "memory/allocation.hpp" #include "memory/metaspaceClosure.hpp" +#include "oops/array.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/method.hpp" #include "oops/objArrayKlass.hpp"