1438121-generator.js (4150B)
1 const mainGlobal = this; 2 const debuggerGlobal = newGlobal({newCompartment: true}); 3 4 function Memory({global}) { 5 this.dbg = new (debuggerGlobal.Debugger); 6 this.gDO = this.dbg.addDebuggee(global); 7 } 8 9 Memory.prototype = { 10 constructor: Memory, 11 attach() { return Promise.resolve('fake attach result'); }, 12 detach() { return Promise.resolve('fake detach result'); }, 13 startRecordingAllocations() { 14 this.dbg.memory.trackingAllocationSites = true; 15 return Promise.resolve('fake startRecordingAllocations result'); 16 }, 17 stopRecordingAllocations() { 18 this.dbg.memory.trackingAllocationSites = false; 19 return Promise.resolve('fake stopRecordingAllocations result'); 20 }, 21 getAllocations() { 22 return Promise.resolve({ allocations: this.dbg.memory.drainAllocationsLog() }); 23 } 24 }; 25 26 function ok(cond, msg) { 27 assertEq(!!cond, true, `ok(${JSON.stringify(cond)}, ${JSON.stringify(msg)})`); 28 } 29 30 const is = assertEq; 31 32 function startServerAndGetSelectedTabMemory() { 33 let memory = new Memory({ global: mainGlobal }); 34 return Promise.resolve({ memory, client: 'fake client' }); 35 } 36 37 function destroyServerAndFinish() { 38 return Promise.resolve('fake destroyServerAndFinish result'); 39 } 40 41 function* body() { 42 let { memory, client } = yield startServerAndGetSelectedTabMemory(); 43 yield memory.attach(); 44 45 yield memory.startRecordingAllocations(); 46 ok(true, "Can start recording allocations"); 47 48 // Allocate some objects. 49 50 let alloc1, alloc2, alloc3; 51 52 /* eslint-disable max-nested-callbacks */ 53 (function outer() { 54 (function middle() { 55 (function inner() { 56 alloc1 = {}; alloc1.line = Error().lineNumber; 57 alloc2 = []; alloc2.line = Error().lineNumber; 58 // eslint-disable-next-line new-parens 59 alloc3 = new function () {}; alloc3.line = Error().lineNumber; 60 }()); 61 }()); 62 }()); 63 /* eslint-enable max-nested-callbacks */ 64 65 let response = yield memory.getAllocations(); 66 67 yield memory.stopRecordingAllocations(); 68 ok(true, "Can stop recording allocations"); 69 70 // Filter out allocations by library and test code, and get only the 71 // allocations that occurred in our test case above. 72 73 function isTestAllocation(alloc) { 74 let frame = alloc.frame; 75 return frame 76 && frame.functionDisplayName === "inner" 77 && (frame.line === alloc1.line 78 || frame.line === alloc2.line 79 || frame.line === alloc3.line); 80 } 81 82 let testAllocations = response.allocations.filter(isTestAllocation); 83 ok(testAllocations.length >= 3, 84 "Should find our 3 test allocations (plus some allocations for the error " 85 + "objects used to get line numbers)"); 86 87 // For each of the test case's allocations, ensure that the parent frame 88 // indices are correct. Also test that we did get an allocation at each 89 // line we expected (rather than a bunch on the first line and none on the 90 // others, etc). 91 92 let expectedLines = new Set([alloc1.line, alloc2.line, alloc3.line]); 93 94 for (let alloc of testAllocations) { 95 let innerFrame = alloc.frame; 96 ok(innerFrame, "Should get the inner frame"); 97 is(innerFrame.functionDisplayName, "inner"); 98 expectedLines.delete(innerFrame.line); 99 100 let middleFrame = innerFrame.parent; 101 ok(middleFrame, "Should get the middle frame"); 102 is(middleFrame.functionDisplayName, "middle"); 103 104 let outerFrame = middleFrame.parent; 105 ok(outerFrame, "Should get the outer frame"); 106 is(outerFrame.functionDisplayName, "outer"); 107 108 // Not going to test the rest of the frames because they are Task.jsm 109 // and promise frames and it gets gross. Plus, I wouldn't want this test 110 // to start failing if they changed their implementations in a way that 111 // added or removed stack frames here. 112 } 113 114 is(expectedLines.size, 0, 115 "Should have found all the expected lines"); 116 117 yield memory.detach(); 118 destroyServerAndFinish(client); 119 } 120 121 const generator = body(); 122 loop(generator.next()); 123 124 function loop({ value: promise, done }) { 125 if (done) 126 return; 127 promise 128 .catch(e => loop(generator.throw(e))) 129 .then(v => { loop(generator.next(v)); }) 130 .catch(e => { print(`Error: ${e}\nstack:\n${e.stack}`); }); 131 }