| // Copyright (c) 2021, 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_snapshot.h" | |
| #include <memory> | |
| #include "platform/assert.h" | |
| #include "platform/unicode.h" | |
| #include "vm/class_finalizer.h" | |
| #include "vm/class_id.h" | |
| #include "vm/dart_api_message.h" | |
| #include "vm/dart_api_state.h" | |
| #include "vm/dart_entry.h" | |
| #include "vm/flags.h" | |
| #include "vm/growable_array.h" | |
| #include "vm/heap/heap.h" | |
| #include "vm/heap/weak_table.h" | |
| #include "vm/longjump.h" | |
| #include "vm/object.h" | |
| #include "vm/object_graph_copy.h" | |
| #include "vm/object_store.h" | |
| #include "vm/symbols.h" | |
| #include "vm/type_testing_stubs.h" | |
| namespace dart { | |
| static Dart_CObject cobj_sentinel = {.type = Dart_CObject_kUnsupported}; | |
| static Dart_CObject cobj_dynamic_type = {.type = Dart_CObject_kUnsupported}; | |
| static Dart_CObject cobj_void_type = {.type = Dart_CObject_kUnsupported}; | |
| static Dart_CObject cobj_empty_type_arguments = {.type = | |
| Dart_CObject_kUnsupported}; | |
| static Dart_CObject cobj_true = {.type = Dart_CObject_kBool, | |
| .value = {.as_bool = true}}; | |
| static Dart_CObject cobj_false = {.type = Dart_CObject_kBool, | |
| .value = {.as_bool = false}}; | |
| static Dart_CObject cobj_null = {.type = Dart_CObject_kNull, | |
| .value = {.as_int64 = 0}}; | |
| static Dart_CObject cobj_empty_array = {.type = Dart_CObject_kArray, | |
| .value = {.as_array = {0, nullptr}}}; | |
| enum class MessagePhase { | |
| kBeforeTypes = 0, | |
| kTypes = 1, | |
| kCanonicalInstances = 2, | |
| kNonCanonicalInstances = 3, | |
| kNumPhases = 4, | |
| }; | |
| class MessageSerializer; | |
| class MessageDeserializer; | |
| class ApiMessageSerializer; | |
| class ApiMessageDeserializer; | |
| class MessageSerializationCluster : public ZoneObject { | |
| public: | |
| explicit MessageSerializationCluster(const char* name, | |
| MessagePhase phase, | |
| intptr_t cid, | |
| bool is_canonical = false) | |
| : name_(name), phase_(phase), cid_(cid), is_canonical_(is_canonical) {} | |
| virtual ~MessageSerializationCluster() {} | |
| virtual void Trace(MessageSerializer* s, Object* object) = 0; | |
| virtual void WriteNodes(MessageSerializer* s) = 0; | |
| virtual void WriteEdges(MessageSerializer* s) {} | |
| virtual void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) {} | |
| virtual void WriteNodesApi(ApiMessageSerializer* s) {} | |
| virtual void WriteEdgesApi(ApiMessageSerializer* s) {} | |
| const char* name() const { return name_; } | |
| MessagePhase phase() const { return phase_; } | |
| intptr_t cid() const { return cid_; } | |
| bool is_canonical() const { return is_canonical_; } | |
| protected: | |
| const char* const name_; | |
| const MessagePhase phase_; | |
| const intptr_t cid_; | |
| const bool is_canonical_; | |
| DISALLOW_COPY_AND_ASSIGN(MessageSerializationCluster); | |
| }; | |
| class MessageDeserializationCluster : public ZoneObject { | |
| public: | |
| explicit MessageDeserializationCluster(const char* name, | |
| bool is_canonical = false) | |
| : name_(name), | |
| is_canonical_(is_canonical), | |
| start_index_(0), | |
| stop_index_(0) {} | |
| virtual ~MessageDeserializationCluster() {} | |
| virtual void ReadNodes(MessageDeserializer* d) = 0; | |
| virtual void ReadEdges(MessageDeserializer* d) {} | |
| virtual ObjectPtr PostLoad(MessageDeserializer* d) { return nullptr; } | |
| virtual void ReadNodesApi(ApiMessageDeserializer* d) {} | |
| virtual void ReadEdgesApi(ApiMessageDeserializer* d) {} | |
| virtual void PostLoadApi(ApiMessageDeserializer* d) {} | |
| void ReadNodesWrapped(MessageDeserializer* d); | |
| void ReadNodesWrappedApi(ApiMessageDeserializer* d); | |
| const char* name() const { return name_; } | |
| bool is_canonical() const { return is_canonical_; } | |
| protected: | |
| ObjectPtr PostLoadAbstractType(MessageDeserializer* d); | |
| ObjectPtr PostLoadLinkedHash(MessageDeserializer* d); | |
| const char* const name_; | |
| const bool is_canonical_; | |
| // The range of the ref array that belongs to this cluster. | |
| intptr_t start_index_; | |
| intptr_t stop_index_; | |
| DISALLOW_COPY_AND_ASSIGN(MessageDeserializationCluster); | |
| }; | |
| class BaseSerializer : public StackResource { | |
| public: | |
| BaseSerializer(Thread* thread, Zone* zone); | |
| ~BaseSerializer(); | |
| // Writes raw data to the stream (basic type). | |
| // sizeof(T) must be in {1,2,4,8}. | |
| template <typename T> | |
| void Write(T value) { | |
| BaseWriteStream::Raw<sizeof(T), T>::Write(&stream_, value); | |
| } | |
| void WriteUnsigned(intptr_t value) { stream_.WriteUnsigned(value); } | |
| void WriteWordWith32BitWrites(uword value) { | |
| stream_.WriteWordWith32BitWrites(value); | |
| } | |
| void WriteBytes(const void* addr, intptr_t len) { | |
| stream_.WriteBytes(addr, len); | |
| } | |
| void WriteAscii(const String& str) { | |
| intptr_t len = str.Length(); | |
| WriteUnsigned(len); | |
| for (intptr_t i = 0; i < len; i++) { | |
| int64_t c = str.CharAt(i); | |
| ASSERT(c < 128); | |
| Write<uint8_t>(c); | |
| } | |
| Write<uint8_t>(0); | |
| } | |
| MessageSerializationCluster* NewClusterForClass(intptr_t cid, | |
| bool is_canonical); | |
| void WriteCluster(MessageSerializationCluster* cluster); | |
| std::unique_ptr<Message> Finish(Dart_Port dest_port, | |
| Message::Priority priority) { | |
| MessageFinalizableData* finalizable_data = finalizable_data_; | |
| finalizable_data_ = nullptr; | |
| finalizable_data->SerializationSucceeded(); | |
| intptr_t size; | |
| uint8_t* buffer = stream_.Steal(&size); | |
| return Message::New(dest_port, buffer, size, finalizable_data, priority); | |
| } | |
| Zone* zone() const { return zone_; } | |
| MessageFinalizableData* finalizable_data() const { return finalizable_data_; } | |
| intptr_t next_ref_index() const { return next_ref_index_; } | |
| protected: | |
| Zone* const zone_; | |
| MallocWriteStream stream_; | |
| MessageFinalizableData* finalizable_data_; | |
| GrowableArray<MessageSerializationCluster*> clusters_; | |
| intptr_t num_base_objects_; | |
| intptr_t num_written_objects_; | |
| intptr_t next_ref_index_; | |
| }; | |
| class MessageSerializer : public BaseSerializer { | |
| public: | |
| explicit MessageSerializer(Thread* thread); | |
| ~MessageSerializer(); | |
| bool MarkObjectId(ObjectPtr object, intptr_t id) { | |
| ASSERT(id != WeakTable::kNoValue); | |
| WeakTable* table; | |
| if (object->IsImmediateOrOldObject()) { | |
| table = thread()->forward_table_old(); | |
| } else { | |
| table = thread()->forward_table_new(); | |
| } | |
| return table->MarkValueExclusive(object, id); | |
| } | |
| void SetObjectId(ObjectPtr object, intptr_t id) { | |
| ASSERT(id != WeakTable::kNoValue); | |
| WeakTable* table; | |
| if (object->IsImmediateOrOldObject()) { | |
| table = thread()->forward_table_old(); | |
| } else { | |
| table = thread()->forward_table_new(); | |
| } | |
| table->SetValueExclusive(object, id); | |
| } | |
| intptr_t GetObjectId(ObjectPtr object) const { | |
| const WeakTable* table; | |
| if (object->IsImmediateOrOldObject()) { | |
| table = thread()->forward_table_old(); | |
| } else { | |
| table = thread()->forward_table_new(); | |
| } | |
| return table->GetValueExclusive(object); | |
| } | |
| DART_NOINLINE void AddBaseObject(ObjectPtr base_object) { | |
| AssignRef(base_object); | |
| num_base_objects_++; | |
| } | |
| DART_NOINLINE void AssignRef(ObjectPtr object) { | |
| SetObjectId(object, next_ref_index_); | |
| next_ref_index_++; | |
| } | |
| void AssignRef(Object* object) { AssignRef(object->ptr()); } | |
| void Push(ObjectPtr object); | |
| void Trace(const Object& root, Object* object); | |
| void IllegalObject(const Object& object, const char* message); | |
| void AddBaseObjects(); | |
| void Serialize(const Object& root); | |
| DART_NOINLINE void WriteRef(ObjectPtr object) { | |
| intptr_t index = GetObjectId(object); | |
| ASSERT(index != WeakTable::kNoValue); | |
| WriteUnsigned(index); | |
| } | |
| Thread* thread() const { | |
| return static_cast<Thread*>(StackResource::thread()); | |
| } | |
| IsolateGroup* isolate_group() const { return thread()->isolate_group(); } | |
| bool HasRef(ObjectPtr object) const { | |
| return GetObjectId(object) != WeakTable::kNoValue; | |
| } | |
| private: | |
| Thread* thread_; | |
| WeakTable* forward_table_new_; | |
| WeakTable* forward_table_old_; | |
| GrowableArray<Object*> stack_; | |
| }; | |
| class ApiMessageSerializer : public BaseSerializer { | |
| public: | |
| explicit ApiMessageSerializer(Zone* zone); | |
| ~ApiMessageSerializer(); | |
| bool MarkObjectId(Dart_CObject* object, intptr_t id) { | |
| ASSERT(id != WeakTable::kNoValue); | |
| return forward_table_.MarkValueExclusive( | |
| static_cast<ObjectPtr>(reinterpret_cast<uword>(object)), id); | |
| } | |
| void SetObjectId(Dart_CObject* object, intptr_t id) { | |
| ASSERT(id != WeakTable::kNoValue); | |
| forward_table_.SetValueExclusive( | |
| static_cast<ObjectPtr>(reinterpret_cast<uword>(object)), id); | |
| } | |
| intptr_t GetObjectId(Dart_CObject* object) const { | |
| return forward_table_.GetValueExclusive( | |
| static_cast<ObjectPtr>(reinterpret_cast<uword>(object))); | |
| } | |
| DART_NOINLINE void AddBaseObject(Dart_CObject* base_object) { | |
| AssignRef(base_object); | |
| num_base_objects_++; | |
| } | |
| DART_NOINLINE intptr_t AssignRef(Dart_CObject* object) { | |
| SetObjectId(object, next_ref_index_); | |
| return next_ref_index_++; | |
| } | |
| void ForwardRef(Dart_CObject* old, Dart_CObject* nue) { | |
| intptr_t id = GetObjectId(nue); | |
| ASSERT(id != WeakTable::kNoValue); | |
| SetObjectId(old, id); | |
| num_written_objects_--; | |
| } | |
| void Push(Dart_CObject* object); | |
| bool Trace(Dart_CObject* object); | |
| void AddBaseObjects(); | |
| bool Serialize(Dart_CObject* root); | |
| void WriteRef(Dart_CObject* object) { | |
| intptr_t index = GetObjectId(object); | |
| ASSERT(index != WeakTable::kNoValue); | |
| WriteUnsigned(index); | |
| } | |
| bool Fail(const char* message) { | |
| exception_message_ = message; | |
| return false; | |
| } | |
| private: | |
| WeakTable forward_table_; | |
| GrowableArray<Dart_CObject*> stack_; | |
| const char* exception_message_; | |
| }; | |
| class BaseDeserializer : public ValueObject { | |
| public: | |
| BaseDeserializer(Zone* zone, Message* message); | |
| ~BaseDeserializer(); | |
| // Reads raw data (for basic types). | |
| // sizeof(T) must be in {1,2,4,8}. | |
| template <typename T> | |
| T Read() { | |
| return ReadStream::Raw<sizeof(T), T>::Read(&stream_); | |
| } | |
| intptr_t ReadUnsigned() { return stream_.ReadUnsigned(); } | |
| uword ReadWordWith32BitReads() { return stream_.ReadWordWith32BitReads(); } | |
| void ReadBytes(void* addr, intptr_t len) { stream_.ReadBytes(addr, len); } | |
| const char* ReadAscii() { | |
| intptr_t len = ReadUnsigned(); | |
| const char* result = reinterpret_cast<const char*>(CurrentBufferAddress()); | |
| Advance(len + 1); | |
| return result; | |
| } | |
| const uint8_t* CurrentBufferAddress() const { | |
| return stream_.AddressOfCurrentPosition(); | |
| } | |
| void Advance(intptr_t value) { stream_.Advance(value); } | |
| MessageDeserializationCluster* ReadCluster(); | |
| Zone* zone() const { return zone_; } | |
| intptr_t next_index() const { return next_ref_index_; } | |
| MessageFinalizableData* finalizable_data() const { return finalizable_data_; } | |
| protected: | |
| Zone* zone_; | |
| ReadStream stream_; | |
| MessageFinalizableData* finalizable_data_; | |
| intptr_t next_ref_index_; | |
| }; | |
| class MessageDeserializer : public BaseDeserializer { | |
| public: | |
| MessageDeserializer(Thread* thread, Message* message) | |
| : BaseDeserializer(thread->zone(), message), | |
| thread_(thread), | |
| refs_(Array::Handle(thread->zone())) {} | |
| ~MessageDeserializer() {} | |
| DART_NOINLINE void AddBaseObject(ObjectPtr base_object) { | |
| AssignRef(base_object); | |
| } | |
| void AssignRef(ObjectPtr object) { | |
| refs_.untag()->set_element(next_ref_index_, object); | |
| next_ref_index_++; | |
| } | |
| ObjectPtr Ref(intptr_t index) const { | |
| ASSERT(index > 0); | |
| ASSERT(index <= next_ref_index_); | |
| return refs_.At(index); | |
| } | |
| void UpdateRef(intptr_t index, const Object& new_object) { | |
| ASSERT(index > 0); | |
| ASSERT(index <= next_ref_index_); | |
| refs_.SetAt(index, new_object); | |
| } | |
| ObjectPtr ReadRef() { return Ref(ReadUnsigned()); } | |
| void AddBaseObjects(); | |
| ObjectPtr Deserialize(); | |
| Thread* thread() const { return thread_; } | |
| IsolateGroup* isolate_group() const { return thread_->isolate_group(); } | |
| ArrayPtr refs() const { return refs_.ptr(); } | |
| private: | |
| Thread* const thread_; | |
| Array& refs_; | |
| }; | |
| class ApiMessageDeserializer : public BaseDeserializer { | |
| public: | |
| ApiMessageDeserializer(Zone* zone, Message* message) | |
| : BaseDeserializer(zone, message), refs_(nullptr) {} | |
| ~ApiMessageDeserializer() {} | |
| void AddBaseObject(Dart_CObject* base_object) { AssignRef(base_object); } | |
| void AssignRef(Dart_CObject* object) { | |
| refs_[next_ref_index_] = object; | |
| next_ref_index_++; | |
| } | |
| Dart_CObject* Allocate(Dart_CObject_Type type) { | |
| Dart_CObject* result = zone()->Alloc<Dart_CObject>(1); | |
| result->type = type; | |
| return result; | |
| } | |
| Dart_CObject* Ref(intptr_t index) const { | |
| ASSERT(index > 0); | |
| ASSERT(index <= next_ref_index_); | |
| return refs_[index]; | |
| } | |
| Dart_CObject* ReadRef() { return Ref(ReadUnsigned()); } | |
| void AddBaseObjects(); | |
| Dart_CObject* Deserialize(); | |
| private: | |
| Dart_CObject** refs_; | |
| }; | |
| void MessageDeserializationCluster::ReadNodesWrapped(MessageDeserializer* d) { | |
| start_index_ = d->next_index(); | |
| this->ReadNodes(d); | |
| stop_index_ = d->next_index(); | |
| } | |
| void MessageDeserializationCluster::ReadNodesWrappedApi( | |
| ApiMessageDeserializer* d) { | |
| start_index_ = d->next_index(); | |
| this->ReadNodesApi(d); | |
| stop_index_ = d->next_index(); | |
| } | |
| ObjectPtr MessageDeserializationCluster::PostLoadAbstractType( | |
| MessageDeserializer* d) { | |
| ClassFinalizer::FinalizationKind finalization = | |
| is_canonical() ? ClassFinalizer::kCanonicalize | |
| : ClassFinalizer::kFinalize; | |
| AbstractType& type = AbstractType::Handle(d->zone()); | |
| Code& code = Code::Handle(d->zone()); | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| type ^= d->Ref(id); | |
| code = TypeTestingStubGenerator::DefaultCodeForType(type); | |
| type.InitializeTypeTestingStubNonAtomic(code); | |
| type ^= ClassFinalizer::FinalizeType(type, finalization); | |
| d->UpdateRef(id, type); | |
| } | |
| return nullptr; | |
| } | |
| ObjectPtr MessageDeserializationCluster::PostLoadLinkedHash( | |
| MessageDeserializer* d) { | |
| ASSERT(!is_canonical()); | |
| Array& maps = Array::Handle(d->zone(), d->refs()); | |
| maps = maps.Slice(start_index_, stop_index_ - start_index_, | |
| /*with_type_argument=*/false); | |
| return DartLibraryCalls::RehashObjectsInDartCompactHash(d->thread(), maps); | |
| } | |
| class ClassMessageSerializationCluster : public MessageSerializationCluster { | |
| public: | |
| ClassMessageSerializationCluster() | |
| : MessageSerializationCluster("Class", | |
| MessagePhase::kBeforeTypes, | |
| kClassCid), | |
| objects_() {} | |
| ~ClassMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| Class* cls = static_cast<Class*>(object); | |
| objects_.Add(cls); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| Library& lib = Library::Handle(s->zone()); | |
| String& str = String::Handle(s->zone()); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Class* cls = objects_[i]; | |
| s->AssignRef(cls); | |
| intptr_t cid = cls->id(); | |
| if (cid < kNumPredefinedCids) { | |
| ASSERT(cid != 0); | |
| s->WriteUnsigned(cid); | |
| } else { | |
| s->WriteUnsigned(0); | |
| lib = cls->library(); | |
| str = lib.url(); | |
| s->WriteAscii(str); | |
| str = cls->Name(); | |
| s->WriteAscii(str); | |
| } | |
| } | |
| } | |
| private: | |
| GrowableArray<Class*> objects_; | |
| }; | |
| class ClassMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| ClassMessageDeserializationCluster() | |
| : MessageDeserializationCluster("Class") {} | |
| ~ClassMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| auto* class_table = d->isolate_group()->class_table(); | |
| String& uri = String::Handle(d->zone()); | |
| Library& lib = Library::Handle(d->zone()); | |
| String& name = String::Handle(d->zone()); | |
| Class& cls = Class::Handle(d->zone()); | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| intptr_t cid = d->ReadUnsigned(); | |
| if (cid != 0) { | |
| cls = class_table->At(cid); | |
| } else { | |
| uri = String::New(d->ReadAscii()); // Library URI. | |
| name = String::New(d->ReadAscii()); // Class name. | |
| lib = Library::LookupLibrary(d->thread(), uri); | |
| if (lib.IsNull()) [[unlikely]] { | |
| FATAL("Not found: %s %s\n", uri.ToCString(), name.ToCString()); | |
| } | |
| if (name.Equals(Symbols::TopLevel())) { | |
| cls = lib.toplevel_class(); | |
| } else { | |
| cls = lib.LookupClass(name); | |
| } | |
| if (cls.IsNull()) [[unlikely]] { | |
| FATAL("Not found: %s %s\n", uri.ToCString(), name.ToCString()); | |
| } | |
| cls.EnsureIsFinalized(d->thread()); | |
| } | |
| d->AssignRef(cls.ptr()); | |
| } | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| intptr_t cid = d->ReadUnsigned(); | |
| if (cid == 0) { | |
| d->ReadAscii(); // Library URI. | |
| d->ReadAscii(); // Class name. | |
| } | |
| d->AssignRef(nullptr); | |
| } | |
| } | |
| }; | |
| class TypeArgumentsMessageSerializationCluster | |
| : public MessageSerializationCluster { | |
| public: | |
| explicit TypeArgumentsMessageSerializationCluster(bool is_canonical) | |
| : MessageSerializationCluster("TypeArguments", | |
| MessagePhase::kTypes, | |
| kTypeArgumentsCid, | |
| is_canonical) {} | |
| ~TypeArgumentsMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| TypeArguments* type_args = static_cast<TypeArguments*>(object); | |
| objects_.Add(type_args); | |
| s->Push(type_args->untag()->instantiations()); | |
| intptr_t length = Smi::Value(type_args->untag()->length()); | |
| for (intptr_t i = 0; i < length; i++) { | |
| s->Push(type_args->untag()->element(i)); | |
| } | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| TypeArguments* type_args = objects_[i]; | |
| s->AssignRef(type_args); | |
| intptr_t length = Smi::Value(type_args->untag()->length()); | |
| s->WriteUnsigned(length); | |
| } | |
| } | |
| void WriteEdges(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| TypeArguments* type_args = objects_[i]; | |
| intptr_t hash = Smi::Value(type_args->untag()->hash()); | |
| s->Write<int32_t>(hash); | |
| const intptr_t nullability = | |
| Smi::Value(type_args->untag()->nullability()); | |
| s->WriteUnsigned(nullability); | |
| intptr_t length = Smi::Value(type_args->untag()->length()); | |
| s->WriteUnsigned(length); | |
| for (intptr_t j = 0; j < length; j++) { | |
| s->WriteRef(type_args->untag()->element(j)); | |
| } | |
| } | |
| } | |
| private: | |
| GrowableArray<TypeArguments*> objects_; | |
| }; | |
| class TypeArgumentsMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| explicit TypeArgumentsMessageDeserializationCluster(bool is_canonical) | |
| : MessageDeserializationCluster("TypeArguments", is_canonical) {} | |
| ~TypeArgumentsMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| intptr_t length = d->ReadUnsigned(); | |
| d->AssignRef(TypeArguments::New(length)); | |
| } | |
| } | |
| void ReadEdges(MessageDeserializer* d) { | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| TypeArgumentsPtr type_args = static_cast<TypeArgumentsPtr>(d->Ref(id)); | |
| type_args->untag()->hash_ = Smi::New(d->Read<int32_t>()); | |
| type_args->untag()->nullability_ = Smi::New(d->ReadUnsigned()); | |
| intptr_t length = d->ReadUnsigned(); | |
| for (intptr_t j = 0; j < length; j++) { | |
| type_args->untag()->types()[j] = | |
| static_cast<AbstractTypePtr>(d->ReadRef()); | |
| } | |
| } | |
| } | |
| ObjectPtr PostLoad(MessageDeserializer* d) { | |
| if (is_canonical()) { | |
| TypeArguments& type_args = TypeArguments::Handle(d->zone()); | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| type_args ^= d->Ref(id); | |
| type_args ^= type_args.Canonicalize(d->thread()); | |
| d->UpdateRef(id, type_args); | |
| } | |
| } | |
| return nullptr; | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| d->ReadUnsigned(); // Length. | |
| d->AssignRef(nullptr); | |
| } | |
| } | |
| void ReadEdgesApi(ApiMessageDeserializer* d) { | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| d->Read<int32_t>(); // Hash. | |
| d->ReadUnsigned(); // Nullability. | |
| intptr_t length = d->ReadUnsigned(); | |
| for (intptr_t j = 0; j < length; j++) { | |
| d->ReadRef(); // Element. | |
| } | |
| } | |
| } | |
| }; | |
| class TypeMessageSerializationCluster : public MessageSerializationCluster { | |
| public: | |
| explicit TypeMessageSerializationCluster(bool is_canonical) | |
| : MessageSerializationCluster("Type", | |
| MessagePhase::kTypes, | |
| kTypeCid, | |
| is_canonical) {} | |
| ~TypeMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| Type* type = static_cast<Type*>(object); | |
| if (!type->IsTypeClassAllowedBySpawnUri()) { | |
| s->IllegalObject(*object, "is a Type"); | |
| } | |
| objects_.Add(type); | |
| s->Push(type->type_class()); | |
| s->Push(type->arguments()); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Type* type = objects_[i]; | |
| s->AssignRef(type); | |
| } | |
| } | |
| void WriteEdges(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Type* type = objects_[i]; | |
| s->WriteRef(type->type_class()); | |
| s->WriteRef(type->arguments()); | |
| s->Write<uint8_t>(static_cast<uint8_t>(type->nullability())); | |
| } | |
| } | |
| private: | |
| GrowableArray<Type*> objects_; | |
| }; | |
| class TypeMessageDeserializationCluster : public MessageDeserializationCluster { | |
| public: | |
| explicit TypeMessageDeserializationCluster(bool is_canonical) | |
| : MessageDeserializationCluster("Type", is_canonical) {} | |
| ~TypeMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| d->AssignRef(Type::New()); | |
| } | |
| } | |
| void ReadEdges(MessageDeserializer* d) { | |
| Class& cls = Class::Handle(d->zone()); | |
| Type& type = Type::Handle(d->zone()); | |
| TypeArguments& type_args = TypeArguments::Handle(d->zone()); | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| type ^= d->Ref(id); | |
| cls ^= d->ReadRef(); | |
| type.set_type_class(cls); | |
| type_args ^= d->ReadRef(); | |
| type.set_arguments(type_args); | |
| type.untag()->set_hash(Smi::New(0)); | |
| type.set_nullability(static_cast<Nullability>(d->Read<uint8_t>())); | |
| type.SetIsFinalized(); | |
| } | |
| } | |
| ObjectPtr PostLoad(MessageDeserializer* d) { return PostLoadAbstractType(d); } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| d->AssignRef(nullptr); | |
| } | |
| } | |
| void ReadEdgesApi(ApiMessageDeserializer* d) { | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| d->ReadRef(); // Class. | |
| d->ReadRef(); // Type arguments. | |
| d->Read<uint8_t>(); // Nullability. | |
| } | |
| } | |
| }; | |
| class SmiMessageSerializationCluster : public MessageSerializationCluster { | |
| public: | |
| explicit SmiMessageSerializationCluster(Zone* zone) | |
| : MessageSerializationCluster("Smi", | |
| MessagePhase::kBeforeTypes, | |
| kSmiCid, | |
| true), | |
| objects_(zone, 0) {} | |
| ~SmiMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| Smi* smi = static_cast<Smi*>(object); | |
| objects_.Add(smi); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Smi* smi = static_cast<Smi*>(objects_[i]); | |
| s->AssignRef(smi); | |
| s->Write<intptr_t>(smi->Value()); | |
| } | |
| } | |
| void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) { | |
| objects_.Add(reinterpret_cast<Smi*>(object)); | |
| } | |
| void WriteNodesApi(ApiMessageSerializer* s) { | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* smi = reinterpret_cast<Dart_CObject*>(objects_[i]); | |
| s->AssignRef(smi); | |
| intptr_t value = smi->type == Dart_CObject_kInt32 ? smi->value.as_int32 | |
| : smi->value.as_int64; | |
| s->Write<intptr_t>(value); | |
| } | |
| } | |
| private: | |
| GrowableArray<Smi*> objects_; | |
| }; | |
| class SmiMessageDeserializationCluster : public MessageDeserializationCluster { | |
| public: | |
| SmiMessageDeserializationCluster() | |
| : MessageDeserializationCluster("Smi", true) {} | |
| ~SmiMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| d->AssignRef(Smi::New(d->Read<intptr_t>())); | |
| } | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| intptr_t value = d->Read<intptr_t>(); | |
| Dart_CObject* smi; | |
| if ((kMinInt32 <= value) && (value <= kMaxInt32)) { | |
| smi = d->Allocate(Dart_CObject_kInt32); | |
| smi->value.as_int32 = value; | |
| } else { | |
| smi = d->Allocate(Dart_CObject_kInt64); | |
| smi->value.as_int64 = value; | |
| } | |
| d->AssignRef(smi); | |
| } | |
| } | |
| }; | |
| class MintMessageSerializationCluster : public MessageSerializationCluster { | |
| public: | |
| explicit MintMessageSerializationCluster(Zone* zone, bool is_canonical) | |
| : MessageSerializationCluster("Mint", | |
| MessagePhase::kBeforeTypes, | |
| kMintCid, | |
| is_canonical), | |
| objects_(zone, 0) {} | |
| ~MintMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| Mint* mint = static_cast<Mint*>(object); | |
| objects_.Add(mint); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Mint* mint = static_cast<Mint*>(objects_[i]); | |
| s->AssignRef(mint); | |
| s->Write<int64_t>(mint->Value()); | |
| } | |
| } | |
| void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) { | |
| objects_.Add(reinterpret_cast<Mint*>(object)); | |
| } | |
| void WriteNodesApi(ApiMessageSerializer* s) { | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* mint = reinterpret_cast<Dart_CObject*>(objects_[i]); | |
| s->AssignRef(mint); | |
| int64_t value = mint->type == Dart_CObject_kInt32 ? mint->value.as_int32 | |
| : mint->value.as_int64; | |
| s->Write<int64_t>(value); | |
| } | |
| } | |
| private: | |
| GrowableArray<Mint*> objects_; | |
| }; | |
| class MintMessageDeserializationCluster : public MessageDeserializationCluster { | |
| public: | |
| explicit MintMessageDeserializationCluster(bool is_canonical) | |
| : MessageDeserializationCluster("int", is_canonical) {} | |
| ~MintMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| int64_t value = d->Read<int64_t>(); | |
| d->AssignRef(is_canonical() ? Mint::NewCanonical(value) | |
| : Mint::New(value)); | |
| } | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| int64_t value = d->Read<int64_t>(); | |
| Dart_CObject* mint; | |
| if ((kMinInt32 <= value) && (value <= kMaxInt32)) { | |
| mint = d->Allocate(Dart_CObject_kInt32); | |
| mint->value.as_int32 = value; | |
| } else { | |
| mint = d->Allocate(Dart_CObject_kInt64); | |
| mint->value.as_int64 = value; | |
| } | |
| d->AssignRef(mint); | |
| } | |
| } | |
| }; | |
| class DoubleMessageSerializationCluster : public MessageSerializationCluster { | |
| public: | |
| explicit DoubleMessageSerializationCluster(Zone* zone, bool is_canonical) | |
| : MessageSerializationCluster("double", | |
| MessagePhase::kBeforeTypes, | |
| kDoubleCid, | |
| is_canonical), | |
| objects_(zone, 0) {} | |
| ~DoubleMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| Double* dbl = static_cast<Double*>(object); | |
| objects_.Add(dbl); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Double* dbl = objects_[i]; | |
| s->AssignRef(dbl); | |
| s->Write<double>(dbl->untag()->value_); | |
| } | |
| } | |
| void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) { | |
| objects_.Add(reinterpret_cast<Double*>(object)); | |
| } | |
| void WriteNodesApi(ApiMessageSerializer* s) { | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* dbl = reinterpret_cast<Dart_CObject*>(objects_[i]); | |
| s->AssignRef(dbl); | |
| s->Write<double>(dbl->value.as_double); | |
| } | |
| } | |
| private: | |
| GrowableArray<Double*> objects_; | |
| }; | |
| class DoubleMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| explicit DoubleMessageDeserializationCluster(bool is_canonical) | |
| : MessageDeserializationCluster("double", is_canonical) {} | |
| ~DoubleMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| double value = d->Read<double>(); | |
| d->AssignRef(is_canonical() ? Double::NewCanonical(value) | |
| : Double::New(value)); | |
| } | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* dbl = d->Allocate(Dart_CObject_kDouble); | |
| dbl->value.as_double = d->Read<double>(); | |
| d->AssignRef(dbl); | |
| } | |
| } | |
| }; | |
| class GrowableObjectArrayMessageSerializationCluster | |
| : public MessageSerializationCluster { | |
| public: | |
| GrowableObjectArrayMessageSerializationCluster() | |
| : MessageSerializationCluster("GrowableObjectArray", | |
| MessagePhase::kNonCanonicalInstances, | |
| kGrowableObjectArrayCid) {} | |
| ~GrowableObjectArrayMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| GrowableObjectArray* array = static_cast<GrowableObjectArray*>(object); | |
| objects_.Add(array); | |
| // Compensation for bogus type prefix optimization. | |
| TypeArguments& args = | |
| TypeArguments::Handle(s->zone(), array->untag()->type_arguments()); | |
| if (!args.IsNull() && (args.Length() != 1)) { | |
| args = args.TruncatedTo(1); | |
| array->untag()->set_type_arguments(args.ptr()); | |
| } | |
| s->Push(array->untag()->type_arguments()); | |
| for (intptr_t i = 0, n = array->Length(); i < n; i++) { | |
| s->Push(array->At(i)); | |
| } | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| GrowableObjectArray* array = objects_[i]; | |
| s->WriteUnsigned(array->Length()); | |
| s->AssignRef(array); | |
| } | |
| } | |
| void WriteEdges(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| GrowableObjectArray* array = objects_[i]; | |
| s->WriteRef(array->untag()->type_arguments()); | |
| for (intptr_t i = 0, n = array->Length(); i < n; i++) { | |
| s->WriteRef(array->At(i)); | |
| } | |
| } | |
| } | |
| private: | |
| GrowableArray<GrowableObjectArray*> objects_; | |
| }; | |
| class GrowableObjectArrayMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| GrowableObjectArrayMessageDeserializationCluster() | |
| : MessageDeserializationCluster("GrowableObjectArray") {} | |
| ~GrowableObjectArrayMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| GrowableObjectArray& array = GrowableObjectArray::Handle(d->zone()); | |
| for (intptr_t i = 0; i < count; i++) { | |
| intptr_t length = d->ReadUnsigned(); | |
| array = GrowableObjectArray::New(length); // Here length is capacity. | |
| array.SetLength(length); | |
| d->AssignRef(array.ptr()); | |
| } | |
| } | |
| void ReadEdges(MessageDeserializer* d) { | |
| GrowableObjectArray& array = GrowableObjectArray::Handle(d->zone()); | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| array ^= d->Ref(id); | |
| array.untag()->set_type_arguments( | |
| static_cast<TypeArgumentsPtr>(d->ReadRef())); | |
| for (intptr_t i = 0, n = array.Length(); i < n; i++) { | |
| array.untag()->data()->untag()->set_element(i, d->ReadRef()); | |
| } | |
| } | |
| } | |
| ObjectPtr PostLoad(MessageDeserializer* d) { | |
| ASSERT(!is_canonical()); | |
| return nullptr; | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* array = d->Allocate(Dart_CObject_kArray); | |
| intptr_t length = d->ReadUnsigned(); | |
| array->value.as_array.length = length; | |
| if (length > 0) { | |
| array->value.as_array.values = d->zone()->Alloc<Dart_CObject*>(length); | |
| } else { | |
| ASSERT(length == 0); | |
| array->value.as_array.values = nullptr; | |
| } | |
| d->AssignRef(array); | |
| } | |
| } | |
| void ReadEdgesApi(ApiMessageDeserializer* d) { | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| Dart_CObject* array = d->Ref(id); | |
| intptr_t length = array->value.as_array.length; | |
| d->ReadRef(); // type_arguments | |
| for (intptr_t i = 0; i < length; i++) { | |
| array->value.as_array.values[i] = d->ReadRef(); | |
| } | |
| } | |
| } | |
| }; | |
| class TypedDataMessageSerializationCluster | |
| : public MessageSerializationCluster { | |
| public: | |
| explicit TypedDataMessageSerializationCluster(Zone* zone, intptr_t cid) | |
| : MessageSerializationCluster("TypedData", | |
| MessagePhase::kNonCanonicalInstances, | |
| cid), | |
| objects_(zone, 0) {} | |
| ~TypedDataMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| TypedData* data = static_cast<TypedData*>(object); | |
| objects_.Add(data); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| intptr_t element_size = TypedData::ElementSizeInBytes(cid_); | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| TypedData* data = objects_[i]; | |
| s->AssignRef(data); | |
| intptr_t length = data->Length(); | |
| s->WriteUnsigned(length); | |
| NoSafepointScope no_safepoint; | |
| uint8_t* cdata = reinterpret_cast<uint8_t*>(data->untag()->data()); | |
| s->WriteBytes(cdata, length * element_size); | |
| } | |
| } | |
| void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) { | |
| objects_.Add(reinterpret_cast<TypedData*>(object)); | |
| } | |
| void WriteNodesApi(ApiMessageSerializer* s) { | |
| intptr_t element_size = TypedData::ElementSizeInBytes(cid_); | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* data = reinterpret_cast<Dart_CObject*>(objects_[i]); | |
| s->AssignRef(data); | |
| intptr_t length = data->value.as_external_typed_data.length; | |
| s->WriteUnsigned(length); | |
| const uint8_t* cdata = data->value.as_typed_data.values; | |
| s->WriteBytes(cdata, length * element_size); | |
| } | |
| } | |
| private: | |
| GrowableArray<TypedData*> objects_; | |
| }; | |
| class TypedDataMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| explicit TypedDataMessageDeserializationCluster(intptr_t cid) | |
| : MessageDeserializationCluster("TypedData"), cid_(cid) {} | |
| ~TypedDataMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| intptr_t element_size = TypedData::ElementSizeInBytes(cid_); | |
| intptr_t count = d->ReadUnsigned(); | |
| TypedData& data = TypedData::Handle(d->zone()); | |
| for (intptr_t i = 0; i < count; i++) { | |
| intptr_t length = d->ReadUnsigned(); | |
| data = TypedData::New(cid_, length); | |
| d->AssignRef(data.ptr()); | |
| const intptr_t length_in_bytes = length * element_size; | |
| NoSafepointScope no_safepoint; | |
| d->ReadBytes(data.untag()->data(), length_in_bytes); | |
| } | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| Dart_TypedData_Type type; | |
| switch (cid_) { | |
| case kTypedDataInt8ArrayCid: | |
| type = Dart_TypedData_kInt8; | |
| break; | |
| case kTypedDataUint8ArrayCid: | |
| type = Dart_TypedData_kUint8; | |
| break; | |
| case kTypedDataUint8ClampedArrayCid: | |
| type = Dart_TypedData_kUint8Clamped; | |
| break; | |
| case kTypedDataInt16ArrayCid: | |
| type = Dart_TypedData_kInt16; | |
| break; | |
| case kTypedDataUint16ArrayCid: | |
| type = Dart_TypedData_kUint16; | |
| break; | |
| case kTypedDataInt32ArrayCid: | |
| type = Dart_TypedData_kInt32; | |
| break; | |
| case kTypedDataUint32ArrayCid: | |
| type = Dart_TypedData_kUint32; | |
| break; | |
| case kTypedDataInt64ArrayCid: | |
| type = Dart_TypedData_kInt64; | |
| break; | |
| case kTypedDataUint64ArrayCid: | |
| type = Dart_TypedData_kUint64; | |
| break; | |
| case kTypedDataFloat32ArrayCid: | |
| type = Dart_TypedData_kFloat32; | |
| break; | |
| case kTypedDataFloat64ArrayCid: | |
| type = Dart_TypedData_kFloat64; | |
| break; | |
| case kTypedDataInt32x4ArrayCid: | |
| type = Dart_TypedData_kInt32x4; | |
| break; | |
| case kTypedDataFloat32x4ArrayCid: | |
| type = Dart_TypedData_kFloat32x4; | |
| break; | |
| case kTypedDataFloat64x2ArrayCid: | |
| type = Dart_TypedData_kFloat64x2; | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| intptr_t element_size = TypedData::ElementSizeInBytes(cid_); | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* data = d->Allocate(Dart_CObject_kTypedData); | |
| intptr_t length = d->ReadUnsigned(); | |
| data->value.as_typed_data.type = type; | |
| data->value.as_typed_data.length = length; | |
| if (length == 0) { | |
| data->value.as_typed_data.values = nullptr; | |
| } else { | |
| data->value.as_typed_data.values = d->CurrentBufferAddress(); | |
| d->Advance(length * element_size); | |
| } | |
| d->AssignRef(data); | |
| } | |
| } | |
| private: | |
| const intptr_t cid_; | |
| }; | |
| // This function's name can appear in VM service responses. | |
| static void IsolateMessageTypedDataFinalizer(void* isolate_callback_data, | |
| void* buffer) { | |
| free(buffer); | |
| } | |
| class ExternalTypedDataMessageSerializationCluster | |
| : public MessageSerializationCluster { | |
| public: | |
| explicit ExternalTypedDataMessageSerializationCluster(Zone* zone, | |
| intptr_t cid) | |
| : MessageSerializationCluster("ExternalTypedData", | |
| MessagePhase::kNonCanonicalInstances, | |
| cid), | |
| objects_(zone, 0) {} | |
| ~ExternalTypedDataMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| ExternalTypedData* data = static_cast<ExternalTypedData*>(object); | |
| objects_.Add(data); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| intptr_t element_size = ExternalTypedData::ElementSizeInBytes(cid_); | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| ExternalTypedData* data = objects_[i]; | |
| s->AssignRef(data); | |
| intptr_t length = Smi::Value(data->untag()->length_); | |
| s->WriteUnsigned(length); | |
| intptr_t length_in_bytes = length * element_size; | |
| void* passed_data = malloc(length_in_bytes); | |
| memmove(passed_data, data->untag()->data_, length_in_bytes); | |
| s->finalizable_data()->Put(length_in_bytes, | |
| passed_data, // data | |
| passed_data, // peer, | |
| IsolateMessageTypedDataFinalizer); | |
| } | |
| } | |
| void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) { | |
| objects_.Add(reinterpret_cast<ExternalTypedData*>(object)); | |
| } | |
| void WriteNodesApi(ApiMessageSerializer* s) { | |
| intptr_t element_size = ExternalTypedData::ElementSizeInBytes(cid_); | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* data = reinterpret_cast<Dart_CObject*>(objects_[i]); | |
| s->AssignRef(data); | |
| intptr_t length = data->value.as_external_typed_data.length; | |
| s->WriteUnsigned(length); | |
| s->finalizable_data()->Put(length * element_size, | |
| data->value.as_external_typed_data.data, | |
| data->value.as_external_typed_data.peer, | |
| data->value.as_external_typed_data.callback); | |
| } | |
| } | |
| private: | |
| GrowableArray<ExternalTypedData*> objects_; | |
| }; | |
| class ExternalTypedDataMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| explicit ExternalTypedDataMessageDeserializationCluster(intptr_t cid) | |
| : MessageDeserializationCluster("ExternalTypedData"), cid_(cid) {} | |
| ~ExternalTypedDataMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| intptr_t element_size = ExternalTypedData::ElementSizeInBytes(cid_); | |
| intptr_t count = d->ReadUnsigned(); | |
| ExternalTypedData& data = ExternalTypedData::Handle(d->zone()); | |
| for (intptr_t i = 0; i < count; i++) { | |
| intptr_t length = d->ReadUnsigned(); | |
| FinalizableData finalizable_data = d->finalizable_data()->Take(); | |
| data = ExternalTypedData::New( | |
| cid_, reinterpret_cast<uint8_t*>(finalizable_data.data), length); | |
| intptr_t external_size = length * element_size; | |
| data.AddFinalizer(finalizable_data.peer, finalizable_data.callback, | |
| external_size); | |
| d->AssignRef(data.ptr()); | |
| } | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| Dart_TypedData_Type type; | |
| switch (cid_) { | |
| case kExternalTypedDataInt8ArrayCid: | |
| type = Dart_TypedData_kInt8; | |
| break; | |
| case kExternalTypedDataUint8ArrayCid: | |
| type = Dart_TypedData_kUint8; | |
| break; | |
| case kExternalTypedDataUint8ClampedArrayCid: | |
| type = Dart_TypedData_kUint8Clamped; | |
| break; | |
| case kExternalTypedDataInt16ArrayCid: | |
| type = Dart_TypedData_kInt16; | |
| break; | |
| case kExternalTypedDataUint16ArrayCid: | |
| type = Dart_TypedData_kUint16; | |
| break; | |
| case kExternalTypedDataInt32ArrayCid: | |
| type = Dart_TypedData_kInt32; | |
| break; | |
| case kExternalTypedDataUint32ArrayCid: | |
| type = Dart_TypedData_kUint32; | |
| break; | |
| case kExternalTypedDataInt64ArrayCid: | |
| type = Dart_TypedData_kInt64; | |
| break; | |
| case kExternalTypedDataUint64ArrayCid: | |
| type = Dart_TypedData_kUint64; | |
| break; | |
| case kExternalTypedDataFloat32ArrayCid: | |
| type = Dart_TypedData_kFloat32; | |
| break; | |
| case kExternalTypedDataFloat64ArrayCid: | |
| type = Dart_TypedData_kFloat64; | |
| break; | |
| case kExternalTypedDataInt32x4ArrayCid: | |
| type = Dart_TypedData_kInt32x4; | |
| break; | |
| case kExternalTypedDataFloat32x4ArrayCid: | |
| type = Dart_TypedData_kFloat32x4; | |
| break; | |
| case kExternalTypedDataFloat64x2ArrayCid: | |
| type = Dart_TypedData_kFloat64x2; | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* data = d->Allocate(Dart_CObject_kTypedData); | |
| intptr_t length = d->ReadUnsigned(); | |
| FinalizableData finalizable_data = d->finalizable_data()->Get(); | |
| data->value.as_typed_data.type = type; | |
| data->value.as_typed_data.length = length; | |
| data->value.as_typed_data.values = | |
| reinterpret_cast<uint8_t*>(finalizable_data.data); | |
| d->AssignRef(data); | |
| } | |
| } | |
| private: | |
| const intptr_t cid_; | |
| }; | |
| class NativePointerMessageSerializationCluster | |
| : public MessageSerializationCluster { | |
| public: | |
| explicit NativePointerMessageSerializationCluster(Zone* zone) | |
| : MessageSerializationCluster("NativePointer", | |
| MessagePhase::kNonCanonicalInstances, | |
| kNativePointer), | |
| objects_(zone, 0) {} | |
| ~NativePointerMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { UNREACHABLE(); } | |
| void WriteNodes(MessageSerializer* s) { UNREACHABLE(); } | |
| void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) { | |
| objects_.Add(object); | |
| } | |
| void WriteNodesApi(ApiMessageSerializer* s) { | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* data = objects_[i]; | |
| s->AssignRef(data); | |
| s->finalizable_data()->Put( | |
| data->value.as_native_pointer.size, | |
| reinterpret_cast<void*>(data->value.as_native_pointer.ptr), | |
| reinterpret_cast<void*>(data->value.as_native_pointer.ptr), | |
| data->value.as_native_pointer.callback); | |
| } | |
| } | |
| private: | |
| GrowableArray<Dart_CObject*> objects_; | |
| }; | |
| class NativePointerMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| NativePointerMessageDeserializationCluster() | |
| : MessageDeserializationCluster("NativePointer"), cid_(kNativePointer) {} | |
| ~NativePointerMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| FinalizableData finalizable_data = d->finalizable_data()->Take(); | |
| intptr_t ptr = reinterpret_cast<intptr_t>(finalizable_data.data); | |
| d->AssignRef(Integer::New(ptr)); | |
| } | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { UNREACHABLE(); } | |
| private: | |
| const intptr_t cid_; | |
| }; | |
| enum TypedDataViewFormat { | |
| kTypedDataViewFromC, | |
| kTypedDataViewFromDart, | |
| }; | |
| class TypedDataViewMessageSerializationCluster | |
| : public MessageSerializationCluster { | |
| public: | |
| explicit TypedDataViewMessageSerializationCluster(Zone* zone, intptr_t cid) | |
| : MessageSerializationCluster("TypedDataView", | |
| MessagePhase::kNonCanonicalInstances, | |
| cid), | |
| objects_(zone, 0) {} | |
| ~TypedDataViewMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| TypedDataView* view = static_cast<TypedDataView*>(object); | |
| objects_.Add(view); | |
| s->Push(view->untag()->length()); | |
| s->Push(view->untag()->typed_data()); | |
| s->Push(view->untag()->offset_in_bytes()); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| s->Write<TypedDataViewFormat>(kTypedDataViewFromDart); | |
| for (intptr_t i = 0; i < count; i++) { | |
| TypedDataView* view = objects_[i]; | |
| s->AssignRef(view); | |
| } | |
| } | |
| void WriteEdges(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| TypedDataView* view = objects_[i]; | |
| s->WriteRef(view->untag()->length()); | |
| s->WriteRef(view->untag()->typed_data()); | |
| s->WriteRef(view->untag()->offset_in_bytes()); | |
| } | |
| } | |
| void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) { | |
| ASSERT(object->type == Dart_CObject_kUnmodifiableExternalTypedData); | |
| objects_.Add(reinterpret_cast<TypedDataView*>(object)); | |
| } | |
| void WriteNodesApi(ApiMessageSerializer* s) { | |
| intptr_t element_size = TypedDataView::ElementSizeInBytes(cid_); | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| s->Write<TypedDataViewFormat>(kTypedDataViewFromC); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* data = reinterpret_cast<Dart_CObject*>(objects_[i]); | |
| s->AssignRef(data); | |
| intptr_t length = data->value.as_external_typed_data.length; | |
| s->WriteUnsigned(length); | |
| s->finalizable_data()->Put(length * element_size, | |
| data->value.as_external_typed_data.data, | |
| data->value.as_external_typed_data.peer, | |
| data->value.as_external_typed_data.callback); | |
| } | |
| } | |
| private: | |
| GrowableArray<TypedDataView*> objects_; | |
| }; | |
| class TypedDataViewMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| explicit TypedDataViewMessageDeserializationCluster(intptr_t cid) | |
| : MessageDeserializationCluster("TypedDataView"), cid_(cid) {} | |
| ~TypedDataViewMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| format_ = d->Read<TypedDataViewFormat>(); | |
| if (format_ == kTypedDataViewFromC) { | |
| intptr_t view_cid = cid_; | |
| ASSERT(IsUnmodifiableTypedDataViewClassId(view_cid)); | |
| intptr_t backing_cid = cid_ - kTypedDataCidRemainderUnmodifiable + | |
| kTypedDataCidRemainderExternal; | |
| ASSERT(IsExternalTypedDataClassId(backing_cid)); | |
| intptr_t element_size = | |
| ExternalTypedData::ElementSizeInBytes(backing_cid); | |
| ExternalTypedData& data = ExternalTypedData::Handle(d->zone()); | |
| TypedDataView& view = TypedDataView::Handle(d->zone()); | |
| for (intptr_t i = 0; i < count; i++) { | |
| intptr_t length = d->ReadUnsigned(); | |
| FinalizableData finalizable_data = d->finalizable_data()->Take(); | |
| data = ExternalTypedData::New( | |
| backing_cid, reinterpret_cast<uint8_t*>(finalizable_data.data), | |
| length); | |
| data.SetDeeplyImmutable(); // Can pass by reference. | |
| intptr_t external_size = length * element_size; | |
| data.AddFinalizer(finalizable_data.peer, finalizable_data.callback, | |
| external_size); | |
| view = TypedDataView::New(view_cid, data, 0, length); | |
| d->AssignRef(data.ptr()); | |
| } | |
| } else { | |
| for (intptr_t i = 0; i < count; i++) { | |
| d->AssignRef(TypedDataView::New(cid_)); | |
| } | |
| } | |
| } | |
| void ReadEdges(MessageDeserializer* d) { | |
| if (format_ == kTypedDataViewFromC) return; | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| TypedDataViewPtr view = static_cast<TypedDataViewPtr>(d->Ref(id)); | |
| view->untag()->set_length(static_cast<SmiPtr>(d->ReadRef())); | |
| view->untag()->set_typed_data( | |
| static_cast<TypedDataBasePtr>(d->ReadRef())); | |
| view->untag()->set_offset_in_bytes(static_cast<SmiPtr>(d->ReadRef())); | |
| } | |
| } | |
| ObjectPtr PostLoad(MessageDeserializer* d) { | |
| if (format_ == kTypedDataViewFromC) return nullptr; | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| TypedDataViewPtr view = static_cast<TypedDataViewPtr>(d->Ref(id)); | |
| view->untag()->RecomputeDataField(); | |
| } | |
| return nullptr; | |
| } | |
| struct Dart_CTypedDataView : public Dart_CObject { | |
| Dart_CObject* length; | |
| Dart_CObject* typed_data; | |
| Dart_CObject* offset_in_bytes; | |
| }; | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| format_ = d->Read<TypedDataViewFormat>(); | |
| if (format_ == kTypedDataViewFromC) { | |
| Dart_TypedData_Type type; | |
| switch (cid_) { | |
| case kUnmodifiableTypedDataInt8ArrayViewCid: | |
| type = Dart_TypedData_kInt8; | |
| break; | |
| case kUnmodifiableTypedDataUint8ArrayViewCid: | |
| type = Dart_TypedData_kUint8; | |
| break; | |
| case kUnmodifiableTypedDataUint8ClampedArrayViewCid: | |
| type = Dart_TypedData_kUint8Clamped; | |
| break; | |
| case kUnmodifiableTypedDataInt16ArrayViewCid: | |
| type = Dart_TypedData_kInt16; | |
| break; | |
| case kUnmodifiableTypedDataUint16ArrayViewCid: | |
| type = Dart_TypedData_kUint16; | |
| break; | |
| case kUnmodifiableTypedDataInt32ArrayViewCid: | |
| type = Dart_TypedData_kInt32; | |
| break; | |
| case kUnmodifiableTypedDataUint32ArrayViewCid: | |
| type = Dart_TypedData_kUint32; | |
| break; | |
| case kUnmodifiableTypedDataInt64ArrayViewCid: | |
| type = Dart_TypedData_kInt64; | |
| break; | |
| case kUnmodifiableTypedDataUint64ArrayViewCid: | |
| type = Dart_TypedData_kUint64; | |
| break; | |
| case kUnmodifiableTypedDataFloat32ArrayViewCid: | |
| type = Dart_TypedData_kFloat32; | |
| break; | |
| case kUnmodifiableTypedDataFloat64ArrayViewCid: | |
| type = Dart_TypedData_kFloat64; | |
| break; | |
| case kUnmodifiableTypedDataInt32x4ArrayViewCid: | |
| type = Dart_TypedData_kInt32x4; | |
| break; | |
| case kUnmodifiableTypedDataFloat32x4ArrayViewCid: | |
| type = Dart_TypedData_kFloat32x4; | |
| break; | |
| case kUnmodifiableTypedDataFloat64x2ArrayViewCid: | |
| type = Dart_TypedData_kFloat64x2; | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| Dart_CObject* data = | |
| d->Allocate(Dart_CObject_kUnmodifiableExternalTypedData); | |
| intptr_t length = d->ReadUnsigned(); | |
| FinalizableData finalizable_data = d->finalizable_data()->Get(); | |
| data->value.as_typed_data.type = type; | |
| data->value.as_typed_data.length = length; | |
| data->value.as_typed_data.values = | |
| reinterpret_cast<uint8_t*>(finalizable_data.data); | |
| d->AssignRef(data); | |
| } else { | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CTypedDataView* view = d->zone()->Alloc<Dart_CTypedDataView>(1); | |
| d->AssignRef(view); | |
| } | |
| } | |
| } | |
| void ReadEdgesApi(ApiMessageDeserializer* d) { | |
| if (format_ == kTypedDataViewFromC) return; | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| Dart_CTypedDataView* view = static_cast<Dart_CTypedDataView*>(d->Ref(id)); | |
| view->length = d->ReadRef(); | |
| view->typed_data = d->ReadRef(); | |
| view->offset_in_bytes = d->ReadRef(); | |
| } | |
| } | |
| void PostLoadApi(ApiMessageDeserializer* d) { | |
| if (format_ == kTypedDataViewFromC) return; | |
| Dart_TypedData_Type type; | |
| switch (cid_) { | |
| case kTypedDataInt8ArrayViewCid: | |
| case kUnmodifiableTypedDataInt8ArrayViewCid: | |
| type = Dart_TypedData_kInt8; | |
| break; | |
| case kTypedDataUint8ArrayViewCid: | |
| case kUnmodifiableTypedDataUint8ArrayViewCid: | |
| type = Dart_TypedData_kUint8; | |
| break; | |
| case kTypedDataUint8ClampedArrayViewCid: | |
| case kUnmodifiableTypedDataUint8ClampedArrayViewCid: | |
| type = Dart_TypedData_kUint8Clamped; | |
| break; | |
| case kTypedDataInt16ArrayViewCid: | |
| case kUnmodifiableTypedDataInt16ArrayViewCid: | |
| type = Dart_TypedData_kInt16; | |
| break; | |
| case kTypedDataUint16ArrayViewCid: | |
| case kUnmodifiableTypedDataUint16ArrayViewCid: | |
| type = Dart_TypedData_kUint16; | |
| break; | |
| case kTypedDataInt32ArrayViewCid: | |
| case kUnmodifiableTypedDataInt32ArrayViewCid: | |
| type = Dart_TypedData_kInt32; | |
| break; | |
| case kTypedDataUint32ArrayViewCid: | |
| case kUnmodifiableTypedDataUint32ArrayViewCid: | |
| type = Dart_TypedData_kUint32; | |
| break; | |
| case kTypedDataInt64ArrayViewCid: | |
| case kUnmodifiableTypedDataInt64ArrayViewCid: | |
| type = Dart_TypedData_kInt64; | |
| break; | |
| case kTypedDataUint64ArrayViewCid: | |
| case kUnmodifiableTypedDataUint64ArrayViewCid: | |
| type = Dart_TypedData_kUint64; | |
| break; | |
| case kTypedDataFloat32ArrayViewCid: | |
| case kUnmodifiableTypedDataFloat32ArrayViewCid: | |
| type = Dart_TypedData_kFloat32; | |
| break; | |
| case kTypedDataFloat64ArrayViewCid: | |
| case kUnmodifiableTypedDataFloat64ArrayViewCid: | |
| type = Dart_TypedData_kFloat64; | |
| break; | |
| case kTypedDataInt32x4ArrayViewCid: | |
| case kUnmodifiableTypedDataInt32x4ArrayViewCid: | |
| type = Dart_TypedData_kInt32x4; | |
| break; | |
| case kTypedDataFloat32x4ArrayViewCid: | |
| case kUnmodifiableTypedDataFloat32x4ArrayViewCid: | |
| type = Dart_TypedData_kFloat32x4; | |
| break; | |
| case kTypedDataFloat64x2ArrayViewCid: | |
| case kUnmodifiableTypedDataFloat64x2ArrayViewCid: | |
| type = Dart_TypedData_kFloat64x2; | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| Dart_CTypedDataView* view = static_cast<Dart_CTypedDataView*>(d->Ref(id)); | |
| if (view->typed_data->type == Dart_CObject_kTypedData) { | |
| view->type = Dart_CObject_kTypedData; | |
| view->value.as_typed_data.type = type; | |
| view->value.as_typed_data.length = view->length->value.as_int32; | |
| view->value.as_typed_data.values = | |
| view->typed_data->value.as_typed_data.values + | |
| view->offset_in_bytes->value.as_int32; | |
| } else { | |
| UNREACHABLE(); | |
| } | |
| } | |
| } | |
| private: | |
| const intptr_t cid_; | |
| TypedDataViewFormat format_; | |
| }; | |
| class TransferableTypedDataMessageSerializationCluster | |
| : public MessageSerializationCluster { | |
| public: | |
| TransferableTypedDataMessageSerializationCluster() | |
| : MessageSerializationCluster("TransferableTypedData", | |
| MessagePhase::kNonCanonicalInstances, | |
| kTransferableTypedDataCid) {} | |
| ~TransferableTypedDataMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| TransferableTypedData* transferable = | |
| static_cast<TransferableTypedData*>(object); | |
| objects_.Add(transferable); | |
| void* peer = s->thread()->heap()->GetPeer(transferable->ptr()); | |
| // Assume that object's Peer is only used to track transferability state. | |
| ASSERT(peer != nullptr); | |
| TransferableTypedDataPeer* tpeer = | |
| reinterpret_cast<TransferableTypedDataPeer*>(peer); | |
| if (tpeer->data() == nullptr) { | |
| s->IllegalObject(*object, | |
| "TransferableTypedData has been transferred already"); | |
| } | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| TransferableTypedData* transferable = objects_[i]; | |
| s->AssignRef(transferable); | |
| void* peer = s->thread()->heap()->GetPeer(transferable->ptr()); | |
| // Assume that object's Peer is only used to track transferability state. | |
| ASSERT(peer != nullptr); | |
| TransferableTypedDataPeer* tpeer = | |
| reinterpret_cast<TransferableTypedDataPeer*>(peer); | |
| intptr_t length = tpeer->length(); // In bytes. | |
| void* data = tpeer->data(); | |
| ASSERT(data != nullptr); | |
| s->WriteUnsigned(length); | |
| s->finalizable_data()->Put( | |
| length, data, tpeer, | |
| // Finalizer does nothing - in case of failure to serialize, | |
| // [data] remains wrapped in sender's [TransferableTypedData]. | |
| [](void* data, void* peer) {}, | |
| // This is invoked on successful serialization of the message | |
| [](void* data, void* peer) { | |
| TransferableTypedDataPeer* ttpeer = | |
| reinterpret_cast<TransferableTypedDataPeer*>(peer); | |
| ttpeer->handle()->EnsureFreedExternal(IsolateGroup::Current()); | |
| ttpeer->ClearData(); | |
| }); | |
| } | |
| } | |
| private: | |
| GrowableArray<TransferableTypedData*> objects_; | |
| }; | |
| class TransferableTypedDataMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| TransferableTypedDataMessageDeserializationCluster() | |
| : MessageDeserializationCluster("TransferableTypedData") {} | |
| ~TransferableTypedDataMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| intptr_t length = d->ReadUnsigned(); | |
| const FinalizableData finalizable_data = d->finalizable_data()->Take(); | |
| d->AssignRef(TransferableTypedData::New( | |
| reinterpret_cast<uint8_t*>(finalizable_data.data), length)); | |
| } | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* data = d->Allocate(Dart_CObject_kTypedData); | |
| data->value.as_typed_data.length = d->ReadUnsigned(); | |
| data->value.as_typed_data.type = Dart_TypedData_kUint8; | |
| FinalizableData finalizable_data = d->finalizable_data()->Get(); | |
| data->value.as_typed_data.values = | |
| reinterpret_cast<const uint8_t*>(finalizable_data.data); | |
| d->AssignRef(data); | |
| } | |
| } | |
| }; | |
| class Simd128MessageSerializationCluster : public MessageSerializationCluster { | |
| public: | |
| explicit Simd128MessageSerializationCluster(intptr_t cid) | |
| : MessageSerializationCluster("Simd128", | |
| MessagePhase::kBeforeTypes, | |
| cid) {} | |
| ~Simd128MessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { objects_.Add(object); } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Object* vector = objects_[i]; | |
| s->AssignRef(vector); | |
| ASSERT_EQUAL(Int32x4::value_offset(), Float32x4::value_offset()); | |
| ASSERT_EQUAL(Int32x4::value_offset(), Float64x2::value_offset()); | |
| s->WriteBytes(&(static_cast<Int32x4Ptr>(vector->ptr())->untag()->value_), | |
| sizeof(simd128_value_t)); | |
| } | |
| } | |
| private: | |
| GrowableArray<Object*> objects_; | |
| }; | |
| class Simd128MessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| explicit Simd128MessageDeserializationCluster(intptr_t cid) | |
| : MessageDeserializationCluster("Simd128"), cid_(cid) { | |
| ASSERT(cid_ == kInt32x4Cid || cid_ == kFloat32x4Cid || | |
| cid_ == kFloat64x2Cid); | |
| #if defined(DEBUG) | |
| // If not for Int32x4, check that all the Int32x4-specific arguments used in | |
| // ReadNodes match those for the actual class. | |
| if (cid_ == kFloat32x4Cid) { | |
| AssertSameStructure<Int32x4, Float32x4>(); | |
| } else if (cid_ == kFloat64x2Cid) { | |
| AssertSameStructure<Int32x4, Float64x2>(); | |
| } | |
| #endif | |
| } | |
| ~Simd128MessageDeserializationCluster() {} | |
| #if defined(DEBUG) | |
| template <typename Expected, typename Got> | |
| static void AssertSameStructure() { | |
| ASSERT_EQUAL(Got::InstanceSize(), Expected::InstanceSize()); | |
| ASSERT_EQUAL(Got::ContainsCompressedPointers(), | |
| Expected::ContainsCompressedPointers()); | |
| ASSERT_EQUAL(Object::from_offset<Got>(), Object::from_offset<Expected>()); | |
| ASSERT_EQUAL(Object::to_offset<Got>(), Object::to_offset<Expected>()); | |
| ASSERT_EQUAL(Got::value_offset(), Expected::value_offset()); | |
| } | |
| #endif | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| ObjectPtr vector = Object::Allocate( | |
| cid_, Int32x4::InstanceSize(), Heap::kNew, | |
| Int32x4::ContainsCompressedPointers(), Object::from_offset<Int32x4>(), | |
| Object::to_offset<Int32x4>()); | |
| d->AssignRef(vector); | |
| d->ReadBytes(&(static_cast<Int32x4Ptr>(vector)->untag()->value_), | |
| sizeof(simd128_value_t)); | |
| } | |
| } | |
| private: | |
| const intptr_t cid_; | |
| }; | |
| class SendPortMessageSerializationCluster : public MessageSerializationCluster { | |
| public: | |
| explicit SendPortMessageSerializationCluster(Zone* zone) | |
| : MessageSerializationCluster("SendPort", | |
| MessagePhase::kNonCanonicalInstances, | |
| kSendPortCid), | |
| objects_(zone, 0) {} | |
| ~SendPortMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| SendPort* port = static_cast<SendPort*>(object); | |
| objects_.Add(port); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| SendPort* port = objects_[i]; | |
| s->AssignRef(port); | |
| s->Write<Dart_Port>(port->untag()->id_); | |
| s->Write<Dart_Port>(port->untag()->origin_id_); | |
| } | |
| } | |
| void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) { | |
| objects_.Add(reinterpret_cast<SendPort*>(object)); | |
| } | |
| void WriteNodesApi(ApiMessageSerializer* s) { | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* port = reinterpret_cast<Dart_CObject*>(objects_[i]); | |
| s->AssignRef(port); | |
| s->Write<Dart_Port>(port->value.as_send_port.id); | |
| s->Write<Dart_Port>(port->value.as_send_port.origin_id); | |
| } | |
| } | |
| private: | |
| GrowableArray<SendPort*> objects_; | |
| }; | |
| class SendPortMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| SendPortMessageDeserializationCluster() | |
| : MessageDeserializationCluster("SendPort") {} | |
| ~SendPortMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_Port id = d->Read<Dart_Port>(); | |
| Dart_Port origin_id = d->Read<Dart_Port>(); | |
| d->AssignRef(SendPort::New(id, origin_id)); | |
| } | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* port = d->Allocate(Dart_CObject_kSendPort); | |
| port->value.as_send_port.id = d->Read<Dart_Port>(); | |
| port->value.as_send_port.origin_id = d->Read<Dart_Port>(); | |
| d->AssignRef(port); | |
| } | |
| } | |
| }; | |
| class CapabilityMessageSerializationCluster | |
| : public MessageSerializationCluster { | |
| public: | |
| explicit CapabilityMessageSerializationCluster(Zone* zone) | |
| : MessageSerializationCluster("Capability", | |
| MessagePhase::kNonCanonicalInstances, | |
| kCapabilityCid), | |
| objects_(zone, 0) {} | |
| ~CapabilityMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| Capability* cap = static_cast<Capability*>(object); | |
| objects_.Add(cap); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Capability* cap = objects_[i]; | |
| s->AssignRef(cap); | |
| s->Write<uint64_t>(cap->untag()->id_); | |
| } | |
| } | |
| void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) { | |
| objects_.Add(reinterpret_cast<Capability*>(object)); | |
| } | |
| void WriteNodesApi(ApiMessageSerializer* s) { | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* cap = reinterpret_cast<Dart_CObject*>(objects_[i]); | |
| s->AssignRef(cap); | |
| s->Write<Dart_Port>(cap->value.as_capability.id); | |
| } | |
| } | |
| private: | |
| GrowableArray<Capability*> objects_; | |
| }; | |
| class CapabilityMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| CapabilityMessageDeserializationCluster() | |
| : MessageDeserializationCluster("Capability") {} | |
| ~CapabilityMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| uint64_t id = d->Read<uint64_t>(); | |
| d->AssignRef(Capability::New(id)); | |
| } | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* cap = d->Allocate(Dart_CObject_kCapability); | |
| cap->value.as_capability.id = d->Read<uint64_t>(); | |
| d->AssignRef(cap); | |
| } | |
| } | |
| }; | |
| class MapMessageSerializationCluster : public MessageSerializationCluster { | |
| public: | |
| MapMessageSerializationCluster(Zone* zone, bool is_canonical, intptr_t cid) | |
| : MessageSerializationCluster("Map", | |
| is_canonical | |
| ? MessagePhase::kCanonicalInstances | |
| : MessagePhase::kNonCanonicalInstances, | |
| cid, | |
| is_canonical), | |
| objects_(zone, 0) {} | |
| ~MapMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| Map* map = static_cast<Map*>(object); | |
| objects_.Add(map); | |
| // Compensation for bogus type prefix optimization. | |
| TypeArguments& args = | |
| TypeArguments::Handle(s->zone(), map->untag()->type_arguments()); | |
| if (!args.IsNull() && (args.Length() != 2)) { | |
| args = args.TruncatedTo(2); | |
| map->untag()->set_type_arguments(args.ptr()); | |
| } | |
| s->Push(map->untag()->type_arguments()); | |
| s->Push(map->untag()->data()); | |
| s->Push(map->untag()->used_data()); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Map* map = objects_[i]; | |
| s->AssignRef(map); | |
| } | |
| } | |
| void WriteEdges(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Map* map = objects_[i]; | |
| s->WriteRef(map->untag()->type_arguments()); | |
| s->WriteRef(map->untag()->data()); | |
| s->WriteRef(map->untag()->used_data()); | |
| } | |
| } | |
| private: | |
| GrowableArray<Map*> objects_; | |
| }; | |
| class MapMessageDeserializationCluster : public MessageDeserializationCluster { | |
| public: | |
| MapMessageDeserializationCluster(bool is_canonical, intptr_t cid) | |
| : MessageDeserializationCluster("Map", is_canonical), cid_(cid) {} | |
| ~MapMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| d->AssignRef(Map::NewUninitialized(cid_)); | |
| } | |
| } | |
| void ReadEdges(MessageDeserializer* d) { | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| MapPtr map = static_cast<MapPtr>(d->Ref(id)); | |
| map->untag()->set_hash_mask(Smi::New(0)); | |
| map->untag()->set_type_arguments( | |
| static_cast<TypeArgumentsPtr>(d->ReadRef())); | |
| map->untag()->set_data(static_cast<ArrayPtr>(d->ReadRef())); | |
| map->untag()->set_used_data(static_cast<SmiPtr>(d->ReadRef())); | |
| map->untag()->set_deleted_keys(Smi::New(0)); | |
| } | |
| } | |
| ObjectPtr PostLoad(MessageDeserializer* d) { | |
| if (!is_canonical()) { | |
| ASSERT(cid_ == kMapCid); | |
| return PostLoadLinkedHash(d); | |
| } | |
| ASSERT(cid_ == kConstMapCid); | |
| SafepointMutexLocker ml( | |
| d->isolate_group()->constant_canonicalization_mutex()); | |
| Map& instance = Map::Handle(d->zone()); | |
| for (intptr_t i = start_index_; i < stop_index_; i++) { | |
| instance ^= d->Ref(i); | |
| instance ^= instance.CanonicalizeLocked(d->thread()); | |
| d->UpdateRef(i, instance); | |
| } | |
| return nullptr; | |
| } | |
| private: | |
| const intptr_t cid_; | |
| }; | |
| class SetMessageSerializationCluster : public MessageSerializationCluster { | |
| public: | |
| SetMessageSerializationCluster(Zone* zone, bool is_canonical, intptr_t cid) | |
| : MessageSerializationCluster("Set", | |
| is_canonical | |
| ? MessagePhase::kCanonicalInstances | |
| : MessagePhase::kNonCanonicalInstances, | |
| cid, | |
| is_canonical), | |
| objects_(zone, 0) {} | |
| ~SetMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| Set* set = static_cast<Set*>(object); | |
| objects_.Add(set); | |
| // Compensation for bogus type prefix optimization. | |
| TypeArguments& args = | |
| TypeArguments::Handle(s->zone(), set->untag()->type_arguments()); | |
| if (!args.IsNull() && (args.Length() != 1)) { | |
| args = args.TruncatedTo(1); | |
| set->untag()->set_type_arguments(args.ptr()); | |
| } | |
| s->Push(set->untag()->type_arguments()); | |
| s->Push(set->untag()->data()); | |
| s->Push(set->untag()->used_data()); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Set* set = objects_[i]; | |
| s->AssignRef(set); | |
| } | |
| } | |
| void WriteEdges(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Set* set = objects_[i]; | |
| s->WriteRef(set->untag()->type_arguments()); | |
| s->WriteRef(set->untag()->data()); | |
| s->WriteRef(set->untag()->used_data()); | |
| } | |
| } | |
| private: | |
| GrowableArray<Set*> objects_; | |
| }; | |
| class SetMessageDeserializationCluster : public MessageDeserializationCluster { | |
| public: | |
| SetMessageDeserializationCluster(bool is_canonical, intptr_t cid) | |
| : MessageDeserializationCluster("Set", is_canonical), cid_(cid) {} | |
| ~SetMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| d->AssignRef(Set::NewUninitialized(cid_)); | |
| } | |
| } | |
| void ReadEdges(MessageDeserializer* d) { | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| SetPtr map = static_cast<SetPtr>(d->Ref(id)); | |
| map->untag()->set_hash_mask(Smi::New(0)); | |
| map->untag()->set_type_arguments( | |
| static_cast<TypeArgumentsPtr>(d->ReadRef())); | |
| map->untag()->set_data(static_cast<ArrayPtr>(d->ReadRef())); | |
| map->untag()->set_used_data(static_cast<SmiPtr>(d->ReadRef())); | |
| map->untag()->set_deleted_keys(Smi::New(0)); | |
| } | |
| } | |
| ObjectPtr PostLoad(MessageDeserializer* d) { | |
| if (!is_canonical()) { | |
| ASSERT(cid_ == kSetCid); | |
| return PostLoadLinkedHash(d); | |
| } | |
| ASSERT(cid_ == kConstSetCid); | |
| SafepointMutexLocker ml( | |
| d->isolate_group()->constant_canonicalization_mutex()); | |
| Set& instance = Set::Handle(d->zone()); | |
| for (intptr_t i = start_index_; i < stop_index_; i++) { | |
| instance ^= d->Ref(i); | |
| instance ^= instance.CanonicalizeLocked(d->thread()); | |
| d->UpdateRef(i, instance); | |
| } | |
| return nullptr; | |
| } | |
| private: | |
| const intptr_t cid_; | |
| }; | |
| class ArrayMessageSerializationCluster : public MessageSerializationCluster { | |
| public: | |
| ArrayMessageSerializationCluster(Zone* zone, bool is_canonical, intptr_t cid) | |
| : MessageSerializationCluster("Array", | |
| is_canonical | |
| ? MessagePhase::kCanonicalInstances | |
| : MessagePhase::kNonCanonicalInstances, | |
| cid, | |
| is_canonical), | |
| objects_(zone, 0) {} | |
| ~ArrayMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| Array* array = static_cast<Array*>(object); | |
| objects_.Add(array); | |
| // Compensation for bogus type prefix optimization. | |
| TypeArguments& args = | |
| TypeArguments::Handle(s->zone(), array->untag()->type_arguments()); | |
| if (!args.IsNull() && (args.Length() != 1)) { | |
| args = args.TruncatedTo(1); | |
| array->untag()->set_type_arguments(args.ptr()); | |
| } | |
| s->Push(array->untag()->type_arguments()); | |
| intptr_t length = Smi::Value(array->untag()->length()); | |
| for (intptr_t i = 0; i < length; i++) { | |
| s->Push(array->untag()->element(i)); | |
| } | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Array* array = objects_[i]; | |
| s->AssignRef(array); | |
| intptr_t length = Smi::Value(array->untag()->length()); | |
| s->WriteUnsigned(length); | |
| } | |
| } | |
| void WriteEdges(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Array* array = objects_[i]; | |
| intptr_t length = array->Length(); | |
| s->WriteRef(array->untag()->type_arguments()); | |
| for (intptr_t j = 0; j < length; j++) { | |
| s->WriteRef(array->untag()->element(j)); | |
| } | |
| } | |
| } | |
| void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) { | |
| objects_.Add(reinterpret_cast<Array*>(object)); | |
| for (intptr_t i = 0, n = object->value.as_array.length; i < n; i++) { | |
| s->Push(object->value.as_array.values[i]); | |
| } | |
| } | |
| void WriteNodesApi(ApiMessageSerializer* s) { | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* array = reinterpret_cast<Dart_CObject*>(objects_[i]); | |
| s->AssignRef(array); | |
| s->WriteUnsigned(array->value.as_array.length); | |
| } | |
| } | |
| void WriteEdgesApi(ApiMessageSerializer* s) { | |
| intptr_t count = objects_.length(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* array = reinterpret_cast<Dart_CObject*>(objects_[i]); | |
| intptr_t length = array->value.as_array.length; | |
| s->WriteRef(&cobj_null); // TypeArguments | |
| for (intptr_t j = 0; j < length; j++) { | |
| s->WriteRef(array->value.as_array.values[j]); | |
| } | |
| } | |
| } | |
| private: | |
| GrowableArray<Array*> objects_; | |
| }; | |
| class ArrayMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| explicit ArrayMessageDeserializationCluster(bool is_canonical, intptr_t cid) | |
| : MessageDeserializationCluster("Array", is_canonical), cid_(cid) {} | |
| ~ArrayMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| intptr_t length = d->ReadUnsigned(); | |
| d->AssignRef(Array::NewUninitialized(cid_, length)); | |
| } | |
| } | |
| void ReadEdges(MessageDeserializer* d) { | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| ArrayPtr array = static_cast<ArrayPtr>(d->Ref(id)); | |
| intptr_t length = Smi::Value(array->untag()->length()); | |
| array->untag()->set_type_arguments( | |
| static_cast<TypeArgumentsPtr>(d->ReadRef())); | |
| for (intptr_t j = 0; j < length; j++) { | |
| array->untag()->set_element(j, d->ReadRef()); | |
| } | |
| } | |
| } | |
| ObjectPtr PostLoad(MessageDeserializer* d) { | |
| if (is_canonical()) { | |
| SafepointMutexLocker ml( | |
| d->isolate_group()->constant_canonicalization_mutex()); | |
| Instance& instance = Instance::Handle(d->zone()); | |
| for (intptr_t i = start_index_; i < stop_index_; i++) { | |
| instance ^= d->Ref(i); | |
| instance = instance.CanonicalizeLocked(d->thread()); | |
| d->UpdateRef(i, instance); | |
| } | |
| } | |
| return nullptr; | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* array = d->Allocate(Dart_CObject_kArray); | |
| intptr_t length = d->ReadUnsigned(); | |
| array->value.as_array.length = length; | |
| if (length == 0) { | |
| array->value.as_array.values = nullptr; | |
| } else { | |
| array->value.as_array.values = d->zone()->Alloc<Dart_CObject*>(length); | |
| } | |
| d->AssignRef(array); | |
| } | |
| } | |
| void ReadEdgesApi(ApiMessageDeserializer* d) { | |
| for (intptr_t id = start_index_; id < stop_index_; id++) { | |
| Dart_CObject* array = d->Ref(id); | |
| intptr_t length = array->value.as_array.length; | |
| d->ReadRef(); // type_arguments | |
| for (intptr_t i = 0; i < length; i++) { | |
| array->value.as_array.values[i] = d->ReadRef(); | |
| } | |
| } | |
| } | |
| private: | |
| const intptr_t cid_; | |
| }; | |
| class OneByteStringMessageSerializationCluster | |
| : public MessageSerializationCluster { | |
| public: | |
| explicit OneByteStringMessageSerializationCluster(Zone* zone, | |
| bool is_canonical) | |
| : MessageSerializationCluster("OneByteString", | |
| MessagePhase::kBeforeTypes, | |
| kOneByteStringCid, | |
| is_canonical), | |
| objects_(zone, 0) {} | |
| ~OneByteStringMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| String* str = static_cast<String*>(object); | |
| objects_.Add(str); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| String* str = objects_[i]; | |
| s->AssignRef(str); | |
| intptr_t length = str->Length(); | |
| s->WriteUnsigned(length); | |
| NoSafepointScope no_safepoint; | |
| s->WriteBytes(OneByteString::DataStart(*str), length * sizeof(uint8_t)); | |
| } | |
| } | |
| void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) { | |
| objects_.Add(reinterpret_cast<String*>(object)); | |
| } | |
| void WriteNodesApi(ApiMessageSerializer* s) { | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* str = reinterpret_cast<Dart_CObject*>(objects_[i]); | |
| s->AssignRef(str); | |
| const uint8_t* utf8_str = | |
| reinterpret_cast<const uint8_t*>(str->value.as_string); | |
| intptr_t utf8_len = strlen(str->value.as_string); | |
| Utf8::Type type = Utf8::kLatin1; | |
| intptr_t latin1_len = Utf8::CodeUnitCount(utf8_str, utf8_len, &type); | |
| uint8_t* latin1_str = reinterpret_cast<uint8_t*>( | |
| dart::malloc(latin1_len * sizeof(uint8_t))); | |
| bool success = | |
| Utf8::DecodeToLatin1(utf8_str, utf8_len, latin1_str, latin1_len); | |
| ASSERT(success); | |
| s->WriteUnsigned(latin1_len); | |
| s->WriteBytes(latin1_str, latin1_len); | |
| ::free(latin1_str); | |
| } | |
| } | |
| private: | |
| GrowableArray<String*> objects_; | |
| }; | |
| class OneByteStringMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| explicit OneByteStringMessageDeserializationCluster(bool is_canonical) | |
| : MessageDeserializationCluster("OneByteString", is_canonical) {} | |
| ~OneByteStringMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| intptr_t length = d->ReadUnsigned(); | |
| const uint8_t* data = d->CurrentBufferAddress(); | |
| d->Advance(length * sizeof(uint8_t)); | |
| d->AssignRef(is_canonical() | |
| ? Symbols::FromLatin1(d->thread(), data, length) | |
| : String::FromLatin1(data, length)); | |
| } | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* str = d->Allocate(Dart_CObject_kString); | |
| intptr_t latin1_length = d->ReadUnsigned(); | |
| const uint8_t* data = d->CurrentBufferAddress(); | |
| d->Advance(latin1_length * sizeof(uint8_t)); | |
| intptr_t utf8_len = 0; | |
| for (intptr_t i = 0; i < latin1_length; i++) { | |
| utf8_len += Utf8::Length(data[i]); | |
| } | |
| char* utf8_data = d->zone()->Alloc<char>(utf8_len + 1); | |
| str->value.as_string = utf8_data; | |
| for (intptr_t i = 0; i < latin1_length; i++) { | |
| utf8_data += Utf8::Encode(data[i], utf8_data); | |
| } | |
| *utf8_data = '\0'; | |
| d->AssignRef(str); | |
| } | |
| } | |
| }; | |
| class TwoByteStringMessageSerializationCluster | |
| : public MessageSerializationCluster { | |
| public: | |
| explicit TwoByteStringMessageSerializationCluster(Zone* zone, | |
| bool is_canonical) | |
| : MessageSerializationCluster("TwoByteString", | |
| MessagePhase::kBeforeTypes, | |
| kTwoByteStringCid, | |
| is_canonical), | |
| objects_(zone, 0) {} | |
| ~TwoByteStringMessageSerializationCluster() {} | |
| void Trace(MessageSerializer* s, Object* object) { | |
| String* str = static_cast<String*>(object); | |
| objects_.Add(str); | |
| } | |
| void WriteNodes(MessageSerializer* s) { | |
| const intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| String* str = objects_[i]; | |
| s->AssignRef(str); | |
| intptr_t length = str->Length(); | |
| s->WriteUnsigned(length); | |
| NoSafepointScope no_safepoint; | |
| uint16_t* utf16 = TwoByteString::DataStart(*str); | |
| s->WriteBytes(reinterpret_cast<const uint8_t*>(utf16), | |
| length * sizeof(uint16_t)); | |
| } | |
| } | |
| void TraceApi(ApiMessageSerializer* s, Dart_CObject* object) { | |
| objects_.Add(reinterpret_cast<String*>(object)); | |
| } | |
| void WriteNodesApi(ApiMessageSerializer* s) { | |
| intptr_t count = objects_.length(); | |
| s->WriteUnsigned(count); | |
| for (intptr_t i = 0; i < count; i++) { | |
| Dart_CObject* str = reinterpret_cast<Dart_CObject*>(objects_[i]); | |
| s->AssignRef(str); | |
| const uint8_t* utf8_str = | |
| reinterpret_cast<const uint8_t*>(str->value.as_string); | |
| intptr_t utf8_len = strlen(str->value.as_string); | |
| Utf8::Type type = Utf8::kLatin1; | |
| intptr_t utf16_len = Utf8::CodeUnitCount(utf8_str, utf8_len, &type); | |
| uint16_t* utf16_str = reinterpret_cast<uint16_t*>( | |
| dart::malloc(utf16_len * sizeof(uint16_t))); | |
| bool success = | |
| Utf8::DecodeToUTF16(utf8_str, utf8_len, utf16_str, utf16_len); | |
| ASSERT(success); | |
| s->WriteUnsigned(utf16_len); | |
| s->WriteBytes(reinterpret_cast<const uint8_t*>(utf16_str), | |
| utf16_len * sizeof(uint16_t)); | |
| ::free(utf16_str); | |
| } | |
| } | |
| private: | |
| GrowableArray<String*> objects_; | |
| }; | |
| class TwoByteStringMessageDeserializationCluster | |
| : public MessageDeserializationCluster { | |
| public: | |
| explicit TwoByteStringMessageDeserializationCluster(bool is_canonical) | |
| : MessageDeserializationCluster("TwoByteString", is_canonical) {} | |
| ~TwoByteStringMessageDeserializationCluster() {} | |
| void ReadNodes(MessageDeserializer* d) { | |
| const intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t i = 0; i < count; i++) { | |
| intptr_t length = d->ReadUnsigned(); | |
| const uint16_t* data = | |
| reinterpret_cast<const uint16_t*>(d->CurrentBufferAddress()); | |
| d->Advance(length * sizeof(uint16_t)); | |
| d->AssignRef(is_canonical() | |
| ? Symbols::FromUTF16(d->thread(), data, length) | |
| : String::FromUTF16(data, length)); | |
| } | |
| } | |
| void ReadNodesApi(ApiMessageDeserializer* d) { | |
| intptr_t count = d->ReadUnsigned(); | |
| for (intptr_t j = 0; j < count; j++) { | |
| // Read all the UTF-16 code units. | |
| intptr_t utf16_length = d->ReadUnsigned(); | |
| const uint16_t* utf16 = | |
| reinterpret_cast<const uint16_t*>(d->CurrentBufferAddress()); | |
| d->Advance(utf16_length * sizeof(uint16_t)); | |
| // Calculate the UTF-8 length and check if the string can be | |
| // UTF-8 encoded. | |
| intptr_t utf8_len = 0; | |
| bool valid = true; | |
| intptr_t i = 0; | |
| while (i < utf16_length && valid) { | |
| int32_t ch = Utf16::Next(utf16, &i, utf16_length); | |
| utf8_len += Utf8::Length(ch); | |
| valid = !Utf16::IsSurrogate(ch); | |
| } | |
| if (!valid) { | |
| d->AssignRef(d->Allocate(Dart_CObject_kUnsupported)); | |
| } else { | |
| Dart_CObject* str = d->Allocate(Dart_CObject_kString); | |
| char* utf8 = d->zone()->Alloc<char>(utf8_len + 1); | |
| str->value.as_string = utf8; | |
| i = 0; | |
| while (i < utf16_length) { | |
| utf8 += Utf8::Encode(Utf16::Next(utf16, &i, utf16_length), utf8); | |
| } | |
| *utf8 = '\0'; | |
| d->AssignRef(str); | |
| } | |
| } | |
| } | |
| }; | |
| static constexpr intptr_t kFirstReference = 1; | |
| static constexpr intptr_t kUnallocatedReference = -1; | |
| BaseSerializer::BaseSerializer(Thread* thread, Zone* zone) | |
| : StackResource(thread), | |
| zone_(zone), | |
| stream_(100), | |
| finalizable_data_(new MessageFinalizableData()), | |
| clusters_(zone, 0), | |
| num_base_objects_(0), | |
| num_written_objects_(0), | |
| next_ref_index_(kFirstReference) {} | |
| BaseSerializer::~BaseSerializer() { | |
| delete finalizable_data_; | |
| } | |
| MessageSerializer::MessageSerializer(Thread* thread) | |
| : BaseSerializer(thread, thread->zone()), | |
| forward_table_new_(), | |
| forward_table_old_(), | |
| stack_(thread->zone(), 0) { | |
| thread->set_forward_table_new(new WeakTable()); | |
| thread->set_forward_table_old(new WeakTable()); | |
| } | |
| MessageSerializer::~MessageSerializer() { | |
| thread()->set_forward_table_new(nullptr); | |
| thread()->set_forward_table_old(nullptr); | |
| } | |
| ApiMessageSerializer::ApiMessageSerializer(Zone* zone) | |
| : BaseSerializer(nullptr, zone), forward_table_(), stack_(zone, 0) {} | |
| ApiMessageSerializer::~ApiMessageSerializer() {} | |
| void MessageSerializer::Push(ObjectPtr object) { | |
| if (MarkObjectId(object, kUnallocatedReference)) { | |
| stack_.Add(&Object::ZoneHandle(zone_, object)); | |
| num_written_objects_++; | |
| } | |
| } | |
| void ApiMessageSerializer::Push(Dart_CObject* object) { | |
| if (MarkObjectId(object, kUnallocatedReference)) { | |
| stack_.Add(object); | |
| num_written_objects_++; | |
| } | |
| } | |
| void MessageSerializer::Trace(const Object& root, Object* object) { | |
| intptr_t cid; | |
| bool is_canonical; | |
| if (!object->ptr()->IsHeapObject()) { | |
| cid = kSmiCid; | |
| is_canonical = true; | |
| } else { | |
| cid = object->GetClassId(); | |
| is_canonical = object->ptr()->untag()->IsCanonical(); | |
| } | |
| MessageSerializationCluster* cluster = nullptr; | |
| for (MessageSerializationCluster* c : clusters_) { | |
| if ((c->cid() == cid) && (c->is_canonical() == is_canonical)) { | |
| cluster = c; | |
| break; | |
| } | |
| } | |
| if (cluster == nullptr) { | |
| if (cid >= kNumPredefinedCids || cid == kInstanceCid) { | |
| // Will stomp over forward_table_new/old WeakTables, which should be ok, | |
| // as they are not going to be used again here. | |
| const char* message = OS::SCreate( | |
| zone_, "is a regular instance reachable via %s", | |
| FindRetainingPath(zone_, thread(), root, *object, | |
| TraversalRules::kExternalBetweenIsolateGroups)); | |
| IllegalObject(*object, message); | |
| } | |
| const char* illegal_cid_string = nullptr; | |
| // Keep the list in sync with the one in lib/isolate.cc, | |
| // vm/object_graph_copy.cc | |
| #define ILLEGAL(type) \ | |
| case k##type##Cid: \ | |
| illegal_cid_string = #type; \ | |
| break; | |
| switch (cid) { | |
| ILLEGAL(Closure) | |
| ILLEGAL(Finalizer) | |
| ILLEGAL(FinalizerEntry) | |
| ILLEGAL(FunctionType) | |
| ILLEGAL(MirrorReference) | |
| ILLEGAL(NativeFinalizer) | |
| ILLEGAL(ReceivePort) | |
| ILLEGAL(Record) | |
| ILLEGAL(RecordType) | |
| ILLEGAL(RegExp) | |
| ILLEGAL(StackTrace) | |
| ILLEGAL(SuspendState) | |
| ILLEGAL(UserTag) | |
| ILLEGAL(WeakProperty) | |
| ILLEGAL(WeakReference) | |
| ILLEGAL(WeakArray) | |
| // From "dart:ffi" we handle only Pointer/DynamicLibrary specially, since | |
| // those are the only non-abstract classes (so we avoid checking more cids | |
| // here that cannot happen in reality) | |
| ILLEGAL(DynamicLibrary) | |
| ILLEGAL(Pointer) | |
| #undef ILLEGAL | |
| } | |
| if (illegal_cid_string != nullptr) { | |
| // Will stomp over forward_table_new/old WeakTables, which should be ok, | |
| // as they are not going to be used again here. | |
| const char* message = OS::SCreate( | |
| zone_, "is a %s reachable via %s", illegal_cid_string, | |
| FindRetainingPath(zone_, thread(), root, *object, | |
| TraversalRules::kExternalBetweenIsolateGroups)); | |
| IllegalObject(*object, message); | |
| } | |
| cluster = NewClusterForClass(cid, is_canonical); | |
| clusters_.Add(cluster); | |
| } | |
| cluster->Trace(this, object); | |
| } | |
| bool ApiMessageSerializer::Trace(Dart_CObject* object) { | |
| const bool is_canonical = false; | |
| intptr_t cid; | |
| switch (object->type) { | |
| case Dart_CObject_kNull: | |
| ForwardRef(object, &cobj_null); | |
| return true; | |
| case Dart_CObject_kBool: | |
| ForwardRef(object, object->value.as_bool ? &cobj_true : &cobj_false); | |
| return true; | |
| case Dart_CObject_kInt32: | |
| cid = Smi::IsValid(object->value.as_int32) ? kSmiCid : kMintCid; | |
| break; | |
| case Dart_CObject_kInt64: | |
| cid = Smi::IsValid(object->value.as_int64) ? kSmiCid : kMintCid; | |
| break; | |
| case Dart_CObject_kDouble: | |
| cid = kDoubleCid; | |
| break; | |
| case Dart_CObject_kString: { | |
| RELEASE_ASSERT(object->value.as_string != nullptr); | |
| const uint8_t* utf8_str = | |
| reinterpret_cast<const uint8_t*>(object->value.as_string); | |
| intptr_t utf8_len = strlen(object->value.as_string); | |
| if (!Utf8::IsValid(utf8_str, utf8_len)) { | |
| return Fail("invalid utf8"); | |
| } | |
| Utf8::Type type = Utf8::kLatin1; | |
| intptr_t len = Utf8::CodeUnitCount(utf8_str, utf8_len, &type); | |
| if (len > String::kMaxElements) { | |
| return Fail("invalid string length"); | |
| } | |
| cid = type == Utf8::kLatin1 ? kOneByteStringCid : kTwoByteStringCid; | |
| break; | |
| } | |
| case Dart_CObject_kArray: | |
| cid = kArrayCid; | |
| if (!Array::IsValidLength(object->value.as_array.length)) { | |
| return Fail("invalid array length"); | |
| } | |
| break; | |
| case Dart_CObject_kTypedData: | |
| switch (object->value.as_typed_data.type) { | |
| case Dart_TypedData_kInt8: | |
| cid = kTypedDataInt8ArrayCid; | |
| break; | |
| case Dart_TypedData_kUint8: | |
| cid = kTypedDataUint8ArrayCid; | |
| break; | |
| case Dart_TypedData_kUint8Clamped: | |
| cid = kTypedDataUint8ClampedArrayCid; | |
| break; | |
| case Dart_TypedData_kInt16: | |
| cid = kTypedDataInt16ArrayCid; | |
| break; | |
| case Dart_TypedData_kUint16: | |
| cid = kTypedDataUint16ArrayCid; | |
| break; | |
| case Dart_TypedData_kInt32: | |
| cid = kTypedDataInt32ArrayCid; | |
| break; | |
| case Dart_TypedData_kUint32: | |
| cid = kTypedDataUint32ArrayCid; | |
| break; | |
| case Dart_TypedData_kInt64: | |
| cid = kTypedDataInt64ArrayCid; | |
| break; | |
| case Dart_TypedData_kUint64: | |
| cid = kTypedDataUint64ArrayCid; | |
| break; | |
| case Dart_TypedData_kFloat32: | |
| cid = kTypedDataFloat32ArrayCid; | |
| break; | |
| case Dart_TypedData_kFloat64: | |
| cid = kTypedDataFloat64ArrayCid; | |
| break; | |
| case Dart_TypedData_kInt32x4: | |
| cid = kTypedDataInt32x4ArrayCid; | |
| break; | |
| case Dart_TypedData_kFloat32x4: | |
| cid = kTypedDataFloat32x4ArrayCid; | |
| break; | |
| case Dart_TypedData_kFloat64x2: | |
| cid = kTypedDataFloat64x2ArrayCid; | |
| break; | |
| default: | |
| return Fail("invalid TypedData type"); | |
| } | |
| { | |
| intptr_t len = object->value.as_typed_data.length; | |
| if (len < 0 || len > TypedData::MaxElements(cid)) { | |
| return Fail("invalid typeddata length"); | |
| } | |
| } | |
| break; | |
| case Dart_CObject_kExternalTypedData: | |
| switch (object->value.as_external_typed_data.type) { | |
| case Dart_TypedData_kInt8: | |
| cid = kExternalTypedDataInt8ArrayCid; | |
| break; | |
| case Dart_TypedData_kUint8: | |
| cid = kExternalTypedDataUint8ArrayCid; | |
| break; | |
| case Dart_TypedData_kUint8Clamped: | |
| cid = kExternalTypedDataUint8ClampedArrayCid; | |
| break; | |
| case Dart_TypedData_kInt16: | |
| cid = kExternalTypedDataInt16ArrayCid; | |
| break; | |
| case Dart_TypedData_kUint16: | |
| cid = kExternalTypedDataUint16ArrayCid; | |
| break; | |
| case Dart_TypedData_kInt32: | |
| cid = kExternalTypedDataInt32ArrayCid; | |
| break; | |
| case Dart_TypedData_kUint32: | |
| cid = kExternalTypedDataUint32ArrayCid; | |
| break; | |
| case Dart_TypedData_kInt64: | |
| cid = kExternalTypedDataInt64ArrayCid; | |
| break; | |
| case Dart_TypedData_kUint64: | |
| cid = kExternalTypedDataUint64ArrayCid; | |
| break; | |
| case Dart_TypedData_kFloat32: | |
| cid = kExternalTypedDataFloat32ArrayCid; | |
| break; | |
| case Dart_TypedData_kFloat64: | |
| cid = kExternalTypedDataFloat64ArrayCid; | |
| break; | |
| case Dart_TypedData_kInt32x4: | |
| cid = kExternalTypedDataInt32x4ArrayCid; | |
| break; | |
| case Dart_TypedData_kFloat32x4: | |
| cid = kExternalTypedDataFloat32x4ArrayCid; | |
| break; | |
| case Dart_TypedData_kFloat64x2: | |
| cid = kExternalTypedDataFloat64x2ArrayCid; | |
| break; | |
| default: | |
| return Fail("invalid TypedData type"); | |
| } | |
| { | |
| intptr_t len = object->value.as_typed_data.length; | |
| if (len < 0 || len > ExternalTypedData::MaxElements(cid)) { | |
| return Fail("invalid typeddata length"); | |
| } | |
| } | |
| break; | |
| case Dart_CObject_kUnmodifiableExternalTypedData: | |
| switch (object->value.as_external_typed_data.type) { | |
| case Dart_TypedData_kInt8: | |
| cid = kUnmodifiableTypedDataInt8ArrayViewCid; | |
| break; | |
| case Dart_TypedData_kUint8: | |
| cid = kUnmodifiableTypedDataUint8ArrayViewCid; | |
| break; | |
| case Dart_TypedData_kUint8Clamped: | |
| cid = kUnmodifiableTypedDataUint8ClampedArrayViewCid; | |
| break; | |
| case Dart_TypedData_kInt16: | |
| cid = kUnmodifiableTypedDataInt16ArrayViewCid; | |
| break; | |
| case Dart_TypedData_kUint16: | |
| cid = kUnmodifiableTypedDataUint16ArrayViewCid; | |
| break; | |
| case Dart_TypedData_kInt32: | |
| cid = kUnmodifiableTypedDataInt32ArrayViewCid; | |
| break; | |
| case Dart_TypedData_kUint32: | |
| cid = kUnmodifiableTypedDataUint32ArrayViewCid; | |
| break; | |
| case Dart_TypedData_kInt64: | |
| cid = kUnmodifiableTypedDataInt64ArrayViewCid; | |
| break; | |
| case Dart_TypedData_kUint64: | |
| cid = kUnmodifiableTypedDataUint64ArrayViewCid; | |
| break; | |
| case Dart_TypedData_kFloat32: | |
| cid = kUnmodifiableTypedDataFloat32ArrayViewCid; | |
| break; | |
| case Dart_TypedData_kFloat64: | |
| cid = kUnmodifiableTypedDataFloat64ArrayViewCid; | |
| break; | |
| case Dart_TypedData_kInt32x4: | |
| cid = kUnmodifiableTypedDataInt32x4ArrayViewCid; | |
| break; | |
| case Dart_TypedData_kFloat32x4: | |
| cid = kUnmodifiableTypedDataFloat32x4ArrayViewCid; | |
| break; | |
| case Dart_TypedData_kFloat64x2: | |
| cid = kUnmodifiableTypedDataFloat64x2ArrayViewCid; | |
| break; | |
| default: | |
| return Fail("invalid TypedData type"); | |
| } | |
| { | |
| intptr_t len = object->value.as_typed_data.length; | |
| if (len < 0 || len > TypedData::MaxElements( | |
| cid - kTypedDataCidRemainderUnmodifiable + | |
| kTypedDataCidRemainderInternal)) { | |
| return Fail("invalid typeddata length"); | |
| } | |
| } | |
| break; | |
| case Dart_CObject_kSendPort: | |
| cid = kSendPortCid; | |
| break; | |
| case Dart_CObject_kCapability: | |
| cid = kCapabilityCid; | |
| break; | |
| case Dart_CObject_kNativePointer: | |
| cid = kNativePointer; | |
| break; | |
| default: | |
| return Fail("invalid Dart_CObject type"); | |
| } | |
| MessageSerializationCluster* cluster = nullptr; | |
| for (MessageSerializationCluster* c : clusters_) { | |
| if (c->cid() == cid) { | |
| cluster = c; | |
| break; | |
| } | |
| } | |
| if (cluster == nullptr) { | |
| cluster = NewClusterForClass(cid, is_canonical); | |
| clusters_.Add(cluster); | |
| } | |
| cluster->TraceApi(this, object); | |
| return true; | |
| } | |
| void MessageSerializer::IllegalObject(const Object& object, | |
| const char* message) { | |
| const Array& args = Array::Handle(zone(), Array::New(3)); | |
| args.SetAt(0, object); | |
| args.SetAt(2, String::Handle(zone(), String::New(message))); | |
| Exceptions::ThrowByType(Exceptions::kArgumentValue, args); | |
| } | |
| BaseDeserializer::BaseDeserializer(Zone* zone, Message* message) | |
| : zone_(zone), | |
| stream_(message->snapshot(), message->snapshot_length()), | |
| finalizable_data_(message->finalizable_data()), | |
| next_ref_index_(kFirstReference) {} | |
| BaseDeserializer::~BaseDeserializer() {} | |
| MessageSerializationCluster* BaseSerializer::NewClusterForClass( | |
| intptr_t cid, | |
| bool is_canonical) { | |
| Zone* Z = zone_; | |
| if (IsTypedDataViewClassId(cid) || cid == kByteDataViewCid || | |
| IsUnmodifiableTypedDataViewClassId(cid) || | |
| cid == kUnmodifiableByteDataViewCid) { | |
| return new (Z) TypedDataViewMessageSerializationCluster(Z, cid); | |
| } | |
| if (IsExternalTypedDataClassId(cid)) { | |
| return new (Z) ExternalTypedDataMessageSerializationCluster(Z, cid); | |
| } | |
| if (IsTypedDataClassId(cid)) { | |
| return new (Z) TypedDataMessageSerializationCluster(Z, cid); | |
| } | |
| switch (cid) { | |
| case kNativePointer: | |
| return new (Z) NativePointerMessageSerializationCluster(Z); | |
| case kClassCid: | |
| return new (Z) ClassMessageSerializationCluster(); | |
| case kTypeArgumentsCid: | |
| return new (Z) TypeArgumentsMessageSerializationCluster(is_canonical); | |
| case kTypeCid: | |
| return new (Z) TypeMessageSerializationCluster(is_canonical); | |
| case kSmiCid: | |
| return new (Z) SmiMessageSerializationCluster(Z); | |
| case kMintCid: | |
| return new (Z) MintMessageSerializationCluster(Z, is_canonical); | |
| case kDoubleCid: | |
| return new (Z) DoubleMessageSerializationCluster(Z, is_canonical); | |
| case kGrowableObjectArrayCid: | |
| return new (Z) GrowableObjectArrayMessageSerializationCluster(); | |
| case kSendPortCid: | |
| return new (Z) SendPortMessageSerializationCluster(Z); | |
| case kCapabilityCid: | |
| return new (Z) CapabilityMessageSerializationCluster(Z); | |
| case kTransferableTypedDataCid: | |
| return new (Z) TransferableTypedDataMessageSerializationCluster(); | |
| case kMapCid: | |
| case kConstMapCid: | |
| return new (Z) MapMessageSerializationCluster(Z, is_canonical, cid); | |
| case kSetCid: | |
| case kConstSetCid: | |
| return new (Z) SetMessageSerializationCluster(Z, is_canonical, cid); | |
| case kArrayCid: | |
| case kImmutableArrayCid: | |
| return new (Z) ArrayMessageSerializationCluster(Z, is_canonical, cid); | |
| case kOneByteStringCid: | |
| return new (Z) OneByteStringMessageSerializationCluster(Z, is_canonical); | |
| case kTwoByteStringCid: | |
| return new (Z) TwoByteStringMessageSerializationCluster(Z, is_canonical); | |
| case kInt32x4Cid: | |
| case kFloat32x4Cid: | |
| case kFloat64x2Cid: | |
| return new (Z) Simd128MessageSerializationCluster(cid); | |
| default: | |
| break; | |
| } | |
| FATAL("No cluster defined for cid %" Pd, cid); | |
| return nullptr; | |
| } | |
| void BaseSerializer::WriteCluster(MessageSerializationCluster* cluster) { | |
| uint64_t cid_and_canonical = (static_cast<uint64_t>(cluster->cid()) << 1) | | |
| (cluster->is_canonical() ? 0x1 : 0x0); | |
| WriteUnsigned(cid_and_canonical); | |
| } | |
| MessageDeserializationCluster* BaseDeserializer::ReadCluster() { | |
| const uint64_t cid_and_canonical = ReadUnsigned(); | |
| const intptr_t cid = (cid_and_canonical >> 1) & kMaxUint32; | |
| const bool is_canonical = (cid_and_canonical & 0x1) == 0x1; | |
| Zone* Z = zone_; | |
| if (IsTypedDataViewClassId(cid) || cid == kByteDataViewCid || | |
| IsUnmodifiableTypedDataViewClassId(cid) || | |
| cid == kUnmodifiableByteDataViewCid) { | |
| ASSERT(!is_canonical); | |
| return new (Z) TypedDataViewMessageDeserializationCluster(cid); | |
| } | |
| if (IsExternalTypedDataClassId(cid)) { | |
| ASSERT(!is_canonical); | |
| return new (Z) ExternalTypedDataMessageDeserializationCluster(cid); | |
| } | |
| if (IsTypedDataClassId(cid)) { | |
| ASSERT(!is_canonical); | |
| return new (Z) TypedDataMessageDeserializationCluster(cid); | |
| } | |
| switch (cid) { | |
| case kNativePointer: | |
| ASSERT(!is_canonical); | |
| return new (Z) NativePointerMessageDeserializationCluster(); | |
| case kClassCid: | |
| ASSERT(!is_canonical); | |
| return new (Z) ClassMessageDeserializationCluster(); | |
| case kTypeArgumentsCid: | |
| return new (Z) TypeArgumentsMessageDeserializationCluster(is_canonical); | |
| case kTypeCid: | |
| return new (Z) TypeMessageDeserializationCluster(is_canonical); | |
| case kSmiCid: | |
| ASSERT(is_canonical); | |
| return new (Z) SmiMessageDeserializationCluster(); | |
| case kMintCid: | |
| return new (Z) MintMessageDeserializationCluster(is_canonical); | |
| case kDoubleCid: | |
| return new (Z) DoubleMessageDeserializationCluster(is_canonical); | |
| case kGrowableObjectArrayCid: | |
| ASSERT(!is_canonical); | |
| return new (Z) GrowableObjectArrayMessageDeserializationCluster(); | |
| case kSendPortCid: | |
| ASSERT(!is_canonical); | |
| return new (Z) SendPortMessageDeserializationCluster(); | |
| case kCapabilityCid: | |
| ASSERT(!is_canonical); | |
| return new (Z) CapabilityMessageDeserializationCluster(); | |
| case kTransferableTypedDataCid: | |
| ASSERT(!is_canonical); | |
| return new (Z) TransferableTypedDataMessageDeserializationCluster(); | |
| case kMapCid: | |
| case kConstMapCid: | |
| return new (Z) MapMessageDeserializationCluster(is_canonical, cid); | |
| case kSetCid: | |
| case kConstSetCid: | |
| return new (Z) SetMessageDeserializationCluster(is_canonical, cid); | |
| case kArrayCid: | |
| case kImmutableArrayCid: | |
| return new (Z) ArrayMessageDeserializationCluster(is_canonical, cid); | |
| case kOneByteStringCid: | |
| return new (Z) OneByteStringMessageDeserializationCluster(is_canonical); | |
| case kTwoByteStringCid: | |
| return new (Z) TwoByteStringMessageDeserializationCluster(is_canonical); | |
| case kInt32x4Cid: | |
| case kFloat32x4Cid: | |
| case kFloat64x2Cid: | |
| ASSERT(!is_canonical); | |
| return new (Z) Simd128MessageDeserializationCluster(cid); | |
| default: | |
| break; | |
| } | |
| FATAL("No cluster defined for cid %" Pd, cid); | |
| return nullptr; | |
| } | |
| void MessageSerializer::AddBaseObjects() { | |
| AddBaseObject(Object::null()); | |
| AddBaseObject(Object::sentinel().ptr()); | |
| AddBaseObject(Object::empty_array().ptr()); | |
| AddBaseObject(Object::dynamic_type().ptr()); | |
| AddBaseObject(Object::void_type().ptr()); | |
| AddBaseObject(Object::empty_type_arguments().ptr()); | |
| AddBaseObject(Bool::True().ptr()); | |
| AddBaseObject(Bool::False().ptr()); | |
| } | |
| void MessageDeserializer::AddBaseObjects() { | |
| AddBaseObject(Object::null()); | |
| AddBaseObject(Object::sentinel().ptr()); | |
| AddBaseObject(Object::empty_array().ptr()); | |
| AddBaseObject(Object::dynamic_type().ptr()); | |
| AddBaseObject(Object::void_type().ptr()); | |
| AddBaseObject(Object::empty_type_arguments().ptr()); | |
| AddBaseObject(Bool::True().ptr()); | |
| AddBaseObject(Bool::False().ptr()); | |
| } | |
| void ApiMessageSerializer::AddBaseObjects() { | |
| AddBaseObject(&cobj_null); | |
| AddBaseObject(&cobj_sentinel); | |
| AddBaseObject(&cobj_empty_array); | |
| AddBaseObject(&cobj_dynamic_type); | |
| AddBaseObject(&cobj_void_type); | |
| AddBaseObject(&cobj_empty_type_arguments); | |
| AddBaseObject(&cobj_true); | |
| AddBaseObject(&cobj_false); | |
| } | |
| void ApiMessageDeserializer::AddBaseObjects() { | |
| AddBaseObject(&cobj_null); | |
| AddBaseObject(&cobj_sentinel); | |
| AddBaseObject(&cobj_empty_array); | |
| AddBaseObject(&cobj_dynamic_type); | |
| AddBaseObject(&cobj_void_type); | |
| AddBaseObject(&cobj_empty_type_arguments); | |
| AddBaseObject(&cobj_true); | |
| AddBaseObject(&cobj_false); | |
| } | |
| void MessageSerializer::Serialize(const Object& root) { | |
| AddBaseObjects(); | |
| Push(root.ptr()); | |
| while (stack_.length() > 0) { | |
| Trace(root, stack_.RemoveLast()); | |
| } | |
| intptr_t num_objects = num_base_objects_ + num_written_objects_; | |
| WriteUnsigned(num_base_objects_); | |
| WriteUnsigned(num_objects); | |
| for (intptr_t i = 0; i < static_cast<intptr_t>(MessagePhase::kNumPhases); | |
| i++) { | |
| intptr_t num_clusters = 0; | |
| for (MessageSerializationCluster* cluster : clusters_) { | |
| if (static_cast<intptr_t>(cluster->phase()) != i) continue; | |
| num_clusters++; | |
| } | |
| WriteUnsigned(num_clusters); | |
| for (MessageSerializationCluster* cluster : clusters_) { | |
| if (static_cast<intptr_t>(cluster->phase()) != i) continue; | |
| WriteCluster(cluster); | |
| cluster->WriteNodes(this); | |
| } | |
| for (MessageSerializationCluster* cluster : clusters_) { | |
| if (static_cast<intptr_t>(cluster->phase()) != i) continue; | |
| cluster->WriteEdges(this); | |
| } | |
| } | |
| // We should have assigned a ref to every object we pushed. | |
| ASSERT((next_ref_index_ - 1) == num_objects); | |
| WriteRef(root.ptr()); | |
| } | |
| bool ApiMessageSerializer::Serialize(Dart_CObject* root) { | |
| AddBaseObjects(); | |
| Push(root); | |
| // Strong references only. | |
| while (stack_.length() > 0) { | |
| if (!Trace(stack_.RemoveLast())) { | |
| return false; | |
| } | |
| } | |
| intptr_t num_objects = num_base_objects_ + num_written_objects_; | |
| WriteUnsigned(num_base_objects_); | |
| WriteUnsigned(num_objects); | |
| for (intptr_t i = 0; i < static_cast<intptr_t>(MessagePhase::kNumPhases); | |
| i++) { | |
| intptr_t num_clusters = 0; | |
| for (MessageSerializationCluster* cluster : clusters_) { | |
| if (static_cast<intptr_t>(cluster->phase()) != i) continue; | |
| num_clusters++; | |
| } | |
| WriteUnsigned(num_clusters); | |
| for (MessageSerializationCluster* cluster : clusters_) { | |
| if (static_cast<intptr_t>(cluster->phase()) != i) continue; | |
| WriteCluster(cluster); | |
| cluster->WriteNodesApi(this); | |
| } | |
| for (MessageSerializationCluster* cluster : clusters_) { | |
| if (static_cast<intptr_t>(cluster->phase()) != i) continue; | |
| cluster->WriteEdgesApi(this); | |
| } | |
| } | |
| // We should have assigned a ref to every object we pushed. | |
| ASSERT((next_ref_index_ - 1) == num_objects); | |
| WriteRef(root); | |
| return true; | |
| } | |
| ObjectPtr MessageDeserializer::Deserialize() { | |
| intptr_t num_base_objects = ReadUnsigned(); | |
| intptr_t num_objects = ReadUnsigned(); | |
| refs_ = Array::New(num_objects + kFirstReference); | |
| AddBaseObjects(); | |
| // Writer and reader must agree on number of base objects. | |
| ASSERT_EQUAL(num_base_objects, (next_ref_index_ - kFirstReference)); | |
| Object& error = Object::Handle(zone()); | |
| for (intptr_t i = 0; i < static_cast<intptr_t>(MessagePhase::kNumPhases); | |
| i++) { | |
| intptr_t num_clusters = ReadUnsigned(); | |
| MessageDeserializationCluster** clusters = | |
| zone()->Alloc<MessageDeserializationCluster*>(num_clusters); | |
| for (intptr_t i = 0; i < num_clusters; i++) { | |
| clusters[i] = ReadCluster(); | |
| clusters[i]->ReadNodesWrapped(this); | |
| } | |
| for (intptr_t i = 0; i < num_clusters; i++) { | |
| clusters[i]->ReadEdges(this); | |
| } | |
| for (intptr_t i = 0; i < num_clusters; i++) { | |
| error = clusters[i]->PostLoad(this); | |
| if (error.IsError()) { | |
| return error.ptr(); // E.g., an UnwindError during rehashing. | |
| } | |
| } | |
| } | |
| // We should have completely filled the ref array. | |
| ASSERT_EQUAL(next_ref_index_ - kFirstReference, num_objects); | |
| return ReadRef(); | |
| } | |
| Dart_CObject* ApiMessageDeserializer::Deserialize() { | |
| intptr_t num_base_objects = ReadUnsigned(); | |
| intptr_t num_objects = ReadUnsigned(); | |
| refs_ = zone()->Alloc<Dart_CObject*>(num_objects + kFirstReference); | |
| AddBaseObjects(); | |
| // Writer and reader must agree on number of base objects. | |
| ASSERT_EQUAL(num_base_objects, (next_ref_index_ - kFirstReference)); | |
| for (intptr_t i = 0; i < static_cast<intptr_t>(MessagePhase::kNumPhases); | |
| i++) { | |
| intptr_t num_clusters = ReadUnsigned(); | |
| MessageDeserializationCluster** clusters = | |
| zone()->Alloc<MessageDeserializationCluster*>(num_clusters); | |
| for (intptr_t i = 0; i < num_clusters; i++) { | |
| clusters[i] = ReadCluster(); | |
| clusters[i]->ReadNodesWrappedApi(this); | |
| } | |
| for (intptr_t i = 0; i < num_clusters; i++) { | |
| clusters[i]->ReadEdgesApi(this); | |
| } | |
| for (intptr_t i = 0; i < num_clusters; i++) { | |
| clusters[i]->PostLoadApi(this); | |
| } | |
| } | |
| // We should have completely filled the ref array. | |
| ASSERT_EQUAL(next_ref_index_ - kFirstReference, num_objects); | |
| return ReadRef(); | |
| } | |
| std::unique_ptr<Message> WriteMessage(bool same_group, | |
| const Object& obj, | |
| Dart_Port dest_port, | |
| Message::Priority priority) { | |
| if (ApiObjectConverter::CanConvert(obj.ptr())) { | |
| return Message::New(dest_port, obj.ptr(), priority); | |
| } else if (same_group) { | |
| const Object& copy = Object::Handle(CopyMutableObjectGraph(obj)); | |
| auto handle = | |
| IsolateGroup::Current()->api_state()->AllocatePersistentHandle(); | |
| handle->set_ptr(copy.ptr()); | |
| return std::make_unique<Message>(dest_port, handle, priority); | |
| } | |
| Thread* thread = Thread::Current(); | |
| MessageSerializer serializer(thread); | |
| serializer.Serialize(obj); | |
| return serializer.Finish(dest_port, priority); | |
| } | |
| std::unique_ptr<Message> WriteApiMessage(Zone* zone, | |
| Dart_CObject* obj, | |
| Dart_Port dest_port, | |
| Message::Priority priority) { | |
| ApiMessageSerializer serializer(zone); | |
| if (!serializer.Serialize(obj)) { | |
| return nullptr; | |
| } | |
| return serializer.Finish(dest_port, priority); | |
| } | |
| ObjectPtr ReadObjectGraphCopyMessage(Thread* thread, PersistentHandle* handle) { | |
| // msg_array = [ | |
| // <message>, | |
| // <collection-lib-objects-to-rehash>, | |
| // <core-lib-objects-to-rehash>, | |
| // ] | |
| Zone* zone = thread->zone(); | |
| Object& msg_obj = Object::Handle(zone); | |
| const auto& msg_array = Array::Handle(zone, Array::RawCast(handle->ptr())); | |
| ASSERT(msg_array.Length() == 3); | |
| msg_obj = msg_array.At(0); | |
| if (msg_array.At(1) != Object::null()) { | |
| const auto& objects_to_rehash = Object::Handle(zone, msg_array.At(1)); | |
| auto& result = Object::Handle(zone); | |
| result = DartLibraryCalls::RehashObjectsInDartCompactHash( | |
| thread, objects_to_rehash); | |
| if (result.ptr() != Object::null()) { | |
| msg_obj = result.ptr(); | |
| } | |
| } | |
| if (msg_array.At(2) != Object::null()) { | |
| const auto& objects_to_rehash = Object::Handle(zone, msg_array.At(2)); | |
| auto& result = Object::Handle(zone); | |
| result = | |
| DartLibraryCalls::RehashObjectsInDartCore(thread, objects_to_rehash); | |
| if (result.ptr() != Object::null()) { | |
| msg_obj = result.ptr(); | |
| } | |
| } | |
| return msg_obj.ptr(); | |
| } | |
| ObjectPtr ReadMessage(Thread* thread, Message* message) { | |
| if (message->IsRaw()) { | |
| return message->raw_obj(); | |
| } else if (message->IsFinalizerInvocationRequest()) { | |
| PersistentHandle* handle = message->persistent_handle(); | |
| Object& msg_obj = Object::Handle(thread->zone(), handle->ptr()); | |
| ASSERT(msg_obj.IsFinalizer() || msg_obj.IsNativeFinalizer()); | |
| return msg_obj.ptr(); | |
| } else if (message->IsPersistentHandle()) { | |
| return ReadObjectGraphCopyMessage(thread, message->persistent_handle()); | |
| } else { | |
| RELEASE_ASSERT(message->IsSnapshot()); | |
| LongJumpScope jump(thread); | |
| if (DART_SETJMP(*jump.Set()) == 0) { | |
| MessageDeserializer deserializer(thread, message); | |
| return deserializer.Deserialize(); | |
| } else { | |
| return thread->StealStickyError(); | |
| } | |
| } | |
| } | |
| Dart_CObject* ReadApiMessage(Zone* zone, Message* message) { | |
| if (message->IsRaw()) { | |
| Dart_CObject* result = zone->Alloc<Dart_CObject>(1); | |
| ApiObjectConverter::Convert(message->raw_obj(), result); | |
| return result; | |
| } else { | |
| RELEASE_ASSERT(message->IsSnapshot()); | |
| ApiMessageDeserializer deserializer(zone, message); | |
| return deserializer.Deserialize(); | |
| } | |
| } | |
| } // namespace dart |