Reviewers: ulan,
Description:
Fix disabling of code flusher while marking.
This fixes a corner case when the code flusher is disabled while
incremental marking is running. The list of candidates needs to be
evicted to prevent list fragments without a head floating around.
[email protected]
BUG=chromium:159140
Please review this at https://chromiumcodereview.appspot.com/11366136/
SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge
Affected files:
M src/mark-compact.h
M src/mark-compact.cc
M test/cctest/test-heap.cc
Index: src/mark-compact.cc
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index
ebba22b44a875b01006d01f0fe790636775ed8bf..80988db5853b14e865cf756a3ce3b40092ae2c61
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;
}
Index: src/mark-compact.h
diff --git a/src/mark-compact.h b/src/mark-compact.h
index
8b1620eb21baf51c5a0f78756dc807ad5b84a21d..642839d254afcd1f90fff74d482dfaa3216d459c
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<JSFunction**>(
Index: test/cctest/test-heap.cc
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index
811973b46ad3f87e636b79e39a00180f7c5f8ef2..2bb3af624dbedf8909c38ca247d0150683fe7174
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<String> 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<JSFunction> 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<Object> 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;
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev