[vm/shared] Snapshot initial values of shared fields.

BUG=https://github.com/dart-lang/sdk/issues/56016
BUG=https://github.com/dart-lang/sdk/issues/55991
TEST=shared_test in appjit

Change-Id: I94ee12355cea95ca1c2698ee77e7ceffe81e27e1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/371944
Commit-Queue: Alexander Aprelev <aam@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Alexander Aprelev
2024-06-20 17:08:10 +00:00
committed by Commit Queue
parent ae3de54bbb
commit f3d7a74181
7 changed files with 99 additions and 50 deletions
+17 -13
View File
@@ -7112,10 +7112,11 @@ class ProgramSerializationRoots : public SerializationRoots {
s->Push(initial_field_table->At(i));
}
FieldTable* shared_field_table =
s->thread()->isolate_group()->shared_field_table();
for (intptr_t i = 0, n = shared_field_table->NumFieldIds(); i < n; i++) {
s->Push(shared_field_table->At(i));
FieldTable* shared_initial_field_table =
s->thread()->isolate_group()->shared_initial_field_table();
for (intptr_t i = 0, n = shared_initial_field_table->NumFieldIds(); i < n;
i++) {
s->Push(shared_initial_field_table->At(i));
}
dispatch_table_entries_ = object_store_->dispatch_table_code_entries();
@@ -7150,12 +7151,13 @@ class ProgramSerializationRoots : public SerializationRoots {
s->WriteRootRef(initial_field_table->At(i), "some-static-field");
}
FieldTable* shared_field_table =
s->thread()->isolate_group()->shared_field_table();
intptr_t n_shared = shared_field_table->NumFieldIds();
FieldTable* shared_initial_field_table =
s->thread()->isolate_group()->shared_initial_field_table();
intptr_t n_shared = shared_initial_field_table->NumFieldIds();
s->WriteUnsigned(n_shared);
for (intptr_t i = 0; i < n_shared; i++) {
s->WriteRootRef(shared_field_table->At(i), "some-shared-static-field");
s->WriteRootRef(shared_initial_field_table->At(i),
"some-shared-static-field");
}
// The dispatch table is serialized only for precompiled snapshots.
@@ -7212,12 +7214,14 @@ class ProgramDeserializationRoots : public DeserializationRoots {
}
{
FieldTable* shared_field_table =
d->thread()->isolate_group()->shared_field_table();
FieldTable* shared_initial_field_table =
d->thread()->isolate_group()->shared_initial_field_table();
intptr_t n_shared = d->ReadUnsigned();
shared_field_table->AllocateIndex(n_shared);
for (intptr_t i = 0; i < n_shared; i++) {
shared_field_table->SetAt(i, d->ReadRef());
if (n_shared > 0) {
shared_initial_field_table->AllocateIndex(n_shared - 1);
for (intptr_t i = 0; i < n_shared; i++) {
shared_initial_field_table->SetAt(i, d->ReadRef());
}
}
}
+1 -1
View File
@@ -1329,7 +1329,7 @@ void Precompiler::AddField(const Field& field) {
fields_to_retain_.Insert(&Field::ZoneHandle(Z, field.ptr()));
if (field.is_static()) {
auto field_table = field.is_shared() ? IG->shared_field_table()
auto field_table = field.is_shared() ? IG->shared_initial_field_table()
: IG->initial_field_table();
const Object& value = Object::Handle(Z, field_table->At(field.field_id()));
// Should not be in the middle of initialization while precompiling.
+6
View File
@@ -920,6 +920,12 @@ ErrorPtr Dart::InitializeIsolateGroup(Thread* T,
Object::VerifyBuiltinVtables();
auto IG = T->isolate_group();
{
SafepointReadRwLocker reader(T, IG->program_lock());
IG->set_shared_field_table(T, IG->shared_initial_field_table()->Clone(
/*for_isolate=*/nullptr,
/*for_isolate_group=*/IG));
}
DEBUG_ONLY(IG->heap()->Verify("InitializeIsolate", kForbidMarked));
#if !defined(DART_PRECOMPILED_RUNTIME)
+26 -16
View File
@@ -55,7 +55,6 @@ intptr_t FieldTable::FieldOffsetFor(intptr_t field_id) {
bool FieldTable::Register(const Field& field, intptr_t expected_field_id) {
DEBUG_ASSERT(
IsolateGroup::Current()->program_lock()->IsCurrentThreadWriter());
ASSERT(is_shared_ == field.is_shared());
ASSERT(is_ready_to_use_);
if (free_head_ < 0) {
@@ -119,28 +118,39 @@ void FieldTable::Grow(intptr_t new_capacity) {
// Ensure that new_table_ is populated before it is published
// via store to table_.
reinterpret_cast<AcqRelAtomic<ObjectPtr*>*>(&table_)->store(new_table);
if (isolate_ != nullptr && isolate_->mutator_thread() != nullptr) {
if (is_shared_) {
isolate_->mutator_thread()->shared_field_table_values_ = table_;
} else {
isolate_->mutator_thread()->field_table_values_ = table_;
}
if (isolate_group_ != nullptr) {
isolate_group_->ForEachIsolate(
[&](Isolate* isolate) {
if (isolate->mutator_thread() != nullptr) {
isolate->mutator_thread()->shared_field_table_values_ = table_;
}
},
/*at_safepoint=*/false);
} else if (isolate_ != nullptr && isolate_->mutator_thread() != nullptr) {
isolate_->mutator_thread()->field_table_values_ = table_;
}
}
FieldTable* FieldTable::Clone(Isolate* for_isolate) {
FieldTable* FieldTable::Clone(Isolate* for_isolate,
IsolateGroup* for_isolate_group) {
DEBUG_ASSERT(
IsolateGroup::Current()->program_lock()->IsCurrentThreadReader());
FieldTable* clone = new FieldTable(for_isolate);
auto new_table =
static_cast<ObjectPtr*>(malloc(capacity_ * sizeof(ObjectPtr))); // NOLINT
memmove(new_table, table_, capacity_ * sizeof(ObjectPtr));
FieldTable* clone = new FieldTable(for_isolate, for_isolate_group);
ASSERT(clone->table_ == nullptr);
clone->table_ = new_table;
clone->capacity_ = capacity_;
clone->top_ = top_;
clone->free_head_ = free_head_;
if (table_ == nullptr) {
ASSERT(capacity_ == 0);
ASSERT(top_ == 0);
ASSERT(free_head_ == -1);
} else {
auto new_table = static_cast<ObjectPtr*>(
malloc(capacity_ * sizeof(ObjectPtr))); // NOLINT
memmove(new_table, table_, capacity_ * sizeof(ObjectPtr));
clone->table_ = new_table;
clone->capacity_ = capacity_;
clone->top_ = top_;
clone->free_head_ = free_head_;
}
return clone;
}
+6 -8
View File
@@ -22,15 +22,15 @@ class FieldInvalidator;
class FieldTable {
public:
explicit FieldTable(Isolate* isolate, bool is_shared = false)
explicit FieldTable(Isolate* isolate, IsolateGroup* isolate_group = nullptr)
: top_(0),
capacity_(0),
free_head_(-1),
table_(nullptr),
old_tables_(new MallocGrowableArray<ObjectPtr*>()),
isolate_(isolate),
is_ready_to_use_(isolate == nullptr),
is_shared_(is_shared) {}
isolate_group_(isolate_group),
is_ready_to_use_(isolate == nullptr) {}
~FieldTable();
@@ -88,7 +88,8 @@ class FieldTable {
}
}
FieldTable* Clone(Isolate* for_isolate);
FieldTable* Clone(Isolate* for_isolate,
IsolateGroup* for_isolate_group = nullptr);
void VisitObjectPointers(ObjectPointerVisitor* visitor);
@@ -114,15 +115,12 @@ class FieldTable {
// Growing the field table will keep the cached field table on the isolate's
// mutator thread up-to-date.
Isolate* isolate_;
IsolateGroup* isolate_group_;
// Whether this field table is ready to use by e.g. registering new static
// fields.
bool is_ready_to_use_ = false;
// Is this the shared field table? Need to know what is the isolate's property
// that have to be updated.
bool is_shared_ = false;
DISALLOW_COPY_AND_ASSIGN(FieldTable);
};
+27 -10
View File
@@ -351,7 +351,9 @@ IsolateGroup::IsolateGroup(std::shared_ptr<IsolateGroupSource> source,
heap_(nullptr),
saved_unlinked_calls_(Array::null()),
initial_field_table_(new FieldTable(/*isolate=*/nullptr)),
shared_field_table_(new FieldTable(/*isolate=*/nullptr, /*shared=*/true)),
shared_initial_field_table_(new FieldTable(/*isolate=*/nullptr,
/*isolate_group=*/nullptr)),
shared_field_table_(new FieldTable(/*isolate=*/nullptr, this)),
#if !defined(DART_PRECOMPILED_RUNTIME)
background_compiler_(new BackgroundCompiler(this)),
#endif
@@ -784,21 +786,35 @@ void IsolateGroup::ValidateClassTable() {
}
#endif // DEBUG
void IsolateGroup::RegisterSharedStaticField(const Field& field,
const Object& initial_value) {
const bool need_to_grow_backing_store =
shared_initial_field_table()->Register(field);
const intptr_t field_id = field.field_id();
shared_initial_field_table()->SetAt(field_id, initial_value.ptr());
if (need_to_grow_backing_store) {
// We have to stop other isolates from accessing shared isolate group
// field state, since we'll have to grow the backing store.
GcSafepointOperationScope scope(Thread::Current());
const bool need_to_grow_other_backing_store =
shared_field_table()->Register(field, field_id);
ASSERT(need_to_grow_other_backing_store);
} else {
const bool need_to_grow_other_backing_store =
shared_field_table()->Register(field, field_id);
ASSERT(!need_to_grow_other_backing_store);
}
shared_field_table()->SetAt(field_id, initial_value.ptr());
}
void IsolateGroup::RegisterStaticField(const Field& field,
const Object& initial_value) {
ASSERT(program_lock()->IsCurrentThreadWriter());
ASSERT(field.is_static());
if (field.is_shared()) {
GcSafepointOperationScope scope(Thread::Current());
if (shared_field_table()->Register(field)) {
for (auto isolate : isolates_) {
isolate->mutator_thread()->shared_field_table_values_ =
shared_field_table()->table();
}
}
const intptr_t field_id = field.field_id();
shared_field_table()->SetAt(field_id, initial_value.ptr());
RegisterSharedStaticField(field, initial_value);
return;
}
const bool need_to_grow_backing_store =
@@ -2915,6 +2931,7 @@ void IsolateGroup::VisitSharedPointers(ObjectPointerVisitor* visitor) {
}
visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&saved_unlinked_calls_));
initial_field_table()->VisitObjectPointers(visitor);
shared_initial_field_table()->VisitObjectPointers(visitor);
shared_field_table()->VisitObjectPointers(visitor);
// Visit the boxed_field_list_.
+16 -2
View File
@@ -747,17 +747,30 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
initial_field_table_ = field_table;
}
FieldTable* shared_initial_field_table() const {
return shared_initial_field_table_.get();
}
std::shared_ptr<FieldTable> shared_initial_field_table_shareable() {
return shared_initial_field_table_;
}
void set_shared_initial_field_table(std::shared_ptr<FieldTable> field_table) {
shared_initial_field_table_ = field_table;
}
FieldTable* shared_field_table() const { return shared_field_table_.get(); }
std::shared_ptr<FieldTable> shared_field_table_shareable() {
return shared_field_table_;
}
void set_shared_field_table(std::shared_ptr<FieldTable> field_table) {
shared_field_table_ = field_table;
void set_shared_field_table(Thread* T, FieldTable* shared_field_table) {
shared_field_table_.reset(shared_field_table);
T->shared_field_table_values_ = shared_field_table->table();
}
MutatorThreadPool* thread_pool() { return thread_pool_.get(); }
void RegisterClass(const Class& cls);
void RegisterSharedStaticField(const Field& field,
const Object& initial_value);
void RegisterStaticField(const Field& field, const Object& initial_value);
void FreeStaticField(const Field& field);
@@ -872,6 +885,7 @@ class IsolateGroup : public IntrusiveDListEntry<IsolateGroup> {
intptr_t dispatch_table_snapshot_size_ = 0;
ArrayPtr saved_unlinked_calls_;
std::shared_ptr<FieldTable> initial_field_table_;
std::shared_ptr<FieldTable> shared_initial_field_table_;
std::shared_ptr<FieldTable> shared_field_table_;
uint32_t isolate_group_flags_ = 0;