Rename clean_getters to pure_getters; add pure_funcs.

This commit is contained in:
Mihai Bazon
2013-10-04 13:17:25 +03:00
parent 253c7c2325
commit f2348dd98b
2 changed files with 41 additions and 5 deletions

View File

@@ -184,38 +184,67 @@ you can pass a comma-separated list of options. Options are in the form
to set `true`; it's effectively a shortcut for `foo=true`). to set `true`; it's effectively a shortcut for `foo=true`).
- `sequences` -- join consecutive simple statements using the comma operator - `sequences` -- join consecutive simple statements using the comma operator
- `properties` -- rewrite property access using the dot notation, for - `properties` -- rewrite property access using the dot notation, for
example `foo["bar"] → foo.bar` example `foo["bar"] → foo.bar`
- `dead_code` -- remove unreachable code - `dead_code` -- remove unreachable code
- `drop_debugger` -- remove `debugger;` statements - `drop_debugger` -- remove `debugger;` statements
- `unsafe` (default: false) -- apply "unsafe" transformations (discussion below) - `unsafe` (default: false) -- apply "unsafe" transformations (discussion below)
- `conditionals` -- apply optimizations for `if`-s and conditional - `conditionals` -- apply optimizations for `if`-s and conditional
expressions expressions
- `comparisons` -- apply certain optimizations to binary nodes, for example: - `comparisons` -- apply certain optimizations to binary nodes, for example:
`!(a <= b) → a > b` (only when `unsafe`), attempts to negate binary nodes, `!(a <= b) → a > b` (only when `unsafe`), attempts to negate binary nodes,
e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc. e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
- `evaluate` -- attempt to evaluate constant expressions - `evaluate` -- attempt to evaluate constant expressions
- `booleans` -- various optimizations for boolean context, for example `!!a - `booleans` -- various optimizations for boolean context, for example `!!a
? b : c → a ? b : c` ? b : c → a ? b : c`
- `loops` -- optimizations for `do`, `while` and `for` loops when we can - `loops` -- optimizations for `do`, `while` and `for` loops when we can
statically determine the condition statically determine the condition
- `unused` -- drop unreferenced functions and variables - `unused` -- drop unreferenced functions and variables
- `hoist_funs` -- hoist function declarations - `hoist_funs` -- hoist function declarations
- `hoist_vars` (default: false) -- hoist `var` declarations (this is `false` - `hoist_vars` (default: false) -- hoist `var` declarations (this is `false`
by default because it seems to increase the size of the output in general) by default because it seems to increase the size of the output in general)
- `if_return` -- optimizations for if/return and if/continue - `if_return` -- optimizations for if/return and if/continue
- `join_vars` -- join consecutive `var` statements - `join_vars` -- join consecutive `var` statements
- `cascade` -- small optimization for sequences, transform `x, x` into `x` - `cascade` -- small optimization for sequences, transform `x, x` into `x`
and `x = something(), x` into `x = something()` and `x = something(), x` into `x = something()`
- `warnings` -- display warnings when dropping unreachable code or unused - `warnings` -- display warnings when dropping unreachable code or unused
declarations etc. declarations etc.
- `negate_iife` -- negate "Immediately-Called Function Expressions" - `negate_iife` -- negate "Immediately-Called Function Expressions"
where the return value is discarded, to avoid the parens that the where the return value is discarded, to avoid the parens that the
code generator would insert. code generator would insert.
- `clean_getters` -- the default is `false`. If you pass `true` for
- `pure_getters` -- the default is `false`. If you pass `true` for
this, UglifyJS will assume that object property access this, UglifyJS will assume that object property access
(e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects. (e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
- `pure_funcs` -- default `null`. You can pass an array of names and
UglifyJS will assume that those functions do not produce side
effects. DANGER: will not check if the name is redefined in scope.
An example case here, for instance `var q = Math.floor(a/b)`. If
variable `q` is not used elsewhere, UglifyJS will drop it, but will
still keep the `Math.floor(a/b)`, not knowing what it does. You can
pass `pure_funcs: [ 'Math.floor' ]` to let it know that this
function won't produce any side effect, in which case the whole
statement would get discarded. The current implementation adds some
overhead (compression will be slower).
### The `unsafe` option ### The `unsafe` option
It enables some transformations that *might* break code logic in certain It enables some transformations that *might* break code logic in certain

View File

@@ -66,7 +66,8 @@ function Compressor(options, false_by_default) {
join_vars : !false_by_default, join_vars : !false_by_default,
cascade : !false_by_default, cascade : !false_by_default,
side_effects : !false_by_default, side_effects : !false_by_default,
clean_getters : false, pure_getters : false,
pure_funcs : null,
negate_iife : !false_by_default, negate_iife : !false_by_default,
screw_ie8 : false, screw_ie8 : false,
@@ -809,6 +810,12 @@ merge(Compressor.prototype, {
def(AST_Constant, function(compressor){ return false }); def(AST_Constant, function(compressor){ return false });
def(AST_This, function(compressor){ return false }); def(AST_This, function(compressor){ return false });
def(AST_Call, function(compressor){
var pure = compressor.option("pure_funcs");
if (!pure) return true;
return pure.indexOf(this.expression.print_to_string()) < 0;
});
def(AST_Block, function(compressor){ def(AST_Block, function(compressor){
for (var i = this.body.length; --i >= 0;) { for (var i = this.body.length; --i >= 0;) {
if (this.body[i].has_side_effects(compressor)) if (this.body[i].has_side_effects(compressor))
@@ -855,16 +862,16 @@ merge(Compressor.prototype, {
return false; return false;
}); });
def(AST_Dot, function(compressor){ def(AST_Dot, function(compressor){
if (!compressor.option("clean_getters")) return true; if (!compressor.option("pure_getters")) return true;
return this.expression.has_side_effects(compressor); return this.expression.has_side_effects(compressor);
}); });
def(AST_Sub, function(compressor){ def(AST_Sub, function(compressor){
if (!compressor.option("clean_getters")) return true; if (!compressor.option("pure_getters")) return true;
return this.expression.has_side_effects(compressor) return this.expression.has_side_effects(compressor)
|| this.property.has_side_effects(compressor); || this.property.has_side_effects(compressor);
}); });
def(AST_PropAccess, function(compressor){ def(AST_PropAccess, function(compressor){
return !compressor.option("clean_getters"); return !compressor.option("pure_getters");
}); });
def(AST_Seq, function(compressor){ def(AST_Seq, function(compressor){
return this.car.has_side_effects(compressor) return this.car.has_side_effects(compressor)