40 #include "runtime/stubRoutines.hpp" |
40 #include "runtime/stubRoutines.hpp" |
41 |
41 |
42 DEF_STUB_INTERFACE(ICStub); |
42 DEF_STUB_INTERFACE(ICStub); |
43 |
43 |
44 StubQueue* InlineCacheBuffer::_buffer = NULL; |
44 StubQueue* InlineCacheBuffer::_buffer = NULL; |
45 ICStub* InlineCacheBuffer::_next_stub = NULL; |
|
46 |
45 |
47 CompiledICHolder* InlineCacheBuffer::_pending_released = NULL; |
46 CompiledICHolder* InlineCacheBuffer::_pending_released = NULL; |
48 int InlineCacheBuffer::_pending_count = 0; |
47 int InlineCacheBuffer::_pending_count = 0; |
|
48 DEBUG_ONLY(volatile int InlineCacheBuffer::_needs_refill = 0;) |
49 |
49 |
50 void ICStub::finalize() { |
50 void ICStub::finalize() { |
51 if (!is_empty()) { |
51 if (!is_empty()) { |
52 ResourceMark rm; |
52 ResourceMark rm; |
53 CompiledIC *ic = CompiledIC_at(CodeCache::find_compiled(ic_site()), ic_site()); |
53 CompiledIC *ic = CompiledIC_at(CodeCache::find_compiled(ic_site()), ic_site()); |
101 #endif |
101 #endif |
102 |
102 |
103 //----------------------------------------------------------------------------------------------- |
103 //----------------------------------------------------------------------------------------------- |
104 // Implementation of InlineCacheBuffer |
104 // Implementation of InlineCacheBuffer |
105 |
105 |
106 void InlineCacheBuffer::init_next_stub() { |
|
107 ICStub* ic_stub = (ICStub*)buffer()->request_committed (ic_stub_code_size()); |
|
108 assert (ic_stub != NULL, "no room for a single stub"); |
|
109 set_next_stub(ic_stub); |
|
110 } |
|
111 |
106 |
112 void InlineCacheBuffer::initialize() { |
107 void InlineCacheBuffer::initialize() { |
113 if (_buffer != NULL) return; // already initialized |
108 if (_buffer != NULL) return; // already initialized |
114 _buffer = new StubQueue(new ICStubInterface, 10*K, InlineCacheBuffer_lock, "InlineCacheBuffer"); |
109 _buffer = new StubQueue(new ICStubInterface, 10*K, InlineCacheBuffer_lock, "InlineCacheBuffer"); |
115 assert (_buffer != NULL, "cannot allocate InlineCacheBuffer"); |
110 assert (_buffer != NULL, "cannot allocate InlineCacheBuffer"); |
116 init_next_stub(); |
|
117 } |
111 } |
118 |
112 |
119 |
113 |
120 ICStub* InlineCacheBuffer::new_ic_stub() { |
114 ICStub* InlineCacheBuffer::new_ic_stub() { |
121 while (true) { |
115 return (ICStub*)buffer()->request_committed(ic_stub_code_size()); |
122 ICStub* ic_stub = (ICStub*)buffer()->request_committed(ic_stub_code_size()); |
116 } |
123 if (ic_stub != NULL) { |
117 |
124 return ic_stub; |
118 |
125 } |
119 void InlineCacheBuffer::refill_ic_stubs() { |
126 // we ran out of inline cache buffer space; must enter safepoint. |
120 DEBUG_ONLY(Atomic::store(0, &_needs_refill)); |
127 // We do this by forcing a safepoint |
121 // we ran out of inline cache buffer space; must enter safepoint. |
128 EXCEPTION_MARK; |
122 // We do this by forcing a safepoint |
129 |
123 EXCEPTION_MARK; |
130 VM_ICBufferFull ibf; |
124 |
131 VMThread::execute(&ibf); |
125 VM_ICBufferFull ibf; |
132 // We could potential get an async. exception at this point. |
126 VMThread::execute(&ibf); |
133 // In that case we will rethrow it to ourselvs. |
127 // We could potential get an async. exception at this point. |
134 if (HAS_PENDING_EXCEPTION) { |
128 // In that case we will rethrow it to ourselvs. |
135 oop exception = PENDING_EXCEPTION; |
129 if (HAS_PENDING_EXCEPTION) { |
136 CLEAR_PENDING_EXCEPTION; |
130 oop exception = PENDING_EXCEPTION; |
137 Thread::send_async_exception(JavaThread::current()->threadObj(), exception); |
131 CLEAR_PENDING_EXCEPTION; |
138 } |
132 Thread::send_async_exception(JavaThread::current()->threadObj(), exception); |
139 } |
133 } |
140 ShouldNotReachHere(); |
|
141 return NULL; |
|
142 } |
134 } |
143 |
135 |
144 |
136 |
145 void InlineCacheBuffer::update_inline_caches() { |
137 void InlineCacheBuffer::update_inline_caches() { |
146 if (buffer()->number_of_stubs() > 1) { |
138 assert(_needs_refill == 0, |
|
139 "Forgot to handle a failed IC transition requiring IC stubs"); |
|
140 if (buffer()->number_of_stubs() > 0) { |
147 if (TraceICBuffer) { |
141 if (TraceICBuffer) { |
148 tty->print_cr("[updating inline caches with %d stubs]", buffer()->number_of_stubs()); |
142 tty->print_cr("[updating inline caches with %d stubs]", buffer()->number_of_stubs()); |
149 } |
143 } |
150 buffer()->remove_all(); |
144 buffer()->remove_all(); |
151 init_next_stub(); |
|
152 } |
145 } |
153 release_pending_icholders(); |
146 release_pending_icholders(); |
154 } |
147 } |
155 |
148 |
156 |
149 |
158 return buffer()->contains(instruction_address); |
151 return buffer()->contains(instruction_address); |
159 } |
152 } |
160 |
153 |
161 |
154 |
162 bool InlineCacheBuffer::is_empty() { |
155 bool InlineCacheBuffer::is_empty() { |
163 return buffer()->number_of_stubs() == 1; // always has sentinel |
156 return buffer()->number_of_stubs() == 0; |
164 } |
157 } |
165 |
158 |
166 |
159 |
167 void InlineCacheBuffer_init() { |
160 void InlineCacheBuffer_init() { |
168 InlineCacheBuffer::initialize(); |
161 InlineCacheBuffer::initialize(); |
169 } |
162 } |
170 |
163 |
171 |
164 |
172 void InlineCacheBuffer::create_transition_stub(CompiledIC *ic, void* cached_value, address entry) { |
165 bool InlineCacheBuffer::create_transition_stub(CompiledIC *ic, void* cached_value, address entry) { |
173 MutexLockerEx ml(CompiledIC_lock->owned_by_self() ? NULL : CompiledIC_lock); |
|
174 assert(!SafepointSynchronize::is_at_safepoint(), "should not be called during a safepoint"); |
166 assert(!SafepointSynchronize::is_at_safepoint(), "should not be called during a safepoint"); |
175 assert(CompiledICLocker::is_safe(ic->instruction_address()), "mt unsafe call"); |
167 assert(CompiledICLocker::is_safe(ic->instruction_address()), "mt unsafe call"); |
176 if (TraceICBuffer) { |
168 if (TraceICBuffer) { |
177 tty->print_cr(" create transition stub for " INTPTR_FORMAT " destination " INTPTR_FORMAT " cached value " INTPTR_FORMAT, |
169 tty->print_cr(" create transition stub for " INTPTR_FORMAT " destination " INTPTR_FORMAT " cached value " INTPTR_FORMAT, |
178 p2i(ic->instruction_address()), p2i(entry), p2i(cached_value)); |
170 p2i(ic->instruction_address()), p2i(entry), p2i(cached_value)); |
179 } |
171 } |
180 |
172 |
|
173 // allocate and initialize new "out-of-line" inline-cache |
|
174 ICStub* ic_stub = new_ic_stub(); |
|
175 if (ic_stub == NULL) { |
|
176 DEBUG_ONLY(Atomic::inc(&_needs_refill)); |
|
177 return false; |
|
178 } |
|
179 |
181 // If an transition stub is already associate with the inline cache, then we remove the association. |
180 // If an transition stub is already associate with the inline cache, then we remove the association. |
182 if (ic->is_in_transition_state()) { |
181 if (ic->is_in_transition_state()) { |
183 ICStub* old_stub = ICStub_from_destination_address(ic->stub_address()); |
182 ICStub* old_stub = ICStub_from_destination_address(ic->stub_address()); |
184 old_stub->clear(); |
183 old_stub->clear(); |
185 } |
184 } |
186 |
185 |
187 // allocate and initialize new "out-of-line" inline-cache |
|
188 ICStub* ic_stub = get_next_stub(); |
|
189 ic_stub->set_stub(ic, cached_value, entry); |
186 ic_stub->set_stub(ic, cached_value, entry); |
190 |
187 |
191 // Update inline cache in nmethod to point to new "out-of-line" allocated inline cache |
188 // Update inline cache in nmethod to point to new "out-of-line" allocated inline cache |
192 ic->set_ic_destination(ic_stub); |
189 ic->set_ic_destination(ic_stub); |
193 |
190 return true; |
194 set_next_stub(new_ic_stub()); // can cause safepoint synchronization |
|
195 } |
191 } |
196 |
192 |
197 |
193 |
198 address InlineCacheBuffer::ic_destination_for(CompiledIC *ic) { |
194 address InlineCacheBuffer::ic_destination_for(CompiledIC *ic) { |
199 ICStub* stub = ICStub_from_destination_address(ic->stub_address()); |
195 ICStub* stub = ICStub_from_destination_address(ic->stub_address()); |
223 |
219 |
224 // Enqueue this icholder for release during the next safepoint. It's |
220 // Enqueue this icholder for release during the next safepoint. It's |
225 // not safe to free them until them since they might be visible to |
221 // not safe to free them until them since they might be visible to |
226 // another thread. |
222 // another thread. |
227 void InlineCacheBuffer::queue_for_release(CompiledICHolder* icholder) { |
223 void InlineCacheBuffer::queue_for_release(CompiledICHolder* icholder) { |
228 MutexLockerEx mex1((CompiledIC_lock->owned_by_self() || |
224 MutexLockerEx mex(InlineCacheBuffer_lock, Mutex::_no_safepoint_check_flag); |
229 SafepointSynchronize::is_at_safepoint()) ? NULL : CompiledIC_lock); |
|
230 MutexLockerEx mex2(InlineCacheBuffer_lock); |
|
231 icholder->set_next(_pending_released); |
225 icholder->set_next(_pending_released); |
232 _pending_released = icholder; |
226 _pending_released = icholder; |
233 _pending_count++; |
227 _pending_count++; |
234 if (TraceICBuffer) { |
228 if (TraceICBuffer) { |
235 tty->print_cr("enqueueing icholder " INTPTR_FORMAT " to be freed", p2i(icholder)); |
229 tty->print_cr("enqueueing icholder " INTPTR_FORMAT " to be freed", p2i(icholder)); |