Reviewers: Hannes Payer,

Description:
Fix corner case when JSFunction is evicted from flusher.

This fixes a corner case that happens when JSFunctions are enqueued as
code flushing candidates but their respective SharedFunctionInfo isn't.
If the JSFunction gets evicted due to optimization the code slot in the
SharedFunctionInfo will never be recorded in the slots buffer.

[email protected]
BUG=chromium:168801
TEST=cctest/test-heap/Regress168801


Please review this at https://codereview.chromium.org/11896064/

SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge

Affected files:
  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 9606092713a0e311ebe9e13b23eb04394d87c95a..f7237041a7a0bcb4f130e6e12173225df1383da6 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -943,8 +943,7 @@ bool CodeFlusher::ContainsCandidate(SharedFunctionInfo* shared_info) {


 void CodeFlusher::EvictCandidate(SharedFunctionInfo* shared_info) {
-  // The function is no longer a candidate, make sure it gets visited
-  // again so that previous flushing decisions are revisited.
+  // Make sure previous flushing decisions are revisited.
   isolate_->heap()->incremental_marking()->RecordWrites(shared_info);

   SharedFunctionInfo* candidate = shared_function_info_candidates_head_;
@@ -974,9 +973,9 @@ void CodeFlusher::EvictCandidate(JSFunction* function) {
   ASSERT(!function->next_function_link()->IsUndefined());
   Object* undefined = isolate_->heap()->undefined_value();

-  // The function is no longer a candidate, make sure it gets visited
-  // again so that previous flushing decisions are revisited.
+  // Make sure previous flushing decisions are revisited.
   isolate_->heap()->incremental_marking()->RecordWrites(function);
+ isolate_->heap()->incremental_marking()->RecordWrites(function->shared());

   JSFunction* candidate = jsfunction_candidates_head_;
   JSFunction* next_candidate;
Index: test/cctest/test-heap.cc
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index eb4f07245a9c9927a800b13d834ab0d73189dadc..d206958f1f8fe9962fbf0e6888ac2a0a0265edc0 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -2778,3 +2778,58 @@ TEST(Regress169928) {
   AlwaysAllocateScope aa_scope;
   v8::Script::Compile(mote_code_string)->Run();
 }
+
+
+TEST(Regress168801) {
+  i::FLAG_always_compact = true;
+  i::FLAG_cache_optimized_code = false;
+  i::FLAG_allow_natives_syntax = true;
+  i::FLAG_flush_code_incrementally = true;
+  InitializeVM();
+  v8::HandleScope scope;
+
+  // Perform one initial GC to enable code flushing.
+  HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
+
+  // Ensure the code ends up on an evacuation candidate.
+  SimulateFullSpace(HEAP->code_space());
+  CompileRun("var x = 0;");
+
+  // Prepare an unoptimized function that is eligible for code flushing.
+  Handle<JSFunction> function;
+  {
+    HandleScope inner_scope;
+    CompileRun("function mkClosure() {"
+               "  return function(x) { return x + 1; };"
+               "}"
+               "var f = mkClosure();"
+               "f(1); f(2);");
+
+    Handle<JSFunction> f =
+        v8::Utils::OpenHandle(
+            *v8::Handle<v8::Function>::Cast(
+                v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
+    CHECK(f->is_compiled());
+    const int kAgingThreshold = 6;
+    for (int i = 0; i < kAgingThreshold; i++) {
+      f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
+    }
+
+    function = inner_scope.CloseAndEscape(handle(*f, ISOLATE));
+  }
+
+ // Simulate incremental marking so that unoptimized function is enqueued as a + // candidate for code flushing. The shared function info however will not be
+  // explicitly enqueued.
+  SimulateIncrementalMarking();
+
+  // Now optimize the function so that it is taken off the candidate list.
+  {
+    HandleScope inner_scope;
+    CompileRun("%OptimizeFunctionOnNextCall(f); f(3);");
+  }
+
+  // This cycle will bust the heap and subsequent cycles will go ballistic.
+  HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+  HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+}


--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to