1 | /* |
2 | * Copyright (c) 1997, 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 | #include "precompiled.hpp" |
26 | #include "code/codeCache.hpp" |
27 | #include "code/compiledIC.hpp" |
28 | #include "code/icBuffer.hpp" |
29 | #include "code/nmethod.hpp" |
30 | #include "code/scopeDesc.hpp" |
31 | #include "gc/shared/collectedHeap.inline.hpp" |
32 | #include "interpreter/interpreter.hpp" |
33 | #include "interpreter/linkResolver.hpp" |
34 | #include "memory/resourceArea.hpp" |
35 | #include "oops/method.hpp" |
36 | #include "oops/oop.inline.hpp" |
37 | #include "runtime/handles.inline.hpp" |
38 | #include "runtime/mutexLocker.hpp" |
39 | #include "runtime/stubRoutines.hpp" |
40 | #include "runtime/thread.hpp" |
41 | |
42 | DEF_STUB_INTERFACE(ICStub); |
43 | |
44 | StubQueue* InlineCacheBuffer::_buffer = NULL; |
45 | |
46 | CompiledICHolder* InlineCacheBuffer::_pending_released = NULL; |
47 | int InlineCacheBuffer::_pending_count = 0; |
48 | |
49 | #ifdef ASSERT |
50 | ICRefillVerifier::ICRefillVerifier() |
51 | : _refill_requested(false), |
52 | _refill_remembered(false) |
53 | { |
54 | Thread* thread = Thread::current(); |
55 | assert(thread->missed_ic_stub_refill_verifier() == NULL, "nesting not supported" ); |
56 | thread->set_missed_ic_stub_refill_verifier(this); |
57 | } |
58 | |
59 | ICRefillVerifier::~ICRefillVerifier() { |
60 | assert(!_refill_requested || _refill_remembered, |
61 | "Forgot to refill IC stubs after failed IC transition" ); |
62 | Thread::current()->set_missed_ic_stub_refill_verifier(NULL); |
63 | } |
64 | |
65 | ICRefillVerifierMark::ICRefillVerifierMark(ICRefillVerifier* verifier) { |
66 | Thread* thread = Thread::current(); |
67 | assert(thread->missed_ic_stub_refill_verifier() == NULL, "nesting not supported" ); |
68 | thread->set_missed_ic_stub_refill_verifier(verifier); |
69 | } |
70 | |
71 | ICRefillVerifierMark::~ICRefillVerifierMark() { |
72 | Thread::current()->set_missed_ic_stub_refill_verifier(NULL); |
73 | } |
74 | |
75 | static ICRefillVerifier* current_ic_refill_verifier() { |
76 | Thread* current = Thread::current(); |
77 | ICRefillVerifier* verifier = current->missed_ic_stub_refill_verifier(); |
78 | assert(verifier != NULL, "need a verifier for safety" ); |
79 | return verifier; |
80 | } |
81 | #endif |
82 | |
83 | void ICStub::finalize() { |
84 | if (!is_empty()) { |
85 | ResourceMark rm; |
86 | CompiledIC *ic = CompiledIC_at(CodeCache::find_compiled(ic_site()), ic_site()); |
87 | assert(CodeCache::find_compiled(ic->instruction_address()) != NULL, "inline cache in non-compiled?" ); |
88 | |
89 | assert(this == ICStub_from_destination_address(ic->stub_address()), "wrong owner of ic buffer" ); |
90 | ic->set_ic_destination_and_value(destination(), cached_value()); |
91 | } |
92 | } |
93 | |
94 | |
95 | address ICStub::destination() const { |
96 | return InlineCacheBuffer::ic_buffer_entry_point(code_begin()); |
97 | } |
98 | |
99 | void* ICStub::cached_value() const { |
100 | return InlineCacheBuffer::ic_buffer_cached_value(code_begin()); |
101 | } |
102 | |
103 | |
104 | void ICStub::set_stub(CompiledIC *ic, void* cached_val, address dest_addr) { |
105 | // We cannot store a pointer to the 'ic' object, since it is resource allocated. Instead we |
106 | // store the location of the inline cache. Then we have enough information recreate the CompiledIC |
107 | // object when we need to remove the stub. |
108 | _ic_site = ic->instruction_address(); |
109 | |
110 | // Assemble new stub |
111 | InlineCacheBuffer::assemble_ic_buffer_code(code_begin(), cached_val, dest_addr); |
112 | assert(destination() == dest_addr, "can recover destination" ); |
113 | assert(cached_value() == cached_val, "can recover destination" ); |
114 | } |
115 | |
116 | |
117 | void ICStub::clear() { |
118 | if (CompiledIC::is_icholder_entry(destination())) { |
119 | InlineCacheBuffer::queue_for_release((CompiledICHolder*)cached_value()); |
120 | } |
121 | _ic_site = NULL; |
122 | } |
123 | |
124 | |
125 | #ifndef PRODUCT |
126 | // anybody calling to this stub will trap |
127 | |
128 | void ICStub::verify() { |
129 | } |
130 | |
131 | void ICStub::print() { |
132 | tty->print_cr("ICStub: site: " INTPTR_FORMAT, p2i(_ic_site)); |
133 | } |
134 | #endif |
135 | |
136 | //----------------------------------------------------------------------------------------------- |
137 | // Implementation of InlineCacheBuffer |
138 | |
139 | |
140 | void InlineCacheBuffer::initialize() { |
141 | if (_buffer != NULL) return; // already initialized |
142 | _buffer = new StubQueue(new ICStubInterface, 10*K, InlineCacheBuffer_lock, "InlineCacheBuffer" ); |
143 | assert (_buffer != NULL, "cannot allocate InlineCacheBuffer" ); |
144 | } |
145 | |
146 | |
147 | ICStub* InlineCacheBuffer::new_ic_stub() { |
148 | return (ICStub*)buffer()->request_committed(ic_stub_code_size()); |
149 | } |
150 | |
151 | |
152 | void InlineCacheBuffer::refill_ic_stubs() { |
153 | #ifdef ASSERT |
154 | ICRefillVerifier* verifier = current_ic_refill_verifier(); |
155 | verifier->request_remembered(); |
156 | #endif |
157 | // we ran out of inline cache buffer space; must enter safepoint. |
158 | // We do this by forcing a safepoint |
159 | EXCEPTION_MARK; |
160 | |
161 | VM_ICBufferFull ibf; |
162 | VMThread::execute(&ibf); |
163 | // We could potential get an async. exception at this point. |
164 | // In that case we will rethrow it to ourselvs. |
165 | if (HAS_PENDING_EXCEPTION) { |
166 | oop exception = PENDING_EXCEPTION; |
167 | CLEAR_PENDING_EXCEPTION; |
168 | Thread::send_async_exception(JavaThread::current()->threadObj(), exception); |
169 | } |
170 | } |
171 | |
172 | |
173 | void InlineCacheBuffer::update_inline_caches() { |
174 | if (buffer()->number_of_stubs() > 0) { |
175 | if (TraceICBuffer) { |
176 | tty->print_cr("[updating inline caches with %d stubs]" , buffer()->number_of_stubs()); |
177 | } |
178 | buffer()->remove_all(); |
179 | } |
180 | release_pending_icholders(); |
181 | } |
182 | |
183 | |
184 | bool InlineCacheBuffer::contains(address instruction_address) { |
185 | return buffer()->contains(instruction_address); |
186 | } |
187 | |
188 | |
189 | bool InlineCacheBuffer::is_empty() { |
190 | return buffer()->number_of_stubs() == 0; |
191 | } |
192 | |
193 | |
194 | void InlineCacheBuffer_init() { |
195 | InlineCacheBuffer::initialize(); |
196 | } |
197 | |
198 | bool InlineCacheBuffer::create_transition_stub(CompiledIC *ic, void* cached_value, address entry) { |
199 | assert(!SafepointSynchronize::is_at_safepoint(), "should not be called during a safepoint" ); |
200 | assert(CompiledICLocker::is_safe(ic->instruction_address()), "mt unsafe call" ); |
201 | if (TraceICBuffer) { |
202 | tty->print_cr(" create transition stub for " INTPTR_FORMAT " destination " INTPTR_FORMAT " cached value " INTPTR_FORMAT, |
203 | p2i(ic->instruction_address()), p2i(entry), p2i(cached_value)); |
204 | } |
205 | |
206 | // allocate and initialize new "out-of-line" inline-cache |
207 | ICStub* ic_stub = new_ic_stub(); |
208 | if (ic_stub == NULL) { |
209 | #ifdef ASSERT |
210 | ICRefillVerifier* verifier = current_ic_refill_verifier(); |
211 | verifier->request_refill(); |
212 | #endif |
213 | return false; |
214 | } |
215 | |
216 | // If an transition stub is already associate with the inline cache, then we remove the association. |
217 | if (ic->is_in_transition_state()) { |
218 | ICStub* old_stub = ICStub_from_destination_address(ic->stub_address()); |
219 | old_stub->clear(); |
220 | } |
221 | |
222 | ic_stub->set_stub(ic, cached_value, entry); |
223 | |
224 | // Update inline cache in nmethod to point to new "out-of-line" allocated inline cache |
225 | ic->set_ic_destination(ic_stub); |
226 | return true; |
227 | } |
228 | |
229 | |
230 | address InlineCacheBuffer::ic_destination_for(CompiledIC *ic) { |
231 | ICStub* stub = ICStub_from_destination_address(ic->stub_address()); |
232 | return stub->destination(); |
233 | } |
234 | |
235 | |
236 | void* InlineCacheBuffer::cached_value_for(CompiledIC *ic) { |
237 | ICStub* stub = ICStub_from_destination_address(ic->stub_address()); |
238 | return stub->cached_value(); |
239 | } |
240 | |
241 | |
242 | // Free CompiledICHolder*s that are no longer in use |
243 | void InlineCacheBuffer::release_pending_icholders() { |
244 | assert(SafepointSynchronize::is_at_safepoint(), "should only be called during a safepoint" ); |
245 | CompiledICHolder* holder = _pending_released; |
246 | _pending_released = NULL; |
247 | while (holder != NULL) { |
248 | CompiledICHolder* next = holder->next(); |
249 | delete holder; |
250 | holder = next; |
251 | _pending_count--; |
252 | } |
253 | assert(_pending_count == 0, "wrong count" ); |
254 | } |
255 | |
256 | // Enqueue this icholder for release during the next safepoint. It's |
257 | // not safe to free them until them since they might be visible to |
258 | // another thread. |
259 | void InlineCacheBuffer::queue_for_release(CompiledICHolder* icholder) { |
260 | MutexLocker mex(InlineCacheBuffer_lock, Mutex::_no_safepoint_check_flag); |
261 | icholder->set_next(_pending_released); |
262 | _pending_released = icholder; |
263 | _pending_count++; |
264 | if (TraceICBuffer) { |
265 | tty->print_cr("enqueueing icholder " INTPTR_FORMAT " to be freed" , p2i(icholder)); |
266 | } |
267 | } |
268 | |