aboutsummaryrefslogtreecommitdiff
path: root/lib/compress.js
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2021-01-05 07:02:49 +0000
committerGitHub <noreply@github.com>2021-01-05 15:02:49 +0800
commit6eceac096694cfa3390e7112c4764a235592751d (patch)
treee22a76acbb8b27726f271c57306b8a08d78e4ab4 /lib/compress.js
parentfc5aee662d99257f59830ebcd5053ead48c9039b (diff)
downloadtracifyjs-6eceac096694cfa3390e7112c4764a235592751d.tar.gz
tracifyjs-6eceac096694cfa3390e7112c4764a235592751d.zip
enhance `inline` & `side_effects` (#4506)
Diffstat (limited to 'lib/compress.js')
-rw-r--r--lib/compress.js164
1 files changed, 131 insertions, 33 deletions
diff --git a/lib/compress.js b/lib/compress.js
index 1934ca3d..459d54f0 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -1210,7 +1210,7 @@ merge(Compressor.prototype, {
});
AST_Node.DEFMETHOD("convert_symbol", noop);
- AST_Destructured.DEFMETHOD("convert_symbol", function(type, process) {
+ function convert_destructured(type, process) {
return this.transform(new TreeTransformer(function(node, descend) {
if (node instanceof AST_DefaultValue) {
node = node.clone();
@@ -1229,7 +1229,9 @@ merge(Compressor.prototype, {
}
return node.convert_symbol(type, process);
}));
- });
+ }
+ AST_DefaultValue.DEFMETHOD("convert_symbol", convert_destructured);
+ AST_Destructured.DEFMETHOD("convert_symbol", convert_destructured);
function convert_symbol(type, process) {
var node = make_node(type, this, this);
process(node, this);
@@ -5314,6 +5316,12 @@ merge(Compressor.prototype, {
}
});
+ function fill_holes(orig, elements) {
+ for (var i = elements.length; --i >= 0;) {
+ if (!elements[i]) elements[i] = make_node(AST_Hole, orig);
+ }
+ }
+
AST_Scope.DEFMETHOD("drop_unused", function(compressor) {
if (!compressor.option("unused")) return;
var self = this;
@@ -6143,9 +6151,7 @@ merge(Compressor.prototype, {
});
value = save;
if (values && elements.length == 0) return null;
- for (var i = elements.length; --i >= 0;) {
- if (!elements[i]) elements[i] = make_node(AST_Hole, node.elements[i] || node);
- }
+ fill_holes(node, elements);
node.elements = elements;
return node;
}
@@ -8052,24 +8058,32 @@ merge(Compressor.prototype, {
var is_func = fn instanceof AST_Lambda && (!is_async(fn)
|| compressor.option("awaits") && compressor.parent() instanceof AST_Await);
var stat = is_func && fn.first_statement();
- var has_default = false;
+ var has_default = 0, has_destructured = false;
+ var has_spread = !all(self.args, function(arg) {
+ return !(arg instanceof AST_Spread);
+ });
var can_drop = is_func && all(fn.argnames, function(argname, index) {
- if (has_default && self.args[index] instanceof AST_Spread) return false;
+ if (has_default == 1 && self.args[index] instanceof AST_Spread) has_default = 2;
if (argname instanceof AST_DefaultValue) {
- has_default = true;
- var arg = self.args[index];
- if (arg && !is_undefined(arg)) return false;
+ if (!has_default) has_default = 1;
+ var arg = has_default == 1 && self.args[index];
+ if (arg && !is_undefined(arg)) has_default = 2;
+ if (has_arg_refs(argname.value)) return false;
+ argname = argname.name;
+ }
+ if (argname instanceof AST_Destructured) {
+ has_destructured = true;
var abort = false;
- argname.value.walk(new TreeWalker(function(node) {
+ argname.walk(new TreeWalker(function(node) {
if (abort) return true;
- if (node instanceof AST_SymbolRef && fn.variables.get(node.name) === node.definition()) {
- return abort = true;
+ if (node instanceof AST_DestructuredKeyVal) {
+ var key = node.key;
+ if (key instanceof AST_Node && has_arg_refs(key)) return abort = true;
}
}));
if (abort) return false;
- argname = argname.name;
}
- return !(argname instanceof AST_Destructured);
+ return true;
});
var can_inline = can_drop && compressor.option("inline") && !self.is_expr_pure(compressor);
if (can_inline && stat instanceof AST_Return) {
@@ -8086,9 +8100,7 @@ merge(Compressor.prototype, {
&& !(fn.name && fn instanceof AST_Function)
&& (exp === fn || !recursive_ref(compressor, def = exp.definition())
&& fn.is_constant_expression(find_scope(compressor)))
- && all(self.args, function(arg) {
- return !(arg instanceof AST_Spread);
- })
+ && !has_spread
&& (value = can_flatten_body(stat))
&& !fn.contains_this()) {
var replacing = exp === fn || def.single_use && def.references.length - def.replaced == 1;
@@ -8161,13 +8173,79 @@ merge(Compressor.prototype, {
}
return try_evaluate(compressor, self);
- function convert_args(value) {
- var args = self.args.map(function(arg) {
- return arg instanceof AST_Spread ? make_node(AST_Array, arg, {
- elements: [ arg ],
- }) : arg;
+ function has_arg_refs(node) {
+ var found = false;
+ node.walk(new TreeWalker(function(node) {
+ if (found) return true;
+ if (node instanceof AST_SymbolRef && fn.variables.get(node.name) === node.definition()) {
+ return found = true;
+ }
+ }));
+ return found;
+ }
+
+ function make_void_lhs(orig) {
+ return make_node(AST_Sub, orig, {
+ expression: make_node(AST_Number, orig, { value: 0 }),
+ property: make_node(AST_Number, orig, { value: 0 }),
});
- fn.argnames.forEach(function(argname, index) {
+ }
+
+ function convert_args(value) {
+ var args = self.args.slice();
+ var destructured = has_default > 1 || has_destructured;
+ if (destructured || has_spread) args = [ make_node(AST_Array, self, { elements: args }) ];
+ if (destructured) {
+ var tt = new TreeTransformer(function(node, descend) {
+ if (node instanceof AST_DefaultValue) return make_node(AST_DefaultValue, node, {
+ name: node.name.transform(tt) || make_void_lhs(node),
+ value: node.value,
+ });
+ if (node instanceof AST_DestructuredArray) {
+ var elements = [];
+ node.elements.forEach(function(node, index) {
+ node = node.transform(tt);
+ if (node) elements[index] = node;
+ });
+ fill_holes(node, elements);
+ return make_node(AST_DestructuredArray, node, { elements: elements });
+ }
+ if (node instanceof AST_DestructuredObject) {
+ var properties = [], side_effects = [];
+ node.properties.forEach(function(prop) {
+ var key = prop.key;
+ var value = prop.value.transform(tt);
+ if (value) {
+ side_effects.push(key instanceof AST_Node ? key : make_node_from_constant(key, prop));
+ properties.push(make_node(AST_DestructuredKeyVal, prop, {
+ key: make_sequence(node, side_effects),
+ value: value,
+ }));
+ side_effects = [];
+ } else if (key instanceof AST_Node) {
+ side_effects.push(key);
+ }
+ });
+ if (side_effects.length) properties.push(make_node(AST_DestructuredKeyVal, node, {
+ key: make_sequence(node, side_effects),
+ value: make_void_lhs(node),
+ }));
+ return make_node(AST_DestructuredObject, node, { properties: properties });
+ }
+ if (node instanceof AST_SymbolFunarg) return null;
+ });
+ var lhs = [];
+ fn.argnames.forEach(function(argname, index) {
+ argname = argname.transform(tt);
+ if (argname) lhs[index] = argname;
+ });
+ fill_holes(fn, lhs);
+ args[0] = make_node(AST_Assign, self, {
+ operator: "=",
+ left: make_node(AST_DestructuredArray, fn, { elements: lhs }),
+ right: args[0],
+ });
+ } else fn.argnames.forEach(function(argname) {
if (argname instanceof AST_DefaultValue) args.push(argname.value);
});
args.push(value || make_node(AST_Undefined, self));
@@ -8241,8 +8319,7 @@ merge(Compressor.prototype, {
}
function can_substitute_directly() {
- if (has_default) return;
- if (var_assigned) return;
+ if (has_default || has_destructured || var_assigned) return;
if (compressor.option("inline") < 2 && fn.argnames.length) return;
if (!fn.variables.all(function(def) {
return def.references.length - def.replaced < 2 && def.orig[0] instanceof AST_SymbolFunarg;
@@ -8308,15 +8385,16 @@ merge(Compressor.prototype, {
}
function can_inject_args(defined, used, safe_to_inject) {
- for (var i = 0; i < fn.argnames.length; i++) {
- var arg = fn.argnames[i];
- if (arg.__unused) continue;
+ var abort = false;
+ fn.each_argname(function(arg) {
+ if (abort) return;
+ if (arg.__unused) return;
if (arg instanceof AST_DefaultValue) arg = arg.name;
- if (!safe_to_inject || var_exists(defined, arg.name)) return false;
+ if (!safe_to_inject || var_exists(defined, arg.name)) return abort = true;
used[arg.name] = true;
if (in_loop) in_loop.push(arg.definition());
- }
- return true;
+ });
+ return !abort;
}
function can_inject_vars(defined, used, safe_to_inject) {
@@ -8450,6 +8528,22 @@ merge(Compressor.prototype, {
}
}
+ function flatten_destructured(decls, expressions) {
+ expressions.push(make_node(AST_Assign, self, {
+ operator: "=",
+ left: make_node(AST_DestructuredArray, self, {
+ elements: fn.argnames.map(function(argname) {
+ return argname.convert_symbol(AST_SymbolRef, function(ref, name) {
+ var symbol = make_node(AST_SymbolVar, name, name);
+ name.definition().orig.push(symbol);
+ append_var(decls, expressions, symbol);
+ });
+ }),
+ }),
+ right: make_node(AST_Array, self, { elements: self.args.slice() }),
+ }));
+ }
+
function flatten_vars(decls, expressions) {
var pos = expressions.length;
for (var i = 0; i < fn.body.length; i++) {
@@ -8484,7 +8578,11 @@ merge(Compressor.prototype, {
function flatten_fn() {
var decls = [];
var expressions = [];
- flatten_args(decls, expressions);
+ if (has_default > 1 || has_destructured) {
+ flatten_destructured(decls, expressions);
+ } else {
+ flatten_args(decls, expressions);
+ }
flatten_vars(decls, expressions);
expressions.push(value);
var args = fn.body.filter(function(stat) {