From 654743772514f5204d38bc7e7dba566b9dafedbd Mon Sep 17 00:00:00 2001 From: alexlamsl Date: Wed, 17 Feb 2016 02:52:28 +0800 Subject: [PATCH] preserve ThisBinding for side_effects --- lib/compress.js | 20 ++++----- lib/scope.js | 9 ++-- test/compress/issue-782.js | 4 ++ test/compress/issue-973.js | 47 +++++++++++++++----- test/compress/issue-976.js | 88 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 144 insertions(+), 24 deletions(-) create mode 100644 test/compress/issue-976.js diff --git a/lib/compress.js b/lib/compress.js index df8975d5..ed4f62ff 100644 --- a/lib/compress.js +++ b/lib/compress.js @@ -179,9 +179,9 @@ merge(Compressor.prototype, { // we shouldn't compress (1,func)(something) to // func(something) because that changes the meaning of // the func (becomes lexical instead of global). - function maintain_call_binding(parent, orig, val) { + function maintain_this_binding(parent, orig, val) { if (parent instanceof AST_Call && parent.expression === orig) { - if (val instanceof AST_PropAccess || (val instanceof AST_Symbol && val.name === "eval")) { + if (val instanceof AST_PropAccess || val instanceof AST_SymbolRef && val.name === "eval") { return make_node(AST_Seq, orig, { car: make_node(AST_Number, orig, { value: 0 @@ -383,7 +383,7 @@ merge(Compressor.prototype, { if (is_lvalue(node, parent)) return node; // Remove var definition and return its value to the TreeTransformer to replace. - var value = maintain_call_binding(parent, node, var_decl.value); + var value = maintain_this_binding(parent, node, var_decl.value); var_decl.value = null; var_defs.splice(var_defs_index, 1); @@ -2125,7 +2125,7 @@ merge(Compressor.prototype, { if (!compressor.option("side_effects")) return self; if (!self.car.has_side_effects(compressor)) { - return maintain_call_binding(compressor.parent(), self, self.cdr); + return maintain_this_binding(compressor.parent(), self, self.cdr); } if (compressor.option("cascade")) { if (self.car instanceof AST_Assign @@ -2315,10 +2315,10 @@ merge(Compressor.prototype, { if (ll.length > 1) { if (ll[1]) { compressor.warn("Condition left of && always true [{file}:{line},{col}]", self.start); - return maintain_call_binding(compressor.parent(), self, self.right.evaluate(compressor)[0]); + return maintain_this_binding(compressor.parent(), self, self.right.evaluate(compressor)[0]); } else { compressor.warn("Condition left of && always false [{file}:{line},{col}]", self.start); - return maintain_call_binding(compressor.parent(), self, ll[0]); + return maintain_this_binding(compressor.parent(), self, ll[0]); } } } @@ -2327,10 +2327,10 @@ merge(Compressor.prototype, { if (ll.length > 1) { if (ll[1]) { compressor.warn("Condition left of || always true [{file}:{line},{col}]", self.start); - return maintain_call_binding(compressor.parent(), self, ll[0]); + return maintain_this_binding(compressor.parent(), self, ll[0]); } else { compressor.warn("Condition left of || always false [{file}:{line},{col}]", self.start); - return maintain_call_binding(compressor.parent(), self, self.right.evaluate(compressor)[0]); + return maintain_this_binding(compressor.parent(), self, self.right.evaluate(compressor)[0]); } } } @@ -2555,10 +2555,10 @@ merge(Compressor.prototype, { if (cond.length > 1) { if (cond[1]) { compressor.warn("Condition always true [{file}:{line},{col}]", self.start); - return maintain_call_binding(compressor.parent(), self, self.consequent); + return maintain_this_binding(compressor.parent(), self, self.consequent); } else { compressor.warn("Condition always false [{file}:{line},{col}]", self.start); - return maintain_call_binding(compressor.parent(), self, self.alternative); + return maintain_this_binding(compressor.parent(), self, self.alternative); } } var negated = cond[0].negate(compressor); diff --git a/lib/scope.js b/lib/scope.js index 20d9d730..ace25894 100644 --- a/lib/scope.js +++ b/lib/scope.js @@ -194,6 +194,11 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ } if (node instanceof AST_SymbolRef) { var name = node.name; + if (name == "eval" && tw.parent() instanceof AST_Call) { + for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) { + s.uses_eval = true; + } + } var sym = node.scope.find_variable(name); if (!sym) { var g; @@ -206,10 +211,6 @@ AST_Toplevel.DEFMETHOD("figure_out_scope", function(options){ globals.set(name, g); } node.thedef = g; - if (name == "eval" && tw.parent() instanceof AST_Call) { - for (var s = node.scope; s && !s.uses_eval; s = s.parent_scope) - s.uses_eval = true; - } if (func && name == "arguments") { func.uses_arguments = true; } diff --git a/test/compress/issue-782.js b/test/compress/issue-782.js index 80b1493c..2f72d1ab 100644 --- a/test/compress/issue-782.js +++ b/test/compress/issue-782.js @@ -1,10 +1,12 @@ remove_redundant_sequence_items: { options = { side_effects: true }; input: { + (0, 1, eval)(); (0, 1, logThis)(); (0, 1, _decorators.logThis)(); } expect: { + (0, eval)(); logThis(); (0, _decorators.logThis)(); } @@ -13,10 +15,12 @@ remove_redundant_sequence_items: { dont_remove_this_binding_sequence: { options = { side_effects: true }; input: { + (0, eval)(); (0, logThis)(); (0, _decorators.logThis)(); } expect: { + (0, eval)(); logThis(); (0, _decorators.logThis)(); } diff --git a/test/compress/issue-973.js b/test/compress/issue-973.js index f2d44010..0e040922 100644 --- a/test/compress/issue-973.js +++ b/test/compress/issue-973.js @@ -18,6 +18,11 @@ this_binding_conditionals: { (0 || a[b])(); (0 || 1 && a[b])(); (1 ? a[b] : 0)(); + + (1 && eval)(); + (0 || eval)(); + (0 || 1 && eval)(); + (1 ? eval : 0)(); } expect: { a(); @@ -34,6 +39,11 @@ this_binding_conditionals: { (0, a[b])(); (0, a[b])(); (0, a[b])(); + + (0, eval)(); + (0, eval)(); + (0, eval)(); + (0, eval)(); } } @@ -44,26 +54,43 @@ this_binding_collapse_vars: { input: { var c = a; c(); var d = a.b; d(); + var e = eval; e(); } expect: { a(); (0, a.b)(); + (0, eval)(); } } -eval_direct_calls: { +this_binding_side_effects: { options = { - side_effects: true, - collapse_vars: true - } + side_effects : true + }; input: { - (0, eval)(''); - - var fn = eval; - fn(''); + (function (foo) { + (0, foo)(); + (0, foo.bar)(); + (0, eval)('console.log(foo);'); + }()); + (function (foo) { + var eval = console; + (0, foo)(); + (0, foo.bar)(); + (0, eval)('console.log(foo);'); + }()); } expect: { - (0, eval)(''); - (0, eval)(''); + (function (foo) { + foo(); + (0, foo.bar)(); + (0, eval)('console.log(foo);'); + }()); + (function (foo) { + var eval = console; + foo(); + (0, foo.bar)(); + (0, eval)('console.log(foo);'); + }()); } } \ No newline at end of file diff --git a/test/compress/issue-976.js b/test/compress/issue-976.js new file mode 100644 index 00000000..dea30705 --- /dev/null +++ b/test/compress/issue-976.js @@ -0,0 +1,88 @@ +eval_collapse_vars: { + options = { + collapse_vars:true, sequences:false, properties:true, dead_code:true, conditionals:true, + comparisons:true, evaluate:true, booleans:true, loops:true, unused:true, hoist_funs:true, + keep_fargs:true, if_return:true, join_vars:true, cascade:true, side_effects:true + }; + input: { + function f1() { + var e = 7; + var s = "abcdef"; + var i = 2; + var eval = console.log.bind(console); + var x = s.charAt(i++); + var y = s.charAt(i++); + var z = s.charAt(i++); + eval(x, y, z, e); + } + function p1() { var a = foo(), b = bar(), eval = baz(); return a + b + eval; } + function p2() { var a = foo(), b = bar(), eval = baz; return a + b + eval(); } + (function f2(eval) { + var a = 2; + console.log(a - 5); + eval("console.log(a);"); + })(eval); + } + expect: { + function f1() { + var e = 7, + s = "abcdef", + i = 2, + eval = console.log.bind(console), + x = s.charAt(i++), + y = s.charAt(i++), + z = s.charAt(i++); + eval(x, y, z, e); + } + function p1() { return foo() + bar() + baz(); } + function p2() { var a = foo(), b = bar(), eval = baz; return a + b + eval(); } + (function f2(eval) { + var a = 2; + console.log(a - 5); + eval("console.log(a);"); + })(eval); + } +} + +eval_unused: { + options = { unused: true, keep_fargs: false }; + input: { + function f1(a, eval, c, d, e) { + return a('c') + eval; + } + function f2(a, b, c, d, e) { + return a + eval('c'); + } + function f3(a, eval, c, d, e) { + return a + eval('c'); + } + } + expect: { + function f1(a, eval) { + return a('c') + eval; + } + function f2(a, b, c, d, e) { + return a + eval('c'); + } + function f3(a, eval, c, d, e) { + return a + eval('c'); + } + } +} + +eval_mangle: { + mangle = { + }; + input: { + function f1(a, eval, c, d, e) { + return a('c') + eval; + } + function f2(a, b, c, d, e) { + return a + eval('c'); + } + function f3(a, eval, c, d, e) { + return a + eval('c'); + } + } + expect_exact: 'function f1(n,c,e,a,o){return n("c")+c}function f2(a,b,c,d,e){return a+eval("c")}function f3(a,eval,c,d,e){return a+eval("c")}' +} -- 2.34.1