Fix prototype transition clearing during full GC.
authormstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 19 Jan 2012 13:38:37 +0000 (13:38 +0000)
committermstarzinger@chromium.org <mstarzinger@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 19 Jan 2012 13:38:37 +0000 (13:38 +0000)
R=vegorov@chromium.org

Review URL: https://chromiumcodereview.appspot.com/9195008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@10439 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/mark-compact.cc
test/cctest/test-heap.cc

index bacff6b..0ca1bfd 100644 (file)
@@ -2316,28 +2316,21 @@ void MarkCompactCollector::ClearNonLiveTransitions() {
               cached_map,
               SKIP_WRITE_BARRIER);
         }
+        new_number_of_transitions++;
       }
+    }
 
-      // Fill slots that became free with undefined value.
-      Object* undefined = heap()->undefined_value();
-      for (int i = new_number_of_transitions * step;
-           i < number_of_transitions * step;
-           i++) {
-        // The undefined object is on a page that is never compacted and never
-        // in new space so it is OK to skip the write barrier.  Also it's a
-        // root.
-        prototype_transitions->set_unchecked(heap_,
-                                             header + i,
-                                             undefined,
-                                             SKIP_WRITE_BARRIER);
-
-        Object** undefined_slot =
-            prototype_transitions->data_start() + i;
-        RecordSlot(undefined_slot, undefined_slot, undefined);
-      }
+    if (new_number_of_transitions != number_of_transitions) {
       map->SetNumberOfProtoTransitions(new_number_of_transitions);
     }
 
+    // Fill slots that became free with undefined value.
+    for (int i = new_number_of_transitions * step;
+         i < number_of_transitions * step;
+         i++) {
+      prototype_transitions->set_undefined(heap_, header + i);
+    }
+
     // Follow the chain of back pointers to find the prototype.
     Map* current = map;
     while (current->IsMap()) {
index 1e4e332..7015a1e 100644 (file)
@@ -1572,3 +1572,38 @@ TEST(InstanceOfStubWriteBarrier) {
   HEAP->incremental_marking()->set_should_hurry(true);
   HEAP->CollectGarbage(OLD_POINTER_SPACE);
 }
+
+
+TEST(PrototypeTransitionClearing) {
+  InitializeVM();
+  v8::HandleScope scope;
+
+  CompileRun(
+      "var base = {};"
+      "var live = [];"
+      "for (var i = 0; i < 10; i++) {"
+      "  var object = {};"
+      "  var prototype = {};"
+      "  object.__proto__ = prototype;"
+      "  if (i >= 3) live.push(object, prototype);"
+      "}");
+
+  Handle<JSObject> baseObject =
+      v8::Utils::OpenHandle(
+          *v8::Handle<v8::Object>::Cast(
+              v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
+
+  // Verify that only dead prototype transitions are cleared.
+  CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
+  HEAP->CollectAllGarbage(Heap::kNoGCFlags);
+  CHECK_EQ(10 - 3, baseObject->map()->NumberOfProtoTransitions());
+
+  // Verify that prototype transitions array was compacted.
+  FixedArray* trans = baseObject->map()->prototype_transitions();
+  for (int i = 0; i < 10 - 3; i++) {
+    int j = Map::kProtoTransitionHeaderSize +
+        i * Map::kProtoTransitionElementsPerEntry;
+    CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
+    CHECK(trans->get(j + Map::kProtoTransitionPrototypeOffset)->IsJSObject());
+  }
+}