| Index: runtime/vm/snapshot.cc | 
| diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc | 
| index de11ff71d8e61109e1206df95016f2bc8440411e..cb9dfde5778a5b8fd62413cb0c0d9ad33d04f408 100644 | 
| --- a/runtime/vm/snapshot.cc | 
| +++ b/runtime/vm/snapshot.cc | 
| @@ -709,21 +709,7 @@ int32_t InstructionsWriter::GetObjectOffsetFor(RawObject* raw_object) { | 
| } | 
|  | 
|  | 
| -static void EnsureIdentifier(char* label) { | 
| -  for (char c = *label; c != '\0'; c = *++label) { | 
| -    if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || | 
| -        ((c >= '0') && (c <= '9'))) { | 
| -      continue; | 
| -    } | 
| -    *label = '_'; | 
| -  } | 
| -} | 
| - | 
| - | 
| -void AssemblyInstructionsWriter::Write(uint8_t* vmisolate_buffer, | 
| -                                       intptr_t vmisolate_length, | 
| -                                       uint8_t* isolate_buffer, | 
| -                                       intptr_t isolate_length) { | 
| +void InstructionsWriter::Write(WriteStream* clustered_stream, bool vm) { | 
| Thread* thread = Thread::Current(); | 
| Zone* zone = thread->zone(); | 
| NOT_IN_PRODUCT(TimelineDurationScope tds(thread, Timeline::GetIsolateStream(), | 
| @@ -742,12 +728,68 @@ void AssemblyInstructionsWriter::Write(uint8_t* vmisolate_buffer, | 
| data.obj_ = &Object::Handle(zone, data.raw_obj_); | 
| } | 
|  | 
| +  // Append the direct-mapped RO data objects after the clustered snapshot. | 
| +  WriteROData(clustered_stream); | 
| + | 
| +  WriteText(clustered_stream, vm); | 
| +} | 
| + | 
| + | 
| +void InstructionsWriter::WriteROData(WriteStream* stream) { | 
| +  stream->Align(OS::kMaxPreferredCodeAlignment); | 
| + | 
| +  // Heap page starts here. | 
| + | 
| +  stream->WriteWord(next_object_offset_);  // Data length. | 
| +  COMPILE_ASSERT(OS::kMaxPreferredCodeAlignment >= kObjectAlignment); | 
| +  stream->Align(OS::kMaxPreferredCodeAlignment); | 
| + | 
| +  // Heap page objects start here. | 
| + | 
| +  for (intptr_t i = 0; i < objects_.length(); i++) { | 
| +    const Object& obj = *objects_[i].obj_; | 
| + | 
| +    NoSafepointScope no_safepoint; | 
| +    uword start = reinterpret_cast<uword>(obj.raw()) - kHeapObjectTag; | 
| +    uword end = start + obj.raw()->Size(); | 
| + | 
| +    // Write object header with the mark and VM heap bits set. | 
| +    uword marked_tags = obj.raw()->ptr()->tags_; | 
| +    marked_tags = RawObject::VMHeapObjectTag::update(true, marked_tags); | 
| +    marked_tags = RawObject::MarkBit::update(true, marked_tags); | 
| +    stream->WriteWord(marked_tags); | 
| +    start += sizeof(uword); | 
| +    for (uword* cursor = reinterpret_cast<uword*>(start); | 
| +         cursor < reinterpret_cast<uword*>(end); cursor++) { | 
| +      stream->WriteWord(*cursor); | 
| +    } | 
| +  } | 
| +} | 
| + | 
| + | 
| +static void EnsureIdentifier(char* label) { | 
| +  for (char c = *label; c != '\0'; c = *++label) { | 
| +    if (((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || | 
| +        ((c >= '0') && (c <= '9'))) { | 
| +      continue; | 
| +    } | 
| +    *label = '_'; | 
| +  } | 
| +} | 
| + | 
| + | 
| +void AssemblyInstructionsWriter::WriteText(WriteStream* clustered_stream, | 
| +                                           bool vm) { | 
| +  Zone* zone = Thread::Current()->zone(); | 
| + | 
| +  const char* instructions_symbol = | 
| +      vm ? "_kDartVmSnapshotInstructions" : "_kDartIsolateSnapshotInstructions"; | 
| assembly_stream_.Print(".text\n"); | 
| -  assembly_stream_.Print(".globl _kInstructionsSnapshot\n"); | 
| +  assembly_stream_.Print(".globl %s\n", instructions_symbol); | 
| // Start snapshot at page boundary. | 
| ASSERT(VirtualMemory::PageSize() >= OS::kMaxPreferredCodeAlignment); | 
| assembly_stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize()); | 
| -  assembly_stream_.Print("_kInstructionsSnapshot:\n"); | 
| +  assembly_stream_.Print("%s:\n", instructions_symbol); | 
|  | 
| // This head also provides the gap to make the instructions snapshot | 
| // look like a HeapPage. | 
| @@ -829,6 +871,8 @@ void AssemblyInstructionsWriter::Write(uint8_t* vmisolate_buffer, | 
| } | 
| } | 
| } | 
| + | 
| + | 
| #if defined(TARGET_OS_LINUX) | 
| assembly_stream_.Print(".section .rodata\n"); | 
| #elif defined(TARGET_OS_MACOS) | 
| @@ -837,76 +881,24 @@ void AssemblyInstructionsWriter::Write(uint8_t* vmisolate_buffer, | 
| // Unsupported platform. | 
| UNREACHABLE(); | 
| #endif | 
| -  assembly_stream_.Print(".globl _kDataSnapshot\n"); | 
| -  // Start snapshot at page boundary. | 
| -  assembly_stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize()); | 
| -  assembly_stream_.Print("_kDataSnapshot:\n"); | 
| -  WriteWordLiteralData(next_object_offset_);  // Data length. | 
| -  COMPILE_ASSERT(OS::kMaxPreferredCodeAlignment >= kObjectAlignment); | 
| + | 
| +  const char* data_symbol = | 
| +      vm ? "_kDartVmSnapshotData" : "_kDartIsolateSnapshotData"; | 
| +  assembly_stream_.Print(".globl %s\n", data_symbol); | 
| assembly_stream_.Print(".balign %" Pd ", 0\n", | 
| OS::kMaxPreferredCodeAlignment); | 
| - | 
| -  for (intptr_t i = 0; i < objects_.length(); i++) { | 
| -    const Object& obj = *objects_[i].obj_; | 
| -    assembly_stream_.Print("Precompiled_Obj_%d:\n", i); | 
| - | 
| -    NoSafepointScope no_safepoint; | 
| -    uword start = reinterpret_cast<uword>(obj.raw()) - kHeapObjectTag; | 
| -    uword end = start + obj.raw()->Size(); | 
| - | 
| -    // Write object header with the mark and VM heap bits set. | 
| -    uword marked_tags = obj.raw()->ptr()->tags_; | 
| -    marked_tags = RawObject::VMHeapObjectTag::update(true, marked_tags); | 
| -    marked_tags = RawObject::MarkBit::update(true, marked_tags); | 
| -    WriteWordLiteralData(marked_tags); | 
| -    start += sizeof(uword); | 
| -    for (uword* cursor = reinterpret_cast<uword*>(start); | 
| -         cursor < reinterpret_cast<uword*>(end); cursor++) { | 
| -      WriteWordLiteralData(*cursor); | 
| -    } | 
| -  } | 
| - | 
| - | 
| -  assembly_stream_.Print(".globl _kVmIsolateSnapshot\n"); | 
| -  assembly_stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize()); | 
| -  assembly_stream_.Print("_kVmIsolateSnapshot:\n"); | 
| -  for (intptr_t i = 0; i < vmisolate_length; i++) { | 
| -    assembly_stream_.Print(".byte %" Pd "\n", vmisolate_buffer[i]); | 
| -  } | 
| - | 
| -  assembly_stream_.Print(".globl _kIsolateSnapshot\n"); | 
| -  assembly_stream_.Print(".balign %" Pd ", 0\n", VirtualMemory::PageSize()); | 
| -  assembly_stream_.Print("_kIsolateSnapshot:\n"); | 
| -  for (intptr_t i = 0; i < isolate_length; i++) { | 
| -    assembly_stream_.Print(".byte %" Pd "\n", isolate_buffer[i]); | 
| +  assembly_stream_.Print("%s:\n", data_symbol); | 
| +  uint8_t* buffer = clustered_stream->buffer(); | 
| +  intptr_t length = clustered_stream->bytes_written(); | 
| +  for (intptr_t i = 0; i < length; i++) { | 
| +    assembly_stream_.Print(".byte %" Pd "\n", buffer[i]); | 
| } | 
| } | 
|  | 
|  | 
| -void BlobInstructionsWriter::Write(uint8_t* vmisolate_buffer, | 
| -                                   intptr_t vmisolate_len, | 
| -                                   uint8_t* isolate_buffer, | 
| -                                   intptr_t isolate_length) { | 
| -  Thread* thread = Thread::Current(); | 
| -  Zone* zone = thread->zone(); | 
| -  NOT_IN_PRODUCT(TimelineDurationScope tds(thread, Timeline::GetIsolateStream(), | 
| -                                           "WriteInstructions")); | 
| - | 
| -  // Handlify collected raw pointers as building the names below | 
| -  // will allocate on the Dart heap. | 
| -  for (intptr_t i = 0; i < instructions_.length(); i++) { | 
| -    InstructionsData& data = instructions_[i]; | 
| -    data.insns_ = &Instructions::Handle(zone, data.raw_insns_); | 
| -    ASSERT(data.raw_code_ != NULL); | 
| -    data.code_ = &Code::Handle(zone, data.raw_code_); | 
| -  } | 
| -  for (intptr_t i = 0; i < objects_.length(); i++) { | 
| -    ObjectData& data = objects_[i]; | 
| -    data.obj_ = &Object::Handle(zone, data.raw_obj_); | 
| -  } | 
| - | 
| -  // This head also provides the gap to make the instructions snapshot | 
| -  // look like a HeapPage. | 
| +void BlobInstructionsWriter::WriteText(WriteStream* clustered_stream, bool vm) { | 
| +  // This header provides the gap to make the instructions snapshot look like a | 
| +  // HeapPage. | 
| intptr_t instructions_length = next_offset_; | 
| instructions_blob_stream_.WriteWord(instructions_length); | 
| intptr_t header_words = InstructionsSnapshot::kHeaderSize / sizeof(uword); | 
| @@ -960,38 +952,18 @@ void BlobInstructionsWriter::Write(uint8_t* vmisolate_buffer, | 
| } | 
| } | 
| } | 
| - | 
| -  rodata_blob_stream_.WriteWord(next_object_offset_);  // Data length. | 
| -  COMPILE_ASSERT(OS::kMaxPreferredCodeAlignment >= kObjectAlignment); | 
| -  while (!Utils::IsAligned(rodata_blob_stream_.bytes_written(), | 
| -                           OS::kMaxPreferredCodeAlignment)) { | 
| -    rodata_blob_stream_.WriteWord(0); | 
| -  } | 
| - | 
| -  for (intptr_t i = 0; i < objects_.length(); i++) { | 
| -    const Object& obj = *objects_[i].obj_; | 
| - | 
| -    NoSafepointScope no_safepoint; | 
| -    uword start = reinterpret_cast<uword>(obj.raw()) - kHeapObjectTag; | 
| -    uword end = start + obj.raw()->Size(); | 
| - | 
| -    // Write object header with the mark and VM heap bits set. | 
| -    uword marked_tags = obj.raw()->ptr()->tags_; | 
| -    marked_tags = RawObject::VMHeapObjectTag::update(true, marked_tags); | 
| -    marked_tags = RawObject::MarkBit::update(true, marked_tags); | 
| -    rodata_blob_stream_.WriteWord(marked_tags); | 
| -    start += sizeof(uword); | 
| -    for (uword* cursor = reinterpret_cast<uword*>(start); | 
| -         cursor < reinterpret_cast<uword*>(end); cursor++) { | 
| -      rodata_blob_stream_.WriteWord(*cursor); | 
| -    } | 
| -  } | 
| } | 
|  | 
|  | 
| -uword InstructionsReader::GetInstructionsAt(int32_t offset) { | 
| +RawInstructions* InstructionsReader::GetInstructionsAt(int32_t offset) { | 
| ASSERT(Utils::IsAligned(offset, OS::PreferredCodeAlignment())); | 
| -  return reinterpret_cast<uword>(instructions_buffer_) + offset; | 
| + | 
| +  RawInstructions* result = reinterpret_cast<RawInstructions*>( | 
| +      reinterpret_cast<uword>(instructions_buffer_) + offset + kHeapObjectTag); | 
| +  ASSERT(result->IsInstructions()); | 
| +  ASSERT(result->IsMarked()); | 
| + | 
| +  return result; | 
| } | 
|  | 
|  | 
|  |