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