Bug 1124563 - Fixup base shape table after moving GC r=terrence a=sylvestre
authorJon Coppeard <jcoppeard@mozilla.com>
Thu, 29 Jan 2015 09:58:06 +0000
changeset 249585 afb266213a03dfe12c61ff128b126caa65fa21fa
parent 249584 af0574d83c519496de80c902cd671ffea2c06e26
child 249586 ce1a8ed9a638781ce5605ca4be320f6949efd5e6
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence, sylvestre
bugs1124563
milestone37.0a2
Bug 1124563 - Fixup base shape table after moving GC r=terrence a=sylvestre
js/src/jit-test/tests/gc/bug-1124563.js
js/src/jsapi-tests/testGCNursery.cpp
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/vm/Shape.cpp
js/src/vm/Shape.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/gc/bug-1124563.js
@@ -0,0 +1,4 @@
+try {
+    gc(0, 'shrinking')({x: 0})
+} catch (e) {}
+eval("({x: 0, x: 0})[{x: 0}]")
--- a/js/src/jsapi-tests/testGCNursery.cpp
+++ b/js/src/jsapi-tests/testGCNursery.cpp
@@ -55,16 +55,22 @@ static const js::Class NurseryClass = {
     nullptr, /* trace */
     JS_NULL_CLASS_SPEC,
     JS_NULL_CLASS_EXT,
     JS_NULL_OBJECT_OPS
 };
 
 BEGIN_TEST(testGCNurseryFinalizer)
 {
+#ifdef JS_GC_ZEAL
+    // Running extra GCs during this test will make us get incorrect
+    // finalization counts.
+    AutoLeaveZeal nozeal(cx);
+#endif /* JS_GC_ZEAL */
+
     JS::RootedObject obj(cx);
 
     obj = JS_NewObject(cx, Jsvalify(&TenuredClass), JS::NullPtr(), JS::NullPtr());
     CHECK(!js::gc::IsInsideNursery(obj));
 
     // Null finalization list with empty nursery.
     rt->gc.minorGC(JS::gcreason::EVICT_NURSERY);
     CHECK(ranFinalizer == 0);
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -652,16 +652,17 @@ JSCompartment::sweepCrossCompartmentWrap
 #ifdef JSGC_COMPACTING
 
 void JSCompartment::fixupAfterMovingGC()
 {
     fixupGlobal();
     fixupNewTypeObjectTable(newTypeObjects);
     fixupNewTypeObjectTable(lazyTypeObjects);
     fixupInitialShapeTable();
+    fixupBaseShapeTable();
 }
 
 void
 JSCompartment::fixupGlobal()
 {
     GlobalObject *global = *global_.unsafeGet();
     if (global)
         global_.set(MaybeForwarded(global));
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -406,16 +406,17 @@ struct JSCompartment
     void purge();
     void clearTables();
 
 #ifdef JSGC_COMPACTING
     void fixupInitialShapeTable();
     void fixupNewTypeObjectTable(js::types::NewTypeObjectTable &table);
     void fixupAfterMovingGC();
     void fixupGlobal();
+    void fixupBaseShapeTable();
 #endif
 
     bool hasObjectMetadataCallback() const { return objectMetadataCallback; }
     void setObjectMetadataCallback(js::ObjectMetadataCallback callback);
     void forgetObjectMetadataCallback() {
         objectMetadataCallback = nullptr;
     }
     bool callObjectMetadataCallback(JSContext *cx, JSObject **obj) const {
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -1468,28 +1468,65 @@ BaseShape::assertConsistency()
         UnownedBaseShape *unowned = baseUnowned();
         MOZ_ASSERT(getObjectParent() == unowned->getObjectParent());
         MOZ_ASSERT(getObjectMetadata() == unowned->getObjectMetadata());
         MOZ_ASSERT(getObjectFlags() == unowned->getObjectFlags());
     }
 #endif
 }
 
+#ifdef JSGC_COMPACTING
+
+bool
+BaseShape::fixupBaseShapeTableEntry()
+{
+    bool updated = false;
+    if (parent && IsForwarded(parent.get())) {
+        parent = Forwarded(parent.get());
+        updated = true;
+    }
+    if (metadata && IsForwarded(metadata.get())) {
+        metadata = Forwarded(metadata.get());
+        updated = true;
+    }
+    return updated;
+}
+
+void
+JSCompartment::fixupBaseShapeTable()
+{
+    if (!baseShapes.initialized())
+        return;
+
+    for (BaseShapeSet::Enum e(baseShapes); !e.empty(); e.popFront()) {
+        UnownedBaseShape *base = e.front().unbarrieredGet();
+        if (base->fixupBaseShapeTableEntry()) {
+            ReadBarriered<UnownedBaseShape *> b(base);
+            e.rekeyFront(base, b);
+        }
+    }
+}
+
+#endif
+
 void
 JSCompartment::sweepBaseShapeTable()
 {
-    if (baseShapes.initialized()) {
-        for (BaseShapeSet::Enum e(baseShapes); !e.empty(); e.popFront()) {
-            UnownedBaseShape *base = e.front().unbarrieredGet();
-            if (IsBaseShapeAboutToBeFinalizedFromAnyThread(&base)) {
-                e.removeFront();
-            } else if (base != e.front().unbarrieredGet()) {
-                ReadBarriered<UnownedBaseShape *> b(base);
-                e.rekeyFront(base, b);
-            }
+    if (!baseShapes.initialized())
+        return;
+
+    for (BaseShapeSet::Enum e(baseShapes); !e.empty(); e.popFront()) {
+        UnownedBaseShape *base = e.front().unbarrieredGet();
+        MOZ_ASSERT_IF(base->getObjectParent(), !IsForwarded(base->getObjectParent()));
+        MOZ_ASSERT_IF(base->getObjectMetadata(), !IsForwarded(base->getObjectMetadata()));
+        if (IsBaseShapeAboutToBeFinalizedFromAnyThread(&base)) {
+            e.removeFront();
+        } else if (base != e.front().unbarrieredGet()) {
+            ReadBarriered<UnownedBaseShape *> b(base);
+            e.rekeyFront(base, b);
         }
     }
 }
 
 #ifdef JSGC_HASH_TABLE_CHECKS
 
 void
 JSCompartment::checkBaseShapeTableAfterMovingGC()
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -527,16 +527,17 @@ class BaseShape : public gc::TenuredCell
             gc::MarkObject(trc, &parent, "parent");
 
         if (metadata)
             gc::MarkObject(trc, &metadata, "metadata");
     }
 
 #ifdef JSGC_COMPACTING
     void fixupAfterMovingGC();
+    bool fixupBaseShapeTableEntry();
 #endif
 
   private:
     static void staticAsserts() {
         JS_STATIC_ASSERT(offsetof(BaseShape, clasp_) == offsetof(js::shadow::BaseShape, clasp_));
     }
 };