mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 23:19:47 +00:00
bf4bb95308
The new implementation moves away from desugaring of async functions on kernel AST, state machine generated in the flow graph and capturing all local variables in the context. Instead, async/await is implemented using a few stubs (InitSuspendableFunction, Suspend, Resume, Return and AsyncExceptionHandler). The stubs are implemented in a platform-independent way using (macro-)assembler helpers. When suspending a function, its frame is copied into a SuspendState object, and when resuming a function it is copied back onto the stack. No extra code is generated for accessing local variables. Callback closures are created lazily on the first await. Design doc: go/compact-async-await. Part 1 (kernel): https://dart-review.googlesource.com/c/sdk/+/241842 TEST=ci Issue: https://github.com/dart-lang/sdk/issues/48378 Change-Id: Ibad757035b7cc438ebdff80b460728b1d3eff1f5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/242000 Reviewed-by: Ryan Macnak <rmacnak@google.com> Reviewed-by: Slava Egorov <vegorov@google.com>
3977 lines
129 KiB
C++
3977 lines
129 KiB
C++
// 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_;
|
|
}
|
|
static Dart_CObject* cobj_zero_array() {
|
|
return &getInstance().cobj_zero_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};
|
|
cobj_zero_array_element.type = Dart_CObject_kInt32;
|
|
cobj_zero_array_element.value.as_int32 = 0;
|
|
cobj_zero_array_values[0] = {&cobj_zero_array_element};
|
|
cobj_zero_array_.type = Dart_CObject_kArray;
|
|
cobj_zero_array_.value.as_array = {1, &cobj_zero_array_values[0]};
|
|
}
|
|
|
|
Dart_CObject cobj_null_;
|
|
Dart_CObject cobj_empty_array_;
|
|
Dart_CObject* cobj_zero_array_values[1];
|
|
Dart_CObject cobj_zero_array_element;
|
|
Dart_CObject cobj_zero_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 WeakPropertyMessageSerializationCluster;
|
|
|
|
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_;
|
|
WeakPropertyMessageSerializationCluster* ephemeron_cluster_;
|
|
intptr_t num_base_objects_;
|
|
intptr_t num_written_objects_;
|
|
intptr_t next_ref_index_;
|
|
};
|
|
|
|
class MessageSerializer : public BaseSerializer {
|
|
public:
|
|
MessageSerializer(Thread* thread, bool can_send_any_object);
|
|
~MessageSerializer();
|
|
|
|
bool MarkObjectId(ObjectPtr object, intptr_t id) {
|
|
ASSERT(id != WeakTable::kNoValue);
|
|
WeakTable* table;
|
|
if (!object->IsSmiOrOldObject()) {
|
|
table = isolate()->forward_table_new();
|
|
} else {
|
|
table = isolate()->forward_table_old();
|
|
}
|
|
return table->MarkValueExclusive(object, id);
|
|
}
|
|
|
|
void SetObjectId(ObjectPtr object, intptr_t id) {
|
|
ASSERT(id != WeakTable::kNoValue);
|
|
WeakTable* table;
|
|
if (!object->IsSmiOrOldObject()) {
|
|
table = isolate()->forward_table_new();
|
|
} else {
|
|
table = isolate()->forward_table_old();
|
|
}
|
|
table->SetValueExclusive(object, id);
|
|
}
|
|
|
|
intptr_t GetObjectId(ObjectPtr object) const {
|
|
const WeakTable* table;
|
|
if (!object->IsSmiOrOldObject()) {
|
|
table = isolate()->forward_table_new();
|
|
} else {
|
|
table = isolate()->forward_table_old();
|
|
}
|
|
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(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);
|
|
}
|
|
|
|
bool can_send_any_object() const { return can_send_any_object_; }
|
|
const char* exception_message() const { return exception_message_; }
|
|
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_;
|
|
bool const can_send_any_object_;
|
|
const char* exception_message_;
|
|
};
|
|
|
|
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& str = String::Handle(d->zone());
|
|
Library& lib = Library::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 {
|
|
str = String::New(d->ReadAscii()); // Library URI.
|
|
lib = Library::LookupLibrary(d->thread(), str);
|
|
RELEASE_ASSERT(!lib.IsNull());
|
|
str = String::New(d->ReadAscii()); // Class name.
|
|
if (str.Equals(Symbols::TopLevel())) {
|
|
cls = lib.toplevel_class();
|
|
} else {
|
|
cls = lib.LookupClass(str);
|
|
}
|
|
RELEASE_ASSERT(!cls.IsNull());
|
|
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 FunctionMessageSerializationCluster : public MessageSerializationCluster {
|
|
public:
|
|
FunctionMessageSerializationCluster()
|
|
: MessageSerializationCluster("Function",
|
|
MessagePhase::kBeforeTypes,
|
|
kFunctionCid) {}
|
|
~FunctionMessageSerializationCluster() {}
|
|
|
|
void Trace(MessageSerializer* s, Object* object) {
|
|
Function* func = static_cast<Function*>(object);
|
|
objects_.Add(func);
|
|
}
|
|
|
|
void WriteNodes(MessageSerializer* s) {
|
|
const intptr_t count = objects_.length();
|
|
s->WriteUnsigned(count);
|
|
Library& lib = Library::Handle(s->zone());
|
|
Class& cls = Class::Handle(s->zone());
|
|
String& str = String::Handle(s->zone());
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
Function* func = objects_[i];
|
|
s->AssignRef(func);
|
|
cls ^= func->Owner();
|
|
lib = cls.library();
|
|
str = lib.url();
|
|
s->WriteAscii(str);
|
|
str = cls.Name();
|
|
s->WriteAscii(str);
|
|
str = func->name();
|
|
s->WriteAscii(str);
|
|
}
|
|
}
|
|
|
|
private:
|
|
GrowableArray<Function*> objects_;
|
|
};
|
|
|
|
class FunctionMessageDeserializationCluster
|
|
: public MessageDeserializationCluster {
|
|
public:
|
|
FunctionMessageDeserializationCluster()
|
|
: MessageDeserializationCluster("Function") {}
|
|
~FunctionMessageDeserializationCluster() {}
|
|
|
|
void ReadNodes(MessageDeserializer* d) {
|
|
const intptr_t count = d->ReadUnsigned();
|
|
String& str = String::Handle(d->zone());
|
|
Library& lib = Library::Handle(d->zone());
|
|
Class& cls = Class::Handle(d->zone());
|
|
Function& func = Function::Handle(d->zone());
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
str = String::New(d->ReadAscii()); // Library URI.
|
|
lib = Library::LookupLibrary(d->thread(), str);
|
|
RELEASE_ASSERT(!lib.IsNull());
|
|
str = String::New(d->ReadAscii()); // Class name.
|
|
if (str.Equals(Symbols::TopLevel())) {
|
|
cls = lib.toplevel_class();
|
|
} else {
|
|
cls = lib.LookupClass(str);
|
|
}
|
|
RELEASE_ASSERT(!cls.IsNull());
|
|
cls.EnsureIsFinalized(d->thread());
|
|
str = String::New(d->ReadAscii()); // Function name.
|
|
func = cls.LookupStaticFunction(str);
|
|
RELEASE_ASSERT(!func.IsNull());
|
|
d->AssignRef(func.ptr());
|
|
}
|
|
}
|
|
};
|
|
|
|
class InstanceMessageSerializationCluster : public MessageSerializationCluster {
|
|
public:
|
|
InstanceMessageSerializationCluster(bool is_canonical, intptr_t cid)
|
|
: MessageSerializationCluster("Instance",
|
|
is_canonical
|
|
? MessagePhase::kCanonicalInstances
|
|
: MessagePhase::kNonCanonicalInstances,
|
|
cid,
|
|
is_canonical),
|
|
cls_(Class::Handle()) {
|
|
cls_ = IsolateGroup::Current()->class_table()->At(cid);
|
|
next_field_offset_ = cls_.host_next_field_offset();
|
|
}
|
|
~InstanceMessageSerializationCluster() {}
|
|
|
|
void Trace(MessageSerializer* s, Object* object) {
|
|
Instance* instance = static_cast<Instance*>(object);
|
|
objects_.Add(instance);
|
|
|
|
const intptr_t next_field_offset = next_field_offset_;
|
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
|
const auto unboxed_fields_bitmap =
|
|
s->isolate_group()->shared_class_table()->GetUnboxedFieldsMapAt(cid_);
|
|
#endif
|
|
for (intptr_t offset = Instance::NextFieldOffset();
|
|
offset < next_field_offset; offset += kCompressedWordSize) {
|
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
|
if (unboxed_fields_bitmap.Get(offset / kCompressedWordSize)) {
|
|
continue;
|
|
}
|
|
#endif
|
|
s->Push(reinterpret_cast<CompressedObjectPtr*>(
|
|
reinterpret_cast<uword>(instance->untag()) + offset)
|
|
->Decompress(instance->untag()->heap_base()));
|
|
}
|
|
}
|
|
|
|
void WriteNodes(MessageSerializer* s) {
|
|
s->WriteRef(cls_.ptr());
|
|
|
|
intptr_t count = objects_.length();
|
|
s->WriteUnsigned(count);
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
Instance* instance = objects_[i];
|
|
s->AssignRef(instance);
|
|
}
|
|
}
|
|
|
|
void WriteEdges(MessageSerializer* s) {
|
|
const intptr_t count = objects_.length();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
Instance* instance = objects_[i];
|
|
|
|
const intptr_t next_field_offset = next_field_offset_;
|
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
|
const auto unboxed_fields_bitmap =
|
|
s->isolate_group()->shared_class_table()->GetUnboxedFieldsMapAt(cid_);
|
|
#endif
|
|
for (intptr_t offset = Instance::NextFieldOffset();
|
|
offset < next_field_offset; offset += kCompressedWordSize) {
|
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
|
if (unboxed_fields_bitmap.Get(offset / kCompressedWordSize)) {
|
|
// Writes 32 bits of the unboxed value at a time
|
|
const uword value = *reinterpret_cast<compressed_uword*>(
|
|
reinterpret_cast<uword>(instance->untag()) + offset);
|
|
s->WriteWordWith32BitWrites(value);
|
|
continue;
|
|
}
|
|
#endif
|
|
s->WriteRef(reinterpret_cast<CompressedObjectPtr*>(
|
|
reinterpret_cast<uword>(instance->untag()) + offset)
|
|
->Decompress(instance->untag()->heap_base()));
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
Class& cls_;
|
|
intptr_t next_field_offset_;
|
|
GrowableArray<Instance*> objects_;
|
|
};
|
|
|
|
class InstanceMessageDeserializationCluster
|
|
: public MessageDeserializationCluster {
|
|
public:
|
|
explicit InstanceMessageDeserializationCluster(bool is_canonical)
|
|
: MessageDeserializationCluster("Instance", is_canonical),
|
|
cls_(Class::Handle()),
|
|
field_stores_(GrowableObjectArray::Handle(GrowableObjectArray::New())) {
|
|
}
|
|
~InstanceMessageDeserializationCluster() {}
|
|
|
|
void ReadNodes(MessageDeserializer* d) {
|
|
cls_ ^= d->ReadRef();
|
|
|
|
intptr_t count = d->ReadUnsigned();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
d->AssignRef(Instance::New(cls_));
|
|
}
|
|
}
|
|
|
|
void ReadEdges(MessageDeserializer* d) {
|
|
const intptr_t next_field_offset = cls_.host_next_field_offset();
|
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
|
const auto unboxed_fields_bitmap =
|
|
d->isolate_group()->shared_class_table()->GetUnboxedFieldsMapAt(
|
|
cls_.id());
|
|
#else
|
|
const intptr_t type_argument_field_offset =
|
|
cls_.host_type_arguments_field_offset();
|
|
const bool use_field_guards = d->isolate_group()->use_field_guards();
|
|
const Array& field_map = Array::Handle(d->zone(), cls_.OffsetToFieldMap());
|
|
Field& field = Field::Handle(d->zone());
|
|
#endif
|
|
Instance& instance = Instance::Handle(d->zone());
|
|
Object& value = Object::Handle(d->zone());
|
|
|
|
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
|
instance ^= d->Ref(id);
|
|
for (intptr_t offset = Instance::NextFieldOffset();
|
|
offset < next_field_offset; offset += kCompressedWordSize) {
|
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
|
if (unboxed_fields_bitmap.Get(offset / kCompressedWordSize)) {
|
|
compressed_uword* p = reinterpret_cast<compressed_uword*>(
|
|
reinterpret_cast<uword>(instance.untag()) + offset);
|
|
// Reads 32 bits of the unboxed value at a time
|
|
*p = d->ReadWordWith32BitReads();
|
|
continue;
|
|
}
|
|
#endif
|
|
value = d->ReadRef();
|
|
instance.SetFieldAtOffset(offset, value);
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
if (use_field_guards && (offset != type_argument_field_offset) &&
|
|
(value.ptr() != Object::sentinel().ptr())) {
|
|
field ^= field_map.At(offset >> kCompressedWordSizeLog2);
|
|
ASSERT(!field.IsNull());
|
|
ASSERT(field.HostOffset() == offset);
|
|
field_stores_.Add(field);
|
|
field_stores_.Add(value);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
if (cls_.ptr() == d->isolate_group()->object_store()->expando_class()) {
|
|
const auto& expandos =
|
|
Array::Handle(d->zone(), Array::New(stop_index_ - start_index_));
|
|
auto& instance = Instance::Handle(d->zone());
|
|
for (intptr_t i = start_index_, j = 0; i < stop_index_; i++, j++) {
|
|
instance ^= d->Ref(i);
|
|
expandos.SetAt(j, instance);
|
|
}
|
|
return DartLibraryCalls::RehashObjectsInDartCore(d->thread(), expandos);
|
|
}
|
|
|
|
Field& field = Field::Handle(d->zone());
|
|
Object& value = Object::Handle(d->zone());
|
|
for (int i = 0; i < field_stores_.Length(); i += 2) {
|
|
field ^= field_stores_.At(i);
|
|
value = field_stores_.At(i + 1);
|
|
field.RecordStore(value);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
private:
|
|
Class& cls_;
|
|
GrowableObjectArray& field_stores_;
|
|
};
|
|
|
|
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);
|
|
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 TypeRefMessageSerializationCluster : public MessageSerializationCluster {
|
|
public:
|
|
explicit TypeRefMessageSerializationCluster(bool is_canonical)
|
|
: MessageSerializationCluster("TypeRef",
|
|
MessagePhase::kTypes,
|
|
kTypeRefCid,
|
|
is_canonical) {}
|
|
~TypeRefMessageSerializationCluster() {}
|
|
|
|
void Trace(MessageSerializer* s, Object* object) {
|
|
TypeRef* type = static_cast<TypeRef*>(object);
|
|
objects_.Add(type);
|
|
|
|
s->Push(type->type());
|
|
}
|
|
|
|
void WriteNodes(MessageSerializer* s) {
|
|
const intptr_t count = objects_.length();
|
|
s->WriteUnsigned(count);
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
TypeRef* type = objects_[i];
|
|
s->AssignRef(type);
|
|
}
|
|
}
|
|
|
|
void WriteEdges(MessageSerializer* s) {
|
|
const intptr_t count = objects_.length();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
TypeRef* type = objects_[i];
|
|
s->WriteRef(type->type());
|
|
}
|
|
}
|
|
|
|
private:
|
|
GrowableArray<TypeRef*> objects_;
|
|
};
|
|
|
|
class TypeRefMessageDeserializationCluster
|
|
: public MessageDeserializationCluster {
|
|
public:
|
|
explicit TypeRefMessageDeserializationCluster(bool is_canonical)
|
|
: MessageDeserializationCluster("TypeRef", is_canonical) {}
|
|
~TypeRefMessageDeserializationCluster() {}
|
|
|
|
void ReadNodes(MessageDeserializer* d) {
|
|
const intptr_t count = d->ReadUnsigned();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
d->AssignRef(TypeRef::New());
|
|
}
|
|
}
|
|
|
|
void ReadEdges(MessageDeserializer* d) {
|
|
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
|
TypeRefPtr type = static_cast<TypeRefPtr>(d->Ref(id));
|
|
type->untag()->set_type(static_cast<AbstractTypePtr>(d->ReadRef()));
|
|
}
|
|
}
|
|
|
|
ObjectPtr PostLoad(MessageDeserializer* d) {
|
|
ClassFinalizer::FinalizationKind finalization =
|
|
is_canonical() ? ClassFinalizer::kCanonicalize
|
|
: ClassFinalizer::kFinalize;
|
|
Code& code = Code::Handle(d->zone());
|
|
TypeRef& type = TypeRef::Handle(d->zone());
|
|
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
|
type ^= d->Ref(id);
|
|
type ^= ClassFinalizer::FinalizeType(type, finalization);
|
|
d->UpdateRef(id, type);
|
|
|
|
code = TypeTestingStubGenerator::DefaultCodeForType(type);
|
|
type.InitializeTypeTestingStubNonAtomic(code);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
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(); // Type.
|
|
}
|
|
}
|
|
};
|
|
|
|
class ClosureMessageSerializationCluster : public MessageSerializationCluster {
|
|
public:
|
|
explicit ClosureMessageSerializationCluster(bool is_canonical)
|
|
: MessageSerializationCluster("Closure",
|
|
MessagePhase::kCanonicalInstances,
|
|
kClosureCid,
|
|
is_canonical) {}
|
|
~ClosureMessageSerializationCluster() {}
|
|
|
|
void Trace(MessageSerializer* s, Object* object) {
|
|
Closure* closure = static_cast<Closure*>(object);
|
|
|
|
if (!s->can_send_any_object() ||
|
|
!Function::IsImplicitStaticClosureFunction(closure->function())) {
|
|
const char* message = OS::SCreate(
|
|
s->zone(),
|
|
"Illegal argument in isolate message : (object is a closure - %s)",
|
|
Function::Handle(closure->function()).ToCString());
|
|
s->IllegalObject(*object, message);
|
|
}
|
|
|
|
objects_.Add(closure);
|
|
|
|
s->Push(closure->function());
|
|
s->Push(closure->delayed_type_arguments());
|
|
}
|
|
|
|
void WriteNodes(MessageSerializer* s) {
|
|
const intptr_t count = objects_.length();
|
|
s->WriteUnsigned(count);
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
Closure* closure = objects_[i];
|
|
s->AssignRef(closure);
|
|
s->WriteRef(closure->function());
|
|
s->WriteRef(closure->delayed_type_arguments());
|
|
}
|
|
}
|
|
|
|
private:
|
|
GrowableArray<Closure*> objects_;
|
|
};
|
|
|
|
class ClosureMessageDeserializationCluster
|
|
: public MessageDeserializationCluster {
|
|
public:
|
|
explicit ClosureMessageDeserializationCluster(bool is_canonical)
|
|
: MessageDeserializationCluster("Closure", is_canonical) {}
|
|
~ClosureMessageDeserializationCluster() {}
|
|
|
|
void ReadNodes(MessageDeserializer* d) {
|
|
const Context& null_context = Context::Handle(d->zone());
|
|
TypeArguments& delayed_type_arguments = TypeArguments::Handle(d->zone());
|
|
Function& func = Function::Handle(d->zone());
|
|
intptr_t count = d->ReadUnsigned();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
func ^= d->ReadRef();
|
|
ASSERT(func.is_static());
|
|
func = func.ImplicitClosureFunction();
|
|
delayed_type_arguments ^= d->ReadRef();
|
|
if (delayed_type_arguments.IsNull()) {
|
|
d->AssignRef(func.ImplicitStaticClosure());
|
|
} else {
|
|
// If delayed type arguments were provided, create and return new
|
|
// closure with those, otherwise return associated implicit static
|
|
// closure. Note that static closures can't have instantiator or
|
|
// function types since statics can't refer to class type arguments,
|
|
// don't have outer functions.
|
|
d->AssignRef(Closure::New(
|
|
/*instantiator_type_arguments=*/Object::null_type_arguments(),
|
|
/*function_type_arguments=*/Object::null_type_arguments(),
|
|
delayed_type_arguments, func, null_context, Heap::kOld));
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
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);
|
|
|
|
s->Push(array->GetTypeArguments());
|
|
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->GetTypeArguments());
|
|
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 = NULL;
|
|
}
|
|
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);
|
|
uint8_t* cdata =
|
|
reinterpret_cast<uint8_t*>(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 = NULL;
|
|
} else {
|
|
data->value.as_typed_data.values =
|
|
const_cast<uint8_t*>(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_;
|
|
};
|
|
|
|
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);
|
|
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());
|
|
}
|
|
}
|
|
|
|
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();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
d->AssignRef(TypedDataView::New(cid_));
|
|
}
|
|
}
|
|
|
|
void ReadEdges(MessageDeserializer* d) {
|
|
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) {
|
|
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();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
Dart_CTypedDataView* view = d->zone()->Alloc<Dart_CTypedDataView>(1);
|
|
d->AssignRef(view);
|
|
}
|
|
}
|
|
|
|
void ReadEdgesApi(ApiMessageDeserializer* d) {
|
|
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) {
|
|
Dart_TypedData_Type type;
|
|
switch (cid_) {
|
|
case kTypedDataInt8ArrayViewCid:
|
|
type = Dart_TypedData_kInt8;
|
|
break;
|
|
case kTypedDataUint8ArrayViewCid:
|
|
type = Dart_TypedData_kUint8;
|
|
break;
|
|
case kTypedDataUint8ClampedArrayViewCid:
|
|
type = Dart_TypedData_kUint8Clamped;
|
|
break;
|
|
case kTypedDataInt16ArrayViewCid:
|
|
type = Dart_TypedData_kInt16;
|
|
break;
|
|
case kTypedDataUint16ArrayViewCid:
|
|
type = Dart_TypedData_kUint16;
|
|
break;
|
|
case kTypedDataInt32ArrayViewCid:
|
|
type = Dart_TypedData_kInt32;
|
|
break;
|
|
case kTypedDataUint32ArrayViewCid:
|
|
type = Dart_TypedData_kUint32;
|
|
break;
|
|
case kTypedDataInt64ArrayViewCid:
|
|
type = Dart_TypedData_kInt64;
|
|
break;
|
|
case kTypedDataUint64ArrayViewCid:
|
|
type = Dart_TypedData_kUint64;
|
|
break;
|
|
case kTypedDataFloat32ArrayViewCid:
|
|
type = Dart_TypedData_kFloat32;
|
|
break;
|
|
case kTypedDataFloat64ArrayViewCid:
|
|
type = Dart_TypedData_kFloat64;
|
|
break;
|
|
case kTypedDataInt32x4ArrayViewCid:
|
|
type = Dart_TypedData_kInt32x4;
|
|
break;
|
|
case kTypedDataFloat32x4ArrayViewCid:
|
|
type = Dart_TypedData_kFloat32x4;
|
|
break;
|
|
case kTypedDataFloat64x2ArrayViewCid:
|
|
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_;
|
|
};
|
|
|
|
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 transferrability state.
|
|
ASSERT(peer != nullptr);
|
|
TransferableTypedDataPeer* tpeer =
|
|
reinterpret_cast<TransferableTypedDataPeer*>(peer);
|
|
if (tpeer->data() == nullptr) {
|
|
s->IllegalObject(
|
|
*object,
|
|
"Illegal argument in isolate message"
|
|
" : (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 transferrability 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<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) {}
|
|
~Simd128MessageDeserializationCluster() {}
|
|
|
|
void ReadNodes(MessageDeserializer* d) {
|
|
const intptr_t count = d->ReadUnsigned();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
ASSERT_EQUAL(Int32x4::InstanceSize(), Float32x4::InstanceSize());
|
|
ASSERT_EQUAL(Int32x4::InstanceSize(), Float64x2::InstanceSize());
|
|
ObjectPtr vector =
|
|
Object::Allocate(cid_, Int32x4::InstanceSize(), Heap::kNew,
|
|
Int32x4::ContainsCompressedPointers());
|
|
d->AssignRef(vector);
|
|
ASSERT_EQUAL(Int32x4::value_offset(), Float32x4::value_offset());
|
|
ASSERT_EQUAL(Int32x4::value_offset(), Float64x2::value_offset());
|
|
d->ReadBytes(&(static_cast<Int32x4Ptr>(vector)->untag()->value_),
|
|
sizeof(simd128_value_t));
|
|
}
|
|
}
|
|
|
|
private:
|
|
const intptr_t cid_;
|
|
};
|
|
|
|
class RegExpMessageSerializationCluster : public MessageSerializationCluster {
|
|
public:
|
|
RegExpMessageSerializationCluster()
|
|
: MessageSerializationCluster("RegExp",
|
|
MessagePhase::kNonCanonicalInstances,
|
|
kRegExpCid) {}
|
|
~RegExpMessageSerializationCluster() {}
|
|
|
|
void Trace(MessageSerializer* s, Object* object) {
|
|
RegExp* regexp = static_cast<RegExp*>(object);
|
|
objects_.Add(regexp);
|
|
|
|
s->Push(regexp->capture_name_map());
|
|
s->Push(regexp->pattern());
|
|
}
|
|
|
|
void WriteNodes(MessageSerializer* s) {
|
|
const intptr_t count = objects_.length();
|
|
s->WriteUnsigned(count);
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
RegExp* regexp = objects_[i];
|
|
s->AssignRef(regexp);
|
|
s->WriteRef(regexp->capture_name_map());
|
|
s->WriteRef(regexp->pattern());
|
|
s->Write<int32_t>(regexp->num_bracket_expressions());
|
|
s->Write<int32_t>(regexp->num_registers(true));
|
|
s->Write<int32_t>(regexp->num_registers(false));
|
|
s->Write<int>(regexp->flags().value());
|
|
}
|
|
}
|
|
|
|
private:
|
|
GrowableArray<RegExp*> objects_;
|
|
};
|
|
|
|
class RegExpMessageDeserializationCluster
|
|
: public MessageDeserializationCluster {
|
|
public:
|
|
RegExpMessageDeserializationCluster()
|
|
: MessageDeserializationCluster("RegExp") {}
|
|
~RegExpMessageDeserializationCluster() {}
|
|
|
|
void ReadNodes(MessageDeserializer* d) {
|
|
RegExp& regexp = RegExp::Handle(d->zone());
|
|
intptr_t count = d->ReadUnsigned();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
regexp = RegExp::New(d->zone());
|
|
d->AssignRef(regexp.ptr());
|
|
regexp.untag()->set_capture_name_map(static_cast<ArrayPtr>(d->ReadRef()));
|
|
regexp.untag()->set_pattern(static_cast<StringPtr>(d->ReadRef()));
|
|
regexp.set_num_bracket_expressions(d->Read<int32_t>());
|
|
regexp.set_num_registers(true, d->Read<int32_t>());
|
|
regexp.set_num_registers(false, d->Read<int32_t>());
|
|
regexp.set_flags(RegExpFlags(d->Read<int>()));
|
|
}
|
|
}
|
|
};
|
|
|
|
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 WeakPropertyMessageSerializationCluster
|
|
: public MessageSerializationCluster {
|
|
public:
|
|
WeakPropertyMessageSerializationCluster()
|
|
: MessageSerializationCluster("WeakProperty",
|
|
MessagePhase::kNonCanonicalInstances,
|
|
kWeakPropertyCid) {}
|
|
~WeakPropertyMessageSerializationCluster() {}
|
|
|
|
void Trace(MessageSerializer* s, Object* object) {
|
|
WeakProperty* property = static_cast<WeakProperty*>(object);
|
|
objects_.Add(property);
|
|
}
|
|
|
|
void RetraceEphemerons(MessageSerializer* s) {
|
|
for (intptr_t i = 0; i < objects_.length(); i++) {
|
|
WeakProperty* property = objects_[i];
|
|
if (s->HasRef(property->untag()->key())) {
|
|
s->Push(property->untag()->value());
|
|
}
|
|
}
|
|
}
|
|
|
|
void WriteNodes(MessageSerializer* s) {
|
|
const intptr_t count = objects_.length();
|
|
s->WriteUnsigned(count);
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
WeakProperty* property = objects_[i];
|
|
s->AssignRef(property);
|
|
}
|
|
}
|
|
|
|
void WriteEdges(MessageSerializer* s) {
|
|
const intptr_t count = objects_.length();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
WeakProperty* property = objects_[i];
|
|
if (s->HasRef(property->untag()->key())) {
|
|
s->WriteRef(property->untag()->key());
|
|
s->WriteRef(property->untag()->value());
|
|
} else {
|
|
s->WriteRef(Object::null());
|
|
s->WriteRef(Object::null());
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
GrowableArray<WeakProperty*> objects_;
|
|
};
|
|
|
|
class WeakPropertyMessageDeserializationCluster
|
|
: public MessageDeserializationCluster {
|
|
public:
|
|
WeakPropertyMessageDeserializationCluster()
|
|
: MessageDeserializationCluster("WeakProperty") {}
|
|
~WeakPropertyMessageDeserializationCluster() {}
|
|
|
|
void ReadNodes(MessageDeserializer* d) {
|
|
const intptr_t count = d->ReadUnsigned();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
d->AssignRef(WeakProperty::New());
|
|
}
|
|
}
|
|
|
|
void ReadEdges(MessageDeserializer* d) {
|
|
ASSERT(!is_canonical()); // Never canonical.
|
|
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
|
WeakPropertyPtr property = static_cast<WeakPropertyPtr>(d->Ref(id));
|
|
property->untag()->set_key(d->ReadRef());
|
|
property->untag()->set_value(d->ReadRef());
|
|
}
|
|
}
|
|
};
|
|
|
|
class WeakReferenceMessageSerializationCluster
|
|
: public MessageSerializationCluster {
|
|
public:
|
|
WeakReferenceMessageSerializationCluster()
|
|
: MessageSerializationCluster("WeakReference",
|
|
MessagePhase::kNonCanonicalInstances,
|
|
kWeakReferenceCid) {}
|
|
~WeakReferenceMessageSerializationCluster() {}
|
|
|
|
void Trace(MessageSerializer* s, Object* object) {
|
|
WeakReference* reference = static_cast<WeakReference*>(object);
|
|
objects_.Add(reference);
|
|
|
|
s->Push(reference->untag()->type_arguments());
|
|
}
|
|
|
|
void WriteNodes(MessageSerializer* s) {
|
|
const intptr_t count = objects_.length();
|
|
s->WriteUnsigned(count);
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
WeakReference* reference = objects_[i];
|
|
s->AssignRef(reference);
|
|
}
|
|
}
|
|
|
|
void WriteEdges(MessageSerializer* s) {
|
|
const intptr_t count = objects_.length();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
WeakReference* reference = objects_[i];
|
|
if (s->HasRef(reference->untag()->target())) {
|
|
s->WriteRef(reference->untag()->target());
|
|
} else {
|
|
s->WriteRef(Object::null());
|
|
}
|
|
s->WriteRef(reference->untag()->type_arguments());
|
|
}
|
|
}
|
|
|
|
private:
|
|
GrowableArray<WeakReference*> objects_;
|
|
};
|
|
|
|
class WeakReferenceMessageDeserializationCluster
|
|
: public MessageDeserializationCluster {
|
|
public:
|
|
WeakReferenceMessageDeserializationCluster()
|
|
: MessageDeserializationCluster("WeakReference") {}
|
|
~WeakReferenceMessageDeserializationCluster() {}
|
|
|
|
void ReadNodes(MessageDeserializer* d) {
|
|
const intptr_t count = d->ReadUnsigned();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
d->AssignRef(WeakReference::New());
|
|
}
|
|
}
|
|
|
|
void ReadEdges(MessageDeserializer* d) {
|
|
ASSERT(!is_canonical()); // Never canonical.
|
|
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
|
WeakReferencePtr reference = static_cast<WeakReferencePtr>(d->Ref(id));
|
|
reference->untag()->set_target(d->ReadRef());
|
|
reference->untag()->set_type_arguments(
|
|
static_cast<TypeArgumentsPtr>(d->ReadRef()));
|
|
}
|
|
}
|
|
};
|
|
|
|
class LinkedHashMapMessageSerializationCluster
|
|
: public MessageSerializationCluster {
|
|
public:
|
|
LinkedHashMapMessageSerializationCluster(Zone* zone,
|
|
bool is_canonical,
|
|
intptr_t cid)
|
|
: MessageSerializationCluster("LinkedHashMap",
|
|
is_canonical
|
|
? MessagePhase::kCanonicalInstances
|
|
: MessagePhase::kNonCanonicalInstances,
|
|
cid,
|
|
is_canonical),
|
|
objects_(zone, 0) {}
|
|
~LinkedHashMapMessageSerializationCluster() {}
|
|
|
|
void Trace(MessageSerializer* s, Object* object) {
|
|
LinkedHashMap* map = static_cast<LinkedHashMap*>(object);
|
|
objects_.Add(map);
|
|
|
|
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++) {
|
|
LinkedHashMap* map = objects_[i];
|
|
s->AssignRef(map);
|
|
}
|
|
}
|
|
|
|
void WriteEdges(MessageSerializer* s) {
|
|
const intptr_t count = objects_.length();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
LinkedHashMap* map = objects_[i];
|
|
s->WriteRef(map->untag()->type_arguments());
|
|
s->WriteRef(map->untag()->data());
|
|
s->WriteRef(map->untag()->used_data());
|
|
}
|
|
}
|
|
|
|
private:
|
|
GrowableArray<LinkedHashMap*> objects_;
|
|
};
|
|
|
|
class LinkedHashMapMessageDeserializationCluster
|
|
: public MessageDeserializationCluster {
|
|
public:
|
|
LinkedHashMapMessageDeserializationCluster(bool is_canonical, intptr_t cid)
|
|
: MessageDeserializationCluster("LinkedHashMap", is_canonical),
|
|
cid_(cid) {}
|
|
~LinkedHashMapMessageDeserializationCluster() {}
|
|
|
|
void ReadNodes(MessageDeserializer* d) {
|
|
const intptr_t count = d->ReadUnsigned();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
d->AssignRef(LinkedHashMap::NewUninitialized(cid_));
|
|
}
|
|
}
|
|
|
|
void ReadEdges(MessageDeserializer* d) {
|
|
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
|
LinkedHashMapPtr map = static_cast<LinkedHashMapPtr>(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_ == kLinkedHashMapCid);
|
|
return PostLoadLinkedHash(d);
|
|
}
|
|
|
|
ASSERT(cid_ == kImmutableLinkedHashMapCid);
|
|
SafepointMutexLocker ml(
|
|
d->isolate_group()->constant_canonicalization_mutex());
|
|
LinkedHashMap& instance = LinkedHashMap::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 LinkedHashSetMessageSerializationCluster
|
|
: public MessageSerializationCluster {
|
|
public:
|
|
LinkedHashSetMessageSerializationCluster(Zone* zone,
|
|
bool is_canonical,
|
|
intptr_t cid)
|
|
: MessageSerializationCluster("LinkedHashSet",
|
|
is_canonical
|
|
? MessagePhase::kCanonicalInstances
|
|
: MessagePhase::kNonCanonicalInstances,
|
|
cid,
|
|
is_canonical),
|
|
objects_(zone, 0) {}
|
|
~LinkedHashSetMessageSerializationCluster() {}
|
|
|
|
void Trace(MessageSerializer* s, Object* object) {
|
|
LinkedHashSet* map = static_cast<LinkedHashSet*>(object);
|
|
objects_.Add(map);
|
|
|
|
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++) {
|
|
LinkedHashSet* map = objects_[i];
|
|
s->AssignRef(map);
|
|
}
|
|
}
|
|
|
|
void WriteEdges(MessageSerializer* s) {
|
|
const intptr_t count = objects_.length();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
LinkedHashSet* map = objects_[i];
|
|
s->WriteRef(map->untag()->type_arguments());
|
|
s->WriteRef(map->untag()->data());
|
|
s->WriteRef(map->untag()->used_data());
|
|
}
|
|
}
|
|
|
|
private:
|
|
GrowableArray<LinkedHashSet*> objects_;
|
|
};
|
|
|
|
class LinkedHashSetMessageDeserializationCluster
|
|
: public MessageDeserializationCluster {
|
|
public:
|
|
LinkedHashSetMessageDeserializationCluster(bool is_canonical, intptr_t cid)
|
|
: MessageDeserializationCluster("LinkedHashSet", is_canonical),
|
|
cid_(cid) {}
|
|
~LinkedHashSetMessageDeserializationCluster() {}
|
|
|
|
void ReadNodes(MessageDeserializer* d) {
|
|
const intptr_t count = d->ReadUnsigned();
|
|
for (intptr_t i = 0; i < count; i++) {
|
|
d->AssignRef(LinkedHashSet::NewUninitialized(cid_));
|
|
}
|
|
}
|
|
|
|
void ReadEdges(MessageDeserializer* d) {
|
|
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
|
LinkedHashSetPtr map = static_cast<LinkedHashSetPtr>(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_ == kLinkedHashSetCid);
|
|
return PostLoadLinkedHash(d);
|
|
}
|
|
|
|
ASSERT(cid_ == kImmutableLinkedHashSetCid);
|
|
SafepointMutexLocker ml(
|
|
d->isolate_group()->constant_canonicalization_mutex());
|
|
LinkedHashSet& instance = LinkedHashSet::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);
|
|
|
|
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::New(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 = NULL;
|
|
} 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 const intptr_t kFirstReference = 1;
|
|
static const intptr_t kUnallocatedReference = -1;
|
|
|
|
BaseSerializer::BaseSerializer(Thread* thread, Zone* zone)
|
|
: StackResource(thread),
|
|
zone_(zone),
|
|
stream_(100),
|
|
finalizable_data_(new MessageFinalizableData()),
|
|
clusters_(zone, 0),
|
|
ephemeron_cluster_(nullptr),
|
|
num_base_objects_(0),
|
|
num_written_objects_(0),
|
|
next_ref_index_(kFirstReference) {}
|
|
|
|
BaseSerializer::~BaseSerializer() {
|
|
delete finalizable_data_;
|
|
}
|
|
|
|
MessageSerializer::MessageSerializer(Thread* thread, bool can_send_any_object)
|
|
: BaseSerializer(thread, thread->zone()),
|
|
forward_table_new_(),
|
|
forward_table_old_(),
|
|
stack_(thread->zone(), 0),
|
|
can_send_any_object_(can_send_any_object),
|
|
exception_message_(nullptr) {
|
|
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(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) {
|
|
const Class& clazz =
|
|
Class::Handle(zone(), isolate_group()->class_table()->At(cid));
|
|
if (!can_send_any_object()) {
|
|
ObjectStore* object_store = isolate_group()->object_store();
|
|
if ((clazz.library() != object_store->core_library()) &&
|
|
(clazz.library() != object_store->collection_library()) &&
|
|
(clazz.library() != object_store->typed_data_library())) {
|
|
IllegalObject(*object,
|
|
"Illegal argument in isolate message"
|
|
" : (object is a regular Dart Instance)");
|
|
}
|
|
}
|
|
if (clazz.num_native_fields() != 0) {
|
|
char* chars = OS::SCreate(thread()->zone(),
|
|
"Illegal argument in isolate message"
|
|
" : (object extends NativeWrapper - %s)",
|
|
clazz.ToCString());
|
|
IllegalObject(*object, chars);
|
|
}
|
|
}
|
|
|
|
// Keep the list in sync with the one in lib/isolate.cc
|
|
#define ILLEGAL(type) \
|
|
if (cid == k##type##Cid) { \
|
|
IllegalObject(*object, \
|
|
"Illegal argument in isolate message" \
|
|
" : (object is a " #type ")"); \
|
|
}
|
|
|
|
ILLEGAL(FunctionType)
|
|
ILLEGAL(MirrorReference)
|
|
ILLEGAL(ReceivePort)
|
|
ILLEGAL(StackTrace)
|
|
ILLEGAL(SuspendState)
|
|
ILLEGAL(UserTag)
|
|
|
|
// 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 (cid >= kNumPredefinedCids || cid == kInstanceCid ||
|
|
cid == kByteBufferCid) {
|
|
Push(isolate_group()->class_table()->At(cid));
|
|
}
|
|
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 != NULL);
|
|
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_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) {
|
|
exception_message_ = message;
|
|
thread()->long_jump_base()->Jump(1, Object::snapshot_writer_error());
|
|
}
|
|
|
|
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 ((cid >= kNumPredefinedCids) || (cid == kInstanceCid) ||
|
|
(cid == kByteBufferCid)) {
|
|
return new (Z) InstanceMessageSerializationCluster(is_canonical, cid);
|
|
}
|
|
if (IsTypedDataViewClassId(cid) || cid == kByteDataViewCid) {
|
|
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 kFunctionCid:
|
|
return new (Z) FunctionMessageSerializationCluster();
|
|
case kTypeCid:
|
|
return new (Z) TypeMessageSerializationCluster(is_canonical);
|
|
case kTypeRefCid:
|
|
return new (Z) TypeRefMessageSerializationCluster(is_canonical);
|
|
case kClosureCid:
|
|
return new (Z) ClosureMessageSerializationCluster(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 kRegExpCid:
|
|
return new (Z) RegExpMessageSerializationCluster();
|
|
case kSendPortCid:
|
|
return new (Z) SendPortMessageSerializationCluster(Z);
|
|
case kCapabilityCid:
|
|
return new (Z) CapabilityMessageSerializationCluster(Z);
|
|
case kTransferableTypedDataCid:
|
|
return new (Z) TransferableTypedDataMessageSerializationCluster();
|
|
case kWeakPropertyCid:
|
|
ephemeron_cluster_ = new (Z) WeakPropertyMessageSerializationCluster();
|
|
return ephemeron_cluster_;
|
|
case kWeakReferenceCid:
|
|
return new (Z) WeakReferenceMessageSerializationCluster();
|
|
case kLinkedHashMapCid:
|
|
case kImmutableLinkedHashMapCid:
|
|
return new (Z)
|
|
LinkedHashMapMessageSerializationCluster(Z, is_canonical, cid);
|
|
case kLinkedHashSetCid:
|
|
case kImmutableLinkedHashSetCid:
|
|
return new (Z)
|
|
LinkedHashSetMessageSerializationCluster(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 ((cid >= kNumPredefinedCids) || (cid == kInstanceCid) ||
|
|
(cid == kByteBufferCid)) {
|
|
return new (Z) InstanceMessageDeserializationCluster(is_canonical);
|
|
}
|
|
if (IsTypedDataViewClassId(cid) || cid == kByteDataViewCid) {
|
|
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 kFunctionCid:
|
|
ASSERT(!is_canonical);
|
|
return new (Z) FunctionMessageDeserializationCluster();
|
|
case kTypeCid:
|
|
return new (Z) TypeMessageDeserializationCluster(is_canonical);
|
|
case kTypeRefCid:
|
|
return new (Z) TypeRefMessageDeserializationCluster(is_canonical);
|
|
case kClosureCid:
|
|
return new (Z) ClosureMessageDeserializationCluster(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 kRegExpCid:
|
|
ASSERT(!is_canonical);
|
|
return new (Z) RegExpMessageDeserializationCluster();
|
|
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 kWeakPropertyCid:
|
|
ASSERT(!is_canonical);
|
|
return new (Z) WeakPropertyMessageDeserializationCluster();
|
|
case kWeakReferenceCid:
|
|
ASSERT(!is_canonical);
|
|
return new (Z) WeakReferenceMessageDeserializationCluster();
|
|
case kLinkedHashMapCid:
|
|
case kImmutableLinkedHashMapCid:
|
|
return new (Z)
|
|
LinkedHashMapMessageDeserializationCluster(is_canonical, cid);
|
|
case kLinkedHashSetCid:
|
|
case kImmutableLinkedHashSetCid:
|
|
return new (Z)
|
|
LinkedHashSetMessageDeserializationCluster(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::zero_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::zero_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(PredefinedCObjects::cobj_zero_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(PredefinedCObjects::cobj_zero_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) {
|
|
// Strong references.
|
|
while (stack_.length() > 0) {
|
|
Trace(stack_.RemoveLast());
|
|
}
|
|
|
|
// Ephemeron references.
|
|
if (ephemeron_cluster_ != nullptr) {
|
|
ephemeron_cluster_->RetraceEphemerons(this);
|
|
}
|
|
}
|
|
|
|
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 can_send_any_object,
|
|
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, can_send_any_object);
|
|
|
|
volatile bool has_exception = false;
|
|
{
|
|
LongJumpScope jump(thread);
|
|
if (setjmp(*jump.Set()) == 0) {
|
|
serializer.Serialize(obj);
|
|
} else {
|
|
has_exception = true;
|
|
}
|
|
}
|
|
|
|
if (has_exception) {
|
|
{
|
|
NoSafepointScope no_safepoint;
|
|
ErrorPtr error = thread->StealStickyError();
|
|
ASSERT(error == Object::snapshot_writer_error().ptr());
|
|
}
|
|
|
|
const String& msg_obj =
|
|
String::Handle(String::New(serializer.exception_message()));
|
|
const Array& args = Array::Handle(Array::New(1));
|
|
args.SetAt(0, msg_obj);
|
|
Exceptions::ThrowByType(Exceptions::kArgument, args);
|
|
}
|
|
|
|
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
|