js/xpconnect/tests/chrome/test_weakmaps.xul

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 <?xml version="1.0"?>
     2 <?xml-stylesheet type="text/css" href="chrome://global/skin"?>
     3 <?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
     4 <!--
     5 https://bugzilla.mozilla.org/show_bug.cgi?id=668855
     6 -->
     7 <window title="Mozilla Bug "
     8         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
     9   <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
    11   <!-- test results are displayed in the html:body -->
    12   <body xmlns="http://www.w3.org/1999/xhtml">
    13   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id="
    14      target="_blank">Mozilla Bug 668855</a>
    15   </body>
    17   <!-- test code goes here -->
    18   <script type="application/javascript">
    19   <![CDATA[
    20   /** Test for Bug 668855 **/
    22   let Cu = Components.utils;
    23   let Ci = Components.interfaces;
    25   /* Create a weak reference, with a single-element weak map. */
    26   let make_weak_ref = function (obj) {
    27     let m = new WeakMap;
    28     m.set(obj, {});
    29     return m;
    30   };
    32   /* Check to see if a weak reference is dead. */
    33   let weak_ref_dead = function (r) {
    34     return Cu.nondeterministicGetWeakMapKeys(r).length == 0;
    35   }
    37   /* Deterministically grab an arbitrary DOM element. */
    38   let get_live_dom = function () {
    39     let elems = document.getElementsByTagName("a");
    40     return elems[0];
    41   };
    44   /* Test case from bug 653248, adapted into a standard test.
    46   This is a dead cycle involving a DOM edge, so the cycle collector can free it.  Keys and
    47   values reachable only from XPConnect must be marked gray for this to work, and the cycle collector
    48   must know the proper structure of the heap.
    50   */
    51   let make_gray_loop = function () {
    52     let map = new WeakMap;
    53     let div = document.createElement("div");
    54     let key = {};
    55     div.setUserData("entrain", {m:map, k:key}, null);
    56     //div.entrain = {m:map, k:key};  This is not sufficient to cause a leak in Fx9
    57     map.set(key, div);
    58     return make_weak_ref(map);
    59   };
    61   let weakref = make_gray_loop();
    64   /* Combinations of live and dead gray maps/keys. */
    65   let basic_weak_ref = null;
    66   let basic_map_weak_ref = null;
    67   let black_map = new WeakMap;
    68   let black_key = {};
    70   let basic_unit_tests = function () {
    71     let live_dom = get_live_dom();
    72     let dead_dom = document.createElement("div");
    73     let live_map = new WeakMap;
    74     let dead_map = new WeakMap;
    75     let live_key = {};
    76     let dead_key = {};
    78     // put the live/dead maps/keys into the appropriate DOM elements
    79     live_dom.basic_unit_tests = {m:live_map, k:live_key};
    80     dead_dom.setUserData("hook", {m:dead_map, k:dead_key}, null);
    81     // dead_dom.hook = {m:dead_map, k:dead_key};
    83     // Create a dead value, and a weak ref to it.
    84     // The loop keeps dead_dom alive unless the CC is smart enough to kill it.
    85     let dead_val = {loop:dead_dom};
    86     basic_weak_ref = make_weak_ref(dead_val);
    87     basic_map_weak_ref = make_weak_ref(dead_map);
    89     // set up the actual entries.  most will die.
    90     live_map.set(live_key, {my_key:'live_live'});
    91     live_map.set(dead_key, dead_val);
    92     live_map.set(black_key, {my_key:'live_black'});
    94     dead_map.set(live_key, dead_val);
    95     dead_map.set(dead_key, dead_val);
    96     dead_map.set(black_key, dead_val);
    98     black_map.set(live_key, {my_key:'black_live'});
    99     black_map.set(dead_key, dead_val);
   100     black_map.set(black_key, {my_key:'black_black'});
   102   };
   104   basic_unit_tests();
   107   let check_basic_unit = function () {
   108     let live_dom = get_live_dom();
   109     let live_map = live_dom.basic_unit_tests.m;
   110     let live_key = live_dom.basic_unit_tests.k;
   112     // check the dead elements
   113     ok(weak_ref_dead(basic_weak_ref), "Dead value was kept alive.");
   114     ok(weak_ref_dead(basic_map_weak_ref), "Dead map was kept alive.");
   116     // check the live gray map
   117     is(live_map.get(live_key).my_key, 'live_live',
   118       "Live key should have the same value in live map.");
   119     is(live_map.get(black_key).my_key, 'live_black',
   120       "Black key should have the same value in live map.");
   121     is(Cu.nondeterministicGetWeakMapKeys(live_map).length, 2,
   122       "Live map should have two entries.");
   124     // check the live black map
   125     is(black_map.get(live_key).my_key, 'black_live',
   126       "Live key should have the same value in black map.");
   127     is(black_map.get(black_key).my_key, 'black_black',
   128       "Black key should have the same value in black map.");
   129     is(Cu.nondeterministicGetWeakMapKeys(black_map).length, 2,
   130       "Black map should have two entries.");    
   132   };
   135   /* live gray chained weak map entries, involving the cycle collector. */
   136   let chainm = new WeakMap;
   137   let num_chains = 5;
   139   let nested_cc_maps = function () {
   140     let dom = get_live_dom();
   141     for(let i = 0; i < num_chains; i++) {
   142       let k = {count:i};
   143       dom.key = k;
   144       dom0 = document.createElement("div");
   145       chainm.set(k, {d:dom0});
   146       dom = document.createElement("div");
   147       dom0.appendChild(dom);
   148     };
   149   };
   151   let check_nested_cc_maps = function () {
   152     let dom = get_live_dom();
   153     let all_ok = true;
   154     for(let i = 0; i < num_chains; i++) {
   155       let k = dom.key;
   156       all_ok = all_ok && k.count == i;
   157       dom = chainm.get(k).d.firstChild;
   158     };
   159     ok(all_ok, "Count was invalid on a key in chained weak map entries.");    
   160   };
   162   nested_cc_maps();
   165   /* black weak map, chained garbage cycle involving DOM */
   166   let garbage_map = new WeakMap;
   168   let chained_garbage_maps = function () {
   169     let dom0 = document.createElement("div");
   170     let dom = dom0;
   171     for(let i = 0; i < num_chains; i++) {
   172       let k = {};
   173       dom.key = k;
   174       let new_dom = document.createElement("div");
   175       garbage_map.set(k, {val_child:new_dom});
   176       dom = document.createElement("div");
   177       new_dom.appendChild(dom);
   178     };
   179     // tie the knot
   180     dom.appendChild(dom0);
   181   };
   183   chained_garbage_maps();
   186   /* black weak map, chained garbage cycle involving DOM, XPCWN keys */
   187   let wn_garbage_map = new WeakMap;
   189   let wn_chained_garbage_maps = function () {
   190     let dom0 = document.createElement("div");
   191     let dom = dom0;
   192     for(let i = 0; i < num_chains; i++) {
   193       let new_dom = document.createElement("div");
   194       wn_garbage_map.set(dom, {wn_val_child:new_dom});
   195       dom = document.createElement("div");
   196       new_dom.appendChild(dom);
   197     };
   198     // tie the knot
   199     dom.appendChild(dom0);
   200   };
   202   wn_chained_garbage_maps();
   205   /* The cycle collector shouldn't remove a live wrapped native key. */
   207   let wn_live_map = new WeakMap;
   209   let make_live_map = function () {
   210     let live = get_live_dom();
   211     wn_live_map.set(live, {});
   212     ok(wn_live_map.has(get_live_dom()), "Live map should have live DOM node before GC.");
   213   }
   215   make_live_map();
   217   let unpreservable_native_key = function () {
   218     // We only allow natives that support wrapper preservation to be used as weak
   219     // map keys.  We should be able to try to add unpreservable natives as keys without
   220     // crashing (bug 711616), but we should throw an error (bug 761620).
   222     let dummy_test_map = new WeakMap;
   224     let rule_fail = false;
   225     let got_rule = false;
   226     try {
   227       var rule = document.styleSheets[0].cssRules[0];
   228       got_rule = true;
   229       dummy_test_map.set(rule, 1);
   230     } catch (e) {
   231       rule_fail = true;
   232     }
   233     ok(got_rule, "Got the CSS rule");
   234     ok(rule_fail, "Using a CSS rule as a weak map key should produce an exception because it can't be wrapper preserved.");
   236   }
   238   unpreservable_native_key();
   240   /* set up for running precise GC/CC then checking the results */
   242   SimpleTest.waitForExplicitFinish();
   244   Cu.schedulePreciseGC(function () {
   245     SpecialPowers.DOMWindowUtils.cycleCollect();
   246     SpecialPowers.DOMWindowUtils.garbageCollect();
   247     SpecialPowers.DOMWindowUtils.garbageCollect();
   249     ok(weak_ref_dead(weakref), "Garbage gray cycle should be collected.");
   251     check_nested_cc_maps();
   253     is(Cu.nondeterministicGetWeakMapKeys(garbage_map).length, 0, "Chained garbage weak map entries should not leak.");
   255     check_basic_unit();
   257     // fixed by Bug 680937
   258     is(Cu.nondeterministicGetWeakMapKeys(wn_garbage_map).length, 0,
   259        "Chained garbage WN weak map entries should not leak.");
   261     // fixed by Bug 680937
   262     is(Cu.nondeterministicGetWeakMapKeys(wn_live_map).length, 1,
   263        "Live weak map wrapped native key should not be removed.");
   265     ok(wn_live_map.has(get_live_dom()), "Live map should have live dom.");
   267     SimpleTest.finish();
   268   });
   270   ]]>
   271   </script>
   272 </window>

mercurial