| // 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("ecba", extract(saveStack())); f(); }'); |
| 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); |