forked from mozilla/gecko-dev
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Bug 972045 - Add a compact representation for call stacks in SpiderMo…
…nkey. r=jimb
- Loading branch information
Nick Fitzgerald
committed
Apr 24, 2014
1 parent
2935429
commit 9f0fc42
Showing
24 changed files
with
1,115 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// The SavedFrame constructor shouldn't have been exposed to JS on the global. | ||
|
||
assertEq(typeof SavedFrame, "undefined"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Test that we can save stacks with direct and indirect eval calls. | ||
|
||
const directEval = (function iife() { | ||
return eval("(" + function evalFrame() { | ||
return saveStack(); | ||
} + "())"); | ||
}()); | ||
|
||
assertEq(directEval.source.contains("> eval"), true); | ||
assertEq(directEval.functionDisplayName, "evalFrame"); | ||
|
||
assertEq(directEval.parent.source.contains("> eval"), true); | ||
|
||
assertEq(directEval.parent.parent.source.contains("> eval"), false); | ||
assertEq(directEval.parent.parent.functionDisplayName, "iife"); | ||
|
||
assertEq(directEval.parent.parent.parent.source.contains("> eval"), false); | ||
|
||
assertEq(directEval.parent.parent.parent.parent, null); | ||
|
||
const lave = eval; | ||
const indirectEval = (function iife() { | ||
return lave("(" + function evalFrame() { | ||
return saveStack(); | ||
} + "())"); | ||
}()); | ||
|
||
assertEq(indirectEval.source.contains("> eval"), true); | ||
assertEq(indirectEval.functionDisplayName, "evalFrame"); | ||
|
||
assertEq(indirectEval.parent.source.contains("> eval"), true); | ||
|
||
assertEq(indirectEval.parent.parent.source.contains("> eval"), false); | ||
assertEq(indirectEval.parent.parent.functionDisplayName, "iife"); | ||
|
||
assertEq(indirectEval.parent.parent.parent.source.contains("> eval"), false); | ||
|
||
assertEq(indirectEval.parent.parent.parent.parent, null); |
17 changes: 17 additions & 0 deletions
17
js/src/jit-test/tests/saved-stacks/function-display-name.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Test the functionDisplayName of SavedFrame instances. | ||
|
||
function uno() { return dos(); } | ||
const dos = () => tres.quattro(); | ||
const tres = { | ||
quattro: () => saveStack() | ||
}; | ||
|
||
const frame = uno(); | ||
|
||
assertEq(frame.functionDisplayName, "tres.quattro"); | ||
assertEq(frame.parent.functionDisplayName, "dos"); | ||
assertEq(frame.parent.parent.functionDisplayName, "uno"); | ||
assertEq(frame.parent.parent.parent.functionDisplayName, null); | ||
|
||
assertEq(frame.parent.parent.parent.parent, null); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
// Test that SavedFrame instances get removed from the SavedStacks frames cache | ||
// after a GC. | ||
|
||
const FUZZ_FACTOR = 3; | ||
|
||
function assertAboutEq(actual, expected) { | ||
if (Math.abs(actual - expected) > FUZZ_FACTOR) | ||
throw new Error("Assertion failed: expected about " + expected + ", got " + actual + | ||
". FUZZ_FACTOR = " + FUZZ_FACTOR); | ||
} | ||
|
||
const stacks = []; | ||
|
||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
stacks.push(saveStack()); | ||
|
||
assertAboutEq(getSavedFrameCount(), 50); | ||
|
||
while (stacks.length) { | ||
stacks.pop(); | ||
} | ||
gc(); | ||
|
||
stacks = null; | ||
gc(); | ||
|
||
assertAboutEq(getSavedFrameCount(), 0); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// Test that we can save stacks which have generator frames. | ||
|
||
const { value: frame } = (function iife1() { | ||
return (function* generator() { | ||
yield (function iife2() { | ||
return saveStack(); | ||
}()); | ||
}()).next(); | ||
}()); | ||
|
||
assertEq(frame.functionDisplayName, "iife2"); | ||
assertEq(frame.parent.functionDisplayName, "generator"); | ||
assertEq(frame.parent.parent.functionDisplayName, "iife1"); | ||
assertEq(frame.parent.parent.parent.functionDisplayName, null); | ||
assertEq(frame.parent.parent.parent.parent, null); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Test that we can save stacks with getter and setter function frames. | ||
|
||
function assertStackLengthEq(stack, expectedLength) { | ||
let actual = 0; | ||
while (stack) { | ||
actual++; | ||
stack = stack.parent; | ||
} | ||
assertEq(actual, expectedLength); | ||
} | ||
|
||
const get = { get s() { return saveStack(); } }.s; | ||
assertStackLengthEq(get, 2); | ||
|
||
let set; | ||
try { | ||
({ | ||
set s(v) { | ||
throw saveStack(); | ||
} | ||
}).s = 1; | ||
} catch (s) { | ||
set = s; | ||
} | ||
assertStackLengthEq(set, 2); |
21 changes: 21 additions & 0 deletions
21
js/src/jit-test/tests/saved-stacks/getters-on-invalid-objects.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Test that you can't call the SavedFrame constructor and can only use | ||
// SavedFrame's getters on SavedFrame instances. | ||
|
||
load(libdir + "asserts.js"); | ||
|
||
let proto = Object.getPrototypeOf(saveStack()); | ||
|
||
// Can't create new SavedFrame instances by hand. | ||
assertThrowsInstanceOf(() => { | ||
new proto.constructor(); | ||
}, TypeError); | ||
|
||
for (let p of ["source", "line", "column", "functionDisplayName", "parent"]) { | ||
// The getters shouldn't work on the prototype. | ||
assertThrowsInstanceOf(() => proto[p], TypeError); | ||
|
||
// Nor should they work on random objects. | ||
let o = {}; | ||
Object.defineProperty(o, p, Object.getOwnPropertyDescriptor(proto, p)); | ||
assertThrowsInstanceOf(() => o[p], TypeError); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
// Test that we can save stacks with native code on the stack. | ||
|
||
// Unlike Array.prototype.map, Array.prototype.filter is not self-hosted. | ||
const filter = (function iife() { | ||
try { | ||
[3].filter(n => { throw saveStack() }); | ||
} catch (s) { | ||
return s; | ||
} | ||
}()); | ||
|
||
assertEq(filter.parent.functionDisplayName, "iife"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
// Test that SavedFrame.prototype.parent gives the next older frame whose | ||
// principals are subsumed by the caller's principals. | ||
|
||
// Given a string of letters |expected|, say "abc", assert that the stack | ||
// contains calls to a series of functions named by the next letter from | ||
// the string, say a, b, and then c. Younger frames appear earlier in | ||
// |expected| than older frames. | ||
function check(expected, stack) { | ||
print("check(" + uneval(expected) + ") against:\n" + stack); | ||
count++; | ||
|
||
while (stack.length && expected.length) { | ||
assertEq(stack.shift(), expected[0]); | ||
expected = expected.slice(1); | ||
} | ||
|
||
if (expected.length > 0) { | ||
throw new Error("Missing frames for: " + expected); | ||
} | ||
if (stack.length > 0 && !stack.every(s => s === null)) { | ||
throw new Error("Unexpected extra frame(s):\n" + stack); | ||
} | ||
} | ||
|
||
// Go from a SavedFrame linked list to an array of function display names. | ||
function extract(stack) { | ||
const results = []; | ||
while (stack) { | ||
results.push(stack.functionDisplayName); | ||
stack = stack.parent; | ||
} | ||
return results; | ||
} | ||
|
||
const low = newGlobal({ principal: 0 }); | ||
const mid = newGlobal({ principal: 0xffff }); | ||
const high = newGlobal({ principal: 0xfffff }); | ||
|
||
var count = 0; | ||
|
||
eval('function a() { check("a", extract(saveStack())); b(); }'); | ||
low .eval('function b() { check("b", extract(saveStack())); c(); }'); | ||
mid .eval('function c() { check("cba", extract(saveStack())); d(); }'); | ||
high.eval('function d() { check("dcba", extract(saveStack())); e(); }'); | ||
eval('function e() { check("edcba", extract(saveStack())); f(); }'); // no principal, so checks skipped | ||
low .eval('function f() { check("fb", extract(saveStack())); g(); }'); | ||
mid .eval('function g() { check("gfecba", extract(saveStack())); h(); }'); | ||
high.eval('function h() { check("hgfedcba", extract(saveStack())); }'); | ||
|
||
// Make everyone's functions visible to each other, as needed. | ||
b = low .b; | ||
low .c = mid .c; | ||
mid .d = high.d; | ||
high.e = e; | ||
f = low .f; | ||
low .g = mid .g; | ||
mid .h = high.h; | ||
|
||
low.check = mid.check = high.check = check; | ||
|
||
// They each must have their own extract so that CCWs don't mess up the | ||
// principals when we ask for the parent property. | ||
low. eval("" + extract); | ||
mid. eval("" + extract); | ||
high.eval("" + extract); | ||
|
||
// Kick the whole process off. | ||
a(); | ||
|
||
assertEq(count, 8); |
Oops, something went wrong.