[Pkg-javascript-commits] [uglifyjs] 174/491: refactor `throw` usage within `compress` (#2193)

Jonas Smedegaard dr at jones.dk
Wed Feb 14 19:51:32 UTC 2018


This is an automated email from the git hooks/post-receive script.

js pushed a commit to annotated tag debian/3.3.10-1
in repository uglifyjs.

commit 20e4f8277fc69b275600770c5d41fa1b75b9984f
Author: Alex Lam S.L <alexlamsl at gmail.com>
Date:   Mon Jul 3 02:10:56 2017 +0800

    refactor `throw` usage within `compress` (#2193)
    
    Eliminate exceptional constructs from normal control flow.
---
 lib/compress.js | 205 ++++++++++++++++++++++++++++++--------------------------
 1 file changed, 111 insertions(+), 94 deletions(-)

diff --git a/lib/compress.js b/lib/compress.js
index eb3ba75..db45c56 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -1198,21 +1198,21 @@ merge(Compressor.prototype, {
             for (var i = 0, len = statements.length; i < len; i++) {
                 var stat = statements[i];
                 if (prev) {
-                    if (stat instanceof AST_For) {
-                        try {
-                            prev.body.walk(new TreeWalker(function(node){
-                                if (node instanceof AST_Binary && node.operator == "in")
-                                    throw cons_seq;
-                            }));
-                            if (stat.init && !(stat.init instanceof AST_Definitions)) {
-                                stat.init = cons_seq(stat.init);
+                    if (stat instanceof AST_For && !(stat.init instanceof AST_Definitions)) {
+                        var abort = false;
+                        prev.body.walk(new TreeWalker(function(node) {
+                            if (abort) return true;
+                            if (node instanceof AST_Binary && node.operator == "in") {
+                                abort = true;
+                                return true;
                             }
-                            else if (!stat.init) {
+                        }));
+                        if (!abort) {
+                            if (stat.init) stat.init = cons_seq(stat.init);
+                            else {
                                 stat.init = prev.body.drop_side_effect_free(compressor);
                                 n--;
                             }
-                        } catch(ex) {
-                            if (ex !== cons_seq) throw ex;
                         }
                     }
                     else if (stat instanceof AST_If) {
@@ -1532,13 +1532,8 @@ merge(Compressor.prototype, {
         // descendant of AST_Node.
         AST_Node.DEFMETHOD("evaluate", function(compressor){
             if (!compressor.option("evaluate")) return this;
-            try {
-                var val = this._eval(compressor);
-                return !val || val instanceof RegExp || typeof val != "object" ? val : this;
-            } catch(ex) {
-                if (ex !== def) throw ex;
-                return this;
-            }
+            var val = this._eval(compressor);
+            return !val || val instanceof RegExp || typeof val != "object" ? val : this;
         });
         var unaryPrefix = makePredicate("! ~ - + void");
         AST_Node.DEFMETHOD("is_constant", function(){
@@ -1584,27 +1579,28 @@ merge(Compressor.prototype, {
         def(AST_Statement, function(){
             throw new Error(string_template("Cannot evaluate a statement [{file}:{line},{col}]", this.start));
         });
-        def(AST_Lambda, function(){
-            throw def;
-        });
+        def(AST_Lambda, return_this);
         function ev(node, compressor) {
             if (!compressor) throw new Error("Compressor must be passed");
 
             return node._eval(compressor);
         };
-        def(AST_Node, function(){
-            throw def;          // not constant
-        });
+        def(AST_Node, return_this);
         def(AST_Constant, function(){
             return this.getValue();
         });
         def(AST_Array, function(compressor){
             if (compressor.option("unsafe")) {
-                return this.elements.map(function(element) {
-                    return ev(element, compressor);
-                });
+                var elements = [];
+                for (var i = 0, len = this.elements.length; i < len; i++) {
+                    var element = this.elements[i];
+                    var value = ev(element, compressor);
+                    if (element === value) return this;
+                    elements.push(value);
+                }
+                return elements;
             }
-            throw def;
+            return this;
         });
         def(AST_Object, function(compressor){
             if (compressor.option("unsafe")) {
@@ -1616,105 +1612,121 @@ merge(Compressor.prototype, {
                         key = key.name;
                     } else if (key instanceof AST_Node) {
                         key = ev(key, compressor);
+                        if (key === prop.key) return this;
                     }
                     if (typeof Object.prototype[key] === 'function') {
-                        throw def;
+                        return this;
                     }
                     val[key] = ev(prop.value, compressor);
+                    if (val[key] === prop.value) return this;
                 }
                 return val;
             }
-            throw def;
+            return this;
         });
         def(AST_UnaryPrefix, function(compressor){
-            var e = this.expression;
+            // Function would be evaluated to an array and so typeof would
+            // incorrectly return 'object'. Hence making is a special case.
+            if (this.operator == "typeof" && this.expression instanceof AST_Function) {
+                return typeof function(){};
+            }
+            var e = ev(this.expression, compressor);
+            if (e === this.expression) return this;
             switch (this.operator) {
-              case "!": return !ev(e, compressor);
+              case "!": return !e;
               case "typeof":
-                // Function would be evaluated to an array and so typeof would
-                // incorrectly return 'object'. Hence making is a special case.
-                if (e instanceof AST_Function) return typeof function(){};
-
-                e = ev(e, compressor);
-
                 // typeof <RegExp> returns "object" or "function" on different platforms
                 // so cannot evaluate reliably
-                if (e instanceof RegExp) throw def;
-
+                if (e instanceof RegExp) return this;
                 return typeof e;
-              case "void": return void ev(e, compressor);
-              case "~": return ~ev(e, compressor);
-              case "-": return -ev(e, compressor);
-              case "+": return +ev(e, compressor);
+              case "void": return void e;
+              case "~": return ~e;
+              case "-": return -e;
+              case "+": return +e;
             }
-            throw def;
+            return this;
         });
-        def(AST_Binary, function(c){
-            var left = this.left, right = this.right, result;
+        def(AST_Binary, function(compressor){
+            var left = ev(this.left, compressor);
+            if (left === this.left) return this;
+            var right = ev(this.right, compressor);
+            if (right === this.right) return this;
+            var result;
             switch (this.operator) {
-              case "&&"  : result = ev(left, c) &&  ev(right, c); break;
-              case "||"  : result = ev(left, c) ||  ev(right, c); break;
-              case "|"   : result = ev(left, c) |   ev(right, c); break;
-              case "&"   : result = ev(left, c) &   ev(right, c); break;
-              case "^"   : result = ev(left, c) ^   ev(right, c); break;
-              case "+"   : result = ev(left, c) +   ev(right, c); break;
-              case "*"   : result = ev(left, c) *   ev(right, c); break;
-              case "/"   : result = ev(left, c) /   ev(right, c); break;
-              case "%"   : result = ev(left, c) %   ev(right, c); break;
-              case "-"   : result = ev(left, c) -   ev(right, c); break;
-              case "<<"  : result = ev(left, c) <<  ev(right, c); break;
-              case ">>"  : result = ev(left, c) >>  ev(right, c); break;
-              case ">>>" : result = ev(left, c) >>> ev(right, c); break;
-              case "=="  : result = ev(left, c) ==  ev(right, c); break;
-              case "===" : result = ev(left, c) === ev(right, c); break;
-              case "!="  : result = ev(left, c) !=  ev(right, c); break;
-              case "!==" : result = ev(left, c) !== ev(right, c); break;
-              case "<"   : result = ev(left, c) <   ev(right, c); break;
-              case "<="  : result = ev(left, c) <=  ev(right, c); break;
-              case ">"   : result = ev(left, c) >   ev(right, c); break;
-              case ">="  : result = ev(left, c) >=  ev(right, c); break;
+              case "&&"  : result = left &&  right; break;
+              case "||"  : result = left ||  right; break;
+              case "|"   : result = left |   right; break;
+              case "&"   : result = left &   right; break;
+              case "^"   : result = left ^   right; break;
+              case "+"   : result = left +   right; break;
+              case "*"   : result = left *   right; break;
+              case "/"   : result = left /   right; break;
+              case "%"   : result = left %   right; break;
+              case "-"   : result = left -   right; break;
+              case "<<"  : result = left <<  right; break;
+              case ">>"  : result = left >>  right; break;
+              case ">>>" : result = left >>> right; break;
+              case "=="  : result = left ==  right; break;
+              case "===" : result = left === right; break;
+              case "!="  : result = left !=  right; break;
+              case "!==" : result = left !== right; break;
+              case "<"   : result = left <   right; break;
+              case "<="  : result = left <=  right; break;
+              case ">"   : result = left >   right; break;
+              case ">="  : result = left >=  right; break;
               default:
-                  throw def;
+                  return this;
             }
-            if (isNaN(result) && c.find_parent(AST_With)) {
+            if (isNaN(result) && compressor.find_parent(AST_With)) {
                 // leave original expression as is
-                throw def;
+                return this;
             }
             return result;
         });
         def(AST_Conditional, function(compressor){
-            return ev(this.condition, compressor)
-                ? ev(this.consequent, compressor)
-                : ev(this.alternative, compressor);
+            var condition = ev(this.condition, compressor);
+            if (condition === this.condition) return this;
+            var node = condition ? this.consequent : this.alternative;
+            var value = ev(node, compressor);
+            return value === node ? this : value;
         });
         def(AST_SymbolRef, function(compressor){
-            if (!compressor.option("reduce_vars") || this._evaluating) throw def;
-            this._evaluating = true;
-            try {
-                var fixed = this.fixed_value();
-                if (!fixed) throw def;
-                var value = ev(fixed, compressor);
-                if (!HOP(fixed, "_eval")) fixed._eval = function() {
-                    return value;
-                };
-                if (value && typeof value == "object" && this.definition().escaped) throw def;
+            if (!compressor.option("reduce_vars")) return this;
+            this._eval = return_this;
+            var fixed = this.fixed_value();
+            if (!fixed) {
+                delete this._eval;
+                return this;
+            }
+            var value = ev(fixed, compressor);
+            if (value === fixed) {
+                delete this._eval;
+                return this;
+            }
+            if (!HOP(fixed, "_eval")) fixed._eval = function() {
                 return value;
-            } finally {
-                this._evaluating = false;
+            };
+            if (value && typeof value == "object" && this.definition().escaped) {
+                delete this._eval;
+                return this;
             }
+            this._eval = fixed._eval;
+            return value;
         });
         def(AST_PropAccess, function(compressor){
             if (compressor.option("unsafe")) {
                 var key = this.property;
                 if (key instanceof AST_Node) {
                     key = ev(key, compressor);
+                    if (key === this.property) return this;
                 }
                 var val = ev(this.expression, compressor);
+                if (val === this.expression) return this;
                 if (val && HOP(val, key)) {
                     return val[key];
                 }
             }
-            throw def;
+            return this;
         });
         var object_fns = [
             'constructor',
@@ -1760,19 +1772,24 @@ merge(Compressor.prototype, {
                 var key = exp.property;
                 if (key instanceof AST_Node) {
                     key = ev(key, compressor);
+                    if (key === exp.property) return this;
                 }
                 var val = ev(exp.expression, compressor);
+                if (val === exp.expression) return this;
                 if ((val && native_fns[val.constructor.name] || return_false)(key)) {
-                    return val[key].apply(val, this.args.map(function(arg) {
-                        return ev(arg, compressor);
-                    }));
+                    var args = [];
+                    for (var i = 0, len = this.args.length; i < len; i++) {
+                        var arg = this.args[i];
+                        var value = ev(arg, compressor);
+                        if (arg === value) return this;
+                        args.push(value);
+                    }
+                    return val[key].apply(val, args);
                 }
             }
-            throw def;
-        });
-        def(AST_New, function(compressor){
-            throw def;
+            return this;
         });
+        def(AST_New, return_this);
     })(function(node, func){
         node.DEFMETHOD("_eval", func);
     });

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/uglifyjs.git



More information about the Pkg-javascript-commits mailing list