summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/tests/chrome/test_weakmaps.xul
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /js/xpconnect/tests/chrome/test_weakmaps.xul
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'js/xpconnect/tests/chrome/test_weakmaps.xul')
-rw-r--r--js/xpconnect/tests/chrome/test_weakmaps.xul272
1 files changed, 272 insertions, 0 deletions
diff --git a/js/xpconnect/tests/chrome/test_weakmaps.xul b/js/xpconnect/tests/chrome/test_weakmaps.xul
new file mode 100644
index 000000000..e741a41c6
--- /dev/null
+++ b/js/xpconnect/tests/chrome/test_weakmaps.xul
@@ -0,0 +1,272 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=668855
+-->
+<window title="Mozilla Bug "
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+ <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+
+ <!-- test results are displayed in the html:body -->
+ <body xmlns="http://www.w3.org/1999/xhtml">
+ <a href="https://bugzilla.mozilla.org/show_bug.cgi?id="
+ target="_blank">Mozilla Bug 668855</a>
+ </body>
+
+ <!-- test code goes here -->
+ <script type="application/javascript">
+ <![CDATA[
+ /** Test for Bug 668855 **/
+
+ let Cu = Components.utils;
+ let Ci = Components.interfaces;
+
+ /* Create a weak reference, with a single-element weak map. */
+ let make_weak_ref = function (obj) {
+ let m = new WeakMap;
+ m.set(obj, {});
+ return m;
+ };
+
+ /* Check to see if a weak reference is dead. */
+ let weak_ref_dead = function (r) {
+ return ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(r).length == 0;
+ }
+
+ /* Deterministically grab an arbitrary DOM element. */
+ let get_live_dom = function () {
+ let elems = document.getElementsByTagName("a");
+ return elems[0];
+ };
+
+
+ /* Test case from bug 653248, adapted into a standard test.
+
+ This is a dead cycle involving a DOM edge, so the cycle collector can free it. Keys and
+ values reachable only from XPConnect must be marked gray for this to work, and the cycle collector
+ must know the proper structure of the heap.
+
+ */
+ let make_gray_loop = function () {
+ let map = new WeakMap;
+ let div = document.createElement("div");
+ let key = {};
+ div.setUserData("entrain", {m:map, k:key}, null);
+ //div.entrain = {m:map, k:key}; This is not sufficient to cause a leak in Fx9
+ map.set(key, div);
+ return make_weak_ref(map);
+ };
+
+ let weakref = make_gray_loop();
+
+
+ /* Combinations of live and dead gray maps/keys. */
+ let basic_weak_ref = null;
+ let basic_map_weak_ref = null;
+ let black_map = new WeakMap;
+ let black_key = {};
+
+ let basic_unit_tests = function () {
+ let live_dom = get_live_dom();
+ let dead_dom = document.createElement("div");
+ let live_map = new WeakMap;
+ let dead_map = new WeakMap;
+ let live_key = {};
+ let dead_key = {};
+
+ // put the live/dead maps/keys into the appropriate DOM elements
+ live_dom.basic_unit_tests = {m:live_map, k:live_key};
+ dead_dom.setUserData("hook", {m:dead_map, k:dead_key}, null);
+ // dead_dom.hook = {m:dead_map, k:dead_key};
+
+ // Create a dead value, and a weak ref to it.
+ // The loop keeps dead_dom alive unless the CC is smart enough to kill it.
+ let dead_val = {loop:dead_dom};
+ basic_weak_ref = make_weak_ref(dead_val);
+ basic_map_weak_ref = make_weak_ref(dead_map);
+
+ // set up the actual entries. most will die.
+ live_map.set(live_key, {my_key:'live_live'});
+ live_map.set(dead_key, dead_val);
+ live_map.set(black_key, {my_key:'live_black'});
+
+ dead_map.set(live_key, dead_val);
+ dead_map.set(dead_key, dead_val);
+ dead_map.set(black_key, dead_val);
+
+ black_map.set(live_key, {my_key:'black_live'});
+ black_map.set(dead_key, dead_val);
+ black_map.set(black_key, {my_key:'black_black'});
+
+ };
+
+ basic_unit_tests();
+
+
+ let check_basic_unit = function () {
+ let live_dom = get_live_dom();
+ let live_map = live_dom.basic_unit_tests.m;
+ let live_key = live_dom.basic_unit_tests.k;
+
+ // check the dead elements
+ ok(weak_ref_dead(basic_weak_ref), "Dead value was kept alive.");
+ ok(weak_ref_dead(basic_map_weak_ref), "Dead map was kept alive.");
+
+ // check the live gray map
+ is(live_map.get(live_key).my_key, 'live_live',
+ "Live key should have the same value in live map.");
+ is(live_map.get(black_key).my_key, 'live_black',
+ "Black key should have the same value in live map.");
+ is(ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(live_map).length, 2,
+ "Live map should have two entries.");
+
+ // check the live black map
+ is(black_map.get(live_key).my_key, 'black_live',
+ "Live key should have the same value in black map.");
+ is(black_map.get(black_key).my_key, 'black_black',
+ "Black key should have the same value in black map.");
+ is(ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(black_map).length, 2,
+ "Black map should have two entries.");
+
+ };
+
+
+ /* live gray chained weak map entries, involving the cycle collector. */
+ let chainm = new WeakMap;
+ let num_chains = 5;
+
+ let nested_cc_maps = function () {
+ let dom = get_live_dom();
+ for(let i = 0; i < num_chains; i++) {
+ let k = {count:i};
+ dom.key = k;
+ dom0 = document.createElement("div");
+ chainm.set(k, {d:dom0});
+ dom = document.createElement("div");
+ dom0.appendChild(dom);
+ };
+ };
+
+ let check_nested_cc_maps = function () {
+ let dom = get_live_dom();
+ let all_ok = true;
+ for(let i = 0; i < num_chains; i++) {
+ let k = dom.key;
+ all_ok = all_ok && k.count == i;
+ dom = chainm.get(k).d.firstChild;
+ };
+ ok(all_ok, "Count was invalid on a key in chained weak map entries.");
+ };
+
+ nested_cc_maps();
+
+
+ /* black weak map, chained garbage cycle involving DOM */
+ let garbage_map = new WeakMap;
+
+ let chained_garbage_maps = function () {
+ let dom0 = document.createElement("div");
+ let dom = dom0;
+ for(let i = 0; i < num_chains; i++) {
+ let k = {};
+ dom.key = k;
+ let new_dom = document.createElement("div");
+ garbage_map.set(k, {val_child:new_dom});
+ dom = document.createElement("div");
+ new_dom.appendChild(dom);
+ };
+ // tie the knot
+ dom.appendChild(dom0);
+ };
+
+ chained_garbage_maps();
+
+
+ /* black weak map, chained garbage cycle involving DOM, XPCWN keys */
+ let wn_garbage_map = new WeakMap;
+
+ let wn_chained_garbage_maps = function () {
+ let dom0 = document.createElement("div");
+ let dom = dom0;
+ for(let i = 0; i < num_chains; i++) {
+ let new_dom = document.createElement("div");
+ wn_garbage_map.set(dom, {wn_val_child:new_dom});
+ dom = document.createElement("div");
+ new_dom.appendChild(dom);
+ };
+ // tie the knot
+ dom.appendChild(dom0);
+ };
+
+ wn_chained_garbage_maps();
+
+
+ /* The cycle collector shouldn't remove a live wrapped native key. */
+
+ let wn_live_map = new WeakMap;
+
+ let make_live_map = function () {
+ let live = get_live_dom();
+ wn_live_map.set(live, {});
+ ok(wn_live_map.has(get_live_dom()), "Live map should have live DOM node before GC.");
+ }
+
+ make_live_map();
+
+ let unpreservable_native_key = function () {
+ // We only allow natives that support wrapper preservation to be used as weak
+ // map keys. We should be able to try to add unpreservable natives as keys without
+ // crashing (bug 711616), but we should throw an error (bug 761620).
+
+ let dummy_test_map = new WeakMap;
+
+ let rule_fail = false;
+ let got_rule = false;
+ try {
+ var rule = document.styleSheets[0].cssRules[0];
+ got_rule = true;
+ dummy_test_map.set(rule, 1);
+ } catch (e) {
+ rule_fail = true;
+ }
+ ok(got_rule, "Got the CSS rule");
+ ok(rule_fail, "Using a CSS rule as a weak map key should produce an exception because it can't be wrapper preserved.");
+
+ }
+
+ unpreservable_native_key();
+
+ /* set up for running precise GC/CC then checking the results */
+
+ SimpleTest.waitForExplicitFinish();
+
+ Cu.schedulePreciseGC(function () {
+ SpecialPowers.DOMWindowUtils.cycleCollect();
+ SpecialPowers.DOMWindowUtils.garbageCollect();
+ SpecialPowers.DOMWindowUtils.garbageCollect();
+
+ ok(weak_ref_dead(weakref), "Garbage gray cycle should be collected.");
+
+ check_nested_cc_maps();
+
+ is(ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(garbage_map).length, 0, "Chained garbage weak map entries should not leak.");
+
+ check_basic_unit();
+
+ // fixed by Bug 680937
+ is(ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(wn_garbage_map).length, 0,
+ "Chained garbage WN weak map entries should not leak.");
+
+ // fixed by Bug 680937
+ is(ThreadSafeChromeUtils.nondeterministicGetWeakMapKeys(wn_live_map).length, 1,
+ "Live weak map wrapped native key should not be removed.");
+
+ ok(wn_live_map.has(get_live_dom()), "Live map should have live dom.");
+
+ SimpleTest.finish();
+ });
+
+ ]]>
+ </script>
+</window>