parent
74ae16f9f8
commit
1893abd2cb
|
|
@ -60,6 +60,7 @@ function Compressor(options, false_by_default) {
|
||||||
expression : false,
|
expression : false,
|
||||||
global_defs : {},
|
global_defs : {},
|
||||||
hoist_funs : !false_by_default,
|
hoist_funs : !false_by_default,
|
||||||
|
hoist_props : false,
|
||||||
hoist_vars : false,
|
hoist_vars : false,
|
||||||
ie8 : false,
|
ie8 : false,
|
||||||
if_return : !false_by_default,
|
if_return : !false_by_default,
|
||||||
|
|
@ -190,6 +191,7 @@ merge(Compressor.prototype, {
|
||||||
if (node._squeezed) return node;
|
if (node._squeezed) return node;
|
||||||
var was_scope = false;
|
var was_scope = false;
|
||||||
if (node instanceof AST_Scope) {
|
if (node instanceof AST_Scope) {
|
||||||
|
node = node.hoist_properties(this);
|
||||||
node = node.hoist_declarations(this);
|
node = node.hoist_declarations(this);
|
||||||
was_scope = true;
|
was_scope = true;
|
||||||
}
|
}
|
||||||
|
|
@ -547,6 +549,7 @@ merge(Compressor.prototype, {
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset_def(def) {
|
function reset_def(def) {
|
||||||
|
def.direct_access = false;
|
||||||
def.escaped = false;
|
def.escaped = false;
|
||||||
if (def.scope.uses_eval) {
|
if (def.scope.uses_eval) {
|
||||||
def.fixed = false;
|
def.fixed = false;
|
||||||
|
|
@ -604,15 +607,18 @@ merge(Compressor.prototype, {
|
||||||
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|
|| parent instanceof AST_Return && node === parent.value && node.scope !== d.scope
|
||||||
|| parent instanceof AST_VarDef && node === parent.value) {
|
|| parent instanceof AST_VarDef && node === parent.value) {
|
||||||
d.escaped = true;
|
d.escaped = true;
|
||||||
|
return;
|
||||||
} else if (parent instanceof AST_Array || parent instanceof AST_Object) {
|
} else if (parent instanceof AST_Array || parent instanceof AST_Object) {
|
||||||
mark_escaped(d, parent, parent, level + 1);
|
mark_escaped(d, parent, parent, level + 1);
|
||||||
} else if (parent instanceof AST_PropAccess && node === parent.expression) {
|
} else if (parent instanceof AST_PropAccess && node === parent.expression) {
|
||||||
mark_escaped(d, parent, read_property(value, parent.property), level + 1);
|
mark_escaped(d, parent, read_property(value, parent.property), level + 1);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
if (level == 0) d.direct_access = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AST_SymbolRef.DEFMETHOD("fixed_value", function() {
|
AST_Symbol.DEFMETHOD("fixed_value", function() {
|
||||||
var fixed = this.definition().fixed;
|
var fixed = this.definition().fixed;
|
||||||
if (!fixed || fixed instanceof AST_Node) return fixed;
|
if (!fixed || fixed instanceof AST_Node) return fixed;
|
||||||
return fixed();
|
return fixed();
|
||||||
|
|
@ -2478,11 +2484,11 @@ merge(Compressor.prototype, {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
switch (body.length) {
|
switch (body.length) {
|
||||||
case 0:
|
case 0:
|
||||||
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
|
return in_list ? MAP.skip : make_node(AST_EmptyStatement, node);
|
||||||
case 1:
|
case 1:
|
||||||
return body[0];
|
return body[0];
|
||||||
default:
|
default:
|
||||||
return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
|
return in_list ? MAP.splice(body) : make_node(AST_BlockStatement, node, {
|
||||||
body: body
|
body: body
|
||||||
});
|
});
|
||||||
|
|
@ -2678,6 +2684,68 @@ merge(Compressor.prototype, {
|
||||||
return self;
|
return self;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AST_Scope.DEFMETHOD("hoist_properties", function(compressor){
|
||||||
|
var self = this;
|
||||||
|
if (!compressor.option("hoist_props") || compressor.has_directive("use asm")) return self;
|
||||||
|
var defs_by_id = Object.create(null);
|
||||||
|
var tt = new TreeTransformer(function(node) {
|
||||||
|
if (node instanceof AST_VarDef) {
|
||||||
|
var sym = node.name, def, value;
|
||||||
|
if (sym.scope === self
|
||||||
|
&& !(def = sym.definition()).escaped
|
||||||
|
&& !def.single_use
|
||||||
|
&& !def.direct_access
|
||||||
|
&& (value = sym.fixed_value()) === node.value
|
||||||
|
&& value instanceof AST_Object) {
|
||||||
|
var defs = new Dictionary();
|
||||||
|
var assignments = [
|
||||||
|
make_node(AST_VarDef, node, {
|
||||||
|
name: sym,
|
||||||
|
value: make_node(AST_Object, value, {
|
||||||
|
properties: []
|
||||||
|
})
|
||||||
|
})
|
||||||
|
];
|
||||||
|
value.properties.forEach(function(prop) {
|
||||||
|
var key = make_node(sym.CTOR, sym, {
|
||||||
|
name: make_node(AST_Sub, sym, {
|
||||||
|
expression: sym,
|
||||||
|
property: make_node(AST_String, prop, {
|
||||||
|
value: prop.key
|
||||||
|
})
|
||||||
|
}).print_to_string(),
|
||||||
|
scope: self
|
||||||
|
});
|
||||||
|
defs.set(prop.key, self.def_variable(key));
|
||||||
|
assignments.push(make_node(AST_VarDef, node, {
|
||||||
|
name: key,
|
||||||
|
value: prop.value
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
if (assignments.length == 1) return assignments[0];
|
||||||
|
defs_by_id[def.id] = defs;
|
||||||
|
return MAP.splice(assignments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (node instanceof AST_PropAccess && node.expression instanceof AST_SymbolRef) {
|
||||||
|
var defs = defs_by_id[node.expression.definition().id];
|
||||||
|
if (defs) {
|
||||||
|
var key = node.property;
|
||||||
|
if (key instanceof AST_Node) key = key.getValue();
|
||||||
|
var def = defs.get(key);
|
||||||
|
var sym = make_node(AST_SymbolRef, node, {
|
||||||
|
name: def.name,
|
||||||
|
scope: node.expression.scope,
|
||||||
|
thedef: def
|
||||||
|
});
|
||||||
|
def.references.push(sym);
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return self.transform(tt);
|
||||||
|
});
|
||||||
|
|
||||||
// drop_side_effect_free()
|
// drop_side_effect_free()
|
||||||
// remove side-effect-free parts which only affects return value
|
// remove side-effect-free parts which only affects return value
|
||||||
(function(def){
|
(function(def){
|
||||||
|
|
|
||||||
157
test/compress/hoist_props.js
Normal file
157
test/compress/hoist_props.js
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
issue_2377_1: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
hoist_props: true,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
foo: 1,
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.foo, obj.cube(3));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var n = 1, o = function(n) {
|
||||||
|
return n * n * n;
|
||||||
|
};
|
||||||
|
console.log(n, o(3));
|
||||||
|
}
|
||||||
|
expect_stdout: "1 27"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2377_2: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
hoist_props: true,
|
||||||
|
passes: 2,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
foo: 1,
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.foo, obj.cube(3));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, function(n) {
|
||||||
|
return n * n * n;
|
||||||
|
}(3));
|
||||||
|
}
|
||||||
|
expect_stdout: "1 27"
|
||||||
|
}
|
||||||
|
|
||||||
|
issue_2377_3: {
|
||||||
|
options = {
|
||||||
|
evaluate: true,
|
||||||
|
inline: true,
|
||||||
|
hoist_props: true,
|
||||||
|
passes: 3,
|
||||||
|
reduce_vars: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
foo: 1,
|
||||||
|
bar: 2,
|
||||||
|
square: function(x) {
|
||||||
|
return x * x;
|
||||||
|
},
|
||||||
|
cube: function(x) {
|
||||||
|
return x * x * x;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.foo, obj.cube(3));
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log(1, 27);
|
||||||
|
}
|
||||||
|
expect_stdout: "1 27"
|
||||||
|
}
|
||||||
|
|
||||||
|
direct_access: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
hoist_props: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var a = 0;
|
||||||
|
var obj = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
};
|
||||||
|
for (var k in obj) a++;
|
||||||
|
console.log(a, obj.a);
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
var a = 0;
|
||||||
|
var o = {
|
||||||
|
a: 1,
|
||||||
|
b: 2,
|
||||||
|
};
|
||||||
|
for (var r in o) a++;
|
||||||
|
console.log(a, o.a);
|
||||||
|
}
|
||||||
|
expect_stdout: "2 1"
|
||||||
|
}
|
||||||
|
|
||||||
|
single_use: {
|
||||||
|
options = {
|
||||||
|
reduce_vars: true,
|
||||||
|
hoist_props: true,
|
||||||
|
toplevel: true,
|
||||||
|
unused: true,
|
||||||
|
}
|
||||||
|
mangle = {
|
||||||
|
toplevel: true,
|
||||||
|
}
|
||||||
|
input: {
|
||||||
|
var obj = {
|
||||||
|
bar: function() {
|
||||||
|
return 42;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
console.log(obj.bar());
|
||||||
|
}
|
||||||
|
expect: {
|
||||||
|
console.log({
|
||||||
|
bar: function() {
|
||||||
|
return 42;
|
||||||
|
},
|
||||||
|
}.bar());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -16,11 +16,9 @@
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
"compress": {
|
"compress": {
|
||||||
"toplevel": true
|
"hoist_props": true
|
||||||
},
|
},
|
||||||
"mangle": {
|
"toplevel": true
|
||||||
"toplevel": true
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"compress": {
|
"compress": {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user