< prev index next >

src/hotspot/share/memory/metaspaceClosure.hpp

Print this page

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2020, 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.

@@ -106,16 +106,18 @@
   //         Symbol*     bar() { return (Symbol*)    _obj; }
   //
   // [2] All Array<T> dimensions are statically declared.
   class Ref : public CHeapObj<mtInternal> {
     Writability _writability;
+    bool _keep_after_pushing;
     Ref* _next;
+    void* _user_data;
     NONCOPYABLE(Ref);
 
   protected:
     virtual void** mpp() const = 0;
-    Ref(Writability w) : _writability(w), _next(NULL) {}
+    Ref(Writability w) : _writability(w), _keep_after_pushing(false), _next(NULL), _user_data(NULL) {}
   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;

@@ -135,10 +137,14 @@
     }
 
     void update(address new_loc) const;
 
     Writability writability() const { return _writability; };
+    void set_keep_after_pushing()   { _keep_after_pushing = true; }
+    bool keep_after_pushing()       { return _keep_after_pushing; }
+    void set_user_data(void* data)  { _user_data = data; }
+    void* user_data()               { return _user_data; }
     void set_next(Ref* n)           { _next = n; }
     Ref* next() const               { return _next; }
 
   private:
     static const uintx FLAG_MASK = 0x03;

@@ -241,25 +247,47 @@
         it->push(mpp);
       }
     }
   };
 
-  // If recursion is too deep, save the Refs in _pending_refs, and push them later using
-  // MetaspaceClosure::finish()
+  // 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.
   static const int MAX_NEST_LEVEL = 5;
   Ref* _pending_refs;
   int _nest_level;
+  Ref* _enclosing_ref;
 
   void push_impl(Ref* ref);
   void do_push(Ref* ref);
 
 public:
-  MetaspaceClosure(): _pending_refs(NULL), _nest_level(0) {}
+  MetaspaceClosure(): _pending_refs(NULL), _nest_level(0), _enclosing_ref(NULL) {}
   ~MetaspaceClosure();
 
   void finish();
 
+  // enclosing_ref() is used to compute the offset of a field in a C++ class. For example
+  // class Foo { intx scala; Bar* ptr; }
+  //    Foo *f = 0x100;
+  // when the f->ptr field is iterated with do_ref() on 64-bit platforms, we will have
+  //    do_ref(Ref* r) {
+  //       r->addr() == 0x108;                // == &f->ptr;
+  //       enclosing_ref()->obj() == 0x100;   // == foo
+  // So we know that we are iterating upon a field at offset 8 of the object at 0x100.
+  //
+  // Note that if we have stack overflow, do_pending_ref(r) will be called first and
+  // do_ref(r) will be called later, for the same r. In this case, enclosing_ref() is valid only
+  // when do_pending_ref(r) is called, and will return NULL when do_ref(r) is called.
+  Ref* enclosing_ref() const {
+    return _enclosing_ref;
+  }
+
+  // This is called when a reference is placed in _pending_refs. Override this
+  // function if you're using enclosing_ref(). See notes above.
+  virtual void do_pending_ref(Ref* ref) {}
+
   // returns true if we want to keep iterating the pointers embedded inside <ref>
   virtual bool do_ref(Ref* ref, bool read_only) = 0;
 
   // When you do:
   //     void MyType::metaspace_pointers_do(MetaspaceClosure* it) {

@@ -283,11 +311,15 @@
   template <class T> void push(T** mpp, Writability w = _default) {
     push_impl(new ObjectRef<T>(mpp, w));
   }
 
   template <class T> void push_method_entry(T** mpp, intptr_t* p) {
-    push_special(_method_entry_ref, new ObjectRef<T>(mpp, _default), (intptr_t*)p);
+    Ref* ref = new ObjectRef<T>(mpp, _default);
+    push_special(_method_entry_ref, ref, (intptr_t*)p);
+    if (!ref->keep_after_pushing()) {
+      delete ref;
+    }
   }
 
   // This is for tagging special pointers that are not a reference to MetaspaceObj. It's currently
   // used to mark the method entry points in Method/ConstMethod.
   virtual void push_special(SpecialRef type, Ref* obj, intptr_t* p) {
< prev index next >