Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.x] convert AST_Seq from binary tree to array #1460

Merged
merged 1 commit into from
Apr 12, 2017

Conversation

alexlamsl
Copy link
Collaborator

@alexlamsl alexlamsl changed the title convert AST_Seq from binary tree to array [WIP][BC] convert AST_Seq from binary tree to array Feb 2, 2017
@alexlamsl
Copy link
Collaborator Author

master

https://code.jquery.com/jquery-3.1.1.js
Timing information (compressed 1 files):
- parse: 0.105s
- scope: 0.297s
- squeeze: 2.019s
- mangle: 0.031s
- generate: 0.101s


https://code.angularjs.org/1.6.1/angular.js
Timing information (compressed 1 files):
- parse: 0.236s
- scope: 0.556s
- squeeze: 2.889s
- mangle: 0.065s
- generate: 0.201s


https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js
Timing information (compressed 1 files):
- parse: 0.463s
- scope: 1.496s
- squeeze: 53.221s
- mangle: 0.144s
- generate: 0.550s


https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js
Timing information (compressed 1 files):
- parse: 0.041s
- scope: 0.103s
- squeeze: 0.480s
- mangle: 0.013s
- generate: 0.036s

This PR

https://code.jquery.com/jquery-3.1.1.js
Timing information (compressed 1 files):
- parse: 0.106s
- scope: 0.289s
- squeeze: 1.777s
- mangle: 0.042s
- generate: 0.114s


https://code.angularjs.org/1.6.1/angular.js
Timing information (compressed 1 files):
- parse: 0.223s
- scope: 0.576s
- squeeze: 2.859s
- mangle: 0.066s
- generate: 0.190s


https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js
Timing information (compressed 1 files):
- parse: 0.461s
- scope: 1.529s
- squeeze: 53.390s
- mangle: 0.145s
- generate: 0.524s


https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js
Timing information (compressed 1 files):
- parse: 0.039s
- scope: 0.118s
- squeeze: 0.485s
- mangle: 0.011s
- generate: 0.037s

@kzc
Copy link
Contributor

kzc commented Feb 2, 2017

Wow! Nicely done.

I trust that it works. I'm not going to pretend to review it.

I'd suggest to change the AST node name to something other than AST_Seq since it's a departure from the old AST. AST_Sequence, perhaps?

You'd likely have to make an equivalent patch for the harmony branch since it's unlikely to merge cleanly. Would be best to wait for the PR queue to emptied and for a release made before rebasing.

@kzc
Copy link
Contributor

kzc commented Feb 2, 2017

@alexlamsl If I'm interpreting your numbers correctly, there is no speed improvement?

@alexlamsl
Copy link
Collaborator Author

@kzc jQuery seems to benefit from this change, whilst other libraries do not suffer noticeably from any performance regressions.

I need to dig out #1145 (comment) to test against this PR next, but let me take care of run-test.js as per your request first 😜

@kzc
Copy link
Contributor

kzc commented Feb 2, 2017

Didn't look at the PR in too much detail, but are there any asserts preventing a sequence array length of 1?

@alexlamsl
Copy link
Collaborator Author

Not at the moment, no. I'm thinking about how to consolidate all the constructions in order to perform the check reliably.

@alexlamsl
Copy link
Collaborator Author

Not only just length > 1, but also none of the elements being AST_Seq as well.

lib/ast.js Outdated
if (this.cdr) this.cdr._walk(visitor);
this.expressions.forEach(function(expression) {
expression._walk(visitor);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if replacingforEach with traditional for loops for all array walkers would be faster.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for-loop

https://code.jquery.com/jquery-3.1.1.js
Timing information (compressed 1 files):
- parse: 0.105s
- scope: 0.300s
- squeeze: 1.772s
- mangle: 0.035s
- generate: 0.104s


https://code.angularjs.org/1.6.1/angular.js
Timing information (compressed 1 files):
- parse: 0.223s
- scope: 0.556s
- squeeze: 2.789s
- mangle: 0.065s
- generate: 0.195s


https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js
Timing information (compressed 1 files):
- parse: 0.489s
- scope: 1.482s
- squeeze: 52.380s
- mangle: 0.141s
- generate: 0.548s


https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js
Timing information (compressed 1 files):
- parse: 0.039s
- scope: 0.101s
- squeeze: 0.475s
- mangle: 0.011s
- generate: 0.036s

Not much difference, I'm afraid... 😥

Copy link
Contributor

@kzc kzc Feb 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It saved a second on math.js compress. That's significant.

You just replaced that single forEach or all of them in that file?

Copy link
Contributor

@kzc kzc Feb 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By the way, timings for all operations can be collapsed into a single wall clock number. We're comparing apples with apples - old program vs. new program with same inputs and options.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just this single one. And sorry for misreading the numbers- I thought it was 53 as before!

I'll have a look at all the forEach()s after filing the next PR...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's so much easier when you code and I just make suggestions. :-)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's so much easier when you code and I just make suggestions. :-)

works for me 😎

@alexlamsl
Copy link
Collaborator Author

Replaced all occurrences of [].forEach() in ast.js so far...

https://code.jquery.com/jquery-3.1.1.js
Timing information (compressed 1 files):
- parse: 0.105s
- scope: 0.292s
- squeeze: 1.798s
- mangle: 0.031s
- generate: 0.105s


https://code.angularjs.org/1.6.1/angular.js
Timing information (compressed 1 files):
- parse: 0.230s
- scope: 0.558s
- squeeze: 2.742s
- mangle: 0.063s
- generate: 0.183s


https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js
Timing information (compressed 1 files):
- parse: 0.492s
- scope: 1.419s
- squeeze: 49.142s
- mangle: 0.136s
- generate: 0.523s


https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js
Timing information (compressed 1 files):
- parse: 0.040s
- scope: 0.099s
- squeeze: 0.475s
- mangle: 0.011s
- generate: 0.037s

So even angular.js is starting to get noticeably faster. By the way, this is --stats from bin\uglifyjs as I was too lazy to time stuff myself 😝

@kzc
Copy link
Contributor

kzc commented Feb 2, 2017

Does the acronym [BC] mean "Binary Compatibility" change or "Breaking Change" or other?

@alexlamsl
Copy link
Collaborator Author

Breaking Change - or should I put in [3.x] so it's easier to understand?

@alexlamsl
Copy link
Collaborator Author

I'd be grateful if you can run node test\benchmark.js on your system to validate these timings. I'm on node-chakracore and presumably you are on the standard V8.

@alexlamsl alexlamsl changed the title [WIP][BC] convert AST_Seq from binary tree to array [WIP][3.x] convert AST_Seq from binary tree to array Feb 2, 2017
@kzc
Copy link
Contributor

kzc commented Feb 2, 2017

Replaced all occurrences of [].forEach() in ast.js so far...
So even angular.js is starting to get noticeably faster

From your stats, compress appears to be roughly 5% to 10% faster with that trivial forEach -> for change - good stuff.

I should have asked you to change it sooner! ;-)

@alexlamsl
Copy link
Collaborator Author

Let's check V8 and/or SpiderMonkey before confirming this 👻

(Re-opening against Travis CI time-out.)

@alexlamsl alexlamsl closed this Feb 2, 2017
@alexlamsl alexlamsl reopened this Feb 2, 2017
@kzc
Copy link
Contributor

kzc commented Feb 2, 2017

test/benchmark.js timings using node v6.9.0 on Mac:

master:

https://code.jquery.com/jquery-3.1.1.js
Timing information (compressed 1 files):
- parse: 0.152s
- scope: 0.300s
- squeeze: 1.777s
- mangle: 0.026s
- generate: 0.091s

https://code.angularjs.org/1.6.1/angular.js
Timing information (compressed 1 files):
- parse: 0.334s
- scope: 0.471s
- squeeze: 2.414s
- mangle: 0.050s
- generate: 0.152s

https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js
Timing information (compressed 1 files):
- parse: 0.580s
- scope: 1.100s
- squeeze: 31.003s
- mangle: 0.080s
- generate: 0.450s

https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js
Timing information (compressed 1 files):
- parse: 0.079s
- scope: 0.107s
- squeeze: 0.477s
- mangle: 0.017s
- generate: 0.043s

this PR with forEach to for change 02c5ca6:

https://code.jquery.com/jquery-3.1.1.js
Timing information (compressed 1 files):
- parse: 0.164s
- scope: 0.265s
- squeeze: 1.486s
- mangle: 0.024s
- generate: 0.089s

https://code.angularjs.org/1.6.1/angular.js
Timing information (compressed 1 files):
- parse: 0.312s
- scope: 0.479s
- squeeze: 2.326s
- mangle: 0.048s
- generate: 0.160s

https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js
Timing information (compressed 1 files):
- parse: 0.579s
- scope: 1.160s
- squeeze: 27.843s
- mangle: 0.075s
- generate: 0.370s

https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js
Timing information (compressed 1 files):
- parse: 0.073s
- scope: 0.103s
- squeeze: 0.472s
- mangle: 0.008s
- generate: 0.045s

math.js compress is 10% quicker.

@alexlamsl
Copy link
Collaborator Author

Cool! Let me finish off compress.js and output.js and test again 😉

@kzc
Copy link
Contributor

kzc commented Feb 2, 2017

uglify-js@2.7.5:

$ time uglifyjs math.js -m -c warnings=false | shasum
2b42f6939f4bc5f20350d74e5c385a535d1876fa  -

real	0m12.760s
user	0m13.298s
sys	0m0.164s

This PR (02c5ca6):

$ time bin/uglifyjs math.js -m -c warnings=false | shasum
2b42f6939f4bc5f20350d74e5c385a535d1876fa  -

real	0m11.868s
user	0m12.273s
sys	0m0.163s

Same output.
7% faster.

@kzc
Copy link
Contributor

kzc commented Feb 2, 2017

@alexlamsl Can you try timing that pathological massive sequence test case against master and this PR?

@alexlamsl
Copy link
Collaborator Author

Will do once I sort out this curious case of https://github.com/mishoo/UglifyJS2/blob/0610c020b1544820be9898a285ab6c9066490552/lib/compress.js#L2080

Replacing it with a for-loop:

for (var i = 0, len = this.definitions; i < len; i++) {
    this.definitions[i].value = null;
}

... gives me test failures. I must be staring at something obvious,,,.

@kzc
Copy link
Contributor

kzc commented Feb 2, 2017

len = this.definitions should be len = this.definitions.length

@alexlamsl
Copy link
Collaborator Author

@kzc saves my day!

@kzc
Copy link
Contributor

kzc commented Feb 2, 2017

You write a thousand line PR and I fix a typo - we're even.

@kzc
Copy link
Contributor

kzc commented Feb 2, 2017

Fantastic work, @alexlamsl.

I'm going to do some non-uglify work now.

@alexlamsl
Copy link
Collaborator Author

@kzc speak soon - it's 4am so I should better catch some sleep as well

@alexlamsl
Copy link
Collaborator Author

As of 18a7ace

https://code.jquery.com/jquery-3.1.1.js
Timing information (compressed 1 files):
- parse: 0.109s
- scope: 0.294s
- squeeze: 1.751s
- mangle: 0.034s
- generate: 0.116s


https://code.angularjs.org/1.6.1/angular.js
Timing information (compressed 1 files):
- parse: 0.225s
- scope: 0.535s
- squeeze: 2.724s
- mangle: 0.063s
- generate: 0.178s


https://cdnjs.cloudflare.com/ajax/libs/mathjs/3.9.0/math.js
Timing information (compressed 1 files):
- parse: 0.461s
- scope: 1.415s
- squeeze: 48.247s
- mangle: 0.134s
- generate: 0.509s


https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.js
Timing information (compressed 1 files):
- parse: 0.040s
- scope: 0.100s
- squeeze: 0.477s
- mangle: 0.011s
- generate: 0.038s

@alexlamsl alexlamsl force-pushed the ast_seq branch 2 times, most recently from b5af664 to f767e64 Compare April 8, 2017 19:21
- rename AST_Seq to AST_Sequence
- raise default sequences_limit from 200 to 800
@alexlamsl
Copy link
Collaborator Author

@1.8MFuzz

var a = 100, b = 10, c = 0;

var arguments = (c = c + 1) + (1 === 1 ? a : b);

var a_1 = function a_1() {
    c = c + 1;
    b <<= a;
    switch ((c = c + 1) + [ new function() {
        ({
            "": (c = c + 1) + [ (c = 1 + c, (null + ([ , 0 ].length === 2) | 0 < 24..toString()) === (a_1 && (a_1[(c = c + 1) + ((c = 1 + c,
            ("bar" <= "foo", 5 != "number") <= (1 <= [ , 0 ][1] < (-5 == 5))) || 0).toString()[(c = 1 + c,
            "" >= 23..toString() !== (23..toString(), [ , 0 ].length === 2) == ("foo" ^ 24..toString() | [] << [ , 0 ][1]))]] /= ("bar" ^ 1) >> (/[a2][^e]+$/ || null)))) ][a++],
            in: 0 === 1 ? a : b,
            NaN: a++ + ++b
        });
        return b = a;
    }() ]) {
      case delete (a_1 == (24..toString() - NaN == (-0 == null) && true >>> undefined & 25 !== 5)):
        c = c + 1;
        --b + (0 === 1 ? a : b);
        break;

      case "bar":
        switch (([] == 0) - ("bar" && []) ^ (Infinity & {}) > (1 ^ "")) {
          case 1 === 1 ? a : b:
            c = c + 1;
            try {
                {
                    var a_1_2 = function f0(Math, b_1, foo_2) {
                        c = 1 + c, (-2 && -1) << ([ , 0 ][1] === 23..toString()) || ({} || -1) & ~true;
                        c = 1 + c, ((a_1 && (a_1.undefined = 23..toString() === [])) == ("object" ^ "")) >>> ([ , 0 ].length === 2 == -5 & true === "undefined");
                    }(a++ + b++);
                }
            } catch (b_1) {
                try {
                    return;
                } catch (c) {
                    c = 1 + c, (25 > {}) >> (22 > 3) ^ undefined >> "undefined" === (a_1 >>>= -0 ^ 25);
                    c = 1 + c, (-5 * -3 ^ (undefined || -5)) <= (("foo" && 3) < 3 % 23..toString());
                }
                c = c + 1;
            }
            break;

          default:
            void b;

          case b |= a:
            {
                var brake20 = 5;
                do {
                    if ([ , (c = 1 + c, (c = c + 1, "number") > (c = c + 1, Infinity) >= (1 ^ 25) << (a_1 == ([ , 0 ][1] ^ -5))), (c = 1 + c,
                    a_1 == ((24..toString(), 22) !== "" <= "bar" | (-5 || Infinity) % (4 != Infinity))), (c = 1 + c,
                    ("undefined" >> 3, "bar" ^ [ , 0 ][1]) * (23..toString() * 0 >= ([ , 0 ].length === 2 != -1))) ][--b + +b]) {} else {
                        var a = a++ + ((c = 1 + c, (bar_2 && (bar_2.in *= "function" << -3 & NaN == 22)) << (({} != "bar") > ("foo",
                        null))) || a || 3).toString(), b_1 = a_1 && a_1.Infinity;
                    }
                } while (/[abc4]/.test((a++ + (++b || 6).toString()[--b + ((c = 1 + c, b_1 && (b_1[delete (a_1 && (a_1[a--] = (undefined > -3) * (NaN,
                {}) === (-2 << 23..toString(), 3, /[a2][^e]+$/)))] = "number" & undefined ^ (c = c + 1,
                "foo") | (5 || -0) << (4, 25))) || 4).toString()[(c = 1 + c, b_1 && b_1.foo !== ("bar" != NaN) < ("bar" & "function") && undefined % ([ , 0 ].length === 2) - undefined % "bar")]] || b || 5).toString()) && --brake20 > 0);
            }
            break;

          case (c = c + 1) + (b = a):
            {
                var brake24 = 5;
                do {
                    return (a_1 && (a_1.NaN = NaN == "") || [ , 0 ][1] >>> 5) + (bar_2 && (bar_2[--b + (a_1 && a_1[(c = 1 + c,
                    ("function" === null !== (c = c + 1, 38..toString())) < ("undefined" / [] === 24..toString() % -5))])] += (22 ^ 1) < (38..toString() || 38..toString())));
                } while (a++ + ++a && --brake24 > 0);
            }
            try {
                switch ((c = c + 1) + (1 === 1 ? a : b)) {
                  case [ ,  ].c:
                    ;
                    for (var brake29 = 5; (c = 1 + c, ((a_1_2 && (a_1_2.length = [] != -2)) >= (([ , 0 ].length === 2) <= ([ , 0 ].length === 2))) - ((-2 >= 4) - (c = c + 1,
                    4))) && brake29 > 0; --brake29) {
                        c = 1 + c, a_1 && (a_1.in <<= (null !== -4 ^ 1 - 25) >>> (a_1 %= true < "function") * ("bar" && undefined));
                    }
                    break;

                  default:
                  case (c = c + 1) + !function a() {}():
                    c = c + 1;
                    {
                    }
                    break;

                  case (c = c + 1) + {
                        Infinity: (c = 1 + c, a_1 && (a_1.foo = (a_1_2 !== (-1 / 0 | -0 > [ , 0 ][1])) >> ((a_1 && (a_1.null = ([ , 0 ].length === 2) < "undefined")) ^ "function" >> undefined))),
                        foo: (c = 1 + c, (-1 != "bar") < (a_1 && (a_1.c = (-5, "function"))) >= ("" >= "function" && (false,
                        22))),
                        NaN: (c = 1 + c, (("bar" === "number") <= undefined / "bar") >> ("function" === "object") % (-5 == 22))
                    }.NaN:
                    c = c + 1;
                    break;
                }
            } catch (foo_2) {
                {
                    c = 1 + c, (bar_2 && (bar_2[--b + [ (c = 1 + c, (NaN === 38..toString() ^ 3 <= -1) < (-3 !== "foo" === /[a2][^e]+$/ << -1)), (c = 1 + c,
                    (-4 + "" < (null > -0)) >> ("object" != "undefined") - (5 >> ([ , 0 ].length === 2))) ].b] ^= (bar_2 != (3 !== 4)) > (-1 || false))) | (24..toString() | -5) !== {} + 1;
                    c = 1 + c, (null / "foo" > Infinity % null) % (c = c + 1, -0 & 23..toString());
                }
                {
                    var brake37 = 5;
                    do {
                        for (var brake38 = 5; (c = 1 + c, (a_1_2 = "" / -3) > (bar_2 && (bar_2.c >>= 2 >>> -2)) ^ ("function" !== true) * (Infinity >= "")) && brake38 > 0; --brake38) {
                            c = 1 + c, a_1_2 && (a_1_2[4] = ("bar" >= {}) >> "number" + "function" < (23..toString() != 38..toString()) / (c = c + 1,
                            {}));
                        }
                    } while (a++ + /[abc4]/.test(((c = 1 + c, (c = c + 1, {}) / (1 << []) < ((c = c + 1,
                    5) >= (25 && NaN))) || b || 5).toString()) && --brake37 > 0);
                }
            }
            break;
        }
        if ([]) {
            return;
        } else {
            try {
                b--;
            } catch (arguments_1) {
                {
                    {
                        var brake45 = 5;
                        while ((c = 1 + c, (4 - 25 <= ("foo" && undefined)) / ("bar" - [] || 38..toString() == -4)) && --brake45 > 0) {
                            c = 1 + c, ("foo" | -2 | ("number", 24..toString())) > ([] * Infinity === ("object" | null));
                        }
                    }
                }
                switch (a++ + typeof --a) {
                  default:
                  case --b + (b != a):
                    {
                        return;
                        c = 1 + c, (c = c + 1, NaN == 0) & (38..toString() !== 5) <= ([] & NaN);
                    }
                    switch (c = 1 + c, c = c + 1, null >> [] <= ({} | "")) {
                      default:
                        ;

                      case c = 1 + c, a_1_2 && (a_1_2.a = ("foo" / true ^ 0 != 0) > ({} !== {} ^ ("number" ^ NaN))):
                        ;
                        break;

                      case c = 1 + c, (-2 != 23..toString() === 24..toString() >>> 25) > (/[a2][^e]+$/ === "function" | "number" ^ 1):
                        ;
                        break;

                      case c = 1 + c, c = c + 1, "number" & [] | "bar" > "number":
                        ;
                        break;
                    }
                    break;

                  case -(((c = c + 1, -0) ^ [ , 0 ][1] == 38..toString()) & (null + true) % (2 | 23..toString())):
                    {
                    }
                    switch (c = 1 + c, ((38..toString() >= "foo") >> (38..toString() <= null)) + /[a2][^e]+$/ % 1 / (1 == "foo")) {
                      case c = 1 + c, (b_1 = -2 << 1) - (4 >> 0) == - -5 <= (3 !== "bar"):
                        ;
                        break;

                      case c = 1 + c, c = c + 1, (Infinity >> {}) % delete 1:
                        ;
                        break;

                      default:
                        ;

                      case c = 1 + c, c = c + 1, 1 >= -1 && -2 === 25:
                        ;
                    }
                    break;

                  case --b + [].undefined:
                    try {
                        c = 1 + c, (-0 ^ "foo") >= (arguments_1 && (arguments_1.c %= /[a2][^e]+$/ < [ , 0 ][1])) < ([ , 0 ].length === 2 & -0) - (4 ^ -3);
                    } catch (bar_2_1) {
                    } finally {
                    }
                    break;
                }
            } finally {
                {
                    if (c = 1 + c, (2 % "undefined" & (a_1 && (a_1.c |= NaN < "object"))) - ([] == 4 & (22 || "object"))) {
                        c = 1 + c, (22 != 23..toString() != 3 / 5) % (-4 << {} <= (4 < 2));
                    }
                    {
                        var brake57 = 5;
                        while ((c = 1 + c, ("number" ^ "foo") != (-3 != -1), 2 * true >>> true - []) && --brake57 > 0) {
                            c = 1 + c, ((25 <= false) << (-0 && -0)) * (([ , 0 ][1] < 2) % (Infinity && "foo"));
                        }
                    }
                    {
                        return;
                        c = 1 + c, 5 >> -2 ^ "undefined" >> true ^ (-0 <= 1 && (23..toString() && 25));
                    }
                    c = 1 + c, c = c + 1, {} !== "" && 24..toString() > 5;
                }
                {
                }
            }
        }
        break;

      case --b + (a++ + (b = a)):
        c = c + 1;
        c = c + 1;
        break;

      case a++ + new function() {
            return [ +(((0 != []) > (-1 && true)) / ((1 | -5) - (a_1_2 <<= true < undefined))), a++ + (0 === 1 ? a : b), (c = c + 1) + b--, , 1 === 1 ? a : b ];
        }():
        {
            var a_2 = function f1() {
                function f2(bar, bar, bar_2_1) {
                    c = 1 + c, (Infinity >= "undefined") * (5 - "object") != (Infinity > -4 & "number" - ([ , 0 ].length === 2));
                    c = 1 + c, ("number" != "number" | (a_1_2 && (a_1_2[(c = 1 + c, (23..toString() || -4 || false << {}) % ((true - 24..toString()) / (3 ^ 25)))] /= /[a2][^e]+$/ || 0))) <= (c = c + 1,
                    -4 * -3);
                }
                var Math_2 = f2(/[a2][^e]+$/);
                function f3(b, arguments, bar_2_2) {
                    c = 1 + c, ("foo" < false) / (undefined | "") - ({} !== 22, void 3);
                    c = 1 + c, (void null | /[a2][^e]+$/ < []) != ("undefined" >>> 5 === (Infinity && 22));
                }
                var a_1_1 = f3(4);
            }(bar_2 && bar_2.undefined);
        }
        break;
    }
}(), bar_2 = new function() {
    return (c = c + 1) + void function a() {
        a++ + (b = a);
    }();
}();

console.log(null, a, b, c);
original result:
null 100 '[Function: __func_1__]' 10

uglified result:
null 100 '[Function: __func_0__]' 10

minify(options):
{ compress: { warnings: false },
  mangle: false,
  fromString: true }

Suspicious compress options:
  side_effects

Mostly likely this part:

var a_1 = function a_1() {
    ...
    switch (...) {
      case delete (a_1 == (24..toString() - NaN == (-0 == null) && true >>> undefined & 25 !== 5)):
...

which uglifies to:

... , a_1 = function a_1() {
    switch (...) {
      case 24..toString(), !0:
...

@kzc
Copy link
Contributor

kzc commented Apr 10, 2017

Same issue on master with this fuzz test case. Are you sure it's not a false positive with function expression and + ?

@alexlamsl
Copy link
Collaborator Author

Oops, I did forget to write that I think this is a false positive.

I'm just putting this sole case down here for record keeping, and to train myself for future job interviews by our uglify-js overlord.

@alexlamsl
Copy link
Collaborator Author

Specifically, a_1 == ... would call a_1.valueOf(), and a_1 is a function defined above.

@alexlamsl
Copy link
Collaborator Author

@2.4MFuzz - this one may be less innocent...

// original code
// (beautified)
var a = 100, b = 10, c = 0;

function f0(parseInt_1, b) {
    function f1(b_1, parseInt_2) {
        {
            var brake2 = 5;
            do {
                {
                    var bar_1 = function f2() {
                        c = 1 + c, parseInt_2 && (parseInt_2[--b + ((-2 || {}) << (-0 ^ NaN) >> (/[a2][^e]+$/ << [ , 0 ][1]) * -0)] <<= (3 >= undefined) * (22 / 4)),
                        (false && "bar") | 3 < -3;
                        c = 1 + c, (parseInt_2 = "undefined" && "foo") >> (2 > undefined) | (25 << -5) / ([ , 0 ].length === 2 & 3);
                    }(a++ + (c = 1 + c, parseInt_2 && parseInt_2.var != 22 << 4 << (-3 >> {}) > (undefined % 4 | -4 % "foo")));
                }
            } while ((-2 || Infinity) != {} * {} & ~"" + (parseInt_1 && (parseInt_1[(c = 1 + c,
            b_1 = (-3 ^ "object" ^ (true && 38..toString())) >>> ((3 != ([ , 0 ].length === 2)) < (22 <= 24..toString())))] >>= {} < 1)) && --brake2 > 0);
        }
    }
    var bar_2 = f1("object");
    function f3(b_2) {
        try {
            {
                var arguments_1 = function f4(a_1, foo_1, foo) {
                    c = 1 + c, ((c = c + 1, -3) === (2 || 4)) <= +(c = c + 1, 24..toString());
                    c = 1 + c, (c = c + 1, 0 && -2) ^ 3 + -1 < (38..toString() ^ 2);
                }(/[abc4]/.test(((c = 1 + c, void ("undefined" || NaN) + (2 > {} && "" / {})) || b || 5).toString()));
            }
        } catch (a_2) {
            var bar_2 = a++ + +((5 | -4 || "number" ^ [ , 0 ][1]) % ("foo" == 3 != (1 && 23..toString()))), foo = (c = c + 1) + (bar_2 && bar_2.undefined == ("function" % -4 ^ ("object" | -0)) - (parseInt_1 && (parseInt_1[(c = c + 1) + -((5 !== 23..toString()) >= 5 - /[a2][^e]+$/ !== ({},
            "object") << (null > [ , 0 ][1]))] >>>= -1 != {} & "number" != "number")));
            ((c = 1 + c, (/[a2][^e]+$/ != -3 || 5 ^ NaN) >>> (24..toString() <= -2 > (24..toString() < /[a2][^e]+$/))) || a || 3).toString();
        } finally {
            {
                var brake12 = 5;
                do {
                } while ({
                    foo: (c = 1 + c, ([ , 0 ][1] < "undefined" && -2 / -2) >>> ("number" ^ [ , 0 ][1] ^ (true ^ -5))),
                    3: (c = 1 + c, (-5 !== false) * (5 | [ , 0 ][1]) & (23..toString() / false ^ 23..toString() >> 1)),
                    NaN: (c = 1 + c, (([ , 0 ].length === 2 & -0) !== !undefined) % ([] >= {} <= (3 == 1))),
                    1.5: (c = 1 + c, null % /[a2][^e]+$/ - Infinity * "function" && (arguments_1 && arguments_1.Infinity != (-5 & undefined)) ^ (bar_2 *= {} | 25))
                }.b && --brake12 > 0);
            }
            {
                var brake14 = 5;
                do {
                    switch (c = 1 + c, (24..toString() % "undefined", 4 >> 2) <= ((24..toString() && null) > 5 >> "bar")) {
                      case c = 1 + c, (-5 + false) / (-3 <= ([ , 0 ].length === 2)) * ((bar_2 && (bar_2.foo = 24..toString() >>> true)) ^ 2 >>> "bar"):
                        ;
                        break;

                      case c = 1 + c, (-0 | "foo") != (5 === 1) !== ((undefined | 2) === 1 >= 24..toString()):
                        ;
                        break;

                      default:
                        ;

                      case c = 1 + c, (-2 === -4 ^ (5 ^ "bar")) * ((NaN ^ -4) === (true | 1)):
                        ;
                        break;
                    }
                } while (bar_2 && bar_2[(c = 1 + c, arguments_1 /= (parseInt_1 && (parseInt_1.NaN ^= "number" / "foo")) | "undefined" & -4 && true + true | {} + 0)] && --brake14 > 0);
            }
        }
        switch (--b + [ delete b, b === a, b-- ]) {
          case --b + delete (("" === undefined) >> -0 + -3 | (c = c + 1, Infinity ^ 4)):
            {
                var brake17 = 5;
                while (--b + (1 === 1 ? a : b) && --brake17 > 0) {}
            }
            c = c + 1;
            break;

          case (c = c + 1) + ((a++ + (b = a) || a || 3).toString() || 4).toString()[a++ + (1 === 1 ? a : b) ? a++ : +function b_2_1() {
            }()]:
            ;
            {
                c = 1 + c, parseInt_1 && parseInt_1[typeof arguments_1 == "object"] !== (arguments_1 && (arguments_1[(c = 1 + c,
                [] / -4 << (4 > 0) ^ ((b_2 %= -2 + 4) | (parseInt_1 && (parseInt_1.Infinity += 38..toString() !== 1))))] <<= null + -1)) * (null != "foo") % ({} / "undefined" / (3 === "bar"));
                c = 1 + c, NaN >> "foo" !== ("" & 23..toString()) == (23..toString() << "bar" ^ false !== null);
                c = 1 + c, 22 < "number" | {} / 1, (-1 && "object") % (-0 ^ 23..toString());
                c = 1 + c, c = c + 1, (0 >= 1) << ("foo" && -1);
            }
            break;

          case (c = c + 1) + a++:
            break;

          case a++ + b--:
            {
                var brake26 = 5;
                while (typeof (c = 1 + c, +(38..toString() == "number") < ([] ^ -4 | -0 << 0)) && --brake26 > 0) {
                }
            }
            {
                return;
                +((c = c + 1, arguments_1 = "function" === -0) || -(-2 != -4));
            }
            break;
        }
    }
    var c_1 = f3({}, 22);
    function f5(b_2) {
        function f6() {
            function f7() {
            }
            var Infinity_1 = f7(38..toString(), "bar");
            function f8(foo_1, c) {
            }
            var c_1_1 = f8(2, "number");
            function f9(bar, c_1_1) {
            }
            var c = f9(-4, []);
        }
        var c = f6();
    }
    var b_2 = f5("foo", false, 1);
    function f10(a_1) {
        function f11(Infinity_2, b_2, b_1) {
            c = 1 + c, c = c + 1, 4 === 2 != "object" + -2;
            c = 1 + c, (c = c + 1, "" >>> -2) == (-2 == -2) % ("undefined" !== /[a2][^e]+$/);
        }
        var b = f11({});
        function f12(undefined, foo) {
            function f13(b_1, b) {
            }
            var c_1 = f13("undefined", -0, 2);
        }
        var b_2 = f12();
        function f14() {
            function f15(Infinity_1) {
            }
            var bar = f15();
            function f16(c_1_1, bar_2) {
            }
            var foo_2 = f16();
        }
        var b_1 = f14();
        function f17(arguments, arguments_1, a) {
            function f18(c_2, Infinity_1) {
            }
            var b_2 = f18([ , 0 ][1]);
            function f19(c_1_1, Infinity) {
            }
            var a_1_1 = f19(-2, "number");
            function f20() {
            }
            var c = f20(-1, -3, "object");
            function f21(c_1, a, b_2) {
            }
            var b_2 = f21(22);
        }
        var a_2 = f17();
    }
    var b_1 = f10(Infinity, true, "");
    function f22() {
        if ((c = c + 1) + [ , !function() {
        }(), b != a ].undefined) {
            var brake33 = 5;
            do {
                {
                    var undefined_2 = function f23(bar, foo) {
                    }((c = 1 + c, (-1, -4) >> (b_2 && b_2.c == -4 < /[a2][^e]+$/), (undefined === Infinity) << "foo" + -0));
                }
            } while (++a && --brake33 > 0);
        } else {
            try {
                var NaN_1 = (c = c + 1) + [ (c = 1 + c, "undefined" < {} !== -3 / -1 == (parseInt_1 != (false === /[a2][^e]+$/) / (true == -3))), (c = 1 + c,
                (~"bar" || -4 && -4) << ((c_1 += (-1, "object")) & -2 !== -1)), (c = 1 + c, void (-1 < 0,
                -0 && 2)) ].b, foo = void function() {
                }();
            } finally {
                c = c + 1;
                {
                    return c = 1 + c, (0 >> "" | (null && "bar")) <= (undefined_2 && (undefined_2.undefined *= null << "function" >= (c_1 &= "foo" && true)));
                }
            }
        }
    }
    var bar_2 = f22("", 5);
}

var Math_1 = f0([], false, "function");

console.log(null, a, b, c);
// uglified code
// (beautified)
function f0(parseInt_1, b) {
    var c_1 = (function(b_1, parseInt_2) {
        var brake2 = 5;
        do {
            (function() {
                c = 1 + c, parseInt_2 && (parseInt_2[--b + (-2 >> -0 * (/[a2][^e]+$/ << [ , 0 ][1]))] <<= 0),
                c = 1 + c, parseInt_2 = "foo";
            })((a++, c = 1 + c, parseInt_2 && parseInt_2.var));
        } while (-2 != {} * {} & -1 + (parseInt_1 && (parseInt_1[(c = 1 + c, (-3 ^ 38..toString()) >>> ((3 != (2 === [ , 0 ].length)) < (22 <= 24..toString())))] >>= {} < 1)) && --brake2 > 0);
    }("object"), function(b_2) {
        try {
            var arguments_1 = function(a_1, foo_1, foo) {
                c = 1 + c, c += 1, c += 1, 24..toString(), c = 1 + c, c += 1, 38..toString();
            }(/[abc4]/.test((c = 1 + c, void 0 + (2 > {} && "" / {}) || b || 5).toString()));
        } catch (a_2) {
            var bar_2 = a++ + -3 % (0 != 23..toString());
            c += 1, bar_2 && (bar_2.undefined, parseInt_1 && (parseInt_1[(c += 1) + -((5 !== 23..toString()) >= NaN !== "object" << (null > [ , 0 ][1]))] >>>= -1 != {} & !1));
            (c = 1 + c, !0 >>> (24..toString() <= -2 > (24..toString() < /[a2][^e]+$/)) || a || 3).toString();
        } finally {
            var brake12 = 5;
            do {} while ({
                foo: (c = 1 + c, ([ , 0 ][1] < "undefined" && 1) >>> ("number" ^ [ , 0 ][1] ^ -6)),
                3: (c = 1 + c, !0 * (5 | [ , 0 ][1]) & (23..toString() / !1 ^ 23..toString() >> 1)),
                NaN: (c = 1 + c, (!0 !== (2 === [ , 0 ].length & -0)) % ([] >= {} <= !1)),
                1.5: (c = 1 + c, NaN)
            }.b && --brake12 > 0);
            var brake14 = 5;
            do {
                switch (c = 1 + c, 24..toString(), 1 <= ((24..toString() && null) > 5)) {
                  case c = 1 + c, -5 / (-3 <= (2 === [ , 0 ].length)) * (2 ^ (bar_2 && (bar_2.foo = 24..toString() >>> !0))):
                  case c = 1 + c, !1 != (2 === 1 >= 24..toString()):
                    break;

                  default:
                  case c = 1 + c, 0:
                }
            } while (bar_2 && bar_2[(c = 1 + c, arguments_1 /= 0 | (parseInt_1 && (parseInt_1.NaN ^= NaN)) && 2 | {} + 0)] && --brake14 > 0);
        }
        switch (--b + [ delete b, b === a, b-- ]) {
          case --b + (c += 1, !0):
            for (var brake17 = 5; --b + a && --brake17 > 0; ) {}
            c += 1;
            break;

          case (c += 1) + ((a++ + (b = a) || a || 3).toString() || 4).toString()[a++ + a ? a++ : NaN]:
            c = 1 + c, parseInt_1 && (parseInt_1["object" == typeof arguments_1], arguments_1 && (arguments_1[(c = 1 + c,
            [] / -4 << !0 ^ ((b_2 %= 2) | (parseInt_1 && (parseInt_1.Infinity += 1 !== 38..toString()))))] <<= -1)),
            c = 1 + c, 23..toString(), 23..toString(), c = 1 + c, 23..toString(), c = 1 + c,
            c += 1;
            break;

          case (c += 1) + a++:
            break;

          case a++ + b--:
            for (var brake26 = 5; c = 1 + c, typeof (+("number" == 38..toString()) < (-4 ^ [] | 0)) && --brake26 > 0; ) {}
            return;
        }
    }({})), b_2 = function(b_2) {
        !function() {
            38..toString();
        }();
    }("foo");
    (function(a_1) {
        !function(Infinity_2, b_2, b_1) {
            c = 1 + c, c += 1, c = 1 + c, c += 1;
        }();
    })(), function() {
        if ((c += 1) + [ , !0, b != a ].undefined) {
            var brake33 = 5;
            do {
                var undefined_2 = (c = 1 + c, void (b_2 && b_2.c));
            } while (++a && --brake33 > 0);
        } else {
            try {
                c += 1, c = 1 + c, c = 1 + c, c_1 += "object", c = 1 + c;
            } finally {
                return c += 1, c = 1 + c, 0 <= (undefined_2 && (undefined_2.undefined *= 0 >= (c_1 &= !0)));
            }
        }
    }();
}

var a = 100, b = 10, c = 0, Math_1 = f0([], !1, "function");

console.log(null, a, b, c);
original result:
null 110 10 45

uglified result:
null 110 10 47

minify(options):
{ compress: { warnings: false },
  mangle: false,
  fromString: true }

Suspicious compress options:
  pure_getters
  unused

@kzc
Copy link
Contributor

kzc commented Apr 10, 2017

uglified result:
null 110 10 47

Same fuzz test results on master.

Are you fuzzing this PR because it will become the first 3.x branch series commit?

@alexlamsl
Copy link
Collaborator Author

Are you fuzzing this PR because it will become the first 3.x branch series commit?

That is my current thinking, yes. Just shakes out anything during the week before I branch this weekend.

@kzc
Copy link
Contributor

kzc commented Apr 10, 2017

Reduced test case - may be out of memory related?

$ cat mega.js
var c = 0, z = [];
function f(z) {
    z[ 4294967292 ] = 1;
    try {
        z != NaN; // throws RangeError: Invalid string length
        c++;
    } finally {
        return ++c;
        // ++c; //replace line above with this for different error
    }
}
f([]);
console.log(c);
$ node mega.js 
1
$ bin/uglifyjs mega.js -c | node
WARN: Dropping side-effect-free statement [mega.js:5,8]
2

@kzc
Copy link
Contributor

kzc commented Apr 10, 2017

$ node

> var z = [];
undefined

> z[1e7] = 1;
1

> z != NaN
true

> z[1e9] = 1;
1

> z != NaN
RangeError: Invalid string length
    at Array.toString (native)

> z == "foo"
RangeError: Invalid string length

> z == 0
RangeError: Invalid string length

> z === 0;
false

> z === "foo";
false

> z > "foo";
RangeError: Invalid string length

> z !== NaN
true

@kzc
Copy link
Contributor

kzc commented Apr 10, 2017

Seems like a Node.JS bug - shouldn't throw or run out of memory with a very large positive index.

$ node0_10_41 -e 'var z = []; z[-1e9] = 1; console.log(z == 0);'
true

$ node0_10_41 -e 'var z = []; z[1e9] = 1; console.log(z == 0);'
FATAL ERROR: Array join result too large. Allocation failed - process out of memory
Abort trap: 6

@alexlamsl
Copy link
Collaborator Author

@kzc thanks for narrowing it down. So the a == ... would call a.valueOf(), which would effectively be a.join():

$ node
> var a = []
> a[42]=1
1
> a.valueOf()
[ , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , 1 ]

@alexlamsl
Copy link
Collaborator Author

alexlamsl commented Apr 11, 2017

@3.6MFuzz - this one most definitely a fluke:

original result:
null 79525 6323589435 814337

uglified result:
Error: Script execution timed out.
    at ContextifyScript.Script.runInContext (vm.js:32:29)
    at ContextifyScript.Script.runInNewContext (vm.js:38:15)
    at Object.runInNewContext (vm.js:91:38)
minify(options):
{ compress: false, fromString: true }

And then it reverses with passes=3:

original result:
Error: Script execution timed out.
    at ContextifyScript.Script.runInContext (vm.js:32:29)
    at ContextifyScript.Script.runInNewContext (vm.js:38:15)
    at Object.runInNewContext (vm.js:91:38)
uglified result:
null 79525 6323589435 814337

minify(options):
{ compress: { keep_fargs: false, passes: 3, warnings: false },
  fromString: true }

For the sake for completeness:

// original code
// (beautified)
var a = 100, b = 10, c = 0;

c = c + 1;

{
    var brake2 = 5;
    do {
        for (var brake3 = 5; b-- && brake3 > 0; --brake3) {
            var brake4 = 5;
            while (a++ + -b && --brake4 > 0) {
                switch ((--b + a++ || 1).toString()[~([ , 0 ][1] % 25 % ([ , 0 ].length === 2 || 4) ^ (c = c + 1,
                a != 3 % "object"))]) {
                  default:
                    {
                        var undefined_1 = function f0(b, bar) {
                            {
                                var b_1 = function f1(foo, parseInt) {
                                }([ (c = 1 + c, b_1 && (b_1.c -= 1 < false & 23..toString() == null | (([ , 0 ].length === 2) >= /[a2][^e]+$/) / (-3 + [ , 0 ][1]))), (c = 1 + c,
                                ((null && 2) != (b_1 && (b_1.var >>= 22 ^ "foo"))) > ((0 | [ , 0 ][1]) >= ("number" > 1))), (c = 1 + c,
                                0 ^ "object" | "number" ^ "number" | ~({} >>> 3)), (c = 1 + c, ~(b_1 && b_1.null !== /[a2][^e]+$/ >> "bar") === (b_1 %= "undefined" >>> "undefined") - (true ^ false)) ].Infinity);
                            }
                            var foo_2;
                        }(--b + typeof [ typeof a_1 ]);
                    }
                    c = c + 1;

                  case /[abc4]/.test((a++ + --b || b || 5).toString()):
                    {
                        var brake10 = 5;
                        do {
                            for (var brake11 = 5; ++a && brake11 > 0; --brake11) {
                                var brake12 = 5;
                                do {
                                    {
                                        var brake13 = 5;
                                        while (a++ + [ (c = 1 + c, undefined_1 && (undefined_1[--b + ~(((5 || true) == !true) <= ([ , 0 ].length === 2) * "bar" - (false != "undefined"))] = (true > "function") >> (5,
                                        false) < (/[a2][^e]+$/ - 3 < "object" % 3))) ] && --brake13 > 0) {
                                            var brake14 = 5;
                                            do {
                                                var NaN_2 = (c = 1 + c, ("function" !== 1) << (NaN_2_1 && (NaN_2_1.undefined = 5 << 5)) | ("function" ^ -5) - (23..toString() >>> -5)), NaN_2_1 = (c = 1 + c,
                                                (NaN_2_1 && NaN_2_1[(c = 1 + c, 24..toString() % -4 << (-4, 0) >> (5 & Infinity,
                                                false === "number"))] !== "foo" + 5) - (/[a2][^e]+$/ != 0) < 3 / true << ([ , 0 ].length === 2 ^ 22));
                                            } while (--b + ((NaN_2_1 && NaN_2_1.in === (true && 38..toString())) >= 23..toString() << "foo" < (undefined_1 && (undefined_1[(c = c + 1) + [ (c = 1 + c,
                                            NaN_2 && (NaN_2[(c = c + 1) + a++] /= (Infinity || 23..toString()) < 3 / 3 <= (-1 << 23..toString() ^ (c = c + 1,
                                            false)))), (c = 1 + c, (38..toString() >= 38..toString() !== (38..toString() & "")) << (undefined === "undefined") % (22,
                                            [ , 0 ][1])), (c = 1 + c, NaN_2 && (NaN_2[(c = c + 1) + (typeof NaN_2 === "symbol")] = ([ , 0 ].length === 2 !== true || /[a2][^e]+$/ >>> "object") === void 2 <= (null | -4))), (c = 1 + c,
                                            (4 && undefined) * (5 * 2) % ((NaN_2 && (NaN_2.null &= -3 | 24..toString())) ^ ([ , 0 ].length === 2) / 24..toString())) ]] >>>= false % "object" && ({} && 0)))) && --brake14 > 0);
                                        }
                                    }
                                } while (a++ + (b += a) && --brake12 > 0);
                            }
                        } while (a++ + delete a && --brake10 > 0);
                    }
                    try {
                        switch (/[abc4]/.test((--b + (0 === 1 ? a : b) || b || 5).toString())) {
                          default:
                            {
                                var NaN_2 = function f2(Math_2, a_1) {
                                }(a++ + (b |= a));
                            }

                          case a++ + []:
                            switch (--b + +b) {
                              case ((c = c + 1) + ++b || a || 3).toString():
                                if (c = 1 + c, (NaN_2_1 && (NaN_2_1.a ^= "function" & 24..toString())) % (3 ^ 3) * ((null | null) >>> (/[a2][^e]+$/ & "object"))) {
                                    c = 1 + c, ({} ^ 0) + ("function" >= 3) & (25 | 23..toString() && ("function", false));
                                } else {
                                    c = 1 + c, ((NaN_2 = "undefined" ^ null) & Infinity + 2) == (NaN_2 && (NaN_2.b = ~"object" >> "" / ""));
                                }

                              case b *= a:
                                if (c = 1 + c, undefined_1 == (-3 * ([ , 0 ].length === 2) - (null && null) == 0 - "function" >= true / -0)) {
                                    c = 1 + c, (NaN >= undefined) >>> (true != -3) ^ (24..toString() !== "number" ^ true << -5);
                                } else {
                                    c = 1 + c, (2 * 0 | (c = c + 1, "")) ^ (null != -5) <= "undefined" >>> null;
                                }
                                break;

                              case /[abc4]/.test((delete a || b || 5).toString()):
                                break;

                              case a++ + 25:
                                var a_1;
                                var bar = (c = 1 + c, NaN_2 && (NaN_2.b = ([] * -5 << (NaN_2 && (NaN_2.NaN = 5 / -4))) * (-3 > 0 ^ (true ^ "undefined"))));
                                break;
                            }
                            if (/[abc4]/.test((a++ + ((38..toString() > ([ , 0 ].length === 2)) << (25 >= "number") >> (undefined > 3 ^ ([ , 0 ].length === 2,
                            -2))) || b || 5).toString())) {
                                try {
                                } finally {
                                    c = 1 + c, (5 - 2 ^ ("undefined" ^ 5)) % (c = c + 1, c = c + 1, 38..toString());
                                    c = 1 + c, (NaN_2 !== (-1 && 2) + (-5 && -2)) + ((NaN_2_1 = "number" != "undefined") === ([ , 0 ][1] ^ "bar"));
                                }
                            } else {
                                --b + (c = 1 + c, (4 !== 5 | (undefined_1 && undefined_1[(c = 1 + c, (c = c + 1,
                                "function") == -1 <= -1 ^ (38..toString() != 25 || (Infinity, "bar")))] == 5 >>> 3)) > (NaN_2_1 != (-2 ^ "object") < 4 - false));
                            }
                            break;

                          case new function() {
                                return a++ + ([ , 0 ].length === 2);
                            }():
                            break;

                          case b &= a:
                            switch (--b + a--) {
                              case --b + new function() {
                                    return -b;
                                }():
                                break;

                              case (c = c + 1) + (1 === 1 ? a : b):
                                break;

                              case {
                                    b: (c = 1 + c, !((undefined_1 && (undefined_1[(c = 1 + c, (3 ^ 1) + (undefined << 0) >>> ((c = c + 1,
                                    Infinity) == (3 !== 23..toString())))] >>>= [ , 0 ][1] - "foo")) & 4 * ""))
                                }[a++ + ((c = 1 + c, ((NaN, 2) || [ , 0 ][1] | 22) | "bar" % 23..toString() !== ("function" ^ [ , 0 ][1])) ? (c = 1 + c,
                                +((true || Infinity) <= (Infinity ^ 3))) : (c = 1 + c, (undefined_1 && (undefined_1[(c = 1 + c,
                                ([ , 0 ].length === 2 || -2) + (true - "function") ^ (25 >= -2 | 23..toString() ^ -3))] &= 38..toString() >= NaN)) & "bar" >= "undefined" || void (c = c + 1,
                                -4)))]:
                                c = c + 1;
                                for (var brake36 = 5; (c = 1 + c, (delete NaN >= (c = c + 1, 23..toString())) * (c = c + 1,
                                NaN_2_1[(c = 1 + c, ("" === 38..toString()) > "function" / {} | (-4 | 3) <= (4 || -0))] %= -5 ^ [ , 0 ][1])) && brake36 > 0; --brake36) {
                                    c = 1 + c, (null != true) + -0 / undefined >= (23..toString() <= 25 & (undefined_1 && (undefined_1[(c = 1 + c,
                                    (([ , 0 ][1] && -1) ^ -5 * -2) <= (5 <= [] != ("bar" ^ undefined)))] *= 25 == 23..toString())));
                                }
                                break;

                              case a++:
                            }
                            a++ + --b;
                            break;
                        }
                    } catch (c_1) {
                        {
                            var a_1 = function f3() {
                                switch (c = 1 + c, c = c + 1, (NaN_2 = 0 << 2) == (-3 == 5)) {
                                  case c = 1 + c, (3 === 2) <= (-3 ^ NaN) < ("bar" < null != (-2 & "")):
                                    ;
                                    break;

                                  case c = 1 + c, (/[a2][^e]+$/ << 1 ^ ({} | -3)) / (("foo" && 22) !== (null !== ([ , 0 ].length === 2))):
                                    ;
                                    break;

                                  case c = 1 + c, (-2 != "foo") >= Infinity - undefined < ("undefined" >> -4 != {} < -0):
                                    ;
                                    break;

                                  default:
                                    ;
                                }
                                var undefined_1_1 = (c = 1 + c, delete ((25 ^ -2) === [ , 0 ][1] % -3));
                            }(a++ + (b = a));
                        }
                        {
                            var a = function f4(bar_1, NaN_2, c_1_1) {
                                {
                                }
                                try {
                                    c = 1 + c, undefined * Infinity - ("foo" < 23..toString()) - ((NaN_2_1 = 4 >>> ([ , 0 ].length === 2)) && 2 >> 4);
                                } catch (c_1) {
                                } finally {
                                }
                            }({
                                c: (c = 1 + c, (c = c + 1, 3 - -4) ^ (0, "function") - 1 * 38..toString()),
                                length: (c = 1 + c, (NaN_2 && (NaN_2[(c = c + 1) + (c = 1 + c, (NaN >> 24..toString()) * (a_1 && (a_1[(c = 1 + c,
                                ("bar" != undefined) > ~([ , 0 ].length === 2) < (true == -3) >> (-3 !== -2))] >>>= true != 23..toString())) >> (undefined_1 && (undefined_1.foo <<= (-5 !== 4) <= (c_1 && (c_1[(c = 1 + c,
                                NaN_2 && (NaN_2[b++] += (c = c + 1, -3) - ([ , 0 ][1] || -1) ^ false << 24..toString() << (2 ^ 23..toString())))] >>= 23..toString() % "object")))))] <<= (c = c + 1,
                                "object") <= (a_1 && (a_1[(c = 1 + c, ({} | 5) * (1 & "undefined") * (([] && "number") ^ ~38..toString()))] &= "number" & "undefined")))) === (true % {} ^ ("" || "function"))),
                                foo: (c = 1 + c, (24..toString() & 4) !== ("function" !== -5) ^ (5 >>> "object" ^ false != 23..toString())),
                                var: (c = 1 + c, (1 >> -1 && "object" !== -1) | ([] ^ Infinity) < (4 == -4))
                            }.null);
                        }
                    } finally {
                        switch ((c = c + 1) + [ "", function() {
                        }() ]) {
                          default:
                          case ([ , 0 ].length === 2) << 2 <= "" - undefined | delete ("bar" % [ , 0 ][1]):
                            break;

                          case a++ + void function() {
                            }():
                            ;
                            break;

                          case b--:
                            break;
                        }
                        try {
                            var b_1 = --b + +function a() {
                                c = 1 + c, a_1 && (a_1[1 === 1 ? a : b] ^= -2 / "number" != true <= 5 ^ (4 && 3 || 0 <= "foo"));
                                c = 1 + c, /[a2][^e]+$/ * true >= void 0 == ((c = c + 1, /[a2][^e]+$/) == {} >= {});
                            }(), NaN = --b + void ((a_1 <<= "undefined" % -3 * (-0 ^ "undefined")) || "function" >= "number" === (c = c + 1,
                            -1));
                        } catch (b_2) {
                            {
                                var b = function f5(undefined, b) {
                                }((c = 1 + c, [ , 0 ][1] % 1 % (2 << undefined) | (NaN_2_1 && (NaN_2_1.a = [ , 0 ][1] + "object" << (0 < 38..toString())))));
                            }
                            {
                                var b_2 = function f6() {
                                }((c = 1 + c, NaN_2_1 &= 25 != -1 === "number" >> 2, !"foo" && -3 << 38..toString()));
                            }
                        }
                    }
                    break;

                  case (c = c + 1) + [ a++ + {
                        b: delete ("bar" && /[a2][^e]+$/) >> ("" >> -1 < undefined >>> true),
                        null: 1 === 1 ? a : b,
                        3: a--
                    }, --b + !function() {
                        1 === 1 ? a : b;
                        if (((c = c + 1) + /[abc4]/.test(((c = 1 + c, ((c = c + 1, true) != (24..toString() && [ , 0 ][1])) << (b_1 && (b_1.c = (NaN_2_1 && (NaN_2_1[(c = 1 + c,
                        1 - /[a2][^e]+$/ - ({}, 5) & ((c = c + 1, 4) & !{}))] &= 22 ^ Infinity)) == false >>> -1))) || b || 5).toString()) || 2).toString()[NaN_2 && NaN_2[(c = 1 + c,
                        (-0 >>> "") - (true + Infinity) !== (c = c + 1, [] & "undefined"))]]) {
                            try {
                                {
                                }
                            } catch (foo) {
                                c = 1 + c, (-0 !== -1 | "number" ^ 24..toString()) + (Infinity >> ([ , 0 ].length === 2)) * (b_2 = 2 >> /[a2][^e]+$/);
                                c = 1 + c, ((NaN, false) !== undefined >> ([ , 0 ].length === 2)) - ((1, -2) <= ({} || [ , 0 ][1]));
                            }
                        }
                    }(), {}, 1 === 1 ? a : b ]:
                    if (!a) {
                        for (var brake62 = 5; (0 === 1 ? a : b) && brake62 > 0; --brake62) {
                            var brake63 = 5;
                            do {
                            } while (a++ + [ , 0 ][1] && --brake63 > 0);
                        }
                    }
                    break;

                  case !a:
                    try {
                        for (var brake66 = 5; ++b && brake66 > 0; --brake66) {
                            --b + (b &= a);
                        }
                    } finally {
                        try {
                            for (var brake69 = 5; (b |= a) && brake69 > 0; --brake69) {
                                var a_2 = b_2 && b_2[(c = 1 + c, (b_2 && (b_2[{
                                    NaN: (c = 1 + c, ((NaN_2 *= null % ([ , 0 ].length === 2)) < (a_1 && (a_1[(c = 1 + c,
                                    ("object" << undefined <= (b_2 && b_2[(c = 1 + c, ("" >>> "object") / ("undefined" <= 22) >> delete (23..toString() <= true))] === true < 2)) << (25 >= /[a2][^e]+$/) + (1 < 2))] = "function" | 5))) >> ("undefined" >> "foo" >= (NaN_2 && (NaN_2.Infinity = null * -2))))
                                }[(c = 1 + c, (-0 * 38..toString() <= "object" >> 1) / (b_1_1 && (b_1_1[(c = c + 1) + ++a] |= null ^ Infinity && /[a2][^e]+$/ - 25)))]] = "bar" >= /[a2][^e]+$/ ^ (c = c + 1,
                                Infinity))) / ((0 && Infinity) ^ (NaN_2 && (NaN_2.var >>= 2 !== Infinity))))], b_1_1 = typeof NaN_2_1 !== "object";
                            }
                        } catch (parseInt_2) {
                            try {
                                for (var brake72 = 5; (c = 1 + c, (c = c + 1, 2, -0 >>> undefined) == (25 !== NaN) < ~-0) && brake72 > 0; --brake72) {
                                    c = 1 + c, "object" * "bar" >> (0 < 25) ^ (a_1 && (a_1[(c = 1 + c, (({} == ([ , 0 ].length === 2)) << (2 >> 3)) % (("object" != "undefined") << ("number" >> "function")))] = "bar" + NaN)) * (Infinity == 4);
                                }
                            } catch (parseInt_2_2) {
                                c = 1 + c, 3 == 3 | Infinity >= 5, (5 && true) | (Infinity, 1);
                                c = 1 + c, (c = c + 1, 38..toString() || -0) * (undefined_1 && undefined_1.in === (c = c + 1,
                                2) > (38..toString() ^ -2));
                            } finally {
                                c = 1 + c, (-0 >= 3 > (23..toString() != 0)) - (25 - -2) / -"object";
                                c = 1 + c, -2 % [ , 0 ][1] <= (38..toString() !== 1) === (a_1 && (a_1.length ^= (c = c + 1,
                                22) << void -1));
                            }
                            {
                                var b = function f7(NaN_2, c, a_1) {
                                }((c = 1 + c, (2 != /[a2][^e]+$/) / ({} ^ Infinity) >> ("undefined" + 3 >> ("bar" <= "object"))));
                            }
                        }
                        (c = c + 1) + (--b + (--b + -(("object" | 23..toString()) >>> ("number" ^ [ , 0 ].length === 2),
                        null * "undefined", -0 >= "function")));
                    }
                    break;
                }
            }
        }
    } while (typeof (--b + +b) && --brake2 > 0);
}

console.log(null, a, b, c);
// uglified code
// (beautified)
var a = 100, b = 10, c = 0;

c = c + 1;

{
    var brake2 = 5;
    do {
        for (var brake3 = 5; b-- && brake3 > 0; --brake3) {
            var brake4 = 5;
            while (a++ + -b && --brake4 > 0) {
                switch ((--b + a++ || 1).toString()[~([ , 0 ][1] % 25 % ([ , 0 ].length === 2 || 4) ^ (c = c + 1,
                a != 3 % "object"))]) {
                  default:
                    {
                        var undefined_1 = function e(n, a) {
                            {
                                var t = function e(n, c) {}([ (c = 1 + c, t && (t.c -= 1 < false & 23..toString() == null | (([ , 0 ].length === 2) >= /[a2][^e]+$/) / (-3 + [ , 0 ][1]))), (c = 1 + c,
                                ((null && 2) != (t && (t.var >>= 22 ^ "foo"))) > ((0 | [ , 0 ][1]) >= ("number" > 1))), (c = 1 + c,
                                0 ^ "object" | "number" ^ "number" | ~({} >>> 3)), (c = 1 + c, ~(t && t.null !== /[a2][^e]+$/ >> "bar") === (t %= "undefined" >>> "undefined") - (true ^ false)) ].Infinity);
                            }
                            var i;
                        }(--b + typeof [ typeof a_1 ]);
                    }
                    c = c + 1;

                  case /[abc4]/.test((a++ + --b || b || 5).toString()):
                    {
                        var brake10 = 5;
                        do {
                            for (var brake11 = 5; ++a && brake11 > 0; --brake11) {
                                var brake12 = 5;
                                do {
                                    {
                                        var brake13 = 5;
                                        while (a++ + [ (c = 1 + c, undefined_1 && (undefined_1[--b + ~(((5 || true) == !true) <= ([ , 0 ].length === 2) * "bar" - (false != "undefined"))] = (true > "function") >> (5,
                                        false) < (/[a2][^e]+$/ - 3 < "object" % 3))) ] && --brake13 > 0) {
                                            var brake14 = 5;
                                            do {
                                                var NaN_2 = (c = 1 + c, ("function" !== 1) << (NaN_2_1 && (NaN_2_1.undefined = 5 << 5)) | ("function" ^ -5) - (23..toString() >>> -5)), NaN_2_1 = (c = 1 + c,
                                                (NaN_2_1 && NaN_2_1[(c = 1 + c, 24..toString() % -4 << (-4, 0) >> (5 & Infinity,
                                                false === "number"))] !== "foo" + 5) - (/[a2][^e]+$/ != 0) < 3 / true << ([ , 0 ].length === 2 ^ 22));
                                            } while (--b + ((NaN_2_1 && NaN_2_1.in === (true && 38..toString())) >= 23..toString() << "foo" < (undefined_1 && (undefined_1[(c = c + 1) + [ (c = 1 + c,
                                            NaN_2 && (NaN_2[(c = c + 1) + a++] /= (Infinity || 23..toString()) < 3 / 3 <= (-1 << 23..toString() ^ (c = c + 1,
                                            false)))), (c = 1 + c, (38..toString() >= 38..toString() !== (38..toString() & "")) << (undefined === "undefined") % (22,
                                            [ , 0 ][1])), (c = 1 + c, NaN_2 && (NaN_2[(c = c + 1) + (typeof NaN_2 === "symbol")] = ([ , 0 ].length === 2 !== true || /[a2][^e]+$/ >>> "object") === void 2 <= (null | -4))), (c = 1 + c,
                                            (4 && undefined) * (5 * 2) % ((NaN_2 && (NaN_2.null &= -3 | 24..toString())) ^ ([ , 0 ].length === 2) / 24..toString())) ]] >>>= false % "object" && ({} && 0)))) && --brake14 > 0);
                                        }
                                    }
                                } while (a++ + (b += a) && --brake12 > 0);
                            }
                        } while (a++ + delete a && --brake10 > 0);
                    }
                    try {
                        switch (/[abc4]/.test((--b + (0 === 1 ? a : b) || b || 5).toString())) {
                          default:
                            {
                                var NaN_2 = function e(n, c) {}(a++ + (b |= a));
                            }

                          case a++ + []:
                            switch (--b + +b) {
                              case ((c = c + 1) + ++b || a || 3).toString():
                                if (c = 1 + c, (NaN_2_1 && (NaN_2_1.a ^= "function" & 24..toString())) % (3 ^ 3) * ((null | null) >>> (/[a2][^e]+$/ & "object"))) {
                                    c = 1 + c, ({} ^ 0) + ("function" >= 3) & (25 | 23..toString() && ("function", false));
                                } else {
                                    c = 1 + c, ((NaN_2 = "undefined" ^ null) & Infinity + 2) == (NaN_2 && (NaN_2.b = ~"object" >> "" / ""));
                                }

                              case b *= a:
                                if (c = 1 + c, undefined_1 == (-3 * ([ , 0 ].length === 2) - (null && null) == 0 - "function" >= true / -0)) {
                                    c = 1 + c, (NaN >= undefined) >>> (true != -3) ^ (24..toString() !== "number" ^ true << -5);
                                } else {
                                    c = 1 + c, (2 * 0 | (c = c + 1, "")) ^ (null != -5) <= "undefined" >>> null;
                                }
                                break;

                              case /[abc4]/.test((delete a || b || 5).toString()):
                                break;

                              case a++ + 25:
                                var a_1;
                                var bar = (c = 1 + c, NaN_2 && (NaN_2.b = ([] * -5 << (NaN_2 && (NaN_2.NaN = 5 / -4))) * (-3 > 0 ^ (true ^ "undefined"))));
                                break;
                            }
                            if (/[abc4]/.test((a++ + ((38..toString() > ([ , 0 ].length === 2)) << (25 >= "number") >> (undefined > 3 ^ ([ , 0 ].length === 2,
                            -2))) || b || 5).toString())) {
                                try {} finally {
                                    c = 1 + c, (5 - 2 ^ ("undefined" ^ 5)) % (c = c + 1, c = c + 1, 38..toString());
                                    c = 1 + c, (NaN_2 !== (-1 && 2) + (-5 && -2)) + ((NaN_2_1 = "number" != "undefined") === ([ , 0 ][1] ^ "bar"));
                                }
                            } else {
                                --b + (c = 1 + c, (4 !== 5 | (undefined_1 && undefined_1[(c = 1 + c, (c = c + 1,
                                "function") == -1 <= -1 ^ (38..toString() != 25 || (Infinity, "bar")))] == 5 >>> 3)) > (NaN_2_1 != (-2 ^ "object") < 4 - false));
                            }
                            break;

                          case new function() {
                                return a++ + ([ , 0 ].length === 2);
                            }():
                            break;

                          case b &= a:
                            switch (--b + a--) {
                              case --b + new function() {
                                    return -b;
                                }():
                                break;

                              case (c = c + 1) + (1 === 1 ? a : b):
                                break;

                              case {
                                    b: (c = 1 + c, !((undefined_1 && (undefined_1[(c = 1 + c, (3 ^ 1) + (undefined << 0) >>> ((c = c + 1,
                                    Infinity) == (3 !== 23..toString())))] >>>= [ , 0 ][1] - "foo")) & 4 * ""))
                                }[a++ + ((c = 1 + c, ((NaN, 2) || [ , 0 ][1] | 22) | "bar" % 23..toString() !== ("function" ^ [ , 0 ][1])) ? (c = 1 + c,
                                +((true || Infinity) <= (Infinity ^ 3))) : (c = 1 + c, (undefined_1 && (undefined_1[(c = 1 + c,
                                ([ , 0 ].length === 2 || -2) + (true - "function") ^ (25 >= -2 | 23..toString() ^ -3))] &= 38..toString() >= NaN)) & "bar" >= "undefined" || void (c = c + 1,
                                -4)))]:
                                c = c + 1;
                                for (var brake36 = 5; (c = 1 + c, (delete NaN >= (c = c + 1, 23..toString())) * (c = c + 1,
                                NaN_2_1[(c = 1 + c, ("" === 38..toString()) > "function" / {} | (-4 | 3) <= (4 || -0))] %= -5 ^ [ , 0 ][1])) && brake36 > 0; --brake36) {
                                    c = 1 + c, (null != true) + -0 / undefined >= (23..toString() <= 25 & (undefined_1 && (undefined_1[(c = 1 + c,
                                    (([ , 0 ][1] && -1) ^ -5 * -2) <= (5 <= [] != ("bar" ^ undefined)))] *= 25 == 23..toString())));
                                }
                                break;

                              case a++:
                            }
                            a++ + --b;
                            break;
                        }
                    } catch (e) {
                        {
                            var a_1 = function e() {
                                switch (c = 1 + c, c = c + 1, (NaN_2 = 0 << 2) == (-3 == 5)) {
                                  case c = 1 + c, (3 === 2) <= (-3 ^ NaN) < ("bar" < null != (-2 & "")):
                                    ;
                                    break;

                                  case c = 1 + c, (/[a2][^e]+$/ << 1 ^ ({} | -3)) / (("foo" && 22) !== (null !== ([ , 0 ].length === 2))):
                                    ;
                                    break;

                                  case c = 1 + c, (-2 != "foo") >= Infinity - undefined < ("undefined" >> -4 != {} < -0):
                                    ;
                                    break;

                                  default:
                                }
                                var n = (c = 1 + c, delete ((25 ^ -2) === [ , 0 ][1] % -3));
                            }(a++ + (b = a));
                        }
                        {
                            var a = function e(n, a, t) {
                                {}
                                try {
                                    c = 1 + c, undefined * Infinity - ("foo" < 23..toString()) - ((NaN_2_1 = 4 >>> ([ , 0 ].length === 2)) && 2 >> 4);
                                } catch (e) {} finally {}
                            }({
                                c: (c = 1 + c, (c = c + 1, 3 - -4) ^ (0, "function") - 1 * 38..toString()),
                                length: (c = 1 + c, (NaN_2 && (NaN_2[(c = c + 1) + (c = 1 + c, (NaN >> 24..toString()) * (a_1 && (a_1[(c = 1 + c,
                                ("bar" != undefined) > ~([ , 0 ].length === 2) < (true == -3) >> (-3 !== -2))] >>>= true != 23..toString())) >> (undefined_1 && (undefined_1.foo <<= (-5 !== 4) <= (e && (e[(c = 1 + c,
                                NaN_2 && (NaN_2[b++] += (c = c + 1, -3) - ([ , 0 ][1] || -1) ^ false << 24..toString() << (2 ^ 23..toString())))] >>= 23..toString() % "object")))))] <<= (c = c + 1,
                                "object") <= (a_1 && (a_1[(c = 1 + c, ({} | 5) * (1 & "undefined") * (([] && "number") ^ ~38..toString()))] &= "number" & "undefined")))) === (true % {} ^ ("" || "function"))),
                                foo: (c = 1 + c, (24..toString() & 4) !== ("function" !== -5) ^ (5 >>> "object" ^ false != 23..toString())),
                                var: (c = 1 + c, (1 >> -1 && "object" !== -1) | ([] ^ Infinity) < (4 == -4))
                            }.null);
                        }
                    } finally {
                        switch ((c = c + 1) + [ "", function() {}() ]) {
                          default:
                          case ([ , 0 ].length === 2) << 2 <= "" - undefined | delete ("bar" % [ , 0 ][1]):
                            break;

                          case a++ + void function() {}():
                            ;
                            break;

                          case b--:
                            break;
                        }
                        try {
                            var b_1 = --b + +function e() {
                                c = 1 + c, a_1 && (a_1[1 === 1 ? e : b] ^= -2 / "number" != true <= 5 ^ (4 && 3 || 0 <= "foo"));
                                c = 1 + c, /[a2][^e]+$/ * true >= void 0 == ((c = c + 1, /[a2][^e]+$/) == {} >= {});
                            }(), NaN = --b + void ((a_1 <<= "undefined" % -3 * (-0 ^ "undefined")) || "function" >= "number" === (c = c + 1,
                            -1));
                        } catch (b_2) {
                            {
                                var b = function e(n, c) {}((c = 1 + c, [ , 0 ][1] % 1 % (2 << undefined) | (NaN_2_1 && (NaN_2_1.a = [ , 0 ][1] + "object" << (0 < 38..toString())))));
                            }
                            {
                                var b_2 = function e() {}((c = 1 + c, NaN_2_1 &= 25 != -1 === "number" >> 2, !"foo" && -3 << 38..toString()));
                            }
                        }
                    }
                    break;

                  case (c = c + 1) + [ a++ + {
                        b: delete ("bar" && /[a2][^e]+$/) >> ("" >> -1 < undefined >>> true),
                        null: 1 === 1 ? a : b,
                        3: a--
                    }, --b + !function() {
                        1 === 1 ? a : b;
                        if (((c = c + 1) + /[abc4]/.test(((c = 1 + c, ((c = c + 1, true) != (24..toString() && [ , 0 ][1])) << (b_1 && (b_1.c = (NaN_2_1 && (NaN_2_1[(c = 1 + c,
                        1 - /[a2][^e]+$/ - ({}, 5) & ((c = c + 1, 4) & !{}))] &= 22 ^ Infinity)) == false >>> -1))) || b || 5).toString()) || 2).toString()[NaN_2 && NaN_2[(c = 1 + c,
                        (-0 >>> "") - (true + Infinity) !== (c = c + 1, [] & "undefined"))]]) {
                            try {
                                {}
                            } catch (e) {
                                c = 1 + c, (-0 !== -1 | "number" ^ 24..toString()) + (Infinity >> ([ , 0 ].length === 2)) * (b_2 = 2 >> /[a2][^e]+$/);
                                c = 1 + c, ((NaN, false) !== undefined >> ([ , 0 ].length === 2)) - ((1, -2) <= ({} || [ , 0 ][1]));
                            }
                        }
                    }(), {}, 1 === 1 ? a : b ]:
                    if (!a) {
                        for (var brake62 = 5; (0 === 1 ? a : b) && brake62 > 0; --brake62) {
                            var brake63 = 5;
                            do {} while (a++ + [ , 0 ][1] && --brake63 > 0);
                        }
                    }
                    break;

                  case !a:
                    try {
                        for (var brake66 = 5; ++b && brake66 > 0; --brake66) {
                            --b + (b &= a);
                        }
                    } finally {
                        try {
                            for (var brake69 = 5; (b |= a) && brake69 > 0; --brake69) {
                                var a_2 = b_2 && b_2[(c = 1 + c, (b_2 && (b_2[{
                                    NaN: (c = 1 + c, ((NaN_2 *= null % ([ , 0 ].length === 2)) < (a_1 && (a_1[(c = 1 + c,
                                    ("object" << undefined <= (b_2 && b_2[(c = 1 + c, ("" >>> "object") / ("undefined" <= 22) >> delete (23..toString() <= true))] === true < 2)) << (25 >= /[a2][^e]+$/) + (1 < 2))] = "function" | 5))) >> ("undefined" >> "foo" >= (NaN_2 && (NaN_2.Infinity = null * -2))))
                                }[(c = 1 + c, (-0 * 38..toString() <= "object" >> 1) / (b_1_1 && (b_1_1[(c = c + 1) + ++a] |= null ^ Infinity && /[a2][^e]+$/ - 25)))]] = "bar" >= /[a2][^e]+$/ ^ (c = c + 1,
                                Infinity))) / ((0 && Infinity) ^ (NaN_2 && (NaN_2.var >>= 2 !== Infinity))))], b_1_1 = typeof NaN_2_1 !== "object";
                            }
                        } catch (e) {
                            try {
                                for (var brake72 = 5; (c = 1 + c, (c = c + 1, 2, -0 >>> undefined) == (25 !== NaN) < ~-0) && brake72 > 0; --brake72) {
                                    c = 1 + c, "object" * "bar" >> (0 < 25) ^ (a_1 && (a_1[(c = 1 + c, (({} == ([ , 0 ].length === 2)) << (2 >> 3)) % (("object" != "undefined") << ("number" >> "function")))] = "bar" + NaN)) * (Infinity == 4);
                                }
                            } catch (e) {
                                c = 1 + c, 3 == 3 | Infinity >= 5, (5 && true) | (Infinity, 1);
                                c = 1 + c, (c = c + 1, 38..toString() || -0) * (undefined_1 && undefined_1.in === (c = c + 1,
                                2) > (38..toString() ^ -2));
                            } finally {
                                c = 1 + c, (-0 >= 3 > (23..toString() != 0)) - (25 - -2) / -"object";
                                c = 1 + c, -2 % [ , 0 ][1] <= (38..toString() !== 1) === (a_1 && (a_1.length ^= (c = c + 1,
                                22) << void -1));
                            }
                            {
                                var b = function e(n, c, a) {}((c = 1 + c, (2 != /[a2][^e]+$/) / ({} ^ Infinity) >> ("undefined" + 3 >> ("bar" <= "object"))));
                            }
                        }
                        (c = c + 1) + (--b + (--b + -(("object" | 23..toString()) >>> ("number" ^ [ , 0 ].length === 2),
                        null * "undefined", -0 >= "function")));
                    }
                    break;
                }
            }
        }
    } while (typeof (--b + +b) && --brake2 > 0);
}

console.log(null, a, b, c);
original result:
null 79525 6323589435 814337

uglified result:
Error: Script execution timed out.
    at ContextifyScript.Script.runInContext (vm.js:32:29)
    at ContextifyScript.Script.runInNewContext (vm.js:38:15)
    at Object.runInNewContext (vm.js:91:38)
minify(options):
{ compress: false, fromString: true }

Suspicious output options:
  indent_level
  inline_script
  shebang
  space_colon
  width

@kzc
Copy link
Contributor

kzc commented Apr 11, 2017

@3.6MFuzz - this one most definitely a fluke:
And then it reverses with passes=3:

Cannot reproduce with original or uglified original code on any node version. Probably a V8 bug.

@alexlamsl
Copy link
Collaborator Author

@kzc thanks for the confirmation 👍

Just stating for the record, Script execution timed out. means vm force-quit after 5 seconds.

@kzc
Copy link
Contributor

kzc commented Apr 11, 2017

Script execution timed out. means vm force-quit after 5 seconds.

Did not run into that problem running standalone. Only 2 seconds max per run locally.

Engine speed must degrade after a certain number of vm's created. Older node versions ran the original test case much faster, as did uglified versions.

@3.6MFuzz

Either you're gonna need a new fuzzer, or you have to introduce more bugs optimizations.

@alexlamsl alexlamsl changed the title [WIP][3.x] convert AST_Seq from binary tree to array [3.x] convert AST_Seq from binary tree to array Apr 11, 2017
@alexlamsl
Copy link
Collaborator Author

Either you're gonna need a new fuzzer, or you have to introduce more bugs optimizations.

Don't worry, they will come 😉

I just want some peace of mind for this to go in and not worry too much about regressions.

@kzc
Copy link
Contributor

kzc commented Apr 11, 2017

With 3.x around the corner, probably best to not introduce any new features/optimizations into 2.x now that it appears to be relatively stable.

@alexlamsl
Copy link
Collaborator Author

Agreed - 2.x has entered maintenance as far as I'm concerned.

@alexlamsl
Copy link
Collaborator Author

@5.5MFuzz - probably b_1 being a yuge array?

// original code
// (beautified)
var a = 100, b = 10, c = 0;

function f0() {
    {
        var bar = function f1(b_1, a, parseInt) {
            {}
            switch ({
                0: a++ + (+function a_1() {}() ? typeof parseInt_2 === "undefined" : --b + (void (23..toString() != {}) ^ (-2 === "undefined") > 2 * -1)),
                "\t": --b + {
                    Infinity: [ (c = 1 + c, ((-0 != null) <= (NaN ^ null)) >>> (NaN << "object" & 4 !== "function")), (c = 1 + c,
                    (5 ^ true) === undefined >>> 5 | "" != "number" & (b_1 >>>= ("function", /[a2][^e]+$/))), (c = 1 + c,
                    delete ("undefined" !== /[a2][^e]+$/ ^ ([ , 0 ].length === 2) < 4)), (c = 1 + c,
                    (c = c + 1, 22) ^ (-3 ^ 38..toString()) ^ (-1 > Infinity, false | -3)), (c = 1 + c,
                    ("foo" && []) === 23..toString() << -0 && -3 < null & "foo" / true) ],
                    b: a++ + ((c = 1 + c, (-2 ^ Infinity) >>> ("number" < true) !== /[a2][^e]+$/ >= -2 > ("function" ^ 22)) || 9).toString()[(c = 1 + c,
                    ("foo" / 38..toString() !== (null, 3)) / ("number" < /[a2][^e]+$/ ^ false - false))],
                    null: (c = c + 1) + new function() {
                        return c = 1 + c, ([ , 0 ].length === 2 == -4 != (38..toString() & 38..toString())) > ((NaN & undefined) <= (b_1 === "number" < /[a2][^e]+$/));
                    }()
                },
                0: (c = c + 1) + (0 === 1 ? a : b),
                foo: void ((-3 || 0) - ([] >>> 25) & (25 | 23..toString(), -5 === 38..toString()))
            }.foo) {
              case b_1 && b_1[{
                    c: 0 === 1 ? a : b,
                    "-2": a++ + a++,
                    a: 22
                }.null]:
                if ((c = c + 1) + (a++ + !function parseInt_2() {
                    c = 1 + c, false >= NaN | NaN >> 25 | NaN >> -5 & 5 !== true;
                    c = 1 + c, ("number" === 23..toString() & (c = c + 1, 22)) == (parseInt_2 && (parseInt_2.undefined &= (-3 || "object") << (-5 & -5)));
                }() || a || 3).toString()) {
                    try {
                        {
                            c = 1 + c, (b_1 && b_1.foo === (22 && -5)) % (3 >>> 24..toString()) > ("function",
                            25, b_1 = "number" && []);
                            c = 1 + c, ((c = c + 1, 1) <= NaN >> 25) * (("undefined" ^ /[a2][^e]+$/) << (-1 || -5));
                        }
                    } catch (Math_1) {
                        try {
                            c = 1 + c, (4, 22) !== (3 ^ 5) ^ ((Math_1 >>>= -5 && -1) | /[a2][^e]+$/ <= /[a2][^e]+$/);
                        } finally {
                        }
                        for (var brake13 = 5; (c = 1 + c, Math_1 && (Math_1[void ((2 >= 22) * ([] >>> 4) / ((Math_1 && (Math_1.NaN += {} ^ "function")) % (c = c + 1,
                        [])))] += ((4, 38..toString()) & 0 + false) !== (c = c + 1, [ , 0 ].length === 2) <= (null ^ []))) && brake13 > 0; --brake13) {
                            c = 1 + c, -0 / Infinity >> (23..toString() <= ([ , 0 ].length === 2)) ^ "" > "object" < 25 % -5;
                        }
                    } finally {
                        try {
                            c = 1 + c, ([ , 0 ].length === 2 && []) >>> (23..toString() | -1) ^ (4 & "bar") / (undefined * 0);
                        } catch (b_2) {
                        } finally {
                        }
                        var Infinity = (c = 1 + c, (b_1 && (b_1[+b] &= (b_1 && b_1.c == (false && -4)) ^ (b_1 && (b_1[(c = 1 + c,
                        ~(null >>> null) >>> (("foo" && -1) >= -1 + 24..toString()))] ^= "foo" === -0)))) > (true < 22 <= [ , 0 ][1] / "object"));
                    }
                }
                switch (++a) {
                  case 1 === 1 ? a : b:
                    ;
                    ;
                    break;

                  case a++ + /[abc4]/.test((b + 1 - .1 - .1 - .1 || b || 5).toString()):
                    a++ + (b_1 -= (5 - 3 ^ (1 ^ 1)) === ((-2 && NaN) & 3 + -3));
                    switch (+((22 >>> 5 == ([] == ([ , 0 ].length === 2))) >= (("foo", [ , 0 ][1]) | 22 / false))) {
                      case b_1 && b_1.foo:
                        c = 1 + c, ([ , 0 ][1] + [ , 0 ][1] !== "foo" <= 25) >> ([ , 0 ][1] ^ [ , 0 ][1]) * ("function" <= undefined);
                        break;

                      default:
                        c = 1 + c, 22 * [] === (null && 3) ^ (c = c + 1, "undefined" << 1);
                        c = 1 + c, ((5 & 22) == (b_1 && (b_1.undefined >>= (false, -1)))) << ((b_1 && (b_1[(c = 1 + c,
                        b_1 %= (25 >> NaN ^ NaN > "") & (3 != {} | [] - -3))] >>>= -0 - -4)) >= (2 || "object"));

                      case typeof b != "number":
                        c = 1 + c, (b_1 = (b_1 && (b_1[(c = 1 + c, (-3 < undefined ^ NaN - -2) > ((b_1 && (b_1[(c = 1 + c,
                        b_1 && (b_1[~b] >>= ("undefined" ^ "function") * ("bar", -0) % ((Infinity & 25) != ("foo" ^ 1))))] >>>= "object" >> 4)) ^ ({} | [])))] |= 4 | 38..toString()),
                        "" || null)) | (4 < "function") << (b_1 && (b_1.Infinity /= Infinity <= /[a2][^e]+$/));
                        break;

                      case b_1 && b_1[(c = 1 + c, ((1 ^ 23..toString()) >>> "undefined" / 2) + ([] < "function" !== (b_1 && b_1.length === "number" >= 24..toString())))]:
                        break;
                    }
                    break;

                  case a++ + --b:
                    {
                        var brake27 = 5;
                        while (5 && --brake27 > 0) {
                            var brake28 = 5;
                            do {
                                c = 1 + c, b_1 = ((23..toString(), -0) !== {} > "number") + ((null | 4) >> (b_1 && (b_1[(c = 1 + c,
                                (b_1 && b_1.null !== ([ , 0 ].length === 2 !== "")) + (38..toString() << 2) - (-3 < NaN) % (1 === -2))] = undefined & /[a2][^e]+$/)));
                            } while ((c = 1 + c, (undefined - "undefined") / ("function" === true) <= "object" / undefined % (-3 % 3)) && --brake28 > 0);
                        }
                    }
                    break;

                  default:
                    --b + (undefined / -0 >>> (Infinity ^ -3) <= ((b_1 && (b_1[(c = 1 + c, ("bar" && []) / (([ , 0 ].length === 2) <= -4) <= (-2 <= 24..toString() == 1 < 25))] += {} * "function")) | true == -1));
                }

              case [ [ ((c = 1 + c, ((-1 != []) + ("undefined" === -0)) % (([ , 0 ].length === 2) <= {} & -3 << NaN)) || 5).toString()[(c = 1 + c,
                (b_1 && (b_1.length = 3 << 23..toString())) != (b_1 && (b_1.Infinity >>>= null && 23..toString())) != (b_1 && (b_1.var += false <= 1)) - (38..toString() != 3))], 1 === 1 ? a : b, {
                    length: (c = 1 + c, (true != ([ , 0 ].length === 2) | ("function", 1)) * (("foo" >= 25) >>> ([ , 0 ].length === 2 ^ -5))),
                    NaN: (c = 1 + c, ((true || true) !== ![ , 0 ][1]) >= (b_1 <<= 25 !== "object" !== 22 > undefined)),
                    null: (c = 1 + c, (b_1 && (b_1[(c = c + 1) + new function() {
                        c = 1 + c, ("undefined" ^ -2) / (-5 || "number") / (5 - 22 || (b_1 ^= true << -0));
                        return c = 1 + c, (-0 !== [] || 22 >> /[a2][^e]+$/) != ((c = c + 1, -3) || 1 ^ "undefined");
                    }()] = (c = c + 1, [ , 0 ][1]) == (c = c + 1, 0))) << ("undefined" >> "bar" !== [] / {})),
                    null: (c = 1 + c, b_1 && (b_1.null >>>= (2 + 22 == !-0) << (([ , 0 ][1] !== -3) >= (b_1 && (b_1.length = "undefined" != [])))))
                }, --b + a++, ((c = 1 + c, NaN / 5 % (3 < 24..toString()) & (-4 ^ 4 | (1 || "foo"))) || a || 3).toString() ] ][a++ + typeof b]:
                ;
                {
                    try {
                        c = 1 + c, (-4 + 5, "number" ^ 0) & (5 == 5 && (3, 38..toString()));
                    } catch (a_1) {
                        c = 1 + c, (Infinity | "foo") >>> ([ , 0 ][1] >> 0) !== ((0 || "number") == -4 << /[a2][^e]+$/);
                        c = 1 + c, /[a2][^e]+$/ * false / (5 >>> null) | [ , 0 ][1] * "undefined" << ("function" > 22);
                    } finally {
                        c = 1 + c, (b_1 == (22 !== ([ , 0 ].length === 2))) >> (5 < ([ , 0 ].length === 2)) || (undefined < {}) >> ("undefined" != null);
                        c = 1 + c, ((-4 !== -3) < (38..toString() & 23..toString())) * (b_1 && (b_1.a = (false,
                        "object") <= NaN / "function"));
                    }
                }

              case (a++ + +a || a || 3).toString():
                {
                    var brake39 = 5;
                    do {
                        {
                            return (c = c + 1) + (b_1 && b_1.length || a || 3).toString();
                        }
                    } while (a++ + [].in && --brake39 > 0);
                }
                break;

              case --b + ("" ? b_1 && b_1[(c = c + 1) + (b_1 && b_1.a)] : (c = c + 1) + b++):
                break;
            }
        }(-5);
    }
    for (var brake41 = 5; (c = c + 1) + (b &= a) && brake41 > 0; --brake41) {
        switch (1 === 1 ? a : b) {
          case a++ + {
                "-2": --b + --b,
                var: --b + {
                    "-2": (c = c + 1) + [ (c = 1 + c, (3 - 4 & "undefined" >> 22) + ((5 ^ NaN) <= 25 / null)), (c = 1 + c,
                    "foo" % [ , 0 ][1] >>> (4 >= 5) >= "foo" << /[a2][^e]+$/ >>> (-4 << "foo")), (c = 1 + c,
                    ([ , 0 ][1] | -1) >> (-4 !== "undefined") != 22 * false + undefined / {}) ] ? (false > -0 | "function" ^ {}) >> (2 * -1 === (/[a2][^e]+$/ != 1)) : (3 - "number") / (5 > "bar") << ("" >= ([ , 0 ].length === 2) !== ("object" != "undefined")),
                    "": a++ + void function() {
                        return c = 1 + c, (38..toString() === [ , 0 ][1] & (22 ^ 23..toString())) >>> (([ , 0 ].length === 2 & 3) !== [] - false);
                        return;
                        var b_1 = (c = 1 + c, (b_1 && (b_1[(c = 1 + c, ("foo" > 3) + (-1 === 38..toString()) === "" + 2 >= (3 !== -0))] >>>= 2 - NaN)) <= (2 && -2) && (b_1 && b_1[b + 1 - .1 - .1 - .1] === (undefined || 25) % (b_1 && (b_1.length = Infinity | "bar"))));
                    }(),
                    "": --b + {
                        b: --b + +function foo_2() {
                        }(),
                        3: [ (c = 1 + c, ((-3 != "number") >= -1 - "function") * (("object" > 25) % (38..toString() ^ "foo"))), (c = 1 + c,
                        ((NaN ^ -5) < (-0 <= -4)) * (5 & /[a2][^e]+$/ || null ^ NaN)) ],
                        0: ((c = 1 + c, (38..toString() * 23..toString() | (4 || 0)) >> (24..toString() !== 25) + (38..toString() != NaN)) || a || 3).toString(),
                        b: --b + [ (c = 1 + c, (38..toString() | -2) != "foo" <= true != ({} % -3 != (-5 || -0))), (c = 1 + c,
                        (-5 >>> "object") * (null, -5) === ("" >> 38..toString() && Infinity >>> 1)), , (c = 1 + c,
                        (-2 << "undefined" & -0 >> 2) >>> ((-3 & Infinity) > (-0 !== "undefined"))), (c = 1 + c,
                        (1 != {}) + -22 <= !(c = c + 1, 24..toString())) ],
                        0: (c = c + 1, "", null & 2) / (a && (a[1 === 1 ? a : b] >>>= ([ , 0 ].length === 2) % /[a2][^e]+$/ >= (3 == true)))
                    },
                    "-2": (c = c + 1) + {
                        Infinity: a++ + void ((22 > null) * ([ , 0 ][1] * "object") < (-3 >= 25, "object" % 23..toString())),
                        undefined: (c = c + 1) + -4,
                        "\t": [ (c = 1 + c, a &= [] * "object" >> NaN % 24..toString() !== (/[a2][^e]+$/ | 24..toString()) + (1 < undefined)), (c = 1 + c,
                        (24..toString() ^ undefined | (c = c + 1, null)) ^ Infinity - Infinity >> (c = c + 1,
                        {})), (c = 1 + c, ("function", 5) || -5 >>> -4 || undefined ^ "foo" ^ (-1, "undefined")), (c = 1 + c,
                        (1 < -2 && "bar" ^ 24..toString()) >>> (null - 22) % (NaN > -2)), (c = 1 + c, (25 || NaN) != NaN <= /[a2][^e]+$/ ^ (c = c + 1,
                        [ , 0 ].length === 2 && null)) ][(c = 1 + c, -2 - 25 << (undefined >>> 4) >= (a && (a.in = -2 / -2 != (3 ^ 3))))],
                        1.5: (c = c + 1) + {
                            c: (c = 1 + c, ((true == Infinity) >>> (-1 << "")) + ((24..toString(), undefined) === -4 / true)),
                            var: (c = 1 + c, ({} !== 25) >= (-0 > 0) ^ ([ , 0 ].length === 2 ^ "bar") === "" / 24..toString()),
                            a: (c = 1 + c, (undefined >= 3 || {} ^ 1) > (-"object" ^ ("object" ^ Infinity))),
                            "\t": (c = 1 + c, void Infinity > ([ , 0 ][1] & "") > ((-4 === ([ , 0 ].length === 2)) >= ([] & 23..toString()))),
                            in: (c = 1 + c, ((c = c + 1, 4) & false < "undefined") > (a && (a[[ (c = 1 + c,
                            ("object" ^ false) < (-1 !== 3) > ((-5 & "object") >= -4 << 5)), (c = 1 + c, c = c + 1,
                            [ , 0 ][1] << 1 != (-0 & {})), (c = 1 + c, c = c + 1, 25 != -2 | /[a2][^e]+$/ & "undefined"), (c = 1 + c,
                            (38..toString() ^ [ , 0 ].length === 2 || 2 >>> "foo") !== ({} && NaN) >= 3 % true), (c = 1 + c,
                            (-1 === true) << (1 ^ [ , 0 ][1]) < (25 <= -4 !== ("object", -2))) ].foo] = ("object" | -5) ^ (undefined && -4))))
                        }
                    }
                }[a++ + (b = a)],
                NaN: (c = c + 1) + --b
            }.null:
            break;

          case --b + (1 === 1 ? a : b) ? (c = c + 1) + ~((a ^= (23..toString() && 38..toString()) - (([ , 0 ].length === 2) >= 1)) * ((25 || NaN) / ("object" != [ , 0 ][1]))) : b++:
            break;

          case a++ + {
                length: [ --b + typeof (a++ + {
                    Infinity: (c = 1 + c, a != (undefined ^ -1) < (c = c + 1, 4) | ([ , 0 ].length === 2 && "number") & -5 >> /[a2][^e]+$/),
                    "": (c = 1 + c, ([] != "" && -0 >= -4) * (a |= ([ , 0 ].length === 2) / "undefined" >= false / "function")),
                    "\t": (c = 1 + c, (false ^ -3 || false % /[a2][^e]+$/) ^ true > 25 !== (a && (a[(c = 1 + c,
                    a && (a.length /= (a && (a.NaN ^= (a && (a[(c = 1 + c, (([ , 0 ].length === 2) >= [] <= ("number" != 38..toString())) << ("function" % -4 || [ , 0 ][1] >>> -1))] %= 1 | -5),
                    a && (a[(c = 1 + c, ("object" && "number") === 24..toString() * 1 ^ ((23..toString() && -5) ^ -3 << /[a2][^e]+$/))] = "bar" | undefined)))) / (("foo" & -4) >>> ("function" == 5))))] %= "function" ^ "bar"))),
                    c: (c = 1 + c, (0 == 2 ^ -0 !== false) !== ([ , 0 ].length === 2 | "undefined") * (22 & 1))
                }[22]), a++ + {
                    1.5: NaN,
                    undefined: (c = c + 1) + (a && a[(c = 1 + c, null >> -4 ^ 5 << 2 && ({}, 3) >= ([ , 0 ][1] <= -1))]),
                    "-2": (c = c + 1) + [ (c = 1 + c, c = c + 1, (22 ^ []) == (NaN === true)), , (c = 1 + c,
                    (-5 << 38..toString() || -5 >= undefined) + (null * {} > 24..toString() * 25)), (c = 1 + c,
                    ((-0 || 1) && -3 <= -5) + (5 * "number" != -4 > false)), (c = 1 + c, (a && (a[a++ + (b ^= a)] = false - "foo" & false > 22)) === (3 >>> NaN || 2 === 25)) ].Infinity,
                    var: typeof bar_1 != "function",
                    NaN: (c = c + 1) + a++
                } ][b--],
                "": a++ + function a_2() {
                    c = c + 1;
                }()
            }:
            var a_1;
            for (var brake48 = 5; 1 && brake48 > 0; --brake48) {
                --b + (null & null ^ -0 >>> /[a2][^e]+$/) % ((false, 5) || -4 && [ , 0 ][1]);
            }
            break;

          case (c = c + 1) + {
                "\t": --b + false,
                1.5: b = a,
                Infinity: --b + "bar",
                c: 1 === 1 ? a : b,
                foo: ++a
            }.b:
        }
    }
}

var Infinity_2 = f0("undefined", 5);

console.log(null, a, b, c);
// uglified code
// (beautified)
function f0() {
    for (var brake41 = (function(b_1, a, parseInt) {
        switch ({
            0: a++ + (--b + (!0 ^ void 23..toString())),
            "\t": --b + {
                Infinity: [ (c = 1 + c, 0), (c = 1 + c, !1 | !0 & (b_1 >>>= /[a2][^e]+$/)), (c = 1 + c,
                !0), (c = 1 + c, -3 ^ (c += 1, -3 ^ 38..toString() ^ 22)), (c = 1 + c, [] === 23..toString() << -0 && 0) ],
                b: a++ + (c = 1 + c, (-2 ^ Infinity) >>> !1 !== !1 || 9).toString()[(c = 1 + c,
                ("foo" / 38..toString() != 3) / 0)],
                null: (c += 1) + new function() {
                    return c = 1 + c, (2 === [ , 0 ].length == -4 != (38..toString() & 38..toString())) > (0 <= (!1 === b_1));
                }()
            },
            0: (c += 1) + b,
            foo: void (23..toString(), 38..toString())
        }.foo) {
          case b_1 && b_1[{
                c: b,
                "-2": a++ + a++,
                a: 22
            }.null]:
            if ((c += 1) + (a++ + !function parseInt_2() {
                c = 1 + c, c = 1 + c, 23..toString(), c += 1, parseInt_2 && (parseInt_2.undefined &= -3 << -5);
            }() || a || 3).toString()) {
                try {
                    c = 1 + c, b_1 && b_1.foo, 24..toString(), b_1 = [], c = 1 + c, c += 1;
                } catch (Math_1) {
                    try {
                        c = 1 + c, Math_1 >>>= -1;
                    } finally {}
                    for (var brake13 = 5; c = 1 + c, Math_1 && (Math_1[void (Math_1 && (Math_1.NaN += "function" ^ {}),
                    c += 1)] += (0 & 38..toString()) !== (c += 1, (2 === [ , 0 ].length) <= (null ^ []))) && brake13 > 0; --brake13) {
                        c = 1 + c, 23..toString();
                    }
                } finally {
                    try {
                        c = 1 + c, 23..toString();
                    } catch (b_2) {}
                    var Infinity = (c = 1 + c, (b_1 && (b_1[+b] &= (b_1 && !1 == b_1.c) ^ (b_1 && (b_1[(c = 1 + c,
                    -1 >>> (-1 >= -1 + 24..toString()))] ^= !1)))) > (!0 <= [ , 0 ][1] / "object"));
                }
            }
            switch (++a) {
              case a:
                break;

              case a++ + /[abc4]/.test((b + 1 - .1 - .1 - .1 || b || 5).toString()):
                switch (a++, b_1 -= !1, +((0 == ([] == (2 === [ , 0 ].length))) >= ([ , 0 ][1] | 1 / 0))) {
                  case b_1 && b_1.foo:
                    c = 1 + c;
                    break;

                  default:
                    c = 1 + c, c += 1, c = 1 + c, b_1 && (b_1.undefined >>= -1), b_1 && (b_1[(c = 1 + c,
                    b_1 %= 25 & (3 != {} | [] - -3))] >>>= 4);

                  case "number" != typeof b:
                    c = 1 + c, b_1 && (b_1[(c = 1 + c, 0 > ((b_1 && (b_1[(c = 1 + c, b_1 && (b_1[~b] >>= -0 % (1 != (25 & Infinity))))] >>>= 0)) ^ ({} | [])))] |= 4 | 38..toString()),
                    (b_1 = null) && (b_1.Infinity /= Infinity <= /[a2][^e]+$/);
                    break;

                  case b_1 && b_1[(c = 1 + c, ((1 ^ 23..toString()) >>> NaN) + ([] < "function" !== (b_1 && b_1.length === "number" >= 24..toString())))]:
                }
                break;

              case a++ + --b:
                for (var brake27 = 5; --brake27 > 0; ) {
                    do {
                        c = 1 + c, 23..toString(), b_1 = (-0 !== {} > "number") + (4 >> (b_1 && (b_1[(c = 1 + c,
                        (b_1 && b_1.null !== (2 === [ , 0 ].length !== "")) + (38..toString() << 2) - NaN)] = 0)));
                    } while (c = 1 + c, !1);
                }
                break;

              default:
                --b, b_1 && (b_1[(c = 1 + c, [] / ((2 === [ , 0 ].length) <= -4) <= (-2 <= 24..toString() == 1))] += "function" * {});
            }

          case [ [ (c = 1 + c, ((-1 != []) + !1) % ((2 === [ , 0 ].length) <= {} & -3) || 5).toString()[(c = 1 + c,
            (b_1 && (b_1.length = 3 << 23..toString())) != (b_1 && (b_1.Infinity >>>= null)) != (b_1 && (b_1.var += !0)) - (3 != 38..toString()))], a, {
                length: (c = 1 + c, (1 != (2 === [ , 0 ].length) | 1) * (!1 >>> (2 === [ , 0 ].length ^ -5))),
                NaN: (c = 1 + c, (!0 != ![ , 0 ][1]) >= (b_1 <<= !0)),
                null: (c = 1 + c, (b_1 && (b_1[(c += 1) + new function() {
                    return c = 1 + c, c = 1 + c, (-0 !== [] || 22) != (c += 1, -3);
                }()] = (c += 1, [ , 0 ][1] == (c += 1, 0)))) << (0 != [] / {})),
                null: (c = 1 + c, b_1 && (b_1.null >>>= !1 << ((-3 !== [ , 0 ][1]) >= (b_1 && (b_1.length = "undefined" != [])))))
            }, --b + a++, (c = 1 + c, NaN % (3 < 24..toString()) & -7 || a || 3).toString() ] ][a++ + typeof b]:
            try {
                c = 1 + c, 38..toString();
            } catch (a_1) {
                c = 1 + c, c = 1 + c;
            } finally {
                c = 1 + c, c = 1 + c, 38..toString(), 23..toString(), b_1 && (b_1.a = !1);
            }

          case (a++ + +a || a || 3).toString():
            var brake39 = 5;
            do {
                return (c += 1) + (b_1 && b_1.length || a || 3).toString();
            } while (a++ + [].in && --brake39 > 0);
            break;

          case --b + ((c += 1) + b++):
        }
    }(-5), 5); (c += 1) + (b &= a) && brake41 > 0; --brake41) {
        switch (a) {
          case a++ + {
                "-2": --b + --b,
                var: --b + {
                    "-2": (c += 1) + [ (c = 1 + c, 1), (c = 1 + c, "foo" % [ , 0 ][1] >>> !1 >= 0), (c = 1 + c,
                    (-1 | [ , 0 ][1]) >> !0 != 0 + void 0 / {}) ] ? (!1 | "function" ^ {}) >> !1 : NaN << ("" >= (2 === [ , 0 ].length) != !0),
                    "": a++ + void function() {
                        return c = 1 + c, (38..toString() === [ , 0 ][1] & (22 ^ 23..toString())) >>> ((2 === [ , 0 ].length & 3) != [] - !1);
                    }(),
                    "": --b + {
                        b: --b + NaN,
                        3: [ (c = 1 + c, !1 * (!1 % ("foo" ^ 38..toString()))), (c = 1 + c, 0) ],
                        0: (c = 1 + c, (38..toString() * 23..toString() | 4) >> (25 !== 24..toString()) + (NaN != 38..toString()) || a || 3).toString(),
                        b: --b + [ (c = 1 + c, 0 != (-2 | 38..toString()) != ({} % -3 != -5)), (c = 1 + c,
                        -21474836455 === ("" >> 38..toString() && 0)), , (c = 1 + c, 0), (c = 1 + c, (1 != {}) + -22 <= (c += 1,
                        !24..toString())) ],
                        0: (c += 1, 0 / (a && (a[a] >>>= (2 === [ , 0 ].length) % /[a2][^e]+$/ >= !1)))
                    },
                    "-2": (c += 1) + {
                        Infinity: a++ + void 23..toString(),
                        undefined: (c += 1) + -4,
                        "\t": [ (c = 1 + c, a &= "object" * [] >> NaN % 24..toString() !== (/[a2][^e]+$/ | 24..toString()) + !1), (c = 1 + c,
                        (void 0 ^ 24..toString() | (c += 1, null)) ^ NaN >> (c += 1, {})), (c = 1 + c, 5), (c = 1 + c,
                        0), (c = 1 + c, !0 ^ (c += 1, 2 === [ , 0 ].length && null)) ][(c = 1 + c, -27 >= (a && (a.in = !0)))],
                        1.5: (c += 1) + {
                            c: (c = 1 + c, 0 + (-4 === void 24..toString())),
                            var: (c = 1 + c, (25 !== {}) >= !1 ^ (2 === [ , 0 ].length ^ "bar") == "" / 24..toString()),
                            a: (c = 1 + c, (1 ^ {}) > 0),
                            "\t": (c = 1 + c, void 0 > ("" & [ , 0 ][1]) > ((-4 === (2 === [ , 0 ].length)) >= ([] & 23..toString()))),
                            in: (c = 1 + c, (!1 & (c += 1, 4)) > (a && (a[[ (c = 1 + c, !1), (c = 1 + c, c += 1,
                            [ , 0 ][1] << 1 != (-0 & {})), (c = 1 + c, c += 1, 1), (c = 1 + c, (38..toString() ^ 2 === [ , 0 ].length || 2) !== ({} && NaN) >= 0), (c = 1 + c,
                            !1 << (1 ^ [ , 0 ][1]) < !0) ].foo] = -5)))
                        }
                    }
                }[a++ + (b = a)],
                NaN: (c += 1) + --b
            }.null:
          case --b + a ? (c += 1) + ~((a ^= (23..toString() && 38..toString()) - ((2 === [ , 0 ].length) >= 1)) * (25 / ("object" != [ , 0 ][1]))) : b++:
            break;

          case a++ + {
                length: [ --b + typeof (a++ + {
                    Infinity: (c = 1 + c, a != -1 < (c += 1, 4) | -5 & (2 === [ , 0 ].length && "number")),
                    "": (c = 1 + c, ("" != [] && !0) * (a |= (2 === [ , 0 ].length) / "undefined" >= NaN)),
                    "\t": (c = 1 + c, -3 ^ !1 !== (a && (a[(c = 1 + c, a && (a.length /= (a && (a.NaN ^= (a && (a[(c = 1 + c,
                    ((2 === [ , 0 ].length) >= [] <= ("number" != 38..toString())) << ([ , 0 ][1] >>> -1))] %= -5),
                    a && (a[(c = 1 + c, "number" === 1 * 24..toString() ^ -3 ^ (23..toString() && -5))] = 0)))) / 0))] %= 0))),
                    c: (c = 1 + c, 1 != 0 * (2 === [ , 0 ].length | "undefined"))
                }[22]), a++ + {
                    1.5: NaN,
                    undefined: (c += 1) + (a && a[(c = 1 + c, 3 >= ([ , 0 ][1] <= -1))]),
                    "-2": (c += 1) + [ (c = 1 + c, c += 1, 0 == (22 ^ [])), , (c = 1 + c, (-5 << 38..toString() || !1) + (null * {} > 25 * 24..toString())), (c = 1 + c,
                    1), (c = 1 + c, 3 === (a && (a[a++ + (b ^= a)] = 0))) ].Infinity,
                    var: "function" != typeof bar_1,
                    NaN: (c += 1) + a++
                } ][b--],
                "": a++ + function() {
                    c += 1;
                }()
            }:
            for (var brake48 = 5; brake48 > 0; --brake48) {
                --b;
            }
            break;

          case (c += 1) + {
                "\t": --b + !1,
                1.5: b = a,
                Infinity: --b + "bar",
                c: a,
                foo: ++a
            }.b:
        }
    }
}

var a = 100, b = 10, c = 0, Infinity_2 = f0("undefined", 5);

console.log(null, a, b, c);
original result:
RangeError: Invalid string length
    at Array.toString (native)
    at f1 (evalmachine.<anonymous>:70:32)
    at f0 (evalmachine.<anonymous>:85:1)
    at evalmachine.<anonymous>:106:18
    at evalmachine.<anonymous>:109:2
    at ContextifyScript.Script.runInContext (vm.js:32:29)
    at ContextifyScript.Script.runInNewContext (vm.js:38:15)
    at Object.runInNewContext (vm.js:91:38)
uglified result:
null 46 44 332

minify(options):
{ compress: { warnings: false },
  mangle: false,
  fromString: true }

Suspicious compress options:
  screw_ie8
  side_effects

Node 7

$ cat test.js | node
[stdin]:122
                        c = 1 + c, (b_1 == (22 !== ([ , 0 ].length === 2))) >> (5 < ([ , 0 ].length === 2)) || (undefined < {}) >> ("undefined" != null);
                                        ^

RangeError: Invalid string length
    at Array.toString (native)
    at f1 ([stdin]:122:41)
    at f0 ([stdin]:142:10)
    at [stdin]:235:18
    at ContextifyScript.Script.runInThisContext (vm.js:23:33)
    at Object.runInThisContext (vm.js:95:38)
    at Object.<anonymous> ([stdin]-wrapper:6:22)
    at Module._compile (module.js:571:32)
    at evalScript (bootstrap_node.js:387:27)
    at Socket.<anonymous> (bootstrap_node.js:184:13)

Chakracore

$ cat test.js | node
Error: Out of memory
   at Script.prototype.runInThisContext (vm.js:44:5)
   at runInThisContext (vm.js:116:3)
   at Anonymous function ([stdin]-wrapper:6:1)
   at Module.prototype._compile (module.js:585:3)
   at evalScript (bootstrap_node.js:411:5)
   at Anonymous function (bootstrap_node.js:190:13)
   at emitNone (events.js:110:7)
   at emit (events.js:207:7)
   at endReadableNT (_stream_readable.js:992:5)
   at _combinedTickCallback (internal/process/next_tick.js:80:11)

@kzc
Copy link
Contributor

kzc commented Apr 12, 2017

@5.5MFuzz - probably b_1 being a yuge array?

Definitely. Cannot run original code successfully on any node version.

I think this fuzzer well has run dry - at least this version of it. I was hoping that the fuzzer would have randomly generated a bug-free ES6 minifier by now, but alas no.

@alexlamsl
Copy link
Collaborator Author

I think it is evolving, albeit slowly. Should get there by the time both of us collect our retirement 💰

It might even become a member of the ECMAScript standards commitee, if not the only member left alive by then.

@alexlamsl
Copy link
Collaborator Author

v2.x branch created - https://github.com/mishoo/UglifyJS2/tree/v2.x

master is now ready for uglify-js 3 😎

@alexlamsl alexlamsl merged commit 2244743 into mishoo:master Apr 12, 2017
@alexlamsl alexlamsl deleted the ast_seq branch April 12, 2017 13:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants