Dart VM

by a frontend developer

Dart VM

by a frontend developer

still a compiler engineer

Three VM whales

Representation

Resolution

Redundancy

JavaScript


var p = Object.create({
  len: function () {
    return Math.sqrt(this.x * this.x +
                     this.x * this.y);
  }
});
p.x = 10;
p.y = 20;

size of p?

where p.x goes?

what is p.len()?


var arr = [0,1,2,3,,5];

var arr = [0,1,2,3, /* I am a hole! */,5];

Array.prototype[4] = "Hello, from the Hole";
var arr = [0,1,2,3,,5];
console.log(arr[4]);

var arr = [0,1,2,3,,5];
console.log(arr["1"]);

var dblArr = [0,1.0,2.1,3.0,,5.0];
// can dblArr be almost as efficient as Float64Array?

var dblArr = [0,1.0,2.1,3.0,,5.0];
dblArr[6] = dblArr[6] * Math.PI;
// dblArr[6] is NaN now

properties come and go

methods are properties

no early errors

MUST: for each object
find efficient representation
while program runs

hidden classes
&
transitions

very powerful

very complex

very powerful

very complex

much heuristic


p /* => class {
  x: @1, y: @2,
  proto => class {
    len: @const function
  }
}*/

dblArr /* => class {
  elements: DOUBLES,
  holes: true
}*/

same hidden class

means

same structure

hidden classes
enable
inline caching

inline caching

old fundamental optimization


p.x // remember what we saw
    // where we found x.

p.x /* => {
  [class 0xf3123bc5]: { @1 }
}*/

x * y /* => {
  [DOUBLE, DOUBLE]: {
    result: DOUBLE
  },
  [SMI, SMI]: {
    result: INT32
  }
}*/

Now Dart

fixed class objects

real arrays
(fixed length too)

int, double, simd
separated

early errors and lack of coercions

predictable for VM & programmer

Still dynamically typed

Still use ICs

simple PICs not V8's specialized IC stubs

Still use ICs

simple PICs not V8's specialized IC stubs

non-opt + opt compilation pipeline

inlining, type inferencing, range inferencing, primitive unboxing, constant propagation, common subexpression elimination, loop invariant code motion, load forwarding, dead store elimination, allocation sinking, block reordering, branch folding

optimizations simplified or enabled by semantics


for (...) {
  CheckClass(x, A);
  CallSmth();
  /* x is still A */
}

load forwarding & allocation sinking


for (var x in list) {
  // use x
}

var iter = list.iterator;
while (it.moveNext()) {
  var x = it.current;
}

var iter = new ListIterator(list);
while (it.moveNext()) {
  var x = it.current;
}

var iter = $alloc(ListIterator);
iter.list = list;
iter.idx = -1;
while (++iter.idx < it.list.length) {
  var x = it.list[it.idx];
}

var iter = $alloc(ListIterator);
iter.list = list;
iter.idx = -1;
while (++iter.idx < it.list.length) {
  var x = it.list[it.idx];
}

var iter = $alloc(ListIterator);
iter.list = list;
iter.idx = -1;
while (++iter.idx < it.list.length) {
  var x = it.list[it.idx];
}

var iter = $alloc(ListIterator);
iter.list = list;
iter.idx = -1;
while (++iter.idx < list.length) {
  var x = list[it.idx];
}

var iter = $alloc(ListIterator);
iter.list = list;
var $idx = iter.idx = -1;
while ((iter.idx = ++$idx) < list.length) {
  var x = list[$idx];
}

var iter = $alloc(ListIterator);
iter.list = list;
var $idx = iter.idx = -1;
var $list_length = list.length; // LICM
while ((iter.idx = ++$idx) < $list_length) {
  var x = list[$idx];
}

/* var iter = $alloc(ListIterator); */
/* iter.list = list; */
var $idx /* = iter.idx */ = -1;
var $list_length = list.length;
while ((/* iter.idx = */ ++$idx) < $list_length) {
  var x = list[$idx];
}

var $idx = -1;
var $list_length = list.length;
while (++$idx < $list_length) {
  var x = list[$idx];
  // use(x)
}

not limited to iterators!


class Vec2 {
  final x;
  final y;
  Vec2(this.x, this.y);

  operator + (other) =>
     new Vec2(x + other.x, y + other.y);
  operator * (other) => x * other.x + y * other.y;
}

final v = (v1 + v2) * (v3 + v4);
// 0 allocations

Thanks!
Q&A