-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
expand symbol space to improve compression #2460
Conversation
|
gzip output appears to be a wash. Is the motivation for this to improve non-gzip output size as discussed in #2422? What does |
|
With improved chances of function inlining and/or substitution, we conceivably increase the average number of variables in |
All things being equal, slightly less CPU use is worth something. |
@kzc slightly OT: how comfortable are you with I'm comtemplating whether to merge this PR now, or wait for |
I think But |
How about I make |
The blanket AST_Defun to AST_Function conversion is a big deal. It slows down a lot of code. I think it should go in the next release. If |
Oh? |
Same scope function inlining is probably fine, but the overhead to repeatedly generate a function expression is quite high - even in latest JS engines. |
I think the same scope replacement should present no performance difference, indeed. I'm just not sure about the a lot of code part, especially whether they are being noticed. Having said that, I'm all for letting people Thinking back though - part of this initiative is to match some of the functionalities of Closure. So wouldn't they suffer from the same performance concern? 🤔 |
The reason why Closure is not subject to performance degradation is due to the fact that they will only inline a function declaration when they can inline the function entirely so there is no function expression at all. What we do is replace the function symbol reference to the function declaration with a function expression and hope a subsequent pass will inline it. |
Gotcha - will bear that in mind in the next round of hacking. |
2f8659a
to
b819670
Compare
Will 3.2.0 include the 3.1.x fixes, this PR and enable |
That's my current plan, yes. |
Would it be possible to cut a final 3.1.10 release with just what is present in master without adding this PR and leaving |
Let's see if I can run |
Off to a bad start with Node.js 9.2.0
|
One of these? var a=[];a[1e10]=1;console.log(a+""); off-topic:
|
That example works just fine - no errors is returned.
I guess that may upset |
Just an example. This one does:
|
Ah, of course - and I can confirm this is new behaviour in Node.js 9:
... which is rather undesirable IMHO because it breaks the process. Let's see how bad this gets - we can always go back to Node.js 8 for |
The fact that |
That's because
|
New stacktrace, but doesn't kill the // original code
// (beautified)
var a = 100, b = 10, c = 0;
{
var brake1 = 5;
while (--b + !b && --brake1 > 0) {
var c_1 = {
set NaN(parseInt_1) {
try {
c = c + 1;
} catch (Infinity) {
} finally {
var parseInt_1_2 = parseInt_1 && parseInt_1.a, bar_1 = bar_1 && bar_1.length;
}
this.length += ((parseInt_1_2 && (parseInt_1_2[(c = c + 1) + (b + 1 - .1 - .1 - .1)] = (("object" >= 22) / (4 >> 22) == (-1 == 2 !== 25 + -5) && (bar_1 && (bar_1[--b + [ (c = 1 + c,
{} > {} == ([ , 0 ].length === 2) << this & (1 > 23..toString()) - (c_1 && (c_1[(c = 1 + c,
(2 % 25 | null >>> /[a2][^e]+$/) < ("", "object", false >> ([ , 0 ].length === 2)))] = -0 >>> 4))), (c = 1 + c,
(("bar" ^ [ , 0 ].length === 2) >= undefined / false) - (parseInt_1_2 &= false / "undefined" - (2 !== "bar"))) ].length] = (parseInt_1 && (parseInt_1.foo = "undefined" & false)) <= [] >>> /[a2][^e]+$/) && this / 0 + ~([ , 0 ].length === 2))) > ((24..toString() || -2) > (4 & "")) / ((-2 >= ([ , 0 ].length === 2)) + (22 || 25)) >>> (-5 / 4 >>> ("function",
4) || "undefined" / "function" !== -1 * this) <= ((parseInt_1 && (parseInt_1[parseInt_1_2] = -(22 % -2 != "bar" >= -4) - (("bar" ^ /[a2][^e]+$/) >= true >>> Infinity | !22 * (null,
"number")))) & "" * -0 % (4 <= "undefined") != (24..toString() >> -5) + (5 & 24..toString()) != (3 < "undefined" & (25 & undefined)) >> ((23..toString() != false) > -0 + [])))) << (((23..toString() === ([ , 0 ].length === 2)) % (1 + "bar") & 3 << this == ("bar" & /[a2][^e]+$/) & ((true & -5 || "object" ^ this) && 5 - 4 >>> - -1)) <= ((parseInt_1 && (parseInt_1[1 === 1 ? a : b] += 0 === 2 & "object" >> "number")) <= (NaN >> -5 < ("undefined" == []))) >>> ((25 < 38..toString()) % ("foo" == true) << (-4 && 0) + (-5 + 3))) * (((("undefined" == this) <= (24..toString() <= "function")) * ((-3 | -1) ^ (bar_1 && (bar_1.undefined &= [] / null))) ^ (3 << -2 || true / -5 || (22 && -3) >>> (c = c + 1,
[ , 0 ][1]))) << (!23..toString() != 0 << 1 | (-3 - [ , 0 ][1]) % (-0 & this)) - (({} != "function" || "foo" ^ "number") && (c_1 && (c_1[(c = 1 + c,
c_1 && (c_1[(a++ + parseInt_1 || a || 3).toString()] += ("foo" || 22) <= (-0 | {}) !== (-3,
[ , 0 ][1]) >= ("function" || "object")))] = [ , 0 ].length === 2 | -4)) <= {} << "object"))) + ((bar_1 && (bar_1.Infinity += (parseInt_1_2 && (parseInt_1_2.undefined = ((Infinity === 23..toString()) <= this * "") - ((-3 && Infinity) | (38..toString() && 5)) <= (c_1 += true > "function" != (-0 | -3) | (parseInt_1 += -2 >>> NaN) - "bar" % null))) & (1 - Infinity + ([ , 0 ].length === 2 & -0) ^ -(-5 != "object")) % (("foo" != "function") - +24..toString() ^ ("bar",
23..toString()) + (2 >= false)))) >> ((c = c + 1, -4) & undefined <= NaN || (parseInt_1 = ~2 <= void "foo") || ((false && 22) << ("number" ^ 4)) - (24..toString() >> 24..toString() && false <= 3)) - (c = c + 1,
c_1 && (c_1[(c = c + 1) + ((-1 ^ -3 ^ (1 || -1)) == 23..toString() + ([ , 0 ].length === 2) >> (c = c + 1,
38..toString()))] += ((22 & 38..toString()) - (22 < true)) / (!"bar", 22 & 1))) ^ delete (((25 - "foo" ^ (0 && -3)) > (this - 25 >= (parseInt_1 && (parseInt_1[(c = 1 + c,
(0 > 3 | 3 / Infinity) - ((3 != false) << ([ , 0 ][1] > -1)))] = 38..toString() ^ -4)))) * (((bar_1 += "foo" ^ "bar") & "undefined" > 23..toString()) / (parseInt_1 && (parseInt_1[!function bar_1() {
}()] = -([ , 0 ].length === 2) && [ , 0 ].length === 2 === [ , 0 ][1]))) & ((("foo" ^ null) >>> (22 === {})) - (parseInt_1_2 += (parseInt_1 && (parseInt_1[(c = 1 + c,
-4 + 4 | "number" * null, (23..toString() || -1) & -3 <= [])] = this - 1)) - (-3 | "foo")) ^ ((2 ^ "function") << ("object" >>> 38..toString())) - (null / 24..toString() ^ (c_1 && (c_1[(c = 1 + c,
(c = c + 1, [] | /[a2][^e]+$/) << ({} >> true) + (-4 >= 23..toString()))] = {} >> []))))));
},
"": [ !function() {
c = c + 1;
return --b + typeof [][(c = 1 + c, (Infinity >>> -4) + (c_1 && (c_1.NaN <<= 25 != -4)) || (-1 >> true) - (0 >> 38..toString()))];
}() ].b,
Infinity: a++ + (c_1 && c_1.in),
"\t": c_1 && c_1.undefined,
c: --b + +(("undefined" && true) < (false !== NaN) & ((c_1 && (c_1.foo += 2 << NaN)) | -4 != 24..toString()))
};
}
}
var Math_1;
console.log(null, a, b, c); original result:
evalmachine.<anonymous>:30
this.length+=(((parseInt_1_2 && (parseInt_1_2[((c = c + 1) + (b + 1-0.1-0.1-0.1))]=(((((("object">=22)/(4>>22))==(((-1)==2)!==(25. + (-5))))&&((bar_1 && (bar_1[((--b) + ([(c = 1 + c, (((({})>({}))==(([,0].length === 2)<<this))&((1>23..toString()) - (c_1 && (c_1[(c = 1 + c, (((2%25. )|(null>>> /[a2][^e]+$/ ))<(("","object"),(false>>([,0].length === 2)))))]=(-0>>>4)))))), (c = 1 + c, ((("bar"^([,0].length === 2))>=(undefined/false)) - (parseInt_1_2&=((false/"undefined") - (2!=="bar"))))), ].length))]=((parseInt_1 && (parseInt_1.foo=("undefined"&false)))<=([]>>> /[a2][^e]+$/ ))))&&((this/0) + (~(([,0].length === 2))))))>((((24 .toString()||(-2))>(4&""))/(((-2)>=([,0].length === 2)) + (22||25. )))>>>((((-5)/4)>>>("function",4))||(("undefined"/"function")!==((-1)*this)))))<=((parseInt_1 && (parseInt_1[(parseInt_1_2)]=((-(((22%(-2))!=("bar">=(-4))))) - ((("bar"^ /[a2][^e]+$/ )>=(true>>>Infinity))|((!(22))*(null,"number"))))))&((((""*-0)%(4<="undefined"))!=((24 .toString()>>(-5)) + (5&2
RangeError: Maximum call stack size exceeded
at RegExp.toString (<anonymous>)
at Object.set NaN [as NaN] (evalmachine.<anonymous>:30:1169)
at Object.set NaN [as NaN] (evalmachine.<anonymous>:30:1878)
at Object.set NaN [as NaN] (evalmachine.<anonymous>:30:1878)
at Object.set NaN [as NaN] (evalmachine.<anonymous>:30:1878)
at Object.set NaN [as NaN] (evalmachine.<anonymous>:30:1878)
at Object.set NaN [as NaN] (evalmachine.<anonymous>:30:1878)
at Object.set NaN [as NaN] (evalmachine.<anonymous>:30:1878)
at Object.set NaN [as NaN] (evalmachine.<anonymous>:30:1878)
at Object.set NaN [as NaN] (evalmachine.<anonymous>:30:1878) |
Is that an official ECMAScript thing or a V8 array optimization? I thought it should have converted the integer index into a string as per the negative key below:
|
Not sure, but IE11 behaves the same way with regards to |
Also $ node
> var a = []
> a[1e10] = 1
1
> a
[ '10000000000': 1 ] |
It's a pseudo standard. I think browsers copied the implementation of the original netscape engine and this array behavior has never been officially standardized.
|
- give globally distinct names to distinct variables - improve ability to compress cross-scoped - introduce `options.rename` to `minify()` - default `true` if both `compress` & `mangle`
Introduce
options.rename
, default totrue
if bothoptions.compress
andoptions.mangle
are enabled.Before
After