Commit Graph

388 Commits

Author SHA1 Message Date
Alex Lam S.L
a30092e20f fix invalid AST_For.init (#1657)
Turns out the only place in `Compressor` which can generate invalid `AST_For.init` is within `drop_unused()`, so focus the fix-up efforts.

supercedes #1652
fixes #1656
2017-03-25 03:18:36 +08:00
Alex Lam S.L
32283a0def fix cascade of evaluate optimisation (#1654)
Operator has changed, so break out from rest of the rules.

fixes #1649
2017-03-24 22:09:19 +08:00
Alex Lam S.L
ac51d4c5a0 fix corner case in AST_For.init (#1652)
Enforce `null` as value for empty initialisation blocks.

fixes #1648
2017-03-24 19:31:17 +08:00
Alex Lam S.L
0432a7abb9 fix assignment extraction from conditional (#1651)
fixes #1645
fixes #1646
2017-03-24 18:52:48 +08:00
Alex Lam S.L
f3a1694a41 fix assignment substitution in sequences (#1643)
take side effects of binary boolean operations into account

fixes #1639
2017-03-24 14:30:31 +08:00
Alex Lam S.L
e918748d88 improve collapsible value detection (#1638)
- #1634 bars variables with cross-scope references in between to collapse
- but if assigned value is side-effect-free, no states can be modified, so it is safe to move
2017-03-24 02:55:32 +08:00
Alex Lam S.L
48ffbef51d account for cross-scope modifications in collapse_vars (#1634)
mostly done by @kzc

fixes #1631
2017-03-23 07:17:34 +08:00
Alex Lam S.L
c0f3feae9f introduce compressor.info() (#1633)
report the following only when `options.warnings = "verbose"`
- unused elements due to inlining
- collpased variables
2017-03-23 06:49:49 +08:00
Alex Lam S.L
96f8befdd7 fix commit 88fb83a (#1622)
The following is wrong:
    `a == (b ? a : c)` => `b`
Because:
- `b` may not be boolean
- `a` might have side effects
- `a == a` is not always `true` (think `NaN`)
- `a == c` is not always `false`
2017-03-19 11:59:42 +08:00
Alex Lam S.L
cd58635dcc fix AST_Binary.lift_sequences() (#1621)
Commit eab99a1c fails to account for side effects from compound assignments.
2017-03-19 03:04:22 +08:00
Alex Lam S.L
274331d0ea transform String.charAt() to index access (#1620)
Guarded by `unsafe` as `charAt()` can be overridden.
2017-03-19 02:17:15 +08:00
Alex Lam S.L
ac40301813 fix chained evaluation (#1610)
`reduce_vars` enables substitution of variables but did not clone the value's `AST_Node`.

This confuses `collapse_vars` and result in invalid AST and subsequent crash.

fixes #1609
2017-03-17 00:26:48 +08:00
Alex Lam S.L
5ae04b3545 make collapse_vars consistent with toplevel (#1608)
fixes #1605
2017-03-16 13:22:26 +08:00
Alex Lam S.L
a80b228d8b fix hoist_vars on reduce_vars (#1607)
`hoist_vars` converts variable declarations into plain assignments, which then confuses `reduce_vars`

fixes #1606
2017-03-16 12:03:30 +08:00
Alex Lam S.L
cf4bf4ceb1 fix stack issues with AST_Node.evaluate() (#1603)
As patched in #1597, `make_node_from_constant()` makes inconsistent and sometimes incorrect calls to `optimize()` and `transform()`.

Fix those issues properly by changing the semantics of `evaluate()` and `make_node_from_constant()`, with the side effect that `evaluate()` no longer eagerly converts constant to `AST_Node`.
2017-03-16 01:02:59 +08:00
Alex Lam S.L
8223b2e0db fix AST_Node.optimize() (#1602)
Liberal use of `Compressor.transform()` and `AST_Node.optimize()` presents an issue for look-up operations like `TreeWalker.in_boolean_context()` and `TreeWalker.parent()`.

This is an incremental fix such that `AST_Node.optimize()` would now contain the correct stack information when called correctly.
2017-03-15 18:44:13 +08:00
Alex Lam S.L
381bd3836e minor clean-ups (#1600)
- remove obsolete optimisation in `AST_Binary` after #1477
- improve `TreeWalker.has_directive()` readability and resilience against multiple visits
2017-03-14 13:19:05 +08:00
Alex Lam S.L
e3a3db73ae temporary fix for boolean bug (#1597)
fixes #1592
2017-03-11 04:59:55 +08:00
Alex Lam S.L
d9344f30b8 disallow parameter substitution for named IIFEs (#1596)
Self-referenced function has non-fixed values assigned to its parameters.

Let `unused` & `!keep_fnames` do the scanning, then apply `reduce_vars` only to unnamed functions.

fixes #1595
2017-03-11 03:34:55 +08:00
Alex Lam S.L
b633706ce4 fix & improve function argument compression (#1584)
- one-use function call => IIFE should take `eval()` & `arguments` into account
- if unused parameter cannot be eliminated, replace it with `0`

fixes #1583
2017-03-09 19:11:05 +08:00
Alex Lam S.L
7e465d4a01 scan RHS of dropped assignments (#1581)
- similar case as #1578 but against #1450 instead
- fix `this` binding in #1450 as well

closes #1580
2017-03-09 05:22:27 +08:00
Alex Lam S.L
711f88dcb4 scan assignment value in drop_unused() (#1578)
those were not optimised for `unused` before, which made it necessary for `reduce_vars` to have separate steps for `keep_fnames`

docs update by @kzc

closes #1577
2017-03-08 18:37:32 +08:00
Alex Lam S.L
c7cdcf06a6 fix function name eliminiation (#1576)
Function expression can be assigned to a variable and be given a name. Ensure function name is the reduced variable before clearing it out.

fixes #1573
fixes #1575
2017-03-08 12:39:57 +08:00
Alex Lam S.L
bd6dee52ab fix return from recursive IIFE (#1570)
`side-effects` did not account for IIFEs being able to reference itself thus making its return value potentially significant
2017-03-08 03:31:51 +08:00
Alex Lam S.L
8153b7bd8a transform function calls to IIFEs (#1560)
- expose function body to call sites for potential optimisations
- suppress substitution of variable used within `AST_Defun`
2017-03-07 15:37:52 +08:00
Alex Lam S.L
d787d70127 avoid substitution of global variables (#1557)
- unless `toplevel` is enabled
- global `const` works as before
2017-03-07 03:11:03 +08:00
kzc
3ac2421932 collapse_vars: do not replace a constant in loop condition or init (#1562) 2017-03-07 01:42:33 +08:00
Alex Lam S.L
067e5a5762 fixup for #1553 (#1555)
- `++a` is the one that is foldable
- transform `a++` into `++a` for better optimisation
2017-03-05 17:15:37 +08:00
Alex Lam S.L
35a849dc48 collapse assignment with adjacent subsequent usage (#1553)
- consolidate `cascade` optimisations
- support ++/-- postfixes
- remove redundant optimisation identified in #1460

fixes #368
2017-03-05 14:56:14 +08:00
Alex Lam S.L
b70591be1a handle variable declaration within catch blocks (#1546)
accounts for IE8- scoping
2017-03-05 13:13:44 +08:00
Alex Lam S.L
b33e7f88e6 improve unsafe on undefined (#1548)
`unsafe` turns undefined keyword into a variable of the same name if found, but that interferes with other related optimisations.

Keep track of such transformations to ensure zero information loss in the process.
2017-03-05 13:09:27 +08:00
Alex Lam S.L
1f0333e9f1 stay safe with constants in IE8- (#1547)
- `undefined` etc. can be redefined at top-level for IE8-, so disable related optimisations
- fixed `--support-ie8` catch mangle bug
2017-03-05 12:51:11 +08:00
Alex Lam S.L
78d1bb92d4 fix a corner case in #1530 (#1552) 2017-03-05 12:12:59 +08:00
kzc
ce54c9ccee disallow collapse_vars constant replacement in for-in statements (#1543) 2017-03-04 02:39:54 +08:00
Alex Lam S.L
07accd2fbb process code with implicit return statement (#1522)
Bookmarklet for instance implicitedly assumes a "completion value" without using `return`.
The `expression` option now supports such use cases.
Optimisations on IIFEs also enhanced.

fixes #354
fixes #543
fixes #625
fixes #628
fixes #640
closes #1293
2017-03-03 18:13:07 +08:00
Alex Lam S.L
18059cc94f compress numerical expressions (#1513)
safe operations
- `a === b` => `a == b`
- `a + -b`  => `a - b`
- `-a + b`  => `b - a`
- `a+ +b`   => `+b+a`

associative operations
(bit-wise operations are safe, otherwise `unsafe_math`)
- `a + (b + c)`       => `(a + b) + c`
- `(n + 2) + 3`       => `5 + n`
- `(2 * n) * 3`       => `6 * n`
- `(a | 1) | (2 | d)` => `(3 | a) | b`

fixes #412
2017-03-03 18:04:32 +08:00
Alex Lam S.L
b5e0e8c203 facilitate fix for #1531 (#1542) 2017-03-03 07:12:24 +08:00
Alex Lam S.L
17b81350d4 fix chained assignment with unused (#1540)
When #1450 optimises `a=b=42`, it stops after the first variable even if both are unused.

fixes #1539
2017-03-03 04:45:20 +08:00
kzc
4d63d4f5b3 collapse_vars should not replace constant in for-in init section (#1538)
fixes #1537
2017-03-03 03:51:15 +08:00
Alex Lam S.L
70d72ad806 properly cover all cases of for-in loop variables (#1536) 2017-03-03 02:39:57 +08:00
Alex Lam S.L
fe9227a41b fix reference marking in for-in loops (#1535)
fixes #1533
2017-03-03 00:56:06 +08:00
Alex Lam S.L
b49e142a26 disable do{...}while(false) optimisation (#1534)
- fails to handle `break` in body

fixes #1532
2017-03-03 00:54:41 +08:00
kzc
ee3b39b909 optimize trivial IIFEs returning constants (#1530) 2017-03-02 15:11:40 +08:00
Alex Lam S.L
9699ffb1af trim unused invocation parameters (#1526) 2017-03-02 11:33:59 +08:00
Alex Lam S.L
fdc9b9413b minor improvement to string optimisation (#1514)
- "" + "a"     => "a"
- "" + a + "b" => a + "b"
- "a" + ""     => "a" (improving on #45)
2017-03-02 11:31:39 +08:00
Alex Lam S.L
7aa69117e1 fix corner cases in reduce_vars (#1524)
Avoid variable substitution in the following cases:
- use of variable before declaration
- declaration within conditional code blocks
- declaration within loop body

fixes #1518
fixes #1525
2017-03-02 00:20:53 +08:00
Alex Lam S.L
c2334baa48 fix crash on missing props to string_template() (#1523)
Patched up `make_node()` without `orig`.

There may be other cases where `start` could be missing, so make it print "undefined" instead of crashing.

fixes #1518
2017-03-01 15:25:26 +08:00
Alex Lam S.L
f5cbe19b75 invert reduce_vars tracking flag (#1519)
Modules like webpack and grunt-contrib-uglify still uses `ast.transform(compressor)` before `Compressor.compress(ast)` was introduced.

Workaround this compatibility issue by deactivating `reduce_vars` in such case.

Also fix use case with omitted `options` when calling `Compressor()`.

fixes #1516
2017-03-01 04:12:10 +08:00
Alex Lam S.L
b34fa11a13 fix evaluate on object getter & setter (#1515) 2017-03-01 02:03:47 +08:00
Alex Lam S.L
4365a51237 temporarily disables reduce_vars (#1517)
... as we investigate #1516
2017-03-01 00:25:43 +08:00
Alex Lam S.L
858e6c78a4 warn & drop #__PURE__ iff IIFE is dropped (#1511)
- consolidate `side-effects` optimisations
- improve string `+` optimisation
- enhance literal & `conditionals` optimisations
2017-02-28 02:25:44 +08:00
Alex Lam S.L
13be50a4a9 faster tree transversal (#1462)
- convert `[].forEach()` to for-loops
2017-02-26 05:58:26 +08:00
Alex Lam S.L
16cd5d57a5 consolidate evaluate & reduce_vars (#1505)
- improve marking efficiency
- apply smarter `const` replacement to `var`

fixes #1501
2017-02-26 00:40:33 +08:00
alexlamsl
4e49302916 enable collapse_vars & reduce_vars by default
- fix corner cases in `const` optimisation
- deprecate `/*@const*/`

fixes #1497
closes #1498
2017-02-24 01:46:57 +08:00
kzc
1e51586996 Support marking a call as pure
A function call or IIFE with an immediately preceding comment
containing `@__PURE__` or `#__PURE__` is deemed to be a
side-effect-free pure function call and can potentially be
dropped.

Depends on `side_effects` option.

`[#@]__PURE__` hint will be removed from comment when pure
call is dropped.

fixes #1261
closes #1448
2017-02-21 14:24:18 +08:00
alexlamsl
26fbeece1c fix pure_funcs & improve side_effects
- only drops side-effect-free arguments
- drop side-effect-free parts with discarded value from `AST_Seq` & `AST_SimpleStatement`

closes #1494
2017-02-21 13:31:59 +08:00
alexlamsl
ec64acd2c8 introduce unsafe_proto
- `Array.prototype.slice` => `[].slice`

closes #1491
2017-02-21 13:29:58 +08:00
alexlamsl
e275148998 enhance global_defs
- support arrays, objects & AST_Node
- support `"a.b":1` on both cli & API
- emit warning if variable is modified
- override top-level variables

fixes #1416
closes #1198
closes #1469
2017-02-21 13:29:58 +08:00
alexlamsl
974247c8c0 evaluate AST_SymbolRef as parameter
fix invalid boolean conversion now exposed in `make_node_from_constant()`

closes #1477
2017-02-21 13:29:58 +08:00
alexlamsl
a0f4fd390a improve reduce_vars and fix a bug
- update modified flag between compress() passes
- support IIFE arguments
- fix corner case with multiple definitions

closes #1473
2017-02-21 13:29:58 +08:00
alexlamsl
b8b133d91a improve keep_fargs & keep_fnames
- utilise in_use_ids instead of unreferenced()
- drop_unused now up-to-date for subsequent passes

closes #1476
2017-02-21 13:29:58 +08:00
kzc
6ffbecb72b smarter const replacement taking name length into account
closes #1459
2017-02-21 13:29:58 +08:00
alexlamsl
f0ff6189be clean up negate_iife
- remove extra tree scanning phase for `negate_iife`
- `negate_iife` now only deals with the narrowest form, i.e. IIFE sitting directly under `AST_SimpleStatement`
- `booleans`, `conditionals` etc. will now take care the rest via more accurate accounting
- `a(); void b();` => `a(); b();`

fixes #1288
closes #1451
2017-02-21 13:29:58 +08:00
alexlamsl
6b3c49e458 improve string concatenation
shuffle associative operations to minimise parentheses and aid other uglification efforts

closes #1454
2017-02-21 13:29:57 +08:00
alexlamsl
f584ca8d07 -c sequences=N suboptimal at N expression cutoff
N = 2:
  a;
  b;
  c;
  d;
was:
  a, b;
  c;
  d;
now:
  a, b;
  c, d;

fixes #1455
closes #1457
2017-02-21 13:29:57 +08:00
alexlamsl
ae4db00991 tweak do-while loops
- `do{...}while(false)` => `{...}`
- clean up `AST_While` logic

closes #1452
2017-02-21 13:29:57 +08:00
alexlamsl
100307ab31 fixes & improvements to [].join()
fixes
- [a].join() => "" + a
- ["a", , "b"].join() => "a,,b"
- ["a", null, "b"].join() => "a,,b"
- ["a", undefined, "b"].join() => "a,,b"

improvements
- ["a", "b"].join(null) => "anullb"
- ["a", "b"].join(undefined) => "a,b"
- [a + "b", c].join("") => a + "b" + c

closes #1453
2017-02-21 13:29:57 +08:00
alexlamsl
148047fbbf drop unused: toplevel, assign-only
- assign statement does not count towards variable usage by default
- only works with assignments on the same scope level as declaration
- can be disabled with `unused` set to "keep_assign"
- `toplevel` to drop unused top-level variables and/or functions
- `top_retain` to whitelist top-level exceptions

closes #1450
2017-02-21 13:29:57 +08:00
kzc
d11dca3cf9 fix stray else in compress with conditionals=false
closes #1449
2017-02-21 13:29:57 +08:00
alexlamsl
e5badb9541 enable typeof "undefined" for general use
move out of unsafe, guard corner case with screw_id8 instead

closes #1446
2017-02-18 19:01:42 +08:00
alexlamsl
11676f9d72 fix crash in unsafe replacement of undefined
remove extraneous call to AST_SymbolRef.reference()

closes #1443
2017-02-18 18:58:23 +08:00
Anthony Van de Gejuchte
dd31d12a91 Improve optimizing function() { if(c){return foo} bar();}
closes #1437
2017-02-18 18:56:18 +08:00
Alex Lam S.L
0610c020b1 optimise binary operands with evaluate() (#1427)
- remove call to evaluate() in is_constant() and let nested optimize() does its job instead
- reject RegExp in is_constant() and remove special case logic under collapse_vars
- operands to conditionals optimisation are now always evaluate()-ed
- throw error in constant_value() instead of returning undefined to catch possible bugs, similar to make_node_from_constant()
- optimise binary boolean operators under `evaluate` instead of `conditionals`
2017-01-26 12:16:50 +01:00
Alex Lam S.L
0d7d4918eb augment evaluate to extract within objects (#1425)
- gated by `unsafe`
- replaces previous optimisation specific to String.length
- "123"[0] => 1
- [1, 2, 3][0] => 1
- [1, 2, 3].length => 3
- does not apply to objects with overridden prototype functions
2017-01-26 12:14:18 +01:00
alexlamsl
48284844a4 add missing LHS cases which global_defs should avoid 2017-01-19 21:06:28 +01:00
Anthony Van de Gejuchte
79b98a9fe8 Do not overwrite options.comments + cleanup 2016-11-29 20:24:08 +01:00
kzc
fc9804b909 Fix (typeof side_effect()) in boolean context
Fixes #1289 with suggestion by @rvanvelzen
2016-10-06 13:50:11 +02:00
alexlamsl
4761d07e0b Optimize unmodified variables 2016-10-01 11:36:11 +02:00
kzc
25fc02743a Account for side effects in string + expr optimization 2016-09-01 09:24:56 -04:00
kzc
0bd8053524 implement optimization: (x = 2 * x) ---> (x *= 2) 2016-08-30 08:43:02 -04:00
Richard van Velzen
8430123e9d Fix negate_iife transform to return a correct tree for nested IIFEs
Fix for #1256, partially reverts d854523783
2016-08-17 11:55:59 +02:00
Anthony Van de Gejuchte
7eb52d2837 Keep const in own scope while compressing
- Fixes #1205
- Fix provided by @kzc
2016-07-15 13:20:52 +02:00
kzc
b40d5de69c Change the default sequences limit to 200 to speed up compress.
Has little or no impact on minification size in the majority of
cases but can speed up rollup builds significantly.

This sequences change also has the beneficial side effect of avoiding
"stack size exceeded" errors on very large input files.

The user is free to alter the sequences limit if they are so inclined.
The previous sequences limit was 2000. 20 is often sufficient.
2016-07-01 09:41:31 +02:00
kzc
b7ef7840f3 Allow sequences maximum length to be user configurable. 2016-07-01 09:41:31 +02:00
kzc
02c638209e Enable --screw-ie8 by default.
catch identifier is mangled correctly for ES5 standards-compliant JS engines by default.

Unconditionally use the ie8 if/do-while workaround whether or not --screw-ie8 is enabled.

To support non-standard ie8 javascript use: uglifyjs --support-ie8
2016-06-30 21:49:48 +02:00
kzc
335b72df03 Fix spidermonkey AST (ESTree) export and import, Array holes
Fixes: #1156 #1161

Also add test to exercise Uglify after spidermonkey export/import of itself.
2016-06-30 21:44:12 +02:00
kzc
ace8aaa0f4 Fix conditional expressions of form (x ? -1 : -1)
Fixes #1154, #1153
2016-06-21 14:52:13 -04:00
kzc
0c003c92a8 Don't replace undefined, NaN and Infinity within with scope 2016-06-21 10:53:29 +02:00
Anthony Van de Gejuchte
d7971ba0e4 Fix test262 failures related to <, <=, in and instanceof
Fixed-by: @kzc
2016-06-15 23:11:08 +02:00
Anthony Van de Gejuchte
ea31da2455 Don't drop unused if scope uses with statement
Fix provided by @kzc
2016-06-12 14:30:28 +02:00
kzc
09d5707a8a collapse_vars: Do not consider RegExp literals to be constants
Fixes #1100
2016-05-27 00:03:51 -04:00
kzc
1e390269d4 Optimize if_return for single if/return cases.
Fixes #1089
2016-05-24 17:54:08 +02:00
Richard van Velzen
bc49dfd27a Completely allow evaluating -0 2016-05-24 17:50:29 +02:00
Richard van Velzen
27eedbc302 Never produce -0 when evaluating expressions (like -"")
Fix for #1085. The major case was already there, but more expressions can result in -0.
2016-05-17 22:34:38 +02:00
kzc
5f464b41e2 Simplify iife new fix
as suggested by @rvanvelzen.

Added a test for IIFEs in nested contexts.
2016-05-15 19:12:17 -04:00
kzc
bcc1318d4b Do not apply negate_iife optimization to new expression 2016-05-09 03:19:28 -04:00
Richard van Velzen
4fe630431c Hoist functions when reversing if (x) return; ... vs. if (!x) ...
Fixes #1052
2016-04-23 23:48:33 +02:00
kzc
c55dd5ed74 Add passes compress option. Fix duplicate compress warnings. 2016-04-19 20:05:33 +02:00
Richard van Velzen
4b4528ee05 Prevent endless recursion when evaluating self-referencing consts
Fix #1041
2016-04-13 15:03:31 +02:00
Mihai Bazon
b5a7a231f7 Actually limit sequence length.
Fix #1038
2016-04-12 14:17:24 +03:00