Revision: 12894
Author:   [email protected]
Date:     Thu Nov  8 02:26:50 2012
Log:      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

Review URL: https://codereview.chromium.org/11366136
http://code.google.com/p/v8/source/detail?r=12894

Modified:
 /branches/bleeding_edge/src/mark-compact.cc
 /branches/bleeding_edge/src/mark-compact.h
 /branches/bleeding_edge/test/cctest/test-heap.cc

=======================================
--- /branches/bleeding_edge/src/mark-compact.cc Tue Nov  6 03:54:05 2012
+++ /branches/bleeding_edge/src/mark-compact.cc Thu Nov  8 02:26:50 2012
@@ -950,6 +950,34 @@
     }
   }
 }
+
+
+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) {
@@ -3629,6 +3657,7 @@
     code_flusher_ = new CodeFlusher(heap()->isolate());
   } else {
     if (code_flusher_ == NULL) return;
+    code_flusher_->EvictAllCandidates();
     delete code_flusher_;
     code_flusher_ = NULL;
   }
=======================================
--- /branches/bleeding_edge/src/mark-compact.h  Fri Oct 26 02:44:34 2012
+++ /branches/bleeding_edge/src/mark-compact.h  Thu Nov  8 02:26:50 2012
@@ -440,12 +440,19 @@
     ProcessSharedFunctionInfoCandidates();
     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**>(
=======================================
--- /branches/bleeding_edge/test/cctest/test-heap.cc Tue Nov 6 03:54:05 2012 +++ /branches/bleeding_edge/test/cctest/test-heap.cc Thu Nov 8 02:26:50 2012
@@ -1131,6 +1131,65 @@
   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
   CHECK(!function->is_compiled() || function->IsOptimized());
 }
+
+
+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.

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

Reply via email to