Skip to content

Commit 14ea27e

Browse files
mkustermanncommit-bot@chromium.org
authored andcommitted
[vm/concurrency] Make thread_registry not depend on [Isolate], move mutator thread from thread registry to isolate
The thread registry is creating [Thread] objects when threads enter an isolate (as mutator or helper). Once threads exit an isolate, the [Thread] structure is returned and the thread registry will put it into a cache for later re-use. The mutator [Thread] object is an exception: Exiting and entering the isolate as mutator will always use the same cached [Thread] object. We want to eventually use one thread registry for an entire isolate group. There will therefore be multiple mutator threads per thread registry. We therefore move the cached mutator thread from the thread registry to the [Isolate] object. Issue #36097 Change-Id: Id27dff886d79ca76f6e05320151aeb72c8ba5140 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/108720 Commit-Queue: Martin Kustermann <[email protected]> Reviewed-by: Ryan Macnak <[email protected]>
1 parent 97587b5 commit 14ea27e

File tree

7 files changed

+122
-116
lines changed

7 files changed

+122
-116
lines changed

runtime/vm/base_isolate.h

+18-2
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,29 @@ class BaseIsolate {
3131
#endif
3232

3333
protected:
34-
BaseIsolate() : scheduled_mutator_thread_(NULL) {}
34+
BaseIsolate() {}
3535

3636
~BaseIsolate() {
3737
// Do not delete stack resources: top_resource_ and current_zone_.
3838
}
3939

40-
Thread* scheduled_mutator_thread_;
40+
Thread* scheduled_mutator_thread_ = nullptr;
41+
42+
// TODO(asiva): Currently we treat a mutator thread as a special thread
43+
// and always schedule execution of Dart code on the same mutator thread
44+
// object. The ApiLocalScope has been made thread specific but we still
45+
// have scenarios where we do a temporary exit of an Isolate with live
46+
// zones/handles in the API scope :
47+
// - Dart_RunLoop()
48+
// - IsolateSaver in Dart_NewNativePort
49+
// Similarly, tracking async_stack_trace requires that we always reschedule
50+
// on the same thread.
51+
// We probably need a mechanism to return to the specific thread only
52+
// for these specific cases. We should also determine if the embedder
53+
// should allow exiting an isolate with live state in zones/handles in
54+
// which case a new API for returning to the specific thread needs to be
55+
// added.
56+
Thread* mutator_thread_ = nullptr;
4157

4258
private:
4359
DISALLOW_COPY_AND_ASSIGN(BaseIsolate);

runtime/vm/compiler/runtime_offsets_extracted.h

+42-42
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,13 @@ static constexpr dart::compiler::target::word ICData_owner_offset = 20;
138138
static constexpr dart::compiler::target::word ICData_state_bits_offset = 28;
139139
static constexpr dart::compiler::target::word
140140
ICData_receivers_static_type_offset = 16;
141-
static constexpr dart::compiler::target::word Isolate_class_table_offset = 32;
142-
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 16;
143-
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 20;
144-
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 24;
145-
static constexpr dart::compiler::target::word Isolate_object_store_offset = 28;
146-
static constexpr dart::compiler::target::word Isolate_single_step_offset = 52;
147-
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 12;
141+
static constexpr dart::compiler::target::word Isolate_class_table_offset = 36;
142+
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
143+
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
144+
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
145+
static constexpr dart::compiler::target::word Isolate_object_store_offset = 32;
146+
static constexpr dart::compiler::target::word Isolate_single_step_offset = 56;
147+
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
148148
static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16;
149149
static constexpr dart::compiler::target::word
150150
LinkedHashMap_deleted_keys_offset = 24;
@@ -491,13 +491,13 @@ static constexpr dart::compiler::target::word ICData_owner_offset = 40;
491491
static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
492492
static constexpr dart::compiler::target::word
493493
ICData_receivers_static_type_offset = 32;
494-
static constexpr dart::compiler::target::word Isolate_class_table_offset = 64;
495-
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 32;
496-
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 40;
497-
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 48;
498-
static constexpr dart::compiler::target::word Isolate_object_store_offset = 56;
499-
static constexpr dart::compiler::target::word Isolate_single_step_offset = 104;
500-
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 24;
494+
static constexpr dart::compiler::target::word Isolate_class_table_offset = 72;
495+
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
496+
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
497+
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
498+
static constexpr dart::compiler::target::word Isolate_object_store_offset = 64;
499+
static constexpr dart::compiler::target::word Isolate_single_step_offset = 112;
500+
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
501501
static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32;
502502
static constexpr dart::compiler::target::word
503503
LinkedHashMap_deleted_keys_offset = 48;
@@ -845,13 +845,13 @@ static constexpr dart::compiler::target::word ICData_owner_offset = 20;
845845
static constexpr dart::compiler::target::word ICData_state_bits_offset = 28;
846846
static constexpr dart::compiler::target::word
847847
ICData_receivers_static_type_offset = 16;
848-
static constexpr dart::compiler::target::word Isolate_class_table_offset = 32;
849-
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 16;
850-
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 20;
851-
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 24;
852-
static constexpr dart::compiler::target::word Isolate_object_store_offset = 28;
853-
static constexpr dart::compiler::target::word Isolate_single_step_offset = 52;
854-
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 12;
848+
static constexpr dart::compiler::target::word Isolate_class_table_offset = 36;
849+
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
850+
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
851+
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
852+
static constexpr dart::compiler::target::word Isolate_object_store_offset = 32;
853+
static constexpr dart::compiler::target::word Isolate_single_step_offset = 56;
854+
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
855855
static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16;
856856
static constexpr dart::compiler::target::word
857857
LinkedHashMap_deleted_keys_offset = 24;
@@ -1194,13 +1194,13 @@ static constexpr dart::compiler::target::word ICData_owner_offset = 40;
11941194
static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
11951195
static constexpr dart::compiler::target::word
11961196
ICData_receivers_static_type_offset = 32;
1197-
static constexpr dart::compiler::target::word Isolate_class_table_offset = 64;
1198-
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 32;
1199-
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 40;
1200-
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 48;
1201-
static constexpr dart::compiler::target::word Isolate_object_store_offset = 56;
1202-
static constexpr dart::compiler::target::word Isolate_single_step_offset = 104;
1203-
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 24;
1197+
static constexpr dart::compiler::target::word Isolate_class_table_offset = 72;
1198+
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
1199+
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
1200+
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
1201+
static constexpr dart::compiler::target::word Isolate_object_store_offset = 64;
1202+
static constexpr dart::compiler::target::word Isolate_single_step_offset = 112;
1203+
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
12041204
static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32;
12051205
static constexpr dart::compiler::target::word
12061206
LinkedHashMap_deleted_keys_offset = 48;
@@ -1551,13 +1551,13 @@ static constexpr dart::compiler::target::word ICData_owner_offset = 40;
15511551
static constexpr dart::compiler::target::word ICData_state_bits_offset = 52;
15521552
static constexpr dart::compiler::target::word
15531553
ICData_receivers_static_type_offset = 32;
1554-
static constexpr dart::compiler::target::word Isolate_class_table_offset = 64;
1555-
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 32;
1556-
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 40;
1557-
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 48;
1558-
static constexpr dart::compiler::target::word Isolate_object_store_offset = 56;
1559-
static constexpr dart::compiler::target::word Isolate_single_step_offset = 104;
1560-
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 24;
1554+
static constexpr dart::compiler::target::word Isolate_class_table_offset = 72;
1555+
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 40;
1556+
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 48;
1557+
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 56;
1558+
static constexpr dart::compiler::target::word Isolate_object_store_offset = 64;
1559+
static constexpr dart::compiler::target::word Isolate_single_step_offset = 112;
1560+
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 32;
15611561
static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 32;
15621562
static constexpr dart::compiler::target::word
15631563
LinkedHashMap_deleted_keys_offset = 48;
@@ -1835,13 +1835,13 @@ static constexpr dart::compiler::target::word ICData_owner_offset = 20;
18351835
static constexpr dart::compiler::target::word ICData_state_bits_offset = 28;
18361836
static constexpr dart::compiler::target::word
18371837
ICData_receivers_static_type_offset = 16;
1838-
static constexpr dart::compiler::target::word Isolate_class_table_offset = 32;
1839-
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 16;
1840-
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 20;
1841-
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 24;
1842-
static constexpr dart::compiler::target::word Isolate_object_store_offset = 28;
1843-
static constexpr dart::compiler::target::word Isolate_single_step_offset = 52;
1844-
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 12;
1838+
static constexpr dart::compiler::target::word Isolate_class_table_offset = 36;
1839+
static constexpr dart::compiler::target::word Isolate_current_tag_offset = 20;
1840+
static constexpr dart::compiler::target::word Isolate_default_tag_offset = 24;
1841+
static constexpr dart::compiler::target::word Isolate_ic_miss_code_offset = 28;
1842+
static constexpr dart::compiler::target::word Isolate_object_store_offset = 32;
1843+
static constexpr dart::compiler::target::word Isolate_single_step_offset = 56;
1844+
static constexpr dart::compiler::target::word Isolate_user_tag_offset = 16;
18451845
static constexpr dart::compiler::target::word LinkedHashMap_data_offset = 16;
18461846
static constexpr dart::compiler::target::word
18471847
LinkedHashMap_deleted_keys_offset = 24;

runtime/vm/isolate.cc

+44-8
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,13 @@ Isolate::~Isolate() {
10211021
nullptr); // No deopt in progress when isolate deleted.
10221022
ASSERT(spawn_count_ == 0);
10231023
delete safepoint_handler_;
1024+
1025+
// We have cached the mutator thread, delete it.
1026+
ASSERT(scheduled_mutator_thread_ == nullptr);
1027+
mutator_thread_->isolate_ = nullptr;
1028+
delete mutator_thread_;
1029+
mutator_thread_ = nullptr;
1030+
10241031
delete thread_registry_;
10251032

10261033
if (obfuscation_map_ != nullptr) {
@@ -1177,7 +1184,7 @@ void Isolate::RetainKernelBlob(const ExternalTypedData& kernel_blob) {
11771184

11781185
Thread* Isolate::mutator_thread() const {
11791186
ASSERT(thread_registry() != nullptr);
1180-
return thread_registry()->mutator_thread();
1187+
return mutator_thread_;
11811188
}
11821189

11831190
RawObject* Isolate::CallTagHandler(Dart_LibraryTag tag,
@@ -2051,6 +2058,12 @@ void Isolate::VisitStackPointers(ObjectPointerVisitor* visitor,
20512058
ValidationPolicy validate_frames) {
20522059
// Visit objects in all threads (e.g., Dart stack, handles in zones).
20532060
thread_registry()->VisitObjectPointers(visitor, validate_frames);
2061+
2062+
// Visit mutator thread, even if the isolate isn't entered/scheduled (there
2063+
// might be live API handles to visit).
2064+
if (mutator_thread_ != nullptr) {
2065+
mutator_thread_->VisitObjectPointers(visitor, validate_frames);
2066+
}
20542067
}
20552068

20562069
void Isolate::VisitWeakPersistentHandles(HandleVisitor* visitor) {
@@ -2887,8 +2900,25 @@ Thread* Isolate::ScheduleThread(bool is_mutator, bool bypass_safepoint) {
28872900
ml.Wait();
28882901
}
28892902

2890-
// Now get a free Thread structure.
2891-
thread = thread_registry()->GetFreeThreadLocked(this, is_mutator);
2903+
// NOTE: We cannot just use `Dart::vm_isolate() == this` here, since during
2904+
// VM startup it might not have been set at this point.
2905+
const bool is_vm_isolate =
2906+
Dart::vm_isolate() == nullptr || Dart::vm_isolate() == this;
2907+
2908+
if (is_mutator) {
2909+
if (mutator_thread_ == nullptr) {
2910+
// Allocate a new [Thread] structure for the mutator thread.
2911+
thread = thread_registry()->GetFreeThreadLocked(is_vm_isolate);
2912+
mutator_thread_ = thread;
2913+
} else {
2914+
// Reuse the existing cached [Thread] structure for the mutator thread.,
2915+
// see comment in 'base_isolate.h'.
2916+
thread_registry()->AddToActiveListLocked(mutator_thread_);
2917+
thread = mutator_thread_;
2918+
}
2919+
} else {
2920+
thread = thread_registry()->GetFreeThreadLocked(is_vm_isolate);
2921+
}
28922922
ASSERT(thread != nullptr);
28932923

28942924
thread->ResetHighWatermark();
@@ -2945,9 +2975,7 @@ void Isolate::UnscheduleThread(Thread* thread,
29452975
os_thread->DisableThreadInterrupts();
29462976
os_thread->set_thread(nullptr);
29472977
OSThread::SetCurrent(os_thread);
2948-
if (is_mutator) {
2949-
scheduled_mutator_thread_ = nullptr;
2950-
}
2978+
29512979
// Even if we unschedule the mutator thread, e.g. via calling
29522980
// `Dart_ExitIsolate()` inside a native, we might still have one or more Dart
29532981
// stacks active, which e.g. GC marker threads want to visit. So we don't
@@ -2967,8 +2995,16 @@ void Isolate::UnscheduleThread(Thread* thread,
29672995
thread->set_safepoint_state(Thread::SetAtSafepoint(true, 0));
29682996
thread->clear_pending_functions();
29692997
ASSERT(thread->no_safepoint_scope_depth() == 0);
2970-
// Return thread structure.
2971-
thread_registry()->ReturnThreadLocked(is_mutator, thread);
2998+
2999+
if (is_mutator) {
3000+
ASSERT(mutator_thread_ == thread);
3001+
ASSERT(mutator_thread_ == scheduled_mutator_thread_);
3002+
thread_registry()->RemoveFromActiveListLocked(thread);
3003+
scheduled_mutator_thread_ = nullptr;
3004+
} else {
3005+
// Return thread structure.
3006+
thread_registry()->ReturnThreadLocked(thread);
3007+
}
29723008
}
29733009

29743010
static const char* NewConstChar(const char* chars) {

runtime/vm/thread.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ Thread::~Thread() {
5656

5757
#define REUSABLE_HANDLE_INITIALIZERS(object) object##_handle_(NULL),
5858

59-
Thread::Thread(Isolate* isolate)
59+
Thread::Thread(bool is_vm_isolate)
6060
: ThreadState(false),
6161
stack_limit_(0),
6262
stack_overflow_flags_(0),
@@ -133,7 +133,7 @@ Thread::Thread(Isolate* isolate)
133133

134134
// We cannot initialize the VM constants here for the vm isolate thread
135135
// due to boot strapping issues.
136-
if ((Dart::vm_isolate() != NULL) && (isolate != Dart::vm_isolate())) {
136+
if (!is_vm_isolate) {
137137
InitVMConstants();
138138
}
139139
}

runtime/vm/thread.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,7 @@ class Thread : public ThreadState {
938938

939939
Thread* next_; // Used to chain the thread structures in an isolate.
940940

941-
explicit Thread(Isolate* isolate);
941+
explicit Thread(bool is_vm_isolate);
942942

943943
void StoreBufferRelease(
944944
StoreBuffer::ThresholdPolicy policy = StoreBuffer::kCheckThreshold);

runtime/vm/thread_registry.cc

+11-35
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
#include "vm/thread_registry.h"
66

7-
#include "vm/isolate.h"
87
#include "vm/json_stream.h"
98
#include "vm/lockers.h"
109

@@ -17,12 +16,6 @@ ThreadRegistry::~ThreadRegistry() {
1716
// At this point the active list should be empty.
1817
ASSERT(active_list_ == NULL);
1918

20-
// The [mutator_thread_] is kept alive until the destruction of the isolate.
21-
mutator_thread_->isolate_ = nullptr;
22-
23-
// We have cached the mutator thread, delete it.
24-
delete mutator_thread_;
25-
mutator_thread_ = NULL;
2619
// Now delete all the threads in the free list.
2720
while (free_list_ != NULL) {
2821
Thread* thread = free_list_;
@@ -32,51 +25,34 @@ ThreadRegistry::~ThreadRegistry() {
3225
}
3326
}
3427

35-
// Gets a free Thread structure, we special case the mutator thread
36-
// by reusing the cached structure, see comment in 'thread_registry.h'.
37-
Thread* ThreadRegistry::GetFreeThreadLocked(Isolate* isolate, bool is_mutator) {
28+
Thread* ThreadRegistry::GetFreeThreadLocked(bool is_vm_isolate) {
3829
ASSERT(threads_lock()->IsOwnedByCurrentThread());
39-
Thread* thread;
40-
if (is_mutator) {
41-
if (mutator_thread_ == NULL) {
42-
mutator_thread_ = GetFromFreelistLocked(isolate);
43-
}
44-
thread = mutator_thread_;
45-
} else {
46-
thread = GetFromFreelistLocked(isolate);
47-
ASSERT(thread->api_top_scope() == NULL);
48-
}
30+
Thread* thread = GetFromFreelistLocked(is_vm_isolate);
31+
ASSERT(thread->api_top_scope() == NULL);
4932
// Now add this Thread to the active list for the isolate.
5033
AddToActiveListLocked(thread);
5134
return thread;
5235
}
5336

54-
void ThreadRegistry::ReturnThreadLocked(bool is_mutator, Thread* thread) {
37+
void ThreadRegistry::ReturnThreadLocked(Thread* thread) {
5538
ASSERT(threads_lock()->IsOwnedByCurrentThread());
5639
// Remove thread from the active list for the isolate.
5740
RemoveFromActiveListLocked(thread);
58-
if (!is_mutator) {
59-
ReturnToFreelistLocked(thread);
60-
}
41+
ReturnToFreelistLocked(thread);
6142
}
6243

6344
void ThreadRegistry::VisitObjectPointers(ObjectPointerVisitor* visitor,
6445
ValidationPolicy validate_frames) {
6546
MonitorLocker ml(threads_lock());
66-
bool mutator_thread_visited = false;
6747
Thread* thread = active_list_;
6848
while (thread != NULL) {
69-
thread->VisitObjectPointers(visitor, validate_frames);
70-
if (mutator_thread_ == thread) {
71-
mutator_thread_visited = true;
49+
// The mutator thread is visited by the isolate itself (see
50+
// [Isolate::VisitStackPointers]).
51+
if (!thread->IsMutatorThread()) {
52+
thread->VisitObjectPointers(visitor, validate_frames);
7253
}
7354
thread = thread->next_;
7455
}
75-
// Visit mutator thread even if it is not in the active list because of
76-
// api handles.
77-
if (!mutator_thread_visited && (mutator_thread_ != NULL)) {
78-
mutator_thread_->VisitObjectPointers(visitor, validate_frames);
79-
}
8056
}
8157

8258
void ThreadRegistry::ReleaseStoreBuffers() {
@@ -174,12 +150,12 @@ void ThreadRegistry::RemoveFromActiveListLocked(Thread* thread) {
174150
}
175151
}
176152

177-
Thread* ThreadRegistry::GetFromFreelistLocked(Isolate* isolate) {
153+
Thread* ThreadRegistry::GetFromFreelistLocked(bool is_vm_isolate) {
178154
ASSERT(threads_lock()->IsOwnedByCurrentThread());
179155
Thread* thread = NULL;
180156
// Get thread structure from free list or create a new one.
181157
if (free_list_ == NULL) {
182-
thread = new Thread(isolate);
158+
thread = new Thread(is_vm_isolate);
183159
} else {
184160
thread = free_list_;
185161
free_list_ = thread->next_;

0 commit comments

Comments
 (0)