diff --git a/src/mark-compact.cc b/src/mark-compact.cc index ebba22b44a..80988db585 100644 --- a/src/mark-compact.cc +++ b/src/mark-compact.cc @@ -952,6 +952,34 @@ void CodeFlusher::EvictCandidate(JSFunction* function) { } +void CodeFlusher::EvictJSFunctionCandidates() { + Object* undefined = isolate_->heap()->undefined_value(); + + JSFunction* candidate = jsfunction_candidates_head_; + JSFunction* next_candidate; + while (candidate != NULL) { + next_candidate = GetNextCandidate(candidate); + ClearNextCandidate(candidate, undefined); + candidate = next_candidate; + } + + jsfunction_candidates_head_ = NULL; +} + + +void CodeFlusher::EvictSharedFunctionInfoCandidates() { + SharedFunctionInfo* candidate = shared_function_info_candidates_head_; + SharedFunctionInfo* next_candidate; + while (candidate != NULL) { + next_candidate = GetNextCandidate(candidate); + ClearNextCandidate(candidate); + candidate = next_candidate; + } + + shared_function_info_candidates_head_ = NULL; +} + + void CodeFlusher::IteratePointersToFromSpace(ObjectVisitor* v) { Heap* heap = isolate_->heap(); @@ -3629,6 +3657,7 @@ void MarkCompactCollector::EnableCodeFlushing(bool enable) { code_flusher_ = new CodeFlusher(heap()->isolate()); } else { if (code_flusher_ == NULL) return; + code_flusher_->EvictAllCandidates(); delete code_flusher_; code_flusher_ = NULL; } diff --git a/src/mark-compact.h b/src/mark-compact.h index 8b1620eb21..642839d254 100644 --- a/src/mark-compact.h +++ b/src/mark-compact.h @@ -441,11 +441,18 @@ class CodeFlusher { ProcessJSFunctionCandidates(); } + void EvictAllCandidates() { + EvictJSFunctionCandidates(); + EvictSharedFunctionInfoCandidates(); + } + void IteratePointersToFromSpace(ObjectVisitor* v); private: void ProcessJSFunctionCandidates(); void ProcessSharedFunctionInfoCandidates(); + void EvictJSFunctionCandidates(); + void EvictSharedFunctionInfoCandidates(); static JSFunction** GetNextCandidateSlot(JSFunction* candidate) { return reinterpret_cast( diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc index 811973b46a..2bb3af624d 100644 --- a/test/cctest/test-heap.cc +++ b/test/cctest/test-heap.cc @@ -1133,6 +1133,65 @@ TEST(TestCodeFlushingIncrementalScavenge) { } +TEST(TestCodeFlushingIncrementalAbort) { + // If we do not flush code this test is invalid. + if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return; + i::FLAG_allow_natives_syntax = true; + InitializeVM(); + v8::HandleScope scope; + const char* source = "function foo() {" + " var x = 42;" + " var y = 42;" + " var z = x + y;" + "};" + "foo()"; + Handle foo_name = FACTORY->LookupAsciiSymbol("foo"); + + // This compile will add the code to the compilation cache. + { v8::HandleScope scope; + CompileRun(source); + } + + // Check function is compiled. + Object* func_value = Isolate::Current()->context()->global_object()-> + GetProperty(*foo_name)->ToObjectChecked(); + CHECK(func_value->IsJSFunction()); + Handle function(JSFunction::cast(func_value)); + CHECK(function->shared()->is_compiled()); + + // The code will survive at least two GCs. + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + CHECK(function->shared()->is_compiled()); + + // Bump the code age so that flushing is triggered. + const int kAgingThreshold = 6; + function->shared()->set_code_age(kAgingThreshold); + + // Simulate incremental marking so that the function is enqueued as + // code flushing candidate. + SimulateIncrementalMarking(); + + // Enable the debugger and add a breakpoint while incremental marking + // is running so that incremental marking aborts and code flushing is + // disabled. + int position = 0; + Handle breakpoint_object(Smi::FromInt(0)); + ISOLATE->debug()->SetBreakPoint(function, breakpoint_object, &position); + ISOLATE->debug()->ClearAllBreakPoints(); + + // Force optimization now that code flushing is disabled. + { v8::HandleScope scope; + CompileRun("%OptimizeFunctionOnNextCall(foo); foo();"); + } + + // Simulate one final GC to make sure the candidate queue is sane. + HEAP->CollectAllGarbage(Heap::kNoGCFlags); + CHECK(function->shared()->is_compiled() || !function->IsOptimized()); + CHECK(function->is_compiled() || !function->IsOptimized()); +} + + // Count the number of native contexts in the weak list of native contexts. int CountNativeContexts() { int count = 0;