101 102 static size_t max_alloc_size() { 103 return chunk_size() - align_object_size(sizeof (VTBufferChunk)); 104 } 105 106 static VTBufferChunk* chunk(void* address) { 107 VTBufferChunk* c = (VTBufferChunk*)((intptr_t)address & chunk_mask()); 108 assert(c->is_valid(), "Sanity check"); 109 return c; 110 } 111 112 static bool check_buffered(void* address) { 113 assert(address != NULL, "Sanity check"); 114 VTBufferChunk* c = (VTBufferChunk*)((intptr_t)address & chunk_mask()); 115 return c->is_valid(); 116 } 117 118 bool contains(void* address) { 119 return address > (char*)chunk(address) && address < ((char*)chunk(address) + chunk_size()); 120 } 121 }; 122 123 class VTBuffer : AllStatic { 124 friend class VMStructs; 125 private: 126 static VTBufferChunk* _free_list; 127 static Mutex* _pool_lock; 128 static int _pool_counter; 129 static int _max_pool_counter; 130 static int _total_allocated; 131 static int _total_deallocated; 132 static int _total_failed; 133 static const int _max_free_list = 64; // Should be tunable 134 135 public: 136 static Mutex* lock() { return _pool_lock; } 137 static oop allocate_value(ValueKlass* k, TRAPS); 138 static bool allocate_vt_chunk(JavaThread* thread); 139 static void recycle_chunk(JavaThread* thread, VTBufferChunk* chunk); 140 static void return_vt_chunk(JavaThread* thread, VTBufferChunk* chunk); 141 142 static int in_pool() { return _pool_counter; } 143 static int max_in_pool() { return _max_pool_counter; } 144 static int total_allocated() { return _total_allocated; } 145 static int total_deallocated() { return _total_deallocated; } 146 static int total_failed() { return _total_failed; } 147 148 static bool is_in_vt_buffer(const void* p) { 149 intptr_t chunk_mask = (~(VTBufferChunk::chunk_size() - 1)); 150 VTBufferChunk* c = (VTBufferChunk*)((intptr_t)p & chunk_mask); 151 return c->is_valid(); 152 } 153 154 static bool value_belongs_to_frame(oop p, frame *f); 155 static void recycle_vt_in_frame(JavaThread* thread, frame* f); 156 static void recycle_vtbuffer(JavaThread *thread, frame f); 157 static address relocate_value(address old, address previous, int previous_size_in_words); 158 static oop relocate_return_value(JavaThread* thread, frame fr, oop old); 159 160 static void fix_frame_vt_alloc_ptr(frame fr, VTBufferChunk* chunk); 161 162 }; 163 164 struct VT_relocation_entry { 165 int chunk_index; 166 address old_ptr; 167 address new_ptr; 168 }; 169 170 171 class BufferedValuesMarking : public BufferedValueClosure { 172 frame* _frame; 173 struct VT_relocation_entry* _reloc_table; 174 int _size; 175 int* _index; 176 public: 177 BufferedValuesMarking(frame* frame, struct VT_relocation_entry* reloc_table, int size, int* index) { 178 _frame = frame; 179 _reloc_table = reloc_table; 180 _size = size; 181 _index = index; 182 } 183 virtual void do_buffered_value(oop* p); 184 }; 185 186 class BufferedValuesPointersUpdate : public BufferedValueClosure { 187 frame* _frame; 188 public: 189 BufferedValuesPointersUpdate(frame* frame) { 190 _frame = frame; 191 } 192 virtual void do_buffered_value(oop* p); 193 }; 194 195 #endif /* SHARE_VM_MEMORY_VTBUFFER_HPP */ | 101 102 static size_t max_alloc_size() { 103 return chunk_size() - align_object_size(sizeof (VTBufferChunk)); 104 } 105 106 static VTBufferChunk* chunk(void* address) { 107 VTBufferChunk* c = (VTBufferChunk*)((intptr_t)address & chunk_mask()); 108 assert(c->is_valid(), "Sanity check"); 109 return c; 110 } 111 112 static bool check_buffered(void* address) { 113 assert(address != NULL, "Sanity check"); 114 VTBufferChunk* c = (VTBufferChunk*)((intptr_t)address & chunk_mask()); 115 return c->is_valid(); 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 value 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 private: 141 static VTBufferChunk* _free_list; 142 static Mutex* _pool_lock; 143 static int _pool_counter; 144 static int _max_pool_counter; 145 static int _total_allocated; 146 static int _total_deallocated; 147 static int _total_failed; 148 static const int _max_free_list = 64; // Should be tunable 149 150 public: 151 static Mutex* lock() { return _pool_lock; } 152 static oop allocate_value(ValueKlass* k, TRAPS); 153 static bool allocate_vt_chunk(JavaThread* thread); 154 static void recycle_chunk(JavaThread* thread, VTBufferChunk* chunk); 155 static void return_vt_chunk(JavaThread* thread, VTBufferChunk* chunk); 156 157 static int in_pool() { return _pool_counter; } 158 static int max_in_pool() { return _max_pool_counter; } 159 static int total_allocated() { return _total_allocated; } 160 static int total_deallocated() { return _total_deallocated; } 161 static int total_failed() { return _total_failed; } 162 163 static bool is_in_vt_buffer(const void* p) { 164 if (p == NULL) return false; 165 intptr_t chunk_mask = (~(VTBufferChunk::chunk_size() - 1)); 166 VTBufferChunk* c = (VTBufferChunk*)((intptr_t)p & chunk_mask); 167 return c->is_valid(); 168 } 169 170 static bool value_belongs_to_frame(oop p, frame *f); 171 static bool is_value_allocated_after(oop p, void* a); 172 static void recycle_vt_in_frame(JavaThread* thread, frame* f); 173 static void recycle_vtbuffer(JavaThread *thread, void* alloc_ptr); 174 static address relocate_value(address old, address previous, int previous_size_in_words); 175 static oop relocate_return_value(JavaThread* thread, void* alloc_ptr, oop old); 176 177 static void fix_frame_vt_alloc_ptr(frame fr, VTBufferChunk* chunk); 178 179 enum Mark { 180 mark_A = 1, 181 mark_B = 2, 182 mark_mask = 3 183 }; 184 185 static Mark switch_mark(Mark m) { 186 assert(m == mark_A || m == mark_B, "Sanity check"); 187 return m == mark_A ? mark_B : mark_A; 188 } 189 190 }; 191 192 struct VT_relocation_entry { 193 int chunk_index; 194 address old_ptr; 195 address new_ptr; 196 markOop mark_word; 197 }; 198 199 200 class BufferedValuesMarking : public BufferedValueClosure { 201 frame* _frame; 202 struct VT_relocation_entry* _reloc_table; 203 int _size; 204 int* _index; 205 public: 206 BufferedValuesMarking(frame* frame, struct VT_relocation_entry* reloc_table, int size, int* index) { 207 _frame = frame; 208 _reloc_table = reloc_table; 209 _size = size; 210 _index = index; 211 } 212 virtual void do_buffered_value(oop* p); 213 }; 214 215 class BufferedValuesPointersUpdate : public BufferedValueClosure { 216 frame* _frame; 217 public: 218 BufferedValuesPointersUpdate(frame* frame) { 219 _frame = frame; 220 } 221 virtual void do_buffered_value(oop* p); 222 }; 223 224 /* Value buffered in a TLVB expose their internal oops as roots for GCs. 225 * A GC root must only be processed once by each GC closure. However, 226 * a Java Thread can have multiple oops (aliases) pointing to the same 227 * buffered value (from local variable entries, operand stack slots, 228 * Handles or runtime data structures). To prevent duplicated processing 229 * of a buffered value, each function processing a Java Thread's GC roots 230 * must allocates a BufferedValuesDealiaser which uses a marking mechanism 231 * to avoid processing a buffered value twice. 232 */ 233 class BufferedValuesDealiaser : public StackObj { 234 private: 235 const JavaThread* _target; 236 VTBuffer::Mark _current_mark; 237 238 public: 239 BufferedValuesDealiaser(JavaThread* thread); 240 VTBuffer::Mark current_mark() const { return _current_mark; } 241 void oops_do(OopClosure* f, oop value); 242 243 ~BufferedValuesDealiaser(); 244 }; 245 246 #endif /* SHARE_VM_MEMORY_VTBUFFER_HPP */ |