Skip to content

Commit

Permalink
feat(es/minifier): Implement correct hoist_props (#8593)
Browse files Browse the repository at this point in the history
**Description:**

 - The option `hoist_props` now does what it's supposed to do.
- Dropping of unused properties now does not drop properties too aggressively.
- The initializer of a dropped variable declaration is now properly visited.
- Indexing with string literals is not marked as a dynamic index anymore. This is required to handle codes like https://github.com/swc-project/swc/blob/c3f67ceb1eb0cab9ef4a47c321acf90684bf216a/crates/swc_ecma_minifier/tests/terser/compress/hoist_props/name_collision_1/input.js#L1-L7.
  • Loading branch information
kdy1 authored Feb 7, 2024
1 parent be55633 commit 3122e94
Show file tree
Hide file tree
Showing 59 changed files with 1,162 additions and 1,250 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,5 @@
import { _ as _class_call_check } from "@swc/helpers/_/_class_call_check";
var c, i, a, f = function(x) {}, f2 = function(x, y) {};
f(1), f(), f2(1), f2(1, 2), c.foo(), c.foo(1), i(), i(1), i.foo(1), i.foo(1, 2), a(), a(1), a.foo(), a.foo(1);
var b = {
foo: function(x) {},
a: function(x, y) {},
b: function(x) {}
};
b.foo(), b.foo(1), b.a(1), b.a(1, 2), b.b(), b.b(1);
var b_foo = function(x) {}, b_a = function(x, y) {}, b_b = function(x) {};
b_foo(), b_foo(1), b_a(1), b_a(1, 2), b_b(), b_b(1);
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//// [/a.js]
var p = {
a: 0,
b: "hello"
b: "hello",
x: 8
};
p.a.toFixed(), p.b.substring(1), p.d;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//// [/a.js]
var p = {
a: 0,
b: "hello"
b: "hello",
x: 8
};
p.a.toFixed(), p.b.substring(1), p.d;
Original file line number Diff line number Diff line change
@@ -1,17 +1,2 @@
//// [checkJsdocTypeTagOnObjectProperty2.ts]
//// [0.js]
var lol, obj = {
bar: 42,
method1: function(n1) {
return "42";
},
method2: function(n1) {
return "lol";
},
arrowFunc: function() {
var num = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : "0";
return num + 42;
},
lol: lol
};
lol = "string", obj.method1(0), obj.method2("0");
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
//// [destructuringObjectBindingPatternAndAssignment8.ts]
const K = {
a: "a",
b: "b"
}, { [K.a]: aVal, [K.b]: bVal } = {
[K.a]: 1,
[K.b]: 1
const { a: aVal, b: bVal } = {
a: 1,
b: 1
};
console.log(aVal, bVal);
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
//// [destructuringObjectBindingPatternAndAssignment8.ts]
import { _ as _define_property } from "@swc/helpers/_/_define_property";
var _obj, K = {
a: "a",
b: "b"
}, _ref = (_define_property(_obj = {}, K.a, 1), _define_property(_obj, K.b, 1), _obj);
console.log(_ref[K.a], _ref[K.b]);
var _obj, _ref = (_define_property(_obj = {}, "a", 1), _define_property(_obj, "b", 1), _obj);
console.log(_ref.a, _ref.b);
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
//// [destructuringVariableDeclaration1ES5.ts]
import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array";
import { _ as _to_consumable_array } from "@swc/helpers/_/_to_consumable_array";
var _ref = {
a1: 10,
a2: "world"
};
_ref.a1, _ref.a2;
var tmp = {
b11: "world"
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
//// [destructuringVariableDeclaration1ES5iterable.ts]
import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array";
import { _ as _to_consumable_array } from "@swc/helpers/_/_to_consumable_array";
var _ref = {
a1: 10,
a2: "world"
};
_ref.a1, _ref.a2;
var tmp = {
b11: "world"
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
//// [destructuringVariableDeclaration2.ts]
var _ref = {
a1: !0,
a2: 1
};
_ref.a1, _ref.a2;
var _ref1 = [
1,
2,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
//// [logicalNotOperatorWithAnyOtherType.ts]
import { _ as _class_call_check } from "@swc/helpers/_/_class_call_check";
var M, obj1 = {
x: "",
y: function() {}
}, A = function() {
var M, A = function() {
function A() {
_class_call_check(this, A);
}
return A.foo = function() {}, A;
}();
M || (M = {});
var objA = new A();
obj1.x, obj1.y, objA.a, M.n, A.foo(), objA.a, M.n;
objA.a, M.n, A.foo(), objA.a, M.n;
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,11 @@ var b2 = _object_spread_props(_object_spread({}, b1), {
z: 55
});
_object_spread({}, b2), opts;
var d1 = {
kind: "a",
pos: {
x: 0,
y: 0
}
var d1_pos = {
x: 0,
y: 0
};
d1.kind, d1.pos, d1.pos.x, d1.pos.y, d1.pos.a, d1.pos.b, f({
d1_pos.x, d1_pos.y, d1_pos.a, d1_pos.b, f({
a: 1,
b: 2
}, {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
//// [parserNotHexLiteral1.ts]
var x = {
e0: "cat",
x0: "dog"
};
console.info(x.x0), console.info(x.e0);
console.info("dog"), console.info("cat");
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { _ as _inherits } from "@swc/helpers/_/_inherits";
import { _ as _create_super } from "@swc/helpers/_/_create_super";
export var inModule = 1;
inmodule.toFixed();
var object = {};
var object = {
spaaace: 3
};
object.spaaaace, object.spaace = 12, object.fresh = 12, other.puuuce, new Date().getGMTDate(), setIntegral(function() {
return console.log("ok");
}, 500), AudioBuffin, Jimmy, Jon;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
//// [stringLiteralTypesAsTags01.ts]
var x = {
kind: "A"
};
x.kind, x.kind;
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
//// [stringLiteralTypesAsTags02.ts]
var x = {
kind: "A"
};
x.kind, x.kind;
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
//// [stringLiteralTypesAsTags03.ts]
var x = {
kind: "A"
};
x.kind, x.kind;
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ var b, crate, RoyalGuard = function() {
}
return FollowerGuard.prototype.follow = function() {}, FollowerGuard;
}(RoyalGuard), a = new FollowerGuard();
a.isLeader() ? a.lead() : a.isFollower() && a.follow(), b.isLeader() ? b.lead() : b.isFollower() && b.follow();
var holder2 = {
a: a
};
holder2.a.isLeader(), holder2.a;
a.isLeader() ? a.lead() : a.isFollower() && a.follow(), b.isLeader() ? b.lead() : b.isFollower() && b.follow(), a.isLeader();
var ArrowGuard = function ArrowGuard() {
var _this = this;
_class_call_check(this, ArrowGuard), this.isElite = function() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1 @@
//// [typeTagOnPropertyAssignment.js]
var o = {
a: "a",
n: function() {
return "b";
}
};
o.a, o.n;
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//// [typedefTagExtraneousProperty.js]
var y = {};
var y = {
bye: "no"
};
y.ignoreMe = "ok but just because of the index signature", y.hi = "yes";
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
//// [a.js]
var sala = {
name: "uppsala",
not: 0,
nested: "ok"
};
sala.name, sala.not, sala.nested;
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,3 @@ var C = function() {
return C.prototype.m = function(x) {}, C.m = function(x) {}, C;
}();
C.m(), new C().m(), new C().p();
var obj = {
m: function(x) {},
p: function(x) {}
};
obj.m(), obj.p();
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
//// [voidOperatorWithAnyOtherType.ts]
import { _ as _class_call_check } from "@swc/helpers/_/_class_call_check";
var M, obj1 = {
x: "",
y: 1
}, A = function() {
var M, A = function() {
function A() {
_class_call_check(this, A);
}
return A.foo = function() {}, A;
}();
M || (M = {});
var objA = new A();
obj1.x, obj1.y, objA.a, M.n, A.foo(), objA.a, M.n;
objA.a, M.n, A.foo(), objA.a, M.n;
2 changes: 2 additions & 0 deletions crates/swc_ecma_minifier/src/compress/optimize/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ impl Optimizer<'_> {

// No use => dropped
if ref_count == 0 {
self.mode.store(ident.to_id(), &*init);

if init.may_have_side_effects(&self.expr_ctx) {
// TODO: Inline partially
return;
Expand Down
17 changes: 9 additions & 8 deletions crates/swc_ecma_minifier/src/compress/optimize/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,6 @@ pub(super) fn optimizer<'a>(
prepend_stmts: Default::default(),
append_stmts: Default::default(),
vars: Default::default(),
vars_for_prop_hoisting: Default::default(),
simple_props: Default::default(),
typeofs: Default::default(),
data,
ctx,
Expand Down Expand Up @@ -209,10 +207,6 @@ struct Optimizer<'a> {

vars: Vars,

/// Used for `hoist_props`.
vars_for_prop_hoisting: Box<FxHashMap<Id, Box<Expr>>>,
/// Used for `hoist_props`.
simple_props: Box<FxHashMap<(Id, JsWord), Box<Expr>>>,
typeofs: Box<AHashMap<Id, JsWord>>,
/// This information is created by analyzing identifier usages.
///
Expand All @@ -236,6 +230,9 @@ struct Vars {
/// Used for inlining.
lits: FxHashMap<Id, Box<Expr>>,

/// Used for `hoist_props`.
hoisted_props: Box<FxHashMap<(Id, JsWord), Ident>>,

/// Literals which are cheap to clone, but not sure if we can inline without
/// making output bigger.
///
Expand Down Expand Up @@ -279,6 +276,7 @@ impl Vars {
lits_for_cmp: &self.lits_for_cmp,
lits_for_array_access: &self.lits_for_array_access,
lits: &self.lits,
hoisted_props: &self.hoisted_props,
vars_to_remove: &self.removed,
changed: false,
};
Expand Down Expand Up @@ -2920,8 +2918,6 @@ impl VisitMut for Optimizer<'_> {
}
};

self.store_var_for_prop_hoisting(var);

self.drop_unused_properties(var);

debug_assert_valid(&var.init);
Expand All @@ -2948,6 +2944,8 @@ impl VisitMut for Optimizer<'_> {
true
});

self.hoist_props_of_vars(vars);

let uses_eval = self.data.scopes.get(&self.ctx.scope).unwrap().has_eval_call;

if !uses_eval && !self.ctx.dont_use_prepend_nor_append {
Expand All @@ -2967,6 +2965,9 @@ impl VisitMut for Optimizer<'_> {
for v in vars.iter_mut() {
let mut storage = None;
self.drop_unused_var_declarator(v, &mut storage);
if let Some(expr) = &mut storage {
expr.visit_mut_with(self);
}
side_effects.extend(storage);

// Dropped. Side effects of the initializer is stored in `side_effects`.
Expand Down
Loading

0 comments on commit 3122e94

Please sign in to comment.