/* 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/. */ function TestInterfaceAll() {} TestInterfaceAll.prototype = { QueryInterface: ChromeUtils.generateQI(["nsIXPCTestInterfaceA", "nsIXPCTestInterfaceB", "nsIXPCTestInterfaceC"]), /* nsIXPCTestInterfaceA / nsIXPCTestInterfaceB */ name: "TestInterfaceAllDefaultName", /* nsIXPCTestInterfaceC */ someInteger: 42 }; function newWrappedJS() { return xpcWrap(new TestInterfaceAll()); } function run_test() { // Shortcut the interfaces we're using. var ifs = { a: Ci['nsIXPCTestInterfaceA'], b: Ci['nsIXPCTestInterfaceB'], c: Ci['nsIXPCTestInterfaceC'] }; // Run through the logic a few times. for (let i = 0; i < 2; ++i) play_with_tearoffs(ifs); } function play_with_tearoffs(ifs) { // Allocate a bunch of objects, QI-ed to B. var instances = []; for (var i = 0; i < 300; ++i) instances.push(newWrappedJS().QueryInterface(ifs.b)); // Nothing to collect. gc(); // QI them to A. instances.forEach(function(v, i, a) { v.QueryInterface(ifs.a); }); // QI them to C. instances.forEach(function(v, i, a) { v.QueryInterface(ifs.c); }); // Check Assert.ok('name' in instances[10], 'Have the prop from A/B'); Assert.ok('someInteger' in instances[10], 'Have the prop from C'); // Grab tearoff reflections for a and b. var aTearOffs = instances.map(function(v, i, a) { return v.nsIXPCTestInterfaceA; } ); var bTearOffs = instances.map(function(v, i, a) { return v.nsIXPCTestInterfaceB; } ); // Check Assert.ok('name' in aTearOffs[1], 'Have the prop from A'); Assert.ok(!('someInteger' in aTearOffs[1]), 'Dont have the prop from C'); // Nothing to collect. gc(); // Null out every even instance pointer. for (var i = 0; i < instances.length; ++i) if (i % 2 == 0) instances[i] = null; // Nothing to collect, since we still have the A and B tearoff reflections. gc(); // Null out A tearoff reflections that are a multiple of 3. for (var i = 0; i < aTearOffs.length; ++i) if (i % 3 == 0) aTearOffs[i] = null; // Nothing to collect, since we still have the B tearoff reflections. gc(); // Null out B tearoff reflections that are a multiple of 5. for (var i = 0; i < bTearOffs.length; ++i) if (i % 5 == 0) bTearOffs[i] = null; // This should collect every 30th object (indices that are multiples of 2, 3, and 5). gc(); // Kill the b tearoffs entirely. bTearOffs = 0; // Collect more. gc(); // Get C tearoffs. var cTearOffs = instances.map(function(v, i, a) { return v ? v.nsIXPCTestInterfaceC : null; } ); // Check. Assert.ok(!('name' in cTearOffs[1]), 'Dont have the prop from A'); Assert.ok('someInteger' in cTearOffs[1], 'have the prop from C'); // Null out the a tearoffs. aTearOffs = null; // Collect all even indices. gc(); // Collect all indices. instances = null; gc(); // Give ourselves a pat on the back. :-) Assert.ok(true, "Got all the way through without crashing!"); }