@samitouri / QOS-React-2 / commits / 3a200fa4a1

Pass to eliminate redundant phis

This is an alternate take on phi elimination to the one we pursued over VC w @poteto driving. This version exploits the RPO ordering of blocks to do phi elimination in a single pass when there are no loops, and to minimize repeated visits when there are loops. The main difference is when redundant phis are removed. Rather than eagerly walking through the CFG for each pruned phi to rewrite its uses, we build up a mapping of rewritten identifiers. As we walk through subsequent instructions, we rewrite each place based on that mapping. We continue cycling through the blocks so long as a given iteration *both* added new rewrites (meaning there may be subsequent uses to rewrite) *and* there are back-edges. With no loops this results in a single visit of each block and of each instruction, but even with loops this is bounded.

Joseph Savona committed Nov 7, 2022 at 08:37 UTC 3a200fa4a1911eb2eee8f5bbfdedfb478462a4ab
12 files changed +321 -59
compiler/forget/src/HIR/EliminateRedundantPhi.ts new
+139
@@ -0,0 +1,139 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + */
7 +
8 +import invariant from "invariant";
9 +import { assertExhaustive } from "../Common/utils";
10 +import { BlockId, HIRFunction, Identifier, Place } from "./HIR";
11 +import { collectInputs } from "./InferMutableLifetimes";
12 +
13 +/**
14 + * Pass to eliminate redundant phi nodes:
15 + * - all operands are the same identifier, ie `x2 = phi(x1, x1, x1)`.
16 + * - all operands are the same identifier *or* the output of the phi, ie `x2 = phi(x1, x2, x1, x2)`.
17 + *
18 + * In both these cases, the phi is eliminated and all usages of the phi identifier
19 + * are replaced with the other operand (ie in both cases above, all usages of `x2` are replaced with `x1` .
20 + *
21 + * The algorithm is inspired by that in https://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
22 + * but modified to reduce passes over the CFG. We visit the blocks in reverse postorder. Each time a redundant
23 + * phi is encountered we add a mapping (eg x2 -> x1) to a rewrite table. Subsequent instructions, terminals,
24 + * and phis rewrite all their identifiers based on this table. The algorithm loops over the CFG repeatedly
25 + * until there are no new rewrites: for a CFG without back-edges it completes in a single pass.
26 + */
27 +export function eliminateRedundantPhi(fn: HIRFunction) {
28 + const ir = fn.body;
29 + const rewrites: Map<Identifier, Identifier> = new Map();
30 +
31 + // Whether or the CFG has a back-edge (a loop). We determine this dynamically
32 + // during the first iteration over the CFG by recording which blocks were already
33 + // visited, and checking if a block has any predecessors that weren't visited yet.
34 + // Because blocks are in reverse postorder, the only time this can occur is a loop.
35 + let hasBackEdge = false;
36 + const visited: Set<BlockId> = new Set();
37 +
38 + // size tracks the number of rewrites at the beginning of each iteration, so we can
39 + // compare to see if any new rewrites were added in that iteration.
40 + let size = rewrites.size;
41 + do {
42 + size = rewrites.size;
43 + for (const [blockId, block] of ir.blocks) {
44 + // On the first iteration of the loop check for any back-edges.
45 + // if there aren't any then there won't be a second iteration
46 + if (!hasBackEdge) {
47 + for (const pred of block.preds) {
48 + if (!visited.has(pred.id)) {
49 + hasBackEdge = true;
50 + }
51 + }
52 + }
53 + visited.add(blockId);
54 +
55 + // Find any redundant phis
56 + phis: for (const phi of block.phis) {
57 + let same: Identifier | null = null;
58 + for (const [_, operand] of phi.operands) {
59 + const ident = rewrites.get(operand) ?? operand;
60 + if (
61 + (same !== null && ident.id === same.id) ||
62 + ident.id === phi.id.id
63 + ) {
64 + // This operand is the same as the phi or is the same as the
65 + // previous non-phi operands
66 + continue;
67 + } else if (same !== null) {
68 + // There are multiple operands not equal to the phi itself,
69 + // this phi can't be eliminated.
70 + continue phis;
71 + } else {
72 + // First non-phi operand
73 + same = ident;
74 + }
75 + }
76 + invariant(same !== null, "Expected phis to be non-empty");
77 + rewrites.set(phi.id, same);
78 + block.phis.delete(phi);
79 + }
80 +
81 + // Rewrite all instruction lvalues and operands
82 + for (const instr of block.instructions) {
83 + for (const place of collectInputs(instr)) {
84 + rewritePlace(place, rewrites);
85 + }
86 + const { lvalue } = instr;
87 + if (lvalue !== null) {
88 + rewritePlace(lvalue.place, rewrites);
89 + }
90 + }
91 +
92 + // Rewrite all terminal operands
93 + const { terminal } = block;
94 + switch (terminal.kind) {
95 + case "if": {
96 + rewritePlace(terminal.test, rewrites);
97 + break;
98 + }
99 + case "switch": {
100 + rewritePlace(terminal.test, rewrites);
101 + for (const case_ of terminal.cases) {
102 + if (case_.test === null) {
103 + continue;
104 + }
105 + rewritePlace(case_.test, rewrites);
106 + }
107 + break;
108 + }
109 + case "return":
110 + case "throw": {
111 + if (terminal.value !== null) {
112 + rewritePlace(terminal.value, rewrites);
113 + }
114 + break;
115 + }
116 + case "goto": {
117 + // no-op
118 + break;
119 + }
120 + default: {
121 + assertExhaustive(
122 + terminal,
123 + `Unexpected terminal kind '${(terminal as any).kind}'`
124 + );
125 + }
126 + }
127 + }
128 + // We only need to loop if there were newly eliminated phis in this iteration
129 + // *and* the CFG has loops. If there are no loops, then all eliminated phis
130 + // have already propagated forwards since we visit in reverse postorder.
131 + } while (rewrites.size > size && hasBackEdge);
132 +}
133 +
134 +function rewritePlace(place: Place, rewrites: Map<Identifier, Identifier>) {
135 + const rewrite = rewrites.get(place.identifier);
136 + if (rewrite != null) {
137 + place.identifier = rewrite;
138 + }
139 +}
compiler/forget/src/HIR/InferMutableLifetimes.ts
+11 -2
@@ -106,7 +106,7 @@ export function inferMutableRanges(func: HIRFunction) {
106 }
107 }
108
109 -function* collectInputs(instr: Instruction) {
109 +export function* collectInputs(instr: Instruction) {
110 const instrValue = instr.value;
111 switch (instrValue.kind) {
112 case "NewExpression":
@@ -142,6 +142,12 @@ function* collectInputs(instr: Instruction) {
142 }
143 break;
144 }
145 + case "JsxFragment": {
146 + for (const c of instrValue.children) {
147 + yield c;
148 + }
149 + break;
150 + }
151 case "ObjectExpression": {
152 if (instrValue.properties !== null) {
153 const props = instrValue.properties;
@@ -163,7 +169,10 @@ function* collectInputs(instr: Instruction) {
169 break;
170 }
171 default: {
166 - console.log(`unhandled instruction: ${printInstruction(instr)}`);
172 + assertExhaustive(
173 + instrValue,
174 + `Unexpected instruction kind '${(instrValue as any).kind}'`
175 + );
176 }
177 }
178 }
compiler/forget/src/__tests__/fixtures/hir/component.expect.md
+11 -16
@@ -37,23 +37,18 @@ function Component(props) {
37 bb0:
38 [1] Const mutate items$27 = read props$26.items
39 [2] Const mutate maxItems$28 = read props$26.maxItems
40 - [3] Const mutate renderedItems$29 = Array []
41 - [4] Const mutate seen$30 = New mutate Set$6()
40 + [3] Const mutate renderedItems$29[3:14] = Array []
41 + [4] Const mutate seen$30[4:11] = New mutate Set$6()
42 [5] Const mutate $31 = 0
43 [6] Const mutate max$32 = Call mutate Math$8.max(read $31, read maxItems$28)
44 Goto bb1
45 bb1:
46 predecessor blocks: bb0 bb4 bb7
47 - items$33: phi(bb0: items$27, bb4: items$33, bb7: items$33)
48 - item$35[-1:11]: phi(bb0: item$10, bb4: item$35, bb7: item$35)
49 - seen$38[-1:11]: phi(bb0: seen$30, bb4: seen$38, bb7: seen$38)
50 - renderedItems$46[-1:14]: phi(bb0: renderedItems$29, bb4: renderedItems$46, bb7: renderedItems$46)
51 - max$48: phi(bb0: max$32, bb4: max$48, bb7: max$48)
52 - If (read items$33) then:bb3 else:bb2
47 + If (read items$27) then:bb3 else:bb2
48 bb3:
49 predecessor blocks: bb1
50 [7] Const mutate $34 = null
56 - [8] Const mutate $36 = Binary read item$35 == read $34
51 + [8] Const mutate $36 = Binary read item$10 == read $34
52 If (read $36) then:bb8 else:bb9
53 bb8:
54 predecessor blocks: bb3
@@ -61,7 +56,7 @@ bb8:
56 Goto bb7
57 bb9:
58 predecessor blocks: bb3
64 - [10] Const mutate $39 = Call mutate seen$38.has(mutate item$35)
59 + [10] Const mutate $39 = Call mutate seen$30.has(mutate item$10)
60 Goto bb7
61 bb7:
62 predecessor blocks: bb9 bb8
@@ -69,15 +64,15 @@ bb7:
64 If (read $40) then:bb1 else:bb4
65 bb4:
66 predecessor blocks: bb7
72 - [11] Call mutate seen$38.add(mutate item$35)
67 + [11] Call mutate seen$30.add(mutate item$10)
68 [12] Const mutate $43 = "div"
74 - [13] Const mutate $44 = JSX <read $43>{read item$35}</read $43>
75 - [14] Call mutate renderedItems$46.push(read $44)
76 - [15] Const mutate $49 = Binary read renderedItems$46.length >= read max$48
69 + [13] Const mutate $44 = JSX <read $43>{read item$10}</read $43>
70 + [14] Call mutate renderedItems$29.push(read $44)
71 + [15] Const mutate $49 = Binary read renderedItems$29.length >= read max$32
72 If (read $49) then:bb2 else:bb1
73 bb2:
74 predecessor blocks: bb1 bb4
80 - [16] Const mutate count$52 = read renderedItems$46.length
75 + [16] Const mutate count$52 = read renderedItems$29.length
76 [17] Const mutate $53 = "div"
77 [18] Const mutate $54 = "\n "
78 [19] Const mutate $55 = "h1"
@@ -85,7 +80,7 @@ bb2:
80 [21] Const mutate $57 = JSX <read $55>{freeze count$52}{read $56}</read $55>
81 [22] Const mutate $58 = "\n "
82 [23] Const mutate $59 = "\n "
88 - [24] Const mutate $60 = JSX <read $53>{read $54}{read $57}{read $58}{freeze renderedItems$46}{read $59}</read $53>
83 + [24] Const mutate $60 = JSX <read $53>{read $54}{read $57}{read $58}{freeze renderedItems$29}{read $59}</read $53>
84 Return read $60
85 ```
86
compiler/forget/src/__tests__/fixtures/hir/mutable-lifetime-loops.expect.md
+3 -5
@@ -84,8 +84,6 @@ bb1:
84 b$20: phi(bb0: b$14, bb3: b$23)
85 c$22: phi(bb0: c$15, bb3: c$25)
86 d$24: phi(bb0: d$16, bb3: d$26)
87 - mutate$27[-1:14]: phi(bb0: mutate$7, bb3: mutate$27)
88 - cond$28[-1:12]: phi(bb0: cond$8, bb3: cond$28)
87 [5] Const mutate $17 = true
88 If (read $17) then:bb3 else:bb2
89 bb3:
@@ -95,8 +93,8 @@ bb3:
93 [8] Reassign mutate b$23[8:11] = read c$22
94 [9] Reassign mutate c$25 = read d$24
95 [10] Reassign mutate d$26 = read z$19
98 - [11] Call mutate mutate$27(mutate a$21, mutate b$23)
99 - [12] Const mutate $29 = Call mutate cond$28(mutate a$21)
96 + [11] Call mutate mutate$7(mutate a$21, mutate b$23)
97 + [12] Const mutate $29 = Call mutate cond$8(mutate a$21)
98 If (read $29) then:bb2 else:bb1
99 bb2:
100 predecessor blocks: bb1 bb3
@@ -117,7 +115,7 @@ bb11:
115 bb13:
116 predecessor blocks: bb11
117 [13] Const mutate $34 = null
120 - [14] Call mutate mutate$27(mutate d$33, read $34)
118 + [14] Call mutate mutate$7(mutate d$33, read $34)
119 Return
120 ```
121
compiler/forget/src/__tests__/fixtures/hir/mutable-liverange-loop.expect.md
+10 -16
@@ -68,42 +68,36 @@ function cond$0() {
68
69 ```
70 bb0:
71 - [1] Let mutate a$12 = Object { }
72 - [2] Let mutate b$13 = Object { }
71 + [1] Let mutate a$12[1:7] = Object { }
72 + [2] Let mutate b$13[2:6] = Object { }
73 [3] Let mutate c$14 = Object { }
74 - [4] Let mutate d$15 = Object { }
74 + [4] Let mutate d$15[4:9] = Object { }
75 Goto bb1
76 bb1:
77 predecessor blocks: bb0 bb3
78 - mutate$17[-1:9]: phi(bb0: mutate$6, bb3: mutate$17)
79 - a$18[-1:7]: phi(bb0: a$12, bb3: a$18)
80 - b$19[-1:6]: phi(bb0: b$13, bb3: b$19)
81 - cond$20[-1:7]: phi(bb0: cond$7, bb3: cond$20)
82 - c$25: phi(bb0: c$14, bb3: c$25)
83 - d$27[-1:9]: phi(bb0: d$15, bb3: d$27)
78 [5] Const mutate $16 = true
79 If (read $16) then:bb3 else:bb2
80 bb3:
81 predecessor blocks: bb1
88 - [6] Call mutate mutate$17(mutate a$18, mutate b$19)
89 - [7] Const mutate $21 = Call mutate cond$20(mutate a$18)
82 + [6] Call mutate mutate$6(mutate a$12, mutate b$13)
83 + [7] Const mutate $21 = Call mutate cond$7(mutate a$12)
84 If (read $21) then:bb2 else:bb1
85 bb2:
86 predecessor blocks: bb1 bb3
93 - If (read a$18) then:bb7 else:bb7
87 + If (read a$12) then:bb7 else:bb7
88 bb7:
89 predecessor blocks: bb2
96 - If (read b$19) then:bb9 else:bb9
90 + If (read b$13) then:bb9 else:bb9
91 bb9:
92 predecessor blocks: bb7
99 - If (read c$25) then:bb11 else:bb11
93 + If (read c$14) then:bb11 else:bb11
94 bb11:
95 predecessor blocks: bb9
102 - If (read d$27) then:bb13 else:bb13
96 + If (read d$15) then:bb13 else:bb13
97 bb13:
98 predecessor blocks: bb11
99 [8] Const mutate $28 = null
106 - [9] Call mutate mutate$17(mutate d$27, read $28)
100 + [9] Call mutate mutate$6(mutate d$15, read $28)
101 Return
102 ```
103
compiler/forget/src/__tests__/fixtures/hir/ssa-for-of.expect.md
+3 -5
@@ -23,20 +23,18 @@ bb0:
23 Goto bb1
24 bb1:
25 predecessor blocks: bb0 bb3 bb5
26 - items$6: phi(bb0: items$5, bb3: items$6, bb5: items$6)
27 - cond$8: phi(bb0: cond$4, bb3: cond$8, bb5: cond$8)
28 - If (read items$6) then:bb3 else:bb2
26 + If (read items$5) then:bb3 else:bb2
27 bb3:
28 predecessor blocks: bb1
29 [2] Let mutate y$7 = 0
32 - If (read cond$8) then:bb5 else:bb1
30 + If (read cond$4) then:bb5 else:bb1
31 bb5:
32 predecessor blocks: bb3
33 [3] Reassign mutate y$9 = 1
34 Goto bb1
35 bb2:
36 predecessor blocks: bb1
39 - Return freeze items$6
37 + Return freeze items$5
38 ```
39
40 ## Code
compiler/forget/src/__tests__/fixtures/hir/ssa-nested-loops-no-reassign.expect.md new
+53
@@ -0,0 +1,53 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo(a, b, c) {
6 + let x = 0;
7 + while (a) {
8 + while (b) {
9 + while (c) {
10 + x + 1;
11 + }
12 + }
13 + }
14 + return x;
15 +}
16 +
17 +```
18 +
19 +## HIR
20 +
21 +```
22 +bb0:
23 + [1] Let mutate x$9 = 0
24 + Goto bb1
25 +bb1:
26 + predecessor blocks: bb0 bb4
27 + If (read a$6) then:bb4 else:bb2
28 +bb4:
29 + predecessor blocks: bb1 bb7
30 + If (read b$7) then:bb7 else:bb1
31 +bb7:
32 + predecessor blocks: bb4 bb9
33 + If (read c$8) then:bb9 else:bb4
34 +bb9:
35 + predecessor blocks: bb7
36 + [2] Const mutate $17 = 1
37 + [3] Binary read x$9 + read $17
38 + Goto bb7
39 +bb2:
40 + predecessor blocks: bb1
41 + Return read x$9
42 +```
43 +
44 +## Code
45 +
46 +```javascript
47 +function foo$0(a$6, b$7, c$8) {
48 + let x$9 = 0;
49 + ("<<TODO: handle complex control flow in codegen>>");
50 +}
51 +
52 +```
53 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-nested-loops-no-reassign.js new
+11
@@ -0,0 +1,11 @@
1 +function foo(a, b, c) {
2 + let x = 0;
3 + while (a) {
4 + while (b) {
5 + while (c) {
6 + x + 1;
7 + }
8 + }
9 + }
10 + return x;
11 +}
compiler/forget/src/__tests__/fixtures/hir/ssa-while-no-reassign.expect.md new
+46
@@ -0,0 +1,46 @@
1 +
2 +## Input
3 +
4 +```javascript
5 +function foo() {
6 + let x = 1;
7 + while (x < 10) {
8 + x + 1;
9 + }
10 +
11 + return x;
12 +}
13 +
14 +```
15 +
16 +## HIR
17 +
18 +```
19 +bb0:
20 + [1] Let mutate x$5 = 1
21 + Goto bb1
22 +bb1:
23 + predecessor blocks: bb0 bb3
24 + [2] Const mutate $6 = 10
25 + [3] Const mutate $8 = Binary read x$5 < read $6
26 + If (read $8) then:bb3 else:bb2
27 +bb3:
28 + predecessor blocks: bb1
29 + [4] Const mutate $9 = 1
30 + [5] Binary read x$5 + read $9
31 + Goto bb1
32 +bb2:
33 + predecessor blocks: bb1
34 + Return read x$5
35 +```
36 +
37 +## Code
38 +
39 +```javascript
40 +function foo$0() {
41 + let x$5 = 1;
42 + ("<<TODO: handle complex control flow in codegen>>");
43 +}
44 +
45 +```
46 +
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/ssa-while-no-reassign.js new
+8
@@ -0,0 +1,8 @@
1 +function foo() {
2 + let x = 1;
3 + while (x < 10) {
4 + x + 1;
5 + }
6 +
7 + return x;
8 +}
compiler/forget/src/__tests__/hir-test.ts
+2
@@ -16,6 +16,7 @@ import path from "path";
16 import prettier from "prettier";
17 import { lower } from "../HIR/BuildHIR";
18 import codegen from "../HIR/Codegen";
19 +import { eliminateRedundantPhi } from "../HIR/EliminateRedundantPhi";
20 import { HIRFunction } from "../HIR/HIR";
21 import { Environment } from "../HIR/HIRBuilder";
22 import { inferMutableRanges } from "../HIR/InferMutableLifetimes";
@@ -64,6 +65,7 @@ describe("React Forget (HIR version)", () => {
65 const env: Environment = new Environment();
66 const ir: HIRFunction = lower(nodePath, env);
67 buildSSA(ir, env);
68 + eliminateRedundantPhi(ir);
69 inferReferenceEffects(ir);
70 inferMutableRanges(ir);
71 // const lifetimeGraph = buildDefUseGraph(ir);
compiler/forget/yarn.lock
+24 -15
@@ -83,12 +83,12 @@
83 "@jridgewell/gen-mapping" "^0.3.2"
84 jsesc "^2.5.1"
85
86 -"@babel/generator@^7.19.6":
87 - version "7.19.6"
88 - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.19.6.tgz#9e481a3fe9ca6261c972645ae3904ec0f9b34a1d"
89 - integrity sha512-oHGRUQeoX1QrKeJIKVe0hwjGqNnVYsM5Nep5zo0uE0m42sLH+Fsd2pStJ5sRM1bNyTUUoz0pe2lTeMJrb/taTA==
86 +"@babel/generator@^7.20.1":
87 + version "7.20.2"
88 + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.2.tgz#c2e89e22613a039285c1e7b749e2cd0b30b9a481"
89 + integrity sha512-SD75PMIK6i9H8G/tfGvB4KKl4Nw6Ssos9nGgYwxbgyTP0iX/Z55DveoH86rmUB/YHTQQ+ZC0F7xxaY8l2OF44Q==
90 dependencies:
91 - "@babel/types" "^7.19.4"
91 + "@babel/types" "^7.20.2"
92 "@jridgewell/gen-mapping" "^0.3.2"
93 jsesc "^2.5.1"
94
@@ -260,10 +260,10 @@
260 resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.3.tgz#8dd36d17c53ff347f9e55c328710321b49479a9a"
261 integrity sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==
262
263 -"@babel/parser@^7.19.6":
264 - version "7.19.6"
265 - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.6.tgz#b923430cb94f58a7eae8facbffa9efd19130e7f8"
266 - integrity sha512-h1IUp81s2JYJ3mRkdxJgs4UvmSsRvDrx5ICSJbPvtWYv5i1nTBGcBpnog+89rAFMwvvru6E5NUHdBe01UeSzYA==
263 +"@babel/parser@^7.20.1":
264 + version "7.20.2"
265 + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.2.tgz#9aeb9b92f64412b5f81064d46f6a1ac0881337f4"
266 + integrity sha512-afk318kh2uKbo7BEj2QtEi8HVCGrwHUffrYDy7dgVcSa2j9lY3LDjPzcyGdpX7xgm35aWqvciZJ4WKmdF/SxYg==
267
268 "@babel/plugin-syntax-async-generators@^7.8.4":
269 version "7.8.4"
@@ -484,18 +484,18 @@
484 lodash "^4.17.10"
485
486 "@babel/traverse@^7.19.1":
487 - version "7.19.6"
488 - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.19.6.tgz#7b4c865611df6d99cb131eec2e8ac71656a490dc"
489 - integrity sha512-6l5HrUCzFM04mfbG09AagtYyR2P0B71B1wN7PfSPiksDPz2k5H9CBC1tcZpz2M8OxbKTPccByoOJ22rUKbpmQQ==
487 + version "7.20.1"
488 + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.1.tgz#9b15ccbf882f6d107eeeecf263fbcdd208777ec8"
489 + integrity sha512-d3tN8fkVJwFLkHkBN479SOsw4DMZnz8cdbL/gvuDuzy3TS6Nfw80HuQqhw1pITbIruHyh7d1fMA47kWzmcUEGA==
490 dependencies:
491 "@babel/code-frame" "^7.18.6"
492 - "@babel/generator" "^7.19.6"
492 + "@babel/generator" "^7.20.1"
493 "@babel/helper-environment-visitor" "^7.18.9"
494 "@babel/helper-function-name" "^7.19.0"
495 "@babel/helper-hoist-variables" "^7.18.6"
496 "@babel/helper-split-export-declaration" "^7.18.6"
497 - "@babel/parser" "^7.19.6"
498 - "@babel/types" "^7.19.4"
497 + "@babel/parser" "^7.20.1"
498 + "@babel/types" "^7.20.0"
499 debug "^4.1.0"
500 globals "^11.1.0"
501
@@ -534,6 +534,15 @@
534 "@babel/helper-validator-identifier" "^7.19.1"
535 to-fast-properties "^2.0.0"
536
537 +"@babel/types@^7.20.0", "@babel/types@^7.20.2":
538 + version "7.20.2"
539 + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.2.tgz#67ac09266606190f496322dbaff360fdaa5e7842"
540 + integrity sha512-FnnvsNWgZCr232sqtXggapvlkk/tuwR/qhGzcmxI0GXLCjmPYQPzio2FbdlWuY6y1sHFfQKk+rRbUZ9VStQMog==
541 + dependencies:
542 + "@babel/helper-string-parser" "^7.19.4"
543 + "@babel/helper-validator-identifier" "^7.19.1"
544 + to-fast-properties "^2.0.0"
545 +
546 "@bcoe/v8-coverage@^0.2.3":
547 version "0.2.3"
548 resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"