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   friend class TemplateTable;
 140   friend class InterpreterRuntime;
 141 private:
 142   static address _base;
 143   static address _end;
 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 VTBufferChunk* get_new_chunk(JavaThread* thread);
 157 
 158   static Mutex* lock() { return _pool_lock; }
 159   static oop allocate_value(ValueKlass* k, TRAPS);
 160   static bool allocate_vt_chunk(JavaThread* thread);
 161   static void recycle_chunk(JavaThread* thread, VTBufferChunk* chunk);
 162   static void return_vt_chunk(JavaThread* thread, VTBufferChunk* chunk);
 163 
 164   static int in_pool() { return _pool_counter; }
 165   static int max_in_pool() { return _max_pool_counter; }
 166   static int total_allocated() { return _total_allocated; }
 167   static int total_failed() { return _total_failed; }
 168 
 169   static bool is_in_vt_buffer(const void* p) {
 170 #ifdef ASSERT
 171     if (p >= _base && p < (_base + _size)) {
 172       assert(p < _commit_ptr, "should not point to an uncommited page");
 173       intptr_t chunk_mask = (~(VTBufferChunk::chunk_size() - 1));
 174       VTBufferChunk* c = (VTBufferChunk*)((intptr_t)p & chunk_mask);
 175       assert(c->is_valid(), "Sanity check");
 176     }
 177 #endif // ASSERT
 178     return p >= _base && p < (_base + _size);
 179   }
 180 
 181   static bool value_belongs_to_frame(oop p, frame *f);
 182   static bool is_value_allocated_after(oop p, void* a);
 183   static void recycle_vt_in_frame(JavaThread* thread, frame* f);
 184   static void recycle_vtbuffer(JavaThread *thread, void* alloc_ptr);
 185   static address relocate_value(address old, address previous, int previous_size_in_words);
 186   static oop relocate_return_value(JavaThread* thread, void* alloc_ptr, oop old);
 187 
 188   static void fix_frame_vt_alloc_ptr(frame fr, VTBufferChunk* chunk);
 189 
 190   enum Mark {
 191     mark_A = 1,
 192     mark_B = 2,
 193     mark_mask = 3
 194   };
 195 
 196   static Mark switch_mark(Mark m) {
 197     assert(m == mark_A || m == mark_B, "Sanity check");
 198     return m == mark_A ? mark_B : mark_A;
 199   }
 200 
 201 };
 202 
 203 struct VT_relocation_entry {
 204   int chunk_index;
 205   address old_ptr;
 206   address new_ptr;
 207   markOop mark_word;
 208 };
 209 
 210 
 211 class BufferedValuesMarking : public BufferedValueClosure {
 212   frame* _frame;
 213   struct VT_relocation_entry* _reloc_table;
 214   int _size;
 215   int* _index;
 216 public:
 217   BufferedValuesMarking(frame* frame, struct VT_relocation_entry* reloc_table, int size, int* index) {
 218     _frame = frame;
 219     _reloc_table = reloc_table;
 220     _size = size;
 221     _index = index;
 222   }
 223   virtual void do_buffered_value(oop* p);
 224 };
 225 
 226 class BufferedValuesPointersUpdate : public BufferedValueClosure {
 227   frame* _frame;
 228 public:
 229   BufferedValuesPointersUpdate(frame* frame) {
 230     _frame = frame;
 231   }
 232   virtual void do_buffered_value(oop* p);
 233 };
 234 
 235 /* Value buffered in a TLVB expose their internal oops as roots for GCs.
 236  * A GC root must only be processed once by each GC closure. However,
 237  * a Java Thread can have multiple oops (aliases) pointing to the same
 238  * buffered value (from local variable entries, operand stack slots,
 239  * Handles or runtime data structures). To prevent duplicated processing
 240  * of a buffered value, each function processing a Java Thread's GC roots
 241  * must allocates a BufferedValuesDealiaser which uses a marking mechanism
 242  * to avoid processing a buffered value twice.
 243  */
 244 class BufferedValuesDealiaser : public StackObj {
 245 private:
 246   const JavaThread* _target;
 247   VTBuffer::Mark _current_mark;
 248 
 249 public:
 250   BufferedValuesDealiaser(JavaThread* thread);
 251   VTBuffer::Mark current_mark() const { return _current_mark; }
 252   void oops_do(OopClosure* f, oop value);
 253 
 254   ~BufferedValuesDealiaser();
 255 };
 256 
 257 #endif /* SHARE_VM_MEMORY_VTBUFFER_HPP */
--- EOF ---