| // 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 = {Dart_CObject_kUnsupported, {false}}; |
| static Dart_CObject cobj_dynamic_type = {Dart_CObject_kUnsupported, {false}}; |
| static Dart_CObject cobj_void_type = {Dart_CObject_kUnsupported, {false}}; |
| static Dart_CObject cobj_empty_type_arguments = {Dart_CObject_kUnsupported, |
| {false}}; |
| static Dart_CObject cobj_true = {Dart_CObject_kBool, {true}}; |
| static Dart_CObject cobj_false = {Dart_CObject_kBool, {false}}; |
| |
| // Workaround for lack of designated initializers until we adopt c++20 |
| class PredefinedCObjects { |
| public: |
| static PredefinedCObjects& getInstance() { |
| static PredefinedCObjects instance; |
| return instance; |
| } |
| |
| static Dart_CObject* cobj_null() { return &getInstance().cobj_null_; } |
| static Dart_CObject* cobj_empty_array() { |
| return &getInstance().cobj_empty_array_; |
| } |
| |
| private: |
| PredefinedCObjects() { |
| cobj_null_.type = Dart_CObject_kNull; |
| cobj_null_.value.as_int64 = 0; |
| cobj_empty_array_.type = Dart_CObject_kArray; |
| cobj_empty_array_.value.as_array = {0, nullptr}; |
| } |
| |
| Dart_CObject cobj_null_; |
| Dart_CObject cobj_empty_array_; |
| |
| DISALLOW_COPY_AND_ASSIGN(PredefinedCObjects); |
| }; |
| |
| enum class MessagePhase { |
| kBeforeTypes = 0, |
| kTypes = 1, |
| kCanonicalInstances = 2, |
| kNonCanonicalInstances = 3, |
| |
| kNumPhases = 4, |
| }; |
| |
| class MessageSerializer; |
| class MessageDeserializer; |
| class ApiMessageSerializer; |
| class ApiMessageDeserializer; |
| |
| class MessageSerializationCluster : public ZoneAllocated { |
| 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 ZoneAllocated { |
| 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 = isolate()->forward_table_old(); |
| } else { |
| table = isolate()->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 = isolate()->forward_table_old(); |
| } else { |
| table = isolate()->forward_table_new(); |
| } |
| table->SetValueExclusive(object, id); |
| } |
| |
| intptr_t GetObjectId(ObjectPtr object) const { |
| const WeakTable* table; |
| if (object->IsImmediateOrOldObject()) { |
| table = isolate()->forward_table_old(); |
| } else { |
| table = isolate()->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()); |
| } |
| Isolate* isolate() const { return thread()->isolate(); } |
| IsolateGroup* isolate_group() const { return thread()->isolate_group(); } |
| |
| bool HasRef(ObjectPtr object) const { |
| return GetObjectId(object) != WeakTable::kNoValue; |
| } |
| |
| private: |
| 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::RehashObjectsInDartCollection(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 (UNLIKELY(lib.IsNull())) { |
| 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 (UNLIKELY(cls.IsNull())) { |
| 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 Observatory. |
| 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.SetImmutable(); // 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(PredefinedCObjects::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* |