HoriSun / closure-compiler

Automatically exported from code.google.com/p/closure-compiler
0 stars 0 forks source link

Const folding with type annotation #1254

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Hi,

we had this topic already with #1209, but I wasn't sure if you read closed 
tickets. The final words were, that you can't fold unless you're 100% sure that 
the variable is a number. But what about annotations? I got another example:

(function(w) {
                /**
                 * foo
                 * 
                 * @type number
                 */
var z = 9;
w.x=function() {
return 3+z-3+1;
}
w.y=function(x) {
z = x;
}
})(this);

Function "y" is just there to make "z" not read-only. You would expect that CG 
can compress this in the optimal case to "return z+1", but in fact it doesn't 
change anything:

(function(a){var b=9;a.x=function(){return 
3+b-3+1};a.y=function(a){b=a}})(this);

Robert

Original issue reported on code.google.com by seo...@googlemail.com on 24 Feb 2014 at 11:44

GoogleCodeExporter commented 9 years ago
If you write 'var y' instead of 'w.y' then the compiler figures out that the 
function is never called, removes it, and switches to 
"(function(a){a.x=function(){return 10}})(this);"

It seems correct to me that if you're adding a function to the global object, 
the compiler should not assume that function will never be called. And of 
course, if it thinks w.y might be called at some point, then it can't assume z 
will always be 9.

Original comment by tbreisac...@google.com on 26 Feb 2014 at 12:12

GoogleCodeExporter commented 9 years ago
The issue here isn't that Z is changing but that the other constants aren't 
folded.  We don't currently use types for this kind of optimization.  If we did 
we would have to ignore declared type information:

/** @param {number} a */
function f(a) {
  var safeA = a - 0;  // force a to be a number, in case someone passed us something else.

  // or
  if (a !== (0 - a)) throw "invalid parameter";
}

There is quite a difference between "expectations" and "guarantees" and the 
annotations are not "guarantees".

Original comment by concavel...@gmail.com on 27 Feb 2014 at 5:07

GoogleCodeExporter commented 9 years ago
I think, if there are annotations, chances are much higher that the user gives 
a guarantee instead of an expectation. The user doesn't have any other chance 
to give the CC any optimization hints, so treating it more strict makes much 
more sense in my opinion.

But nevertheless, all the constant factors in an equation can be folded anyway, 
as long as the compiler doesn't lose type information, such as: x * 1 + 4 - 3, 
which can only be folded to "x * 1 + 1", as long as there is no {number} 
annotation present. Otherwise it could be folded to "x + 1".

Original comment by seo...@googlemail.com on 28 Feb 2014 at 12:07

GoogleCodeExporter commented 9 years ago
To be fair, this has been bought up many times. It's a good idea, IMHO at 
least. But let me bore everyone with the technical details on why the team is 
hesitated to do this:

1. "expectations" vs "guarantees" concept that John mentioned.  In other word, 
soundness. The type system is inherently not sound. Optimizations that is based 
on the type system will not be sound. Does this mean we can't do it? Not 
really, we have type based optimizations in advance mode. But we can need to be 
careful on how much risk we take for the gain we get from it.

2. Like I mentioned in #1209. A truly safe solution to optimize with reordering 
order of operation requires Range Analysis. Example:

> Number.MAX_VALUE * 2 / 2
Infinity

> Number.MAX_VALUE * (2 / 2)
1.7976931348623157e+308

It doesn't mean we should do it. With the type inference being improved 
constantly by dimvar / ben, we should leverage their work. However,  the size 
saving for this particular case given the amount of work + compilation time 
increase we are looking at, the marginal gain we get is small unless you can 
show us some code base that can greatly benefit from this.

Original comment by acle...@gmail.com on 28 Feb 2014 at 9:18

GoogleCodeExporter commented 9 years ago
Let me reiterate #2: 
We can not perform these kinds of operations unless we can prove:
1) The code is not exported
2) We can know the type due to properties of the language

To do otherwise would open exploitable security holes:

/** @param {number} a */ 
function f(a) {
  return Function("return " + Number(a) + ";");
};

Optimizations based on declared types would allow:

/** @param {number} a */ 
function f(a) {
  return Function("return " + a + ";");
};

Original comment by concavel...@gmail.com on 1 Mar 2014 at 6:08

GoogleCodeExporter commented 9 years ago
Issue tracking has been migrated to github. Please make any further comments on 
this issue through https://github.com/google/closure-compiler/issues

Original comment by blic...@google.com on 1 May 2014 at 6:31

GoogleCodeExporter commented 9 years ago

Original comment by blic...@google.com on 1 May 2014 at 6:34