// Copyright (c) 2012, 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. #include "vm/message.h" #include "vm/native_entry.h" #include "vm/object.h" #include "vm/object_store.h" #include "vm/snapshot.h" #include "vm/stub_code.h" #include "vm/symbols.h" #include "vm/type_testing_stubs.h" #include "vm/visitor.h" namespace dart { #define OFFSET_OF_FROM(obj) \ obj.raw()->from() - reinterpret_cast(obj.raw()->ptr()) // TODO(18854): Need to assert No GC can happen here, even though // allocations may happen. #define READ_OBJECT_FIELDS(object, from, to, as_reference) \ intptr_t num_flds = (to) - (from); \ intptr_t from_offset = OFFSET_OF_FROM(object); \ for (intptr_t i = 0; i <= num_flds; i++) { \ (*reader->PassiveObjectHandle()) = \ reader->ReadObjectImpl(as_reference, object_id, (i + from_offset)); \ object.StorePointer(((from) + i), reader->PassiveObjectHandle()->raw()); \ } RawClass* Class::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); Class& cls = Class::ZoneHandle(reader->zone(), Class::null()); bool is_in_fullsnapshot = reader->Read(); if ((kind == Snapshot::kScript) && !is_in_fullsnapshot) { // Read in the base information. classid_t class_id = reader->ReadClassIDValue(); // Allocate class object of specified kind. if (class_id < kNumPredefinedCids) { ASSERT((class_id >= kInstanceCid) && (class_id <= kMirrorReferenceCid)); cls = reader->isolate()->class_table()->At(class_id); } else { cls = Class::NewInstanceClass(); } reader->AddBackRef(object_id, &cls, kIsDeserialized); // Set all non object fields. if (!RawObject::IsInternalVMdefinedClassId(class_id)) { // Instance size of a VM defined class is already set up. cls.set_instance_size_in_words(reader->Read()); cls.set_next_field_offset_in_words(reader->Read()); } cls.set_type_arguments_field_offset_in_words(reader->Read()); cls.set_num_type_arguments(reader->Read()); cls.set_num_own_type_arguments(reader->Read()); cls.set_num_native_fields(reader->Read()); cls.set_token_pos(TokenPosition::SnapshotDecode(reader->Read())); cls.set_state_bits(reader->Read()); #if !defined(DART_PRECOMPILED_RUNTIME) cls.set_kernel_offset(reader->Read()); #endif // Set all the object fields. READ_OBJECT_FIELDS(cls, cls.raw()->from(), cls.raw()->to_snapshot(kind), kAsReference); cls.StorePointer(&cls.raw_ptr()->dependent_code_, Array::null()); ASSERT(!cls.IsInFullSnapshot()); // Also sets instance size in class table. reader->isolate()->class_table()->SetAt(cls.id(), cls.raw()); } else { cls ^= reader->ReadClassId(object_id); ASSERT((kind == Snapshot::kMessage) || cls.IsInFullSnapshot()); } return cls.raw(); } void RawClass::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); bool is_in_fullsnapshot = Class::IsInFullSnapshot(this); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // 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(is_in_fullsnapshot); if ((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_; ASSERT(class_id != kIllegalCid); writer->Write(class_id); if (!RawObject::IsInternalVMdefinedClassId(class_id)) { // We don't write the instance size of VM defined classes as they // are already setup during initialization as part of pre populating // the class table. writer->Write(ptr()->instance_size_in_words_); writer->Write(ptr()->next_field_offset_in_words_); } writer->Write(ptr()->type_arguments_field_offset_in_words_); writer->Write(ptr()->num_type_arguments_); writer->Write(ptr()->num_own_type_arguments_); writer->Write(ptr()->num_native_fields_); writer->Write(ptr()->token_pos_.SnapshotEncode()); writer->Write(ptr()->state_bits_); #if !defined(DART_PRECOMPILED_RUNTIME) writer->Write(ptr()->kernel_offset_); #endif // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to_snapshot(kind)); } else { if (writer->can_send_any_object() || writer->AllowObjectsInDartLibrary(ptr()->library_)) { writer->WriteClassId(this); } else { // We do not allow regular dart instances in isolate messages. writer->SetWriteException(Exceptions::kArgument, "Illegal argument in isolate message" " : (object is a regular Dart Instance)"); } } } RawUnresolvedClass* UnresolvedClass::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Allocate unresolved class object. UnresolvedClass& unresolved_class = UnresolvedClass::ZoneHandle(reader->zone(), UnresolvedClass::New()); reader->AddBackRef(object_id, &unresolved_class, kIsDeserialized); // Set all non object fields. unresolved_class.set_token_pos( TokenPosition::SnapshotDecode(reader->Read())); // Set all the object fields. READ_OBJECT_FIELDS(unresolved_class, unresolved_class.raw()->from(), unresolved_class.raw()->to(), kAsReference); return unresolved_class.raw(); } void RawUnresolvedClass::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kUnresolvedClassCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the non object pointer fields. writer->Write(ptr()->token_pos_.SnapshotEncode()); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); } RawAbstractType* AbstractType::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); // AbstractType is an abstract class. return NULL; } void RawAbstractType::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); // AbstractType is an abstract class. } RawType* Type::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Determine if the type class of this type is in the full snapshot. bool typeclass_is_in_fullsnapshot = reader->Read(); // Allocate type object. Type& type = Type::ZoneHandle(reader->zone(), Type::New()); bool is_canonical = RawObject::IsCanonical(tags); bool defer_canonicalization = is_canonical && ((kind == Snapshot::kMessage) || (!Snapshot::IsFull(kind) && typeclass_is_in_fullsnapshot)); reader->AddBackRef(object_id, &type, kIsDeserialized, defer_canonicalization); // Set all non object fields. type.set_token_pos(TokenPosition::SnapshotDecode(reader->Read())); type.set_type_state(reader->Read()); // Read the code object for the type testing stub and set its entrypoint. reader->EnqueueTypePostprocessing(type); // Set all the object fields. READ_OBJECT_FIELDS(type, type.raw()->from(), type.raw()->to(), kAsReference); // Read in the type class. (*reader->ClassHandle()) = Class::RawCast(reader->ReadObjectImpl(kAsReference)); type.set_type_class(*reader->ClassHandle()); // Set the canonical bit. if (!defer_canonicalization && is_canonical) { type.SetCanonical(); } // Fill in the type testing stub. Instructions& instr = *reader->InstructionsHandle(); instr = TypeTestingStubGenerator::DefaultCodeForType(type); type.SetTypeTestingStub(instr); return type.raw(); } void RawType::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // 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_id_ != Object::null()); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kTypeCid); writer->WriteTags(writer->GetObjectTags(this)); if (ptr()->type_class_id_->IsHeapObject()) { // Type class is still an unresolved class. UNREACHABLE(); } // Lookup the type class. RawSmi* raw_type_class_id = Smi::RawCast(ptr()->type_class_id_); RawClass* type_class = writer->isolate()->class_table()->At(Smi::Value(raw_type_class_id)); // Write out typeclass_is_in_fullsnapshot first as this will // help the reader decide on how to canonicalize the type object. intptr_t tags = writer->GetObjectTags(type_class); bool typeclass_is_in_fullsnapshot = (ClassIdTag::decode(tags) == kClassCid) && Class::IsInFullSnapshot(reinterpret_cast(type_class)); writer->Write(typeclass_is_in_fullsnapshot); // Write out all the non object pointer fields. writer->Write(ptr()->token_pos_.SnapshotEncode()); writer->Write(ptr()->type_state_); // Write out all the object pointer fields. ASSERT(ptr()->type_class_id_ != Object::null()); SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); // Write out the type class. writer->WriteObjectImpl(type_class, kAsReference); } RawTypeRef* TypeRef::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Allocate type ref object. TypeRef& type_ref = TypeRef::ZoneHandle(reader->zone(), TypeRef::New()); reader->AddBackRef(object_id, &type_ref, kIsDeserialized); // Read the code object for the type testing stub and set its entrypoint. reader->EnqueueTypePostprocessing(type_ref); // Set all the object fields. READ_OBJECT_FIELDS(type_ref, type_ref.raw()->from(), type_ref.raw()->to(), kAsReference); // Fill in the type testing stub. Instructions& instr = *reader->InstructionsHandle(); instr = TypeTestingStubGenerator::DefaultCodeForType(type_ref); type_ref.SetTypeTestingStub(instr); return type_ref.raw(); } void RawTypeRef::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kTypeRefCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); } RawTypeParameter* TypeParameter::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Allocate type parameter object. TypeParameter& type_parameter = TypeParameter::ZoneHandle(reader->zone(), TypeParameter::New()); reader->AddBackRef(object_id, &type_parameter, kIsDeserialized); // Set all non object fields. type_parameter.set_token_pos( TokenPosition::SnapshotDecode(reader->Read())); type_parameter.set_index(reader->Read()); type_parameter.set_type_state(reader->Read()); // Read the code object for the type testing stub and set its entrypoint. reader->EnqueueTypePostprocessing(type_parameter); // Set all the object fields. READ_OBJECT_FIELDS(type_parameter, type_parameter.raw()->from(), type_parameter.raw()->to(), kAsReference); // Read in the parameterized class. (*reader->ClassHandle()) = Class::RawCast(reader->ReadObjectImpl(kAsReference)); type_parameter.set_parameterized_class(*reader->ClassHandle()); // Fill in the type testing stub. Instructions& instr = *reader->InstructionsHandle(); instr = TypeTestingStubGenerator::DefaultCodeForType(type_parameter); type_parameter.SetTypeTestingStub(instr); return type_parameter.raw(); } void RawTypeParameter::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Only finalized type parameters should be written to a snapshot. ASSERT(ptr()->type_state_ == RawTypeParameter::kFinalizedUninstantiated); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kTypeParameterCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the non object pointer fields. writer->Write(ptr()->token_pos_.SnapshotEncode()); writer->Write(ptr()->index_); writer->Write(ptr()->type_state_); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); // Write out the parameterized class. RawClass* param_class = writer->isolate()->class_table()->At(ptr()->parameterized_class_id_); writer->WriteObjectImpl(param_class, kAsReference); } RawBoundedType* BoundedType::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Allocate bounded type object. BoundedType& bounded_type = BoundedType::ZoneHandle(reader->zone(), BoundedType::New()); reader->AddBackRef(object_id, &bounded_type, kIsDeserialized); // Read the code object for the type testing stub and set its entrypoint. reader->EnqueueTypePostprocessing(bounded_type); // Set all the object fields. READ_OBJECT_FIELDS(bounded_type, bounded_type.raw()->from(), bounded_type.raw()->to(), kAsReference); return bounded_type.raw(); } void RawBoundedType::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kBoundedTypeCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); } RawMixinAppType* MixinAppType::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); // MixinAppType objects do not survive finalization. return MixinAppType::null(); } void RawMixinAppType::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); // MixinAppType objects do not survive finalization. } RawTypeArguments* TypeArguments::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Read the length so that we can determine instance size to allocate. intptr_t len = reader->ReadSmiValue(); TypeArguments& type_arguments = TypeArguments::ZoneHandle( reader->zone(), TypeArguments::New(len, HEAP_SPACE(kind))); bool is_canonical = RawObject::IsCanonical(tags); bool defer_canonicalization = is_canonical && (!Snapshot::IsFull(kind)); reader->AddBackRef(object_id, &type_arguments, kIsDeserialized, defer_canonicalization); // Set the instantiations field, which is only read from a full snapshot. type_arguments.set_instantiations(Object::zero_array()); // Now set all the type fields. intptr_t offset = type_arguments.TypeAddr(0) - reinterpret_cast(type_arguments.raw()->ptr()); for (intptr_t i = 0; i < len; i++) { *reader->TypeHandle() ^= reader->ReadObjectImpl(kAsReference, object_id, (i + offset)); type_arguments.SetTypeAt(i, *reader->TypeHandle()); } // Set the canonical bit. if (!defer_canonicalization && is_canonical) { type_arguments.SetCanonical(); } return type_arguments.raw(); } void RawTypeArguments::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kTypeArgumentsCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out the length field. writer->Write(ptr()->length_); // Write out the individual types. intptr_t len = Smi::Value(ptr()->length_); for (intptr_t i = 0; i < len; i++) { // The Dart VM reuses type argument lists across instances in order // to reduce memory footprint, this can sometimes lead to a type from // such a shared type argument list being sent over to another isolate. // In such scenarios where it is not appropriate to send the types // across (isolates spawned using spawnURI) we send them as dynamic. if (!writer->can_send_any_object()) { // Lookup the type class. RawType* raw_type = Type::RawCast(ptr()->types()[i]); RawSmi* raw_type_class_id = Smi::RawCast(raw_type->ptr()->type_class_id_); RawClass* type_class = writer->isolate()->class_table()->At(Smi::Value(raw_type_class_id)); if (!writer->AllowObjectsInDartLibrary(type_class->ptr()->library_)) { writer->WriteVMIsolateObject(kDynamicType); } else { writer->WriteObjectImpl(ptr()->types()[i], kAsReference); } } else { writer->WriteObjectImpl(ptr()->types()[i], kAsReference); } } } RawPatchClass* PatchClass::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind == Snapshot::kScript); // Allocate function object. PatchClass& cls = PatchClass::ZoneHandle(reader->zone(), PatchClass::New()); reader->AddBackRef(object_id, &cls, kIsDeserialized); #if !defined(DART_PRECOMPILED_RUNTIME) cls.set_library_kernel_offset(reader->Read()); #endif // Set all the object fields. READ_OBJECT_FIELDS(cls, cls.raw()->from(), cls.raw()->to_snapshot(kind), kAsReference); return cls.raw(); } void RawPatchClass::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(kind == Snapshot::kScript); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kPatchClassCid); writer->WriteTags(writer->GetObjectTags(this)); #if !defined(DART_PRECOMPILED_RUNTIME) writer->Write(ptr()->library_kernel_offset_); #endif // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to_snapshot(kind)); } RawClosure* Closure::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return Closure::null(); } void RawClosure::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT((kind == Snapshot::kMessage) || (kind == Snapshot::kScript)); // Check if closure is serializable, throw an exception otherwise. RawFunction* func = writer->IsSerializableClosure(this); if (func != Function::null()) { writer->WriteStaticImplicitClosure(object_id, func, writer->GetObjectTags(this)); return; } UNREACHABLE(); } RawClosureData* ClosureData::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind == Snapshot::kScript); // Allocate closure data object. ClosureData& data = ClosureData::ZoneHandle(reader->zone(), ClosureData::New()); reader->AddBackRef(object_id, &data, kIsDeserialized); // Set all the object fields. READ_OBJECT_FIELDS(data, data.raw()->from(), data.raw()->to(), kAsInlinedObject); return data.raw(); } void RawClosureData::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(kind == Snapshot::kScript); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kClosureDataCid); writer->WriteTags(writer->GetObjectTags(this)); // Context scope. if (ptr()->context_scope_ == Object::empty_context_scope().raw()) { writer->WriteVMIsolateObject(kEmptyContextScopeObject); } else if (ptr()->context_scope_->ptr()->is_implicit_) { writer->WriteObjectImpl(ptr()->context_scope_, kAsInlinedObject); } else { // We don't write non implicit context scopes in the snapshot. writer->WriteVMIsolateObject(kNullObject); } // Parent function. writer->WriteObjectImpl(ptr()->parent_function_, kAsInlinedObject); // Signature type. writer->WriteObjectImpl(ptr()->signature_type_, kAsInlinedObject); // Canonical static closure. writer->WriteObjectImpl(ptr()->closure_, kAsInlinedObject); } RawSignatureData* SignatureData::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind == Snapshot::kScript); // Allocate signature data object. SignatureData& data = SignatureData::ZoneHandle(reader->zone(), SignatureData::New()); reader->AddBackRef(object_id, &data, kIsDeserialized); // Set all the object fields. READ_OBJECT_FIELDS(data, data.raw()->from(), data.raw()->to(), kAsInlinedObject); return data.raw(); } void RawSignatureData::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(kind == Snapshot::kScript); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kSignatureDataCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsInlinedObject); visitor.VisitPointers(from(), to()); } RawRedirectionData* RedirectionData::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind == Snapshot::kScript); // Allocate redirection data object. RedirectionData& data = RedirectionData::ZoneHandle(reader->zone(), RedirectionData::New()); reader->AddBackRef(object_id, &data, kIsDeserialized); // Set all the object fields. READ_OBJECT_FIELDS(data, data.raw()->from(), data.raw()->to(), kAsReference); return data.raw(); } void RawRedirectionData::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(kind == Snapshot::kScript); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kRedirectionDataCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); } RawFunction* Function::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind == Snapshot::kScript); bool is_in_fullsnapshot = reader->Read(); if (!is_in_fullsnapshot) { // Allocate function object. Function& func = Function::ZoneHandle(reader->zone(), Function::New()); reader->AddBackRef(object_id, &func, kIsDeserialized); // Set all the non object fields. Read the token positions now but // don't set them until after setting the kind. const int32_t token_pos = reader->Read(); const int32_t end_token_pos = reader->Read(); int32_t kernel_offset = 0; #if !defined(DART_PRECOMPILED_RUNTIME) kernel_offset = reader->Read(); #endif func.set_packed_fields(reader->Read()); func.set_kind_tag(reader->Read()); func.set_token_pos(TokenPosition::SnapshotDecode(token_pos)); func.set_end_token_pos(TokenPosition::SnapshotDecode(end_token_pos)); func.set_kernel_offset(kernel_offset); func.set_usage_counter(reader->Read()); func.set_deoptimization_counter(reader->Read()); func.set_optimized_instruction_count(reader->Read()); func.set_optimized_call_site_count(reader->Read()); func.set_state_bits(0); // Set all the object fields. READ_OBJECT_FIELDS(func, func.raw()->from(), func.raw()->to_snapshot(kind), kAsReference); // Initialize all fields that are not part of the snapshot. bool is_optimized = func.usage_counter() != 0; if (is_optimized) { // Read the ic data array as the function is an optimized one. (*reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsReference); func.set_ic_data_array(*reader->ArrayHandle()); } else { func.ClearICDataArray(); } func.ClearCode(); return func.raw(); } else { return reader->ReadFunctionId(object_id); } } void RawFunction::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(kind == Snapshot::kScript); bool is_in_fullsnapshot = false; bool owner_is_class = false; if ((kind == Snapshot::kScript) && !Function::IsSignatureFunction(this)) { intptr_t tags = writer->GetObjectTags(ptr()->owner_); intptr_t cid = ClassIdTag::decode(tags); owner_is_class = (cid == kClassCid); is_in_fullsnapshot = owner_is_class ? Class::IsInFullSnapshot( reinterpret_cast(ptr()->owner_)) : PatchClass::IsInFullSnapshot( reinterpret_cast(ptr()->owner_)); } // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kFunctionCid); 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(is_in_fullsnapshot); if (!is_in_fullsnapshot) { bool is_optimized = Code::IsOptimized(ptr()->code_); // Write out all the non object fields. #if !defined(DART_PRECOMPILED_RUNTIME) writer->Write(ptr()->token_pos_.SnapshotEncode()); writer->Write(ptr()->end_token_pos_.SnapshotEncode()); writer->Write(ptr()->kernel_offset_); #endif writer->Write(ptr()->packed_fields_); writer->Write(ptr()->kind_tag_); #if !defined(DART_PRECOMPILED_RUNTIME) if (is_optimized) { writer->Write(FLAG_optimization_counter_threshold); } else { writer->Write(0); } writer->Write(ptr()->deoptimization_counter_); writer->Write(ptr()->optimized_instruction_count_); writer->Write(ptr()->optimized_call_site_count_); #endif // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to_snapshot(kind)); if (is_optimized) { // Write out the ic data array as the function is optimized. writer->WriteObjectImpl(ptr()->ic_data_array_, kAsReference); } } else { writer->WriteFunctionId(this, owner_is_class); } } RawField* Field::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind == Snapshot::kScript); // Allocate field object. Field& field = Field::ZoneHandle(reader->zone(), Field::New()); reader->AddBackRef(object_id, &field, kIsDeserialized); // Set all non object fields. field.set_token_pos(TokenPosition::SnapshotDecode(reader->Read())); field.set_end_token_pos( TokenPosition::SnapshotDecode(reader->Read())); field.set_guarded_cid(reader->Read()); field.set_is_nullable(reader->Read()); #if !defined(DART_PRECOMPILED_RUNTIME) field.set_kernel_offset(reader->Read()); #endif field.set_kind_bits(reader->Read()); // Set all the object fields. READ_OBJECT_FIELDS(field, field.raw()->from(), field.raw()->to_snapshot(kind), kAsReference); field.StorePointer(&field.raw_ptr()->dependent_code_, Array::null()); if (!reader->isolate()->use_field_guards()) { field.set_guarded_cid(kDynamicCid); field.set_is_nullable(true); field.set_guarded_list_length(Field::kNoFixedLength); field.set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset); } else { field.InitializeGuardedListLengthInObjectOffset(); } return field.raw(); } void RawField::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(kind == Snapshot::kScript); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kFieldCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the non object fields. writer->Write(ptr()->token_pos_.SnapshotEncode()); writer->Write(ptr()->end_token_pos_.SnapshotEncode()); writer->Write(ptr()->guarded_cid_); writer->Write(ptr()->is_nullable_); #if !defined(DART_PRECOMPILED_RUNTIME) writer->Write(ptr()->kernel_offset_); #endif writer->Write(ptr()->kind_bits_); // Write out the name. writer->WriteObjectImpl(ptr()->name_, kAsReference); // Write out the owner. writer->WriteObjectImpl(ptr()->owner_, kAsReference); // Write out the type. writer->WriteObjectImpl(ptr()->type_, kAsReference); // Write out the initial static value or field offset. if (Field::StaticBit::decode(ptr()->kind_bits_)) { if (Field::ConstBit::decode(ptr()->kind_bits_)) { // Do not reset const fields. writer->WriteObjectImpl(ptr()->value_.static_value_, kAsReference); } else { // Otherwise, for static fields we write out the initial static value. writer->WriteObjectImpl(ptr()->initializer_.saved_value_, kAsReference); } } else { writer->WriteObjectImpl(ptr()->value_.offset_, kAsReference); } // Write out the initializer function or saved initial value. writer->WriteObjectImpl(ptr()->initializer_.saved_value_, kAsReference); // Write out the guarded list length. writer->WriteObjectImpl(ptr()->guarded_list_length_, kAsReference); } RawLiteralToken* LiteralToken::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind != Snapshot::kMessage); // Create the literal token object. LiteralToken& literal_token = LiteralToken::ZoneHandle(reader->zone(), LiteralToken::New()); reader->AddBackRef(object_id, &literal_token, kIsDeserialized); // Read the token attributes. Token::Kind token_kind = static_cast(reader->Read()); literal_token.set_kind(token_kind); // Set all the object fields. READ_OBJECT_FIELDS(literal_token, literal_token.raw()->from(), literal_token.raw()->to(), kAsReference); return literal_token.raw(); } void RawLiteralToken::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(kind != Snapshot::kMessage); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kLiteralTokenCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out the kind field. writer->Write(ptr()->kind_); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); } RawTokenStream* TokenStream::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind == Snapshot::kScript); // Read the length so that we can determine number of tokens to read. intptr_t len = reader->ReadSmiValue(); // Create the token stream object. TokenStream& token_stream = TokenStream::ZoneHandle(reader->zone(), TokenStream::New(len)); reader->AddBackRef(object_id, &token_stream, kIsDeserialized); // Read the stream of tokens into the TokenStream object for script // snapshots as we made a copy of token stream. if (kind == Snapshot::kScript) { NoSafepointScope no_safepoint; RawExternalTypedData* stream = token_stream.GetStream(); reader->ReadBytes(stream->ptr()->data_, len); } // Read in the literal/identifier token array. *(reader->TokensHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject); token_stream.SetTokenObjects(*(reader->TokensHandle())); // Read in the private key in use by the token stream. *(reader->StringHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject); token_stream.SetPrivateKey(*(reader->StringHandle())); return token_stream.raw(); } void RawTokenStream::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(kind == Snapshot::kScript); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kTokenStreamCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out the length field and the token stream. RawExternalTypedData* stream = ptr()->stream_; intptr_t len = Smi::Value(stream->ptr()->length_); writer->Write(stream->ptr()->length_); writer->WriteBytes(stream->ptr()->data_, len); // Write out the literal/identifier token array. writer->WriteObjectImpl(ptr()->token_objects_, kAsInlinedObject); // Write out the private key in use by the token stream. writer->WriteObjectImpl(ptr()->private_key_, kAsInlinedObject); } RawScript* Script::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind == Snapshot::kScript); // Allocate script object. Script& script = Script::ZoneHandle(reader->zone(), Script::New()); reader->AddBackRef(object_id, &script, kIsDeserialized); script.StoreNonPointer(&script.raw_ptr()->line_offset_, reader->Read()); script.StoreNonPointer(&script.raw_ptr()->col_offset_, reader->Read()); script.StoreNonPointer(&script.raw_ptr()->kind_, reader->Read()); script.StoreNonPointer(&script.raw_ptr()->kernel_script_index_, reader->Read()); script.StoreNonPointer(&script.raw_ptr()->load_timestamp_, 0); *reader->StringHandle() ^= String::null(); script.set_source(*reader->StringHandle()); *reader->StreamHandle() ^= TokenStream::null(); script.set_tokens(*reader->StreamHandle()); // Set all the object fields. // TODO(5411462): Need to assert No GC can happen here, even though // allocations may happen. intptr_t num_flds = (script.raw()->to_snapshot(kind) - script.raw()->from()); for (intptr_t i = 0; i <= num_flds; i++) { (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference); script.StorePointer((script.raw()->from() + i), reader->PassiveObjectHandle()->raw()); } return script.raw(); } void RawScript::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(tokens_ != TokenStream::null()); ASSERT(kind == Snapshot::kScript); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kScriptCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the non object fields. writer->Write(ptr()->line_offset_); writer->Write(ptr()->col_offset_); writer->Write(ptr()->kind_); writer->Write(ptr()->kernel_script_index_); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to_snapshot(kind)); } RawLibrary* Library::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind != Snapshot::kMessage); Library& library = Library::ZoneHandle(reader->zone(), Library::null()); reader->AddBackRef(object_id, &library, kIsDeserialized); bool is_in_fullsnapshot = reader->Read(); 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->thread(), *reader->StringHandle()); ASSERT(library.is_in_fullsnapshot()); } else { // Allocate library object. library = Library::New(); // Set all non object fields. library.StoreNonPointer(&library.raw_ptr()->index_, reader->ReadClassIDValue()); library.StoreNonPointer(&library.raw_ptr()->num_imports_, reader->Read()); library.StoreNonPointer(&library.raw_ptr()->load_state_, reader->Read()); library.StoreNonPointer(&library.raw_ptr()->corelib_imported_, reader->Read()); library.StoreNonPointer(&library.raw_ptr()->is_dart_scheme_, reader->Read()); library.StoreNonPointer(&library.raw_ptr()->debuggable_, reader->Read()); #if !defined(DART_PRECOMPILED_RUNTIME) library.StoreNonPointer(&library.raw_ptr()->kernel_offset_, reader->Read()); #endif 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); // Set all the object fields. // TODO(5411462): Need to assert No GC can happen here, even though // allocations may happen. intptr_t num_flds = library.raw()->to_snapshot(kind) - library.raw()->from(); for (intptr_t i = 0; i <= num_flds; i++) { (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference); library.StorePointer((library.raw()->from() + i), reader->PassiveObjectHandle()->raw()); } // Initialize caches that are not serialized. library.StorePointer(&library.raw_ptr()->resolved_names_, Array::null()); library.StorePointer(&library.raw_ptr()->exported_names_, Array::null()); library.StorePointer(&library.raw_ptr()->loaded_scripts_, Array::null()); library.Register(reader->thread()); } return library.raw(); } void RawLibrary::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(kind != Snapshot::kMessage); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kLibraryCid); 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(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(!ptr()->is_in_fullsnapshot_); // Write out all non object fields. ASSERT(ptr()->index_ != static_cast(-1)); writer->WriteClassIDValue(ptr()->index_); writer->Write(ptr()->num_imports_); writer->Write(ptr()->load_state_); writer->Write(ptr()->corelib_imported_); writer->Write(ptr()->is_dart_scheme_); writer->Write(ptr()->debuggable_); #if !defined(DART_PRECOMPILED_RUNTIME) writer->Write(ptr()->kernel_offset_); #endif // We do not serialize the native resolver or symbolizer. These need to be // explicitly set after deserialization. // We do not write the loaded_scripts_ and resolved_names_ caches to the // snapshot. They get initialized when reading the library from the // snapshot and will be rebuilt lazily. // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to_snapshot(kind)); } } RawLibraryPrefix* LibraryPrefix::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind == Snapshot::kScript); // Allocate library prefix object. LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(reader->zone(), LibraryPrefix::New()); reader->AddBackRef(object_id, &prefix, kIsDeserialized); // Set all non object fields. prefix.StoreNonPointer(&prefix.raw_ptr()->num_imports_, reader->Read()); prefix.StoreNonPointer(&prefix.raw_ptr()->is_deferred_load_, reader->Read()); prefix.StoreNonPointer(&prefix.raw_ptr()->is_loaded_, !prefix.raw_ptr()->is_deferred_load_); // Set all the object fields. READ_OBJECT_FIELDS(prefix, prefix.raw()->from(), prefix.raw()->to_snapshot(kind), kAsReference); prefix.StorePointer(&prefix.raw_ptr()->dependent_code_, Array::null()); return prefix.raw(); } void RawLibraryPrefix::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(kind == Snapshot::kScript); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kLibraryPrefixCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all non object fields. writer->Write(ptr()->num_imports_); writer->Write(ptr()->is_deferred_load_); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to_snapshot(kind)); } RawNamespace* Namespace::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind == Snapshot::kScript); // Allocate Namespace object. Namespace& ns = Namespace::ZoneHandle(reader->zone(), Namespace::New()); reader->AddBackRef(object_id, &ns, kIsDeserialized); // Set all the object fields. READ_OBJECT_FIELDS(ns, ns.raw()->from(), ns.raw()->to(), kAsReference); return ns.raw(); } void RawNamespace::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(kind == Snapshot::kScript); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kNamespaceCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); } RawKernelProgramInfo* KernelProgramInfo::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind == Snapshot::kScript); KernelProgramInfo& info = KernelProgramInfo::ZoneHandle(reader->zone(), KernelProgramInfo::New()); reader->AddBackRef(object_id, &info, kIsDeserialized); // Set all the object fields. READ_OBJECT_FIELDS(info, info.raw()->from(), info.raw()->to(), kAsReference); return info.raw(); } void RawKernelProgramInfo::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); ASSERT(kind == Snapshot::kScript); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kKernelProgramInfoCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); } RawCode* Code::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return Code::null(); } void RawCode::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawInstructions* Instructions::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return Instructions::null(); } void RawInstructions::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawObjectPool* ObjectPool::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return ObjectPool::null(); } void RawObjectPool::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawPcDescriptors* PcDescriptors::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return PcDescriptors::null(); } void RawPcDescriptors::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawCodeSourceMap* CodeSourceMap::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return CodeSourceMap::null(); } void RawCodeSourceMap::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawStackMap* StackMap::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return StackMap::null(); } void RawStackMap::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawLocalVarDescriptors* LocalVarDescriptors::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return LocalVarDescriptors::null(); } void RawLocalVarDescriptors::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawExceptionHandlers* ExceptionHandlers::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return ExceptionHandlers::null(); } void RawExceptionHandlers::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawContext* Context::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Allocate context object. int32_t num_vars = reader->Read(); Context& context = Context::ZoneHandle(reader->zone()); reader->AddBackRef(object_id, &context, kIsDeserialized); if (num_vars != 0) { context ^= Context::New(num_vars); // Set all the object fields. // TODO(5411462): Need to assert No GC can happen here, even though // allocations may happen. intptr_t num_flds = (context.raw()->to(num_vars) - context.raw()->from()); for (intptr_t i = 0; i <= num_flds; i++) { (*reader->PassiveObjectHandle()) = reader->ReadObjectImpl(kAsReference); context.StorePointer((context.raw()->from() + i), reader->PassiveObjectHandle()->raw()); } } return context.raw(); } void RawContext::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kContextCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out num of variables in the context. int32_t num_variables = ptr()->num_variables_; writer->Write(num_variables); if (num_variables != 0) { // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to(num_variables)); } } RawContextScope* ContextScope::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Allocate context object. bool is_implicit = reader->Read(); if (is_implicit) { ContextScope& context_scope = ContextScope::ZoneHandle(reader->zone()); context_scope = ContextScope::New(1, true); reader->AddBackRef(object_id, &context_scope, kIsDeserialized); *reader->TypeHandle() ^= reader->ReadObjectImpl(kAsInlinedObject); // Create a descriptor for 'this' variable. context_scope.SetTokenIndexAt(0, TokenPosition::kMinSource); context_scope.SetDeclarationTokenIndexAt(0, TokenPosition::kMinSource); context_scope.SetNameAt(0, Symbols::This()); context_scope.SetIsFinalAt(0, true); context_scope.SetIsConstAt(0, false); context_scope.SetTypeAt(0, *reader->TypeHandle()); context_scope.SetContextIndexAt(0, 0); context_scope.SetContextLevelAt(0, 0); return context_scope.raw(); } UNREACHABLE(); return NULL; } void RawContextScope::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); if (ptr()->is_implicit_) { ASSERT(ptr()->num_variables_ == 1); const VariableDesc* var = ptr()->VariableDescAddr(0); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kContextScopeCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out is_implicit flag for the context scope. writer->Write(true); // Write out the type of 'this' the variable. writer->WriteObjectImpl(var->type, kAsInlinedObject); return; } UNREACHABLE(); } RawSingleTargetCache* SingleTargetCache::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return SingleTargetCache::null(); } void RawSingleTargetCache::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawUnlinkedCall* UnlinkedCall::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return UnlinkedCall::null(); } void RawUnlinkedCall::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawICData* ICData::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(kind == Snapshot::kScript); ICData& result = ICData::ZoneHandle(reader->zone(), ICData::New()); reader->AddBackRef(object_id, &result, kIsDeserialized); NOT_IN_PRECOMPILED(result.set_deopt_id(reader->Read())); result.set_state_bits(reader->Read()); #if defined(TAG_IC_DATA) result.set_tag(reader->Read()); #endif // Set all the object fields. READ_OBJECT_FIELDS(result, result.raw()->from(), result.raw()->to_snapshot(kind), kAsReference); return result.raw(); } void RawICData::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(kind == Snapshot::kScript); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kICDataCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the non object fields. NOT_IN_PRECOMPILED(writer->Write(ptr()->deopt_id_)); writer->Write(ptr()->state_bits_); #if defined(TAG_IC_DATA) writer->Write(ptr()->tag_); #endif // Write out all the object pointer fields. // In precompiled snapshots, omit the owner field. The owner field may // refer to a function which was always inlined and no longer needed. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to_snapshot(kind)); } RawMegamorphicCache* MegamorphicCache::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return MegamorphicCache::null(); } void RawMegamorphicCache::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawSubtypeTestCache* SubtypeTestCache::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return SubtypeTestCache::null(); } void RawSubtypeTestCache::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawError* Error::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_referenec) { UNREACHABLE(); return Error::null(); // Error is an abstract class. } void RawError::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); // Error is an abstract class. } RawApiError* ApiError::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Allocate ApiError object. ApiError& api_error = ApiError::ZoneHandle(reader->zone(), ApiError::New()); reader->AddBackRef(object_id, &api_error, kIsDeserialized); // Set all the object fields. READ_OBJECT_FIELDS(api_error, api_error.raw()->from(), api_error.raw()->to(), kAsReference); return api_error.raw(); } void RawApiError::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kApiErrorCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); } RawLanguageError* LanguageError::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Allocate LanguageError object. LanguageError& language_error = LanguageError::ZoneHandle(reader->zone(), LanguageError::New()); reader->AddBackRef(object_id, &language_error, kIsDeserialized); // Set all non object fields. language_error.set_token_pos( TokenPosition::SnapshotDecode(reader->Read())); language_error.set_report_after_token(reader->Read()); language_error.set_kind(reader->Read()); // Set all the object fields. READ_OBJECT_FIELDS(language_error, language_error.raw()->from(), language_error.raw()->to(), kAsReference); return language_error.raw(); } void RawLanguageError::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kLanguageErrorCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the non object fields. writer->Write(ptr()->token_pos_.SnapshotEncode()); writer->Write(ptr()->report_after_token_); writer->Write(ptr()->kind_); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); } RawUnhandledException* UnhandledException::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UnhandledException& result = UnhandledException::ZoneHandle(reader->zone(), UnhandledException::New()); reader->AddBackRef(object_id, &result, kIsDeserialized); // Set all the object fields. READ_OBJECT_FIELDS(result, result.raw()->from(), result.raw()->to(), kAsReference); return result.raw(); } void RawUnhandledException::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteVMIsolateObject(kUnhandledExceptionCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); } RawUnwindError* UnwindError::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return UnwindError::null(); } void RawUnwindError::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawInstance* Instance::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Create an Instance object or get canonical one if it is a canonical // constant. Instance& obj = Instance::ZoneHandle(reader->zone(), Instance::null()); obj ^= Object::Allocate(kInstanceCid, Instance::InstanceSize(), HEAP_SPACE(kind)); if (RawObject::IsCanonical(tags)) { obj = obj.CheckAndCanonicalize(reader->thread(), NULL); } reader->AddBackRef(object_id, &obj, kIsDeserialized); return obj.raw(); } void RawInstance::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kInstanceCid); writer->WriteTags(writer->GetObjectTags(this)); } RawInteger* Mint::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Read the 64 bit value for the object. int64_t value = reader->Read(); // Check if the value could potentially fit in a Smi in our current // architecture, if so return the object as a Smi. if (Smi::IsValid(value)) { Smi& smi = Smi::ZoneHandle(reader->zone(), Smi::New(static_cast(value))); reader->AddBackRef(object_id, &smi, kIsDeserialized); return smi.raw(); } // Create a Mint object or get canonical one if it is a canonical constant. Mint& mint = Mint::ZoneHandle(reader->zone(), Mint::null()); // 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)) { mint = Mint::NewCanonical(value); ASSERT(mint.IsCanonical()); } else { mint = Mint::New(value, HEAP_SPACE(kind)); } reader->AddBackRef(object_id, &mint, kIsDeserialized); return mint.raw(); } void RawMint::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kMintCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out the 64 bit value. writer->Write(ptr()->value_); } RawDouble* Double::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); ASSERT(kind != Snapshot::kMessage); // Read the double value for the object. double value = reader->ReadDouble(); // Create a Double object or get canonical one if it is a canonical constant. Double& dbl = Double::ZoneHandle(reader->zone(), Double::null()); // 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)) { dbl = Double::NewCanonical(value); ASSERT(dbl.IsCanonical()); } else { dbl = Double::New(value, HEAP_SPACE(kind)); } reader->AddBackRef(object_id, &dbl, kIsDeserialized); return dbl.raw(); } void RawDouble::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kDoubleCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out the double value. writer->WriteDouble(ptr()->value_); } RawString* String::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); // String is an abstract class. return String::null(); } void RawString::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); // String is an abstract class. } template void String::ReadFromImpl(SnapshotReader* reader, String* str_obj, intptr_t len, intptr_t tags, CallbackType new_symbol, Snapshot::Kind kind) { ASSERT(reader != NULL); if (RawObject::IsCanonical(tags)) { // Set up canonical string object. ASSERT(reader != NULL); CharacterType* ptr = reader->zone()->Alloc(len); for (intptr_t i = 0; i < len; i++) { ptr[i] = reader->Read(); } *str_obj ^= (*new_symbol)(reader->thread(), ptr, len); } else { // Set up the string object. *str_obj = StringType::New(len, HEAP_SPACE(kind)); str_obj->SetHash(0); // Will get computed when needed. if (len == 0) { return; } NoSafepointScope no_safepoint; CharacterType* str_addr = StringType::DataStart(*str_obj); for (intptr_t i = 0; i < len; i++) { *str_addr = reader->Read(); str_addr++; } } } RawOneByteString* OneByteString::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { // Read the length so that we can determine instance size to allocate. ASSERT(reader != NULL); intptr_t len = reader->ReadSmiValue(); String& str_obj = String::ZoneHandle(reader->zone(), String::null()); String::ReadFromImpl(reader, &str_obj, len, tags, Symbols::FromLatin1, kind); reader->AddBackRef(object_id, &str_obj, kIsDeserialized); return raw(str_obj); } RawTwoByteString* TwoByteString::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { // Read the length so that we can determine instance size to allocate. ASSERT(reader != NULL); intptr_t len = reader->ReadSmiValue(); String& str_obj = String::ZoneHandle(reader->zone(), String::null()); String::ReadFromImpl(reader, &str_obj, len, tags, Symbols::FromUTF16, kind); reader->AddBackRef(object_id, &str_obj, kIsDeserialized); return raw(str_obj); } template static void StringWriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, intptr_t class_id, intptr_t tags, RawSmi* length, T* data) { ASSERT(writer != NULL); intptr_t len = Smi::Value(length); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(class_id); writer->WriteTags(tags); // Write out the length field. writer->Write(length); // Write out the string. if (len > 0) { if (class_id == kOneByteStringCid) { writer->WriteBytes(reinterpret_cast(data), len); } else { for (intptr_t i = 0; i < len; i++) { writer->Write(data[i]); } } } } void RawOneByteString::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { StringWriteTo(writer, object_id, kind, kOneByteStringCid, writer->GetObjectTags(this), ptr()->length_, ptr()->data()); } void RawTwoByteString::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { StringWriteTo(writer, object_id, kind, kTwoByteStringCid, writer->GetObjectTags(this), ptr()->length_, ptr()->data()); } RawExternalOneByteString* ExternalOneByteString::ReadFrom( SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return ExternalOneByteString::null(); } RawExternalTwoByteString* ExternalTwoByteString::ReadFrom( SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return ExternalTwoByteString::null(); } void RawExternalOneByteString::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { // Serialize as a non-external one byte string. StringWriteTo(writer, object_id, kind, kOneByteStringCid, writer->GetObjectTags(this), ptr()->length_, ptr()->external_data_); } void RawExternalTwoByteString::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { // Serialize as a non-external two byte string. StringWriteTo(writer, object_id, kind, kTwoByteStringCid, writer->GetObjectTags(this), ptr()->length_, ptr()->external_data_); } RawBool* Bool::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return Bool::null(); } void RawBool::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); } RawArray* Array::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Read the length so that we can determine instance size to allocate. intptr_t len = reader->ReadSmiValue(); Array* array = NULL; DeserializeState state; if (!as_reference) { array = reinterpret_cast(reader->GetBackRef(object_id)); state = kIsDeserialized; } else { state = kIsNotDeserialized; } if (array == NULL) { array = &(Array::ZoneHandle(reader->zone(), Array::New(len, HEAP_SPACE(kind)))); reader->AddBackRef(object_id, array, state); } if (!as_reference) { // Read all the individual elements for inlined objects. ASSERT(!RawObject::IsCanonical(tags)); reader->ArrayReadFrom(object_id, *array, len, tags); } return array->raw(); } RawImmutableArray* ImmutableArray::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Read the length so that we can determine instance size to allocate. intptr_t len = reader->ReadSmiValue(); Array* array = NULL; DeserializeState state; if (!as_reference) { array = reinterpret_cast(reader->GetBackRef(object_id)); state = kIsDeserialized; } else { state = kIsNotDeserialized; } if (array == NULL) { array = &(Array::ZoneHandle(reader->zone(), ImmutableArray::New(len, HEAP_SPACE(kind)))); reader->AddBackRef(object_id, array, state); } if (!as_reference) { // Read all the individual elements for inlined objects. reader->ArrayReadFrom(object_id, *array, len, tags); if (RawObject::IsCanonical(tags)) { *array ^= array->CheckAndCanonicalize(reader->thread(), NULL); } } return raw(*array); } void RawArray::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(!this->IsCanonical()); writer->ArrayWriteTo(object_id, kArrayCid, writer->GetObjectTags(this), ptr()->length_, ptr()->type_arguments_, ptr()->data(), as_reference); } void RawImmutableArray::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { writer->ArrayWriteTo(object_id, kImmutableArrayCid, writer->GetObjectTags(this), ptr()->length_, ptr()->type_arguments_, ptr()->data(), as_reference); } RawGrowableObjectArray* GrowableObjectArray::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Read the length so that we can determine instance size to allocate. GrowableObjectArray& array = GrowableObjectArray::ZoneHandle( reader->zone(), GrowableObjectArray::null()); array = GrowableObjectArray::New(0, HEAP_SPACE(kind)); reader->AddBackRef(object_id, &array, kIsDeserialized); // Read type arguments of growable array object. const intptr_t typeargs_offset = GrowableObjectArray::type_arguments_offset() / kWordSize; *reader->TypeArgumentsHandle() ^= reader->ReadObjectImpl(kAsInlinedObject, object_id, typeargs_offset); array.StorePointer(&array.raw_ptr()->type_arguments_, reader->TypeArgumentsHandle()->raw()); // Read length of growable array object. array.SetLength(reader->ReadSmiValue()); // Read the backing array of growable array object. *(reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsReference); array.SetData(*(reader->ArrayHandle())); return array.raw(); } void RawGrowableObjectArray::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kGrowableObjectArrayCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out the type arguments field. writer->WriteObjectImpl(ptr()->type_arguments_, kAsInlinedObject); // Write out the used length field. writer->Write(ptr()->length_); // Write out the Array object. writer->WriteObjectImpl(ptr()->data_, kAsReference); } RawLinkedHashMap* LinkedHashMap::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); LinkedHashMap& map = LinkedHashMap::ZoneHandle(reader->zone(), LinkedHashMap::null()); if (kind == Snapshot::kScript) { // The immutable maps that seed map literals are not yet VM-internal, so // we don't reach this. UNREACHABLE(); } else { // Since the map might contain itself as a key or value, allocate first. map = LinkedHashMap::NewUninitialized(HEAP_SPACE(kind)); } reader->AddBackRef(object_id, &map, kIsDeserialized); // Read the type arguments. const intptr_t typeargs_offset = GrowableObjectArray::type_arguments_offset() / kWordSize; *reader->TypeArgumentsHandle() ^= reader->ReadObjectImpl(kAsInlinedObject, object_id, typeargs_offset); map.SetTypeArguments(*reader->TypeArgumentsHandle()); // Read the number of key/value pairs. intptr_t len = reader->ReadSmiValue(); intptr_t used_data = (len << 1); map.SetUsedData(used_data); // Allocate the data array. intptr_t data_size = Utils::Maximum(Utils::RoundUpToPowerOfTwo(used_data), static_cast(LinkedHashMap::kInitialIndexSize)); Array& data = Array::ZoneHandle(reader->zone(), Array::New(data_size, HEAP_SPACE(kind))); map.SetData(data); map.SetDeletedKeys(0); // The index and hashMask is regenerated by the maps themselves on demand. // Thus, the index will probably be allocated in new space (unless it's huge). // TODO(koda): Eagerly rehash here when no keys have user-defined '==', and // in particular, if/when (const) maps are needed in the VM isolate snapshot. ASSERT(reader->isolate() != Dart::vm_isolate()); map.SetHashMask(0); // Prefer sentinel 0 over null for better type feedback. reader->EnqueueRehashingOfMap(map); // Read the keys and values. bool read_as_reference = RawObject::IsCanonical(tags) ? false : true; for (intptr_t i = 0; i < used_data; i++) { *reader->PassiveObjectHandle() = reader->ReadObjectImpl(read_as_reference); data.SetAt(i, *reader->PassiveObjectHandle()); } return map.raw(); } void RawLinkedHashMap::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { if (kind == Snapshot::kScript) { // The immutable maps that seed map literals are not yet VM-internal, so // we don't reach this. } ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kLinkedHashMapCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out the type arguments. writer->WriteObjectImpl(ptr()->type_arguments_, kAsInlinedObject); const intptr_t used_data = Smi::Value(ptr()->used_data_); ASSERT((used_data & 1) == 0); // Keys + values, so must be even. const intptr_t deleted_keys = Smi::Value(ptr()->deleted_keys_); // Write out the number of (not deleted) key/value pairs that will follow. writer->Write(Smi::New((used_data >> 1) - deleted_keys)); // Write out the keys and values. const bool write_as_reference = this->IsCanonical() ? false : true; RawArray* data_array = ptr()->data_; RawObject** data_elements = data_array->ptr()->data(); ASSERT(used_data <= Smi::Value(data_array->ptr()->length_)); #if defined(DEBUG) intptr_t deleted_keys_found = 0; #endif // DEBUG for (intptr_t i = 0; i < used_data; i += 2) { RawObject* key = data_elements[i]; if (key == data_array) { #if defined(DEBUG) ++deleted_keys_found; #endif // DEBUG continue; } RawObject* value = data_elements[i + 1]; writer->WriteObjectImpl(key, write_as_reference); writer->WriteObjectImpl(value, write_as_reference); } DEBUG_ASSERT(deleted_keys_found == deleted_keys); } RawFloat32x4* Float32x4::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Read the values. float value0 = reader->Read(); float value1 = reader->Read(); float value2 = reader->Read(); float value3 = reader->Read(); // Create a Float32x4 object. Float32x4& simd = Float32x4::ZoneHandle(reader->zone(), Float32x4::null()); simd = Float32x4::New(value0, value1, value2, value3, HEAP_SPACE(kind)); reader->AddBackRef(object_id, &simd, kIsDeserialized); return simd.raw(); } void RawFloat32x4::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kFloat32x4Cid); writer->WriteTags(writer->GetObjectTags(this)); // Write out the float values. writer->Write(ptr()->value_[0]); writer->Write(ptr()->value_[1]); writer->Write(ptr()->value_[2]); writer->Write(ptr()->value_[3]); } RawInt32x4* Int32x4::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Read the values. uint32_t value0 = reader->Read(); uint32_t value1 = reader->Read(); uint32_t value2 = reader->Read(); uint32_t value3 = reader->Read(); // Create a Float32x4 object. Int32x4& simd = Int32x4::ZoneHandle(reader->zone(), Int32x4::null()); simd = Int32x4::New(value0, value1, value2, value3, HEAP_SPACE(kind)); reader->AddBackRef(object_id, &simd, kIsDeserialized); return simd.raw(); } void RawInt32x4::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kInt32x4Cid); writer->WriteTags(writer->GetObjectTags(this)); // Write out the mask values. writer->Write(ptr()->value_[0]); writer->Write(ptr()->value_[1]); writer->Write(ptr()->value_[2]); writer->Write(ptr()->value_[3]); } RawFloat64x2* Float64x2::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Read the values. double value0 = reader->Read(); double value1 = reader->Read(); // Create a Float64x2 object. Float64x2& simd = Float64x2::ZoneHandle(reader->zone(), Float64x2::null()); simd = Float64x2::New(value0, value1, HEAP_SPACE(kind)); reader->AddBackRef(object_id, &simd, kIsDeserialized); return simd.raw(); } void RawFloat64x2::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kFloat64x2Cid); writer->WriteTags(writer->GetObjectTags(this)); // Write out the float values. writer->Write(ptr()->value_[0]); writer->Write(ptr()->value_[1]); } RawTypedData* TypedData::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); intptr_t cid = RawObject::ClassIdTag::decode(tags); intptr_t len = reader->ReadSmiValue(); TypedData& result = TypedData::ZoneHandle( reader->zone(), TypedData::New(cid, len, HEAP_SPACE(kind))); reader->AddBackRef(object_id, &result, kIsDeserialized); // Setup the array elements. intptr_t element_size = ElementSizeInBytes(cid); intptr_t length_in_bytes = len * element_size; NoSafepointScope no_safepoint; uint8_t* data = reinterpret_cast(result.DataAddr(0)); reader->ReadBytes(data, length_in_bytes); // 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 or a message snapshot we always have // to canonicalize the object. if (RawObject::IsCanonical(tags)) { result ^= result.CheckAndCanonicalize(reader->thread(), NULL); ASSERT(!result.IsNull()); ASSERT(result.IsCanonical()); } return result.raw(); } RawExternalTypedData* ExternalTypedData::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(!Snapshot::IsFull(kind)); intptr_t cid = RawObject::ClassIdTag::decode(tags); intptr_t length = reader->ReadSmiValue(); FinalizableData finalizable_data = static_cast(reader)->finalizable_data()->Take(); uint8_t* data = reinterpret_cast(finalizable_data.data); ExternalTypedData& obj = ExternalTypedData::ZoneHandle(ExternalTypedData::New(cid, data, length)); reader->AddBackRef(object_id, &obj, kIsDeserialized); intptr_t external_size = obj.LengthInBytes(); obj.AddFinalizer(finalizable_data.peer, finalizable_data.callback, external_size); return obj.raw(); } // This function's name can appear in Observatory. static void IsolateMessageTypedDataFinalizer(void* isolate_callback_data, Dart_WeakPersistentHandle handle, void* buffer) { free(buffer); } static const intptr_t kExternalizeTypedDataThreshold = 4 * KB; void RawTypedData::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); intptr_t cid = this->GetClassId(); intptr_t length = Smi::Value(ptr()->length_); // In elements. intptr_t external_cid; intptr_t bytes; switch (cid) { case kTypedDataInt8ArrayCid: external_cid = kExternalTypedDataInt8ArrayCid; bytes = length * sizeof(int8_t); break; case kTypedDataUint8ArrayCid: external_cid = kExternalTypedDataUint8ArrayCid; bytes = length * sizeof(uint8_t); break; case kTypedDataUint8ClampedArrayCid: external_cid = kExternalTypedDataUint8ClampedArrayCid; bytes = length * sizeof(uint8_t); break; case kTypedDataInt16ArrayCid: external_cid = kExternalTypedDataInt16ArrayCid; bytes = length * sizeof(int16_t); break; case kTypedDataUint16ArrayCid: external_cid = kExternalTypedDataUint16ArrayCid; bytes = length * sizeof(uint16_t); break; case kTypedDataInt32ArrayCid: external_cid = kExternalTypedDataInt32ArrayCid; bytes = length * sizeof(int32_t); break; case kTypedDataUint32ArrayCid: external_cid = kExternalTypedDataUint32ArrayCid; bytes = length * sizeof(uint32_t); break; case kTypedDataInt64ArrayCid: external_cid = kExternalTypedDataInt64ArrayCid; bytes = length * sizeof(int64_t); break; case kTypedDataUint64ArrayCid: external_cid = kExternalTypedDataUint64ArrayCid; bytes = length * sizeof(uint64_t); break; case kTypedDataFloat32ArrayCid: external_cid = kExternalTypedDataFloat32ArrayCid; bytes = length * sizeof(float); break; case kTypedDataFloat64ArrayCid: external_cid = kExternalTypedDataFloat64ArrayCid; bytes = length * sizeof(double); break; case kTypedDataInt32x4ArrayCid: external_cid = kExternalTypedDataInt32x4ArrayCid; bytes = length * sizeof(int32_t) * 4; break; case kTypedDataFloat32x4ArrayCid: external_cid = kExternalTypedDataFloat32x4ArrayCid; bytes = length * sizeof(float) * 4; break; case kTypedDataFloat64x2ArrayCid: external_cid = kExternalTypedDataFloat64x2ArrayCid; bytes = length * sizeof(double) * 2; break; default: external_cid = kIllegalCid; bytes = 0; UNREACHABLE(); } // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); if ((kind == Snapshot::kMessage) && (bytes >= kExternalizeTypedDataThreshold)) { // Write as external. writer->WriteIndexedObject(external_cid); writer->WriteTags(writer->GetObjectTags(this)); writer->Write(ptr()->length_); uint8_t* data = reinterpret_cast(ptr()->data()); void* passed_data = malloc(bytes); if (passed_data == NULL) { OUT_OF_MEMORY(); } memmove(passed_data, data, bytes); static_cast(writer)->finalizable_data()->Put( bytes, passed_data, // data passed_data, // peer, IsolateMessageTypedDataFinalizer); } else { // Write as internal. writer->WriteIndexedObject(cid); writer->WriteTags(writer->GetObjectTags(this)); writer->Write(ptr()->length_); uint8_t* data = reinterpret_cast(ptr()->data()); writer->WriteBytes(data, bytes); } } void RawExternalTypedData::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); intptr_t cid = this->GetClassId(); intptr_t length = Smi::Value(ptr()->length_); // In elements. intptr_t internal_cid; intptr_t bytes; switch (cid) { case kExternalTypedDataInt8ArrayCid: internal_cid = kTypedDataInt8ArrayCid; bytes = length * sizeof(int8_t); break; case kExternalTypedDataUint8ArrayCid: internal_cid = kTypedDataUint8ArrayCid; bytes = length * sizeof(uint8_t); break; case kExternalTypedDataUint8ClampedArrayCid: internal_cid = kTypedDataUint8ClampedArrayCid; bytes = length * sizeof(uint8_t); break; case kExternalTypedDataInt16ArrayCid: internal_cid = kTypedDataInt16ArrayCid; bytes = length * sizeof(int16_t); break; case kExternalTypedDataUint16ArrayCid: internal_cid = kTypedDataUint16ArrayCid; bytes = length * sizeof(uint16_t); break; case kExternalTypedDataInt32ArrayCid: internal_cid = kTypedDataInt32ArrayCid; bytes = length * sizeof(int32_t); break; case kExternalTypedDataUint32ArrayCid: internal_cid = kTypedDataUint32ArrayCid; bytes = length * sizeof(uint32_t); break; case kExternalTypedDataInt64ArrayCid: internal_cid = kTypedDataInt64ArrayCid; bytes = length * sizeof(int64_t); break; case kExternalTypedDataUint64ArrayCid: internal_cid = kTypedDataUint64ArrayCid; bytes = length * sizeof(uint64_t); break; case kExternalTypedDataFloat32ArrayCid: internal_cid = kTypedDataFloat32ArrayCid; bytes = length * sizeof(float); // NOLINT. break; case kExternalTypedDataFloat64ArrayCid: internal_cid = kTypedDataFloat64ArrayCid, bytes = length * sizeof(double); // NOLINT. break; case kExternalTypedDataInt32x4ArrayCid: internal_cid = kTypedDataInt32x4ArrayCid; bytes = length * sizeof(int32_t) * 4; break; case kExternalTypedDataFloat32x4ArrayCid: internal_cid = kTypedDataFloat32x4ArrayCid; bytes = length * sizeof(float) * 4; break; case kExternalTypedDataFloat64x2ArrayCid: internal_cid = kTypedDataFloat64x2ArrayCid; bytes = length * sizeof(double) * 2; break; default: internal_cid = kIllegalCid; bytes = 0; UNREACHABLE(); } // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); if ((kind == Snapshot::kMessage) && (bytes >= kExternalizeTypedDataThreshold)) { // Write as external. writer->WriteIndexedObject(cid); writer->WriteTags(writer->GetObjectTags(this)); writer->Write(ptr()->length_); uint8_t* data = reinterpret_cast(ptr()->data_); void* passed_data = malloc(bytes); if (passed_data == NULL) { OUT_OF_MEMORY(); } memmove(passed_data, data, bytes); static_cast(writer)->finalizable_data()->Put( bytes, passed_data, // data passed_data, // peer, IsolateMessageTypedDataFinalizer); } else { // Write as internal. writer->WriteIndexedObject(internal_cid); writer->WriteTags(writer->GetObjectTags(this)); writer->Write(ptr()->length_); uint8_t* data = reinterpret_cast(ptr()->data_); writer->WriteBytes(data, bytes); } } RawCapability* Capability::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { uint64_t id = reader->Read(); Capability& result = Capability::ZoneHandle(reader->zone(), Capability::New(id)); reader->AddBackRef(object_id, &result, kIsDeserialized); return result.raw(); } void RawCapability::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kCapabilityCid); writer->WriteTags(writer->GetObjectTags(this)); writer->Write(ptr()->id_); } RawReceivePort* ReceivePort::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return ReceivePort::null(); } void RawReceivePort::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { if (kind == Snapshot::kMessage) { // We do not allow objects with native fields in an isolate message. writer->SetWriteException(Exceptions::kArgument, "Illegal argument in isolate message" " : (object is a RawReceivePort)"); } else { UNREACHABLE(); } } RawSendPort* SendPort::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(kind == Snapshot::kMessage); uint64_t id = reader->Read(); uint64_t origin_id = reader->Read(); SendPort& result = SendPort::ZoneHandle(reader->zone(), SendPort::New(id, origin_id)); reader->AddBackRef(object_id, &result, kIsDeserialized); return result.raw(); } void RawSendPort::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kSendPortCid); writer->WriteTags(writer->GetObjectTags(this)); writer->Write(ptr()->id_); writer->Write(ptr()->origin_id_); } RawStackTrace* StackTrace::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); // StackTraces are not sent in a snapshot. return StackTrace::null(); } void RawStackTrace::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(kind == Snapshot::kMessage); writer->SetWriteException(Exceptions::kArgument, "Illegal argument in isolate message" " : (object is a stacktrace)"); } RawRegExp* RegExp::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Allocate RegExp object. RegExp& regex = RegExp::ZoneHandle(reader->zone(), RegExp::New()); reader->AddBackRef(object_id, ®ex, kIsDeserialized); // Read and Set all the other fields. regex.StoreSmi(®ex.raw_ptr()->num_bracket_expressions_, reader->ReadAsSmi()); *reader->StringHandle() ^= reader->ReadObjectImpl(kAsInlinedObject); regex.set_pattern(*reader->StringHandle()); regex.StoreNonPointer(®ex.raw_ptr()->num_registers_, reader->Read()); regex.StoreNonPointer(®ex.raw_ptr()->type_flags_, reader->Read()); const Function& no_function = Function::Handle(reader->zone()); for (intptr_t cid = kOneByteStringCid; cid <= kExternalTwoByteStringCid; cid++) { regex.set_function(cid, /*sticky=*/false, no_function); regex.set_function(cid, /*sticky=*/true, no_function); } return regex.raw(); } void RawRegExp::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kRegExpCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the other fields. writer->Write(ptr()->num_bracket_expressions_); writer->WriteObjectImpl(ptr()->pattern_, kAsInlinedObject); writer->Write(ptr()->num_registers_); writer->Write(ptr()->type_flags_); } RawWeakProperty* WeakProperty::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { ASSERT(reader != NULL); // Allocate the weak property object. WeakProperty& weak_property = WeakProperty::ZoneHandle(reader->zone(), WeakProperty::New()); reader->AddBackRef(object_id, &weak_property, kIsDeserialized); // Set all the object fields. READ_OBJECT_FIELDS(weak_property, weak_property.raw()->from(), weak_property.raw()->to(), kAsReference); return weak_property.raw(); } void RawWeakProperty::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { ASSERT(writer != NULL); // Write out the serialization header value for this object. writer->WriteInlinedObjectHeader(object_id); // Write out the class and tags information. writer->WriteIndexedObject(kWeakPropertyCid); writer->WriteTags(writer->GetObjectTags(this)); // Write out all the object pointer fields. SnapshotWriterVisitor visitor(writer, kAsReference); visitor.VisitPointers(from(), to()); } RawMirrorReference* MirrorReference::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_referenec) { UNREACHABLE(); return MirrorReference::null(); } void RawMirrorReference::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { if (kind == Snapshot::kMessage) { // We do not allow objects with native fields in an isolate message. writer->SetWriteException(Exceptions::kArgument, "Illegal argument in isolate message" " : (object is a MirrorReference)"); } else { UNREACHABLE(); } } RawUserTag* UserTag::ReadFrom(SnapshotReader* reader, intptr_t object_id, intptr_t tags, Snapshot::Kind kind, bool as_reference) { UNREACHABLE(); return UserTag::null(); } void RawUserTag::WriteTo(SnapshotWriter* writer, intptr_t object_id, Snapshot::Kind kind, bool as_reference) { if (kind == Snapshot::kMessage) { // We do not allow objects with native fields in an isolate message. writer->SetWriteException(Exceptions::kArgument, "Illegal argument in isolate message" " : (object is a UserTag)"); } else { UNREACHABLE(); } } } // namespace dart