[vm/bytecode] Revise representation of objects and strings in bytecode

This is a major revamp of bytecode metadata format. Now bytecode has
its own serialization mechanisms.

This CL adds 'bytecode component' metadata, which contains bytecode
object table and string table. All references from bytecode (constant
pools) to libraries, classes, members, types and strings now have a new
format. References to frequently used objects are represented as indices
in object table, while rarely used objects are written inline.
This allows VM to cache frequently used objects while reading bytecode.

Representation of strings is aligned with VM - string characters are
stored in separate pools of one-byte and two-byte strings. This allows
VM to avoid UTF-8 decoding and extra copying.

Closure declarations are now explicit. Type parameters no longer require
enslosing scopes when reading/writing them.

Benchmarks:
GenKernelKernelReadAllBytecode (Intel Core i5) +29.84%
GenKernelKernelReadAllBytecode (Intel Xeon) +28.74%
Change-Id: I4b80009733a8f8c038264af74f97c4e094b9e311
Reviewed-on: https://dart-review.googlesource.com/c/85469
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 56152ba..b39a376 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -625,6 +625,8 @@
     _byteOffset = index.binaryOffsetForStringTable; // Read backwards.
     _readMetadataMappings(component, index.binaryOffsetForMetadataPayloads);
 
+    _associateMetadata(component, _componentStartOffset);
+
     _byteOffset = index.binaryOffsetForSourceTable;
     Map<Uri, Source> uriToSource = readUriToSource();
     component.uriToSource.addAll(uriToSource);
@@ -642,8 +644,6 @@
         getMemberReferenceFromInt(index.mainMethodReference, allowNull: true);
     component.mainMethodName ??= mainMethod;
 
-    _associateMetadata(component, _componentStartOffset);
-
     _byteOffset = _componentStartOffset + componentFileSize;
   }
 
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index 6c8a75a..5e19c6e 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -413,6 +413,9 @@
     writeSpaced('=');
     inner.writeMemberReferenceFromReference(component.mainMethodName);
     endLine(';');
+    if (showMetadata) {
+      inner.writeMetadata(component);
+    }
     for (var library in component.libraries) {
       if (library.isExternal) {
         if (!showExternal) {
diff --git a/pkg/vm/lib/bytecode/bytecode_serialization.dart b/pkg/vm/lib/bytecode/bytecode_serialization.dart
new file mode 100644
index 0000000..a592981
--- /dev/null
+++ b/pkg/vm/lib/bytecode/bytecode_serialization.dart
@@ -0,0 +1,360 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library vm.bytecode.bytecode_serialization;
+
+import 'dart:io' show BytesBuilder;
+import 'dart:typed_data' show Uint8List, Uint16List;
+
+abstract class StringWriter {
+  int put(String string);
+}
+
+abstract class StringReader {
+  String get(int ref);
+}
+
+abstract class BytecodeObject {}
+
+abstract class ObjectWriter {
+  void writeObject(BytecodeObject object, BufferedWriter writer);
+}
+
+abstract class ObjectReader {
+  BytecodeObject readObject(BufferedReader reader);
+}
+
+class BufferedWriter {
+  final int formatVersion;
+  final StringWriter stringWriter;
+  final ObjectWriter objectWriter;
+  final BytesBuilder bytes = new BytesBuilder();
+  final int baseOffset;
+
+  BufferedWriter(this.formatVersion, this.stringWriter, this.objectWriter,
+      {this.baseOffset: 0});
+
+  factory BufferedWriter.fromWriter(BufferedWriter writer) =>
+      new BufferedWriter(
+          writer.formatVersion, writer.stringWriter, writer.objectWriter);
+
+  List<int> takeBytes() => bytes.takeBytes();
+
+  int get offset => bytes.length;
+
+  void writeByte(int value) {
+    assert((value >> 8) == 0);
+    bytes.addByte(value);
+  }
+
+  void writeBytes(List<int> values) {
+    bytes.add(values);
+  }
+
+  void writeUInt32(int value) {
+    if ((value >> 32) != 0) {
+      throw 'Unable to write $value as 32-bit unsigned integer';
+    }
+    // TODO(alexmarkov): consider using native byte order
+    bytes.addByte((value >> 24) & 0xFF);
+    bytes.addByte((value >> 16) & 0xFF);
+    bytes.addByte((value >> 8) & 0xFF);
+    bytes.addByte(value & 0xFF);
+  }
+
+  void writePackedUInt30(int value) {
+    if ((value >> 30) != 0) {
+      throw 'Unable to write $value as 30-bit unsigned integer';
+    }
+    if (value < 0x80) {
+      bytes.addByte(value);
+    } else if (value < 0x4000) {
+      bytes.addByte((value >> 8) | 0x80);
+      bytes.addByte(value & 0xFF);
+    } else {
+      bytes.addByte((value >> 24) | 0xC0);
+      bytes.addByte((value >> 16) & 0xFF);
+      bytes.addByte((value >> 8) & 0xFF);
+      bytes.addByte(value & 0xFF);
+    }
+  }
+
+  void writeSLEB128(int value) {
+    bool last = false;
+    do {
+      int part = value & 0x7f;
+      value >>= 7;
+      if ((value == 0 && (part & 0x40) == 0) ||
+          (value == -1 && (part & 0x40) != 0)) {
+        last = true;
+      } else {
+        part |= 0x80;
+      }
+      bytes.addByte(part);
+    } while (!last);
+  }
+
+  void writePackedStringReference(String value) {
+    writePackedUInt30(stringWriter.put(value));
+  }
+
+  void writePackedObject(BytecodeObject object) {
+    objectWriter.writeObject(object, this);
+  }
+
+  void writePackedList(List<BytecodeObject> objects) {
+    writePackedUInt30(objects.length);
+    for (var obj in objects) {
+      writePackedObject(obj);
+    }
+  }
+
+  void align(int alignment) {
+    assert(alignment & (alignment - 1) == 0);
+    int offs = baseOffset + offset;
+    int padding = ((offs + alignment - 1) & -alignment) - offs;
+    for (int i = 0; i < padding; ++i) {
+      bytes.addByte(0);
+    }
+  }
+}
+
+class BufferedReader {
+  int formatVersion;
+  StringReader stringReader;
+  ObjectReader objectReader;
+  final List<int> bytes;
+  final int baseOffset;
+
+  /// Position within [bytes], already includes [baseOffset].
+  int _pos;
+
+  BufferedReader(
+      this.formatVersion, this.stringReader, this.objectReader, this.bytes,
+      {this.baseOffset: 0})
+      : _pos = baseOffset {
+    assert((0 <= _pos) && (_pos <= bytes.length));
+  }
+
+  int get offset => _pos - baseOffset;
+
+  set offset(int offs) {
+    _pos = baseOffset + offs;
+    assert((0 <= _pos) && (_pos <= bytes.length));
+  }
+
+  int readByte() => bytes[_pos++];
+
+  int readUInt32() {
+    return (readByte() << 24) |
+        (readByte() << 16) |
+        (readByte() << 8) |
+        readByte();
+  }
+
+  int readPackedUInt30() {
+    var byte = readByte();
+    if (byte & 0x80 == 0) {
+      // 0xxxxxxx
+      return byte;
+    } else if (byte & 0x40 == 0) {
+      // 10xxxxxx
+      return ((byte & 0x3F) << 8) | readByte();
+    } else {
+      // 11xxxxxx
+      return ((byte & 0x3F) << 24) |
+          (readByte() << 16) |
+          (readByte() << 8) |
+          readByte();
+    }
+  }
+
+  int readSLEB128() {
+    int value = 0;
+    int shift = 0;
+    int part = 0;
+    do {
+      part = readByte();
+      value |= (part & 0x7f) << shift;
+      shift += 7;
+    } while ((part & 0x80) != 0);
+    const int kBitsPerInt = 64;
+    if ((shift < kBitsPerInt) && ((part & 0x40) != 0)) {
+      value |= (-1) << shift;
+    }
+    return value;
+  }
+
+  String readPackedStringReference() {
+    return stringReader.get(readPackedUInt30());
+  }
+
+  BytecodeObject readPackedObject() {
+    return objectReader.readObject(this);
+  }
+
+  List<T> readPackedList<T extends BytecodeObject>() {
+    final int len = readPackedUInt30();
+    final list = new List<T>(len);
+    for (int i = 0; i < len; ++i) {
+      list[i] = readPackedObject();
+    }
+    return list;
+  }
+
+  Uint8List readBytesAsUint8List(int count) {
+    final Uint8List result = new Uint8List(count);
+    result.setRange(0, result.length, bytes, _pos);
+    _pos += count;
+    return result;
+  }
+
+  Uint16List readBytesAsUint16List(int count) {
+    final Uint16List result = new Uint16List(count);
+    int pos = _pos;
+    for (int i = 0; i < count; ++i) {
+      result[i] = bytes[pos] | (bytes[pos + 1] << 8);
+      pos += 2;
+    }
+    _pos += count << 1;
+    return result;
+  }
+
+  void align(int alignment) {
+    assert(alignment & (alignment - 1) == 0);
+    _pos = ((_pos + alignment - 1) & -alignment);
+  }
+}
+
+class StringTable implements StringWriter, StringReader {
+  // Bit 0 in string reference is set for two-byte strings.
+  static const int flagTwoByteString = 1;
+
+  Map<String, int> _map = <String, int>{};
+  List<String> _oneByteStrings = <String>[];
+  List<String> _twoByteStrings = <String>[];
+  bool _written = false;
+
+  StringTable();
+
+  @override
+  int put(String string) {
+    int ref = _map[string];
+    if (ref == null) {
+      if (_written) {
+        throw 'Unable to add a string to string table after it was written';
+      }
+      if (isOneByteString(string)) {
+        ref = (_oneByteStrings.length << 1);
+        _oneByteStrings.add(string);
+      } else {
+        ref = (_twoByteStrings.length << 1) | flagTwoByteString;
+        _twoByteStrings.add(string);
+      }
+      _map[string] = ref;
+    }
+    return ref;
+  }
+
+  @override
+  String get(int ref) {
+    if ((ref & flagTwoByteString) == 0) {
+      return _oneByteStrings[ref >> 1];
+    } else {
+      return _twoByteStrings[ref >> 1];
+    }
+  }
+
+  bool isOneByteString(String value) {
+    const int maxLatin1 = 0xff;
+    for (int i = 0; i < value.length; ++i) {
+      if (value.codeUnitAt(i) > maxLatin1) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  void write(BufferedWriter writer) {
+    writer.writeUInt32(_oneByteStrings.length);
+    writer.writeUInt32(_twoByteStrings.length);
+    int endOffset = 0;
+    for (var str in _oneByteStrings) {
+      endOffset += str.length;
+      writer.writeUInt32(endOffset);
+    }
+    for (var str in _twoByteStrings) {
+      endOffset += str.length << 1;
+      writer.writeUInt32(endOffset);
+    }
+    for (var str in _oneByteStrings) {
+      for (int i = 0; i < str.length; ++i) {
+        writer.writeByte(str.codeUnitAt(i));
+      }
+    }
+    for (var str in _twoByteStrings) {
+      for (int i = 0; i < str.length; ++i) {
+        int utf16codeUnit = str.codeUnitAt(i);
+        writer.writeByte(utf16codeUnit & 0xFF);
+        writer.writeByte(utf16codeUnit >> 8);
+      }
+    }
+    _written = true;
+  }
+
+  StringTable.read(BufferedReader reader) {
+    final int numOneByteStrings = reader.readUInt32();
+    final int numTwoByteStrings = reader.readUInt32();
+    final List<int> oneByteEndOffsets = new List<int>(numOneByteStrings);
+    for (int i = 0; i < oneByteEndOffsets.length; ++i) {
+      oneByteEndOffsets[i] = reader.readUInt32();
+    }
+    List<int> twoByteEndOffsets = new List<int>(numTwoByteStrings);
+    for (int i = 0; i < twoByteEndOffsets.length; ++i) {
+      twoByteEndOffsets[i] = reader.readUInt32();
+    }
+    int start = 0;
+    if (numOneByteStrings > 0) {
+      _oneByteStrings = new List<String>(numOneByteStrings);
+      final charCodes = reader.readBytesAsUint8List(oneByteEndOffsets.last);
+      for (int i = 0; i < _oneByteStrings.length; ++i) {
+        final end = oneByteEndOffsets[i];
+        final str = new String.fromCharCodes(charCodes, start, end);
+        _oneByteStrings[i] = str;
+        _map[str] = i << 1;
+        start = end;
+      }
+    }
+    final int twoByteBaseOffset = start;
+    if (numTwoByteStrings > 0) {
+      int start = 0;
+      _twoByteStrings = new List<String>(numTwoByteStrings);
+      final charCodes = reader.readBytesAsUint16List(
+          (twoByteEndOffsets.last - twoByteBaseOffset) >> 1);
+      for (int i = 0; i < _twoByteStrings.length; ++i) {
+        final end = (twoByteEndOffsets[i] - twoByteBaseOffset) >> 1;
+        final str = new String.fromCharCodes(charCodes, start, end);
+        _twoByteStrings[i] = str;
+        _map[str] = (i << 1) | flagTwoByteString;
+        start = end;
+      }
+    }
+  }
+
+  @override
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.writeln('StringTable {');
+    sb.writeln('  // One Byte Strings');
+    for (String str in _oneByteStrings) {
+      sb.writeln('  "$str"');
+    }
+    sb.writeln('  // Two Byte Strings');
+    for (String str in _twoByteStrings) {
+      sb.writeln('  "$str"');
+    }
+    sb.writeln('}');
+    return sb.toString();
+  }
+}
diff --git a/pkg/vm/lib/bytecode/constant_pool.dart b/pkg/vm/lib/bytecode/constant_pool.dart
index 398cc7a..fda38ee 100644
--- a/pkg/vm/lib/bytecode/constant_pool.dart
+++ b/pkg/vm/lib/bytecode/constant_pool.dart
@@ -7,9 +7,11 @@
 import 'dart:typed_data';
 
 import 'package:kernel/ast.dart' hide MapEntry;
-import 'package:kernel/text/ast_to_text.dart' show Printer;
 
 import 'dbc.dart' show constantPoolIndexLimit, BytecodeLimitExceededException;
+import 'bytecode_serialization.dart'
+    show BufferedWriter, BufferedReader, StringTable;
+import 'object_table.dart' show ObjectHandle, ObjectTable;
 
 /*
 
@@ -32,7 +34,7 @@
 
 type ConstantString extends ConstantPoolEntry {
   Byte tag = 2;
-  StringReference value;
+  PackedString value;
 }
 
 type ConstantInt extends ConstantPoolEntry {
@@ -49,14 +51,14 @@
 
 type ConstantBool extends ConstantPoolEntry {
   Byte tag = 5;
-  UInt flag;
+  Byte flag;
 }
 
 type ConstantArgDesc extends ConstantPoolEntry {
   Byte tag = 6;
   UInt numArguments;
   UInt numTypeArgs;
-  List<StringReference> names;
+  List<PackedString> names;
 }
 
 enum InvocationKind {
@@ -69,76 +71,74 @@
   Byte tag = 7;
   Byte flags(invocationKindBit0, invocationKindBit1, isDynamic);
              // Where invocationKind is index into InvocationKind.
-  Name targetName;
+  PackedObject targetName;
   ConstantIndex argDesc;
 }
 
 type ConstantStaticICData extends ConstantPoolEntry {
   Byte tag = 8;
-  Byte invocationKind; // Index in InvocationKind enum.
-  CanonicalNameReference target;
+  PackedObject target;
   ConstantIndex argDesc;
 }
 
 type ConstantStaticField extends ConstantPoolEntry {
   Byte tag = 9;
-  CanonicalNameReference field;
+  PackedObject field;
 }
 
 // Occupies 2 entries in the constant pool.
 type ConstantInstanceField extends ConstantPoolEntry {
   Byte tag = 10;
-  CanonicalNameReference field;
+  PackedObject field;
 }
 
 type ConstantClass extends ConstantPoolEntry {
   Byte tag = 11;
-  CanonicalNameReference class;
+  PackedObject class;
 }
 
 type ConstantTypeArgumentsField extends ConstantPoolEntry {
   Byte tag = 12;
-  CanonicalNameReference class;
+  PackedObject class;
 }
 
 type ConstantTearOff extends ConstantPoolEntry {
   Byte tag = 13;
-  CanonicalNameReference target;
+  PackedObject target;
 }
 
 type ConstantType extends ConstantPoolEntry {
   Byte tag = 14;
-  DartType type;
+  PackedObject type;
 }
 
 type ConstantTypeArguments extends ConstantPoolEntry {
   Byte tag = 15;
-  List<DartType> types;
+  List<PackedObject> types;
 }
 
 type ConstantList extends ConstantPoolEntry {
   Byte tag = 16;
-  DartType typeArg;
+  PackedObject typeArg;
   List<ConstantIndex> entries;
 }
 
 type ConstantInstance extends ConstantPoolEntry {
   Byte tag = 17;
-  CanonicalNameReference class;
+  PackedObject class;
   ConstantIndex typeArguments;
-  List<Pair<CanonicalNameReference, ConstantIndex>> fieldValues;
+  List<Pair<PackedObject, ConstantIndex>> fieldValues;
 }
 
 type ConstantTypeArgumentsForInstanceAllocation extends ConstantPoolEntry {
   Byte tag = 18;
-  CanonicalNameReference instantiatingClass;
-  List<DartType> types;
+  PackedObject instantiatingClass;
+  List<PackedObject> types;
 }
 
 type ConstantClosureFunction extends ConstantPoolEntry {
   Byte tag = 19;
-  StringReference name;
-  FunctionNode function; // Doesn't have a body.
+  UInt closureIndex;
 }
 
 type ConstantEndClosureFunctionScope extends ConstantPoolEntry {
@@ -147,7 +147,7 @@
 
 type ConstantNativeEntry extends ConstantPoolEntry {
   Byte tag = 21;
-  StringReference nativeName;
+  PackedString nativeName;
 }
 
 type ConstantSubtypeTestCache extends ConstantPoolEntry {
@@ -166,8 +166,7 @@
 
 type ConstantSymbol extends ConstantPoolEntry {
   Byte tag = 25;
-  Option<LibraryReference> library;
-  StringReference name;
+  PackedObject name;
 }
 
 */
@@ -210,69 +209,68 @@
   // following this entry.
   int get numReservedEntries => 0;
 
-  void writeToBinary(BinarySink sink) {
-    sink.writeUInt30(tag.index);
-    writeValueToBinary(sink);
+  void write(BufferedWriter writer) {
+    writer.writeByte(tag.index);
+    writeValue(writer);
   }
 
-  void writeValueToBinary(BinarySink sink);
+  void writeValue(BufferedWriter writer);
 
-  factory ConstantPoolEntry.readFromBinary(BinarySource source) {
-    ConstantTag tag = ConstantTag.values[source.readUInt()];
+  factory ConstantPoolEntry.read(BufferedReader reader) {
+    ConstantTag tag = ConstantTag.values[reader.readByte()];
     switch (tag) {
       case ConstantTag.kInvalid:
         break;
       case ConstantTag.kNull:
-        return new ConstantNull.readFromBinary(source);
+        return new ConstantNull.read(reader);
       case ConstantTag.kString:
-        return new ConstantString.readFromBinary(source);
+        return new ConstantString.read(reader);
       case ConstantTag.kInt:
-        return new ConstantInt.readFromBinary(source);
+        return new ConstantInt.read(reader);
       case ConstantTag.kDouble:
-        return new ConstantDouble.readFromBinary(source);
+        return new ConstantDouble.read(reader);
       case ConstantTag.kBool:
-        return new ConstantBool.readFromBinary(source);
+        return new ConstantBool.read(reader);
       case ConstantTag.kICData:
-        return new ConstantICData.readFromBinary(source);
+        return new ConstantICData.read(reader);
       case ConstantTag.kStaticICData:
-        return new ConstantStaticICData.readFromBinary(source);
+        return new ConstantStaticICData.read(reader);
       case ConstantTag.kArgDesc:
-        return new ConstantArgDesc.readFromBinary(source);
+        return new ConstantArgDesc.read(reader);
       case ConstantTag.kStaticField:
-        return new ConstantStaticField.readFromBinary(source);
+        return new ConstantStaticField.read(reader);
       case ConstantTag.kInstanceField:
-        return new ConstantInstanceField.readFromBinary(source);
+        return new ConstantInstanceField.read(reader);
       case ConstantTag.kClass:
-        return new ConstantClass.readFromBinary(source);
+        return new ConstantClass.read(reader);
       case ConstantTag.kTypeArgumentsField:
-        return new ConstantTypeArgumentsField.readFromBinary(source);
+        return new ConstantTypeArgumentsField.read(reader);
       case ConstantTag.kTearOff:
-        return new ConstantTearOff.readFromBinary(source);
+        return new ConstantTearOff.read(reader);
       case ConstantTag.kType:
-        return new ConstantType.readFromBinary(source);
+        return new ConstantType.read(reader);
       case ConstantTag.kTypeArguments:
-        return new ConstantTypeArguments.readFromBinary(source);
+        return new ConstantTypeArguments.read(reader);
       case ConstantTag.kList:
-        return new ConstantList.readFromBinary(source);
+        return new ConstantList.read(reader);
       case ConstantTag.kInstance:
-        return new ConstantInstance.readFromBinary(source);
+        return new ConstantInstance.read(reader);
       case ConstantTag.kTypeArgumentsForInstanceAllocation:
-        return new ConstantTypeArgumentsForInstanceAllocation.readFromBinary(
-            source);
+        return new ConstantTypeArgumentsForInstanceAllocation.read(reader);
       case ConstantTag.kClosureFunction:
-        return new ConstantClosureFunction.readFromBinary(source);
+        return new ConstantClosureFunction.read(reader);
       case ConstantTag.kEndClosureFunctionScope:
-        return new ConstantEndClosureFunctionScope.readFromBinary(source);
+        return new ConstantEndClosureFunctionScope.read(reader);
       case ConstantTag.kNativeEntry:
-        return new ConstantNativeEntry.readFromBinary(source);
+        return new ConstantNativeEntry.read(reader);
       case ConstantTag.kSubtypeTestCache:
-        return new ConstantSubtypeTestCache.readFromBinary(source);
+        return new ConstantSubtypeTestCache.read(reader);
       case ConstantTag.kPartialTearOffInstantiation:
-        return new ConstantPartialTearOffInstantiation.readFromBinary(source);
+        return new ConstantPartialTearOffInstantiation.read(reader);
       case ConstantTag.kEmptyTypeArguments:
-        return new ConstantEmptyTypeArguments.readFromBinary(source);
+        return new ConstantEmptyTypeArguments.read(reader);
       case ConstantTag.kSymbol:
-        return new ConstantSymbol.readFromBinary(source);
+        return new ConstantSymbol.read(reader);
     }
     throw 'Unexpected constant tag $tag';
   }
@@ -285,9 +283,9 @@
   ConstantTag get tag => ConstantTag.kNull;
 
   @override
-  void writeValueToBinary(BinarySink sink) {}
+  void writeValue(BufferedWriter writer) {}
 
-  ConstantNull.readFromBinary(BinarySource source);
+  ConstantNull.read(BufferedReader reader);
 
   @override
   String toString() => 'Null';
@@ -309,12 +307,12 @@
   ConstantTag get tag => ConstantTag.kString;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeStringReference(value);
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedStringReference(value);
   }
 
-  ConstantString.readFromBinary(BinarySource source)
-      : value = source.readStringReference();
+  ConstantString.read(BufferedReader reader)
+      : value = reader.readPackedStringReference();
 
   @override
   String toString() => 'String \'$value\'';
@@ -336,14 +334,14 @@
   ConstantTag get tag => ConstantTag.kInt;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
+  void writeValue(BufferedWriter writer) {
     // TODO(alexmarkov): more efficient encoding
-    sink.writeUInt32(value & 0xffffffff);
-    sink.writeUInt32((value >> 32) & 0xffffffff);
+    writer.writeUInt32(value & 0xffffffff);
+    writer.writeUInt32((value >> 32) & 0xffffffff);
   }
 
-  ConstantInt.readFromBinary(BinarySource source)
-      : value = source.readUint32() | (source.readUint32() << 32);
+  ConstantInt.read(BufferedReader reader)
+      : value = reader.readUInt32() | (reader.readUInt32() << 32);
 
   @override
   String toString() => 'Int $value';
@@ -376,16 +374,16 @@
   }
 
   @override
-  void writeValueToBinary(BinarySink sink) {
+  void writeValue(BufferedWriter writer) {
     // TODO(alexmarkov): more efficient encoding
     int bits = doubleToIntBits(value);
-    sink.writeUInt32(bits & 0xffffffff);
-    sink.writeUInt32((bits >> 32) & 0xffffffff);
+    writer.writeUInt32(bits & 0xffffffff);
+    writer.writeUInt32((bits >> 32) & 0xffffffff);
   }
 
-  ConstantDouble.readFromBinary(BinarySource source)
+  ConstantDouble.read(BufferedReader reader)
       : value =
-            intBitsToDouble(source.readUint32() | (source.readUint32() << 32));
+            intBitsToDouble(reader.readUInt32() | (reader.readUInt32() << 32));
 
   @override
   String toString() => 'Double $value';
@@ -408,12 +406,11 @@
   ConstantTag get tag => ConstantTag.kBool;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeUInt30(value ? 1 : 0);
+  void writeValue(BufferedWriter writer) {
+    writer.writeByte(value ? 1 : 0);
   }
 
-  ConstantBool.readFromBinary(BinarySource source)
-      : value = source.readUInt() != 0;
+  ConstantBool.read(BufferedReader reader) : value = reader.readByte() != 0;
 
   @override
   String toString() => 'Bool $value';
@@ -450,18 +447,18 @@
   ConstantTag get tag => ConstantTag.kArgDesc;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeUInt30(numArguments);
-    sink.writeUInt30(numTypeArgs);
-    sink.writeUInt30(argNames.length);
-    argNames.forEach(sink.writeStringReference);
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedUInt30(numArguments);
+    writer.writePackedUInt30(numTypeArgs);
+    writer.writePackedUInt30(argNames.length);
+    argNames.forEach(writer.writePackedStringReference);
   }
 
-  ConstantArgDesc.readFromBinary(BinarySource source)
-      : numArguments = source.readUInt(),
-        numTypeArgs = source.readUInt(),
-        argNames = new List<String>.generate(
-            source.readUInt(), (_) => source.readStringReference());
+  ConstantArgDesc.read(BufferedReader reader)
+      : numArguments = reader.readPackedUInt30(),
+        numTypeArgs = reader.readPackedUInt30(),
+        argNames = new List<String>.generate(reader.readPackedUInt30(),
+            (_) => reader.readPackedStringReference());
 
   @override
   String toString() =>
@@ -498,7 +495,7 @@
   static const int flagDynamic = 1 << 2;
 
   final int _flags;
-  final Name targetName;
+  final ObjectHandle targetName;
   final int argDescConstantIndex;
 
   ConstantICData(InvocationKind invocationKind, this.targetName,
@@ -515,16 +512,16 @@
   ConstantTag get tag => ConstantTag.kICData;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeByte(_flags);
-    sink.writeName(targetName);
-    sink.writeUInt30(argDescConstantIndex);
+  void writeValue(BufferedWriter writer) {
+    writer.writeByte(_flags);
+    writer.writePackedObject(targetName);
+    writer.writePackedUInt30(argDescConstantIndex);
   }
 
-  ConstantICData.readFromBinary(BinarySource source)
-      : _flags = source.readByte(),
-        targetName = source.readName(),
-        argDescConstantIndex = source.readUInt();
+  ConstantICData.read(BufferedReader reader)
+      : _flags = reader.readByte(),
+        targetName = reader.readPackedObject(),
+        argDescConstantIndex = reader.readPackedUInt30();
 
   @override
   String toString() => 'ICData '
@@ -543,37 +540,26 @@
 }
 
 class ConstantStaticICData extends ConstantPoolEntry {
-  final InvocationKind invocationKind;
-  final Reference _reference;
+  final ObjectHandle target;
   final int argDescConstantIndex;
 
-  ConstantStaticICData(
-      InvocationKind invocationKind, Member member, int argDescConstantIndex)
-      : this.byReference(
-            invocationKind, member.reference, argDescConstantIndex);
-
-  ConstantStaticICData.byReference(
-      this.invocationKind, this._reference, this.argDescConstantIndex);
-
-  Member get target => _reference.asMember;
+  ConstantStaticICData(this.target, this.argDescConstantIndex);
 
   @override
   ConstantTag get tag => ConstantTag.kStaticICData;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeByte(invocationKind.index);
-    sink.writeCanonicalNameReference(getCanonicalNameOfMember(target));
-    sink.writeUInt30(argDescConstantIndex);
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedObject(target);
+    writer.writePackedUInt30(argDescConstantIndex);
   }
 
-  ConstantStaticICData.readFromBinary(BinarySource source)
-      : invocationKind = InvocationKind.values[source.readByte()],
-        _reference = source.readCanonicalNameReference().getReference(),
-        argDescConstantIndex = source.readUInt();
+  ConstantStaticICData.read(BufferedReader reader)
+      : target = reader.readPackedObject(),
+        argDescConstantIndex = reader.readPackedUInt30();
 
   @override
-  String toString() => 'StaticICData ${_invocationKindToString(invocationKind)}'
+  String toString() => 'StaticICData '
       'target \'$target\', arg-desc CP#$argDescConstantIndex';
 
   // ConstantStaticICData entries are created per call site and should not be
@@ -588,23 +574,20 @@
 }
 
 class ConstantStaticField extends ConstantPoolEntry {
-  final Reference _reference;
+  final ObjectHandle field;
 
-  Field get field => _reference.asField;
-
-  ConstantStaticField(Field field) : this.byReference(field.reference);
-  ConstantStaticField.byReference(this._reference);
+  ConstantStaticField(this.field);
 
   @override
   ConstantTag get tag => ConstantTag.kStaticField;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeCanonicalNameReference(getCanonicalNameOfMember(field));
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedObject(field);
   }
 
-  ConstantStaticField.readFromBinary(BinarySource source)
-      : _reference = source.readCanonicalNameReference().getReference();
+  ConstantStaticField.read(BufferedReader reader)
+      : field = reader.readPackedObject();
 
   @override
   String toString() => 'StaticField $field';
@@ -618,24 +601,22 @@
 }
 
 class ConstantInstanceField extends ConstantPoolEntry {
-  final Reference _reference;
+  final ObjectHandle field;
 
-  Field get field => _reference.asField;
   int get numReservedEntries => 1;
 
-  ConstantInstanceField(Field field) : this.byReference(field.reference);
-  ConstantInstanceField.byReference(this._reference);
+  ConstantInstanceField(this.field);
 
   @override
   ConstantTag get tag => ConstantTag.kInstanceField;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeCanonicalNameReference(getCanonicalNameOfMember(field));
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedObject(field);
   }
 
-  ConstantInstanceField.readFromBinary(BinarySource source)
-      : _reference = source.readCanonicalNameReference().getReference();
+  ConstantInstanceField.read(BufferedReader reader)
+      : field = reader.readPackedObject();
 
   @override
   String toString() => 'InstanceField $field';
@@ -649,83 +630,75 @@
 }
 
 class ConstantClass extends ConstantPoolEntry {
-  final Reference _reference;
+  final ObjectHandle classHandle;
 
-  Class get classNode => _reference.asClass;
-
-  ConstantClass(Class class_) : this.byReference(class_.reference);
-  ConstantClass.byReference(this._reference);
+  ConstantClass(this.classHandle);
 
   @override
   ConstantTag get tag => ConstantTag.kClass;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeCanonicalNameReference(getCanonicalNameOfClass(classNode));
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedObject(classHandle);
   }
 
-  ConstantClass.readFromBinary(BinarySource source)
-      : _reference = source.readCanonicalNameReference().getReference();
+  ConstantClass.read(BufferedReader reader)
+      : classHandle = reader.readPackedObject();
 
   @override
-  String toString() => 'Class $classNode';
+  String toString() => 'Class $classHandle';
 
   @override
-  int get hashCode => classNode.hashCode;
+  int get hashCode => classHandle.hashCode;
 
   @override
   bool operator ==(other) =>
-      other is ConstantClass && this.classNode == other.classNode;
+      other is ConstantClass && this.classHandle == other.classHandle;
 }
 
 class ConstantTypeArgumentsField extends ConstantPoolEntry {
-  final Reference _reference;
+  final ObjectHandle classHandle;
 
-  Class get classNode => _reference.asClass;
-
-  ConstantTypeArgumentsField(Class class_) : this.byReference(class_.reference);
-  ConstantTypeArgumentsField.byReference(this._reference);
+  ConstantTypeArgumentsField(this.classHandle);
 
   @override
   ConstantTag get tag => ConstantTag.kTypeArgumentsField;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeCanonicalNameReference(getCanonicalNameOfClass(classNode));
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedObject(classHandle);
   }
 
-  ConstantTypeArgumentsField.readFromBinary(BinarySource source)
-      : _reference = source.readCanonicalNameReference().getReference();
+  ConstantTypeArgumentsField.read(BufferedReader reader)
+      : classHandle = reader.readPackedObject();
 
   @override
-  String toString() => 'TypeArgumentsField $classNode';
+  String toString() => 'TypeArgumentsField $classHandle';
 
   @override
-  int get hashCode => classNode.hashCode;
+  int get hashCode => classHandle.hashCode;
 
   @override
   bool operator ==(other) =>
-      other is ConstantTypeArgumentsField && this.classNode == other.classNode;
+      other is ConstantTypeArgumentsField &&
+      this.classHandle == other.classHandle;
 }
 
 class ConstantTearOff extends ConstantPoolEntry {
-  final Reference _reference;
+  final ObjectHandle procedure;
 
-  Procedure get procedure => _reference.asProcedure;
-
-  ConstantTearOff(Procedure procedure) : this.byReference(procedure.reference);
-  ConstantTearOff.byReference(this._reference);
+  ConstantTearOff(this.procedure);
 
   @override
   ConstantTag get tag => ConstantTag.kTearOff;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeCanonicalNameReference(getCanonicalNameOfMember(procedure));
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedObject(procedure);
   }
 
-  ConstantTearOff.readFromBinary(BinarySource source)
-      : _reference = source.readCanonicalNameReference().getReference();
+  ConstantTearOff.read(BufferedReader reader)
+      : procedure = reader.readPackedObject();
 
   @override
   String toString() => 'TearOff $procedure';
@@ -739,7 +712,7 @@
 }
 
 class ConstantType extends ConstantPoolEntry {
-  final DartType type;
+  final ObjectHandle type;
 
   ConstantType(this.type);
 
@@ -747,12 +720,11 @@
   ConstantTag get tag => ConstantTag.kType;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeDartType(type);
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedObject(type);
   }
 
-  ConstantType.readFromBinary(BinarySource source)
-      : type = source.readDartType();
+  ConstantType.read(BufferedReader reader) : type = reader.readPackedObject();
 
   @override
   String toString() => 'Type $type';
@@ -765,7 +737,7 @@
 }
 
 class ConstantTypeArguments extends ConstantPoolEntry {
-  final List<DartType> typeArgs;
+  final List<ObjectHandle> typeArgs;
 
   ConstantTypeArguments(this.typeArgs);
 
@@ -773,14 +745,12 @@
   ConstantTag get tag => ConstantTag.kTypeArguments;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeUInt30(typeArgs.length);
-    typeArgs.forEach(sink.writeDartType);
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedList(typeArgs);
   }
 
-  ConstantTypeArguments.readFromBinary(BinarySource source)
-      : typeArgs = new List<DartType>.generate(
-            source.readUInt(), (_) => source.readDartType());
+  ConstantTypeArguments.read(BufferedReader reader)
+      : typeArgs = reader.readPackedList();
 
   @override
   String toString() => 'TypeArgs $typeArgs';
@@ -795,7 +765,7 @@
 }
 
 class ConstantList extends ConstantPoolEntry {
-  final DartType typeArg;
+  final ObjectHandle typeArg;
   final List<int> entries;
 
   ConstantList(this.typeArg, this.entries);
@@ -804,16 +774,16 @@
   ConstantTag get tag => ConstantTag.kList;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeDartType(typeArg);
-    sink.writeUInt30(entries.length);
-    entries.forEach(sink.writeUInt30);
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedObject(typeArg);
+    writer.writePackedUInt30(entries.length);
+    entries.forEach(writer.writePackedUInt30);
   }
 
-  ConstantList.readFromBinary(BinarySource source)
-      : typeArg = source.readDartType(),
-        entries =
-            new List<int>.generate(source.readUInt(), (_) => source.readUInt());
+  ConstantList.read(BufferedReader reader)
+      : typeArg = reader.readPackedObject(),
+        entries = new List<int>.generate(
+            reader.readPackedUInt30(), (_) => reader.readPackedUInt30());
 
   @override
   String toString() => 'List type-arg $typeArg, entries CP# $entries';
@@ -829,96 +799,79 @@
 }
 
 class ConstantInstance extends ConstantPoolEntry {
-  final Reference _classReference;
+  final ObjectHandle classHandle;
   final int _typeArgumentsConstantIndex;
-  final Map<Reference, int> _fieldValues;
+  final Map<ObjectHandle, int> _fieldValues;
 
-  ConstantInstance(Class class_, int typeArgumentsConstantIndex,
-      Map<Reference, int> fieldValues)
-      : this.byReference(
-            class_.reference, typeArgumentsConstantIndex, fieldValues);
-
-  ConstantInstance.byReference(this._classReference,
-      this._typeArgumentsConstantIndex, this._fieldValues);
+  ConstantInstance(
+      this.classHandle, this._typeArgumentsConstantIndex, this._fieldValues);
 
   @override
   ConstantTag get tag => ConstantTag.kInstance;
 
-  Class get classNode => _classReference.asClass;
-
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeCanonicalNameReference(getCanonicalNameOfClass(classNode));
-    sink.writeUInt30(_typeArgumentsConstantIndex);
-    sink.writeUInt30(_fieldValues.length);
-    _fieldValues.forEach((Reference fieldRef, int valueIndex) {
-      sink.writeCanonicalNameReference(
-          getCanonicalNameOfMember(fieldRef.asField));
-      sink.writeUInt30(valueIndex);
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedObject(classHandle);
+    writer.writePackedUInt30(_typeArgumentsConstantIndex);
+    writer.writePackedUInt30(_fieldValues.length);
+    _fieldValues.forEach((ObjectHandle field, int valueIndex) {
+      writer.writePackedObject(field);
+      writer.writePackedUInt30(valueIndex);
     });
   }
 
-  ConstantInstance.readFromBinary(BinarySource source)
-      : _classReference = source.readCanonicalNameReference().getReference(),
-        _typeArgumentsConstantIndex = source.readUInt(),
-        _fieldValues = new Map<Reference, int>() {
-    final fieldValuesLen = source.readUInt();
+  ConstantInstance.read(BufferedReader reader)
+      : classHandle = reader.readPackedObject(),
+        _typeArgumentsConstantIndex = reader.readPackedUInt30(),
+        _fieldValues = new Map<ObjectHandle, int>() {
+    final fieldValuesLen = reader.readPackedUInt30();
     for (int i = 0; i < fieldValuesLen; i++) {
-      final fieldRef = source.readCanonicalNameReference().getReference();
-      final valueIndex = source.readUInt();
-      _fieldValues[fieldRef] = valueIndex;
+      final field = reader.readPackedObject();
+      final valueIndex = reader.readPackedUInt30();
+      _fieldValues[field] = valueIndex;
     }
   }
 
   @override
   String toString() {
     final values = _fieldValues.map<String, String>(
-        (Reference fieldRef, int valueIndex) =>
-            new MapEntry(fieldRef.asField.name.name, 'CP#$valueIndex'));
-    return 'Instance $classNode type-args CP#$_typeArgumentsConstantIndex $values';
+        (ObjectHandle field, int valueIndex) =>
+            new MapEntry(field.toString(), 'CP#$valueIndex'));
+    return 'Instance $classHandle type-args CP#$_typeArgumentsConstantIndex $values';
   }
 
   @override
   int get hashCode => _combineHashes(
-      _combineHashes(classNode.hashCode, _typeArgumentsConstantIndex),
+      _combineHashes(classHandle.hashCode, _typeArgumentsConstantIndex),
       mapHashCode(_fieldValues));
 
   @override
   bool operator ==(other) =>
       other is ConstantInstance &&
-      this.classNode == other.classNode &&
+      this.classHandle == other.classHandle &&
       this._typeArgumentsConstantIndex == other._typeArgumentsConstantIndex &&
       mapEquals(this._fieldValues, other._fieldValues);
 }
 
 class ConstantTypeArgumentsForInstanceAllocation extends ConstantPoolEntry {
-  final Reference _instantiatingClassRef;
-  final List<DartType> typeArgs;
-
-  Class get instantiatingClass => _instantiatingClassRef.asClass;
+  final ObjectHandle instantiatingClass;
+  final List<ObjectHandle> typeArgs;
 
   ConstantTypeArgumentsForInstanceAllocation(
-      Class instantiatingClass, List<DartType> typeArgs)
-      : this.byReference(instantiatingClass.reference, typeArgs);
-  ConstantTypeArgumentsForInstanceAllocation.byReference(
-      this._instantiatingClassRef, this.typeArgs);
+      this.instantiatingClass, this.typeArgs);
 
   @override
   ConstantTag get tag => ConstantTag.kTypeArgumentsForInstanceAllocation;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeCanonicalNameReference(
-        getCanonicalNameOfClass(instantiatingClass));
-    sink.writeUInt30(typeArgs.length);
-    typeArgs.forEach(sink.writeDartType);
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedObject(instantiatingClass);
+    writer.writePackedList(typeArgs);
   }
 
-  ConstantTypeArgumentsForInstanceAllocation.readFromBinary(BinarySource source)
-      : _instantiatingClassRef =
-            source.readCanonicalNameReference().getReference(),
-        typeArgs = new List<DartType>.generate(
-            source.readUInt(), (_) => source.readDartType());
+  ConstantTypeArgumentsForInstanceAllocation.read(BufferedReader reader)
+      : instantiatingClass = reader.readPackedObject(),
+        typeArgs = reader.readPackedList();
 
   @override
   String toString() =>
@@ -936,47 +889,33 @@
 }
 
 class ConstantClosureFunction extends ConstantPoolEntry {
-  final String name;
-  final FunctionNode function;
+  final int closureIndex;
 
-  ConstantClosureFunction(this.name, this.function);
+  ConstantClosureFunction(this.closureIndex);
 
   @override
   ConstantTag get tag => ConstantTag.kClosureFunction;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeStringReference(name);
-    _withoutFunctionBody(() {
-      sink.writeNode(function);
-    });
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedUInt30(closureIndex);
   }
 
-  ConstantClosureFunction.readFromBinary(BinarySource source)
-      : name = source.readStringReference(),
-        function = source.readFunctionNode() {
-    assert(function.body == null);
-  }
+  ConstantClosureFunction.read(BufferedReader reader)
+      : closureIndex = reader.readPackedUInt30();
 
   @override
   String toString() {
-    StringBuffer buffer = new StringBuffer();
-    _withoutFunctionBody(() {
-      new Printer(buffer).writeFunction(function);
-    });
-    return 'ClosureFunction $name ${buffer.toString().trim()}';
+    return 'ClosureFunction $closureIndex';
   }
 
-  _withoutFunctionBody(action()) {
-    final savedBody = function.body;
-    function.body = null;
-    action();
-    function.body = savedBody;
-  }
+  @override
+  int get hashCode => closureIndex;
 
-  // ConstantClosureFunction entries are created per closure and should not
-  // be merged, so ConstantClosureFunction class uses identity [hashCode] and
-  // [operator ==].
+  @override
+  bool operator ==(other) =>
+      other is ConstantClosureFunction &&
+      this.closureIndex == other.closureIndex;
 }
 
 class ConstantEndClosureFunctionScope extends ConstantPoolEntry {
@@ -986,9 +925,9 @@
   ConstantTag get tag => ConstantTag.kEndClosureFunctionScope;
 
   @override
-  void writeValueToBinary(BinarySink sink) {}
+  void writeValue(BufferedWriter writer) {}
 
-  ConstantEndClosureFunctionScope.readFromBinary(BinarySource source) {}
+  ConstantEndClosureFunctionScope.read(BufferedReader reader) {}
 
   @override
   String toString() => 'EndClosureFunctionScope';
@@ -1007,12 +946,12 @@
   ConstantTag get tag => ConstantTag.kNativeEntry;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeStringReference(nativeName);
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedStringReference(nativeName);
   }
 
-  ConstantNativeEntry.readFromBinary(BinarySource source)
-      : nativeName = source.readStringReference();
+  ConstantNativeEntry.read(BufferedReader reader)
+      : nativeName = reader.readPackedStringReference();
 
   @override
   String toString() => 'NativeEntry $nativeName';
@@ -1032,9 +971,9 @@
   ConstantTag get tag => ConstantTag.kSubtypeTestCache;
 
   @override
-  void writeValueToBinary(BinarySink sink) {}
+  void writeValue(BufferedWriter writer) {}
 
-  ConstantSubtypeTestCache.readFromBinary(BinarySource source);
+  ConstantSubtypeTestCache.read(BufferedReader reader);
 
   @override
   String toString() => 'SubtypeTestCache';
@@ -1061,14 +1000,14 @@
   ConstantTag get tag => ConstantTag.kPartialTearOffInstantiation;
 
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeUInt30(tearOffConstantIndex);
-    sink.writeUInt30(typeArgumentsConstantIndex);
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedUInt30(tearOffConstantIndex);
+    writer.writePackedUInt30(typeArgumentsConstantIndex);
   }
 
-  ConstantPartialTearOffInstantiation.readFromBinary(BinarySource source)
-      : tearOffConstantIndex = source.readUInt(),
-        typeArgumentsConstantIndex = source.readUInt();
+  ConstantPartialTearOffInstantiation.read(BufferedReader reader)
+      : tearOffConstantIndex = reader.readPackedUInt30(),
+        typeArgumentsConstantIndex = reader.readPackedUInt30();
 
   @override
   String toString() {
@@ -1093,9 +1032,9 @@
   ConstantTag get tag => ConstantTag.kEmptyTypeArguments;
 
   @override
-  void writeValueToBinary(BinarySink sink) {}
+  void writeValue(BufferedWriter writer) {}
 
-  ConstantEmptyTypeArguments.readFromBinary(BinarySource source);
+  ConstantEmptyTypeArguments.read(BufferedReader reader);
 
   @override
   String toString() => 'EmptyTypeArguments';
@@ -1108,38 +1047,28 @@
 }
 
 class ConstantSymbol extends ConstantPoolEntry {
-  final Reference _libraryRef;
-  final String value;
+  final ObjectHandle name;
 
-  ConstantSymbol(this._libraryRef, this.value);
+  ConstantSymbol(this.name);
 
   @override
   ConstantTag get tag => ConstantTag.kSymbol;
 
-  Library get library => _libraryRef?.asLibrary;
-
   @override
-  void writeValueToBinary(BinarySink sink) {
-    sink.writeCanonicalNameReference(library?.canonicalName);
-    sink.writeStringReference(value);
+  void writeValue(BufferedWriter writer) {
+    writer.writePackedObject(name);
   }
 
-  ConstantSymbol.readFromBinary(BinarySource source)
-      : _libraryRef = source.readCanonicalNameReference()?.getReference(),
-        value = source.readStringReference();
+  ConstantSymbol.read(BufferedReader reader) : name = reader.readPackedObject();
 
   @override
-  String toString() => 'Symbol '
-      '${library != null ? '$library::' : ''}\'$value\'';
+  String toString() => 'Symbol $name';
 
   @override
-  int get hashCode => value.hashCode;
+  int get hashCode => name.hashCode;
 
   @override
-  bool operator ==(other) =>
-      other is ConstantSymbol &&
-      this.value == other.value &&
-      this.library == other.library;
+  bool operator ==(other) => other is ConstantSymbol && this.name == other.name;
 }
 
 /// Reserved constant pool entry.
@@ -1147,7 +1076,7 @@
   const _ReservedConstantPoolEntry();
 
   ConstantTag get tag => throw 'This constant pool entry is reserved';
-  void writeValueToBinary(BinarySink sink) =>
+  void writeValue(BufferedWriter writer) =>
       throw 'This constant pool entry is reserved';
 
   @override
@@ -1155,15 +1084,17 @@
 }
 
 class ConstantPool {
+  final StringTable stringTable;
+  final ObjectTable objectTable;
   final List<ConstantPoolEntry> entries = <ConstantPoolEntry>[];
   final Map<ConstantPoolEntry, int> _canonicalizationCache =
       <ConstantPoolEntry, int>{};
 
-  ConstantPool();
+  ConstantPool(this.stringTable, this.objectTable);
 
   int addNull() => _add(const ConstantNull());
 
-  int addString(String value) => _add(new ConstantString(value));
+  int addString(String value) => _add(new ConstantString(_indexString(value)));
 
   int addInt(int value) => _add(new ConstantInt(value));
 
@@ -1173,61 +1104,78 @@
 
   int addArgDesc(int numArguments,
           {int numTypeArgs = 0, List<String> argNames = const <String>[]}) =>
-      _add(new ConstantArgDesc(numArguments, numTypeArgs, argNames));
+      _add(new ConstantArgDesc(
+          numArguments, numTypeArgs, _indexStrings(argNames)));
 
   int addArgDescByArguments(Arguments args,
           {bool hasReceiver: false, bool isFactory: false}) =>
-      _add(new ConstantArgDesc.fromArguments(args, hasReceiver, isFactory));
+      _add(new ConstantArgDesc.fromArguments(
+          _indexArgNames(args), hasReceiver, isFactory));
 
   int addICData(
           InvocationKind invocationKind, Name targetName, int argDescCpIndex,
           {bool isDynamic: false}) =>
       _add(new ConstantICData(
-          invocationKind, targetName, argDescCpIndex, isDynamic));
+          invocationKind,
+          objectTable.getSelectorNameHandle(targetName,
+              isGetter: invocationKind == InvocationKind.getter,
+              isSetter: invocationKind == InvocationKind.setter),
+          argDescCpIndex,
+          isDynamic));
 
   int addStaticICData(
           InvocationKind invocationKind, Member target, int argDescCpIndex) =>
-      _add(new ConstantStaticICData(invocationKind, target, argDescCpIndex));
+      _add(new ConstantStaticICData(
+          objectTable.getMemberHandle(target,
+              isGetter: invocationKind == InvocationKind.getter,
+              isSetter: invocationKind == InvocationKind.setter),
+          argDescCpIndex));
 
-  int addStaticField(Field field) => _add(new ConstantStaticField(field));
+  int addStaticField(Field field) =>
+      _add(new ConstantStaticField(objectTable.getHandle(field)));
 
-  int addInstanceField(Field field) => _add(new ConstantInstanceField(field));
+  int addInstanceField(Field field) =>
+      _add(new ConstantInstanceField(objectTable.getHandle(field)));
 
-  int addClass(Class node) => _add(new ConstantClass(node));
+  int addClass(Class node) =>
+      _add(new ConstantClass(objectTable.getHandle(node)));
 
   int addTypeArgumentsField(Class node) =>
-      _add(new ConstantTypeArgumentsField(node));
+      _add(new ConstantTypeArgumentsField(objectTable.getHandle(node)));
 
-  int addTearOff(Procedure node) => _add(new ConstantTearOff(node));
+  int addTearOff(Procedure node) =>
+      _add(new ConstantTearOff(objectTable.getHandle(node)));
 
-  int addType(DartType type) => _add(new ConstantType(type));
+  int addType(DartType type) =>
+      _add(new ConstantType(objectTable.getHandle(type)));
 
   int addTypeArguments(List<DartType> typeArgs) =>
-      _add(new ConstantTypeArguments(typeArgs));
+      _add(new ConstantTypeArguments(objectTable.getHandles(typeArgs)));
 
   int addList(DartType typeArgument, List<int> entries) =>
-      _add(new ConstantList(typeArgument, entries));
+      _add(new ConstantList(objectTable.getHandle(typeArgument), entries));
 
   int addInstance(
           Class klass, int typeArgumentsCpIndex, Map<Field, int> fieldValues) =>
       _add(new ConstantInstance(
-          klass,
+          objectTable.getHandle(klass),
           typeArgumentsCpIndex,
-          fieldValues.map<Reference, int>((Field field, int valueCpIndex) =>
-              new MapEntry(field.reference, valueCpIndex))));
+          fieldValues.map<ObjectHandle, int>((Field field, int valueCpIndex) =>
+              new MapEntry(objectTable.getHandle(field), valueCpIndex))));
 
   int addTypeArgumentsForInstanceAllocation(
           Class classNode, List<DartType> typeArgs) =>
-      _add(new ConstantTypeArgumentsForInstanceAllocation(classNode, typeArgs));
+      _add(new ConstantTypeArgumentsForInstanceAllocation(
+          objectTable.getHandle(classNode), objectTable.getHandles(typeArgs)));
 
-  int addClosureFunction(String name, FunctionNode function) =>
-      _add(new ConstantClosureFunction(name, function));
+  int addClosureFunction(int closureIndex) =>
+      _add(new ConstantClosureFunction(closureIndex));
 
   int addEndClosureFunctionScope() =>
       _add(new ConstantEndClosureFunctionScope());
 
   int addNativeEntry(String nativeName) =>
-      _add(new ConstantNativeEntry(nativeName));
+      _add(new ConstantNativeEntry(_indexString(nativeName)));
 
   int addSubtypeTestCache() => _add(new ConstantSubtypeTestCache());
 
@@ -1239,7 +1187,7 @@
   int addEmptyTypeArguments() => _add(const ConstantEmptyTypeArguments());
 
   int addSymbol(Library library, String name) =>
-      _add(new ConstantSymbol(library?.reference, name));
+      _add(new ConstantSymbol(objectTable.getNameHandle(library, name)));
 
   int _add(ConstantPoolEntry entry) {
     return _canonicalizationCache.putIfAbsent(entry, () {
@@ -1259,63 +1207,46 @@
     }
   }
 
-  void writeToBinary(Node node, BinarySink sink) {
-    final function = (node as Member).function;
-    sink.enterScope(
-        typeParameters: function?.typeParameters, memberScope: true);
+  // Currently, string table is written as a part of Component's metadata
+  // *before* constant pools are written.
+  // So we need to index all strings when filling up constant pools.
+  String _indexString(String str) {
+    stringTable.put(str);
+    return str;
+  }
 
-    final closureStack = <ConstantClosureFunction>[];
+  List<String> _indexStrings(List<String> strings) {
+    for (var str in strings) {
+      stringTable.put(str);
+    }
+    return strings;
+  }
 
-    sink.writeUInt30(entries.length);
+  Arguments _indexArgNames(Arguments args) {
+    for (var arg in args.named) {
+      stringTable.put(arg.name);
+    }
+    return args;
+  }
+
+  void write(BufferedWriter writer) {
+    writer.writePackedUInt30(entries.length);
     entries.forEach((e) {
       if (e is _ReservedConstantPoolEntry) {
         return;
       }
-
-      e.writeToBinary(sink);
-
-      if (e is ConstantClosureFunction) {
-        sink.enterScope(typeParameters: e.function.typeParameters);
-        closureStack.add(e);
-      } else if (e is ConstantEndClosureFunctionScope) {
-        sink.leaveScope(
-            typeParameters: closureStack.removeLast().function.typeParameters);
-      }
+      e.write(writer);
     });
-
-    assert(closureStack.isEmpty);
-
-    sink.leaveScope(
-        typeParameters: function?.typeParameters, memberScope: true);
   }
 
-  ConstantPool.readFromBinary(Node node, BinarySource source) {
-    final function = (node as Member).function;
-    if (function != null) {
-      source.enterScope(typeParameters: function.typeParameters);
-    }
-
-    final closureStack = <ConstantClosureFunction>[];
-
-    int len = source.readUInt();
+  ConstantPool.read(BufferedReader reader)
+      : stringTable = reader.stringReader,
+        objectTable = reader.objectReader {
+    int len = reader.readPackedUInt30();
     for (int i = 0; i < len; i++) {
-      final e = new ConstantPoolEntry.readFromBinary(source);
+      final e = new ConstantPoolEntry.read(reader);
       _addEntry(e);
       i += e.numReservedEntries;
-
-      if (e is ConstantClosureFunction) {
-        source.enterScope(typeParameters: e.function.typeParameters);
-        closureStack.add(e);
-      } else if (e is ConstantEndClosureFunctionScope) {
-        source.leaveScope(
-            typeParameters: closureStack.removeLast().function.typeParameters);
-      }
-    }
-
-    assert(closureStack.isEmpty);
-
-    if (function != null) {
-      source.leaveScope(typeParameters: function.typeParameters);
     }
   }
 
diff --git a/pkg/vm/lib/bytecode/dbc.dart b/pkg/vm/lib/bytecode/dbc.dart
index 13eb462..1092e14 100644
--- a/pkg/vm/lib/bytecode/dbc.dart
+++ b/pkg/vm/lib/bytecode/dbc.dart
@@ -19,6 +19,9 @@
 /// runtime/vm/constants_kbc.h.
 const int futureBytecodeFormatVersion = stableBytecodeFormatVersion + 1;
 
+/// Alignment of bytecode instructions.
+const int bytecodeInstructionsAlignment = 4;
+
 enum Opcode {
   kTrap,
 
diff --git a/pkg/vm/lib/bytecode/exceptions.dart b/pkg/vm/lib/bytecode/exceptions.dart
index 7c955a3..2147790 100644
--- a/pkg/vm/lib/bytecode/exceptions.dart
+++ b/pkg/vm/lib/bytecode/exceptions.dart
@@ -4,7 +4,7 @@
 
 library vm.bytecode.exceptions;
 
-import 'package:kernel/ast.dart' show BinarySink, BinarySource;
+import 'bytecode_serialization.dart' show BufferedWriter, BufferedReader;
 
 /*
 
@@ -59,26 +59,26 @@
     flags = (flags & ~flagIsSynthetic) | (value ? flagIsSynthetic : 0);
   }
 
-  void writeToBinary(BinarySink sink) {
-    sink.writeUInt30(outerTryIndex + 1);
-    sink.writeUInt30(startPC);
-    sink.writeUInt30(endPC);
-    sink.writeUInt30(handlerPC);
-    sink.writeByte(flags);
-    sink.writeUInt30(types.length);
-    types.forEach(sink.writeUInt30);
+  void write(BufferedWriter writer) {
+    writer.writePackedUInt30(outerTryIndex + 1);
+    writer.writePackedUInt30(startPC);
+    writer.writePackedUInt30(endPC);
+    writer.writePackedUInt30(handlerPC);
+    writer.writeByte(flags);
+    writer.writePackedUInt30(types.length);
+    types.forEach(writer.writePackedUInt30);
   }
 
-  factory TryBlock.readFromBinary(BinarySource source, int tryIndex) {
-    final outerTryIndex = source.readUInt() - 1;
-    final startPC = source.readUInt();
+  factory TryBlock.read(BufferedReader reader, int tryIndex) {
+    final outerTryIndex = reader.readPackedUInt30() - 1;
+    final startPC = reader.readPackedUInt30();
     final tryBlock = new TryBlock._(tryIndex, outerTryIndex, startPC);
 
-    tryBlock.endPC = source.readUInt();
-    tryBlock.handlerPC = source.readUInt();
-    tryBlock.flags = source.readByte();
-    tryBlock.types =
-        new List<int>.generate(source.readUInt(), (_) => source.readUInt());
+    tryBlock.endPC = reader.readPackedUInt30();
+    tryBlock.handlerPC = reader.readPackedUInt30();
+    tryBlock.flags = reader.readByte();
+    tryBlock.types = new List<int>.generate(
+        reader.readPackedUInt30(), (_) => reader.readPackedUInt30());
 
     return tryBlock;
   }
@@ -114,14 +114,14 @@
     return -1;
   }
 
-  void writeToBinary(BinarySink sink) {
-    sink.writeUInt30(blocks.length);
-    blocks.forEach((b) => b.writeToBinary(sink));
+  void write(BufferedWriter writer) {
+    writer.writePackedUInt30(blocks.length);
+    blocks.forEach((b) => b.write(writer));
   }
 
-  ExceptionsTable.readFromBinary(BinarySource source)
-      : blocks = new List<TryBlock>.generate(source.readUInt(),
-            (int index) => new TryBlock.readFromBinary(source, index));
+  ExceptionsTable.read(BufferedReader reader)
+      : blocks = new List<TryBlock>.generate(reader.readPackedUInt30(),
+            (int index) => new TryBlock.read(reader, index));
 
   @override
   String toString() {
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 379be40..9c49962 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -23,11 +23,13 @@
 import 'package:kernel/vm/constants_native_effects.dart'
     show VmConstantsBackend;
 import 'assembler.dart';
+import 'bytecode_serialization.dart' show StringTable;
 import 'constant_pool.dart';
 import 'dbc.dart';
 import 'exceptions.dart';
 import 'local_vars.dart' show LocalVariables;
 import 'nullability_detector.dart' show NullabilityDetector;
+import 'object_table.dart' show ObjectHandle, ObjectTable, NameAndType;
 import 'recognized_methods.dart' show RecognizedMethods;
 import '../constants_error_reporter.dart' show ForwardConstantEvaluationErrors;
 import '../metadata/bytecode.dart';
@@ -81,6 +83,9 @@
   final ErrorReporter errorReporter;
   final BytecodeMetadataRepository metadata = new BytecodeMetadataRepository();
   final RecognizedMethods recognizedMethods;
+  final int formatVersion;
+  StringTable stringTable;
+  ObjectTable objectTable;
   NullabilityDetector nullabilityDetector;
 
   Class enclosingClass;
@@ -100,9 +105,9 @@
   Map<TryFinally, List<FinallyBlock>> finallyBlocks;
   List<Label> yieldPoints;
   Map<TreeNode, int> contextLevels;
-  List<ClosureBytecode> closures;
+  List<ClosureDeclaration> closures;
   Set<Field> initializedFields;
-  List<Reference> nullableFields;
+  List<ObjectHandle> nullableFields;
   ConstantPool cp;
   ConstantEmitter constantEmitter;
   BytecodeAssembler asm;
@@ -120,9 +125,19 @@
       this.omitAssertSourcePositions,
       this.useFutureBytecodeFormat,
       this.errorReporter)
-      : recognizedMethods = new RecognizedMethods(typeEnvironment) {
+      : recognizedMethods = new RecognizedMethods(typeEnvironment),
+        formatVersion = useFutureBytecodeFormat
+            ? futureBytecodeFormatVersion
+            : stableBytecodeFormatVersion {
     nullabilityDetector = new NullabilityDetector(recognizedMethods);
     component.addMetadataRepository(metadata);
+
+    metadata.bytecodeComponent = new BytecodeComponent(formatVersion);
+    metadata.mapping[component] = metadata.bytecodeComponent;
+
+    stringTable = metadata.bytecodeComponent.stringTable;
+    objectTable = metadata.bytecodeComponent.objectTable;
+    objectTable.coreTypes = coreTypes;
   }
 
   @override
@@ -330,10 +345,10 @@
     _generateNodeList(node.initializers);
 
     if (!isRedirecting) {
-      nullableFields = <Reference>[];
+      nullableFields = <ObjectHandle>[];
       for (var field in node.enclosingClass.fields) {
         if (!field.isStatic && !initializedFields.contains(field)) {
-          nullableFields.add(field.reference);
+          nullableFields.add(objectTable.getHandle(field));
         }
       }
       initializedFields = null; // No more initialized fields, please.
@@ -819,10 +834,10 @@
     finallyBlocks = <TryFinally, List<FinallyBlock>>{};
     yieldPoints = null; // Initialized when entering sync-yielding closure.
     contextLevels = <TreeNode, int>{};
-    closures = <ClosureBytecode>[];
+    closures = <ClosureDeclaration>[];
     initializedFields = null; // Tracked for constructors only.
-    nullableFields = const <Reference>[];
-    cp = new ConstantPool();
+    nullableFields = const <ObjectHandle>[];
+    cp = new ConstantPool(stringTable, objectTable);
     constantEmitter = new ConstantEmitter(cp);
     asm = new BytecodeAssembler();
     savedAssemblers = <BytecodeAssembler>[];
@@ -861,17 +876,8 @@
 
   void end(Member node) {
     if (!hasErrors) {
-      final formatVersion = useFutureBytecodeFormat
-          ? futureBytecodeFormatVersion
-          : stableBytecodeFormatVersion;
-      metadata.mapping[node] = new BytecodeMetadata(
-          formatVersion,
-          cp,
-          asm.bytecode,
-          asm.exceptionsTable,
-          asm.sourcePositions,
-          nullableFields,
-          closures);
+      metadata.mapping[node] = new MemberBytecode(cp, asm.bytecode,
+          asm.exceptionsTable, asm.sourcePositions, nullableFields, closures);
     }
 
     typeEnvironment.thisType = null;
@@ -1282,7 +1288,29 @@
     function.positionalParameters.forEach(_evaluateDefaultParameterValue);
     locals.sortedNamedParameters.forEach(_evaluateDefaultParameterValue);
 
-    final int closureFunctionIndex = cp.addClosureFunction(name, function);
+    final int closureIndex = closures.length;
+    objectTable.declareClosure(function, enclosingMember, closureIndex);
+    final List<NameAndType> parameters = function.positionalParameters
+        .followedBy(function.namedParameters)
+        .map((v) => new NameAndType(objectTable.getNameHandle(null, v.name),
+            objectTable.getHandle(v.type)))
+        .toList();
+    final ClosureDeclaration closure = new ClosureDeclaration(
+        objectTable
+            .getHandle(savedIsClosure ? parentFunction : enclosingMember),
+        objectTable.getNameHandle(null, name),
+        function.typeParameters
+            .map((tp) => new NameAndType(
+                objectTable.getNameHandle(null, tp.name),
+                objectTable.getHandle(tp.bound)))
+            .toList(),
+        function.requiredParameterCount,
+        function.namedParameters.length,
+        parameters,
+        objectTable.getHandle(function.returnType));
+    closures.add(closure);
+
+    final int closureFunctionIndex = cp.addClosureFunction(closureIndex);
 
     _genPrologue(node, function);
 
@@ -1325,8 +1353,8 @@
 
     locals.leaveScope();
 
-    closures.add(new ClosureBytecode(closureFunctionIndex, asm.bytecode,
-        asm.exceptionsTable, asm.sourcePositions));
+    closure.bytecode = new ClosureBytecode(
+        asm.bytecode, asm.exceptionsTable, asm.sourcePositions);
 
     _popAssemblerState();
     yieldPoints = savedYieldPoints;
@@ -2119,7 +2147,8 @@
         asm.emitPushNull();
       }
       args =
-          new Arguments(node.arguments.positional, named: node.arguments.named);
+          new Arguments(node.arguments.positional, named: node.arguments.named)
+            ..parent = node;
     }
     _genArguments(null, args);
     _genStaticCallWithArgs(target, args, isFactory: target.isFactory);
diff --git a/pkg/vm/lib/bytecode/object_table.dart b/pkg/vm/lib/bytecode/object_table.dart
new file mode 100644
index 0000000..4b17c60
--- /dev/null
+++ b/pkg/vm/lib/bytecode/object_table.dart
@@ -0,0 +1,1214 @@
+// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library vm.bytecode.object_table;
+
+import 'package:kernel/ast.dart' hide MapEntry;
+import 'package:kernel/core_types.dart' show CoreTypes;
+
+import 'bytecode_serialization.dart'
+    show
+        BufferedWriter,
+        BufferedReader,
+        BytecodeObject,
+        ObjectReader,
+        ObjectWriter,
+        StringWriter;
+
+/*
+
+Bytecode object table is encoded in the following way
+(using notation from pkg/kernel/binary.md):
+
+type ObjectTable {
+  UInt numEntries;
+  UInt contentsSize;
+
+  //  Occupies contentsSize bytes.
+  ObjectContents objects[numEntries]
+
+  UInt objectOffsets[numEntries]
+}
+
+// Either reference to an object in object table, or object contents
+// written inline.
+PackedObject = ObjectReference | ObjectContents
+
+type ObjectReference {
+  // Bit 0 (reference bit): 1
+  // Bits 1+: index in object table
+  UInt reference(<index>1)
+}
+
+type ObjectContents {
+  // Bit 0 (reference bit): 0
+  // Bits 1-4: object kind
+  // Bits 5+ object flags
+  UInt header(<flags><kind>0)
+}
+
+// Reference to a string in string table.
+type PackedString {
+  // Bit 0: set for two byte string
+  // Bits 1+: index in string table
+  UInt indexAndKind(<index><kind>)
+}
+
+// Invalid object table entry (at index 0).
+type InvalidObject extends ObjectContents {
+  kind = 0;
+}
+
+type Library extends ObjectContents {
+  kind = 1;
+  PackedString importUri;
+}
+
+type Class extends ObjectContents {
+  kind = 2;
+  PackedObject library;
+  // Empty name is used for artificial class containing top-level
+  // members of a library.
+  PackedObject name;
+}
+
+type Member extends ObjectContents {
+  kind = 3;
+  flags = (isField, isConstructor);
+  PackedObject class;
+  PackedObject name;
+}
+
+type Closure extends ObjectContents {
+  kind = 4;
+  PackedObject enclosingMember;
+  UInt closureIndex;
+}
+
+type SimpleType extends ObjectContents {
+  kind = 5;
+  flags = (isDynamic, isVoid);
+  PackedObject class;
+}
+
+type TypeParameter extends ObjectContents {
+  kind = 6;
+  // Class, Member or Closure declaring this type parameter.
+  // Invalid if declared by function type.
+  PackedObject parent;
+  UInt indexInParent;
+}
+
+type GenericType extends ObjectContents {
+  kind = 7;
+  PackedObject class;
+  List<PackedObject> typeArgs;
+}
+
+type FunctionType extends ObjectContents {
+  kind = 8;
+  flags = (hasOptionalPositionalParams, hasOptionalNamedParams, hasTypeParams)
+
+  if hasTypeParams
+    UInt numTypeParameters
+    PackedObject[numTypeParameters] typeParameterNames
+    PackedObject[numTypeParameters] typeParameterBounds
+
+  UInt numParameters
+
+  if hasOptionalPositionalParams || hasOptionalNamedParams
+    UInt numRequiredParameters
+
+   Type[] positionalParameters
+   NameAndType[] namedParameters
+   PackedObject returnType
+}
+
+type NameAndType {
+  PackedObject name;
+  PackedObject type;
+}
+
+type Name extends ObjectContents {
+  kind = 9;
+
+  // Invalid for public names
+  PackedObject library;
+
+  // Getters are prefixed with 'get:'.
+  // Setters are prefixed with 'set:'.
+  PackedString string;
+}
+
+*/
+
+enum ObjectKind {
+  kInvalid,
+  kLibrary,
+  kClass,
+  kMember,
+  kClosure,
+  kSimpleType,
+  kTypeParameter,
+  kGenericType,
+  kFunctionType,
+  kName,
+}
+
+String objectKindToString(ObjectKind kind) =>
+    kind.toString().substring('ObjectKind.k'.length);
+
+/// Represents object (library, class, member, closure, type or name) in the
+/// object table.
+abstract class ObjectHandle extends BytecodeObject {
+  static const int referenceBit = 1 << 0;
+  static const int indexShift = 1;
+  static const int inlineObject = -1;
+
+  static const int kindShift = 1;
+  static const int kindMask = 0x0F;
+
+  static const int flagBit0 = 1 << 5;
+  static const int flagBit1 = 1 << 6;
+  static const int flagBit2 = 1 << 7;
+  static const int flagsMask = flagBit0 | flagBit1 | flagBit2;
+
+  static int _makeReference(int index) => (index << indexShift) | referenceBit;
+
+  static int _getIndexFromReference(int reference) {
+    assert((reference & referenceBit) != 0);
+    return reference >> indexShift;
+  }
+
+  static int _makeHeader(ObjectKind kind, int flags) {
+    assert((kind.index & kindMask) == kind.index);
+    assert((flags & flagsMask) == flags);
+    return (kind.index << kindShift) | flags;
+  }
+
+  static ObjectKind _getKindFromHeader(int header) {
+    assert((header & referenceBit) == 0);
+    return ObjectKind.values[(header >> kindShift) & kindMask];
+  }
+
+  static int _getFlagsFromHeader(int header) {
+    assert((header & referenceBit) == 0);
+    return header & flagsMask;
+  }
+
+  int _useCount = 0;
+  int _reference;
+
+  ObjectHandle();
+
+  ObjectKind get kind;
+
+  int get flags => 0;
+  set flags(int value) {}
+
+  bool get isCacheable => true;
+
+  factory ObjectHandle._empty(ObjectKind kind) {
+    switch (kind) {
+      case ObjectKind.kInvalid:
+        return new _InvalidHandle();
+      case ObjectKind.kLibrary:
+        return new _LibraryHandle._empty();
+      case ObjectKind.kClass:
+        return new _ClassHandle._empty();
+      case ObjectKind.kMember:
+        return new _MemberHandle._empty();
+      case ObjectKind.kClosure:
+        return new _ClosureHandle._empty();
+      case ObjectKind.kSimpleType:
+        return new _SimpleTypeHandle._empty();
+      case ObjectKind.kGenericType:
+        return new _GenericTypeHandle._empty();
+      case ObjectKind.kTypeParameter:
+        return new _TypeParameterHandle._empty();
+      case ObjectKind.kFunctionType:
+        return new _FunctionTypeHandle._empty();
+      case ObjectKind.kName:
+        return new _NameHandle._empty();
+    }
+    throw 'Unexpected object kind $kind';
+  }
+
+  void _write(BufferedWriter writer) {
+    int header = _makeHeader(kind, flags);
+    assert((header & referenceBit) == 0);
+    writer.writePackedUInt30(header);
+    writeContents(writer);
+  }
+
+  void writeContents(BufferedWriter writer);
+
+  factory ObjectHandle._read(BufferedReader reader, int header) {
+    assert((header & referenceBit) == 0);
+    final ObjectKind kind = _getKindFromHeader(header);
+    final obj = new ObjectHandle._empty(kind);
+    obj.flags = _getFlagsFromHeader(header);
+    obj.readContents(reader);
+    return obj;
+  }
+
+  void readContents(BufferedReader reader);
+
+  void accountUsesForObjectCopies(int numCopies) {}
+
+  void indexStrings(StringWriter strings) {}
+}
+
+class _InvalidHandle extends ObjectHandle {
+  _InvalidHandle();
+
+  @override
+  ObjectKind get kind => ObjectKind.kInvalid;
+
+  @override
+  void writeContents(BufferedWriter writer) {}
+
+  @override
+  void readContents(BufferedReader reader) {}
+
+  @override
+  String toString() => 'Invalid';
+}
+
+class _LibraryHandle extends ObjectHandle {
+  String uri;
+
+  _LibraryHandle._empty();
+
+  _LibraryHandle(this.uri);
+
+  @override
+  ObjectKind get kind => ObjectKind.kLibrary;
+
+  @override
+  void writeContents(BufferedWriter writer) {
+    writer.writePackedStringReference(uri);
+  }
+
+  @override
+  void readContents(BufferedReader reader) {
+    uri = reader.readPackedStringReference();
+  }
+
+  @override
+  void indexStrings(StringWriter strings) {
+    strings.put(uri);
+  }
+
+  @override
+  int get hashCode => uri.hashCode + 11;
+
+  @override
+  bool operator ==(other) => other is _LibraryHandle && this.uri == other.uri;
+
+  @override
+  String toString() => uri;
+}
+
+class _ClassHandle extends ObjectHandle {
+  /// Name of artificial class containing top-level members of a library.
+  static const String topLevelClassName = '';
+
+  _LibraryHandle library;
+  _NameHandle name;
+
+  _ClassHandle._empty();
+
+  _ClassHandle(this.library, this.name);
+
+  @override
+  ObjectKind get kind => ObjectKind.kClass;
+
+  @override
+  void writeContents(BufferedWriter writer) {
+    writer.writePackedObject(library);
+    writer.writePackedObject(name);
+  }
+
+  @override
+  void readContents(BufferedReader reader) {
+    library = reader.readPackedObject();
+    name = reader.readPackedObject();
+  }
+
+  @override
+  void accountUsesForObjectCopies(int numCopies) {
+    library._useCount += numCopies;
+    name._useCount += numCopies;
+  }
+
+  @override
+  int get hashCode => _combineHashes(library.hashCode, name.hashCode);
+
+  @override
+  bool operator ==(other) =>
+      other is _ClassHandle &&
+      this.library == other.library &&
+      this.name == other.name;
+
+  @override
+  String toString() =>
+      name.name == topLevelClassName ? '$library' : '$library::$name';
+}
+
+class _MemberHandle extends ObjectHandle {
+  static const int flagIsField = ObjectHandle.flagBit0;
+  static const int flagIsConstructor = ObjectHandle.flagBit1;
+
+  int _flags = 0;
+  _ClassHandle parent;
+  _NameHandle name;
+
+  _MemberHandle._empty();
+  _MemberHandle(this.parent, this.name, bool isField, bool isConstructor) {
+    if (isField) {
+      _flags |= flagIsField;
+    }
+    if (isConstructor) {
+      _flags |= flagIsConstructor;
+    }
+  }
+
+  @override
+  ObjectKind get kind => ObjectKind.kMember;
+
+  @override
+  int get flags => _flags;
+
+  @override
+  set flags(int value) {
+    _flags = value;
+  }
+
+  @override
+  void writeContents(BufferedWriter writer) {
+    writer.writePackedObject(parent);
+    writer.writePackedObject(name);
+  }
+
+  @override
+  void readContents(BufferedReader reader) {
+    parent = reader.readPackedObject();
+    name = reader.readPackedObject();
+  }
+
+  @override
+  void accountUsesForObjectCopies(int numCopies) {
+    parent._useCount += numCopies;
+    name._useCount += numCopies;
+  }
+
+  @override
+  int get hashCode => _combineHashes(parent.hashCode, name.hashCode);
+
+  @override
+  bool operator ==(other) =>
+      other is _MemberHandle &&
+      this.parent == other.parent &&
+      this.name == other.name &&
+      this.flags == other.flags;
+
+  @override
+  String toString() =>
+      '$parent::$name' +
+      (flags & flagIsField != 0 ? ' (field)' : '') +
+      (flags & flagIsConstructor != 0 ? ' (constructor)' : '');
+}
+
+class _ClosureHandle extends ObjectHandle {
+  _MemberHandle enclosingMember;
+  int closureIndex;
+
+  _ClosureHandle._empty();
+
+  _ClosureHandle(this.enclosingMember, this.closureIndex) {
+    assert(closureIndex >= 0);
+  }
+
+  @override
+  ObjectKind get kind => ObjectKind.kClosure;
+
+  @override
+  void writeContents(BufferedWriter writer) {
+    writer.writePackedObject(enclosingMember);
+    writer.writePackedUInt30(closureIndex);
+  }
+
+  @override
+  void readContents(BufferedReader reader) {
+    enclosingMember = reader.readPackedObject();
+    closureIndex = reader.readPackedUInt30();
+  }
+
+  @override
+  void accountUsesForObjectCopies(int numCopies) {
+    enclosingMember._useCount += numCopies;
+  }
+
+  @override
+  int get hashCode => _combineHashes(enclosingMember.hashCode, closureIndex);
+
+  @override
+  bool operator ==(other) =>
+      other is _ClosureHandle &&
+      this.enclosingMember == other.enclosingMember &&
+      this.closureIndex == other.closureIndex;
+
+  @override
+  String toString() => '$enclosingMember::Closure/$closureIndex';
+}
+
+abstract class _TypeHandle extends ObjectHandle {}
+
+class _SimpleTypeHandle extends _TypeHandle {
+  static const int flagIsDynamic = ObjectHandle.flagBit0;
+  static const int flagIsVoid = ObjectHandle.flagBit1;
+
+  _ClassHandle class_;
+  int _flags = 0;
+
+  _SimpleTypeHandle._empty();
+
+  _SimpleTypeHandle(this.class_);
+
+  _SimpleTypeHandle._dynamic() : _flags = flagIsDynamic;
+
+  _SimpleTypeHandle._void() : _flags = flagIsVoid;
+
+  @override
+  ObjectKind get kind => ObjectKind.kSimpleType;
+
+  @override
+  int get flags => _flags;
+
+  @override
+  set flags(int value) {
+    _flags = value;
+  }
+
+  @override
+  void writeContents(BufferedWriter writer) {
+    writer.writePackedObject(class_);
+  }
+
+  @override
+  void readContents(BufferedReader reader) {
+    class_ = reader.readPackedObject();
+  }
+
+  @override
+  void accountUsesForObjectCopies(int numCopies) {
+    if (class_ != null) {
+      class_._useCount += numCopies;
+    }
+  }
+
+  @override
+  int get hashCode => class_.hashCode + _flags + 11;
+
+  @override
+  bool operator ==(other) =>
+      other is _SimpleTypeHandle &&
+      this.class_ == other.class_ &&
+      this._flags == other._flags;
+
+  @override
+  String toString() {
+    if ((_flags & flagIsDynamic) != 0) return 'dynamic';
+    if ((_flags & flagIsVoid) != 0) return 'void';
+    return '$class_';
+  }
+}
+
+class _TypeParameterHandle extends _TypeHandle {
+  ObjectHandle parent;
+  int indexInParent;
+
+  _TypeParameterHandle._empty();
+
+  _TypeParameterHandle(this.parent, this.indexInParent) {
+    assert(parent is _ClassHandle ||
+        parent is _MemberHandle ||
+        parent is _ClosureHandle ||
+        parent == null);
+    assert(indexInParent >= 0);
+  }
+
+  @override
+  ObjectKind get kind => ObjectKind.kTypeParameter;
+
+  @override
+  bool get isCacheable => (parent != null);
+
+  @override
+  void writeContents(BufferedWriter writer) {
+    writer.writePackedObject(parent);
+    writer.writePackedUInt30(indexInParent);
+  }
+
+  @override
+  void readContents(BufferedReader reader) {
+    parent = reader.readPackedObject();
+    indexInParent = reader.readPackedUInt30();
+  }
+
+  @override
+  void accountUsesForObjectCopies(int numCopies) {
+    if (parent != null) {
+      parent._useCount += numCopies;
+    }
+  }
+
+  @override
+  int get hashCode => _combineHashes(parent.hashCode, indexInParent);
+
+  @override
+  bool operator ==(other) =>
+      other is _TypeParameterHandle &&
+      this.parent == other.parent &&
+      this.indexInParent == other.indexInParent;
+
+  @override
+  String toString() => '$parent::TypeParam/$indexInParent';
+}
+
+class _GenericTypeHandle extends _TypeHandle {
+  _ClassHandle class_;
+  List<_TypeHandle> typeArgs;
+
+  _GenericTypeHandle._empty();
+
+  _GenericTypeHandle(this.class_, this.typeArgs);
+
+  @override
+  ObjectKind get kind => ObjectKind.kGenericType;
+
+  @override
+  void writeContents(BufferedWriter writer) {
+    writer.writePackedObject(class_);
+    writer.writePackedList(typeArgs);
+  }
+
+  @override
+  void readContents(BufferedReader reader) {
+    class_ = reader.readPackedObject();
+    typeArgs = reader.readPackedList<_TypeHandle>();
+  }
+
+  @override
+  void accountUsesForObjectCopies(int numCopies) {
+    class_._useCount += numCopies;
+    typeArgs.forEach((t) {
+      t._useCount += numCopies;
+    });
+  }
+
+  @override
+  int get hashCode => _combineHashes(class_.hashCode, listHashCode(typeArgs));
+
+  @override
+  bool operator ==(other) =>
+      other is _GenericTypeHandle &&
+      this.class_ == other.class_ &&
+      listEquals(this.typeArgs, other.typeArgs);
+
+  @override
+  String toString() => '$class_ < ${typeArgs.join(', ')} >';
+}
+
+class NameAndType {
+  _NameHandle name;
+  _TypeHandle type;
+
+  NameAndType(this.name, this.type);
+
+  @override
+  int get hashCode => _combineHashes(name.hashCode, type.hashCode);
+
+  @override
+  bool operator ==(other) =>
+      other is NameAndType &&
+      this.name == other.name &&
+      this.type == other.type;
+
+  @override
+  String toString() => '$type $name';
+}
+
+class _FunctionTypeHandle extends _TypeHandle {
+  static const int flagHasOptionalPositionalParams = ObjectHandle.flagBit0;
+  static const int flagHasOptionalNamedParams = ObjectHandle.flagBit1;
+  static const int flagHasTypeParams = ObjectHandle.flagBit2;
+
+  int _flags = 0;
+  List<NameAndType> typeParams;
+  int numRequiredParams;
+  List<_TypeHandle> positionalParams;
+  List<NameAndType> namedParams;
+  _TypeHandle returnType;
+
+  _FunctionTypeHandle._empty();
+
+  _FunctionTypeHandle(this.typeParams, this.numRequiredParams,
+      this.positionalParams, this.namedParams, this.returnType) {
+    assert(numRequiredParams <= positionalParams.length + namedParams.length);
+    if (numRequiredParams < positionalParams.length) {
+      assert(namedParams.isEmpty);
+      _flags |= flagHasOptionalPositionalParams;
+    }
+    if (namedParams.isNotEmpty) {
+      assert(numRequiredParams == positionalParams.length);
+      _flags |= flagHasOptionalNamedParams;
+    }
+    if (typeParams.isNotEmpty) {
+      _flags |= flagHasTypeParams;
+    }
+  }
+
+  @override
+  int get flags => _flags;
+
+  @override
+  set flags(int value) {
+    _flags = value;
+  }
+
+  ObjectKind get kind => ObjectKind.kFunctionType;
+
+  @override
+  void writeContents(BufferedWriter writer) {
+    if ((_flags & flagHasTypeParams) != 0) {
+      writer.writePackedUInt30(typeParams.length);
+      for (var tp in typeParams) {
+        writer.writePackedObject(tp.name);
+      }
+      for (var tp in typeParams) {
+        writer.writePackedObject(tp.type);
+      }
+    }
+    writer.writePackedUInt30(positionalParams.length + namedParams.length);
+    if (_flags &
+            (flagHasOptionalPositionalParams | flagHasOptionalNamedParams) !=
+        0) {
+      writer.writePackedUInt30(numRequiredParams);
+    }
+    for (var param in positionalParams) {
+      writer.writePackedObject(param);
+    }
+    for (var param in namedParams) {
+      writer.writePackedObject(param.name);
+      writer.writePackedObject(param.type);
+    }
+    writer.writePackedObject(returnType);
+  }
+
+  @override
+  void readContents(BufferedReader reader) {
+    if ((_flags & flagHasTypeParams) != 0) {
+      final int numTypeParams = reader.readPackedUInt30();
+      List<_NameHandle> names = new List<_NameHandle>.generate(
+          numTypeParams, (_) => reader.readPackedObject());
+      List<_TypeHandle> bounds = new List<_TypeHandle>.generate(
+          numTypeParams, (_) => reader.readPackedObject());
+      typeParams = new List<NameAndType>.generate(
+          numTypeParams, (int i) => new NameAndType(names[i], bounds[i]));
+    } else {
+      typeParams = const <NameAndType>[];
+    }
+    final int numParams = reader.readPackedUInt30();
+    numRequiredParams = numParams;
+    if ((_flags &
+            (flagHasOptionalPositionalParams | flagHasOptionalNamedParams)) !=
+        0) {
+      numRequiredParams = reader.readPackedUInt30();
+    }
+    final bool hasNamedParams = (_flags & flagHasOptionalNamedParams) != 0;
+    positionalParams = new List<_TypeHandle>.generate(
+        hasNamedParams ? numRequiredParams : numParams,
+        (_) => reader.readPackedObject());
+    if (hasNamedParams) {
+      namedParams = new List<NameAndType>.generate(
+          reader.readPackedUInt30(),
+          (_) => new NameAndType(
+              reader.readPackedObject(), reader.readPackedObject()));
+    } else {
+      namedParams = const <NameAndType>[];
+    }
+    returnType = reader.readPackedObject();
+  }
+
+  @override
+  void accountUsesForObjectCopies(int numCopies) {
+    positionalParams.forEach((p) {
+      p._useCount += numCopies;
+    });
+    namedParams.forEach((p) {
+      p.name._useCount += numCopies;
+      p.type._useCount += numCopies;
+    });
+  }
+
+  @override
+  int get hashCode {
+    int hash = listHashCode(typeParams);
+    hash = _combineHashes(hash, numRequiredParams);
+    hash = _combineHashes(hash, listHashCode(positionalParams));
+    hash = _combineHashes(hash, listHashCode(namedParams));
+    hash = _combineHashes(hash, returnType.hashCode);
+    return hash;
+  }
+
+  @override
+  bool operator ==(other) =>
+      other is _FunctionTypeHandle &&
+      listEquals(this.typeParams, other.typeParams) &&
+      this.numRequiredParams == other.numRequiredParams &&
+      listEquals(this.positionalParams, other.positionalParams) &&
+      listEquals(this.namedParams, other.namedParams) &&
+      this.returnType == other.returnType;
+
+  @override
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write('FunctionType');
+    if (typeParams.isNotEmpty) {
+      sb.write(' <${typeParams.join(', ')}>');
+    }
+    sb.write(' (');
+    sb.write(positionalParams.sublist(0, numRequiredParams).join(', '));
+    if (numRequiredParams != positionalParams.length) {
+      if (numRequiredParams > 0) {
+        sb.write(', ');
+      }
+      sb.write('[ ${positionalParams.sublist(numRequiredParams).join(', ')} ]');
+    }
+    if (namedParams.isNotEmpty) {
+      if (numRequiredParams > 0) {
+        sb.write(', ');
+      }
+      sb.write('{ ${namedParams.join(', ')} }');
+    }
+    sb.write(') -> ');
+    sb.write(returnType);
+    return sb.toString();
+  }
+}
+
+class _NameHandle extends ObjectHandle {
+  _LibraryHandle library;
+  String name;
+
+  _NameHandle._empty();
+
+  _NameHandle(this.library, this.name);
+
+  @override
+  ObjectKind get kind => ObjectKind.kName;
+
+  @override
+  void writeContents(BufferedWriter writer) {
+    writer.writePackedObject(library);
+    writer.writePackedStringReference(name);
+  }
+
+  @override
+  void readContents(BufferedReader reader) {
+    library = reader.readPackedObject();
+    name = reader.readPackedStringReference();
+  }
+
+  @override
+  void accountUsesForObjectCopies(int numCopies) {
+    if (library != null) {
+      library._useCount += numCopies;
+    }
+  }
+
+  @override
+  void indexStrings(StringWriter strings) {
+    strings.put(name);
+  }
+
+  @override
+  int get hashCode => _combineHashes(name.hashCode, library.hashCode);
+
+  @override
+  bool operator ==(other) =>
+      other is _NameHandle &&
+      this.name == other.name &&
+      this.library == other.library;
+
+  @override
+  String toString() => name.isEmpty ? "''" : name;
+}
+
+class ObjectTable implements ObjectWriter, ObjectReader {
+  /// Object is added to an index table if it is used more than this
+  /// number of times.
+  static const int indexTableUseCountThreshold = 3;
+
+  final List<ObjectHandle> _objects = new List<ObjectHandle>();
+  final Map<ObjectHandle, ObjectHandle> _canonicalizationCache =
+      <ObjectHandle, ObjectHandle>{};
+  final Map<Node, ObjectHandle> _nodeCache = <Node, ObjectHandle>{};
+  List<ObjectHandle> _indexTable;
+  _TypeHandle _dynamicType;
+  _TypeHandle _voidType;
+  CoreTypes coreTypes;
+  _NodeVisitor _nodeVisitor;
+
+  ObjectTable() {
+    _dynamicType = getOrAddObject(new _SimpleTypeHandle._dynamic());
+    _voidType = getOrAddObject(new _SimpleTypeHandle._void());
+    _nodeVisitor = new _NodeVisitor(this);
+  }
+
+  ObjectHandle getHandle(Node node) {
+    if (node == null) {
+      return null;
+    }
+    ObjectHandle handle = _nodeCache[node];
+    if (handle == null) {
+      handle = node.accept(_nodeVisitor);
+      _nodeCache[node] = handle;
+    } else {
+      ++handle._useCount;
+    }
+    return handle;
+  }
+
+  List<ObjectHandle> getHandles(List<Node> nodes) =>
+      nodes.map((n) => getHandle(n)).toList();
+
+  String mangleGetterName(String name) => 'get:$name';
+
+  String mangleSetterName(String name) => 'set:$name';
+
+  String mangleSelectorName(String name, bool isGetter, bool isSetter) {
+    if (isGetter) {
+      return mangleGetterName(name);
+    } else if (isSetter) {
+      return mangleSetterName(name);
+    } else {
+      return name;
+    }
+  }
+
+  String mangleMemberName(Member member, bool isGetter, bool isSetter) {
+    final name = member.name.name;
+    if (isGetter || (member is Procedure && member.isGetter)) {
+      return mangleGetterName(name);
+    }
+    if (isSetter || (member is Procedure && member.isSetter)) {
+      return mangleSetterName(name);
+    }
+    return name;
+  }
+
+  ObjectHandle getNameHandle(Library library, String name) {
+    final libraryHandle = library != null ? getHandle(library) : null;
+    return getOrAddObject(new _NameHandle(libraryHandle, name));
+  }
+
+  ObjectHandle getSelectorNameHandle(Name name,
+      {bool isGetter: false, bool isSetter: false}) {
+    return getNameHandle(
+        name.library, mangleSelectorName(name.name, isGetter, isSetter));
+  }
+
+  ObjectHandle getMemberHandle(Member member,
+      {bool isGetter: false, bool isSetter: false}) {
+    final parent = member.parent;
+    ObjectHandle classHandle;
+    if (parent is Class) {
+      classHandle = getHandle(parent);
+    } else if (parent is Library) {
+      final library = getHandle(parent);
+      final name = getNameHandle(null, _ClassHandle.topLevelClassName);
+      classHandle = getOrAddObject(new _ClassHandle(library, name));
+    } else {
+      throw "Unexpected Member's parent ${parent.runtimeType} $parent";
+    }
+    if (member is Constructor || member is Procedure && member.isFactory) {}
+    final nameHandle = getNameHandle(
+        member.name.library, mangleMemberName(member, isGetter, isSetter));
+    bool isField = member is Field && !isGetter && !isSetter;
+    bool isConstructor =
+        member is Constructor || (member is Procedure && member.isFactory);
+    return getOrAddObject(
+        new _MemberHandle(classHandle, nameHandle, isField, isConstructor));
+  }
+
+  void declareClosure(
+      FunctionNode function, Member enclosingMember, int closureIndex) {
+    final handle = getOrAddObject(
+        new _ClosureHandle(getHandle(enclosingMember), closureIndex));
+    _nodeCache[function] = handle;
+  }
+
+  ObjectHandle getOrAddObject(ObjectHandle obj) {
+    assert(obj._useCount == 0);
+    ObjectHandle canonical = _canonicalizationCache.putIfAbsent(obj, () {
+      assert(_indexTable == null);
+      _objects.add(obj);
+      return obj;
+    });
+    ++canonical._useCount;
+    return canonical;
+  }
+
+  void allocateIndexTable() {
+    int tableSize = 1; // Reserve invalid entry.
+    for (var obj in _objects.reversed) {
+      assert(obj._reference == null);
+      if (obj._useCount >= indexTableUseCountThreshold && obj.isCacheable) {
+        // This object will be included into index table.
+        ++tableSize;
+      } else {
+        // This object will be copied and written inline. Bump use count for
+        // objects referenced from this one for each copy after the first.
+        obj._reference = ObjectHandle.inlineObject;
+        obj.accountUsesForObjectCopies(obj._useCount - 1);
+      }
+    }
+    _indexTable = new List<ObjectHandle>(tableSize);
+    int count = 0;
+    _indexTable[count++] = new _InvalidHandle()
+      .._reference = ObjectHandle._makeReference(0);
+    for (var obj in _objects) {
+      if (obj._reference == null) {
+        obj._reference = ObjectHandle._makeReference(count);
+        _indexTable[count++] = obj;
+      } else {
+        assert(obj._reference == ObjectHandle.inlineObject);
+      }
+    }
+    assert(count == tableSize);
+  }
+
+  @override
+  void writeObject(BytecodeObject object, BufferedWriter writer) {
+    ObjectHandle handle = object as ObjectHandle;
+    if (handle == null) {
+      writer.writePackedUInt30(ObjectHandle._makeReference(0));
+      return;
+    }
+    if (handle._reference == ObjectHandle.inlineObject) {
+      handle._write(writer);
+    } else {
+      assert(handle._reference >= 0);
+      assert((handle._reference & ObjectHandle.referenceBit) != 0);
+      writer.writePackedUInt30(handle._reference);
+    }
+  }
+
+  @override
+  BytecodeObject readObject(BufferedReader reader) {
+    final int header = reader.readPackedUInt30();
+    if ((header & ObjectHandle.referenceBit) == 0) {
+      return new ObjectHandle._read(reader, header);
+    } else {
+      final int index = ObjectHandle._getIndexFromReference(header);
+      return (index == 0) ? null : _indexTable[index];
+    }
+  }
+
+  void write(BufferedWriter writer) {
+    assert(writer.objectWriter == this);
+    assert(_indexTable != null);
+
+    BufferedWriter contentsWriter = new BufferedWriter.fromWriter(writer);
+    List<int> offsets = new List<int>(_indexTable.length);
+
+    for (int i = 0; i < _indexTable.length; ++i) {
+      offsets[i] = contentsWriter.offset;
+      _indexTable[i]._write(contentsWriter);
+    }
+
+    writer.writePackedUInt30(_indexTable.length);
+    writer.writePackedUInt30(contentsWriter.offset);
+    writer.writeBytes(contentsWriter.takeBytes());
+    for (var offs in offsets) {
+      writer.writePackedUInt30(offs);
+    }
+
+    // Index strings in objects which will be written inline
+    // in constant pool entries.
+    for (var obj in _objects) {
+      if (obj._reference == ObjectHandle.inlineObject) {
+        obj.indexStrings(writer.stringWriter);
+      }
+    }
+  }
+
+  ObjectTable.read(BufferedReader reader) {
+    reader.objectReader = this;
+
+    final int numEntries = reader.readPackedUInt30();
+    reader.readPackedUInt30(); // Contents length
+
+    _indexTable = new List<ObjectHandle>(numEntries);
+    for (int i = 0; i < numEntries; ++i) {
+      final int header = reader.readPackedUInt30();
+      _indexTable[i] = new ObjectHandle._read(reader, header)
+        .._reference = ObjectHandle._makeReference(i);
+    }
+    // Skip index table.
+    for (int i = 0; i < numEntries; ++i) {
+      reader.readPackedUInt30();
+    }
+  }
+
+  @override
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.writeln('ObjectTable {');
+    for (int i = 0; i < _indexTable.length; ++i) {
+      final obj = _indexTable[i];
+      sb.writeln('  [$i] = ${objectKindToString(obj.kind)} $obj');
+    }
+    sb.writeln('}');
+    return sb.toString();
+  }
+}
+
+class _NodeVisitor extends Visitor<ObjectHandle> {
+  final ObjectTable objectTable;
+  final _typeParameters = <TypeParameter, ObjectHandle>{};
+
+  _NodeVisitor(this.objectTable);
+
+  @override
+  ObjectHandle defaultNode(Node node) =>
+      throw 'Unexpected node ${node.runtimeType} $node';
+
+  @override
+  ObjectHandle visitLibrary(Library node) =>
+      objectTable.getOrAddObject(new _LibraryHandle(node.importUri.toString()));
+
+  @override
+  ObjectHandle visitClass(Class node) {
+    final ObjectHandle library = objectTable.getHandle(node.enclosingLibrary);
+    final name = objectTable.getOrAddObject(
+        new _NameHandle(node.name.startsWith('_') ? library : null, node.name));
+    return objectTable.getOrAddObject(new _ClassHandle(library, name));
+  }
+
+  @override
+  ObjectHandle defaultMember(Member node) => objectTable.getMemberHandle(node);
+
+  @override
+  ObjectHandle visitDynamicType(DynamicType node) => objectTable._dynamicType;
+
+  @override
+  ObjectHandle visitVoidType(VoidType node) => objectTable._voidType;
+
+  @override
+  ObjectHandle visitBottomType(BottomType node) =>
+      objectTable.getHandle(objectTable.coreTypes.nullClass.rawType);
+
+  @override
+  ObjectHandle visitInterfaceType(InterfaceType node) {
+    final classHandle = objectTable.getHandle(node.classNode);
+    if (node.typeArguments.isEmpty) {
+      return objectTable.getOrAddObject(new _SimpleTypeHandle(classHandle));
+    }
+    final List<_TypeHandle> typeArgs = node.typeArguments
+        .map((t) => objectTable.getHandle(t) as _TypeHandle)
+        .toList();
+    return objectTable
+        .getOrAddObject(new _GenericTypeHandle(classHandle, typeArgs));
+  }
+
+  @override
+  ObjectHandle visitTypeParameterType(TypeParameterType node) {
+    final param = node.parameter;
+    final handle = _typeParameters[param];
+    if (handle != null) {
+      return handle;
+    }
+
+    final parent = param.parent;
+    if (parent == null) {
+      throw 'Type parameter $param without parent, but not declared by function type';
+    }
+
+    ObjectHandle parentHandle;
+    int indexInParent;
+    if (parent is Class) {
+      parentHandle = objectTable.getHandle(parent);
+      indexInParent = parent.typeParameters.indexOf(param);
+      if (indexInParent < 0) {
+        throw 'Type parameter $param is not found in its parent class $parent';
+      }
+    } else if (parent is FunctionNode) {
+      final funcParent = parent.parent;
+      if (funcParent is Member) {
+        parentHandle = objectTable.getHandle(funcParent);
+      } else if (funcParent is FunctionExpression ||
+          funcParent is FunctionDeclaration) {
+        parentHandle = objectTable.getHandle(parent);
+      } else {
+        throw 'Unexpected parent of FunctionNode: ${funcParent.runtimeType} $funcParent';
+      }
+      indexInParent = parent.typeParameters.indexOf(node.parameter);
+      if (indexInParent < 0) {
+        throw 'Type parameter $param is not found in its parent function $parent';
+      }
+    } else {
+      throw 'Unexpected parent of TypeParameter: ${parent.runtimeType} $parent';
+    }
+    return objectTable
+        .getOrAddObject(new _TypeParameterHandle(parentHandle, indexInParent));
+  }
+
+  @override
+  ObjectHandle visitFunctionType(FunctionType node) {
+    final typeParameters = new List<_TypeParameterHandle>.generate(
+        node.typeParameters.length,
+        (i) => objectTable.getOrAddObject(new _TypeParameterHandle(null, i)));
+    for (int i = 0; i < node.typeParameters.length; ++i) {
+      _typeParameters[node.typeParameters[i]] = typeParameters[i];
+    }
+
+    final positionalParams = new List<_TypeHandle>();
+    for (var param in node.positionalParameters) {
+      positionalParams.add(objectTable.getHandle(param));
+    }
+    final namedParams = new List<NameAndType>();
+    for (var param in node.namedParameters) {
+      namedParams.add(new NameAndType(
+          objectTable.getNameHandle(null, param.name),
+          objectTable.getHandle(param.type)));
+    }
+    final returnType = objectTable.getHandle(node.returnType);
+
+    for (int i = 0; i < node.typeParameters.length; ++i) {
+      _typeParameters.remove(node.typeParameters[i]);
+    }
+
+    return objectTable.getOrAddObject(new _FunctionTypeHandle(
+        node.typeParameters
+            .map((tp) => new NameAndType(
+                objectTable.getNameHandle(null, tp.name),
+                objectTable.getHandle(tp.bound)))
+            .toList(),
+        node.requiredParameterCount,
+        positionalParams,
+        namedParams,
+        returnType));
+  }
+
+  @override
+  ObjectHandle visitTypedefType(TypedefType node) =>
+      objectTable.getHandle(node.unalias);
+}
+
+int _combineHashes(int hash1, int hash2) =>
+    (((hash1 * 31) & 0x3fffffff) + hash2) & 0x3fffffff;
diff --git a/pkg/vm/lib/bytecode/source_positions.dart b/pkg/vm/lib/bytecode/source_positions.dart
index 055f394..ce4bc3a 100644
--- a/pkg/vm/lib/bytecode/source_positions.dart
+++ b/pkg/vm/lib/bytecode/source_positions.dart
@@ -4,7 +4,7 @@
 
 library vm.bytecode.source_positions;
 
-import 'dart:io' show BytesBuilder;
+import 'bytecode_serialization.dart' show BufferedWriter, BufferedReader;
 
 /// Maintains mapping between bytecode instructions and source positions.
 class SourcePositions {
@@ -24,20 +24,28 @@
     }
   }
 
-  List<int> toBytes() {
-    final write = new BufferedWriter();
-    write.writePackedUInt30(mapping.length);
+  void writeContents(BufferedWriter writer) {
+    writer.writePackedUInt30(mapping.length);
     final encodePC = new PackedUInt30DeltaEncoder();
     final encodeOffset = new SLEB128DeltaEncoder();
     mapping.forEach((int pc, int fileOffset) {
-      encodePC.write(write, pc);
-      encodeOffset.write(write, fileOffset);
+      encodePC.write(writer, pc);
+      encodeOffset.write(writer, fileOffset);
     });
-    return write.buffer.takeBytes();
   }
 
-  SourcePositions.fromBytes(List<int> bytes) {
-    final reader = new BufferedReader(bytes);
+  void write(BufferedWriter writer) {
+    // TODO(alexmarkov): write source positions in a separate section
+    BufferedWriter contentsWriter = new BufferedWriter.fromWriter(writer);
+    writeContents(contentsWriter);
+
+    final contents = contentsWriter.takeBytes();
+    writer.writePackedUInt30(contents.length);
+    writer.writeBytes(contents);
+  }
+
+  SourcePositions.read(BufferedReader reader) {
+    reader.readPackedUInt30(); // Contents length in bytes.
     final int length = reader.readPackedUInt30();
     final decodePC = new PackedUInt30DeltaDecoder();
     final decodeOffset = new SLEB128DeltaDecoder();
@@ -57,84 +65,6 @@
   }
 }
 
-class BufferedWriter {
-  final BytesBuilder buffer = new BytesBuilder();
-
-  void writePackedUInt30(int value) {
-    if ((value >> 30) != 0) {
-      throw 'Value $value is out of range';
-    }
-    if (value < 0x80) {
-      buffer.addByte(value);
-    } else if (value < 0x4000) {
-      buffer.addByte((value >> 8) | 0x80);
-      buffer.addByte(value & 0xFF);
-    } else {
-      buffer.addByte((value >> 24) | 0xC0);
-      buffer.addByte((value >> 16) & 0xFF);
-      buffer.addByte((value >> 8) & 0xFF);
-      buffer.addByte(value & 0xFF);
-    }
-  }
-
-  void writeSLEB128(int value) {
-    bool last = false;
-    do {
-      int part = value & 0x7f;
-      value >>= 7;
-      if ((value == 0 && (part & 0x40) == 0) ||
-          (value == -1 && (part & 0x40) != 0)) {
-        last = true;
-      } else {
-        part |= 0x80;
-      }
-      buffer.addByte(part);
-    } while (!last);
-  }
-}
-
-class BufferedReader {
-  final List<int> _buffer;
-  int _pos = 0;
-
-  BufferedReader(this._buffer);
-
-  int readByte() => _buffer[_pos++];
-
-  int readPackedUInt30() {
-    var byte = readByte();
-    if (byte & 0x80 == 0) {
-      // 0xxxxxxx
-      return byte;
-    } else if (byte & 0x40 == 0) {
-      // 10xxxxxx
-      return ((byte & 0x3F) << 8) | readByte();
-    } else {
-      // 11xxxxxx
-      return ((byte & 0x3F) << 24) |
-          (readByte() << 16) |
-          (readByte() << 8) |
-          readByte();
-    }
-  }
-
-  int readSLEB128() {
-    int value = 0;
-    int shift = 0;
-    int part = 0;
-    do {
-      part = readByte();
-      value |= (part & 0x7f) << shift;
-      shift += 7;
-    } while ((part & 0x80) != 0);
-    const int kBitsPerInt = 64;
-    if ((shift < kBitsPerInt) && ((part & 0x40) != 0)) {
-      value |= (-1) << shift;
-    }
-    return value;
-  }
-}
-
 class PackedUInt30DeltaEncoder {
   int _last = 0;
 
diff --git a/pkg/vm/lib/metadata/bytecode.dart b/pkg/vm/lib/metadata/bytecode.dart
index e333cfc..7a86c70 100644
--- a/pkg/vm/lib/metadata/bytecode.dart
+++ b/pkg/vm/lib/metadata/bytecode.dart
@@ -5,26 +5,37 @@
 library vm.metadata.bytecode;
 
 import 'package:kernel/ast.dart';
+import '../bytecode/bytecode_serialization.dart'
+    show BufferedWriter, BufferedReader, StringTable;
 import '../bytecode/constant_pool.dart' show ConstantPool;
 import '../bytecode/dbc.dart'
-    show stableBytecodeFormatVersion, futureBytecodeFormatVersion;
+    show
+        stableBytecodeFormatVersion,
+        futureBytecodeFormatVersion,
+        bytecodeInstructionsAlignment;
 import '../bytecode/disassembler.dart' show BytecodeDisassembler;
 import '../bytecode/exceptions.dart' show ExceptionsTable;
+import '../bytecode/object_table.dart'
+    show ObjectTable, ObjectHandle, NameAndType;
 import '../bytecode/source_positions.dart' show SourcePositions;
 
-/// Metadata containing bytecode.
+abstract class BytecodeMetadata {
+  void write(BufferedWriter writer);
+}
+
+/// Bytecode of a member is encoded in the following way:
 ///
-/// In kernel binary, bytecode metadata is encoded as following:
-///
-/// type BytecodeMetadata {
-///   UInt bytecodeFormatVersion
+/// type MemberBytecode {
 ///   UInt flags (HasExceptionsTable, HasSourcePositions, HasNullableFields,
 ///               HasClosures)
+///
+///   (optional, present if HasClosures)
+///   List<ClosureDeclaration> closureDeclarations
+///
 ///   ConstantPool constantPool
 ///
 ///   UInt bytecodeSizeInBytes
-///   Byte paddingSizeInBytes
-///   Byte[paddingSizeInBytes] padding
+///   Byte[] padding
 ///   Byte[bytecodeSizeInBytes] bytecodes
 ///
 ///   (optional, present if HasExceptionsTable)
@@ -34,19 +45,38 @@
 ///   SourcePositions sourcePositionsTabe
 ///
 ///   (optional, present if HasNullableFields)
-///   List<CanonicalName> nullableFields
+///   List<PackedObject> nullableFields
 ///
 ///   (optional, present if HasClosures)
-///   List<ClosureBytecode> closures
+///   ClosureBytecode[] closures
+/// }
+///
+/// type ClosureDeclaration {
+///   UInt flags (hasOptionalPositionalParams, hasOptionalNamedParams,
+///               hasTypeParams)
+///
+///   PackedObject parent // Member or Closure
+///   PackedObject name
+///
+///   if hasTypeParams
+///     UInt numTypeParameters
+///     PackedObject[numTypeParameters] typeParameterNames
+///     PackedObject[numTypeParameters] typeParameterBounds
+///
+///   UInt numParameters
+///
+///   if hasOptionalPositionalParams || hasOptionalNamedParams
+///     UInt numRequiredParameters
+///
+///   NameAndType[numParameters] parameters
+///   PackedObject returnType
 /// }
 ///
 /// type ClosureBytecode {
-///   ConstantIndex closureFunction
 ///   UInt flags (HasExceptionsTable, HasSourcePositions)
 ///
 ///   UInt bytecodeSizeInBytes
-///   Byte paddingSizeInBytes
-///   Byte[paddingSizeInBytes] padding
+///   Byte[] padding
 ///   Byte[bytecodeSizeInBytes] bytecodes
 ///
 ///   (optional, present if HasExceptionsTable)
@@ -62,19 +92,18 @@
 /// Encoding of ConstantPool is described in
 /// pkg/vm/lib/bytecode/constant_pool.dart.
 ///
-class BytecodeMetadata {
+class MemberBytecode extends BytecodeMetadata {
   static const hasExceptionsTableFlag = 1 << 0;
   static const hasSourcePositionsFlag = 1 << 1;
   static const hasNullableFieldsFlag = 1 << 2;
   static const hasClosuresFlag = 1 << 3;
 
-  final int version;
   final ConstantPool constantPool;
   final List<int> bytecodes;
   final ExceptionsTable exceptionsTable;
   final SourcePositions sourcePositions;
-  final List<Reference> nullableFields;
-  final List<ClosureBytecode> closures;
+  final List<ObjectHandle> nullableFields;
+  final List<ClosureDeclaration> closures;
 
   bool get hasExceptionsTable => exceptionsTable.blocks.isNotEmpty;
   bool get hasSourcePositions => sourcePositions.mapping.isNotEmpty;
@@ -87,35 +116,197 @@
       (hasNullableFields ? hasNullableFieldsFlag : 0) |
       (hasClosures ? hasClosuresFlag : 0);
 
-  BytecodeMetadata(
-      this.version,
-      this.constantPool,
-      this.bytecodes,
-      this.exceptionsTable,
-      this.sourcePositions,
-      this.nullableFields,
-      this.closures);
+  MemberBytecode(this.constantPool, this.bytecodes, this.exceptionsTable,
+      this.sourcePositions, this.nullableFields, this.closures);
+
+  @override
+  void write(BufferedWriter writer) {
+    writer.writePackedUInt30(flags);
+    if (hasClosures) {
+      writer.writePackedUInt30(closures.length);
+      closures.forEach((c) => c.write(writer));
+    }
+    constantPool.write(writer);
+    _writeBytecodeInstructions(writer, bytecodes);
+    if (hasExceptionsTable) {
+      exceptionsTable.write(writer);
+    }
+    if (hasSourcePositions) {
+      sourcePositions.write(writer);
+    }
+    if (hasNullableFields) {
+      writer.writePackedList(nullableFields);
+    }
+    if (hasClosures) {
+      closures.forEach((c) => c.bytecode.write(writer));
+    }
+  }
+
+  factory MemberBytecode.read(BufferedReader reader) {
+    int flags = reader.readPackedUInt30();
+    final List<ClosureDeclaration> closures = ((flags & hasClosuresFlag) != 0)
+        ? new List<ClosureDeclaration>.generate(reader.readPackedUInt30(),
+            (_) => new ClosureDeclaration.read(reader))
+        : const <ClosureDeclaration>[];
+    final ConstantPool constantPool = new ConstantPool.read(reader);
+    final List<int> bytecodes = _readBytecodeInstructions(reader);
+    final exceptionsTable = ((flags & hasExceptionsTableFlag) != 0)
+        ? new ExceptionsTable.read(reader)
+        : new ExceptionsTable();
+    final sourcePositions = ((flags & hasSourcePositionsFlag) != 0)
+        ? new SourcePositions.read(reader)
+        : new SourcePositions();
+    final List<ObjectHandle> nullableFields =
+        ((flags & hasNullableFieldsFlag) != 0)
+            ? reader.readPackedList<ObjectHandle>()
+            : const <ObjectHandle>[];
+    for (var c in closures) {
+      c.bytecode = new ClosureBytecode.read(reader);
+    }
+    return new MemberBytecode(constantPool, bytecodes, exceptionsTable,
+        sourcePositions, nullableFields, closures);
+  }
 
   // TODO(alexmarkov): Consider printing constant pool before bytecode.
   @override
   String toString() => "\n"
-      "Bytecode"
-      " (version: "
-      "${version == stableBytecodeFormatVersion ? 'stable' : version == futureBytecodeFormatVersion ? 'future' : "v$version"}"
-      ") {\n"
+      "Bytecode {\n"
       "${new BytecodeDisassembler().disassemble(bytecodes, exceptionsTable, annotations: [
         sourcePositions.getBytecodeAnnotations()
       ])}}\n"
       "$exceptionsTable"
-      "${nullableFields.isEmpty ? '' : 'Nullable fields: ${nullableFields.map((ref) => ref.asField).toList()}\n'}"
+      "${nullableFields.isEmpty ? '' : 'Nullable fields: $nullableFields}\n'}"
       "$constantPool"
       "${closures.join('\n')}";
 }
 
+class ClosureDeclaration {
+  static const int flagHasOptionalPositionalParams = 1 << 0;
+  static const int flagHasOptionalNamedParams = 1 << 1;
+  static const int flagHasTypeParams = 1 << 2;
+
+  final ObjectHandle parent;
+  final ObjectHandle name;
+  final List<NameAndType> typeParams;
+  final int numRequiredParams;
+  final int numNamedParams;
+  final List<NameAndType> parameters;
+  final ObjectHandle returnType;
+  ClosureBytecode bytecode;
+
+  ClosureDeclaration(
+      this.parent,
+      this.name,
+      this.typeParams,
+      this.numRequiredParams,
+      this.numNamedParams,
+      this.parameters,
+      this.returnType);
+
+  void write(BufferedWriter writer) {
+    int flags = 0;
+    if (numRequiredParams != parameters.length) {
+      if (numNamedParams > 0) {
+        flags |= flagHasOptionalNamedParams;
+      } else {
+        flags |= flagHasOptionalPositionalParams;
+      }
+    }
+    if (typeParams.isNotEmpty) {
+      flags |= flagHasTypeParams;
+    }
+    writer.writePackedUInt30(flags);
+    writer.writePackedObject(parent);
+    writer.writePackedObject(name);
+
+    if (flags & flagHasTypeParams != 0) {
+      writer.writePackedUInt30(typeParams.length);
+      for (var tp in typeParams) {
+        writer.writePackedObject(tp.name);
+      }
+      for (var tp in typeParams) {
+        writer.writePackedObject(tp.type);
+      }
+    }
+    writer.writePackedUInt30(parameters.length);
+    if (flags &
+            (flagHasOptionalPositionalParams | flagHasOptionalNamedParams) !=
+        0) {
+      writer.writePackedUInt30(numRequiredParams);
+    }
+    for (var param in parameters) {
+      writer.writePackedObject(param.name);
+      writer.writePackedObject(param.type);
+    }
+    writer.writePackedObject(returnType);
+  }
+
+  factory ClosureDeclaration.read(BufferedReader reader) {
+    final int flags = reader.readPackedUInt30();
+    final parent = reader.readPackedObject();
+    final name = reader.readPackedObject();
+    List<NameAndType> typeParams;
+    if ((flags & flagHasTypeParams) != 0) {
+      final int numTypeParams = reader.readPackedUInt30();
+      List<ObjectHandle> names = new List<ObjectHandle>.generate(
+          numTypeParams, (_) => reader.readPackedObject());
+      List<ObjectHandle> bounds = new List<ObjectHandle>.generate(
+          numTypeParams, (_) => reader.readPackedObject());
+      typeParams = new List<NameAndType>.generate(
+          numTypeParams, (int i) => new NameAndType(names[i], bounds[i]));
+    } else {
+      typeParams = const <NameAndType>[];
+    }
+    final numParams = reader.readPackedUInt30();
+    final numRequiredParams = (flags &
+                (flagHasOptionalPositionalParams |
+                    flagHasOptionalNamedParams) !=
+            0)
+        ? reader.readPackedUInt30()
+        : numParams;
+    final numNamedParams = (flags & flagHasOptionalNamedParams != 0)
+        ? (numParams - numRequiredParams)
+        : 0;
+    final List<NameAndType> parameters = new List<NameAndType>.generate(
+        numParams,
+        (_) => new NameAndType(
+            reader.readPackedObject(), reader.readPackedObject()));
+    final returnType = reader.readPackedObject();
+    return new ClosureDeclaration(parent, name, typeParams, numRequiredParams,
+        numNamedParams, parameters, returnType);
+  }
+
+  @override
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write('Closure $parent::$name');
+    if (typeParams.isNotEmpty) {
+      sb.write(' <${typeParams.join(', ')}>');
+    }
+    sb.write(' (');
+    sb.write(parameters.sublist(0, numRequiredParams).join(', '));
+    if (numRequiredParams != parameters.length) {
+      if (numRequiredParams > 0) {
+        sb.write(', ');
+      }
+      if (numNamedParams > 0) {
+        sb.write('{ ${parameters.sublist(numRequiredParams).join(', ')} }');
+      } else {
+        sb.write('[ ${parameters.sublist(numRequiredParams).join(', ')} ]');
+      }
+    }
+    sb.write(') -> ');
+    sb.writeln(returnType);
+    if (bytecode != null) {
+      sb.write(bytecode.toString());
+    }
+    return sb.toString();
+  }
+}
+
 /// Bytecode of a nested function (closure).
 /// Closures share the constant pool of a top-level member.
 class ClosureBytecode {
-  final int closureFunctionConstantIndex;
   final List<int> bytecodes;
   final ExceptionsTable exceptionsTable;
   final SourcePositions sourcePositions;
@@ -124,44 +315,40 @@
   bool get hasSourcePositions => sourcePositions.mapping.isNotEmpty;
 
   int get flags =>
-      (hasExceptionsTable ? BytecodeMetadata.hasExceptionsTableFlag : 0) |
-      (hasSourcePositions ? BytecodeMetadata.hasSourcePositionsFlag : 0);
+      (hasExceptionsTable ? MemberBytecode.hasExceptionsTableFlag : 0) |
+      (hasSourcePositions ? MemberBytecode.hasSourcePositionsFlag : 0);
 
-  ClosureBytecode(this.closureFunctionConstantIndex, this.bytecodes,
-      this.exceptionsTable, this.sourcePositions);
+  ClosureBytecode(this.bytecodes, this.exceptionsTable, this.sourcePositions);
 
-  void writeToBinary(BinarySink sink) {
-    sink.writeUInt30(closureFunctionConstantIndex);
-    sink.writeUInt30(flags);
-    _writeBytecodeInstructions(sink, bytecodes);
+  void write(BufferedWriter writer) {
+    writer.writePackedUInt30(flags);
+    _writeBytecodeInstructions(writer, bytecodes);
     if (hasExceptionsTable) {
-      exceptionsTable.writeToBinary(sink);
+      exceptionsTable.write(writer);
     }
     if (hasSourcePositions) {
-      sink.writeByteList(sourcePositions.toBytes());
+      sourcePositions.write(writer);
     }
   }
 
-  factory ClosureBytecode.readFromBinary(BinarySource source) {
-    final closureFunctionConstantIndex = source.readUInt();
-    final int flags = source.readUInt();
-    final List<int> bytecodes = _readBytecodeInstructions(source);
+  factory ClosureBytecode.read(BufferedReader reader) {
+    final int flags = reader.readPackedUInt30();
+    final List<int> bytecodes = _readBytecodeInstructions(reader);
     final exceptionsTable =
-        ((flags & BytecodeMetadata.hasExceptionsTableFlag) != 0)
-            ? new ExceptionsTable.readFromBinary(source)
+        ((flags & MemberBytecode.hasExceptionsTableFlag) != 0)
+            ? new ExceptionsTable.read(reader)
             : new ExceptionsTable();
     final sourcePositions =
-        ((flags & BytecodeMetadata.hasSourcePositionsFlag) != 0)
-            ? new SourcePositions.fromBytes(source.readByteList())
+        ((flags & MemberBytecode.hasSourcePositionsFlag) != 0)
+            ? new SourcePositions.read(reader)
             : new SourcePositions();
-    return new ClosureBytecode(closureFunctionConstantIndex, bytecodes,
-        exceptionsTable, sourcePositions);
+    return new ClosureBytecode(bytecodes, exceptionsTable, sourcePositions);
   }
 
   @override
   String toString() {
     StringBuffer sb = new StringBuffer();
-    sb.writeln('Closure CP#$closureFunctionConstantIndex {');
+    sb.writeln('ClosureBytecode {');
     sb.writeln(new BytecodeDisassembler().disassemble(
         bytecodes, exceptionsTable,
         annotations: [sourcePositions.getBytecodeAnnotations()]));
@@ -170,6 +357,62 @@
   }
 }
 
+class BytecodeComponent extends BytecodeMetadata {
+  int version;
+  StringTable stringTable;
+  ObjectTable objectTable;
+
+  BytecodeComponent(this.version)
+      : stringTable = new StringTable(),
+        objectTable = new ObjectTable();
+
+  @override
+  void write(BufferedWriter writer) {
+    objectTable.allocateIndexTable();
+
+    // Writing object table may add new strings to strings table,
+    // so serialize object table first.
+    BufferedWriter objectsWriter = new BufferedWriter.fromWriter(writer);
+    objectTable.write(objectsWriter);
+
+    BufferedWriter stringsWriter = new BufferedWriter.fromWriter(writer);
+    stringTable.write(stringsWriter);
+
+    writer.writePackedUInt30(version);
+    writer.writePackedUInt30(stringsWriter.offset);
+    writer.writePackedUInt30(objectsWriter.offset);
+
+    writer.writeBytes(stringsWriter.takeBytes());
+    writer.writeBytes(objectsWriter.takeBytes());
+  }
+
+  BytecodeComponent.read(BufferedReader reader) {
+    version = reader.readPackedUInt30();
+    if (version != stableBytecodeFormatVersion &&
+        version != futureBytecodeFormatVersion) {
+      throw 'Error: unexpected bytecode version $version';
+    }
+    reader.formatVersion = version;
+    reader.readPackedUInt30(); // Strings size
+    reader.readPackedUInt30(); // Objects size
+
+    stringTable = new StringTable.read(reader);
+    reader.stringReader = stringTable;
+
+    objectTable = new ObjectTable.read(reader);
+    reader.objectReader = objectTable;
+  }
+
+  String toString() => "\n"
+      "Bytecode"
+      " (version: "
+      "${version == stableBytecodeFormatVersion ? 'stable' : version == futureBytecodeFormatVersion ? 'future' : "v$version"}"
+      ")\n"
+//      "$objectTable\n"
+//      "$stringTable\n"
+      ;
+}
+
 /// Repository for [BytecodeMetadata].
 class BytecodeMetadataRepository extends MetadataRepository<BytecodeMetadata> {
   @override
@@ -179,89 +422,49 @@
   final Map<TreeNode, BytecodeMetadata> mapping =
       <TreeNode, BytecodeMetadata>{};
 
+  BytecodeComponent bytecodeComponent;
+
   @override
   void writeToBinary(BytecodeMetadata metadata, Node node, BinarySink sink) {
-    sink.writeUInt30(metadata.version);
-    sink.writeUInt30(metadata.flags);
-    metadata.constantPool.writeToBinary(node, sink);
-    _writeBytecodeInstructions(sink, metadata.bytecodes);
-    if (metadata.hasExceptionsTable) {
-      metadata.exceptionsTable.writeToBinary(sink);
+    if (node is Component) {
+      bytecodeComponent = metadata as BytecodeComponent;
+    } else {
+      assert(bytecodeComponent != null);
     }
-    if (metadata.hasSourcePositions) {
-      sink.writeByteList(metadata.sourcePositions.toBytes());
-    }
-    if (metadata.hasNullableFields) {
-      sink.writeUInt30(metadata.nullableFields.length);
-      metadata.nullableFields.forEach((ref) => sink
-          .writeCanonicalNameReference(getCanonicalNameOfMember(ref.asField)));
-    }
-    if (metadata.hasClosures) {
-      sink.writeUInt30(metadata.closures.length);
-      metadata.closures.forEach((c) => c.writeToBinary(sink));
-    }
+    final writer = new BufferedWriter(bytecodeComponent.version,
+        bytecodeComponent.stringTable, bytecodeComponent.objectTable,
+        baseOffset: sink.getBufferOffset());
+    metadata.write(writer);
+    sink.writeBytes(writer.takeBytes());
   }
 
   @override
   BytecodeMetadata readFromBinary(Node node, BinarySource source) {
-    int version = source.readUInt();
-    if (version != stableBytecodeFormatVersion &&
-        version != futureBytecodeFormatVersion) {
-      throw 'Error: unexpected bytecode version $version';
+    if (node is Component) {
+      final reader = new BufferedReader(-1, null, null, source.bytes,
+          baseOffset: source.currentOffset);
+      bytecodeComponent = new BytecodeComponent.read(reader);
+      return bytecodeComponent;
+    } else {
+      final reader = new BufferedReader(
+          bytecodeComponent.version,
+          bytecodeComponent.stringTable,
+          bytecodeComponent.objectTable,
+          source.bytes,
+          baseOffset: source.currentOffset);
+      return new MemberBytecode.read(reader);
     }
-    int flags = source.readUInt();
-    final ConstantPool constantPool =
-        new ConstantPool.readFromBinary(node, source);
-    final List<int> bytecodes = _readBytecodeInstructions(source);
-    final exceptionsTable =
-        ((flags & BytecodeMetadata.hasExceptionsTableFlag) != 0)
-            ? new ExceptionsTable.readFromBinary(source)
-            : new ExceptionsTable();
-    final sourcePositions =
-        ((flags & BytecodeMetadata.hasSourcePositionsFlag) != 0)
-            ? new SourcePositions.fromBytes(source.readByteList())
-            : new SourcePositions();
-    final List<Reference> nullableFields =
-        ((flags & BytecodeMetadata.hasNullableFieldsFlag) != 0)
-            ? new List<Reference>.generate(source.readUInt(),
-                (_) => source.readCanonicalNameReference().getReference())
-            : const <Reference>[];
-    final List<ClosureBytecode> closures =
-        ((flags & BytecodeMetadata.hasClosuresFlag) != 0)
-            ? new List<ClosureBytecode>.generate(source.readUInt(),
-                (_) => new ClosureBytecode.readFromBinary(source))
-            : const <ClosureBytecode>[];
-    return new BytecodeMetadata(version, constantPool, bytecodes,
-        exceptionsTable, sourcePositions, nullableFields, closures);
   }
 }
 
-void _writeBytecodeInstructions(BinarySink sink, List<int> bytecodes) {
-  sink.writeUInt30(bytecodes.length);
-  _writeBytecodePadding(sink);
-  sink.writeBytes(bytecodes);
+void _writeBytecodeInstructions(BufferedWriter writer, List<int> bytecodes) {
+  writer.writePackedUInt30(bytecodes.length);
+  writer.align(bytecodeInstructionsAlignment);
+  writer.writeBytes(bytecodes);
 }
 
-List<int> _readBytecodeInstructions(BinarySource source) {
-  int len = source.readUInt();
-  _readBytecodePadding(source);
-  return source.readBytes(len);
-}
-
-void _writeBytecodePadding(BinarySink sink) {
-  const int bytecodeAlignment = 4;
-  int offset = sink.getBufferOffset() + 1; // +1 is for the length.
-  int len = ((offset + bytecodeAlignment - 1) & -bytecodeAlignment) - offset;
-  sink.writeByte(len);
-  for (int i = 0; i < len; ++i) {
-    sink.writeByte(0);
-  }
-  assert((sink.getBufferOffset() & (bytecodeAlignment - 1)) == 0);
-}
-
-void _readBytecodePadding(BinarySource source) {
-  int len = source.readByte();
-  for (int i = 0; i < len; ++i) {
-    source.readByte();
-  }
+List<int> _readBytecodeInstructions(BufferedReader reader) {
+  int len = reader.readPackedUInt30();
+  reader.align(bytecodeInstructionsAlignment);
+  return reader.readBytesAsUint8List(len);
 }
diff --git a/pkg/vm/test/bytecode/gen_bytecode_test.dart b/pkg/vm/test/bytecode/gen_bytecode_test.dart
index 1cb36de..f821480 100644
--- a/pkg/vm/test/bytecode/gen_bytecode_test.dart
+++ b/pkg/vm/test/bytecode/gen_bytecode_test.dart
@@ -34,7 +34,11 @@
     generateBytecode(component, omitAssertSourcePositions: true);
   });
 
-  final actual = kernelLibraryToString(component.mainMethod.enclosingLibrary);
+  String actual = kernelLibraryToString(component.mainMethod.enclosingLibrary);
+
+  // Remove absolute library URIs.
+  actual = actual.replaceAll(new Uri.file(pkgVmDir).toString(), '#pkg/vm');
+
   compareResultWithExpectationsFile(source, actual);
 }
 
diff --git a/pkg/vm/test/common_test_utils.dart b/pkg/vm/test/common_test_utils.dart
index 2e5cbbd..9669536 100644
--- a/pkg/vm/test/common_test_utils.dart
+++ b/pkg/vm/test/common_test_utils.dart
@@ -54,7 +54,9 @@
   final StringBuffer buffer = new StringBuffer();
   new Printer(buffer, showExternal: false, showMetadata: true)
       .writeLibraryFile(library);
-  return buffer.toString();
+  return buffer
+      .toString()
+      .replaceAll(library.importUri.toString(), library.name);
 }
 
 class DevNullSink<T> extends Sink<T> {
diff --git a/pkg/vm/testcases/bytecode/asserts.dart.expect b/pkg/vm/testcases/bytecode/asserts.dart.expect
index e61e22a..a7706b7 100644
--- a/pkg/vm/testcases/bytecode/asserts.dart.expect
+++ b/pkg/vm/testcases/bytecode/asserts.dart.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   JumpIfNoAsserts      L1
@@ -22,13 +22,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 3, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::_AssertionError::_throwNew', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::_AssertionError::_throwNew', arg-desc CP#0
 }
 ]static method test1(core::bool condition) → void {
   assert(condition);
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   JumpIfNoAsserts      L1
@@ -52,13 +52,13 @@
   [1] = ICData dynamic target-name 'call', arg-desc CP#0
   [2] = ICData dynamic target-name 'call', arg-desc CP#0
   [3] = ArgDesc num-args 3, num-type-args 0, names []
-  [4] = StaticICData target 'dart.core::_AssertionError::_throwNew', arg-desc CP#3
+  [4] = StaticICData target 'dart:core::_AssertionError::_throwNew', arg-desc CP#3
 }
 ]static method test2(() → core::bool condition, () → core::String message) → void {
   assert([@vm.call-site-attributes.metadata=receiverType:() → dart.core::bool] condition.call(), [@vm.call-site-attributes.metadata=receiverType:() → dart.core::String] message.call());
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
diff --git a/pkg/vm/testcases/bytecode/async.dart.expect b/pkg/vm/testcases/bytecode/async.dart.expect
index 52a3d89..db9690f 100644
--- a/pkg/vm/testcases/bytecode/async.dart.expect
+++ b/pkg/vm/testcases/bytecode/async.dart.expect
@@ -4,7 +4,7 @@
 import "dart:core" as core;
 
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                3
   CheckStack           0
   Allocate             CP#19
@@ -27,133 +27,45 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = ClosureFunction <anonymous closure> (dart.async::Future<dart.core::int> x) → dart.async::Future<dart.core::Null> /* originally async */ ;
-  [1] = InstanceField dart.core::_Closure::_context
+  [0] = ClosureFunction 0
+  [1] = InstanceField dart:core::_Closure::_context (field)
   [2] = Reserved
-  [3] = Type dart.async::Future<dart.core::int>
+  [3] = Type dart:async::Future < dart:core::int >
   [4] = String 'x'
   [5] = SubtypeTestCache
-  [6] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::Null]
+  [6] = TypeArgumentsForInstanceAllocation dart:async::Completer [dart:core::Null]
   [7] = ArgDesc num-args 1, num-type-args 0, names []
-  [8] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#7
-  [9] = ClosureFunction :async_op ([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding ;
+  [8] = StaticICData target 'dart:async::Completer::sync (constructor)', arg-desc CP#7
+  [9] = ClosureFunction 1
   [10] = Null
   [11] = ArgDesc num-args 4, num-type-args 0, names []
-  [12] = StaticICData target 'dart.async::_awaitHelper', arg-desc CP#11
+  [12] = StaticICData target 'dart:async::_awaitHelper', arg-desc CP#11
   [13] = ArgDesc num-args 2, num-type-args 0, names []
-  [14] = StaticICData target 'dart.async::_completeOnAsyncReturn', arg-desc CP#13
+  [14] = StaticICData target 'dart:async::_completeOnAsyncReturn', arg-desc CP#13
   [15] = Type dynamic
   [16] = ArgDesc num-args 3, num-type-args 0, names []
   [17] = ICData target-name 'completeError', arg-desc CP#16
   [18] = EndClosureFunctionScope
-  [19] = Class dart.core::_Closure
-  [20] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [19] = Class dart:core::_Closure
+  [20] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [21] = Reserved
-  [22] = InstanceField dart.core::_Closure::_function_type_arguments
+  [22] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [23] = Reserved
   [24] = EmptyTypeArguments
-  [25] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [25] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [26] = Reserved
-  [27] = InstanceField dart.core::_Closure::_function
+  [27] = InstanceField dart:core::_Closure::_function (field)
   [28] = Reserved
-  [29] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#7
-  [30] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#7
-  [31] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#7
-  [32] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
-  [33] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#13
-  [34] = ICData get target-name 'future', arg-desc CP#7
+  [29] = StaticICData target 'dart:async::_asyncStackTraceHelper', arg-desc CP#7
+  [30] = StaticICData target 'dart:async::_asyncThenWrapperHelper', arg-desc CP#7
+  [31] = StaticICData target 'dart:async::_asyncErrorWrapperHelper', arg-desc CP#7
+  [32] = TypeArgumentsForInstanceAllocation dart:async::Future [dynamic]
+  [33] = StaticICData target 'dart:async::Future::microtask (constructor)', arg-desc CP#13
+  [34] = ICData get target-name 'get:future', arg-desc CP#7
   [35] = EndClosureFunctionScope
 }
-Closure CP#9 {
-  EntryOptional        1, 3, 0
-  LoadConstant         r1, CP#10
-  LoadConstant         r2, CP#10
-  LoadConstant         r3, CP#10
-  Frame                6
-  CheckStack           0
-  Push                 r0
-  LoadFieldTOS         CP#1
-  PopLocal             r4
-  Push                 r4
-  LoadContextVar       0, 5
-  StoreLocal           r5
-  PushInt              0
-  JumpIfNeStrict       L1
-  Push                 r4
-  Push                 r4
-  StoreContextVar      0, 7
-Try #0 start:
-  Push                 r4
-  PushInt              1
-  StoreContextVar      0, 5
-  Push                 r4
-  Push                 r4
-  StoreContextVar      0, 6
-  Push                 r4
-  LoadContextVar       0, 0
-  Push                 r4
-  LoadContextVar       0, 3
-  Push                 r4
-  LoadContextVar       0, 4
-  Push                 r4
-  LoadContextVar       0, 8
-  PushConstant         CP#12
-  IndirectStaticCall   4, CP#11
-  PopLocal             r8
-  PushNull
-  ReturnTOS
-L4:
-  Push                 r2
-  JumpIfNull           L2
-  Push                 r2
-  Push                 r3
-  Throw                1
-L2:
-  Push                 r1
-  Drop1
-  Push                 r4
-  LoadContextVar       0, 1
-  Push                 r4
-  LoadContextVar       0, 2
-  PushConstant         CP#14
-  IndirectStaticCall   2, CP#13
-  Drop1
-  PushNull
-  ReturnTOS
-Try #0 end:
-Try #0 handler:
-  SetFrame             10
-  Push                 r0
-  LoadFieldTOS         CP#1
-  PopLocal             r4
-  Push                 r4
-  LoadContextVar       0, 7
-  PopLocal             r4
-  MoveSpecial          exception, r6
-  MoveSpecial          stackTrace, r7
-  Push                 r6
-  PopLocal             r8
-  Push                 r7
-  PopLocal             r9
-  Push                 r4
-  LoadContextVar       0, 1
-  Push                 r8
-  Push                 r9
-  InstanceCall         3, CP#17
-  Drop1
-  Jump                 L3
-L3:
-  PushNull
-  ReturnTOS
-L1:
-  Push                 r4
-  LoadContextVar       0, 6
-  PopLocal             r4
-  Jump                 L4
-
-}
-
-Closure CP#0 {
+Closure #lib::asyncInFieldInitializer (field)::<anonymous closure> (dart:async::Future < dart:core::int > x) -> dart:async::Future < dart:core::Null >
+ClosureBytecode {
   EntryFixed           2, 4
   CheckStack           0
   Push                 FP[-6]
@@ -244,6 +156,96 @@
   ReturnTOS
 
 }
+
+Closure #lib::asyncInFieldInitializer (field)::Closure/0:::async_op ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
+ClosureBytecode {
+  EntryOptional        1, 3, 0
+  LoadConstant         r1, CP#10
+  LoadConstant         r2, CP#10
+  LoadConstant         r3, CP#10
+  Frame                6
+  CheckStack           0
+  Push                 r0
+  LoadFieldTOS         CP#1
+  PopLocal             r4
+  Push                 r4
+  LoadContextVar       0, 5
+  StoreLocal           r5
+  PushInt              0
+  JumpIfNeStrict       L1
+  Push                 r4
+  Push                 r4
+  StoreContextVar      0, 7
+Try #0 start:
+  Push                 r4
+  PushInt              1
+  StoreContextVar      0, 5
+  Push                 r4
+  Push                 r4
+  StoreContextVar      0, 6
+  Push                 r4
+  LoadContextVar       0, 0
+  Push                 r4
+  LoadContextVar       0, 3
+  Push                 r4
+  LoadContextVar       0, 4
+  Push                 r4
+  LoadContextVar       0, 8
+  PushConstant         CP#12
+  IndirectStaticCall   4, CP#11
+  PopLocal             r8
+  PushNull
+  ReturnTOS
+L4:
+  Push                 r2
+  JumpIfNull           L2
+  Push                 r2
+  Push                 r3
+  Throw                1
+L2:
+  Push                 r1
+  Drop1
+  Push                 r4
+  LoadContextVar       0, 1
+  Push                 r4
+  LoadContextVar       0, 2
+  PushConstant         CP#14
+  IndirectStaticCall   2, CP#13
+  Drop1
+  PushNull
+  ReturnTOS
+Try #0 end:
+Try #0 handler:
+  SetFrame             10
+  Push                 r0
+  LoadFieldTOS         CP#1
+  PopLocal             r4
+  Push                 r4
+  LoadContextVar       0, 7
+  PopLocal             r4
+  MoveSpecial          exception, r6
+  MoveSpecial          stackTrace, r7
+  Push                 r6
+  PopLocal             r8
+  Push                 r7
+  PopLocal             r9
+  Push                 r4
+  LoadContextVar       0, 1
+  Push                 r8
+  Push                 r9
+  InstanceCall         3, CP#17
+  Drop1
+  Jump                 L3
+L3:
+  PushNull
+  ReturnTOS
+L1:
+  Push                 r4
+  LoadContextVar       0, 6
+  PopLocal             r4
+  Jump                 L4
+
+}
 ]static field (asy::Future<core::int>) → asy::Future<core::Null> asyncInFieldInitializer = (asy::Future<core::int> x) → asy::Future<core::Null> /* originally async */ {
   final asy::Completer<core::Null> :async_completer = asy::Completer::sync<core::Null>();
   asy::FutureOr<core::Null> :return_value;
@@ -273,7 +275,7 @@
   return :async_completer.{asy::Completer::future};
 };
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                7
   CheckStack           0
   AllocateContext      0, 4
@@ -339,37 +341,38 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
+  [0] = TypeArgumentsForInstanceAllocation dart:async::Completer [dart:core::int]
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#1
-  [3] = ClosureFunction :async_op ([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding ;
+  [2] = StaticICData target 'dart:async::Completer::sync (constructor)', arg-desc CP#1
+  [3] = ClosureFunction 0
   [4] = Null
-  [5] = InstanceField dart.core::_Closure::_context
+  [5] = InstanceField dart:core::_Closure::_context (field)
   [6] = Reserved
   [7] = ArgDesc num-args 2, num-type-args 0, names []
-  [8] = StaticICData target 'dart.async::_completeOnAsyncReturn', arg-desc CP#7
+  [8] = StaticICData target 'dart:async::_completeOnAsyncReturn', arg-desc CP#7
   [9] = Type dynamic
   [10] = ArgDesc num-args 3, num-type-args 0, names []
   [11] = ICData target-name 'completeError', arg-desc CP#10
   [12] = EndClosureFunctionScope
-  [13] = Class dart.core::_Closure
-  [14] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [13] = Class dart:core::_Closure
+  [14] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [15] = Reserved
-  [16] = InstanceField dart.core::_Closure::_function_type_arguments
+  [16] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [17] = Reserved
   [18] = EmptyTypeArguments
-  [19] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [19] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [20] = Reserved
-  [21] = InstanceField dart.core::_Closure::_function
+  [21] = InstanceField dart:core::_Closure::_function (field)
   [22] = Reserved
-  [23] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#1
-  [24] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#1
-  [25] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#1
-  [26] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
-  [27] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#7
-  [28] = ICData get target-name 'future', arg-desc CP#1
+  [23] = StaticICData target 'dart:async::_asyncStackTraceHelper', arg-desc CP#1
+  [24] = StaticICData target 'dart:async::_asyncThenWrapperHelper', arg-desc CP#1
+  [25] = StaticICData target 'dart:async::_asyncErrorWrapperHelper', arg-desc CP#1
+  [26] = TypeArgumentsForInstanceAllocation dart:async::Future [dynamic]
+  [27] = StaticICData target 'dart:async::Future::microtask (constructor)', arg-desc CP#7
+  [28] = ICData get target-name 'get:future', arg-desc CP#1
 }
-Closure CP#3 {
+Closure #lib::foo:::async_op ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
+ClosureBytecode {
   EntryOptional        1, 3, 0
   LoadConstant         r1, CP#4
   LoadConstant         r2, CP#4
@@ -454,7 +457,7 @@
   return :async_completer.{asy::Completer::future};
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                4
   CheckStack           0
   AllocateContext      0, 11
@@ -541,41 +544,42 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
+  [0] = TypeArgumentsForInstanceAllocation dart:async::Completer [dart:core::int]
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#1
-  [3] = ClosureFunction :async_op ([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding ;
+  [2] = StaticICData target 'dart:async::Completer::sync (constructor)', arg-desc CP#1
+  [3] = ClosureFunction 0
   [4] = Null
-  [5] = InstanceField dart.core::_Closure::_context
+  [5] = InstanceField dart:core::_Closure::_context (field)
   [6] = Reserved
   [7] = ArgDesc num-args 4, num-type-args 0, names []
-  [8] = StaticICData target 'dart.async::_awaitHelper', arg-desc CP#7
-  [9] = StaticICData target 'dart.async::_awaitHelper', arg-desc CP#7
+  [8] = StaticICData target 'dart:async::_awaitHelper', arg-desc CP#7
+  [9] = StaticICData target 'dart:async::_awaitHelper', arg-desc CP#7
   [10] = ArgDesc num-args 2, num-type-args 0, names []
   [11] = ICData target-name '+', arg-desc CP#10
-  [12] = StaticICData target 'dart.async::_completeOnAsyncReturn', arg-desc CP#10
+  [12] = StaticICData target 'dart:async::_completeOnAsyncReturn', arg-desc CP#10
   [13] = Type dynamic
   [14] = ArgDesc num-args 3, num-type-args 0, names []
   [15] = ICData target-name 'completeError', arg-desc CP#14
   [16] = EndClosureFunctionScope
-  [17] = Class dart.core::_Closure
-  [18] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [17] = Class dart:core::_Closure
+  [18] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [19] = Reserved
-  [20] = InstanceField dart.core::_Closure::_function_type_arguments
+  [20] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [21] = Reserved
   [22] = EmptyTypeArguments
-  [23] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [23] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [24] = Reserved
-  [25] = InstanceField dart.core::_Closure::_function
+  [25] = InstanceField dart:core::_Closure::_function (field)
   [26] = Reserved
-  [27] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#1
-  [28] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#1
-  [29] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#1
-  [30] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
-  [31] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#10
-  [32] = ICData get target-name 'future', arg-desc CP#1
+  [27] = StaticICData target 'dart:async::_asyncStackTraceHelper', arg-desc CP#1
+  [28] = StaticICData target 'dart:async::_asyncThenWrapperHelper', arg-desc CP#1
+  [29] = StaticICData target 'dart:async::_asyncErrorWrapperHelper', arg-desc CP#1
+  [30] = TypeArgumentsForInstanceAllocation dart:async::Future [dynamic]
+  [31] = StaticICData target 'dart:async::Future::microtask (constructor)', arg-desc CP#10
+  [32] = ICData get target-name 'get:future', arg-desc CP#1
 }
-Closure CP#3 {
+Closure #lib::simpleAsyncAwait:::async_op ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
+ClosureBytecode {
   EntryOptional        1, 3, 0
   LoadConstant         r1, CP#4
   LoadConstant         r2, CP#4
@@ -734,7 +738,7 @@
   return :async_completer.{asy::Completer::future};
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                4
   CheckStack           0
   AllocateContext      0, 11
@@ -821,46 +825,47 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
+  [0] = TypeArgumentsForInstanceAllocation dart:async::Completer [dart:core::int]
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#1
-  [3] = ClosureFunction :async_op ([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding ;
+  [2] = StaticICData target 'dart:async::Completer::sync (constructor)', arg-desc CP#1
+  [3] = ClosureFunction 0
   [4] = Null
-  [5] = InstanceField dart.core::_Closure::_context
+  [5] = InstanceField dart:core::_Closure::_context (field)
   [6] = Reserved
-  [7] = ICData get target-name 'iterator', arg-desc CP#1
+  [7] = ICData get target-name 'get:iterator', arg-desc CP#1
   [8] = ICData target-name 'moveNext', arg-desc CP#1
-  [9] = ICData get target-name 'current', arg-desc CP#1
+  [9] = ICData get target-name 'get:current', arg-desc CP#1
   [10] = ArgDesc num-args 0, num-type-args 0, names []
   [11] = StaticICData target '#lib::foo', arg-desc CP#10
   [12] = ArgDesc num-args 4, num-type-args 0, names []
-  [13] = StaticICData target 'dart.async::_awaitHelper', arg-desc CP#12
+  [13] = StaticICData target 'dart:async::_awaitHelper', arg-desc CP#12
   [14] = ArgDesc num-args 2, num-type-args 0, names []
   [15] = ICData target-name '+', arg-desc CP#14
   [16] = ICData target-name '+', arg-desc CP#14
-  [17] = StaticICData target 'dart.async::_completeOnAsyncReturn', arg-desc CP#14
+  [17] = StaticICData target 'dart:async::_completeOnAsyncReturn', arg-desc CP#14
   [18] = Type dynamic
   [19] = ArgDesc num-args 3, num-type-args 0, names []
   [20] = ICData target-name 'completeError', arg-desc CP#19
   [21] = EndClosureFunctionScope
-  [22] = Class dart.core::_Closure
-  [23] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [22] = Class dart:core::_Closure
+  [23] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [24] = Reserved
-  [25] = InstanceField dart.core::_Closure::_function_type_arguments
+  [25] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [26] = Reserved
   [27] = EmptyTypeArguments
-  [28] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [28] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [29] = Reserved
-  [30] = InstanceField dart.core::_Closure::_function
+  [30] = InstanceField dart:core::_Closure::_function (field)
   [31] = Reserved
-  [32] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#1
-  [33] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#1
-  [34] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#1
-  [35] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
-  [36] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#14
-  [37] = ICData get target-name 'future', arg-desc CP#1
+  [32] = StaticICData target 'dart:async::_asyncStackTraceHelper', arg-desc CP#1
+  [33] = StaticICData target 'dart:async::_asyncThenWrapperHelper', arg-desc CP#1
+  [34] = StaticICData target 'dart:async::_asyncErrorWrapperHelper', arg-desc CP#1
+  [35] = TypeArgumentsForInstanceAllocation dart:async::Future [dynamic]
+  [36] = StaticICData target 'dart:async::Future::microtask (constructor)', arg-desc CP#14
+  [37] = ICData get target-name 'get:future', arg-desc CP#1
 }
-Closure CP#3 {
+Closure #lib::loops:::async_op ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
+ClosureBytecode {
   EntryOptional        1, 3, 0
   LoadConstant         r1, CP#4
   LoadConstant         r2, CP#4
@@ -1145,7 +1150,7 @@
   return :async_completer.{asy::Completer::future};
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                4
   CheckStack           0
   AllocateContext      0, 16
@@ -1247,54 +1252,55 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
+  [0] = TypeArgumentsForInstanceAllocation dart:async::Completer [dart:core::int]
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#1
-  [3] = ClosureFunction :async_op ([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding ;
+  [2] = StaticICData target 'dart:async::Completer::sync (constructor)', arg-desc CP#1
+  [3] = ClosureFunction 0
   [4] = Null
-  [5] = InstanceField dart.core::_Closure::_context
+  [5] = InstanceField dart:core::_Closure::_context (field)
   [6] = Reserved
   [7] = ArgDesc num-args 4, num-type-args 0, names []
-  [8] = StaticICData target 'dart.async::_awaitHelper', arg-desc CP#7
+  [8] = StaticICData target 'dart:async::_awaitHelper', arg-desc CP#7
   [9] = ArgDesc num-args 2, num-type-args 0, names []
   [10] = ICData target-name '+', arg-desc CP#9
   [11] = Type dynamic
-  [12] = Type dart.core::Error
-  [13] = ICData target-name 'dart.core::_simpleInstanceOf', arg-desc CP#9
-  [14] = StaticICData target 'dart.async::_awaitHelper', arg-desc CP#7
+  [12] = Type dart:core::Error
+  [13] = ICData target-name '_simpleInstanceOf', arg-desc CP#9
+  [14] = StaticICData target 'dart:async::_awaitHelper', arg-desc CP#7
   [15] = ICData target-name '+', arg-desc CP#9
   [16] = String 'fin'
-  [17] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [18] = StaticICData target 'dart.async::_awaitHelper', arg-desc CP#7
+  [17] = StaticICData target 'dart:core::print', arg-desc CP#1
+  [18] = StaticICData target 'dart:async::_awaitHelper', arg-desc CP#7
   [19] = ICData target-name '+', arg-desc CP#9
-  [20] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [21] = StaticICData target 'dart.async::_awaitHelper', arg-desc CP#7
+  [20] = StaticICData target 'dart:core::print', arg-desc CP#1
+  [21] = StaticICData target 'dart:async::_awaitHelper', arg-desc CP#7
   [22] = ICData target-name '+', arg-desc CP#9
-  [23] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [24] = StaticICData target 'dart.async::_awaitHelper', arg-desc CP#7
+  [23] = StaticICData target 'dart:core::print', arg-desc CP#1
+  [24] = StaticICData target 'dart:async::_awaitHelper', arg-desc CP#7
   [25] = ICData target-name '+', arg-desc CP#9
-  [26] = StaticICData target 'dart.async::_completeOnAsyncReturn', arg-desc CP#9
+  [26] = StaticICData target 'dart:async::_completeOnAsyncReturn', arg-desc CP#9
   [27] = ArgDesc num-args 3, num-type-args 0, names []
   [28] = ICData target-name 'completeError', arg-desc CP#27
   [29] = EndClosureFunctionScope
-  [30] = Class dart.core::_Closure
-  [31] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [30] = Class dart:core::_Closure
+  [31] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [32] = Reserved
-  [33] = InstanceField dart.core::_Closure::_function_type_arguments
+  [33] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [34] = Reserved
   [35] = EmptyTypeArguments
-  [36] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [36] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [37] = Reserved
-  [38] = InstanceField dart.core::_Closure::_function
+  [38] = InstanceField dart:core::_Closure::_function (field)
   [39] = Reserved
-  [40] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#1
-  [41] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#1
-  [42] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#1
-  [43] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
-  [44] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#9
-  [45] = ICData get target-name 'future', arg-desc CP#1
+  [40] = StaticICData target 'dart:async::_asyncStackTraceHelper', arg-desc CP#1
+  [41] = StaticICData target 'dart:async::_asyncThenWrapperHelper', arg-desc CP#1
+  [42] = StaticICData target 'dart:async::_asyncErrorWrapperHelper', arg-desc CP#1
+  [43] = TypeArgumentsForInstanceAllocation dart:async::Future [dynamic]
+  [44] = StaticICData target 'dart:async::Future::microtask (constructor)', arg-desc CP#9
+  [45] = ICData get target-name 'get:future', arg-desc CP#1
 }
-Closure CP#3 {
+Closure #lib::tryCatchRethrow:::async_op ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
+ClosureBytecode {
   EntryOptional        1, 3, 0
   LoadConstant         r1, CP#4
   LoadConstant         r2, CP#4
@@ -1778,7 +1784,7 @@
   return :async_completer.{asy::Completer::future};
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                4
   CheckStack           0
   AllocateContext      0, 2
@@ -1811,44 +1817,135 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = ClosureFunction nested () → dart.async::Future<dart.core::int> /* originally async */ ;
-  [1] = InstanceField dart.core::_Closure::_context
+  [0] = ClosureFunction 0
+  [1] = InstanceField dart:core::_Closure::_context (field)
   [2] = Reserved
-  [3] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
+  [3] = TypeArgumentsForInstanceAllocation dart:async::Completer [dart:core::int]
   [4] = ArgDesc num-args 1, num-type-args 0, names []
-  [5] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#4
-  [6] = ClosureFunction :async_op ([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding ;
+  [5] = StaticICData target 'dart:async::Completer::sync (constructor)', arg-desc CP#4
+  [6] = ClosureFunction 1
   [7] = Null
   [8] = ArgDesc num-args 4, num-type-args 0, names []
-  [9] = StaticICData target 'dart.async::_awaitHelper', arg-desc CP#8
+  [9] = StaticICData target 'dart:async::_awaitHelper', arg-desc CP#8
   [10] = Type dynamic
   [11] = String 'fin'
-  [12] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [13] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [12] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [13] = StaticICData target 'dart:core::print', arg-desc CP#4
   [14] = ArgDesc num-args 2, num-type-args 0, names []
-  [15] = StaticICData target 'dart.async::_completeOnAsyncReturn', arg-desc CP#14
+  [15] = StaticICData target 'dart:async::_completeOnAsyncReturn', arg-desc CP#14
   [16] = ArgDesc num-args 3, num-type-args 0, names []
   [17] = ICData target-name 'completeError', arg-desc CP#16
   [18] = EndClosureFunctionScope
-  [19] = Class dart.core::_Closure
-  [20] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [19] = Class dart:core::_Closure
+  [20] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [21] = Reserved
-  [22] = InstanceField dart.core::_Closure::_function_type_arguments
+  [22] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [23] = Reserved
   [24] = EmptyTypeArguments
-  [25] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [25] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [26] = Reserved
-  [27] = InstanceField dart.core::_Closure::_function
+  [27] = InstanceField dart:core::_Closure::_function (field)
   [28] = Reserved
-  [29] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#4
-  [30] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#4
-  [31] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#4
-  [32] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
-  [33] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#14
-  [34] = ICData get target-name 'future', arg-desc CP#4
+  [29] = StaticICData target 'dart:async::_asyncStackTraceHelper', arg-desc CP#4
+  [30] = StaticICData target 'dart:async::_asyncThenWrapperHelper', arg-desc CP#4
+  [31] = StaticICData target 'dart:async::_asyncErrorWrapperHelper', arg-desc CP#4
+  [32] = TypeArgumentsForInstanceAllocation dart:async::Future [dynamic]
+  [33] = StaticICData target 'dart:async::Future::microtask (constructor)', arg-desc CP#14
+  [34] = ICData get target-name 'get:future', arg-desc CP#4
   [35] = EndClosureFunctionScope
 }
-Closure CP#6 {
+Closure #lib::closure::nested () -> dart:async::Future < dart:core::int >
+ClosureBytecode {
+  EntryFixed           1, 4
+  CheckStack           0
+  Push                 FP[-5]
+  LoadFieldTOS         CP#1
+  PopLocal             r0
+  AllocateContext      1, 9
+  StoreLocal           r1
+  Push                 r1
+  Push                 r0
+  StoreContextParent
+  PopLocal             r0
+  Push                 r0
+  PushConstant         CP#3
+  PushConstant         CP#5
+  IndirectStaticCall   1, CP#4
+  StoreContextVar      1, 0
+  Push                 r0
+  PushNull
+  StoreContextVar      1, 1
+  PushNull
+  PopLocal             r2
+  Push                 r0
+  PushNull
+  StoreContextVar      1, 2
+  Push                 r0
+  PushNull
+  StoreContextVar      1, 3
+  Push                 r0
+  PushInt              0
+  StoreContextVar      1, 4
+  Push                 r0
+  PushNull
+  StoreContextVar      1, 5
+  Push                 r0
+  PushNull
+  StoreContextVar      1, 6
+  Push                 r0
+  PushNull
+  StoreContextVar      1, 7
+  Push                 r0
+  Allocate             CP#19
+  StoreLocal           r3
+  Push                 r3
+  PushNull
+  StoreFieldTOS        CP#20
+  Push                 r3
+  PushNull
+  StoreFieldTOS        CP#22
+  Push                 r3
+  PushConstant         CP#24
+  StoreFieldTOS        CP#25
+  Push                 r3
+  PushConstant         CP#6
+  StoreFieldTOS        CP#27
+  Push                 r3
+  Push                 r0
+  StoreFieldTOS        CP#1
+  StoreContextVar      1, 8
+  Push                 r0
+  LoadContextVar       1, 8
+  PushConstant         CP#29
+  IndirectStaticCall   1, CP#4
+  PopLocal             r2
+  Push                 r0
+  Push                 r0
+  LoadContextVar       1, 8
+  PushConstant         CP#30
+  IndirectStaticCall   1, CP#4
+  StoreContextVar      1, 2
+  Push                 r0
+  Push                 r0
+  LoadContextVar       1, 8
+  PushConstant         CP#31
+  IndirectStaticCall   1, CP#4
+  StoreContextVar      1, 3
+  PushConstant         CP#32
+  Push                 r0
+  LoadContextVar       1, 8
+  PushConstant         CP#33
+  IndirectStaticCall   2, CP#14
+  Drop1
+  Push                 r0
+  LoadContextVar       1, 0
+  InstanceCall         1, CP#34
+  ReturnTOS
+
+}
+
+Closure #lib::closure::Closure/0:::async_op ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
+ClosureBytecode {
   EntryOptional        1, 3, 0
   LoadConstant         r1, CP#7
   LoadConstant         r2, CP#7
@@ -2008,95 +2105,6 @@
   Jump                 L6
 
 }
-
-Closure CP#0 {
-  EntryFixed           1, 4
-  CheckStack           0
-  Push                 FP[-5]
-  LoadFieldTOS         CP#1
-  PopLocal             r0
-  AllocateContext      1, 9
-  StoreLocal           r1
-  Push                 r1
-  Push                 r0
-  StoreContextParent
-  PopLocal             r0
-  Push                 r0
-  PushConstant         CP#3
-  PushConstant         CP#5
-  IndirectStaticCall   1, CP#4
-  StoreContextVar      1, 0
-  Push                 r0
-  PushNull
-  StoreContextVar      1, 1
-  PushNull
-  PopLocal             r2
-  Push                 r0
-  PushNull
-  StoreContextVar      1, 2
-  Push                 r0
-  PushNull
-  StoreContextVar      1, 3
-  Push                 r0
-  PushInt              0
-  StoreContextVar      1, 4
-  Push                 r0
-  PushNull
-  StoreContextVar      1, 5
-  Push                 r0
-  PushNull
-  StoreContextVar      1, 6
-  Push                 r0
-  PushNull
-  StoreContextVar      1, 7
-  Push                 r0
-  Allocate             CP#19
-  StoreLocal           r3
-  Push                 r3
-  PushNull
-  StoreFieldTOS        CP#20
-  Push                 r3
-  PushNull
-  StoreFieldTOS        CP#22
-  Push                 r3
-  PushConstant         CP#24
-  StoreFieldTOS        CP#25
-  Push                 r3
-  PushConstant         CP#6
-  StoreFieldTOS        CP#27
-  Push                 r3
-  Push                 r0
-  StoreFieldTOS        CP#1
-  StoreContextVar      1, 8
-  Push                 r0
-  LoadContextVar       1, 8
-  PushConstant         CP#29
-  IndirectStaticCall   1, CP#4
-  PopLocal             r2
-  Push                 r0
-  Push                 r0
-  LoadContextVar       1, 8
-  PushConstant         CP#30
-  IndirectStaticCall   1, CP#4
-  StoreContextVar      1, 2
-  Push                 r0
-  Push                 r0
-  LoadContextVar       1, 8
-  PushConstant         CP#31
-  IndirectStaticCall   1, CP#4
-  StoreContextVar      1, 3
-  PushConstant         CP#32
-  Push                 r0
-  LoadContextVar       1, 8
-  PushConstant         CP#33
-  IndirectStaticCall   2, CP#14
-  Drop1
-  Push                 r0
-  LoadContextVar       1, 0
-  InstanceCall         1, CP#34
-  ReturnTOS
-
-}
 ]static method closure(asy::Future<core::int> a) → dynamic {
   core::int x = 3;
   function nested() → asy::Future<core::int> /* originally async */ {
@@ -2140,7 +2148,7 @@
   return nested;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                4
   CheckStack           0
   AllocateContext      0, 9
@@ -2221,41 +2229,42 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgumentsForInstanceAllocation dart.async::Completer [dart.core::int]
+  [0] = TypeArgumentsForInstanceAllocation dart:async::Completer [dart:core::int]
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.async::Completer::sync', arg-desc CP#1
-  [3] = ClosureFunction :async_op ([dynamic :result, dynamic :exception, dynamic :stack_trace]) → dynamic yielding ;
+  [2] = StaticICData target 'dart:async::Completer::sync (constructor)', arg-desc CP#1
+  [3] = ClosureFunction 0
   [4] = Null
-  [5] = InstanceField dart.core::_Closure::_context
+  [5] = InstanceField dart:core::_Closure::_context (field)
   [6] = Reserved
   [7] = ArgDesc num-args 4, num-type-args 0, names []
-  [8] = StaticICData target 'dart.async::_awaitHelper', arg-desc CP#7
+  [8] = StaticICData target 'dart:async::_awaitHelper', arg-desc CP#7
   [9] = ArgDesc num-args 2, num-type-args 0, names []
   [10] = ICData target-name '==', arg-desc CP#9
   [11] = ArgDesc num-args 3, num-type-args 0, names []
-  [12] = StaticICData target 'dart.core::_AssertionError::_throwNew', arg-desc CP#11
-  [13] = StaticICData target 'dart.async::_completeOnAsyncReturn', arg-desc CP#9
+  [12] = StaticICData target 'dart:core::_AssertionError::_throwNew', arg-desc CP#11
+  [13] = StaticICData target 'dart:async::_completeOnAsyncReturn', arg-desc CP#9
   [14] = Type dynamic
   [15] = ICData target-name 'completeError', arg-desc CP#11
   [16] = EndClosureFunctionScope
-  [17] = Class dart.core::_Closure
-  [18] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [17] = Class dart:core::_Closure
+  [18] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [19] = Reserved
-  [20] = InstanceField dart.core::_Closure::_function_type_arguments
+  [20] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [21] = Reserved
   [22] = EmptyTypeArguments
-  [23] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [23] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [24] = Reserved
-  [25] = InstanceField dart.core::_Closure::_function
+  [25] = InstanceField dart:core::_Closure::_function (field)
   [26] = Reserved
-  [27] = StaticICData target 'dart.async::_asyncStackTraceHelper', arg-desc CP#1
-  [28] = StaticICData target 'dart.async::_asyncThenWrapperHelper', arg-desc CP#1
-  [29] = StaticICData target 'dart.async::_asyncErrorWrapperHelper', arg-desc CP#1
-  [30] = TypeArgumentsForInstanceAllocation dart.async::Future [dynamic]
-  [31] = StaticICData target 'dart.async::Future::microtask', arg-desc CP#9
-  [32] = ICData get target-name 'future', arg-desc CP#1
+  [27] = StaticICData target 'dart:async::_asyncStackTraceHelper', arg-desc CP#1
+  [28] = StaticICData target 'dart:async::_asyncThenWrapperHelper', arg-desc CP#1
+  [29] = StaticICData target 'dart:async::_asyncErrorWrapperHelper', arg-desc CP#1
+  [30] = TypeArgumentsForInstanceAllocation dart:async::Future [dynamic]
+  [31] = StaticICData target 'dart:async::Future::microtask (constructor)', arg-desc CP#9
+  [32] = ICData get target-name 'get:future', arg-desc CP#1
 }
-Closure CP#3 {
+Closure #lib::testAssert:::async_op ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
+ClosureBytecode {
   EntryOptional        1, 3, 0
   LoadConstant         r1, CP#4
   LoadConstant         r2, CP#4
@@ -2393,7 +2402,7 @@
   return :async_completer.{asy::Completer::future};
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
diff --git a/pkg/vm/testcases/bytecode/bootstrapping.dart.expect b/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
index 774c558..5b7b1bf 100644
--- a/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
+++ b/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
@@ -7,7 +7,7 @@
 class _ScheduleImmediate extends core::Object {
   static field (() → void) → void _closure = null;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -19,7 +19,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::_ScheduleImmediate
     : super core::Object::•()
@@ -28,7 +28,7 @@
 class _NamespaceImpl extends core::Object implements self::_Namespace {
   static field self::_NamespaceImpl _cachedNamespace = null;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -40,13 +40,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  constructor _() → self::_NamespaceImpl
     : super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-6]
@@ -60,7 +60,7 @@
 ]  @_in::ExternalName::•("Namespace_Create")
   external static method _create(self::_NamespaceImpl namespace, dynamic n) → self::_NamespaceImpl;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -73,7 +73,7 @@
 ]  @_in::ExternalName::•("Namespace_GetPointer")
   external static method _getPointer(self::_NamespaceImpl namespace) → core::int;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   NativeCall           CP#0
@@ -85,7 +85,7 @@
 ]  @_in::ExternalName::•("Namespace_GetDefault")
   external static method _getDefault() → core::int;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   Allocate             CP#0
@@ -104,16 +104,16 @@
 ConstantPool {
   [0] = Class #lib::_NamespaceImpl
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target '#lib::_NamespaceImpl::_', arg-desc CP#1
+  [2] = StaticICData target '#lib::_NamespaceImpl::_ (constructor)', arg-desc CP#1
   [3] = ArgDesc num-args 2, num-type-args 0, names []
   [4] = StaticICData target '#lib::_NamespaceImpl::_create', arg-desc CP#3
-  [5] = StaticField #lib::_NamespaceImpl::_cachedNamespace
+  [5] = StaticField #lib::_NamespaceImpl::_cachedNamespace (field)
 }
 ]  static method _setupNamespace(dynamic namespace) → void {
     self::_NamespaceImpl::_cachedNamespace = self::_NamespaceImpl::_create(new self::_NamespaceImpl::_(), namespace);
   }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   PushConstant         CP#0
@@ -137,10 +137,10 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = StaticField #lib::_NamespaceImpl::_cachedNamespace
+  [0] = StaticField #lib::_NamespaceImpl::_cachedNamespace (field)
   [1] = Class #lib::_NamespaceImpl
   [2] = ArgDesc num-args 1, num-type-args 0, names []
-  [3] = StaticICData target '#lib::_NamespaceImpl::_', arg-desc CP#2
+  [3] = StaticICData target '#lib::_NamespaceImpl::_ (constructor)', arg-desc CP#2
   [4] = ArgDesc num-args 0, num-type-args 0, names []
   [5] = StaticICData target '#lib::_NamespaceImpl::_getDefault', arg-desc CP#4
   [6] = ArgDesc num-args 2, num-type-args 0, names []
@@ -153,7 +153,7 @@
     return self::_NamespaceImpl::_cachedNamespace;
   }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#1
@@ -164,7 +164,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 0, num-type-args 0, names []
-  [1] = StaticICData get target '#lib::_NamespaceImpl::_namespace', arg-desc CP#0
+  [1] = StaticICData target '#lib::_NamespaceImpl::get:_namespace', arg-desc CP#0
   [2] = ArgDesc num-args 1, num-type-args 0, names []
   [3] = StaticICData target '#lib::_NamespaceImpl::_getPointer', arg-desc CP#2
 }
@@ -173,7 +173,7 @@
 }
 class _Namespace extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -185,13 +185,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::_Namespace
     : super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -209,7 +209,7 @@
     self::_NamespaceImpl::_setupNamespace(namespace);
   }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#1
@@ -218,12 +218,12 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 0, num-type-args 0, names []
-  [1] = StaticICData get target '#lib::_NamespaceImpl::_namespace', arg-desc CP#0
+  [1] = StaticICData target '#lib::_NamespaceImpl::get:_namespace', arg-desc CP#0
 }
 ]  static get _namespace() → self::_Namespace
     return self::_NamespaceImpl::_namespace;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#1
@@ -232,7 +232,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 0, num-type-args 0, names []
-  [1] = StaticICData get target '#lib::_NamespaceImpl::_namespacePointer', arg-desc CP#0
+  [1] = StaticICData target '#lib::_NamespaceImpl::get:_namespacePointer', arg-desc CP#0
 }
 ]  static get _namespacePointer() → core::int
     return self::_NamespaceImpl::_namespacePointer;
@@ -250,7 +250,7 @@
   static field dynamic _computeScriptUri = null;
   static field dynamic _cachedScript = null;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -262,13 +262,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::VMLibraryHooks
     : super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -279,15 +279,15 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = StaticField #lib::VMLibraryHooks::_computeScriptUri
-  [1] = StaticField #lib::VMLibraryHooks::_cachedScript
+  [0] = StaticField #lib::VMLibraryHooks::_computeScriptUri (field)
+  [1] = StaticField #lib::VMLibraryHooks::_cachedScript (field)
 }
 ]  static set platformScript(dynamic f) → void {
     self::VMLibraryHooks::_computeScriptUri = f;
     self::VMLibraryHooks::_cachedScript = null;
   }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   PushConstant         CP#0
@@ -316,8 +316,8 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = StaticField #lib::VMLibraryHooks::_cachedScript
-  [1] = StaticField #lib::VMLibraryHooks::_computeScriptUri
+  [0] = StaticField #lib::VMLibraryHooks::_cachedScript (field)
+  [1] = StaticField #lib::VMLibraryHooks::_computeScriptUri (field)
   [2] = ArgDesc num-args 1, num-type-args 0, names []
   [3] = ICData dynamic target-name 'call', arg-desc CP#2
 }
@@ -330,7 +330,7 @@
 }
 class Stdin extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -342,7 +342,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::Stdin
     : super core::Object::•()
@@ -350,7 +350,7 @@
 }
 class _StdIOUtils extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -362,13 +362,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::_StdIOUtils
     : super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
@@ -385,7 +385,7 @@
 static field core::String _rawScript;
 static field self::Stdin _stdin;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -398,7 +398,7 @@
 ]@_in::ExternalName::•("Builtin_PrintString")
 external static method _printString(core::String s) → void;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -418,7 +418,7 @@
   self::_printString(arg.{core::Object::toString}());
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#0
@@ -430,7 +430,7 @@
 ]static method _getPrintClosure() → dynamic
   return self::_print;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -439,13 +439,13 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = StaticField #lib::_ScheduleImmediate::_closure
+  [0] = StaticField #lib::_ScheduleImmediate::_closure (field)
 }
 ]static method _setScheduleImmediateClosure((() → void) → void closure) → void {
   self::_ScheduleImmediate::_closure = closure;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-7]
@@ -458,9 +458,9 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = StaticField #lib::_stdinFD
-  [1] = StaticField #lib::_stdoutFD
-  [2] = StaticField #lib::_stderrFD
+  [0] = StaticField #lib::_stdinFD (field)
+  [1] = StaticField #lib::_stdoutFD (field)
+  [2] = StaticField #lib::_stderrFD (field)
 }
 ]static method _setStdioFDs(core::int stdin, core::int stdout, core::int stderr) → void {
   self::_stdinFD = stdin;
@@ -468,7 +468,7 @@
   self::_stderrFD = stderr;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   PushConstant         CP#0
@@ -520,7 +520,7 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = StaticField #lib::_rawScript
+  [0] = StaticField #lib::_rawScript (field)
   [1] = String 'http:'
   [2] = ArgDesc num-args 2, num-type-args 0, names []
   [3] = ICData target-name 'startsWith', arg-desc CP#2
@@ -529,10 +529,10 @@
   [6] = String 'file:'
   [7] = ICData target-name 'startsWith', arg-desc CP#2
   [8] = ArgDesc num-args 1, num-type-args 0, names []
-  [9] = StaticICData target 'dart.core::Uri::parse', arg-desc CP#8
+  [9] = StaticICData target 'dart:core::Uri::parse', arg-desc CP#8
   [10] = ArgDesc num-args 0, num-type-args 0, names []
-  [11] = StaticICData get target 'dart.core::Uri::base', arg-desc CP#10
-  [12] = StaticICData target 'dart.core::_Uri::file', arg-desc CP#2
+  [11] = StaticICData target 'dart:core::Uri::get:base', arg-desc CP#10
+  [12] = StaticICData target 'dart:core::_Uri::file (constructor)', arg-desc CP#2
   [13] = ICData target-name 'resolveUri', arg-desc CP#2
 }
 ]static method _scriptUri() → core::Uri {
@@ -544,7 +544,7 @@
   }
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   PushConstant         CP#0
@@ -557,13 +557,13 @@
 ConstantPool {
   [0] = TearOff #lib::_scriptUri
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData set target '#lib::VMLibraryHooks::platformScript', arg-desc CP#1
+  [2] = StaticICData target '#lib::VMLibraryHooks::set:platformScript', arg-desc CP#1
 }
 ]static method _setupHooks() → dynamic {
   self::VMLibraryHooks::platformScript = self::_scriptUri;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   PushConstant         CP#0
@@ -590,8 +590,8 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = StaticField #lib::_stdin
-  [1] = StaticField #lib::_stdinFD
+  [0] = StaticField #lib::_stdin (field)
+  [1] = StaticField #lib::_stdinFD (field)
   [2] = ArgDesc num-args 1, num-type-args 0, names []
   [3] = StaticICData target '#lib::_StdIOUtils::_getStdioInputStream', arg-desc CP#2
 }
@@ -600,7 +600,7 @@
   return self::_stdin;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
diff --git a/pkg/vm/testcases/bytecode/closures.dart.expect b/pkg/vm/testcases/bytecode/closures.dart.expect
index 2add8c9..cf8425c 100644
--- a/pkg/vm/testcases/bytecode/closures.dart.expect
+++ b/pkg/vm/testcases/bytecode/closures.dart.expect
@@ -5,7 +5,7 @@
 typedef IntFunc = (core::int) → dynamic;
 class C1 extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -17,7 +17,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::C1
     : super core::Object::•()
@@ -25,7 +25,7 @@
 }
 class C2 extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -37,7 +37,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::C2
     : super core::Object::•()
@@ -45,7 +45,7 @@
 }
 class C3 extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -57,7 +57,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::C3
     : super core::Object::•()
@@ -65,7 +65,7 @@
 }
 class C4 extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -77,7 +77,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::C4
     : super core::Object::•()
@@ -85,7 +85,7 @@
 }
 class C5 extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -97,7 +97,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::C5
     : super core::Object::•()
@@ -105,7 +105,7 @@
 }
 class C6 extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -117,7 +117,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::C6
     : super core::Object::•()
@@ -125,7 +125,7 @@
 }
 class C7 extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -137,7 +137,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::C7
     : super core::Object::•()
@@ -145,7 +145,7 @@
 }
 class C8 extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -157,7 +157,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::C8
     : super core::Object::•()
@@ -165,7 +165,7 @@
 }
 class A<T1 extends core::Object = dynamic, T2 extends core::Object = dynamic> extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -177,13 +177,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::A<self::A::T1, self::A::T2>
     : super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                5
   CheckStack           0
   CheckFunctionTypeArgs 2, r0
@@ -223,56 +223,168 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = ClosureFunction nested1 <T5 extends dart.core::Object = dynamic, T6 extends dart.core::Object = dynamic>() → void;
-  [1] = InstanceField dart.core::_Closure::_context
+  [0] = ClosureFunction 0
+  [1] = InstanceField dart:core::_Closure::_context (field)
   [2] = Reserved
-  [3] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [3] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [4] = Reserved
   [5] = EmptyTypeArguments
-  [6] = InstanceField dart.core::_Closure::_function_type_arguments
+  [6] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [7] = Reserved
   [8] = ArgDesc num-args 4, num-type-args 0, names []
-  [9] = StaticICData target 'dart._internal::_prependTypeArguments', arg-desc CP#8
-  [10] = ClosureFunction nested2 <T7 extends dart.core::Object = dynamic, T8 extends dart.core::Object = dynamic>() → void;
-  [11] = StaticICData target 'dart._internal::_prependTypeArguments', arg-desc CP#8
-  [12] = ClosureFunction <anonymous closure> () → dart.core::Null;
-  [13] = TypeArgs [dart.core::Type]
-  [14] = Type #lib::A::T1
+  [9] = StaticICData target 'dart:_internal::_prependTypeArguments', arg-desc CP#8
+  [10] = ClosureFunction 1
+  [11] = StaticICData target 'dart:_internal::_prependTypeArguments', arg-desc CP#8
+  [12] = ClosureFunction 2
+  [13] = TypeArgs [dart:core::Type]
+  [14] = Type #lib::A::TypeParam/0
   [15] = TypeArgumentsField #lib::A
-  [16] = Type #lib::A::T2
-  [17] = Type #lib::A::foo::T3
-  [18] = Type #lib::A::foo::T4
-  [19] = Type T5
-  [20] = Type T6
-  [21] = Type T7
-  [22] = Type T8
+  [16] = Type #lib::A::TypeParam/1
+  [17] = Type #lib::A::foo::TypeParam/0
+  [18] = Type #lib::A::foo::TypeParam/1
+  [19] = Type #lib::A::foo::Closure/0::TypeParam/0
+  [20] = Type #lib::A::foo::Closure/0::TypeParam/1
+  [21] = Type #lib::A::foo::Closure/1::TypeParam/0
+  [22] = Type #lib::A::foo::Closure/1::TypeParam/1
   [23] = ArgDesc num-args 2, num-type-args 0, names []
-  [24] = StaticICData target 'dart.core::List::_fromLiteral', arg-desc CP#23
+  [24] = StaticICData target 'dart:core::List::_fromLiteral (constructor)', arg-desc CP#23
   [25] = ArgDesc num-args 1, num-type-args 0, names []
-  [26] = StaticICData target 'dart.core::print', arg-desc CP#25
-  [27] = TypeArgs [#lib::A::T1, #lib::A::T2, #lib::A::foo::T3, #lib::A::foo::T4, T5, T6, T7, T8]
+  [26] = StaticICData target 'dart:core::print', arg-desc CP#25
+  [27] = TypeArgs [#lib::A::TypeParam/0, #lib::A::TypeParam/1, #lib::A::foo::TypeParam/0, #lib::A::foo::TypeParam/1, #lib::A::foo::Closure/0::TypeParam/0, #lib::A::foo::Closure/0::TypeParam/1, #lib::A::foo::Closure/1::TypeParam/0, #lib::A::foo::Closure/1::TypeParam/1]
   [28] = ArgDesc num-args 0, num-type-args 8, names []
   [29] = StaticICData target '#lib::callWithArgs', arg-desc CP#28
   [30] = EndClosureFunctionScope
-  [31] = Class dart.core::_Closure
-  [32] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [31] = Class dart:core::_Closure
+  [32] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [33] = Reserved
-  [34] = InstanceField dart.core::_Closure::_function
+  [34] = InstanceField dart:core::_Closure::_function (field)
   [35] = Reserved
   [36] = ICData dynamic target-name 'call', arg-desc CP#25
   [37] = EndClosureFunctionScope
   [38] = TypeArgs [#lib::C7, #lib::C8]
   [39] = ArgDesc num-args 1, num-type-args 2, names []
   [40] = ICData dynamic target-name 'call', arg-desc CP#39
-  [41] = TypeArgs [dart.core::List<#lib::C7>, dart.core::List<#lib::C8>]
+  [41] = TypeArgs [dart:core::List < #lib::C7 >, dart:core::List < #lib::C8 >]
   [42] = ICData dynamic target-name 'call', arg-desc CP#39
   [43] = EndClosureFunctionScope
   [44] = TypeArgs [#lib::C5, #lib::C6]
   [45] = ICData dynamic target-name 'call', arg-desc CP#39
-  [46] = TypeArgs [dart.core::List<#lib::C5>, dart.core::List<#lib::C6>]
+  [46] = TypeArgs [dart:core::List < #lib::C5 >, dart:core::List < #lib::C6 >]
   [47] = ICData dynamic target-name 'call', arg-desc CP#39
 }
-Closure CP#12 {
+Closure #lib::A::foo::nested1 <dart:core::Object T5, dart:core::Object T6> () -> void
+ClosureBytecode {
+  EntryFixed           1, 5
+  CheckStack           0
+  Push                 FP[-5]
+  LoadFieldTOS         CP#1
+  PopLocal             r1
+  Push                 FP[-5]
+  LoadFieldTOS         CP#3
+  StoreLocal           r0
+  PushConstant         CP#5
+  JumpIfEqStrict       L1
+  CheckFunctionTypeArgs 0, r2
+  Jump                 L2
+L1:
+  CheckFunctionTypeArgs 2, r0
+L2:
+  Push                 r0
+  Push                 FP[-5]
+  LoadFieldTOS         CP#6
+  PushInt              2
+  PushInt              4
+  PushConstant         CP#9
+  IndirectStaticCall   4, CP#8
+  PopLocal             r0
+  Allocate             CP#31
+  StoreLocal           r4
+  Push                 r4
+  Push                 r1
+  LoadContextVar       0, 0
+  LoadTypeArgumentsField CP#15
+  StoreFieldTOS        CP#32
+  Push                 r4
+  Push                 r0
+  StoreFieldTOS        CP#6
+  Push                 r4
+  PushConstant         CP#5
+  StoreFieldTOS        CP#3
+  Push                 r4
+  PushConstant         CP#10
+  StoreFieldTOS        CP#34
+  Push                 r4
+  Push                 r1
+  StoreFieldTOS        CP#1
+  PopLocal             r3
+  PushConstant         CP#38
+  Push                 r3
+  InstanceCall         2, CP#40
+  Drop1
+  PushConstant         CP#41
+  Push                 r3
+  InstanceCall         2, CP#42
+  Drop1
+  PushNull
+  ReturnTOS
+
+}
+
+Closure #lib::A::foo::Closure/0::nested2 <dart:core::Object T7, dart:core::Object T8> () -> void
+ClosureBytecode {
+  EntryFixed           1, 5
+  CheckStack           0
+  Push                 FP[-5]
+  LoadFieldTOS         CP#1
+  PopLocal             r1
+  Push                 FP[-5]
+  LoadFieldTOS         CP#3
+  StoreLocal           r0
+  PushConstant         CP#5
+  JumpIfEqStrict       L1
+  CheckFunctionTypeArgs 0, r2
+  Jump                 L2
+L1:
+  CheckFunctionTypeArgs 2, r0
+L2:
+  Push                 r0
+  Push                 FP[-5]
+  LoadFieldTOS         CP#6
+  PushInt              4
+  PushInt              6
+  PushConstant         CP#11
+  IndirectStaticCall   4, CP#8
+  PopLocal             r0
+  Allocate             CP#31
+  StoreLocal           r4
+  Push                 r4
+  Push                 r1
+  LoadContextVar       0, 0
+  LoadTypeArgumentsField CP#15
+  StoreFieldTOS        CP#32
+  Push                 r4
+  Push                 r0
+  StoreFieldTOS        CP#6
+  Push                 r4
+  PushConstant         CP#5
+  StoreFieldTOS        CP#3
+  Push                 r4
+  PushConstant         CP#12
+  StoreFieldTOS        CP#34
+  Push                 r4
+  Push                 r1
+  StoreFieldTOS        CP#1
+  PopLocal             r3
+  Push                 r3
+  InstanceCall         1, CP#36
+  Drop1
+  PushNull
+  ReturnTOS
+
+}
+
+Closure #lib::A::foo::Closure/1::<anonymous closure> () -> dart:core::Null
+ClosureBytecode {
   EntryFixed           1, 4
   CheckStack           0
   Push                 FP[-5]
@@ -356,115 +468,6 @@
   ReturnTOS
 
 }
-
-Closure CP#10 {
-  EntryFixed           1, 5
-  CheckStack           0
-  Push                 FP[-5]
-  LoadFieldTOS         CP#1
-  PopLocal             r1
-  Push                 FP[-5]
-  LoadFieldTOS         CP#3
-  StoreLocal           r0
-  PushConstant         CP#5
-  JumpIfEqStrict       L1
-  CheckFunctionTypeArgs 0, r2
-  Jump                 L2
-L1:
-  CheckFunctionTypeArgs 2, r0
-L2:
-  Push                 r0
-  Push                 FP[-5]
-  LoadFieldTOS         CP#6
-  PushInt              4
-  PushInt              6
-  PushConstant         CP#11
-  IndirectStaticCall   4, CP#8
-  PopLocal             r0
-  Allocate             CP#31
-  StoreLocal           r4
-  Push                 r4
-  Push                 r1
-  LoadContextVar       0, 0
-  LoadTypeArgumentsField CP#15
-  StoreFieldTOS        CP#32
-  Push                 r4
-  Push                 r0
-  StoreFieldTOS        CP#6
-  Push                 r4
-  PushConstant         CP#5
-  StoreFieldTOS        CP#3
-  Push                 r4
-  PushConstant         CP#12
-  StoreFieldTOS        CP#34
-  Push                 r4
-  Push                 r1
-  StoreFieldTOS        CP#1
-  PopLocal             r3
-  Push                 r3
-  InstanceCall         1, CP#36
-  Drop1
-  PushNull
-  ReturnTOS
-
-}
-
-Closure CP#0 {
-  EntryFixed           1, 5
-  CheckStack           0
-  Push                 FP[-5]
-  LoadFieldTOS         CP#1
-  PopLocal             r1
-  Push                 FP[-5]
-  LoadFieldTOS         CP#3
-  StoreLocal           r0
-  PushConstant         CP#5
-  JumpIfEqStrict       L1
-  CheckFunctionTypeArgs 0, r2
-  Jump                 L2
-L1:
-  CheckFunctionTypeArgs 2, r0
-L2:
-  Push                 r0
-  Push                 FP[-5]
-  LoadFieldTOS         CP#6
-  PushInt              2
-  PushInt              4
-  PushConstant         CP#9
-  IndirectStaticCall   4, CP#8
-  PopLocal             r0
-  Allocate             CP#31
-  StoreLocal           r4
-  Push                 r4
-  Push                 r1
-  LoadContextVar       0, 0
-  LoadTypeArgumentsField CP#15
-  StoreFieldTOS        CP#32
-  Push                 r4
-  Push                 r0
-  StoreFieldTOS        CP#6
-  Push                 r4
-  PushConstant         CP#5
-  StoreFieldTOS        CP#3
-  Push                 r4
-  PushConstant         CP#10
-  StoreFieldTOS        CP#34
-  Push                 r4
-  Push                 r1
-  StoreFieldTOS        CP#1
-  PopLocal             r3
-  PushConstant         CP#38
-  Push                 r3
-  InstanceCall         2, CP#40
-  Drop1
-  PushConstant         CP#41
-  Push                 r3
-  InstanceCall         2, CP#42
-  Drop1
-  PushNull
-  ReturnTOS
-
-}
 ]  method foo<T3 extends core::Object = dynamic, T4 extends core::Object = dynamic>() → void {
     function nested1<T5 extends core::Object = dynamic, T6 extends core::Object = dynamic>() → void {
       function nested2<T7 extends core::Object = dynamic, T8 extends core::Object = dynamic>() → void {
@@ -484,7 +487,7 @@
 class B extends core::Object {
   field core::int foo = null;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -494,16 +497,16 @@
   PushNull
   ReturnTOS
 }
-Nullable fields: [#lib::B::foo]
+Nullable fields: [#lib::B::foo (field)]}
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::B
     : super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                5
   CheckStack           0
   AllocateContext      0, 4
@@ -587,69 +590,42 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = ClosureFunction <anonymous closure> (dart.core::int y) → dart.core::Null;
-  [1] = InstanceField dart.core::_Closure::_context
+  [0] = ClosureFunction 0
+  [1] = InstanceField dart:core::_Closure::_context (field)
   [2] = Reserved
-  [3] = Type dart.core::int
+  [3] = Type dart:core::int
   [4] = String 'y'
   [5] = SubtypeTestCache
-  [6] = ClosureFunction closure2 () → void;
+  [6] = ClosureFunction 1
   [7] = ArgDesc num-args 1, num-type-args 0, names []
-  [8] = ICData get target-name 'foo', arg-desc CP#7
+  [8] = ICData get target-name 'get:foo', arg-desc CP#7
   [9] = EndClosureFunctionScope
-  [10] = Class dart.core::_Closure
-  [11] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [10] = Class dart:core::_Closure
+  [11] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [12] = Reserved
-  [13] = InstanceField dart.core::_Closure::_function_type_arguments
+  [13] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [14] = Reserved
   [15] = EmptyTypeArguments
-  [16] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [16] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [17] = Reserved
-  [18] = InstanceField dart.core::_Closure::_function
+  [18] = InstanceField dart:core::_Closure::_function (field)
   [19] = Reserved
   [20] = ICData dynamic target-name 'call', arg-desc CP#7
-  [21] = StaticICData target 'dart.core::print', arg-desc CP#7
+  [21] = StaticICData target 'dart:core::print', arg-desc CP#7
   [22] = EndClosureFunctionScope
   [23] = ArgDesc num-args 2, num-type-args 0, names []
   [24] = ICData dynamic target-name 'call', arg-desc CP#23
   [25] = ICData dynamic target-name 'call', arg-desc CP#23
-  [26] = StaticICData target 'dart.core::print', arg-desc CP#7
-  [27] = StaticICData target 'dart.core::print', arg-desc CP#7
-  [28] = StaticICData target 'dart.core::print', arg-desc CP#7
-  [29] = ClosureFunction <anonymous closure> () → dart.core::Null;
-  [30] = ICData set target-name 'foo', arg-desc CP#23
+  [26] = StaticICData target 'dart:core::print', arg-desc CP#7
+  [27] = StaticICData target 'dart:core::print', arg-desc CP#7
+  [28] = StaticICData target 'dart:core::print', arg-desc CP#7
+  [29] = ClosureFunction 2
+  [30] = ICData set target-name 'set:foo', arg-desc CP#23
   [31] = EndClosureFunctionScope
   [32] = ICData dynamic target-name 'call', arg-desc CP#7
 }
-Closure CP#6 {
-  EntryFixed           1, 3
-  CheckStack           0
-  Push                 FP[-5]
-  LoadFieldTOS         CP#1
-  PopLocal             r0
-  Push                 r0
-  LoadContextParent
-  Push                 r0
-  LoadContextParent
-  LoadContextVar       0, 1
-  PushInt              2
-  AddInt
-  StoreContextVar      0, 2
-  Push                 r0
-  Push                 r0
-  LoadContextParent
-  LoadContextVar       0, 0
-  InstanceCall         1, CP#8
-  Push                 r0
-  LoadContextVar       1, 0
-  AddInt
-  StoreContextVar      1, 1
-  PushNull
-  ReturnTOS
-
-}
-
-Closure CP#0 {
+Closure #lib::B::topLevel::<anonymous closure> (dart:core::int y) -> dart:core::Null
+ClosureBytecode {
   EntryFixed           2, 4
   CheckStack           0
   Push                 FP[-6]
@@ -719,7 +695,37 @@
 
 }
 
-Closure CP#29 {
+Closure #lib::B::topLevel::Closure/0::closure2 () -> void
+ClosureBytecode {
+  EntryFixed           1, 3
+  CheckStack           0
+  Push                 FP[-5]
+  LoadFieldTOS         CP#1
+  PopLocal             r0
+  Push                 r0
+  LoadContextParent
+  Push                 r0
+  LoadContextParent
+  LoadContextVar       0, 1
+  PushInt              2
+  AddInt
+  StoreContextVar      0, 2
+  Push                 r0
+  Push                 r0
+  LoadContextParent
+  LoadContextVar       0, 0
+  InstanceCall         1, CP#8
+  Push                 r0
+  LoadContextVar       1, 0
+  AddInt
+  StoreContextVar      1, 1
+  PushNull
+  ReturnTOS
+
+}
+
+Closure #lib::B::topLevel::<anonymous closure> () -> dart:core::Null
+ClosureBytecode {
   EntryFixed           1, 3
   CheckStack           0
   Push                 FP[-5]
@@ -771,7 +777,7 @@
 }
 class C extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -783,13 +789,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::C
     : super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                5
   CheckStack           0
   AllocateContext      0, 1
@@ -895,33 +901,34 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgs [dart.core::Function]
+  [0] = TypeArgs [dart:core::Function]
   [1] = ArgDesc num-args 2, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::List::_fromLiteral', arg-desc CP#1
-  [3] = StaticICData target 'dart.core::List::_fromLiteral', arg-desc CP#1
-  [4] = ClosureFunction <anonymous closure> () → dart.core::int;
-  [5] = InstanceField dart.core::_Closure::_context
+  [2] = StaticICData target 'dart:core::List::_fromLiteral (constructor)', arg-desc CP#1
+  [3] = StaticICData target 'dart:core::List::_fromLiteral (constructor)', arg-desc CP#1
+  [4] = ClosureFunction 0
+  [5] = InstanceField dart:core::_Closure::_context (field)
   [6] = Reserved
   [7] = EndClosureFunctionScope
-  [8] = Class dart.core::_Closure
-  [9] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [8] = Class dart:core::_Closure
+  [9] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [10] = Reserved
-  [11] = InstanceField dart.core::_Closure::_function_type_arguments
+  [11] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [12] = Reserved
   [13] = EmptyTypeArguments
-  [14] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [14] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [15] = Reserved
-  [16] = InstanceField dart.core::_Closure::_function
+  [16] = InstanceField dart:core::_Closure::_function (field)
   [17] = Reserved
   [18] = ICData target-name 'add', arg-desc CP#1
-  [19] = ClosureFunction <anonymous closure> (dart.core::int ii) → dart.core::Null;
-  [20] = Type dart.core::int
+  [19] = ClosureFunction 1
+  [20] = Type dart:core::int
   [21] = String 'ii'
   [22] = SubtypeTestCache
   [23] = EndClosureFunctionScope
   [24] = ICData target-name 'add', arg-desc CP#1
 }
-Closure CP#4 {
+Closure #lib::C::testForLoop::<anonymous closure> () -> dart:core::int
+ClosureBytecode {
   EntryFixed           1, 2
   CheckStack           0
   Push                 FP[-5]
@@ -937,7 +944,8 @@
 
 }
 
-Closure CP#19 {
+Closure #lib::C::testForLoop::<anonymous closure> (dart:core::int ii) -> dart:core::Null
+ClosureBytecode {
   EntryFixed           2, 3
   CheckStack           0
   Push                 FP[-6]
@@ -973,7 +981,7 @@
     }
   }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                5
   CheckStack           0
   Push                 FP[-5]
@@ -1026,27 +1034,28 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = ICData get target-name 'iterator', arg-desc CP#0
+  [1] = ICData get target-name 'get:iterator', arg-desc CP#0
   [2] = ICData target-name 'moveNext', arg-desc CP#0
-  [3] = ICData get target-name 'current', arg-desc CP#0
-  [4] = ClosureFunction <anonymous closure> () → dart.core::Null;
-  [5] = InstanceField dart.core::_Closure::_context
+  [3] = ICData get target-name 'get:current', arg-desc CP#0
+  [4] = ClosureFunction 0
+  [5] = InstanceField dart:core::_Closure::_context (field)
   [6] = Reserved
   [7] = EndClosureFunctionScope
-  [8] = Class dart.core::_Closure
-  [9] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [8] = Class dart:core::_Closure
+  [9] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [10] = Reserved
-  [11] = InstanceField dart.core::_Closure::_function_type_arguments
+  [11] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [12] = Reserved
   [13] = EmptyTypeArguments
-  [14] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [14] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [15] = Reserved
-  [16] = InstanceField dart.core::_Closure::_function
+  [16] = InstanceField dart:core::_Closure::_function (field)
   [17] = Reserved
   [18] = ICData dynamic target-name 'call', arg-desc CP#0
-  [19] = StaticICData target 'dart.core::print', arg-desc CP#0
+  [19] = StaticICData target 'dart:core::print', arg-desc CP#0
 }
-Closure CP#4 {
+Closure #lib::C::testForInLoop::<anonymous closure> () -> dart:core::Null
+ClosureBytecode {
   EntryFixed           1, 3
   CheckStack           0
   Push                 FP[-5]
@@ -1074,7 +1083,7 @@
 }
 class D<T extends core::Object = dynamic> extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -1086,13 +1095,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::D<self::D::T>
     : super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                3
   CheckStack           0
   AllocateContext      0, 1
@@ -1129,26 +1138,27 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = Type #lib::D::T
+  [0] = Type #lib::D::TypeParam/0
   [1] = TypeArgumentsField #lib::D
   [2] = String 't'
   [3] = SubtypeTestCache
-  [4] = ClosureFunction <anonymous closure> () → #lib::D::T;
-  [5] = InstanceField dart.core::_Closure::_context
+  [4] = ClosureFunction 0
+  [5] = InstanceField dart:core::_Closure::_context (field)
   [6] = Reserved
   [7] = EndClosureFunctionScope
-  [8] = Class dart.core::_Closure
-  [9] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [8] = Class dart:core::_Closure
+  [9] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [10] = Reserved
-  [11] = InstanceField dart.core::_Closure::_function_type_arguments
+  [11] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [12] = Reserved
   [13] = EmptyTypeArguments
-  [14] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [14] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [15] = Reserved
-  [16] = InstanceField dart.core::_Closure::_function
+  [16] = InstanceField dart:core::_Closure::_function (field)
   [17] = Reserved
 }
-Closure CP#4 {
+Closure #lib::D::foo::<anonymous closure> () -> #lib::D::TypeParam/0
+ClosureBytecode {
   EntryFixed           1, 2
   CheckStack           0
   Push                 FP[-5]
@@ -1164,7 +1174,7 @@
   }
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                4
   CheckStack           0
   AllocateContext      0, 1
@@ -1199,27 +1209,28 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = ClosureFunction <anonymous closure> (dart.core::int y) → dart.core::Null;
-  [1] = InstanceField dart.core::_Closure::_context
+  [0] = ClosureFunction 0
+  [1] = InstanceField dart:core::_Closure::_context (field)
   [2] = Reserved
-  [3] = Type dart.core::int
+  [3] = Type dart:core::int
   [4] = String 'y'
   [5] = SubtypeTestCache
   [6] = EndClosureFunctionScope
-  [7] = Class dart.core::_Closure
-  [8] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [7] = Class dart:core::_Closure
+  [8] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [9] = Reserved
-  [10] = InstanceField dart.core::_Closure::_function_type_arguments
+  [10] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [11] = Reserved
   [12] = EmptyTypeArguments
-  [13] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [13] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [14] = Reserved
-  [15] = InstanceField dart.core::_Closure::_function
+  [15] = InstanceField dart:core::_Closure::_function (field)
   [16] = Reserved
   [17] = ArgDesc num-args 2, num-type-args 0, names []
   [18] = ICData dynamic target-name 'call', arg-desc CP#17
 }
-Closure CP#0 {
+Closure #lib::simpleClosure::<anonymous closure> (dart:core::int y) -> dart:core::Null
+ClosureBytecode {
   EntryFixed           2, 3
   CheckStack           0
   Push                 FP[-6]
@@ -1251,7 +1262,7 @@
   return x;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   CheckFunctionTypeArgs 8, r0
@@ -1318,25 +1329,25 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgs [dart.core::Type]
-  [1] = Type #lib::callWithArgs::T1
-  [2] = Type #lib::callWithArgs::T2
-  [3] = Type #lib::callWithArgs::T3
-  [4] = Type #lib::callWithArgs::T4
-  [5] = Type #lib::callWithArgs::T5
-  [6] = Type #lib::callWithArgs::T6
-  [7] = Type #lib::callWithArgs::T7
-  [8] = Type #lib::callWithArgs::T8
+  [0] = TypeArgs [dart:core::Type]
+  [1] = Type #lib::callWithArgs::TypeParam/0
+  [2] = Type #lib::callWithArgs::TypeParam/1
+  [3] = Type #lib::callWithArgs::TypeParam/2
+  [4] = Type #lib::callWithArgs::TypeParam/3
+  [5] = Type #lib::callWithArgs::TypeParam/4
+  [6] = Type #lib::callWithArgs::TypeParam/5
+  [7] = Type #lib::callWithArgs::TypeParam/6
+  [8] = Type #lib::callWithArgs::TypeParam/7
   [9] = ArgDesc num-args 2, num-type-args 0, names []
-  [10] = StaticICData target 'dart.core::List::_fromLiteral', arg-desc CP#9
+  [10] = StaticICData target 'dart:core::List::_fromLiteral (constructor)', arg-desc CP#9
   [11] = ArgDesc num-args 1, num-type-args 0, names []
-  [12] = StaticICData target 'dart.core::print', arg-desc CP#11
+  [12] = StaticICData target 'dart:core::print', arg-desc CP#11
 }
 ]static method callWithArgs<T1 extends core::Object = dynamic, T2 extends core::Object = dynamic, T3 extends core::Object = dynamic, T4 extends core::Object = dynamic, T5 extends core::Object = dynamic, T6 extends core::Object = dynamic, T7 extends core::Object = dynamic, T8 extends core::Object = dynamic>() → void {
   core::print(<core::Type>[self::callWithArgs::T1, self::callWithArgs::T2, self::callWithArgs::T3, self::callWithArgs::T4, self::callWithArgs::T5, self::callWithArgs::T6, self::callWithArgs::T7, self::callWithArgs::T8]);
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   PushConstant         CP#0
@@ -1380,14 +1391,14 @@
   [1] = Class #lib::A
   [2] = TypeArgumentsForInstanceAllocation #lib::A [#lib::C1, #lib::C2]
   [3] = ArgDesc num-args 1, num-type-args 0, names []
-  [4] = StaticICData target '#lib::A::', arg-desc CP#3
+  [4] = StaticICData target '#lib::A::'' (constructor)', arg-desc CP#3
   [5] = ArgDesc num-args 1, num-type-args 2, names []
   [6] = ICData target-name 'foo', arg-desc CP#5
-  [7] = TypeArgs [dart.core::List<#lib::C3>, dart.core::List<#lib::C4>]
-  [8] = StaticICData target '#lib::A::', arg-desc CP#3
+  [7] = TypeArgs [dart:core::List < #lib::C3 >, dart:core::List < #lib::C4 >]
+  [8] = StaticICData target '#lib::A::'' (constructor)', arg-desc CP#3
   [9] = ICData target-name 'foo', arg-desc CP#5
-  [10] = TypeArgumentsForInstanceAllocation #lib::A [dart.core::List<#lib::C1>, dart.core::List<#lib::C2>]
-  [11] = StaticICData target '#lib::A::', arg-desc CP#3
+  [10] = TypeArgumentsForInstanceAllocation #lib::A [dart:core::List < #lib::C1 >, dart:core::List < #lib::C2 >]
+  [11] = StaticICData target '#lib::A::'' (constructor)', arg-desc CP#3
   [12] = ICData target-name 'foo', arg-desc CP#5
 }
 ]static method callA() → void {
@@ -1396,7 +1407,7 @@
   new self::A::•<core::List<self::C1>, core::List<self::C2>>().{self::A::foo}<core::List<self::C3>, core::List<self::C4>>();
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                7
   CheckStack           0
   Allocate             CP#14
@@ -1450,30 +1461,31 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = ClosureFunction foo <T extends dart.core::Object = dynamic>(T t) → void;
-  [1] = InstanceField dart.core::_Closure::_context
+  [0] = ClosureFunction 0
+  [1] = InstanceField dart:core::_Closure::_context (field)
   [2] = Reserved
-  [3] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [3] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [4] = Reserved
   [5] = EmptyTypeArguments
-  [6] = InstanceField dart.core::_Closure::_function_type_arguments
+  [6] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [7] = Reserved
   [8] = ArgDesc num-args 4, num-type-args 0, names []
-  [9] = StaticICData target 'dart._internal::_prependTypeArguments', arg-desc CP#8
-  [10] = Type T
+  [9] = StaticICData target 'dart:_internal::_prependTypeArguments', arg-desc CP#8
+  [10] = Type #lib::testPartialInstantiation::Closure/0::TypeParam/0
   [11] = String 't'
   [12] = SubtypeTestCache
   [13] = EndClosureFunctionScope
-  [14] = Class dart.core::_Closure
-  [15] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [14] = Class dart:core::_Closure
+  [15] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [16] = Reserved
-  [17] = InstanceField dart.core::_Closure::_function
+  [17] = InstanceField dart:core::_Closure::_function (field)
   [18] = Reserved
-  [19] = TypeArgs [dart.core::int]
+  [19] = TypeArgs [dart:core::int]
   [20] = ArgDesc num-args 2, num-type-args 0, names []
-  [21] = StaticICData target 'dart._internal::_boundsCheckForPartialInstantiation', arg-desc CP#20
+  [21] = StaticICData target 'dart:_internal::_boundsCheckForPartialInstantiation', arg-desc CP#20
 }
-Closure CP#0 {
+Closure #lib::testPartialInstantiation::foo <dart:core::Object T> (#lib::testPartialInstantiation::Closure/0::TypeParam/0 t) -> void
+ClosureBytecode {
   EntryFixed           2, 3
   CheckStack           0
   Push                 FP[-6]
@@ -1514,7 +1526,7 @@
   return intFunc;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
diff --git a/pkg/vm/testcases/bytecode/deferred_lib.dart.expect b/pkg/vm/testcases/bytecode/deferred_lib.dart.expect
index 9004858..ec106c3 100644
--- a/pkg/vm/testcases/bytecode/deferred_lib.dart.expect
+++ b/pkg/vm/testcases/bytecode/deferred_lib.dart.expect
@@ -3,7 +3,7 @@
 import "./hello.dart" as hel;
 
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   PushNull
@@ -16,14 +16,14 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.async::Future::value', arg-desc CP#0
+  [1] = StaticICData target 'dart:async::Future::value (constructor)', arg-desc CP#0
   [2] = ArgDesc num-args 0, num-type-args 0, names []
-  [3] = StaticICData target '#lib1::main', arg-desc CP#2
+  [3] = StaticICData target '#pkg/vm/testcases/bytecode/hello.dart::main', arg-desc CP#2
 }
 ]static method callDeferred() → dynamic
   return let final dynamic #t1 = CheckLibraryIsLoaded(lib) in hel::main();
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
@@ -33,12 +33,12 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.async::Future::value', arg-desc CP#0
+  [1] = StaticICData target 'dart:async::Future::value (constructor)', arg-desc CP#0
 }
 ]static method testLoadLibrary() → dynamic
   return LoadLibrary(lib);
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
diff --git a/pkg/vm/testcases/bytecode/field_initializers.dart.expect b/pkg/vm/testcases/bytecode/field_initializers.dart.expect
index a375935..695f1a9 100644
--- a/pkg/vm/testcases/bytecode/field_initializers.dart.expect
+++ b/pkg/vm/testcases/bytecode/field_initializers.dart.expect
@@ -9,7 +9,7 @@
   field core::int foo4;
   field core::int foo5 = 43;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-6]
@@ -31,22 +31,22 @@
   PushNull
   ReturnTOS
 }
-Nullable fields: [#lib::A::foo1, #lib::A::foo2]
+Nullable fields: [#lib::A::foo1 (field), #lib::A::foo2 (field)]}
 ConstantPool {
-  [0] = InstanceField #lib::A::foo3
+  [0] = InstanceField #lib::A::foo3 (field)
   [1] = Reserved
-  [2] = InstanceField #lib::A::foo5
+  [2] = InstanceField #lib::A::foo5 (field)
   [3] = Reserved
-  [4] = InstanceField #lib::A::foo4
+  [4] = InstanceField #lib::A::foo4 (field)
   [5] = Reserved
   [6] = ArgDesc num-args 1, num-type-args 0, names []
-  [7] = StaticICData target 'dart.core::Object::', arg-desc CP#6
+  [7] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#6
 }
 ]  constructor •(core::int foo4) → self::A
     : self::A::foo1 = null, self::A::foo4 = foo4, self::A::foo5 = 44, super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-7]
@@ -70,22 +70,22 @@
   PushNull
   ReturnTOS
 }
-Nullable fields: [#lib::A::foo2, #lib::A::foo4]
+Nullable fields: [#lib::A::foo2 (field), #lib::A::foo4 (field)]}
 ConstantPool {
-  [0] = InstanceField #lib::A::foo3
+  [0] = InstanceField #lib::A::foo3 (field)
   [1] = Reserved
-  [2] = InstanceField #lib::A::foo5
+  [2] = InstanceField #lib::A::foo5 (field)
   [3] = Reserved
-  [4] = InstanceField #lib::A::foo1
+  [4] = InstanceField #lib::A::foo1 (field)
   [5] = Reserved
   [6] = ArgDesc num-args 1, num-type-args 0, names []
-  [7] = StaticICData target 'dart.core::Object::', arg-desc CP#6
+  [7] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#6
 }
 ]  constructor constr2(core::int x, core::int y) → self::A
     : self::A::foo4 = null, self::A::foo1 = x, self::A::foo5 = y.{core::num::+}(1), super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -98,13 +98,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 2, num-type-args 0, names []
-  [1] = StaticICData target '#lib::A::', arg-desc CP#0
+  [1] = StaticICData target '#lib::A::'' (constructor)', arg-desc CP#0
 }
 ]  constructor redirecting1() → self::A
     : this self::A::•(45)
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-8]
@@ -120,7 +120,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 3, num-type-args 0, names []
-  [1] = StaticICData target '#lib::A::constr2', arg-desc CP#0
+  [1] = StaticICData target '#lib::A::constr2 (constructor)', arg-desc CP#0
 }
 ]  constructor redirecting2(core::int a, core::int b, core::int c) → self::A
     : this self::A::constr2(a, b.{core::num::*}(c))
@@ -131,7 +131,7 @@
   static field core::int foo7 = 47;
   static const field core::int foo8 = 48;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -146,16 +146,16 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = InstanceField #lib::B::foo6
+  [0] = InstanceField #lib::B::foo6 (field)
   [1] = Reserved
   [2] = ArgDesc num-args 2, num-type-args 0, names []
-  [3] = StaticICData target '#lib::A::', arg-desc CP#2
+  [3] = StaticICData target '#lib::A::'' (constructor)', arg-desc CP#2
 }
 ]  constructor •() → self::B
     : super self::A::•(49)
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-7]
@@ -175,17 +175,17 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = InstanceField #lib::B::foo6
+  [0] = InstanceField #lib::B::foo6 (field)
   [1] = Reserved
   [2] = ArgDesc num-args 4, num-type-args 0, names []
-  [3] = StaticICData target '#lib::A::redirecting2', arg-desc CP#2
+  [3] = StaticICData target '#lib::A::redirecting2 (constructor)', arg-desc CP#2
 }
 ]  constructor c2(core::int i, core::int j) → self::B
     : self::B::foo6 = 50, super self::A::redirecting2(i, j, 51)
     ;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
diff --git a/pkg/vm/testcases/bytecode/hello.dart.expect b/pkg/vm/testcases/bytecode/hello.dart.expect
index 1bc42dd..0c5c9de 100644
--- a/pkg/vm/testcases/bytecode/hello.dart.expect
+++ b/pkg/vm/testcases/bytecode/hello.dart.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#0
@@ -16,7 +16,7 @@
 ConstantPool {
   [0] = String 'Hello, Dart Bytecode!'
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [2] = StaticICData target 'dart:core::print', arg-desc CP#1
 }
 ]static method main() → dynamic {
   core::print("Hello, Dart Bytecode!");
diff --git a/pkg/vm/testcases/bytecode/instance_creation.dart.expect b/pkg/vm/testcases/bytecode/instance_creation.dart.expect
index 8f84e7e..1407a9e 100644
--- a/pkg/vm/testcases/bytecode/instance_creation.dart.expect
+++ b/pkg/vm/testcases/bytecode/instance_creation.dart.expect
@@ -7,7 +7,7 @@
   generic-covariant-impl field self::Base::T1 t1 = null;
   generic-covariant-impl field self::Base::T2 t2 = null;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -48,17 +48,17 @@
   PushNull
   ReturnTOS
 }
-Nullable fields: [#lib::Base::t1, #lib::Base::t2]
+Nullable fields: [#lib::Base::t1 (field), #lib::Base::t2 (field)]}
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
   [2] = String 'Base: '
-  [3] = Type #lib::Base::T1
+  [3] = Type #lib::Base::TypeParam/0
   [4] = TypeArgumentsField #lib::Base
   [5] = String ', '
-  [6] = Type #lib::Base::T2
-  [7] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#0
-  [8] = StaticICData target 'dart.core::print', arg-desc CP#0
+  [6] = Type #lib::Base::TypeParam/1
+  [7] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#0
+  [8] = StaticICData target 'dart:core::print', arg-desc CP#0
 }
 ]  constructor •() → self::Base<self::Base::T1, self::Base::T2>
     : super core::Object::•() {
@@ -67,7 +67,7 @@
 }
 class A extends self::Base<core::int, core::String> {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-6]
@@ -79,7 +79,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target '#lib::Base::', arg-desc CP#0
+  [1] = StaticICData target '#lib::Base::'' (constructor)', arg-desc CP#0
 }
 ]  constructor •(core::String s) → self::A
     : super self::Base::•()
@@ -87,7 +87,7 @@
 }
 class B<T extends core::Object = dynamic> extends self::Base<core::List<self::B::T>, core::String> {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -119,12 +119,12 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target '#lib::Base::', arg-desc CP#0
+  [1] = StaticICData target '#lib::Base::'' (constructor)', arg-desc CP#0
   [2] = String 'B: '
-  [3] = Type #lib::B::T
+  [3] = Type #lib::B::TypeParam/0
   [4] = TypeArgumentsField #lib::B
-  [5] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#0
-  [6] = StaticICData target 'dart.core::print', arg-desc CP#0
+  [5] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#0
+  [6] = StaticICData target 'dart:core::print', arg-desc CP#0
 }
 ]  constructor •() → self::B<self::B::T>
     : super self::Base::•() {
@@ -133,7 +133,7 @@
 }
 class C extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-6]
@@ -162,10 +162,10 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
   [2] = String 'C: '
-  [3] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#0
-  [4] = StaticICData target 'dart.core::print', arg-desc CP#0
+  [3] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#0
+  [4] = StaticICData target 'dart:core::print', arg-desc CP#0
 }
 ]  constructor •(core::String s) → self::C
     : super core::Object::•() {
@@ -174,7 +174,7 @@
 }
 class E<K extends core::Object = dynamic, V extends core::Object = dynamic> extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -186,13 +186,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::E<self::E::K, self::E::V>
     : super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -204,14 +204,14 @@
 ConstantPool {
   [0] = TypeArgumentsField #lib::E
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::Map::', arg-desc CP#1
+  [2] = StaticICData target 'dart:core::Map::'' (constructor)', arg-desc CP#1
 }
 ]  method test_reuse1() → dynamic
     return core::Map::•<self::E::K, self::E::V>();
 }
 class F<K extends core::Object = dynamic, V extends core::Object = dynamic> extends self::E<core::String, core::List<self::F::V>> {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -223,13 +223,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target '#lib::E::', arg-desc CP#0
+  [1] = StaticICData target '#lib::E::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::F<self::F::K, self::F::V>
     : super self::E::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -241,14 +241,14 @@
 ConstantPool {
   [0] = TypeArgumentsField #lib::F
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::Map::', arg-desc CP#1
+  [2] = StaticICData target 'dart:core::Map::'' (constructor)', arg-desc CP#1
 }
 ]  method test_reuse2() → dynamic
     return core::Map::•<core::String, core::List<self::F::V>>();
 }
 class G<K extends core::Object = dynamic, V extends core::Object = dynamic> extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -260,13 +260,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  constructor •() → self::G<self::G::K, self::G::V>
     : super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -283,16 +283,16 @@
 }
 ConstantPool {
   [0] = Class #lib::H
-  [1] = TypeArgumentsForInstanceAllocation #lib::H [dart.core::String, #lib::G::test_factory::K, #lib::G::test_factory::V]
+  [1] = TypeArgumentsForInstanceAllocation #lib::H [dart:core::String, #lib::G::test_factory (constructor)::TypeParam/0, #lib::G::test_factory (constructor)::TypeParam/1]
   [2] = ArgDesc num-args 1, num-type-args 0, names []
-  [3] = StaticICData target '#lib::H::', arg-desc CP#2
+  [3] = StaticICData target '#lib::H::'' (constructor)', arg-desc CP#2
 }
 ]  static factory test_factory<K extends core::Object = dynamic, V extends core::Object = dynamic>() → self::G<self::G::test_factory::K, self::G::test_factory::V>
     return new self::H::•<core::String, self::G::test_factory::K, self::G::test_factory::V>();
 }
 class H<P1 extends core::Object = dynamic, P2 extends core::Object = dynamic, P3 extends core::Object = dynamic> extends self::G<self::H::P2, self::H::P3> {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -304,7 +304,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target '#lib::G::', arg-desc CP#0
+  [1] = StaticICData target '#lib::G::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::H<self::H::P1, self::H::P2, self::H::P3>
     : super self::G::•()
@@ -312,7 +312,7 @@
 }
 class I extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-6]
@@ -324,13 +324,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  constructor •(dynamic param) → self::I
     : super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   EntryOptional        1, 0, 1
   LoadConstant         r1, CP#0
   LoadConstant         r1, CP#1
@@ -350,14 +350,14 @@
   [1] = Null
   [2] = Class #lib::I
   [3] = ArgDesc num-args 2, num-type-args 0, names []
-  [4] = StaticICData target '#lib::I::', arg-desc CP#3
+  [4] = StaticICData target '#lib::I::'' (constructor)', arg-desc CP#3
 }
 ]  static factory test_factory2({dynamic param = null}) → self::I
     return new self::I::•(param);
 }
 class J extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -372,7 +372,7 @@
 }
 abstract class K<A extends core::Object = dynamic, B extends core::Object = dynamic> extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -388,14 +388,14 @@
 ConstantPool {
   [0] = Class #lib::TestTypeArgReuse
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target '#lib::TestTypeArgReuse::', arg-desc CP#1
+  [2] = StaticICData target '#lib::TestTypeArgReuse::'' (constructor)', arg-desc CP#1
 }
 ]  static factory •<A extends core::Object = dynamic, B extends core::Object = dynamic>() → self::K<self::K::•::A, self::K::•::B>
     return new self::TestTypeArgReuse::•<self::K::•::A, self::K::•::B>();
 }
 class TestTypeArgReuse<P extends core::Object = dynamic, Q extends core::Object = dynamic> extends self::Base<self::TestTypeArgReuse::P, self::TestTypeArgReuse::Q> implements self::K<self::TestTypeArgReuse::P, self::TestTypeArgReuse::Q> {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -407,14 +407,14 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target '#lib::Base::', arg-desc CP#0
+  [1] = StaticICData target '#lib::Base::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::TestTypeArgReuse<self::TestTypeArgReuse::P, self::TestTypeArgReuse::Q>
     : super self::Base::•()
     ;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Allocate             CP#0
@@ -430,12 +430,12 @@
   [0] = Class #lib::C
   [1] = String 'hello'
   [2] = ArgDesc num-args 2, num-type-args 0, names []
-  [3] = StaticICData target '#lib::C::', arg-desc CP#2
+  [3] = StaticICData target '#lib::C::'' (constructor)', arg-desc CP#2
 }
 ]static method foo1() → dynamic
   return new self::C::•("hello");
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   PushConstant         CP#1
@@ -465,18 +465,18 @@
   [1] = TypeArgumentsForInstanceAllocation #lib::A []
   [2] = String 'hi'
   [3] = ArgDesc num-args 2, num-type-args 0, names []
-  [4] = StaticICData target '#lib::A::', arg-desc CP#3
+  [4] = StaticICData target '#lib::A::'' (constructor)', arg-desc CP#3
   [5] = Class #lib::B
-  [6] = TypeArgumentsForInstanceAllocation #lib::B [dart.core::int]
+  [6] = TypeArgumentsForInstanceAllocation #lib::B [dart:core::int]
   [7] = ArgDesc num-args 1, num-type-args 0, names []
-  [8] = StaticICData target '#lib::B::', arg-desc CP#7
+  [8] = StaticICData target '#lib::B::'' (constructor)', arg-desc CP#7
 }
 ]static method foo2() → void {
   new self::A::•("hi");
   new self::B::•<core::int>();
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   CheckFunctionTypeArgs 1, r0
@@ -496,15 +496,15 @@
 }
 ConstantPool {
   [0] = Class #lib::B
-  [1] = TypeArgumentsForInstanceAllocation #lib::B [dart.core::List<#lib::foo3::T>]
+  [1] = TypeArgumentsForInstanceAllocation #lib::B [dart:core::List < #lib::foo3::TypeParam/0 >]
   [2] = ArgDesc num-args 1, num-type-args 0, names []
-  [3] = StaticICData target '#lib::B::', arg-desc CP#2
+  [3] = StaticICData target '#lib::B::'' (constructor)', arg-desc CP#2
 }
 ]static method foo3<T extends core::Object = dynamic>() → void {
   new self::B::•<core::List<self::foo3::T>>();
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#0
@@ -515,15 +515,15 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgumentsForInstanceAllocation #lib::G [dart.core::int, dart.core::List<dart.core::String>]
+  [0] = TypeArgumentsForInstanceAllocation #lib::G [dart:core::int, dart:core::List < dart:core::String >]
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target '#lib::G::test_factory', arg-desc CP#1
+  [2] = StaticICData target '#lib::G::test_factory (constructor)', arg-desc CP#1
 }
 ]static method foo4() → void {
   self::G::test_factory<core::int, core::List<core::String>>();
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
@@ -540,16 +540,16 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target '#lib::I::test_factory2', arg-desc CP#0
+  [1] = StaticICData target '#lib::I::test_factory2 (constructor)', arg-desc CP#0
   [2] = ArgDesc num-args 2, num-type-args 0, names [param]
-  [3] = StaticICData target '#lib::I::test_factory2', arg-desc CP#2
+  [3] = StaticICData target '#lib::I::test_factory2 (constructor)', arg-desc CP#2
 }
 ]static method foo5() → void {
   self::I::test_factory2();
   self::I::test_factory2(param: 42);
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#0
@@ -559,14 +559,14 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgumentsForInstanceAllocation dart.core::_GrowableList [dart.core::String]
+  [0] = TypeArgumentsForInstanceAllocation dart:core::_GrowableList [dart:core::String]
   [1] = ArgDesc num-args 2, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::_GrowableList::', arg-desc CP#1
+  [2] = StaticICData target 'dart:core::_GrowableList::'' (constructor)', arg-desc CP#1
 }
 ]static method foo6() → dynamic
   return core::_GrowableList::•<core::String>(0);
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#0
@@ -576,14 +576,14 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgumentsForInstanceAllocation dart.core::_List [dart.core::int]
+  [0] = TypeArgumentsForInstanceAllocation dart:core::_List [dart:core::int]
   [1] = ArgDesc num-args 2, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::_List::', arg-desc CP#1
+  [2] = StaticICData target 'dart:core::_List::'' (constructor)', arg-desc CP#1
 }
 ]static method foo7(core::int n) → dynamic
   return core::_List::•<core::int>(n);
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#1
@@ -603,7 +603,7 @@
   [0] = ArgDesc num-args 0, num-type-args 0, names []
   [1] = StaticICData target '#lib::foo1', arg-desc CP#0
   [2] = StaticICData target '#lib::foo2', arg-desc CP#0
-  [3] = TypeArgs [dart.core::String]
+  [3] = TypeArgs [dart:core::String]
   [4] = ArgDesc num-args 0, num-type-args 1, names []
   [5] = StaticICData target '#lib::foo3', arg-desc CP#4
 }
diff --git a/pkg/vm/testcases/bytecode/literals.dart.expect b/pkg/vm/testcases/bytecode/literals.dart.expect
index f3fe8f4..233eed7 100644
--- a/pkg/vm/testcases/bytecode/literals.dart.expect
+++ b/pkg/vm/testcases/bytecode/literals.dart.expect
@@ -7,7 +7,7 @@
   final field core::int index;
   final field core::String _name;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#13
@@ -17,21 +17,21 @@
   [0] = Null
   [1] = Int 0
   [2] = String 'A.elem1'
-  [3] = Instance #lib::A type-args CP#0 {index: CP#1, _name: CP#2}
+  [3] = Instance #lib::A type-args CP#0 {#lib::A::index (field): CP#1, #lib::A::_name (field): CP#2}
   [4] = Int 1
   [5] = String 'A.elem2'
-  [6] = Instance #lib::A type-args CP#0 {index: CP#4, _name: CP#5}
+  [6] = Instance #lib::A type-args CP#0 {#lib::A::index (field): CP#4, #lib::A::_name (field): CP#5}
   [7] = Int 2
   [8] = String 'A.elem3'
-  [9] = Instance #lib::A type-args CP#0 {index: CP#7, _name: CP#8}
+  [9] = Instance #lib::A type-args CP#0 {#lib::A::index (field): CP#7, #lib::A::_name (field): CP#8}
   [10] = Int 3
   [11] = String 'A.elem4'
-  [12] = Instance #lib::A type-args CP#0 {index: CP#10, _name: CP#11}
+  [12] = Instance #lib::A type-args CP#0 {#lib::A::index (field): CP#10, #lib::A::_name (field): CP#11}
   [13] = List type-arg #lib::A, entries CP# [3, 6, 9, 12]
 }
 ]  static const field core::List<self::A> values = const <self::A>[self::A::elem1, self::A::elem2, self::A::elem3, self::A::elem4];
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#3
@@ -41,11 +41,11 @@
   [0] = Null
   [1] = Int 0
   [2] = String 'A.elem1'
-  [3] = Instance #lib::A type-args CP#0 {index: CP#1, _name: CP#2}
+  [3] = Instance #lib::A type-args CP#0 {#lib::A::index (field): CP#1, #lib::A::_name (field): CP#2}
 }
 ]  static const field self::A elem1 = const self::A::•(0, "A.elem1");
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#3
@@ -55,11 +55,11 @@
   [0] = Null
   [1] = Int 1
   [2] = String 'A.elem2'
-  [3] = Instance #lib::A type-args CP#0 {index: CP#1, _name: CP#2}
+  [3] = Instance #lib::A type-args CP#0 {#lib::A::index (field): CP#1, #lib::A::_name (field): CP#2}
 }
 ]  static const field self::A elem2 = const self::A::•(1, "A.elem2");
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#3
@@ -69,11 +69,11 @@
   [0] = Null
   [1] = Int 2
   [2] = String 'A.elem3'
-  [3] = Instance #lib::A type-args CP#0 {index: CP#1, _name: CP#2}
+  [3] = Instance #lib::A type-args CP#0 {#lib::A::index (field): CP#1, #lib::A::_name (field): CP#2}
 }
 ]  static const field self::A elem3 = const self::A::•(2, "A.elem3");
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#3
@@ -83,11 +83,11 @@
   [0] = Null
   [1] = Int 3
   [2] = String 'A.elem4'
-  [3] = Instance #lib::A type-args CP#0 {index: CP#1, _name: CP#2}
+  [3] = Instance #lib::A type-args CP#0 {#lib::A::index (field): CP#1, #lib::A::_name (field): CP#2}
 }
 ]  static const field self::A elem4 = const self::A::•(3, "A.elem4");
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-7]
@@ -104,18 +104,18 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = InstanceField #lib::A::index
+  [0] = InstanceField #lib::A::index (field)
   [1] = Reserved
-  [2] = InstanceField #lib::A::_name
+  [2] = InstanceField #lib::A::_name (field)
   [3] = Reserved
   [4] = ArgDesc num-args 1, num-type-args 0, names []
-  [5] = StaticICData target 'dart.core::Object::', arg-desc CP#4
+  [5] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#4
 }
 ]  const constructor •(core::int index, core::String _name) → self::A
     : self::A::index = index, self::A::_name = _name, super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -125,7 +125,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData get target '#lib::A::_name', arg-desc CP#0
+  [1] = StaticICData target '#lib::A::get:_name', arg-desc CP#0
 }
 ]  method toString() → core::String
     return this.{=self::A::_name};
@@ -133,7 +133,7 @@
 class B extends core::Object {
   final field core::int i;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-6]
@@ -147,10 +147,10 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = InstanceField #lib::B::i
+  [0] = InstanceField #lib::B::i (field)
   [1] = Reserved
   [2] = ArgDesc num-args 1, num-type-args 0, names []
-  [3] = StaticICData target 'dart.core::Object::', arg-desc CP#2
+  [3] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#2
 }
 ]  const constructor •(core::int i) → self::B
     : self::B::i = i, super core::Object::•()
@@ -159,7 +159,7 @@
 class C extends self::B {
   final field core::int j;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-8]
@@ -178,10 +178,10 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = InstanceField #lib::C::j
+  [0] = InstanceField #lib::C::j (field)
   [1] = Reserved
   [2] = ArgDesc num-args 2, num-type-args 0, names []
-  [3] = StaticICData target '#lib::B::', arg-desc CP#2
+  [3] = StaticICData target '#lib::B::'' (constructor)', arg-desc CP#2
 }
 ]  const constructor •(core::int a, core::int b, core::int c) → self::C
     : self::C::j = a.{core::num::+}(b), super self::B::•(c.{core::num::*}(5))
@@ -191,7 +191,7 @@
   final field dynamic x;
   final field dynamic y;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   EntryOptional        2, 1, 0
   LoadConstant         r2, CP#0
   Frame                0
@@ -211,12 +211,12 @@
 }
 ConstantPool {
   [0] = Null
-  [1] = InstanceField #lib::D::x
+  [1] = InstanceField #lib::D::x (field)
   [2] = Reserved
-  [3] = InstanceField #lib::D::y
+  [3] = InstanceField #lib::D::y (field)
   [4] = Reserved
   [5] = ArgDesc num-args 1, num-type-args 0, names []
-  [6] = StaticICData target 'dart.core::Object::', arg-desc CP#5
+  [6] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#5
 }
 ]  const constructor •(dynamic x, [dynamic y = null]) → self::D
     : self::D::x = x, self::D::y = y, super core::Object::•()
@@ -224,7 +224,7 @@
 }
 class E<T extends core::Object = dynamic> extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -236,7 +236,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  const constructor •() → self::E<self::E::T>
     : super core::Object::•()
@@ -244,7 +244,7 @@
 }
 class F<P extends core::Object = dynamic, Q extends core::Object = dynamic> extends self::E<core::Map<self::F::P, self::F::Q>> {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -256,14 +256,14 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target '#lib::E::', arg-desc CP#0
+  [1] = StaticICData target '#lib::E::'' (constructor)', arg-desc CP#0
 }
 ]  const constructor •() → self::F<self::F::P, self::F::Q>
     : super self::E::•()
     ;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#3
@@ -273,12 +273,12 @@
   [0] = Null
   [1] = Int 2
   [2] = String 'A.elem3'
-  [3] = Instance #lib::A type-args CP#0 {index: CP#1, _name: CP#2}
+  [3] = Instance #lib::A type-args CP#0 {#lib::A::index (field): CP#1, #lib::A::_name (field): CP#2}
 }
 ]static const field self::A c1 = self::A::elem3;
 static const field core::String c2 = "hello!";
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushInt              6
@@ -288,7 +288,7 @@
 }
 ]static const field core::int c3 = self::c2.{core::String::length};
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#3
@@ -298,11 +298,11 @@
   [0] = Null
   [1] = Int 3
   [2] = Int 15
-  [3] = Instance #lib::C type-args CP#0 {j: CP#1, i: CP#2}
+  [3] = Instance #lib::C type-args CP#0 {#lib::C::j (field): CP#1, #lib::B::i (field): CP#2}
 }
 ]static const field self::C c4 = const self::C::•(1, 2, 3);
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#3
@@ -311,13 +311,13 @@
 ConstantPool {
   [0] = Null
   [1] = Int 4
-  [2] = Instance #lib::B type-args CP#0 {i: CP#1}
-  [3] = Instance #lib::D type-args CP#0 {x: CP#2, y: CP#0}
+  [2] = Instance #lib::B type-args CP#0 {#lib::B::i (field): CP#1}
+  [3] = Instance #lib::D type-args CP#0 {#lib::D::x (field): CP#2, #lib::D::y (field): CP#0}
 }
 ]static const field self::D c5 = const self::D::•(const self::B::•(4));
 static field core::double fieldWithDoubleLiteralInitializer = 1.0;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#3
@@ -347,20 +347,20 @@
   [0] = Null
   [1] = Int 2
   [2] = String 'A.elem3'
-  [3] = Instance #lib::A type-args CP#0 {index: CP#1, _name: CP#2}
+  [3] = Instance #lib::A type-args CP#0 {#lib::A::index (field): CP#1, #lib::A::_name (field): CP#2}
   [4] = ArgDesc num-args 1, num-type-args 0, names []
-  [5] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [5] = StaticICData target 'dart:core::print', arg-desc CP#4
   [6] = String 'hello!'
-  [7] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [8] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [7] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [8] = StaticICData target 'dart:core::print', arg-desc CP#4
   [9] = Int 3
   [10] = Int 15
-  [11] = Instance #lib::C type-args CP#0 {j: CP#9, i: CP#10}
-  [12] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [11] = Instance #lib::C type-args CP#0 {#lib::C::j (field): CP#9, #lib::B::i (field): CP#10}
+  [12] = StaticICData target 'dart:core::print', arg-desc CP#4
   [13] = Int 4
-  [14] = Instance #lib::B type-args CP#0 {i: CP#13}
-  [15] = Instance #lib::D type-args CP#0 {x: CP#14, y: CP#0}
-  [16] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [14] = Instance #lib::B type-args CP#0 {#lib::B::i (field): CP#13}
+  [15] = Instance #lib::D type-args CP#0 {#lib::D::x (field): CP#14, #lib::D::y (field): CP#0}
+  [16] = StaticICData target 'dart:core::print', arg-desc CP#4
 }
 ]static method test_constants1() → void {
   core::print(self::c1);
@@ -370,7 +370,7 @@
   core::print(self::c5);
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushInt              42
@@ -402,38 +402,38 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::print', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::print', arg-desc CP#0
   [2] = String 'foo'
-  [3] = StaticICData target 'dart.core::print', arg-desc CP#0
+  [3] = StaticICData target 'dart:core::print', arg-desc CP#0
   [4] = Null
   [5] = Int 1
   [6] = String 'A.elem2'
-  [7] = Instance #lib::A type-args CP#4 {index: CP#5, _name: CP#6}
-  [8] = StaticICData target 'dart.core::print', arg-desc CP#0
+  [7] = Instance #lib::A type-args CP#4 {#lib::A::index (field): CP#5, #lib::A::_name (field): CP#6}
+  [8] = StaticICData target 'dart:core::print', arg-desc CP#0
   [9] = Int 42
-  [10] = Type dart.core::int
-  [11] = List type-arg dart.core::Object, entries CP# [9, 2, 10]
-  [12] = StaticICData target 'dart.core::print', arg-desc CP#0
-  [13] = TypeArgumentsForInstanceAllocation dart.core::_ImmutableMap [dart.core::String, #lib::A]
+  [10] = Type dart:core::int
+  [11] = List type-arg dart:core::Object, entries CP# [9, 2, 10]
+  [12] = StaticICData target 'dart:core::print', arg-desc CP#0
+  [13] = TypeArgumentsForInstanceAllocation dart:core::_ImmutableMap [dart:core::String, #lib::A]
   [14] = String 'E2'
   [15] = String 'E4'
   [16] = Int 3
   [17] = String 'A.elem4'
-  [18] = Instance #lib::A type-args CP#4 {index: CP#16, _name: CP#17}
+  [18] = Instance #lib::A type-args CP#4 {#lib::A::index (field): CP#16, #lib::A::_name (field): CP#17}
   [19] = List type-arg dynamic, entries CP# [14, 7, 15, 18]
-  [20] = Instance dart.core::_ImmutableMap type-args CP#13 {_kvPairs: CP#19}
-  [21] = StaticICData target 'dart.core::print', arg-desc CP#0
+  [20] = Instance dart:core::_ImmutableMap type-args CP#13 {dart:core::_ImmutableMap::_kvPairs (field): CP#19}
+  [21] = StaticICData target 'dart:core::print', arg-desc CP#0
   [22] = Int 9
   [23] = Int 30
-  [24] = Instance #lib::C type-args CP#4 {j: CP#22, i: CP#23}
-  [25] = TypeArgumentsForInstanceAllocation dart.core::_ImmutableMap [dart.core::String, dart.core::Object]
+  [24] = Instance #lib::C type-args CP#4 {#lib::C::j (field): CP#22, #lib::B::i (field): CP#23}
+  [25] = TypeArgumentsForInstanceAllocation dart:core::_ImmutableMap [dart:core::String, dart:core::Object]
   [26] = String 'bar'
   [27] = Int 6
-  [28] = Instance #lib::B type-args CP#4 {i: CP#27}
+  [28] = Instance #lib::B type-args CP#4 {#lib::B::i (field): CP#27}
   [29] = List type-arg dynamic, entries CP# [2, 9, 26, 28]
-  [30] = Instance dart.core::_ImmutableMap type-args CP#25 {_kvPairs: CP#29}
-  [31] = Instance #lib::D type-args CP#4 {x: CP#24, y: CP#30}
-  [32] = StaticICData target 'dart.core::print', arg-desc CP#0
+  [30] = Instance dart:core::_ImmutableMap type-args CP#25 {dart:core::_ImmutableMap::_kvPairs (field): CP#29}
+  [31] = Instance #lib::D type-args CP#4 {#lib::D::x (field): CP#24, #lib::D::y (field): CP#30}
+  [32] = StaticICData target 'dart:core::print', arg-desc CP#0
 }
 ]static method test_constants2() → void {
   core::print(42);
@@ -444,7 +444,7 @@
   core::print(const self::D::•(const self::C::•(4, 5, 6), const <core::String, core::Object>{"foo": 42, "bar": const self::B::•(self::c2.{core::String::length})}));
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   PushConstant         CP#0
@@ -498,24 +498,24 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgs [dart.core::int]
+  [0] = TypeArgs [dart:core::int]
   [1] = ArgDesc num-args 2, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::List::_fromLiteral', arg-desc CP#1
+  [2] = StaticICData target 'dart:core::List::_fromLiteral (constructor)', arg-desc CP#1
   [3] = ArgDesc num-args 1, num-type-args 0, names []
-  [4] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [5] = TypeArgs [dart.core::String]
+  [4] = StaticICData target 'dart:core::print', arg-desc CP#3
+  [5] = TypeArgs [dart:core::String]
   [6] = String 'a'
   [7] = ICData target-name 'toString', arg-desc CP#3
   [8] = String 'b'
-  [9] = StaticICData target 'dart.core::List::_fromLiteral', arg-desc CP#1
-  [10] = StaticICData target 'dart.core::print', arg-desc CP#3
+  [9] = StaticICData target 'dart:core::List::_fromLiteral (constructor)', arg-desc CP#1
+  [10] = StaticICData target 'dart:core::print', arg-desc CP#3
 }
 ]static method test_list_literal(core::int a) → void {
   core::print(<core::int>[1, a, 3]);
   core::print(<core::String>["a", a.{core::int::toString}(), "b"]);
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   CheckFunctionTypeArgs 1, r0
@@ -605,24 +605,24 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgs [dart.core::int, dart.core::int]
+  [0] = TypeArgs [dart:core::int, dart:core::int]
   [1] = TypeArgs [dynamic]
   [2] = ArgDesc num-args 2, num-type-args 0, names []
-  [3] = StaticICData target 'dart.core::Map::_fromLiteral', arg-desc CP#2
+  [3] = StaticICData target 'dart:core::Map::_fromLiteral (constructor)', arg-desc CP#2
   [4] = ArgDesc num-args 1, num-type-args 0, names []
-  [5] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [6] = TypeArgs [dart.core::String, dart.core::int]
+  [5] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [6] = TypeArgs [dart:core::String, dart:core::int]
   [7] = String 'foo'
   [8] = ICData target-name 'toString', arg-desc CP#4
-  [9] = StaticICData target 'dart.core::Map::_fromLiteral', arg-desc CP#2
-  [10] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [11] = TypeArgs [dart.core::String, #lib::test_map_literal::T]
+  [9] = StaticICData target 'dart:core::Map::_fromLiteral (constructor)', arg-desc CP#2
+  [10] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [11] = TypeArgs [dart:core::String, #lib::test_map_literal::TypeParam/0]
   [12] = List type-arg dynamic, entries CP# []
-  [13] = StaticICData target 'dart.core::Map::_fromLiteral', arg-desc CP#2
-  [14] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [15] = TypeArgs [#lib::test_map_literal::T, dart.core::int]
-  [16] = StaticICData target 'dart.core::Map::_fromLiteral', arg-desc CP#2
-  [17] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [13] = StaticICData target 'dart:core::Map::_fromLiteral (constructor)', arg-desc CP#2
+  [14] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [15] = TypeArgs [#lib::test_map_literal::TypeParam/0, dart:core::int]
+  [16] = StaticICData target 'dart:core::Map::_fromLiteral (constructor)', arg-desc CP#2
+  [17] = StaticICData target 'dart:core::print', arg-desc CP#4
 }
 ]static method test_map_literal<T extends core::Object = dynamic>(core::int a, core::int b, self::test_map_literal::T c) → void {
   core::print(<core::int, core::int>{1: a, b: 2});
@@ -631,7 +631,7 @@
   core::print(<self::test_map_literal::T, core::int>{c: 4});
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#0
@@ -646,18 +646,18 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = Symbol 'test_symbol'
+  [0] = Symbol test_symbol
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [3] = Symbol #lib::'_private_symbol'
-  [4] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [2] = StaticICData target 'dart:core::print', arg-desc CP#1
+  [3] = Symbol _private_symbol
+  [4] = StaticICData target 'dart:core::print', arg-desc CP#1
 }
 ]static method test_symbol() → void {
   core::print(#test_symbol);
   core::print(#_private_symbol);
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   CheckFunctionTypeArgs 1, r0
@@ -675,43 +675,43 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = Type dart.core::String
+  [0] = Type dart:core::String
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [3] = Type #lib::test_type_literal::T
-  [4] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [2] = StaticICData target 'dart:core::print', arg-desc CP#1
+  [3] = Type #lib::test_type_literal::TypeParam/0
+  [4] = StaticICData target 'dart:core::print', arg-desc CP#1
 }
 ]static method test_type_literal<T extends core::Object = dynamic>() → void {
   core::print(core::String);
   core::print(self::test_type_literal::T);
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#1
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgumentsForInstanceAllocation #lib::F [dart.core::int, dart.core::String]
+  [0] = TypeArgumentsForInstanceAllocation #lib::F [dart:core::int, dart:core::String]
   [1] = Instance #lib::F type-args CP#0 {}
 }
 ]static method testGenericConstInstance() → dynamic
   return const self::F::•<core::int, core::String>();
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#0
   ReturnTOS
 }
 ConstantPool {
-  [0] = Type <X extends dart.core::Object = dynamic>(X) → X
+  [0] = Type FunctionType <dart:core::Object X> (null::TypeParam/0) -> null::TypeParam/0
 }
 ]static method testGenericFunctionTypeLiteral() → dynamic
   return <X extends core::Object = dynamic>(X) → X;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#0
@@ -719,12 +719,12 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = StaticField #lib::fieldWithDoubleLiteralInitializer
+  [0] = StaticField #lib::fieldWithDoubleLiteralInitializer (field)
 }
 ]static method testFieldWithDoubleLiteralInitializer() → dynamic
   return self::fieldWithDoubleLiteralInitializer;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
diff --git a/pkg/vm/testcases/bytecode/loops.dart.expect b/pkg/vm/testcases/bytecode/loops.dart.expect
index 77b4601..b3714bd 100644
--- a/pkg/vm/testcases/bytecode/loops.dart.expect
+++ b/pkg/vm/testcases/bytecode/loops.dart.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   PushInt              0
@@ -35,7 +35,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = ICData get target-name 'length', arg-desc CP#0
+  [1] = ICData get target-name 'get:length', arg-desc CP#0
   [2] = ArgDesc num-args 2, num-type-args 0, names []
   [3] = ICData target-name '[]', arg-desc CP#2
 }
@@ -47,7 +47,7 @@
   return sum;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   PushInt              0
@@ -85,7 +85,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = ICData get target-name 'length', arg-desc CP#0
+  [1] = ICData get target-name 'get:length', arg-desc CP#0
   [2] = ArgDesc num-args 2, num-type-args 0, names []
   [3] = ICData target-name '[]', arg-desc CP#2
 }
@@ -101,7 +101,7 @@
   return sum;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   PushInt              0
@@ -141,7 +141,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = ICData get target-name 'length', arg-desc CP#0
+  [1] = ICData get target-name 'get:length', arg-desc CP#0
   [2] = ArgDesc num-args 2, num-type-args 0, names []
   [3] = ICData target-name '[]', arg-desc CP#2
 }
@@ -158,7 +158,7 @@
   return sum;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                4
   CheckStack           0
   PushInt              0
@@ -192,7 +192,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = ICData get target-name 'length', arg-desc CP#0
+  [1] = ICData get target-name 'get:length', arg-desc CP#0
   [2] = ArgDesc num-args 2, num-type-args 0, names []
   [3] = ICData target-name '[]', arg-desc CP#2
 }
@@ -205,7 +205,7 @@
   return sum;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   PushInt              0
@@ -236,7 +236,7 @@
   [0] = ArgDesc num-args 2, num-type-args 0, names []
   [1] = ICData target-name '[]', arg-desc CP#0
   [2] = ArgDesc num-args 1, num-type-args 0, names []
-  [3] = ICData get target-name 'length', arg-desc CP#2
+  [3] = ICData get target-name 'get:length', arg-desc CP#2
 }
 ]static method test_do_while(core::List<core::int> list) → core::int {
   core::int sum = 0;
@@ -249,7 +249,7 @@
   return sum;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                3
   CheckStack           0
   PushInt              0
@@ -276,9 +276,9 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = ICData get target-name 'iterator', arg-desc CP#0
+  [1] = ICData get target-name 'get:iterator', arg-desc CP#0
   [2] = ICData target-name 'moveNext', arg-desc CP#0
-  [3] = ICData get target-name 'current', arg-desc CP#0
+  [3] = ICData get target-name 'get:current', arg-desc CP#0
 }
 ]static method test_for_in(core::List<core::int> list) → core::int {
   core::int sum = 0;
@@ -288,7 +288,7 @@
   return sum;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                4
   CheckStack           0
   PushInt              0
@@ -319,9 +319,9 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = ICData get target-name 'iterator', arg-desc CP#0
+  [1] = ICData get target-name 'get:iterator', arg-desc CP#0
   [2] = ICData target-name 'moveNext', arg-desc CP#0
-  [3] = ICData get target-name 'current', arg-desc CP#0
+  [3] = ICData get target-name 'get:current', arg-desc CP#0
 }
 ]static method test_for_in_with_outer_var(core::List<core::int> list) → core::int {
   core::int sum = 0;
@@ -333,7 +333,7 @@
   return sum;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
diff --git a/pkg/vm/testcases/bytecode/optional_params.dart.expect b/pkg/vm/testcases/bytecode/optional_params.dart.expect
index 8fa1589..d715039 100644
--- a/pkg/vm/testcases/bytecode/optional_params.dart.expect
+++ b/pkg/vm/testcases/bytecode/optional_params.dart.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   EntryOptional        1, 2, 0
   LoadConstant         r1, CP#0
   LoadConstant         r2, CP#1
@@ -68,14 +68,14 @@
   [1] = String 'default_b'
   [2] = String 'x = '
   [3] = ArgDesc num-args 1, num-type-args 0, names []
-  [4] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#3
-  [5] = StaticICData target 'dart.core::print', arg-desc CP#3
+  [4] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#3
+  [5] = StaticICData target 'dart:core::print', arg-desc CP#3
   [6] = String 'a = '
-  [7] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#3
-  [8] = StaticICData target 'dart.core::print', arg-desc CP#3
+  [7] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#3
+  [8] = StaticICData target 'dart:core::print', arg-desc CP#3
   [9] = String 'b = '
-  [10] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#3
-  [11] = StaticICData target 'dart.core::print', arg-desc CP#3
+  [10] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#3
+  [11] = StaticICData target 'dart:core::print', arg-desc CP#3
 }
 ]static method foo1(dynamic x, [dynamic a = "default_a", dynamic b = "default_b"]) → void {
   core::print("x = ${x}");
@@ -83,7 +83,7 @@
   core::print("b = ${b}");
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   EntryOptional        2, 0, 3
   LoadConstant         r2, CP#0
   LoadConstant         r2, CP#1
@@ -186,25 +186,25 @@
   [1] = Int 42
   [2] = String 'b'
   [3] = String 'default_b'
-  [4] = List type-arg dart.core::String, entries CP# [3]
+  [4] = List type-arg dart:core::String, entries CP# [3]
   [5] = String 'c'
   [6] = String 'default_c'
   [7] = String 'y = '
   [8] = ArgDesc num-args 1, num-type-args 0, names []
-  [9] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#8
-  [10] = StaticICData target 'dart.core::print', arg-desc CP#8
+  [9] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#8
+  [10] = StaticICData target 'dart:core::print', arg-desc CP#8
   [11] = String 'z = '
-  [12] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#8
-  [13] = StaticICData target 'dart.core::print', arg-desc CP#8
+  [12] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#8
+  [13] = StaticICData target 'dart:core::print', arg-desc CP#8
   [14] = String 'a = '
-  [15] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#8
-  [16] = StaticICData target 'dart.core::print', arg-desc CP#8
+  [15] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#8
+  [16] = StaticICData target 'dart:core::print', arg-desc CP#8
   [17] = String 'b = '
-  [18] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#8
-  [19] = StaticICData target 'dart.core::print', arg-desc CP#8
+  [18] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#8
+  [19] = StaticICData target 'dart:core::print', arg-desc CP#8
   [20] = String 'c = '
-  [21] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#8
-  [22] = StaticICData target 'dart.core::print', arg-desc CP#8
+  [21] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#8
+  [22] = StaticICData target 'dart:core::print', arg-desc CP#8
 }
 ]static method foo2(dynamic y, dynamic z, {dynamic c = "default_c", dynamic a = 42, dynamic b = const <core::String>["default_b"]}) → void {
   core::print("y = ${y}");
@@ -214,7 +214,7 @@
   core::print("c = ${c}");
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   EntryOptional        2, 0, 2
   LoadConstant         r2, CP#0
   LoadConstant         r2, CP#1
@@ -245,11 +245,11 @@
   [1] = Bool false
   [2] = String 'b'
   [3] = Null
-  [4] = Type #lib::foo3::P
+  [4] = Type #lib::foo3::TypeParam/0
   [5] = ArgDesc num-args 1, num-type-args 0, names []
-  [6] = StaticICData target 'dart.core::print', arg-desc CP#5
-  [7] = StaticICData target 'dart.core::print', arg-desc CP#5
-  [8] = StaticICData target 'dart.core::print', arg-desc CP#5
+  [6] = StaticICData target 'dart:core::print', arg-desc CP#5
+  [7] = StaticICData target 'dart:core::print', arg-desc CP#5
+  [8] = StaticICData target 'dart:core::print', arg-desc CP#5
 }
 ]static method foo3<P extends core::Object = dynamic, Q extends core::Object = dynamic>(dynamic z, dynamic y, {core::bool a = false, core::Map<self::foo3::P, self::foo3::Q> b = null}) → void {
   core::print(self::foo3::P);
@@ -257,7 +257,7 @@
   core::print(b);
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushConstant         CP#0
diff --git a/pkg/vm/testcases/bytecode/super_calls.dart.expect b/pkg/vm/testcases/bytecode/super_calls.dart.expect
index 2302eb4..9ee6e1e 100644
--- a/pkg/vm/testcases/bytecode/super_calls.dart.expect
+++ b/pkg/vm/testcases/bytecode/super_calls.dart.expect
@@ -4,7 +4,7 @@
 
 class Base1 extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -16,13 +16,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::Base1
     : super core::Object::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   CheckFunctionTypeArgs 1, r0
@@ -33,7 +33,7 @@
 }
 ]  method foo<T extends core::Object = dynamic>(self::Base1::foo::T a1, core::int a2) → void {}
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushInt              42
@@ -44,7 +44,7 @@
 ]  get bar() → dynamic
     return 42;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
@@ -56,7 +56,7 @@
 }
 class A extends self::Base1 {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -68,13 +68,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target '#lib::Base1::', arg-desc CP#0
+  [1] = StaticICData target '#lib::Base1::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::A
     : super self::Base1::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   PushConstant         CP#0
@@ -86,7 +86,7 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgs [dart.core::String]
+  [0] = TypeArgs [dart:core::String]
   [1] = String 'a1'
   [2] = ArgDesc num-args 3, num-type-args 1, names []
   [3] = StaticICData target '#lib::Base1::foo', arg-desc CP#2
@@ -94,7 +94,7 @@
 ]  method testSuperCall(core::int x) → dynamic
     return super.{self::Base1::foo}<core::String>("a1", 2);
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -104,12 +104,12 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData get target '#lib::Base1::foo', arg-desc CP#0
+  [1] = StaticICData target '#lib::Base1::get:foo', arg-desc CP#0
 }
 ]  method testSuperTearOff() → dynamic
     return super.{self::Base1::foo};
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -119,12 +119,12 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData get target '#lib::Base1::bar', arg-desc CP#0
+  [1] = StaticICData target '#lib::Base1::get:bar', arg-desc CP#0
 }
 ]  method testSuperGet() → dynamic
     return super.{self::Base1::bar};
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   PushConstant         CP#0
@@ -136,9 +136,9 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgs [dart.core::int]
+  [0] = TypeArgs [dart:core::int]
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData get target '#lib::Base1::bar', arg-desc CP#1
+  [2] = StaticICData target '#lib::Base1::get:bar', arg-desc CP#1
   [3] = String 'param'
   [4] = ArgDesc num-args 2, num-type-args 1, names []
   [5] = ICData dynamic target-name 'call', arg-desc CP#4
@@ -146,7 +146,7 @@
 ]  method testSuperCallViaGetter() → dynamic
     return [@vm.call-site-attributes.metadata=receiverType:dynamic] super.{self::Base1::bar}.call<core::int>("param");
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -159,7 +159,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 2, num-type-args 0, names []
-  [1] = StaticICData set target '#lib::Base1::bazz', arg-desc CP#0
+  [1] = StaticICData target '#lib::Base1::set:bazz', arg-desc CP#0
 }
 ]  method testSuperSet() → dynamic {
     super.{self::Base1::bazz} = 3;
@@ -167,7 +167,7 @@
 }
 abstract class Base2 extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -179,7 +179,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::Base2
     : super core::Object::•()
@@ -190,7 +190,7 @@
 }
 abstract class B extends self::Base2 {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -202,13 +202,13 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target '#lib::Base2::', arg-desc CP#0
+  [1] = StaticICData target '#lib::Base2::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::B
     : super self::Base2::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-6]
@@ -249,18 +249,18 @@
   [0] = ArgDesc num-args 4, num-type-args 1, names []
   [1] = String 'foo'
   [2] = TypeArgs [dynamic]
-  [3] = TypeArgs [dart.core::double]
+  [3] = TypeArgs [dart:core::double]
   [4] = String 'a1'
   [5] = Double 3.14
   [6] = ArgDesc num-args 4, num-type-args 0, names []
-  [7] = StaticICData target 'dart.core::_InvocationMirror::_allocateInvocationMirror', arg-desc CP#6
+  [7] = StaticICData target 'dart:core::_InvocationMirror::_allocateInvocationMirror', arg-desc CP#6
   [8] = ArgDesc num-args 2, num-type-args 0, names []
-  [9] = StaticICData target 'dart.core::Object::noSuchMethod', arg-desc CP#8
+  [9] = StaticICData target 'dart:core::Object::noSuchMethod', arg-desc CP#8
 }
 ]  method testSuperCall(core::int x) → dynamic
     return super.{self::Base2::foo}<core::double>("a1", 3.14, 5);
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -286,14 +286,14 @@
   [1] = String 'foo'
   [2] = TypeArgs [dynamic]
   [3] = ArgDesc num-args 4, num-type-args 0, names []
-  [4] = StaticICData target 'dart.core::_InvocationMirror::_allocateInvocationMirror', arg-desc CP#3
+  [4] = StaticICData target 'dart:core::_InvocationMirror::_allocateInvocationMirror', arg-desc CP#3
   [5] = ArgDesc num-args 2, num-type-args 0, names []
-  [6] = StaticICData target 'dart.core::Object::noSuchMethod', arg-desc CP#5
+  [6] = StaticICData target 'dart:core::Object::noSuchMethod', arg-desc CP#5
 }
 ]  method testSuperTearOff() → dynamic
     return super.{self::Base2::foo};
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -319,14 +319,14 @@
   [1] = String 'bar'
   [2] = TypeArgs [dynamic]
   [3] = ArgDesc num-args 4, num-type-args 0, names []
-  [4] = StaticICData target 'dart.core::_InvocationMirror::_allocateInvocationMirror', arg-desc CP#3
+  [4] = StaticICData target 'dart:core::_InvocationMirror::_allocateInvocationMirror', arg-desc CP#3
   [5] = ArgDesc num-args 2, num-type-args 0, names []
-  [6] = StaticICData target 'dart.core::Object::noSuchMethod', arg-desc CP#5
+  [6] = StaticICData target 'dart:core::Object::noSuchMethod', arg-desc CP#5
 }
 ]  method testSuperGet() → dynamic
     return super.{self::Base2::bar};
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   PushConstant         CP#0
@@ -351,14 +351,14 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = TypeArgs [dart.core::int]
+  [0] = TypeArgs [dart:core::int]
   [1] = ArgDesc num-args 1, num-type-args 0, names []
   [2] = String 'bar'
   [3] = TypeArgs [dynamic]
   [4] = ArgDesc num-args 4, num-type-args 0, names []
-  [5] = StaticICData target 'dart.core::_InvocationMirror::_allocateInvocationMirror', arg-desc CP#4
+  [5] = StaticICData target 'dart:core::_InvocationMirror::_allocateInvocationMirror', arg-desc CP#4
   [6] = ArgDesc num-args 2, num-type-args 0, names []
-  [7] = StaticICData target 'dart.core::Object::noSuchMethod', arg-desc CP#6
+  [7] = StaticICData target 'dart:core::Object::noSuchMethod', arg-desc CP#6
   [8] = String 'param'
   [9] = ArgDesc num-args 2, num-type-args 1, names []
   [10] = ICData dynamic target-name 'call', arg-desc CP#9
@@ -366,7 +366,7 @@
 ]  method testSuperCallViaGetter() → dynamic
     return [@vm.call-site-attributes.metadata=receiverType:dynamic] super.{self::Base2::bar}.call<core::int>("param");
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -398,15 +398,15 @@
   [1] = String 'bazz'
   [2] = TypeArgs [dynamic]
   [3] = ArgDesc num-args 4, num-type-args 0, names []
-  [4] = StaticICData target 'dart.core::_InvocationMirror::_allocateInvocationMirror', arg-desc CP#3
-  [5] = StaticICData target 'dart.core::Object::noSuchMethod', arg-desc CP#0
+  [4] = StaticICData target 'dart:core::_InvocationMirror::_allocateInvocationMirror', arg-desc CP#3
+  [5] = StaticICData target 'dart:core::Object::noSuchMethod', arg-desc CP#0
 }
 ]  method testSuperSet() → dynamic {
     super.{self::Base2::bazz} = 3;
   }
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
diff --git a/pkg/vm/testcases/bytecode/switch.dart.expect b/pkg/vm/testcases/bytecode/switch.dart.expect
index 3ed2d95..fe265d6 100644
--- a/pkg/vm/testcases/bytecode/switch.dart.expect
+++ b/pkg/vm/testcases/bytecode/switch.dart.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   PushNull
@@ -71,7 +71,7 @@
   return y;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   PushNull
@@ -156,7 +156,7 @@
   return y;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   PushNull
@@ -240,7 +240,7 @@
   return y;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
diff --git a/pkg/vm/testcases/bytecode/try_blocks.dart.expect b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
index 8b87d84..e50ba42 100644
--- a/pkg/vm/testcases/bytecode/try_blocks.dart.expect
+++ b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
@@ -3,7 +3,7 @@
 import "dart:core" as core;
 
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                4
   CheckStack           0
 Try #0 start:
@@ -47,11 +47,11 @@
 ConstantPool {
   [0] = String 'danger!'
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [2] = StaticICData target 'dart:core::print', arg-desc CP#1
   [3] = Type dynamic
   [4] = String 'caught '
-  [5] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#1
-  [6] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [5] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#1
+  [6] = StaticICData target 'dart:core::print', arg-desc CP#1
 }
 ]static method testTryCatch1() → dynamic {
   try {
@@ -62,7 +62,7 @@
   }
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                5
   CheckStack           0
 Try #0 start:
@@ -186,27 +186,27 @@
 ConstantPool {
   [0] = String 'danger!'
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [3] = Type dart.core::TypeError
+  [2] = StaticICData target 'dart:core::print', arg-desc CP#1
+  [3] = Type dart:core::TypeError
   [4] = ArgDesc num-args 2, num-type-args 0, names []
-  [5] = ICData target-name 'dart.core::_simpleInstanceOf', arg-desc CP#4
+  [5] = ICData target-name '_simpleInstanceOf', arg-desc CP#4
   [6] = String 'caught type error'
-  [7] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [8] = Type dart.core::AssertionError
-  [9] = ICData target-name 'dart.core::_simpleInstanceOf', arg-desc CP#4
+  [7] = StaticICData target 'dart:core::print', arg-desc CP#1
+  [8] = Type dart:core::AssertionError
+  [9] = ICData target-name '_simpleInstanceOf', arg-desc CP#4
   [10] = String 'caught assertion error '
-  [11] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#1
-  [12] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [13] = Type dart.core::Error
-  [14] = ICData target-name 'dart.core::_simpleInstanceOf', arg-desc CP#4
+  [11] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#1
+  [12] = StaticICData target 'dart:core::print', arg-desc CP#1
+  [13] = Type dart:core::Error
+  [14] = ICData target-name '_simpleInstanceOf', arg-desc CP#4
   [15] = String 'caught error '
   [16] = String ' '
-  [17] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#1
-  [18] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [17] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#1
+  [18] = StaticICData target 'dart:core::print', arg-desc CP#1
   [19] = Type dynamic
   [20] = String 'caught something '
-  [21] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#1
-  [22] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [21] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#1
+  [22] = StaticICData target 'dart:core::print', arg-desc CP#1
 }
 ]static method testTryCatch2() → dynamic {
   try {
@@ -226,7 +226,7 @@
   }
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                7
   CheckStack           0
   AllocateContext      0, 3
@@ -336,44 +336,45 @@
   try-index 0, outer -1, start 9, end 39, handler 39, needs-stack-trace, types [CP#6]
 }
 ConstantPool {
-  [0] = ClosureFunction foo () → void;
-  [1] = InstanceField dart.core::_Closure::_context
+  [0] = ClosureFunction 0
+  [1] = InstanceField dart:core::_Closure::_context (field)
   [2] = Reserved
   [3] = String 'danger foo'
   [4] = ArgDesc num-args 1, num-type-args 0, names []
-  [5] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [5] = StaticICData target 'dart:core::print', arg-desc CP#4
   [6] = Type dynamic
-  [7] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [7] = StaticICData target 'dart:core::print', arg-desc CP#4
   [8] = EndClosureFunctionScope
-  [9] = Class dart.core::_Closure
-  [10] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [9] = Class dart:core::_Closure
+  [10] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [11] = Reserved
-  [12] = InstanceField dart.core::_Closure::_function_type_arguments
+  [12] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [13] = Reserved
   [14] = EmptyTypeArguments
-  [15] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [15] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [16] = Reserved
-  [17] = InstanceField dart.core::_Closure::_function
+  [17] = InstanceField dart:core::_Closure::_function (field)
   [18] = Reserved
   [19] = ICData dynamic target-name 'call', arg-desc CP#4
-  [20] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [20] = StaticICData target 'dart:core::print', arg-desc CP#4
   [21] = String 'caught '
   [22] = String ' '
-  [23] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#4
-  [24] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [25] = ClosureFunction bar () → void;
+  [23] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#4
+  [24] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [25] = ClosureFunction 1
   [26] = String 'danger bar'
-  [27] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [28] = Type dart.core::Error
+  [27] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [28] = Type dart:core::Error
   [29] = ArgDesc num-args 2, num-type-args 0, names []
-  [30] = ICData target-name 'dart.core::_simpleInstanceOf', arg-desc CP#29
+  [30] = ICData target-name '_simpleInstanceOf', arg-desc CP#29
   [31] = String 'error '
   [32] = String ', captured stack trace: '
-  [33] = StaticICData target 'dart.core::_StringBase::_interpolate', arg-desc CP#4
-  [34] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [33] = StaticICData target 'dart:core::_StringBase::_interpolate', arg-desc CP#4
+  [34] = StaticICData target 'dart:core::print', arg-desc CP#4
   [35] = EndClosureFunctionScope
 }
-Closure CP#0 {
+Closure #lib::testTryCatch3::foo () -> void
+ClosureBytecode {
   EntryFixed           1, 6
   CheckStack           0
   Push                 FP[-5]
@@ -411,7 +412,8 @@
 
 }
 
-Closure CP#25 {
+Closure #lib::testTryCatch3::bar () -> void
+ClosureBytecode {
   EntryFixed           1, 6
   CheckStack           0
   Push                 FP[-5]
@@ -504,7 +506,7 @@
   }
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                8
   CheckStack           0
 Try #0 start:
@@ -580,15 +582,15 @@
 ConstantPool {
   [0] = String 'try 1 > try 2'
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [2] = StaticICData target 'dart:core::print', arg-desc CP#1
   [3] = Type dynamic
   [4] = String 'try 1 > catch 2 > try 3'
-  [5] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [5] = StaticICData target 'dart:core::print', arg-desc CP#1
   [6] = String 'try 1 > catch 2 > catch 3'
-  [7] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [7] = StaticICData target 'dart:core::print', arg-desc CP#1
   [8] = String 'catch 1'
-  [9] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [10] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [9] = StaticICData target 'dart:core::print', arg-desc CP#1
+  [10] = StaticICData target 'dart:core::print', arg-desc CP#1
 }
 ]static method testRethrow(core::bool cond) → dynamic {
   try {
@@ -613,7 +615,7 @@
   }
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                3
   CheckStack           0
   PushInt              0
@@ -671,9 +673,9 @@
 ConstantPool {
   [0] = Type dynamic
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [3] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [4] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [2] = StaticICData target 'dart:core::print', arg-desc CP#1
+  [3] = StaticICData target 'dart:core::print', arg-desc CP#1
+  [4] = StaticICData target 'dart:core::print', arg-desc CP#1
 }
 ]static method testTryFinally1() → dynamic {
   #L1:
@@ -689,7 +691,7 @@
   }
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                9
   CheckStack           0
   AllocateContext      0, 2
@@ -813,39 +815,40 @@
   [2] = ICData target-name '==', arg-desc CP#0
   [3] = String 'before try 1'
   [4] = ArgDesc num-args 1, num-type-args 0, names []
-  [5] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [5] = StaticICData target 'dart:core::print', arg-desc CP#4
   [6] = String 'try'
-  [7] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [8] = ClosureFunction foo () → void;
-  [9] = InstanceField dart.core::_Closure::_context
+  [7] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [8] = ClosureFunction 0
+  [9] = InstanceField dart:core::_Closure::_context (field)
   [10] = Reserved
-  [11] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [12] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [11] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [12] = StaticICData target 'dart:core::print', arg-desc CP#4
   [13] = EndClosureFunctionScope
-  [14] = Class dart.core::_Closure
-  [15] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [14] = Class dart:core::_Closure
+  [15] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [16] = Reserved
-  [17] = InstanceField dart.core::_Closure::_function_type_arguments
+  [17] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [18] = Reserved
   [19] = EmptyTypeArguments
-  [20] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [20] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [21] = Reserved
-  [22] = InstanceField dart.core::_Closure::_function
+  [22] = InstanceField dart:core::_Closure::_function (field)
   [23] = Reserved
   [24] = ICData dynamic target-name 'call', arg-desc CP#4
   [25] = Type dynamic
   [26] = String 'finally 1'
-  [27] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [28] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [27] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [28] = StaticICData target 'dart:core::print', arg-desc CP#4
   [29] = String 'after try 1'
-  [30] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [30] = StaticICData target 'dart:core::print', arg-desc CP#4
   [31] = String 'finally 2'
-  [32] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [33] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [32] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [33] = StaticICData target 'dart:core::print', arg-desc CP#4
   [34] = String 'case 2'
-  [35] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [35] = StaticICData target 'dart:core::print', arg-desc CP#4
 }
-Closure CP#8 {
+Closure #lib::testTryFinally2::foo () -> void
+ClosureBytecode {
   EntryFixed           1, 2
   CheckStack           0
   Push                 FP[-5]
@@ -902,7 +905,7 @@
   }
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                6
   CheckStack           0
   AllocateContext      0, 1
@@ -973,38 +976,39 @@
   try-index 0, outer -1, start 11, end 30, handler 30, needs-stack-trace, types [CP#7]
 }
 ConstantPool {
-  [0] = ClosureFunction <anonymous closure> () → dart.core::int;
-  [1] = InstanceField dart.core::_Closure::_context
+  [0] = ClosureFunction 0
+  [1] = InstanceField dart:core::_Closure::_context (field)
   [2] = Reserved
   [3] = ArgDesc num-args 1, num-type-args 0, names []
-  [4] = StaticICData target 'dart.core::print', arg-desc CP#3
+  [4] = StaticICData target 'dart:core::print', arg-desc CP#3
   [5] = String 'try 1'
-  [6] = StaticICData target 'dart.core::print', arg-desc CP#3
+  [6] = StaticICData target 'dart:core::print', arg-desc CP#3
   [7] = Type dynamic
   [8] = String 'try 2'
-  [9] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [10] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [11] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [12] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [13] = StaticICData target 'dart.core::print', arg-desc CP#3
-  [14] = StaticICData target 'dart.core::print', arg-desc CP#3
+  [9] = StaticICData target 'dart:core::print', arg-desc CP#3
+  [10] = StaticICData target 'dart:core::print', arg-desc CP#3
+  [11] = StaticICData target 'dart:core::print', arg-desc CP#3
+  [12] = StaticICData target 'dart:core::print', arg-desc CP#3
+  [13] = StaticICData target 'dart:core::print', arg-desc CP#3
+  [14] = StaticICData target 'dart:core::print', arg-desc CP#3
   [15] = EndClosureFunctionScope
-  [16] = Class dart.core::_Closure
-  [17] = InstanceField dart.core::_Closure::_instantiator_type_arguments
+  [16] = Class dart:core::_Closure
+  [17] = InstanceField dart:core::_Closure::_instantiator_type_arguments (field)
   [18] = Reserved
-  [19] = InstanceField dart.core::_Closure::_function_type_arguments
+  [19] = InstanceField dart:core::_Closure::_function_type_arguments (field)
   [20] = Reserved
   [21] = EmptyTypeArguments
-  [22] = InstanceField dart.core::_Closure::_delayed_type_arguments
+  [22] = InstanceField dart:core::_Closure::_delayed_type_arguments (field)
   [23] = Reserved
-  [24] = InstanceField dart.core::_Closure::_function
+  [24] = InstanceField dart:core::_Closure::_function (field)
   [25] = Reserved
-  [26] = StaticICData target 'dart.core::print', arg-desc CP#3
+  [26] = StaticICData target 'dart:core::print', arg-desc CP#3
   [27] = ICData dynamic target-name 'call', arg-desc CP#3
-  [28] = StaticICData target 'dart.core::print', arg-desc CP#3
+  [28] = StaticICData target 'dart:core::print', arg-desc CP#3
   [29] = ICData dynamic target-name 'call', arg-desc CP#3
 }
-Closure CP#0 {
+Closure #lib::testTryFinally3::<anonymous closure> () -> dart:core::int
+ClosureBytecode {
   EntryFixed           1, 6
   CheckStack           0
   Push                 FP[-5]
@@ -1128,7 +1132,7 @@
   }
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                5
   CheckStack           0
 Try #0 start:
@@ -1179,13 +1183,13 @@
 ConstantPool {
   [0] = String 'try'
   [1] = ArgDesc num-args 1, num-type-args 0, names []
-  [2] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [2] = StaticICData target 'dart:core::print', arg-desc CP#1
   [3] = Type dynamic
   [4] = String 'catch'
-  [5] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [5] = StaticICData target 'dart:core::print', arg-desc CP#1
   [6] = String 'finally'
-  [7] = StaticICData target 'dart.core::print', arg-desc CP#1
-  [8] = StaticICData target 'dart.core::print', arg-desc CP#1
+  [7] = StaticICData target 'dart:core::print', arg-desc CP#1
+  [8] = StaticICData target 'dart:core::print', arg-desc CP#1
 }
 ]static method testTryCatchFinally() → dynamic {
   try
@@ -1200,7 +1204,7 @@
   }
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
diff --git a/pkg/vm/testcases/bytecode/type_ops.dart.expect b/pkg/vm/testcases/bytecode/type_ops.dart.expect
index 292a062..43203fc 100644
--- a/pkg/vm/testcases/bytecode/type_ops.dart.expect
+++ b/pkg/vm/testcases/bytecode/type_ops.dart.expect
@@ -4,7 +4,7 @@
 
 class A<T extends core::Object = dynamic> extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -16,7 +16,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target 'dart.core::Object::', arg-desc CP#0
+  [1] = StaticICData target 'dart:core::Object::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::A<self::A::T>
     : super core::Object::•()
@@ -24,7 +24,7 @@
 }
 class B extends self::A<core::String> {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -36,7 +36,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target '#lib::A::', arg-desc CP#0
+  [1] = StaticICData target '#lib::A::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::B
     : super self::A::•()
@@ -44,7 +44,7 @@
 }
 class C<T1 extends core::Object = dynamic, T2 extends core::Object = dynamic, T3 extends core::Object = dynamic> extends self::B {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -56,7 +56,7 @@
 }
 ConstantPool {
   [0] = ArgDesc num-args 1, num-type-args 0, names []
-  [1] = StaticICData target '#lib::B::', arg-desc CP#0
+  [1] = StaticICData target '#lib::B::'' (constructor)', arg-desc CP#0
 }
 ]  synthetic constructor •() → self::C<self::C::T1, self::C::T2, self::C::T3>
     : super self::B::•()
@@ -65,7 +65,7 @@
 class D<P extends core::Object = dynamic, Q extends core::Object = dynamic> extends self::C<core::int, self::D::Q, self::D::P> {
   generic-covariant-impl field core::Map<self::D::P, self::D::Q> foo;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-6]
@@ -85,20 +85,20 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = Type dart.core::Map<#lib::D::P, #lib::D::Q>
+  [0] = Type dart:core::Map < #lib::D::TypeParam/0, #lib::D::TypeParam/1 >
   [1] = TypeArgumentsField #lib::D
   [2] = String ''
   [3] = SubtypeTestCache
-  [4] = InstanceField #lib::D::foo
+  [4] = InstanceField #lib::D::foo (field)
   [5] = Reserved
   [6] = ArgDesc num-args 1, num-type-args 0, names []
-  [7] = StaticICData target '#lib::C::', arg-desc CP#6
+  [7] = StaticICData target '#lib::C::'' (constructor)', arg-desc CP#6
 }
 ]  constructor •(dynamic tt) → self::D<self::D::P, self::D::Q>
     : self::D::foo = tt as{TypeError} core::Map<self::D::P, self::D::Q>, super self::C::•()
     ;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -140,21 +140,21 @@
 }
 ConstantPool {
   [0] = TypeArgumentsField #lib::D
-  [1] = Type #lib::A<#lib::D::P>
+  [1] = Type #lib::A < #lib::D::TypeParam/0 >
   [2] = ArgDesc num-args 4, num-type-args 0, names []
-  [3] = ICData target-name 'dart.core::_instanceOf', arg-desc CP#2
+  [3] = ICData target-name '_instanceOf', arg-desc CP#2
   [4] = String '21'
   [5] = ArgDesc num-args 1, num-type-args 0, names []
-  [6] = StaticICData target 'dart.core::print', arg-desc CP#5
-  [7] = Type #lib::C<dynamic, #lib::D::Q, dart.core::List<#lib::D::P>>
-  [8] = ICData target-name 'dart.core::_instanceOf', arg-desc CP#2
+  [6] = StaticICData target 'dart:core::print', arg-desc CP#5
+  [7] = Type #lib::C < dynamic, #lib::D::TypeParam/1, dart:core::List < #lib::D::TypeParam/0 > >
+  [8] = ICData target-name '_instanceOf', arg-desc CP#2
   [9] = String '22'
-  [10] = StaticICData target 'dart.core::print', arg-desc CP#5
-  [11] = Type dart.core::Map<#lib::D::P, #lib::D::Q>
+  [10] = StaticICData target 'dart:core::print', arg-desc CP#5
+  [11] = Type dart:core::Map < #lib::D::TypeParam/0, #lib::D::TypeParam/1 >
   [12] = String ''
   [13] = SubtypeTestCache
   [14] = ArgDesc num-args 2, num-type-args 0, names []
-  [15] = ICData set target-name 'foo', arg-desc CP#14
+  [15] = ICData set target-name 'set:foo', arg-desc CP#14
 }
 ]  method foo2(dynamic y) → dynamic {
     if(y is self::A<self::D::P>) {
@@ -166,7 +166,7 @@
     [@vm.call-site-attributes.metadata=receiverType:#lib::D<#lib::D::P, #lib::D::Q>] this.{self::D::foo} = y as{TypeError} core::Map<self::D::P, self::D::Q>;
   }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   CheckFunctionTypeArgs 2, r0
@@ -204,21 +204,21 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = Type #lib::A<#lib::D::foo3::T1>
+  [0] = Type #lib::A < #lib::D::foo3::TypeParam/0 >
   [1] = ArgDesc num-args 4, num-type-args 0, names []
-  [2] = ICData target-name 'dart.core::_instanceOf', arg-desc CP#1
+  [2] = ICData target-name '_instanceOf', arg-desc CP#1
   [3] = String '31'
   [4] = ArgDesc num-args 1, num-type-args 0, names []
-  [5] = StaticICData target 'dart.core::print', arg-desc CP#4
+  [5] = StaticICData target 'dart:core::print', arg-desc CP#4
   [6] = TypeArgumentsField #lib::D
-  [7] = Type #lib::C<dart.core::Map<#lib::D::foo3::T1, #lib::D::P>, dart.core::List<#lib::D::foo3::T2>, #lib::D::Q>
-  [8] = ICData target-name 'dart.core::_instanceOf', arg-desc CP#1
+  [7] = Type #lib::C < dart:core::Map < #lib::D::foo3::TypeParam/0, #lib::D::TypeParam/0 >, dart:core::List < #lib::D::foo3::TypeParam/1 >, #lib::D::TypeParam/1 >
+  [8] = ICData target-name '_instanceOf', arg-desc CP#1
   [9] = String '32'
-  [10] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [11] = Type dart.core::Map<#lib::D::foo3::T2, #lib::D::Q>
+  [10] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [11] = Type dart:core::Map < #lib::D::foo3::TypeParam/1, #lib::D::TypeParam/1 >
   [12] = String ' in type cast'
   [13] = SubtypeTestCache
-  [14] = ICData get target-name 'values', arg-desc CP#4
+  [14] = ICData get target-name 'get:values', arg-desc CP#4
 }
 ]  method foo3<T1 extends core::Object = dynamic, T2 extends core::Object = dynamic>(dynamic z) → dynamic {
     if(z is self::A<self::D::foo3::T1>) {
@@ -230,7 +230,7 @@
     return (z as core::Map<self::D::foo3::T2, self::D::Q>).{core::Map::values};
   }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                2
   CheckStack           0
   Push                 FP[-6]
@@ -266,12 +266,12 @@
 }
 ConstantPool {
   [0] = TypeArgumentsField #lib::D
-  [1] = TypeArgs [dart.core::Map<#lib::D::P, #lib::D::Q>]
-  [2] = Type dart.core::Map<#lib::D::P, #lib::D::Q>
+  [1] = TypeArgs [dart:core::Map < #lib::D::TypeParam/0, #lib::D::TypeParam/1 >]
+  [2] = Type dart:core::Map < #lib::D::TypeParam/0, #lib::D::TypeParam/1 >
   [3] = String ''
   [4] = SubtypeTestCache
   [5] = ArgDesc num-args 2, num-type-args 0, names []
-  [6] = StaticICData target 'dart.core::List::_fromLiteral', arg-desc CP#5
+  [6] = StaticICData target 'dart:core::List::_fromLiteral (constructor)', arg-desc CP#5
   [7] = SubtypeTestCache
 }
 ]  method foo4(dynamic w) → core::Map<self::D::P, self::D::Q> {
@@ -281,7 +281,7 @@
 }
 class E<P extends core::String = core::String> extends core::Object {
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
@@ -292,7 +292,7 @@
 ]  static factory •<P extends core::String = dynamic>() → self::E<self::E::•::P>
     return null;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   CheckFunctionTypeArgs 2, r0
@@ -315,16 +315,16 @@
 }
 ConstantPool {
   [0] = TypeArgumentsField #lib::E
-  [1] = TypeArgs [#lib::E::P, dart.core::List<#lib::E::P>]
-  [2] = Type #lib::E::foo6::T
-  [3] = Type #lib::E::P
+  [1] = TypeArgs [#lib::E::TypeParam/0, dart:core::List < #lib::E::TypeParam/0 >]
+  [2] = Type #lib::E::foo6::TypeParam/0
+  [3] = Type #lib::E::TypeParam/0
   [4] = String 'T'
 }
 ]  method foo6<generic-covariant-impl T extends self::E::P = self::E::P, U extends core::List<self::E::foo6::T> = core::List<self::E::P>>(core::Map<self::E::foo6::T, self::E::foo6::U> map) → void {}
 }
 static field core::List<core::Iterable<dynamic>> globalVar;
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   Push                 FP[-5]
@@ -358,16 +358,16 @@
 ConstantPool {
   [0] = Type #lib::B
   [1] = ArgDesc num-args 2, num-type-args 0, names []
-  [2] = ICData target-name 'dart.core::_simpleInstanceOf', arg-desc CP#1
+  [2] = ICData target-name '_simpleInstanceOf', arg-desc CP#1
   [3] = String '11'
   [4] = ArgDesc num-args 1, num-type-args 0, names []
-  [5] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [6] = Type #lib::C<dart.core::int, dart.core::Object, dynamic>
+  [5] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [6] = Type #lib::C < dart:core::int, dart:core::Object, dynamic >
   [7] = ArgDesc num-args 4, num-type-args 0, names []
-  [8] = ICData target-name 'dart.core::_instanceOf', arg-desc CP#7
+  [8] = ICData target-name '_instanceOf', arg-desc CP#7
   [9] = String '12'
-  [10] = StaticICData target 'dart.core::print', arg-desc CP#4
-  [11] = Type #lib::A<dart.core::int>
+  [10] = StaticICData target 'dart:core::print', arg-desc CP#4
+  [11] = Type #lib::A < dart:core::int >
   [12] = String ' in type cast'
   [13] = SubtypeTestCache
 }
@@ -381,7 +381,7 @@
   return x as self::A<core::int>;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                1
   CheckStack           0
   Push                 FP[-5]
@@ -395,16 +395,16 @@
   ReturnTOS
 }
 ConstantPool {
-  [0] = Type dart.core::List<dart.core::Iterable<dynamic>>
+  [0] = Type dart:core::List < dart:core::Iterable < dynamic > >
   [1] = String ''
   [2] = SubtypeTestCache
-  [3] = StaticField #lib::globalVar
+  [3] = StaticField #lib::globalVar (field)
 }
 ]static method foo5(dynamic x) → void {
   self::globalVar = x as{TypeError} core::List<core::Iterable<dynamic>>;
 }
 [@vm.bytecode=
-Bytecode (version: stable) {
+Bytecode {
   Entry                0
   CheckStack           0
   PushNull
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index b5f2acc..4a3ebfc 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -12,11 +12,12 @@
 #include "vm/dart_entry.h"
 #include "vm/longjump.h"
 #include "vm/object_store.h"
+#include "vm/reusable_handles.h"
 #include "vm/timeline.h"
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
 
-#define Z (zone_)
+#define Z (helper_->zone_)
 #define H (translation_helper_)
 #define T (type_translator_)
 #define I Isolate::Current()
@@ -32,7 +33,10 @@
                                                ActiveClass* active_class)
     : MetadataHelper(helper, tag(), /* precompiler_only = */ false),
       type_translator_(*type_translator),
-      active_class_(active_class) {}
+      active_class_(active_class),
+      bytecode_component_(nullptr),
+      closures_(nullptr),
+      function_type_type_parameters_(nullptr) {}
 
 bool BytecodeMetadataHelper::HasBytecode(intptr_t node_offset) {
   const intptr_t md_offset = GetNextMetadataPayloadOffset(node_offset);
@@ -59,20 +63,18 @@
 
   ASSERT(Thread::Current()->IsMutatorThread());
 
+  Array& bytecode_component_array =
+      Array::Handle(Z, translation_helper_.GetBytecodeComponent());
+  if (bytecode_component_array.IsNull()) {
+    bytecode_component_array = ReadBytecodeComponent();
+    ASSERT(!bytecode_component_array.IsNull());
+  }
+  BytecodeComponentData bytecode_component(bytecode_component_array);
+  bytecode_component_ = &bytecode_component;
+
   AlternativeReadingScope alt(&helper_->reader_, &H.metadata_payloads(),
                               md_offset);
 
-  const intptr_t version = helper_->reader_.ReadUInt();
-  if ((version < KernelBytecode::kMinSupportedBytecodeFormatVersion) ||
-      (version > KernelBytecode::kMaxSupportedBytecodeFormatVersion)) {
-    FATAL3(
-        "Unsupported Dart bytecode format version %" Pd
-        ". This version of Dart VM supports bytecode format versions from %" Pd
-        " to %" Pd ".",
-        version, KernelBytecode::kMinSupportedBytecodeFormatVersion,
-        KernelBytecode::kMaxSupportedBytecodeFormatVersion);
-  }
-
   const int kHasExceptionsTableFlag = 1 << 0;
   const int kHasSourcePositionsFlag = 1 << 1;
   const int kHasNullableFieldsFlag = 1 << 2;
@@ -84,6 +86,15 @@
   const bool has_nullable_fields = (flags & kHasNullableFieldsFlag) != 0;
   const bool has_closures = (flags & kHasClosuresFlag) != 0;
 
+  intptr_t num_closures = 0;
+  if (has_closures) {
+    num_closures = helper_->ReadListLength();
+    closures_ = &Array::Handle(Z, Array::New(num_closures));
+    for (intptr_t i = 0; i < num_closures; i++) {
+      ReadClosureDeclaration(function, i);
+    }
+  }
+
   // Create object pool and read pool entries.
   const intptr_t obj_count = helper_->reader_.ReadListLength();
   const ObjectPool& pool =
@@ -96,7 +107,7 @@
     // TODO(alexmarkov): allocate deopt_ids for closures separately
     DeoptIdScope deopt_id_scope(H.thread(), 0);
 
-    ReadPoolEntries(function, function, pool, 0);
+    ReadConstantPool(function, pool);
   }
 
   // Read bytecode and attach to function.
@@ -122,13 +133,12 @@
     if (I->use_field_guards()) {
       Field& field = Field::Handle(helper_->zone_);
       for (intptr_t i = 0; i < num_fields; i++) {
-        NameIndex name_index = helper_->ReadCanonicalNameReference();
-        field = H.LookupFieldByKernelField(name_index);
+        field ^= ReadObject();
         field.RecordStore(Object::null_object());
       }
     } else {
       for (intptr_t i = 0; i < num_fields; i++) {
-        helper_->SkipCanonicalNameReference();
+        ReadObject();
       }
     }
   }
@@ -137,11 +147,8 @@
   if (has_closures) {
     Function& closure = Function::Handle(helper_->zone_);
     Bytecode& closure_bytecode = Bytecode::Handle(helper_->zone_);
-    const intptr_t num_closures = helper_->ReadListLength();
     for (intptr_t i = 0; i < num_closures; i++) {
-      intptr_t closure_index = helper_->ReadUInt();
-      ASSERT(closure_index < obj_count);
-      closure ^= pool.ObjectAt(closure_index);
+      closure ^= closures_->At(i);
 
       const intptr_t flags = helper_->reader_.ReadUInt();
       const bool has_exceptions_table = (flags & kHasExceptionsTableFlag) != 0;
@@ -162,15 +169,150 @@
       }
     }
   }
+
+  bytecode_component_ = nullptr;
 }
 
-intptr_t BytecodeMetadataHelper::ReadPoolEntries(const Function& function,
-                                                 const Function& inner_function,
-                                                 const ObjectPool& pool,
-                                                 intptr_t from_index) {
+void BytecodeMetadataHelper::ReadClosureDeclaration(const Function& function,
+                                                    intptr_t closureIndex) {
+  const int kHasOptionalPositionalParams = 1 << 0;
+  const int kHasOptionalNamedParams = 1 << 1;
+  const int kHasTypeParams = 1 << 2;
+
+  const intptr_t flags = helper_->reader_.ReadUInt();
+
+  Object& parent = Object::Handle(Z, ReadObject());
+  if (!parent.IsFunction()) {
+    ASSERT(parent.IsField());
+    ASSERT(function.kind() == RawFunction::kImplicitStaticFinalGetter);
+    // Closure in a static field initializer, so use current function as parent.
+    parent = function.raw();
+  }
+
+  String& name = String::CheckedHandle(Z, ReadObject());
+  ASSERT(name.IsSymbol());
+
+  const Function& closure = Function::Handle(
+      Z, Function::NewClosureFunction(name, Function::Cast(parent),
+                                      TokenPosition::kNoSource));
+
+  closures_->SetAt(closureIndex, closure);
+
+  Type& signature_type =
+      Type::Handle(Z, ReadFunctionSignature(
+                          closure, (flags & kHasOptionalPositionalParams) != 0,
+                          (flags & kHasOptionalNamedParams) != 0,
+                          (flags & kHasTypeParams) != 0,
+                          /* has_positional_param_names = */ true));
+
+  closure.SetSignatureType(signature_type);
+}
+
+RawType* BytecodeMetadataHelper::ReadFunctionSignature(
+    const Function& func,
+    bool has_optional_positional_params,
+    bool has_optional_named_params,
+    bool has_type_params,
+    bool has_positional_param_names) {
+  FunctionTypeScope function_type_scope(this);
+
+  if (has_type_params) {
+    const intptr_t num_type_params = helper_->reader_.ReadUInt();
+    ReadTypeParametersDeclaration(Class::Handle(Z), func, num_type_params);
+    function_type_type_parameters_ =
+        &TypeArguments::Handle(Z, func.type_parameters());
+  }
+
+  const intptr_t kImplicitClosureParam = 1;
+  const intptr_t num_params =
+      kImplicitClosureParam + helper_->reader_.ReadUInt();
+
+  intptr_t num_required_params = num_params;
+  if (has_optional_positional_params || has_optional_named_params) {
+    num_required_params = kImplicitClosureParam + helper_->reader_.ReadUInt();
+  }
+
+  func.set_num_fixed_parameters(num_required_params);
+  func.SetNumOptionalParameters(num_params - num_required_params,
+                                !has_optional_named_params);
+  const Array& parameter_types =
+      Array::Handle(Z, Array::New(num_params, Heap::kOld));
+  func.set_parameter_types(parameter_types);
+  const Array& parameter_names =
+      Array::Handle(Z, Array::New(num_params, Heap::kOld));
+  func.set_parameter_names(parameter_names);
+
+  intptr_t i = 0;
+  parameter_types.SetAt(i, AbstractType::dynamic_type());
+  parameter_names.SetAt(i, Symbols::ClosureParameter());
+  ++i;
+
+  AbstractType& type = AbstractType::Handle(Z);
+  String& name = String::Handle(Z);
+  for (; i < num_params; ++i) {
+    if (has_positional_param_names ||
+        (has_optional_named_params && (i >= num_required_params))) {
+      name ^= ReadObject();
+    } else {
+      name = Symbols::NotNamed().raw();
+    }
+    parameter_names.SetAt(i, name);
+    type ^= ReadObject();
+    parameter_types.SetAt(i, type);
+  }
+
+  type ^= ReadObject();
+  func.set_result_type(type);
+
+  // Finalize function type.
+  type = func.SignatureType();
+  type ^= ClassFinalizer::FinalizeType(*(active_class_->klass), type);
+  return Type::Cast(type).raw();
+}
+
+void BytecodeMetadataHelper::ReadTypeParametersDeclaration(
+    const Class& parameterized_class,
+    const Function& parameterized_function,
+    intptr_t num_type_params) {
+  ASSERT(parameterized_class.IsNull() != parameterized_function.IsNull());
+  ASSERT(num_type_params > 0);
+
+  // First setup the type parameters, so if any of the following code uses it
+  // (in a recursive way) we're fine.
+  //
+  // Step a) Create array of [TypeParameter] objects (without bound).
+  const TypeArguments& type_parameters =
+      TypeArguments::Handle(Z, TypeArguments::New(num_type_params));
+  String& name = String::Handle(Z);
+  TypeParameter& parameter = TypeParameter::Handle(Z);
+  AbstractType& bound = AbstractType::Handle(Z);
+  for (intptr_t i = 0; i < num_type_params; ++i) {
+    name ^= ReadObject();
+    ASSERT(name.IsSymbol());
+    parameter = TypeParameter::New(parameterized_class, parameterized_function,
+                                   i, name, bound, TokenPosition::kNoSource);
+    type_parameters.SetTypeAt(i, parameter);
+  }
+
+  if (!parameterized_class.IsNull()) {
+    parameterized_class.set_type_parameters(type_parameters);
+  } else {
+    parameterized_function.set_type_parameters(type_parameters);
+  }
+
+  // Step b) Fill in the bounds of all [TypeParameter]s.
+  for (intptr_t i = 0; i < num_type_params; ++i) {
+    parameter ^= type_parameters.TypeAt(i);
+    bound ^= ReadObject();
+    parameter.set_bound(bound);
+  }
+}
+
+void BytecodeMetadataHelper::ReadConstantPool(const Function& function,
+                                              const ObjectPool& pool) {
 #if !defined(PRODUCT)
   TimelineDurationScope tds(Thread::Current(), Timeline::GetCompilerStream(),
-                            "BytecodeMetadataHelper::ReadPoolEntries");
+                            "BytecodeMetadataHelper::ReadConstantPool");
 #endif  // !defined(PRODUCT)
 
   // These enums and the code below reading the constant pool from kernel must
@@ -218,14 +360,13 @@
   Array& array = Array::Handle(helper_->zone_);
   Field& field = Field::Handle(helper_->zone_);
   Class& cls = Class::Handle(helper_->zone_);
-  Library& lib = Library::Handle(helper_->zone_);
   String& name = String::Handle(helper_->zone_);
   TypeArguments& type_args = TypeArguments::Handle(helper_->zone_);
   Class* symbol_class = nullptr;
   Field* symbol_name_field = nullptr;
   const String* simpleInstanceOf = nullptr;
   const intptr_t obj_count = pool.Length();
-  for (intptr_t i = from_index; i < obj_count; ++i) {
+  for (intptr_t i = 0; i < obj_count; ++i) {
     const intptr_t tag = helper_->ReadTag();
     switch (tag) {
       case ConstantPoolTag::kInvalid:
@@ -234,9 +375,8 @@
         obj = Object::null();
         break;
       case ConstantPoolTag::kString:
-        obj = H.DartString(helper_->ReadStringReference()).raw();
-        ASSERT(obj.IsString());
-        obj = H.Canonicalize(String::Cast(obj));
+        obj = ReadString();
+        ASSERT(obj.IsString() && obj.IsCanonical());
         break;
       case ConstantPoolTag::kInt: {
         uint32_t low_bits = helper_->ReadUInt32();
@@ -254,7 +394,7 @@
         obj = H.Canonicalize(Double::Cast(obj));
       } break;
       case ConstantPoolTag::kBool:
-        if (helper_->ReadUInt() == 1) {
+        if (helper_->ReadByte() == 1) {
           obj = Bool::True().raw();
         } else {
           obj = Bool::False().raw();
@@ -269,7 +409,8 @@
         } else {
           array = Array::New(num_arg_names);
           for (intptr_t j = 0; j < num_arg_names; j++) {
-            array.SetAt(j, H.DartSymbolPlain(helper_->ReadStringReference()));
+            name = ReadString();
+            array.SetAt(j, name);
           }
           obj = ArgumentsDescriptor::New(num_type_args, num_arguments, array);
         }
@@ -279,14 +420,8 @@
         InvocationKind kind =
             static_cast<InvocationKind>(flags & kInvocationKindMask);
         bool isDynamic = (flags & kFlagDynamic) != 0;
-        if (kind == InvocationKind::getter) {
-          name = helper_->ReadNameAsGetterName().raw();
-        } else if (kind == InvocationKind::setter) {
-          name = helper_->ReadNameAsSetterName().raw();
-        } else {
-          ASSERT(kind == InvocationKind::method);
-          name = helper_->ReadNameAsMethodName().raw();
-        }
+        name ^= ReadObject();
+        ASSERT(name.IsSymbol());
         intptr_t arg_desc_index = helper_->ReadUInt();
         ASSERT(arg_desc_index < i);
         array ^= pool.ObjectAt(arg_desc_index);
@@ -324,38 +459,11 @@
 #endif
       } break;
       case ConstantPoolTag::kStaticICData: {
-        InvocationKind kind = static_cast<InvocationKind>(helper_->ReadByte());
-        NameIndex target = helper_->ReadCanonicalNameReference();
-        if (H.IsConstructor(target)) {
-          name = H.DartConstructorName(target).raw();
-          elem = H.LookupConstructorByKernelConstructor(target);
-        } else if (H.IsField(target)) {
-          if (kind == InvocationKind::getter) {
-            name = H.DartGetterName(target).raw();
-          } else if (kind == InvocationKind::setter) {
-            name = H.DartSetterName(target).raw();
-          } else {
-            ASSERT(kind == InvocationKind::method);
-            UNIMPLEMENTED();  // TODO(regis): Revisit.
-          }
-          field = H.LookupFieldByKernelField(target);
-          cls = field.Owner();
-          elem = cls.LookupFunctionAllowPrivate(name);
-        } else {
-          if ((kind == InvocationKind::method) && H.IsGetter(target)) {
-            UNIMPLEMENTED();  // TODO(regis): Revisit.
-          }
-          name = H.DartProcedureName(target).raw();
-          elem = H.LookupStaticMethodByKernelProcedure(target);
-          if ((kind == InvocationKind::getter) && !H.IsGetter(target)) {
-            // Tear-off
-            name = H.DartGetterName(target).raw();
-            elem = Function::Cast(elem).GetMethodExtractor(name);
-          }
-        }
+        elem = ReadObject();
+        ASSERT(elem.IsFunction());
+        name = Function::Cast(elem).name();
         const int num_args_checked =
             MethodRecognizer::NumArgsCheckedForStaticCall(Function::Cast(elem));
-        ASSERT(elem.IsFunction());
         intptr_t arg_desc_index = helper_->ReadUInt();
         ASSERT(arg_desc_index < i);
         array ^= pool.ObjectAt(arg_desc_index);
@@ -369,12 +477,11 @@
 #endif
       } break;
       case ConstantPoolTag::kStaticField:
-        obj = H.LookupFieldByKernelField(helper_->ReadCanonicalNameReference());
+        obj = ReadObject();
         ASSERT(obj.IsField());
         break;
       case ConstantPoolTag::kInstanceField:
-        field =
-            H.LookupFieldByKernelField(helper_->ReadCanonicalNameReference());
+        field ^= ReadObject();
         // InstanceField constant occupies 2 entries.
         // The first entry is used for field offset.
         obj = Smi::New(field.Offset() / kWordSize);
@@ -386,16 +493,15 @@
         obj = field.raw();
         break;
       case ConstantPoolTag::kClass:
-        obj = H.LookupClassByKernelClass(helper_->ReadCanonicalNameReference());
+        obj = ReadObject();
         ASSERT(obj.IsClass());
         break;
       case ConstantPoolTag::kTypeArgumentsField:
-        cls = H.LookupClassByKernelClass(helper_->ReadCanonicalNameReference());
+        cls ^= ReadObject();
         obj = Smi::New(cls.type_arguments_field_offset() / kWordSize);
         break;
       case ConstantPoolTag::kTearOff:
-        obj = H.LookupStaticMethodByKernelProcedure(
-            helper_->ReadCanonicalNameReference());
+        obj = ReadObject();
         ASSERT(obj.IsFunction());
         obj = Function::Cast(obj).ImplicitClosureFunction();
         ASSERT(obj.IsFunction());
@@ -404,16 +510,16 @@
         obj = H.Canonicalize(Instance::Cast(obj));
         break;
       case ConstantPoolTag::kType:
-        obj = type_translator_.BuildType().raw();
+        obj = ReadObject();
         ASSERT(obj.IsAbstractType());
         break;
       case ConstantPoolTag::kTypeArguments:
-        obj = type_translator_.BuildTypeArguments(helper_->ReadListLength())
-                  .raw();
+        cls = Class::null();
+        obj = ReadTypeArguments(cls);
         ASSERT(obj.IsNull() || obj.IsTypeArguments());
         break;
       case ConstantPoolTag::kList: {
-        obj = type_translator_.BuildType().raw();
+        obj = ReadObject();
         ASSERT(obj.IsAbstractType());
         const intptr_t length = helper_->ReadListLength();
         array = Array::New(length, AbstractType::Cast(obj));
@@ -428,7 +534,7 @@
         ASSERT(!obj.IsNull());
       } break;
       case ConstantPoolTag::kInstance: {
-        cls = H.LookupClassByKernelClass(helper_->ReadCanonicalNameReference());
+        cls ^= ReadObject();
         obj = Instance::New(cls, Heap::kOld);
         intptr_t type_args_index = helper_->ReadUInt();
         ASSERT(type_args_index < i);
@@ -438,9 +544,7 @@
         }
         intptr_t num_fields = helper_->ReadUInt();
         for (intptr_t j = 0; j < num_fields; j++) {
-          NameIndex field_name = helper_->ReadCanonicalNameReference();
-          ASSERT(H.IsField(field_name));
-          field = H.LookupFieldByKernelField(field_name);
+          field ^= ReadObject();
           intptr_t elem_index = helper_->ReadUInt();
           ASSERT(elem_index < i);
           elem = pool.ObjectAt(elem_index);
@@ -449,133 +553,21 @@
         obj = H.Canonicalize(Instance::Cast(obj));
       } break;
       case ConstantPoolTag::kTypeArgumentsForInstanceAllocation: {
-        cls = H.LookupClassByKernelClass(helper_->ReadCanonicalNameReference());
-        obj =
-            type_translator_
-                .BuildInstantiatedTypeArguments(cls, helper_->ReadListLength())
-                .raw();
+        cls ^= ReadObject();
+        obj = ReadTypeArguments(cls);
         ASSERT(obj.IsNull() || obj.IsTypeArguments());
       } break;
       case ConstantPoolTag::kClosureFunction: {
-        name = H.DartSymbolPlain(helper_->ReadStringReference()).raw();
-        const Function& closure = Function::Handle(
-            helper_->zone_,
-            Function::NewClosureFunction(name, inner_function,
-                                         TokenPosition::kNoSource));
-
-        FunctionNodeHelper function_node_helper(helper_);
-        function_node_helper.ReadUntilExcluding(
-            FunctionNodeHelper::kTypeParameters);
-        type_translator_.LoadAndSetupTypeParameters(
-            active_class_, closure, helper_->ReadListLength(), closure);
-        function_node_helper.SetJustRead(FunctionNodeHelper::kTypeParameters);
-
-        // Scope remains opened until ConstantPoolTag::kEndClosureFunctionScope.
-        ActiveTypeParametersScope scope(
-            active_class_, &closure,
-            TypeArguments::Handle(helper_->zone_, closure.type_parameters()),
-            helper_->zone_);
-
-        function_node_helper.ReadUntilExcluding(
-            FunctionNodeHelper::kPositionalParameters);
-
-        intptr_t required_parameter_count =
-            function_node_helper.required_parameter_count_;
-        intptr_t total_parameter_count =
-            function_node_helper.total_parameter_count_;
-
-        intptr_t positional_parameter_count = helper_->ReadListLength();
-
-        intptr_t named_parameter_count =
-            total_parameter_count - positional_parameter_count;
-
-        const intptr_t extra_parameters = 1;
-        closure.set_num_fixed_parameters(extra_parameters +
-                                         required_parameter_count);
-        if (named_parameter_count > 0) {
-          closure.SetNumOptionalParameters(named_parameter_count, false);
-        } else {
-          closure.SetNumOptionalParameters(
-              positional_parameter_count - required_parameter_count, true);
-        }
-        intptr_t parameter_count = extra_parameters + total_parameter_count;
-        closure.set_parameter_types(Array::Handle(
-            helper_->zone_, Array::New(parameter_count, Heap::kOld)));
-        closure.set_parameter_names(Array::Handle(
-            helper_->zone_, Array::New(parameter_count, Heap::kOld)));
-
-        intptr_t pos = 0;
-        closure.SetParameterTypeAt(pos, AbstractType::dynamic_type());
-        closure.SetParameterNameAt(pos, Symbols::ClosureParameter());
-        pos++;
-
-        lib = active_class_->klass->library();
-        for (intptr_t j = 0; j < positional_parameter_count; ++j, ++pos) {
-          VariableDeclarationHelper helper(helper_);
-          helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
-          const AbstractType& type = type_translator_.BuildVariableType();
-          Tag tag = helper_->ReadTag();  // read (first part of) initializer.
-          if (tag == kSomething) {
-            helper_->SkipExpression();  // read (actual) initializer.
-          }
-
-          closure.SetParameterTypeAt(pos, type);
-          closure.SetParameterNameAt(pos,
-                                     H.DartIdentifier(lib, helper.name_index_));
-        }
-
-        intptr_t named_parameter_count_check = helper_->ReadListLength();
-        ASSERT(named_parameter_count_check == named_parameter_count);
-        for (intptr_t j = 0; j < named_parameter_count; ++j, ++pos) {
-          VariableDeclarationHelper helper(helper_);
-          helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
-          const AbstractType& type = type_translator_.BuildVariableType();
-          Tag tag = helper_->ReadTag();  // read (first part of) initializer.
-          if (tag == kSomething) {
-            helper_->SkipExpression();  // read (actual) initializer.
-          }
-
-          closure.SetParameterTypeAt(pos, type);
-          closure.SetParameterNameAt(pos,
-                                     H.DartIdentifier(lib, helper.name_index_));
-        }
-
-        function_node_helper.SetJustRead(FunctionNodeHelper::kNamedParameters);
-
-        const AbstractType& return_type = type_translator_.BuildVariableType();
-        closure.set_result_type(return_type);
-        function_node_helper.SetJustRead(FunctionNodeHelper::kReturnType);
-        // The closure has no body.
-        function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
-
-        // Finalize function type.
-        Type& signature_type =
-            Type::Handle(helper_->zone_, closure.SignatureType());
-        signature_type ^= ClassFinalizer::FinalizeType(*(active_class_->klass),
-                                                       signature_type);
-        closure.SetSignatureType(signature_type);
-
-        pool.SetTypeAt(i, ObjectPool::kTaggedObject, ObjectPool::kNotPatchable);
-        pool.SetObjectAt(i, closure);
-
-        // Continue reading the constant pool entries inside the opened
-        // ActiveTypeParametersScope until the scope gets closed by a
-        // kEndClosureFunctionScope tag, in which case control returns here.
-        i = ReadPoolEntries(function, closure, pool, i + 1);
-        // Pool entry at index i has been set to null, because it was a
-        // kEndClosureFunctionScope.
-        ASSERT(pool.ObjectAt(i) == Object::null());
-        continue;
-      }
+        intptr_t closure_index = helper_->ReadUInt();
+        obj = closures_->At(closure_index);
+        ASSERT(obj.IsFunction());
+      } break;
       case ConstantPoolTag::kEndClosureFunctionScope: {
         // Entry is not used and set to null.
         obj = Object::null();
-        pool.SetTypeAt(i, ObjectPool::kTaggedObject, ObjectPool::kNotPatchable);
-        pool.SetObjectAt(i, obj);
-        return i;  // The caller will close the scope.
       } break;
       case ConstantPoolTag::kNativeEntry: {
-        name = H.DartString(helper_->ReadStringReference()).raw();
+        name = ReadString();
         obj = NativeEntry(function, name);
         pool.SetTypeAt(i, ObjectPool::kNativeEntryData,
                        ObjectPool::kNotPatchable);
@@ -608,13 +600,8 @@
         obj = Object::empty_type_arguments().raw();
         break;
       case ConstantPoolTag::kSymbol: {
-        const NameIndex lib_index = helper_->ReadCanonicalNameReference();
-        lib = Library::null();
-        if (!H.IsRoot(lib_index)) {
-          lib = H.LookupLibraryByKernelLibrary(lib_index);
-        }
-        const String& symbol =
-            H.DartIdentifier(lib, helper_->ReadStringReference());
+        name ^= ReadObject();
+        ASSERT(name.IsSymbol());
         if (symbol_class == nullptr) {
           elem = Library::InternalLibrary();
           ASSERT(!elem.IsNull());
@@ -628,7 +615,7 @@
           ASSERT(!symbol_name_field->IsNull());
         }
         obj = Instance::New(*symbol_class, Heap::kOld);
-        Instance::Cast(obj).SetField(*symbol_name_field, symbol);
+        Instance::Cast(obj).SetField(*symbol_name_field, name);
         obj = H.Canonicalize(Instance::Cast(obj));
       } break;
       default:
@@ -637,8 +624,6 @@
     pool.SetTypeAt(i, ObjectPool::kTaggedObject, ObjectPool::kNotPatchable);
     pool.SetObjectAt(i, obj);
   }
-  // Return the index of the last read pool entry.
-  return obj_count - 1;
 }
 
 RawBytecode* BytecodeMetadataHelper::ReadBytecode(const ObjectPool& pool) {
@@ -647,9 +632,7 @@
                             "BytecodeMetadataHelper::ReadBytecode");
 #endif  // !defined(PRODUCT)
   intptr_t size = helper_->ReadUInt();
-  helper_->SkipBytes(helper_->ReadByte());
-  intptr_t offset = helper_->reader_.offset();
-  ASSERT(Utils::IsAligned(offset, sizeof(KBCInstr)));
+  intptr_t offset = Utils::RoundUp(helper_->reader_.offset(), sizeof(KBCInstr));
   const uint8_t* data = helper_->reader_.BufferAt(offset);
   ASSERT(Utils::IsAligned(data, sizeof(KBCInstr)));
   helper_->reader_.set_offset(offset + size);
@@ -804,6 +787,412 @@
   return NativeEntryData::New(kind, trampoline, native_function, argc_tag);
 }
 
+RawArray* BytecodeMetadataHelper::ReadBytecodeComponent() {
+  const intptr_t md_offset = GetComponentMetadataPayloadOffset();
+  if (md_offset < 0) {
+    return Array::null();
+  }
+
+  ASSERT(Thread::Current()->IsMutatorThread());
+
+  AlternativeReadingScope alt(&helper_->reader_, &H.metadata_payloads(),
+                              md_offset);
+
+  const intptr_t version = helper_->reader_.ReadUInt();
+  if ((version < KernelBytecode::kMinSupportedBytecodeFormatVersion) ||
+      (version > KernelBytecode::kMaxSupportedBytecodeFormatVersion)) {
+    FATAL3("Unsupported Dart bytecode format version %" Pd
+           ". "
+           "This version of Dart VM supports bytecode format versions from %" Pd
+           " to %" Pd ".",
+           version, KernelBytecode::kMinSupportedBytecodeFormatVersion,
+           KernelBytecode::kMaxSupportedBytecodeFormatVersion);
+  }
+
+  const intptr_t strings_size = helper_->reader_.ReadUInt();
+  helper_->reader_.ReadUInt();  // Objects table size.
+
+  // Read header of strings table.
+  const intptr_t strings_header_offset = helper_->reader_.offset();
+  const intptr_t num_one_byte_strings = helper_->reader_.ReadUInt32();
+  const intptr_t num_two_byte_strings = helper_->reader_.ReadUInt32();
+  const intptr_t strings_contents_offset =
+      helper_->reader_.offset() +
+      (num_one_byte_strings + num_two_byte_strings) * 4;
+
+  // Read header of objects table.
+  helper_->reader_.set_offset(strings_header_offset + strings_size);
+  const intptr_t num_objects = helper_->reader_.ReadUInt();
+  const intptr_t objects_size = helper_->reader_.ReadUInt();
+
+  // Skip over contents of objects.
+  const intptr_t objects_contents_offset = helper_->reader_.offset();
+  helper_->reader_.set_offset(objects_contents_offset + objects_size);
+
+  const Array& bytecode_component_array = Array::Handle(
+      Z, BytecodeComponentData::New(
+             Z, version, num_objects, strings_header_offset,
+             strings_contents_offset, objects_contents_offset, Heap::kOld));
+  BytecodeComponentData bytecode_component(bytecode_component_array);
+
+  // Read object offsets.
+  Smi& offs = Smi::Handle(helper_->zone_);
+  for (intptr_t i = 0; i < num_objects; ++i) {
+    offs = Smi::New(helper_->reader_.ReadUInt());
+    bytecode_component.SetObject(i, offs);
+  }
+
+  H.SetBytecodeComponent(bytecode_component_array);
+
+  return bytecode_component_array.raw();
+}
+
+// TODO(alexmarkov): create a helper class with cached handles to avoid handle
+// allocations.
+RawObject* BytecodeMetadataHelper::ReadObject() {
+  uint32_t header = helper_->reader_.ReadUInt();
+  if ((header & kReferenceBit) != 0) {
+    intptr_t index = header >> kIndexShift;
+    if (index == 0) {
+      return Object::null();
+    }
+    RawObject* obj = bytecode_component_->GetObject(index);
+    if (obj->IsHeapObject()) {
+      return obj;
+    }
+    // Object is not loaded yet.
+    intptr_t offset = bytecode_component_->GetObjectsContentsOffset() +
+                      Smi::Value(Smi::RawCast(obj));
+    AlternativeReadingScope alt(&helper_->reader_, &H.metadata_payloads(),
+                                offset);
+    header = helper_->reader_.ReadUInt();
+
+    obj = ReadObjectContents(header);
+    ASSERT(obj->IsHeapObject());
+    {
+      Thread* thread = H.thread();
+      REUSABLE_OBJECT_HANDLESCOPE(thread);
+      Object& obj_handle = thread->ObjectHandle();
+      obj_handle = obj;
+      bytecode_component_->SetObject(index, obj_handle);
+    }
+    return obj;
+  }
+
+  return ReadObjectContents(header);
+}
+
+RawObject* BytecodeMetadataHelper::ReadObjectContents(uint32_t header) {
+  ASSERT(((header & kReferenceBit) == 0));
+
+  // Must be in sync with enum ObjectKind in
+  // pkg/vm/lib/bytecode/object_table.dart.
+  enum ObjectKind {
+    kInvalid,
+    kLibrary,
+    kClass,
+    kMember,
+    kClosure,
+    kSimpleType,
+    kTypeParameter,
+    kGenericType,
+    kFunctionType,
+    kName,
+  };
+
+  // Member flags, must be in sync with _MemberHandle constants in
+  // pkg/vm/lib/bytecode/object_table.dart.
+  const intptr_t kFlagIsField = kFlagBit0;
+  const intptr_t kFlagIsConstructor = kFlagBit1;
+
+  // SimpleType flags, must be in sync with _SimpleTypeHandle constants in
+  // pkg/vm/lib/bytecode/object_table.dart.
+  const intptr_t kFlagIsDynamic = kFlagBit0;
+  const intptr_t kFlagIsVoid = kFlagBit1;
+
+  // FunctionType flags, must be in sync with _FunctionTypeHandle constants in
+  // pkg/vm/lib/bytecode/object_table.dart.
+  const int kFlagHasOptionalPositionalParams = kFlagBit0;
+  const int kFlagHasOptionalNamedParams = kFlagBit1;
+  const int kFlagHasTypeParams = kFlagBit2;
+
+  const intptr_t kind = (header >> kKindShift) & kKindMask;
+  const intptr_t flags = header & kFlagsMask;
+
+  switch (kind) {
+    case kInvalid:
+      UNREACHABLE();
+      break;
+    case kLibrary: {
+      const String& uri = String::Handle(Z, ReadString());
+      RawLibrary* library = Library::LookupLibrary(H.thread(), uri);
+      if (library == Library::null()) {
+        FATAL1("Unable to find library %s", uri.ToCString());
+      }
+      return library;
+    }
+    case kClass: {
+      const Library& library = Library::CheckedHandle(Z, ReadObject());
+      const String& class_name = String::CheckedHandle(Z, ReadObject());
+      if (class_name.raw() == Symbols::Empty().raw()) {
+        return library.toplevel_class();
+      }
+      RawClass* cls = library.LookupClassAllowPrivate(class_name);
+      if (cls == Class::null()) {
+        FATAL2("Unable to find class %s in %s", class_name.ToCString(),
+               library.ToCString());
+      }
+      return cls;
+    }
+    case kMember: {
+      const Class& cls = Class::CheckedHandle(Z, ReadObject());
+      String& name = String::CheckedHandle(Z, ReadObject());
+      if ((flags & kFlagIsField) != 0) {
+        RawField* field = cls.LookupFieldAllowPrivate(name);
+        if (field == Field::null()) {
+          FATAL2("Unable to find field %s in %s", name.ToCString(),
+                 cls.ToCString());
+        }
+        return field;
+      } else {
+        if ((flags & kFlagIsConstructor) != 0) {
+          GrowableHandlePtrArray<const String> pieces(Z, 3);
+          pieces.Add(String::Handle(Z, cls.Name()));
+          pieces.Add(Symbols::Dot());
+          pieces.Add(name);
+          name = Symbols::FromConcatAll(H.thread(), pieces);
+        }
+        RawFunction* function = cls.LookupFunctionAllowPrivate(name);
+        if (function == Function::null()) {
+          // When requesting a getter, also return method extractors.
+          if (Field::IsGetterName(name)) {
+            String& method_name =
+                String::Handle(Z, Field::NameFromGetter(name));
+            function = cls.LookupFunctionAllowPrivate(method_name);
+            if (function != Function::null()) {
+              function = Function::Handle(Z, function).GetMethodExtractor(name);
+              if (function != Function::null()) {
+                return function;
+              }
+            }
+          }
+          FATAL2("Unable to find function %s in %s", name.ToCString(),
+                 cls.ToCString());
+        }
+        return function;
+      }
+    }
+    case kClosure: {
+      ReadObject();  // Skip enclosing member.
+      const intptr_t closure_index = helper_->reader_.ReadUInt();
+      return closures_->At(closure_index);
+    }
+    case kSimpleType: {
+      const Class& cls = Class::CheckedHandle(Z, ReadObject());
+      if ((flags & kFlagIsDynamic) != 0) {
+        ASSERT(cls.IsNull());
+        return AbstractType::dynamic_type().raw();
+      }
+      if ((flags & kFlagIsVoid) != 0) {
+        ASSERT(cls.IsNull());
+        return AbstractType::void_type().raw();
+      }
+      // TODO(alexmarkov): inline/move here to avoid handle allocations.
+      return H.GetCanonicalType(cls).raw();
+    }
+    case kTypeParameter: {
+      Object& parent = Object::Handle(Z, ReadObject());
+      const intptr_t index_in_parent = helper_->reader_.ReadUInt();
+      TypeArguments& type_parameters = TypeArguments::Handle(Z);
+      if (parent.IsClass()) {
+        type_parameters = Class::Cast(parent).type_parameters();
+      } else if (parent.IsFunction()) {
+        if (Function::Cast(parent).IsFactory()) {
+          // For factory constructors VM uses type parameters of a class
+          // instead of constructor's type parameters.
+          parent = Function::Cast(parent).Owner();
+          type_parameters = Class::Cast(parent).type_parameters();
+        } else {
+          type_parameters = Function::Cast(parent).type_parameters();
+        }
+      } else if (parent.IsNull()) {
+        ASSERT(function_type_type_parameters_ != nullptr);
+        type_parameters = function_type_type_parameters_->raw();
+      } else {
+        UNREACHABLE();
+      }
+      AbstractType& type =
+          AbstractType::Handle(Z, type_parameters.TypeAt(index_in_parent));
+      // TODO(alexmarkov): figure out how to skip this type finalization
+      // (consider finalizing type parameters of classes/functions eagerly).
+      return ClassFinalizer::FinalizeType(*active_class_->klass, type);
+    }
+    case kGenericType: {
+      const Class& cls = Class::CheckedHandle(Z, ReadObject());
+      const TypeArguments& type_arguments =
+          TypeArguments::Handle(Z, ReadTypeArguments(Class::Handle(Z)));
+      const Type& type = Type::Handle(
+          Z, Type::New(cls, type_arguments, TokenPosition::kNoSource));
+      return ClassFinalizer::FinalizeType(*active_class_->klass, type);
+    }
+    case kFunctionType: {
+      Function& signature_function = Function::ZoneHandle(
+          Z, Function::NewSignatureFunction(*active_class_->klass,
+                                            active_class_->enclosing != NULL
+                                                ? *active_class_->enclosing
+                                                : Function::Handle(Z),
+                                            TokenPosition::kNoSource));
+
+      return ReadFunctionSignature(
+          signature_function, (flags & kFlagHasOptionalPositionalParams) != 0,
+          (flags & kFlagHasOptionalNamedParams) != 0,
+          (flags & kFlagHasTypeParams) != 0,
+          /* has_positional_param_names = */ false);
+    }
+    case kName: {
+      const Library& library = Library::CheckedHandle(Z, ReadObject());
+      if (library.IsNull()) {
+        return ReadString();
+      } else {
+        const String& name =
+            String::Handle(Z, ReadString(/* is_canonical = */ false));
+        return library.PrivateName(name);
+      }
+    }
+  }
+
+  return Object::null();
+}
+
+RawString* BytecodeMetadataHelper::ReadString(bool is_canonical) {
+  const int kFlagTwoByteString = 1;
+  const int kHeaderFields = 2;
+  const int kUInt32Size = 4;
+
+  uint32_t ref = helper_->reader_.ReadUInt();
+  const bool isOneByteString = (ref & kFlagTwoByteString) == 0;
+  intptr_t index = ref >> 1;
+
+  if (!isOneByteString) {
+    const uint32_t num_one_byte_strings = helper_->reader_.ReadUInt32At(
+        bytecode_component_->GetStringsHeaderOffset());
+    index += num_one_byte_strings;
+  }
+
+  AlternativeReadingScope alt(&helper_->reader_, &H.metadata_payloads(),
+                              bytecode_component_->GetStringsHeaderOffset() +
+                                  (kHeaderFields + index - 1) * kUInt32Size);
+  intptr_t start_offs = helper_->ReadUInt32();
+  intptr_t end_offs = helper_->ReadUInt32();
+  if (index == 0) {
+    // For the 0-th string we read a header field instead of end offset of
+    // the previous string.
+    start_offs = 0;
+  }
+
+  // Bytecode strings reside in ExternalTypedData which is not movable by GC,
+  // so it is OK to take a direct pointer to string characters even if
+  // symbol allocation triggers GC.
+  const uint8_t* data = helper_->reader_.BufferAt(
+      bytecode_component_->GetStringsContentsOffset() + start_offs);
+
+  if (is_canonical) {
+    if (isOneByteString) {
+      return Symbols::FromLatin1(H.thread(), data, end_offs - start_offs);
+    } else {
+      return Symbols::FromUTF16(H.thread(),
+                                reinterpret_cast<const uint16_t*>(data),
+                                (end_offs - start_offs) >> 1);
+    }
+  } else {
+    if (isOneByteString) {
+      return String::FromLatin1(data, end_offs - start_offs, Heap::kOld);
+    } else {
+      return String::FromUTF16(reinterpret_cast<const uint16_t*>(data),
+                               (end_offs - start_offs) >> 1, Heap::kOld);
+    }
+  }
+}
+
+RawTypeArguments* BytecodeMetadataHelper::ReadTypeArguments(
+    const Class& instantiator) {
+  const intptr_t length = helper_->reader_.ReadUInt();
+  TypeArguments& type_arguments =
+      TypeArguments::ZoneHandle(Z, TypeArguments::New(length));
+  AbstractType& type = AbstractType::Handle(Z);
+  for (intptr_t i = 0; i < length; ++i) {
+    type ^= ReadObject();
+    type_arguments.SetTypeAt(i, type);
+  }
+
+  type_arguments = type_arguments.Canonicalize();
+
+  if (instantiator.IsNull()) {
+    return type_arguments.raw();
+  }
+
+  if (type_arguments.IsNull() && instantiator.NumTypeArguments() == length) {
+    return type_arguments.raw();
+  }
+
+  // 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::New(instantiator, type_arguments, TokenPosition::kNoSource);
+  type ^= ClassFinalizer::FinalizeType(*active_class_->klass, type);
+  return type.arguments();
+}
+
+intptr_t BytecodeComponentData::GetVersion() const {
+  return Smi::Value(Smi::RawCast(data_.At(kVersion)));
+}
+
+intptr_t BytecodeComponentData::GetStringsHeaderOffset() const {
+  return Smi::Value(Smi::RawCast(data_.At(kStringsHeaderOffset)));
+}
+
+intptr_t BytecodeComponentData::GetStringsContentsOffset() const {
+  return Smi::Value(Smi::RawCast(data_.At(kStringsContentsOffset)));
+}
+
+intptr_t BytecodeComponentData::GetObjectsContentsOffset() const {
+  return Smi::Value(Smi::RawCast(data_.At(kObjectsContentsOffset)));
+}
+
+void BytecodeComponentData::SetObject(intptr_t index, const Object& obj) const {
+  data_.SetAt(kNumFields + index, obj);
+}
+
+RawObject* BytecodeComponentData::GetObject(intptr_t index) const {
+  return data_.At(kNumFields + index);
+}
+
+RawArray* BytecodeComponentData::New(Zone* zone,
+                                     intptr_t version,
+                                     intptr_t num_objects,
+                                     intptr_t strings_header_offset,
+                                     intptr_t strings_contents_offset,
+                                     intptr_t objects_contents_offset,
+                                     Heap::Space space) {
+  const Array& data =
+      Array::Handle(zone, Array::New(kNumFields + num_objects, space));
+  Smi& smi_handle = Smi::Handle(zone);
+
+  smi_handle = Smi::New(version);
+  data.SetAt(kVersion, smi_handle);
+
+  smi_handle = Smi::New(strings_header_offset);
+  data.SetAt(kStringsHeaderOffset, smi_handle);
+
+  smi_handle = Smi::New(strings_contents_offset);
+  data.SetAt(kStringsContentsOffset, smi_handle);
+
+  smi_handle = Smi::New(objects_contents_offset);
+  data.SetAt(kObjectsContentsOffset, smi_handle);
+
+  return data.raw();
+}
+
 RawError* BytecodeReader::ReadFunctionBytecode(Thread* thread,
                                                const Function& function) {
   ASSERT(!FLAG_precompiled_mode);
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.h b/runtime/vm/compiler/frontend/bytecode_reader.h
index 079316c..ad1fef8 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.h
+++ b/runtime/vm/compiler/frontend/bytecode_reader.h
@@ -14,6 +14,8 @@
 namespace dart {
 namespace kernel {
 
+class BytecodeComponentData;
+
 // Helper class which provides access to bytecode metadata.
 class BytecodeMetadataHelper : public MetadataHelper {
  public:
@@ -27,24 +29,100 @@
 
   void ReadMetadata(const Function& function);
 
+  RawArray* ReadBytecodeComponent();
+
  private:
-  // Returns the index of the last read pool entry.
-  intptr_t ReadPoolEntries(const Function& function,
-                           const Function& inner_function,
-                           const ObjectPool& pool,
-                           intptr_t from_index);
+  // These constants should match corresponding constants in class ObjectHandle
+  // (pkg/vm/lib/bytecode/object_table.dart).
+  static const int kReferenceBit = 1 << 0;
+  static const int kIndexShift = 1;
+  static const int kKindShift = 1;
+  static const int kKindMask = 0x0f;
+  static const int kFlagBit0 = 1 << 5;
+  static const int kFlagBit1 = 1 << 6;
+  static const int kFlagBit2 = 1 << 7;
+  static const int kFlagsMask = (kFlagBit0 | kFlagBit1 | kFlagBit2);
+
+  class FunctionTypeScope : public ValueObject {
+   public:
+    explicit FunctionTypeScope(BytecodeMetadataHelper* bytecode_reader)
+        : bytecode_reader_(bytecode_reader),
+          saved_type_parameters_(
+              bytecode_reader->function_type_type_parameters_) {}
+
+    ~FunctionTypeScope() {
+      bytecode_reader_->function_type_type_parameters_ = saved_type_parameters_;
+    }
+
+   private:
+    BytecodeMetadataHelper* bytecode_reader_;
+    TypeArguments* const saved_type_parameters_;
+  };
+
+  void ReadClosureDeclaration(const Function& function, intptr_t closureIndex);
+  RawType* ReadFunctionSignature(const Function& func,
+                                 bool has_optional_positional_params,
+                                 bool has_optional_named_params,
+                                 bool has_type_params,
+                                 bool has_positional_param_names);
+  void ReadTypeParametersDeclaration(const Class& parameterized_class,
+                                     const Function& parameterized_function,
+                                     intptr_t num_type_params);
+
+  void ReadConstantPool(const Function& function, const ObjectPool& pool);
   RawBytecode* ReadBytecode(const ObjectPool& pool);
   void ReadExceptionsTable(const Bytecode& bytecode, bool has_exceptions_table);
   void ReadSourcePositions(const Bytecode& bytecode, bool has_source_positions);
   RawTypedData* NativeEntry(const Function& function,
                             const String& external_name);
 
+  RawObject* ReadObject();
+  RawObject* ReadObjectContents(uint32_t header);
+  RawString* ReadString(bool is_canonical = true);
+  RawTypeArguments* ReadTypeArguments(const Class& instantiator);
+
   TypeTranslator& type_translator_;
   ActiveClass* const active_class_;
+  BytecodeComponentData* bytecode_component_;
+  Array* closures_;
+  TypeArguments* function_type_type_parameters_;
 
   DISALLOW_COPY_AND_ASSIGN(BytecodeMetadataHelper);
 };
 
+class BytecodeComponentData : ValueObject {
+ public:
+  enum {
+    kVersion,
+    kStringsHeaderOffset,
+    kStringsContentsOffset,
+    kObjectsContentsOffset,
+    kNumFields
+  };
+
+  explicit BytecodeComponentData(const Array& data) : data_(data) {}
+
+  intptr_t GetVersion() const;
+  intptr_t GetStringsHeaderOffset() const;
+  intptr_t GetStringsContentsOffset() const;
+  intptr_t GetObjectsContentsOffset() const;
+  void SetObject(intptr_t index, const Object& obj) const;
+  RawObject* GetObject(intptr_t index) const;
+
+  bool IsNull() const { return data_.IsNull(); }
+
+  static RawArray* New(Zone* zone,
+                       intptr_t version,
+                       intptr_t num_objects,
+                       intptr_t strings_header_offset,
+                       intptr_t strings_contents_offset,
+                       intptr_t objects_contents_offset,
+                       Heap::Space space);
+
+ private:
+  const Array& data_;
+};
+
 class BytecodeReader : public AllStatic {
  public:
   // Reads bytecode for the given function and sets its bytecode field.
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index 95767c3..17dcadb 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -1567,6 +1567,12 @@
   }
 }
 
+intptr_t MetadataHelper::GetComponentMetadataPayloadOffset() {
+  const intptr_t kComponentNodeOffset = 0;
+  return GetNextMetadataPayloadOffset(kComponentNodeOffset -
+                                      helper_->data_program_offset_);
+}
+
 DirectCallMetadataHelper::DirectCallMetadataHelper(KernelReaderHelper* helper)
     : MetadataHelper(helper, tag(), /* precompiler_only = */ true) {}
 
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 949c0b5..43518c7 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -169,6 +169,11 @@
                    const char* format,
                    ...) PRINTF_ATTRIBUTE(5, 6);
 
+  RawArray* GetBytecodeComponent() const { return info_.bytecode_component(); }
+  void SetBytecodeComponent(const Array& bytecode_component) {
+    info_.set_bytecode_component(bytecode_component);
+  }
+
  private:
   // This will mangle [name_to_modify] if necessary and make the result a symbol
   // if asked.  The result will be available in [name_to_modify] and it is also
@@ -794,6 +799,9 @@
   // Assumes metadata is accesses for nodes in linear order most of the time.
   intptr_t GetNextMetadataPayloadOffset(intptr_t node_offset);
 
+  // Returns metadata associated with component.
+  intptr_t GetComponentMetadataPayloadOffset();
+
   KernelReaderHelper* helper_;
   TranslationHelper& translation_helper_;
 
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index b68203a..dc370e1 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -348,6 +348,10 @@
     script = LoadScriptAt(index);
     scripts.SetAt(index, script);
   }
+
+  if (FLAG_enable_interpreter || FLAG_use_bytecode_compiler) {
+    bytecode_metadata_helper_.ReadBytecodeComponent();
+  }
 }
 
 KernelLoader::KernelLoader(const Script& script,
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 8056ab2..c3e8d86 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -12336,6 +12336,11 @@
   return result.raw();
 }
 
+void KernelProgramInfo::set_bytecode_component(
+    const Array& bytecode_component) const {
+  StorePointer(&raw_ptr()->bytecode_component_, bytecode_component.raw());
+}
+
 RawError* Library::CompileAll(bool ignore_error /* = false */) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
@@ -18760,7 +18765,9 @@
 const char* TypeParameter::ToCString() const {
   const char* name_cstr = String::Handle(Name()).ToCString();
   const AbstractType& upper_bound = AbstractType::Handle(bound());
-  const char* bound_cstr = String::Handle(upper_bound.Name()).ToCString();
+  const char* bound_cstr = upper_bound.IsNull()
+                               ? "<null>"
+                               : String::Handle(upper_bound.Name()).ToCString();
   if (IsFunctionTypeParameter()) {
     const char* format =
         "TypeParameter: name %s; index: %d; function: %s; bound: %s";
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 2e65d5d..b0c2f2d 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -4153,6 +4153,11 @@
                         const Smi& name_index,
                         const Class& klass) const;
 
+  RawArray* bytecode_component() const {
+    return raw_ptr()->bytecode_component_;
+  }
+  void set_bytecode_component(const Array& bytecode_component) const;
+
  private:
   static RawKernelProgramInfo* New();
 
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 3f9ef48..25da8e7 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -1358,6 +1358,7 @@
   RawExternalTypedData* metadata_mappings_;
   RawArray* scripts_;
   RawArray* constants_;
+  RawArray* bytecode_component_;
   RawGrowableObjectArray* potential_natives_;
   RawGrowableObjectArray* potential_pragma_functions_;
   RawExternalTypedData* constants_table_;