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 343894 cd05e24fefffc0e409a30a8a720cb7e05f7a0019
parent 343893 58594006a6fa3fadf523b3c0faa28a964c788103
child 343895 55cdebd1726441794acdd5d5f3d40d4d04c6cbaa
push id31391
push userphilringnalda@gmail.com
push dateTue, 21 Feb 2017 04:29:09 +0000
treeherdermozilla-central@d84beb192e57 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1340604
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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);