[kernel] [partial] Streaming of kernel binary without AST nodes

This CL allows for streaming big parts of the binary,
i.e. without using the AST nodes.
It is thus a stepping-stone in getting rid of the AST nodes in the VM.

Generally, all Expressions except "FunctionExpression",
and all Statements except "FunctionDeclaration" can be streamed.

There are currently not streamed because they create new functions,
which has a pointer to an AstNode (which we don't have when streaming).

Once we no longer need AstNodes at all these can be streamed as well.
This is, I think, mostly a matter of streaming the ScopeBuilder as well,
something that is not currently done.

The way the streaming is build, one has to stream an entire subtree.
That means, that if an expression (or statement), A, that is generally
streamable contains an expression or a statement, B, that is not streamable,
A cannot be streamed.
The way this is build is by marking AstNodes as streamable or not
("cannot_stream_" field). That way we know up front whether we can stream
a subtree or not.

The streaming is done via "kernel_binary_flowgraph".

In this file there are many obvious comments, e.g.
```
  TokenPosition position = ReadPosition();  // read position.
```
This has been done in an attempt to add a comment to everything that
reads from the binary to make it stand out more.

All changes from kernel_to_il up to and including May 2nd 2017
should be included.

R=kmillikin@google.com

Review-Url: https://codereview.chromium.org/2854393002 .
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index a8fa140..5f3d560 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -46,6 +46,12 @@
   UInt length;
   T[length] items;
 }
+
+// Untagged pairs.
+type Pair<T0, T1> {
+  T0 first;
+  T1 second;
+}
 ```
 
 A string table consists of an array of end offsets and a payload array of
@@ -346,6 +352,7 @@
 type VariableGet extends Expression {
   Byte tag = 20;
   FileOffset fileOffset;
+  UInt variableDeclarationPosition; // Byte offset in the binary for the variable declaration.
   VariableReference variable;
 }
 
@@ -353,11 +360,13 @@
   Byte tag = 128 + N; // Where 0 <= N < 8.
   // Equivalent to a VariableGet with index N.
   FileOffset fileOffset;
+  UInt variableDeclarationPosition; // Byte offset in the binary for the variable declaration.
 }
 
 type VariableSet extends Expression {
   Byte tag = 21;
   FileOffset fileOffset;
+  UInt variableDeclarationPosition; // Byte offset in the binary for the variable declaration.
   VariableReference variable;
   Expression value;
 }
@@ -365,6 +374,7 @@
 type SpecializedVariableSet extends Expression {
   Byte tag = 136 + N; // Where 0 <= N < 8.
   FileOffset fileOffset;
+  UInt variableDeclarationPosition; // Byte offset in the binary for the variable declaration.
   Expression value;
   // Equivalent to VariableSet with index N.
 }
@@ -429,6 +439,7 @@
 
 type Arguments {
   // Note: there is no tag on Arguments.
+  UInt numArguments; // equals positional.length + named.length
   List<DartType> types;
   List<Expression> positional;
   List<NamedExpression> named;
@@ -782,8 +793,7 @@
 
 type SwitchCase {
   // Note: there is no tag on SwitchCase
-  List<Expression> expressions;
-  FileOffset[expressions.length] expressionOffsets; // 1-to-1 with expressions.
+  List<Pair<FileOffset, Expression>> expressions;
   Byte isDefault; // 1 if default, 0 is not default.
   Statement body;
 }
@@ -819,6 +829,7 @@
 type TryCatch extends Statement {
   Byte tag = 75;
   Statement body;
+  Byte anyCatchNeedsStackTrace; // 1 if any catch needs a stacktrace (have a stacktrace variable).
   List<Catch> catches;
 }
 
@@ -910,6 +921,7 @@
   Byte tag = 94;
   List<TypeParameter> typeParameters;
   UInt requiredParameterCount;
+  UInt totalParameterCount; // positionalParameters.length + namedParameters.length
   List<DartType> positionalParameters;
   List<NamedDartType> namedParameters;
   DartType returnType;
@@ -949,7 +961,10 @@
   // the class type parameters in a constructor refer to those declared on the
   // class.
   UInt index;
-  
+
+  // Byte offset in the binary for the type declaration.
+  // Note: This can also be 0, which is a 'forward reference' and is not to be used.
+  UInt typeParameterPosition;
   Option<DartType> bound;
 }
 
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 59fc9ed..c1b6670 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -3586,6 +3586,9 @@
   int flags = 0;
   DartType type; // Not null, defaults to dynamic.
 
+  /// Offset of the declaration, set and used when writing the binary.
+  int binaryOffset = -1;
+
   /// For locals, this is the initial value.
   /// For parameters, this is the default value.
   ///
@@ -4169,6 +4172,9 @@
   /// be set to the root class for type parameters without an explicit bound.
   DartType bound;
 
+  /// Offset of the declaration, set and used when writing the binary.
+  int binaryOffset = 0;
+
   TypeParameter([this.name, this.bound]);
 
   accept(TreeVisitor v) => v.visitTypeParameter(this);
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index e5af2a3..db11ce4 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -665,19 +665,23 @@
         return new InvalidExpression();
       case Tag.VariableGet:
         int offset = readOffset();
+        readUInt(); // offset of the variable declaration in the binary.
         return new VariableGet(readVariableReference(), readDartTypeOption())
           ..fileOffset = offset;
       case Tag.SpecializedVariableGet:
         int index = tagByte & Tag.SpecializedPayloadMask;
         int offset = readOffset();
+        readUInt(); // offset of the variable declaration in the binary.
         return new VariableGet(variableStack[index])..fileOffset = offset;
       case Tag.VariableSet:
         int offset = readOffset();
+        readUInt(); // offset of the variable declaration in the binary.
         return new VariableSet(readVariableReference(), readExpression())
           ..fileOffset = offset;
       case Tag.SpecializedVariableSet:
         int index = tagByte & Tag.SpecializedPayloadMask;
         int offset = readOffset();
+        readUInt(); // offset of the variable declaration in the binary.
         return new VariableSet(variableStack[index], readExpression())
           ..fileOffset = offset;
       case Tag.PropertyGet:
@@ -949,10 +953,12 @@
         switchCaseStack.addAll(cases);
         for (int i = 0; i < cases.length; ++i) {
           var caseNode = cases[i];
-          _fillTreeNodeList(caseNode.expressions, readExpression, caseNode);
-          caseNode.expressionOffsets.length = caseNode.expressions.length;
-          for (int i = 0; i < caseNode.expressionOffsets.length; ++i) {
+          int length = readUInt();
+          caseNode.expressions.length = length;
+          caseNode.expressionOffsets.length = length;
+          for (int i = 0; i < length; ++i) {
             caseNode.expressionOffsets[i] = readOffset();
+            caseNode.expressions[i] = readExpression()..parent = caseNode;
           }
           caseNode.isDefault = readByte() == 1;
           caseNode.body = readStatement()..parent = caseNode;
@@ -969,7 +975,9 @@
         int offset = readOffset();
         return new ReturnStatement(readExpressionOption())..fileOffset = offset;
       case Tag.TryCatch:
-        return new TryCatch(readStatement(), readCatchList());
+        Statement body = readStatement();
+        readByte(); // whether any catch needs a stacktrace.
+        return new TryCatch(body, readCatchList());
       case Tag.TryFinally:
         return new TryFinally(readStatement(), readStatement());
       case Tag.YieldStatement:
@@ -1070,8 +1078,10 @@
         int typeParameterStackHeight = typeParameterStack.length;
         var typeParameters = readAndPushTypeParameterList();
         var requiredParameterCount = readUInt();
+        var totalParameterCount = readUInt();
         var positional = readDartTypeList();
         var named = readNamedTypeList();
+        assert(positional.length + named.length == totalParameterCount);
         var returnType = readDartType();
         typeParameterStack.length = typeParameterStackHeight;
         return new FunctionType(positional, returnType,
@@ -1084,6 +1094,7 @@
         return new FunctionType(positional, returnType);
       case Tag.TypeParameterType:
         int index = readUInt();
+        readUInt(); // offset of the TypeParameter declaration in the binary.
         var bound = readDartTypeOption();
         return new TypeParameterType(typeParameterStack[index], bound);
       default:
@@ -1117,9 +1128,11 @@
   }
 
   Arguments readArguments() {
+    var numArguments = readUInt();
     var typeArguments = readDartTypeList();
     var positional = readExpressionList();
     var named = readNamedExpressionList();
+    assert(numArguments == positional.length + named.length);
     return new Arguments(positional, types: typeArguments, named: named);
   }
 
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index cdc92ea..0edfdd8 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -404,7 +404,7 @@
 
   visitLocalInitializer(LocalInitializer node) {
     writeByte(Tag.LocalInitializer);
-    writeVariableDeclaration(node.variable);
+    writeVariableDeclaration(node.variable, false);
   }
 
   visitFunctionNode(FunctionNode node) {
@@ -444,9 +444,11 @@
         node.promotedType == null) {
       writeByte(Tag.SpecializedVariableGet + index);
       writeOffset(node.fileOffset);
+      writeUInt30(node.variable.binaryOffset);
     } else {
       writeByte(Tag.VariableGet);
       writeOffset(node.fileOffset);
+      writeUInt30(node.variable.binaryOffset);
       writeUInt30(_variableIndexer[node.variable]);
       writeOptionalNode(node.promotedType);
     }
@@ -458,10 +460,12 @@
     if (index & Tag.SpecializedPayloadMask == index) {
       writeByte(Tag.SpecializedVariableSet + index);
       writeOffset(node.fileOffset);
+      writeUInt30(node.variable.binaryOffset);
       writeNode(node.value);
     } else {
       writeByte(Tag.VariableSet);
       writeOffset(node.fileOffset);
+      writeUInt30(node.variable.binaryOffset);
       writeUInt30(_variableIndexer[node.variable]);
       writeNode(node.value);
     }
@@ -566,6 +570,7 @@
   }
 
   visitArguments(Arguments node) {
+    writeUInt30(node.positional.length + node.named.length);
     writeNodeList(node.types);
     writeNodeList(node.positional);
     writeNodeList(node.named);
@@ -724,7 +729,7 @@
 
   visitLet(Let node) {
     writeByte(Tag.Let);
-    writeVariableDeclaration(node.variable);
+    writeVariableDeclaration(node.variable, false);
     writeNode(node.body);
     --_variableIndexer.stackHeight;
   }
@@ -842,7 +847,7 @@
     _variableIndexer.pushScope();
     writeByte(node.isAsync ? Tag.AsyncForInStatement : Tag.ForInStatement);
     writeOffset(node.fileOffset);
-    writeVariableDeclaration(node.variable);
+    writeVariableDeclaration(node.variable, false);
     writeNode(node.iterable);
     writeNode(node.body);
     _variableIndexer.popScope();
@@ -858,8 +863,12 @@
 
   visitSwitchCase(SwitchCase node) {
     // Note: there is no tag on SwitchCase.
-    writeNodeList(node.expressions);
-    node.expressionOffsets.forEach(writeOffset);
+    int length = node.expressions.length;
+    writeUInt30(length);
+    for (int i = 0; i < length; ++i) {
+      writeOffset(node.expressionOffsets[i]);
+      writeNode(node.expressions[i]);
+    }
     writeByte(node.isDefault ? 1 : 0);
     writeNode(node.body);
   }
@@ -885,6 +894,13 @@
   visitTryCatch(TryCatch node) {
     writeByte(Tag.TryCatch);
     writeNode(node.body);
+    if (node.catches.any((Catch c) => c.stackTrace != null)) {
+      // at least one catch needs the stack trace.
+      writeByte(1);
+    } else {
+      // no catch needs the stack trace.
+      writeByte(0);
+    }
     writeNodeList(node.catches);
   }
 
@@ -912,11 +928,13 @@
   }
 
   visitVariableDeclaration(VariableDeclaration node) {
-    writeByte(Tag.VariableDeclaration);
-    writeVariableDeclaration(node);
+    writeVariableDeclaration(node, true);
   }
 
-  void writeVariableDeclaration(VariableDeclaration node) {
+  void writeVariableDeclaration(VariableDeclaration node,
+      [bool hasTag = false]) {
+    node.binaryOffset = _sink.flushedLength + _sink.length;
+    if (hasTag) writeByte(Tag.VariableDeclaration);
     writeOffset(node.fileOffset);
     writeOffset(node.fileEqualsOffset);
     writeByte(node.flags);
@@ -937,14 +955,14 @@
       writeByte(Tag.Nothing);
     } else {
       writeByte(Tag.Something);
-      writeVariableDeclaration(node);
+      writeVariableDeclaration(node, false);
     }
   }
 
   visitFunctionDeclaration(FunctionDeclaration node) {
     writeByte(Tag.FunctionDeclaration);
     writeOffset(node.fileOffset);
-    writeVariableDeclaration(node.variable);
+    writeVariableDeclaration(node.variable, false);
     writeNode(node.function);
   }
 
@@ -998,6 +1016,8 @@
       _typeParameterIndexer.enter(node.typeParameters);
       writeNodeList(node.typeParameters);
       writeUInt30(node.requiredParameterCount);
+      writeUInt30(
+          node.positionalParameters.length + node.namedParameters.length);
       writeNodeList(node.positionalParameters);
       writeNodeList(node.namedParameters);
       writeNode(node.returnType);
@@ -1013,6 +1033,7 @@
   visitTypeParameterType(TypeParameterType node) {
     writeByte(Tag.TypeParameterType);
     writeUInt30(_typeParameterIndexer[node.parameter]);
+    writeUInt30(node.parameter.binaryOffset);
     writeOptionalNode(node.bound);
   }
 
@@ -1027,6 +1048,7 @@
   }
 
   visitTypeParameter(TypeParameter node) {
+    node.binaryOffset = _sink.flushedLength + _sink.length;
     writeStringReference(node.name ?? '');
     writeNode(node.bound);
   }
@@ -1307,6 +1329,7 @@
   final Sink<List<int>> _sink;
   Uint8List _buffer = new Uint8List(SIZE);
   int length = 0;
+  int flushedLength = 0;
 
   BufferedSink(this._sink);
 
@@ -1316,6 +1339,7 @@
       _sink.add(_buffer);
       _buffer = new Uint8List(SIZE);
       length = 0;
+      flushedLength += SIZE;
     }
   }
 
@@ -1326,6 +1350,7 @@
         (bytes.length < SMALL || length < SMALL)) {
       if (length == 0) {
         _sink.add(bytes);
+        flushedLength += bytes.length;
       } else {
         _buffer.setRange(length, length + bytes.length, bytes);
         length += bytes.length;
@@ -1341,10 +1366,13 @@
       _buffer = new Uint8List(SIZE);
       _buffer.setRange(0, remainder, bytes, alreadyEmitted);
       length = remainder;
+      flushedLength += SIZE;
     } else {
       _sink.add(_buffer.sublist(0, length));
       _sink.add(bytes);
       _buffer = new Uint8List(SIZE);
+      flushedLength += length;
+      flushedLength += bytes.length;
       length = 0;
     }
   }
@@ -1352,6 +1380,7 @@
   void flush() {
     _sink.add(_buffer.sublist(0, length));
     _buffer = new Uint8List(SIZE);
+    flushedLength += length;
     length = 0;
   }
 
diff --git a/runtime/vm/kernel.h b/runtime/vm/kernel.h
index 5125d44..54c794a 100644
--- a/runtime/vm/kernel.h
+++ b/runtime/vm/kernel.h
@@ -230,6 +230,13 @@
 
   T** raw_array() { return array_; }
 
+  bool CanStream() {
+    for (intptr_t i = 0; i < length_; ++i) {
+      if (!array_[i]->can_stream()) return false;
+    }
+    return true;
+  }
+
  private:
   T** array_;
   int length_;
@@ -387,14 +394,17 @@
   virtual void AcceptVisitor(Visitor* visitor);
   virtual void AcceptTreeVisitor(TreeVisitor* visitor) = 0;
   intptr_t kernel_offset() const { return kernel_offset_; }
+  bool can_stream() { return can_stream_; }
 
  protected:
-  TreeNode() : kernel_offset_(-1) {}
+  TreeNode() : kernel_offset_(-1), can_stream_(true) {}
 
   // Offset for this node in the kernel-binary. If this node has a tag the
   // offset includes the tag. Can be -1 to indicate "unknown" or invalid offset.
   intptr_t kernel_offset_;
 
+  bool can_stream_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(TreeNode);
 };
@@ -1018,6 +1028,7 @@
   VariableGet() {}
 
   Ref<VariableDeclaration> variable_;
+  intptr_t variable_kernel_offset_;
 
   DISALLOW_COPY_AND_ASSIGN(VariableGet);
 };
@@ -1042,6 +1053,7 @@
   VariableSet() {}
 
   Ref<VariableDeclaration> variable_;
+  intptr_t variable_kernel_offset_;
   Child<Expression> expression_;
 
   DISALLOW_COPY_AND_ASSIGN(VariableSet);
@@ -1152,7 +1164,9 @@
 
 class StaticGet : public Expression {
  public:
-  explicit StaticGet(NameIndex target) : target_reference_(target) {}
+  StaticGet(NameIndex target, bool can_stream) : target_reference_(target) {
+    can_stream_ = can_stream;
+  }
 
   static StaticGet* ReadFrom(Reader* reader);
 
@@ -2174,12 +2188,12 @@
   virtual void AcceptStatementVisitor(StatementVisitor* visitor);
   virtual void VisitChildren(Visitor* visitor);
 
-  LabeledStatement* target() { return target_; }
+  intptr_t target_index() { return target_index_; }
 
  private:
   BreakStatement() {}
 
-  Ref<LabeledStatement> target_;
+  intptr_t target_index_;
 
   DISALLOW_COPY_AND_ASSIGN(BreakStatement);
 };
@@ -2365,12 +2379,12 @@
   virtual void AcceptStatementVisitor(StatementVisitor* visitor);
   virtual void VisitChildren(Visitor* visitor);
 
-  SwitchCase* target() { return target_; }
+  intptr_t target_index() { return target_index_; }
 
  private:
   ContinueSwitchStatement() {}
 
-  Ref<SwitchCase> target_;
+  intptr_t target_index_;
 
   DISALLOW_COPY_AND_ASSIGN(ContinueSwitchStatement);
 };
@@ -2404,7 +2418,10 @@
 
 class ReturnStatement : public Statement {
  public:
-  explicit ReturnStatement(Expression* expression) : expression_(expression) {}
+  ReturnStatement(Expression* expression, bool can_stream)
+      : expression_(expression) {
+    can_stream_ = can_stream;
+  }
 
   static ReturnStatement* ReadFrom(Reader* reader);
 
diff --git a/runtime/vm/kernel_binary.cc b/runtime/vm/kernel_binary.cc
index 55cee46..220355d 100644
--- a/runtime/vm/kernel_binary.cc
+++ b/runtime/vm/kernel_binary.cc
@@ -201,6 +201,10 @@
 
   fields().ReadFrom<Field>(reader, this);
   procedures().ReadFrom<Procedure>(reader, this);
+
+  can_stream_ =
+      classes().CanStream() && fields().CanStream() && procedures().CanStream();
+
   return this;
 }
 
@@ -231,6 +235,8 @@
   reader->record_token_position(position_);
   annotations_.ReadFromStatic<Expression>(reader);
 
+  can_stream_ = annotations_.CanStream();
+
   return this;
 }
 
@@ -251,6 +257,9 @@
   constructors_.ReadFrom<Constructor>(reader, this);
   procedures_.ReadFrom<Procedure>(reader, this);
 
+  can_stream_ = can_stream_ && fields_.CanStream() &&
+                constructors_.CanStream() && procedures_.CanStream();
+
   return this;
 }
 
@@ -266,6 +275,9 @@
   implemented_classes_.ReadFromStatic<DowncastReader<DartType, InterfaceType> >(
       reader);
   constructors_.ReadFrom<Constructor>(reader, this);
+
+  can_stream_ = constructors_.CanStream();
+
   return this;
 }
 
@@ -318,6 +330,10 @@
   annotations_.ReadFromStatic<Expression>(reader);
   type_ = DartType::ReadFrom(reader);
   initializer_ = reader->ReadOptional<Expression>();
+
+  can_stream_ = (initializer_ == NULL || initializer_->can_stream()) &&
+                annotations_.CanStream();
+
   return this;
 }
 
@@ -336,6 +352,10 @@
   annotations_.ReadFromStatic<Expression>(reader);
   function_ = FunctionNode::ReadFrom(reader);
   initializers_.ReadFromStatic<Initializer>(reader);
+
+  can_stream_ = annotations_.CanStream() && function_->can_stream() &&
+                initializers_.CanStream();
+
   return this;
 }
 
@@ -358,6 +378,10 @@
   reader->record_token_position(end_position_);
   annotations_.ReadFromStatic<Expression>(reader);
   function_ = reader->ReadOptional<FunctionNode>();
+
+  can_stream_ = annotations_.CanStream() &&
+                (function_ == NULL || function_->can_stream());
+
   return this;
 }
 
@@ -394,6 +418,9 @@
   FieldInitializer* initializer = new FieldInitializer();
   initializer->field_reference_ = Reference::ReadMemberFrom(reader);
   initializer->value_ = Expression::ReadFrom(reader);
+
+  initializer->can_stream_ = initializer->value_->can_stream();
+
   return initializer;
 }
 
@@ -403,6 +430,9 @@
   SuperInitializer* init = new SuperInitializer();
   init->target_reference_ = Reference::ReadMemberFrom(reader);
   init->arguments_ = Arguments::ReadFrom(reader);
+
+  init->can_stream_ = init->arguments_->can_stream();
+
   return init;
 }
 
@@ -412,6 +442,9 @@
   RedirectingInitializer* init = new RedirectingInitializer();
   init->target_reference_ = Reference::ReadMemberFrom(reader);
   init->arguments_ = Arguments::ReadFrom(reader);
+
+  init->can_stream_ = init->arguments_->can_stream();
+
   return init;
 }
 
@@ -420,6 +453,9 @@
   TRACE_READ_OFFSET();
   LocalInitializer* init = new LocalInitializer();
   init->variable_ = VariableDeclaration::ReadFromImpl(reader, false);
+
+  init->can_stream_ = init->variable_->can_stream();
+
   return init;
 }
 
@@ -548,7 +584,9 @@
   VariableGet* get = new VariableGet();
   get->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   get->position_ = reader->ReadPosition();
+  get->variable_kernel_offset_ = reader->ReadUInt();
   get->variable_ = reader->helper()->variables().Lookup(reader->ReadUInt());
+  ASSERT(get->variable_->kernel_offset() == get->variable_kernel_offset_);
   reader->ReadOptional<DartType>();  // Unused promoted type.
   return get;
 }
@@ -559,7 +597,9 @@
   VariableGet* get = new VariableGet();
   get->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   get->position_ = reader->ReadPosition();
+  get->variable_kernel_offset_ = reader->ReadUInt();
   get->variable_ = reader->helper()->variables().Lookup(payload);
+  ASSERT(get->variable_->kernel_offset() == get->variable_kernel_offset_);
   return get;
 }
 
@@ -569,8 +609,13 @@
   VariableSet* set = new VariableSet();
   set->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   set->position_ = reader->ReadPosition();
+  set->variable_kernel_offset_ = reader->ReadUInt();
   set->variable_ = reader->helper()->variables().Lookup(reader->ReadUInt());
+  ASSERT(set->variable_->kernel_offset() == set->variable_kernel_offset_);
   set->expression_ = Expression::ReadFrom(reader);
+
+  set->can_stream_ = set->expression_->can_stream();
+
   return set;
 }
 
@@ -581,7 +626,12 @@
   set->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   set->variable_ = reader->helper()->variables().Lookup(payload);
   set->position_ = reader->ReadPosition();
+  set->variable_kernel_offset_ = reader->ReadUInt();
+  ASSERT(set->variable_->kernel_offset() == set->variable_kernel_offset_);
   set->expression_ = Expression::ReadFrom(reader);
+
+  set->can_stream_ = set->expression_->can_stream();
+
   return set;
 }
 
@@ -594,6 +644,9 @@
   get->receiver_ = Expression::ReadFrom(reader);
   get->name_ = Name::ReadFrom(reader);
   get->interface_target_reference_ = Reference::ReadMemberFrom(reader, true);
+
+  get->can_stream_ = get->receiver_->can_stream();
+
   return get;
 }
 
@@ -607,6 +660,9 @@
   set->name_ = Name::ReadFrom(reader);
   set->value_ = Expression::ReadFrom(reader);
   set->interface_target_reference_ = Reference::ReadMemberFrom(reader, true);
+
+  set->can_stream_ = set->receiver_->can_stream() && set->value_->can_stream();
+
   return set;
 }
 
@@ -618,6 +674,9 @@
   get->position_ = reader->ReadPosition();
   get->receiver_ = Expression::ReadFrom(reader);
   get->target_reference_ = Reference::ReadMemberFrom(reader);
+
+  get->can_stream_ = get->receiver_->can_stream();
+
   return get;
 }
 
@@ -630,6 +689,9 @@
   set->receiver_ = Expression::ReadFrom(reader);
   set->target_reference_ = Reference::ReadMemberFrom(reader);
   set->value_ = Expression::ReadFrom(reader);
+
+  set->can_stream_ = set->receiver_->can_stream() && set->value_->can_stream();
+
   return set;
 }
 
@@ -651,6 +713,9 @@
   set->position_ = reader->ReadPosition();
   set->target_reference_ = Reference::ReadMemberFrom(reader);
   set->expression_ = Expression::ReadFrom(reader);
+
+  set->can_stream_ = set->expression_->can_stream();
+
   return set;
 }
 
@@ -658,9 +723,15 @@
 Arguments* Arguments::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   Arguments* arguments = new Arguments();
+  intptr_t num_arguments = reader->ReadUInt();
   arguments->types().ReadFromStatic<DartType>(reader);
   arguments->positional().ReadFromStatic<Expression>(reader);
   arguments->named().ReadFromStatic<NamedExpression>(reader);
+  ASSERT(arguments->count() == num_arguments);
+
+  arguments->can_stream_ =
+      arguments->positional().CanStream() && arguments->named().CanStream();
+
   return arguments;
 }
 
@@ -669,7 +740,11 @@
   TRACE_READ_OFFSET();
   StringIndex name_index(reader->ReadUInt());
   Expression* expression = Expression::ReadFrom(reader);
-  return new NamedExpression(name_index, expression);
+  NamedExpression* named = new NamedExpression(name_index, expression);
+
+  named->can_stream_ = expression->can_stream();
+
+  return named;
 }
 
 
@@ -683,6 +758,10 @@
   invocation->arguments_ = Arguments::ReadFrom(reader);
   invocation->interface_target_reference_ =
       Reference::ReadMemberFrom(reader, true);
+
+  invocation->can_stream_ = invocation->receiver_->can_stream() &&
+                            invocation->arguments_->can_stream();
+
   return invocation;
 }
 
@@ -694,6 +773,10 @@
   invocation->receiver_ = Expression::ReadFrom(reader);
   invocation->target_reference_ = Reference::ReadMemberFrom(reader);
   invocation->arguments_ = Arguments::ReadFrom(reader);
+
+  invocation->can_stream_ = invocation->receiver_->can_stream() &&
+                            invocation->arguments_->can_stream();
+
   return invocation;
 }
 
@@ -706,6 +789,9 @@
   invocation->position_ = reader->ReadPosition();
   invocation->procedure_reference_ = Reference::ReadMemberFrom(reader);
   invocation->arguments_ = Arguments::ReadFrom(reader);
+
+  invocation->can_stream_ = invocation->arguments_->can_stream();
+
   return invocation;
 }
 
@@ -719,6 +805,9 @@
   invocation->position_ = reader->ReadPosition();
   invocation->target_reference_ = Reference::ReadMemberFrom(reader);
   invocation->arguments_ = Arguments::ReadFrom(reader);
+
+  invocation->can_stream_ = invocation->arguments_->can_stream();
+
   return invocation;
 }
 
@@ -728,6 +817,9 @@
   Not* n = new Not();
   n->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   n->expression_ = Expression::ReadFrom(reader);
+
+  n->can_stream_ = n->expression_->can_stream();
+
   return n;
 }
 
@@ -739,6 +831,9 @@
   expr->left_ = Expression::ReadFrom(reader);
   expr->operator_ = static_cast<Operator>(reader->ReadByte());
   expr->right_ = Expression::ReadFrom(reader);
+
+  expr->can_stream_ = expr->left_->can_stream() && expr->right_->can_stream();
+
   return expr;
 }
 
@@ -751,6 +846,11 @@
   expr->then_ = Expression::ReadFrom(reader);
   expr->otherwise_ = Expression::ReadFrom(reader);
   reader->ReadOptional<DartType>();  // Unused static type.
+
+  expr->can_stream_ = expr->condition_->can_stream() &&
+                      expr->then_->can_stream() &&
+                      expr->otherwise_->can_stream();
+
   return expr;
 }
 
@@ -761,6 +861,9 @@
   concat->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   concat->position_ = reader->ReadPosition();
   concat->expressions_.ReadFromStatic<Expression>(reader);
+
+  concat->can_stream_ = concat->expressions_.CanStream();
+
   return concat;
 }
 
@@ -772,6 +875,9 @@
   expr->position_ = reader->ReadPosition();
   expr->operand_ = Expression::ReadFrom(reader);
   expr->type_ = DartType::ReadFrom(reader);
+
+  expr->can_stream_ = expr->operand_->can_stream();
+
   return expr;
 }
 
@@ -783,6 +889,9 @@
   expr->position_ = reader->ReadPosition();
   expr->operand_ = Expression::ReadFrom(reader);
   expr->type_ = DartType::ReadFrom(reader);
+
+  expr->can_stream_ = expr->operand_->can_stream();
+
   return expr;
 }
 
@@ -891,6 +1000,9 @@
   t->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   t->position_ = reader->ReadPosition();
   t->expression_ = Expression::ReadFrom(reader);
+
+  t->can_stream_ = t->expression_->can_stream();
+
   return t;
 }
 
@@ -903,6 +1015,9 @@
   literal->position_ = reader->ReadPosition();
   literal->type_ = DartType::ReadFrom(reader);
   literal->expressions_.ReadFromStatic<Expression>(reader);
+
+  literal->can_stream_ = literal->expressions_.CanStream();
+
   return literal;
 }
 
@@ -916,6 +1031,9 @@
   literal->key_type_ = DartType::ReadFrom(reader);
   literal->value_type_ = DartType::ReadFrom(reader);
   literal->entries_.ReadFromStatic<MapEntry>(reader);
+
+  literal->can_stream_ = literal->entries_.CanStream();
+
   return literal;
 }
 
@@ -924,6 +1042,9 @@
   MapEntry* entry = new MapEntry();
   entry->key_ = Expression::ReadFrom(reader);
   entry->value_ = Expression::ReadFrom(reader);
+
+  entry->can_stream_ = entry->key_->can_stream() && entry->value_->can_stream();
+
   return entry;
 }
 
@@ -933,6 +1054,9 @@
   AwaitExpression* await = new AwaitExpression();
   await->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   await->operand_ = Expression::ReadFrom(reader);
+
+  await->can_stream_ = await->operand_->can_stream();
+
   return await;
 }
 
@@ -943,6 +1067,9 @@
   FunctionExpression* expr = new FunctionExpression();
   expr->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   expr->function_ = FunctionNode::ReadFrom(reader);
+
+  expr->can_stream_ = false;
+
   return expr;
 }
 
@@ -959,6 +1086,8 @@
   let->position_ = reader->min_position();
   let->end_position_ = reader->max_position();
 
+  let->can_stream_ = let->variable_->can_stream() && let->body_->can_stream();
+
   return let;
 }
 
@@ -983,6 +1112,8 @@
   vector_get->vector_expression_ = Expression::ReadFrom(reader);
   vector_get->index_ = reader->ReadUInt();
 
+  vector_get->can_stream_ = false;
+
   return vector_get;
 }
 
@@ -996,6 +1127,8 @@
   vector_set->index_ = reader->ReadUInt();
   vector_set->value_ = Expression::ReadFrom(reader);
 
+  vector_set->can_stream_ = false;
+
   return vector_set;
 }
 
@@ -1008,6 +1141,8 @@
       reader->offset() - 1;  // -1 to include tag byte.
   vector_copy->vector_expression_ = Expression::ReadFrom(reader);
 
+  vector_copy->can_stream_ = false;
+
   return vector_copy;
 }
 
@@ -1024,6 +1159,8 @@
   closure_creation->function_type_ =
       FunctionType::Cast(DartType::ReadFrom(reader));
 
+  closure_creation->can_stream_ = false;
+
   return closure_creation;
 }
 
@@ -1083,13 +1220,22 @@
 
 InvalidStatement* InvalidStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
-  return new InvalidStatement();
+  InvalidStatement* stmt = new InvalidStatement();
+  stmt->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
+  return stmt;
 }
 
 
 ExpressionStatement* ExpressionStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
-  return new ExpressionStatement(Expression::ReadFrom(reader));
+  intptr_t offset = reader->offset() - 1;  // -1 to include tag byte.
+  ExpressionStatement* stmt =
+      new ExpressionStatement(Expression::ReadFrom(reader));
+  stmt->kernel_offset_ = offset;
+
+  stmt->can_stream_ = stmt->expression_->can_stream();
+
+  return stmt;
 }
 
 
@@ -1104,21 +1250,30 @@
   block->position_ = reader->min_position();
   block->end_position_ = reader->max_position();
 
+  block->can_stream_ = block->statements().CanStream();
+
   return block;
 }
 
 
 EmptyStatement* EmptyStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
-  return new EmptyStatement();
+  EmptyStatement* stmt = new EmptyStatement();
+  stmt->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
+  return stmt;
 }
 
 
 AssertStatement* AssertStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   AssertStatement* stmt = new AssertStatement();
+  stmt->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   stmt->condition_ = Expression::ReadFrom(reader);
   stmt->message_ = reader->ReadOptional<Expression>();
+
+  stmt->can_stream_ = stmt->condition_->can_stream() &&
+                      (stmt->message_ == NULL || stmt->message_->can_stream());
+
   return stmt;
 }
 
@@ -1126,9 +1281,14 @@
 LabeledStatement* LabeledStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   LabeledStatement* stmt = new LabeledStatement();
+  stmt->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
+
   reader->helper()->labels()->Push(stmt);
   stmt->body_ = Statement::ReadFrom(reader);
   reader->helper()->labels()->Pop(stmt);
+
+  stmt->can_stream_ = stmt->body_->can_stream();
+
   return stmt;
 }
 
@@ -1136,8 +1296,9 @@
 BreakStatement* BreakStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   BreakStatement* stmt = new BreakStatement();
+  stmt->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   stmt->position_ = reader->ReadPosition();
-  stmt->target_ = reader->helper()->labels()->Lookup(reader->ReadUInt());
+  stmt->target_index_ = reader->ReadUInt();
   return stmt;
 }
 
@@ -1145,8 +1306,13 @@
 WhileStatement* WhileStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   WhileStatement* stmt = new WhileStatement();
+  stmt->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   stmt->condition_ = Expression::ReadFrom(reader);
   stmt->body_ = Statement::ReadFrom(reader);
+
+  stmt->can_stream_ =
+      stmt->condition_->can_stream() && stmt->body_->can_stream();
+
   return stmt;
 }
 
@@ -1154,8 +1320,13 @@
 DoStatement* DoStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   DoStatement* dostmt = new DoStatement();
+  dostmt->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   dostmt->body_ = Statement::ReadFrom(reader);
   dostmt->condition_ = Expression::ReadFrom(reader);
+
+  dostmt->can_stream_ =
+      dostmt->body_->can_stream() && dostmt->condition_->can_stream();
+
   return dostmt;
 }
 
@@ -1174,6 +1345,11 @@
   forstmt->end_position_ = reader->max_position();
   forstmt->position_ = reader->min_position();
 
+  forstmt->can_stream_ =
+      forstmt->body_->can_stream() &&
+      (forstmt->condition_ == NULL || forstmt->condition_->can_stream()) &&
+      forstmt->variables_.CanStream() && forstmt->updates_.CanStream();
+
   return forstmt;
 }
 
@@ -1196,39 +1372,49 @@
   }
   forinstmt->variable_->set_end_position(forinstmt->position_);
 
+  forinstmt->can_stream_ = forinstmt->variable_->can_stream() &&
+                           forinstmt->iterable_->can_stream() &&
+                           forinstmt->body_->can_stream();
+
   return forinstmt;
 }
 
 
 SwitchStatement* SwitchStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
-  SwitchCaseScope<ReaderHelper> scope(reader->helper());
   SwitchStatement* stmt = new SwitchStatement();
+  stmt->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   stmt->condition_ = Expression::ReadFrom(reader);
-  // We need to explicitly create empty [SwitchCase]s first in order to add them
-  // to the [SwitchCaseScope]. This is necessary since a [Statement] in a switch
-  // case can refer to one defined later on.
   int count = reader->ReadUInt();
+  stmt->cases_.EnsureInitialized(count);
   for (intptr_t i = 0; i < count; i++) {
     SwitchCase* sc = stmt->cases_.GetOrCreate<SwitchCase>(i);
-    reader->helper()->switch_cases().Push(sc);
-  }
-  for (intptr_t i = 0; i < count; i++) {
-    SwitchCase* sc = stmt->cases_[i];
     sc->ReadFrom(reader);
   }
+
+  stmt->can_stream_ =
+      stmt->condition_->can_stream() && stmt->cases_.CanStream();
+
   return stmt;
 }
 
 
 SwitchCase* SwitchCase::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
-  expressions_.ReadFromStatic<Expression>(reader);
-  for (intptr_t i = 0; i < expressions_.length(); ++i) {
-    expressions_[i]->set_position(reader->ReadPosition());
+  int length = reader->ReadListLength();
+  expressions_.EnsureInitialized(length);
+
+  for (intptr_t i = 0; i < length; i++) {
+    ASSERT(expressions_[i] == NULL);
+    TokenPosition position = reader->ReadPosition();
+    expressions_[i] = Expression::ReadFrom(reader);
+    expressions_[i]->set_position(position);
   }
   is_default_ = reader->ReadBool();
   body_ = Statement::ReadFrom(reader);
+
+  can_stream_ = expressions_.CanStream() && body_->can_stream();
+
   return this;
 }
 
@@ -1236,7 +1422,9 @@
 ContinueSwitchStatement* ContinueSwitchStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   ContinueSwitchStatement* stmt = new ContinueSwitchStatement();
-  stmt->target_ = reader->helper()->switch_cases().Lookup(reader->ReadUInt());
+  stmt->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
+  stmt->target_index_ = reader->ReadUInt();
+
   return stmt;
 }
 
@@ -1244,9 +1432,15 @@
 IfStatement* IfStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   IfStatement* ifstmt = new IfStatement();
+  ifstmt->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   ifstmt->condition_ = Expression::ReadFrom(reader);
   ifstmt->then_ = Statement::ReadFrom(reader);
   ifstmt->otherwise_ = Statement::ReadFrom(reader);
+
+  ifstmt->can_stream_ = ifstmt->condition_->can_stream() &&
+                        ifstmt->then_->can_stream() &&
+                        ifstmt->otherwise_->can_stream();
+
   return ifstmt;
 }
 
@@ -1254,8 +1448,13 @@
 ReturnStatement* ReturnStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   ReturnStatement* ret = new ReturnStatement();
+  ret->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   ret->position_ = reader->ReadPosition();
   ret->expression_ = reader->ReadOptional<Expression>();
+
+  ret->can_stream_ =
+      (ret->expression_ == NULL || ret->expression_->can_stream());
+
   return ret;
 }
 
@@ -1265,10 +1464,14 @@
   PositionScope scope(reader);
 
   TryCatch* tc = new TryCatch();
+  tc->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   tc->body_ = Statement::ReadFrom(reader);
+  reader->ReadBool();  // whether any catch needs a stacktrace.
   tc->catches_.ReadFromStatic<Catch>(reader);
   tc->position_ = reader->min_position();
 
+  tc->can_stream_ = tc->body_->can_stream() && tc->catches_.CanStream();
+
   return tc;
 }
 
@@ -1289,6 +1492,8 @@
   c->end_position_ = reader->max_position();
   c->position_ = reader->min_position();
 
+  c->can_stream_ = c->body_->can_stream();
+
   return c;
 }
 
@@ -1296,8 +1501,12 @@
 TryFinally* TryFinally::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   TryFinally* tf = new TryFinally();
+  tf->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   tf->body_ = Statement::ReadFrom(reader);
   tf->finalizer_ = Statement::ReadFrom(reader);
+
+  tf->can_stream_ = tf->body_->can_stream() && tf->finalizer_->can_stream();
+
   return tf;
 }
 
@@ -1305,10 +1514,14 @@
 YieldStatement* YieldStatement::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
   YieldStatement* stmt = new YieldStatement();
+  stmt->kernel_offset_ = reader->offset() - 1;  // -1 to include tag byte.
   stmt->position_ = reader->ReadPosition();
   reader->record_yield_token_position(stmt->position_);
   stmt->flags_ = reader->ReadByte();
   stmt->expression_ = Expression::ReadFrom(reader);
+
+  stmt->can_stream_ = stmt->expression_->can_stream();
+
   return stmt;
 }
 
@@ -1343,6 +1556,9 @@
   decl->end_position_ = position;
   reader->helper()->variables().Push(decl);
 
+  decl->can_stream_ =
+      (decl->initializer_ == NULL || decl->initializer_->can_stream());
+
   return decl;
 }
 
@@ -1355,6 +1571,9 @@
   decl->variable_ = VariableDeclaration::ReadFromImpl(reader, false);
   VariableScope<ReaderHelper> parameters(reader->helper());
   decl->function_ = FunctionNode::ReadFrom(reader);
+
+  decl->can_stream_ = false;
+
   return decl;
 }
 
@@ -1463,8 +1682,12 @@
   TypeParameterScope<ReaderHelper> scope(reader->helper());
   type->type_parameters().ReadFrom(reader);
   type->required_parameter_count_ = reader->ReadUInt();
+  intptr_t total_parameter_count = reader->ReadUInt();
   type->positional_parameters().ReadFromStatic<DartType>(reader);
   type->named_parameters().ReadFromStatic<NamedParameter>(reader);
+  ASSERT(type->positional_parameters().length() +
+             type->named_parameters().length() ==
+         total_parameter_count);
   type->return_type_ = DartType::ReadFrom(reader);
   return type;
 }
@@ -1486,6 +1709,7 @@
   TypeParameterType* type = new TypeParameterType();
   type->parameter_ =
       reader->helper()->type_parameters().Lookup(reader->ReadUInt());
+  reader->ReadUInt();  // binary offset of parameter
   // There is an optional promoted bound, currently ignored.
   delete reader->ReadOptional<DartType>();
   return type;
@@ -1546,6 +1770,8 @@
   program->main_method_reference_ =
       Reference::ReadMemberFrom(reader, /*allow_null=*/true);
 
+  program->can_stream_ = false;
+
   return program;
 }
 
@@ -1573,12 +1799,19 @@
       reader->helper());
   VariableScope<ReaderHelper> vars(reader->helper());
   function->body_ = reader->ReadOptional<Statement>();
+
+  function->can_stream_ =
+      function->positional_parameters_.CanStream() &&
+      function->named_parameters_.CanStream() &&
+      (function->body_ == NULL || function->body_->can_stream());
+
   return function;
 }
 
 
 TypeParameter* TypeParameter::ReadFrom(Reader* reader) {
   TRACE_READ_OFFSET();
+  kernel_offset_ = reader->offset();
   name_index_ = StringIndex(reader->ReadUInt());
   bound_ = DartType::ReadFrom(reader);
   return this;
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index b8ae51c..0e6459f 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -268,19 +268,6 @@
 };
 
 
-template <typename T>
-class SwitchCaseScope {
- public:
-  explicit SwitchCaseScope(T* builder) : builder_(builder) {
-    builder_->switch_cases().EnterScope();
-  }
-  ~SwitchCaseScope() { builder_->switch_cases().LeaveScope(); }
-
- private:
-  T* builder_;
-};
-
-
 // Unlike other scopes, labels from enclosing functions are not visible in
 // nested functions.  The LabelScope class is used to hide outer labels.
 template <typename Builder, typename Block>
@@ -308,7 +295,6 @@
 
   BlockStack<VariableDeclaration>& variables() { return scope_; }
   BlockStack<TypeParameter>& type_parameters() { return type_parameters_; }
-  BlockStack<SwitchCase>& switch_cases() { return switch_cases_; }
 
   BlockStack<LabeledStatement>* labels() { return labels_; }
   void set_labels(BlockStack<LabeledStatement>* labels) { labels_ = labels; }
@@ -317,7 +303,6 @@
   Program* program_;
   BlockStack<VariableDeclaration> scope_;
   BlockStack<TypeParameter> type_parameters_;
-  BlockStack<SwitchCase> switch_cases_;
   BlockStack<LabeledStatement>* labels_;
 };
 
@@ -422,6 +407,8 @@
 
   uint8_t ReadByte() { return buffer_[offset_++]; }
 
+  uint8_t PeekByte() { return buffer_[offset_]; }
+
   bool ReadBool() { return (ReadByte() & 1) == 1; }
 
   word ReadFlags() { return ReadByte(); }
@@ -439,6 +426,19 @@
     }
   }
 
+  Tag PeekTag(uint8_t* payload = NULL) {
+    uint8_t byte = PeekByte();
+    bool has_payload = (byte & kSpecializedTagHighBit) != 0;
+    if (has_payload) {
+      if (payload != NULL) {
+        *payload = byte & kSpecializedPayloadMask;
+      }
+      return static_cast<Tag>(byte & kSpecializedTagMask);
+    } else {
+      return static_cast<Tag>(byte);
+    }
+  }
+
   const uint8_t* Consume(int count) {
     ASSERT(offset_ + count <= size_);
     const uint8_t* old = buffer_ + offset_;
diff --git a/runtime/vm/kernel_binary_flowgraph.cc b/runtime/vm/kernel_binary_flowgraph.cc
index ca31817..dec055d 100644
--- a/runtime/vm/kernel_binary_flowgraph.cc
+++ b/runtime/vm/kernel_binary_flowgraph.cc
@@ -4,6 +4,7 @@
 
 #include "vm/kernel_binary_flowgraph.h"
 
+#include "vm/longjump.h"
 #include "vm/object_store.h"
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -13,54 +14,599 @@
 
 #define Z (zone_)
 #define H (translation_helper_)
+#define T (type_translator_)
 #define I Isolate::Current()
 
-StreamingConstantEvaluator::StreamingConstantEvaluator(
+
+StreamingDartTypeTranslator::StreamingDartTypeTranslator(
     StreamingFlowGraphBuilder* builder,
-    Zone* zone,
-    TranslationHelper* h,
-    DartTypeTranslator* type_translator)
+    bool finalize)
+    : builder_(builder),
+      translation_helper_(builder->translation_helper_),
+      active_class_(builder->active_class()),
+      type_parameter_scope_(NULL),
+      zone_(translation_helper_.zone()),
+      result_(AbstractType::Handle(translation_helper_.zone())),
+      finalize_(finalize) {}
+
+
+AbstractType& StreamingDartTypeTranslator::BuildType() {
+  BuildTypeInternal();
+
+  // We return a new `ZoneHandle` here on purpose: The intermediate language
+  // instructions do not make a copy of the handle, so we do it.
+  return dart::AbstractType::ZoneHandle(Z, result_.raw());
+}
+
+void StreamingDartTypeTranslator::BuildTypeInternal() {
+  Tag tag = builder_->ReadTag();
+  switch (tag) {
+    case kInvalidType:
+      result_ = ClassFinalizer::NewFinalizedMalformedType(
+          Error::Handle(Z),  // No previous error.
+          dart::Script::Handle(Z, dart::Script::null()),
+          TokenPosition::kNoSource, "[InvalidType] in Kernel IR.");
+      break;
+    case kDynamicType:
+      result_ = Object::dynamic_type().raw();
+      break;
+    case kVoidType:
+      result_ = Object::void_type().raw();
+      break;
+    case kBottomType:
+      result_ = dart::Class::Handle(Z, I->object_store()->null_class())
+                    .CanonicalType();
+      break;
+    case kInterfaceType:
+      BuildInterfaceType(false);
+      break;
+    case kSimpleInterfaceType:
+      BuildInterfaceType(true);
+      break;
+    case kFunctionType:
+      BuildFunctionType(false);
+      break;
+    case kSimpleFunctionType:
+      BuildFunctionType(true);
+      break;
+    case kTypeParameterType:
+      BuildTypeParameterType();
+      break;
+    default:
+      UNREACHABLE();
+  }
+}
+
+void StreamingDartTypeTranslator::BuildInterfaceType(bool simple) {
+  // NOTE: That an interface type like `T<A, B>` is considered to be
+  // malformed iff `T` is malformed.
+  //   => We therefore ignore errors in `A` or `B`.
+
+  NameIndex klass_name =
+      builder_->ReadCanonicalNameReference();  // read klass_name.
+
+  intptr_t length;
+  if (simple) {
+    length = 0;
+  } else {
+    length = builder_->ReadListLength();  // read type_arguments list length.
+  }
+  const TypeArguments& type_arguments =
+      BuildTypeArguments(length);  // read type arguments.
+
+  dart::Object& klass =
+      dart::Object::Handle(Z, H.LookupClassByKernelClass(klass_name));
+  result_ = Type::New(klass, type_arguments, TokenPosition::kNoSource);
+  if (finalize_) {
+    ASSERT(active_class_->klass != NULL);
+    result_ = ClassFinalizer::FinalizeType(*active_class_->klass, result_);
+  }
+}
+
+void StreamingDartTypeTranslator::BuildFunctionType(bool simple) {
+  intptr_t list_length = 0;
+  intptr_t* type_parameters = NULL;
+  if (!simple) {
+    list_length =
+        builder_->ReadListLength();  // read type_parameters list length
+    type_parameters = new intptr_t[list_length];
+    for (int i = 0; i < list_length; ++i) {
+      type_parameters[i] = builder_->ReaderOffset();
+      builder_->SkipStringReference();  // read string index (name).
+      builder_->SkipDartType();         // read dart type.
+    }
+  }
+
+  // The spec describes in section "19.1 Static Types":
+  //
+  //     Any use of a malformed type gives rise to a static warning. A
+  //     malformed type is then interpreted as dynamic by the static type
+  //     checker and the runtime unless explicitly specified otherwise.
+  //
+  // So we convert malformed return/parameter types to `dynamic`.
+  TypeParameterScope scope(this, type_parameters, list_length);
+
+  Function& signature_function = Function::ZoneHandle(
+      Z, Function::NewSignatureFunction(*active_class_->klass,
+                                        TokenPosition::kNoSource));
+
+  intptr_t required_count;
+  intptr_t all_count;
+  intptr_t positional_count;
+  if (!simple) {
+    required_count = builder_->ReadUInt();  // read required parameter count.
+    all_count = builder_->ReadUInt();       // read total parameter count.
+    positional_count =
+        builder_->ReadListLength();  // read positional_parameters list length.
+  } else {
+    positional_count =
+        builder_->ReadListLength();  // read positional_parameters list length.
+    required_count = positional_count;
+    all_count = positional_count;
+  }
+
+  const Array& parameter_types =
+      Array::Handle(Z, Array::New(1 + all_count, Heap::kOld));
+  signature_function.set_parameter_types(parameter_types);
+  const Array& parameter_names =
+      Array::Handle(Z, Array::New(1 + all_count, Heap::kOld));
+  signature_function.set_parameter_names(parameter_names);
+
+  intptr_t pos = 0;
+  parameter_types.SetAt(pos, AbstractType::dynamic_type());
+  parameter_names.SetAt(pos, H.DartSymbol("_receiver_"));
+  ++pos;
+  for (intptr_t i = 0; i < positional_count; ++i, ++pos) {
+    BuildTypeInternal();  // read ith positional parameter.
+    if (result_.IsMalformed()) {
+      result_ = AbstractType::dynamic_type().raw();
+    }
+    parameter_types.SetAt(pos, result_);
+    parameter_names.SetAt(pos, H.DartSymbol("noname"));
+  }
+
+  // The additional first parameter is the receiver type (set to dynamic).
+  signature_function.set_num_fixed_parameters(1 + required_count);
+  signature_function.SetNumOptionalParameters(
+      all_count - required_count, positional_count > required_count);
+
+  if (!simple) {
+    const intptr_t named_count =
+        builder_->ReadListLength();  // read named_parameters list length.
+    for (intptr_t i = 0; i < named_count; ++i, ++pos) {
+      // read string reference (i.e. named_parameters[i].name).
+      dart::String& name = H.DartSymbol(builder_->ReadStringReference());
+      BuildTypeInternal();  // read named_parameters[i].type.
+      if (result_.IsMalformed()) {
+        result_ = AbstractType::dynamic_type().raw();
+      }
+      parameter_types.SetAt(pos, result_);
+      parameter_names.SetAt(pos, name);
+    }
+  }
+
+  BuildTypeInternal();  // read return type.
+  if (result_.IsMalformed()) {
+    result_ = AbstractType::dynamic_type().raw();
+  }
+  signature_function.set_result_type(result_);
+
+  Type& signature_type =
+      Type::ZoneHandle(Z, signature_function.SignatureType());
+
+  if (finalize_) {
+    signature_type ^=
+        ClassFinalizer::FinalizeType(*active_class_->klass, signature_type);
+    // Do not refer to signature_function anymore, since it may have been
+    // replaced during canonicalization.
+    signature_function = Function::null();
+  }
+
+  result_ = signature_type.raw();
+}
+
+static intptr_t FindTypeParameterIndex(intptr_t* parameters,
+                                       intptr_t parameters_count,
+                                       intptr_t look_for) {
+  for (intptr_t i = 0; i < parameters_count; ++i) {
+    if (look_for == parameters[i]) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+static intptr_t FindTypeParameterIndex(List<TypeParameter>* parameters,
+                                       intptr_t look_for) {
+  for (intptr_t i = 0; i < parameters->length(); ++i) {
+    if (look_for == (*parameters)[i]->kernel_offset()) {
+      return i;
+    }
+  }
+  return -1;
+}
+
+void StreamingDartTypeTranslator::BuildTypeParameterType() {
+  builder_->ReadUInt();                           // read parameter index.
+  intptr_t binary_offset = builder_->ReadUInt();  // read binary offset.
+  builder_->SkipOptionalDartType();               // read bound.
+
+  if (binary_offset == 0) {
+    // TODO(jensj): This doesn't appear to actually happen.
+    UNIMPLEMENTED();
+    return;
+  }
+
+  for (TypeParameterScope* scope = type_parameter_scope_; scope != NULL;
+       scope = scope->outer()) {
+    const intptr_t index = FindTypeParameterIndex(
+        scope->parameters(), scope->parameters_count(), binary_offset);
+    if (index >= 0) {
+      result_ ^= dart::Type::DynamicType();
+      return;
+    }
+  }
+
+  if ((active_class_->member != NULL) && active_class_->member->IsProcedure()) {
+    Procedure* procedure = Procedure::Cast(active_class_->member);
+    if ((procedure->function() != NULL) &&
+        (procedure->function()->type_parameters().length() > 0)) {
+      //
+      // WARNING: This is a little hackish:
+      //
+      // We have a static factory constructor. The kernel IR gives the factory
+      // constructor function it's own type parameters (which are equal in name
+      // and number to the ones of the enclosing class).
+      // I.e.,
+      //
+      //   class A<T> {
+      //     factory A.x() { return new B<T>(); }
+      //   }
+      //
+      //  is basically translated to this:
+      //
+      //   class A<T> {
+      //     static A.x<T'>() { return new B<T'>(); }
+      //   }
+      //
+      const intptr_t index = FindTypeParameterIndex(
+          &procedure->function()->type_parameters(), binary_offset);
+      if (index >= 0) {
+        if (procedure->kind() == Procedure::kFactory) {
+          // The index of the type parameter in [parameters] is
+          // the same index into the `klass->type_parameters()` array.
+          result_ ^= dart::TypeArguments::Handle(
+                         Z, active_class_->klass->type_parameters())
+                         .TypeAt(index);
+        } else {
+          result_ ^= dart::Type::DynamicType();
+        }
+        return;
+      }
+    }
+  }
+
+  ASSERT(active_class_->kernel_class != NULL);
+  List<TypeParameter>* parameters =
+      &active_class_->kernel_class->type_parameters();
+  const intptr_t index = FindTypeParameterIndex(parameters, binary_offset);
+  if (index >= 0) {
+    // The index of the type parameter in [parameters] is
+    // the same index into the `klass->type_parameters()` array.
+    result_ ^=
+        dart::TypeArguments::Handle(Z, active_class_->klass->type_parameters())
+            .TypeAt(index);
+    return;
+  }
+
+  UNREACHABLE();
+}
+
+const TypeArguments& StreamingDartTypeTranslator::BuildTypeArguments(
+    intptr_t length) {
+  bool only_dynamic = true;
+  intptr_t offset = builder_->ReaderOffset();
+  for (intptr_t i = 0; i < length; ++i) {
+    if (builder_->ReadTag() != kDynamicType) {  // read ith type's tag.
+      only_dynamic = false;
+      builder_->SetOffset(offset);
+      break;
+    }
+  }
+  TypeArguments& type_arguments = TypeArguments::ZoneHandle(Z);
+  if (!only_dynamic) {
+    type_arguments = TypeArguments::New(length);
+    for (intptr_t i = 0; i < length; ++i) {
+      BuildTypeInternal();  // read ith type.
+      if (!result_.IsDynamicType()) {
+        only_dynamic = false;
+      }
+      if (result_.IsMalformed()) {
+        type_arguments = TypeArguments::null();
+        return type_arguments;
+      }
+      type_arguments.SetTypeAt(i, result_);
+    }
+
+    if (finalize_) {
+      type_arguments = type_arguments.Canonicalize();
+    }
+  }
+  return type_arguments;
+}
+
+const TypeArguments&
+StreamingDartTypeTranslator::BuildInstantiatedTypeArguments(
+    const dart::Class& receiver_class,
+    intptr_t length) {
+  const TypeArguments& type_arguments = BuildTypeArguments(length);
+  if (type_arguments.IsNull()) return type_arguments;
+
+  // We make a temporary [Type] object and use `ClassFinalizer::FinalizeType` to
+  // finalize the argument types.
+  // (This can for example make the [type_arguments] vector larger)
+  Type& type = Type::Handle(
+      Z, Type::New(receiver_class, type_arguments, TokenPosition::kNoSource));
+  if (finalize_) {
+    type ^=
+        ClassFinalizer::FinalizeType(*builder_->active_class()->klass, type);
+  }
+
+  const TypeArguments& instantiated_type_arguments =
+      TypeArguments::ZoneHandle(Z, type.arguments());
+  return instantiated_type_arguments;
+}
+
+
+const Type& StreamingDartTypeTranslator::ReceiverType(
+    const dart::Class& klass) {
+  ASSERT(!klass.IsNull());
+  ASSERT(!klass.IsTypedefClass());
+  // Note that if klass is _Closure, the returned type will be _Closure,
+  // and not the signature type.
+  Type& type = Type::ZoneHandle(Z, klass.CanonicalType());
+  if (!type.IsNull()) {
+    return type;
+  }
+  type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()),
+                   klass.token_pos());
+  if (klass.is_type_finalized()) {
+    type ^= ClassFinalizer::FinalizeType(klass, type);
+    klass.SetCanonicalType(type);
+  }
+  return type;
+}
+
+
+StreamingConstantEvaluator::StreamingConstantEvaluator(
+    StreamingFlowGraphBuilder* builder)
     : builder_(builder),
       isolate_(Isolate::Current()),
-      zone_(zone),
-      translation_helper_(*h),
-      // type_translator_(*type_translator),
+      zone_(builder_->zone_),
+      translation_helper_(builder_->translation_helper_),
+      type_translator_(builder_->type_translator_),
       script_(Script::Handle(
-          zone,
+          zone_,
           builder == NULL ? Script::null()
                           : builder_->parsed_function()->function().script())),
-      result_(Instance::Handle(zone)) {}
+      result_(Instance::Handle(zone_)) {}
 
 
-Instance& StreamingConstantEvaluator::EvaluateExpression() {
-  intptr_t offset = builder_->ReaderOffset();
+Instance& StreamingConstantEvaluator::EvaluateExpression(intptr_t offset,
+                                                         bool reset_position) {
   if (!GetCachedConstant(offset, &result_)) {
+    intptr_t original_offset = builder_->ReaderOffset();
+    builder_->SetOffset(offset);
     uint8_t payload = 0;
-    Tag tag = builder_->ReadTag(&payload);
+    Tag tag = builder_->ReadTag(&payload);  // read tag.
     switch (tag) {
+      case kVariableGet:
+        EvaluateVariableGet();
+        break;
+      case kSpecializedVariableGet:
+        EvaluateVariableGet(payload);
+        break;
+      case kPropertyGet:
+        EvaluatePropertyGet();
+        break;
       case kStaticGet:
         EvaluateStaticGet();
         break;
+      case kMethodInvocation:
+        EvaluateMethodInvocation();
+        break;
+      case kStaticInvocation:
+      case kConstStaticInvocation:
+        EvaluateStaticInvocation();
+        break;
+      case kConstructorInvocation:
+      case kConstConstructorInvocation:
+        EvaluateConstructorInvocationInternal();
+        break;
+      case kNot:
+        EvaluateNot();
+        break;
+      case kLogicalExpression:
+        EvaluateLogicalExpression();
+        break;
+      case kConditionalExpression:
+        EvaluateConditionalExpression();
+        break;
+      case kStringConcatenation:
+        EvaluateStringConcatenation();
+        break;
       case kSymbolLiteral:
         EvaluateSymbolLiteral();
         break;
+      case kTypeLiteral:
+        EvaluateTypeLiteral();
+        break;
+      case kListLiteral:
+      case kConstListLiteral:
+        EvaluateListLiteralInternal();
+        break;
+      case kMapLiteral:
+      case kConstMapLiteral:
+        EvaluateMapLiteralInternal();
+        break;
+      case kLet:
+        EvaluateLet();
+        break;
+      case kBigIntLiteral:
+        EvaluateBigIntLiteral();
+        break;
+      case kStringLiteral:
+        EvaluateStringLiteral();
+        break;
+      case kSpecialIntLiteral:
+        EvaluateIntLiteral(payload);
+        break;
+      case kNegativeIntLiteral:
+        EvaluateIntLiteral(true);
+        break;
+      case kPositiveIntLiteral:
+        EvaluateIntLiteral(false);
+        break;
       case kDoubleLiteral:
         EvaluateDoubleLiteral();
         break;
+      case kTrueLiteral:
+        EvaluateBoolLiteral(true);
+        break;
+      case kFalseLiteral:
+        EvaluateBoolLiteral(false);
+        break;
+      case kNullLiteral:
+        EvaluateNullLiteral();
+        break;
       default:
         UNREACHABLE();
     }
 
     CacheConstantValue(offset, result_);
+    if (reset_position) builder_->SetOffset(original_offset);
   }
   // We return a new `ZoneHandle` here on purpose: The intermediate language
   // instructions do not make a copy of the handle, so we do it.
-  return dart::Instance::ZoneHandle(Z, result_.raw());
+  return Instance::ZoneHandle(Z, result_.raw());
+}
+
+Instance& StreamingConstantEvaluator::EvaluateListLiteral(intptr_t offset,
+                                                          bool reset_position) {
+  if (!GetCachedConstant(offset, &result_)) {
+    intptr_t original_offset = builder_->ReaderOffset();
+    builder_->SetOffset(offset);
+    builder_->ReadTag();  // skip tag.
+    EvaluateListLiteralInternal();
+
+    CacheConstantValue(offset, result_);
+    if (reset_position) builder_->SetOffset(original_offset);
+  }
+  // We return a new `ZoneHandle` here on purpose: The intermediate language
+  // instructions do not make a copy of the handle, so we do it.
+  return Instance::ZoneHandle(Z, result_.raw());
+}
+
+Instance& StreamingConstantEvaluator::EvaluateMapLiteral(intptr_t offset,
+                                                         bool reset_position) {
+  if (!GetCachedConstant(offset, &result_)) {
+    intptr_t original_offset = builder_->ReaderOffset();
+    builder_->SetOffset(offset);
+    builder_->ReadTag();  // skip tag.
+    EvaluateMapLiteralInternal();
+
+    CacheConstantValue(offset, result_);
+    if (reset_position) builder_->SetOffset(original_offset);
+  }
+  // We return a new `ZoneHandle` here on purpose: The intermediate language
+  // instructions do not make a copy of the handle, so we do it.
+  return Instance::ZoneHandle(Z, result_.raw());
+}
+
+Instance& StreamingConstantEvaluator::EvaluateConstructorInvocation(
+    intptr_t offset,
+    bool reset_position) {
+  if (!GetCachedConstant(offset, &result_)) {
+    intptr_t original_offset = builder_->ReaderOffset();
+    builder_->SetOffset(offset);
+    builder_->ReadTag();  // skip tag.
+    EvaluateConstructorInvocationInternal();
+
+    CacheConstantValue(offset, result_);
+    if (reset_position) builder_->SetOffset(original_offset);
+  }
+  // We return a new `ZoneHandle` here on purpose: The intermediate language
+  // instructions do not make a copy of the handle, so we do it.
+  return Instance::ZoneHandle(Z, result_.raw());
+}
+
+Object& StreamingConstantEvaluator::EvaluateExpressionSafe(intptr_t offset) {
+  LongJumpScope jump;
+  if (setjmp(*jump.Set()) == 0) {
+    return EvaluateExpression(offset);
+  } else {
+    Thread* thread = H.thread();
+    Error& error = Error::Handle(Z);
+    error = thread->sticky_error();
+    thread->clear_sticky_error();
+    return error;
+  }
+}
+
+void StreamingConstantEvaluator::EvaluateVariableGet() {
+  // When we see a [VariableGet] the corresponding [VariableDeclaration] must've
+  // been executed already. It therefore must have a constant object associated
+  // with it.
+  builder_->ReadPosition();  // read position.
+  intptr_t variable_kernel_position =
+      builder_->ReadUInt();          // read kernel position.
+  builder_->ReadUInt();              // read relative variable index.
+  builder_->SkipOptionalDartType();  // read promoted type.
+  LocalVariable* variable = builder_->LookupVariable(variable_kernel_position);
+  ASSERT(variable->IsConst());
+  result_ = variable->ConstValue()->raw();
+}
+
+void StreamingConstantEvaluator::EvaluateVariableGet(uint8_t payload) {
+  // When we see a [VariableGet] the corresponding [VariableDeclaration] must've
+  // been executed already. It therefore must have a constant object associated
+  // with it.
+  builder_->ReadPosition();  // read position.
+  intptr_t variable_kernel_position =
+      builder_->ReadUInt();  // read kernel position.
+  LocalVariable* variable = builder_->LookupVariable(variable_kernel_position);
+  ASSERT(variable->IsConst());
+  result_ = variable->ConstValue()->raw();
+}
+
+void StreamingConstantEvaluator::EvaluatePropertyGet() {
+  builder_->ReadPosition();  // read position.
+  intptr_t expression_offset = builder_->ReaderOffset();
+  builder_->SkipExpression();                            // read receiver.
+  StringIndex name = builder_->ReadNameAsStringIndex();  // read name.
+  // Read unused "interface_target_reference".
+  builder_->SkipCanonicalNameReference();
+
+  if (H.StringEquals(name, "length")) {
+    EvaluateExpression(expression_offset);
+    if (result_.IsString()) {
+      const dart::String& str =
+          dart::String::Handle(Z, dart::String::RawCast(result_.raw()));
+      result_ = Integer::New(str.Length());
+    } else {
+      H.ReportError(
+          "Constant expressions can only call "
+          "'length' on string constants.");
+    }
+  } else {
+    UNREACHABLE();
+  }
 }
 
 void StreamingConstantEvaluator::EvaluateStaticGet() {
-  builder_->ReadPosition();
-  NameIndex target = builder_->ReadCanonicalNameReference();
+  builder_->ReadPosition();  // read position.
+  NameIndex target =
+      builder_->ReadCanonicalNameReference();  // read target_reference.
 
   if (H.IsField(target)) {
     const dart::Field& field =
@@ -92,10 +638,183 @@
   }
 }
 
+void StreamingConstantEvaluator::EvaluateMethodInvocation() {
+  builder_->ReadPosition();  // read position.
+  // This method call wasn't cached, so receiver et al. isn't cached either.
+  const dart::Instance& receiver =
+      EvaluateExpression(builder_->ReaderOffset(), false);  // read receiver.
+  dart::Class& klass = dart::Class::Handle(
+      Z, isolate_->class_table()->At(receiver.GetClassId()));
+  ASSERT(!klass.IsNull());
+
+  // Search the superclass chain for the selector.
+  dart::Function& function = dart::Function::Handle(Z);
+  const dart::String& method_name =
+      builder_->ReadNameAsMethodName();  // read name.
+  while (!klass.IsNull()) {
+    function = klass.LookupDynamicFunctionAllowPrivate(method_name);
+    if (!function.IsNull()) break;
+    klass = klass.SuperClass();
+  }
+
+  // The frontend should guarantee that [MethodInvocation]s inside constant
+  // expressions are always valid.
+  ASSERT(!function.IsNull());
+
+  // Read first parts of arguments: count and list of types.
+  intptr_t argument_count = builder_->PeekArgumentsCount();
+  // Dart does not support generic methods yet.
+  ASSERT(builder_->PeekArgumentsTypeCount() == 0);
+  builder_->SkipArgumentsBeforeActualArguments();
+
+  // Run the method and canonicalize the result.
+  const Object& result = RunFunction(function, argument_count, &receiver, NULL);
+  result_ ^= result.raw();
+  result_ = H.Canonicalize(result_);
+
+  builder_->SkipCanonicalNameReference();  // read "interface_target_reference"
+}
+
+void StreamingConstantEvaluator::EvaluateStaticInvocation() {
+  builder_->ReadPosition();  // read position.
+  NameIndex procedue_reference =
+      builder_->ReadCanonicalNameReference();  // read procedure reference.
+
+  const Function& function = Function::ZoneHandle(
+      Z, H.LookupStaticMethodByKernelProcedure(procedue_reference));
+  dart::Class& klass = dart::Class::Handle(Z, function.Owner());
+
+  intptr_t argument_count =
+      builder_->ReadUInt();  // read arguments part #1: arguments count.
+
+  // Build the type arguments vector (if necessary).
+  const TypeArguments* type_arguments =
+      TranslateTypeArguments(function, &klass);  // read argument types.
+
+  // read positional and named parameters.
+  const Object& result =
+      RunFunction(function, argument_count, NULL, type_arguments);
+  result_ ^= result.raw();
+  result_ = H.Canonicalize(result_);
+}
+
+void StreamingConstantEvaluator::EvaluateConstructorInvocationInternal() {
+  builder_->ReadPosition();  // read position.
+
+  NameIndex target = builder_->ReadCanonicalNameReference();  // read target.
+  const Function& constructor =
+      Function::Handle(Z, H.LookupConstructorByKernelConstructor(target));
+  dart::Class& klass = dart::Class::Handle(Z, constructor.Owner());
+
+  intptr_t argument_count =
+      builder_->ReadUInt();  // read arguments part #1: arguments count.
+
+  // Build the type arguments vector (if necessary).
+  const TypeArguments* type_arguments =
+      TranslateTypeArguments(constructor, &klass);  // read argument types.
+
+  // Prepare either the instance or the type argument vector for the constructor
+  // call.
+  Instance* receiver = NULL;
+  const TypeArguments* type_arguments_argument = NULL;
+  if (!constructor.IsFactory()) {
+    receiver = &Instance::ZoneHandle(Z, Instance::New(klass, Heap::kOld));
+    if (type_arguments != NULL) {
+      receiver->SetTypeArguments(*type_arguments);
+    }
+  } else {
+    type_arguments_argument = type_arguments;
+  }
+
+  // read positional and named parameters.
+  const Object& result = RunFunction(constructor, argument_count, receiver,
+                                     type_arguments_argument);
+
+  if (constructor.IsFactory()) {
+    // Factories return the new object.
+    result_ ^= result.raw();
+    result_ = H.Canonicalize(result_);
+  } else {
+    ASSERT(!receiver->IsNull());
+    result_ = H.Canonicalize(*receiver);
+  }
+}
+
+void StreamingConstantEvaluator::EvaluateNot() {
+  result_ ^= Bool::Get(!EvaluateBooleanExpressionHere()).raw();
+}
+
+void StreamingConstantEvaluator::EvaluateLogicalExpression() {
+  bool left = EvaluateBooleanExpressionHere();  // read left.
+  LogicalExpression::Operator op = static_cast<LogicalExpression::Operator>(
+      builder_->ReadByte());  // read operator.
+  if (op == LogicalExpression::kAnd) {
+    if (left) {
+      EvaluateBooleanExpressionHere();  // read right.
+    } else {
+      builder_->SkipExpression();  // read right.
+    }
+  } else {
+    ASSERT(op == LogicalExpression::kOr);
+    if (!left) {
+      EvaluateBooleanExpressionHere();  // read right.
+    } else {
+      builder_->SkipExpression();  // read right.
+    }
+  }
+}
+
+void StreamingConstantEvaluator::EvaluateConditionalExpression() {
+  bool condition = EvaluateBooleanExpressionHere();
+  if (condition) {
+    EvaluateExpression(builder_->ReaderOffset(), false);  // read then.
+    builder_->SkipExpression();                           // read otherwise.
+  } else {
+    builder_->SkipExpression();                           // read then.
+    EvaluateExpression(builder_->ReaderOffset(), false);  // read otherwise.
+  }
+  builder_->SkipOptionalDartType();  // read unused static type.
+}
+
+void StreamingConstantEvaluator::EvaluateStringConcatenation() {
+  builder_->ReadPosition();                      // read position.
+  intptr_t length = builder_->ReadListLength();  // read list length.
+
+  bool all_string = true;
+  const Array& strings = Array::Handle(Z, Array::New(length));
+  for (intptr_t i = 0; i < length; ++i) {
+    EvaluateExpression(builder_->ReaderOffset(),
+                       false);  // read ith expression.
+    strings.SetAt(i, result_);
+    all_string = all_string && result_.IsString();
+  }
+  if (all_string) {
+    result_ = dart::String::ConcatAll(strings, Heap::kOld);
+    result_ = H.Canonicalize(result_);
+  } else {
+    // Get string interpolation function.
+    const dart::Class& cls = dart::Class::Handle(
+        Z, dart::Library::LookupCoreClass(Symbols::StringBase()));
+    ASSERT(!cls.IsNull());
+    const Function& func = Function::Handle(
+        Z, cls.LookupStaticFunction(
+               dart::Library::PrivateCoreLibName(Symbols::Interpolate())));
+    ASSERT(!func.IsNull());
+
+    // Build argument array to pass to the interpolation function.
+    const Array& interpolate_arg = Array::Handle(Z, Array::New(1, Heap::kOld));
+    interpolate_arg.SetAt(0, strings);
+
+    // Run and canonicalize.
+    const Object& result =
+        RunFunction(func, interpolate_arg, Array::null_array());
+    result_ = H.Canonicalize(dart::String::Cast(result));
+  }
+}
 
 void StreamingConstantEvaluator::EvaluateSymbolLiteral() {
-  StringIndex str_index(builder_->ReadUInt());
-  const dart::String& symbol_value = H.DartSymbol(str_index);
+  const dart::String& symbol_value = H.DartSymbol(
+      builder_->ReadStringReference());  // read index into string table.
 
   const dart::Class& symbol_class =
       dart::Class::ZoneHandle(Z, I->object_store()->symbol_class());
@@ -107,13 +826,184 @@
       symbol_class, TypeArguments::Handle(Z), symbol_constructor, symbol_value);
 }
 
+void StreamingConstantEvaluator::EvaluateTypeLiteral() {
+  const AbstractType& type = T.BuildType();
+  if (type.IsMalformed()) {
+    H.ReportError("Malformed type literal in constant expression.");
+  }
+  result_ = type.raw();
+}
 
-void StreamingConstantEvaluator::EvaluateDoubleLiteral() {
-  StringIndex str_index(builder_->ReadUInt());
-  result_ = dart::Double::New(H.DartString(str_index), Heap::kOld);
+void StreamingConstantEvaluator::EvaluateListLiteralInternal() {
+  builder_->ReadPosition();  // read position.
+  const TypeArguments& type_arguments = T.BuildTypeArguments(1);  // read type.
+  intptr_t length = builder_->ReadListLength();  // read list length.
+  const Array& const_list =
+      Array::ZoneHandle(Z, Array::New(length, Heap::kOld));
+  const_list.SetTypeArguments(type_arguments);
+  for (intptr_t i = 0; i < length; ++i) {
+    const Instance& expression = EvaluateExpression(
+        builder_->ReaderOffset(), false);  // read ith expression.
+    const_list.SetAt(i, expression);
+  }
+  const_list.MakeImmutable();
+  result_ = H.Canonicalize(const_list);
+}
+
+void StreamingConstantEvaluator::EvaluateMapLiteralInternal() {
+  builder_->ReadPosition();  // read position.
+  const TypeArguments& type_arguments =
+      T.BuildTypeArguments(2);  // read key type and value type.
+
+  intptr_t length = builder_->ReadListLength();  // read length of entries.
+
+  // This MapLiteral wasn't cached, so content isn't cached either.
+  Array& const_kv_array =
+      Array::ZoneHandle(Z, Array::New(2 * length, Heap::kOld));
+  for (intptr_t i = 0; i < length; ++i) {
+    const_kv_array.SetAt(2 * i + 0, EvaluateExpression(builder_->ReaderOffset(),
+                                                       false));  // read key.
+    const_kv_array.SetAt(2 * i + 1, EvaluateExpression(builder_->ReaderOffset(),
+                                                       false));  // read value.
+  }
+
+  const_kv_array.MakeImmutable();
+  const_kv_array ^= H.Canonicalize(const_kv_array);
+
+  const dart::Class& map_class = dart::Class::Handle(
+      Z, dart::Library::LookupCoreClass(Symbols::ImmutableMap()));
+  ASSERT(!map_class.IsNull());
+  ASSERT(map_class.NumTypeArguments() == 2);
+
+  const dart::Field& field = dart::Field::Handle(
+      Z, map_class.LookupInstanceFieldAllowPrivate(H.DartSymbol("_kvPairs")));
+  ASSERT(!field.IsNull());
+
+  // NOTE: This needs to be kept in sync with `runtime/lib/immutable_map.dart`!
+  result_ = Instance::New(map_class, Heap::kOld);
+  ASSERT(!result_.IsNull());
+  result_.SetTypeArguments(type_arguments);
+  result_.SetField(field, const_kv_array);
   result_ = H.Canonicalize(result_);
 }
 
+void StreamingConstantEvaluator::EvaluateLet() {
+  intptr_t kernel_position = builder_->ReaderOffset();
+  LocalVariable* local = builder_->LookupVariable(kernel_position);
+
+  // read variable declaration.
+  builder_->ReadPosition();         // read position.
+  builder_->ReadPosition();         // read equals position.
+  builder_->ReadFlags();            // read flags.
+  builder_->SkipStringReference();  // read name index.
+  builder_->SkipDartType();         // read type.
+  Tag tag = builder_->ReadTag();    // read (first part of) initializer.
+  if (tag == kNothing) {
+    local->SetConstValue(Instance::ZoneHandle(Z, dart::Instance::null()));
+  } else {
+    local->SetConstValue(EvaluateExpression(
+        builder_->ReaderOffset(), false));  // read rest of initializer.
+  }
+
+  EvaluateExpression(builder_->ReaderOffset(), false);  // read body
+}
+
+void StreamingConstantEvaluator::EvaluateBigIntLiteral() {
+  const dart::String& value =
+      H.DartString(builder_->ReadStringReference());  // read string reference.
+  result_ = Integer::New(value, Heap::kOld);
+  result_ = H.Canonicalize(result_);
+}
+
+void StreamingConstantEvaluator::EvaluateStringLiteral() {
+  result_ = H.DartSymbol(builder_->ReadStringReference())
+                .raw();  // read string reference.
+}
+
+void StreamingConstantEvaluator::EvaluateIntLiteral(uint8_t payload) {
+  int64_t value = static_cast<int32_t>(payload) - SpecializedIntLiteralBias;
+  result_ = dart::Integer::New(value, Heap::kOld);
+  result_ = H.Canonicalize(result_);
+}
+
+void StreamingConstantEvaluator::EvaluateIntLiteral(bool is_negative) {
+  int64_t value = is_negative ? -static_cast<int64_t>(builder_->ReadUInt())
+                              : builder_->ReadUInt();  // read value.
+  result_ = dart::Integer::New(value, Heap::kOld);
+  result_ = H.Canonicalize(result_);
+}
+
+void StreamingConstantEvaluator::EvaluateDoubleLiteral() {
+  result_ = Double::New(H.DartString(builder_->ReadStringReference()),
+                        Heap::kOld);  // read string reference.
+  result_ = H.Canonicalize(result_);
+}
+
+void StreamingConstantEvaluator::EvaluateBoolLiteral(bool value) {
+  result_ = dart::Bool::Get(value).raw();
+}
+
+void StreamingConstantEvaluator::EvaluateNullLiteral() {
+  result_ = dart::Instance::null();
+}
+
+// This depends on being about to read the list of positionals on arguments.
+const Object& StreamingConstantEvaluator::RunFunction(
+    const Function& function,
+    intptr_t argument_count,
+    const Instance* receiver,
+    const TypeArguments* type_args) {
+  // We do not support generic methods yet.
+  ASSERT((receiver == NULL) || (type_args == NULL));
+  intptr_t extra_arguments =
+      (receiver != NULL ? 1 : 0) + (type_args != NULL ? 1 : 0);
+
+  // Build up arguments.
+  const Array& arguments =
+      Array::ZoneHandle(Z, Array::New(extra_arguments + argument_count));
+  intptr_t pos = 0;
+  if (receiver != NULL) {
+    arguments.SetAt(pos++, *receiver);
+  }
+  if (type_args != NULL) {
+    arguments.SetAt(pos++, *type_args);
+  }
+
+  // List of positional.
+  intptr_t list_length = builder_->ReadListLength();  // read list length.
+  for (intptr_t i = 0; i < list_length; ++i) {
+    EvaluateExpression(builder_->ReaderOffset(),
+                       false);  // read ith expression.
+    arguments.SetAt(pos++, result_);
+  }
+
+  // List of named.
+  list_length = builder_->ReadListLength();  // read list length.
+  const Array& names = Array::ZoneHandle(Z, Array::New(list_length));
+  for (intptr_t i = 0; i < list_length; ++i) {
+    dart::String& name =
+        H.DartSymbol(builder_->ReadStringReference());  // read ith name index.
+    names.SetAt(i, name);
+    EvaluateExpression(builder_->ReaderOffset(),
+                       false);  // read ith expression.
+    arguments.SetAt(pos++, result_);
+  }
+
+  return RunFunction(function, arguments, names);
+}
+
+const Object& StreamingConstantEvaluator::RunFunction(const Function& function,
+                                                      const Array& arguments,
+                                                      const Array& names) {
+  const Array& args_descriptor =
+      Array::Handle(Z, ArgumentsDescriptor::New(arguments.Length(), names));
+  const Object& result = Object::Handle(
+      Z, DartEntry::InvokeFunction(function, arguments, args_descriptor));
+  if (result.IsError()) {
+    H.ReportError(Error::Cast(result), "error evaluating constant constructor");
+  }
+  return result;
+}
 
 RawObject* StreamingConstantEvaluator::EvaluateConstConstructorCall(
     const dart::Class& type_class,
@@ -154,6 +1044,33 @@
   return H.Canonicalize(instance);
 }
 
+const TypeArguments* StreamingConstantEvaluator::TranslateTypeArguments(
+    const Function& target,
+    dart::Class* target_klass) {
+  intptr_t types_count = builder_->ReadListLength();  // read types count.
+
+  const TypeArguments* type_arguments = NULL;
+  if (types_count > 0) {
+    type_arguments = &T.BuildInstantiatedTypeArguments(
+        *target_klass, types_count);  // read types.
+
+    if (!(type_arguments->IsNull() || type_arguments->IsInstantiated())) {
+      H.ReportError("Type must be constant in const constructor.");
+    }
+  } else if (target.IsFactory() && type_arguments == NULL) {
+    // All factories take a type arguments vector as first argument (independent
+    // of whether the class is generic or not).
+    type_arguments = &TypeArguments::ZoneHandle(Z, TypeArguments::null());
+  }
+  return type_arguments;
+}
+
+bool StreamingConstantEvaluator::EvaluateBooleanExpressionHere() {
+  EvaluateExpression(builder_->ReaderOffset(), false);
+  AssertBoolInCheckedMode();
+  return result_.raw() == Bool::True().raw();
+}
+
 bool StreamingConstantEvaluator::GetCachedConstant(intptr_t kernel_offset,
                                                    Instance* value) {
   if (builder_ == NULL) return false;
@@ -177,7 +1094,7 @@
   // do not assert that 'compile_time_constants' has not changed.
   constants.Release();
   if (FLAG_compiler_stats && is_present) {
-    H.thread()->compiler_stats()->num_const_cache_hits++;
+    ++H.thread()->compiler_stats()->num_const_cache_hits;
   }
   return is_present;
 }
@@ -208,100 +1125,108 @@
 }
 
 
-Fragment StreamingFlowGraphBuilder::BuildAt(intptr_t kernel_offset) {
+Fragment StreamingFlowGraphBuilder::BuildExpressionAt(intptr_t kernel_offset) {
   SetOffset(kernel_offset);
+  return BuildExpression();  // read expression.
+}
 
+Fragment StreamingFlowGraphBuilder::BuildStatementAt(intptr_t kernel_offset) {
+  SetOffset(kernel_offset);
+  return BuildStatement();  // read statement.
+}
+
+Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) {
   uint8_t payload = 0;
-  Tag tag = ReadTag(&payload);
+  Tag tag = ReadTag(&payload);  // read tag.
   switch (tag) {
     case kInvalidExpression:
-      return BuildInvalidExpression();
-    //    case kVariableGet:
-    //      return VariableGet::ReadFrom(reader_);
-    //    case kSpecializedVariableGet:
-    //      return VariableGet::ReadFrom(reader_, payload);
-    //    case kVariableSet:
-    //      return VariableSet::ReadFrom(reader_);
-    //    case kSpecializedVariableSet:
-    //      return VariableSet::ReadFrom(reader_, payload);
-    //    case kPropertyGet:
-    //      return PropertyGet::ReadFrom(reader_);
-    //    case kPropertySet:
-    //      return PropertySet::ReadFrom(reader_);
-    //    case kDirectPropertyGet:
-    //      return DirectPropertyGet::ReadFrom(reader_);
-    //    case kDirectPropertySet:
-    //      return DirectPropertySet::ReadFrom(reader_);
+      return BuildInvalidExpression(position);
+    case kVariableGet:
+      return BuildVariableGet(position);
+    case kSpecializedVariableGet:
+      return BuildVariableGet(payload, position);
+    case kVariableSet:
+      return BuildVariableSet(position);
+    case kSpecializedVariableSet:
+      return BuildVariableSet(payload, position);
+    case kPropertyGet:
+      return BuildPropertyGet(position);
+    case kPropertySet:
+      return BuildPropertySet(position);
+    case kDirectPropertyGet:
+      return BuildDirectPropertyGet(position);
+    case kDirectPropertySet:
+      return BuildDirectPropertySet(position);
     case kStaticGet:
-      return BuildStaticGet();
-    //    case kStaticSet:
-    //      return StaticSet::ReadFrom(reader_);
-    //    case kMethodInvocation:
-    //      return MethodInvocation::ReadFrom(reader_);
-    //    case kDirectMethodInvocation:
-    //      return DirectMethodInvocation::ReadFrom(reader_);
-    //    case kStaticInvocation:
-    //      return StaticInvocation::ReadFrom(reader_, false);
-    //    case kConstStaticInvocation:
-    //      return StaticInvocation::ReadFrom(reader_, true);
-    //    case kConstructorInvocation:
-    //      return ConstructorInvocation::ReadFrom(reader_, false);
-    //    case kConstConstructorInvocation:
-    //      return ConstructorInvocation::ReadFrom(reader_, true);
-    //    case kNot:
-    //      return Not::ReadFrom(reader_);
-    //    case kLogicalExpression:
-    //      return LogicalExpression::ReadFrom(reader_);
-    //    case kConditionalExpression:
-    //      return ConditionalExpression::ReadFrom(reader_);
-    //    case kStringConcatenation:
-    //      return StringConcatenation::ReadFrom(reader_);
-    //    case kIsExpression:
-    //      return IsExpression::ReadFrom(reader_);
-    //    case kAsExpression:
-    //      return AsExpression::ReadFrom(reader_);
+      return BuildStaticGet(position);
+    case kStaticSet:
+      return BuildStaticSet(position);
+    case kMethodInvocation:
+      return BuildMethodInvocation(position);
+    case kDirectMethodInvocation:
+      return BuildDirectMethodInvocation(position);
+    case kStaticInvocation:
+      return BuildStaticInvocation(false, position);
+    case kConstStaticInvocation:
+      return BuildStaticInvocation(true, position);
+    case kConstructorInvocation:
+      return BuildConstructorInvocation(false, position);
+    case kConstConstructorInvocation:
+      return BuildConstructorInvocation(true, position);
+    case kNot:
+      return BuildNot(position);
+    case kLogicalExpression:
+      return BuildLogicalExpression(position);
+    case kConditionalExpression:
+      return BuildConditionalExpression(position);
+    case kStringConcatenation:
+      return BuildStringConcatenation(position);
+    case kIsExpression:
+      return BuildIsExpression(position);
+    case kAsExpression:
+      return BuildAsExpression(position);
     case kSymbolLiteral:
-      return BuildSymbolLiteral();
-    //    case kTypeLiteral:
-    //      return TypeLiteral::ReadFrom(reader_);
+      return BuildSymbolLiteral(position);
+    case kTypeLiteral:
+      return BuildTypeLiteral(position);
     case kThisExpression:
-      return BuildThisExpression();
+      return BuildThisExpression(position);
     case kRethrow:
-      return BuildRethrow();
-    //    case kThrow:
-    //      return Throw::ReadFrom(reader_);
-    //    case kListLiteral:
-    //      return ListLiteral::ReadFrom(reader_, false);
-    //    case kConstListLiteral:
-    //      return ListLiteral::ReadFrom(reader_, true);
-    //    case kMapLiteral:
-    //      return MapLiteral::ReadFrom(reader_, false);
-    //    case kConstMapLiteral:
-    //      return MapLiteral::ReadFrom(reader_, true);
-    //    case kAwaitExpression:
-    //      return AwaitExpression::ReadFrom(reader_);
-    //    case kFunctionExpression:
-    //      return FunctionExpression::ReadFrom(reader_);
-    //    case kLet:
-    //      return Let::ReadFrom(reader_);
+      return BuildRethrow(position);
+    case kThrow:
+      return BuildThrow(position);
+    case kListLiteral:
+      return BuildListLiteral(false, position);
+    case kConstListLiteral:
+      return BuildListLiteral(true, position);
+    case kMapLiteral:
+      return BuildMapLiteral(false, position);
+    case kConstMapLiteral:
+      return BuildMapLiteral(true, position);
+    case kFunctionExpression:
+      // TODO(jensj)
+      UNIMPLEMENTED();
+      return Fragment();
+    case kLet:
+      return BuildLet(position);
     case kBigIntLiteral:
-      return BuildBigIntLiteral();
+      return BuildBigIntLiteral(position);
     case kStringLiteral:
-      return BuildStringLiteral();
+      return BuildStringLiteral(position);
     case kSpecialIntLiteral:
-      return BuildIntLiteral(payload);
+      return BuildIntLiteral(payload, position);
     case kNegativeIntLiteral:
-      return BuildIntLiteral(true);
+      return BuildIntLiteral(true, position);
     case kPositiveIntLiteral:
-      return BuildIntLiteral(false);
+      return BuildIntLiteral(false, position);
     case kDoubleLiteral:
-      return BuildDoubleLiteral();
+      return BuildDoubleLiteral(position);
     case kTrueLiteral:
-      return BuildBoolLiteral(true);
+      return BuildBoolLiteral(true, position);
     case kFalseLiteral:
-      return BuildBoolLiteral(false);
+      return BuildBoolLiteral(false, position);
     case kNullLiteral:
-      return BuildNullLiteral();
+      return BuildNullLiteral(position);
     default:
       UNREACHABLE();
   }
@@ -309,129 +1234,1287 @@
   return Fragment();
 }
 
+Fragment StreamingFlowGraphBuilder::BuildStatement() {
+  Tag tag = ReadTag();  // read tag.
+  switch (tag) {
+    case kInvalidStatement:
+      return BuildInvalidStatement();
+    case kExpressionStatement:
+      return BuildExpressionStatement();
+    case kBlock:
+      return BuildBlock();
+    case kEmptyStatement:
+      return BuildEmptyStatement();
+    case kAssertStatement:
+      return BuildAssertStatement();
+    case kLabeledStatement:
+      return BuildLabeledStatement();
+    case kBreakStatement:
+      return BuildBreakStatement();
+    case kWhileStatement:
+      return BuildWhileStatement();
+    case kDoStatement:
+      return BuildDoStatement();
+    case kForStatement:
+      return BuildForStatement();
+    case kForInStatement:
+      return BuildForInStatement(false);
+    case kAsyncForInStatement:
+      return BuildForInStatement(true);
+    case kSwitchStatement:
+      return BuildSwitchStatement();
+    case kContinueSwitchStatement:
+      return BuildContinueSwitchStatement();
+    case kIfStatement:
+      return BuildIfStatement();
+    case kReturnStatement:
+      return BuildReturnStatement();
+    case kTryCatch:
+      return BuildTryCatch();
+    case kTryFinally:
+      return BuildTryFinally();
+    case kYieldStatement:
+      return BuildYieldStatement();
+    case kVariableDeclaration:
+      return BuildVariableDeclaration(true);
+    case kFunctionDeclaration:
+      // TODO(jensj)
+      UNIMPLEMENTED();
+      return Fragment();
+    default:
+      UNREACHABLE();
+  }
+  return Fragment();
+}
 
 intptr_t StreamingFlowGraphBuilder::ReaderOffset() {
   return reader_->offset();
 }
 
-
 void StreamingFlowGraphBuilder::SetOffset(intptr_t offset) {
   reader_->set_offset(offset);
 }
 
-
 void StreamingFlowGraphBuilder::SkipBytes(intptr_t bytes) {
   reader_->set_offset(ReaderOffset() + bytes);
 }
 
+bool StreamingFlowGraphBuilder::ReadBool() {
+  return reader_->ReadBool();
+}
+
+uint8_t StreamingFlowGraphBuilder::ReadByte() {
+  return reader_->ReadByte();
+}
 
 uint32_t StreamingFlowGraphBuilder::ReadUInt() {
   return reader_->ReadUInt();
 }
 
+uint32_t StreamingFlowGraphBuilder::PeekUInt() {
+  intptr_t offset = ReaderOffset();
+  uint32_t result = reader_->ReadUInt();
+  SetOffset(offset);
+  return result;
+}
 
 intptr_t StreamingFlowGraphBuilder::ReadListLength() {
   return reader_->ReadListLength();
 }
 
+StringIndex StreamingFlowGraphBuilder::ReadStringReference() {
+  return StringIndex(ReadUInt());
+}
 
 NameIndex StreamingFlowGraphBuilder::ReadCanonicalNameReference() {
   return reader_->ReadCanonicalNameReference();
 }
 
+StringIndex StreamingFlowGraphBuilder::ReadNameAsStringIndex() {
+  StringIndex name_index = ReadStringReference();  // read name index.
+  if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
+    ReadUInt();  // read library index.
+  }
+  return name_index;
+}
+
+const dart::String& StreamingFlowGraphBuilder::ReadNameAsMethodName() {
+  StringIndex name_index = ReadStringReference();  // read name index.
+  if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
+    NameIndex library_reference =
+        ReadCanonicalNameReference();  // read library index.
+    return H.DartMethodName(library_reference, name_index);
+  } else {
+    return H.DartMethodName(NameIndex(NULL), name_index);
+  }
+}
+
+const dart::String& StreamingFlowGraphBuilder::ReadNameAsSetterName() {
+  StringIndex name_index = ReadStringReference();  // read name index.
+  if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
+    NameIndex library_reference =
+        ReadCanonicalNameReference();  // read library index.
+    return H.DartSetterName(library_reference, name_index);
+  } else {
+    return H.DartSetterName(NameIndex(NULL), name_index);
+  }
+}
+
+const dart::String& StreamingFlowGraphBuilder::ReadNameAsGetterName() {
+  StringIndex name_index = ReadStringReference();  // read name index.
+  if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
+    NameIndex library_reference =
+        ReadCanonicalNameReference();  // read library index.
+    return H.DartGetterName(library_reference, name_index);
+  } else {
+    return H.DartGetterName(NameIndex(NULL), name_index);
+  }
+}
+
+void StreamingFlowGraphBuilder::SkipStringReference() {
+  ReadUInt();
+}
+
+void StreamingFlowGraphBuilder::SkipCanonicalNameReference() {
+  ReadUInt();
+}
+
+void StreamingFlowGraphBuilder::SkipDartType() {
+  Tag tag = ReadTag();
+  switch (tag) {
+    case kInvalidType:
+    case kDynamicType:
+    case kVoidType:
+    case kBottomType:
+      // those contain nothing.
+      return;
+    case kInterfaceType:
+      SkipInterfaceType(false);
+      return;
+    case kSimpleInterfaceType:
+      SkipInterfaceType(true);
+      return;
+    case kFunctionType:
+      SkipFunctionType(false);
+      return;
+    case kSimpleFunctionType:
+      SkipFunctionType(true);
+      return;
+    case kTypeParameterType:
+      ReadUInt();              // read index for parameter.
+      ReadUInt();              // read binary offset.
+      SkipOptionalDartType();  // read bound bound.
+      return;
+    default:
+      UNREACHABLE();
+  }
+}
+
+void StreamingFlowGraphBuilder::SkipOptionalDartType() {
+  Tag tag = ReadTag();  // read tag.
+  if (tag == kNothing) {
+    return;
+  }
+  ASSERT(tag == kSomething);
+
+  SkipDartType();  // read type.
+}
+
+void StreamingFlowGraphBuilder::SkipInterfaceType(bool simple) {
+  ReadUInt();  // read klass_name.
+  if (!simple) {
+    intptr_t length = ReadListLength();  // read number of types.
+    for (intptr_t i = 0; i < length; ++i) {
+      SkipDartType();  // skip the ith type.
+    }
+  }
+}
+
+void StreamingFlowGraphBuilder::SkipFunctionType(bool simple) {
+  if (!simple) {
+    intptr_t list_length =
+        ReadListLength();  // read type_parameters list length.
+    for (int i = 0; i < list_length; ++i) {
+      SkipStringReference();  // read string index (name).
+      SkipDartType();         // read dart type.
+    }
+    ReadUInt();  // read required parameter count.
+    ReadUInt();  // read total parameter count.
+  }
+
+  const intptr_t positional_count =
+      ReadListLength();  // read positional_parameters list length.
+  for (intptr_t i = 0; i < positional_count; ++i) {
+    SkipDartType();  // read ith positional parameter.
+  }
+
+  if (!simple) {
+    const intptr_t named_count =
+        ReadListLength();  // read named_parameters list length.
+    for (intptr_t i = 0; i < named_count; ++i) {
+      // read string reference (i.e. named_parameters[i].name).
+      SkipStringReference();
+      SkipDartType();  // read named_parameters[i].type.
+    }
+  }
+
+  SkipDartType();  // read return type.
+}
+
+void StreamingFlowGraphBuilder::SkipExpression() {
+  uint8_t payload = 0;
+  Tag tag = ReadTag(&payload);
+  switch (tag) {
+    case kInvalidExpression:
+      return;
+    case kVariableGet:
+      ReadPosition();          // read position.
+      ReadUInt();              // read kernel position.
+      ReadUInt();              // read relative variable index.
+      SkipOptionalDartType();  // read promoted type.
+      return;
+    case kSpecializedVariableGet:
+      ReadPosition();  // read position.
+      ReadUInt();      // read kernel position.
+      return;
+    case kVariableSet:
+      ReadPosition();    // read position.
+      ReadUInt();        // read kernel position.
+      ReadUInt();        // read relative variable index.
+      SkipExpression();  // read expression.
+      return;
+    case kSpecializedVariableSet:
+      ReadPosition();    // read position.
+      ReadUInt();        // read kernel position.
+      SkipExpression();  // read expression.
+      return;
+    case kPropertyGet:
+      ReadPosition();    // read position.
+      SkipExpression();  // read receiver.
+      SkipName();        // read name.
+      // Read unused "interface_target_reference".
+      SkipCanonicalNameReference();
+      return;
+    case kPropertySet:
+      ReadPosition();    // read position.
+      SkipExpression();  // read receiver.
+      SkipName();        // read name.
+      SkipExpression();  // read value.
+      // read unused "interface_target_reference".
+      SkipCanonicalNameReference();
+      return;
+    case kDirectPropertyGet:
+      ReadPosition();                // read position.
+      SkipExpression();              // read receiver.
+      SkipCanonicalNameReference();  // read target_reference.
+      return;
+    case kDirectPropertySet:
+      ReadPosition();                // read position.
+      SkipExpression();              // read receiver.
+      SkipCanonicalNameReference();  // read target_reference.
+      SkipExpression();              // read value·
+      return;
+    case kStaticGet:
+      ReadPosition();                // read position.
+      SkipCanonicalNameReference();  // read target_reference.
+      return;
+    case kStaticSet:
+      ReadPosition();                // read position.
+      SkipCanonicalNameReference();  // read target_reference.
+      SkipExpression();              // read expression.
+      return;
+    case kMethodInvocation:
+      ReadPosition();    // read position.
+      SkipExpression();  // read receiver.
+      SkipName();        // read name.
+      SkipArguments();   // read arguments.
+      // read unused "interface_target_reference".
+      SkipCanonicalNameReference();
+      return;
+    case kDirectMethodInvocation:
+      SkipExpression();              // read receiver.
+      SkipCanonicalNameReference();  // read target_reference.
+      SkipArguments();               // read arguments.
+      return;
+    case kStaticInvocation:
+    case kConstStaticInvocation:
+      ReadPosition();                // read position.
+      SkipCanonicalNameReference();  // read procedure_reference.
+      SkipArguments();               // read arguments.
+      return;
+    case kConstructorInvocation:
+    case kConstConstructorInvocation:
+      ReadPosition();                // read position.
+      SkipCanonicalNameReference();  // read target_reference.
+      SkipArguments();               // read arguments.
+      return;
+    case kNot:
+      SkipExpression();  // read expression.
+      return;
+    case kLogicalExpression:
+      SkipExpression();  // read left.
+      SkipBytes(1);      // read operator.
+      SkipExpression();  // read right.
+      return;
+    case kConditionalExpression:
+      SkipExpression();        // read condition.
+      SkipExpression();        // read then.
+      SkipExpression();        // read otherwise.
+      SkipOptionalDartType();  // read unused static type.
+      return;
+    case kStringConcatenation: {
+      ReadPosition();                           // read position.
+      intptr_t list_length = ReadListLength();  // read list length.
+      for (intptr_t i = 0; i < list_length; ++i) {
+        SkipExpression();  // read ith expression.
+      }
+      return;
+    }
+    case kIsExpression:
+      ReadPosition();    // read position.
+      SkipExpression();  // read operand.
+      SkipDartType();    // read type.
+      return;
+    case kAsExpression:
+      ReadPosition();    // read position.
+      SkipExpression();  // read operand.
+      SkipDartType();    // read type.
+      return;
+    case kSymbolLiteral:
+      SkipStringReference();  // read index into string table.
+      return;
+    case kTypeLiteral:
+      SkipDartType();  // read type.
+      return;
+    case kThisExpression:
+      return;
+    case kRethrow:
+      ReadPosition();  // read position.
+      return;
+    case kThrow:
+      ReadPosition();    // read position.
+      SkipExpression();  // read expression.
+      return;
+    case kListLiteral:
+    case kConstListLiteral: {
+      ReadPosition();                           // read position.
+      SkipDartType();                           // read type.
+      intptr_t list_length = ReadListLength();  // read list length.
+      for (intptr_t i = 0; i < list_length; ++i) {
+        SkipExpression();  // read ith expression.
+      }
+      return;
+    }
+    case kMapLiteral:
+    case kConstMapLiteral: {
+      ReadPosition();                           // read position.
+      SkipDartType();                           // read key type.
+      SkipDartType();                           // read value type.
+      intptr_t list_length = ReadListLength();  // read list length.
+      for (intptr_t i = 0; i < list_length; ++i) {
+        SkipExpression();  // read ith key.
+        SkipExpression();  // read ith value.
+      }
+      return;
+    }
+    case kFunctionExpression:
+      // TODO(jensj)
+      UNIMPLEMENTED();
+      return;
+    case kLet:
+      SkipVariableDeclaration();  // read variable declaration.
+      SkipExpression();           // read expression.
+      return;
+    case kBigIntLiteral:
+      SkipStringReference();  // read string reference.
+      return;
+    case kStringLiteral:
+      SkipStringReference();  // read string reference.
+      return;
+    case kSpecialIntLiteral:
+      return;
+    case kNegativeIntLiteral:
+      ReadUInt();  // read value.
+      return;
+    case kPositiveIntLiteral:
+      ReadUInt();  // read value.
+      return;
+    case kDoubleLiteral:
+      SkipStringReference();  // read index into string table.
+      return;
+    case kTrueLiteral:
+      return;
+    case kFalseLiteral:
+      return;
+    case kNullLiteral:
+      return;
+    default:
+      UNREACHABLE();
+  }
+}
+
+void StreamingFlowGraphBuilder::SkipStatement() {
+  Tag tag = ReadTag();  // read tag.
+  switch (tag) {
+    case kInvalidStatement:
+      return;
+    case kExpressionStatement:
+      SkipExpression();  // read expression.
+      return;
+    case kBlock: {
+      intptr_t list_length = ReadListLength();  // read number of statements.
+      for (intptr_t i = 0; i < list_length; ++i) {
+        SkipStatement();  // read ith statement.
+      }
+      return;
+    }
+    case kEmptyStatement:
+      return;
+    case kAssertStatement: {
+      SkipExpression();     // Read condition.
+      Tag tag = ReadTag();  // read (first part of) message.
+      if (tag == kSomething) {
+        SkipExpression();  // read (rest of) message.
+      }
+      return;
+    }
+    case kLabeledStatement:
+      SkipStatement();  // read body.
+      return;
+    case kBreakStatement:
+      ReadPosition();  // read position.
+      ReadUInt();      // read target_index.
+      return;
+    case kWhileStatement:
+      SkipExpression();  // read condition.
+      SkipStatement();   // read body.
+      return;
+    case kDoStatement:
+      SkipStatement();   // read body.
+      SkipExpression();  // read condition.
+      return;
+    case kForStatement: {
+      intptr_t list_length = ReadListLength();  // read number of variables.
+      for (intptr_t i = 0; i < list_length; ++i) {
+        SkipVariableDeclaration();  // read ith variable.
+      }
+      Tag tag = ReadTag();  // Read first part of condition.
+      if (tag == kSomething) {
+        SkipExpression();  // read rest of condition.
+      }
+      list_length = ReadListLength();  // read number of updates.
+      for (intptr_t i = 0; i < list_length; ++i) {
+        SkipExpression();  // read ith update.
+      }
+      SkipStatement();  // read body.
+      return;
+    }
+    case kForInStatement:
+    case kAsyncForInStatement:
+      ReadPosition();             // read position.
+      SkipVariableDeclaration();  // read variable.
+      SkipExpression();           // read iterable.
+      SkipStatement();            // read body.
+      return;
+    case kSwitchStatement: {
+      SkipExpression();                  // read condition.
+      int num_cases = ReadListLength();  // read number of cases.
+      for (intptr_t i = 0; i < num_cases; ++i) {
+        int num_expressions = ReadListLength();  // read number of expressions.
+        for (intptr_t j = 0; j < num_expressions; ++j) {
+          ReadPosition();    // read jth position.
+          SkipExpression();  // read jth expression.
+        }
+        ReadBool();       // read is_default.
+        SkipStatement();  // read body.
+      }
+      return;
+    }
+    case kContinueSwitchStatement:
+      ReadUInt();  // read target_index.
+      return;
+    case kIfStatement:
+      SkipExpression();  // read condition.
+      SkipStatement();   // read then.
+      SkipStatement();   // read otherwise.
+      return;
+    case kReturnStatement: {
+      ReadPosition();       // read position
+      Tag tag = ReadTag();  // read (first part of) expression.
+      if (tag == kSomething) {
+        SkipExpression();  // read (rest of) expression.
+      }
+      return;
+    }
+    case kTryCatch: {
+      SkipStatement();  // read body.
+      ReadBool();       // read any_catch_needs_stack_trace.
+      intptr_t num_matches = ReadListLength();  // read number of catches.
+      for (intptr_t i = 0; i < num_matches; ++i) {
+        SkipDartType();   // read guard.
+        tag = ReadTag();  // read first part of exception.
+        if (tag == kSomething) {
+          SkipVariableDeclaration();  // read exception.
+        }
+        tag = ReadTag();  // read first part of stack trace.
+        if (tag == kSomething) {
+          SkipVariableDeclaration();  // read stack trace.
+        }
+        SkipStatement();  // read body.
+      }
+      return;
+    }
+    case kTryFinally:
+      SkipStatement();  // read body.
+      SkipStatement();  // read finalizer.
+      return;
+    case kYieldStatement:
+      ReadPosition();    // read position.
+      ReadByte();        // read flags.
+      SkipExpression();  // read expression.
+      return;
+    case kVariableDeclaration:
+      SkipVariableDeclaration();
+      return;
+    case kFunctionDeclaration:
+      // TODO(jensj)
+      UNIMPLEMENTED();
+      return;
+    default:
+      UNREACHABLE();
+  }
+}
+
+void StreamingFlowGraphBuilder::SkipName() {
+  StringIndex name_index = ReadStringReference();  // read name index.
+  if ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_') {
+    SkipCanonicalNameReference();  // read library index.
+  }
+}
+
+void StreamingFlowGraphBuilder::SkipArguments() {
+  ReadUInt();  // read argument count.
+
+  // List of types.
+  intptr_t list_length = ReadListLength();  // read list length.
+  for (intptr_t i = 0; i < list_length; ++i) {
+    SkipDartType();  // read ith type.
+  }
+
+  // List of positional.
+  list_length = ReadListLength();  // read list length.
+  for (intptr_t i = 0; i < list_length; ++i) {
+    SkipExpression();  // read ith expression.
+  }
+
+  // List of named.
+  list_length = ReadListLength();  // read list length.
+  for (intptr_t i = 0; i < list_length; ++i) {
+    SkipStringReference();  // read ith name index.
+    SkipExpression();       // read ith expression.
+  }
+}
+
+void StreamingFlowGraphBuilder::SkipVariableDeclaration() {
+  ReadPosition();         // read position.
+  ReadPosition();         // read equals position.
+  ReadFlags();            // read flags.
+  SkipStringReference();  // read name index.
+  SkipDartType();         // read type.
+  Tag tag = ReadTag();    // read (first part of) initializer.
+  if (tag == kSomething) {
+    SkipExpression();  // read (actual) initializer.
+  }
+}
 
 TokenPosition StreamingFlowGraphBuilder::ReadPosition(bool record) {
   return reader_->ReadPosition(record);
 }
 
-
 Tag StreamingFlowGraphBuilder::ReadTag(uint8_t* payload) {
   return reader_->ReadTag(payload);
 }
 
+Tag StreamingFlowGraphBuilder::PeekTag(uint8_t* payload) {
+  return reader_->PeekTag(payload);
+}
+
+word StreamingFlowGraphBuilder::ReadFlags() {
+  return reader_->ReadFlags();
+}
+
+void StreamingFlowGraphBuilder::loop_depth_inc() {
+  ++flow_graph_builder_->loop_depth_;
+}
+
+void StreamingFlowGraphBuilder::loop_depth_dec() {
+  --flow_graph_builder_->loop_depth_;
+}
+
+intptr_t StreamingFlowGraphBuilder::for_in_depth() {
+  return flow_graph_builder_->for_in_depth_;
+}
+
+void StreamingFlowGraphBuilder::for_in_depth_inc() {
+  ++flow_graph_builder_->for_in_depth_;
+}
+
+void StreamingFlowGraphBuilder::for_in_depth_dec() {
+  --flow_graph_builder_->for_in_depth_;
+}
+
+void StreamingFlowGraphBuilder::catch_depth_inc() {
+  ++flow_graph_builder_->catch_depth_;
+}
+
+void StreamingFlowGraphBuilder::catch_depth_dec() {
+  --flow_graph_builder_->catch_depth_;
+}
+
+void StreamingFlowGraphBuilder::try_depth_inc() {
+  ++flow_graph_builder_->try_depth_;
+}
+
+void StreamingFlowGraphBuilder::try_depth_dec() {
+  --flow_graph_builder_->try_depth_;
+}
+
+intptr_t StreamingFlowGraphBuilder::CurrentTryIndex() {
+  return flow_graph_builder_->CurrentTryIndex();
+}
+
+intptr_t StreamingFlowGraphBuilder::AllocateTryIndex() {
+  return flow_graph_builder_->AllocateTryIndex();
+}
+
+LocalVariable* StreamingFlowGraphBuilder::CurrentException() {
+  return flow_graph_builder_->CurrentException();
+}
+
+LocalVariable* StreamingFlowGraphBuilder::CurrentStackTrace() {
+  return flow_graph_builder_->CurrentStackTrace();
+}
 
 CatchBlock* StreamingFlowGraphBuilder::catch_block() {
   return flow_graph_builder_->catch_block_;
 }
 
+ActiveClass* StreamingFlowGraphBuilder::active_class() {
+  return &flow_graph_builder_->active_class_;
+}
 
 ScopeBuildingResult* StreamingFlowGraphBuilder::scopes() {
   return flow_graph_builder_->scopes_;
 }
 
-
 ParsedFunction* StreamingFlowGraphBuilder::parsed_function() {
   return flow_graph_builder_->parsed_function_;
 }
 
+TryFinallyBlock* StreamingFlowGraphBuilder::try_finally_block() {
+  return flow_graph_builder_->try_finally_block_;
+}
+
+SwitchBlock* StreamingFlowGraphBuilder::switch_block() {
+  return flow_graph_builder_->switch_block_;
+}
+
+BreakableBlock* StreamingFlowGraphBuilder::breakable_block() {
+  return flow_graph_builder_->breakable_block_;
+}
+
+GrowableArray<YieldContinuation>&
+StreamingFlowGraphBuilder::yield_continuations() {
+  return flow_graph_builder_->yield_continuations_;
+}
+
+Value* StreamingFlowGraphBuilder::stack() {
+  return flow_graph_builder_->stack_;
+}
+
+Value* StreamingFlowGraphBuilder::Pop() {
+  return flow_graph_builder_->Pop();
+}
+
+Tag StreamingFlowGraphBuilder::PeekArgumentsFirstPositionalTag() {
+  // read parts of arguments, then go back to before doing so.
+  intptr_t offset = ReaderOffset();
+  ReadUInt();  // read number of arguments.
+
+  // List of types.
+  intptr_t list_length = ReadListLength();  // read list length.
+  for (intptr_t i = 0; i < list_length; ++i) {
+    SkipDartType();  // read ith type.
+  }
+
+  // List of positional.
+  list_length = ReadListLength();  // read list length.
+  for (intptr_t i = 0; i < list_length; ++i) {
+    Tag tag = ReadTag();  // read first tag.
+    SetOffset(offset);    // reset offset.
+    return tag;
+  }
+
+  UNREACHABLE();
+  return kNothing;
+}
+
+const TypeArguments& StreamingFlowGraphBuilder::PeekArgumentsInstantiatedType(
+    const dart::Class& klass) {
+  // read parts of arguments, then go back to before doing so.
+  intptr_t offset = ReaderOffset();
+  ReadUInt();                               // read argument count.
+  intptr_t list_length = ReadListLength();  // read types list length.
+  const TypeArguments& type_arguments =
+      T.BuildInstantiatedTypeArguments(klass, list_length);  // read types.
+  SetOffset(offset);
+  return type_arguments;
+}
+
+intptr_t StreamingFlowGraphBuilder::PeekArgumentsCount() {
+  return PeekUInt();
+}
+
+intptr_t StreamingFlowGraphBuilder::PeekArgumentsTypeCount() {
+  intptr_t offset = ReaderOffset();
+  ReadUInt();                               // read arguments count.
+  intptr_t types_count = ReadListLength();  // read length of types list.
+  SetOffset(offset);
+  return types_count;
+}
+
+void StreamingFlowGraphBuilder::SkipArgumentsBeforeActualArguments() {
+  ReadUInt();  // read arguments count.
+  intptr_t types_count = ReadListLength();
+  for (intptr_t i = 0; i < types_count; ++i) {
+    SkipDartType();  // read ith type.
+  }
+}
+
+LocalVariable* StreamingFlowGraphBuilder::LookupVariable(
+    intptr_t kernel_offset) {
+  return flow_graph_builder_->LookupVariable(kernel_offset);
+}
+
+LocalVariable* StreamingFlowGraphBuilder::MakeTemporary() {
+  return flow_graph_builder_->MakeTemporary();
+}
+
+Token::Kind StreamingFlowGraphBuilder::MethodKind(const dart::String& name) {
+  return flow_graph_builder_->MethodKind(name);
+}
+
+dart::RawFunction* StreamingFlowGraphBuilder::LookupMethodByMember(
+    NameIndex target,
+    const dart::String& method_name) {
+  return flow_graph_builder_->LookupMethodByMember(target, method_name);
+}
+
+bool StreamingFlowGraphBuilder::NeedsDebugStepCheck(const Function& function,
+                                                    TokenPosition position) {
+  return flow_graph_builder_->NeedsDebugStepCheck(function, position);
+}
+
+bool StreamingFlowGraphBuilder::NeedsDebugStepCheck(Value* value,
+                                                    TokenPosition position) {
+  return flow_graph_builder_->NeedsDebugStepCheck(value, position);
+}
+
+void StreamingFlowGraphBuilder::InlineBailout(const char* reason) {
+  flow_graph_builder_->InlineBailout(reason);
+}
 
 Fragment StreamingFlowGraphBuilder::DebugStepCheck(TokenPosition position) {
   return flow_graph_builder_->DebugStepCheck(position);
 }
 
-
 Fragment StreamingFlowGraphBuilder::LoadLocal(LocalVariable* variable) {
   return flow_graph_builder_->LoadLocal(variable);
 }
 
+Fragment StreamingFlowGraphBuilder::Return(TokenPosition position) {
+  return flow_graph_builder_->Return(position);
+}
 
 Fragment StreamingFlowGraphBuilder::PushArgument() {
   return flow_graph_builder_->PushArgument();
 }
 
+Fragment StreamingFlowGraphBuilder::EvaluateAssertion() {
+  return flow_graph_builder_->EvaluateAssertion();
+}
 
 Fragment StreamingFlowGraphBuilder::RethrowException(TokenPosition position,
                                                      int catch_try_index) {
   return flow_graph_builder_->RethrowException(position, catch_try_index);
 }
 
-
 Fragment StreamingFlowGraphBuilder::ThrowNoSuchMethodError() {
   return flow_graph_builder_->ThrowNoSuchMethodError();
 }
 
-
 Fragment StreamingFlowGraphBuilder::Constant(const Object& value) {
   return flow_graph_builder_->Constant(value);
 }
 
-
 Fragment StreamingFlowGraphBuilder::IntConstant(int64_t value) {
   return flow_graph_builder_->IntConstant(value);
 }
 
-
 Fragment StreamingFlowGraphBuilder::LoadStaticField() {
   return flow_graph_builder_->LoadStaticField();
 }
 
-
 Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position,
                                                const Function& target,
                                                intptr_t argument_count) {
   return flow_graph_builder_->StaticCall(position, target, argument_count);
 }
 
+Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position,
+                                               const Function& target,
+                                               intptr_t argument_count,
+                                               const Array& argument_names) {
+  return flow_graph_builder_->StaticCall(position, target, argument_count,
+                                         argument_names);
+}
 
-Fragment StreamingFlowGraphBuilder::BuildInvalidExpression() {
+Fragment StreamingFlowGraphBuilder::InstanceCall(TokenPosition position,
+                                                 const dart::String& name,
+                                                 Token::Kind kind,
+                                                 intptr_t argument_count,
+                                                 intptr_t num_args_checked) {
+  return flow_graph_builder_->InstanceCall(position, name, kind, argument_count,
+                                           num_args_checked);
+}
+
+Fragment StreamingFlowGraphBuilder::ThrowException(TokenPosition position) {
+  return flow_graph_builder_->ThrowException(position);
+}
+
+Fragment StreamingFlowGraphBuilder::BooleanNegate() {
+  return flow_graph_builder_->BooleanNegate();
+}
+
+Fragment StreamingFlowGraphBuilder::TranslateInstantiatedTypeArguments(
+    const TypeArguments& type_arguments) {
+  return flow_graph_builder_->TranslateInstantiatedTypeArguments(
+      type_arguments);
+}
+
+Fragment StreamingFlowGraphBuilder::StrictCompare(Token::Kind kind,
+                                                  bool number_check) {
+  return flow_graph_builder_->StrictCompare(kind, number_check);
+}
+
+Fragment StreamingFlowGraphBuilder::AllocateObject(const dart::Class& klass,
+                                                   intptr_t argument_count) {
+  return flow_graph_builder_->AllocateObject(klass, argument_count);
+}
+
+Fragment StreamingFlowGraphBuilder::InstanceCall(TokenPosition position,
+                                                 const dart::String& name,
+                                                 Token::Kind kind,
+                                                 intptr_t argument_count,
+                                                 const Array& argument_names,
+                                                 intptr_t num_args_checked) {
+  return flow_graph_builder_->InstanceCall(position, name, kind, argument_count,
+                                           argument_names, num_args_checked);
+}
+
+Fragment StreamingFlowGraphBuilder::StoreLocal(TokenPosition position,
+                                               LocalVariable* variable) {
+  return flow_graph_builder_->StoreLocal(position, variable);
+}
+
+Fragment StreamingFlowGraphBuilder::StoreStaticField(TokenPosition position,
+                                                     const dart::Field& field) {
+  return flow_graph_builder_->StoreStaticField(position, field);
+}
+
+Fragment StreamingFlowGraphBuilder::StringInterpolate(TokenPosition position) {
+  return flow_graph_builder_->StringInterpolate(position);
+}
+
+Fragment StreamingFlowGraphBuilder::StringInterpolateSingle(
+    TokenPosition position) {
+  return flow_graph_builder_->StringInterpolateSingle(position);
+}
+
+Fragment StreamingFlowGraphBuilder::ThrowTypeError() {
+  return flow_graph_builder_->ThrowTypeError();
+}
+
+Fragment StreamingFlowGraphBuilder::LoadInstantiatorTypeArguments() {
+  return flow_graph_builder_->LoadInstantiatorTypeArguments();
+}
+
+Fragment StreamingFlowGraphBuilder::LoadFunctionTypeArguments() {
+  return flow_graph_builder_->LoadFunctionTypeArguments();
+}
+
+Fragment StreamingFlowGraphBuilder::InstantiateType(const AbstractType& type) {
+  return flow_graph_builder_->InstantiateType(type);
+}
+
+Fragment StreamingFlowGraphBuilder::CreateArray() {
+  return flow_graph_builder_->CreateArray();
+}
+
+Fragment StreamingFlowGraphBuilder::StoreIndexed(intptr_t class_id) {
+  return flow_graph_builder_->StoreIndexed(class_id);
+}
+
+Fragment StreamingFlowGraphBuilder::CheckStackOverflow() {
+  return flow_graph_builder_->CheckStackOverflow();
+}
+
+Fragment StreamingFlowGraphBuilder::CloneContext() {
+  return flow_graph_builder_->CloneContext();
+}
+
+Fragment StreamingFlowGraphBuilder::TranslateFinallyFinalizers(
+    TryFinallyBlock* outer_finally,
+    intptr_t target_context_depth) {
+  // TranslateFinallyFinalizers can move the readers offset.
+  // Save the current position and restore it afterwards.
+  intptr_t offset = ReaderOffset();
+  Fragment result = flow_graph_builder_->TranslateFinallyFinalizers(
+      outer_finally, target_context_depth);
+  SetOffset(offset);
+  return result;
+}
+
+Fragment StreamingFlowGraphBuilder::BranchIfTrue(
+    TargetEntryInstr** then_entry,
+    TargetEntryInstr** otherwise_entry,
+    bool negate) {
+  return flow_graph_builder_->BranchIfTrue(then_entry, otherwise_entry, negate);
+}
+
+Fragment StreamingFlowGraphBuilder::BranchIfEqual(
+    TargetEntryInstr** then_entry,
+    TargetEntryInstr** otherwise_entry,
+    bool negate) {
+  return flow_graph_builder_->BranchIfEqual(then_entry, otherwise_entry,
+                                            negate);
+}
+
+Fragment StreamingFlowGraphBuilder::BranchIfNull(
+    TargetEntryInstr** then_entry,
+    TargetEntryInstr** otherwise_entry,
+    bool negate) {
+  return flow_graph_builder_->BranchIfNull(then_entry, otherwise_entry, negate);
+}
+
+Fragment StreamingFlowGraphBuilder::CatchBlockEntry(const Array& handler_types,
+                                                    intptr_t handler_index,
+                                                    bool needs_stacktrace) {
+  return flow_graph_builder_->CatchBlockEntry(handler_types, handler_index,
+                                              needs_stacktrace);
+}
+
+Fragment StreamingFlowGraphBuilder::TryCatch(int try_handler_index) {
+  return flow_graph_builder_->TryCatch(try_handler_index);
+}
+
+Fragment StreamingFlowGraphBuilder::Drop() {
+  return flow_graph_builder_->Drop();
+}
+
+Fragment StreamingFlowGraphBuilder::NullConstant() {
+  return flow_graph_builder_->NullConstant();
+}
+
+JoinEntryInstr* StreamingFlowGraphBuilder::BuildJoinEntry() {
+  return flow_graph_builder_->BuildJoinEntry();
+}
+
+JoinEntryInstr* StreamingFlowGraphBuilder::BuildJoinEntry(intptr_t try_index) {
+  return flow_graph_builder_->BuildJoinEntry(try_index);
+}
+
+Fragment StreamingFlowGraphBuilder::Goto(JoinEntryInstr* destination) {
+  return flow_graph_builder_->Goto(destination);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildImplicitClosureCreation(
+    const Function& target) {
+  return flow_graph_builder_->BuildImplicitClosureCreation(target);
+}
+
+Fragment StreamingFlowGraphBuilder::CheckBooleanInCheckedMode() {
+  return flow_graph_builder_->CheckBooleanInCheckedMode();
+}
+
+Fragment StreamingFlowGraphBuilder::CheckAssignableInCheckedMode(
+    const dart::AbstractType& dst_type,
+    const dart::String& dst_name) {
+  return flow_graph_builder_->CheckAssignableInCheckedMode(dst_type, dst_name);
+}
+
+Fragment StreamingFlowGraphBuilder::CheckVariableTypeInCheckedMode(
+    intptr_t variable_kernel_position) {
+  if (I->type_checks()) {
+    LocalVariable* variable = LookupVariable(variable_kernel_position);
+    return flow_graph_builder_->CheckVariableTypeInCheckedMode(
+        variable->type(), variable->name());
+  }
+  return Fragment();
+}
+
+Fragment StreamingFlowGraphBuilder::CheckVariableTypeInCheckedMode(
+    const AbstractType& dst_type,
+    const dart::String& name_symbol) {
+  return flow_graph_builder_->CheckVariableTypeInCheckedMode(dst_type,
+                                                             name_symbol);
+}
+
+Fragment StreamingFlowGraphBuilder::EnterScope(intptr_t kernel_offset,
+                                               bool* new_context) {
+  return flow_graph_builder_->EnterScope(kernel_offset, new_context);
+}
+
+Fragment StreamingFlowGraphBuilder::ExitScope(intptr_t kernel_offset) {
+  return flow_graph_builder_->ExitScope(kernel_offset);
+}
+
+Fragment StreamingFlowGraphBuilder::TranslateCondition(bool* negate) {
+  *negate = PeekTag() == kNot;
+  if (*negate) {
+    SkipBytes(1);  // Skip Not tag, thus go directly to the inner expression.
+  }
+  Fragment instructions = BuildExpression();  // read expression.
+  instructions += CheckBooleanInCheckedMode();
+  return instructions;
+}
+
+const TypeArguments& StreamingFlowGraphBuilder::BuildTypeArguments() {
+  ReadUInt();                                // read arguments count.
+  intptr_t types_count = ReadListLength();   // read type count.
+  return T.BuildTypeArguments(types_count);  // read types.
+}
+
+Fragment StreamingFlowGraphBuilder::BuildArguments(Array* argument_names,
+                                                   intptr_t* argument_count,
+                                                   bool skip_push_arguments,
+                                                   bool do_drop) {
+  intptr_t dummy;
+  if (argument_count == NULL) argument_count = &dummy;
+  *argument_count = ReadUInt();  // read arguments count.
+
+  // List of types.
+  intptr_t list_length = ReadListLength();  // read type count.
+  for (intptr_t i = 0; i < list_length; ++i) {
+    SkipDartType();  // read ith type.
+  }
+
+  return BuildArgumentsFromActualArguments(argument_names, skip_push_arguments,
+                                           do_drop);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildArgumentsFromActualArguments(
+    Array* argument_names,
+    bool skip_push_arguments,
+    bool do_drop) {
+  Fragment instructions;
+
+  // List of positional.
+  intptr_t list_length = ReadListLength();  // read list length.
+  for (intptr_t i = 0; i < list_length; ++i) {
+    instructions += BuildExpression();  // read ith expression.
+    if (!skip_push_arguments) instructions += PushArgument();
+    if (do_drop) instructions += Drop();
+  }
+
+  // List of named.
+  list_length = ReadListLength();  // read list length.
+  if (argument_names != NULL && list_length > 0) {
+    *argument_names ^= Array::New(list_length, Heap::kOld);
+  }
+  for (intptr_t i = 0; i < list_length; ++i) {
+    dart::String& name =
+        H.DartSymbol(ReadStringReference());  // read ith name index.
+    instructions += BuildExpression();        // read ith expression.
+    if (!skip_push_arguments) instructions += PushArgument();
+    if (do_drop) instructions += Drop();
+    if (argument_names != NULL) {
+      argument_names->SetAt(i, name);
+    }
+  }
+
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildInvalidExpression(
+    TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
+
   // The frontend will take care of emitting normal errors (like
   // [NoSuchMethodError]s) and only emit [InvalidExpression]s in very special
   // situations (e.g. an invalid annotation).
   return ThrowNoSuchMethodError();
 }
 
+Fragment StreamingFlowGraphBuilder::BuildVariableGet(TokenPosition* position) {
+  (position != NULL) ? * position = ReadPosition()
+                     : ReadPosition();             // read position.
+  intptr_t variable_kernel_position = ReadUInt();  // read kernel position.
+  ReadUInt();              // read relative variable index.
+  SkipOptionalDartType();  // read promoted type.
 
-Fragment StreamingFlowGraphBuilder::BuildStaticGet() {
-  intptr_t saved_offset = ReaderOffset() - 1;  // Include the tag.
-  TokenPosition position = ReadPosition();
-  NameIndex target = ReadCanonicalNameReference();
+  return LoadLocal(LookupVariable(variable_kernel_position));
+}
+
+Fragment StreamingFlowGraphBuilder::BuildVariableGet(uint8_t payload,
+                                                     TokenPosition* position) {
+  (position != NULL) ? * position = ReadPosition()
+                     : ReadPosition();             // read position.
+  intptr_t variable_kernel_position = ReadUInt();  // read kernel position.
+  return LoadLocal(LookupVariable(variable_kernel_position));
+}
+
+Fragment StreamingFlowGraphBuilder::BuildVariableSet(TokenPosition* p) {
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  intptr_t variable_kernel_position = ReadUInt();  // read kernel position.
+  ReadUInt();                                 // read relative variable index.
+  Fragment instructions = BuildExpression();  // read expression.
+
+  if (NeedsDebugStepCheck(stack(), position)) {
+    instructions = DebugStepCheck(position) + instructions;
+  }
+  instructions += CheckVariableTypeInCheckedMode(variable_kernel_position);
+  instructions +=
+      StoreLocal(position, LookupVariable(variable_kernel_position));
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildVariableSet(uint8_t payload,
+                                                     TokenPosition* p) {
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  intptr_t variable_kernel_position = ReadUInt();  // read kernel position.
+  Fragment instructions = BuildExpression();       // read expression.
+
+  if (NeedsDebugStepCheck(stack(), position)) {
+    instructions = DebugStepCheck(position) + instructions;
+  }
+  instructions += CheckVariableTypeInCheckedMode(variable_kernel_position);
+  instructions +=
+      StoreLocal(position, LookupVariable(variable_kernel_position));
+
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildPropertyGet(TokenPosition* p) {
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  Fragment instructions = BuildExpression();  // read receiver.
+  instructions += PushArgument();
+
+  const dart::String& getter_name = ReadNameAsGetterName();  // read name.
+  SkipCanonicalNameReference();  // Read unused "interface_target_reference".
+
+  return instructions + InstanceCall(position, getter_name, Token::kGET, 1);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildPropertySet(TokenPosition* p) {
+  Fragment instructions(NullConstant());
+  LocalVariable* variable = MakeTemporary();
+
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  instructions += BuildExpression();  // read receiver.
+  instructions += PushArgument();
+
+  const dart::String& setter_name = ReadNameAsSetterName();  // read name.
+
+  instructions += BuildExpression();  // read value.
+  instructions += StoreLocal(TokenPosition::kNoSource, variable);
+  instructions += PushArgument();
+
+  SkipCanonicalNameReference();  // read unused "interface_target_reference".
+
+  instructions += InstanceCall(position, setter_name, Token::kSET, 2);
+  return instructions + Drop();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildDirectPropertyGet(TokenPosition* p) {
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  Fragment instructions = BuildExpression();  // read receiver.
+  NameIndex kernel_name =
+      ReadCanonicalNameReference();  // read target_reference.
+
+  Function& target = Function::ZoneHandle(Z);
+  if (H.IsProcedure(kernel_name)) {
+    if (H.IsGetter(kernel_name)) {
+      target = LookupMethodByMember(kernel_name, H.DartGetterName(kernel_name));
+    } else {
+      // Undo stack change for the BuildExpression.
+      Pop();
+
+      target = LookupMethodByMember(kernel_name, H.DartMethodName(kernel_name));
+      target = target.ImplicitClosureFunction();
+      ASSERT(!target.IsNull());
+      return BuildImplicitClosureCreation(target);
+    }
+  } else {
+    ASSERT(H.IsField(kernel_name));
+    const dart::String& getter_name = H.DartGetterName(kernel_name);
+    target = LookupMethodByMember(kernel_name, getter_name);
+    ASSERT(target.IsGetterFunction() || target.IsImplicitGetterFunction());
+  }
+
+  instructions += PushArgument();
+  return instructions + StaticCall(position, target, 1);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildDirectPropertySet(TokenPosition* p) {
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  Fragment instructions(NullConstant());
+  LocalVariable* value = MakeTemporary();
+
+  instructions += BuildExpression();  // read receiver.
+  instructions += PushArgument();
+
+  NameIndex target_reference =
+      ReadCanonicalNameReference();  // read target_reference.
+  const dart::String& method_name = H.DartSetterName(target_reference);
+  const Function& target = Function::ZoneHandle(
+      Z, LookupMethodByMember(target_reference, method_name));
+  ASSERT(target.IsSetterFunction() || target.IsImplicitSetterFunction());
+
+  instructions += BuildExpression();  // read value.
+  instructions += StoreLocal(TokenPosition::kNoSource, value);
+  instructions += PushArgument();
+
+  instructions += StaticCall(position, target, 2);
+
+  return instructions + Drop();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildStaticGet(TokenPosition* p) {
+  intptr_t offset = ReaderOffset() - 1;  // Include the tag.
+
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  NameIndex target = ReadCanonicalNameReference();  // read target_reference.
 
   if (H.IsField(target)) {
     const dart::Field& field =
         dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(target));
     if (field.is_const()) {
-      SetOffset(saved_offset);  // EvaluateExpression needs the tag.
-      return Constant(constant_evaluator_.EvaluateExpression());
+      return Constant(constant_evaluator_.EvaluateExpression(offset));
     } else {
       const dart::Class& owner = dart::Class::Handle(Z, field.Owner());
       const dart::String& getter_name = H.DartGetterName(target);
@@ -451,8 +2534,7 @@
     if (H.IsGetter(target)) {
       return StaticCall(position, function, 0);
     } else if (H.IsMethod(target)) {
-      SetOffset(saved_offset);  // EvaluateExpression needs the tag.
-      return Constant(constant_evaluator_.EvaluateExpression());
+      return Constant(constant_evaluator_.EvaluateExpression(offset));
     } else {
       UNIMPLEMENTED();
     }
@@ -461,20 +2543,632 @@
   return Fragment();
 }
 
+Fragment StreamingFlowGraphBuilder::BuildStaticSet(TokenPosition* p) {
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
 
-Fragment StreamingFlowGraphBuilder::BuildSymbolLiteral() {
-  SkipBytes(-1);  // EvaluateExpression needs the tag.
-  return Constant(constant_evaluator_.EvaluateExpression());
+  NameIndex target = ReadCanonicalNameReference();  // read target_reference.
+
+  if (H.IsField(target)) {
+    const dart::Field& field =
+        dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(target));
+    const AbstractType& dst_type = AbstractType::ZoneHandle(Z, field.type());
+    Fragment instructions = BuildExpression();  // read expression.
+    if (NeedsDebugStepCheck(stack(), position)) {
+      instructions = DebugStepCheck(position) + instructions;
+    }
+    instructions += CheckAssignableInCheckedMode(
+        dst_type, dart::String::ZoneHandle(Z, field.name()));
+    LocalVariable* variable = MakeTemporary();
+    instructions += LoadLocal(variable);
+    return instructions + StoreStaticField(position, field);
+  } else {
+    ASSERT(H.IsProcedure(target));
+
+    // Evaluate the expression on the right hand side.
+    Fragment instructions = BuildExpression();  // read expression.
+    LocalVariable* variable = MakeTemporary();
+
+    // Prepare argument.
+    instructions += LoadLocal(variable);
+    instructions += PushArgument();
+
+    // Invoke the setter function.
+    const Function& function =
+        Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target));
+    instructions += StaticCall(position, function, 1);
+
+    // Drop the unused result & leave the stored value on the stack.
+    return instructions + Drop();
+  }
 }
 
+static bool IsNumberLiteral(Tag tag) {
+  return tag == kNegativeIntLiteral || tag == kPositiveIntLiteral ||
+         tag == kSpecialIntLiteral || tag == kDoubleLiteral;
+}
 
-Fragment StreamingFlowGraphBuilder::BuildThisExpression() {
+Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p) {
+  intptr_t offset = ReaderOffset() - 1;     // Include the tag.
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  Tag receiver_tag = PeekTag();  // peek tag for receiver.
+  if (IsNumberLiteral(receiver_tag)) {
+    intptr_t before_branch_offset = ReaderOffset();
+
+    SkipExpression();  // read receiver (it's just a number literal).
+
+    const dart::String& name = ReadNameAsMethodName();  // read name.
+    const Token::Kind token_kind = MethodKind(name);
+    intptr_t argument_count = PeekArgumentsCount() + 1;
+
+    if ((argument_count == 1) && (token_kind == Token::kNEGATE)) {
+      const Object& result = constant_evaluator_.EvaluateExpressionSafe(offset);
+      if (!result.IsError()) {
+        SkipArguments();  // read arguments,
+        // read unused "interface_target_reference".
+        SkipCanonicalNameReference();
+        return Constant(result);
+      }
+    } else if ((argument_count == 2) &&
+               Token::IsBinaryArithmeticOperator(token_kind) &&
+               IsNumberLiteral(PeekArgumentsFirstPositionalTag())) {
+      const Object& result = constant_evaluator_.EvaluateExpressionSafe(offset);
+      if (!result.IsError()) {
+        SkipArguments();
+        // read unused "interface_target_reference".
+        SkipCanonicalNameReference();
+        return Constant(result);
+      }
+    }
+
+    SetOffset(before_branch_offset);
+  }
+
+  Fragment instructions = BuildExpression();  // read receiver.
+
+  const dart::String& name = ReadNameAsMethodName();  // read name.
+  const Token::Kind token_kind = MethodKind(name);
+
+  // Detect comparison with null.
+  if ((token_kind == Token::kEQ || token_kind == Token::kNE) &&
+      PeekArgumentsCount() == 1 &&
+      (receiver_tag == kNullLiteral ||
+       PeekArgumentsFirstPositionalTag() == kNullLiteral)) {
+    // "==" or "!=" with null on either side.
+    instructions += BuildArguments(NULL, NULL, true);  // read arguments.
+    SkipCanonicalNameReference();  // read unused "interface_target_reference".
+    Token::Kind strict_cmp_kind =
+        token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT;
+    return instructions +
+           StrictCompare(strict_cmp_kind, /*number_check = */ true);
+  }
+
+  instructions += PushArgument();  // push receiver as argument.
+
+  // TODO(28109) Support generic methods in the VM or reify them away.
+  Array& argument_names = Array::ZoneHandle(Z);
+  intptr_t argument_count;
+  instructions +=
+      BuildArguments(&argument_names, &argument_count);  // read arguments.
+  ++argument_count;
+
+  intptr_t num_args_checked = 1;
+  // If we have a special operation (e.g. +/-/==) we mark both arguments as
+  // to be checked.
+  if (token_kind != Token::kILLEGAL) {
+    ASSERT(argument_count <= 2);
+    num_args_checked = argument_count;
+  }
+
+  instructions += InstanceCall(position, name, token_kind, argument_count,
+                               argument_names, num_args_checked);
+  // Later optimization passes assume that result of a x.[]=(...) call is not
+  // used. We must guarantee this invariant because violation will lead to an
+  // illegal IL once we replace x.[]=(...) with a sequence that does not
+  // actually produce any value. See http://dartbug.com/29135 for more details.
+  if (name.raw() == Symbols::AssignIndexToken().raw()) {
+    instructions += Drop();
+    instructions += NullConstant();
+  }
+
+  SkipCanonicalNameReference();  // read unused "interface_target_reference".
+
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildDirectMethodInvocation(
+    TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
+
+  // TODO(28109) Support generic methods in the VM or reify them away.
+  Tag receiver_tag = PeekTag();               // peek tag for receiver.
+  Fragment instructions = BuildExpression();  // read receiver.
+
+  NameIndex kernel_name =
+      ReadCanonicalNameReference();  // read target_reference.
+  const dart::String& method_name = H.DartProcedureName(kernel_name);
+  const Token::Kind token_kind = MethodKind(method_name);
+
+  // Detect comparison with null.
+  if ((token_kind == Token::kEQ || token_kind == Token::kNE) &&
+      PeekArgumentsCount() == 1 &&
+      (receiver_tag == kNullLiteral ||
+       PeekArgumentsFirstPositionalTag() == kNullLiteral)) {
+    // "==" or "!=" with null on either side.
+    instructions += BuildArguments(NULL, NULL, true);  // read arguments.
+    Token::Kind strict_cmp_kind =
+        token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT;
+    return instructions +
+           StrictCompare(strict_cmp_kind, /*number_check = */ true);
+  }
+
+  instructions += PushArgument();  // push receiver as argument.
+
+  const Function& target =
+      Function::ZoneHandle(Z, LookupMethodByMember(kernel_name, method_name));
+
+  Array& argument_names = Array::ZoneHandle(Z);
+  intptr_t argument_count;
+  instructions +=
+      BuildArguments(&argument_names, &argument_count);  // read arguments.
+  ++argument_count;
+  return instructions + StaticCall(TokenPosition::kNoSource, target,
+                                   argument_count, argument_names);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(bool is_const,
+                                                          TokenPosition* p) {
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  NameIndex procedue_reference =
+      ReadCanonicalNameReference();  // read procedure reference.
+  intptr_t argument_count = PeekArgumentsCount();
+  const Function& target = Function::ZoneHandle(
+      Z, H.LookupStaticMethodByKernelProcedure(procedue_reference));
+  const dart::Class& klass = dart::Class::ZoneHandle(Z, target.Owner());
+  if (target.IsGenerativeConstructor() || target.IsFactory()) {
+    // The VM requires a TypeArguments object as first parameter for
+    // every factory constructor.
+    ++argument_count;
+  }
+
+  Fragment instructions;
+  LocalVariable* instance_variable = NULL;
+
+  // If we cross the Kernel -> VM core library boundary, a [StaticInvocation]
+  // can appear, but the thing we're calling is not a static method, but a
+  // factory constructor.
+  // The `H.LookupStaticmethodByKernelProcedure` will potentially resolve to the
+  // forwarded constructor.
+  // In that case we'll make an instance and pass it as first argument.
+  //
+  // TODO(27590): Get rid of this after we're using core libraries compiled
+  // into Kernel.
+  if (target.IsGenerativeConstructor()) {
+    if (klass.NumTypeArguments() > 0) {
+      const TypeArguments& type_arguments =
+          PeekArgumentsInstantiatedType(klass);
+      instructions += TranslateInstantiatedTypeArguments(type_arguments);
+      instructions += PushArgument();
+      instructions += AllocateObject(klass, 1);
+    } else {
+      instructions += AllocateObject(klass, 0);
+    }
+
+    instance_variable = MakeTemporary();
+
+    instructions += LoadLocal(instance_variable);
+    instructions += PushArgument();
+  } else if (target.IsFactory()) {
+    // The VM requires currently a TypeArguments object as first parameter for
+    // every factory constructor :-/ !
+    //
+    // TODO(27590): Get rid of this after we're using core libraries compiled
+    // into Kernel.
+    const TypeArguments& type_arguments = PeekArgumentsInstantiatedType(klass);
+    instructions += TranslateInstantiatedTypeArguments(type_arguments);
+    instructions += PushArgument();
+  } else {
+    // TODO(28109) Support generic methods in the VM or reify them away.
+  }
+
+  bool special_case_identical =
+      klass.IsTopLevel() && (klass.library() == dart::Library::CoreLibrary()) &&
+      (target.name() == Symbols::Identical().raw());
+
+  Array& argument_names = Array::ZoneHandle(Z);
+  instructions += BuildArguments(&argument_names, NULL,
+                                 special_case_identical);  // read arguments.
+  ASSERT(target.AreValidArguments(argument_count, argument_names, NULL));
+
+  // Special case identical(x, y) call.
+  // TODO(27590) consider moving this into the inliner and force inline it
+  // there.
+  if (special_case_identical) {
+    ASSERT(argument_count == 2);
+    instructions += StrictCompare(Token::kEQ_STRICT, /*number_check=*/true);
+  } else {
+    instructions +=
+        StaticCall(position, target, argument_count, argument_names);
+    if (target.IsGenerativeConstructor()) {
+      // Drop the result of the constructor call and leave [instance_variable]
+      // on top-of-stack.
+      instructions += Drop();
+    }
+  }
+
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildConstructorInvocation(
+    bool is_const,
+    TokenPosition* p) {
+  if (is_const) {
+    intptr_t offset = ReaderOffset() - 1;                 // Include the tag.
+    (p != NULL) ? * p = ReadPosition() : ReadPosition();  // read position.
+
+    SetOffset(offset);
+    SkipExpression();  // read past this ConstructorInvocation.
+    return Constant(constant_evaluator_.EvaluateConstructorInvocation(offset));
+  }
+
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  NameIndex kernel_name =
+      ReadCanonicalNameReference();  // read target_reference.
+
+  dart::Class& klass = dart::Class::ZoneHandle(
+      Z, H.LookupClassByKernelClass(H.EnclosingName(kernel_name)));
+
+  Fragment instructions;
+
+  // Check for malbounded-ness of type.
+  if (I->type_checks()) {
+    intptr_t offset = ReaderOffset();
+
+    const TypeArguments& type_arguments = BuildTypeArguments();
+
+    AbstractType& type = AbstractType::Handle(
+        Z, Type::New(klass, type_arguments, TokenPosition::kNoSource));
+    type = ClassFinalizer::FinalizeType(klass, type);
+
+    if (type.IsMalbounded()) {
+      // Evaluate expressions for correctness.
+      instructions +=
+          BuildArgumentsFromActualArguments(NULL, false, /*do_drop*/ true);
+
+      // Throw an error & keep the [Value] on the stack.
+      instructions += ThrowTypeError();
+
+      // Bail out early.
+      return instructions;
+    }
+
+    SetOffset(offset);
+  }
+
+  if (klass.NumTypeArguments() > 0) {
+    const TypeArguments& type_arguments = PeekArgumentsInstantiatedType(klass);
+    if (!klass.IsGeneric()) {
+      Type& type = Type::ZoneHandle(Z, T.ReceiverType(klass).raw());
+
+      // TODO(27590): Can we move this code into [ReceiverType]?
+      type ^= ClassFinalizer::FinalizeType(*active_class()->klass, type,
+                                           ClassFinalizer::kFinalize);
+      ASSERT(!type.IsMalformedOrMalbounded());
+
+      TypeArguments& canonicalized_type_arguments =
+          TypeArguments::ZoneHandle(Z, type.arguments());
+      canonicalized_type_arguments =
+          canonicalized_type_arguments.Canonicalize();
+      instructions += Constant(canonicalized_type_arguments);
+    } else {
+      instructions += TranslateInstantiatedTypeArguments(type_arguments);
+    }
+
+    instructions += PushArgument();
+    instructions += AllocateObject(klass, 1);
+  } else {
+    instructions += AllocateObject(klass, 0);
+  }
+  LocalVariable* variable = MakeTemporary();
+
+  instructions += LoadLocal(variable);
+  instructions += PushArgument();
+
+  Array& argument_names = Array::ZoneHandle(Z);
+  intptr_t argument_count;
+  instructions +=
+      BuildArguments(&argument_names, &argument_count);  // read arguments.
+
+  const Function& target = Function::ZoneHandle(
+      Z, H.LookupConstructorByKernelConstructor(klass, kernel_name));
+  ++argument_count;
+  instructions += StaticCall(position, target, argument_count, argument_names);
+  return instructions + Drop();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildNot(TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
+
+  Fragment instructions = BuildExpression();  // read expression.
+  instructions += CheckBooleanInCheckedMode();
+  instructions += BooleanNegate();
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildLogicalExpression(
+    TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
+
+  bool negate;
+  Fragment instructions = TranslateCondition(&negate);  // read left.
+
+  TargetEntryInstr* right_entry;
+  TargetEntryInstr* constant_entry;
+  LogicalExpression::Operator op =
+      static_cast<LogicalExpression::Operator>(ReadByte());
+
+  if (op == LogicalExpression::kAnd) {
+    instructions += BranchIfTrue(&right_entry, &constant_entry, negate);
+  } else {
+    instructions += BranchIfTrue(&constant_entry, &right_entry, negate);
+  }
+
+  Value* top = stack();
+  Fragment right_fragment(right_entry);
+  right_fragment += TranslateCondition(&negate);  // read right.
+
+  right_fragment += Constant(Bool::True());
+  right_fragment +=
+      StrictCompare(negate ? Token::kNE_STRICT : Token::kEQ_STRICT);
+  right_fragment += StoreLocal(TokenPosition::kNoSource,
+                               parsed_function()->expression_temp_var());
+  right_fragment += Drop();
+
+  ASSERT(top == stack());
+  Fragment constant_fragment(constant_entry);
+  constant_fragment += Constant(Bool::Get(op == LogicalExpression::kOr));
+  constant_fragment += StoreLocal(TokenPosition::kNoSource,
+                                  parsed_function()->expression_temp_var());
+  constant_fragment += Drop();
+
+  JoinEntryInstr* join = BuildJoinEntry();
+  right_fragment += Goto(join);
+  constant_fragment += Goto(join);
+
+  return Fragment(instructions.entry, join) +
+         LoadLocal(parsed_function()->expression_temp_var());
+}
+
+Fragment StreamingFlowGraphBuilder::BuildConditionalExpression(
+    TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
+
+  bool negate;
+  Fragment instructions = TranslateCondition(&negate);  // read condition.
+
+  TargetEntryInstr* then_entry;
+  TargetEntryInstr* otherwise_entry;
+  instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate);
+
+  Value* top = stack();
+  Fragment then_fragment(then_entry);
+  then_fragment += BuildExpression();  // read then.
+  then_fragment += StoreLocal(TokenPosition::kNoSource,
+                              parsed_function()->expression_temp_var());
+  then_fragment += Drop();
+  ASSERT(stack() == top);
+
+  Fragment otherwise_fragment(otherwise_entry);
+  otherwise_fragment += BuildExpression();  // read otherwise.
+  otherwise_fragment += StoreLocal(TokenPosition::kNoSource,
+                                   parsed_function()->expression_temp_var());
+  otherwise_fragment += Drop();
+  ASSERT(stack() == top);
+
+  JoinEntryInstr* join = BuildJoinEntry();
+  then_fragment += Goto(join);
+  otherwise_fragment += Goto(join);
+
+  SkipOptionalDartType();  // read unused static type.
+
+  return Fragment(instructions.entry, join) +
+         LoadLocal(parsed_function()->expression_temp_var());
+}
+
+Fragment StreamingFlowGraphBuilder::BuildStringConcatenation(TokenPosition* p) {
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  intptr_t length = ReadListLength();  // read list length.
+  // Note: there will be "length" expressions.
+
+  Fragment instructions;
+  if (length == 1) {
+    instructions += BuildExpression();  // read expression.
+    instructions += StringInterpolateSingle(position);
+  } else {
+    // The type arguments for CreateArray.
+    instructions += Constant(TypeArguments::ZoneHandle(Z));
+    instructions += IntConstant(length);
+    instructions += CreateArray();
+    LocalVariable* array = MakeTemporary();
+
+    for (intptr_t i = 0; i < length; ++i) {
+      instructions += LoadLocal(array);
+      instructions += IntConstant(i);
+      instructions += BuildExpression();  // read ith expression.
+      instructions += StoreIndexed(kArrayCid);
+      instructions += Drop();
+    }
+
+    instructions += StringInterpolate(position);
+  }
+
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildIsExpression(TokenPosition* p) {
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  Fragment instructions = BuildExpression();  // read operand.
+
+  const AbstractType& type = T.BuildType();  // read type.
+
+  // The VM does not like an instanceOf call with a dynamic type. We need to
+  // special case this situation.
+  const Type& object_type = Type::Handle(Z, Type::ObjectType());
+
+  if (type.IsMalformed()) {
+    instructions += Drop();
+    instructions += ThrowTypeError();
+    return instructions;
+  }
+
+  if (type.IsInstantiated() &&
+      object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
+    // Evaluate the expression on the left but ignore it's result.
+    instructions += Drop();
+
+    // Let condition be always true.
+    instructions += Constant(Bool::True());
+  } else {
+    instructions += PushArgument();
+
+    // See if simple instanceOf is applicable.
+    if (dart::FlowGraphBuilder::SimpleInstanceOfType(type)) {
+      instructions += Constant(type);
+      instructions += PushArgument();  // Type.
+      instructions += InstanceCall(position, dart::Library::PrivateCoreLibName(
+                                                 Symbols::_simpleInstanceOf()),
+                                   Token::kIS, 2, 2);  // 2 checked arguments.
+      return instructions;
+    }
+
+    if (!type.IsInstantiated(kCurrentClass)) {
+      instructions += LoadInstantiatorTypeArguments();
+    } else {
+      instructions += NullConstant();
+    }
+    instructions += PushArgument();  // Instantiator type arguments.
+
+    if (!type.IsInstantiated(kFunctions)) {
+      instructions += LoadFunctionTypeArguments();
+    } else {
+      instructions += NullConstant();
+    }
+    instructions += PushArgument();  // Function type arguments.
+
+    instructions += Constant(type);
+    instructions += PushArgument();  // Type.
+
+    instructions += InstanceCall(
+        position, dart::Library::PrivateCoreLibName(Symbols::_instanceOf()),
+        Token::kIS, 4);
+  }
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildAsExpression(TokenPosition* p) {
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  Fragment instructions = BuildExpression();  // read operand.
+
+  const AbstractType& type = T.BuildType();  // read type.
+
+  // The VM does not like an Object_as call with a dynamic type. We need to
+  // special case this situation.
+  const Type& object_type = Type::Handle(Z, Type::ObjectType());
+
+  if (type.IsMalformed()) {
+    instructions += Drop();
+    instructions += ThrowTypeError();
+    return instructions;
+  }
+
+  if (type.IsInstantiated() &&
+      object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
+    // We already evaluated the operand on the left and just leave it there as
+    // the result of the `obj as dynamic` expression.
+  } else {
+    instructions += PushArgument();
+
+    if (!type.IsInstantiated(kCurrentClass)) {
+      instructions += LoadInstantiatorTypeArguments();
+    } else {
+      instructions += NullConstant();
+    }
+    instructions += PushArgument();  // Instantiator type arguments.
+
+    if (!type.IsInstantiated(kFunctions)) {
+      instructions += LoadFunctionTypeArguments();
+    } else {
+      instructions += NullConstant();
+    }
+    instructions += PushArgument();  // Function type arguments.
+
+    instructions += Constant(type);
+    instructions += PushArgument();  // Type.
+
+    instructions += InstanceCall(
+        position, dart::Library::PrivateCoreLibName(Symbols::_as()), Token::kAS,
+        4);
+  }
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildSymbolLiteral(
+    TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
+
+  intptr_t offset = ReaderOffset() - 1;  // EvaluateExpression needs the tag.
+  SkipStringReference();                 // read index into string table.
+  return Constant(constant_evaluator_.EvaluateExpression(offset));
+}
+
+Fragment StreamingFlowGraphBuilder::BuildTypeLiteral(TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
+
+  const AbstractType& type = T.BuildType();  // read type.
+  if (type.IsMalformed()) H.ReportError("Malformed type literal");
+
+  Fragment instructions;
+  if (type.IsInstantiated()) {
+    instructions += Constant(type);
+  } else {
+    if (!type.IsInstantiated(kCurrentClass)) {
+      instructions += LoadInstantiatorTypeArguments();
+    } else {
+      instructions += NullConstant();
+    }
+    if (!type.IsInstantiated(kFunctions)) {
+      instructions += LoadFunctionTypeArguments();
+    } else {
+      instructions += NullConstant();
+    }
+    instructions += InstantiateType(type);
+  }
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildThisExpression(
+    TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
+
   return LoadLocal(scopes()->this_variable);
 }
 
+Fragment StreamingFlowGraphBuilder::BuildRethrow(TokenPosition* p) {
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
 
-Fragment StreamingFlowGraphBuilder::BuildRethrow() {
-  TokenPosition position = ReadPosition();
   Fragment instructions = DebugStepCheck(position);
   instructions += LoadLocal(catch_block()->exception_var());
   instructions += PushArgument();
@@ -485,46 +3179,1140 @@
   return instructions;
 }
 
+Fragment StreamingFlowGraphBuilder::BuildThrow(TokenPosition* p) {
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
 
-Fragment StreamingFlowGraphBuilder::BuildBigIntLiteral() {
-  const dart::String& value = H.DartString(StringIndex(ReadUInt()));
+  Fragment instructions;
+
+  instructions += BuildExpression();  // read expression.
+
+  if (NeedsDebugStepCheck(stack(), position)) {
+    instructions = DebugStepCheck(position) + instructions;
+  }
+  instructions += PushArgument();
+  instructions += ThrowException(position);
+  ASSERT(instructions.is_closed());
+
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildListLiteral(bool is_const,
+                                                     TokenPosition* p) {
+  if (is_const) {
+    intptr_t offset = ReaderOffset() - 1;                 // Include the tag.
+    (p != NULL) ? * p = ReadPosition() : ReadPosition();  // read position.
+
+    SetOffset(offset);
+    SkipExpression();  // read past the ListLiteral.
+    return Constant(constant_evaluator_.EvaluateListLiteral(offset));
+  }
+
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  const TypeArguments& type_arguments = T.BuildTypeArguments(1);  // read type.
+  intptr_t length = ReadListLength();  // read list length.
+  // Note: there will be "length" expressions.
+
+  // The type argument for the factory call.
+  Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
+  instructions += PushArgument();
+  if (length == 0) {
+    instructions += Constant(Object::empty_array());
+  } else {
+    // The type arguments for CreateArray.
+    instructions += Constant(TypeArguments::ZoneHandle(Z));
+    instructions += IntConstant(length);
+    instructions += CreateArray();
+
+    LocalVariable* array = MakeTemporary();
+    for (intptr_t i = 0; i < length; ++i) {
+      instructions += LoadLocal(array);
+      instructions += IntConstant(i);
+      instructions += BuildExpression();  // read ith expression.
+      instructions += StoreIndexed(kArrayCid);
+      instructions += Drop();
+    }
+  }
+  instructions += PushArgument();  // The array.
+
+  const dart::Class& factory_class =
+      dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::List()));
+  const Function& factory_method = Function::ZoneHandle(
+      Z, factory_class.LookupFactory(
+             dart::Library::PrivateCoreLibName(Symbols::ListLiteralFactory())));
+
+  return instructions + StaticCall(position, factory_method, 2);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildMapLiteral(bool is_const,
+                                                    TokenPosition* p) {
+  if (is_const) {
+    intptr_t offset = ReaderOffset() - 1;  // Include the tag.
+    (p != NULL) ? * p = ReadPosition() : ReadPosition();
+
+    SetOffset(offset);
+    SkipExpression();  // Read past the MapLiteral.
+    return Constant(constant_evaluator_.EvaluateMapLiteral(offset));
+  }
+
+  TokenPosition position = ReadPosition();  // read position.
+  if (p != NULL) *p = position;
+
+  const TypeArguments& type_arguments =
+      T.BuildTypeArguments(2);  // read key_type and value_type.
+
+  // The type argument for the factory call `new Map<K, V>._fromLiteral(List)`.
+  Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
+  instructions += PushArgument();
+
+  intptr_t length = ReadListLength();  // read list length.
+  // Note: there will be "length" map entries (i.e. key and value expressions).
+
+  if (length == 0) {
+    instructions += Constant(Object::empty_array());
+  } else {
+    // The type arguments for `new List<X>(int len)`.
+    instructions += Constant(TypeArguments::ZoneHandle(Z));
+
+    // We generate a list of tuples, i.e. [key1, value1, ..., keyN, valueN].
+    instructions += IntConstant(2 * length);
+    instructions += CreateArray();
+
+    LocalVariable* array = MakeTemporary();
+    for (intptr_t i = 0; i < length; ++i) {
+      instructions += LoadLocal(array);
+      instructions += IntConstant(2 * i);
+      instructions += BuildExpression();  // read ith key.
+      instructions += StoreIndexed(kArrayCid);
+      instructions += Drop();
+
+      instructions += LoadLocal(array);
+      instructions += IntConstant(2 * i + 1);
+      instructions += BuildExpression();  // read ith value.
+      instructions += StoreIndexed(kArrayCid);
+      instructions += Drop();
+    }
+  }
+  instructions += PushArgument();  // The array.
+
+
+  const dart::Class& map_class =
+      dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::Map()));
+  const Function& factory_method = Function::ZoneHandle(
+      Z, map_class.LookupFactory(
+             dart::Library::PrivateCoreLibName(Symbols::MapLiteralFactory())));
+
+  return instructions + StaticCall(position, factory_method, 2);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildLet(TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
+
+  Fragment instructions = BuildVariableDeclaration(false);  // read variable.
+  instructions += BuildExpression();                        // read body.
+  return instructions;
+}
+
+
+Fragment StreamingFlowGraphBuilder::BuildBigIntLiteral(
+    TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
+
+  const dart::String& value =
+      H.DartString(ReadStringReference());  // read index into string table.
   return Constant(Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld)));
 }
 
+Fragment StreamingFlowGraphBuilder::BuildStringLiteral(
+    TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
 
-Fragment StreamingFlowGraphBuilder::BuildStringLiteral() {
-  StringIndex str_index(ReadUInt());
-  return Constant(H.DartSymbol(str_index));
+  return Constant(
+      H.DartSymbol(ReadStringReference()));  // read index into string table.
 }
 
+Fragment StreamingFlowGraphBuilder::BuildIntLiteral(uint8_t payload,
+                                                    TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
 
-Fragment StreamingFlowGraphBuilder::BuildIntLiteral(uint8_t payload) {
   int64_t value = static_cast<int32_t>(payload) - SpecializedIntLiteralBias;
   return IntConstant(value);
 }
 
+Fragment StreamingFlowGraphBuilder::BuildIntLiteral(bool is_negative,
+                                                    TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
 
-Fragment StreamingFlowGraphBuilder::BuildIntLiteral(bool is_negative) {
-  int64_t value = is_negative ? -static_cast<int64_t>(ReadUInt()) : ReadUInt();
+  int64_t value = is_negative ? -static_cast<int64_t>(ReadUInt())
+                              : ReadUInt();  // read value.
   return IntConstant(value);
 }
 
+Fragment StreamingFlowGraphBuilder::BuildDoubleLiteral(
+    TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
 
-Fragment StreamingFlowGraphBuilder::BuildDoubleLiteral() {
-  SkipBytes(-1);  // EvaluateExpression needs the tag.
-  return Constant(constant_evaluator_.EvaluateExpression());
+  intptr_t offset = ReaderOffset() - 1;  // EvaluateExpression needs the tag.
+  SkipStringReference();                 // read index into string table.
+  return Constant(constant_evaluator_.EvaluateExpression(offset));
 }
 
+Fragment StreamingFlowGraphBuilder::BuildBoolLiteral(bool value,
+                                                     TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
 
-Fragment StreamingFlowGraphBuilder::BuildBoolLiteral(bool value) {
   return Constant(Bool::Get(value));
 }
 
+Fragment StreamingFlowGraphBuilder::BuildNullLiteral(TokenPosition* position) {
+  if (position != NULL) *position = TokenPosition::kNoSource;
 
-Fragment StreamingFlowGraphBuilder::BuildNullLiteral() {
   return Constant(Instance::ZoneHandle(Z, Instance::null()));
 }
 
+Fragment StreamingFlowGraphBuilder::BuildInvalidStatement() {
+  H.ReportError("Invalid statements not implemented yet!");
+  return Fragment();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildExpressionStatement() {
+  Fragment instructions = BuildExpression();  // read expression.
+  instructions += Drop();
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildBlock() {
+  intptr_t offset = ReaderOffset() - 1;  // Include the tag.
+
+  Fragment instructions;
+
+  instructions += EnterScope(offset);
+  intptr_t list_length = ReadListLength();  // read number of statements.
+  for (intptr_t i = 0; i < list_length; ++i) {
+    if (instructions.is_open()) {
+      instructions += BuildStatement();  // read ith statement.
+    } else {
+      SkipStatement();  // read ith statement.
+    }
+  }
+  instructions += ExitScope(offset);
+
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildEmptyStatement() {
+  return Fragment();
+}
+
+Fragment StreamingFlowGraphBuilder::BuildAssertStatement() {
+  if (!I->asserts()) {
+    intptr_t offset = ReaderOffset() - 1;  // Include the tag.
+    SetOffset(offset);
+    SkipStatement();  // read this statement.
+    return Fragment();
+  }
+
+  TargetEntryInstr* then;
+  TargetEntryInstr* otherwise;
+
+  Fragment instructions;
+  // Asserts can be of the following two kinds:
+  //
+  //    * `assert(expr)`
+  //    * `assert(() { ... })`
+  //
+  // The call to `_AssertionError._evaluateAssertion()` will take care of both
+  // and returns a boolean.
+  instructions += BuildExpression();  // read condition.
+  instructions += PushArgument();
+  instructions += EvaluateAssertion();
+  instructions += CheckBooleanInCheckedMode();
+  instructions += Constant(Bool::True());
+  instructions += BranchIfEqual(&then, &otherwise, false);
+
+  const dart::Class& klass = dart::Class::ZoneHandle(
+      Z, dart::Library::LookupCoreClass(Symbols::AssertionError()));
+  ASSERT(!klass.IsNull());
+  const dart::Function& constructor = dart::Function::ZoneHandle(
+      Z, klass.LookupConstructorAllowPrivate(
+             H.DartSymbol("_AssertionError._create")));
+  ASSERT(!constructor.IsNull());
+
+  const dart::String& url = H.DartString(
+      parsed_function()->function().ToLibNamePrefixedQualifiedCString(),
+      Heap::kOld);
+
+  // Create instance of _AssertionError
+  Fragment otherwise_fragment(otherwise);
+  otherwise_fragment += AllocateObject(klass, 0);
+  LocalVariable* instance = MakeTemporary();
+
+  // Call _AssertionError._create constructor.
+  otherwise_fragment += LoadLocal(instance);
+  otherwise_fragment += PushArgument();  // this
+
+  otherwise_fragment += Constant(H.DartString("<no message>", Heap::kOld));
+  otherwise_fragment += PushArgument();  // failedAssertion
+
+  otherwise_fragment += Constant(url);
+  otherwise_fragment += PushArgument();  // url
+
+  otherwise_fragment += IntConstant(0);
+  otherwise_fragment += PushArgument();  // line
+
+  otherwise_fragment += IntConstant(0);
+  otherwise_fragment += PushArgument();  // column
+
+  Tag tag = ReadTag();  // read (first part of) message.
+  if (tag == kSomething) {
+    otherwise_fragment += BuildExpression();  // read (rest of) message.
+  } else {
+    otherwise_fragment += Constant(H.DartString("<no message>", Heap::kOld));
+  }
+  otherwise_fragment += PushArgument();  // message
+
+  otherwise_fragment += StaticCall(TokenPosition::kNoSource, constructor, 6);
+  otherwise_fragment += Drop();
+
+  // Throw _AssertionError exception.
+  otherwise_fragment += PushArgument();
+  otherwise_fragment += ThrowException(TokenPosition::kNoSource);
+  otherwise_fragment += Drop();
+
+  return Fragment(instructions.entry, then);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildLabeledStatement() {
+  // There can be serveral cases:
+  //
+  //   * the body contains a break
+  //   * the body doesn't contain a break
+  //
+  //   * translating the body results in a closed fragment
+  //   * translating the body results in a open fragment
+  //
+  // => We will only know which case we are in after the body has been
+  //    traversed.
+
+  BreakableBlock block(flow_graph_builder_);
+  Fragment instructions = BuildStatement();  // read body.
+  if (block.HadJumper()) {
+    if (instructions.is_open()) {
+      instructions += Goto(block.destination());
+    }
+    return Fragment(instructions.entry, block.destination());
+  } else {
+    return instructions;
+  }
+}
+
+Fragment StreamingFlowGraphBuilder::BuildBreakStatement() {
+  TokenPosition position = ReadPosition();  // read position.
+  intptr_t target_index = ReadUInt();       // read target index.
+
+  TryFinallyBlock* outer_finally = NULL;
+  intptr_t target_context_depth = -1;
+  JoinEntryInstr* destination = breakable_block()->BreakDestination(
+      target_index, &outer_finally, &target_context_depth);
+
+  Fragment instructions;
+  instructions +=
+      TranslateFinallyFinalizers(outer_finally, target_context_depth);
+  if (instructions.is_open()) {
+    if (NeedsDebugStepCheck(parsed_function()->function(), position)) {
+      instructions += DebugStepCheck(position);
+    }
+    instructions += Goto(destination);
+  }
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildWhileStatement() {
+  loop_depth_inc();
+  bool negate;
+  Fragment condition = TranslateCondition(&negate);  // read condition.
+  TargetEntryInstr* body_entry;
+  TargetEntryInstr* loop_exit;
+  condition += BranchIfTrue(&body_entry, &loop_exit, negate);
+
+  Fragment body(body_entry);
+  body += BuildStatement();  // read body.
+
+  Instruction* entry;
+  if (body.is_open()) {
+    JoinEntryInstr* join = BuildJoinEntry();
+    body += Goto(join);
+
+    Fragment loop(join);
+    loop += CheckStackOverflow();
+    loop += condition;
+    entry = new (Z) GotoInstr(join);
+  } else {
+    entry = condition.entry;
+  }
+
+
+  loop_depth_dec();
+  return Fragment(entry, loop_exit);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildDoStatement() {
+  loop_depth_inc();
+  Fragment body = BuildStatement();  // read body.
+
+  if (body.is_closed()) {
+    SkipExpression();  // read condition.
+    loop_depth_dec();
+    return body;
+  }
+
+  bool negate;
+  JoinEntryInstr* join = BuildJoinEntry();
+  Fragment loop(join);
+  loop += CheckStackOverflow();
+  loop += body;
+  loop += TranslateCondition(&negate);  // read condition.
+  TargetEntryInstr* loop_repeat;
+  TargetEntryInstr* loop_exit;
+  loop += BranchIfTrue(&loop_repeat, &loop_exit, negate);
+
+  Fragment repeat(loop_repeat);
+  repeat += Goto(join);
+
+  loop_depth_dec();
+  return Fragment(new (Z) GotoInstr(join), loop_exit);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildForStatement() {
+  intptr_t offset = ReaderOffset() - 1;  // Include the tag.
+
+  Fragment declarations;
+
+  bool new_context = false;
+  declarations += EnterScope(offset, &new_context);
+
+  intptr_t list_length = ReadListLength();  // read number of variables.
+  for (intptr_t i = 0; i < list_length; ++i) {
+    declarations += BuildVariableDeclaration(false);  // read ith variable.
+  }
+
+  loop_depth_inc();
+  bool negate = false;
+  Tag tag = ReadTag();  // Read first part of condition.
+  Fragment condition =
+      tag == kNothing ? Constant(Bool::True())
+                      : TranslateCondition(&negate);  // read rest of condition.
+  TargetEntryInstr* body_entry;
+  TargetEntryInstr* loop_exit;
+  condition += BranchIfTrue(&body_entry, &loop_exit, negate);
+
+  Fragment updates;
+  list_length = ReadListLength();  // read number of updates.
+  for (intptr_t i = 0; i < list_length; ++i) {
+    updates += BuildExpression();  // read ith update.
+    updates += Drop();
+  }
+
+  Fragment body(body_entry);
+  body += BuildStatement();  // read body.
+
+  if (body.is_open()) {
+    // We allocated a fresh context before the loop which contains captured
+    // [ForStatement] variables.  Before jumping back to the loop entry we clone
+    // the context object (at same depth) which ensures the next iteration of
+    // the body gets a fresh set of [ForStatement] variables (with the old
+    // (possibly updated) values).
+    if (new_context) body += CloneContext();
+
+    body += updates;
+    JoinEntryInstr* join = BuildJoinEntry();
+    declarations += Goto(join);
+    body += Goto(join);
+
+    Fragment loop(join);
+    loop += CheckStackOverflow();
+    loop += condition;
+  } else {
+    declarations += condition;
+  }
+
+  Fragment loop(declarations.entry, loop_exit);
+  loop_depth_dec();
+
+  loop += ExitScope(offset);
+
+  return loop;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildForInStatement(bool async) {
+  intptr_t offset = ReaderOffset() - 1;  // Include the tag.
+
+  TokenPosition position = ReadPosition();  // read position.
+  intptr_t variable_kernel_position = ReaderOffset();
+  SkipVariableDeclaration();  // read variable.
+
+  TokenPosition iterable_position = TokenPosition::kNoSource;
+  Fragment instructions =
+      BuildExpression(&iterable_position);  // read iterable.
+  instructions += PushArgument();
+
+  const dart::String& iterator_getter = dart::String::ZoneHandle(
+      Z, dart::Field::GetterSymbol(Symbols::Iterator()));
+  instructions +=
+      InstanceCall(iterable_position, iterator_getter, Token::kGET, 1);
+  LocalVariable* iterator = scopes()->iterator_variables[for_in_depth()];
+  instructions += StoreLocal(TokenPosition::kNoSource, iterator);
+  instructions += Drop();
+
+  for_in_depth_inc();
+  loop_depth_inc();
+  Fragment condition = LoadLocal(iterator);
+  condition += PushArgument();
+  condition +=
+      InstanceCall(iterable_position, Symbols::MoveNext(), Token::kILLEGAL, 1);
+  TargetEntryInstr* body_entry;
+  TargetEntryInstr* loop_exit;
+  condition += BranchIfTrue(&body_entry, &loop_exit, false);
+
+  Fragment body(body_entry);
+  body += EnterScope(offset);
+  body += LoadLocal(iterator);
+  body += PushArgument();
+  const dart::String& current_getter = dart::String::ZoneHandle(
+      Z, dart::Field::GetterSymbol(Symbols::Current()));
+  body += InstanceCall(position, current_getter, Token::kGET, 1);
+  body += StoreLocal(TokenPosition::kNoSource,
+                     LookupVariable(variable_kernel_position));
+  body += Drop();
+  body += BuildStatement();  // read body.
+  body += ExitScope(offset);
+
+  if (body.is_open()) {
+    JoinEntryInstr* join = BuildJoinEntry();
+    instructions += Goto(join);
+    body += Goto(join);
+
+    Fragment loop(join);
+    loop += CheckStackOverflow();
+    loop += condition;
+  } else {
+    instructions += condition;
+  }
+
+  loop_depth_dec();
+  for_in_depth_dec();
+  return Fragment(instructions.entry, loop_exit);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildSwitchStatement() {
+  // We need the number of cases. So start by getting that, then go back.
+  intptr_t offset = ReaderOffset();
+  SkipExpression();                  // temporarily skip condition
+  int num_cases = ReadListLength();  // read number of cases.
+  SetOffset(offset);
+
+  SwitchBlock block(flow_graph_builder_, num_cases);
+
+  // Instead of using a variable we should reuse the expression on the stack,
+  // since it won't be assigned again, we don't need phi nodes.
+  Fragment head_instructions = BuildExpression();  // read condition.
+  head_instructions +=
+      StoreLocal(TokenPosition::kNoSource, scopes()->switch_variable);
+  head_instructions += Drop();
+
+  num_cases = ReadListLength();  // read number of cases.
+
+  // Phase 1: Generate bodies and try to find out whether a body will be target
+  // of a jump due to:
+  //   * `continue case_label`
+  //   * `case e1: case e2: body`
+  Fragment* body_fragments = new Fragment[num_cases];
+  intptr_t* case_expression_offsets = new intptr_t[num_cases];
+  bool* case_is_default = new bool[num_cases];
+
+  for (intptr_t i = 0; i < num_cases; ++i) {
+    case_expression_offsets[i] = ReaderOffset();
+    int num_expressions = ReadListLength();  // read number of expressions.
+    for (intptr_t j = 0; j < num_expressions; ++j) {
+      ReadPosition();    // read jth position.
+      SkipExpression();  // read jth expression.
+    }
+    bool is_default = ReadBool();  // read is_default.
+    case_is_default[i] = is_default;
+    Fragment& body_fragment = body_fragments[i] =
+        BuildStatement();  // read body.
+
+    if (body_fragment.entry == NULL) {
+      // Make a NOP in order to ensure linking works properly.
+      body_fragment = NullConstant();
+      body_fragment += Drop();
+    }
+
+    // The Dart language specification mandates fall-throughs in [SwitchCase]es
+    // to be runtime errors.
+    if (!is_default && body_fragment.is_open() && (i < (num_cases - 1))) {
+      const dart::Class& klass = dart::Class::ZoneHandle(
+          Z, dart::Library::LookupCoreClass(Symbols::FallThroughError()));
+      ASSERT(!klass.IsNull());
+      const dart::Function& constructor = dart::Function::ZoneHandle(
+          Z, klass.LookupConstructorAllowPrivate(
+                 H.DartSymbol("FallThroughError._create")));
+      ASSERT(!constructor.IsNull());
+      const dart::String& url = H.DartString(
+          parsed_function()->function().ToLibNamePrefixedQualifiedCString(),
+          Heap::kOld);
+
+      // Create instance of _FallThroughError
+      body_fragment += AllocateObject(klass, 0);
+      LocalVariable* instance = MakeTemporary();
+
+      // Call _FallThroughError._create constructor.
+      body_fragment += LoadLocal(instance);
+      body_fragment += PushArgument();  // this
+
+      body_fragment += Constant(url);
+      body_fragment += PushArgument();  // url
+
+      body_fragment += NullConstant();
+      body_fragment += PushArgument();  // line
+
+      body_fragment += StaticCall(TokenPosition::kNoSource, constructor, 3);
+      body_fragment += Drop();
+
+      // Throw the exception
+      body_fragment += PushArgument();
+      body_fragment += ThrowException(TokenPosition::kNoSource);
+      body_fragment += Drop();
+    }
+
+    // If there is an implicit fall-through we have one [SwitchCase] and
+    // multiple expressions, e.g.
+    //
+    //    switch(expr) {
+    //      case a:
+    //      case b:
+    //        <stmt-body>
+    //    }
+    //
+    // This means that the <stmt-body> will have more than 1 incoming edge (one
+    // from `a == expr` and one from `a != expr && b == expr`). The
+    // `block.Destination()` records the additional jump.
+    if (num_expressions > 1) {
+      block.DestinationDirect(i);
+    }
+  }
+
+  intptr_t end_offset = ReaderOffset();
+
+  // Phase 2: Generate everything except the real bodies:
+  //   * jump directly to a body (if there is no jumper)
+  //   * jump to a wrapper block which jumps to the body (if there is a jumper)
+  Fragment current_instructions = head_instructions;
+  for (intptr_t i = 0; i < num_cases; ++i) {
+    SetOffset(case_expression_offsets[i]);
+    int num_expressions = ReadListLength();  // read length of expressions.
+
+    if (case_is_default[i]) {
+      ASSERT(i == (num_cases - 1));
+
+      // Evaluate the conditions for the default [SwitchCase] just for the
+      // purpose of potentially triggering a compile-time error.
+
+      for (intptr_t j = 0; j < num_expressions; ++j) {
+        ReadPosition();  // read jth position.
+        // this reads the expression, but doesn't skip past it.
+        constant_evaluator_.EvaluateExpression(ReaderOffset());
+        SkipExpression();  // read jth expression.
+      }
+
+      if (block.HadJumper(i)) {
+        // There are several branches to the body, so we will make a goto to
+        // the join block (and prepend a join instruction to the real body).
+        JoinEntryInstr* join = block.DestinationDirect(i);
+        current_instructions += Goto(join);
+
+        current_instructions = Fragment(current_instructions.entry, join);
+        current_instructions += body_fragments[i];
+      } else {
+        current_instructions += body_fragments[i];
+      }
+    } else {
+      JoinEntryInstr* body_join = NULL;
+      if (block.HadJumper(i)) {
+        body_join = block.DestinationDirect(i);
+        body_fragments[i] = Fragment(body_join) + body_fragments[i];
+      }
+
+      for (intptr_t j = 0; j < num_expressions; ++j) {
+        TargetEntryInstr* then;
+        TargetEntryInstr* otherwise;
+
+        TokenPosition position = ReadPosition();  // read jth position.
+        current_instructions +=
+            Constant(constant_evaluator_.EvaluateExpression(ReaderOffset()));
+        SkipExpression();  // read jth expression.
+        current_instructions += PushArgument();
+        current_instructions += LoadLocal(scopes()->switch_variable);
+        current_instructions += PushArgument();
+        current_instructions +=
+            InstanceCall(position, Symbols::EqualOperator(), Token::kEQ,
+                         /*argument_count=*/2,
+                         /*num_args_checked=*/2);
+        current_instructions += BranchIfTrue(&then, &otherwise, false);
+
+        Fragment then_fragment(then);
+
+        if (body_join != NULL) {
+          // There are several branches to the body, so we will make a goto to
+          // the join block (the real body has already been prepended with a
+          // join instruction).
+          then_fragment += Goto(body_join);
+        } else {
+          // There is only a signle branch to the body, so we will just append
+          // the body fragment.
+          then_fragment += body_fragments[i];
+        }
+
+        current_instructions = Fragment(otherwise);
+      }
+    }
+  }
+
+  bool has_no_default = num_cases > 0 && !case_is_default[num_cases - 1];
+  if (has_no_default) {
+    // There is no default, which means we have an open [current_instructions]
+    // (which is a [TargetEntryInstruction] for the last "otherwise" branch).
+    //
+    // Furthermore the last [SwitchCase] can be open as well.  If so, we need
+    // to join these two.
+    Fragment& last_body = body_fragments[num_cases - 1];
+    if (last_body.is_open()) {
+      ASSERT(current_instructions.is_open());
+      ASSERT(current_instructions.current->IsTargetEntry());
+
+      // Join the last "otherwise" branch and the last [SwitchCase] fragment.
+      JoinEntryInstr* join = BuildJoinEntry();
+      current_instructions += Goto(join);
+      last_body += Goto(join);
+
+      current_instructions = Fragment(join);
+    }
+  } else {
+    // All non-default cases will be closed (i.e. break/continue/throw/return)
+    // So it is fine to just let more statements after the switch append to the
+    // default case.
+  }
+
+  delete[] body_fragments;
+
+  SetOffset(end_offset);
+  return Fragment(head_instructions.entry, current_instructions.current);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildContinueSwitchStatement() {
+  intptr_t target_index = ReadUInt();  // read target index.
+
+  TryFinallyBlock* outer_finally = NULL;
+  intptr_t target_context_depth = -1;
+  JoinEntryInstr* entry = switch_block()->Destination(
+      target_index, &outer_finally, &target_context_depth);
+
+  Fragment instructions;
+  instructions +=
+      TranslateFinallyFinalizers(outer_finally, target_context_depth);
+  if (instructions.is_open()) {
+    instructions += Goto(entry);
+  }
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildIfStatement() {
+  bool negate;
+  Fragment instructions = TranslateCondition(&negate);  // read condition.
+  TargetEntryInstr* then_entry;
+  TargetEntryInstr* otherwise_entry;
+  instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate);
+
+  Fragment then_fragment(then_entry);
+  then_fragment += BuildStatement();  // read then.
+
+  Fragment otherwise_fragment(otherwise_entry);
+  otherwise_fragment += BuildStatement();  // read otherwise.
+
+  if (then_fragment.is_open()) {
+    if (otherwise_fragment.is_open()) {
+      JoinEntryInstr* join = BuildJoinEntry();
+      then_fragment += Goto(join);
+      otherwise_fragment += Goto(join);
+      return Fragment(instructions.entry, join);
+    } else {
+      return Fragment(instructions.entry, then_fragment.current);
+    }
+  } else if (otherwise_fragment.is_open()) {
+    return Fragment(instructions.entry, otherwise_fragment.current);
+  } else {
+    return instructions.closed();
+  }
+}
+
+Fragment StreamingFlowGraphBuilder::BuildReturnStatement() {
+  TokenPosition position = ReadPosition();  // read position.
+  Tag tag = ReadTag();                      // read first part of expression.
+
+  bool inside_try_finally = try_finally_block() != NULL;
+
+  Fragment instructions = tag == kNothing
+                              ? NullConstant()
+                              : BuildExpression();  // read rest of expression.
+
+  if (instructions.is_open()) {
+    if (inside_try_finally) {
+      ASSERT(scopes()->finally_return_variable != NULL);
+      const Function& function = parsed_function()->function();
+      if (NeedsDebugStepCheck(function, position)) {
+        instructions += DebugStepCheck(position);
+      }
+      instructions += StoreLocal(position, scopes()->finally_return_variable);
+      instructions += Drop();
+      instructions += TranslateFinallyFinalizers(NULL, -1);
+      if (instructions.is_open()) {
+        instructions += LoadLocal(scopes()->finally_return_variable);
+        instructions += Return(TokenPosition::kNoSource);
+      }
+    } else {
+      instructions += Return(position);
+    }
+  } else {
+    Pop();
+  }
+
+  return instructions;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildTryCatch() {
+  InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch");
+
+  intptr_t try_handler_index = AllocateTryIndex();
+  Fragment try_body = TryCatch(try_handler_index);
+  JoinEntryInstr* after_try = BuildJoinEntry();
+
+  // Fill in the body of the try.
+  try_depth_inc();
+  {
+    TryCatchBlock block(flow_graph_builder_, try_handler_index);
+    try_body += BuildStatement();  // read body.
+    try_body += Goto(after_try);
+  }
+  try_depth_dec();
+
+  bool needs_stacktrace = ReadBool();  // read any_catch_needs_stack_trace
+
+  catch_depth_inc();
+  intptr_t num_matches = ReadListLength();  // read number of catches.
+  const Array& handler_types =
+      Array::ZoneHandle(Z, Array::New(num_matches, Heap::kOld));
+  Fragment catch_body =
+      CatchBlockEntry(handler_types, try_handler_index, needs_stacktrace);
+  // Fill in the body of the catch.
+  for (intptr_t i = 0; i < num_matches; ++i) {
+    intptr_t catch_offset = ReaderOffset();  // Catch has no tag.
+    Tag tag = PeekTag();                     // peek guard type.
+    AbstractType* type_guard = NULL;
+    if (tag != kDynamicType) {
+      type_guard = &T.BuildType();  // read guard.
+      handler_types.SetAt(i, *type_guard);
+    } else {
+      SkipDartType();  // read guard.
+      handler_types.SetAt(i, Object::dynamic_type());
+    }
+
+    Fragment catch_handler_body = EnterScope(catch_offset);
+
+    tag = ReadTag();  // read first part of exception.
+    if (tag == kSomething) {
+      catch_handler_body += LoadLocal(CurrentException());
+      catch_handler_body +=
+          StoreLocal(TokenPosition::kNoSource, LookupVariable(ReaderOffset()));
+      catch_handler_body += Drop();
+      SkipVariableDeclaration();  // read exception.
+    }
+
+    tag = ReadTag();  // read first part of stack trace.
+    if (tag == kSomething) {
+      catch_handler_body += LoadLocal(CurrentStackTrace());
+      catch_handler_body +=
+          StoreLocal(TokenPosition::kNoSource, LookupVariable(ReaderOffset()));
+      catch_handler_body += Drop();
+      SkipVariableDeclaration();  // read stack trace.
+    }
+
+    {
+      CatchBlock block(flow_graph_builder_, CurrentException(),
+                       CurrentStackTrace(), try_handler_index);
+
+      catch_handler_body += BuildStatement();  // read body.
+
+      // Note: ExitScope adjusts context_depth_ so even if catch_handler_body
+      // is closed we still need to execute ExitScope for its side effect.
+      catch_handler_body += ExitScope(catch_offset);
+      if (catch_handler_body.is_open()) {
+        catch_handler_body += Goto(after_try);
+      }
+    }
+
+    if (type_guard != NULL) {
+      if (type_guard->IsMalformed()) {
+        catch_body += ThrowTypeError();
+        catch_body += Drop();
+      } else {
+        catch_body += LoadLocal(CurrentException());
+        catch_body += PushArgument();  // exception
+        catch_body += NullConstant();
+        catch_body += PushArgument();  // instantiator type arguments
+        catch_body += NullConstant();
+        catch_body += PushArgument();  // function type arguments
+        catch_body += Constant(*type_guard);
+        catch_body += PushArgument();  // guard type
+        catch_body += InstanceCall(
+            TokenPosition::kNoSource,
+            dart::Library::PrivateCoreLibName(Symbols::_instanceOf()),
+            Token::kIS, 4);
+
+        TargetEntryInstr* catch_entry;
+        TargetEntryInstr* next_catch_entry;
+        catch_body += BranchIfTrue(&catch_entry, &next_catch_entry, false);
+
+        Fragment(catch_entry) + catch_handler_body;
+        catch_body = Fragment(next_catch_entry);
+      }
+    } else {
+      catch_body += catch_handler_body;
+    }
+  }
+
+  // In case the last catch body was not handling the exception and branching to
+  // after the try block, we will rethrow the exception (i.e. no default catch
+  // handler).
+  if (catch_body.is_open()) {
+    catch_body += LoadLocal(CurrentException());
+    catch_body += PushArgument();
+    catch_body += LoadLocal(CurrentStackTrace());
+    catch_body += PushArgument();
+    catch_body += RethrowException(TokenPosition::kNoSource, try_handler_index);
+    Drop();
+  }
+  catch_depth_dec();
+
+  return Fragment(try_body.entry, after_try);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildTryFinally() {
+  // Note on streaming:
+  // We only stream this TryFinally if we can stream everything inside it,
+  // so creating a "TryFinallyBlock" with a kernel binary offset instead of an
+  // AST node isn't a problem.
+
+
+  InlineBailout("kernel::FlowgraphBuilder::VisitTryFinally");
+
+  // There are 5 different cases where we need to execute the finally block:
+  //
+  //  a) 1/2/3th case: Special control flow going out of `node->body()`:
+  //
+  //   * [BreakStatement] transfers control to a [LabledStatement]
+  //   * [ContinueSwitchStatement] transfers control to a [SwitchCase]
+  //   * [ReturnStatement] returns a value
+  //
+  //   => All three cases will automatically append all finally blocks
+  //      between the branching point and the destination (so we don't need to
+  //      do anything here).
+  //
+  //  b) 4th case: Translating the body resulted in an open fragment (i.e. body
+  //               executes without any control flow out of it)
+  //
+  //   => We are responsible for jumping out of the body to a new block (with
+  //      different try index) and execute the finalizer.
+  //
+  //  c) 5th case: An exception occurred inside the body.
+  //
+  //   => We are responsible for catching it, executing the finally block and
+  //      rethrowing the exception.
+  intptr_t try_handler_index = AllocateTryIndex();
+  Fragment try_body = TryCatch(try_handler_index);
+  JoinEntryInstr* after_try = BuildJoinEntry();
+
+  intptr_t offset = ReaderOffset();
+  SkipStatement();  // temporarily read body.
+  intptr_t finalizer_offset = ReaderOffset();
+  SetOffset(offset);
+
+  // Fill in the body of the try.
+  try_depth_inc();
+  {
+    TryFinallyBlock tfb(flow_graph_builder_, NULL, finalizer_offset);
+    TryCatchBlock tcb(flow_graph_builder_, try_handler_index);
+    try_body += BuildStatement();  // read body.
+  }
+  try_depth_dec();
+
+  if (try_body.is_open()) {
+    // Please note: The try index will be on level out of this block,
+    // thereby ensuring if there's an exception in the finally block we
+    // won't run it twice.
+    JoinEntryInstr* finally_entry = BuildJoinEntry();
+
+    try_body += Goto(finally_entry);
+
+    Fragment finally_body(finally_entry);
+    finally_body += BuildStatement();  // read finalizer.
+    finally_body += Goto(after_try);
+  }
+
+  // Fill in the body of the catch.
+  catch_depth_inc();
+  const Array& handler_types = Array::ZoneHandle(Z, Array::New(1, Heap::kOld));
+  handler_types.SetAt(0, Object::dynamic_type());
+  // Note: rethrow will actually force mark the handler as needing a stacktrace.
+  Fragment finally_body = CatchBlockEntry(handler_types, try_handler_index,
+                                          /* needs_stacktrace = */ false);
+  SetOffset(finalizer_offset);
+  finally_body += BuildStatement();  // read finalizer
+  if (finally_body.is_open()) {
+    finally_body += LoadLocal(CurrentException());
+    finally_body += PushArgument();
+    finally_body += LoadLocal(CurrentStackTrace());
+    finally_body += PushArgument();
+    finally_body +=
+        RethrowException(TokenPosition::kNoSource, try_handler_index);
+    Drop();
+  }
+  catch_depth_dec();
+
+  return Fragment(try_body.entry, after_try);
+}
+
+Fragment StreamingFlowGraphBuilder::BuildYieldStatement() {
+  TokenPosition position = ReadPosition();  // read position.
+  uint8_t flags = ReadByte();               // read flags.
+
+  ASSERT((flags & YieldStatement::kFlagNative) ==
+         YieldStatement::kFlagNative);  // Must have been desugared.
+
+  // Setup yield/continue point:
+  //
+  //   ...
+  //   :await_jump_var = index;
+  //   :await_ctx_var = :current_context_var
+  //   return <expr>
+  //
+  // Continuation<index>:
+  //   Drop(1)
+  //   ...
+  //
+  // BuildGraphOfFunction will create a dispatch that jumps to
+  // Continuation<:await_jump_var> upon entry to the function.
+  //
+  Fragment instructions = IntConstant(yield_continuations().length() + 1);
+  instructions +=
+      StoreLocal(TokenPosition::kNoSource, scopes()->yield_jump_variable);
+  instructions += Drop();
+  instructions += LoadLocal(parsed_function()->current_context_var());
+  instructions +=
+      StoreLocal(TokenPosition::kNoSource, scopes()->yield_context_variable);
+  instructions += Drop();
+  instructions += BuildExpression();  // read expression.
+  instructions += Return(TokenPosition::kNoSource);
+
+  // Note: DropTempsInstr serves as an anchor instruction. It will not
+  // be linked into the resulting graph.
+  DropTempsInstr* anchor = new (Z) DropTempsInstr(0, NULL);
+  yield_continuations().Add(YieldContinuation(anchor, CurrentTryIndex()));
+
+  Fragment continuation(instructions.entry, anchor);
+
+  if (parsed_function()->function().IsAsyncClosure() ||
+      parsed_function()->function().IsAsyncGenClosure()) {
+    // If function is async closure or async gen closure it takes three
+    // parameters where the second and the third are exception and stack_trace.
+    // Check if exception is non-null and rethrow it.
+    //
+    //   :async_op([:result, :exception, :stack_trace]) {
+    //     ...
+    //     Continuation<index>:
+    //       if (:exception != null) rethrow(:exception, :stack_trace);
+    //     ...
+    //   }
+    //
+    LocalScope* scope = parsed_function()->node_sequence()->scope();
+    LocalVariable* exception_var = scope->VariableAt(2);
+    LocalVariable* stack_trace_var = scope->VariableAt(3);
+    ASSERT(exception_var->name().raw() == Symbols::ExceptionParameter().raw());
+    ASSERT(stack_trace_var->name().raw() ==
+           Symbols::StackTraceParameter().raw());
+
+    TargetEntryInstr* no_error;
+    TargetEntryInstr* error;
+
+    continuation += LoadLocal(exception_var);
+    continuation += BranchIfNull(&no_error, &error);
+
+    Fragment rethrow(error);
+    rethrow += LoadLocal(exception_var);
+    rethrow += PushArgument();
+    rethrow += LoadLocal(stack_trace_var);
+    rethrow += PushArgument();
+    rethrow += RethrowException(position, CatchClauseNode::kInvalidTryIndex);
+    Drop();
+
+
+    continuation = Fragment(continuation.entry, no_error);
+  }
+
+  return continuation;
+}
+
+Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration(bool has_tag) {
+  intptr_t kernel_position = ReaderOffset() - (has_tag ? 1 : 0);
+  LocalVariable* variable = LookupVariable(kernel_position);
+
+  TokenPosition position = ReadPosition();         // read position.
+  TokenPosition equals_position = ReadPosition();  // read equals position.
+  word flags = ReadFlags();                        // read flags.
+  dart::String& name = H.DartSymbol(ReadStringReference());  // read name index.
+  AbstractType& type = T.BuildType();                        // read type.
+  Tag tag = ReadTag();  // read (first part of) initializer.
+
+  Fragment instructions;
+  if (tag == kNothing) {
+    instructions += NullConstant();
+  } else {
+    if ((flags & VariableDeclaration::kFlagConst) ==
+        VariableDeclaration::kFlagConst) {
+      // Const!
+      const Instance& constant_value = constant_evaluator_.EvaluateExpression(
+          ReaderOffset());  // read initializer form current position.
+      variable->SetConstValue(constant_value);
+      instructions += Constant(constant_value);
+      SkipExpression();  // skip initializer.
+    } else {
+      // Initializer
+      instructions += BuildExpression();  // read (actual) initializer.
+      instructions += CheckVariableTypeInCheckedMode(type, name);
+    }
+  }
+
+  // Use position of equal sign if it exists. If the equal sign does not exist
+  // use the position of the identifier.
+  TokenPosition debug_position = Utils::Maximum(position, equals_position);
+  if (NeedsDebugStepCheck(stack(), debug_position)) {
+    instructions = DebugStepCheck(debug_position) + instructions;
+  }
+  instructions += StoreLocal(position, variable);
+  instructions += Drop();
+  return instructions;
+}
 
 }  // namespace kernel
 }  // namespace dart
diff --git a/runtime/vm/kernel_binary_flowgraph.h b/runtime/vm/kernel_binary_flowgraph.h
index 124987a..3e741db 100644
--- a/runtime/vm/kernel_binary_flowgraph.h
+++ b/runtime/vm/kernel_binary_flowgraph.h
@@ -17,27 +17,132 @@
 namespace dart {
 namespace kernel {
 
+class StreamingDartTypeTranslator {
+ public:
+  StreamingDartTypeTranslator(StreamingFlowGraphBuilder* builder,
+                              bool finalize = false);
+
+  // Can return a malformed type.
+  AbstractType& BuildType();
+  // Will return `TypeArguments::null()` in case any of the arguments are
+  // malformed.
+  const TypeArguments& BuildTypeArguments(intptr_t length);
+
+  // Will return `TypeArguments::null()` in case any of the arguments are
+  // malformed.
+  const TypeArguments& BuildInstantiatedTypeArguments(
+      const dart::Class& receiver_class,
+      intptr_t length);
+
+  const Type& ReceiverType(const dart::Class& klass);
+
+ private:
+  // Can build a malformed type.
+  void BuildTypeInternal();
+  void BuildInterfaceType(bool simple);
+  void BuildFunctionType(bool simple);
+  void BuildTypeParameterType();
+
+  class TypeParameterScope {
+   public:
+    TypeParameterScope(StreamingDartTypeTranslator* translator,
+                       intptr_t* parameters,
+                       intptr_t parameters_count)
+        : parameters_(parameters),
+          parameters_count_(parameters_count),
+          outer_(translator->type_parameter_scope_),
+          translator_(translator) {
+      translator_->type_parameter_scope_ = this;
+    }
+    ~TypeParameterScope() {
+      delete[] parameters_;
+      translator_->type_parameter_scope_ = outer_;
+    }
+
+    TypeParameterScope* outer() const { return outer_; }
+    intptr_t* parameters() const { return parameters_; }
+    intptr_t parameters_count() const { return parameters_count_; }
+
+   private:
+    intptr_t* parameters_;
+    intptr_t parameters_count_;
+    TypeParameterScope* outer_;
+    StreamingDartTypeTranslator* translator_;
+  };
+
+  StreamingFlowGraphBuilder* builder_;
+  TranslationHelper& translation_helper_;
+  ActiveClass* active_class_;
+  TypeParameterScope* type_parameter_scope_;
+  Zone* zone_;
+  AbstractType& result_;
+  bool finalize_;
+};
+
+
 class StreamingConstantEvaluator {
  public:
-  StreamingConstantEvaluator(StreamingFlowGraphBuilder* builder,
-                             Zone* zone,
-                             TranslationHelper* h,
-                             DartTypeTranslator* type_translator);
+  explicit StreamingConstantEvaluator(StreamingFlowGraphBuilder* builder);
 
   virtual ~StreamingConstantEvaluator() {}
 
-  Instance& EvaluateExpression();
-
-  void EvaluateStaticGet();
-  void EvaluateSymbolLiteral();
-  void EvaluateDoubleLiteral();
+  Instance& EvaluateExpression(intptr_t offset, bool reset_position = true);
+  Instance& EvaluateListLiteral(intptr_t offset, bool reset_position = true);
+  Instance& EvaluateMapLiteral(intptr_t offset, bool reset_position = true);
+  Instance& EvaluateConstructorInvocation(intptr_t offset,
+                                          bool reset_position = true);
+  Object& EvaluateExpressionSafe(intptr_t offset);
 
  private:
+  void EvaluateVariableGet();
+  void EvaluateVariableGet(uint8_t payload);
+  void EvaluatePropertyGet();
+  void EvaluateStaticGet();
+  void EvaluateMethodInvocation();
+  void EvaluateStaticInvocation();
+  void EvaluateConstructorInvocationInternal();
+  void EvaluateNot();
+  void EvaluateLogicalExpression();
+  void EvaluateConditionalExpression();
+  void EvaluateStringConcatenation();
+  void EvaluateSymbolLiteral();
+  void EvaluateTypeLiteral();
+  void EvaluateListLiteralInternal();
+  void EvaluateMapLiteralInternal();
+  void EvaluateLet();
+  void EvaluateBigIntLiteral();
+  void EvaluateStringLiteral();
+  void EvaluateIntLiteral(uint8_t payload);
+  void EvaluateIntLiteral(bool is_negative);
+  void EvaluateDoubleLiteral();
+  void EvaluateBoolLiteral(bool value);
+  void EvaluateNullLiteral();
+
+  const Object& RunFunction(const Function& function,
+                            intptr_t argument_count,
+                            const Instance* receiver,
+                            const TypeArguments* type_args);
+
+  const Object& RunFunction(const Function& function,
+                            const Array& arguments,
+                            const Array& names);
+
   RawObject* EvaluateConstConstructorCall(const dart::Class& type_class,
                                           const TypeArguments& type_arguments,
                                           const Function& constructor,
                                           const Object& argument);
 
+  const TypeArguments* TranslateTypeArguments(const Function& target,
+                                              dart::Class* target_klass);
+
+  void AssertBoolInCheckedMode() {
+    if (isolate_->type_checks() && !result_.IsBool()) {
+      translation_helper_.ReportError("Expected boolean expression.");
+    }
+  }
+
+  bool EvaluateBooleanExpressionHere();
+
   bool GetCachedConstant(intptr_t kernel_offset, Instance* value);
   void CacheConstantValue(intptr_t kernel_offset, const Instance& value);
 
@@ -45,7 +150,7 @@
   Isolate* isolate_;
   Zone* zone_;
   TranslationHelper& translation_helper_;
-  //  DartTypeTranslator& type_translator_;
+  StreamingDartTypeTranslator& type_translator_;
 
   Script& script_;
   Instance& result_;
@@ -61,32 +166,91 @@
         translation_helper_(flow_graph_builder->translation_helper_),
         zone_(flow_graph_builder->zone_),
         reader_(new Reader(buffer, buffer_length)),
-        constant_evaluator_(this,
-                            flow_graph_builder->zone_,
-                            &flow_graph_builder->translation_helper_,
-                            &flow_graph_builder->type_translator_) {}
+        constant_evaluator_(this),
+        type_translator_(this, /* finalize= */ true) {}
 
-  virtual ~StreamingFlowGraphBuilder() {}
-
-  Fragment BuildAt(intptr_t kernel_offset);
+  Fragment BuildExpressionAt(intptr_t kernel_offset);
+  Fragment BuildStatementAt(intptr_t kernel_offset);
 
  private:
+  Fragment BuildExpression(TokenPosition* position = NULL);
+  Fragment BuildStatement();
+
   intptr_t ReaderOffset();
   void SetOffset(intptr_t offset);
   void SkipBytes(intptr_t skip);
+  bool ReadBool();
+  uint8_t ReadByte();
   uint32_t ReadUInt();
+  uint32_t PeekUInt();
   intptr_t ReadListLength();
+  StringIndex ReadStringReference();
   NameIndex ReadCanonicalNameReference();
+  StringIndex ReadNameAsStringIndex();
+  const dart::String& ReadNameAsMethodName();
+  const dart::String& ReadNameAsGetterName();
+  const dart::String& ReadNameAsSetterName();
+  void SkipStringReference();
+  void SkipCanonicalNameReference();
+  void SkipDartType();
+  void SkipOptionalDartType();
+  void SkipInterfaceType(bool simple);
+  void SkipFunctionType(bool simple);
+  void SkipExpression();
+  void SkipStatement();
+  void SkipName();
+  void SkipArguments();
+  void SkipVariableDeclaration();
   TokenPosition ReadPosition(bool record = true);
   Tag ReadTag(uint8_t* payload = NULL);
+  Tag PeekTag(uint8_t* payload = NULL);
+  word ReadFlags();
 
+  void loop_depth_inc();
+  void loop_depth_dec();
+  intptr_t for_in_depth();
+  void for_in_depth_inc();
+  void for_in_depth_dec();
+  void catch_depth_inc();
+  void catch_depth_dec();
+  void try_depth_inc();
+  void try_depth_dec();
+  intptr_t CurrentTryIndex();
+  intptr_t AllocateTryIndex();
+  LocalVariable* CurrentException();
+  LocalVariable* CurrentStackTrace();
   CatchBlock* catch_block();
+  ActiveClass* active_class();
   ScopeBuildingResult* scopes();
   ParsedFunction* parsed_function();
+  TryFinallyBlock* try_finally_block();
+  SwitchBlock* switch_block();
+  BreakableBlock* breakable_block();
+  GrowableArray<YieldContinuation>& yield_continuations();
+  Value* stack();
+  Value* Pop();
 
+  Tag PeekArgumentsFirstPositionalTag();
+  const TypeArguments& PeekArgumentsInstantiatedType(const dart::Class& klass);
+  intptr_t PeekArgumentsCount();
+  intptr_t PeekArgumentsTypeCount();
+  void SkipArgumentsBeforeActualArguments();
+
+  LocalVariable* LookupVariable(intptr_t kernel_offset);
+  LocalVariable* MakeTemporary();
+  Token::Kind MethodKind(const dart::String& name);
+  dart::RawFunction* LookupMethodByMember(NameIndex target,
+                                          const dart::String& method_name);
+
+  bool NeedsDebugStepCheck(const Function& function, TokenPosition position);
+  bool NeedsDebugStepCheck(Value* value, TokenPosition position);
+
+  void InlineBailout(const char* reason);
   Fragment DebugStepCheck(TokenPosition position);
   Fragment LoadLocal(LocalVariable* variable);
+  Fragment Return(TokenPosition position);
   Fragment PushArgument();
+  Fragment EvaluateAssertion();
   Fragment RethrowException(TokenPosition position, int catch_try_index);
   Fragment ThrowNoSuchMethodError();
   Fragment Constant(const Object& value);
@@ -95,27 +259,145 @@
   Fragment StaticCall(TokenPosition position,
                       const Function& target,
                       intptr_t argument_count);
+  Fragment StaticCall(TokenPosition position,
+                      const Function& target,
+                      intptr_t argument_count,
+                      const Array& argument_names);
+  Fragment InstanceCall(TokenPosition position,
+                        const dart::String& name,
+                        Token::Kind kind,
+                        intptr_t argument_count,
+                        intptr_t num_args_checked = 1);
+  Fragment InstanceCall(TokenPosition position,
+                        const dart::String& name,
+                        Token::Kind kind,
+                        intptr_t argument_count,
+                        const Array& argument_names,
+                        intptr_t num_args_checked);
+  Fragment ThrowException(TokenPosition position);
+  Fragment BooleanNegate();
+  Fragment TranslateInstantiatedTypeArguments(
+      const TypeArguments& type_arguments);
+  Fragment StrictCompare(Token::Kind kind, bool number_check = false);
+  Fragment AllocateObject(const dart::Class& klass, intptr_t argument_count);
+  Fragment StoreLocal(TokenPosition position, LocalVariable* variable);
+  Fragment StoreStaticField(TokenPosition position, const dart::Field& field);
+  Fragment StringInterpolate(TokenPosition position);
+  Fragment StringInterpolateSingle(TokenPosition position);
+  Fragment ThrowTypeError();
+  Fragment LoadInstantiatorTypeArguments();
+  Fragment LoadFunctionTypeArguments();
+  Fragment InstantiateType(const AbstractType& type);
+  Fragment CreateArray();
+  Fragment StoreIndexed(intptr_t class_id);
+  Fragment CheckStackOverflow();
+  Fragment CloneContext();
+  Fragment TranslateFinallyFinalizers(TryFinallyBlock* outer_finally,
+                                      intptr_t target_context_depth);
+  Fragment BranchIfTrue(TargetEntryInstr** then_entry,
+                        TargetEntryInstr** otherwise_entry,
+                        bool negate);
+  Fragment BranchIfEqual(TargetEntryInstr** then_entry,
+                         TargetEntryInstr** otherwise_entry,
+                         bool negate);
+  Fragment BranchIfNull(TargetEntryInstr** then_entry,
+                        TargetEntryInstr** otherwise_entry,
+                        bool negate = false);
+  Fragment CatchBlockEntry(const Array& handler_types,
+                           intptr_t handler_index,
+                           bool needs_stacktrace);
+  Fragment TryCatch(int try_handler_index);
+  Fragment Drop();
+  Fragment NullConstant();
+  JoinEntryInstr* BuildJoinEntry();
+  JoinEntryInstr* BuildJoinEntry(intptr_t try_index);
+  Fragment Goto(JoinEntryInstr* destination);
+  Fragment BuildImplicitClosureCreation(const Function& target);
+  Fragment CheckBooleanInCheckedMode();
+  Fragment CheckAssignableInCheckedMode(const dart::AbstractType& dst_type,
+                                        const dart::String& dst_name);
+  Fragment CheckVariableTypeInCheckedMode(intptr_t variable_kernel_position);
+  Fragment CheckVariableTypeInCheckedMode(const AbstractType& dst_type,
+                                          const dart::String& name_symbol);
+  Fragment EnterScope(intptr_t kernel_offset, bool* new_context = NULL);
+  Fragment ExitScope(intptr_t kernel_offset);
 
-  Fragment BuildInvalidExpression();
-  Fragment BuildStaticGet();
-  Fragment BuildSymbolLiteral();
-  Fragment BuildThisExpression();
-  Fragment BuildRethrow();
-  Fragment BuildBigIntLiteral();
-  Fragment BuildStringLiteral();
-  Fragment BuildIntLiteral(uint8_t payload);
-  Fragment BuildIntLiteral(bool is_negative);
-  Fragment BuildDoubleLiteral();
-  Fragment BuildBoolLiteral(bool value);
-  Fragment BuildNullLiteral();
+  Fragment TranslateCondition(bool* negate);
+  const TypeArguments& BuildTypeArguments();
+  Fragment BuildArguments(Array* argument_names,
+                          intptr_t* argument_count,
+                          bool skip_push_arguments = false,
+                          bool do_drop = false);
+  Fragment BuildArgumentsFromActualArguments(Array* argument_names,
+                                             bool skip_push_arguments = false,
+                                             bool do_drop = false);
+
+  Fragment BuildInvalidExpression(TokenPosition* position);
+  Fragment BuildVariableGet(TokenPosition* position);
+  Fragment BuildVariableGet(uint8_t payload, TokenPosition* position);
+  Fragment BuildVariableSet(TokenPosition* position);
+  Fragment BuildVariableSet(uint8_t payload, TokenPosition* position);
+  Fragment BuildPropertyGet(TokenPosition* position);
+  Fragment BuildPropertySet(TokenPosition* position);
+  Fragment BuildDirectPropertyGet(TokenPosition* position);
+  Fragment BuildDirectPropertySet(TokenPosition* position);
+  Fragment BuildStaticGet(TokenPosition* position);
+  Fragment BuildStaticSet(TokenPosition* position);
+  Fragment BuildMethodInvocation(TokenPosition* position);
+  Fragment BuildDirectMethodInvocation(TokenPosition* position);
+  Fragment BuildStaticInvocation(bool is_const, TokenPosition* position);
+  Fragment BuildConstructorInvocation(bool is_const, TokenPosition* position);
+  Fragment BuildNot(TokenPosition* position);
+  Fragment BuildLogicalExpression(TokenPosition* position);
+  Fragment BuildConditionalExpression(TokenPosition* position);
+  Fragment BuildStringConcatenation(TokenPosition* position);
+  Fragment BuildIsExpression(TokenPosition* position);
+  Fragment BuildAsExpression(TokenPosition* position);
+  Fragment BuildSymbolLiteral(TokenPosition* position);
+  Fragment BuildTypeLiteral(TokenPosition* position);
+  Fragment BuildThisExpression(TokenPosition* position);
+  Fragment BuildRethrow(TokenPosition* position);
+  Fragment BuildThrow(TokenPosition* position);
+  Fragment BuildListLiteral(bool is_const, TokenPosition* position);
+  Fragment BuildMapLiteral(bool is_const, TokenPosition* position);
+  Fragment BuildLet(TokenPosition* position);
+  Fragment BuildBigIntLiteral(TokenPosition* position);
+  Fragment BuildStringLiteral(TokenPosition* position);
+  Fragment BuildIntLiteral(uint8_t payload, TokenPosition* position);
+  Fragment BuildIntLiteral(bool is_negative, TokenPosition* position);
+  Fragment BuildDoubleLiteral(TokenPosition* position);
+  Fragment BuildBoolLiteral(bool value, TokenPosition* position);
+  Fragment BuildNullLiteral(TokenPosition* position);
+
+  Fragment BuildInvalidStatement();
+  Fragment BuildExpressionStatement();
+  Fragment BuildBlock();
+  Fragment BuildEmptyStatement();
+  Fragment BuildAssertStatement();
+  Fragment BuildLabeledStatement();
+  Fragment BuildBreakStatement();
+  Fragment BuildWhileStatement();
+  Fragment BuildDoStatement();
+  Fragment BuildForStatement();
+  Fragment BuildForInStatement(bool async);
+  Fragment BuildSwitchStatement();
+  Fragment BuildContinueSwitchStatement();
+  Fragment BuildIfStatement();
+  Fragment BuildReturnStatement();
+  Fragment BuildTryCatch();
+  Fragment BuildTryFinally();
+  Fragment BuildYieldStatement();
+  Fragment BuildVariableDeclaration(bool has_tag);
 
   FlowGraphBuilder* flow_graph_builder_;
   TranslationHelper& translation_helper_;
   Zone* zone_;
   Reader* reader_;
   StreamingConstantEvaluator constant_evaluator_;
+  StreamingDartTypeTranslator type_translator_;
 
   friend class StreamingConstantEvaluator;
+  friend class StreamingDartTypeTranslator;
 };
 
 
diff --git a/runtime/vm/kernel_reader.cc b/runtime/vm/kernel_reader.cc
index 458ad1b..1ddd641 100644
--- a/runtime/vm/kernel_reader.cc
+++ b/runtime/vm/kernel_reader.cc
@@ -212,11 +212,13 @@
       // to be patched.
       if (procedure != NULL) {
         // We will handle the StaticGet specially and will not use the name.
+        // Note that we pass "true" in cannot_stream to avoid trying to stream
+        // a non-existing part of the binary.
         //
         // TODO(kmillikin): we are leaking the new function body.  Find a way to
         // deallocate it.
         procedure->function()->ReplaceBody(
-            new ReturnStatement(new StaticGet(NameIndex())));
+            new ReturnStatement(new StaticGet(NameIndex(), false), false));
       }
       return library;
     }
diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc
index f5c2b83..1130320 100644
--- a/runtime/vm/kernel_to_il.cc
+++ b/runtime/vm/kernel_to_il.cc
@@ -816,186 +816,6 @@
 }
 
 
-class BreakableBlock {
- public:
-  BreakableBlock(FlowGraphBuilder* builder, LabeledStatement* statement)
-      : builder_(builder),
-        labeled_statement_(statement),
-        outer_(builder->breakable_block_),
-        destination_(NULL),
-        outer_finally_(builder->try_finally_block_),
-        context_depth_(builder->context_depth_),
-        try_index_(builder->CurrentTryIndex()) {
-    builder_->breakable_block_ = this;
-  }
-  ~BreakableBlock() { builder_->breakable_block_ = outer_; }
-
-  bool HadJumper() { return destination_ != NULL; }
-
-  JoinEntryInstr* destination() { return destination_; }
-
-  JoinEntryInstr* BreakDestination(LabeledStatement* label,
-                                   TryFinallyBlock** outer_finally,
-                                   intptr_t* context_depth) {
-    BreakableBlock* block = builder_->breakable_block_;
-    while (block->labeled_statement_ != label) {
-      block = block->outer_;
-    }
-    ASSERT(block != NULL);
-    *outer_finally = block->outer_finally_;
-    *context_depth = block->context_depth_;
-    return block->EnsureDestination();
-  }
-
- private:
-  JoinEntryInstr* EnsureDestination() {
-    if (destination_ == NULL) {
-      destination_ = builder_->BuildJoinEntry(try_index_);
-    }
-    return destination_;
-  }
-
-  FlowGraphBuilder* builder_;
-  LabeledStatement* labeled_statement_;
-  BreakableBlock* outer_;
-  JoinEntryInstr* destination_;
-  TryFinallyBlock* outer_finally_;
-  intptr_t context_depth_;
-  intptr_t try_index_;
-};
-
-
-class SwitchBlock {
- public:
-  SwitchBlock(FlowGraphBuilder* builder, SwitchStatement* switch_stmt)
-      : builder_(builder),
-        outer_(builder->switch_block_),
-        outer_finally_(builder->try_finally_block_),
-        switch_statement_(switch_stmt),
-        context_depth_(builder->context_depth_),
-        try_index_(builder->CurrentTryIndex()) {
-    builder_->switch_block_ = this;
-  }
-  ~SwitchBlock() { builder_->switch_block_ = outer_; }
-
-  bool HadJumper(SwitchCase* switch_case) {
-    return destinations_.Lookup(switch_case) != NULL;
-  }
-
-  JoinEntryInstr* Destination(SwitchCase* label,
-                              TryFinallyBlock** outer_finally = NULL,
-                              intptr_t* context_depth = NULL) {
-    // Find corresponding [SwitchStatement].
-    SwitchBlock* block = this;
-    while (true) {
-      block->EnsureSwitchCaseMapping();
-      if (block->Contains(label)) break;
-      block = block->outer_;
-    }
-
-    // Set the outer finally block.
-    if (outer_finally != NULL) {
-      *outer_finally = block->outer_finally_;
-      *context_depth = block->context_depth_;
-    }
-
-    // Ensure there's [JoinEntryInstr] for that [SwitchCase].
-    return block->EnsureDestination(label);
-  }
-
- private:
-  typedef std::set<SwitchCase*> DestinationSwitches;
-
-  JoinEntryInstr* EnsureDestination(SwitchCase* switch_case) {
-    JoinEntryInstr* cached_inst = destinations_.Lookup(switch_case);
-    if (cached_inst == NULL) {
-      JoinEntryInstr* inst = builder_->BuildJoinEntry(try_index_);
-      destinations_.Insert(switch_case, inst);
-      return inst;
-    }
-    return cached_inst;
-  }
-
-  void EnsureSwitchCaseMapping() {
-    if (destination_switches_.begin() == destination_switches_.end()) {
-      List<SwitchCase>& cases = switch_statement_->cases();
-      for (intptr_t i = 0; i < cases.length(); i++) {
-        destination_switches_.insert(cases[i]);
-      }
-    }
-  }
-
-  bool Contains(SwitchCase* sc) {
-    return destination_switches_.find(sc) != destination_switches_.end();
-  }
-
-  FlowGraphBuilder* builder_;
-  SwitchBlock* outer_;
-
-  Map<SwitchCase, JoinEntryInstr*> destinations_;
-  DestinationSwitches destination_switches_;
-
-  TryFinallyBlock* outer_finally_;
-  SwitchStatement* switch_statement_;
-  intptr_t context_depth_;
-  intptr_t try_index_;
-};
-
-
-class TryFinallyBlock {
- public:
-  TryFinallyBlock(FlowGraphBuilder* builder, Statement* finalizer)
-      : builder_(builder),
-        outer_(builder->try_finally_block_),
-        finalizer_(finalizer),
-        context_depth_(builder->context_depth_),
-        // Finalizers are executed outside of the try block hence
-        // try depth of finalizers are one less than current try
-        // depth.
-        try_depth_(builder->try_depth_ - 1),
-        try_index_(builder_->CurrentTryIndex()) {
-    builder_->try_finally_block_ = this;
-  }
-  ~TryFinallyBlock() { builder_->try_finally_block_ = outer_; }
-
-  Statement* finalizer() const { return finalizer_; }
-  intptr_t context_depth() const { return context_depth_; }
-  intptr_t try_depth() const { return try_depth_; }
-  intptr_t try_index() const { return try_index_; }
-  TryFinallyBlock* outer() const { return outer_; }
-
- private:
-  FlowGraphBuilder* const builder_;
-  TryFinallyBlock* const outer_;
-  Statement* const finalizer_;
-  const intptr_t context_depth_;
-  const intptr_t try_depth_;
-  const intptr_t try_index_;
-};
-
-
-class TryCatchBlock {
- public:
-  explicit TryCatchBlock(FlowGraphBuilder* builder,
-                         intptr_t try_handler_index = -1)
-      : builder_(builder),
-        outer_(builder->try_catch_block_),
-        try_index_(try_handler_index) {
-    if (try_index_ == -1) try_index_ = builder->AllocateTryIndex();
-    builder->try_catch_block_ = this;
-  }
-  ~TryCatchBlock() { builder_->try_catch_block_ = outer_; }
-
-  intptr_t try_index() { return try_index_; }
-  TryCatchBlock* outer() const { return outer_; }
-
- private:
-  FlowGraphBuilder* builder_;
-  TryCatchBlock* outer_;
-  intptr_t try_index_;
-};
-
-
 Fragment& Fragment::operator+=(const Fragment& other) {
   if (entry == NULL) {
     entry = other.entry;
@@ -2271,11 +2091,17 @@
     }
 
     Statement* finalizer = try_finally_block_->finalizer();
+    intptr_t finalizer_kernel_offset =
+        try_finally_block_->finalizer_kernel_offset();
     try_finally_block_ = try_finally_block_->outer();
-
-    // This will potentially have exceptional cases as described in
-    // [VisitTryFinally] and will handle them.
-    instructions += TranslateStatement(finalizer);
+    if (finalizer != NULL) {
+      // This will potentially have exceptional cases as described in
+      // [VisitTryFinally] and will handle them.
+      instructions += TranslateStatement(finalizer);
+    } else {
+      instructions += streaming_flow_graph_builder_->BuildStatementAt(
+          finalizer_kernel_offset);
+    }
 
     // We only need to make sure that if the finalizer ended normally, we
     // continue towards the next outer try-finally.
@@ -2299,9 +2125,15 @@
 
 
 Fragment FlowGraphBuilder::EnterScope(TreeNode* node, bool* new_context) {
+  return EnterScope(node->kernel_offset(), new_context);
+}
+
+
+Fragment FlowGraphBuilder::EnterScope(intptr_t kernel_offset,
+                                      bool* new_context) {
   Fragment instructions;
   const intptr_t context_size =
-      scopes_->scopes.Lookup(node->kernel_offset())->num_context_variables();
+      scopes_->scopes.Lookup(kernel_offset)->num_context_variables();
   if (context_size > 0) {
     instructions += PushContext(context_size);
     instructions += Drop();
@@ -2314,9 +2146,14 @@
 
 
 Fragment FlowGraphBuilder::ExitScope(TreeNode* node) {
+  return ExitScope(node->kernel_offset());
+}
+
+
+Fragment FlowGraphBuilder::ExitScope(intptr_t kernel_offset) {
   Fragment instructions;
   const intptr_t context_size =
-      scopes_->scopes.Lookup(node->kernel_offset())->num_context_variables();
+      scopes_->scopes.Lookup(kernel_offset)->num_context_variables();
   if (context_size > 0) {
     instructions += PopContext();
   }
@@ -3193,6 +3030,13 @@
 }
 
 
+dart::LocalVariable* FlowGraphBuilder::LookupVariable(intptr_t kernel_offset) {
+  LocalVariable* local = scopes_->locals.Lookup(kernel_offset);
+  ASSERT(local != NULL);
+  return local;
+}
+
+
 void FlowGraphBuilder::SetTempIndex(Definition* definition) {
   definition->set_temp_index(
       stack_ == NULL ? 0 : stack_->definition()->temp_index() + 1);
@@ -3988,6 +3832,18 @@
   return Fragment();
 }
 
+Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode(
+    const AbstractType& dst_type,
+    const dart::String& name_symbol) {
+  if (I->type_checks()) {
+    if (dst_type.IsMalformed()) {
+      return ThrowTypeError();
+    }
+    return CheckAssignableInCheckedMode(dst_type, name_symbol);
+  }
+  return Fragment();
+}
+
 
 bool FlowGraphBuilder::NeedsDebugStepCheck(const Function& function,
                                            TokenPosition position) {
@@ -4541,7 +4397,15 @@
 #ifdef DEBUG
   intptr_t original_context_depth = context_depth_;
 #endif
-  statement->AcceptStatementVisitor(this);
+
+  // TODO(jensj): VariableDeclaration doesn't necessarily have a tag.
+  if (statement->can_stream() &&
+      statement->Type() != Node::kTypeVariableDeclaration) {
+    fragment_ = streaming_flow_graph_builder_->BuildStatementAt(
+        statement->kernel_offset());
+  } else {
+    statement->AcceptStatementVisitor(this);
+  }
   DEBUG_ASSERT(context_depth_ == original_context_depth);
   return fragment_;
 }
@@ -4562,7 +4426,12 @@
 
 
 Fragment FlowGraphBuilder::TranslateExpression(Expression* expression) {
-  expression->AcceptExpressionVisitor(this);
+  if (expression->can_stream()) {
+    fragment_ = streaming_flow_graph_builder_->BuildExpressionAt(
+        expression->kernel_offset());
+  } else {
+    expression->AcceptExpressionVisitor(this);
+  }
   return fragment_;
 }
 
@@ -4583,43 +4452,59 @@
 }
 
 
+#define STREAM_EXPRESSION_IF_POSSIBLE(node)                                    \
+  if (node->can_stream()) {                                                    \
+    fragment_ = streaming_flow_graph_builder_->BuildExpressionAt(              \
+        node->kernel_offset());                                                \
+    return;                                                                    \
+  }
+
+
 void FlowGraphBuilder::VisitInvalidExpression(InvalidExpression* node) {
-  fragment_ = streaming_flow_graph_builder_->BuildAt(node->kernel_offset());
+  fragment_ =
+      streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitNullLiteral(NullLiteral* node) {
-  fragment_ = streaming_flow_graph_builder_->BuildAt(node->kernel_offset());
+  fragment_ =
+      streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitBoolLiteral(BoolLiteral* node) {
-  fragment_ = streaming_flow_graph_builder_->BuildAt(node->kernel_offset());
+  fragment_ =
+      streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitIntLiteral(IntLiteral* node) {
-  fragment_ = streaming_flow_graph_builder_->BuildAt(node->kernel_offset());
+  fragment_ =
+      streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitBigintLiteral(BigintLiteral* node) {
-  fragment_ = streaming_flow_graph_builder_->BuildAt(node->kernel_offset());
+  fragment_ =
+      streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitDoubleLiteral(DoubleLiteral* node) {
-  fragment_ = streaming_flow_graph_builder_->BuildAt(node->kernel_offset());
+  fragment_ =
+      streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitStringLiteral(StringLiteral* node) {
-  fragment_ = streaming_flow_graph_builder_->BuildAt(node->kernel_offset());
+  fragment_ =
+      streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitSymbolLiteral(SymbolLiteral* node) {
-  fragment_ = streaming_flow_graph_builder_->BuildAt(node->kernel_offset());
+  fragment_ =
+      streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
 }
 
 
@@ -4922,8 +4807,9 @@
   return type;
 }
 
-
 void FlowGraphBuilder::VisitTypeLiteral(TypeLiteral* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   const AbstractType& type = T.TranslateType(node->type());
   if (type.IsMalformed()) H.ReportError("Malformed type literal");
 
@@ -4948,11 +4834,14 @@
 
 
 void FlowGraphBuilder::VisitVariableGet(VariableGet* node) {
-  fragment_ = LoadLocal(LookupVariable(node->variable()));
+  fragment_ =
+      streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitVariableSet(VariableSet* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   Fragment instructions = TranslateExpression(node->expression());
   if (NeedsDebugStepCheck(stack_, node->position())) {
     instructions = DebugStepCheck(node->position()) + instructions;
@@ -4965,10 +4854,8 @@
 
 
 void FlowGraphBuilder::VisitStaticGet(StaticGet* node) {
-  if (node->kernel_offset() != -1) {
-    fragment_ = streaming_flow_graph_builder_->BuildAt(node->kernel_offset());
-    return;
-  }
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   // A StaticGet will always have a kernel_offset, except for the StaticGet that
   // was manually created for _getMainClosure in dart:_builtin.  Compile that
   // one specially here.
@@ -4998,6 +4885,8 @@
 
 
 void FlowGraphBuilder::VisitStaticSet(StaticSet* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   NameIndex target = node->target();
   if (H.IsField(target)) {
     const dart::Field& field =
@@ -5035,6 +4924,8 @@
 
 
 void FlowGraphBuilder::VisitPropertyGet(PropertyGet* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   Fragment instructions = TranslateExpression(node->receiver());
   instructions += PushArgument();
   const dart::String& getter_name = H.DartGetterName(node->name());
@@ -5044,6 +4935,8 @@
 
 
 void FlowGraphBuilder::VisitPropertySet(PropertySet* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   Fragment instructions(NullConstant());
   LocalVariable* variable = MakeTemporary();
   instructions += TranslateExpression(node->receiver());
@@ -5059,6 +4952,8 @@
 
 
 void FlowGraphBuilder::VisitDirectPropertyGet(DirectPropertyGet* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   Function& target = Function::ZoneHandle(Z);
   NameIndex kernel_name = node->target();
   if (H.IsProcedure(kernel_name)) {
@@ -5085,6 +4980,8 @@
 
 
 void FlowGraphBuilder::VisitDirectPropertySet(DirectPropertySet* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   const dart::String& method_name = H.DartSetterName(node->target());
   const Function& target = Function::ZoneHandle(
       Z, LookupMethodByMember(node->target(), method_name));
@@ -5104,6 +5001,8 @@
 
 
 void FlowGraphBuilder::VisitStaticInvocation(StaticInvocation* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   const Function& target = Function::ZoneHandle(
       Z, H.LookupStaticMethodByKernelProcedure(node->procedure()));
   const dart::Class& klass = dart::Class::ZoneHandle(Z, target.Owner());
@@ -5223,6 +5122,8 @@
 
 
 void FlowGraphBuilder::VisitMethodInvocation(MethodInvocation* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   const dart::String& name = H.DartMethodName(node->name());
   const intptr_t argument_count = node->arguments()->count() + 1;
   const Token::Kind token_kind = MethodKind(name);
@@ -5277,6 +5178,8 @@
 
 void FlowGraphBuilder::VisitDirectMethodInvocation(
     DirectMethodInvocation* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   const dart::String& method_name = H.DartProcedureName(node->target());
   const Token::Kind token_kind = MethodKind(method_name);
 
@@ -5298,6 +5201,8 @@
 
 
 void FlowGraphBuilder::VisitConstructorInvocation(ConstructorInvocation* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   if (node->is_const()) {
     fragment_ =
         Constant(constant_evaluator_.EvaluateConstructorInvocation(node));
@@ -5386,6 +5291,8 @@
 
 
 void FlowGraphBuilder::VisitIsExpression(IsExpression* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   Fragment instructions = TranslateExpression(node->operand());
 
   // The VM does not like an instanceOf call with a dynamic type. We need to
@@ -5449,6 +5356,8 @@
 
 
 void FlowGraphBuilder::VisitAsExpression(AsExpression* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   Fragment instructions = TranslateExpression(node->operand());
 
   // The VM does not like an Object_as call with a dynamic type. We need to
@@ -5496,6 +5405,8 @@
 
 
 void FlowGraphBuilder::VisitConditionalExpression(ConditionalExpression* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   bool negate;
   Fragment instructions = TranslateCondition(node->condition(), &negate);
 
@@ -5528,6 +5439,8 @@
 
 
 void FlowGraphBuilder::VisitLogicalExpression(LogicalExpression* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   bool negate;
   Fragment instructions = TranslateCondition(node->left(), &negate);
   TargetEntryInstr* right_entry;
@@ -5567,6 +5480,8 @@
 
 
 void FlowGraphBuilder::VisitNot(Not* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   Fragment instructions = TranslateExpression(node->expression());
   instructions += CheckBooleanInCheckedMode();
   instructions += BooleanNegate();
@@ -5575,11 +5490,14 @@
 
 
 void FlowGraphBuilder::VisitThisExpression(ThisExpression* node) {
-  fragment_ = streaming_flow_graph_builder_->BuildAt(node->kernel_offset());
+  fragment_ =
+      streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitStringConcatenation(StringConcatenation* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   List<Expression>& expressions = node->expressions();
 
   Fragment instructions;
@@ -5609,6 +5527,8 @@
 
 
 void FlowGraphBuilder::VisitListLiteral(ListLiteral* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   if (node->is_const()) {
     fragment_ = Constant(constant_evaluator_.EvaluateListLiteral(node));
     return;
@@ -5650,6 +5570,8 @@
 
 
 void FlowGraphBuilder::VisitMapLiteral(MapLiteral* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   if (node->is_const()) {
     fragment_ = Constant(constant_evaluator_.EvaluateMapLiteral(node));
     return;
@@ -5706,6 +5628,8 @@
 
 
 void FlowGraphBuilder::VisitLet(Let* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   Fragment instructions = TranslateStatement(node->variable());
   instructions += TranslateExpression(node->body());
   fragment_ = instructions;
@@ -5713,6 +5637,8 @@
 
 
 void FlowGraphBuilder::VisitThrow(Throw* node) {
+  STREAM_EXPRESSION_IF_POSSIBLE(node);
+
   Fragment instructions;
 
   instructions += TranslateExpression(node->expression());
@@ -5728,7 +5654,8 @@
 
 
 void FlowGraphBuilder::VisitRethrow(Rethrow* node) {
-  fragment_ = streaming_flow_graph_builder_->BuildAt(node->kernel_offset());
+  fragment_ =
+      streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset());
 }
 
 
@@ -5754,18 +5681,29 @@
   return instructions;
 }
 
+#define STREAM_STATEMENT_IF_POSSIBLE(node)                                     \
+  if (node->can_stream()) {                                                    \
+    fragment_ = streaming_flow_graph_builder_->BuildStatementAt(               \
+        node->kernel_offset());                                                \
+    return;                                                                    \
+  }
+
 
 void FlowGraphBuilder::VisitInvalidStatement(InvalidStatement* node) {
-  H.ReportError("Invalid statements not implemented yet!");
+  fragment_ =
+      streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* node) {
-  fragment_ = Fragment();
+  fragment_ =
+      streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitBlock(Block* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   Fragment instructions;
 
   instructions += EnterScope(node);
@@ -5781,6 +5719,8 @@
 
 
 void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   bool inside_try_finally = try_finally_block_ != NULL;
 
   Fragment instructions = node->expression() == NULL
@@ -5812,6 +5752,8 @@
 
 
 void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   Fragment instructions = TranslateExpression(node->expression());
   instructions += Drop();
   fragment_ = instructions;
@@ -5860,6 +5802,8 @@
 
 
 void FlowGraphBuilder::VisitIfStatement(IfStatement* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   bool negate;
   Fragment instructions = TranslateCondition(node->condition(), &negate);
   TargetEntryInstr* then_entry;
@@ -5890,6 +5834,8 @@
 
 
 void FlowGraphBuilder::VisitWhileStatement(WhileStatement* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   ++loop_depth_;
   bool negate;
   Fragment condition = TranslateCondition(node->condition(), &negate);
@@ -5920,6 +5866,8 @@
 
 
 void FlowGraphBuilder::VisitDoStatement(DoStatement* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   ++loop_depth_;
   Fragment body = TranslateStatement(node->body());
 
@@ -5948,6 +5896,8 @@
 
 
 void FlowGraphBuilder::VisitForStatement(ForStatement* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   Fragment declarations;
 
   bool new_context = false;
@@ -6004,6 +5954,8 @@
 
 
 void FlowGraphBuilder::VisitForInStatement(ForInStatement* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   Fragment instructions = TranslateExpression(node->iterable());
   instructions += PushArgument();
 
@@ -6057,6 +6009,8 @@
 
 
 void FlowGraphBuilder::VisitLabeledStatement(LabeledStatement* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   // There can be serveral cases:
   //
   //   * the body contains a break
@@ -6068,7 +6022,7 @@
   // => We will only know which case we are in after the body has been
   //    traversed.
 
-  BreakableBlock block(this, node);
+  BreakableBlock block(this);
   Fragment instructions = TranslateStatement(node->body());
   if (block.HadJumper()) {
     if (instructions.is_open()) {
@@ -6082,26 +6036,15 @@
 
 
 void FlowGraphBuilder::VisitBreakStatement(BreakStatement* node) {
-  TryFinallyBlock* outer_finally = NULL;
-  intptr_t target_context_depth = -1;
-  JoinEntryInstr* destination = breakable_block_->BreakDestination(
-      node->target(), &outer_finally, &target_context_depth);
-
-  Fragment instructions;
-  instructions +=
-      TranslateFinallyFinalizers(outer_finally, target_context_depth);
-  if (instructions.is_open()) {
-    if (NeedsDebugStepCheck(parsed_function_->function(), node->position())) {
-      instructions += DebugStepCheck(node->position());
-    }
-    instructions += Goto(destination);
-  }
-  fragment_ = instructions;
+  fragment_ =
+      streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* node) {
-  SwitchBlock block(this, node);
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
+  SwitchBlock block(this, node->cases().length());
 
   // Instead of using a variable we should reuse the expression on the stack,
   // since it won't be assigned again, we don't need phi nodes.
@@ -6179,7 +6122,7 @@
     // from `a == expr` and one from `a != expr && b == expr`). The
     // `block.Destination()` records the additional jump.
     if (switch_case->expressions().length() > 1) {
-      block.Destination(switch_case);
+      block.DestinationDirect(i);
     }
   }
 
@@ -6199,10 +6142,10 @@
         constant_evaluator_.EvaluateExpression(switch_case->expressions()[k]);
       }
 
-      if (block.HadJumper(switch_case)) {
+      if (block.HadJumper(i)) {
         // There are several branches to the body, so we will make a goto to
         // the join block (and prepend a join instruction to the real body).
-        JoinEntryInstr* join = block.Destination(switch_case);
+        JoinEntryInstr* join = block.DestinationDirect(i);
         current_instructions += Goto(join);
 
         current_instructions = Fragment(current_instructions.entry, join);
@@ -6212,8 +6155,8 @@
       }
     } else {
       JoinEntryInstr* body_join = NULL;
-      if (block.HadJumper(switch_case)) {
-        body_join = block.Destination(switch_case);
+      if (block.HadJumper(i)) {
+        body_join = block.DestinationDirect(i);
         body_fragments[i] = Fragment(body_join) + body_fragments[i];
       }
 
@@ -6285,22 +6228,14 @@
 
 void FlowGraphBuilder::VisitContinueSwitchStatement(
     ContinueSwitchStatement* node) {
-  TryFinallyBlock* outer_finally = NULL;
-  intptr_t target_context_depth = -1;
-  JoinEntryInstr* entry = switch_block_->Destination(
-      node->target(), &outer_finally, &target_context_depth);
-
-  Fragment instructions;
-  instructions +=
-      TranslateFinallyFinalizers(outer_finally, target_context_depth);
-  if (instructions.is_open()) {
-    instructions += Goto(entry);
-  }
-  fragment_ = instructions;
+  fragment_ =
+      streaming_flow_graph_builder_->BuildStatementAt(node->kernel_offset());
 }
 
 
 void FlowGraphBuilder::VisitAssertStatement(AssertStatement* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   if (!I->asserts()) {
     fragment_ = Fragment();
     return;
@@ -6376,6 +6311,8 @@
 
 
 void FlowGraphBuilder::VisitTryFinally(TryFinally* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   InlineBailout("kernel::FlowgraphBuilder::VisitTryFinally");
 
   // There are 5 different cases where we need to execute the finally block:
@@ -6407,7 +6344,7 @@
   // Fill in the body of the try.
   ++try_depth_;
   {
-    TryFinallyBlock tfb(this, node->finalizer());
+    TryFinallyBlock tfb(this, node->finalizer(), -1);
     TryCatchBlock tcb(this, try_handler_index);
     try_body += TranslateStatement(node->body());
   }
@@ -6450,6 +6387,8 @@
 
 
 void FlowGraphBuilder::VisitTryCatch(class TryCatch* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch");
 
   intptr_t try_handler_index = AllocateTryIndex();
@@ -6569,6 +6508,8 @@
 
 
 void FlowGraphBuilder::VisitYieldStatement(YieldStatement* node) {
+  STREAM_STATEMENT_IF_POSSIBLE(node);
+
   ASSERT(node->is_native());  // Must have been desugared.
   // Setup yield/continue point:
   //
diff --git a/runtime/vm/kernel_to_il.h b/runtime/vm/kernel_to_il.h
index 524a13a..ae0db18 100644
--- a/runtime/vm/kernel_to_il.h
+++ b/runtime/vm/kernel_to_il.h
@@ -347,9 +347,11 @@
 
   const dart::String& DartSetterName(NameIndex setter);
   const dart::String& DartSetterName(Name* setter_name);
+  const dart::String& DartSetterName(NameIndex parent, StringIndex setter);
 
   const dart::String& DartGetterName(NameIndex getter);
   const dart::String& DartGetterName(Name* getter_name);
+  const dart::String& DartGetterName(NameIndex parent, StringIndex getter);
 
   const dart::String& DartFieldName(Name* kernel_name);
 
@@ -357,6 +359,7 @@
 
   const dart::String& DartMethodName(NameIndex method);
   const dart::String& DartMethodName(Name* method_name);
+  const dart::String& DartMethodName(NameIndex parent, StringIndex method);
 
   const dart::String& DartFactoryName(NameIndex factory);
 
@@ -389,9 +392,6 @@
                                   dart::String* name_to_modify,
                                   bool symbolize = true);
 
-  const dart::String& DartSetterName(NameIndex parent, StringIndex setter);
-  const dart::String& DartGetterName(NameIndex parent, StringIndex getter);
-  const dart::String& DartMethodName(NameIndex parent, StringIndex method);
 
   Thread* thread_;
   Zone* zone_;
@@ -770,6 +770,17 @@
   bool needs_expr_temp_;
 };
 
+struct YieldContinuation {
+  Instruction* entry;
+  intptr_t try_index;
+
+  YieldContinuation(Instruction* entry, intptr_t try_index)
+      : entry(entry), try_index(try_index) {}
+
+  YieldContinuation()
+      : entry(NULL), try_index(CatchClauseNode::kInvalidTryIndex) {}
+};
+
 class FlowGraphBuilder : public ExpressionVisitor, public StatementVisitor {
  public:
   FlowGraphBuilder(TreeNode* node,
@@ -880,7 +891,9 @@
   Fragment TranslateFunctionNode(FunctionNode* node, TreeNode* parent);
 
   Fragment EnterScope(TreeNode* node, bool* new_context = NULL);
+  Fragment EnterScope(intptr_t kernel_offset, bool* new_context = NULL);
   Fragment ExitScope(TreeNode* node);
+  Fragment ExitScope(intptr_t kernel_offset);
 
   Fragment LoadContextAt(int depth);
   Fragment AdjustContextTo(int depth);
@@ -983,6 +996,8 @@
   Fragment EvaluateAssertion();
   Fragment CheckReturnTypeInCheckedMode();
   Fragment CheckVariableTypeInCheckedMode(VariableDeclaration* variable);
+  Fragment CheckVariableTypeInCheckedMode(const AbstractType& dst_type,
+                                          const dart::String& name_symbol);
   Fragment CheckBooleanInCheckedMode();
   Fragment CheckAssignableInCheckedMode(const dart::AbstractType& dst_type,
                                         const dart::String& dst_name);
@@ -1012,6 +1027,7 @@
                     LocalVariable* variable,
                     intptr_t pos);
   dart::LocalVariable* LookupVariable(VariableDeclaration* var);
+  dart::LocalVariable* LookupVariable(intptr_t kernel_offset);
 
   void SetTempIndex(Definition* definition);
 
@@ -1056,17 +1072,6 @@
 
   ScopeBuildingResult* scopes_;
 
-  struct YieldContinuation {
-    Instruction* entry;
-    intptr_t try_index;
-
-    YieldContinuation(Instruction* entry, intptr_t try_index)
-        : entry(entry), try_index(try_index) {}
-
-    YieldContinuation()
-        : entry(NULL), try_index(CatchClauseNode::kInvalidTryIndex) {}
-  };
-
   GrowableArray<YieldContinuation> yield_continuations_;
 
   LocalVariable* CurrentException() {
@@ -1119,6 +1124,199 @@
 };
 
 
+class SwitchBlock {
+ public:
+  SwitchBlock(FlowGraphBuilder* builder, intptr_t num_cases)
+      : builder_(builder),
+        outer_(builder->switch_block_),
+        outer_finally_(builder->try_finally_block_),
+        num_cases_(num_cases),
+        context_depth_(builder->context_depth_),
+        try_index_(builder->CurrentTryIndex()) {
+    builder_->switch_block_ = this;
+    if (outer_ != NULL) {
+      depth_ = outer_->depth_ + outer_->num_cases_;
+    } else {
+      depth_ = 0;
+    }
+  }
+  ~SwitchBlock() { builder_->switch_block_ = outer_; }
+
+  bool HadJumper(intptr_t case_num) {
+    return destinations_.Lookup(case_num) != NULL;
+  }
+
+  // Get destination via absolute target number (i.e. the correct destination
+  // is not not necessarily in this block.
+  JoinEntryInstr* Destination(intptr_t target_index,
+                              TryFinallyBlock** outer_finally = NULL,
+                              intptr_t* context_depth = NULL) {
+    // Find corresponding [SwitchStatement].
+    SwitchBlock* block = this;
+    while (block->depth_ > target_index) {
+      block = block->outer_;
+    }
+
+    // Set the outer finally block.
+    if (outer_finally != NULL) {
+      *outer_finally = block->outer_finally_;
+      *context_depth = block->context_depth_;
+    }
+
+    // Ensure there's [JoinEntryInstr] for that [SwitchCase].
+    return block->EnsureDestination(target_index - block->depth_);
+  }
+
+  // Get destination via relative target number (i.e. relative to this block,
+  // 0 is first case in this block etc).
+  JoinEntryInstr* DestinationDirect(intptr_t case_num,
+                                    TryFinallyBlock** outer_finally = NULL,
+                                    intptr_t* context_depth = NULL) {
+    // Set the outer finally block.
+    if (outer_finally != NULL) {
+      *outer_finally = outer_finally_;
+      *context_depth = context_depth_;
+    }
+
+    // Ensure there's [JoinEntryInstr] for that [SwitchCase].
+    return EnsureDestination(case_num);
+  }
+
+ private:
+  JoinEntryInstr* EnsureDestination(intptr_t case_num) {
+    JoinEntryInstr* cached_inst = destinations_.Lookup(case_num);
+    if (cached_inst == NULL) {
+      JoinEntryInstr* inst = builder_->BuildJoinEntry(try_index_);
+      destinations_.Insert(case_num, inst);
+      return inst;
+    }
+    return cached_inst;
+  }
+
+  FlowGraphBuilder* builder_;
+  SwitchBlock* outer_;
+
+  IntMap<JoinEntryInstr*> destinations_;
+
+  TryFinallyBlock* outer_finally_;
+  intptr_t num_cases_;
+  intptr_t depth_;
+  intptr_t context_depth_;
+  intptr_t try_index_;
+};
+
+
+class TryCatchBlock {
+ public:
+  explicit TryCatchBlock(FlowGraphBuilder* builder,
+                         intptr_t try_handler_index = -1)
+      : builder_(builder),
+        outer_(builder->try_catch_block_),
+        try_index_(try_handler_index) {
+    if (try_index_ == -1) try_index_ = builder->AllocateTryIndex();
+    builder->try_catch_block_ = this;
+  }
+  ~TryCatchBlock() { builder_->try_catch_block_ = outer_; }
+
+  intptr_t try_index() { return try_index_; }
+  TryCatchBlock* outer() const { return outer_; }
+
+ private:
+  FlowGraphBuilder* builder_;
+  TryCatchBlock* outer_;
+  intptr_t try_index_;
+};
+
+
+class TryFinallyBlock {
+ public:
+  TryFinallyBlock(FlowGraphBuilder* builder,
+                  Statement* finalizer,
+                  intptr_t finalizer_kernel_offset)
+      : builder_(builder),
+        outer_(builder->try_finally_block_),
+        finalizer_(finalizer),
+        finalizer_kernel_offset_(finalizer_kernel_offset),
+        context_depth_(builder->context_depth_),
+        // Finalizers are executed outside of the try block hence
+        // try depth of finalizers are one less than current try
+        // depth.
+        try_depth_(builder->try_depth_ - 1),
+        try_index_(builder_->CurrentTryIndex()) {
+    builder_->try_finally_block_ = this;
+  }
+  ~TryFinallyBlock() { builder_->try_finally_block_ = outer_; }
+
+  Statement* finalizer() const { return finalizer_; }
+  intptr_t finalizer_kernel_offset() const { return finalizer_kernel_offset_; }
+  intptr_t context_depth() const { return context_depth_; }
+  intptr_t try_depth() const { return try_depth_; }
+  intptr_t try_index() const { return try_index_; }
+  TryFinallyBlock* outer() const { return outer_; }
+
+ private:
+  FlowGraphBuilder* const builder_;
+  TryFinallyBlock* const outer_;
+  Statement* const finalizer_;
+  intptr_t finalizer_kernel_offset_;
+  const intptr_t context_depth_;
+  const intptr_t try_depth_;
+  const intptr_t try_index_;
+};
+
+
+class BreakableBlock {
+ public:
+  explicit BreakableBlock(FlowGraphBuilder* builder)
+      : builder_(builder),
+        outer_(builder->breakable_block_),
+        destination_(NULL),
+        outer_finally_(builder->try_finally_block_),
+        context_depth_(builder->context_depth_),
+        try_index_(builder->CurrentTryIndex()) {
+    if (builder_->breakable_block_ == NULL) {
+      index_ = 0;
+    } else {
+      index_ = builder_->breakable_block_->index_ + 1;
+    }
+    builder_->breakable_block_ = this;
+  }
+  ~BreakableBlock() { builder_->breakable_block_ = outer_; }
+
+  bool HadJumper() { return destination_ != NULL; }
+
+  JoinEntryInstr* destination() { return destination_; }
+
+  JoinEntryInstr* BreakDestination(intptr_t label_index,
+                                   TryFinallyBlock** outer_finally,
+                                   intptr_t* context_depth) {
+    BreakableBlock* block = builder_->breakable_block_;
+    while (block->index_ != label_index) {
+      block = block->outer_;
+    }
+    ASSERT(block != NULL);
+    *outer_finally = block->outer_finally_;
+    *context_depth = block->context_depth_;
+    return block->EnsureDestination();
+  }
+
+ private:
+  JoinEntryInstr* EnsureDestination() {
+    if (destination_ == NULL) {
+      destination_ = builder_->BuildJoinEntry(try_index_);
+    }
+    return destination_;
+  }
+
+  FlowGraphBuilder* builder_;
+  intptr_t index_;
+  BreakableBlock* outer_;
+  JoinEntryInstr* destination_;
+  TryFinallyBlock* outer_finally_;
+  intptr_t context_depth_;
+  intptr_t try_index_;
+};
+
 class CatchBlock {
  public:
   CatchBlock(FlowGraphBuilder* builder,