Skip to content

Commit e5cbd3e

Browse files
authoredNov 22, 2022
enhance join_vars (#5739)
1 parent 68d62a8 commit e5cbd3e

File tree

4 files changed

+195
-26
lines changed

4 files changed

+195
-26
lines changed
 

‎lib/compress.js

+65-26
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ Compressor.prototype.compress = function(node) {
487487
return all(def.orig, function(sym) {
488488
if (sym instanceof AST_SymbolConst || sym instanceof AST_SymbolLet) {
489489
if (sym instanceof AST_SymbolImport) return true;
490-
return compressor && can_varify(compressor, sym);
490+
return compressor && safe_from_tdz(compressor, sym);
491491
}
492492
return !(keep_lambda && sym instanceof AST_SymbolLambda);
493493
});
@@ -525,10 +525,11 @@ Compressor.prototype.compress = function(node) {
525525
function reset_def(tw, compressor, def) {
526526
def.assignments = 0;
527527
def.bool_return = 0;
528-
def.drop_return = 0;
529528
def.cross_loop = false;
530529
def.direct_access = false;
530+
def.drop_return = 0;
531531
def.escaped = [];
532+
def.first_decl = null;
532533
def.fixed = !def.const_redefs
533534
&& !def.scope.pinned()
534535
&& !compressor.exposed(def)
@@ -951,6 +952,7 @@ Compressor.prototype.compress = function(node) {
951952

952953
function visit(node, fixed) {
953954
var d = node.definition();
955+
if (!d.first_decl && d.references.length == 0) d.first_decl = node;
954956
if (fixed && safe && d.fixed === undefined) {
955957
mark(tw, d);
956958
tw.loop_ids[d.id] = tw.in_loop;
@@ -1371,10 +1373,18 @@ Compressor.prototype.compress = function(node) {
13711373
return true;
13721374
});
13731375
def(AST_SymbolCatch, function() {
1374-
this.definition().fixed = false;
1376+
var d = this.definition();
1377+
if (!d.first_decl && d.references.length == 0) d.first_decl = this;
1378+
d.fixed = false;
1379+
});
1380+
def(AST_SymbolDeclaration, function() {
1381+
var d = this.definition();
1382+
if (!d.first_decl && d.references.length == 0) d.first_decl = this;
13751383
});
13761384
def(AST_SymbolImport, function() {
1377-
this.definition().fixed = false;
1385+
var d = this.definition();
1386+
d.first_decl = this;
1387+
d.fixed = false;
13781388
});
13791389
def(AST_SymbolRef, function(tw, descend, compressor) {
13801390
var ref = this;
@@ -1558,6 +1568,8 @@ Compressor.prototype.compress = function(node) {
15581568
walk_defn();
15591569
} else if (tw.parent() instanceof AST_Let) {
15601570
walk_defn();
1571+
} else {
1572+
node.name.walk(tw);
15611573
}
15621574
return true;
15631575

@@ -1566,6 +1578,7 @@ Compressor.prototype.compress = function(node) {
15661578
return node.value || make_node(AST_Undefined, node);
15671579
}, function(name, fixed) {
15681580
var d = name.definition();
1581+
if (!d.first_decl && d.references.length == 0) d.first_decl = name;
15691582
if (fixed && safe_to_assign(tw, d, true)) {
15701583
mark(tw, d);
15711584
tw.loop_ids[d.id] = tw.in_loop;
@@ -4249,14 +4262,22 @@ Compressor.prototype.compress = function(node) {
42494262
}
42504263

42514264
function join_consecutive_vars(statements) {
4252-
var changed = false, defs;
4265+
var changed = false, defs, prev_defs;
42534266
for (var i = 0, j = -1; i < statements.length; i++) {
42544267
var stat = statements[i];
42554268
var prev = statements[j];
42564269
if (stat instanceof AST_Definitions) {
42574270
if (prev && prev.TYPE == stat.TYPE) {
42584271
prev.definitions = prev.definitions.concat(stat.definitions);
42594272
changed = true;
4273+
} else if (stat && prev instanceof AST_Let && stat.can_letify(compressor)) {
4274+
prev.definitions = prev.definitions.concat(to_let(stat).definitions);
4275+
changed = true;
4276+
} else if (prev && stat instanceof AST_Let && prev.can_letify(compressor)) {
4277+
defs = prev_defs;
4278+
statements[j] = prev = to_let(prev);
4279+
prev.definitions = prev.definitions.concat(stat.definitions);
4280+
changed = true;
42604281
} else if (defs && defs.TYPE == stat.TYPE && declarations_only(stat)) {
42614282
defs.definitions = defs.definitions.concat(stat.definitions);
42624283
changed = true;
@@ -4271,6 +4292,7 @@ Compressor.prototype.compress = function(node) {
42714292
} else {
42724293
j++;
42734294
}
4295+
prev_defs = defs;
42744296
statements[j] = defs = stat;
42754297
} else {
42764298
statements[++j] = stat;
@@ -4288,6 +4310,7 @@ Compressor.prototype.compress = function(node) {
42884310
prev.definitions = prev.definitions.concat(stat.init.definitions);
42894311
}
42904312
stat = stat.clone();
4313+
prev_defs = defs;
42914314
defs = stat.init = prev;
42924315
statements[j] = merge_defns(stat);
42934316
changed = true;
@@ -4297,6 +4320,7 @@ Compressor.prototype.compress = function(node) {
42974320
stat.init = null;
42984321
changed = true;
42994322
} else if (stat.init instanceof AST_Var) {
4323+
prev_defs = defs;
43004324
defs = stat.init;
43014325
exprs = merge_assigns(prev, stat.init);
43024326
if (exprs) {
@@ -9365,7 +9389,7 @@ Compressor.prototype.compress = function(node) {
93659389
}
93669390
}, true)) {
93679391
self.init = to_var(self.init, self.resolve());
9368-
} else if (can_letify(self.init, compressor, 1)) {
9392+
} else if (self.init.can_letify(compressor, true)) {
93699393
self.init = to_let(self.init);
93709394
}
93719395
}
@@ -10213,45 +10237,60 @@ Compressor.prototype.compress = function(node) {
1021310237
});
1021410238
}
1021510239

10216-
function can_letify(stat, compressor, assigned) {
10217-
if (!(stat instanceof AST_Const)) return false;
10218-
if (!compressor.option("module") && all(stat.definitions, function(defn) {
10219-
return defn.name instanceof AST_SymbolConst;
10220-
})) return false;
10221-
return all(stat.definitions, function(defn) {
10222-
return !defn.name.match_symbol(function(node) {
10223-
if (node instanceof AST_SymbolDeclaration) return node.definition().assignments != assigned;
10224-
}, true);
10240+
(function(def) {
10241+
def(AST_Node, return_false);
10242+
def(AST_Const, function(compressor, assigned) {
10243+
assigned = assigned ? 1 : 0;
10244+
var defns = this.definitions;
10245+
if (!compressor.option("module") && all(defns, function(defn) {
10246+
return defn.name instanceof AST_SymbolConst;
10247+
})) return false;
10248+
return all(defns, function(defn) {
10249+
return !defn.name.match_symbol(function(node) {
10250+
if (node instanceof AST_SymbolDeclaration) return node.definition().assignments != assigned;
10251+
}, true);
10252+
});
1022510253
});
10226-
}
10254+
def(AST_Var, function(compressor) {
10255+
return all(this.definitions, function(defn) {
10256+
return !defn.name.match_symbol(function(node) {
10257+
if (!(node instanceof AST_SymbolDeclaration)) return false;
10258+
if (node.definition().first_decl !== node) return true;
10259+
return !safe_from_tdz(compressor, node);
10260+
}, true);
10261+
});
10262+
});
10263+
})(function(node, func) {
10264+
node.DEFMETHOD("can_letify", func);
10265+
});
1022710266

10228-
function can_varify(compressor, sym) {
10267+
function safe_from_tdz(compressor, sym) {
1022910268
var def = sym.definition();
1023010269
return (def.fixed || def.fixed === 0)
1023110270
&& is_safe_lexical(def)
1023210271
&& same_scope(def)
1023310272
&& !may_overlap(compressor, def);
1023410273
}
1023510274

10236-
function varify(self, compressor) {
10237-
if (all(self.definitions, function(defn) {
10275+
AST_Definitions.DEFMETHOD("can_varify", function(compressor) {
10276+
return all(this.definitions, function(defn) {
1023810277
return !defn.name.match_symbol(function(node) {
10239-
if (node instanceof AST_SymbolDeclaration) return !can_varify(compressor, node);
10278+
if (node instanceof AST_SymbolDeclaration) return !safe_from_tdz(compressor, node);
1024010279
}, true);
10241-
})) return to_var(self, compressor.find_parent(AST_Scope));
10242-
}
10280+
});
10281+
});
1024310282

1024410283
OPT(AST_Const, function(self, compressor) {
1024510284
if (!compressor.option("varify")) return self;
10246-
var decl = varify(self, compressor);
10247-
if (decl) return decl;
10248-
if (can_letify(self, compressor, 0)) return to_let(self);
10285+
if (self.can_varify(compressor)) return to_var(self, compressor.find_parent(AST_Scope));
10286+
if (self.can_letify(compressor)) return to_let(self);
1024910287
return self;
1025010288
});
1025110289

1025210290
OPT(AST_Let, function(self, compressor) {
1025310291
if (!compressor.option("varify")) return self;
10254-
return varify(self, compressor) || self;
10292+
if (self.can_varify(compressor)) return to_var(self, compressor.find_parent(AST_Scope));
10293+
return self;
1025510294
});
1025610295

1025710296
function trim_optional_chain(node, compressor) {

‎test/benchmark.js

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
"use strict";
55

6+
require("../tools/tty");
67
var createHash = require("crypto").createHash;
78
var fetch = require("./fetch");
89
var spawn = require("child_process").spawn;

‎test/compress/let.js

+124
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,130 @@ default_init: {
11301130
node_version: ">=4"
11311131
}
11321132

1133+
join_let_var_1: {
1134+
options = {
1135+
join_vars: true,
1136+
reduce_vars: true,
1137+
toplevel: true,
1138+
}
1139+
input: {
1140+
"use strict";
1141+
var a = "foo";
1142+
let b = "bar";
1143+
for (var c of [ a, b ])
1144+
console.log(c);
1145+
}
1146+
expect: {
1147+
"use strict";
1148+
let a = "foo", b = "bar";
1149+
for (var c of [ a, b ])
1150+
console.log(c);
1151+
}
1152+
expect_stdout: [
1153+
"foo",
1154+
"bar",
1155+
]
1156+
node_version: ">=4"
1157+
}
1158+
1159+
join_let_var_2: {
1160+
options = {
1161+
join_vars: true,
1162+
reduce_vars: true,
1163+
toplevel: true,
1164+
}
1165+
input: {
1166+
"use strict";
1167+
let a = "foo";
1168+
var b = "bar";
1169+
for (let c of [ a, b ])
1170+
console.log(c);
1171+
}
1172+
expect: {
1173+
"use strict";
1174+
let a = "foo", b = "bar";
1175+
for (let c of [ a, b ])
1176+
console.log(c);
1177+
}
1178+
expect_stdout: [
1179+
"foo",
1180+
"bar",
1181+
]
1182+
node_version: ">=4"
1183+
}
1184+
1185+
keep_let_var_1: {
1186+
options = {
1187+
join_vars: true,
1188+
reduce_vars: true,
1189+
toplevel: true,
1190+
}
1191+
input: {
1192+
"use strict";
1193+
var a = "foo";
1194+
let b = "bar";
1195+
for (var c of [ a, b ])
1196+
console.log(c);
1197+
function f() {
1198+
return a;
1199+
}
1200+
console.log(f(f));
1201+
}
1202+
expect: {
1203+
"use strict";
1204+
var a = "foo", c;
1205+
let b = "bar";
1206+
for (c of [ a, b ])
1207+
console.log(c);
1208+
function f() {
1209+
return a;
1210+
}
1211+
console.log(f(f));
1212+
}
1213+
expect_stdout: [
1214+
"foo",
1215+
"bar",
1216+
"foo",
1217+
]
1218+
node_version: ">=4"
1219+
}
1220+
1221+
keep_let_var_2: {
1222+
options = {
1223+
join_vars: true,
1224+
reduce_vars: true,
1225+
toplevel: true,
1226+
}
1227+
input: {
1228+
"use strict";
1229+
let a = "foo";
1230+
var b = "bar";
1231+
for (let c of [ a, b ])
1232+
console.log(c);
1233+
function f() {
1234+
return b;
1235+
}
1236+
console.log(f(f));
1237+
}
1238+
expect: {
1239+
"use strict";
1240+
let a = "foo";
1241+
var b = "bar";
1242+
for (let c of [ a, b ])
1243+
console.log(c);
1244+
function f() {
1245+
return b;
1246+
}
1247+
console.log(f(f));
1248+
}
1249+
expect_stdout: [
1250+
"foo",
1251+
"bar",
1252+
"bar",
1253+
]
1254+
node_version: ">=4"
1255+
}
1256+
11331257
issue_4191: {
11341258
options = {
11351259
functions: true,

‎test/release/buble.sh

+5
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ rm -rf tmp/buble \
4141
@@ -309 +309 @@ export default class BlockStatement extends Node {
4242
- let cont = false; // TODO implement proper continue...
4343
+ let cont = !declarations; // TODO implement proper continue...
44+
--- a/src/program/types/VariableDeclaration.js
45+
+++ b/src/program/types/VariableDeclaration.js
46+
@@ -38 +38 @@ export default class VariableDeclaration extends Node {
47+
- code.remove(c, declarator.id.start);
48+
+ code.remove(c, declarator.id.start, lastDeclaratorIsPattern);
4449
EOF
4550
ERR=$?; if [ "$ERR" != "0" ]; then echo "Error: $ERR"; exit $ERR; fi
4651
minify_in_situ "src" \

0 commit comments

Comments
 (0)
Please sign in to comment.