workaround v8 performance quirks (#5207)
authorAlex Lam S.L <alexlamsl@gmail.com>
Wed, 8 Dec 2021 05:40:47 +0000 (05:40 +0000)
committerGitHub <noreply@github.com>
Wed, 8 Dec 2021 05:40:47 +0000 (13:40 +0800)
bin/uglifyjs
lib/ast.js
lib/compress.js
lib/scope.js

index 726cd88..8e67997 100755 (executable)
@@ -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 = {};
index b21ea0c..b8732a7 100644 (file)
@@ -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);
 
index 27878f1..5bb9bcb 100644 (file)
@@ -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;
             }
         }
index be0dc08..89c6671 100644 (file)
@@ -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);