Revision f230a1cf deps/v8/src/optimizing-compiler-thread.cc

View differences:

deps/v8/src/optimizing-compiler-thread.cc
29 29

  
30 30
#include "v8.h"
31 31

  
32
#include "full-codegen.h"
32 33
#include "hydrogen.h"
33 34
#include "isolate.h"
34 35
#include "v8threads.h"
......
36 37
namespace v8 {
37 38
namespace internal {
38 39

  
40
OptimizingCompilerThread::~OptimizingCompilerThread() {
41
  ASSERT_EQ(0, input_queue_length_);
42
  DeleteArray(input_queue_);
43
  if (FLAG_concurrent_osr) {
44
#ifdef DEBUG
45
    for (int i = 0; i < osr_buffer_capacity_; i++) {
46
      CHECK_EQ(NULL, osr_buffer_[i]);
47
    }
48
#endif
49
    DeleteArray(osr_buffer_);
50
  }
51
}
52

  
39 53

  
40 54
void OptimizingCompilerThread::Run() {
41 55
#ifdef DEBUG
......
74 88
        { AllowHandleDereference allow_handle_dereference;
75 89
          FlushInputQueue(true);
76 90
        }
77
        Release_Store(&queue_length_, static_cast<AtomicWord>(0));
78 91
        Release_Store(&stop_thread_, static_cast<AtomicWord>(CONTINUE));
79 92
        stop_semaphore_.Signal();
80 93
        // Return to start of consumer loop.
......
93 106
}
94 107

  
95 108

  
109
RecompileJob* OptimizingCompilerThread::NextInput() {
110
  LockGuard<Mutex> access_input_queue_(&input_queue_mutex_);
111
  if (input_queue_length_ == 0) return NULL;
112
  RecompileJob* job = input_queue_[InputQueueIndex(0)];
113
  ASSERT_NE(NULL, job);
114
  input_queue_shift_ = InputQueueIndex(1);
115
  input_queue_length_--;
116
  return job;
117
}
118

  
119

  
96 120
void OptimizingCompilerThread::CompileNext() {
97
  OptimizingCompiler* optimizing_compiler = NULL;
98
  bool result = input_queue_.Dequeue(&optimizing_compiler);
99
  USE(result);
100
  ASSERT(result);
101
  Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(-1));
121
  RecompileJob* job = NextInput();
122
  ASSERT_NE(NULL, job);
102 123

  
103 124
  // The function may have already been optimized by OSR.  Simply continue.
104
  OptimizingCompiler::Status status = optimizing_compiler->OptimizeGraph();
125
  RecompileJob::Status status = job->OptimizeGraph();
105 126
  USE(status);   // Prevent an unused-variable error in release mode.
106
  ASSERT(status != OptimizingCompiler::FAILED);
127
  ASSERT(status != RecompileJob::FAILED);
107 128

  
108 129
  // The function may have already been optimized by OSR.  Simply continue.
109 130
  // Use a mutex to make sure that functions marked for install
110 131
  // are always also queued.
111
  if (!optimizing_compiler->info()->osr_ast_id().IsNone()) {
112
    ASSERT(FLAG_concurrent_osr);
113
    LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
114
    osr_candidates_.RemoveElement(optimizing_compiler);
115
    ready_for_osr_.Add(optimizing_compiler);
116
  } else {
117
    output_queue_.Enqueue(optimizing_compiler);
118
    isolate_->stack_guard()->RequestInstallCode();
132
  output_queue_.Enqueue(job);
133
  isolate_->stack_guard()->RequestInstallCode();
134
}
135

  
136

  
137
static void DisposeRecompileJob(RecompileJob* job,
138
                                bool restore_function_code) {
139
  // The recompile job is allocated in the CompilationInfo's zone.
140
  CompilationInfo* info = job->info();
141
  if (restore_function_code) {
142
    if (info->is_osr()) {
143
      if (!job->IsWaitingForInstall()) BackEdgeTable::RemoveStackCheck(info);
144
    } else {
145
      Handle<JSFunction> function = info->closure();
146
      function->ReplaceCode(function->shared()->code());
147
    }
119 148
  }
149
  delete info;
120 150
}
121 151

  
122 152

  
123 153
void OptimizingCompilerThread::FlushInputQueue(bool restore_function_code) {
124
  OptimizingCompiler* optimizing_compiler;
125
  // The optimizing compiler is allocated in the CompilationInfo's zone.
126
  while (input_queue_.Dequeue(&optimizing_compiler)) {
154
  RecompileJob* job;
155
  while ((job = NextInput())) {
127 156
    // This should not block, since we have one signal on the input queue
128 157
    // semaphore corresponding to each element in the input queue.
129 158
    input_queue_semaphore_.Wait();
130
    CompilationInfo* info = optimizing_compiler->info();
131
    if (restore_function_code) {
132
      Handle<JSFunction> function = info->closure();
133
      function->ReplaceCode(function->shared()->code());
159
    // OSR jobs are dealt with separately.
160
    if (!job->info()->is_osr()) {
161
      DisposeRecompileJob(job, restore_function_code);
134 162
    }
135
    delete info;
136 163
  }
137 164
}
138 165

  
139 166

  
140 167
void OptimizingCompilerThread::FlushOutputQueue(bool restore_function_code) {
141
  OptimizingCompiler* optimizing_compiler;
142
  // The optimizing compiler is allocated in the CompilationInfo's zone.
143
  while (output_queue_.Dequeue(&optimizing_compiler)) {
144
    CompilationInfo* info = optimizing_compiler->info();
145
    if (restore_function_code) {
146
      Handle<JSFunction> function = info->closure();
147
      function->ReplaceCode(function->shared()->code());
168
  RecompileJob* job;
169
  while (output_queue_.Dequeue(&job)) {
170
    // OSR jobs are dealt with separately.
171
    if (!job->info()->is_osr()) {
172
      DisposeRecompileJob(job, restore_function_code);
148 173
    }
149
    delete info;
150 174
  }
175
}
176

  
151 177

  
152
  osr_candidates_.Clear();
153
  RemoveStaleOSRCandidates(0);
178
void OptimizingCompilerThread::FlushOsrBuffer(bool restore_function_code) {
179
  for (int i = 0; i < osr_buffer_capacity_; i++) {
180
    if (osr_buffer_[i] != NULL) {
181
      DisposeRecompileJob(osr_buffer_[i], restore_function_code);
182
      osr_buffer_[i] = NULL;
183
    }
184
  }
154 185
}
155 186

  
156 187

  
157 188
void OptimizingCompilerThread::Flush() {
158 189
  ASSERT(!IsOptimizerThread());
159 190
  Release_Store(&stop_thread_, static_cast<AtomicWord>(FLUSH));
191
  if (FLAG_block_concurrent_recompilation) Unblock();
160 192
  input_queue_semaphore_.Signal();
161 193
  stop_semaphore_.Wait();
162 194
  FlushOutputQueue(true);
195
  if (FLAG_concurrent_osr) FlushOsrBuffer(true);
196
  if (FLAG_trace_concurrent_recompilation) {
197
    PrintF("  ** Flushed concurrent recompilation queues.\n");
198
  }
163 199
}
164 200

  
165 201

  
166 202
void OptimizingCompilerThread::Stop() {
167 203
  ASSERT(!IsOptimizerThread());
168 204
  Release_Store(&stop_thread_, static_cast<AtomicWord>(STOP));
205
  if (FLAG_block_concurrent_recompilation) Unblock();
169 206
  input_queue_semaphore_.Signal();
170 207
  stop_semaphore_.Wait();
171 208

  
172 209
  if (FLAG_concurrent_recompilation_delay != 0) {
173
    // Barrier when loading queue length is not necessary since the write
174
    // happens in CompileNext on the same thread.
175
    // This is used only for testing.
176
    while (NoBarrier_Load(&queue_length_) > 0) CompileNext();
210
    // At this point the optimizing compiler thread's event loop has stopped.
211
    // There is no need for a mutex when reading input_queue_length_.
212
    while (input_queue_length_ > 0) CompileNext();
177 213
    InstallOptimizedFunctions();
178 214
  } else {
179 215
    FlushInputQueue(false);
180 216
    FlushOutputQueue(false);
181 217
  }
182 218

  
219
  if (FLAG_concurrent_osr) FlushOsrBuffer(false);
220

  
183 221
  if (FLAG_trace_concurrent_recompilation) {
184 222
    double percentage = time_spent_compiling_.PercentOf(time_spent_total_);
185 223
    PrintF("  ** Compiler thread did %.2f%% useful work\n", percentage);
186 224
  }
187 225

  
188
  if (FLAG_trace_osr && FLAG_concurrent_osr) {
226
  if ((FLAG_trace_osr || FLAG_trace_concurrent_recompilation) &&
227
      FLAG_concurrent_osr) {
189 228
    PrintF("[COSR hit rate %d / %d]\n", osr_hits_, osr_attempts_);
190 229
  }
191 230

  
......
196 235
void OptimizingCompilerThread::InstallOptimizedFunctions() {
197 236
  ASSERT(!IsOptimizerThread());
198 237
  HandleScope handle_scope(isolate_);
199
  OptimizingCompiler* compiler;
200
  while (true) {
201
    if (!output_queue_.Dequeue(&compiler)) return;
202
    Compiler::InstallOptimizedCode(compiler);
203
  }
204 238

  
205
  // Remove the oldest OSR candidates that are ready so that we
206
  // only have limited number of them waiting.
207
  if (FLAG_concurrent_osr) RemoveStaleOSRCandidates();
239
  RecompileJob* job;
240
  while (output_queue_.Dequeue(&job)) {
241
    CompilationInfo* info = job->info();
242
    if (info->is_osr()) {
243
      if (FLAG_trace_osr) {
244
        PrintF("[COSR - ");
245
        info->closure()->PrintName();
246
        PrintF(" is ready for install and entry at AST id %d]\n",
247
               info->osr_ast_id().ToInt());
248
      }
249
      job->WaitForInstall();
250
      BackEdgeTable::RemoveStackCheck(info);
251
    } else {
252
      Compiler::InstallOptimizedCode(job);
253
    }
254
  }
208 255
}
209 256

  
210 257

  
211
void OptimizingCompilerThread::QueueForOptimization(
212
    OptimizingCompiler* optimizing_compiler) {
258
void OptimizingCompilerThread::QueueForOptimization(RecompileJob* job) {
213 259
  ASSERT(IsQueueAvailable());
214 260
  ASSERT(!IsOptimizerThread());
215
  Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(1));
216
  if (optimizing_compiler->info()->osr_ast_id().IsNone()) {
217
    optimizing_compiler->info()->closure()->MarkInRecompileQueue();
218
  } else {
219
    LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
220
    osr_candidates_.Add(optimizing_compiler);
261
  CompilationInfo* info = job->info();
262
  if (info->is_osr()) {
263
    if (FLAG_trace_concurrent_recompilation) {
264
      PrintF("  ** Queueing ");
265
      info->closure()->PrintName();
266
      PrintF(" for concurrent on-stack replacement.\n");
267
    }
221 268
    osr_attempts_++;
269
    BackEdgeTable::AddStackCheck(info);
270
    AddToOsrBuffer(job);
271
    // Add job to the front of the input queue.
272
    LockGuard<Mutex> access_input_queue(&input_queue_mutex_);
273
    ASSERT_LT(input_queue_length_, input_queue_capacity_);
274
    // Move shift_ back by one.
275
    input_queue_shift_ = InputQueueIndex(input_queue_capacity_ - 1);
276
    input_queue_[InputQueueIndex(0)] = job;
277
    input_queue_length_++;
278
  } else {
279
    info->closure()->MarkInRecompileQueue();
280
    // Add job to the back of the input queue.
281
    LockGuard<Mutex> access_input_queue(&input_queue_mutex_);
282
    ASSERT_LT(input_queue_length_, input_queue_capacity_);
283
    input_queue_[InputQueueIndex(input_queue_length_)] = job;
284
    input_queue_length_++;
285
  }
286
  if (FLAG_block_concurrent_recompilation) {
287
    blocked_jobs_++;
288
  } else {
289
    input_queue_semaphore_.Signal();
290
  }
291
}
292

  
293

  
294
void OptimizingCompilerThread::Unblock() {
295
  ASSERT(!IsOptimizerThread());
296
  while (blocked_jobs_ > 0) {
297
    input_queue_semaphore_.Signal();
298
    blocked_jobs_--;
222 299
  }
223
  input_queue_.Enqueue(optimizing_compiler);
224
  input_queue_semaphore_.Signal();
225 300
}
226 301

  
227 302

  
228
OptimizingCompiler* OptimizingCompilerThread::FindReadyOSRCandidate(
303
RecompileJob* OptimizingCompilerThread::FindReadyOSRCandidate(
229 304
    Handle<JSFunction> function, uint32_t osr_pc_offset) {
230 305
  ASSERT(!IsOptimizerThread());
231
  OptimizingCompiler* result = NULL;
232
  { LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
233
    for (int i = 0; i < ready_for_osr_.length(); i++) {
234
      if (ready_for_osr_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) {
235
        osr_hits_++;
236
        result = ready_for_osr_.Remove(i);
237
        break;
238
      }
306
  for (int i = 0; i < osr_buffer_capacity_; i++) {
307
    RecompileJob* current = osr_buffer_[i];
308
    if (current != NULL &&
309
        current->IsWaitingForInstall() &&
310
        current->info()->HasSameOsrEntry(function, osr_pc_offset)) {
311
      osr_hits_++;
312
      osr_buffer_[i] = NULL;
313
      return current;
239 314
    }
240 315
  }
241
  RemoveStaleOSRCandidates();
242
  return result;
316
  return NULL;
243 317
}
244 318

  
245 319

  
246 320
bool OptimizingCompilerThread::IsQueuedForOSR(Handle<JSFunction> function,
247 321
                                              uint32_t osr_pc_offset) {
248 322
  ASSERT(!IsOptimizerThread());
249
  LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
250
  for (int i = 0; i < osr_candidates_.length(); i++) {
251
    if (osr_candidates_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) {
252
      return true;
323
  for (int i = 0; i < osr_buffer_capacity_; i++) {
324
    RecompileJob* current = osr_buffer_[i];
325
    if (current != NULL &&
326
        current->info()->HasSameOsrEntry(function, osr_pc_offset)) {
327
      return !current->IsWaitingForInstall();
253 328
    }
254 329
  }
255 330
  return false;
......
258 333

  
259 334
bool OptimizingCompilerThread::IsQueuedForOSR(JSFunction* function) {
260 335
  ASSERT(!IsOptimizerThread());
261
  LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
262
  for (int i = 0; i < osr_candidates_.length(); i++) {
263
    if (*osr_candidates_[i]->info()->closure() == function) {
264
      return true;
336
  for (int i = 0; i < osr_buffer_capacity_; i++) {
337
    RecompileJob* current = osr_buffer_[i];
338
    if (current != NULL && *current->info()->closure() == function) {
339
      return !current->IsWaitingForInstall();
265 340
    }
266 341
  }
267 342
  return false;
268 343
}
269 344

  
270 345

  
271
void OptimizingCompilerThread::RemoveStaleOSRCandidates(int limit) {
346
void OptimizingCompilerThread::AddToOsrBuffer(RecompileJob* job) {
272 347
  ASSERT(!IsOptimizerThread());
273
  LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
274
  while (ready_for_osr_.length() > limit) {
275
    OptimizingCompiler* compiler = ready_for_osr_.Remove(0);
276
    CompilationInfo* throw_away = compiler->info();
348
  // Find the next slot that is empty or has a stale job.
349
  while (true) {
350
    RecompileJob* stale = osr_buffer_[osr_buffer_cursor_];
351
    if (stale == NULL || stale->IsWaitingForInstall()) break;
352
    osr_buffer_cursor_ = (osr_buffer_cursor_ + 1) % osr_buffer_capacity_;
353
  }
354

  
355
  // Add to found slot and dispose the evicted job.
356
  RecompileJob* evicted = osr_buffer_[osr_buffer_cursor_];
357
  if (evicted != NULL) {
358
    ASSERT(evicted->IsWaitingForInstall());
359
    CompilationInfo* info = evicted->info();
277 360
    if (FLAG_trace_osr) {
278 361
      PrintF("[COSR - Discarded ");
279
      throw_away->closure()->PrintName();
280
      PrintF(", AST id %d]\n",
281
             throw_away->osr_ast_id().ToInt());
362
      info->closure()->PrintName();
363
      PrintF(", AST id %d]\n", info->osr_ast_id().ToInt());
282 364
    }
283
    delete throw_away;
365
    DisposeRecompileJob(evicted, false);
284 366
  }
367
  osr_buffer_[osr_buffer_cursor_] = job;
368
  osr_buffer_cursor_ = (osr_buffer_cursor_ + 1) % osr_buffer_capacity_;
285 369
}
286 370

  
287 371

  

Also available in: Unified diff