diff options
author | Alex Lam S.L <alexlamsl@gmail.com> | 2021-01-05 07:02:49 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-05 15:02:49 +0800 |
commit | 6eceac096694cfa3390e7112c4764a235592751d (patch) | |
tree | e22a76acbb8b27726f271c57306b8a08d78e4ab4 /lib/compress.js | |
parent | fc5aee662d99257f59830ebcd5053ead48c9039b (diff) | |
download | tracifyjs-6eceac096694cfa3390e7112c4764a235592751d.tar.gz tracifyjs-6eceac096694cfa3390e7112c4764a235592751d.zip |
enhance `inline` & `side_effects` (#4506)
Diffstat (limited to 'lib/compress.js')
-rw-r--r-- | lib/compress.js | 164 |
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) { |