reduce memory pressure via bit fields (#5203)

This commit is contained in:
Alex Lam S.L
2021-12-06 03:30:05 +00:00
committed by GitHub
parent b0799105c2
commit 033d8d9405
8 changed files with 97 additions and 21 deletions

View File

@@ -10,7 +10,9 @@ var info = require("../package.json");
var path = require("path"); var path = require("path");
var UglifyJS = require("../tools/node"); var UglifyJS = require("../tools/node");
var skip_keys = [ "cname", "fixed", "inlined", "parent_scope", "scope", "uses_eval", "uses_with" ]; var skip_keys = [ "cname", "fixed", "inlined", "length_read", "parent_scope", "scope" ];
var truthy_keys = [ "optional", "pure", "terminal", "uses_arguments", "uses_eval", "uses_with" ];
var files = {}; var files = {};
var options = {}; var options = {};
var short_forms = { var short_forms = {
@@ -430,7 +432,7 @@ function run() {
case "thedef": case "thedef":
return symdef(value); return symdef(value);
} }
if (skip_key(key)) return; if (skip_property(key, value)) return;
if (value instanceof UglifyJS.AST_Token) return; if (value instanceof UglifyJS.AST_Token) return;
if (value instanceof UglifyJS.Dictionary) return; if (value instanceof UglifyJS.Dictionary) return;
if (value instanceof UglifyJS.AST_Node) { if (value instanceof UglifyJS.AST_Node) {
@@ -559,8 +561,10 @@ function parse_js(value, options, flag) {
return options; return options;
} }
function skip_key(key) { function skip_property(key, value) {
return skip_keys.indexOf(key) >= 0; return skip_keys.indexOf(key) >= 0
// only skip truthy_keys if their value is falsy
|| truthy_keys.indexOf(key) >= 0 && !value;
} }
function symdef(def) { function symdef(def) {

View File

@@ -50,6 +50,8 @@ function DEFNODE(type, props, methods, base) {
if (base && base.PROPS) props = props.concat(base.PROPS); if (base && base.PROPS) props = props.concat(base.PROPS);
var code = [ var code = [
"return function AST_", type, "(props){", "return function AST_", type, "(props){",
// not essential, but speeds up compress by a few percent
"this._bits=0;",
"if(props){", "if(props){",
]; ];
props.forEach(function(prop) { props.forEach(function(prop) {
@@ -135,6 +137,52 @@ var AST_Node = DEFNODE("Node", "start end", {
}, },
}, null); }, null);
DEF_BITPROPS(AST_Node, [
"_optimized",
"_squeezed",
// AST_Call
"call_only",
"collapse_scanning",
// AST_SymbolRef
"defined",
"evaluating",
"falsy",
// AST_SymbolRef
"in_arg",
// AST_Return
"in_bool",
// AST_SymbolRef
"is_undefined",
// AST_LambdaExpression
// AST_LambdaDefinition
"inlined",
// AST_Lambda
"length_read",
// AST_Yield
"nested",
// AST_Lambda
"new",
// AST_Call
// AST_PropAccess
"optional",
// AST_ClassProperty
"private",
// AST_Call
"pure",
// AST_Assign
"redundant",
// AST_ClassProperty
"static",
// AST_Call
// AST_PropAccess
"terminal",
"truthy",
// AST_Scope
"uses_eval",
// AST_Scope
"uses_with",
]);
(AST_Node.log_function = function(fn, verbose) { (AST_Node.log_function = function(fn, verbose) {
if (typeof fn != "function") { if (typeof fn != "function") {
AST_Node.info = AST_Node.warn = noop; AST_Node.info = AST_Node.warn = noop;
@@ -549,7 +597,7 @@ var AST_Lambda = DEFNODE("Lambda", "argnames length_read rest uses_arguments", {
argnames: "[(AST_DefaultValue|AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals", argnames: "[(AST_DefaultValue|AST_Destructured|AST_SymbolFunarg)*] array of function arguments and/or destructured literals",
length_read: "[boolean/S] whether length property of this function is accessed", length_read: "[boolean/S] whether length property of this function is accessed",
rest: "[(AST_Destructured|AST_SymbolFunarg)?] rest parameter, or null if absent", rest: "[(AST_Destructured|AST_SymbolFunarg)?] rest parameter, or null if absent",
uses_arguments: "[boolean/S] whether this function accesses the arguments array", uses_arguments: "[boolean|number/S] whether this function accesses the arguments array",
}, },
each_argname: function(visit) { each_argname: function(visit) {
var tw = new TreeWalker(function(node) { var tw = new TreeWalker(function(node) {
@@ -1295,7 +1343,7 @@ var AST_Call = DEFNODE("Call", "args expression optional pure terminal", {
args: "[AST_Node*] array of arguments", args: "[AST_Node*] array of arguments",
expression: "[AST_Node] expression to invoke as function", expression: "[AST_Node] expression to invoke as function",
optional: "[boolean] whether the expression is optional chaining", optional: "[boolean] whether the expression is optional chaining",
pure: "[string/S] marker for side-effect-free call expression", pure: "[boolean/S] marker for side-effect-free call expression",
terminal: "[boolean] whether the chain has ended", terminal: "[boolean] whether the chain has ended",
}, },
walk: function(visitor) { walk: function(visitor) {

View File

@@ -898,7 +898,7 @@ Compressor.prototype.compress = function(node) {
if (left.equivalent_to(right) && !left.has_side_effects(compressor)) { if (left.equivalent_to(right) && !left.has_side_effects(compressor)) {
right.walk(tw); right.walk(tw);
walk_prop(left); walk_prop(left);
node.__drop = true; node.redundant = true;
return true; return true;
} }
if (ld && right instanceof AST_LambdaExpression) { if (ld && right instanceof AST_LambdaExpression) {
@@ -2274,7 +2274,7 @@ Compressor.prototype.compress = function(node) {
stop_if_hit = if_hit; stop_if_hit = if_hit;
stop_after = after; stop_after = after;
can_replace = replace; can_replace = replace;
delete fn.collapse_scanning; fn.collapse_scanning = false;
if (!abort) return false; if (!abort) return false;
abort = false; abort = false;
return true; return true;
@@ -4919,7 +4919,7 @@ Compressor.prototype.compress = function(node) {
} }
if (node instanceof AST_Scope && node !== fn) return true; if (node instanceof AST_Scope && node !== fn) return true;
})); }));
delete fn.evaluating; fn.evaluating = false;
if (!found) return; if (!found) return;
} }
return this; return this;
@@ -4935,7 +4935,7 @@ Compressor.prototype.compress = function(node) {
}); });
fn.evaluating = true; fn.evaluating = true;
val = val._eval(compressor, ignore_side_effects, cached, depth); val = val._eval(compressor, ignore_side_effects, cached, depth);
delete fn.evaluating; fn.evaluating = false;
} }
cached_args.forEach(function(node) { cached_args.forEach(function(node) {
delete node._eval; delete node._eval;
@@ -8055,7 +8055,7 @@ Compressor.prototype.compress = function(node) {
}) && all(fn.argnames, function(argname) { }) && all(fn.argnames, function(argname) {
return !argname.match_symbol(return_false); return !argname.match_symbol(return_false);
}) && !(fn.rest && fn.rest.match_symbol(return_false)); }) && !(fn.rest && fn.rest.match_symbol(return_false));
delete fn.new; fn.new = false;
return result; return result;
} }
function drop_class(self, compressor, first_in_statement) { function drop_class(self, compressor, first_in_statement) {
@@ -11640,7 +11640,7 @@ Compressor.prototype.compress = function(node) {
if (compressor.option("dead_code")) { if (compressor.option("dead_code")) {
if (self.left instanceof AST_PropAccess) { if (self.left instanceof AST_PropAccess) {
if (self.operator == "=") { if (self.operator == "=") {
if (self.__drop) { if (self.redundant) {
var exprs = [ self.left.expression ]; var exprs = [ self.left.expression ];
if (self.left instanceof AST_Sub) exprs.push(self.left.property); if (self.left instanceof AST_Sub) exprs.push(self.left.property);
exprs.push(self.right); exprs.push(self.right);

View File

@@ -1465,7 +1465,7 @@ function OutputStream(options) {
parent = output.parent(level++); parent = output.parent(level++);
if (parent instanceof AST_Call && parent.expression === node) return; if (parent instanceof AST_Call && parent.expression === node) return;
} while (parent instanceof AST_PropAccess && parent.expression === node); } while (parent instanceof AST_PropAccess && parent.expression === node);
output.print(typeof self.pure == "string" ? "/*" + self.pure + "*/" : "/*@__PURE__*/"); output.print("/*@__PURE__*/");
} }
function print_call_args(self, output) { function print_call_args(self, output) {
if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) { if (self.expression instanceof AST_Call || self.expression instanceof AST_Lambda) {

View File

@@ -2316,9 +2316,8 @@ function parse($TEXT, options) {
var comments = start.comments_before; var comments = start.comments_before;
var i = HOP(start, "comments_before_length") ? start.comments_before_length : comments.length; var i = HOP(start, "comments_before_length") ? start.comments_before_length : comments.length;
while (--i >= 0) { while (--i >= 0) {
var match = /[@#]__PURE__/.exec(comments[i].value); if (/[@#]__PURE__/.test(comments[i].value)) {
if (match) { expr.pure = true;
expr.pure = match[0];
break; break;
} }
} }

View File

@@ -44,9 +44,8 @@
"use strict"; "use strict";
function SymbolDef(id, scope, orig, init) { function SymbolDef(id, scope, orig, init) {
this._bits = 0;
this.eliminated = 0; this.eliminated = 0;
this.exported = false;
this.global = false;
this.id = id; this.id = id;
this.init = init; this.init = init;
this.mangled_name = null; this.mangled_name = null;
@@ -55,7 +54,6 @@ function SymbolDef(id, scope, orig, init) {
this.references = []; this.references = [];
this.replaced = 0; this.replaced = 0;
this.scope = scope; this.scope = scope;
this.undeclared = false;
} }
SymbolDef.prototype = { SymbolDef.prototype = {
@@ -104,6 +102,15 @@ SymbolDef.prototype = {
}, },
}; };
DEF_BITPROPS(SymbolDef, [
"const_redefs",
"cross_loop",
"direct_access",
"exported",
"global",
"undeclared",
]);
var unary_side_effects = makePredicate("delete ++ --"); var unary_side_effects = makePredicate("delete ++ --");
function is_lhs(node, parent) { function is_lhs(node, parent) {

View File

@@ -273,3 +273,21 @@ function first_in_statement(stack, arrow, export_default) {
return false; return false;
} }
} }
function DEF_BITPROPS(ctor, props) {
if (props.length > 31) throw new Error("Too many properties: " + props.length + "\n" + props.join(", "));
props.forEach(function(name, pos) {
var mask = 1 << pos;
Object.defineProperty(ctor.prototype, name, {
get: function() {
return !!(this._bits & mask);
},
set: function(val) {
if (val)
this._bits |= mask;
else
this._bits &= ~mask;
},
});
});
}

View File

@@ -442,9 +442,9 @@ compress_annotations_disabled_output_annotations_enabled: {
} }
expect_exact: [ expect_exact: [
"/*@__PURE__*/a(3),", "/*@__PURE__*/a(3),",
"/*#__PURE__*/b(5),", "/*@__PURE__*/b(5),",
"c(side_effect),", "c(side_effect),",
"/*#__PURE__*/d(effect());", "/*@__PURE__*/d(effect());",
] ]
} }