From bc27966a196ecb91f33a53a11497bdf2d85eb8cf Mon Sep 17 00:00:00 2001 From: "Alex Lam S.L" Date: Wed, 8 Dec 2021 05:40:47 +0000 Subject: [PATCH] workaround v8 performance quirks (#5207) --- bin/uglifyjs | 2 +- lib/ast.js | 8 ++++---- lib/compress.js | 53 +++++++++++++++++++++++++++---------------------- lib/scope.js | 6 ++++-- 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/bin/uglifyjs b/bin/uglifyjs index 726cd881..8e679977 100755 --- a/bin/uglifyjs +++ b/bin/uglifyjs @@ -10,7 +10,7 @@ var info = require("../package.json"); var path = require("path"); var UglifyJS = require("../tools/node"); -var skip_keys = [ "cname", "fixed", "inlined", "length_read", "parent_scope", "scope" ]; +var skip_keys = [ "cname", "fixed", "in_arg", "inlined", "length_read", "parent_scope", "redef", "scope", "unused" ]; var truthy_keys = [ "optional", "pure", "terminal", "uses_arguments", "uses_eval", "uses_with" ]; var files = {}; diff --git a/lib/ast.js b/lib/ast.js index b21ea0cb..b8732a78 100644 --- a/lib/ast.js +++ b/lib/ast.js @@ -301,7 +301,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", { }, }, AST_Statement); -var AST_BlockScope = DEFNODE("BlockScope", "enclosed functions make_def parent_scope variables", { +var AST_BlockScope = DEFNODE("BlockScope", "_var_names enclosed functions make_def parent_scope variables", { $documentation: "Base class for all statements introducing a lexical scope", $propdoc: { enclosed: "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes", @@ -532,7 +532,7 @@ var AST_With = DEFNODE("With", "expression", { /* -----[ scope and functions ]----- */ -var AST_Scope = DEFNODE("Scope", "uses_eval uses_with", { +var AST_Scope = DEFNODE("Scope", "fn_defs may_call_this uses_eval uses_with", { $documentation: "Base class for all statements introducing a lexical scope", $propdoc: { uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`", @@ -591,7 +591,7 @@ var AST_Toplevel = DEFNODE("Toplevel", "globals", { } }, AST_Scope); -var AST_Lambda = DEFNODE("Lambda", "argnames length_read rest uses_arguments", { +var AST_Lambda = DEFNODE("Lambda", "argnames length_read rest safe_ids uses_arguments", { $documentation: "Base class for functions", $propdoc: { argnames: "[(AST_DefaultValue|AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals", @@ -1795,7 +1795,7 @@ var AST_SymbolVar = DEFNODE("SymbolVar", null, { $documentation: "Symbol defining a variable", }, AST_SymbolDeclaration); -var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, { +var AST_SymbolFunarg = DEFNODE("SymbolFunarg", "unused", { $documentation: "Symbol naming a function argument", }, AST_SymbolVar); diff --git a/lib/compress.js b/lib/compress.js index 27878f1f..5bb9bcb0 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -531,6 +531,11 @@ Compressor.prototype.compress = function(node) { }); } + function safe_to_visit(tw, fn) { + var marker = fn.safe_ids; + return marker === undefined || marker === tw.safe_ids; + } + function walk_fn_def(tw, fn) { var was_scanning = tw.fn_scanning; tw.fn_scanning = fn; @@ -545,14 +550,14 @@ Compressor.prototype.compress = function(node) { d.single_use = false; var fixed = d.fixed; if (typeof fixed == "function") fixed = fixed(); - if (fixed instanceof AST_Lambda && HOP(fixed, "safe_ids")) return; + if (fixed instanceof AST_Lambda && fixed.safe_ids !== undefined) return; d.fixed = false; }); } function mark_fn_def(tw, def, fn) { - if (!HOP(fn, "safe_ids")) return; var marker = fn.safe_ids; + if (marker === undefined) return; if (marker === false) return; if (fn.parent_scope.resolve().may_call_this === return_true) { if (member(fn, tw.fn_visited)) revisit_fn_def(tw, fn); @@ -587,10 +592,10 @@ Compressor.prototype.compress = function(node) { walk_fn_def(tw, fn); }); fn_defs.forEach(function(fn) { - delete fn.safe_ids; + fn.safe_ids = undefined; }); - delete scope.fn_defs; - delete scope.may_call_this; + scope.fn_defs = undefined; + scope.may_call_this = undefined; } function push(tw) { @@ -621,7 +626,7 @@ Compressor.prototype.compress = function(node) { if (def.global && def.name == "arguments") return false; tw.loop_ids[def.id] = null; def.fixed = make_node(AST_Undefined, def.orig[0]); - if (in_order) delete def.safe_ids; + if (in_order) def.safe_ids = undefined; return true; } return !safe.assign || safe.assign === tw.safe_ids; @@ -643,7 +648,7 @@ Compressor.prototype.compress = function(node) { var safe = tw.safe_ids[def.id]; if (def.safe_ids) { def.safe_ids[def.id] = false; - delete def.safe_ids; + def.safe_ids = undefined; return def.fixed === null || HOP(tw.safe_ids, def.id) && !safe.read; } if (!HOP(tw.safe_ids, def.id)) { @@ -1206,7 +1211,7 @@ Compressor.prototype.compress = function(node) { }); def(AST_Lambda, function(tw, descend, compressor) { var fn = this; - if (HOP(fn, "safe_ids") && fn.safe_ids !== tw.safe_ids) return true; + if (!safe_to_visit(tw, fn)) return true; if (!push_uniq(tw.fn_visited, fn)) return true; fn.inlined = false; push(tw); @@ -1221,7 +1226,7 @@ Compressor.prototype.compress = function(node) { var def = fn.name.definition(); var parent = tw.parent(); if (parent instanceof AST_ExportDeclaration || parent instanceof AST_ExportDefault) def.single_use = false; - if (HOP(fn, "safe_ids") && fn.safe_ids !== tw.safe_ids) return true; + if (!safe_to_visit(tw, fn)) return true; if (!push_uniq(tw.fn_visited, fn)) return true; fn.inlined = false; push(tw); @@ -1469,8 +1474,8 @@ Compressor.prototype.compress = function(node) { function reset_flags(node) { node._squeezed = false; node._optimized = false; - delete node.fixed; - if (node instanceof AST_Scope) delete node._var_names; + if (node instanceof AST_BlockScope) node._var_names = undefined; + if (node instanceof AST_SymbolRef) node.fixed = undefined; } AST_Toplevel.DEFMETHOD("reset_opt_flags", function(compressor) { @@ -6592,7 +6597,7 @@ Compressor.prototype.compress = function(node) { argnames.pop(); } else if (i > default_length) { log(sym.name, "Dropping unused default argument assignment {name}"); - sym.name.__unused = true; + sym.name.unused = true; argnames[i] = sym.name; } else { log(sym.name, "Dropping unused default argument value {name}"); @@ -6603,12 +6608,12 @@ Compressor.prototype.compress = function(node) { var def = sym.definition(); if (def.id in in_use_ids) { trim = false; - if (indexOf_assign(def, sym) < 0) sym.__unused = null; + if (indexOf_assign(def, sym) < 0) sym.unused = null; } else if (trim) { log(sym, "Dropping unused function argument {name}"); argnames.pop(); } else { - sym.__unused = true; + sym.unused = true; } } fns_with_marked_args.push(node); @@ -7162,7 +7167,7 @@ Compressor.prototype.compress = function(node) { var value = node.value.drop_side_effect_free(compressor); if (!value) return null; log(node.name, "Side effects in default value of unused variable {name}"); - node.name.__unused = null; + node.name.unused = null; node.value = value; } return node; @@ -7419,7 +7424,7 @@ Compressor.prototype.compress = function(node) { } return make_node(AST_DestructuredObject, node, { properties: [] }); } - node.__unused = null; + node.unused = null; return node; } } @@ -9247,7 +9252,7 @@ Compressor.prototype.compress = function(node) { if (argname instanceof AST_DestructuredObject) { return argname.properties.length == 0 && !argname.rest && arg && !arg.may_throw_on_access(compressor); } - return argname.__unused; + return argname.unused; } : return_false; var side_effects = []; for (var i = 0; i < args.length; i++) { @@ -9255,7 +9260,7 @@ Compressor.prototype.compress = function(node) { if (drop_defaults && argname instanceof AST_DefaultValue && args[i].is_defined(compressor)) { argnames[i] = argname = argname.name; } - if (!argname || "__unused" in argname) { + if (!argname || argname.unused !== undefined) { var node = args[i].drop_side_effect_free(compressor); if (drop_fargs(argname)) { if (argname) argnames.splice(i, 1); @@ -9969,7 +9974,7 @@ Compressor.prototype.compress = function(node) { var abort = false; fn.each_argname(function(arg) { if (abort) return; - if (arg.__unused) return; + if (arg.unused) return; if (!safe_to_inject || var_exists(defined, arg.name)) return abort = true; arg_used.set(arg.name, true); if (in_loop) in_loop.push(arg.definition()); @@ -10080,12 +10085,12 @@ Compressor.prototype.compress = function(node) { name = argname; } var value = self.args[i]; - if (name.__unused || scope.var_names().has(name.name)) { + if (name.unused || scope.var_names().has(name.name)) { if (value) expressions.push(value); } else { var symbol = make_node(AST_SymbolVar, name, name); name.definition().orig.push(symbol); - if ("__unused" in name) { + if (name.unused !== undefined) { append_var(decls, expressions, symbol); if (value) expressions.push(value); } else { @@ -10098,7 +10103,7 @@ Compressor.prototype.compress = function(node) { expressions.reverse(); for (i = default_args.length; --i >= 0;) { var node = default_args[i]; - if ("__unused" in node.name) { + if (node.name.unused !== undefined) { expressions.push(node.value); } else { var sym = make_node(AST_SymbolRef, node.name, node.name); @@ -10117,7 +10122,7 @@ Compressor.prototype.compress = function(node) { operator: "=", left: make_node(AST_DestructuredArray, self, { elements: fn.argnames.map(function(argname) { - if (argname.__unused) return make_node(AST_Hole, argname); + if (argname.unused) return make_node(AST_Hole, argname); return argname.convert_symbol(AST_SymbolRef, process); }), rest: fn.rest && fn.rest.convert_symbol(AST_SymbolRef, process), @@ -12307,7 +12312,7 @@ Compressor.prototype.compress = function(node) { if (assigned) def.reassigned--; var sym = make_node(AST_SymbolRef, self, argname); sym.reference(); - delete argname.__unused; + argname.unused = undefined; return sym; } } diff --git a/lib/scope.js b/lib/scope.js index be0dc08a..89c66714 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -45,6 +45,7 @@ function SymbolDef(id, scope, orig, init) { this._bits = 0; + this.defun = undefined; this.eliminated = 0; this.id = id; this.init = init; @@ -53,6 +54,7 @@ function SymbolDef(id, scope, orig, init) { this.orig = [ orig ]; this.references = []; this.replaced = 0; + this.safe_ids = undefined; this.scope = scope; } @@ -370,7 +372,7 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options) { if (node instanceof AST_SymbolLambda) { var def = node.thedef; if (!redefine(node, node.scope.parent_scope.resolve())) { - delete def.defun; + def.defun = undefined; } else if (typeof node.thedef.init !== "undefined") { node.thedef.init = false; } else if (def.init) { @@ -472,7 +474,7 @@ AST_Symbol.DEFMETHOD("mark_enclosed", function(options) { for (var s = this.scope; s; s = s.parent_scope) { push_uniq(s.enclosed, def); if (!options) { - delete s._var_names; + s._var_names = undefined; } else if (options.keep_fnames) { s.functions.each(function(d) { push_uniq(def.scope.enclosed, d);