1 /*
   2  * Copyright (c) 2016, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #ifndef SHARE_VM_MEMORY_VTBUFFER_HPP
  26 #define SHARE_VM_MEMORY_VTBUFFER_HPP
  27 
  28 #include "memory/allocation.hpp"
  29 #include "runtime/globals.hpp"
  30 #include "runtime/os.hpp"
  31 #include "utilities/globalDefinitions.hpp"
  32 
  33 class VTBufferChunk {
  34   friend class VMStructs;
  35 
  36   static const int MAGIC_NUMBER = 3141592;
  37 
  38 private:
  39   int            _magic;
  40   int            _index;
  41   VTBufferChunk* _prev;
  42   VTBufferChunk* _next;
  43   JavaThread*    _owner;
  44  public:
  45 
  46   /* A VTBufferChunk is a 4KB page used to create a thread-local
  47    * buffer to store values. They are allocated in a global pool,
  48    * and then threads can get them to create their own buffer.
  49    * Each thread creates a linked list of VTBufferChunk to build
  50    * its buffer. Fields _prev and _next are used to link the
  51    * chunks together, the _owner field indicates to which thread
  52    * this chunk belongs to (if NULL, it means the chunk has been
  53    * returned to the global pool). When creating the linked list,
  54    * the field _index is used to store the position of the chunk
  55    * in the list. The index is used to optimize the comparison
  56    * of addresses of buffered values. Because the thread local
  57    * buffer is made of non-contiguous chunks, it is not possible
  58    * to directly compare the two addresses. The comparison requires
  59    * first to compare the indexes of each address' chunk, and if
  60    * they are equal, compare the addresses directly. Without
  61    * the _index field, this operation would require to walk the
  62    * linked list for each comparison.
  63    */
  64 
  65   VTBufferChunk(JavaThread* thread) {
  66     fatal("Should not reach here");
  67     VTBufferChunk::init(this, thread);
  68   }
  69 
  70   static void init(VTBufferChunk* chunk, JavaThread* thread) {
  71     chunk->_magic = MAGIC_NUMBER;
  72     chunk->_index = -1;
  73     chunk->_prev = NULL;
  74     chunk->_next = NULL;
  75     chunk->_owner = thread;
  76   }
  77 
  78   int            index() { return _index; }
  79   void           set_index(int index) { _index = index; }
  80   VTBufferChunk* prev() { return _prev; }
  81   void           set_prev(VTBufferChunk* prev) { _prev = prev; }
  82   VTBufferChunk* next() { return _next; }
  83   void           set_next(VTBufferChunk* next) { _next = next; }
  84   JavaThread*    owner() { return _owner; }
  85   void           set_owner(JavaThread* thread) {
  86     assert(thread == NULL || _owner == NULL || _owner == thread, "Sanity check");
  87     _owner = thread;
  88   }
  89 
  90   bool is_valid() {
  91     return _magic == MAGIC_NUMBER && _owner != NULL && _index != -1;
  92   }
  93 
  94   void* first_alloc() { return (void*)((char*)this + align_object_size(sizeof (VTBufferChunk))); }
  95   void* alloc_limit() { return (void*)((char*)this + chunk_size() - 1); }
  96 
  97   static int chunk_size() {
  98     return os::vm_page_size();
  99   }
 100 
 101   static uintptr_t chunk_mask() {
 102     return ~(chunk_size() - 1);
 103   }
 104 
 105   static ByteSize index_offset() { return byte_offset_of(VTBufferChunk, _index); }
 106 
 107   static size_t max_alloc_size() {
 108     return chunk_size() - align_object_size(sizeof (VTBufferChunk));
 109   }
 110 
 111   static VTBufferChunk* chunk(void* address) {
 112     VTBufferChunk* c = (VTBufferChunk*)((intptr_t)address & chunk_mask());
 113     assert(c->is_valid(), "Sanity check");
 114     return c;
 115   }
 116 
 117   bool contains(void* address) {
 118     return address > (char*)chunk(address) && address < ((char*)chunk(address) + chunk_size());
 119   }
 120 
 121   void zap(void *start);
 122 };
 123 
 124 /* VTBuffer is a thread-local buffer used to store values, or TLVB (Thread-Local Value Buffer).
 125  * Values allocated in the TLVB have the same layout as values allocated in the Java heap:
 126  * same header size, same offsets for fields. The only difference is on the meaning of the
 127  * mark word: in a buffered value, the mark word contains an oop pointing to the Java mirror
 128  * of the value's class, with the two least significant bits used for internal marking.
 129  * Values allocated in the TLVB are references through oops, however, because TLVBs are not
 130  * part of the Java heap, those oops *must never be exposed to GCs*. But buffered values
 131  * can contain references to Java heap allocated objects or values, in addition to the
 132  * reference to the Java mirror, and these oops have to be processed by GC. The solution is
 133  * to let GC closures iterate over the internal oops, but not directly on the buffered value
 134  * itself (see ValueKlass::iterate_over_inside_oops() method).
 135  */
 136 
 137 class VTBuffer : AllStatic {
 138   friend class VMStructs;
 139 private:
 140   static address _base;
 141   static size_t _size;
 142   static address _commit_ptr;
 143 
 144   static VTBufferChunk* _free_list;
 145   static Mutex* _pool_lock;
 146   static int _pool_counter;
 147   static int _max_pool_counter;
 148   static int _total_allocated;
 149   static int _total_failed;
 150 
 151 public:
 152   static void init();
 153   static VTBufferChunk* get_new_chunk(JavaThread* thread);
 154 
 155   static Mutex* lock() { return _pool_lock; }
 156   static oop allocate_value(ValueKlass* k, TRAPS);
 157   static bool allocate_vt_chunk(JavaThread* thread);
 158   static void recycle_chunk(JavaThread* thread, VTBufferChunk* chunk);
 159   static void return_vt_chunk(JavaThread* thread, VTBufferChunk* chunk);
 160 
 161   static int in_pool() { return _pool_counter; }
 162   static int max_in_pool() { return _max_pool_counter; }
 163   static int total_allocated() { return _total_allocated; }
 164   static int total_failed() { return _total_failed; }
 165 
 166   static bool is_in_vt_buffer(const void* p) {
 167 #ifdef ASSERT
 168     if (p >= _base && p < (_base + _size)) {
 169       assert(p < _commit_ptr, "should not point to an uncommited page");
 170       intptr_t chunk_mask = (~(VTBufferChunk::chunk_size() - 1));
 171       VTBufferChunk* c = (VTBufferChunk*)((intptr_t)p & chunk_mask);
 172       assert(c->is_valid(), "Sanity check");
 173     }
 174 #endif // ASSERT
 175     return p >= _base && p < (_base + _size);
 176   }
 177 
 178   static bool value_belongs_to_frame(oop p, frame *f);
 179   static bool is_value_allocated_after(oop p, void* a);
 180   static void recycle_vt_in_frame(JavaThread* thread, frame* f);
 181   static void recycle_vtbuffer(JavaThread *thread, void* alloc_ptr);
 182   static address relocate_value(address old, address previous, int previous_size_in_words);
 183   static oop relocate_return_value(JavaThread* thread, void* alloc_ptr, oop old);
 184 
 185   static void fix_frame_vt_alloc_ptr(frame fr, VTBufferChunk* chunk);
 186 
 187   enum Mark {
 188     mark_A = 1,
 189     mark_B = 2,
 190     mark_mask = 3
 191   };
 192 
 193   static Mark switch_mark(Mark m) {
 194     assert(m == mark_A || m == mark_B, "Sanity check");
 195     return m == mark_A ? mark_B : mark_A;
 196   }
 197 
 198 };
 199 
 200 struct VT_relocation_entry {
 201   int chunk_index;
 202   address old_ptr;
 203   address new_ptr;
 204   markOop mark_word;
 205 };
 206 
 207 
 208 class BufferedValuesMarking : public BufferedValueClosure {
 209   frame* _frame;
 210   struct VT_relocation_entry* _reloc_table;
 211   int _size;
 212   int* _index;
 213 public:
 214   BufferedValuesMarking(frame* frame, struct VT_relocation_entry* reloc_table, int size, int* index) {
 215     _frame = frame;
 216     _reloc_table = reloc_table;
 217     _size = size;
 218     _index = index;
 219   }
 220   virtual void do_buffered_value(oop* p);
 221 };
 222 
 223 class BufferedValuesPointersUpdate : public BufferedValueClosure {
 224   frame* _frame;
 225 public:
 226   BufferedValuesPointersUpdate(frame* frame) {
 227     _frame = frame;
 228   }
 229   virtual void do_buffered_value(oop* p);
 230 };
 231 
 232 /* Value buffered in a TLVB expose their internal oops as roots for GCs.
 233  * A GC root must only be processed once by each GC closure. However,
 234  * a Java Thread can have multiple oops (aliases) pointing to the same
 235  * buffered value (from local variable entries, operand stack slots,
 236  * Handles or runtime data structures). To prevent duplicated processing
 237  * of a buffered value, each function processing a Java Thread's GC roots
 238  * must allocates a BufferedValuesDealiaser which uses a marking mechanism
 239  * to avoid processing a buffered value twice.
 240  */
 241 class BufferedValuesDealiaser : public StackObj {
 242 private:
 243   const JavaThread* _target;
 244   VTBuffer::Mark _current_mark;
 245 
 246 public:
 247   BufferedValuesDealiaser(JavaThread* thread);
 248   VTBuffer::Mark current_mark() const { return _current_mark; }
 249   void oops_do(OopClosure* f, oop value);
 250 
 251   ~BufferedValuesDealiaser();
 252 };
 253 
 254 #endif /* SHARE_VM_MEMORY_VTBUFFER_HPP */