@samitouri / QOS-React / commits / 316aa36865

[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;