Dart & Javascript on single VM

7 views
Skip to first unread message

Duane Sand

unread,
Oct 12, 2011, 11:01:26 AM10/12/11
to General Dart Discussion
Are the underlying semantics of the Dart and Ecmascript languages
close enough that both can be efficiently implemented in a single V8-
style virtual machine? Or are there differences which pragmatically
mean that getting the best performance for each will require separate
implementations?

Florian Loitsch

unread,
Oct 12, 2011, 1:32:09 PM10/12/11
to Duane Sand, General Dart Discussion
For best performance one definitely needs separate implementations. Just three very small examples (there are hundreds more):
1. in JS it is possible to replace global functions. If I want to inline such a function I also need to compile a check that the inlined function is still the same. In Dart it is not possible to change static function. Inlining thus becomes faster.
2. in JS all numbers are doubles. In dart there are integers and doubles. Under the hood a JS (V8-like) VM optimizes for integers too, but needs to keep in mind that a double can only represent 53bits of integers efficiently. This leads to the strange situation that on 64-bit machines only 32bit of integers are optimized.
A Dart VM can go up to 63 bits (before switching to big integers).
3. A JS VM needs to guess the class description of objects (it does this using "hidden classes"). That is it assigns a guessed class-description to every object it sees. This is much less efficient than having the description given to it as part of the source-code.

// florian

--
Give a man a fire and he's warm for the whole day,
but set fire to him and he's warm for the rest of his life. - Terry Pratchett

Rémi Forax

unread,
Oct 12, 2011, 2:11:48 PM10/12/11
to mi...@dartlang.org
On 10/12/2011 07:32 PM, Florian Loitsch wrote:
On Wed, Oct 12, 2011 at 17:01, Duane Sand <duane....@gmail.com> wrote:
Are the underlying semantics of the Dart and Ecmascript languages
close enough that both can be efficiently implemented in a single V8-
style virtual machine?  Or are there differences which pragmatically
mean that getting the best performance for each will require separate
implementations?
For best performance one definitely needs separate implementations. Just three very small examples (there are hundreds more):
1. in JS it is possible to replace global functions. If I want to inline such a function I also need to compile a check that the inlined function is still the same. In Dart it is not possible to change static function. Inlining thus becomes faster.

The JVM is able to optimize this case :)
The interpreter does the check but the JIT remove the check and install a dependency
to invalidate the generated assembler code if the global function is changed and
deopt back to the interpreter.
I think cranksaft is able to do this kind of deopt.


2. in JS all numbers are doubles. In dart there are integers and doubles. Under the hood a JS (V8-like) VM optimizes for integers too, but needs to keep in mind that a double can only represent 53bits of integers efficiently. This leads to the strange situation that on 64-bit machines only 32bit of integers are optimized.
A Dart VM can go up to 63 bits (before switching to big integers).
3. A JS VM needs to guess the class description of objects (it does this using "hidden classes"). That is it assigns a guessed class-description to every object it sees. This is much less efficient than having the description given to it as part of the source-code.

// florian

Rémi

Florian Loitsch

unread,
Oct 12, 2011, 2:17:03 PM10/12/11
to Rémi Forax, mi...@dartlang.org
On Wed, Oct 12, 2011 at 20:11, Rémi Forax <fo...@univ-mlv.fr> wrote:
On 10/12/2011 07:32 PM, Florian Loitsch wrote:
On Wed, Oct 12, 2011 at 17:01, Duane Sand <duane....@gmail.com> wrote:
Are the underlying semantics of the Dart and Ecmascript languages
close enough that both can be efficiently implemented in a single V8-
style virtual machine?  Or are there differences which pragmatically
mean that getting the best performance for each will require separate
implementations?
For best performance one definitely needs separate implementations. Just three very small examples (there are hundreds more):
1. in JS it is possible to replace global functions. If I want to inline such a function I also need to compile a check that the inlined function is still the same. In Dart it is not possible to change static function. Inlining thus becomes faster.

The JVM is able to optimize this case :)
The interpreter does the check but the JIT remove the check and install a dependency
to invalidate the generated assembler code if the global function is changed and
deopt back to the interpreter.
Class changes are extremely rare in the JVM.
 
I think cranksaft is able to do this kind of deopt.
Crankshaft checks at every access unless it just did the check and knows that nothing could have changed in the mean-time. Typically calling another function invalidates all assumptions.
// florian



2. in JS all numbers are doubles. In dart there are integers and doubles. Under the hood a JS (V8-like) VM optimizes for integers too, but needs to keep in mind that a double can only represent 53bits of integers efficiently. This leads to the strange situation that on 64-bit machines only 32bit of integers are optimized.
A Dart VM can go up to 63 bits (before switching to big integers).
3. A JS VM needs to guess the class description of objects (it does this using "hidden classes"). That is it assigns a guessed class-description to every object it sees. This is much less efficient than having the description given to it as part of the source-code.

// florian

Rémi

Rémi Forax

unread,
Oct 12, 2011, 2:24:22 PM10/12/11
to Florian Loitsch, mi...@dartlang.org
On 10/12/2011 08:17 PM, Florian Loitsch wrote:
On Wed, Oct 12, 2011 at 20:11, Rémi Forax <fo...@univ-mlv.fr> wrote:
On 10/12/2011 07:32 PM, Florian Loitsch wrote:
On Wed, Oct 12, 2011 at 17:01, Duane Sand <duane....@gmail.com> wrote:
Are the underlying semantics of the Dart and Ecmascript languages
close enough that both can be efficiently implemented in a single V8-
style virtual machine?  Or are there differences which pragmatically
mean that getting the best performance for each will require separate
implementations?
For best performance one definitely needs separate implementations. Just three very small examples (there are hundreds more):
1. in JS it is possible to replace global functions. If I want to inline such a function I also need to compile a check that the inlined function is still the same. In Dart it is not possible to change static function. Inlining thus becomes faster.

The JVM is able to optimize this case :)
The interpreter does the check but the JIT remove the check and install a dependency
to invalidate the generated assembler code if the global function is changed and
deopt back to the interpreter.
Class changes are extremely rare in the JVM.

It's more, after some time, class changes are rare,
discovering a new class is frequent during the initialization of the application.


 
I think cranksaft is able to do this kind of deopt.
Crankshaft checks at every access unless it just did the check and knows that nothing could have changed in the mean-time. Typically calling another function invalidates all assumptions.

You mean a function that is not inlined.

Anyway, you can do this kind of optimizations on a server because you will run the code
for days but not in a browser or you need tiered compilation.

// florian

Rémi

Duane Sand

unread,
Oct 12, 2011, 4:01:45 PM10/12/11
to General Dart Discussion


On Oct 12, 10:32 am, Florian Loitsch <floit...@google.com> wrote:
> On Wed, Oct 12, 2011 at 17:01, Duane Sand <duane.1.s...@gmail.com> wrote:
> > Are the underlying semantics of the Dart and Ecmascript languages
> > close enough that both can be efficiently implemented in a single V8-
> > style virtual machine?  Or are there differences which pragmatically
> > mean that getting the best performance for each will require separate
> > implementations?
>
> For best performance one definitely needs separate implementations. Just
> three very small examples (there are hundreds more):
> 1. in JS it is possible to replace global functions. If I want to inline
> such a function I also need to compile a check that the inlined function is
> still the same. In Dart it is not possible to change static function.
> Inlining thus becomes faster.

Dart style defaults to function names being immutably bound to a
specific function body.
But Dart can also express the JS flavor of (seldom-changed) function
pointers:

var foo = (arg1, arg2) { ... };

So Dart's Vm can easily handle foo() calls after foo has been
reassigned.
If Dart VM made the reasonable guess that var foo is never or rarely
reassigned,
it could generate exactly the same runtime check that V8 now does for
Javascript.


> 2. in JS all numbers are doubles. In dart there are integers and doubles.
> Under the hood a JS (V8-like) VM optimizes for integers too, but needs to
> keep in mind that a double can only represent 53bits of integers
> efficiently. This leads to the strange situation that on 64-bit machines
> only 32bit of integers are optimized.
> A Dart VM can go up to 63 bits (before switching to big integers).

The same handling of 63-bit ints could be done in a future version of
V8.
Or this optimization for 33..63 bit integers could be dropped from
both,
as a rarely profitable trick. (Was this motivated by Uint32Arrays?)



> 3. A JS VM needs to guess the class description of objects (it does this
> using "hidden classes"). That is it assigns a guessed class-description to
> every object it sees. This is much less efficient than having the
> description given to it as part of the source-code.

Yes. That difference particularly applies during the initial runs of
a function,
before either V8 or dartvm recompiles hot functions with their
optimizing
code generator. Perhaps things are less different, during
optimization
and during execution of the optimized code?

I thought Dart can express the case where a named object has
unpredicted type
and hence unknown class description. In those cases, the dart vm will
either
need to do the slow symbol table lookups every time, or apply the same
class
discovery and cached binding methods as V8.

Florian Loitsch

unread,
Oct 12, 2011, 4:43:47 PM10/12/11
to Duane Sand, General Dart Discussion
You asked for best performance...
Also note that supporting both languages would makes the VM much more difficult. Adding support for strict mode to V8 is already a pain.
Now, to be clear, you can have one VM that has the best performance for both languages, by simply having two different code-bases merged together into one program. You might even be able to share some code, but at some point it just gets too complicated.
You argue below that the Dart-VM could make global function calls (for JS programs) as efficient as V8 by doing the same "did-the-global-function-change?" check as V8. That's obviously true, but you can say that for every difference. If the Dart-Vm did the same thing as V8 it would never be slower.
The point is, that it doesn't need to do these things which makes its life easier.


No it cannot. V8 must only allow 53bits.

Or this optimization for 33..63 bit integers could be dropped from
both,
as a rarely profitable trick.  (Was this motivated by Uint32Arrays?)
It's just more efficient on 64-bit machines. 



> 3. A JS VM needs to guess the class description of objects (it does this
> using "hidden classes"). That is it assigns a guessed class-description to
> every object it sees. This is much less efficient than having the
> description given to it as part of the source-code.

Yes.  That difference particularly applies during the initial runs of
a function, before either V8 or dartvm recompiles hot functions with their
optimizing code generator.  Perhaps things are less different, during
optimization and during execution of the optimized code?
This is not just a start-up problem. Objects run through class-transitions whenever a new field is added. Unless a program stops creating new objects (and assigning fields to them) the hidden-class problem is still there. (Note that a good JS program can avoid most of them, but that's another story).


I thought Dart can express the case where a named object has unpredicted type and hence unknown class description.  In those cases, the dart vm will either
need to do the slow symbol table lookups every time, or apply the same class discovery and cached binding methods as V8.
Yes. When the class is unknown Dart has to do a hashtable lookup too. (Probably less costly, since there are no prototype-chains).

// florian
 


>
> // florian
>
> --
> Give a man a fire and he's warm for the whole day,
> but set fire to him and he's warm for the rest of his life. - Terry
> Pratchett
Reply all
Reply to author
Forward
0 new messages