OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 11 matching lines...) Expand all Loading... |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "optimizing-compiler-thread.h" | 28 #include "optimizing-compiler-thread.h" |
29 | 29 |
30 #include "v8.h" | 30 #include "v8.h" |
31 | 31 |
| 32 #include "full-codegen.h" |
32 #include "hydrogen.h" | 33 #include "hydrogen.h" |
33 #include "isolate.h" | 34 #include "isolate.h" |
34 #include "v8threads.h" | 35 #include "v8threads.h" |
35 | 36 |
36 namespace v8 { | 37 namespace v8 { |
37 namespace internal { | 38 namespace internal { |
38 | 39 |
39 | 40 |
40 void OptimizingCompilerThread::Run() { | 41 void OptimizingCompilerThread::Run() { |
41 #ifdef DEBUG | 42 #ifdef DEBUG |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(-1)); | 101 Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(-1)); |
101 | 102 |
102 // The function may have already been optimized by OSR. Simply continue. | 103 // The function may have already been optimized by OSR. Simply continue. |
103 OptimizingCompiler::Status status = optimizing_compiler->OptimizeGraph(); | 104 OptimizingCompiler::Status status = optimizing_compiler->OptimizeGraph(); |
104 USE(status); // Prevent an unused-variable error in release mode. | 105 USE(status); // Prevent an unused-variable error in release mode. |
105 ASSERT(status != OptimizingCompiler::FAILED); | 106 ASSERT(status != OptimizingCompiler::FAILED); |
106 | 107 |
107 // The function may have already been optimized by OSR. Simply continue. | 108 // The function may have already been optimized by OSR. Simply continue. |
108 // Use a mutex to make sure that functions marked for install | 109 // Use a mutex to make sure that functions marked for install |
109 // are always also queued. | 110 // are always also queued. |
110 if (!optimizing_compiler->info()->osr_ast_id().IsNone()) { | 111 LockGuard<Mutex> access_queue(&queue_mutex_); |
111 ASSERT(FLAG_concurrent_osr); | 112 output_queue_.Enqueue(optimizing_compiler); |
112 LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | 113 isolate_->stack_guard()->RequestInstallCode(); |
113 osr_candidates_.RemoveElement(optimizing_compiler); | |
114 ready_for_osr_.Add(optimizing_compiler); | |
115 } else { | |
116 LockGuard<Mutex> access_queue(&queue_mutex_); | |
117 output_queue_.Enqueue(optimizing_compiler); | |
118 isolate_->stack_guard()->RequestInstallCode(); | |
119 } | |
120 } | 114 } |
121 | 115 |
122 | 116 |
| 117 static void DisposeOptimizingCompiler(OptimizingCompiler* compiler, |
| 118 bool restore_function_code) { |
| 119 CompilationInfo* info = compiler->info(); |
| 120 if (restore_function_code) { |
| 121 Handle<JSFunction> function = info->closure(); |
| 122 function->ReplaceCode(function->shared()->code()); |
| 123 } |
| 124 delete info; |
| 125 } |
| 126 |
| 127 |
123 void OptimizingCompilerThread::FlushInputQueue(bool restore_function_code) { | 128 void OptimizingCompilerThread::FlushInputQueue(bool restore_function_code) { |
124 OptimizingCompiler* optimizing_compiler; | 129 OptimizingCompiler* optimizing_compiler; |
125 // The optimizing compiler is allocated in the CompilationInfo's zone. | 130 // The optimizing compiler is allocated in the CompilationInfo's zone. |
126 while (input_queue_.Dequeue(&optimizing_compiler)) { | 131 while (input_queue_.Dequeue(&optimizing_compiler)) { |
127 // This should not block, since we have one signal on the input queue | 132 // This should not block, since we have one signal on the input queue |
128 // semaphore corresponding to each element in the input queue. | 133 // semaphore corresponding to each element in the input queue. |
129 input_queue_semaphore_.Wait(); | 134 input_queue_semaphore_.Wait(); |
130 CompilationInfo* info = optimizing_compiler->info(); | 135 if (optimizing_compiler->info()->osr_ast_id().IsNone()) { |
131 if (restore_function_code) { | 136 // OSR jobs are dealt with separately. |
132 Handle<JSFunction> function = info->closure(); | 137 DisposeOptimizingCompiler(optimizing_compiler, restore_function_code); |
133 function->ReplaceCode(function->shared()->code()); | |
134 } | 138 } |
135 delete info; | |
136 } | 139 } |
137 Release_Store(&queue_length_, static_cast<AtomicWord>(0)); | 140 Release_Store(&queue_length_, static_cast<AtomicWord>(0)); |
138 | |
139 LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | |
140 osr_candidates_.Clear(); | |
141 } | 141 } |
142 | 142 |
143 | 143 |
144 void OptimizingCompilerThread::FlushOutputQueue(bool restore_function_code) { | 144 void OptimizingCompilerThread::FlushOutputQueue(bool restore_function_code) { |
145 OptimizingCompiler* optimizing_compiler; | 145 OptimizingCompiler* optimizing_compiler; |
146 // The optimizing compiler is allocated in the CompilationInfo's zone. | 146 // The optimizing compiler is allocated in the CompilationInfo's zone. |
147 while (true) { | 147 while (true) { |
148 { LockGuard<Mutex> access_queue(&queue_mutex_); | 148 { LockGuard<Mutex> access_queue(&queue_mutex_); |
149 if (!output_queue_.Dequeue(&optimizing_compiler)) break; | 149 if (!output_queue_.Dequeue(&optimizing_compiler)) break; |
150 } | 150 } |
151 CompilationInfo* info = optimizing_compiler->info(); | 151 if (optimizing_compiler->info()->osr_ast_id().IsNone()) { |
152 if (restore_function_code) { | 152 // OSR jobs are dealt with separately. |
153 Handle<JSFunction> function = info->closure(); | 153 DisposeOptimizingCompiler(optimizing_compiler, restore_function_code); |
154 function->ReplaceCode(function->shared()->code()); | |
155 } | 154 } |
156 delete info; | |
157 } | 155 } |
158 | |
159 RemoveStaleOSRCandidates(0); | |
160 } | 156 } |
161 | 157 |
162 | 158 |
| 159 void OptimizingCompilerThread::FlushOsrBuffer(bool restore_function_code) { |
| 160 OptimizingCompiler* optimizing_compiler; |
| 161 for (int i = 0; i < osr_buffer_size_; i++) { |
| 162 optimizing_compiler = osr_buffer_[i]; |
| 163 if (optimizing_compiler != NULL) { |
| 164 DisposeOptimizingCompiler(optimizing_compiler, restore_function_code); |
| 165 } |
| 166 } |
| 167 osr_cursor_ = 0; |
| 168 } |
| 169 |
| 170 |
163 void OptimizingCompilerThread::Flush() { | 171 void OptimizingCompilerThread::Flush() { |
164 ASSERT(!IsOptimizerThread()); | 172 ASSERT(!IsOptimizerThread()); |
165 Release_Store(&stop_thread_, static_cast<AtomicWord>(FLUSH)); | 173 Release_Store(&stop_thread_, static_cast<AtomicWord>(FLUSH)); |
166 input_queue_semaphore_.Signal(); | 174 input_queue_semaphore_.Signal(); |
167 stop_semaphore_.Wait(); | 175 stop_semaphore_.Wait(); |
168 FlushOutputQueue(true); | 176 FlushOutputQueue(true); |
| 177 if (FLAG_concurrent_osr) FlushOsrBuffer(true); |
169 } | 178 } |
170 | 179 |
171 | 180 |
172 void OptimizingCompilerThread::Stop() { | 181 void OptimizingCompilerThread::Stop() { |
173 ASSERT(!IsOptimizerThread()); | 182 ASSERT(!IsOptimizerThread()); |
174 Release_Store(&stop_thread_, static_cast<AtomicWord>(STOP)); | 183 Release_Store(&stop_thread_, static_cast<AtomicWord>(STOP)); |
175 input_queue_semaphore_.Signal(); | 184 input_queue_semaphore_.Signal(); |
176 stop_semaphore_.Wait(); | 185 stop_semaphore_.Wait(); |
177 | 186 |
178 if (FLAG_concurrent_recompilation_delay != 0) { | 187 if (FLAG_concurrent_recompilation_delay != 0) { |
179 // Barrier when loading queue length is not necessary since the write | 188 // Barrier when loading queue length is not necessary since the write |
180 // happens in CompileNext on the same thread. | 189 // happens in CompileNext on the same thread. |
181 // This is used only for testing. | 190 // This is used only for testing. |
182 while (NoBarrier_Load(&queue_length_) > 0) CompileNext(); | 191 while (NoBarrier_Load(&queue_length_) > 0) CompileNext(); |
183 InstallOptimizedFunctions(); | 192 InstallOptimizedFunctions(); |
184 } else { | 193 } else { |
185 FlushInputQueue(false); | 194 FlushInputQueue(false); |
186 FlushOutputQueue(false); | 195 FlushOutputQueue(false); |
187 } | 196 } |
188 | 197 |
| 198 if (FLAG_concurrent_osr) FlushOsrBuffer(false); |
| 199 |
189 if (FLAG_trace_concurrent_recompilation) { | 200 if (FLAG_trace_concurrent_recompilation) { |
190 double percentage = time_spent_compiling_.PercentOf(time_spent_total_); | 201 double percentage = time_spent_compiling_.PercentOf(time_spent_total_); |
191 PrintF(" ** Compiler thread did %.2f%% useful work\n", percentage); | 202 PrintF(" ** Compiler thread did %.2f%% useful work\n", percentage); |
192 } | 203 } |
193 | 204 |
194 if (FLAG_trace_osr && FLAG_concurrent_osr) { | 205 if ((FLAG_trace_osr || FLAG_trace_concurrent_recompilation) && |
| 206 FLAG_concurrent_osr) { |
195 PrintF("[COSR hit rate %d / %d]\n", osr_hits_, osr_attempts_); | 207 PrintF("[COSR hit rate %d / %d]\n", osr_hits_, osr_attempts_); |
196 } | 208 } |
197 | 209 |
198 Join(); | 210 Join(); |
199 } | 211 } |
200 | 212 |
201 | 213 |
202 void OptimizingCompilerThread::InstallOptimizedFunctions() { | 214 void OptimizingCompilerThread::InstallOptimizedFunctions() { |
203 ASSERT(!IsOptimizerThread()); | 215 ASSERT(!IsOptimizerThread()); |
204 HandleScope handle_scope(isolate_); | 216 HandleScope handle_scope(isolate_); |
205 | 217 |
206 OptimizingCompiler* compiler; | 218 OptimizingCompiler* compiler; |
207 while (true) { | 219 while (true) { |
208 { LockGuard<Mutex> access_queue(&queue_mutex_); | 220 { LockGuard<Mutex> access_queue(&queue_mutex_); |
209 if (!output_queue_.Dequeue(&compiler)) break; | 221 if (!output_queue_.Dequeue(&compiler)) break; |
210 } | 222 } |
211 Compiler::InstallOptimizedCode(compiler); | 223 CompilationInfo* info = compiler->info(); |
| 224 if (info->osr_ast_id().IsNone()) { |
| 225 Compiler::InstallOptimizedCode(compiler); |
| 226 } else { |
| 227 if (FLAG_trace_osr) { |
| 228 PrintF("[COSR - "); |
| 229 info->closure()->PrintName(); |
| 230 PrintF(" is ready for install and entry at AST id %d]\n", |
| 231 info->osr_ast_id().ToInt()); |
| 232 } |
| 233 compiler->WaitForInstall(); |
| 234 BackEdgeTable::RemoveStackCheck(info); |
| 235 } |
212 } | 236 } |
213 | |
214 // Remove the oldest OSR candidates that are ready so that we | |
215 // only have limited number of them waiting. | |
216 if (FLAG_concurrent_osr) RemoveStaleOSRCandidates(); | |
217 } | 237 } |
218 | 238 |
219 | 239 |
220 void OptimizingCompilerThread::QueueForOptimization( | 240 void OptimizingCompilerThread::QueueForOptimization( |
221 OptimizingCompiler* optimizing_compiler) { | 241 OptimizingCompiler* optimizing_compiler) { |
222 ASSERT(IsQueueAvailable()); | 242 ASSERT(IsQueueAvailable()); |
223 ASSERT(!IsOptimizerThread()); | 243 ASSERT(!IsOptimizerThread()); |
224 Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(1)); | 244 Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(1)); |
225 if (optimizing_compiler->info()->osr_ast_id().IsNone()) { | 245 CompilationInfo* info = optimizing_compiler->info(); |
226 optimizing_compiler->info()->closure()->MarkInRecompileQueue(); | 246 if (info->osr_ast_id().IsNone()) { |
| 247 info->closure()->MarkInRecompileQueue(); |
227 } else { | 248 } else { |
228 LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | 249 if (FLAG_trace_concurrent_recompilation) { |
229 osr_candidates_.Add(optimizing_compiler); | 250 PrintF(" ** Queueing "); |
| 251 info->closure()->PrintName(); |
| 252 PrintF(" for concurrent on-stack replacement.\n"); |
| 253 } |
| 254 AddToOsrBuffer(optimizing_compiler); |
230 osr_attempts_++; | 255 osr_attempts_++; |
| 256 BackEdgeTable::AddStackCheck(info); |
231 } | 257 } |
232 input_queue_.Enqueue(optimizing_compiler); | 258 input_queue_.Enqueue(optimizing_compiler); |
233 input_queue_semaphore_.Signal(); | 259 input_queue_semaphore_.Signal(); |
234 } | 260 } |
235 | 261 |
236 | 262 |
237 OptimizingCompiler* OptimizingCompilerThread::FindReadyOSRCandidate( | 263 OptimizingCompiler* OptimizingCompilerThread::FindReadyOSRCandidate( |
238 Handle<JSFunction> function, uint32_t osr_pc_offset) { | 264 Handle<JSFunction> function, uint32_t osr_pc_offset) { |
239 ASSERT(!IsOptimizerThread()); | 265 ASSERT(!IsOptimizerThread()); |
240 OptimizingCompiler* result = NULL; | 266 OptimizingCompiler* result = NULL; |
241 { LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | 267 for (int i = 0; i < osr_buffer_size_; i++) { |
242 for (int i = 0; i < ready_for_osr_.length(); i++) { | 268 result = osr_buffer_[i]; |
243 if (ready_for_osr_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) { | 269 if (result == NULL) continue; |
244 osr_hits_++; | 270 if (result->IsWaitingForInstall() && |
245 result = ready_for_osr_.Remove(i); | 271 result->info()->HasSameOsrEntry(function, osr_pc_offset)) { |
246 break; | 272 osr_hits_++; |
247 } | 273 osr_buffer_[i] = NULL; |
| 274 return result; |
248 } | 275 } |
249 } | 276 } |
250 RemoveStaleOSRCandidates(); | 277 return NULL; |
251 return result; | |
252 } | 278 } |
253 | 279 |
254 | 280 |
255 bool OptimizingCompilerThread::IsQueuedForOSR(Handle<JSFunction> function, | 281 bool OptimizingCompilerThread::IsQueuedForOSR(Handle<JSFunction> function, |
256 uint32_t osr_pc_offset) { | 282 uint32_t osr_pc_offset) { |
257 ASSERT(!IsOptimizerThread()); | 283 ASSERT(!IsOptimizerThread()); |
258 LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | 284 for (int i = 0; i < osr_buffer_size_; i++) { |
259 for (int i = 0; i < osr_candidates_.length(); i++) { | 285 if (osr_buffer_[i] != NULL && |
260 if (osr_candidates_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) { | 286 osr_buffer_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) { |
261 return true; | 287 return !osr_buffer_[i]->IsWaitingForInstall(); |
262 } | 288 } |
263 } | 289 } |
264 return false; | 290 return false; |
265 } | 291 } |
266 | 292 |
267 | 293 |
268 bool OptimizingCompilerThread::IsQueuedForOSR(JSFunction* function) { | 294 bool OptimizingCompilerThread::IsQueuedForOSR(JSFunction* function) { |
269 ASSERT(!IsOptimizerThread()); | 295 ASSERT(!IsOptimizerThread()); |
270 LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | 296 for (int i = 0; i < osr_buffer_size_; i++) { |
271 for (int i = 0; i < osr_candidates_.length(); i++) { | 297 if (osr_buffer_[i] != NULL && |
272 if (*osr_candidates_[i]->info()->closure() == function) { | 298 *osr_buffer_[i]->info()->closure() == function) { |
273 return true; | 299 return !osr_buffer_[i]->IsWaitingForInstall(); |
274 } | 300 } |
275 } | 301 } |
276 return false; | 302 return false; |
277 } | 303 } |
278 | 304 |
279 | 305 |
280 void OptimizingCompilerThread::RemoveStaleOSRCandidates(int limit) { | 306 void OptimizingCompilerThread::AddToOsrBuffer(OptimizingCompiler* compiler) { |
281 ASSERT(!IsOptimizerThread()); | 307 ASSERT(!IsOptimizerThread()); |
282 LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | 308 // Store into next empty slot or replace next stale OSR job that's waiting |
283 while (ready_for_osr_.length() > limit) { | 309 // in vain. Dispose in the latter case. |
284 OptimizingCompiler* compiler = ready_for_osr_.Remove(0); | 310 OptimizingCompiler* stale; |
285 CompilationInfo* throw_away = compiler->info(); | 311 while (true) { |
286 if (FLAG_trace_osr) { | 312 stale = osr_buffer_[osr_cursor_]; |
287 PrintF("[COSR - Discarded "); | 313 if (stale == NULL) break; |
288 throw_away->closure()->PrintName(); | 314 if (stale->IsWaitingForInstall()) { |
289 PrintF(", AST id %d]\n", | 315 CompilationInfo* info = stale->info(); |
290 throw_away->osr_ast_id().ToInt()); | 316 if (FLAG_trace_osr) { |
| 317 PrintF("[COSR - Discarded "); |
| 318 info->closure()->PrintName(); |
| 319 PrintF(", AST id %d]\n", info->osr_ast_id().ToInt()); |
| 320 } |
| 321 BackEdgeTable::RemoveStackCheck(info); |
| 322 DisposeOptimizingCompiler(stale, false); |
| 323 break; |
291 } | 324 } |
292 delete throw_away; | 325 AdvanceOsrCursor(); |
293 } | 326 } |
| 327 |
| 328 osr_buffer_[osr_cursor_] = compiler; |
| 329 AdvanceOsrCursor(); |
294 } | 330 } |
295 | 331 |
296 | 332 |
297 #ifdef DEBUG | 333 #ifdef DEBUG |
298 bool OptimizingCompilerThread::IsOptimizerThread() { | 334 bool OptimizingCompilerThread::IsOptimizerThread() { |
299 if (!FLAG_concurrent_recompilation) return false; | 335 if (!FLAG_concurrent_recompilation) return false; |
300 LockGuard<Mutex> lock_guard(&thread_id_mutex_); | 336 LockGuard<Mutex> lock_guard(&thread_id_mutex_); |
301 return ThreadId::Current().ToInteger() == thread_id_; | 337 return ThreadId::Current().ToInteger() == thread_id_; |
302 } | 338 } |
303 #endif | 339 #endif |
304 | 340 |
305 | 341 |
306 } } // namespace v8::internal | 342 } } // namespace v8::internal |
OLD | NEW |