Dart is the language a Smalltalk VM guru would build after getting fed up with trying to make Javascript go fast. The semantics seem very well-selected to include only dynamic language features that we know how to make fast.
So the V8 lineage of VM's (including Strongtalk and Self) has two major tricks: type feedback and optimistic inlining with deoptimization. They can see what implementations of a method are actually being reached at given call-site and then optimistically inline those specific implementations, transparently deoptimizing the call-site if that inlining later becomes invalid. You can support a lot of dynamic features on top of this framework:
1) Sensible numerics. Dart numbers are represented as integers until they can't be, overflowing to bignums if necessary. The semantics are similar to Smalltalk's or CL's except without exact fractions which is a reasonable design decision in this day and age.
If a given invocation of '+' is always operating on integers, the VM can emit a regular integer addition plus a type-check. If sometime later a float appears and the type-check fails, the VM can fall back to the generic implementation of '+'.
Unrelated to the above, we've known pretty much forever how to efficiently represent integers in a tagged fashion so they don't need to be treated as a special "primitive" type.
2) Generic operators. '+' and '-' are methods rather than special functions as in CL. For the reasons outlined above, there is no reason to special-case '+' or other common operators in the VM. The VM can always inline whatever actual implementation of the operator is actually being invoked at any given call-site.
3) Generic iteration objects. There is no reason to special-case iteration for arrays versus lists, etc. If a loop always ends up iterating over an array, there is no reason the use of the Iterator.next() method can't be optimistically compiled down to a simple pointer increment plus dereference.
4) Higher-order functions. There is no reason to discourage use of higher-order functions in tight loops (e.g. with map or similar functional constructs). If the same function is always called in the loop the VM can optimistically inline that function.
Some of the things that Dart leaves out are introspection related. There is no Python obj.__dict__ which would make it hard to implement objects as linear structures. There is no introspection of the stack frame as in Python's locals() or Javascripts arguments object which make it harder to allocate local variables to registers (or represent them as SSA values in an optimizer). LuaJIT is at the cutting-edge of optimizing-away some features like these, but it's not well-understood yet.
Can anyone give more information about the thread lock in class initialization that he's talking about? Is he talking about static class initializers?
If so, I agree with him that these definitely seem like a terrible idea, along with destructors in java (in c++ they are fine because you call them explicitly). I wonder if anyone has actually found a good use for them.
5 comments
[ 3.8 ms ] story [ 22.5 ms ] thread1) Sensible numerics. Dart numbers are represented as integers until they can't be, overflowing to bignums if necessary. The semantics are similar to Smalltalk's or CL's except without exact fractions which is a reasonable design decision in this day and age.
If a given invocation of '+' is always operating on integers, the VM can emit a regular integer addition plus a type-check. If sometime later a float appears and the type-check fails, the VM can fall back to the generic implementation of '+'.
Unrelated to the above, we've known pretty much forever how to efficiently represent integers in a tagged fashion so they don't need to be treated as a special "primitive" type.
2) Generic operators. '+' and '-' are methods rather than special functions as in CL. For the reasons outlined above, there is no reason to special-case '+' or other common operators in the VM. The VM can always inline whatever actual implementation of the operator is actually being invoked at any given call-site.
3) Generic iteration objects. There is no reason to special-case iteration for arrays versus lists, etc. If a loop always ends up iterating over an array, there is no reason the use of the Iterator.next() method can't be optimistically compiled down to a simple pointer increment plus dereference.
4) Higher-order functions. There is no reason to discourage use of higher-order functions in tight loops (e.g. with map or similar functional constructs). If the same function is always called in the loop the VM can optimistically inline that function.
Some of the things that Dart leaves out are introspection related. There is no Python obj.__dict__ which would make it hard to implement objects as linear structures. There is no introspection of the stack frame as in Python's locals() or Javascripts arguments object which make it harder to allocate local variables to registers (or represent them as SSA values in an optimizer). LuaJIT is at the cutting-edge of optimizing-away some features like these, but it's not well-understood yet.
If so, I agree with him that these definitely seem like a terrible idea, along with destructors in java (in c++ they are fine because you call them explicitly). I wonder if anyone has actually found a good use for them.