Skip to content

Commit

Permalink
Fix again
Browse files Browse the repository at this point in the history
  • Loading branch information
hoodmane committed Jan 17, 2024
1 parent 9f25cc9 commit 87cc1d7
Showing 1 changed file with 217 additions and 0 deletions.
217 changes: 217 additions & 0 deletions emsdk/patches/acorn-optimizer.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
diff --git a/tools/acorn-optimizer.js b/tools/acorn-optimizer.js
index 5274f3114..c62e29f06 100755
--- a/tools/acorn-optimizer.js
+++ b/tools/acorn-optimizer.js
@@ -1,10 +1,8 @@
#!/usr/bin/env node

-'use strict';
-
-const acorn = require('acorn');
-const terser = require('../third_party/terser/terser');
-const fs = require('fs');
+import * as acorn from 'acorn';
+import * as terser from '../third_party/terser/terser.js';
+import * as fs from 'fs';

// Utilities

@@ -26,6 +24,15 @@ function assert(condition, text) {
}
}

+function assertAt(condition, node, message = '') {
+ if (!condition) {
+ const loc = acorn.getLineInfo(input, node.start);
+ throw new Error(
+ `${infile}:${loc.line}: ${message} (use EMCC_DEBUG_SAVE=1 to preserve temporary inputs)`,
+ );
+ }
+}
+
function warnOnce(msg) {
if (!warnOnce.msgs) warnOnce.msgs = {};
if (msg in warnOnce.msgs) return;
@@ -190,7 +197,7 @@ function restoreForVars(node) {
let restored = 0;
function fix(init) {
if (init && init.type === 'EmptyStatement') {
- assert(init.oldDeclarations);
+ assertAt(init.oldDeclarations, init);
init.type = 'VariableDeclaration';
init.declarations = init.oldDeclarations;
restored++;
@@ -319,7 +326,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;
@@ -361,12 +377,30 @@ function runJSDCE(ast, aggressive) {
ensureData(scopes[scopes.length - 1], node.id.name).def = 1;
}
const scope = {};
- node.params.forEach((param) => {
- const name = param.name;
- ensureData(scope, name).def = 1;
- scope[name].param = 1;
- });
scopes.push(scope);
+ node.params.forEach(function traverse(param) {
+ if (param.type === 'RestElement') {
+ param = param.argument;
+ }
+ if (param.type === 'AssignmentPattern') {
+ c(param.right);
+ param = param.left;
+ }
+ if (param.type === 'ArrayPattern') {
+ for (var elem of param.elements) {
+ traverse(elem);
+ }
+ } else if (param.type === 'ObjectPattern') {
+ for (var prop of param.properties) {
+ traverse(prop.key);
+ }
+ } else {
+ assert(param.type === 'Identifier', param.type);
+ const name = param.name;
+ ensureData(scope, name).def = 1;
+ scope[name].param = 1;
+ }
+ });
c(node.body);
// we can ignore self-references, i.e., references to ourselves inside
// ourselves, for named defined (defun) functions
@@ -390,8 +424,22 @@ function runJSDCE(ast, aggressive) {

recursiveWalk(ast, {
VariableDeclarator(node, c) {
- const name = node.id.name;
- ensureData(scopes[scopes.length - 1], name).def = 1;
+ function traverse(id) {
+ if (id.type === 'ObjectPattern') {
+ for (const prop of id.properties) {
+ traverse(prop.value);
+ }
+ } else if (id.type === 'ArrayPattern') {
+ for (const elem of id.elements) {
+ if (elem) traverse(elem);
+ }
+ } else {
+ assertAt(id.type === 'Identifier', id, `expected Indentifier but found ${id.type}`);
+ const name = id.name;
+ ensureData(scopes[scopes.length - 1], name).def = 1;
+ }
+ }
+ traverse(node.id);
if (node.init) c(node.init);
},
ObjectExpression(node, c) {
@@ -682,7 +730,7 @@ function emitDCEGraph(ast) {
// use the left hand identifier.
value = value.left;
}
- assert(value.type === 'Identifier');
+ assertAt(value.type === 'Identifier', value);
imports.push(value.name); // the name doesn't matter, only the value which is that actual thing we are importing
});
foundWasmImportsAssign = true;
@@ -742,7 +790,7 @@ function emitDCEGraph(ast) {
// var x = Module['x'] = 1234;
// this form occurs when global addresses are exported from the
// module. It doesn't constitute a usage.
- assert(typeof value.right.value === 'number');
+ assertAt(typeof value.right.value === 'number', value.right);
emptyOut(node);
}
}
@@ -829,7 +877,7 @@ function emitDCEGraph(ast) {
// must find the info we need
assert(
foundWasmImportsAssign,
- 'could not find the assigment to "wasmImports". perhaps --pre-js or --post-js code moved it out of the global scope? (things like that should be done after emcc runs, as they do not need to be run through the optimizer which is the special thing about --pre-js/--post-js code)'
+ 'could not find the assigment to "wasmImports". perhaps --pre-js or --post-js code moved it out of the global scope? (things like that should be done after emcc runs, as they do not need to be run through the optimizer which is the special thing about --pre-js/--post-js code)',
);
// Read exports that were declared in extraInfo
if (extraInfo) {
@@ -943,7 +991,10 @@ function emitDCEGraph(ast) {
print(JSON.stringify(graph, null, ' '));
}

-// Apply graph removals from running wasm-metadce
+// Apply graph removals from running wasm-metadce. This only removes imports and
+// exports from JS side, effectively disentangling the wasm and JS sides that
+// way (and we leave further DCE on the JS and wasm sides to their respective
+// optimizers, closure compiler and binaryen).
function applyDCEGraphRemovals(ast) {
const unused = new Set(extraInfo.unused);

@@ -1010,7 +1061,7 @@ function applyDCEGraphRemovals(ast) {

// Need a parser to pass to acorn.Node constructor.
// Create it once and reuse it.
-const stubParser = new acorn.Parser({ecmaVersion: 2020});
+const stubParser = new acorn.Parser({ecmaVersion: 2021});

function createNode(props) {
const node = new acorn.Node(stubParser);
@@ -1676,7 +1727,7 @@ function minifyLocals(ast) {
// locals are just numbers, not functions; functions are all declared
// in the outer scope. If a local is called, that is a bug.
if (node.callee.type === 'Identifier') {
- assert(!isLocalName(node.callee.name), 'cannot call a local');
+ assertAt(!isLocalName(node.callee.name), node.callee, 'cannot call a local');
}
},
});
@@ -1785,7 +1836,7 @@ function minifyGlobals(ast) {
ast.type === 'Program' &&
ast.body.length === 1 &&
ast.body[0].type === 'FunctionDeclaration' &&
- ast.body[0].id.name === 'instantiate'
+ ast.body[0].id.name === 'instantiate',
);
const fun = ast.body[0];

@@ -1890,7 +1941,7 @@ function reattachComments(ast, comments) {
if (node.start && node.start.pos) {
symbols.push(node);
}
- })
+ }),
);

// Sort them by ascending line number
@@ -1922,8 +1973,8 @@ function reattachComments(ast, comments) {
false,
undefined,
undefined,
- '0'
- )
+ '0',
+ ),
);
}
}
@@ -1974,7 +2025,7 @@ let ast;
try {
ast = acorn.parse(input, {
// Keep in sync with --language_in that we pass to closure in building.py
- ecmaVersion: 2020,
+ ecmaVersion: 2021,
preserveParens: closureFriendly,
onComment: closureFriendly ? sourceComments : undefined,
sourceType: exportES6 ? 'module' : 'script',

0 comments on commit 87cc1d7

Please sign in to comment.