1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
|
// Test that async stacks are limited on recursion.
const defaultAsyncStackLimit = 60;
function recur(n, limit) {
if (n > 0) {
return callFunctionWithAsyncStack(function recur() {return recur(n - 1, limit)},
saveStack(limit), "Recurse");
}
return saveStack(limit);
}
function checkRecursion(n, limit) {
print("checkRecursion(" + String(n) + ", " + String(limit) + ")");
try {
var stack = recur(n, limit);
} catch (e) {
// Some platforms, like ASAN builds, can end up overrecursing. Tolerate
// these failures.
assertEq(/too much recursion/.test("" + e), true);
return;
}
// Async stacks are limited even if we didn't ask for a limit. There is a
// default limit on frames attached on top of any synchronous frames, and
// every time the limit is reached when capturing, half of the frames are
// truncated from the old end of the async stack.
if (limit == 0) {
// Always add one synchronous frame that is the last call to `recur`.
if (n + 1 < defaultAsyncStackLimit) {
limit = defaultAsyncStackLimit + 1;
} else {
limit = n + 2 - (defaultAsyncStackLimit / 2);
}
}
// The first `n` or `limit` frames should have `recur` as their `asyncParent`.
for (var i = 0; i < Math.min(n, limit); i++) {
assertEq(stack.functionDisplayName, "recur");
assertEq(stack.parent, null);
stack = stack.asyncParent;
}
// This frame should be the first call to `recur`.
if (limit > n) {
assertEq(stack.functionDisplayName, "recur");
assertEq(stack.asyncParent, null);
stack = stack.parent;
} else {
assertEq(stack, null);
}
// This frame should be the call to `checkRecursion`.
if (limit > n + 1) {
assertEq(stack.functionDisplayName, "checkRecursion");
assertEq(stack.asyncParent, null);
stack = stack.parent;
} else {
assertEq(stack, null);
}
// We should be at the top frame, which is the test script itself.
if (limit > n + 2) {
assertEq(stack.functionDisplayName, null);
assertEq(stack.asyncParent, null);
assertEq(stack.parent, null);
} else {
assertEq(stack, null);
}
}
// Check capturing with no limit, which should still apply a default limit.
checkRecursion(0, 0);
checkRecursion(1, 0);
checkRecursion(2, 0);
checkRecursion(defaultAsyncStackLimit - 10, 0);
checkRecursion(defaultAsyncStackLimit, 0);
checkRecursion(defaultAsyncStackLimit + 10, 0);
// Limit of 1 frame.
checkRecursion(0, 1);
checkRecursion(1, 1);
checkRecursion(2, 1);
// Limit of 2 frames.
checkRecursion(0, 2);
checkRecursion(1, 2);
checkRecursion(2, 2);
// Limit of 3 frames.
checkRecursion(0, 3);
checkRecursion(1, 3);
checkRecursion(2, 3);
// Limit higher than the default limit.
checkRecursion(defaultAsyncStackLimit + 10, defaultAsyncStackLimit + 10);
checkRecursion(defaultAsyncStackLimit + 11, defaultAsyncStackLimit + 10);
checkRecursion(defaultAsyncStackLimit + 12, defaultAsyncStackLimit + 10);
|