1 | /* |
2 | * Copyright (c) 2015, 2019, 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_CODE_DEPENDENCYCONTEXT_HPP |
26 | #define SHARE_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 | volatile int _count; |
52 | nmethodBucket* volatile _next; |
53 | nmethodBucket* volatile _purge_list_next; |
54 | |
55 | public: |
56 | nmethodBucket(nmethod* nmethod, nmethodBucket* next) : |
57 | _nmethod(nmethod), _count(1), _next(next), _purge_list_next(NULL) {} |
58 | |
59 | int count() { return _count; } |
60 | int increment() { _count += 1; return _count; } |
61 | int decrement(); |
62 | nmethodBucket* next(); |
63 | nmethodBucket* next_not_unloading(); |
64 | void set_next(nmethodBucket* b); |
65 | nmethodBucket* purge_list_next(); |
66 | void set_purge_list_next(nmethodBucket* b); |
67 | nmethod* get_nmethod() { return _nmethod; } |
68 | }; |
69 | |
70 | // |
71 | // Utility class to manipulate nmethod dependency context. |
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 nmethodBucket* value |
75 | // and uint64_t integer recording the safepoint counter at the last cleanup. |
76 | // |
77 | class DependencyContext : public StackObj { |
78 | friend class VMStructs; |
79 | friend class TestDependencyContext; |
80 | private: |
81 | nmethodBucket* volatile* _dependency_context_addr; |
82 | volatile uint64_t* _last_cleanup_addr; |
83 | |
84 | bool claim_cleanup(); |
85 | void set_dependencies(nmethodBucket* b); |
86 | nmethodBucket* dependencies(); |
87 | nmethodBucket* dependencies_not_unloading(); |
88 | |
89 | static PerfCounter* _perf_total_buckets_allocated_count; |
90 | static PerfCounter* _perf_total_buckets_deallocated_count; |
91 | static PerfCounter* _perf_total_buckets_stale_count; |
92 | static PerfCounter* _perf_total_buckets_stale_acc_count; |
93 | static nmethodBucket* volatile _purge_list; |
94 | static uint64_t _cleaning_epoch_monotonic; |
95 | static volatile uint64_t _cleaning_epoch; |
96 | |
97 | public: |
98 | #ifdef ASSERT |
99 | // Safepoints are forbidden during DC lifetime. GC can invalidate |
100 | // _dependency_context_addr if it relocates the holder |
101 | // (e.g. CallSiteContext Java object). |
102 | SafepointStateTracker _safepoint_tracker; |
103 | |
104 | DependencyContext(nmethodBucket* volatile* bucket_addr, volatile uint64_t* last_cleanup_addr) |
105 | : _dependency_context_addr(bucket_addr), |
106 | _last_cleanup_addr(last_cleanup_addr), |
107 | _safepoint_tracker(SafepointSynchronize::safepoint_state_tracker()) {} |
108 | |
109 | ~DependencyContext() { |
110 | assert(!_safepoint_tracker.safepoint_state_changed(), "must be the same safepoint" ); |
111 | } |
112 | #else |
113 | DependencyContext(nmethodBucket* volatile* bucket_addr, volatile uint64_t* last_cleanup_addr) |
114 | : _dependency_context_addr(bucket_addr), |
115 | _last_cleanup_addr(last_cleanup_addr) {} |
116 | #endif // ASSERT |
117 | |
118 | static void init(); |
119 | |
120 | int mark_dependent_nmethods(DepChange& changes); |
121 | void add_dependent_nmethod(nmethod* nm); |
122 | void remove_dependent_nmethod(nmethod* nm); |
123 | int remove_all_dependents(); |
124 | void clean_unloading_dependents(); |
125 | static void purge_dependency_contexts(); |
126 | static void release(nmethodBucket* b); |
127 | static void cleaning_start(); |
128 | static void cleaning_end(); |
129 | |
130 | #ifndef PRODUCT |
131 | void print_dependent_nmethods(bool verbose); |
132 | bool is_dependent_nmethod(nmethod* nm); |
133 | #endif //PRODUCT |
134 | }; |
135 | #endif // SHARE_CODE_DEPENDENCYCONTEXT_HPP |
136 | |