()
| 58 | * @private |
| 59 | */ |
| 60 | export function enterTask() { |
| 61 | // If this is the first task we enter, record the current stack position as |
| 62 | // the top of the entire stack and leave it alone. |
| 63 | if (stackTop === undefined) { |
| 64 | stackTop = stackSave(); |
| 65 | return; |
| 66 | } |
| 67 | // Search for a gap in the stack large enough that we feel like sticking a |
| 68 | // task in it. We search from bottom to top because insertion is cheaper |
| 69 | // closer to the bottom. (More specifically, if the tasks run a long time then |
| 70 | // it costs the same no matter where we insert but if they are short lived |
| 71 | // inserting lower is better). |
| 72 | |
| 73 | // If we make threshold bigger, we will use up more stack space but also copy |
| 74 | // less stack around. If we make it smaller, we use less stack space but copy |
| 75 | // more stack. |
| 76 | const threshold = (taskSizeTotal / taskSizeCount) * 0.8; |
| 77 | let lastStop = stackStates.at(-1)?.stop; |
| 78 | for (let idx = stackStates.length - 2; idx >= -1; idx--) { |
| 79 | const state = |
| 80 | idx >= 0 ? stackStates[idx] : { start: stackTop, stop: stackTop }; |
| 81 | if (state.start - lastStop > threshold) { |
| 82 | setStackPosition(state.start); |
| 83 | return; |
| 84 | } |
| 85 | lastStop = state.stop; |
| 86 | } |
| 87 | // No large enough gaps found. Last, check if the current stack position is |
| 88 | // below the bottom used stack position and if so move the stack up. This can |
| 89 | // happen if a task higher on the stack exited first followed by a task lower |
| 90 | // on the stack. |
| 91 | const bottomUsed = stackStates.at(-1)?.start ?? stackTop; |
| 92 | if (bottomUsed > stackSave()) { |
| 93 | setStackPosition(bottomUsed); |
| 94 | return; |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | function evictStackUpTo(stop) { |
| 99 | let total = 0; |
no test coverage detected
searching dependent graphs…