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 */