1 /* 2 * Copyright (c) 2015, 2018, 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_CODE_DEPENDENCYCONTEXT_HPP 26 #define SHARE_VM_CODE_DEPENDENCYCONTEXT_HPP 27 28 #include "memory/allocation.hpp" 29 #include "oops/oop.hpp" 30 #include "runtime/handles.hpp" 31 #include "runtime/perfData.hpp" 32 #include "runtime/safepoint.hpp" 33 34 class nmethod; 35 class DepChange; 36 37 // 38 // nmethodBucket is used to record dependent nmethods for 39 // deoptimization. nmethod dependencies are actually <klass, method> 40 // pairs but we really only care about the klass part for purposes of 41 // finding nmethods which might need to be deoptimized. Instead of 42 // recording the method, a count of how many times a particular nmethod 43 // was recorded is kept. This ensures that any recording errors are 44 // noticed since an nmethod should be removed as many times are it's 45 // added. 46 // 47 class nmethodBucket: public CHeapObj<mtClass> { 48 friend class VMStructs; 49 private: 50 nmethod* _nmethod; 51 int _count; 52 nmethodBucket* _next; 53 54 public: 55 nmethodBucket(nmethod* nmethod, nmethodBucket* next) : 56 _nmethod(nmethod), _count(1), _next(next) {} 57 58 int count() { return _count; } 59 int increment() { _count += 1; return _count; } 60 int decrement(); 61 nmethodBucket* next() { return _next; } 62 void set_next(nmethodBucket* b) { _next = b; } 63 nmethod* get_nmethod() { return _nmethod; } 64 }; 65 66 // 67 // Utility class to manipulate nmethod dependency context. 68 // The context consists of nmethodBucket* (a head of a linked list) 69 // and a boolean flag (does the list contains stale entries). The structure is 70 // encoded as an intptr_t: lower bit is used for the flag. It is possible since 71 // nmethodBucket* is aligned - the structure is malloc'ed in C heap. 72 // Dependency context can be attached either to an InstanceKlass (_dep_context field) 73 // or CallSiteContext oop for call_site_target dependencies (see javaClasses.hpp). 74 // DependencyContext class operates on some location which holds a intptr_t value. 75 // 76 class DependencyContext : public StackObj { 77 friend class VMStructs; 78 friend class TestDependencyContext; 79 private: 80 enum TagBits { _has_stale_entries_bit = 1, _has_stale_entries_mask = 1 }; 81 82 intptr_t* _dependency_context_addr; 83 84 void set_dependencies(nmethodBucket* b) { 85 assert((intptr_t(b) & _has_stale_entries_mask) == 0, "should be aligned"); 86 if (has_stale_entries()) { 87 *_dependency_context_addr = intptr_t(b) | _has_stale_entries_mask; 88 } else { 89 *_dependency_context_addr = intptr_t(b); 90 } 91 } 92 93 void set_has_stale_entries(bool x) { 94 if (x) { 95 *_dependency_context_addr |= _has_stale_entries_mask; 96 } else { 97 *_dependency_context_addr &= ~_has_stale_entries_mask; 98 } 99 } 100 101 nmethodBucket* dependencies() { 102 intptr_t value = *_dependency_context_addr; 103 return (nmethodBucket*) (value & ~_has_stale_entries_mask); 104 } 105 106 bool has_stale_entries() const { 107 intptr_t value = *_dependency_context_addr; 108 return (value & _has_stale_entries_mask) != 0; 109 } 110 111 static PerfCounter* _perf_total_buckets_allocated_count; 112 static PerfCounter* _perf_total_buckets_deallocated_count; 113 static PerfCounter* _perf_total_buckets_stale_count; 114 static PerfCounter* _perf_total_buckets_stale_acc_count; 115 116 public: 117 #ifdef ASSERT 118 // Safepoints are forbidden during DC lifetime. GC can invalidate 119 // _dependency_context_addr if it relocates the holder 120 // (e.g. CallSiteContext Java object). 121 int _safepoint_counter; 122 123 DependencyContext(intptr_t* addr) : _dependency_context_addr(addr), 124 _safepoint_counter(SafepointSynchronize::_safepoint_counter) {} 125 126 ~DependencyContext() { 127 assert(_safepoint_counter == SafepointSynchronize::_safepoint_counter, "safepoint happened"); 128 } 129 #else 130 DependencyContext(intptr_t* addr) : _dependency_context_addr(addr) {} 131 #endif // ASSERT 132 133 static const intptr_t EMPTY = 0; // dependencies = NULL, has_stale_entries = false 134 135 static void init(); 136 137 int mark_dependent_nmethods(DepChange& changes); 138 void add_dependent_nmethod(nmethod* nm, bool expunge_stale_entries = false); 139 void remove_dependent_nmethod(nmethod* nm, bool expunge_stale_entries = false); 140 int remove_all_dependents(); 141 142 void expunge_stale_entries(); 143 144 #ifndef PRODUCT 145 void print_dependent_nmethods(bool verbose); 146 bool is_dependent_nmethod(nmethod* nm); 147 bool find_stale_entries(); 148 #endif //PRODUCT 149 }; 150 #endif // SHARE_VM_CODE_DEPENDENCYCONTEXT_HPP