
Why dart2js produces faster JavaScript code from Dart - stesch
http://news.dartlang.org/2013/03/why-dart2js-produces-faster-javascript.html
======
bsimpson
I'm not terribly familiar with the details of Dart. How does it know that
something can never be null? Maybe an external caller sends null to a method
not expecting it. Or, can you not call Dart compiled code from JS?

~~~
munificent
> How does it know that something can never be null?

It can see every place it gets assigned. If it's never assigned from something
that can be null, it can't be null. Of course, that requires global inference
to determine the possible types that the RHS can be. dart2js does that with
increasing sophistication.

> Maybe an external caller sends null to a method not expecting it.

dart2js is a whole program compiler so it can make closed world assumptions
like this. At the point that it's compiling, there are no "external" callers.
It can see every callsite in the entire program.

> Or, can you not call Dart compiled code from JS?

Yes, Dart does have a JS interop story[1]. We're still working on it, but, by
design, it's not as seamless as say CoffeeScript. It's an actual _interop_
process and not just "it's all JS so it can all call each other". I think that
helps dart2js control the places where unknown values can leak in from JS.

[1]: <http://www.dartlang.org/articles/js-dart-interop/>

~~~
lmkg
Is this a limitation of Dart in general, or just the Dart2JS framework?

Doing whole-program analysis seems like it would restrict your deployment
methods, right? It's fairly common in the JS world to be calling into
libraries that are split into separate files and hosted on external servers.
Something like jQuery you do it for the load times, something like Google
Analytics you do it so that Google can push updates without you needing to
redeploy your script. There are also possible use cases with lazy-loading
libraries for load times, or only loading scripts on certain pages.

Does the whole-program compiling approach mean that I would have to import
whole libraries into my own project in order to use them, and that I can only
deploy single script files? How does the whole-program approach interact with
event handlers embedded in HTML, which it would not have visibility into?

I would expect that some of these restrictions could maybe be eased in a
native-Dart client. But given that for the foreseeable future most Dart
projects will have to target non-Dart-enabled clients, in practical terms Dart
as a whole will have to be shackled to any limitations in Dart2JS. I'm curious
what your thoughts on this are and if you have any plans to address it.

~~~
floitsch
This is a property of dart2js. (I wouldn't call it a limitation nor a
feature). Dart2js takes your whole program and compiles it to JavaScript.

Dart2js needs to see all the libraries that are used. It performs tree-shaking
to remove unused parts and then compiles the rest to JavaScript. By default
dart2js produces one big JavaScript file, but it can cut your program on
library boundaries that can be loaded lazily. This is still work in progress
(only allows to split into 2 files so far) but looks promising.

The lazy loading needs to be done by the user before parts of the lazy library
are used.

I don't see how event-handlers change the game. The html-library is a library
like any other.

~~~
lnanek2
There are a lot JS frameworks nowadays where there is no HTML, really, just a
little something to trigger the script. Everything else is JavaScript
generated and inserted HTML. I don't see how this could handle something like
a new anchor being added with an javascript: href, or even just the eval
command, for example. Doesn't seem smart to break JS compatibility like this
if the language wants to win any mind share.

~~~
sethladd
[disclaimer, I work on the Dart team]

While I do believe our Dart/JavaScript interop story will continue to be
refined, I do want to point out that the days of javascript: URLs and eval are
nearly over. The Web is getting a stronger security model through CSP [1]
(content security policy). New restrictions put in place by CSP include
turning off eval, new Function, inline JavaScript, and more. This is a very
good thing, because it reduces the attack vectors for XSS and more.

[1] [http://www.html5rocks.com/en/tutorials/security/content-
secu...](http://www.html5rocks.com/en/tutorials/security/content-security-
policy/)

------
podperson
Doesn't a 30% performance improvement (I'm just talking dart vs. JavaScript,
not dart2js generated code vs JavaScript) seem like a pretty weak result given
that they've created a new language? Sure, performance isn't the _only_
argument for Dart, but still.

It seems to me that if we're going to migrate away from JavaScript, let's get
a serious performance boost while we're at it.

~~~
pekk
It seems to me that a nicer language even with a slight performance hit would
be an advantage. Let alone 30% improvement

~~~
podperson
There are other downsides to a new language, so if you're going to get people
to migrate you need some pretty big wins. Javascript is (a) not a terrible
language (despite its warts) and (b) not a static target.

------
marchopy
GWT has been doing this for years, i'm actually surprised Dart has only just
got it, given that both come from google.

~~~
sethladd
Good point, Dart2js isn't the only compiler that can apply optimizations. I
believe Closure Compiler also performs optimizations. Both GWT and Closure
have been out for years, to be fair. :)

[disclaimer: I work on the Dart team]

~~~
cromwellian
We do some global inferencing in GWT, but we don't do range check elimination.
There was a 20% contributor who added it at one point, but it never landed. We
tighten types by looking at flow into and out of methods globally and locally
(e.g. if you method says it return Object, but you return new Foo(), we
consider the method as actually returning Foo). We also do nullability
analysis, so for example, we can short circuit an if(x instanceof Foo) if x is
known to be null, or Foo is a null type (never instantiated anywhere)

------
hencq
The article mentions that for optimizing out of bounds checks it uses constant
lists or fixed length lists. Could it also optimize the check in a loop if it
knows the loop ends at the end of the list? For example, in the article it
mentions:

    
    
      for (int i = 0; i < v.constraints.length; i++) {
        ...
        c = t1[i]; 
        ...
      }
    

Does it do that optimization because it knows v.constraints is fixed length or
because it knows that i can never be bigger than v.constraints.length?

~~~
floitsch
dart2js does range analyses. For example the indexing in the following example
will not do any bounds checks.

    
    
        for (int i = 0; i < list.length; i++) {
          var t = list[i];
        }
    

Things get more complicated when there are function calls in the loop-body
that could potentially change the list-length:

    
    
        for (int i = 0; i < list.length; i++) {
          foo("random call", list);  // could have side-effect.
          var t = list[i];  // needs to check bounds.
        }
    

However if the element is read before the call, it should still work:

    
    
        for (int i = 0; i < list.length; i++) {
          var t = list[i];  // no need for bounds-check.
          foo("random call", list);  // could have side-effect.
        }
    

The last example doesn't need a bounds-check, but it does need to reload the
length-field of the list at every iteration (in case the length changed).

