Path: blob/master/src/hotspot/share/memory/metaspaceClosure.hpp
41144 views
/*1* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#ifndef SHARE_MEMORY_METASPACECLOSURE_HPP25#define SHARE_MEMORY_METASPACECLOSURE_HPP2627#include "logging/log.hpp"28#include "memory/allocation.hpp"29#include "metaprogramming/enableIf.hpp"30#include "oops/array.hpp"31#include "utilities/globalDefinitions.hpp"32#include "utilities/growableArray.hpp"33#include "utilities/hashtable.inline.hpp"34#include "utilities/macros.hpp"35#include <type_traits>3637// The metadata hierarchy is separate from the oop hierarchy38class MetaspaceObj; // no C++ vtable39//class Array; // no C++ vtable40class Annotations; // no C++ vtable41class ConstantPoolCache; // no C++ vtable42class ConstMethod; // no C++ vtable43class MethodCounters; // no C++ vtable44class Symbol; // no C++ vtable45class Metadata; // has C++ vtable (so do all subclasses)46class ConstantPool;47class MethodData;48class Method;49class Klass;50class InstanceKlass;51class InstanceMirrorKlass;52class InstanceClassLoaderKlass;53class InstanceRefKlass;54class ArrayKlass;55class ObjArrayKlass;56class TypeArrayKlass;5758// class MetaspaceClosure --59//60// This class is used for iterating the objects in the HotSpot Metaspaces. It61// provides an API to walk all the reachable objects starting from a set of62// root references (such as all Klass'es in the SystemDictionary).63//64// Currently it is used for compacting the CDS archive by eliminate temporary65// objects allocated during archive creation time. See ArchiveBuilder for an example.66//67// To support MetaspaceClosure, each subclass of MetaspaceObj must provide68// a method of the type void metaspace_pointers_do(MetaspaceClosure*). This method69// should call MetaspaceClosure::push() on every pointer fields of this70// class that points to a MetaspaceObj. See Annotations::metaspace_pointers_do()71// for an example.72class MetaspaceClosure {73public:74enum Writability {75_writable,76_not_writable,77_default78};7980enum SpecialRef {81_method_entry_ref82};8384// class MetaspaceClosure::Ref --85//86// MetaspaceClosure can be viewed as a very simple type of copying garbage87// collector. For it to function properly, it requires each subclass of88// MetaspaceObj to provide two methods:89//90// size_t size(); -- to determine how much data to copy91// void metaspace_pointers_do(MetaspaceClosure*); -- to locate all the embedded pointers92//93// Calling these methods would be trivial if these two were virtual methods.94// However, to save space, MetaspaceObj has NO vtable. The vtable is introduced95// only in the Metadata class.96//97// To work around the lack of a vtable, we use the Ref class with templates98// (see MSORef, OtherArrayRef, MSOArrayRef, and MSOPointerArrayRef)99// so that we can statically discover the type of a object. The use of Ref100// depends on the fact that:101//102// [1] We don't use polymorphic pointers for MetaspaceObj's that are not subclasses103// of Metadata. I.e., we don't do this:104// class Klass {105// MetaspaceObj *_obj;106// Array<int>* foo() { return (Array<int>*)_obj; }107// Symbol* bar() { return (Symbol*) _obj; }108//109// [2] All Array<T> dimensions are statically declared.110class Ref : public CHeapObj<mtMetaspace> {111Writability _writability;112bool _keep_after_pushing;113Ref* _next;114void* _user_data;115NONCOPYABLE(Ref);116117protected:118virtual void** mpp() const = 0;119Ref(Writability w) : _writability(w), _keep_after_pushing(false), _next(NULL), _user_data(NULL) {}120public:121virtual bool not_null() const = 0;122virtual int size() const = 0;123virtual void metaspace_pointers_do(MetaspaceClosure *it) const = 0;124virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const = 0;125virtual MetaspaceObj::Type msotype() const = 0;126virtual bool is_read_only_by_default() const = 0;127virtual ~Ref() {}128129address obj() const {130// In some rare cases (see CPSlot in constantPool.hpp) we store some flags in the lowest131// 2 bits of a MetaspaceObj pointer. Unmask these when manipulating the pointer.132uintx p = (uintx)*mpp();133return (address)(p & (~FLAG_MASK));134}135136address* addr() const {137return (address*)mpp();138}139140void update(address new_loc) const;141142Writability writability() const { return _writability; };143void set_keep_after_pushing() { _keep_after_pushing = true; }144bool keep_after_pushing() { return _keep_after_pushing; }145void set_user_data(void* data) { _user_data = data; }146void* user_data() { return _user_data; }147void set_next(Ref* n) { _next = n; }148Ref* next() const { return _next; }149150private:151static const uintx FLAG_MASK = 0x03;152153int flag_bits() const {154uintx p = (uintx)*mpp();155return (int)(p & FLAG_MASK);156}157};158159private:160// MSORef -- iterate an instance of MetaspaceObj161template <class T> class MSORef : public Ref {162T** _mpp;163T* dereference() const {164return *_mpp;165}166protected:167virtual void** mpp() const {168return (void**)_mpp;169}170171public:172MSORef(T** mpp, Writability w) : Ref(w), _mpp(mpp) {}173174virtual bool is_read_only_by_default() const { return T::is_read_only_by_default(); }175virtual bool not_null() const { return dereference() != NULL; }176virtual int size() const { return dereference()->size(); }177virtual MetaspaceObj::Type msotype() const { return dereference()->type(); }178179virtual void metaspace_pointers_do(MetaspaceClosure *it) const {180dereference()->metaspace_pointers_do(it);181}182virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const {183((T*)new_loc)->metaspace_pointers_do(it);184}185};186187// abstract base class for MSOArrayRef, MSOPointerArrayRef and OtherArrayRef188template <class T> class ArrayRef : public Ref {189Array<T>** _mpp;190protected:191Array<T>* dereference() const {192return *_mpp;193}194virtual void** mpp() const {195return (void**)_mpp;196}197198ArrayRef(Array<T>** mpp, Writability w) : Ref(w), _mpp(mpp) {}199200// all Arrays are read-only by default201virtual bool is_read_only_by_default() const { return true; }202virtual bool not_null() const { return dereference() != NULL; }203virtual int size() const { return dereference()->size(); }204virtual MetaspaceObj::Type msotype() const { return MetaspaceObj::array_type(sizeof(T)); }205};206207// OtherArrayRef -- iterate an instance of Array<T>, where T is NOT a subtype of MetaspaceObj.208// T can be a primitive type, such as int, or a structure. However, we do not scan209// the fields inside T, so you should not embed any pointers inside T.210template <class T> class OtherArrayRef : public ArrayRef<T> {211public:212OtherArrayRef(Array<T>** mpp, Writability w) : ArrayRef<T>(mpp, w) {}213214virtual void metaspace_pointers_do(MetaspaceClosure *it) const {215Array<T>* array = ArrayRef<T>::dereference();216log_trace(cds)("Iter(OtherArray): %p [%d]", array, array->length());217}218virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const {219Array<T>* array = (Array<T>*)new_loc;220log_trace(cds)("Iter(OtherArray): %p [%d]", array, array->length());221}222};223224// MSOArrayRef -- iterate an instance of Array<T>, where T is a subtype of MetaspaceObj.225// We recursively call T::metaspace_pointers_do() for each element in this array.226template <class T> class MSOArrayRef : public ArrayRef<T> {227public:228MSOArrayRef(Array<T>** mpp, Writability w) : ArrayRef<T>(mpp, w) {}229230virtual void metaspace_pointers_do(MetaspaceClosure *it) const {231metaspace_pointers_do_at_impl(it, ArrayRef<T>::dereference());232}233virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const {234metaspace_pointers_do_at_impl(it, (Array<T>*)new_loc);235}236private:237void metaspace_pointers_do_at_impl(MetaspaceClosure *it, Array<T>* array) const {238log_trace(cds)("Iter(MSOArray): %p [%d]", array, array->length());239for (int i = 0; i < array->length(); i++) {240T* elm = array->adr_at(i);241elm->metaspace_pointers_do(it);242}243}244};245246// MSOPointerArrayRef -- iterate an instance of Array<T*>, where T is a subtype of MetaspaceObj.247// We recursively call MetaspaceClosure::push() for each pointer in this array.248template <class T> class MSOPointerArrayRef : public ArrayRef<T*> {249public:250MSOPointerArrayRef(Array<T*>** mpp, Writability w) : ArrayRef<T*>(mpp, w) {}251252virtual void metaspace_pointers_do(MetaspaceClosure *it) const {253metaspace_pointers_do_at_impl(it, ArrayRef<T*>::dereference());254}255virtual void metaspace_pointers_do_at(MetaspaceClosure *it, address new_loc) const {256metaspace_pointers_do_at_impl(it, (Array<T*>*)new_loc);257}258private:259void metaspace_pointers_do_at_impl(MetaspaceClosure *it, Array<T*>* array) const {260log_trace(cds)("Iter(MSOPointerArray): %p [%d]", array, array->length());261for (int i = 0; i < array->length(); i++) {262T** mpp = array->adr_at(i);263it->push(mpp);264}265}266};267268// Normally, chains of references like a->b->c->d are iterated recursively. However,269// if recursion is too deep, we save the Refs in _pending_refs, and push them later in270// MetaspaceClosure::finish(). This avoids overflowing the C stack.271static const int MAX_NEST_LEVEL = 5;272Ref* _pending_refs;273int _nest_level;274Ref* _enclosing_ref;275276void push_impl(Ref* ref);277void do_push(Ref* ref);278279public:280MetaspaceClosure(): _pending_refs(NULL), _nest_level(0), _enclosing_ref(NULL) {}281~MetaspaceClosure();282283void finish();284285// enclosing_ref() is used to compute the offset of a field in a C++ class. For example286// class Foo { intx scala; Bar* ptr; }287// Foo *f = 0x100;288// when the f->ptr field is iterated with do_ref() on 64-bit platforms, we will have289// do_ref(Ref* r) {290// r->addr() == 0x108; // == &f->ptr;291// enclosing_ref()->obj() == 0x100; // == foo292// So we know that we are iterating upon a field at offset 8 of the object at 0x100.293//294// Note that if we have stack overflow, do_pending_ref(r) will be called first and295// do_ref(r) will be called later, for the same r. In this case, enclosing_ref() is valid only296// when do_pending_ref(r) is called, and will return NULL when do_ref(r) is called.297Ref* enclosing_ref() const {298return _enclosing_ref;299}300301// This is called when a reference is placed in _pending_refs. Override this302// function if you're using enclosing_ref(). See notes above.303virtual void do_pending_ref(Ref* ref) {}304305// returns true if we want to keep iterating the pointers embedded inside <ref>306virtual bool do_ref(Ref* ref, bool read_only) = 0;307308private:309template <class REF_TYPE, typename T>310void push_with_ref(T** mpp, Writability w) {311push_impl(new REF_TYPE(mpp, w));312}313314public:315// When MetaspaceClosure::push(...) is called, pick the correct Ref subtype to handle it:316//317// MetaspaceClosure* it = ...;318// Klass* o = ...; it->push(&o); => MSORef319// Array<int>* a1 = ...; it->push(&a1); => OtherArrayRef320// Array<Annotation>* a2 = ...; it->push(&a2); => MSOArrayRef321// Array<Klass*>* a3 = ...; it->push(&a3); => MSOPointerArrayRef322// Array<Array<Klass*>*>* a4 = ...; it->push(&a4); => MSOPointerArrayRef323// Array<Annotation*>* a5 = ...; it->push(&a5); => MSOPointerArrayRef324//325// Note that the following will fail to compile (to prevent you from adding new fields326// into the MetaspaceObj subtypes that cannot be properly copied by CDS):327//328// Hashtable* h = ...; it->push(&h); => Hashtable is not a subclass of MetaspaceObj329// Array<Hashtable*>* a6 = ...; it->push(&a6); => Hashtable is not a subclass of MetaspaceObj330// Array<int*>* a7 = ...; it->push(&a7); => int is not a subclass of MetaspaceObj331332template <typename T>333void push(T** mpp, Writability w = _default) {334static_assert(std::is_base_of<MetaspaceObj, T>::value, "Do not push pointers of arbitrary types");335push_with_ref<MSORef<T>>(mpp, w);336}337338template <typename T, ENABLE_IF(!std::is_base_of<MetaspaceObj, T>::value)>339void push(Array<T>** mpp, Writability w = _default) {340push_with_ref<OtherArrayRef<T>>(mpp, w);341}342343template <typename T, ENABLE_IF(std::is_base_of<MetaspaceObj, T>::value)>344void push(Array<T>** mpp, Writability w = _default) {345push_with_ref<MSOArrayRef<T>>(mpp, w);346}347348template <typename T>349void push(Array<T*>** mpp, Writability w = _default) {350static_assert(std::is_base_of<MetaspaceObj, T>::value, "Do not push Arrays of arbitrary pointer types");351push_with_ref<MSOPointerArrayRef<T>>(mpp, w);352}353354#if 0355// Enable this block if you're changing the push(...) methods, to test for types that should be356// disallowed. Each of the following "push" calls should result in a compile-time error.357void test_disallowed_types(MetaspaceClosure* it) {358Hashtable<bool, mtInternal>* h = NULL;359it->push(&h);360361Array<Hashtable<bool, mtInternal>*>* a6 = NULL;362it->push(&a6);363364Array<int*>* a7 = NULL;365it->push(&a7);366}367#endif368369template <class T> void push_method_entry(T** mpp, intptr_t* p) {370Ref* ref = new MSORef<T>(mpp, _default);371push_special(_method_entry_ref, ref, (intptr_t*)p);372if (!ref->keep_after_pushing()) {373delete ref;374}375}376377// This is for tagging special pointers that are not a reference to MetaspaceObj. It's currently378// used to mark the method entry points in Method/ConstMethod.379virtual void push_special(SpecialRef type, Ref* obj, intptr_t* p) {380assert(type == _method_entry_ref, "only special type allowed for now");381}382};383384// This is a special MetaspaceClosure that visits each unique MetaspaceObj once.385class UniqueMetaspaceClosure : public MetaspaceClosure {386static const int INITIAL_TABLE_SIZE = 15889;387static const int MAX_TABLE_SIZE = 1000000;388389// Do not override. Returns true if we are discovering ref->obj() for the first time.390virtual bool do_ref(Ref* ref, bool read_only);391392public:393// Gets called the first time we discover an object.394virtual bool do_unique_ref(Ref* ref, bool read_only) = 0;395UniqueMetaspaceClosure() : _has_been_visited(INITIAL_TABLE_SIZE) {}396397private:398KVHashtable<address, bool, mtInternal> _has_been_visited;399};400401#endif // SHARE_MEMORY_METASPACECLOSURE_HPP402403404