Reviewers: ulan,

Description:
Fix code flusher to process weak function links.

This fixes a corner case where weak function links of the code flushing
candidates list were destroyed by scavenges that happened during
incremental marking. Now those weak function links are updated while
scavenging happens.

[email protected]
TEST=cctest/test-heap/TestCodeFlushingIncrementalScavenge


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

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

Affected files:
  M src/heap.cc
  M src/mark-compact.h
  M src/mark-compact.cc
  M src/objects-debug.cc
  M test/cctest/test-heap.cc


Index: src/heap.cc
diff --git a/src/heap.cc b/src/heap.cc
index 0d2cc42402f4b3457b1d28340984069d452dbd7d..ef7d62139fe0d944657a518d8912065005192e45 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -1351,6 +1351,11 @@ void Heap::Scavenge() {
   ScavengeWeakObjectRetainer weak_object_retainer(this);
   ProcessWeakReferences(&weak_object_retainer);

+  MarkCompactCollector* collector = mark_compact_collector();
+  if (collector->is_code_flushing_enabled()) {
+ collector->code_flusher()->ProcessWeakReferences(&weak_object_retainer);
+  }
+
   ASSERT(new_space_front == new_space_.top());

   // Set age mark.
@@ -5542,6 +5547,7 @@ bool Heap::LookupSymbolIfExists(String* string, String** symbol) {
   return symbol_table()->LookupSymbolIfExists(string, symbol);
 }

+
 void Heap::ZapFromSpace() {
   NewSpacePageIterator it(new_space_.FromSpaceStart(),
                           new_space_.FromSpaceEnd());
Index: src/mark-compact.cc
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 412bc6b736fb9b6d58820476c0fdf881cca56074..f5a2020dee768e70620252c79853e2b1aa14fca0 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -952,6 +952,23 @@ void CodeFlusher::EvictCandidate(JSFunction* function) {
 }


+void CodeFlusher::ProcessWeakReferences(WeakObjectRetainer* retainer) {
+  JSFunction* prev_candidate = NULL;
+  JSFunction* candidate = jsfunction_candidates_head_;
+  while (candidate != NULL) {
+    Object* retain = retainer->RetainAs(candidate);
+    JSFunction* retain_candidate = JSFunction::cast(retain);
+    if (prev_candidate == NULL) {
+      jsfunction_candidates_head_ = retain_candidate;
+    } else {
+      SetNextCandidate(prev_candidate, retain_candidate);
+    }
+    prev_candidate = retain_candidate;
+    candidate = GetNextCandidate(prev_candidate);
+  }
+}
+
+
 MarkCompactCollector::~MarkCompactCollector() {
   if (code_flusher_ != NULL) {
     delete code_flusher_;
Index: src/mark-compact.h
diff --git a/src/mark-compact.h b/src/mark-compact.h
index 7ab83c41e56a0f392ca68bf5b8ea1ec4507ec652..0c1b0b85ddca093727fc334fe0d09d511df8f212 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -45,6 +45,7 @@ class GCTracer;
 class MarkCompactCollector;
 class MarkingVisitor;
 class RootMarkingVisitor;
+class WeakObjectRetainer;


 class Marking {
@@ -441,6 +442,8 @@ class CodeFlusher {
     ProcessJSFunctionCandidates();
   }

+  void ProcessWeakReferences(WeakObjectRetainer* retainer);
+
  private:
   void ProcessJSFunctionCandidates();
   void ProcessSharedFunctionInfoCandidates();
Index: src/objects-debug.cc
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index be96592962458f5125f88d674ae42f57745969a2..c2f64d482e07d3b3e73688ef3be6fc3b12d473f3 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -499,7 +499,8 @@ void JSFunction::JSFunctionVerify() {
   VerifyObjectField(kPrototypeOrInitialMapOffset);
   VerifyObjectField(kNextFunctionLinkOffset);
   CHECK(code()->IsCode());
-  CHECK(next_function_link()->IsUndefined() ||
+  CHECK(next_function_link() == NULL ||
+        next_function_link()->IsUndefined() ||
         next_function_link()->IsJSFunction());
 }

Index: test/cctest/test-heap.cc
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index 2ccc9d41e69c4b795742eba362033998b1ad2f8b..a6d6b0bbbc28469fec0ee3db96dfb89dd5e1dd41 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -1069,6 +1069,53 @@ TEST(TestCodeFlushingIncremental) {
 }


+TEST(TestCodeFlushingIncrementalScavenge) {
+  // If we do not flush code this test is invalid.
+  if (!FLAG_flush_code) return;
+  i::FLAG_allow_natives_syntax = true;
+  InitializeVM();
+  v8::HandleScope scope;
+  const char* source = "var foo = function() {"
+                       "  var x = 42;"
+                       "  var y = 42;"
+                       "  var z = x + y;"
+                       "};"
+                       "foo()";
+  Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
+
+  // Perfrom one initial GC to enable code flushing.
+  HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+
+  // 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());
+
+  // Bump the code age so that flushing is triggered while the function
+  // object is still located in new-space.
+  const int kAgingThreshold = 6;
+  function->shared()->set_code_age(kAgingThreshold);
+
+  // Simulate incremental marking so that the function is enqueued as a
+  // code flushing candidate. Then perform a scavenge while incremental
+  // marking is still running.
+  SimulateIncrementalMarking();
+  HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
+
+  // 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

Reply via email to