blob: c07eb6f628adfa980f77b1ecd5590cff5ccebe8a [file] [log] [blame]
// 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_transition_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* thread)
: BaseSerializer(thread, thread->zone()),
forward_table_new_(),
forward_table_old_(),
stack_(thread->zone(), 0) {
isolate()->set_forward_table_new(new WeakTable());
isolate()->set_forward_table_old(new WeakTable());
}
MessageSerializer::~MessageSerializer() {
isolate()->set_forward_table_new(nullptr);
isolate()->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_, isolate(), 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_, isolate(), 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, PredefinedCObjects::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::transition_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::transition_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(PredefinedCObjects::cobj_null());
AddBaseObject(&cobj_sentinel);
AddBaseObject(&cobj_transition_sentinel);
AddBaseObject(PredefinedCObjects::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(PredefinedCObjects::cobj_null());
AddBaseObject(&cobj_sentinel);
AddBaseObject(&cobj_transition_sentinel);
AddBaseObject(PredefinedCObjects::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::RehashObjectsInDartCollection(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 (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