Skip to content

Commit dae3084

Browse files
mkustermanncommit-bot@chromium.org
authored andcommitted
[vm/concurrency] Share [Heap] and [SharedClassTable] between all isolates within one isolate group
This CL: * Moves [Heap]/[SharedClassTable] from [Isolate] to [IsolateGroup], which will make all isolates in the group use the same heap. The GC will use the shared class table for object size information. * Adds support for entering/leaving an isolate group as a helper thread (e.g. via [Thread::EnterIsolateGroupAsHelper]). The current active isolate group can be accessed via TLS `IsolateGroup::Current()` or `Thread::isolate_group_`. When entering as a helper thread there will be no current isolate. * Changes the GC to use the above mechanism and ensures GC works without a currently active isolate. The GC will use information purely available via [IsolateGroup]. The GC will iterate all isolates within an isolate group e.g. for scanning roots. * Makes spawning of new isolates start in their own isolate group. Once the isolate is fully functional it's heap will be merged into the original isolate group * Moves ApiState, containing persistent and weak persistent handles, from [Isolate] to [IsolateGroup], plus adds appropriate locking. Issue dart-lang/sdk#36097 Change-Id: Ia8e1d8aa78750e8400864200f4825395a182c004 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/126646 Commit-Queue: Martin Kustermann <kustermann@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
1 parent f7a9017 commit dae3084

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+1810
-1134
lines changed

runtime/bin/main.cc

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -267,14 +267,6 @@ static bool OnIsolateInitialize(void** child_callback_data, char** error) {
267267
if (Dart_IsError(result)) goto failed;
268268
}
269269

270-
if (Options::gen_snapshot_kind() == kAppJIT) {
271-
// If we sort, we must do it for all isolates, not just the main isolate,
272-
// otherwise isolates related by spawnFunction will disagree on CIDs and
273-
// cannot correctly send each other messages.
274-
result = Dart_SortClasses();
275-
if (Dart_IsError(result)) goto failed;
276-
}
277-
278270
// Make the isolate runnable so that it is ready to handle messages.
279271
Dart_ExitScope();
280272
Dart_ExitIsolate();

runtime/bin/process_android.cc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1027,9 +1027,6 @@ intptr_t Process::SetSignalHandler(intptr_t signal) {
10271027
}
10281028

10291029
void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) {
1030-
// Either the port is illegal or there is no current isolate, but not both.
1031-
ASSERT((port != ILLEGAL_PORT) || (Dart_CurrentIsolate() == NULL));
1032-
ASSERT((port == ILLEGAL_PORT) || (Dart_CurrentIsolate() != NULL));
10331030
ThreadSignalBlocker blocker(kSignalsCount, kSignals);
10341031
MutexLocker lock(signal_mutex);
10351032
SignalInfo* handler = signal_handlers;

runtime/bin/process_linux.cc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,9 +1023,6 @@ intptr_t Process::SetSignalHandler(intptr_t signal) {
10231023
}
10241024

10251025
void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) {
1026-
// Either the port is illegal or there is no current isolate, but not both.
1027-
ASSERT((port != ILLEGAL_PORT) || (Dart_CurrentIsolate() == NULL));
1028-
ASSERT((port == ILLEGAL_PORT) || (Dart_CurrentIsolate() != NULL));
10291026
ThreadSignalBlocker blocker(kSignalsCount, kSignals);
10301027
MutexLocker lock(signal_mutex);
10311028
SignalInfo* handler = signal_handlers;

runtime/bin/process_macos.cc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,9 +1055,6 @@ intptr_t Process::SetSignalHandler(intptr_t signal) {
10551055
}
10561056

10571057
void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) {
1058-
// Either the port is illegal or there is no current isolate, but not both.
1059-
ASSERT((port != ILLEGAL_PORT) || (Dart_CurrentIsolate() == NULL));
1060-
ASSERT((port == ILLEGAL_PORT) || (Dart_CurrentIsolate() != NULL));
10611058
signal = SignalMap(signal);
10621059
if (signal == -1) {
10631060
return;

runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,10 @@ void allEventsHaveIsolateNumber(List events) {
110110
}
111111
Map arguments = event['args'];
112112
expect(arguments, new isInstanceOf<Map>());
113-
expect(arguments['isolateId'], new isInstanceOf<String>());
113+
expect(arguments['isolateGroupId'], new isInstanceOf<String>());
114+
if (event['cat'] != 'GC') {
115+
expect(arguments['isolateId'], new isInstanceOf<String>());
116+
}
114117
}
115118
}
116119

runtime/vm/class_finalizer.cc

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
#include <memory>
6+
#include <utility>
7+
58
#include "vm/class_finalizer.h"
69

710
#include "vm/compiler/jit/compiler.h"
@@ -1389,7 +1392,9 @@ void ClassFinalizer::SortClasses() {
13891392

13901393
ClassTable* table = I->class_table();
13911394
intptr_t num_cids = table->NumCids();
1392-
intptr_t* old_to_new_cid = new intptr_t[num_cids];
1395+
1396+
std::unique_ptr<intptr_t[]> old_to_new_cid(new intptr_t[num_cids]);
1397+
13931398
for (intptr_t cid = 0; cid < kNumPredefinedCids; cid++) {
13941399
old_to_new_cid[cid] = cid; // The predefined classes cannot change cids.
13951400
}
@@ -1450,9 +1455,7 @@ void ClassFinalizer::SortClasses() {
14501455
}
14511456
}
14521457
ASSERT(next_new_cid == num_cids);
1453-
1454-
RemapClassIds(old_to_new_cid);
1455-
delete[] old_to_new_cid;
1458+
RemapClassIds(std::move(old_to_new_cid));
14561459
RehashTypes(); // Types use cid's as part of their hashes.
14571460
I->RehashConstants(); // Const objects use cid's as part of their hashes.
14581461
}
@@ -1501,34 +1504,52 @@ class CidRewriteVisitor : public ObjectVisitor {
15011504
intptr_t* old_to_new_cids_;
15021505
};
15031506

1504-
void ClassFinalizer::RemapClassIds(intptr_t* old_to_new_cid) {
1507+
void ClassFinalizer::RemapClassIds(std::unique_ptr<intptr_t[]> old_to_new_cid) {
15051508
Thread* T = Thread::Current();
1506-
Isolate* I = T->isolate();
1509+
IsolateGroup* IG = T->isolate_group();
15071510

15081511
// Code, ICData, allocation stubs have now-invalid cids.
15091512
ClearAllCode();
15101513

15111514
{
1515+
// The [HeapIterationScope] also safepoints all threads.
15121516
HeapIterationScope his(T);
1513-
I->set_remapping_cids(true);
15141517

1515-
// Update the class table. Do it before rewriting cids in headers, as the
1516-
// heap walkers load an object's size *after* calling the visitor.
1517-
I->class_table()->Remap(old_to_new_cid);
1518+
IG->class_table()->Remap(old_to_new_cid.get());
1519+
IG->ForEachIsolate(
1520+
[&](Isolate* I) {
1521+
I->set_remapping_cids(true);
1522+
1523+
// Update the class table. Do it before rewriting cids in headers, as
1524+
// the heap walkers load an object's size *after* calling the visitor.
1525+
I->class_table()->Remap(old_to_new_cid.get());
1526+
},
1527+
/*is_at_safepoint=*/true);
15181528

15191529
// Rewrite cids in headers and cids in Classes, Fields, Types and
15201530
// TypeParameters.
15211531
{
1522-
CidRewriteVisitor visitor(old_to_new_cid);
1523-
I->heap()->VisitObjects(&visitor);
1532+
CidRewriteVisitor visitor(old_to_new_cid.get());
1533+
IG->heap()->VisitObjects(&visitor);
15241534
}
1525-
I->set_remapping_cids(false);
1535+
1536+
IG->ForEachIsolate(
1537+
[&](Isolate* I) {
1538+
I->set_remapping_cids(false);
1539+
#if defined(DEBUG)
1540+
I->class_table()->Validate();
1541+
#endif
1542+
},
1543+
/*is_at_safepoint=*/true);
15261544
}
15271545

15281546
#if defined(DEBUG)
1529-
I->class_table()->Validate();
1530-
I->heap()->Verify();
1547+
IG->heap()->Verify();
15311548
#endif
1549+
1550+
// Ensure any newly spawned isolate will apply this permutation map right
1551+
// after kernel loading.
1552+
IG->source()->cid_permutation_map = std::move(old_to_new_cid);
15321553
}
15331554

15341555
// Clears the cached canonicalized hash codes for all instances which directly

runtime/vm/class_finalizer.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#ifndef RUNTIME_VM_CLASS_FINALIZER_H_
66
#define RUNTIME_VM_CLASS_FINALIZER_H_
77

8+
#include <memory>
9+
810
#include "vm/allocation.h"
911
#include "vm/growable_array.h"
1012
#include "vm/object.h"
@@ -41,7 +43,7 @@ class ClassFinalizer : public AllStatic {
4143

4244
// Useful for sorting classes to make dispatch faster.
4345
static void SortClasses();
44-
static void RemapClassIds(intptr_t* old_to_new_cid);
46+
static void RemapClassIds(std::unique_ptr<intptr_t[]> old_to_new_cid);
4547
static void RehashTypes();
4648
static void ClearAllCode(bool including_nonchanging_cids = false);
4749

runtime/vm/class_table.cc

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ SharedClassTable::SharedClassTable()
3333
table_ = static_cast<intptr_t*>(calloc(capacity_, sizeof(intptr_t)));
3434
} else {
3535
// Duplicate the class table from the VM isolate.
36-
auto vm_shared_class_table = Dart::vm_isolate()->shared_class_table();
36+
auto vm_shared_class_table = Dart::vm_isolate()->group()->class_table();
3737
capacity_ = vm_shared_class_table->capacity_;
3838
// Note that [calloc] will zero-initialize the memory.
3939
table_ = static_cast<intptr_t*>(calloc(capacity_, sizeof(RawClass*)));
@@ -114,14 +114,6 @@ ClassTable::ClassTable(SharedClassTable* shared_class_table)
114114
}
115115
}
116116

117-
ClassTable::ClassTable(ClassTable* original,
118-
SharedClassTable* shared_class_table)
119-
: top_(original->top_),
120-
capacity_(original->top_),
121-
table_(original->table_),
122-
old_class_tables_(nullptr),
123-
shared_class_table_(shared_class_table) {}
124-
125117
ClassTable::~ClassTable() {
126118
if (old_class_tables_ != nullptr) {
127119
FreeOldTables();
@@ -308,26 +300,23 @@ void SharedClassTable::Unregister(intptr_t index) {
308300

309301
void ClassTable::Remap(intptr_t* old_to_new_cid) {
310302
ASSERT(Thread::Current()->IsAtSafepoint());
311-
shared_class_table_->Remap(old_to_new_cid);
312-
313303
const intptr_t num_cids = NumCids();
314-
auto cls_by_old_cid = new RawClass*[num_cids];
315-
memmove(cls_by_old_cid, table_, sizeof(RawClass*) * num_cids);
304+
std::unique_ptr<RawClass*[]> cls_by_old_cid(new RawClass*[num_cids]);
305+
memmove(cls_by_old_cid.get(), table_, sizeof(RawClass*) * num_cids);
316306
for (intptr_t i = 0; i < num_cids; i++) {
317307
table_[old_to_new_cid[i]] = cls_by_old_cid[i];
318308
}
319-
delete[] cls_by_old_cid;
320309
}
321310

322311
void SharedClassTable::Remap(intptr_t* old_to_new_cid) {
323312
ASSERT(Thread::Current()->IsAtSafepoint());
324313
const intptr_t num_cids = NumCids();
325-
std::unique_ptr<intptr_t[]> cls_by_old_cid(new intptr_t[num_cids]);
314+
std::unique_ptr<intptr_t[]> size_by_old_cid(new intptr_t[num_cids]);
326315
for (intptr_t i = 0; i < num_cids; i++) {
327-
cls_by_old_cid[i] = table_[i];
316+
size_by_old_cid[i] = table_[i];
328317
}
329318
for (intptr_t i = 0; i < num_cids; i++) {
330-
table_[old_to_new_cid[i]] = cls_by_old_cid[i];
319+
table_[old_to_new_cid[i]] = size_by_old_cid[i];
331320
}
332321

333322
#if defined(SUPPORT_UNBOXED_INSTANCE_FIELDS)
@@ -428,18 +417,20 @@ intptr_t SharedClassTable::ClassOffsetFor(intptr_t cid) {
428417
void ClassTable::AllocationProfilePrintJSON(JSONStream* stream, bool internal) {
429418
Isolate* isolate = Isolate::Current();
430419
ASSERT(isolate != NULL);
431-
Heap* heap = isolate->heap();
420+
auto isolate_group = isolate->group();
421+
Heap* heap = isolate_group->heap();
432422
ASSERT(heap != NULL);
433423
JSONObject obj(stream);
434424
obj.AddProperty("type", "AllocationProfile");
435-
if (isolate->last_allocationprofile_accumulator_reset_timestamp() != 0) {
425+
if (isolate_group->last_allocationprofile_accumulator_reset_timestamp() !=
426+
0) {
436427
obj.AddPropertyF(
437428
"dateLastAccumulatorReset", "%" Pd64 "",
438-
isolate->last_allocationprofile_accumulator_reset_timestamp());
429+
isolate_group->last_allocationprofile_accumulator_reset_timestamp());
439430
}
440-
if (isolate->last_allocationprofile_gc_timestamp() != 0) {
431+
if (isolate_group->last_allocationprofile_gc_timestamp() != 0) {
441432
obj.AddPropertyF("dateLastServiceGC", "%" Pd64 "",
442-
isolate->last_allocationprofile_gc_timestamp());
433+
isolate_group->last_allocationprofile_gc_timestamp());
443434
}
444435

445436
if (internal) {
@@ -458,7 +449,7 @@ void ClassTable::AllocationProfilePrintJSON(JSONStream* stream, bool internal) {
458449
{
459450
HeapIterationScope iter(thread);
460451
iter.IterateObjects(&visitor);
461-
isolate->VisitWeakPersistentHandles(&visitor);
452+
isolate->group()->VisitWeakPersistentHandles(&visitor);
462453
}
463454

464455
{

runtime/vm/class_table.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#ifndef RUNTIME_VM_CLASS_TABLE_H_
66
#define RUNTIME_VM_CLASS_TABLE_H_
77

8+
#include <memory>
9+
810
#include "platform/assert.h"
911
#include "platform/atomic.h"
1012
#include "platform/utils.h"
@@ -80,6 +82,7 @@ class SharedClassTable {
8082

8183
void SetSizeAt(intptr_t index, intptr_t size) {
8284
ASSERT(IsValidIndex(index));
85+
8386
// Ensure we never change size for a given cid from one non-zero size to
8487
// another non-zero size.
8588
RELEASE_ASSERT(table_[index] == 0 || table_[index] == size);
@@ -230,10 +233,6 @@ class SharedClassTable {
230233
class ClassTable {
231234
public:
232235
explicit ClassTable(SharedClassTable* shared_class_table_);
233-
234-
// Creates a shallow copy of the original class table for some read-only
235-
// access, without support for stats data.
236-
ClassTable(ClassTable* original, SharedClassTable* shared_class_table);
237236
~ClassTable();
238237

239238
SharedClassTable* shared_class_table() const { return shared_class_table_; }
@@ -357,6 +356,9 @@ class ClassTable {
357356
friend class MarkingWeakVisitor;
358357
friend class Scavenger;
359358
friend class ScavengerWeakVisitor;
359+
friend Isolate* CreateWithinExistingIsolateGroup(IsolateGroup* group,
360+
const char* name,
361+
char** error);
360362
static const int kInitialCapacity = SharedClassTable::kInitialCapacity;
361363
static const int kCapacityIncrement = SharedClassTable::kCapacityIncrement;
362364

runtime/vm/clustered_snapshot.cc

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ class ClassSerializationCluster : public SerializationCluster {
206206
UnboxedFieldBitmap CalculateTargetUnboxedFieldsBitmap(Serializer* s,
207207
intptr_t class_id) {
208208
const auto unboxed_fields_bitmap_host =
209-
s->isolate()->shared_class_table()->GetUnboxedFieldsMapAt(class_id);
209+
s->isolate()->group()->class_table()->GetUnboxedFieldsMapAt(class_id);
210210

211211
UnboxedFieldBitmap unboxed_fields_bitmap;
212212
if (unboxed_fields_bitmap_host.IsEmpty() ||
@@ -310,6 +310,7 @@ class ClassDeserializationCluster : public DeserializationCluster {
310310
}
311311
}
312312

313+
auto shared_class_table = d->isolate()->group()->class_table();
313314
for (intptr_t id = start_index_; id < stop_index_; id++) {
314315
RawClass* cls = reinterpret_cast<RawClass*>(d->Ref(id));
315316
Deserializer::InitializeHeader(cls, kClassCid, Class::InstanceSize());
@@ -347,8 +348,7 @@ class ClassDeserializationCluster : public DeserializationCluster {
347348

348349
if (FLAG_precompiled_mode) {
349350
const UnboxedFieldBitmap unboxed_fields_map(d->ReadUnsigned64());
350-
d->isolate()->shared_class_table()->SetUnboxedFieldsMapAt(
351-
class_id, unboxed_fields_map);
351+
shared_class_table->SetUnboxedFieldsMapAt(class_id, unboxed_fields_map);
352352
}
353353
}
354354
}
@@ -2802,7 +2802,7 @@ class InstanceSerializationCluster : public SerializationCluster {
28022802
const intptr_t next_field_offset = host_next_field_offset_in_words_
28032803
<< kWordSizeLog2;
28042804
const auto unboxed_fields_bitmap =
2805-
s->isolate()->shared_class_table()->GetUnboxedFieldsMapAt(cid_);
2805+
s->isolate()->group()->class_table()->GetUnboxedFieldsMapAt(cid_);
28062806
intptr_t offset = Instance::NextFieldOffset();
28072807
while (offset < next_field_offset) {
28082808
// Skips unboxed fields
@@ -2837,13 +2837,12 @@ class InstanceSerializationCluster : public SerializationCluster {
28372837
intptr_t next_field_offset = host_next_field_offset_in_words_
28382838
<< kWordSizeLog2;
28392839
const intptr_t count = objects_.length();
2840-
const auto shared_class_table = s->isolate()->shared_class_table();
2840+
const auto unboxed_fields_bitmap =
2841+
s->isolate()->group()->class_table()->GetUnboxedFieldsMapAt(cid_);
28412842
for (intptr_t i = 0; i < count; i++) {
28422843
RawInstance* instance = objects_[i];
28432844
AutoTraceObject(instance);
28442845
s->Write<bool>(instance->IsCanonical());
2845-
const auto unboxed_fields_bitmap =
2846-
shared_class_table->GetUnboxedFieldsMapAt(cid_);
28472846
intptr_t offset = Instance::NextFieldOffset();
28482847
while (offset < next_field_offset) {
28492848
if (unboxed_fields_bitmap.Get(offset / kWordSize)) {
@@ -2896,14 +2895,13 @@ class InstanceDeserializationCluster : public DeserializationCluster {
28962895
intptr_t instance_size =
28972896
Object::RoundedAllocationSize(instance_size_in_words_ * kWordSize);
28982897

2899-
const auto shared_class_table = d->isolate()->shared_class_table();
2898+
const auto unboxed_fields_bitmap =
2899+
d->isolate()->group()->class_table()->GetUnboxedFieldsMapAt(cid_);
29002900
for (intptr_t id = start_index_; id < stop_index_; id++) {
29012901
RawInstance* instance = reinterpret_cast<RawInstance*>(d->Ref(id));
29022902
bool is_canonical = d->Read<bool>();
29032903
Deserializer::InitializeHeader(instance, cid_, instance_size,
29042904
is_canonical);
2905-
const auto unboxed_fields_bitmap =
2906-
shared_class_table->GetUnboxedFieldsMapAt(cid_);
29072905
intptr_t offset = Instance::NextFieldOffset();
29082906
while (offset < next_field_offset) {
29092907
if (unboxed_fields_bitmap.Get(offset / kWordSize)) {

0 commit comments

Comments
 (0)