Compare commits

..

9 Commits

Author SHA1 Message Date
Alex Lam S.L
68645b28d3 harmony-v3.1.2 2017-09-24 11:13:25 +08:00
alexlamsl
aaa8212837 improve test for #2316 2017-09-24 02:23:38 +08:00
alexlamsl
bd84007cf4 Merge branch 'master' into harmony-v3.1.2 2017-09-24 02:20:47 +08:00
Alex Lam S.L
55387e8fd0 v3.1.2 2017-09-24 02:02:04 +08:00
GUENEGO Jean-Louis
1241600013 mangle: do not mangle reserved class (#2317)
fixes #2316
2017-09-24 00:08:47 +08:00
kzc
7e3e9da860 fix "use asm" numeric output (#2328)
fixes #2324
2017-09-21 04:42:40 +08:00
kzc
a784717fe2 allow RegExp for unsafe_methods compress option (#2327) 2017-09-21 00:48:16 +08:00
Alex Lam S.L
00f509405b suppress collapse_vars of this into "use strict" (#2326)
fixes #2319
2017-09-20 05:23:20 +08:00
kzc
e8235657e4 add new compress option unsafe_methods for ecma >= 6 (#2325)
fixes #2321
2017-09-20 00:15:54 +08:00
12 changed files with 295 additions and 17 deletions

View File

@@ -631,6 +631,13 @@ If you're using the `X-SourceMap` header instead, you can just omit `sourceMap.u
- `unsafe_math` (default: false) -- optimize numerical expressions like
`2 * x * 3` into `6 * x`, which may give imprecise floating point results.
- `unsafe_methods` (default: false) -- Converts `{ m: function(){} }` to
`{ m(){} }`. `ecma` must be set to `6` or greater to enable this transform.
If `unsafe_methods` is a RegExp then key/value pairs with keys matching the
RegExp will be converted to concise methods.
Note: if enabled there is a risk of getting a "`<method name>` is not a
constructor" TypeError should any code try to `new` the former function.
- `unsafe_proto` (default: false) -- optimize expressions like
`Array.prototype.slice.call(a)` into `[].slice.call(a)`

View File

@@ -134,11 +134,10 @@ var AST_Debugger = DEFNODE("Debugger", null, {
$documentation: "Represents a debugger statement",
}, AST_Statement);
var AST_Directive = DEFNODE("Directive", "value scope quote", {
var AST_Directive = DEFNODE("Directive", "value quote", {
$documentation: "Represents a directive, like \"use strict\";",
$propdoc: {
value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
scope: "[AST_Scope/S] The scope that this directive affects",
quote: "[string] the original quote character"
},
}, AST_Statement);
@@ -303,10 +302,9 @@ var AST_With = DEFNODE("With", "expression", {
/* -----[ scope and functions ]----- */
var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_eval parent_scope enclosed cname", {
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
$documentation: "Base class for all statements introducing a lexical scope",
$propdoc: {
directives: "[string*/S] an array of directives declared in this scope",
variables: "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope",
functions: "[Object/S] like `variables`, but only lists function declarations",
uses_with: "[boolean/S] tells whether this scope uses the `with` statement",

View File

@@ -88,6 +88,7 @@ function Compressor(options, false_by_default) {
unsafe_comps : false,
unsafe_Func : false,
unsafe_math : false,
unsafe_methods: false,
unsafe_proto : false,
unsafe_regexp : false,
unused : !false_by_default,
@@ -874,7 +875,7 @@ merge(Compressor.prototype, {
}
}
function has_overlapping_symbol(fn, arg) {
function has_overlapping_symbol(fn, arg, fn_strict) {
var found = false, scan_this = !(fn instanceof AST_Arrow);
arg.walk(new TreeWalker(function(node, descend) {
if (found) return true;
@@ -885,7 +886,7 @@ merge(Compressor.prototype, {
}
return found = true;
}
if (scan_this && node instanceof AST_This) {
if ((fn_strict || scan_this) && node instanceof AST_This) {
return found = true;
}
if (node instanceof AST_Scope && !(node instanceof AST_Arrow)) {
@@ -910,6 +911,8 @@ merge(Compressor.prototype, {
&& all(iife.args, function(arg) {
return !(arg instanceof AST_Expansion);
})) {
var fn_strict = compressor.has_directive("use strict");
if (fn_strict && fn.body.indexOf(fn_strict) < 0) fn_strict = false;
var names = Object.create(null);
for (var i = fn.argnames.length; --i >= 0;) {
var sym = fn.argnames[i];
@@ -918,7 +921,7 @@ merge(Compressor.prototype, {
if (sym instanceof AST_Expansion) {
var elements = iife.args.slice(i);
if (all(elements, function(arg) {
return !has_overlapping_symbol(fn, arg);
return !has_overlapping_symbol(fn, arg, fn_strict);
})) {
candidates.unshift(make_node(AST_VarDef, sym, {
name: sym.expression,
@@ -930,7 +933,7 @@ merge(Compressor.prototype, {
} else {
var arg = iife.args[i];
if (!arg) arg = make_node(AST_Undefined, sym).transform(compressor);
else if (has_overlapping_symbol(fn, arg)) arg = null;
else if (has_overlapping_symbol(fn, arg, fn_strict)) arg = null;
if (arg) candidates.unshift(make_node(AST_VarDef, sym, {
name: sym,
value: arg
@@ -4866,7 +4869,10 @@ merge(Compressor.prototype, {
// p:async function(){} ---> async p(){}
// p:()=>{} ---> p(){}
// p:async()=>{} ---> async p(){}
if (compressor.option("ecma") >= 6) {
var unsafe_methods = compressor.option("unsafe_methods");
if (unsafe_methods
&& compressor.option("ecma") >= 6
&& (!(unsafe_methods instanceof RegExp) || unsafe_methods.test(self.key + ""))) {
var key = self.key;
var value = self.value;
var is_arrow_with_block = value instanceof AST_Arrow

View File

@@ -506,13 +506,17 @@ function OutputStream(options) {
nodetype.DEFMETHOD("_codegen", generator);
};
var use_asm = false;
var in_directive = false;
var active_scope = null;
var use_asm = null;
AST_Node.DEFMETHOD("print", function(stream, force_parens){
var self = this, generator = self._codegen, prev_use_asm = use_asm;
if (self instanceof AST_Directive && self.value == "use asm" && stream.parent() instanceof AST_Scope) {
use_asm = true;
var self = this, generator = self._codegen;
if (self instanceof AST_Scope) {
active_scope = self;
}
else if (!use_asm && self instanceof AST_Directive && self.value == "use asm") {
use_asm = active_scope;
}
function doit() {
self.add_comments(stream);
@@ -526,8 +530,8 @@ function OutputStream(options) {
doit();
}
stream.pop_node();
if (self instanceof AST_Scope) {
use_asm = prev_use_asm;
if (self === use_asm) {
use_asm = null;
}
});
AST_Node.DEFMETHOD("_print", AST_Node.prototype.print);

View File

@@ -546,7 +546,7 @@ AST_Toplevel.DEFMETHOD("mangle_names", function(options){
var mangle_with_block_scope =
(!options.ie8 && node instanceof AST_SymbolCatch) ||
node instanceof AST_SymbolBlockDeclaration;
if (mangle_with_block_scope) {
if (mangle_with_block_scope && options.reserved.indexOf(node.name) < 0) {
to_mangle.push(node.definition());
return;
}

View File

@@ -4,7 +4,7 @@
"homepage": "https://github.com/mishoo/UglifyJS2/tree/harmony",
"author": "Mihai Bazon <mihai.bazon@gmail.com> (http://lisperator.net/)",
"license": "BSD-2-Clause",
"version": "3.1.1",
"version": "3.1.2",
"engines": {
"node": ">=0.8.0"
},

View File

@@ -290,6 +290,7 @@ issue_2105_1: {
passes: 3,
reduce_vars: true,
side_effects: true,
unsafe_methods: true,
unused: true,
}
input: {

View File

@@ -104,3 +104,65 @@ asm_mixed: {
}
}
asm_toplevel: {
options = {}
input: {
"use asm";
0.0;
function f() {
0.0;
(function(){
0.0;
});
}
0.0;
}
expect_exact: '"use asm";0.0;function f(){0.0;(function(){0.0})}0.0;'
}
asm_function_expression: {
options = {}
input: {
0.0;
var a = function() {
"use asm";
0.0;
}
function f() {
0.0;
return function(){
"use asm";
0.0;
}
0.0;
}
0.0;
}
expect_exact: '0;var a=function(){"use asm";0.0};function f(){0;return function(){"use asm";0.0};0}0;'
}
asm_nested_functions: {
options = {}
input: {
0.0;
function a() {
"use asm";
0.0;
}
0.0;
function b() {
0.0;
function c(){
"use asm";
0.0;
}
0.0;
function d(){
0.0;
}
0.0;
}
0.0;
}
expect_exact: '0;function a(){"use asm";0.0}0;function b(){0;function c(){"use asm";0.0}0;function d(){0}0}0;'
}

View File

@@ -2725,3 +2725,73 @@ issue_2313_2: {
}
expect_stdout: "0"
}
issue_2319_1: {
options = {
collapse_vars: true,
unused: true,
}
input: {
console.log(function(a) {
return a;
}(!function() {
return this;
}()));
}
expect: {
console.log(function(a) {
return !function() {
return this;
}();
}());
}
expect_stdout: "false"
}
issue_2319_2: {
options = {
collapse_vars: true,
unused: true,
}
input: {
console.log(function(a) {
"use strict";
return a;
}(!function() {
return this;
}()));
}
expect: {
console.log(function(a) {
"use strict";
return a;
}(!function() {
return this;
}()));
}
expect_stdout: "false"
}
issue_2319_3: {
options = {
collapse_vars: true,
unused: true,
}
input: {
"use strict";
console.log(function(a) {
return a;
}(!function() {
return this;
}()));
}
expect: {
"use strict";
console.log(function(a) {
return !function() {
return this;
}();
}());
}
expect_stdout: "true"
}

View File

@@ -804,3 +804,38 @@ object_spread_of_sequence: {
console.log({ ...o || o });
}
}
// issue 2316
class_name_can_be_preserved_with_reserved: {
mangle = {
reserved: [ "Foo" ],
}
input: {
function x() {
class Foo {}
Foo.bar;
class Bar {}
Bar.foo;
}
function y() {
var Foo = class Foo {};
Foo.bar;
var Bar = class Bar {};
Bar.bar;
}
}
expect: {
function x() {
class Foo {}
Foo.bar;
class a {}
a.foo;
}
function y() {
var Foo = class Foo {};
Foo.bar;
var a = class a {};
a.bar;
}
}
}

View File

@@ -516,6 +516,7 @@ variable_as_computed_property: {
prop_func_to_concise_method: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
({
@@ -544,6 +545,7 @@ prop_func_to_concise_method: {
prop_arrow_to_concise_method: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
({
@@ -592,6 +594,7 @@ concise_method_to_prop_arrow: {
prop_func_to_async_concise_method: {
options = {
ecma: 8,
unsafe_methods: true,
}
input: {
({
@@ -614,6 +617,7 @@ prop_func_to_async_concise_method: {
prop_func_to_concise_method_various: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
({
@@ -646,6 +650,7 @@ prop_func_to_concise_method_various: {
prop_arrows_to_concise_method_various: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
({
@@ -674,6 +679,7 @@ prop_arrows_to_concise_method_various: {
prop_arrow_with_this: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
function run(arg) {
@@ -711,6 +717,7 @@ prop_arrow_with_this: {
prop_arrow_with_nested_this: {
options = {
ecma: 6,
unsafe_methods: true,
}
input: {
function run(arg) {

View File

@@ -887,6 +887,7 @@ methods_keep_quoted_true: {
options = {
arrows: true,
ecma: 6,
unsafe_methods: true,
}
mangle = {
properties: {
@@ -906,6 +907,7 @@ methods_keep_quoted_false: {
options = {
arrows: true,
ecma: 6,
unsafe_methods: true,
}
mangle = {
properties: {
@@ -931,6 +933,7 @@ methods_keep_quoted_from_dead_code: {
evaluate: true,
reduce_vars: true,
side_effects: true,
unsafe_methods: true,
}
mangle = {
properties: {
@@ -964,3 +967,88 @@ issue_2256: {
g.keep = g.g;
}
}
issue_2321: {
options = {
ecma: 6,
unsafe_methods: false,
}
input: {
var f = {
foo: function(){ console.log("foo") },
bar() { console.log("bar") }
};
var foo = new f.foo();
var bar = f.bar();
}
expect: {
var f = {
foo: function() {
console.log("foo");
},
bar() {
console.log("bar");
}
};
var foo = new f.foo();
var bar = f.bar();
}
expect_stdout: [
"foo",
"bar",
]
node_version: ">=6"
}
unsafe_methods_regex: {
options = {
ecma: 6,
unsafe_methods: /^[A-Z1]/,
}
input: {
var f = {
123: function(){ console.log("123") },
foo: function(){ console.log("foo") },
bar() { console.log("bar") },
Baz: function(){ console.log("baz") },
BOO: function(){ console.log("boo") },
null: function(){ console.log("null") },
undefined: function(){ console.log("undefined") },
};
f[123]();
new f.foo();
f.bar();
f.Baz();
f.BOO();
new f.null();
new f.undefined();
}
expect: {
var f = {
123() { console.log("123") },
foo: function(){ console.log("foo") },
bar() { console.log("bar"); },
Baz() { console.log("baz") },
BOO() { console.log("boo") },
null: function(){ console.log("null") },
undefined: function(){ console.log("undefined") },
};
f[123]();
new f.foo();
f.bar();
f.Baz();
f.BOO();
new f.null();
new f.undefined();
}
expect_stdout: [
"123",
"foo",
"bar",
"baz",
"boo",
"null",
"undefined",
]
node_version: ">=6"
}