Bug 819131 - Preserve reflector delegate weak map keys. r=billm a=lsblakk
authorAndrew McCreight <amccreight@mozilla.com>
Fri, 25 May 2012 09:07:23 -0700
changeset 127510 8c557b7c03a4a753e5c163038f04862e9f65fce1
parent 127509 a12a304c16aff0a9f9dfd12b775c947a8bb7b84f
child 127511 0e3b5d954cf11f46cea771571bf946c044f33dfd
push id2151
push userlsblakk@mozilla.com
push dateTue, 19 Feb 2013 18:06:57 +0000
treeherdermozilla-beta@4952e88741ec [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm, lsblakk
bugs819131
milestone20.0a2
Bug 819131 - Preserve reflector delegate weak map keys. r=billm a=lsblakk
js/src/jsweakmap.cpp
js/xpconnect/tests/mochitest/Makefile.in
js/xpconnect/tests/mochitest/file_crosscompartment_weakmap.html
js/xpconnect/tests/mochitest/test_crosscompartment_weakmap.html
--- a/js/src/jsweakmap.cpp
+++ b/js/src/jsweakmap.cpp
@@ -257,16 +257,32 @@ WeakMap_delete_impl(JSContext *cx, CallA
 
 JSBool
 WeakMap_delete(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return CallNonGenericMethod<IsWeakMap, WeakMap_delete_impl>(cx, args);
 }
 
+static bool
+TryPreserveReflector(JSContext *cx, HandleObject obj)
+{
+    if (obj->getClass()->ext.isWrappedNative ||
+        (obj->getClass()->flags & JSCLASS_IS_DOMJSCLASS) ||
+        (obj->isProxy() && GetProxyHandler(obj)->family() == GetListBaseHandlerFamily()))
+    {
+        JS_ASSERT(cx->runtime->preserveWrapperCallback);
+        if (!cx->runtime->preserveWrapperCallback(cx, obj)) {
+            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_WEAKMAP_KEY);
+            return false;
+        }
+    }
+    return true;
+}
+
 JS_ALWAYS_INLINE bool
 WeakMap_set_impl(JSContext *cx, CallArgs args)
 {
     JS_ASSERT(IsWeakMap(args.thisv()));
 
     if (args.length() < 1) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
                              "WeakMap.set", "0", "s");
@@ -286,25 +302,23 @@ WeakMap_set_impl(JSContext *cx, CallArgs
             js_delete(map);
             JS_ReportOutOfMemory(cx);
             return false;
         }
         thisObj->setPrivate(map);
     }
 
     // Preserve wrapped native keys to prevent wrapper optimization.
-    if (key->getClass()->ext.isWrappedNative ||
-        (key->getClass()->flags & JSCLASS_IS_DOMJSCLASS) ||
-        (key->isProxy() && GetProxyHandler(key)->family() == GetListBaseHandlerFamily()))
-    {
-        JS_ASSERT(cx->runtime->preserveWrapperCallback);
-        if (!cx->runtime->preserveWrapperCallback(cx, key)) {
-            JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_WEAKMAP_KEY);
+    if (!TryPreserveReflector(cx, key))
+        return false;
+
+    if (JSWeakmapKeyDelegateOp op = key->getClass()->ext.weakmapKeyDelegateOp) {
+        RootedObject delegate(cx, op(key));
+        if (delegate && !TryPreserveReflector(cx, delegate))
             return false;
-        }
     }
 
     JS_ASSERT(key->compartment() == thisObj->compartment());
     JS_ASSERT_IF(value.isObject(), value.toObject().compartment() == thisObj->compartment());
     if (!map->put(key, value)) {
         JS_ReportOutOfMemory(cx);
         return false;
     }
--- a/js/xpconnect/tests/mochitest/Makefile.in
+++ b/js/xpconnect/tests/mochitest/Makefile.in
@@ -84,16 +84,18 @@ MOCHITEST_FILES =	chrome_wrappers_helper
 		file_bug795275.html \
 		file_bug795275.xml \
 		file_bug799348.html \
 		test_bug800864.html \
 		test_bug802557.html \
 		file_bug802557.html \
 		test_bug803730.html \
 		test_bug809547.html \
+		file_crosscompartment_weakmap.html \
+		test_crosscompartment_weakmap.html \
 		$(NULL)
 
 ifneq ($(OS_TARGET),Android)
 ifndef MOZ_PLATFORM_MAEMO
 MOCHITEST_FILES +=	test_bug564330.html \
 		test_bug618017.html
 endif
 endif
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/mochitest/file_crosscompartment_weakmap.html
@@ -0,0 +1,8 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test Cross-Compartment DOM WeakMaps</title>
+</head>
+<body>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/mochitest/test_crosscompartment_weakmap.html
@@ -0,0 +1,44 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>Test Cross-Compartment DOM WeakMaps</title>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<p id="display"></p>
+<script type="application/javascript">
+
+var my_map = WeakMap();
+
+function setup() {
+  var item = window.frames[0].document.querySelector("body");
+
+  my_map.set(item, "success_string");
+
+  var navi_fail = false;
+  try {
+    my_map.set(window.frames[0].navigator, 1);
+  } catch (e) {
+    navi_fail = true;
+  }
+  ok(navi_fail, "Using window.navigator as a weak map key across compartments should produce an exception because it can't be wrapper preserved.");
+}
+
+function runTest() {
+  setup();
+  SpecialPowers.forceGC();
+  SpecialPowers.forceCC();
+  SpecialPowers.forceGC();
+  SpecialPowers.forceCC();
+  var item = window.frames[0].document.querySelector("body");
+  is(my_map.get(item), "success_string", "Preserve reflectors used cross-compartment as weak map keys.");
+}
+
+</script>
+<iframe src="file_crosscompartment_weakmap.html" onload="runTest()"></iframe>
+
+
+</pre>
+</body>
+</html>