| Index: src/optimizing-compiler-thread.cc
|
| diff --git a/src/optimizing-compiler-thread.cc b/src/optimizing-compiler-thread.cc
|
| index 029c115fcab978f1beef82e7fcfdeca2c83efde3..d9c82ce70152abea0200a6e9d78a43a87de1bb61 100644
|
| --- a/src/optimizing-compiler-thread.cc
|
| +++ b/src/optimizing-compiler-thread.cc
|
| @@ -29,6 +29,7 @@
|
|
|
| #include "v8.h"
|
|
|
| +#include "full-codegen.h"
|
| #include "hydrogen.h"
|
| #include "isolate.h"
|
| #include "v8threads.h"
|
| @@ -93,70 +94,78 @@ void OptimizingCompilerThread::Run() {
|
|
|
|
|
| void OptimizingCompilerThread::CompileNext() {
|
| - OptimizingCompiler* optimizing_compiler = NULL;
|
| - bool result = input_queue_.Dequeue(&optimizing_compiler);
|
| + RecompileJob* job = NULL;
|
| + bool result = input_queue_.Dequeue(&job);
|
| USE(result);
|
| ASSERT(result);
|
| Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(-1));
|
|
|
| // The function may have already been optimized by OSR. Simply continue.
|
| - OptimizingCompiler::Status status = optimizing_compiler->OptimizeGraph();
|
| + RecompileJob::Status status = job->OptimizeGraph();
|
| USE(status); // Prevent an unused-variable error in release mode.
|
| - ASSERT(status != OptimizingCompiler::FAILED);
|
| + ASSERT(status != RecompileJob::FAILED);
|
|
|
| // The function may have already been optimized by OSR. Simply continue.
|
| // Use a mutex to make sure that functions marked for install
|
| // are always also queued.
|
| - if (!optimizing_compiler->info()->osr_ast_id().IsNone()) {
|
| - ASSERT(FLAG_concurrent_osr);
|
| - LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
|
| - osr_candidates_.RemoveElement(optimizing_compiler);
|
| - ready_for_osr_.Add(optimizing_compiler);
|
| - } else {
|
| - LockGuard<Mutex> access_queue(&queue_mutex_);
|
| - output_queue_.Enqueue(optimizing_compiler);
|
| - isolate_->stack_guard()->RequestInstallCode();
|
| + LockGuard<Mutex> access_queue(&queue_mutex_);
|
| + output_queue_.Enqueue(job);
|
| + isolate_->stack_guard()->RequestInstallCode();
|
| +}
|
| +
|
| +
|
| +static void DisposeRecompileJob(RecompileJob* job,
|
| + bool restore_function_code) {
|
| + // The recompile job is allocated in the CompilationInfo's zone.
|
| + CompilationInfo* info = job->info();
|
| + if (restore_function_code) {
|
| + if (info->is_osr()) {
|
| + if (!job->IsWaitingForInstall()) BackEdgeTable::RemoveStackCheck(info);
|
| + } else {
|
| + Handle<JSFunction> function = info->closure();
|
| + function->ReplaceCode(function->shared()->code());
|
| + }
|
| }
|
| + delete info;
|
| }
|
|
|
|
|
| void OptimizingCompilerThread::FlushInputQueue(bool restore_function_code) {
|
| - OptimizingCompiler* optimizing_compiler;
|
| - // The optimizing compiler is allocated in the CompilationInfo's zone.
|
| - while (input_queue_.Dequeue(&optimizing_compiler)) {
|
| + RecompileJob* job;
|
| + while (input_queue_.Dequeue(&job)) {
|
| // This should not block, since we have one signal on the input queue
|
| // semaphore corresponding to each element in the input queue.
|
| input_queue_semaphore_.Wait();
|
| - CompilationInfo* info = optimizing_compiler->info();
|
| - if (restore_function_code) {
|
| - Handle<JSFunction> function = info->closure();
|
| - function->ReplaceCode(function->shared()->code());
|
| + // OSR jobs are dealt with separately.
|
| + if (!job->info()->is_osr()) {
|
| + DisposeRecompileJob(job, restore_function_code);
|
| }
|
| - delete info;
|
| }
|
| Release_Store(&queue_length_, static_cast<AtomicWord>(0));
|
| -
|
| - LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
|
| - osr_candidates_.Clear();
|
| }
|
|
|
|
|
| void OptimizingCompilerThread::FlushOutputQueue(bool restore_function_code) {
|
| - OptimizingCompiler* optimizing_compiler;
|
| - // The optimizing compiler is allocated in the CompilationInfo's zone.
|
| + RecompileJob* job;
|
| while (true) {
|
| { LockGuard<Mutex> access_queue(&queue_mutex_);
|
| - if (!output_queue_.Dequeue(&optimizing_compiler)) break;
|
| + if (!output_queue_.Dequeue(&job)) break;
|
| }
|
| - CompilationInfo* info = optimizing_compiler->info();
|
| - if (restore_function_code) {
|
| - Handle<JSFunction> function = info->closure();
|
| - function->ReplaceCode(function->shared()->code());
|
| + // OSR jobs are dealt with separately.
|
| + if (!job->info()->is_osr()) {
|
| + DisposeRecompileJob(job, restore_function_code);
|
| }
|
| - delete info;
|
| }
|
| +}
|
| +
|
|
|
| - RemoveStaleOSRCandidates(0);
|
| +void OptimizingCompilerThread::FlushOsrBuffer(bool restore_function_code) {
|
| + RecompileJob* job;
|
| + for (int i = 0; i < osr_buffer_size_; i++) {
|
| + job = osr_buffer_[i];
|
| + if (job != NULL) DisposeRecompileJob(job, restore_function_code);
|
| + }
|
| + osr_cursor_ = 0;
|
| }
|
|
|
|
|
| @@ -166,6 +175,10 @@ void OptimizingCompilerThread::Flush() {
|
| input_queue_semaphore_.Signal();
|
| stop_semaphore_.Wait();
|
| FlushOutputQueue(true);
|
| + if (FLAG_concurrent_osr) FlushOsrBuffer(true);
|
| + if (FLAG_trace_concurrent_recompilation) {
|
| + PrintF(" ** Flushed concurrent recompilation queues.\n");
|
| + }
|
| }
|
|
|
|
|
| @@ -186,12 +199,15 @@ void OptimizingCompilerThread::Stop() {
|
| FlushOutputQueue(false);
|
| }
|
|
|
| + if (FLAG_concurrent_osr) FlushOsrBuffer(false);
|
| +
|
| if (FLAG_trace_concurrent_recompilation) {
|
| double percentage = time_spent_compiling_.PercentOf(time_spent_total_);
|
| PrintF(" ** Compiler thread did %.2f%% useful work\n", percentage);
|
| }
|
|
|
| - if (FLAG_trace_osr && FLAG_concurrent_osr) {
|
| + if ((FLAG_trace_osr || FLAG_trace_concurrent_recompilation) &&
|
| + FLAG_concurrent_osr) {
|
| PrintF("[COSR hit rate %d / %d]\n", osr_hits_, osr_attempts_);
|
| }
|
|
|
| @@ -203,62 +219,75 @@ void OptimizingCompilerThread::InstallOptimizedFunctions() {
|
| ASSERT(!IsOptimizerThread());
|
| HandleScope handle_scope(isolate_);
|
|
|
| - OptimizingCompiler* compiler;
|
| + RecompileJob* job;
|
| while (true) {
|
| { LockGuard<Mutex> access_queue(&queue_mutex_);
|
| - if (!output_queue_.Dequeue(&compiler)) break;
|
| + if (!output_queue_.Dequeue(&job)) break;
|
| + }
|
| + CompilationInfo* info = job->info();
|
| + if (info->is_osr()) {
|
| + if (FLAG_trace_osr) {
|
| + PrintF("[COSR - ");
|
| + info->closure()->PrintName();
|
| + PrintF(" is ready for install and entry at AST id %d]\n",
|
| + info->osr_ast_id().ToInt());
|
| + }
|
| + job->WaitForInstall();
|
| + BackEdgeTable::RemoveStackCheck(info);
|
| + } else {
|
| + Compiler::InstallOptimizedCode(job);
|
| }
|
| - Compiler::InstallOptimizedCode(compiler);
|
| }
|
| -
|
| - // Remove the oldest OSR candidates that are ready so that we
|
| - // only have limited number of them waiting.
|
| - if (FLAG_concurrent_osr) RemoveStaleOSRCandidates();
|
| }
|
|
|
|
|
| -void OptimizingCompilerThread::QueueForOptimization(
|
| - OptimizingCompiler* optimizing_compiler) {
|
| +void OptimizingCompilerThread::QueueForOptimization(RecompileJob* job) {
|
| ASSERT(IsQueueAvailable());
|
| ASSERT(!IsOptimizerThread());
|
| Barrier_AtomicIncrement(&queue_length_, static_cast<Atomic32>(1));
|
| - if (optimizing_compiler->info()->osr_ast_id().IsNone()) {
|
| - optimizing_compiler->info()->closure()->MarkInRecompileQueue();
|
| - } else {
|
| - LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
|
| - osr_candidates_.Add(optimizing_compiler);
|
| + CompilationInfo* info = job->info();
|
| + if (info->is_osr()) {
|
| + if (FLAG_trace_concurrent_recompilation) {
|
| + PrintF(" ** Queueing ");
|
| + info->closure()->PrintName();
|
| + PrintF(" for concurrent on-stack replacement.\n");
|
| + }
|
| + AddToOsrBuffer(job);
|
| osr_attempts_++;
|
| + BackEdgeTable::AddStackCheck(info);
|
| + } else {
|
| + info->closure()->MarkInRecompileQueue();
|
| }
|
| - input_queue_.Enqueue(optimizing_compiler);
|
| + input_queue_.Enqueue(job);
|
| input_queue_semaphore_.Signal();
|
| }
|
|
|
|
|
| -OptimizingCompiler* OptimizingCompilerThread::FindReadyOSRCandidate(
|
| +RecompileJob* OptimizingCompilerThread::FindReadyOSRCandidate(
|
| Handle<JSFunction> function, uint32_t osr_pc_offset) {
|
| ASSERT(!IsOptimizerThread());
|
| - OptimizingCompiler* result = NULL;
|
| - { LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
|
| - for (int i = 0; i < ready_for_osr_.length(); i++) {
|
| - if (ready_for_osr_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) {
|
| - osr_hits_++;
|
| - result = ready_for_osr_.Remove(i);
|
| - break;
|
| - }
|
| + RecompileJob* result = NULL;
|
| + for (int i = 0; i < osr_buffer_size_; i++) {
|
| + result = osr_buffer_[i];
|
| + if (result == NULL) continue;
|
| + if (result->IsWaitingForInstall() &&
|
| + result->info()->HasSameOsrEntry(function, osr_pc_offset)) {
|
| + osr_hits_++;
|
| + osr_buffer_[i] = NULL;
|
| + return result;
|
| }
|
| }
|
| - RemoveStaleOSRCandidates();
|
| - return result;
|
| + return NULL;
|
| }
|
|
|
|
|
| bool OptimizingCompilerThread::IsQueuedForOSR(Handle<JSFunction> function,
|
| uint32_t osr_pc_offset) {
|
| ASSERT(!IsOptimizerThread());
|
| - LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
|
| - for (int i = 0; i < osr_candidates_.length(); i++) {
|
| - if (osr_candidates_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) {
|
| - return true;
|
| + for (int i = 0; i < osr_buffer_size_; i++) {
|
| + if (osr_buffer_[i] != NULL &&
|
| + osr_buffer_[i]->info()->HasSameOsrEntry(function, osr_pc_offset)) {
|
| + return !osr_buffer_[i]->IsWaitingForInstall();
|
| }
|
| }
|
| return false;
|
| @@ -267,30 +296,39 @@ bool OptimizingCompilerThread::IsQueuedForOSR(Handle<JSFunction> function,
|
|
|
| bool OptimizingCompilerThread::IsQueuedForOSR(JSFunction* function) {
|
| ASSERT(!IsOptimizerThread());
|
| - LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
|
| - for (int i = 0; i < osr_candidates_.length(); i++) {
|
| - if (*osr_candidates_[i]->info()->closure() == function) {
|
| - return true;
|
| + for (int i = 0; i < osr_buffer_size_; i++) {
|
| + if (osr_buffer_[i] != NULL &&
|
| + *osr_buffer_[i]->info()->closure() == function) {
|
| + return !osr_buffer_[i]->IsWaitingForInstall();
|
| }
|
| }
|
| return false;
|
| }
|
|
|
|
|
| -void OptimizingCompilerThread::RemoveStaleOSRCandidates(int limit) {
|
| +void OptimizingCompilerThread::AddToOsrBuffer(RecompileJob* job) {
|
| ASSERT(!IsOptimizerThread());
|
| - LockGuard<Mutex> access_osr_lists(&osr_list_mutex_);
|
| - while (ready_for_osr_.length() > limit) {
|
| - OptimizingCompiler* compiler = ready_for_osr_.Remove(0);
|
| - CompilationInfo* throw_away = compiler->info();
|
| - if (FLAG_trace_osr) {
|
| - PrintF("[COSR - Discarded ");
|
| - throw_away->closure()->PrintName();
|
| - PrintF(", AST id %d]\n",
|
| - throw_away->osr_ast_id().ToInt());
|
| + // Store into next empty slot or replace next stale OSR job that's waiting
|
| + // in vain. Dispose in the latter case.
|
| + RecompileJob* stale;
|
| + while (true) {
|
| + stale = osr_buffer_[osr_cursor_];
|
| + if (stale == NULL) break;
|
| + if (stale->IsWaitingForInstall()) {
|
| + CompilationInfo* info = stale->info();
|
| + if (FLAG_trace_osr) {
|
| + PrintF("[COSR - Discarded ");
|
| + info->closure()->PrintName();
|
| + PrintF(", AST id %d]\n", info->osr_ast_id().ToInt());
|
| + }
|
| + DisposeRecompileJob(stale, false);
|
| + break;
|
| }
|
| - delete throw_away;
|
| + AdvanceOsrCursor();
|
| }
|
| +
|
| + osr_buffer_[osr_cursor_] = job;
|
| + AdvanceOsrCursor();
|
| }
|
|
|
|
|
|
|