pyodide/emsdk/patches/0001-JSDCE-Add-support-for-...

140 lines
4.8 KiB
Diff
Raw Normal View History

From b1502949816e4a343b90ca8a6e0411160dbc33ce Mon Sep 17 00:00:00 2001
From: Alon Zakai <azakai@google.com>
Date: Thu, 5 Oct 2023 16:29:07 -0700
Subject: [PATCH] JSDCE: Add support for destructuring declarations (#20402)
Rather than let x = 10, these look like let {x: y, ..} = ... or
let [x, y] = ...
Fixes https://github.com/emscripten-core/emscripten/issues/20393
---
test/optimizer/JSDCE-objectPattern-output.js | 16 ++++++++++
test/optimizer/JSDCE-objectPattern.js | 28 +++++++++++++++++
test/test_other.py | 1 +
tools/acorn-optimizer.js | 32 ++++++++++++++++++--
4 files changed, 74 insertions(+), 3 deletions(-)
create mode 100644 test/optimizer/JSDCE-objectPattern-output.js
create mode 100644 test/optimizer/JSDCE-objectPattern.js
diff --git a/test/optimizer/JSDCE-objectPattern-output.js b/test/optimizer/JSDCE-objectPattern-output.js
new file mode 100644
index 000000000..fb6ecf8ad
--- /dev/null
+++ b/test/optimizer/JSDCE-objectPattern-output.js
@@ -0,0 +1,16 @@
+let d = 40;
+
+let z = 50;
+
+globalThis.f = function(r) {
+ let {a: a, b: b} = r;
+ let {z: c} = r;
+ return g(a, b, c, d, z);
+};
+
+let d2 = 40;
+
+globalThis.f2 = function(r2) {
+ let [a2, b2, c2] = r2;
+ return g2(a2, b2, c2, d2);
+};
diff --git a/test/optimizer/JSDCE-objectPattern.js b/test/optimizer/JSDCE-objectPattern.js
new file mode 100644
index 000000000..61ff37638
--- /dev/null
+++ b/test/optimizer/JSDCE-objectPattern.js
@@ -0,0 +1,28 @@
+// Of all these, only d must remain: the others are defined in the function, and
+// used from that scope, not the global scope.
+let a = 10;
+let b = 20;
+let c = 30;
+let d = 40;
+
+// This one must also remain: z in the function is not a local variable, but the
+// id in an object, so it does not affect scoping at all, and we use the global
+// z.
+let z = 50;
+
+globalThis.f = function(r) {
+ let { a, b } = r;
+ let { z: c } = r;
+ return g(a, b, c, d, z);
+};
+
+// As above, but now with array destructuring.
+let a2 = 10;
+let b2 = 20;
+let c2 = 30;
+let d2 = 40;
+
+globalThis.f2 = function(r2) {
+ let [ a2, b2, c2 ] = r2;
+ return g2(a2, b2, c2, d2);
+};
diff --git a/test/test_other.py b/test/test_other.py
index cc775be0f..fe75f7683 100644
--- a/test/test_other.py
+++ b/test/test_other.py
@@ -2492,6 +2492,7 @@ int f() {
'JSDCE': ('optimizer/JSDCE.js', ['JSDCE']),
'JSDCE-hasOwnProperty': ('optimizer/JSDCE-hasOwnProperty.js', ['JSDCE']),
'JSDCE-fors': ('optimizer/JSDCE-fors.js', ['JSDCE']),
+ 'JSDCE-objectPattern': ('optimizer/JSDCE-objectPattern.js', ['JSDCE']),
'AJSDCE': ('optimizer/AJSDCE.js', ['AJSDCE']),
'emitDCEGraph': ('optimizer/emitDCEGraph.js', ['emitDCEGraph', 'noPrint']),
'emitDCEGraph-closure': ('optimizer/emitDCEGraph.js', ['emitDCEGraph', 'noPrint', '--closureFriendly']),
diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js
index 5274f3114..281b21b25 100755
--- a/tools/acorn-optimizer.js
+++ b/tools/acorn-optimizer.js
@@ -319,7 +319,16 @@ function runJSDCE(ast, aggressive) {
const old = node.declarations;
let removedHere = 0;
node.declarations = node.declarations.filter((node) => {
- const curr = node.id.name;
+ assert(node.type === 'VariableDeclarator');
+ const id = node.id;
+ if (id.type === 'ObjectPattern' || id.type === 'ArrayPattern') {
+ // TODO: DCE into object patterns, that is, things like
+ // let { a, b } = ..
+ // let [ a, b ] = ..
+ return true;
+ }
+ assert(id.type === 'Identifier');
+ const curr = id.name;
const value = node.init;
const keep = !(curr in names) || (value && hasSideEffects(value));
if (!keep) removedHere = 1;
@@ -390,8 +399,25 @@ function runJSDCE(ast, aggressive) {
recursiveWalk(ast, {
VariableDeclarator(node, c) {
- const name = node.id.name;
- ensureData(scopes[scopes.length - 1], name).def = 1;
+ const id = node.id;
+ if (id.type === 'ObjectPattern') {
+ id.properties.forEach((node) => {
+ const value = node.value;
+ assert(value.type === 'Identifier');
+ const name = value.name;
+ ensureData(scopes[scopes.length - 1], name).def = 1;
+ });
+ } else if (id.type === 'ArrayPattern') {
+ id.elements.forEach((node) => {
+ assert(node.type === 'Identifier');
+ const name = node.name;
+ ensureData(scopes[scopes.length - 1], name).def = 1;
+ });
+ } else {
+ assert(id.type === 'Identifier');
+ const name = id.name;
+ ensureData(scopes[scopes.length - 1], name).def = 1;
+ }
if (node.init) c(node.init);
},
ObjectExpression(node, c) {
--
2.25.1