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 DisposeOptimizingCompiler(optimizing_compiler, restore_function_code); |
131 if (restore_function_code) { | |
132 Handle<JSFunction> function = info->closure(); | |
133 function->ReplaceCode(function->shared()->code()); | |
134 } | |
135 delete info; | |
136 } | 136 } |
137 Release_Store(&queue_length_, static_cast<AtomicWord>(0)); | 137 Release_Store(&queue_length_, static_cast<AtomicWord>(0)); |
138 | 138 |
139 LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | |
140 osr_candidates_.Clear(); | 139 osr_candidates_.Clear(); |
141 } | 140 } |
142 | 141 |
143 | 142 |
144 void OptimizingCompilerThread::FlushOutputQueue(bool restore_function_code) { | 143 void OptimizingCompilerThread::FlushOutputQueue(bool restore_function_code) { |
145 OptimizingCompiler* optimizing_compiler; | 144 OptimizingCompiler* optimizing_compiler; |
146 // The optimizing compiler is allocated in the CompilationInfo's zone. | 145 // The optimizing compiler is allocated in the CompilationInfo's zone. |
147 while (true) { | 146 while (true) { |
148 { LockGuard<Mutex> access_queue(&queue_mutex_); | 147 { LockGuard<Mutex> access_queue(&queue_mutex_); |
149 if (!output_queue_.Dequeue(&optimizing_compiler)) break; | 148 if (!output_queue_.Dequeue(&optimizing_compiler)) break; |
150 } | 149 } |
151 CompilationInfo* info = optimizing_compiler->info(); | 150 DisposeOptimizingCompiler(optimizing_compiler, restore_function_code); |
152 if (restore_function_code) { | |
153 Handle<JSFunction> function = info->closure(); | |
154 function->ReplaceCode(function->shared()->code()); | |
155 } | |
156 delete info; | |
157 } | 151 } |
158 | 152 |
159 RemoveStaleOSRCandidates(0); | 153 for (int i = 0; i < kOsrBufferSize; i++) { |
154 optimizing_compiler = osr_buffer_[i]; | |
155 if (optimizing_compiler != NULL) { | |
156 DisposeOptimizingCompiler(optimizing_compiler, restore_function_code); | |
157 } | |
158 } | |
159 osr_cursor_ = 0; | |
160 } | 160 } |
161 | 161 |
162 | 162 |
163 void OptimizingCompilerThread::Flush() { | 163 void OptimizingCompilerThread::Flush() { |
164 ASSERT(!IsOptimizerThread()); | 164 ASSERT(!IsOptimizerThread()); |
165 Release_Store(&stop_thread_, static_cast<AtomicWord>(FLUSH)); | 165 Release_Store(&stop_thread_, static_cast<AtomicWord>(FLUSH)); |
166 input_queue_semaphore_.Signal(); | 166 input_queue_semaphore_.Signal(); |
167 stop_semaphore_.Wait(); | 167 stop_semaphore_.Wait(); |
168 FlushOutputQueue(true); | 168 FlushOutputQueue(true); |
169 } | 169 } |
170 | 170 |
171 | 171 |
172 void OptimizingCompilerThread::Stop() { | 172 void OptimizingCompilerThread::Stop() { |
173 ASSERT(!IsOptimizerThread()); | 173 ASSERT(!IsOptimizerThread()); |
174 Release_Store(&stop_thread_, static_cast<AtomicWord>(STOP)); | 174 Release_Store(&stop_thread_, static_cast<AtomicWord>(STOP)); |
175 input_queue_semaphore_.Signal(); | 175 input_queue_semaphore_.Signal(); |
176 stop_semaphore_.Wait(); | 176 stop_semaphore_.Wait(); |
177 | 177 |
178 if (FLAG_concurrent_recompilation_delay != 0) { | 178 if (FLAG_concurrent_recompilation_delay != 0) { |
179 // Barrier when loading queue length is not necessary since the write | 179 // Barrier when loading queue length is not necessary since the write |
180 // happens in CompileNext on the same thread. | 180 // happens in CompileNext on the same thread. |
181 // This is used only for testing. | 181 // This is used only for testing. |
182 while (NoBarrier_Load(&queue_length_) > 0) CompileNext(); | 182 while (NoBarrier_Load(&queue_length_) > 0) CompileNext(); |
183 InstallOptimizedFunctions(); | 183 InstallOptimizedFunctions(); |
184 } else { | 184 } else { |
185 FlushInputQueue(false); | 185 FlushInputQueue(false); |
186 FlushOutputQueue(false); | 186 FlushOutputQueue(false); |
titzer
2013/09/24 09:42:01
Shouldn't you also empty the osr buffer here too?
Yang
2013/09/24 10:07:11
This is already done in FlushOutputQueue.
| |
187 } | 187 } |
188 | 188 |
189 if (FLAG_trace_concurrent_recompilation) { | 189 if (FLAG_trace_concurrent_recompilation) { |
190 double percentage = time_spent_compiling_.PercentOf(time_spent_total_); | 190 double percentage = time_spent_compiling_.PercentOf(time_spent_total_); |
191 PrintF(" ** Compiler thread did %.2f%% useful work\n", percentage); | 191 PrintF(" ** Compiler thread did %.2f%% useful work\n", percentage); |
192 } | 192 } |
193 | 193 |
194 if (FLAG_trace_osr && FLAG_concurrent_osr) { | 194 if ((FLAG_trace_osr || FLAG_trace_concurrent_recompilation) && |
195 FLAG_concurrent_osr) { | |
195 PrintF("[COSR hit rate %d / %d]\n", osr_hits_, osr_attempts_); | 196 PrintF("[COSR hit rate %d / %d]\n", osr_hits_, osr_attempts_); |
196 } | 197 } |
197 | 198 |
198 Join(); | 199 Join(); |
199 } | 200 } |
200 | 201 |
201 | 202 |
202 void OptimizingCompilerThread::InstallOptimizedFunctions() { | 203 void OptimizingCompilerThread::InstallOptimizedFunctions() { |
203 ASSERT(!IsOptimizerThread()); | 204 ASSERT(!IsOptimizerThread()); |
204 HandleScope handle_scope(isolate_); | 205 HandleScope handle_scope(isolate_); |
205 | 206 |
206 OptimizingCompiler* compiler; | 207 OptimizingCompiler* compiler; |
207 while (true) { | 208 while (true) { |
208 { LockGuard<Mutex> access_queue(&queue_mutex_); | 209 { LockGuard<Mutex> access_queue(&queue_mutex_); |
209 if (!output_queue_.Dequeue(&compiler)) break; | 210 if (!output_queue_.Dequeue(&compiler)) break; |
210 } | 211 } |
211 Compiler::InstallOptimizedCode(compiler); | 212 CompilationInfo* info = compiler->info(); |
213 if (info->osr_ast_id().IsNone()) { | |
214 Compiler::InstallOptimizedCode(compiler); | |
215 } else { | |
216 if (FLAG_trace_osr) { | |
217 PrintF("[COSR - "); | |
218 info->closure()->PrintName(); | |
219 PrintF(" is ready for install and entry at AST id %d]\n", | |
220 info->osr_ast_id().ToInt()); | |
221 } | |
222 osr_candidates_.RemoveElement(compiler); | |
223 AddToOsrBuffer(compiler); | |
224 BackEdgeTable::RemoveStackCheck(info); | |
225 } | |
212 } | 226 } |
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 } | 227 } |
218 | 228 |
219 | 229 |
220 void OptimizingCompilerThread::QueueForOptimization( | 230 void OptimizingCompilerThread::QueueForOptimization( |
221 OptimizingCompiler* optimizing_compiler) { | 231 OptimizingCompiler* optimizing_compiler) { |
222 ASSERT(IsQueueAvailable()); | 232 ASSERT(IsQueueAvailable()); |
223 ASSERT(!IsOptimizerThread()); | 233 ASSERT(!IsOptimizerThread()); |
224 Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(1)); | 234 Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(1)); |
225 if (optimizing_compiler->info()->osr_ast_id().IsNone()) { | 235 CompilationInfo* info = optimizing_compiler->info(); |
226 optimizing_compiler->info()->closure()->MarkInRecompileQueue(); | 236 if (info->osr_ast_id().IsNone()) { |
237 info->closure()->MarkInRecompileQueue(); | |
227 } else { | 238 } else { |
228 LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | 239 if (FLAG_trace_concurrent_recompilation) { |
240 PrintF(" ** Queueing "); | |
241 info->closure()->PrintName(); | |
242 PrintF(" for concurrent on-stack replacement.\n"); | |
243 } | |
229 osr_candidates_.Add(optimizing_compiler); | 244 osr_candidates_.Add(optimizing_compiler); |
230 osr_attempts_++; | 245 osr_attempts_++; |
246 BackEdgeTable::AddStackCheck(info); | |
231 } | 247 } |
232 input_queue_.Enqueue(optimizing_compiler); | 248 input_queue_.Enqueue(optimizing_compiler); |
233 input_queue_semaphore_.Signal(); | 249 input_queue_semaphore_.Signal(); |
234 } | 250 } |
235 | 251 |
236 | 252 |
237 OptimizingCompiler* OptimizingCompilerThread::FindReadyOSRCandidate( | 253 OptimizingCompiler* OptimizingCompilerThread::FindReadyOSRCandidate( |
238 Handle<JSFunction> function, uint32_t osr_pc_offset) { | 254 Handle<JSFunction> function, uint32_t osr_pc_offset) { |
239 ASSERT(!IsOptimizerThread()); | 255 ASSERT(!IsOptimizerThread()); |
240 OptimizingCompiler* result = NULL; | 256 OptimizingCompiler* result = NULL; |
241 { LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | 257 for (int i = 0; i < kOsrBufferSize; i++) { |
242 for (int i = 0; i < ready_for_osr_.length(); i++) { | 258 result = osr_buffer_[i]; |
243 if (ready_for_osr_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) { | 259 if (result == NULL) continue; |
244 osr_hits_++; | 260 if (result->info()->HasSameOsrEntry(function, osr_pc_offset)) { |
245 result = ready_for_osr_.Remove(i); | 261 osr_hits_++; |
246 break; | 262 osr_buffer_[i] = NULL; |
247 } | 263 return result; |
248 } | 264 } |
249 } | 265 } |
250 RemoveStaleOSRCandidates(); | 266 return NULL; |
251 return result; | |
252 } | 267 } |
253 | 268 |
254 | 269 |
255 bool OptimizingCompilerThread::IsQueuedForOSR(Handle<JSFunction> function, | 270 bool OptimizingCompilerThread::IsQueuedForOSR(Handle<JSFunction> function, |
256 uint32_t osr_pc_offset) { | 271 uint32_t osr_pc_offset) { |
257 ASSERT(!IsOptimizerThread()); | 272 ASSERT(!IsOptimizerThread()); |
258 LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | |
259 for (int i = 0; i < osr_candidates_.length(); i++) { | 273 for (int i = 0; i < osr_candidates_.length(); i++) { |
260 if (osr_candidates_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) { | 274 if (osr_candidates_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) { |
261 return true; | 275 return true; |
262 } | 276 } |
263 } | 277 } |
264 return false; | 278 return false; |
265 } | 279 } |
266 | 280 |
267 | 281 |
268 bool OptimizingCompilerThread::IsQueuedForOSR(JSFunction* function) { | 282 bool OptimizingCompilerThread::IsQueuedForOSR(JSFunction* function) { |
269 ASSERT(!IsOptimizerThread()); | 283 ASSERT(!IsOptimizerThread()); |
270 LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | |
271 for (int i = 0; i < osr_candidates_.length(); i++) { | 284 for (int i = 0; i < osr_candidates_.length(); i++) { |
272 if (*osr_candidates_[i]->info()->closure() == function) { | 285 if (*osr_candidates_[i]->info()->closure() == function) { |
273 return true; | 286 return true; |
274 } | 287 } |
275 } | 288 } |
276 return false; | 289 return false; |
277 } | 290 } |
278 | 291 |
279 | 292 |
280 void OptimizingCompilerThread::RemoveStaleOSRCandidates(int limit) { | 293 void OptimizingCompilerThread::AddToOsrBuffer(OptimizingCompiler* compiler) { |
281 ASSERT(!IsOptimizerThread()); | 294 ASSERT(!IsOptimizerThread()); |
282 LockGuard<Mutex> access_osr_lists(&osr_list_mutex_); | 295 OptimizingCompiler* stale = osr_buffer_[osr_cursor_]; |
283 while (ready_for_osr_.length() > limit) { | 296 if (stale != NULL) { |
284 OptimizingCompiler* compiler = ready_for_osr_.Remove(0); | 297 CompilationInfo* info = stale->info(); |
285 CompilationInfo* throw_away = compiler->info(); | |
286 if (FLAG_trace_osr) { | 298 if (FLAG_trace_osr) { |
287 PrintF("[COSR - Discarded "); | 299 PrintF("[COSR - Discarded "); |
288 throw_away->closure()->PrintName(); | 300 info->closure()->PrintName(); |
289 PrintF(", AST id %d]\n", | 301 PrintF(", AST id %d]\n", info->osr_ast_id().ToInt()); |
290 throw_away->osr_ast_id().ToInt()); | |
291 } | 302 } |
292 delete throw_away; | 303 BackEdgeTable::RemoveStackCheck(info); |
304 delete info; | |
titzer
2013/09/24 09:42:01
Maybe you want DisposeOptimizingCompiler(stale, fa
Yang
2013/09/24 10:07:11
Done.
| |
293 } | 305 } |
306 | |
307 osr_buffer_[osr_cursor_] = compiler; | |
308 osr_cursor_ = (osr_cursor_ + 1) % kOsrBufferSize; | |
294 } | 309 } |
295 | 310 |
296 | 311 |
297 #ifdef DEBUG | 312 #ifdef DEBUG |
298 bool OptimizingCompilerThread::IsOptimizerThread() { | 313 bool OptimizingCompilerThread::IsOptimizerThread() { |
299 if (!FLAG_concurrent_recompilation) return false; | 314 if (!FLAG_concurrent_recompilation) return false; |
300 LockGuard<Mutex> lock_guard(&thread_id_mutex_); | 315 LockGuard<Mutex> lock_guard(&thread_id_mutex_); |
301 return ThreadId::Current().ToInteger() == thread_id_; | 316 return ThreadId::Current().ToInteger() == thread_id_; |
302 } | 317 } |
303 #endif | 318 #endif |
304 | 319 |
305 | 320 |
306 } } // namespace v8::internal | 321 } } // namespace v8::internal |
OLD | NEW |