Bug 1340604 - Add more test code for weak map gray marking behaviour r=sfink
authorJon Coppeard <jcoppeard@mozilla.com>
Mon, 20 Feb 2017 13:00:15 +0000
changeset 372921 cd05e24fefffc0e409a30a8a720cb7e05f7a0019
parent 372920 58594006a6fa3fadf523b3c0faa28a964c788103
child 372922 55cdebd1726441794acdd5d5f3d40d4d04c6cbaa
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1340604
milestone54.0a1
Bug 1340604 - Add more test code for weak map gray marking behaviour r=sfink
js/src/jsapi-tests/testGCGrayMarking.cpp
js/src/jsweakmap.h
--- a/js/src/jsapi-tests/testGCGrayMarking.cpp
+++ b/js/src/jsapi-tests/testGCGrayMarking.cpp
@@ -1,39 +1,67 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=8 sts=4 et sw=4 tw=99:
 */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "jsweakmap.h"
+
 #include "gc/Heap.h"
 #include "gc/Zone.h"
 
 #include "jsapi-tests/tests.h"
 
 using namespace js;
 using namespace js::gc;
 
+namespace JS {
+
+template <>
+struct DeletePolicy<js::ObjectWeakMap> : public js::GCManagedDeletePolicy<js::ObjectWeakMap>
+{};
+
+template <>
+struct MapTypeToRootKind<js::ObjectWeakMap*> {
+    static const JS::RootKind kind = JS::RootKind::Traceable;
+};
+
+template <>
+struct GCPolicy<js::ObjectWeakMap*> {
+    static void trace(JSTracer* trc, js::ObjectWeakMap** tp, const char* name) {
+        (*tp)->trace(trc);
+    }
+};
+
+} // namespace JS
+
+
 class AutoNoAnalysisForTest
 {
   public:
     AutoNoAnalysisForTest() {}
 } JS_HAZ_GC_SUPPRESSED;
 
 BEGIN_TEST(testGCGrayMarking)
 {
     AutoNoAnalysisForTest disableAnalysis;
 
     CHECK(InitGlobals());
     JSAutoCompartment ac(cx, global1);
 
     InitGrayRootTracer();
 
-    bool ok = TestMarking() && TestWeakMaps() && TestWatchpoints() && TestCCWs();
+    bool ok =
+        TestMarking() &&
+        TestWeakMaps() &&
+        TestUnassociatedWeakMaps() &&
+        TestWatchpoints() &&
+        TestCCWs();
 
     global1 = nullptr;
     global2 = nullptr;
     RemoveGrayRootTracer();
 
     return ok;
 }
 
@@ -285,16 +313,117 @@ TestWeakMaps()
     blackRoot2 = nullptr;
     grayRoots.grayRoot1 = nullptr;
     grayRoots.grayRoot2 = nullptr;
 
     return true;
 }
 
 bool
+TestUnassociatedWeakMaps()
+{
+    // Make a weakmap that's not associated with a JSObject.
+    auto weakMap = cx->make_unique<ObjectWeakMap>(cx);
+    CHECK(weakMap);
+    CHECK(weakMap->init());
+
+    // Make sure this gets traced during GC.
+    Rooted<ObjectWeakMap*> rootMap(cx, weakMap.get());
+
+    JSObject* key = AllocWeakmapKeyObject();
+    CHECK(key);
+
+    JSObject* value = AllocPlainObject();
+    CHECK(value);
+
+    CHECK(weakMap->add(cx, key, value));
+
+    // Test the value of a weakmap entry is marked gray by GC if the
+    // key is marked gray.
+
+    grayRoots.grayRoot1 = key;
+    JS_GC(cx);
+    CHECK(IsMarkedGray(key));
+    CHECK(IsMarkedGray(value));
+
+    // Test the value of a weakmap entry is marked gray by GC if the key is marked gray.
+
+    grayRoots.grayRoot1 = key;
+    grayRoots.grayRoot2 = nullptr;
+    JS_GC(cx);
+    CHECK(IsMarkedGray(key));
+    CHECK(IsMarkedGray(value));
+
+    // Test the value of a weakmap entry is marked black by GC if the key is
+    // marked black.
+
+    JS::RootedObject blackRoot(cx);
+    blackRoot = key;
+    grayRoots.grayRoot1 = nullptr;
+    grayRoots.grayRoot2 = nullptr;
+    JS_GC(cx);
+    CHECK(IsMarkedBlack(key));
+    CHECK(IsMarkedBlack(value));
+
+    // Test that a weakmap key is marked gray if it has a gray delegate.
+
+    JSObject* delegate = AllocDelegateForKey(key);
+    blackRoot = nullptr;
+    grayRoots.grayRoot1 = delegate;
+    grayRoots.grayRoot2 = nullptr;
+    JS_GC(cx);
+    CHECK(IsMarkedGray(delegate));
+    CHECK(IsMarkedGray(key));
+    CHECK(IsMarkedGray(value));
+
+    // Test that a weakmap key is marked black if it has a black delegate.
+
+    blackRoot = delegate;
+    grayRoots.grayRoot1 = nullptr;
+    grayRoots.grayRoot2 = nullptr;
+    JS_GC(cx);
+    CHECK(IsMarkedBlack(delegate));
+    CHECK(IsMarkedBlack(key));
+    CHECK(IsMarkedBlack(value));
+
+    blackRoot = delegate;
+    grayRoots.grayRoot1 = key;
+    grayRoots.grayRoot2 = nullptr;
+    JS_GC(cx);
+    CHECK(IsMarkedBlack(delegate));
+    CHECK(IsMarkedBlack(key));
+    CHECK(IsMarkedBlack(value));
+
+    // Test what happens if there is a delegate but it is not marked for both
+    // black and gray cases.
+
+    delegate = nullptr;
+    blackRoot = key;
+    grayRoots.grayRoot1 = nullptr;
+    grayRoots.grayRoot2 = nullptr;
+    JS_GC(cx);
+    CHECK(IsMarkedBlack(key));
+    CHECK(IsMarkedBlack(value));
+
+    CHECK(AllocDelegateForKey(key));
+    blackRoot = nullptr;
+    grayRoots.grayRoot1 = key;
+    grayRoots.grayRoot2 = nullptr;
+    JS_GC(cx);
+    CHECK(IsMarkedGray(key));
+    CHECK(IsMarkedGray(value));
+
+    blackRoot = nullptr;
+    grayRoots.grayRoot1 = nullptr;
+    grayRoots.grayRoot2 = nullptr;
+
+    return true;
+}
+
+bool
 TestWatchpoints()
 {
     JSObject* watched = AllocPlainObject();
     CHECK(watched);
 
     JSObject* closure = AllocPlainObject();
     CHECK(closure);
 
--- a/js/src/jsweakmap.h
+++ b/js/src/jsweakmap.h
@@ -397,16 +397,18 @@ class ObjectValueMap : public WeakMap<He
 class ObjectWeakMap
 {
     ObjectValueMap map;
 
   public:
     explicit ObjectWeakMap(JSContext* cx);
     bool init();
 
+    JS::Zone* zone() const { return map.zone(); }
+
     JSObject* lookup(const JSObject* obj);
     bool add(JSContext* cx, JSObject* obj, JSObject* target);
     void clear();
 
     void trace(JSTracer* trc);
     size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf);
     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) {
         return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);