[Scheduler] Fix de-opt caused by out-of-bounds access (#21147)
Scheduler's heap implementation sometimes accesses indices that are out of bounds (larger than the size of the array). This causes a VM de-opt. This change fixes the de-opt by always checking the index before accessing the array. In exchange, we can remove the typecheck on the returned element. Background: https://v8.dev/blog/elements-kinds#avoid-reading-beyond-the-length-of-the-array Co-authored-by: Andrew Clark <git@andrewclark.io>
Andrey Marchenko committed
Apr 6, 2021 at 07:05 UTC
316aa368654427270a53543cd3f4952746374596
1 file changed
+16
-17
packages/scheduler/src/SchedulerMinHeap.js
+16
-17
@@ -20,30 +20,28 @@ export function push(heap: Heap, node: Node): void {
20
}
21
22
export function peek(heap: Heap): Node | null {
23
- const first = heap[0];
24
- return first === undefined ? null : first;
23
+ return heap.length === 0 ? null : heap[0];
24
}
25
26
export function pop(heap: Heap): Node | null {
28
- const first = heap[0];
29
- if (first !== undefined) {
30
- const last = heap.pop();
31
- if (last !== first) {
32
- heap[0] = last;
33
- siftDown(heap, last, 0);
34
- }
35
- return first;
36
- } else {
27
+ if (heap.length === 0) {
28
return null;
29
}
30
+ const first = heap[0];
31
+ const last = heap.pop();
32
+ if (last !== first) {
33
+ heap[0] = last;
34
+ siftDown(heap, last, 0);
35
+ }
36
+ return first;
37
}
38
39
function siftUp(heap, node, i) {
40
let index = i;
43
- while (true) {
41
+ while (index > 0) {
42
const parentIndex = (index - 1) >>> 1;
43
const parent = heap[parentIndex];
46
- if (parent !== undefined && compare(parent, node) > 0) {
44
+ if (compare(parent, node) > 0) {
45
// The parent is larger. Swap positions.
46
heap[parentIndex] = node;
47
heap[index] = parent;
@@ -58,15 +56,16 @@ function siftUp(heap, node, i) {
56
function siftDown(heap, node, i) {
57
let index = i;
58
const length = heap.length;
61
- while (index < length) {
59
+ const halfLength = length >>> 1;
60
+ while (index < halfLength) {
61
const leftIndex = (index + 1) * 2 - 1;
62
const left = heap[leftIndex];
63
const rightIndex = leftIndex + 1;
64
const right = heap[rightIndex];
65
66
// If the left or right node is smaller, swap with the smaller of those.
68
- if (left !== undefined && compare(left, node) < 0) {
69
- if (right !== undefined && compare(right, left) < 0) {
67
+ if (compare(left, node) < 0) {
68
+ if (rightIndex < length && compare(right, left) < 0) {
69
heap[index] = right;
70
heap[rightIndex] = node;
71
index = rightIndex;
@@ -75,7 +74,7 @@ function siftDown(heap, node, i) {
74
heap[leftIndex] = node;
75
index = leftIndex;
76
}
78
- } else if (right !== undefined && compare(right, node) < 0) {
77
+ } else if (rightIndex < length && compare(right, node) < 0) {
78
heap[index] = right;
79
heap[rightIndex] = node;
80
index = rightIndex;