1. Reclaim the CreatedFromSnapshot bit and use the bit to indicate VM heap object.

2. Cleanup calls to set_tags when reading objects from a snapshot.

3. Fixes issue 21816

R=regis@google.com

Review URL: https://codereview.chromium.org//1221503004 .
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index 2788be0..69fb891 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -535,6 +535,7 @@
                                                      intptr_t object_id) {
   switch (class_id) {
     case kClassCid: {
+      Read<bool>();  // Consume the is_in_fullsnapshot indicator.
       Dart_CObject_Internal* object = AllocateDartCObjectClass();
       AddBackRef(object_id, object, kIsDeserialized);
       object->internal.as_class.library_url = ReadObjectImpl();
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 88ebd0e..4351b1d 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -399,7 +399,7 @@
     uword address = heap->Allocate(Instance::InstanceSize(), Heap::kOld);
     null_ = reinterpret_cast<RawInstance*>(address + kHeapObjectTag);
     // The call below is using 'null_' to initialize itself.
-    InitializeObject(address, kNullCid, Instance::InstanceSize());
+    InitializeObject(address, kNullCid, Instance::InstanceSize(), true);
   }
 }
 
@@ -462,7 +462,7 @@
     intptr_t size = Class::InstanceSize();
     uword address = heap->Allocate(size, Heap::kOld);
     class_class_ = reinterpret_cast<RawClass*>(address + kHeapObjectTag);
-    InitializeObject(address, Class::kClassId, size);
+    InitializeObject(address, Class::kClassId, size, true);
 
     Class fake;
     // Initialization from Class::New<Class>.
@@ -635,7 +635,7 @@
   // Allocate and initialize the empty_array instance.
   {
     uword address = heap->Allocate(Array::InstanceSize(0), Heap::kOld);
-    InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(0));
+    InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(0), true);
     Array::initializeHandle(
         empty_array_,
         reinterpret_cast<RawArray*>(address + kHeapObjectTag));
@@ -646,7 +646,7 @@
   // Allocate and initialize the zero_array instance.
   {
     uword address = heap->Allocate(Array::InstanceSize(1), Heap::kOld);
-    InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(1));
+    InitializeObject(address, kImmutableArrayCid, Array::InstanceSize(1), true);
     Array::initializeHandle(
         zero_array_,
         reinterpret_cast<RawArray*>(address + kHeapObjectTag));
@@ -661,7 +661,8 @@
         heap->Allocate(ObjectPool::InstanceSize(0), Heap::kOld);
     InitializeObject(address,
                      kObjectPoolCid,
-                     ObjectPool::InstanceSize(0));
+                     ObjectPool::InstanceSize(0),
+                     true);
     ObjectPool::initializeHandle(
         empty_object_pool_,
         reinterpret_cast<RawObjectPool*>(address + kHeapObjectTag));
@@ -673,7 +674,8 @@
   {
     uword address = heap->Allocate(PcDescriptors::InstanceSize(0), Heap::kOld);
     InitializeObject(address, kPcDescriptorsCid,
-                     PcDescriptors::InstanceSize(0));
+                     PcDescriptors::InstanceSize(0),
+                     true);
     PcDescriptors::initializeHandle(
         empty_descriptors_,
         reinterpret_cast<RawPcDescriptors*>(address + kHeapObjectTag));
@@ -687,7 +689,8 @@
         heap->Allocate(LocalVarDescriptors::InstanceSize(0), Heap::kOld);
     InitializeObject(address,
                      kLocalVarDescriptorsCid,
-                     LocalVarDescriptors::InstanceSize(0));
+                     LocalVarDescriptors::InstanceSize(0),
+                     true);
     LocalVarDescriptors::initializeHandle(
         empty_var_descriptors_,
         reinterpret_cast<RawLocalVarDescriptors*>(address + kHeapObjectTag));
@@ -703,7 +706,8 @@
         heap->Allocate(ExceptionHandlers::InstanceSize(0), Heap::kOld);
     InitializeObject(address,
                      kExceptionHandlersCid,
-                     ExceptionHandlers::InstanceSize(0));
+                     ExceptionHandlers::InstanceSize(0),
+                     true);
     ExceptionHandlers::initializeHandle(
         empty_exception_handlers_,
         reinterpret_cast<RawExceptionHandlers*>(address + kHeapObjectTag));
@@ -809,6 +813,7 @@
     ASSERT(!obj->IsMarked());
     // Free list elements should never be marked.
     if (!obj->IsFreeListElement()) {
+      ASSERT(obj->IsVMHeapObject());
       obj->SetMarkBitUnsynchronized();
     }
   }
@@ -1674,7 +1679,10 @@
 }
 
 
-void Object::InitializeObject(uword address, intptr_t class_id, intptr_t size) {
+void Object::InitializeObject(uword address,
+                              intptr_t class_id,
+                              intptr_t size,
+                              bool is_vm_object) {
   // TODO(iposva): Get a proper halt instruction from the assembler which
   // would be needed here for code objects.
   uword initial_value = reinterpret_cast<uword>(null_);
@@ -1688,7 +1696,9 @@
   ASSERT(class_id != kIllegalCid);
   tags = RawObject::ClassIdTag::update(class_id, tags);
   tags = RawObject::SizeTag::update(size, tags);
+  tags = RawObject::VMHeapObjectTag::update(is_vm_object, tags);
   reinterpret_cast<RawObject*>(address)->tags_ = tags;
+  ASSERT(is_vm_object == RawObject::IsVMHeapObject(tags));
   VerifiedMemory::Accept(address, size);
 }
 
@@ -1746,7 +1756,7 @@
     Profiler::RecordAllocation(isolate, cls_id);
   }
   NoSafepointScope no_safepoint;
-  InitializeObject(address, cls_id, size);
+  InitializeObject(address, cls_id, size, (isolate == Dart::vm_isolate()));
   RawObject* raw_obj = reinterpret_cast<RawObject*>(address + kHeapObjectTag);
   ASSERT(cls_id == RawObject::ClassIdTag::decode(raw_obj->ptr()->tags_));
   return raw_obj;
@@ -1840,6 +1850,12 @@
 }
 
 
+bool Class::IsInFullSnapshot() const {
+  NoSafepointScope no_safepoint;
+  return raw_ptr()->library_->ptr()->is_in_fullsnapshot_;
+}
+
+
 RawType* Class::SignatureType() const {
   ASSERT(IsSignatureClass());
   const Function& function = Function::Handle(signature_function());
@@ -9826,6 +9842,7 @@
   result.StorePointer(&result.raw_ptr()->load_error_, Instance::null());
   result.set_native_entry_resolver(NULL);
   result.set_native_entry_symbol_resolver(NULL);
+  result.set_is_in_fullsnapshot(false);
   result.StoreNonPointer(&result.raw_ptr()->corelib_imported_, true);
   result.set_debuggable(false);
   result.set_is_dart_scheme(url.StartsWith(Symbols::DartScheme()));
@@ -15258,6 +15275,7 @@
 void Type::SetIsFinalized() const {
   ASSERT(!IsFinalized());
   if (IsInstantiated()) {
+    ASSERT(HasResolvedTypeClass());
     set_type_state(RawType::kFinalizedInstantiated);
   } else {
     set_type_state(RawType::kFinalizedUninstantiated);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 8df34c1..8d3ef5e 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -249,23 +249,6 @@
     return AtomicOperations::CompareAndSwapWord(
         &raw()->ptr()->tags_, old_tags, new_tags);
   }
-  void set_tags(intptr_t value) const {
-    ASSERT(!IsNull());
-    // TODO(asiva): Remove the capability of setting tags in general. The mask
-    // here only allows for canonical and from_snapshot flags to be set.
-    value = value & 0x0000000c;
-    uword tags = raw()->ptr()->tags_;
-    uword old_tags;
-    do {
-      old_tags = tags;
-      uword new_tags = (old_tags & ~0x0000000c) | value;
-      tags = CompareAndSwapTags(old_tags, new_tags);
-    } while (tags != old_tags);
-  }
-  void SetCreatedFromSnapshot() const {
-    ASSERT(!IsNull());
-    raw()->SetCreatedFromSnapshot();
-  }
   bool IsCanonical() const {
     ASSERT(!IsNull());
     return raw()->IsCanonical();
@@ -728,7 +711,10 @@
     return -kWordSize;
   }
 
-  static void InitializeObject(uword address, intptr_t id, intptr_t size);
+  static void InitializeObject(uword address,
+                               intptr_t id,
+                               intptr_t size,
+                               bool is_vm_object);
 
   static void RegisterClass(const Class& cls,
                             const String& name,
@@ -945,6 +931,7 @@
   RawString* Name() const;
   RawString* PrettyName() const;
   RawString* UserVisibleName() const;
+  bool IsInFullSnapshot() const;
 
   virtual RawString* DictionaryName() const { return Name(); }
 
@@ -1115,6 +1102,10 @@
   static bool IsSignatureClass(RawClass* cls) {
     return cls->ptr()->signature_function_ != Object::null();
   }
+  static bool IsInFullSnapshot(RawClass* cls) {
+    NoSafepointScope no_safepoint;
+    return cls->ptr()->library_->ptr()->is_in_fullsnapshot_;
+  }
 
   // Check if this class represents a canonical signature class, i.e. not an
   // alias as defined in a typedef.
@@ -3392,6 +3383,11 @@
                     native_symbol_resolver);
   }
 
+  bool is_in_fullsnapshot() const { return raw_ptr()->is_in_fullsnapshot_; }
+  void set_is_in_fullsnapshot(bool value) const {
+    StoreNonPointer(&raw_ptr()->is_in_fullsnapshot_, value);
+  }
+
   RawError* Patch(const Script& script) const;
 
   RawString* PrivateName(const String& name) const;
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 67f0afc..61c2994 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -18,10 +18,6 @@
 DEFINE_FLAG(bool, validate_overwrite, true, "Verify overwritten fields.");
 #endif  // DEBUG
 
-bool RawObject::IsVMHeapObject() const {
-  return Dart::vm_isolate()->heap()->Contains(ToAddr(this));
-}
-
 
 void RawObject::Validate(Isolate* isolate) const {
   if (Object::void_class_ == reinterpret_cast<RawClass*>(kHeapObjectTag)) {
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 9976c93..517379b 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -236,7 +236,7 @@
     kWatchedBit = 0,
     kMarkBit = 1,
     kCanonicalBit = 2,
-    kFromSnapshotBit = 3,
+    kVMHeapObjectBit = 3,
     kRememberedBit = 4,
 #if defined(ARCH_IS_32_BIT)
     kReservedTagPos = 5,  // kReservedBit{100K,1M,10M}
@@ -315,8 +315,6 @@
     uword addr = reinterpret_cast<uword>(this);
     return (addr & kNewObjectAlignmentOffset) == kOldObjectAlignmentOffset;
   }
-  // Assumes this is a heap object.
-  bool IsVMHeapObject() const;
 
   // Like !IsHeapObject() || IsOldObject(), but compiles to a single branch.
   bool IsSmiOrOldObject() const {
@@ -372,11 +370,11 @@
   void ClearCanonical() {
     UpdateTagBit<CanonicalObjectTag>(false);
   }
-  bool IsCreatedFromSnapshot() const {
-    return CreatedFromSnapshotTag::decode(ptr()->tags_);
+  bool IsVMHeapObject() const {
+    return VMHeapObjectTag::decode(ptr()->tags_);
   }
-  void SetCreatedFromSnapshot() {
-    UpdateTagBit<CreatedFromSnapshotTag>(true);
+  void SetVMHeapObject() {
+    UpdateTagBit<VMHeapObjectTag>(true);
   }
 
   // Support for GC remembered bit.
@@ -445,8 +443,8 @@
     return reinterpret_cast<uword>(raw_obj->ptr());
   }
 
-  static bool IsCreatedFromSnapshot(intptr_t value) {
-    return CreatedFromSnapshotTag::decode(value);
+  static bool IsVMHeapObject(intptr_t value) {
+    return VMHeapObjectTag::decode(value);
   }
 
   static bool IsCanonical(intptr_t value) {
@@ -482,7 +480,7 @@
 
   class CanonicalObjectTag : public BitField<bool, kCanonicalBit, 1> {};
 
-  class CreatedFromSnapshotTag : public BitField<bool, kFromSnapshotBit, 1> {};
+  class VMHeapObjectTag : public BitField<bool, kVMHeapObjectBit, 1> {};
 
   class ReservedBits : public
       BitField<intptr_t, kReservedTagPos, kReservedTagSize> {};  // NOLINT
@@ -950,7 +948,9 @@
   bool corelib_imported_;
   bool is_dart_scheme_;
   bool debuggable_;             // True if debugger can stop in library.
+  bool is_in_fullsnapshot_;     // True if library is in a full snapshot.
 
+  friend class Class;
   friend class Isolate;
 };
 
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 01aef3a..9a12d08 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -31,8 +31,9 @@
   ASSERT(reader != NULL);
 
   Class& cls = Class::ZoneHandle(reader->zone(), Class::null());
+  bool is_in_fullsnapshot = reader->Read<bool>();
   if ((kind == Snapshot::kFull) ||
-      (kind == Snapshot::kScript && !RawObject::IsCreatedFromSnapshot(tags))) {
+      (kind == Snapshot::kScript && !is_in_fullsnapshot)) {
     // Read in the base information.
     classid_t class_id = reader->ReadClassIDValue();
 
@@ -49,9 +50,6 @@
     }
     reader->AddBackRef(object_id, &cls, kIsDeserialized);
 
-    // Set the object tags.
-    cls.set_tags(tags);
-
     // Set all non object fields.
     if (!RawObject::IsInternalVMdefinedClassId(class_id)) {
       // Instance size of a VM defined class is already set up.
@@ -76,8 +74,10 @@
       cls.StorePointer((cls.raw()->from() + i),
                        reader->PassiveObjectHandle()->raw());
     }
+    ASSERT(!cls.IsInFullSnapshot() || (kind == Snapshot::kFull));
   } else {
     cls ^= reader->ReadClassId(object_id);
+    ASSERT((kind == Snapshot::kMessage) || cls.IsInFullSnapshot());
   }
   return cls.raw();
 }
@@ -87,17 +87,22 @@
                        intptr_t object_id,
                        Snapshot::Kind kind) {
   ASSERT(writer != NULL);
+  bool is_in_fullsnapshot = Class::IsInFullSnapshot(this);
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
 
-  if ((kind == Snapshot::kFull) ||
-      (kind == Snapshot::kScript &&
-       !RawObject::IsCreatedFromSnapshot(writer->GetObjectTags(this)))) {
-    // Write out the class and tags information.
-    writer->WriteVMIsolateObject(kClassCid);
-    writer->WriteTags(writer->GetObjectTags(this));
+  // Write out the class and tags information.
+  writer->WriteVMIsolateObject(kClassCid);
+  writer->WriteTags(writer->GetObjectTags(this));
 
+  // Write out the boolean is_in_fullsnapshot first as this will
+  // help the reader decide how the rest of the information needs
+  // to be interpreted.
+  writer->Write<bool>(is_in_fullsnapshot);
+
+  if ((kind == Snapshot::kFull) ||
+      (kind == Snapshot::kScript && !is_in_fullsnapshot)) {
     // Write out all the non object pointer fields.
     // NOTE: cpp_vtable_ is not written.
     classid_t class_id = ptr()->id_;
@@ -144,9 +149,6 @@
       reader->zone(), NEW_OBJECT(UnresolvedClass));
   reader->AddBackRef(object_id, &unresolved_class, kIsDeserialized);
 
-  // Set the object tags.
-  unresolved_class.set_tags(tags);
-
   // Set all non object fields.
   unresolved_class.set_token_pos(reader->Read<int32_t>());
 
@@ -229,11 +231,9 @@
                       reader->PassiveObjectHandle()->raw());
   }
 
-  // Set the object tags.
-  type.set_tags(tags);
-  if (defer_canonicalization) {
-    // We are deferring canonicalization so mark object as not canonical.
-    type.ClearCanonical();
+  // Set the canonical bit.
+  if (!defer_canonicalization && RawObject::IsCanonical(tags)) {
+    type.SetCanonical();
   }
 
   return type.raw();
@@ -248,6 +248,7 @@
   // Only resolved and finalized types should be written to a snapshot.
   ASSERT((ptr()->type_state_ == RawType::kFinalizedInstantiated) ||
          (ptr()->type_state_ == RawType::kFinalizedUninstantiated));
+  ASSERT(ptr()->type_class_ != Object::null());
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -263,6 +264,7 @@
   // Write out all the object pointer fields. Since we will be canonicalizing
   // the type object when reading it back we should write out all the fields
   // inline and not as references.
+  ASSERT(ptr()->type_class_ != Object::null());
   SnapshotWriterVisitor visitor(writer);
   visitor.VisitPointers(from(), to());
 }
@@ -279,9 +281,6 @@
       reader->zone(), NEW_OBJECT(TypeRef));
   reader->AddBackRef(object_id, &type_ref, kIsDeserialized);
 
-  // Set the object tags.
-  type_ref.set_tags(tags);
-
   // Set all the object fields.
   // TODO(5411462): Need to assert No GC can happen here, even though
   // allocations may happen.
@@ -327,9 +326,6 @@
       reader->zone(), NEW_OBJECT(TypeParameter));
   reader->AddBackRef(object_id, &type_parameter, kIsDeserialized);
 
-  // Set the object tags.
-  type_parameter.set_tags(tags);
-
   // Set all non object fields.
   type_parameter.set_token_pos(reader->Read<int32_t>());
   type_parameter.set_index(reader->Read<int16_t>());
@@ -389,9 +385,6 @@
       reader->zone(), NEW_OBJECT(BoundedType));
   reader->AddBackRef(object_id, &bounded_type, kIsDeserialized);
 
-  // Set the object tags.
-  bounded_type.set_tags(tags);
-
   // Set all the object fields.
   // TODO(5411462): Need to assert No GC can happen here, even though
   // allocations may happen.
@@ -478,11 +471,9 @@
     type_arguments.SetTypeAt(i, *reader->TypeHandle());
   }
 
-  // Set the object tags .
-  type_arguments.set_tags(tags);
-  if (defer_canonicalization) {
-    // We are deferring canonicalization so mark object as not canonical.
-    type_arguments.ClearCanonical();
+  // Set the canonical bit.
+  if (!defer_canonicalization && RawObject::IsCanonical(tags)) {
+    type_arguments.SetCanonical();
   }
 
   return type_arguments.raw();
@@ -522,18 +513,12 @@
                                     intptr_t tags,
                                     Snapshot::Kind kind) {
   ASSERT(reader != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(tags)) ||
-         (kind == Snapshot::kFull));
 
   // Allocate function object.
   PatchClass& cls = PatchClass::ZoneHandle(reader->zone(),
                                             NEW_OBJECT(PatchClass));
   reader->AddBackRef(object_id, &cls, kIsDeserialized);
 
-  // Set the object tags.
-  cls.set_tags(tags);
-
   // Set all the object fields.
   // TODO(5411462): Need to assert No GC can happen here, even though
   // allocations may happen.
@@ -543,6 +528,9 @@
     cls.StorePointer((cls.raw()->from() + i),
                      reader->PassiveObjectHandle()->raw());
   }
+  ASSERT(((kind == Snapshot::kScript) &&
+          !Class::IsInFullSnapshot(cls.source_class())) ||
+         (kind == Snapshot::kFull));
 
   return cls.raw();
 }
@@ -552,9 +540,7 @@
                             intptr_t object_id,
                             Snapshot::Kind kind) {
   ASSERT(writer != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(writer->GetObjectTags(this))) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -573,18 +559,13 @@
                                       intptr_t tags,
                                       Snapshot::Kind kind) {
   ASSERT(reader != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(tags)) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Allocate closure data object.
   ClosureData& data = ClosureData::ZoneHandle(
       reader->zone(), NEW_OBJECT(ClosureData));
   reader->AddBackRef(object_id, &data, kIsDeserialized);
 
-  // Set the object tags.
-  data.set_tags(tags);
-
   // Set all the object fields.
   // TODO(5411462): Need to assert No GC can happen here, even though
   // allocations may happen.
@@ -601,9 +582,7 @@
                              intptr_t object_id,
                              Snapshot::Kind kind) {
   ASSERT(writer != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(writer->GetObjectTags(this))) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -633,18 +612,13 @@
                                               intptr_t tags,
                                               Snapshot::Kind kind) {
   ASSERT(reader != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(tags)) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Allocate redirection data object.
   RedirectionData& data = RedirectionData::ZoneHandle(
       reader->zone(), NEW_OBJECT(RedirectionData));
   reader->AddBackRef(object_id, &data, kIsDeserialized);
 
-  // Set the object tags.
-  data.set_tags(tags);
-
   // Set all the object fields.
   // TODO(5411462): Need to assert No GC can happen here, even though
   // allocations may happen.
@@ -665,9 +639,7 @@
                                  intptr_t object_id,
                                  Snapshot::Kind kind) {
   ASSERT(writer != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(writer->GetObjectTags(this))) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -687,18 +659,13 @@
                                 intptr_t tags,
                                 Snapshot::Kind kind) {
   ASSERT(reader != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(tags)) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Allocate function object.
   Function& func = Function::ZoneHandle(
       reader->zone(), NEW_OBJECT(Function));
   reader->AddBackRef(object_id, &func, kIsDeserialized);
 
-  // Set the object tags.
-  func.set_tags(tags);
-
   // Set all the non object fields.
   func.set_token_pos(reader->Read<int32_t>());
   func.set_end_token_pos(reader->Read<int32_t>());
@@ -734,9 +701,7 @@
                           intptr_t object_id,
                           Snapshot::Kind kind) {
   ASSERT(writer != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(writer->GetObjectTags(this))) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -768,17 +733,12 @@
                           intptr_t tags,
                           Snapshot::Kind kind) {
   ASSERT(reader != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(tags)) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Allocate field object.
   Field& field = Field::ZoneHandle(reader->zone(), NEW_OBJECT(Field));
   reader->AddBackRef(object_id, &field, kIsDeserialized);
 
-  // Set the object tags.
-  field.set_tags(tags);
-
   // Set all non object fields.
   field.set_token_pos(reader->Read<int32_t>());
   field.set_guarded_cid(reader->Read<int32_t>());
@@ -807,9 +767,7 @@
                        intptr_t object_id,
                        Snapshot::Kind kind) {
   ASSERT(writer != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(writer->GetObjectTags(this))) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -842,9 +800,6 @@
       reader->zone(), NEW_OBJECT(LiteralToken));
   reader->AddBackRef(object_id, &literal_token, kIsDeserialized);
 
-  // Set the object tags.
-  literal_token.set_tags(tags);
-
   // Read the token attributes.
   Token::Kind token_kind = static_cast<Token::Kind>(reader->Read<int32_t>());
   literal_token.set_kind(token_kind);
@@ -890,9 +845,7 @@
                                       intptr_t tags,
                                       Snapshot::Kind kind) {
   ASSERT(reader != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(tags)) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Read the length so that we can determine number of tokens to read.
   intptr_t len = reader->ReadSmiValue();
@@ -902,9 +855,6 @@
       reader->zone(), NEW_OBJECT_WITH_LEN(TokenStream, len));
   reader->AddBackRef(object_id, &token_stream, kIsDeserialized);
 
-  // Set the object tags.
-  token_stream.set_tags(tags);
-
   // Read the stream of tokens into the TokenStream object for script
   // snapshots as we made a copy of token stream.
   if (kind == Snapshot::kScript) {
@@ -928,9 +878,7 @@
                              intptr_t object_id,
                              Snapshot::Kind kind) {
   ASSERT(writer != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(writer->GetObjectTags(this))) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -957,17 +905,12 @@
                             intptr_t tags,
                             Snapshot::Kind kind) {
   ASSERT(reader != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(tags)) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Allocate script object.
   Script& script = Script::ZoneHandle(reader->zone(), NEW_OBJECT(Script));
   reader->AddBackRef(object_id, &script, kIsDeserialized);
 
-  // Set the object tags.
-  script.set_tags(tags);
-
   script.StoreNonPointer(&script.raw_ptr()->line_offset_,
                          reader->Read<int32_t>());
   script.StoreNonPointer(&script.raw_ptr()->col_offset_,
@@ -997,9 +940,7 @@
                         Snapshot::Kind kind) {
   ASSERT(writer != NULL);
   ASSERT(tokens_ != TokenStream::null());
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(writer->GetObjectTags(this))) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -1029,18 +970,16 @@
   Library& library = Library::ZoneHandle(reader->zone(), Library::null());
   reader->AddBackRef(object_id, &library, kIsDeserialized);
 
-  if ((kind == Snapshot::kScript) && RawObject::IsCreatedFromSnapshot(tags)) {
-    ASSERT(kind != Snapshot::kFull);
+  bool is_in_fullsnapshot = reader->Read<bool>();
+  if ((kind == Snapshot::kScript) && is_in_fullsnapshot) {
     // Lookup the object as it should already exist in the heap.
     *reader->StringHandle() ^= reader->ReadObjectImpl(kAsInlinedObject);
     library = Library::LookupLibrary(*reader->StringHandle());
+    ASSERT(library.is_in_fullsnapshot());
   } else {
     // Allocate library object.
     library = NEW_OBJECT(Library);
 
-    // Set the object tags.
-    library.set_tags(tags);
-
     // Set all non object fields.
     library.StoreNonPointer(&library.raw_ptr()->index_,
                             reader->ReadClassIDValue());
@@ -1056,6 +995,11 @@
                             reader->Read<bool>());
     library.StoreNonPointer(&library.raw_ptr()->debuggable_,
                             reader->Read<bool>());
+    if (kind == Snapshot::kFull) {
+      is_in_fullsnapshot = true;
+    }
+    library.StoreNonPointer(&library.raw_ptr()->is_in_fullsnapshot_,
+                            is_in_fullsnapshot);
     // The native resolver and symbolizer are not serialized.
     library.set_native_entry_resolver(NULL);
     library.set_native_entry_symbol_resolver(NULL);
@@ -1092,12 +1036,16 @@
   writer->WriteVMIsolateObject(kLibraryCid);
   writer->WriteTags(writer->GetObjectTags(this));
 
-  if ((kind == Snapshot::kScript) &&
-      RawObject::IsCreatedFromSnapshot(writer->GetObjectTags(this))) {
-    ASSERT(kind != Snapshot::kFull);
+  // Write out the boolean is_in_fullsnapshot_ first as this will
+  // help the reader decide how the rest of the information needs
+  // to be interpreted.
+  writer->Write<bool>(ptr()->is_in_fullsnapshot_);
+
+  if ((kind == Snapshot::kScript) && ptr()->is_in_fullsnapshot_) {
     // Write out library URL so that it can be looked up when reading.
     writer->WriteObjectImpl(ptr()->url_, kAsInlinedObject);
   } else {
+    ASSERT((kind == Snapshot::kFull) || !ptr()->is_in_fullsnapshot_);
     // Write out all non object fields.
     writer->WriteClassIDValue(ptr()->index_);
     writer->WriteClassIDValue(ptr()->num_anonymous_);
@@ -1124,18 +1072,13 @@
                                           intptr_t tags,
                                           Snapshot::Kind kind) {
   ASSERT(reader != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(tags)) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Allocate library prefix object.
   LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(
       reader->zone(), NEW_OBJECT(LibraryPrefix));
   reader->AddBackRef(object_id, &prefix, kIsDeserialized);
 
-  // Set the object tags.
-  prefix.set_tags(tags);
-
   // Set all non object fields.
   prefix.StoreNonPointer(&prefix.raw_ptr()->num_imports_,
                          reader->Read<int16_t>());
@@ -1161,9 +1104,7 @@
                                intptr_t object_id,
                                Snapshot::Kind kind) {
   ASSERT(writer != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(writer->GetObjectTags(this))) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -1188,18 +1129,13 @@
                                   intptr_t tags,
                                   Snapshot::Kind kind) {
   ASSERT(reader != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(tags)) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Allocate Namespace object.
   Namespace& ns = Namespace::ZoneHandle(
       reader->zone(), NEW_OBJECT(Namespace));
   reader->AddBackRef(object_id, &ns, kIsDeserialized);
 
-  // Set the object tags.
-  ns.set_tags(tags);
-
   // Set all the object fields.
   // TODO(5411462): Need to assert No GC can happen here, even though
   // allocations may happen.
@@ -1218,9 +1154,7 @@
                            intptr_t object_id,
                            Snapshot::Kind kind) {
   ASSERT(writer != NULL);
-  ASSERT(((kind == Snapshot::kScript) &&
-          !RawObject::IsCreatedFromSnapshot(writer->GetObjectTags(this))) ||
-         (kind == Snapshot::kFull));
+  ASSERT((kind == Snapshot::kScript) || (kind == Snapshot::kFull));
 
   // Write out the serialization header value for this object.
   writer->WriteInlinedObjectHeader(object_id);
@@ -1296,9 +1230,6 @@
                                                     PcDescriptors::New(length));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
-  // Set the object tags.
-  result.set_tags(tags);
-
   if (result.Length() > 0) {
     NoSafepointScope no_safepoint;
     intptr_t len = result.Length();
@@ -1343,9 +1274,6 @@
         Stackmap::New(length, register_bit_count, pc_offset));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
-  // Set the object tags.
-  result.set_tags(tags);
-
   if (result.Length() > 0) {
     NoSafepointScope no_safepoint;
     intptr_t len = (result.Length() + 7) / 8;
@@ -1390,9 +1318,6 @@
         LocalVarDescriptors::New(num_entries));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
-  // Set the object tags.
-  result.set_tags(tags);
-
   for (intptr_t i = 0; i < num_entries; i++) {
     (*reader->StringHandle()) ^= reader->ReadObjectImpl(kAsReference);
     result.StorePointer(result.raw()->nameAddrAt(i),
@@ -1446,9 +1371,6 @@
         ExceptionHandlers::New(*reader->ArrayHandle()));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
-  // Set the object tags.
-  result.set_tags(tags);
-
   if (result.num_entries() > 0) {
     NoSafepointScope no_safepoint;
     const intptr_t len =
@@ -1496,9 +1418,6 @@
   } else {
     context ^= NEW_OBJECT_WITH_LEN(Context, num_vars);
 
-    // Set the object tags.
-    context.set_tags(tags);
-
     // Set all the object fields.
     // TODO(5411462): Need to assert No GC can happen here, even though
     // allocations may happen.
@@ -1627,9 +1546,6 @@
       ApiError::ZoneHandle(reader->zone(), NEW_OBJECT(ApiError));
   reader->AddBackRef(object_id, &api_error, kIsDeserialized);
 
-  // Set the object tags.
-  api_error.set_tags(tags);
-
   // Set all the object fields.
   // TODO(5411462): Need to assert No GC can happen here, even though
   // allocations may happen.
@@ -1673,9 +1589,6 @@
       LanguageError::ZoneHandle(reader->zone(), NEW_OBJECT(LanguageError));
   reader->AddBackRef(object_id, &language_error, kIsDeserialized);
 
-  // Set the object tags.
-  language_error.set_tags(tags);
-
   // Set all non object fields.
   language_error.set_token_pos(reader->Read<int32_t>());
   language_error.set_kind(reader->Read<uint8_t>());
@@ -1725,9 +1638,6 @@
       reader->zone(), NEW_OBJECT(UnhandledException));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
-  // Set the object tags.
-  result.set_tags(tags);
-
   // Set all the object fields.
   // TODO(5411462): Need to assert No GC can happen here, even though
   // allocations may happen.
@@ -1784,26 +1694,20 @@
   Instance& obj = Instance::ZoneHandle(reader->zone(), Instance::null());
   if (kind == Snapshot::kFull) {
     obj = reader->NewInstance();
+    // Set the canonical bit.
+    if (RawObject::IsCanonical(tags)) {
+      obj.SetCanonical();
+    }
   } else {
     obj ^= Object::Allocate(kInstanceCid,
                             Instance::InstanceSize(),
                             HEAP_SPACE(kind));
-    // When reading a script snapshot we need to canonicalize only those object
-    // references that are objects from the core library (loaded from a
-    // full snapshot). Objects that are only in the script need not be
-    // canonicalized as they are already canonical.
-    // When reading a message snapshot we always have to canonicalize.
-    if (RawObject::IsCanonical(tags) &&
-        (RawObject::IsCreatedFromSnapshot(tags) ||
-         (kind == Snapshot::kMessage))) {
+    if (RawObject::IsCanonical(tags)) {
       obj = obj.CheckAndCanonicalize(NULL);
     }
   }
   reader->AddBackRef(object_id, &obj, kIsDeserialized);
 
-  // Set the object tags.
-  obj.set_tags(tags);
-
   return obj.raw();
 }
 
@@ -1844,25 +1748,21 @@
   Mint& mint = Mint::ZoneHandle(reader->zone(), Mint::null());
   if (kind == Snapshot::kFull) {
     mint = reader->NewMint(value);
-    // Set the object tags.
-    mint.set_tags(tags);
+    // Set the canonical bit.
+    if (RawObject::IsCanonical(tags)) {
+      mint.SetCanonical();
+    }
   } else {
     // When reading a script snapshot we need to canonicalize only those object
     // references that are objects from the core library (loaded from a
     // full snapshot). Objects that are only in the script need not be
     // canonicalized as they are already canonical.
     // When reading a message snapshot we always have to canonicalize.
-    if (RawObject::IsCanonical(tags) &&
-        (RawObject::IsCreatedFromSnapshot(tags) ||
-         (kind == Snapshot::kMessage))) {
+    if (RawObject::IsCanonical(tags)) {
       mint = Mint::NewCanonical(value);
-      ASSERT(mint.IsCanonical() &&
-             (kind == Snapshot::kMessage ||
-              RawObject::IsCreatedFromSnapshot(mint.raw()->ptr()->tags_)));
+      ASSERT(mint.IsCanonical());
     } else {
       mint = Mint::New(value, HEAP_SPACE(kind));
-      // Set the object tags.
-      mint.set_tags(tags);
     }
   }
   reader->AddBackRef(object_id, &mint, kIsDeserialized);
@@ -1910,25 +1810,17 @@
   // If it is a canonical constant make it one.
   // When reading a full snapshot we don't need to canonicalize the object
   // as it would already be a canonical object.
-  // When reading a script snapshot we need to canonicalize only those object
-  // references that are objects from the core library (loaded from a
-  // full snapshot). Objects that are only in the script need not be
-  // canonicalized as they are already canonical.
-  // When reading a message snapshot we always have to canonicalize the object.
-  if (kind == Snapshot::kFull) {
-    // Set the object tags.
-    obj.set_tags(tags);
-  } else if (RawObject::IsCanonical(tags) &&
-             (RawObject::IsCreatedFromSnapshot(tags) ||
-              (kind == Snapshot::kMessage))) {
-    obj ^= obj.CheckAndCanonicalize(NULL);
-    ASSERT(!obj.IsNull());
-    ASSERT(obj.IsCanonical() &&
-           (kind == Snapshot::kMessage ||
-            RawObject::IsCreatedFromSnapshot(obj.raw()->ptr()->tags_)));
-  } else {
-    // Set the object tags.
-    obj.set_tags(tags);
+  // When reading a script snapshot or a message snapshot we always have
+  // to canonicalize the object.
+  if (RawObject::IsCanonical(tags)) {
+    if (kind == Snapshot::kFull) {
+      // Set the canonical bit.
+      obj.SetCanonical();
+    } else {
+      obj ^= obj.CheckAndCanonicalize(NULL);
+      ASSERT(!obj.IsNull());
+      ASSERT(obj.IsCanonical());
+    }
   }
   return obj.raw();
 }
@@ -1965,23 +1857,20 @@
   Double& dbl = Double::ZoneHandle(reader->zone(), Double::null());
   if (kind == Snapshot::kFull) {
     dbl = reader->NewDouble(value);
-    // Set the object tags.
-    dbl.set_tags(tags);
+    // Set the canonical bit.
+    if (RawObject::IsCanonical(tags)) {
+      dbl.SetCanonical();
+    }
   } else {
     // When reading a script snapshot we need to canonicalize only those object
     // references that are objects from the core library (loaded from a
     // full snapshot). Objects that are only in the script need not be
     // canonicalized as they are already canonical.
-    if (RawObject::IsCanonical(tags) &&
-        RawObject::IsCreatedFromSnapshot(tags)) {
+    if (RawObject::IsCanonical(tags)) {
       dbl = Double::NewCanonical(value);
-      ASSERT(dbl.IsCanonical() &&
-             (kind == Snapshot::kMessage ||
-              RawObject::IsCreatedFromSnapshot(dbl.raw()->ptr()->tags_)));
+      ASSERT(dbl.IsCanonical());
     } else {
       dbl = Double::New(value, HEAP_SPACE(kind));
-      // Set the object tags.
-      dbl.set_tags(tags);
     }
   }
   reader->AddBackRef(object_id, &dbl, kIsDeserialized);
@@ -2041,7 +1930,6 @@
   } else {
     // Set up the string object.
     *str_obj = StringType::New(len, HEAP_SPACE(kind));
-    str_obj->set_tags(tags);
     str_obj->SetHash(0);  // Will get computed when needed.
     if (len == 0) {
       return;
@@ -2072,7 +1960,9 @@
     ASSERT(Thread::Current()->no_safepoint_scope_depth() != 0);
     RawOneByteString* obj = reader->NewOneByteString(len);
     str_obj = obj;
-    str_obj.set_tags(tags);
+    if (RawObject::IsCanonical(tags)) {
+      str_obj.SetCanonical();
+    }
     str_obj.SetHash(hash);
     if (len > 0) {
       uint8_t* raw_ptr = CharAddr(str_obj, 0);
@@ -2101,7 +1991,9 @@
   if (kind == Snapshot::kFull) {
     RawTwoByteString* obj = reader->NewTwoByteString(len);
     str_obj = obj;
-    str_obj.set_tags(tags);
+    if (RawObject::IsCanonical(tags)) {
+      str_obj.SetCanonical();
+    }
     str_obj.SetHash(hash);
     NoSafepointScope no_safepoint;
     uint16_t* raw_ptr = (len > 0)? CharAddr(str_obj, 0) : NULL;
@@ -2290,7 +2182,11 @@
   }
   reader->ArrayReadFrom(object_id, *array, len, tags);
   if (RawObject::IsCanonical(tags)) {
-    *array ^= array->CheckAndCanonicalize(NULL);
+    if (kind == Snapshot::kFull) {
+      array->SetCanonical();
+    } else {
+      *array ^= array->CheckAndCanonicalize(NULL);
+    }
   }
   return raw(*array);
 }
@@ -2396,8 +2292,6 @@
     map = LinkedHashMap::NewUninitialized(HEAP_SPACE(kind));
   }
   reader->AddBackRef(object_id, &map, kIsDeserialized);
-  // Set the object tags.
-  map.set_tags(tags);
 
   // Read the type arguments.
   const intptr_t typeargs_offset =
@@ -2509,8 +2403,6 @@
     simd = Float32x4::New(value0, value1, value2, value3, HEAP_SPACE(kind));
   }
   reader->AddBackRef(object_id, &simd, kIsDeserialized);
-  // Set the object tags.
-  simd.set_tags(tags);
   return simd.raw();
 }
 
@@ -2555,8 +2447,6 @@
     simd = Int32x4::New(value0, value1, value2, value3, HEAP_SPACE(kind));
   }
   reader->AddBackRef(object_id, &simd, kIsDeserialized);
-  // Set the object tags.
-  simd.set_tags(tags);
   return simd.raw();
 }
 
@@ -2599,8 +2489,6 @@
     simd = Float64x2::New(value0, value1, HEAP_SPACE(kind));
   }
   reader->AddBackRef(object_id, &simd, kIsDeserialized);
-  // Set the object tags.
-  simd.set_tags(tags);
   return simd.raw();
 }
 
@@ -2642,9 +2530,6 @@
                                 : TypedData::New(cid, len, HEAP_SPACE(kind)));
   reader->AddBackRef(object_id, &result, kIsDeserialized);
 
-  // Set the object tags.
-  result.set_tags(tags);
-
   // Setup the array elements.
   intptr_t element_size = ElementSizeInBytes(cid);
   intptr_t length_in_bytes = len * element_size;
@@ -2993,9 +2878,6 @@
       reader->zone(), JSRegExp::New(HEAP_SPACE(kind)));
   reader->AddBackRef(object_id, &regex, kIsDeserialized);
 
-  // Set the object tags.
-  regex.set_tags(tags);
-
   // Read and Set all the other fields.
   regex.StoreSmi(&regex.raw_ptr()->num_bracket_expressions_,
                  reader->ReadAsSmi());
@@ -3043,9 +2925,6 @@
       reader->zone(), WeakProperty::New(HEAP_SPACE(kind)));
   reader->AddBackRef(object_id, &weak_property, kIsDeserialized);
 
-  // Set the object tags.
-  weak_property.set_tags(tags);
-
   // Set all the object fields.
   // TODO(5411462): Need to assert No GC can happen here, even though
   // allocations may happen.
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index b08e704..907e805 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -325,6 +325,11 @@
 }
 
 
+bool SnapshotReader::is_vm_isolate() const {
+  return isolate_ == Dart::vm_isolate();
+}
+
+
 RawObject* SnapshotReader::ReadObjectImpl(bool as_reference,
                                           intptr_t patch_object_id,
                                           intptr_t patch_offset) {
@@ -463,9 +468,6 @@
 #undef SNAPSHOT_READ
     default: UNREACHABLE(); break;
   }
-  if (kind_ == Snapshot::kFull) {
-    pobj_.SetCreatedFromSnapshot();
-  }
   return pobj_.raw();
 }
 
@@ -536,10 +538,14 @@
         result->SetFieldAtOffset(offset, Object::null_object());
         offset += kWordSize;
       }
-      result->SetCreatedFromSnapshot();
-    } else if (RawObject::IsCanonical(tags)) {
-      *result = result->CheckAndCanonicalize(NULL);
-      ASSERT(!result->IsNull());
+    }
+    if (RawObject::IsCanonical(tags)) {
+      if (kind_ == Snapshot::kFull) {
+        result->SetCanonical();
+      } else {
+        *result = result->CheckAndCanonicalize(NULL);
+        ASSERT(!result->IsNull());
+      }
     }
     return result->raw();
   } else if (header_id == kStaticImplicitClosureObjectId) {
@@ -578,9 +584,6 @@
 #undef SNAPSHOT_READ
     default: UNREACHABLE(); break;
   }
-  if (kind_ == Snapshot::kFull) {
-    pobj_.SetCreatedFromSnapshot();
-  }
   AddPatchRecord(object_id, patch_object_id, patch_offset);
   return pobj_.raw();
 }
@@ -1071,6 +1074,7 @@
   ASSERT(class_id != kIllegalCid);
   tags = RawObject::ClassIdTag::update(class_id, tags);
   tags = RawObject::SizeTag::update(size, tags);
+  tags = RawObject::VMHeapObjectTag::update(is_vm_isolate(), tags);
   raw_obj->ptr()->tags_ = tags;
   return raw_obj;
 }
@@ -1209,9 +1213,6 @@
                                    const Array& result,
                                    intptr_t len,
                                    intptr_t tags) {
-  // Set the object tags.
-  result.set_tags(tags);
-
   // Setup the object fields.
   const intptr_t typeargs_offset =
       GrowableObjectArray::type_arguments_offset() / kWordSize;
@@ -2053,11 +2054,6 @@
   ASSERT(kind_ != Snapshot::kFull);
   int class_id = cls->ptr()->id_;
   ASSERT(!IsSingletonClassId(class_id) && !IsObjectStoreClassId(class_id));
-  // TODO(5411462): Should restrict this to only core-lib classes in this
-  // case.
-  // Write out the class and tags information.
-  WriteVMIsolateObject(kClassCid);
-  WriteTags(GetObjectTags(cls));
 
   // Write out the library url and class name.
   RawLibrary* library = cls->ptr()->library_;
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 161da59..4b3a278 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -450,6 +450,8 @@
 
   RawObject* VmIsolateSnapshotObject(intptr_t index) const;
 
+  bool is_vm_isolate() const;
+
   Snapshot::Kind kind_;  // Indicates type of snapshot(full, script, message).
   Isolate* isolate_;  // Current isolate.
   Zone* zone_;  // Zone for allocations while reading snapshot.
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 41355d7..035100e 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -18,9 +18,6 @@
 ping_pause_test: Skip     # Resolve test issues
 kill3_test: Pass, Fail    # Bad test: expects total message order
 
-message3_test/constList_identical: RuntimeError # Issue 21816
-message3_test/constMap: RuntimeError  # Issue 21816
-message3_test/constInstance: RuntimeError # Issue 21816
 message3_test/byteBuffer: Crash # Issue 21818
 message3_test/int32x4: Crash # Issue 21818
 
diff --git a/tests/isolate/message3_test.dart b/tests/isolate/message3_test.dart
index c07a7e6..4267cee 100644
--- a/tests/isolate/message3_test.dart
+++ b/tests/isolate/message3_test.dart
@@ -394,7 +394,7 @@
     Expect.equals("field", f.field);
     Expect.isFalse(identical(nonConstF, f));
   });
-  checks.add((x) {  // g1.
+  checks.add((x) {  // g2.
     Expect.isTrue(x is G);
     Expect.isFalse(identical(g1, x));
     F f = x.field;
@@ -403,7 +403,7 @@
   });
   checks.add((x) {  // g3.
     Expect.isTrue(x is G);
-    Expect.identical(g1, x);  /// constInstance: continued
+    Expect.identical(g3, x);  /// constInstance: continued
     F f = x.field;
     Expect.equals("field", f.field);
     Expect.identical(constF, f);  /// constInstance: continued