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 : public CMmapObj<VTBufferChunk, mtValueTypes> { 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 _magic = MAGIC_NUMBER; 67 _index = -1; 68 _prev = NULL; 69 _next = NULL; 70 _owner = thread; 71 } 72 73 int index() { return _index; } 74 void set_index(int index) { _index = index; } 75 VTBufferChunk* prev() { return _prev; } 76 void set_prev(VTBufferChunk* prev) { _prev = prev; } 77 VTBufferChunk* next() { return _next; } 78 void set_next(VTBufferChunk* next) { _next = next; } 79 JavaThread* owner() { return _owner; } 80 void set_owner(JavaThread* thread) { 81 assert(thread == NULL || _owner == NULL || _owner == thread, "Sanity check"); 82 _owner = thread; 83 } 84 85 bool is_valid() { 86 return _magic == MAGIC_NUMBER && _owner != NULL && _index != -1; 87 } 88 89 void* first_alloc() { return (void*)((char*)this + align_object_size(sizeof (VTBufferChunk))); } 90 void* alloc_limit() { return (void*)((char*)this + chunk_size() - 1); } 91 92 static int chunk_size() { 93 return os::vm_page_size(); 94 } 95 96 static uintptr_t chunk_mask() { 97 return ~(chunk_size() - 1); 98 } 99 100 static ByteSize index_offset() { return byte_offset_of(VTBufferChunk, _index); } 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 */