1// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include <utility>
6
7#include "vm/isolate.h"
8
9#include "include/dart_api.h"
10#include "include/dart_native_api.h"
11#include "platform/assert.h"
12#include "platform/atomic.h"
13#include "platform/text_buffer.h"
14#include "vm/canonical_tables.h"
15#include "vm/class_finalizer.h"
16#include "vm/code_observers.h"
17#include "vm/compiler/jit/compiler.h"
18#include "vm/dart_api_message.h"
19#include "vm/dart_api_state.h"
20#include "vm/dart_entry.h"
21#include "vm/debugger.h"
22#include "vm/deopt_instructions.h"
23#include "vm/dispatch_table.h"
24#include "vm/ffi_callback_metadata.h"
25#include "vm/flags.h"
26#include "vm/heap/heap.h"
27#include "vm/heap/pointer_block.h"
28#include "vm/heap/safepoint.h"
29#include "vm/heap/verifier.h"
30#include "vm/image_snapshot.h"
31#include "vm/isolate_reload.h"
32#include "vm/kernel_isolate.h"
33#include "vm/lockers.h"
34#include "vm/log.h"
35#include "vm/message_handler.h"
36#include "vm/message_snapshot.h"
37#include "vm/object.h"
38#include "vm/object_id_ring.h"
39#include "vm/object_store.h"
40#include "vm/os_thread.h"
41#include "vm/port.h"
42#include "vm/profiler.h"
43#include "vm/reusable_handles.h"
44#include "vm/reverse_pc_lookup_cache.h"
45#include "vm/service.h"
46#include "vm/service_event.h"
47#include "vm/service_isolate.h"
48#include "vm/simulator.h"
49#include "vm/stack_frame.h"
50#include "vm/stub_code.h"
51#include "vm/symbols.h"
52#include "vm/tags.h"
53#include "vm/thread.h"
54#include "vm/thread_interrupter.h"
55#include "vm/thread_registry.h"
56#include "vm/timeline.h"
57#include "vm/visitor.h"
58
59#if !defined(DART_PRECOMPILED_RUNTIME)
60#include "vm/compiler/assembler/assembler.h"
61#include "vm/compiler/stub_code_compiler.h"
62#endif
63
64namespace dart {
65
66DECLARE_FLAG(bool, print_metrics);
67DECLARE_FLAG(bool, trace_service);
68DECLARE_FLAG(bool, trace_shutdown);
69DECLARE_FLAG(bool, warn_on_pause_with_no_debugger);
70DECLARE_FLAG(int, old_gen_growth_time_ratio);
71
72// Reload flags.
73DECLARE_FLAG(int, reload_every);
74#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
75DECLARE_FLAG(bool, check_reloaded);
76DECLARE_FLAG(bool, reload_every_back_off);
77DECLARE_FLAG(bool, trace_reload);
78#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
79
80static void DeterministicModeHandler(bool value) {
81 if (value) {
82 FLAG_background_compilation = false; // Timing dependent.
83 FLAG_concurrent_mark = false; // Timing dependent.
84 FLAG_concurrent_sweep = false; // Timing dependent.
85 FLAG_scavenger_tasks = 0; // Timing dependent.
86 FLAG_old_gen_growth_time_ratio = 0; // Timing dependent.
87 FLAG_random_seed = 0x44617274; // "Dart"
88 }
89}
90
91DEFINE_FLAG_HANDLER(DeterministicModeHandler,
92 deterministic,
93 "Enable deterministic mode.");
94
95DEFINE_FLAG(bool,
96 disable_thread_pool_limit,
97 false,
98 "Disables the limit of the thread pool (simulates custom embedder "
99 "with custom message handler on unlimited number of threads).");
100
101// Quick access to the locally defined thread() and isolate() methods.
102#define T (thread())
103#define I (isolate())
104#define IG (isolate_group())
105
106#if defined(DEBUG)
107// Helper class to ensure that a live origin_id is never reused
108// and assigned to an isolate.
109class VerifyOriginId : public IsolateVisitor {
110 public:
111 explicit VerifyOriginId(Dart_Port id) : id_(id) {}
112
113 void VisitIsolate(Isolate* isolate) { ASSERT(isolate->origin_id() != id_); }
114
115 private:
116 Dart_Port id_;
117 DISALLOW_COPY_AND_ASSIGN(VerifyOriginId);
118};
119#endif
120
121static std::unique_ptr<Message> SerializeMessage(Dart_Port dest_port,
122 const Instance& obj) {
123 return WriteMessage(/* same_group */ false, obj, dest_port,
124 priority: Message::kNormalPriority);
125}
126
127static std::unique_ptr<Message> SerializeMessage(Zone* zone,
128 Dart_Port dest_port,
129 Dart_CObject* obj) {
130 return WriteApiMessage(zone, obj, dest_port, priority: Message::kNormalPriority);
131}
132
133void IsolateGroupSource::add_loaded_blob(
134 Zone* zone,
135 const ExternalTypedData& external_typed_data) {
136 Array& loaded_blobs = Array::Handle();
137 bool saved_external_typed_data = false;
138 if (loaded_blobs_ != nullptr) {
139 loaded_blobs = loaded_blobs_;
140
141 // Walk the array, and (if stuff was removed) compact and reuse the space.
142 // Note that the space has to be compacted as the ordering is important.
143 WeakProperty& weak_property = WeakProperty::Handle();
144 WeakProperty& weak_property_tmp = WeakProperty::Handle();
145 ExternalTypedData& existing_entry = ExternalTypedData::Handle(zone);
146 intptr_t next_entry_index = 0;
147 for (intptr_t i = 0; i < loaded_blobs.Length(); i++) {
148 weak_property ^= loaded_blobs.At(index: i);
149 if (weak_property.key() != ExternalTypedData::null()) {
150 if (i != next_entry_index) {
151 existing_entry = ExternalTypedData::RawCast(raw: weak_property.key());
152 weak_property_tmp ^= loaded_blobs.At(index: next_entry_index);
153 weak_property_tmp.set_key(existing_entry);
154 }
155 next_entry_index++;
156 }
157 }
158 if (next_entry_index < loaded_blobs.Length()) {
159 // There's now space to re-use.
160 weak_property ^= loaded_blobs.At(index: next_entry_index);
161 weak_property.set_key(external_typed_data);
162 next_entry_index++;
163 saved_external_typed_data = true;
164 }
165 if (next_entry_index < loaded_blobs.Length()) {
166 ExternalTypedData& nullExternalTypedData =
167 ExternalTypedData::Handle(zone);
168 while (next_entry_index < loaded_blobs.Length()) {
169 // Null out any extra spaces.
170 weak_property ^= loaded_blobs.At(index: next_entry_index);
171 weak_property.set_key(nullExternalTypedData);
172 next_entry_index++;
173 }
174 }
175 }
176 if (!saved_external_typed_data) {
177 const WeakProperty& weak_property =
178 WeakProperty::Handle(ptr: WeakProperty::New(space: Heap::kOld));
179 weak_property.set_key(external_typed_data);
180
181 intptr_t length = loaded_blobs.IsNull() ? 0 : loaded_blobs.Length();
182 Array& new_array =
183 Array::Handle(ptr: Array::Grow(source: loaded_blobs, new_length: length + 1, space: Heap::kOld));
184 new_array.SetAt(index: length, value: weak_property);
185 loaded_blobs_ = new_array.ptr();
186 }
187 num_blob_loads_++;
188}
189
190void IdleTimeHandler::InitializeWithHeap(Heap* heap) {
191 MutexLocker ml(&mutex_);
192 ASSERT(heap_ == nullptr && heap != nullptr);
193 heap_ = heap;
194}
195
196bool IdleTimeHandler::ShouldCheckForIdle() {
197 MutexLocker ml(&mutex_);
198 return idle_start_time_ > 0 && FLAG_idle_timeout_micros != 0 &&
199 disabled_counter_ == 0;
200}
201
202void IdleTimeHandler::UpdateStartIdleTime() {
203 MutexLocker ml(&mutex_);
204 if (disabled_counter_ == 0) {
205 idle_start_time_ = OS::GetCurrentMonotonicMicros();
206 }
207}
208
209bool IdleTimeHandler::ShouldNotifyIdle(int64_t* expiry) {
210 const int64_t now = OS::GetCurrentMonotonicMicros();
211
212 MutexLocker ml(&mutex_);
213 if (idle_start_time_ > 0 && disabled_counter_ == 0) {
214 const int64_t expiry_time = idle_start_time_ + FLAG_idle_timeout_micros;
215 if (expiry_time < now) {
216 idle_start_time_ = 0;
217 return true;
218 }
219 }
220
221 *expiry = now + FLAG_idle_timeout_micros;
222 return false;
223}
224
225void IdleTimeHandler::NotifyIdle(int64_t deadline) {
226 {
227 MutexLocker ml(&mutex_);
228 disabled_counter_++;
229 }
230 if (heap_ != nullptr) {
231 heap_->NotifyIdle(deadline);
232 }
233 {
234 MutexLocker ml(&mutex_);
235 disabled_counter_--;
236 idle_start_time_ = 0;
237 }
238}
239
240void IdleTimeHandler::NotifyIdleUsingDefaultDeadline() {
241 const int64_t now = OS::GetCurrentMonotonicMicros();
242 NotifyIdle(deadline: now + FLAG_idle_duration_micros);
243}
244
245DisableIdleTimerScope::DisableIdleTimerScope(IdleTimeHandler* handler)
246 : handler_(handler) {
247 if (handler_ != nullptr) {
248 MutexLocker ml(&handler_->mutex_);
249 ++handler_->disabled_counter_;
250 handler_->idle_start_time_ = 0;
251 }
252}
253
254DisableIdleTimerScope::~DisableIdleTimerScope() {
255 if (handler_ != nullptr) {
256 MutexLocker ml(&handler_->mutex_);
257 --handler_->disabled_counter_;
258 ASSERT(handler_->disabled_counter_ >= 0);
259 }
260}
261
262class FinalizeWeakPersistentHandlesVisitor : public HandleVisitor {
263 public:
264 explicit FinalizeWeakPersistentHandlesVisitor(IsolateGroup* isolate_group)
265 : HandleVisitor(Thread::Current()), isolate_group_(isolate_group) {}
266
267 void VisitHandle(uword addr) override {
268 auto handle = reinterpret_cast<FinalizablePersistentHandle*>(addr);
269 handle->UpdateUnreachable(isolate_group: isolate_group_);
270 }
271
272 private:
273 IsolateGroup* isolate_group_;
274
275 DISALLOW_COPY_AND_ASSIGN(FinalizeWeakPersistentHandlesVisitor);
276};
277
278void MutatorThreadPool::OnEnterIdleLocked(MonitorLocker* ml) {
279 if (FLAG_idle_timeout_micros == 0) return;
280
281 // If the isolate has not started running application code yet, we ignore the
282 // idle time.
283 if (!isolate_group_->initial_spawn_successful()) return;
284
285 int64_t idle_expiry = 0;
286 // Obtain the idle time we should wait.
287 if (isolate_group_->idle_time_handler()->ShouldNotifyIdle(expiry: &idle_expiry)) {
288 MonitorLeaveScope mls(ml);
289 NotifyIdle();
290 return;
291 }
292
293 // Avoid shutdown having to wait for the timeout to expire.
294 if (ShuttingDownLocked()) return;
295
296 // Wait for the recommended idle timeout.
297 // We can be woken up because of a), b) or c)
298 const auto result =
299 ml->WaitMicros(micros: idle_expiry - OS::GetCurrentMonotonicMicros());
300
301 // a) If there are new tasks we have to run them.
302 if (TasksWaitingToRunLocked()) return;
303
304 // b) If the thread pool is shutting down we're done.
305 if (ShuttingDownLocked()) return;
306
307 // c) We timed out and should run the idle notifier.
308 if (result == Monitor::kTimedOut &&
309 isolate_group_->idle_time_handler()->ShouldNotifyIdle(expiry: &idle_expiry)) {
310 MonitorLeaveScope mls(ml);
311 NotifyIdle();
312 return;
313 }
314
315 // There must've been another thread doing active work in the meantime.
316 // If that thread becomes idle and is the last idle thread it will run this
317 // code again.
318}
319
320void MutatorThreadPool::NotifyIdle() {
321 EnterIsolateGroupScope isolate_group_scope(isolate_group_);
322 isolate_group_->idle_time_handler()->NotifyIdleUsingDefaultDeadline();
323}
324
325IsolateGroup::IsolateGroup(std::shared_ptr<IsolateGroupSource> source,
326 void* embedder_data,
327 ObjectStore* object_store,
328 Dart_IsolateFlags api_flags)
329 : class_table_(nullptr),
330 cached_class_table_table_(nullptr),
331 object_store_(object_store),
332 class_table_allocator_(),
333 embedder_data_(embedder_data),
334 thread_pool_(),
335 isolates_lock_(new SafepointRwLock()),
336 isolates_(),
337 start_time_micros_(OS::GetCurrentMonotonicMicros()),
338 is_system_isolate_group_(source->flags.is_system_isolate),
339 random_(),
340#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
341 last_reload_timestamp_(OS::GetCurrentTimeMillis()),
342 reload_every_n_stack_overflow_checks_(FLAG_reload_every),
343#endif
344 source_(std::move(source)),
345 api_state_(new ApiState()),
346 thread_registry_(new ThreadRegistry()),
347 safepoint_handler_(new SafepointHandler(this)),
348 store_buffer_(new StoreBuffer()),
349 heap_(nullptr),
350 saved_unlinked_calls_(Array::null()),
351 initial_field_table_(new FieldTable(/*isolate=*/nullptr)),
352#if !defined(DART_PRECOMPILED_RUNTIME)
353 background_compiler_(new BackgroundCompiler(this)),
354#endif
355 symbols_mutex_(NOT_IN_PRODUCT("IsolateGroup::symbols_mutex_")),
356 type_canonicalization_mutex_(
357 NOT_IN_PRODUCT("IsolateGroup::type_canonicalization_mutex_")),
358 type_arguments_canonicalization_mutex_(NOT_IN_PRODUCT(
359 "IsolateGroup::type_arguments_canonicalization_mutex_")),
360 subtype_test_cache_mutex_(
361 NOT_IN_PRODUCT("IsolateGroup::subtype_test_cache_mutex_")),
362 megamorphic_table_mutex_(
363 NOT_IN_PRODUCT("IsolateGroup::megamorphic_table_mutex_")),
364 type_feedback_mutex_(
365 NOT_IN_PRODUCT("IsolateGroup::type_feedback_mutex_")),
366 patchable_call_mutex_(
367 NOT_IN_PRODUCT("IsolateGroup::patchable_call_mutex_")),
368 constant_canonicalization_mutex_(
369 NOT_IN_PRODUCT("IsolateGroup::constant_canonicalization_mutex_")),
370 kernel_data_lib_cache_mutex_(
371 NOT_IN_PRODUCT("IsolateGroup::kernel_data_lib_cache_mutex_")),
372 kernel_data_class_cache_mutex_(
373 NOT_IN_PRODUCT("IsolateGroup::kernel_data_class_cache_mutex_")),
374 kernel_constants_mutex_(
375 NOT_IN_PRODUCT("IsolateGroup::kernel_constants_mutex_")),
376 field_list_mutex_(NOT_IN_PRODUCT("Isolate::field_list_mutex_")),
377 boxed_field_list_(GrowableObjectArray::null()),
378 program_lock_(new SafepointRwLock()),
379 active_mutators_monitor_(new Monitor()),
380 max_active_mutators_(Scavenger::MaxMutatorThreadCount())
381#if !defined(PRODUCT)
382 ,
383 debugger_(new GroupDebugger(this))
384#endif
385{
386 FlagsCopyFrom(api_flags);
387 const bool is_vm_isolate = Dart::VmIsolateNameEquals(name: source_->name);
388 if (!is_vm_isolate) {
389 thread_pool_.reset(
390 p: new MutatorThreadPool(this, FLAG_disable_thread_pool_limit
391 ? 0
392 : Scavenger::MaxMutatorThreadCount()));
393 }
394 {
395 WriteRwLocker wl(ThreadState::Current(), isolate_groups_rwlock_);
396 // Keep isolate IDs less than 2^53 so web clients of the service
397 // protocol can process it properly.
398 //
399 // See https://github.com/dart-lang/sdk/issues/53081.
400 id_ = isolate_group_random_->NextJSInt();
401 }
402 heap_walk_class_table_ = class_table_ =
403 new ClassTable(&class_table_allocator_);
404 cached_class_table_table_.store(arg: class_table_->table());
405}
406
407IsolateGroup::IsolateGroup(std::shared_ptr<IsolateGroupSource> source,
408 void* embedder_data,
409 Dart_IsolateFlags api_flags)
410 : IsolateGroup(source, embedder_data, new ObjectStore(), api_flags) {
411 if (object_store() != nullptr) {
412 object_store()->InitStubs();
413 }
414}
415
416IsolateGroup::~IsolateGroup() {
417 // Ensure we destroy the heap before the other members.
418 heap_ = nullptr;
419 ASSERT(marking_stack_ == nullptr);
420
421 if (obfuscation_map_ != nullptr) {
422 for (intptr_t i = 0; obfuscation_map_[i] != nullptr; i++) {
423 delete[] obfuscation_map_[i];
424 }
425 delete[] obfuscation_map_;
426 }
427
428 class_table_allocator_.Free(table: class_table_);
429 if (heap_walk_class_table_ != class_table_) {
430 class_table_allocator_.Free(table: heap_walk_class_table_);
431 }
432
433#if !defined(PRODUCT)
434 delete debugger_;
435 debugger_ = nullptr;
436#endif
437}
438
439void IsolateGroup::RegisterIsolate(Isolate* isolate) {
440 SafepointWriteRwLocker ml(Thread::Current(), isolates_lock_.get());
441 ASSERT(isolates_lock_->IsCurrentThreadWriter());
442 isolates_.Append(a: isolate);
443 isolate_count_++;
444}
445
446bool IsolateGroup::ContainsOnlyOneIsolate() {
447 SafepointReadRwLocker ml(Thread::Current(), isolates_lock_.get());
448 // We do allow 0 here as well, because the background compiler might call
449 // this method while the mutator thread is in shutdown procedure and
450 // unregistered itself already.
451 return isolate_count_ == 0 || isolate_count_ == 1;
452}
453
454void IsolateGroup::RunWithLockedGroup(std::function<void()> fun) {
455 SafepointWriteRwLocker ml(Thread::Current(), isolates_lock_.get());
456 fun();
457}
458
459void IsolateGroup::UnregisterIsolate(Isolate* isolate) {
460 SafepointWriteRwLocker ml(Thread::Current(), isolates_lock_.get());
461 isolates_.Remove(a: isolate);
462}
463
464bool IsolateGroup::UnregisterIsolateDecrementCount() {
465 SafepointWriteRwLocker ml(Thread::Current(), isolates_lock_.get());
466 isolate_count_--;
467 return isolate_count_ == 0;
468}
469
470void IsolateGroup::CreateHeap(bool is_vm_isolate,
471 bool is_service_or_kernel_isolate) {
472 Heap::Init(isolate_group: this, is_vm_isolate,
473 max_new_gen_words: is_vm_isolate
474 ? 0 // New gen size 0; VM isolate should only allocate in old.
475 : FLAG_new_gen_semi_max_size * MBInWords,
476 max_old_gen_words: (is_service_or_kernel_isolate ? kDefaultMaxOldGenHeapSize
477 : FLAG_old_gen_heap_size) *
478 MBInWords);
479
480 is_vm_isolate_heap_ = is_vm_isolate;
481
482#define ISOLATE_GROUP_METRIC_CONSTRUCTORS(type, variable, name, unit) \
483 metric_##variable##_.InitInstance(this, name, nullptr, Metric::unit);
484 ISOLATE_GROUP_METRIC_LIST(ISOLATE_GROUP_METRIC_CONSTRUCTORS)
485#undef ISOLATE_GROUP_METRIC_CONSTRUCTORS
486}
487
488void IsolateGroup::Shutdown() {
489 char* name = nullptr;
490 // We retrieve the flag value once to avoid the compiler complaining about the
491 // possibly uninitialized value of name, as the compiler is unaware that when
492 // the flag variable is non-const, it is set once during VM initialization and
493 // never changed after, and that modification never runs concurrently with
494 // this method.
495 const bool trace_shutdown = FLAG_trace_shutdown;
496
497 if (trace_shutdown) {
498 name = Utils::StrDup(s: source()->name);
499 OS::PrintErr(format: "[+%" Pd64 "ms] SHUTDOWN: Shutdown starting for group %s\n",
500 Dart::UptimeMillis(), name);
501 }
502 // Ensure to join all threads before waiting for pending GC tasks (the thread
503 // pool can trigger idle notification, which can start new GC tasks).
504 //
505 // (The vm-isolate doesn't have a thread pool.)
506 if (!Dart::VmIsolateNameEquals(name: source()->name)) {
507 ASSERT(thread_pool_ != nullptr);
508 thread_pool_->Shutdown();
509 thread_pool_.reset();
510 }
511
512 // Wait for any pending GC tasks.
513 if (heap_ != nullptr) {
514 // Wait for any concurrent GC tasks to finish before shutting down.
515 // TODO(rmacnak): Interrupt tasks for faster shutdown.
516 PageSpace* old_space = heap_->old_space();
517 MonitorLocker ml(old_space->tasks_lock());
518 while (old_space->tasks() > 0) {
519 ml.Wait();
520 }
521 // Needs to happen before ~PageSpace so TLS and the thread registry are
522 // still valid.
523 old_space->AbandonMarkingForShutdown();
524 }
525
526 UnregisterIsolateGroup(isolate_group: this);
527
528 // If the creation of the isolate group (or the first isolate within the
529 // isolate group) failed, we do not invoke the cleanup callback (the
530 // embedder is responsible for handling the creation error).
531 if (initial_spawn_successful_) {
532 auto group_shutdown_callback = Isolate::GroupCleanupCallback();
533 if (group_shutdown_callback != nullptr) {
534 group_shutdown_callback(embedder_data());
535 }
536 }
537
538 delete this;
539
540 // After this isolate group has died we might need to notify a pending
541 // `Dart_Cleanup()` call.
542 {
543 if (trace_shutdown) {
544 OS::PrintErr(format: "[+%" Pd64
545 "ms] SHUTDOWN: Notifying "
546 "isolate group shutdown (%s)\n",
547 Dart::UptimeMillis(), name);
548 }
549 MonitorLocker ml(Isolate::isolate_creation_monitor_);
550 if (!Isolate::creation_enabled_ &&
551 !IsolateGroup::HasApplicationIsolateGroups()) {
552 ml.Notify();
553 }
554 if (trace_shutdown) {
555 OS::PrintErr(format: "[+%" Pd64
556 "ms] SHUTDOWN: Done Notifying "
557 "isolate group shutdown (%s)\n",
558 Dart::UptimeMillis(), name);
559 }
560 }
561 if (trace_shutdown) {
562 OS::PrintErr(format: "[+%" Pd64 "ms] SHUTDOWN: Done shutdown for group %s\n",
563 Dart::UptimeMillis(), name);
564 free(ptr: name);
565 }
566}
567
568void IsolateGroup::set_heap(std::unique_ptr<Heap> heap) {
569 idle_time_handler_.InitializeWithHeap(heap: heap.get());
570 heap_ = std::move(heap);
571}
572
573void IsolateGroup::set_saved_unlinked_calls(const Array& saved_unlinked_calls) {
574 saved_unlinked_calls_ = saved_unlinked_calls.ptr();
575}
576
577void IsolateGroup::IncreaseMutatorCount(Isolate* mutator,
578 bool is_nested_reenter) {
579 ASSERT(mutator->group() == this);
580
581 // If the mutator was temporarily blocked on a worker thread, we have to
582 // unblock the worker thread again.
583 if (is_nested_reenter) {
584 ASSERT(mutator->mutator_thread() != nullptr);
585 thread_pool()->MarkCurrentWorkerAsUnBlocked();
586 }
587
588 // Prevent too many mutators from entering the isolate group to avoid
589 // pathological behavior where many threads are fighting for obtaining TLABs.
590 {
591 // NOTE: This is performance critical code, we should avoid monitors and use
592 // std::atomics in the fast case (where active_mutators <
593 // max_active_mutators) and only use monitors in the uncommon case.
594 MonitorLocker ml(active_mutators_monitor_.get());
595 ASSERT(active_mutators_ <= max_active_mutators_);
596 while (active_mutators_ == max_active_mutators_) {
597 waiting_mutators_++;
598 ml.Wait();
599 waiting_mutators_--;
600 }
601 active_mutators_++;
602 }
603}
604
605void IsolateGroup::DecreaseMutatorCount(Isolate* mutator, bool is_nested_exit) {
606 ASSERT(mutator->group() == this);
607
608 // If the mutator thread has an active stack and runs on our thread pool we
609 // will mark the worker as blocked, thereby possibly spawning a new worker for
610 // pending tasks (if there are any).
611 if (is_nested_exit) {
612 ASSERT(mutator->mutator_thread() != nullptr);
613 thread_pool()->MarkCurrentWorkerAsBlocked();
614 }
615
616 {
617 // NOTE: This is performance critical code, we should avoid monitors and use
618 // std::atomics in the fast case (where active_mutators <
619 // max_active_mutators) and only use monitors in the uncommon case.
620 MonitorLocker ml(active_mutators_monitor_.get());
621 ASSERT(active_mutators_ <= max_active_mutators_);
622 active_mutators_--;
623 if (waiting_mutators_ > 0) {
624 ml.Notify();
625 }
626 }
627}
628
629#ifndef PRODUCT
630void IsolateGroup::PrintJSON(JSONStream* stream, bool ref) {
631 JSONObject jsobj(stream);
632 PrintToJSONObject(jsobj: &jsobj, ref);
633}
634
635void IsolateGroup::PrintToJSONObject(JSONObject* jsobj, bool ref) {
636 jsobj->AddProperty(name: "type", s: (ref ? "@IsolateGroup" : "IsolateGroup"));
637 jsobj->AddServiceId(ISOLATE_GROUP_SERVICE_ID_FORMAT_STRING, id());
638
639 jsobj->AddProperty(name: "name", s: source()->script_uri);
640 jsobj->AddPropertyF(name: "number", format: "%" Pu64 "", id());
641 jsobj->AddProperty(name: "isSystemIsolateGroup", b: is_system_isolate_group());
642 if (ref) {
643 return;
644 }
645
646 {
647 JSONArray isolate_array(jsobj, "isolates");
648 for (auto it = isolates_.Begin(); it != isolates_.End(); ++it) {
649 Isolate* isolate = *it;
650 isolate_array.AddValue(isolate, /*ref=*/true);
651 }
652 }
653}
654
655void IsolateGroup::PrintMemoryUsageJSON(JSONStream* stream) {
656 int64_t used = heap()->TotalUsedInWords();
657 int64_t capacity = heap()->TotalCapacityInWords();
658 int64_t external_used = heap()->TotalExternalInWords();
659
660 JSONObject jsobj(stream);
661 // This is the same "MemoryUsage" that the isolate-specific "getMemoryUsage"
662 // rpc method returns.
663 jsobj.AddProperty(name: "type", s: "MemoryUsage");
664 jsobj.AddProperty64(name: "heapUsage", i: used * kWordSize);
665 jsobj.AddProperty64(name: "heapCapacity", i: capacity * kWordSize);
666 jsobj.AddProperty64(name: "externalUsage", i: external_used * kWordSize);
667}
668#endif
669
670void IsolateGroup::ForEach(std::function<void(IsolateGroup*)> action) {
671 ReadRwLocker wl(Thread::Current(), isolate_groups_rwlock_);
672 for (auto isolate_group : *isolate_groups_) {
673 action(isolate_group);
674 }
675}
676
677void IsolateGroup::RunWithIsolateGroup(
678 uint64_t id,
679 std::function<void(IsolateGroup*)> action,
680 std::function<void()> not_found) {
681 ReadRwLocker wl(Thread::Current(), isolate_groups_rwlock_);
682 for (auto isolate_group : *isolate_groups_) {
683 if (isolate_group->id() == id) {
684 action(isolate_group);
685 return;
686 }
687 }
688 not_found();
689}
690
691void IsolateGroup::RegisterIsolateGroup(IsolateGroup* isolate_group) {
692 WriteRwLocker wl(ThreadState::Current(), isolate_groups_rwlock_);
693 isolate_groups_->Append(a: isolate_group);
694}
695
696void IsolateGroup::UnregisterIsolateGroup(IsolateGroup* isolate_group) {
697 WriteRwLocker wl(ThreadState::Current(), isolate_groups_rwlock_);
698 isolate_groups_->Remove(a: isolate_group);
699}
700
701bool IsolateGroup::HasApplicationIsolateGroups() {
702 ReadRwLocker wl(ThreadState::Current(), isolate_groups_rwlock_);
703 for (auto group : *isolate_groups_) {
704 if (!IsolateGroup::IsSystemIsolateGroup(group)) {
705 return true;
706 }
707 }
708 return false;
709}
710
711bool IsolateGroup::HasOnlyVMIsolateGroup() {
712 ReadRwLocker wl(ThreadState::Current(), isolate_groups_rwlock_);
713 for (auto group : *isolate_groups_) {
714 if (!Dart::VmIsolateNameEquals(name: group->source()->name)) {
715 return false;
716 }
717 }
718 return true;
719}
720
721void IsolateGroup::Init() {
722 ASSERT(isolate_groups_rwlock_ == nullptr);
723 isolate_groups_rwlock_ = new RwLock();
724 ASSERT(isolate_groups_ == nullptr);
725 isolate_groups_ = new IntrusiveDList<IsolateGroup>();
726 isolate_group_random_ = new Random();
727}
728
729void IsolateGroup::Cleanup() {
730 delete isolate_group_random_;
731 isolate_group_random_ = nullptr;
732 delete isolate_groups_rwlock_;
733 isolate_groups_rwlock_ = nullptr;
734 ASSERT(isolate_groups_->IsEmpty());
735 delete isolate_groups_;
736 isolate_groups_ = nullptr;
737}
738
739bool IsolateVisitor::IsSystemIsolate(Isolate* isolate) const {
740 return Isolate::IsSystemIsolate(isolate);
741}
742
743Bequest::~Bequest() {
744 if (handle_ == nullptr) {
745 return;
746 }
747
748 IsolateGroup* isolate_group = IsolateGroup::Current();
749 CHECK_ISOLATE_GROUP(isolate_group);
750 NoSafepointScope no_safepoint_scope;
751 ApiState* state = isolate_group->api_state();
752 ASSERT(state != nullptr);
753 state->FreePersistentHandle(ref: handle_);
754}
755
756void IsolateGroup::RegisterClass(const Class& cls) {
757#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
758 if (IsReloading()) {
759 program_reload_context()->RegisterClass(new_cls: cls);
760 return;
761 }
762#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
763 if (cls.IsTopLevel()) {
764 class_table()->RegisterTopLevel(cls);
765 } else {
766 class_table()->Register(cls);
767 }
768}
769
770#if defined(DEBUG)
771void IsolateGroup::ValidateClassTable() {
772 class_table()->Validate();
773}
774#endif // DEBUG
775
776void IsolateGroup::RegisterStaticField(const Field& field,
777 const Object& initial_value) {
778 ASSERT(program_lock()->IsCurrentThreadWriter());
779
780 ASSERT(field.is_static());
781 const bool need_to_grow_backing_store =
782 initial_field_table()->Register(field);
783 const intptr_t field_id = field.field_id();
784 initial_field_table()->SetAt(index: field_id, raw_instance: initial_value.ptr());
785
786 SafepointReadRwLocker ml(Thread::Current(), isolates_lock_.get());
787 if (need_to_grow_backing_store) {
788 // We have to stop other isolates from accessing their field state, since
789 // we'll have to grow the backing store.
790 GcSafepointOperationScope scope(Thread::Current());
791 for (auto isolate : isolates_) {
792 auto field_table = isolate->field_table();
793 if (field_table->IsReadyToUse()) {
794 field_table->Register(field, expected_field_id: field_id);
795 field_table->SetAt(index: field_id, raw_instance: initial_value.ptr());
796 }
797 }
798 } else {
799 for (auto isolate : isolates_) {
800 auto field_table = isolate->field_table();
801 if (field_table->IsReadyToUse()) {
802 field_table->Register(field, expected_field_id: field_id);
803 field_table->SetAt(index: field_id, raw_instance: initial_value.ptr());
804 }
805 }
806 }
807}
808
809void IsolateGroup::FreeStaticField(const Field& field) {
810#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
811 // This can only be called during hot-reload.
812 ASSERT(program_reload_context() != nullptr);
813#endif
814
815 const intptr_t field_id = field.field_id();
816 initial_field_table()->Free(index: field_id);
817 ForEachIsolate(function: [&](Isolate* isolate) {
818 auto field_table = isolate->field_table();
819 // The isolate might've just been created and is now participating in
820 // the reload request inside `IsolateGroup::RegisterIsolate()`.
821 // At that point it doesn't have the field table setup yet.
822 if (field_table->IsReadyToUse()) {
823 field_table->Free(index: field_id);
824 }
825 });
826}
827
828Isolate* IsolateGroup::EnterTemporaryIsolate() {
829 Dart_IsolateFlags flags;
830 Isolate::FlagsInitialize(api_flags: &flags);
831 Isolate* const isolate = Isolate::InitIsolate(name_prefix: "temp", isolate_group: this, api_flags: flags);
832 ASSERT(isolate != nullptr);
833 ASSERT(Isolate::Current() == isolate);
834 return isolate;
835}
836
837void IsolateGroup::ExitTemporaryIsolate() {
838 Thread* thread = Thread::Current();
839 ASSERT(thread != nullptr);
840 thread->set_execution_state(Thread::kThreadInVM);
841 Dart::ShutdownIsolate(T: thread);
842}
843
844void IsolateGroup::RehashConstants(Become* become) {
845 // Even though no individual constant contains a cycle, there can be "cycles"
846 // between the canonical tables if some const instances of A have fields that
847 // are const instance of B and vice versa. So set all the old tables to the
848 // side and clear all the tables attached to the classes before rehashing
849 // instead of resetting and rehash one class at a time.
850
851 Thread* thread = Thread::Current();
852 StackZone stack_zone(thread);
853 Zone* zone = stack_zone.GetZone();
854
855 intptr_t num_cids = class_table()->NumCids();
856 Array** old_constant_tables = zone->Alloc<Array*>(len: num_cids);
857 for (intptr_t i = 0; i < num_cids; i++) {
858 old_constant_tables[i] = nullptr;
859 }
860
861 Class& cls = Class::Handle(zone);
862 for (intptr_t cid = kInstanceCid; cid < num_cids; cid++) {
863 if (!class_table()->IsValidIndex(cid) ||
864 !class_table()->HasValidClassAt(cid)) {
865 continue;
866 }
867 if ((cid == kTypeArgumentsCid) || IsStringClassId(index: cid)) {
868 // TypeArguments and Symbols have special tables for canonical objects
869 // that aren't based on address.
870 continue;
871 }
872 if ((cid == kMintCid) || (cid == kDoubleCid)) {
873 // Constants stored as a plain list or in a hashset with a stable
874 // hashcode, which only depends on the actual value of the constant.
875 continue;
876 }
877
878 cls = class_table()->At(cid);
879 if (cls.constants() == Array::null()) continue;
880 old_constant_tables[cid] = &Array::Handle(zone, ptr: cls.constants());
881 cls.set_constants(Object::null_array());
882 }
883
884 // Clear invalid hashes.
885 heap()->ResetCanonicalHashTable();
886
887 Instance& constant = Instance::Handle(zone);
888 Field& field = Field::Handle(zone);
889 String& name = String::Handle(zone);
890 Array& new_values = Array::Handle(zone);
891 Instance& old_value = Instance::Handle(zone);
892 Instance& new_value = Instance::Handle(zone);
893 Instance& deleted = Instance::Handle(zone);
894 for (intptr_t cid = kInstanceCid; cid < num_cids; cid++) {
895 Array* old_constants = old_constant_tables[cid];
896 if (old_constants == nullptr) continue;
897
898 cls = class_table()->At(cid);
899 CanonicalInstancesSet set(zone, old_constants->ptr());
900 CanonicalInstancesSet::Iterator it(&set);
901
902 if (cls.is_enum_class() && (become != nullptr)) {
903 field = cls.LookupStaticField(name: Symbols::_DeletedEnumSentinel());
904 deleted ^= field.StaticConstFieldValue();
905 if (deleted.IsNull()) {
906 deleted = Instance::New(cls, space: Heap::kOld);
907 field = object_store()->enum_name_field();
908 name = cls.ScrubbedName();
909 name = Symbols::FromConcat(thread, str1: Symbols::_DeletedEnumPrefix(), str2: name);
910 deleted.SetField(field, value: name);
911 field = object_store()->enum_index_field();
912 new_value = Smi::New(value: -1);
913 deleted.SetField(field, value: new_value);
914 field = cls.LookupStaticField(name: Symbols::_DeletedEnumSentinel());
915 // The static const field contains `Object::null()` instead of
916 // `Object::sentinel()` - so it's not considered an initializing store.
917 field.SetStaticConstFieldValue(value: deleted,
918 /*assert_initializing_store*/ false);
919 }
920
921 field = cls.LookupField(name: Symbols::Values());
922 new_values ^= field.StaticConstFieldValue();
923
924 field = object_store()->enum_name_field();
925 while (it.MoveNext()) {
926 old_value ^= set.GetKey(entry: it.Current());
927 ASSERT(old_value.GetClassId() == cid);
928 bool found = false;
929 for (intptr_t j = 0; j < new_values.Length(); j++) {
930 new_value ^= new_values.At(index: j);
931 ASSERT(new_value.GetClassId() == cid);
932 if (old_value.GetField(field) == new_value.GetField(field)) {
933 found = true;
934 break;
935 }
936 }
937 if (!found) {
938 new_value = deleted.ptr();
939 }
940
941 if (old_value.ptr() != new_value.ptr()) {
942 become->Add(before: old_value, after: new_value);
943 }
944 if (new_value.IsCanonical()) {
945 cls.InsertCanonicalConstant(zone, constant: new_value);
946 }
947 }
948 } else {
949 while (it.MoveNext()) {
950 constant ^= set.GetKey(entry: it.Current());
951 ASSERT(!constant.IsNull());
952 // Shape changes lose the canonical bit because they may result/ in
953 // merging constants. E.g., [x1, y1], [x1, y2] -> [x1].
954 DEBUG_ASSERT(constant.IsCanonical() || HasAttemptedReload());
955 cls.InsertCanonicalConstant(zone, constant);
956 }
957 }
958 set.Release();
959 }
960
961 // Save memory.
962 heap()->ResetCanonicalHashTable();
963}
964
965void Isolate::SendInternalLibMessage(LibMsgId msg_id, uint64_t capability) {
966 const bool ok = SendInternalLibMessage(main_port: main_port(), msg_id, capability);
967 if (!ok) UNREACHABLE();
968}
969
970bool Isolate::SendInternalLibMessage(Dart_Port main_port,
971 LibMsgId msg_id,
972 uint64_t capability) {
973 Dart_CObject array_entry_msg_kind;
974 array_entry_msg_kind.type = Dart_CObject_kInt64;
975 array_entry_msg_kind.value.as_int64 = Message::kIsolateLibOOBMsg;
976
977 Dart_CObject array_entry_msg_id;
978 array_entry_msg_id.type = Dart_CObject_kInt64;
979 array_entry_msg_id.value.as_int64 = msg_id;
980
981 Dart_CObject array_entry_capability;
982 array_entry_capability.type = Dart_CObject_kCapability;
983 array_entry_capability.value.as_capability.id = capability;
984
985 Dart_CObject* array_entries[3] = {
986 &array_entry_msg_kind,
987 &array_entry_msg_id,
988 &array_entry_capability,
989 };
990
991 Dart_CObject message;
992 message.type = Dart_CObject_kArray;
993 message.value.as_array.values = array_entries;
994 message.value.as_array.length = ARRAY_SIZE(array_entries);
995
996 AllocOnlyStackZone zone;
997 std::unique_ptr<Message> msg = WriteApiMessage(
998 zone: zone.GetZone(), obj: &message, dest_port: main_port, priority: Message::kOOBPriority);
999 if (msg == nullptr) UNREACHABLE();
1000
1001 return PortMap::PostMessage(message: std::move(msg));
1002}
1003
1004void IsolateGroup::set_object_store(ObjectStore* object_store) {
1005 object_store_.reset(p: object_store);
1006}
1007
1008class IsolateMessageHandler : public MessageHandler {
1009 public:
1010 explicit IsolateMessageHandler(Isolate* isolate);
1011 ~IsolateMessageHandler();
1012
1013 const char* name() const;
1014 void MessageNotify(Message::Priority priority);
1015 MessageStatus HandleMessage(std::unique_ptr<Message> message);
1016#ifndef PRODUCT
1017 void NotifyPauseOnStart();
1018 void NotifyPauseOnExit();
1019#endif // !PRODUCT
1020
1021#if defined(DEBUG)
1022 // Check that it is safe to access this handler.
1023 void CheckAccess();
1024#endif
1025 bool IsCurrentIsolate() const;
1026 virtual Isolate* isolate() const { return isolate_; }
1027 virtual IsolateGroup* isolate_group() const { return isolate_->group(); }
1028
1029 private:
1030 // A result of false indicates that the isolate should terminate the
1031 // processing of further events.
1032 ErrorPtr HandleLibMessage(const Array& message);
1033
1034 MessageStatus ProcessUnhandledException(const Error& result);
1035 Isolate* isolate_;
1036};
1037
1038IsolateMessageHandler::IsolateMessageHandler(Isolate* isolate)
1039 : isolate_(isolate) {}
1040
1041IsolateMessageHandler::~IsolateMessageHandler() {}
1042
1043const char* IsolateMessageHandler::name() const {
1044 return isolate_->name();
1045}
1046
1047// Isolate library OOB messages are fixed sized arrays which have the
1048// following format:
1049// [ OOB dispatch, Isolate library dispatch, <message specific data> ]
1050ErrorPtr IsolateMessageHandler::HandleLibMessage(const Array& message) {
1051 if (message.Length() < 2) return Error::null();
1052 Zone* zone = T->zone();
1053 const Object& type = Object::Handle(zone, ptr: message.At(index: 1));
1054 if (!type.IsSmi()) return Error::null();
1055 const intptr_t msg_type = Smi::Cast(obj: type).Value();
1056 switch (msg_type) {
1057 case Isolate::kPauseMsg: {
1058 // [ OOB, kPauseMsg, pause capability, resume capability ]
1059 if (message.Length() != 4) return Error::null();
1060 Object& obj = Object::Handle(zone, ptr: message.At(index: 2));
1061 if (!I->VerifyPauseCapability(capability: obj)) return Error::null();
1062 obj = message.At(index: 3);
1063 if (!obj.IsCapability()) return Error::null();
1064 if (I->AddResumeCapability(capability: Capability::Cast(obj))) {
1065 increment_paused();
1066 }
1067 break;
1068 }
1069 case Isolate::kResumeMsg: {
1070 // [ OOB, kResumeMsg, pause capability, resume capability ]
1071 if (message.Length() != 4) return Error::null();
1072 Object& obj = Object::Handle(zone, ptr: message.At(index: 2));
1073 if (!I->VerifyPauseCapability(capability: obj)) return Error::null();
1074 obj = message.At(index: 3);
1075 if (!obj.IsCapability()) return Error::null();
1076 if (I->RemoveResumeCapability(capability: Capability::Cast(obj))) {
1077 decrement_paused();
1078 }
1079 break;
1080 }
1081 case Isolate::kPingMsg: {
1082 // [ OOB, kPingMsg, responsePort, priority, response ]
1083 if (message.Length() != 5) return Error::null();
1084 const Object& obj2 = Object::Handle(zone, ptr: message.At(index: 2));
1085 if (!obj2.IsSendPort()) return Error::null();
1086 const SendPort& send_port = SendPort::Cast(obj: obj2);
1087 const Object& obj3 = Object::Handle(zone, ptr: message.At(index: 3));
1088 if (!obj3.IsSmi()) return Error::null();
1089 const intptr_t priority = Smi::Cast(obj: obj3).Value();
1090 const Object& obj4 = Object::Handle(zone, ptr: message.At(index: 4));
1091 if (!obj4.IsInstance() && !obj4.IsNull()) return Error::null();
1092 const Instance& response =
1093 obj4.IsNull() ? Instance::null_instance() : Instance::Cast(obj: obj4);
1094 if (priority == Isolate::kImmediateAction) {
1095 PortMap::PostMessage(message: SerializeMessage(dest_port: send_port.Id(), obj: response));
1096 } else {
1097 ASSERT((priority == Isolate::kBeforeNextEventAction) ||
1098 (priority == Isolate::kAsEventAction));
1099 // Update the message so that it will be handled immediately when it
1100 // is picked up from the message queue the next time.
1101 message.SetAt(
1102 index: 0, value: Smi::Handle(zone, ptr: Smi::New(value: Message::kDelayedIsolateLibOOBMsg)));
1103 message.SetAt(index: 3,
1104 value: Smi::Handle(zone, ptr: Smi::New(value: Isolate::kImmediateAction)));
1105 this->PostMessage(
1106 message: SerializeMessage(dest_port: Message::kIllegalPort, obj: message),
1107 before_events: priority == Isolate::kBeforeNextEventAction /* at_head */);
1108 }
1109 break;
1110 }
1111 case Isolate::kKillMsg:
1112 case Isolate::kInternalKillMsg: {
1113 // [ OOB, kKillMsg, terminate capability, priority ]
1114 if (message.Length() != 4) return Error::null();
1115 Object& obj = Object::Handle(zone, ptr: message.At(index: 3));
1116 if (!obj.IsSmi()) return Error::null();
1117 const intptr_t priority = Smi::Cast(obj).Value();
1118 if (priority == Isolate::kImmediateAction) {
1119 Thread::Current()->StartUnwindError();
1120 obj = message.At(index: 2);
1121 if (I->VerifyTerminateCapability(capability: obj)) {
1122 // We will kill the current isolate by returning an UnwindError.
1123 if (msg_type == Isolate::kKillMsg) {
1124 const String& msg = String::Handle(
1125 ptr: String::New(cstr: "isolate terminated by Isolate.kill"));
1126 const UnwindError& error =
1127 UnwindError::Handle(ptr: UnwindError::New(message: msg));
1128 error.set_is_user_initiated(true);
1129 return error.ptr();
1130 } else if (msg_type == Isolate::kInternalKillMsg) {
1131 const String& msg =
1132 String::Handle(ptr: String::New(cstr: "isolate terminated by vm"));
1133 return UnwindError::New(message: msg);
1134 } else {
1135 UNREACHABLE();
1136 }
1137 } else {
1138 return Error::null();
1139 }
1140 } else {
1141 ASSERT((priority == Isolate::kBeforeNextEventAction) ||
1142 (priority == Isolate::kAsEventAction));
1143 // Update the message so that it will be handled immediately when it
1144 // is picked up from the message queue the next time.
1145 message.SetAt(
1146 index: 0, value: Smi::Handle(zone, ptr: Smi::New(value: Message::kDelayedIsolateLibOOBMsg)));
1147 message.SetAt(index: 3,
1148 value: Smi::Handle(zone, ptr: Smi::New(value: Isolate::kImmediateAction)));
1149 this->PostMessage(
1150 message: SerializeMessage(dest_port: Message::kIllegalPort, obj: message),
1151 before_events: priority == Isolate::kBeforeNextEventAction /* at_head */);
1152 }
1153 break;
1154 }
1155 case Isolate::kInterruptMsg: {
1156 // [ OOB, kInterruptMsg, pause capability ]
1157 if (message.Length() != 3) return Error::null();
1158 Object& obj = Object::Handle(zone, ptr: message.At(index: 2));
1159 if (!I->VerifyPauseCapability(capability: obj)) return Error::null();
1160
1161#if !defined(PRODUCT)
1162 // If we are already paused, don't pause again.
1163 if (I->debugger()->PauseEvent() == nullptr) {
1164 return I->debugger()->PauseInterrupted();
1165 }
1166#endif
1167 break;
1168 }
1169 case Isolate::kDrainServiceExtensionsMsg: {
1170#ifndef PRODUCT
1171 Object& obj = Object::Handle(zone, ptr: message.At(index: 2));
1172 if (!obj.IsSmi()) return Error::null();
1173 const intptr_t priority = Smi::Cast(obj).Value();
1174 if (priority == Isolate::kImmediateAction) {
1175 return I->InvokePendingServiceExtensionCalls();
1176 } else {
1177 ASSERT((priority == Isolate::kBeforeNextEventAction) ||
1178 (priority == Isolate::kAsEventAction));
1179 // Update the message so that it will be handled immediately when it
1180 // is picked up from the message queue the next time.
1181 message.SetAt(
1182 index: 0, value: Smi::Handle(zone, ptr: Smi::New(value: Message::kDelayedIsolateLibOOBMsg)));
1183 message.SetAt(index: 2,
1184 value: Smi::Handle(zone, ptr: Smi::New(value: Isolate::kImmediateAction)));
1185 this->PostMessage(
1186 message: SerializeMessage(dest_port: Message::kIllegalPort, obj: message),
1187 before_events: priority == Isolate::kBeforeNextEventAction /* at_head */);
1188 }
1189#else
1190 UNREACHABLE();
1191#endif // !PRODUCT
1192 break;
1193 }
1194
1195 case Isolate::kAddExitMsg:
1196 case Isolate::kDelExitMsg:
1197 case Isolate::kAddErrorMsg:
1198 case Isolate::kDelErrorMsg: {
1199 // [ OOB, msg, listener port ]
1200 if (message.Length() < 3) return Error::null();
1201 const Object& obj = Object::Handle(zone, ptr: message.At(index: 2));
1202 if (!obj.IsSendPort()) return Error::null();
1203 const SendPort& listener = SendPort::Cast(obj);
1204 switch (msg_type) {
1205 case Isolate::kAddExitMsg: {
1206 if (message.Length() != 4) return Error::null();
1207 // [ OOB, msg, listener port, response object ]
1208 const Object& response = Object::Handle(zone, ptr: message.At(index: 3));
1209 if (!response.IsInstance() && !response.IsNull()) {
1210 return Error::null();
1211 }
1212 I->AddExitListener(listener, response: response.IsNull()
1213 ? Instance::null_instance()
1214 : Instance::Cast(obj: response));
1215 break;
1216 }
1217 case Isolate::kDelExitMsg:
1218 if (message.Length() != 3) return Error::null();
1219 I->RemoveExitListener(listener);
1220 break;
1221 case Isolate::kAddErrorMsg:
1222 if (message.Length() != 3) return Error::null();
1223 I->AddErrorListener(listener);
1224 break;
1225 case Isolate::kDelErrorMsg:
1226 if (message.Length() != 3) return Error::null();
1227 I->RemoveErrorListener(listener);
1228 break;
1229 default:
1230 UNREACHABLE();
1231 }
1232 break;
1233 }
1234 case Isolate::kErrorFatalMsg: {
1235 // [ OOB, kErrorFatalMsg, terminate capability, val ]
1236 if (message.Length() != 4) return Error::null();
1237 // Check that the terminate capability has been passed correctly.
1238 Object& obj = Object::Handle(zone, ptr: message.At(index: 2));
1239 if (!I->VerifyTerminateCapability(capability: obj)) return Error::null();
1240 // Get the value to be set.
1241 obj = message.At(index: 3);
1242 if (!obj.IsBool()) return Error::null();
1243 I->SetErrorsFatal(Bool::Cast(obj).value());
1244 break;
1245 }
1246 case Isolate::kCheckForReload: {
1247 // [ OOB, kCheckForReload, ignored ]
1248#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
1249 {
1250 ReloadParticipationScope allow_reload(T);
1251 T->CheckForSafepoint();
1252 }
1253#else
1254 UNREACHABLE();
1255#endif
1256 break;
1257 }
1258#if defined(DEBUG)
1259 // Malformed OOB messages are silently ignored in release builds.
1260 default:
1261 FATAL("Unknown OOB message type: %" Pd "\n", msg_type);
1262 break;
1263#endif // defined(DEBUG)
1264 }
1265 return Error::null();
1266}
1267
1268void IsolateMessageHandler::MessageNotify(Message::Priority priority) {
1269 if (priority >= Message::kOOBPriority) {
1270 // Handle out of band messages even if the mutator thread is busy.
1271 I->ScheduleInterrupts(interrupt_bits: Thread::kMessageInterrupt);
1272 }
1273 Dart_MessageNotifyCallback callback = I->message_notify_callback();
1274 if (callback != nullptr) {
1275 // Allow the embedder to handle message notification.
1276 (*callback)(Api::CastIsolate(I));
1277 }
1278}
1279
1280bool Isolate::HasPendingMessages() {
1281 return message_handler_->HasMessages() || message_handler_->HasOOBMessages();
1282}
1283
1284MessageHandler::MessageStatus IsolateMessageHandler::HandleMessage(
1285 std::unique_ptr<Message> message) {
1286 ASSERT(IsCurrentIsolate());
1287 Thread* thread = Thread::Current();
1288 StackZone stack_zone(thread);
1289 Zone* zone = stack_zone.GetZone();
1290 HandleScope handle_scope(thread);
1291#if defined(SUPPORT_TIMELINE)
1292 TimelineBeginEndScope tbes(
1293 thread, Timeline::GetIsolateStream(),
1294 message->IsOOB() ? "HandleOOBMessage" : "HandleMessage");
1295 tbes.SetNumArguments(1);
1296 tbes.CopyArgument(i: 0, name: "isolateName", I->name());
1297#endif
1298
1299 // Parse the message.
1300 Object& msg_obj = Object::Handle(zone, ptr: ReadMessage(thread, message: message.get()));
1301 if (msg_obj.IsError()) {
1302 // An error occurred while reading the message.
1303 return ProcessUnhandledException(result: Error::Cast(obj: msg_obj));
1304 }
1305 if (!msg_obj.IsNull() && !msg_obj.IsInstance()) {
1306 // TODO(turnidge): We need to decide what an isolate does with
1307 // malformed messages. If they (eventually) come from a remote
1308 // machine, then it might make sense to drop the message entirely.
1309 // In the case that the message originated locally, which is
1310 // always true for now, then this should never occur.
1311 UNREACHABLE();
1312 }
1313 Instance& msg = Instance::Handle(zone);
1314 msg ^= msg_obj.ptr(); // Can't use Instance::Cast because may be null.
1315
1316 MessageStatus status = kOK;
1317 if (message->IsOOB()) {
1318 // OOB messages are expected to be fixed length arrays where the first
1319 // element is a Smi describing the OOB destination. Messages that do not
1320 // confirm to this layout are silently ignored.
1321 if (msg.IsArray()) {
1322 const Array& oob_msg = Array::Cast(obj: msg);
1323 if (oob_msg.Length() > 0) {
1324 const Object& oob_tag = Object::Handle(zone, ptr: oob_msg.At(index: 0));
1325 if (oob_tag.IsSmi()) {
1326 switch (Smi::Cast(obj: oob_tag).Value()) {
1327 case Message::kServiceOOBMsg: {
1328#ifndef PRODUCT
1329 const Error& error =
1330 Error::Handle(ptr: Service::HandleIsolateMessage(I, message: oob_msg));
1331 if (!error.IsNull()) {
1332 status = ProcessUnhandledException(result: error);
1333 }
1334#else
1335 UNREACHABLE();
1336#endif
1337 break;
1338 }
1339 case Message::kIsolateLibOOBMsg: {
1340 const Error& error = Error::Handle(ptr: HandleLibMessage(message: oob_msg));
1341 if (!error.IsNull()) {
1342 status = ProcessUnhandledException(result: error);
1343 }
1344 break;
1345 }
1346#if defined(DEBUG)
1347 // Malformed OOB messages are silently ignored in release builds.
1348 default: {
1349 UNREACHABLE();
1350 break;
1351 }
1352#endif // defined(DEBUG)
1353 }
1354 }
1355 }
1356 }
1357 } else if (message->IsFinalizerInvocationRequest()) {
1358 const Object& msg_handler = Object::Handle(
1359 zone,
1360 ptr: DartLibraryCalls::HandleFinalizerMessage(finalizer: FinalizerBase::Cast(obj: msg)));
1361 if (msg_handler.IsError()) {
1362 status = ProcessUnhandledException(result: Error::Cast(obj: msg_handler));
1363 } else {
1364 // The handler closure which was used to successfully handle the message.
1365 }
1366 } else if (message->dest_port() == Message::kIllegalPort) {
1367 // Check whether this is a delayed OOB message which needed handling as
1368 // part of the regular message dispatch. All other messages are dropped on
1369 // the floor.
1370 if (msg.IsArray()) {
1371 const Array& msg_arr = Array::Cast(obj: msg);
1372 if (msg_arr.Length() > 0) {
1373 const Object& oob_tag = Object::Handle(zone, ptr: msg_arr.At(index: 0));
1374 if (oob_tag.IsSmi() &&
1375 (Smi::Cast(obj: oob_tag).Value() == Message::kDelayedIsolateLibOOBMsg)) {
1376 const Error& error = Error::Handle(ptr: HandleLibMessage(message: msg_arr));
1377 if (!error.IsNull()) {
1378 status = ProcessUnhandledException(result: error);
1379 }
1380 }
1381 }
1382 }
1383 } else {
1384 const Object& msg_handler = Object::Handle(
1385 zone, ptr: DartLibraryCalls::HandleMessage(port_id: message->dest_port(), message: msg));
1386 if (msg_handler.IsError()) {
1387 status = ProcessUnhandledException(result: Error::Cast(obj: msg_handler));
1388 } else if (msg_handler.IsNull()) {
1389 // If the port has been closed then the message will be dropped at this
1390 // point. Make sure to post to the delivery failure port in that case.
1391 } else {
1392 // The handler closure which was used to successfully handle the message.
1393 }
1394 }
1395 return status;
1396}
1397
1398#ifndef PRODUCT
1399void IsolateMessageHandler::NotifyPauseOnStart() {
1400 if (Isolate::IsSystemIsolate(I)) {
1401 return;
1402 }
1403 if (Service::debug_stream.enabled() || FLAG_warn_on_pause_with_no_debugger) {
1404 StartIsolateScope start_isolate(I);
1405 StackZone zone(T);
1406 HandleScope handle_scope(T);
1407 ServiceEvent pause_event(I, ServiceEvent::kPauseStart);
1408 Service::HandleEvent(event: &pause_event);
1409 } else if (FLAG_trace_service) {
1410 OS::PrintErr(format: "vm-service: Dropping event of type PauseStart (%s)\n",
1411 I->name());
1412 }
1413}
1414
1415void IsolateMessageHandler::NotifyPauseOnExit() {
1416 if (Isolate::IsSystemIsolate(I)) {
1417 return;
1418 }
1419 if (Service::debug_stream.enabled() || FLAG_warn_on_pause_with_no_debugger) {
1420 StartIsolateScope start_isolate(I);
1421 StackZone zone(T);
1422 HandleScope handle_scope(T);
1423 ServiceEvent pause_event(I, ServiceEvent::kPauseExit);
1424 Service::HandleEvent(event: &pause_event);
1425 } else if (FLAG_trace_service) {
1426 OS::PrintErr(format: "vm-service: Dropping event of type PauseExit (%s)\n",
1427 I->name());
1428 }
1429}
1430#endif // !PRODUCT
1431
1432#if defined(DEBUG)
1433void IsolateMessageHandler::CheckAccess() {
1434 ASSERT(IsCurrentIsolate());
1435}
1436#endif
1437
1438bool IsolateMessageHandler::IsCurrentIsolate() const {
1439 return (I == Isolate::Current());
1440}
1441
1442static MessageHandler::MessageStatus StoreError(Thread* thread,
1443 const Error& error) {
1444 thread->set_sticky_error(error);
1445 if (error.IsUnwindError()) {
1446 const UnwindError& unwind = UnwindError::Cast(obj: error);
1447 if (!unwind.is_user_initiated()) {
1448 return MessageHandler::kShutdown;
1449 }
1450 }
1451 return MessageHandler::kError;
1452}
1453
1454MessageHandler::MessageStatus IsolateMessageHandler::ProcessUnhandledException(
1455 const Error& result) {
1456 if (FLAG_trace_isolates) {
1457 OS::PrintErr(
1458 format: "[!] Unhandled exception in %s:\n"
1459 " exception: %s\n",
1460 T->isolate()->name(), result.ToErrorCString());
1461 }
1462
1463 NoReloadScope no_reload(T);
1464 // Generate the error and stacktrace strings for the error message.
1465 const char* exception_cstr = nullptr;
1466 const char* stacktrace_cstr = nullptr;
1467 if (result.IsUnhandledException()) {
1468 Zone* zone = T->zone();
1469 const UnhandledException& uhe = UnhandledException::Cast(obj: result);
1470 const Instance& exception = Instance::Handle(zone, ptr: uhe.exception());
1471 if (exception.ptr() == IG->object_store()->out_of_memory()) {
1472 exception_cstr = "Out of Memory"; // Cf. OutOfMemoryError.toString().
1473 } else if (exception.ptr() == IG->object_store()->stack_overflow()) {
1474 exception_cstr = "Stack Overflow"; // Cf. StackOverflowError.toString().
1475 } else {
1476 const Object& exception_str =
1477 Object::Handle(zone, ptr: DartLibraryCalls::ToString(receiver: exception));
1478 if (!exception_str.IsString()) {
1479 exception_cstr = exception.ToCString();
1480 } else {
1481 exception_cstr = exception_str.ToCString();
1482 }
1483 }
1484
1485 const Instance& stacktrace = Instance::Handle(zone, ptr: uhe.stacktrace());
1486 stacktrace_cstr = stacktrace.ToCString();
1487 } else {
1488 exception_cstr = result.ToErrorCString();
1489 }
1490 if (result.IsUnwindError()) {
1491 // When unwinding we don't notify error listeners and we ignore
1492 // whether errors are fatal for the current isolate.
1493 return StoreError(T, error: result);
1494 } else {
1495 bool has_listener =
1496 I->NotifyErrorListeners(msg: exception_cstr, stacktrace: stacktrace_cstr);
1497 if (I->ErrorsFatal()) {
1498 if (has_listener) {
1499 T->ClearStickyError();
1500 } else {
1501 T->set_sticky_error(result);
1502 }
1503#if !defined(PRODUCT)
1504 // Notify the debugger about specific unhandled exceptions which are
1505 // withheld when being thrown. Do this after setting the sticky error
1506 // so the isolate has an error set when paused with the unhandled
1507 // exception.
1508 if (result.IsUnhandledException()) {
1509 const UnhandledException& error = UnhandledException::Cast(obj: result);
1510 InstancePtr exception = error.exception();
1511 if ((exception == IG->object_store()->out_of_memory()) ||
1512 (exception == IG->object_store()->stack_overflow())) {
1513 // We didn't notify the debugger when the stack was full. Do it now.
1514 I->debugger()->PauseException(exc: Instance::Handle(ptr: exception));
1515 }
1516 }
1517#endif // !defined(PRODUCT)
1518 return kError;
1519 }
1520 }
1521 return kOK;
1522}
1523
1524void IsolateGroup::FlagsInitialize(Dart_IsolateFlags* api_flags) {
1525 api_flags->version = DART_FLAGS_CURRENT_VERSION;
1526#define INIT_FROM_FLAG(when, name, bitname, isolate_flag, flag) \
1527 api_flags->isolate_flag = flag;
1528 BOOL_ISOLATE_GROUP_FLAG_LIST(INIT_FROM_FLAG)
1529#undef INIT_FROM_FLAG
1530 api_flags->copy_parent_code = false;
1531}
1532
1533void IsolateGroup::FlagsCopyTo(Dart_IsolateFlags* api_flags) {
1534 api_flags->version = DART_FLAGS_CURRENT_VERSION;
1535#define INIT_FROM_FIELD(when, name, bitname, isolate_flag, flag) \
1536 api_flags->isolate_flag = name();
1537 BOOL_ISOLATE_GROUP_FLAG_LIST(INIT_FROM_FIELD)
1538#undef INIT_FROM_FIELD
1539 api_flags->copy_parent_code = false;
1540}
1541
1542void IsolateGroup::FlagsCopyFrom(const Dart_IsolateFlags& api_flags) {
1543#if defined(DART_PRECOMPILER)
1544#define FLAG_FOR_PRECOMPILER(action) action
1545#else
1546#define FLAG_FOR_PRECOMPILER(action)
1547#endif
1548
1549#if !defined(PRODUCT)
1550#define FLAG_FOR_NONPRODUCT(action) action
1551#else
1552#define FLAG_FOR_NONPRODUCT(action)
1553#endif
1554
1555#define FLAG_FOR_PRODUCT(action) action
1556
1557#define SET_FROM_FLAG(when, name, bitname, isolate_flag, flag) \
1558 FLAG_FOR_##when(isolate_group_flags_ = bitname##Bit::update( \
1559 api_flags.isolate_flag, isolate_group_flags_));
1560
1561 BOOL_ISOLATE_GROUP_FLAG_LIST(SET_FROM_FLAG)
1562 // Needs to be called manually, otherwise we don't set the null_safety_set
1563 // bit.
1564 set_null_safety(api_flags.null_safety);
1565#undef FLAG_FOR_NONPRODUCT
1566#undef FLAG_FOR_PRECOMPILER
1567#undef FLAG_FOR_PRODUCT
1568#undef SET_FROM_FLAG
1569}
1570
1571void Isolate::FlagsInitialize(Dart_IsolateFlags* api_flags) {
1572 IsolateGroup::FlagsInitialize(api_flags);
1573
1574 api_flags->version = DART_FLAGS_CURRENT_VERSION;
1575#define INIT_FROM_FLAG(when, name, bitname, isolate_flag, flag) \
1576 api_flags->isolate_flag = flag;
1577 BOOL_ISOLATE_FLAG_LIST(INIT_FROM_FLAG)
1578#undef INIT_FROM_FLAG
1579 api_flags->copy_parent_code = false;
1580}
1581
1582void Isolate::FlagsCopyTo(Dart_IsolateFlags* api_flags) const {
1583 group()->FlagsCopyTo(api_flags);
1584
1585 api_flags->version = DART_FLAGS_CURRENT_VERSION;
1586#define INIT_FROM_FIELD(when, name, bitname, isolate_flag, flag) \
1587 api_flags->isolate_flag = name();
1588 BOOL_ISOLATE_FLAG_LIST(INIT_FROM_FIELD)
1589#undef INIT_FROM_FIELD
1590 api_flags->copy_parent_code = false;
1591}
1592
1593void Isolate::FlagsCopyFrom(const Dart_IsolateFlags& api_flags) {
1594 const bool copy_parent_code_ = copy_parent_code();
1595#if defined(DART_PRECOMPILER)
1596#define FLAG_FOR_PRECOMPILER(action) action
1597#else
1598#define FLAG_FOR_PRECOMPILER(action)
1599#endif
1600
1601#if !defined(PRODUCT)
1602#define FLAG_FOR_NONPRODUCT(action) action
1603#else
1604#define FLAG_FOR_NONPRODUCT(action)
1605#endif
1606
1607#define FLAG_FOR_PRODUCT(action) action
1608
1609#define SET_FROM_FLAG(when, name, bitname, isolate_flag, flag) \
1610 FLAG_FOR_##when(isolate_flags_ = bitname##Bit::update( \
1611 api_flags.isolate_flag, isolate_flags_));
1612
1613 BOOL_ISOLATE_FLAG_LIST(SET_FROM_FLAG)
1614 isolate_flags_ = CopyParentCodeBit::update(value: copy_parent_code_, original: isolate_flags_);
1615#undef FLAG_FOR_NONPRODUCT
1616#undef FLAG_FOR_PRECOMPILER
1617#undef FLAG_FOR_PRODUCT
1618#undef SET_FROM_FLAG
1619}
1620
1621#if defined(DEBUG)
1622// static
1623void BaseIsolate::AssertCurrent(BaseIsolate* isolate) {
1624 ASSERT(isolate == Isolate::Current());
1625}
1626#endif // defined(DEBUG)
1627
1628#if defined(DEBUG)
1629#define REUSABLE_HANDLE_SCOPE_INIT(object) \
1630 reusable_##object##_handle_scope_active_(false),
1631#else
1632#define REUSABLE_HANDLE_SCOPE_INIT(object)
1633#endif // defined(DEBUG)
1634
1635#define REUSABLE_HANDLE_INITIALIZERS(object) object##_handle_(nullptr),
1636
1637class LibraryPrefixMapTraits {
1638 public:
1639 static bool ReportStats() { return false; }
1640 static const char* Name() { return "LibraryPrefixMapTraits"; }
1641
1642 static bool IsMatch(const Object& a, const Object& b) {
1643 if (!a.IsLibraryPrefix() || !b.IsLibraryPrefix()) {
1644 return false;
1645 }
1646 return a.ptr() == b.ptr();
1647 }
1648
1649 static uword Hash(const Object& obj) {
1650 auto& prefix = LibraryPrefix::Cast(obj);
1651 return String::Hash(raw: prefix.name());
1652 }
1653};
1654
1655// TODO(srdjan): Some Isolate monitors can be shared. Replace their usage with
1656// that shared monitor.
1657Isolate::Isolate(IsolateGroup* isolate_group,
1658 const Dart_IsolateFlags& api_flags)
1659 : BaseIsolate(),
1660 current_tag_(UserTag::null()),
1661 default_tag_(UserTag::null()),
1662 field_table_(new FieldTable(/*isolate=*/this)),
1663 finalizers_(GrowableObjectArray::null()),
1664 isolate_group_(isolate_group),
1665 isolate_object_store_(new IsolateObjectStore()),
1666 isolate_flags_(0),
1667#if !defined(PRODUCT)
1668 last_resume_timestamp_(OS::GetCurrentTimeMillis()),
1669 vm_tag_counters_(),
1670 pending_service_extension_calls_(GrowableObjectArray::null()),
1671 registered_service_extension_handlers_(GrowableObjectArray::null()),
1672#define ISOLATE_METRIC_CONSTRUCTORS(type, variable, name, unit) \
1673 metric_##variable##_(),
1674 ISOLATE_METRIC_LIST(ISOLATE_METRIC_CONSTRUCTORS)
1675#undef ISOLATE_METRIC_CONSTRUCTORS
1676#endif // !defined(PRODUCT)
1677 start_time_micros_(OS::GetCurrentMonotonicMicros()),
1678 message_notify_callback_(nullptr),
1679 on_shutdown_callback_(Isolate::ShutdownCallback()),
1680 on_cleanup_callback_(Isolate::CleanupCallback()),
1681 random_(),
1682 mutex_(NOT_IN_PRODUCT("Isolate::mutex_")),
1683 tag_table_(GrowableObjectArray::null()),
1684 sticky_error_(Error::null()),
1685 spawn_count_monitor_(),
1686 handler_info_cache_(),
1687 catch_entry_moves_cache_(),
1688 wake_pause_event_handler_count_(0),
1689 loaded_prefixes_set_storage_(nullptr) {
1690 FlagsCopyFrom(api_flags);
1691 SetErrorsFatal(true);
1692 // TODO(asiva): A Thread is not available here, need to figure out
1693 // how the vm_tag (kEmbedderTagId) can be set, these tags need to
1694 // move to the OSThread structure.
1695 set_user_tag(UserTags::kDefaultUserTag);
1696}
1697
1698#undef REUSABLE_HANDLE_SCOPE_INIT
1699#undef REUSABLE_HANDLE_INITIALIZERS
1700
1701Isolate::~Isolate() {
1702#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
1703 // TODO(32796): Re-enable assertion.
1704 // RELEASE_ASSERT(program_reload_context_ == nullptr);
1705#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
1706
1707#if !defined(PRODUCT)
1708 delete debugger_;
1709 debugger_ = nullptr;
1710 delete object_id_ring_;
1711 object_id_ring_ = nullptr;
1712 delete pause_loop_monitor_;
1713 pause_loop_monitor_ = nullptr;
1714#endif // !defined(PRODUCT)
1715
1716 free(ptr: name_);
1717 delete field_table_;
1718#if defined(USING_SIMULATOR)
1719 delete simulator_;
1720#endif
1721 delete message_handler_;
1722 message_handler_ =
1723 nullptr; // Fail fast if we send messages to a dead isolate.
1724 ASSERT(deopt_context_ ==
1725 nullptr); // No deopt in progress when isolate deleted.
1726 ASSERT(spawn_count_ == 0);
1727
1728 // The [Thread] object should've been released on the last
1729 // `Thread::ExitIsolate()` call.
1730 ASSERT(scheduled_mutator_thread_ == nullptr);
1731 ASSERT(mutator_thread_ == nullptr);
1732}
1733
1734void Isolate::InitVM() {
1735 create_group_callback_ = nullptr;
1736 initialize_callback_ = nullptr;
1737 shutdown_callback_ = nullptr;
1738 cleanup_callback_ = nullptr;
1739 cleanup_group_callback_ = nullptr;
1740 register_kernel_blob_callback_ = nullptr;
1741 unregister_kernel_blob_callback_ = nullptr;
1742 if (isolate_creation_monitor_ == nullptr) {
1743 isolate_creation_monitor_ = new Monitor();
1744 }
1745 ASSERT(isolate_creation_monitor_ != nullptr);
1746 EnableIsolateCreation();
1747}
1748
1749Isolate* Isolate::InitIsolate(const char* name_prefix,
1750 IsolateGroup* isolate_group,
1751 const Dart_IsolateFlags& api_flags,
1752 bool is_vm_isolate) {
1753 Isolate* result = new Isolate(isolate_group, api_flags);
1754 result->BuildName(name_prefix);
1755 if (!is_vm_isolate) {
1756 // vm isolate object store is initialized later, after null instance
1757 // is created (in Dart::Init).
1758 // Non-vm isolates need to have isolate object store initialized is that
1759 // exit_listeners have to be null-initialized as they will be used if
1760 // we fail to create isolate below, have to do low level shutdown.
1761 ASSERT(result->group()->object_store() != nullptr);
1762 result->isolate_object_store()->Init();
1763 }
1764
1765 ASSERT(result != nullptr);
1766
1767#if !defined(PRODUCT)
1768// Initialize metrics.
1769#define ISOLATE_METRIC_INIT(type, variable, name, unit) \
1770 result->metric_##variable##_.InitInstance(result, name, nullptr, \
1771 Metric::unit);
1772 ISOLATE_METRIC_LIST(ISOLATE_METRIC_INIT);
1773#undef ISOLATE_METRIC_INIT
1774#endif // !defined(PRODUCT)
1775
1776 // First we ensure we enter the isolate. This will ensure we're participating
1777 // in any safepointing requests from this point on. Other threads requesting a
1778 // safepoint operation will therefore wait until we've stopped.
1779 //
1780 // Though the [result] isolate is still in a state where no memory has been
1781 // allocated, which means it's safe to GC the isolate group until here.
1782 Thread::EnterIsolate(isolate: result);
1783
1784 // Setup the isolate message handler.
1785 MessageHandler* handler = new IsolateMessageHandler(result);
1786 ASSERT(handler != nullptr);
1787 result->set_message_handler(handler);
1788
1789 result->set_main_port(PortMap::CreatePort(handler: result->message_handler()));
1790#if defined(DEBUG)
1791 // Verify that we are never reusing a live origin id.
1792 VerifyOriginId id_verifier(result->main_port());
1793 Isolate::VisitIsolates(&id_verifier);
1794#endif
1795 result->set_origin_id(result->main_port());
1796
1797 // Keep capability IDs less than 2^53 so web clients of the service
1798 // protocol can process it properly.
1799 //
1800 // See https://github.com/dart-lang/sdk/issues/53081.
1801 result->set_pause_capability(result->random()->NextJSInt());
1802 result->set_terminate_capability(result->random()->NextJSInt());
1803
1804#if !defined(PRODUCT)
1805 result->debugger_ = new Debugger(result);
1806#endif
1807
1808 // Now we register the isolate in the group. From this point on any GC would
1809 // traverse the isolate roots (before this point, the roots are only pointing
1810 // to vm-isolate objects, e.g. null)
1811 isolate_group->RegisterIsolate(isolate: result);
1812
1813 if (ServiceIsolate::NameEquals(name: name_prefix)) {
1814 ASSERT(!ServiceIsolate::Exists());
1815 ServiceIsolate::SetServiceIsolate(result);
1816#if !defined(DART_PRECOMPILED_RUNTIME)
1817 } else if (KernelIsolate::NameEquals(name: name_prefix)) {
1818 ASSERT(!KernelIsolate::Exists());
1819 KernelIsolate::SetKernelIsolate(result);
1820#endif // !defined(DART_PRECOMPILED_RUNTIME)
1821 }
1822
1823 if (FLAG_trace_isolates) {
1824 if (name_prefix == nullptr || strcmp(s1: name_prefix, s2: "vm-isolate") != 0) {
1825 OS::PrintErr(
1826 format: "[+] Starting isolate:\n"
1827 "\tisolate: %s\n",
1828 result->name());
1829 }
1830 }
1831
1832 // Add to isolate list. Shutdown and delete the isolate on failure.
1833 if (!TryMarkIsolateReady(isolate: result)) {
1834 result->LowLevelShutdown();
1835 Isolate::LowLevelCleanup(isolate: result);
1836 return nullptr;
1837 }
1838
1839 return result;
1840}
1841
1842Thread* Isolate::mutator_thread() const {
1843 ASSERT(thread_registry() != nullptr);
1844 return mutator_thread_;
1845}
1846
1847ObjectPtr IsolateGroup::CallTagHandler(Dart_LibraryTag tag,
1848 const Object& arg1,
1849 const Object& arg2) {
1850 Thread* thread = Thread::Current();
1851 Api::Scope api_scope(thread);
1852 Dart_Handle api_arg1 = Api::NewHandle(thread, raw: arg1.ptr());
1853 Dart_Handle api_arg2 = Api::NewHandle(thread, raw: arg2.ptr());
1854 Dart_Handle api_result;
1855 {
1856 TransitionVMToNative transition(thread);
1857 ASSERT(HasTagHandler());
1858 api_result = library_tag_handler()(tag, api_arg1, api_arg2);
1859 }
1860 return Api::UnwrapHandle(object: api_result);
1861}
1862
1863ObjectPtr Isolate::CallDeferredLoadHandler(intptr_t id) {
1864 Thread* thread = Thread::Current();
1865 Api::Scope api_scope(thread);
1866 Dart_Handle api_result;
1867 {
1868 TransitionVMToNative transition(thread);
1869 RELEASE_ASSERT(HasDeferredLoadHandler());
1870 api_result = group()->deferred_load_handler()(id);
1871 }
1872 return Api::UnwrapHandle(object: api_result);
1873}
1874
1875void IsolateGroup::SetupImagePage(const uint8_t* image_buffer,
1876 bool is_executable) {
1877 Image image(image_buffer);
1878 heap()->SetupImagePage(pointer: image.object_start(), size: image.object_size(),
1879 is_executable);
1880}
1881
1882void Isolate::ScheduleInterrupts(uword interrupt_bits) {
1883 // We take the threads lock here to ensure that the mutator thread does not
1884 // exit the isolate while we are trying to schedule interrupts on it.
1885 MonitorLocker ml(group()->thread_registry()->threads_lock());
1886 Thread* mthread = mutator_thread();
1887 if (mthread != nullptr) {
1888 mthread->ScheduleInterrupts(interrupt_bits);
1889 }
1890}
1891
1892void Isolate::set_name(const char* name) {
1893 free(ptr: name_);
1894 name_ = Utils::StrDup(s: name);
1895}
1896
1897int64_t IsolateGroup::UptimeMicros() const {
1898 return OS::GetCurrentMonotonicMicros() - start_time_micros_;
1899}
1900
1901int64_t Isolate::UptimeMicros() const {
1902 return OS::GetCurrentMonotonicMicros() - start_time_micros_;
1903}
1904
1905Dart_Port Isolate::origin_id() {
1906 MutexLocker ml(&origin_id_mutex_);
1907 return origin_id_;
1908}
1909
1910void Isolate::set_origin_id(Dart_Port id) {
1911 MutexLocker ml(&origin_id_mutex_);
1912 ASSERT((id == main_port_ && origin_id_ == 0) || (origin_id_ == main_port_));
1913 origin_id_ = id;
1914}
1915
1916void Isolate::set_finalizers(const GrowableObjectArray& value) {
1917 finalizers_ = value.ptr();
1918}
1919
1920bool Isolate::IsPaused() const {
1921#if defined(PRODUCT)
1922 return false;
1923#else
1924 return (debugger_ != nullptr) && (debugger_->PauseEvent() != nullptr);
1925#endif // !defined(PRODUCT)
1926}
1927
1928ErrorPtr Isolate::PausePostRequest() {
1929#if !defined(PRODUCT)
1930 if (debugger_ == nullptr) {
1931 return Error::null();
1932 }
1933 ASSERT(!IsPaused());
1934 const Error& error = Error::Handle(ptr: debugger_->PausePostRequest());
1935 if (!error.IsNull()) {
1936 if (Thread::Current()->top_exit_frame_info() == 0) {
1937 return error.ptr();
1938 } else {
1939 Exceptions::PropagateError(error);
1940 UNREACHABLE();
1941 }
1942 }
1943#endif
1944 return Error::null();
1945}
1946
1947void Isolate::BuildName(const char* name_prefix) {
1948 ASSERT(name_ == nullptr);
1949 if (name_prefix == nullptr) {
1950 name_ = OS::SCreate(zone: nullptr, format: "isolate-%" Pd64 "", main_port());
1951 } else {
1952 name_ = Utils::StrDup(s: name_prefix);
1953 }
1954}
1955
1956#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
1957bool IsolateGroup::CanReload() {
1958 // We only call this method on the mutator thread. Normally the caller is
1959 // inside of the "reloadSources" service OOB message handler. Though
1960 // we also use it in the slow path of StackOverflowCheck in the artificial
1961 // --hot-reload-test-mode like flags.
1962 //
1963 // During reload itself we don't process OOB messages and don't execute Dart
1964 // code, so the caller should implicitly have a guarantee we're not reloading
1965 // already.
1966 RELEASE_ASSERT(!Thread::Current()->OwnsReloadSafepoint());
1967
1968 // We only allow reload to take place from the point on where the first
1969 // isolate within an isolate group has setup it's root library. From that
1970 // point on it's safe to perform hot-reload.
1971 auto thread = Thread::Current();
1972 if (object_store()->root_library() == Library::null()) {
1973 return false;
1974 }
1975
1976 // We only care about the current thread's [NoReloadScope]. If we're inside
1977 // one we cannot reload right now. Though if another isolate's mutator
1978 // thread is inside such a scope, the multi-isolate reload will simply wait
1979 // until it's out of that scope again.
1980 if (thread->no_reload_scope_depth_ != 0) {
1981 return false;
1982 }
1983
1984 return !IsolateGroup::IsSystemIsolateGroup(group: this) &&
1985 OSThread::Current()->HasStackHeadroom(headroom: 64 * KB);
1986}
1987
1988bool IsolateGroup::ReloadSources(JSONStream* js,
1989 bool force_reload,
1990 const char* root_script_url,
1991 const char* packages_url,
1992 bool dont_delete_reload_context) {
1993 ASSERT(!IsReloading());
1994
1995 // Ensure all isolates inside the isolate group are paused at a place where we
1996 // can safely do a reload.
1997 RELOAD_OPERATION_SCOPE(Thread::Current());
1998
1999 auto class_table = IsolateGroup::Current()->class_table();
2000 std::shared_ptr<IsolateGroupReloadContext> group_reload_context(
2001 new IsolateGroupReloadContext(this, class_table, js));
2002 group_reload_context_ = group_reload_context;
2003
2004 SetHasAttemptedReload(true);
2005 program_reload_context_ =
2006 new ProgramReloadContext(group_reload_context_, this);
2007 const bool success =
2008 group_reload_context_->Reload(force_reload, root_script_url, packages_url,
2009 /*kernel_buffer=*/nullptr,
2010 /*kernel_buffer_size=*/0);
2011 if (!dont_delete_reload_context) {
2012 DeleteReloadContext();
2013 }
2014 return success;
2015}
2016
2017bool IsolateGroup::ReloadKernel(JSONStream* js,
2018 bool force_reload,
2019 const uint8_t* kernel_buffer,
2020 intptr_t kernel_buffer_size,
2021 bool dont_delete_reload_context) {
2022 ASSERT(!IsReloading());
2023
2024 // Ensure all isolates inside the isolate group are paused at a place where we
2025 // can safely do a reload.
2026 RELOAD_OPERATION_SCOPE(Thread::Current());
2027
2028 auto class_table = IsolateGroup::Current()->class_table();
2029 std::shared_ptr<IsolateGroupReloadContext> group_reload_context(
2030 new IsolateGroupReloadContext(this, class_table, js));
2031 group_reload_context_ = group_reload_context;
2032
2033 SetHasAttemptedReload(true);
2034 program_reload_context_ =
2035 new ProgramReloadContext(group_reload_context_, this);
2036 const bool success = group_reload_context_->Reload(
2037 force_reload,
2038 /*root_script_url=*/nullptr,
2039 /*packages_url=*/nullptr, kernel_buffer, kernel_buffer_size);
2040 if (!dont_delete_reload_context) {
2041 DeleteReloadContext();
2042 }
2043 return success;
2044}
2045
2046void IsolateGroup::DeleteReloadContext() {
2047 GcSafepointOperationScope safepoint_scope(Thread::Current());
2048 group_reload_context_.reset();
2049
2050 delete program_reload_context_;
2051 program_reload_context_ = nullptr;
2052}
2053#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
2054
2055const char* Isolate::MakeRunnable() {
2056 MutexLocker ml(&mutex_);
2057 // Check if we are in a valid state to make the isolate runnable.
2058 if (is_runnable() == true) {
2059 return "Isolate is already runnable";
2060 }
2061 if (group()->object_store()->root_library() == Library::null()) {
2062 return "The embedder has to ensure there is a root library (e.g. by "
2063 "calling Dart_LoadScriptFromKernel ).";
2064 }
2065 MakeRunnableLocked();
2066 return nullptr;
2067}
2068
2069void Isolate::MakeRunnableLocked() {
2070 ASSERT(mutex_.IsOwnedByCurrentThread());
2071 ASSERT(!is_runnable());
2072 ASSERT(group()->object_store()->root_library() != Library::null());
2073
2074 // Set the isolate as runnable and if we are being spawned schedule
2075 // isolate on thread pool for execution.
2076 set_is_runnable(true);
2077#ifndef PRODUCT
2078 if (!Isolate::IsSystemIsolate(isolate: this)) {
2079 if (FLAG_pause_isolates_on_unhandled_exceptions) {
2080 debugger()->SetExceptionPauseInfo(kPauseOnUnhandledExceptions);
2081 }
2082 }
2083#endif // !PRODUCT
2084#if defined(SUPPORT_TIMELINE)
2085 TimelineStream* stream = Timeline::GetIsolateStream();
2086 ASSERT(stream != nullptr);
2087 TimelineEvent* event = stream->StartEvent();
2088 if (event != nullptr) {
2089 event->Instant(label: "Runnable");
2090 event->Complete();
2091 }
2092#endif
2093#ifndef PRODUCT
2094 if (!Isolate::IsSystemIsolate(isolate: this) && Service::isolate_stream.enabled()) {
2095 ServiceEvent runnableEvent(this, ServiceEvent::kIsolateRunnable);
2096 Service::HandleEvent(event: &runnableEvent, /* enter_safepoint */ false);
2097 }
2098 GetRunnableLatencyMetric()->set_value(UptimeMicros());
2099#endif // !PRODUCT
2100}
2101
2102bool Isolate::VerifyPauseCapability(const Object& capability) const {
2103 return !capability.IsNull() && capability.IsCapability() &&
2104 (pause_capability() == Capability::Cast(obj: capability).Id());
2105}
2106
2107bool Isolate::VerifyTerminateCapability(const Object& capability) const {
2108 return !capability.IsNull() && capability.IsCapability() &&
2109 (terminate_capability() == Capability::Cast(obj: capability).Id());
2110}
2111
2112bool Isolate::AddResumeCapability(const Capability& capability) {
2113 // Ensure a limit for the number of resume capabilities remembered.
2114 const intptr_t kMaxResumeCapabilities =
2115 compiler::target::kSmiMax / (6 * kWordSize);
2116
2117 const GrowableObjectArray& caps = GrowableObjectArray::Handle(
2118 zone: current_zone(), ptr: isolate_object_store()->resume_capabilities());
2119 Capability& current = Capability::Handle(zone: current_zone());
2120 intptr_t insertion_index = -1;
2121 for (intptr_t i = 0; i < caps.Length(); i++) {
2122 current ^= caps.At(index: i);
2123 if (current.IsNull()) {
2124 if (insertion_index < 0) {
2125 insertion_index = i;
2126 }
2127 } else if (current.Id() == capability.Id()) {
2128 return false;
2129 }
2130 }
2131 if (insertion_index < 0) {
2132 if (caps.Length() >= kMaxResumeCapabilities) {
2133 // Cannot grow the array of resume capabilities beyond its max. Additional
2134 // pause requests are ignored. In practice will never happen as we will
2135 // run out of memory beforehand.
2136 return false;
2137 }
2138 caps.Add(value: capability);
2139 } else {
2140 caps.SetAt(index: insertion_index, value: capability);
2141 }
2142 return true;
2143}
2144
2145bool Isolate::RemoveResumeCapability(const Capability& capability) {
2146 const GrowableObjectArray& caps = GrowableObjectArray::Handle(
2147 zone: current_zone(), ptr: isolate_object_store()->resume_capabilities());
2148 Capability& current = Capability::Handle(zone: current_zone());
2149 for (intptr_t i = 0; i < caps.Length(); i++) {
2150 current ^= caps.At(index: i);
2151 if (!current.IsNull() && (current.Id() == capability.Id())) {
2152 // Remove the matching capability from the list.
2153 current = Capability::null();
2154 caps.SetAt(index: i, value: current);
2155 return true;
2156 }
2157 }
2158 return false;
2159}
2160
2161// TODO(iposva): Remove duplicated code and start using some hash based
2162// structure instead of these linear lookups.
2163void Isolate::AddExitListener(const SendPort& listener,
2164 const Instance& response) {
2165 // Ensure a limit for the number of listeners remembered.
2166 const intptr_t kMaxListeners = compiler::target::kSmiMax / (12 * kWordSize);
2167
2168 const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
2169 zone: current_zone(), ptr: isolate_object_store()->exit_listeners());
2170 SendPort& current = SendPort::Handle(zone: current_zone());
2171 intptr_t insertion_index = -1;
2172 for (intptr_t i = 0; i < listeners.Length(); i += 2) {
2173 current ^= listeners.At(index: i);
2174 if (current.IsNull()) {
2175 if (insertion_index < 0) {
2176 insertion_index = i;
2177 }
2178 } else if (current.Id() == listener.Id()) {
2179 listeners.SetAt(index: i + 1, value: response);
2180 return;
2181 }
2182 }
2183 if (insertion_index < 0) {
2184 if (listeners.Length() >= kMaxListeners) {
2185 // Cannot grow the array of listeners beyond its max. Additional
2186 // listeners are ignored. In practice will never happen as we will
2187 // run out of memory beforehand.
2188 return;
2189 }
2190 listeners.Add(value: listener);
2191 listeners.Add(value: response);
2192 } else {
2193 listeners.SetAt(index: insertion_index, value: listener);
2194 listeners.SetAt(index: insertion_index + 1, value: response);
2195 }
2196}
2197
2198void Isolate::RemoveExitListener(const SendPort& listener) {
2199 const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
2200 zone: current_zone(), ptr: isolate_object_store()->exit_listeners());
2201 SendPort& current = SendPort::Handle(zone: current_zone());
2202 for (intptr_t i = 0; i < listeners.Length(); i += 2) {
2203 current ^= listeners.At(index: i);
2204 if (!current.IsNull() && (current.Id() == listener.Id())) {
2205 // Remove the matching listener from the list.
2206 current = SendPort::null();
2207 listeners.SetAt(index: i, value: current);
2208 listeners.SetAt(index: i + 1, value: Object::null_instance());
2209 return;
2210 }
2211 }
2212}
2213
2214void Isolate::NotifyExitListeners() {
2215 const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
2216 zone: current_zone(), ptr: isolate_object_store()->exit_listeners());
2217 if (listeners.IsNull()) return;
2218
2219 SendPort& listener = SendPort::Handle(zone: current_zone());
2220 Instance& response = Instance::Handle(zone: current_zone());
2221 for (intptr_t i = 0; i < listeners.Length(); i += 2) {
2222 listener ^= listeners.At(index: i);
2223 if (!listener.IsNull()) {
2224 Dart_Port port_id = listener.Id();
2225 response ^= listeners.At(index: i + 1);
2226 PortMap::PostMessage(message: SerializeMessage(dest_port: port_id, obj: response));
2227 }
2228 }
2229}
2230
2231void Isolate::AddErrorListener(const SendPort& listener) {
2232 // Ensure a limit for the number of listeners remembered.
2233 const intptr_t kMaxListeners = compiler::target::kSmiMax / (6 * kWordSize);
2234
2235 const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
2236 zone: current_zone(), ptr: isolate_object_store()->error_listeners());
2237 SendPort& current = SendPort::Handle(zone: current_zone());
2238 intptr_t insertion_index = -1;
2239 for (intptr_t i = 0; i < listeners.Length(); i++) {
2240 current ^= listeners.At(index: i);
2241 if (current.IsNull()) {
2242 if (insertion_index < 0) {
2243 insertion_index = i;
2244 }
2245 } else if (current.Id() == listener.Id()) {
2246 return;
2247 }
2248 }
2249 if (insertion_index < 0) {
2250 if (listeners.Length() >= kMaxListeners) {
2251 // Cannot grow the array of listeners beyond its max. Additional
2252 // listeners are ignored. In practice will never happen as we will
2253 // run out of memory beforehand.
2254 return;
2255 }
2256 listeners.Add(value: listener);
2257 } else {
2258 listeners.SetAt(index: insertion_index, value: listener);
2259 }
2260}
2261
2262void Isolate::RemoveErrorListener(const SendPort& listener) {
2263 const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
2264 zone: current_zone(), ptr: isolate_object_store()->error_listeners());
2265 SendPort& current = SendPort::Handle(zone: current_zone());
2266 for (intptr_t i = 0; i < listeners.Length(); i++) {
2267 current ^= listeners.At(index: i);
2268 if (!current.IsNull() && (current.Id() == listener.Id())) {
2269 // Remove the matching listener from the list.
2270 current = SendPort::null();
2271 listeners.SetAt(index: i, value: current);
2272 return;
2273 }
2274 }
2275}
2276
2277bool Isolate::NotifyErrorListeners(const char* message,
2278 const char* stacktrace) {
2279 const GrowableObjectArray& listeners = GrowableObjectArray::Handle(
2280 zone: current_zone(), ptr: isolate_object_store()->error_listeners());
2281 if (listeners.IsNull()) return false;
2282
2283 Dart_CObject arr;
2284 Dart_CObject* arr_values[2];
2285 arr.type = Dart_CObject_kArray;
2286 arr.value.as_array.length = 2;
2287 arr.value.as_array.values = arr_values;
2288 Dart_CObject msg;
2289 msg.type = Dart_CObject_kString;
2290 msg.value.as_string = const_cast<char*>(message);
2291 arr_values[0] = &msg;
2292 Dart_CObject stack;
2293 if (stacktrace == nullptr) {
2294 stack.type = Dart_CObject_kNull;
2295 } else {
2296 stack.type = Dart_CObject_kString;
2297 stack.value.as_string = const_cast<char*>(stacktrace);
2298 }
2299 arr_values[1] = &stack;
2300
2301 SendPort& listener = SendPort::Handle(zone: current_zone());
2302 for (intptr_t i = 0; i < listeners.Length(); i++) {
2303 listener ^= listeners.At(index: i);
2304 if (!listener.IsNull()) {
2305 Dart_Port port_id = listener.Id();
2306 PortMap::PostMessage(message: SerializeMessage(zone: current_zone(), dest_port: port_id, obj: &arr));
2307 }
2308 }
2309 return listeners.Length() > 0;
2310}
2311
2312static void ShutdownIsolate(uword parameter) {
2313 Dart_EnterIsolate(isolate: reinterpret_cast<Dart_Isolate>(parameter));
2314 Dart_ShutdownIsolate();
2315}
2316
2317void Isolate::SetStickyError(ErrorPtr sticky_error) {
2318 ASSERT(
2319 ((sticky_error_ == Error::null()) || (sticky_error == Error::null())) &&
2320 (sticky_error != sticky_error_));
2321 sticky_error_ = sticky_error;
2322}
2323
2324void Isolate::Run() {
2325 message_handler()->Run(pool: group()->thread_pool(), start_callback: nullptr, end_callback: ShutdownIsolate,
2326 data: reinterpret_cast<uword>(this));
2327}
2328
2329void Isolate::RunAndCleanupFinalizersOnShutdown() {
2330 if (finalizers_ == GrowableObjectArray::null()) return;
2331
2332 // Ensure we have a zone and handle scope so that we can call VM functions,
2333 // but we no longer allocate new heap objects.
2334 Thread* thread = Thread::Current();
2335 StackZone stack_zone(thread);
2336 HandleScope handle_scope(thread);
2337 NoSafepointScope no_safepoint_scope;
2338
2339 // Set live finalizers isolate to null, before deleting the message handler.
2340 const auto& finalizers =
2341 GrowableObjectArray::Handle(zone: stack_zone.GetZone(), ptr: finalizers_);
2342 if (!finalizers.IsNull()) {
2343 const intptr_t num_finalizers = finalizers.Length();
2344 auto& weak_reference = WeakReference::Handle(zone: stack_zone.GetZone());
2345 auto& finalizer = FinalizerBase::Handle(zone: stack_zone.GetZone());
2346 auto& current_entry = FinalizerEntry::Handle(zone: stack_zone.GetZone());
2347 auto& all_entries = Set::Handle(zone: stack_zone.GetZone());
2348 for (int i = 0; i < num_finalizers; i++) {
2349 weak_reference ^= finalizers.At(index: i);
2350 finalizer ^= weak_reference.target();
2351 if (!finalizer.IsNull()) {
2352 if (finalizer.isolate() == this) {
2353 if (FLAG_trace_finalizers) {
2354 THR_Print("Isolate %p Setting finalizer %p isolate to null\n", this,
2355 finalizer.ptr()->untag());
2356 }
2357 // Finalizer was not sent to another isolate with send and exit.
2358 finalizer.set_isolate(nullptr);
2359 } else {
2360 // TODO(http://dartbug.com/47777): Send and exit support.
2361 UNREACHABLE();
2362 }
2363
2364 if (finalizer.IsNativeFinalizer()) {
2365 // Immediately call native callback.
2366 const auto& native_finalizer = NativeFinalizer::Cast(obj: finalizer);
2367 all_entries = finalizer.all_entries();
2368 Set::Iterator iterator(all_entries);
2369 while (iterator.MoveNext()) {
2370 current_entry ^= iterator.CurrentKey();
2371 native_finalizer.RunCallback(entry: current_entry, trace_context: "Isolate shutdown");
2372 }
2373 }
2374 }
2375 }
2376 }
2377}
2378
2379void Isolate::LowLevelShutdown() {
2380 // Ensure we have a zone and handle scope so that we can call VM functions,
2381 // but we no longer allocate new heap objects.
2382 Thread* thread = Thread::Current();
2383 StackZone stack_zone(thread);
2384 HandleScope handle_scope(thread);
2385 NoSafepointScope no_safepoint_scope;
2386
2387 // Notify exit listeners that this isolate is shutting down.
2388 if (group()->object_store() != nullptr) {
2389 const Error& error = Error::Handle(ptr: thread->sticky_error());
2390 if (error.IsNull() || !error.IsUnwindError() ||
2391 UnwindError::Cast(obj: error).is_user_initiated()) {
2392 NotifyExitListeners();
2393 }
2394 }
2395
2396 // Close all the ports owned by this isolate.
2397 PortMap::ClosePorts(handler: message_handler());
2398
2399 // Fail fast if anybody tries to post any more messages to this isolate.
2400 delete message_handler();
2401 set_message_handler(nullptr);
2402
2403 // Clean up any synchronous FFI callbacks registered with this isolate. Skip
2404 // if this isolate never registered any.
2405 if (ffi_callback_list_head_ != nullptr) {
2406 FfiCallbackMetadata::Instance()->DeleteAllCallbacks(
2407 list_head: &ffi_callback_list_head_);
2408 }
2409
2410#if !defined(PRODUCT)
2411 if (FLAG_dump_megamorphic_stats) {
2412 MegamorphicCacheTable::PrintSizes(thread);
2413 }
2414 if (FLAG_dump_symbol_stats) {
2415 Symbols::DumpStats(isolate_group: group());
2416 }
2417 if (FLAG_trace_isolates) {
2418 group()->heap()->PrintSizes();
2419 OS::PrintErr(
2420 format: "[-] Stopping isolate:\n"
2421 "\tisolate: %s\n",
2422 name());
2423 }
2424 if (FLAG_print_metrics) {
2425 LogBlock lb;
2426 OS::PrintErr(format: "Printing metrics for %s\n", name());
2427#define ISOLATE_GROUP_METRIC_PRINT(type, variable, name, unit) \
2428 OS::PrintErr("%s\n", isolate_group_->Get##variable##Metric()->ToString());
2429 ISOLATE_GROUP_METRIC_LIST(ISOLATE_GROUP_METRIC_PRINT)
2430#undef ISOLATE_GROUP_METRIC_PRINT
2431#define ISOLATE_METRIC_PRINT(type, variable, name, unit) \
2432 OS::PrintErr("%s\n", metric_##variable##_.ToString());
2433 ISOLATE_METRIC_LIST(ISOLATE_METRIC_PRINT)
2434#undef ISOLATE_METRIC_PRINT
2435 OS::PrintErr(format: "\n");
2436 }
2437#endif // !defined(PRODUCT)
2438}
2439
2440#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
2441void IsolateGroup::MaybeIncreaseReloadEveryNStackOverflowChecks() {
2442 if (FLAG_reload_every_back_off) {
2443 if (reload_every_n_stack_overflow_checks_ < 5000) {
2444 reload_every_n_stack_overflow_checks_ += 99;
2445 } else {
2446 const auto old_value = reload_every_n_stack_overflow_checks_;
2447 reload_every_n_stack_overflow_checks_ = old_value * old_value;
2448 }
2449 // Cap the value.
2450 if (reload_every_n_stack_overflow_checks_ > 1000000) {
2451 reload_every_n_stack_overflow_checks_ = 1000000;
2452 }
2453 }
2454}
2455#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
2456
2457void Isolate::set_forward_table_new(WeakTable* table) {
2458 std::unique_ptr<WeakTable> value(table);
2459 forward_table_new_ = std::move(value);
2460}
2461void Isolate::set_forward_table_old(WeakTable* table) {
2462 std::unique_ptr<WeakTable> value(table);
2463 forward_table_old_ = std::move(value);
2464}
2465
2466void Isolate::Shutdown() {
2467 Thread* thread = Thread::Current();
2468 ASSERT(this == thread->isolate());
2469
2470 // Don't allow anymore dart code to execution on this isolate.
2471 thread->ClearStackLimit();
2472
2473 {
2474 StackZone zone(thread);
2475 ServiceIsolate::SendIsolateShutdownMessage();
2476#if !defined(PRODUCT)
2477 HandleScope handle_scope(thread);
2478 debugger()->Shutdown();
2479 Profiler::IsolateShutdown(thread);
2480#endif
2481 }
2482
2483#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
2484 if (FLAG_check_reloaded && is_runnable() && !Isolate::IsSystemIsolate(isolate: this)) {
2485 if (!group()->HasAttemptedReload()) {
2486 FATAL(
2487 "Isolate did not reload before exiting and "
2488 "--check-reloaded is enabled.\n");
2489 }
2490 }
2491#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
2492
2493 // Then, proceed with low-level teardown.
2494 Isolate::UnMarkIsolateReady(isolate: this);
2495
2496 // Ensure native finalizers are run before isolate has shutdown message is
2497 // sent. This way users can rely on the exit message that an isolate will not
2498 // run any Dart code anymore _and_ will not run any native finalizers anymore.
2499 RunAndCleanupFinalizersOnShutdown();
2500
2501 // Post message before LowLevelShutdown that sends onExit message.
2502 // This ensures that exit message comes last.
2503 if (bequest_ != nullptr) {
2504 auto beneficiary = bequest_->beneficiary();
2505 auto handle = bequest_->TakeHandle();
2506 PortMap::PostMessage(
2507 message: Message::New(args&: beneficiary, args&: handle, args: Message::kNormalPriority));
2508 bequest_.reset();
2509 }
2510
2511 LowLevelShutdown();
2512
2513 // Now we can unregister from the thread, invoke cleanup callback, delete the
2514 // isolate (and possibly the isolate group).
2515 Isolate::LowLevelCleanup(isolate: this);
2516}
2517
2518void Isolate::LowLevelCleanup(Isolate* isolate) {
2519#if !defined(DART_PRECOMPILED_RUNTIME)
2520 if (KernelIsolate::IsKernelIsolate(isolate)) {
2521 KernelIsolate::SetKernelIsolate(nullptr);
2522 }
2523#endif
2524 if (ServiceIsolate::IsServiceIsolate(isolate)) {
2525 ServiceIsolate::SetServiceIsolate(nullptr);
2526 }
2527
2528 // Cache these two fields, since they are no longer available after the
2529 // `delete isolate` further down.
2530 IsolateGroup* isolate_group = isolate->isolate_group_;
2531 Dart_IsolateCleanupCallback cleanup = isolate->on_cleanup_callback();
2532 auto callback_data = isolate->init_callback_data_;
2533
2534 // From this point on the isolate is no longer visited by GC (which is ok,
2535 // since we're just going to delete it anyway).
2536 isolate_group->UnregisterIsolate(isolate);
2537
2538 // From this point on the isolate doesn't participate in safepointing
2539 // requests anymore.
2540 ASSERT(!Thread::Current()->HasActiveState());
2541 Thread::ExitIsolate(/*isolate_shutdown=*/true);
2542
2543 // Now it's safe to delete the isolate.
2544 delete isolate;
2545
2546 // Run isolate specific cleanup function for all non "vm-isolate's.
2547 const bool is_vm_isolate = Dart::vm_isolate() == isolate;
2548 if (!is_vm_isolate) {
2549 if (cleanup != nullptr) {
2550 cleanup(isolate_group->embedder_data(), callback_data);
2551 }
2552 }
2553
2554 const bool shutdown_group = isolate_group->UnregisterIsolateDecrementCount();
2555 if (shutdown_group) {
2556 KernelIsolate::NotifyAboutIsolateGroupShutdown(isolate_group);
2557
2558 if (!is_vm_isolate) {
2559 Thread::EnterIsolateGroupAsHelper(isolate_group, kind: Thread::kUnknownTask,
2560 /*bypass_safepoint=*/false);
2561#if !defined(DART_PRECOMPILED_RUNTIME)
2562 BackgroundCompiler::Stop(isolate_group);
2563#endif // !defined(DART_PRECOMPILED_RUNTIME)
2564
2565 // Finalize any weak persistent handles with a non-null referent with
2566 // isolate group still being available.
2567 FinalizeWeakPersistentHandlesVisitor visitor(isolate_group);
2568 isolate_group->api_state()->VisitWeakHandlesUnlocked(visitor: &visitor);
2569
2570 Thread::ExitIsolateGroupAsHelper(/*bypass_safepoint=*/false);
2571 }
2572
2573 // The "vm-isolate" does not have a thread pool.
2574 ASSERT(is_vm_isolate == (isolate_group->thread_pool() == nullptr));
2575 if (is_vm_isolate ||
2576 !isolate_group->thread_pool()->CurrentThreadIsWorker()) {
2577 isolate_group->Shutdown();
2578 } else {
2579 class ShutdownGroupTask : public ThreadPool::Task {
2580 public:
2581 explicit ShutdownGroupTask(IsolateGroup* isolate_group)
2582 : isolate_group_(isolate_group) {}
2583
2584 virtual void Run() { isolate_group_->Shutdown(); }
2585
2586 private:
2587 IsolateGroup* isolate_group_;
2588 };
2589 // The current thread is running on the isolate group's thread pool.
2590 // So we cannot safely delete the isolate group (and it's pool).
2591 // Instead we will destroy the isolate group on the VM-global pool.
2592 if (FLAG_trace_shutdown) {
2593 OS::PrintErr(format: "[+%" Pd64 "ms] : Scheduling shutdown on VM pool %s\n",
2594 Dart::UptimeMillis(), isolate_group->source()->name);
2595 }
2596 Dart::thread_pool()->Run<ShutdownGroupTask>(args&: isolate_group);
2597 }
2598 } else {
2599 // TODO(dartbug.com/36097): An isolate just died. A significant amount of
2600 // memory might have become unreachable. We should evaluate how to best
2601 // inform the GC about this situation.
2602 }
2603}
2604
2605Dart_InitializeIsolateCallback Isolate::initialize_callback_ = nullptr;
2606Dart_IsolateGroupCreateCallback Isolate::create_group_callback_ = nullptr;
2607Dart_IsolateShutdownCallback Isolate::shutdown_callback_ = nullptr;
2608Dart_IsolateCleanupCallback Isolate::cleanup_callback_ = nullptr;
2609Dart_IsolateGroupCleanupCallback Isolate::cleanup_group_callback_ = nullptr;
2610Dart_RegisterKernelBlobCallback Isolate::register_kernel_blob_callback_ =
2611 nullptr;
2612Dart_UnregisterKernelBlobCallback Isolate::unregister_kernel_blob_callback_ =
2613 nullptr;
2614
2615Random* IsolateGroup::isolate_group_random_ = nullptr;
2616Monitor* Isolate::isolate_creation_monitor_ = nullptr;
2617bool Isolate::creation_enabled_ = false;
2618
2619RwLock* IsolateGroup::isolate_groups_rwlock_ = nullptr;
2620IntrusiveDList<IsolateGroup>* IsolateGroup::isolate_groups_ = nullptr;
2621
2622void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor,
2623 ValidationPolicy validate_frames) {
2624 ASSERT(visitor != nullptr);
2625
2626 // Visit objects in the field table.
2627 // N.B.: The heap snapshot writer requires visiting the field table first, so
2628 // that the pointer visitation order aligns with order of field name metadata.
2629 if (!visitor->trace_values_through_fields()) {
2630 field_table()->VisitObjectPointers(visitor);
2631 }
2632
2633 // Visit objects in the isolate object store.
2634 if (isolate_object_store() != nullptr) {
2635 isolate_object_store()->VisitObjectPointers(visitor);
2636 }
2637
2638 visitor->clear_gc_root_type();
2639 // Visit the objects directly referenced from the isolate structure.
2640 visitor->VisitPointer(p: reinterpret_cast<ObjectPtr*>(&current_tag_));
2641 visitor->VisitPointer(p: reinterpret_cast<ObjectPtr*>(&default_tag_));
2642 visitor->VisitPointer(p: reinterpret_cast<ObjectPtr*>(&tag_table_));
2643 visitor->VisitPointer(p: reinterpret_cast<ObjectPtr*>(&sticky_error_));
2644 visitor->VisitPointer(p: reinterpret_cast<ObjectPtr*>(&finalizers_));
2645#if !defined(PRODUCT)
2646 visitor->VisitPointer(
2647 p: reinterpret_cast<ObjectPtr*>(&pending_service_extension_calls_));
2648 visitor->VisitPointer(
2649 p: reinterpret_cast<ObjectPtr*>(&registered_service_extension_handlers_));
2650#endif // !defined(PRODUCT)
2651
2652#if !defined(PRODUCT)
2653 // Visit objects in the debugger.
2654 if (debugger() != nullptr) {
2655 debugger()->VisitObjectPointers(visitor);
2656 }
2657 if (ServiceIsolate::IsServiceIsolate(isolate: this)) {
2658 ServiceIsolate::VisitObjectPointers(visitor);
2659 }
2660#endif // !defined(PRODUCT)
2661
2662#if !defined(DART_PRECOMPILED_RUNTIME)
2663 // Visit objects that are being used for deoptimization.
2664 if (deopt_context() != nullptr) {
2665 deopt_context()->VisitObjectPointers(visitor);
2666 }
2667#endif // !defined(DART_PRECOMPILED_RUNTIME)
2668
2669 visitor->VisitPointer(
2670 p: reinterpret_cast<ObjectPtr*>(&loaded_prefixes_set_storage_));
2671
2672 if (pointers_to_verify_at_exit_.length() != 0) {
2673 visitor->VisitPointers(p: &pointers_to_verify_at_exit_[0],
2674 len: pointers_to_verify_at_exit_.length());
2675 }
2676}
2677
2678void Isolate::VisitStackPointers(ObjectPointerVisitor* visitor,
2679 ValidationPolicy validate_frames) {
2680 if (mutator_thread_ != nullptr) {
2681 mutator_thread_->VisitObjectPointers(visitor, validate_frames);
2682 }
2683}
2684
2685void IsolateGroup::ReleaseStoreBuffers() {
2686 thread_registry()->ReleaseStoreBuffers();
2687}
2688
2689void Isolate::RememberLiveTemporaries() {
2690 if (mutator_thread_ != nullptr) {
2691 mutator_thread_->RememberLiveTemporaries();
2692 }
2693}
2694
2695void Isolate::DeferredMarkLiveTemporaries() {
2696 if (mutator_thread_ != nullptr) {
2697 mutator_thread_->DeferredMarkLiveTemporaries();
2698 }
2699}
2700
2701void Isolate::init_loaded_prefixes_set_storage() {
2702 ASSERT(loaded_prefixes_set_storage_ == nullptr);
2703 loaded_prefixes_set_storage_ =
2704 HashTables::New<UnorderedHashSet<LibraryPrefixMapTraits> >(initial_capacity: 4);
2705}
2706
2707bool Isolate::IsPrefixLoaded(const LibraryPrefix& prefix) const {
2708 UnorderedHashSet<LibraryPrefixMapTraits> loaded_prefixes_set(
2709 loaded_prefixes_set_storage_);
2710 bool result = loaded_prefixes_set.GetOrNull(key: prefix) != Object::null();
2711 loaded_prefixes_set.Release();
2712 return result;
2713}
2714
2715void Isolate::SetPrefixIsLoaded(const LibraryPrefix& prefix) {
2716 UnorderedHashSet<LibraryPrefixMapTraits> loaded_prefixes_set(
2717 loaded_prefixes_set_storage_);
2718 loaded_prefixes_set.InsertOrGet(key: prefix);
2719 loaded_prefixes_set_storage_ = loaded_prefixes_set.Release().ptr();
2720}
2721
2722void IsolateGroup::EnableIncrementalBarrier(
2723 MarkingStack* marking_stack,
2724 MarkingStack* deferred_marking_stack) {
2725 ASSERT(marking_stack_ == nullptr);
2726 marking_stack_ = marking_stack;
2727 deferred_marking_stack_ = deferred_marking_stack;
2728 thread_registry()->AcquireMarkingStacks();
2729 ASSERT(Thread::Current()->is_marking());
2730}
2731
2732void IsolateGroup::DisableIncrementalBarrier() {
2733 thread_registry()->ReleaseMarkingStacks();
2734 ASSERT(marking_stack_ != nullptr);
2735 marking_stack_ = nullptr;
2736 deferred_marking_stack_ = nullptr;
2737}
2738
2739void IsolateGroup::ForEachIsolate(
2740 std::function<void(Isolate* isolate)> function,
2741 bool at_safepoint) {
2742 auto thread = Thread::Current();
2743 if (at_safepoint) {
2744 ASSERT(thread->OwnsSafepoint() ||
2745 (thread->task_kind() == Thread::kMutatorTask) ||
2746 (thread->task_kind() == Thread::kMarkerTask) ||
2747 (thread->task_kind() == Thread::kCompactorTask) ||
2748 (thread->task_kind() == Thread::kScavengerTask));
2749 for (Isolate* isolate : isolates_) {
2750 function(isolate);
2751 }
2752 return;
2753 }
2754 if (thread != nullptr && thread->OwnsSafepoint()) {
2755 for (Isolate* isolate : isolates_) {
2756 function(isolate);
2757 }
2758 return;
2759 }
2760 SafepointReadRwLocker ml(thread, isolates_lock_.get());
2761 for (Isolate* isolate : isolates_) {
2762 function(isolate);
2763 }
2764}
2765
2766Isolate* IsolateGroup::FirstIsolate() const {
2767 SafepointReadRwLocker ml(Thread::Current(), isolates_lock_.get());
2768 return FirstIsolateLocked();
2769}
2770
2771Isolate* IsolateGroup::FirstIsolateLocked() const {
2772 return isolates_.IsEmpty() ? nullptr : isolates_.First();
2773}
2774
2775void IsolateGroup::RunWithStoppedMutatorsCallable(
2776 Callable* single_current_mutator,
2777 Callable* otherwise,
2778 bool use_force_growth_in_otherwise) {
2779 auto thread = Thread::Current();
2780 StoppedMutatorsScope stopped_mutators_scope(thread);
2781
2782 if (thread->OwnsSafepoint()) {
2783 RELEASE_ASSERT(thread->OwnsSafepoint());
2784 single_current_mutator->Call();
2785 return;
2786 }
2787
2788 {
2789 SafepointReadRwLocker ml(thread, isolates_lock_.get());
2790 if (thread->IsDartMutatorThread() && ContainsOnlyOneIsolate()) {
2791 single_current_mutator->Call();
2792 return;
2793 }
2794 }
2795
2796 // We use the more strict safepoint operation scope here (which ensures that
2797 // all other threads, including auxiliary threads are at a safepoint), even
2798 // though we only need to ensure that the mutator threads are stopped.
2799 if (use_force_growth_in_otherwise) {
2800 ForceGrowthSafepointOperationScope safepoint_scope(
2801 thread, SafepointLevel::kGCAndDeopt);
2802 otherwise->Call();
2803 } else {
2804 DeoptSafepointOperationScope safepoint_scope(thread);
2805 otherwise->Call();
2806 }
2807}
2808
2809void IsolateGroup::VisitObjectPointers(ObjectPointerVisitor* visitor,
2810 ValidationPolicy validate_frames) {
2811 VisitSharedPointers(visitor);
2812 for (Isolate* isolate : isolates_) {
2813 isolate->VisitObjectPointers(visitor, validate_frames);
2814 }
2815 VisitStackPointers(visitor, validate_frames);
2816}
2817
2818void IsolateGroup::VisitSharedPointers(ObjectPointerVisitor* visitor) {
2819 // Visit objects in the class table.
2820 class_table()->VisitObjectPointers(visitor);
2821 if (heap_walk_class_table() != class_table()) {
2822 heap_walk_class_table()->VisitObjectPointers(visitor);
2823 }
2824 api_state()->VisitObjectPointersUnlocked(visitor);
2825 // Visit objects in the object store.
2826 if (object_store() != nullptr) {
2827 object_store()->VisitObjectPointers(visitor);
2828 }
2829 visitor->VisitPointer(p: reinterpret_cast<ObjectPtr*>(&saved_unlinked_calls_));
2830 initial_field_table()->VisitObjectPointers(visitor);
2831
2832 // Visit the boxed_field_list_.
2833 // 'boxed_field_list_' access via mutator and background compilation threads
2834 // is guarded with a monitor. This means that we can visit it only
2835 // when at safepoint or the field_list_mutex_ lock has been taken.
2836 visitor->VisitPointer(p: reinterpret_cast<ObjectPtr*>(&boxed_field_list_));
2837
2838 NOT_IN_PRECOMPILED(background_compiler()->VisitPointers(visitor));
2839
2840#if !defined(PRODUCT)
2841 if (debugger() != nullptr) {
2842 debugger()->VisitObjectPointers(visitor);
2843 }
2844#endif
2845
2846#if !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
2847 // Visit objects that are being used for isolate reload.
2848 if (program_reload_context() != nullptr) {
2849 program_reload_context()->VisitObjectPointers(visitor);
2850 program_reload_context()->group_reload_context()->VisitObjectPointers(
2851 visitor);
2852 }
2853#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
2854
2855 if (source()->loaded_blobs_ != nullptr) {
2856 visitor->VisitPointer(
2857 p: reinterpret_cast<ObjectPtr*>(&(source()->loaded_blobs_)));
2858 }
2859
2860 if (become() != nullptr) {
2861 become()->VisitObjectPointers(visitor);
2862 }
2863}
2864
2865void IsolateGroup::VisitStackPointers(ObjectPointerVisitor* visitor,
2866 ValidationPolicy validate_frames) {
2867 visitor->set_gc_root_type("stack");
2868
2869 // Visit objects in all threads (e.g. Dart stack, handles in zones), except
2870 // for the mutator threads themselves.
2871 thread_registry()->VisitObjectPointers(isolate_group_of_interest: this, visitor, validate_frames);
2872
2873 for (Isolate* isolate : isolates_) {
2874 // Visit mutator thread, even if the isolate isn't entered/scheduled
2875 // (there might be live API handles to visit).
2876 isolate->VisitStackPointers(visitor, validate_frames);
2877 }
2878
2879 visitor->clear_gc_root_type();
2880}
2881
2882void IsolateGroup::VisitObjectIdRingPointers(ObjectPointerVisitor* visitor) {
2883#if !defined(PRODUCT)
2884 for (Isolate* isolate : isolates_) {
2885 ObjectIdRing* ring = isolate->object_id_ring();
2886 if (ring != nullptr) {
2887 ring->VisitPointers(visitor);
2888 }
2889 }
2890#endif // !defined(PRODUCT)
2891}
2892
2893void IsolateGroup::VisitWeakPersistentHandles(HandleVisitor* visitor) {
2894 api_state()->VisitWeakHandlesUnlocked(visitor);
2895}
2896
2897void IsolateGroup::DeferredMarkLiveTemporaries() {
2898 ForEachIsolate(
2899 function: [&](Isolate* isolate) { isolate->DeferredMarkLiveTemporaries(); },
2900 /*at_safepoint=*/true);
2901}
2902
2903void IsolateGroup::RememberLiveTemporaries() {
2904 ForEachIsolate(function: [&](Isolate* isolate) { isolate->RememberLiveTemporaries(); },
2905 /*at_safepoint=*/true);
2906}
2907
2908#if !defined(PRODUCT)
2909ObjectIdRing* Isolate::EnsureObjectIdRing() {
2910 if (object_id_ring_ == nullptr) {
2911 object_id_ring_ = new ObjectIdRing();
2912 }
2913 return object_id_ring_;
2914}
2915#endif // !defined(PRODUCT)
2916
2917#ifndef PRODUCT
2918static const char* ExceptionPauseInfoToServiceEnum(Dart_ExceptionPauseInfo pi) {
2919 switch (pi) {
2920 case kPauseOnAllExceptions:
2921 return "All";
2922 case kNoPauseOnExceptions:
2923 return "None";
2924 case kPauseOnUnhandledExceptions:
2925 return "Unhandled";
2926 default:
2927 UNIMPLEMENTED();
2928 return nullptr;
2929 }
2930}
2931
2932static ServiceEvent IsolatePauseEvent(Isolate* isolate) {
2933 if (!isolate->is_runnable()) {
2934 // Isolate is not yet runnable.
2935 ASSERT((isolate->debugger() == nullptr) ||
2936 (isolate->debugger()->PauseEvent() == nullptr));
2937 return ServiceEvent(isolate, ServiceEvent::kNone);
2938 } else if (isolate->message_handler()->should_pause_on_start()) {
2939 if (isolate->message_handler()->is_paused_on_start()) {
2940 ASSERT((isolate->debugger() == nullptr) ||
2941 (isolate->debugger()->PauseEvent() == nullptr));
2942 return ServiceEvent(isolate, ServiceEvent::kPauseStart);
2943 } else {
2944 // Isolate is runnable but not paused on start.
2945 // Some service clients get confused if they see:
2946 // NotRunnable -> Runnable -> PausedAtStart
2947 // Treat Runnable+ShouldPauseOnStart as NotRunnable so they see:
2948 // NonRunnable -> PausedAtStart
2949 // The should_pause_on_start flag is set to false after resume.
2950 ASSERT((isolate->debugger() == nullptr) ||
2951 (isolate->debugger()->PauseEvent() == nullptr));
2952 return ServiceEvent(isolate, ServiceEvent::kNone);
2953 }
2954 } else if (isolate->message_handler()->is_paused_on_exit() &&
2955 ((isolate->debugger() == nullptr) ||
2956 (isolate->debugger()->PauseEvent() == nullptr))) {
2957 return ServiceEvent(isolate, ServiceEvent::kPauseExit);
2958 } else if ((isolate->debugger() != nullptr) &&
2959 (isolate->debugger()->PauseEvent() != nullptr) &&
2960 !isolate->ResumeRequest()) {
2961 return *(isolate->debugger()->PauseEvent());
2962 } else {
2963 ServiceEvent pause_event(isolate, ServiceEvent::kResume);
2964
2965 if (isolate->debugger() != nullptr) {
2966 // TODO(turnidge): Don't compute a full stack trace.
2967 DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
2968 if (stack->Length() > 0) {
2969 pause_event.set_top_frame(stack->FrameAt(i: 0));
2970 }
2971 }
2972
2973 return pause_event;
2974 }
2975}
2976
2977void Isolate::PrintJSON(JSONStream* stream, bool ref) {
2978 JSONObject jsobj(stream);
2979 jsobj.AddProperty(name: "type", s: (ref ? "@Isolate" : "Isolate"));
2980 jsobj.AddServiceId(ISOLATE_SERVICE_ID_FORMAT_STRING,
2981 static_cast<int64_t>(main_port()));
2982
2983 jsobj.AddProperty(name: "name", s: name());
2984 jsobj.AddPropertyF(name: "number", format: "%" Pd64 "", static_cast<int64_t>(main_port()));
2985 jsobj.AddProperty(name: "isSystemIsolate", b: is_system_isolate());
2986 jsobj.AddPropertyF(name: "isolateGroupId", ISOLATE_GROUP_SERVICE_ID_FORMAT_STRING,
2987 group()->id());
2988 if (ref) {
2989 return;
2990 }
2991 jsobj.AddPropertyF(name: "_originNumber", format: "%" Pd64 "",
2992 static_cast<int64_t>(origin_id()));
2993 int64_t uptime_millis = UptimeMicros() / kMicrosecondsPerMillisecond;
2994 int64_t start_time = OS::GetCurrentTimeMillis() - uptime_millis;
2995 jsobj.AddPropertyTimeMillis(name: "startTime", millis: start_time);
2996 {
2997 JSONObject jsheap(&jsobj, "_heaps");
2998 group()->heap()->PrintToJSONObject(space: Heap::kNew, object: &jsheap);
2999 group()->heap()->PrintToJSONObject(space: Heap::kOld, object: &jsheap);
3000 }
3001
3002 {
3003// Stringification macros
3004// See https://gcc.gnu.org/onlinedocs/gcc-4.8.5/cpp/Stringification.html
3005#define TO_STRING(s) STR(s)
3006#define STR(s) #s
3007
3008#define ADD_ISOLATE_FLAGS(when, name, bitname, isolate_flag_name, flag_name) \
3009 { \
3010 JSONObject jsflag(&jsflags); \
3011 jsflag.AddProperty("name", TO_STRING(name)); \
3012 jsflag.AddProperty("valueAsString", name() ? "true" : "false"); \
3013 }
3014 JSONArray jsflags(&jsobj, "isolateFlags");
3015 BOOL_ISOLATE_FLAG_LIST(ADD_ISOLATE_FLAGS)
3016#undef ADD_ISOLATE_FLAGS
3017#undef TO_STRING
3018#undef STR
3019 }
3020
3021 jsobj.AddProperty(name: "runnable", b: is_runnable());
3022 jsobj.AddProperty(name: "livePorts", i: message_handler()->live_ports());
3023 jsobj.AddProperty(name: "pauseOnExit", b: message_handler()->should_pause_on_exit());
3024#if !defined(DART_PRECOMPILED_RUNTIME)
3025 jsobj.AddProperty(name: "_isReloading", b: group()->IsReloading());
3026#endif // !defined(DART_PRECOMPILED_RUNTIME)
3027
3028 ServiceEvent pause_event = IsolatePauseEvent(isolate: this);
3029 jsobj.AddProperty(name: "pauseEvent", event: &pause_event);
3030
3031 const Library& lib = Library::Handle(ptr: group()->object_store()->root_library());
3032 if (!lib.IsNull()) {
3033 jsobj.AddProperty(name: "rootLib", obj: lib);
3034 }
3035
3036 if (FLAG_profiler) {
3037 JSONObject tagCounters(&jsobj, "_tagCounters");
3038 vm_tag_counters()->PrintToJSONObject(obj: &tagCounters);
3039 }
3040 if (Thread::Current()->sticky_error() != Object::null()) {
3041 Error& error = Error::Handle(ptr: Thread::Current()->sticky_error());
3042 ASSERT(!error.IsNull());
3043 jsobj.AddProperty(name: "error", obj: error, ref: false);
3044 } else if (sticky_error() != Object::null()) {
3045 Error& error = Error::Handle(ptr: sticky_error());
3046 ASSERT(!error.IsNull());
3047 jsobj.AddProperty(name: "error", obj: error, ref: false);
3048 }
3049
3050 {
3051 const GrowableObjectArray& libs =
3052 GrowableObjectArray::Handle(ptr: group()->object_store()->libraries());
3053 intptr_t num_libs = libs.Length();
3054 Library& lib = Library::Handle();
3055
3056 JSONArray lib_array(&jsobj, "libraries");
3057 for (intptr_t i = 0; i < num_libs; i++) {
3058 lib ^= libs.At(index: i);
3059 ASSERT(!lib.IsNull());
3060 lib_array.AddValue(obj: lib);
3061 }
3062 }
3063
3064 {
3065 JSONArray breakpoints(&jsobj, "breakpoints");
3066 if (debugger() != nullptr) {
3067 debugger()->PrintBreakpointsToJSONArray(jsarr: &breakpoints);
3068 }
3069 }
3070
3071 Dart_ExceptionPauseInfo pause_info = (debugger() != nullptr)
3072 ? debugger()->GetExceptionPauseInfo()
3073 : kNoPauseOnExceptions;
3074 jsobj.AddProperty(name: "exceptionPauseMode",
3075 s: ExceptionPauseInfoToServiceEnum(pi: pause_info));
3076
3077 if (debugger() != nullptr) {
3078 JSONObject settings(&jsobj, "_debuggerSettings");
3079 debugger()->PrintSettingsToJSONObject(jsobj: &settings);
3080 }
3081
3082 {
3083 GrowableObjectArray& handlers =
3084 GrowableObjectArray::Handle(ptr: registered_service_extension_handlers());
3085 if (!handlers.IsNull()) {
3086 JSONArray extensions(&jsobj, "extensionRPCs");
3087 String& handler_name = String::Handle();
3088 for (intptr_t i = 0; i < handlers.Length(); i += kRegisteredEntrySize) {
3089 handler_name ^= handlers.At(index: i + kRegisteredNameIndex);
3090 extensions.AddValue(s: handler_name.ToCString());
3091 }
3092 }
3093 }
3094
3095 {
3096 JSONObject isolate_group(&jsobj, "isolate_group");
3097 group()->PrintToJSONObject(jsobj: &isolate_group, /*ref=*/true);
3098 }
3099}
3100
3101void Isolate::PrintMemoryUsageJSON(JSONStream* stream) {
3102 group()->heap()->PrintMemoryUsageJSON(stream);
3103}
3104
3105void Isolate::PrintPauseEventJSON(JSONStream* stream) {
3106 IsolatePauseEvent(isolate: this).PrintJSON(js: stream);
3107}
3108
3109#endif
3110
3111void Isolate::set_tag_table(const GrowableObjectArray& value) {
3112 tag_table_ = value.ptr();
3113}
3114
3115void Isolate::set_current_tag(const UserTag& tag) {
3116 uword user_tag = tag.tag();
3117 ASSERT(user_tag < kUwordMax);
3118 set_user_tag(user_tag);
3119 current_tag_ = tag.ptr();
3120}
3121
3122void Isolate::set_default_tag(const UserTag& tag) {
3123 default_tag_ = tag.ptr();
3124}
3125
3126ErrorPtr Isolate::StealStickyError() {
3127 NoSafepointScope no_safepoint;
3128 ErrorPtr return_value = sticky_error_;
3129 sticky_error_ = Error::null();
3130 return return_value;
3131}
3132
3133#if !defined(PRODUCT)
3134void Isolate::set_pending_service_extension_calls(
3135 const GrowableObjectArray& value) {
3136 pending_service_extension_calls_ = value.ptr();
3137}
3138
3139void Isolate::set_registered_service_extension_handlers(
3140 const GrowableObjectArray& value) {
3141 registered_service_extension_handlers_ = value.ptr();
3142}
3143#endif // !defined(PRODUCT)
3144
3145#ifndef PRODUCT
3146ErrorPtr Isolate::InvokePendingServiceExtensionCalls() {
3147 GrowableObjectArray& calls =
3148 GrowableObjectArray::Handle(ptr: GetAndClearPendingServiceExtensionCalls());
3149 if (calls.IsNull()) {
3150 return Error::null();
3151 }
3152 // Grab run function.
3153 const Library& developer_lib = Library::Handle(ptr: Library::DeveloperLibrary());
3154 ASSERT(!developer_lib.IsNull());
3155 const Function& run_extension = Function::Handle(
3156 ptr: developer_lib.LookupLocalFunction(name: Symbols::_runExtension()));
3157 ASSERT(!run_extension.IsNull());
3158
3159 const Array& arguments =
3160 Array::Handle(ptr: Array::New(len: kPendingEntrySize + 1, space: Heap::kNew));
3161 Object& result = Object::Handle();
3162 String& method_name = String::Handle();
3163 Instance& closure = Instance::Handle();
3164 Array& parameter_keys = Array::Handle();
3165 Array& parameter_values = Array::Handle();
3166 Instance& reply_port = Instance::Handle();
3167 Instance& id = Instance::Handle();
3168 for (intptr_t i = 0; i < calls.Length(); i += kPendingEntrySize) {
3169 // Grab arguments for call.
3170 closure ^= calls.At(index: i + kPendingHandlerIndex);
3171 ASSERT(!closure.IsNull());
3172 arguments.SetAt(index: kPendingHandlerIndex, value: closure);
3173 method_name ^= calls.At(index: i + kPendingMethodNameIndex);
3174 ASSERT(!method_name.IsNull());
3175 arguments.SetAt(index: kPendingMethodNameIndex, value: method_name);
3176 parameter_keys ^= calls.At(index: i + kPendingKeysIndex);
3177 ASSERT(!parameter_keys.IsNull());
3178 arguments.SetAt(index: kPendingKeysIndex, value: parameter_keys);
3179 parameter_values ^= calls.At(index: i + kPendingValuesIndex);
3180 ASSERT(!parameter_values.IsNull());
3181 arguments.SetAt(index: kPendingValuesIndex, value: parameter_values);
3182 reply_port ^= calls.At(index: i + kPendingReplyPortIndex);
3183 ASSERT(!reply_port.IsNull());
3184 arguments.SetAt(index: kPendingReplyPortIndex, value: reply_port);
3185 id ^= calls.At(index: i + kPendingIdIndex);
3186 arguments.SetAt(index: kPendingIdIndex, value: id);
3187 arguments.SetAt(index: kPendingEntrySize, value: Bool::Get(value: FLAG_trace_service));
3188
3189 if (FLAG_trace_service) {
3190 OS::PrintErr(format: "[+%" Pd64 "ms] Isolate %s invoking _runExtension for %s\n",
3191 Dart::UptimeMillis(), name(), method_name.ToCString());
3192 }
3193 result = DartEntry::InvokeFunction(function: run_extension, arguments);
3194 if (FLAG_trace_service) {
3195 OS::PrintErr(format: "[+%" Pd64 "ms] Isolate %s _runExtension complete for %s\n",
3196 Dart::UptimeMillis(), name(), method_name.ToCString());
3197 }
3198 // Propagate the error.
3199 if (result.IsError()) {
3200 // Remaining service extension calls are dropped.
3201 if (!result.IsUnwindError()) {
3202 // Send error back over the protocol.
3203 Service::PostError(method_name, parameter_keys, parameter_values,
3204 reply_port, id, error: Error::Cast(obj: result));
3205 }
3206 return Error::Cast(obj: result).ptr();
3207 }
3208 // Drain the microtask queue.
3209 result = DartLibraryCalls::DrainMicrotaskQueue();
3210 // Propagate the error.
3211 if (result.IsError()) {
3212 // Remaining service extension calls are dropped.
3213 return Error::Cast(obj: result).ptr();
3214 }
3215 }
3216 return Error::null();
3217}
3218
3219GrowableObjectArrayPtr Isolate::GetAndClearPendingServiceExtensionCalls() {
3220 GrowableObjectArrayPtr r = pending_service_extension_calls_;
3221 pending_service_extension_calls_ = GrowableObjectArray::null();
3222 return r;
3223}
3224
3225void Isolate::AppendServiceExtensionCall(const Instance& closure,
3226 const String& method_name,
3227 const Array& parameter_keys,
3228 const Array& parameter_values,
3229 const Instance& reply_port,
3230 const Instance& id) {
3231 if (FLAG_trace_service) {
3232 OS::PrintErr(format: "[+%" Pd64
3233 "ms] Isolate %s ENQUEUING request for extension %s\n",
3234 Dart::UptimeMillis(), name(), method_name.ToCString());
3235 }
3236 GrowableObjectArray& calls =
3237 GrowableObjectArray::Handle(ptr: pending_service_extension_calls());
3238 bool schedule_drain = false;
3239 if (calls.IsNull()) {
3240 calls = GrowableObjectArray::New();
3241 ASSERT(!calls.IsNull());
3242 set_pending_service_extension_calls(calls);
3243 schedule_drain = true;
3244 }
3245 ASSERT(kPendingHandlerIndex == 0);
3246 calls.Add(value: closure);
3247 ASSERT(kPendingMethodNameIndex == 1);
3248 calls.Add(value: method_name);
3249 ASSERT(kPendingKeysIndex == 2);
3250 calls.Add(value: parameter_keys);
3251 ASSERT(kPendingValuesIndex == 3);
3252 calls.Add(value: parameter_values);
3253 ASSERT(kPendingReplyPortIndex == 4);
3254 calls.Add(value: reply_port);
3255 ASSERT(kPendingIdIndex == 5);
3256 calls.Add(value: id);
3257
3258 if (schedule_drain) {
3259 const Array& msg = Array::Handle(ptr: Array::New(len: 3));
3260 Object& element = Object::Handle();
3261 element = Smi::New(value: Message::kIsolateLibOOBMsg);
3262 msg.SetAt(index: 0, value: element);
3263 element = Smi::New(value: Isolate::kDrainServiceExtensionsMsg);
3264 msg.SetAt(index: 1, value: element);
3265 element = Smi::New(value: Isolate::kBeforeNextEventAction);
3266 msg.SetAt(index: 2, value: element);
3267 std::unique_ptr<Message> message = WriteMessage(
3268 /* same_group */ false, obj: msg, dest_port: main_port(), priority: Message::kOOBPriority);
3269 bool posted = PortMap::PostMessage(message: std::move(message));
3270 ASSERT(posted);
3271 }
3272}
3273
3274// This function is written in C++ and not Dart because we must do this
3275// operation atomically in the face of random OOB messages. Do not port
3276// to Dart code unless you can ensure that the operations will can be
3277// done atomically.
3278void Isolate::RegisterServiceExtensionHandler(const String& name,
3279 const Instance& closure) {
3280 // Don't allow for service extensions to be registered for internal isolates.
3281 if (Isolate::IsVMInternalIsolate(isolate: this)) {
3282 return;
3283 }
3284 GrowableObjectArray& handlers =
3285 GrowableObjectArray::Handle(ptr: registered_service_extension_handlers());
3286 if (handlers.IsNull()) {
3287 handlers = GrowableObjectArray::New(space: Heap::kOld);
3288 set_registered_service_extension_handlers(handlers);
3289 }
3290#if defined(DEBUG)
3291 {
3292 // Sanity check.
3293 const Instance& existing_handler =
3294 Instance::Handle(LookupServiceExtensionHandler(name));
3295 ASSERT(existing_handler.IsNull());
3296 }
3297#endif
3298 ASSERT(kRegisteredNameIndex == 0);
3299 handlers.Add(value: name, space: Heap::kOld);
3300 ASSERT(kRegisteredHandlerIndex == 1);
3301 handlers.Add(value: closure, space: Heap::kOld);
3302 {
3303 // Fire off an event.
3304 ServiceEvent event(this, ServiceEvent::kServiceExtensionAdded);
3305 event.set_extension_rpc(&name);
3306 Service::HandleEvent(event: &event);
3307 }
3308}
3309
3310// This function is written in C++ and not Dart because we must do this
3311// operation atomically in the face of random OOB messages. Do not port
3312// to Dart code unless you can ensure that the operations will can be
3313// done atomically.
3314InstancePtr Isolate::LookupServiceExtensionHandler(const String& name) {
3315 const GrowableObjectArray& handlers =
3316 GrowableObjectArray::Handle(ptr: registered_service_extension_handlers());
3317 if (handlers.IsNull()) {
3318 return Instance::null();
3319 }
3320 String& handler_name = String::Handle();
3321 for (intptr_t i = 0; i < handlers.Length(); i += kRegisteredEntrySize) {
3322 handler_name ^= handlers.At(index: i + kRegisteredNameIndex);
3323 ASSERT(!handler_name.IsNull());
3324 if (handler_name.Equals(str: name)) {
3325 return Instance::RawCast(raw: handlers.At(index: i + kRegisteredHandlerIndex));
3326 }
3327 }
3328 return Instance::null();
3329}
3330
3331void Isolate::WakePauseEventHandler(Dart_Isolate isolate) {
3332 Isolate* iso = reinterpret_cast<Isolate*>(isolate);
3333 MonitorLocker ml(iso->pause_loop_monitor_);
3334 ml.Notify();
3335
3336 Dart_MessageNotifyCallback current_notify_callback =
3337 iso->message_notify_callback();
3338 // It is possible that WakePauseEventHandler was replaced by original callback
3339 // while waiting for pause_loop_monitor_. In that case PauseEventHandler
3340 // is no longer running and the original callback needs to be invoked instead
3341 // of incrementing wake_pause_event_handler_count_.
3342 if (current_notify_callback != Isolate::WakePauseEventHandler) {
3343 if (current_notify_callback != nullptr) {
3344 current_notify_callback(isolate);
3345 }
3346 } else {
3347 ++iso->wake_pause_event_handler_count_;
3348 }
3349}
3350
3351void Isolate::PauseEventHandler() {
3352 // We are stealing a pause event (like a breakpoint) from the
3353 // embedder. We don't know what kind of thread we are on -- it
3354 // could be from our thread pool or it could be a thread from the
3355 // embedder. Sit on the current thread handling service events
3356 // until we are told to resume.
3357 if (pause_loop_monitor_ == nullptr) {
3358 pause_loop_monitor_ = new Monitor();
3359 }
3360 Dart_EnterScope();
3361 MonitorLocker ml(pause_loop_monitor_, false);
3362
3363 Dart_MessageNotifyCallback saved_notify_callback = message_notify_callback();
3364 ASSERT(wake_pause_event_handler_count_ == 0);
3365 set_message_notify_callback(Isolate::WakePauseEventHandler);
3366
3367#if !defined(DART_PRECOMPILED_RUNTIME)
3368 const bool had_program_reload_context =
3369 group()->program_reload_context() != nullptr;
3370 const int64_t start_time_micros = !had_program_reload_context
3371 ? 0
3372 : group()
3373 ->program_reload_context()
3374 ->group_reload_context()
3375 ->start_time_micros();
3376#endif // !defined(DART_PRECOMPILED_RUNTIME)
3377 bool resume = false;
3378 while (true) {
3379 // Handle all available vm service messages, up to a resume
3380 // request.
3381 while (!resume && Dart_HasServiceMessages()) {
3382 ml.Exit();
3383 resume = Dart_HandleServiceMessages();
3384 ml.Enter();
3385 }
3386 if (resume) {
3387 break;
3388 }
3389
3390#if !defined(DART_PRECOMPILED_RUNTIME)
3391 if (had_program_reload_context &&
3392 (group()->program_reload_context() == nullptr)) {
3393 if (FLAG_trace_reload) {
3394 const int64_t reload_time_micros =
3395 OS::GetCurrentMonotonicMicros() - start_time_micros;
3396 double reload_millis = MicrosecondsToMilliseconds(micros: reload_time_micros);
3397 OS::PrintErr(format: "Reloading has finished! (%.2f ms)\n", reload_millis);
3398 }
3399 break;
3400 }
3401#endif // !defined(DART_PRECOMPILED_RUNTIME)
3402
3403 // Wait for more service messages.
3404 Monitor::WaitResult res = ml.Wait();
3405 ASSERT(res == Monitor::kNotified);
3406 }
3407 // If any non-service messages came in, we need to notify the registered
3408 // message notify callback to check for unhandled messages. Otherwise, events
3409 // may be left unhandled until the next event comes in. See
3410 // https://github.com/dart-lang/sdk/issues/37312.
3411 if (saved_notify_callback != nullptr) {
3412 while (wake_pause_event_handler_count_ > 0) {
3413 saved_notify_callback(Api::CastIsolate(isolate: this));
3414 --wake_pause_event_handler_count_;
3415 }
3416 } else {
3417 wake_pause_event_handler_count_ = 0;
3418 }
3419 set_message_notify_callback(saved_notify_callback);
3420 Dart_ExitScope();
3421}
3422#endif // !PRODUCT
3423
3424void Isolate::VisitIsolates(IsolateVisitor* visitor) {
3425 if (visitor == nullptr) {
3426 return;
3427 }
3428 IsolateGroup::ForEach(action: [&](IsolateGroup* group) {
3429 group->ForEachIsolate(
3430 function: [&](Isolate* isolate) { visitor->VisitIsolate(isolate); });
3431 });
3432}
3433
3434intptr_t Isolate::IsolateListLength() {
3435 intptr_t count = 0;
3436 IsolateGroup::ForEach(action: [&](IsolateGroup* group) {
3437 group->ForEachIsolate(function: [&](Isolate* isolate) { count++; });
3438 });
3439 return count;
3440}
3441
3442Isolate* Isolate::LookupIsolateByPort(Dart_Port port) {
3443 Isolate* match = nullptr;
3444 IsolateGroup::ForEach(action: [&](IsolateGroup* group) {
3445 group->ForEachIsolate(function: [&](Isolate* isolate) {
3446 if (isolate->main_port() == port) {
3447 match = isolate;
3448 }
3449 });
3450 });
3451 return match;
3452}
3453
3454std::unique_ptr<char[]> Isolate::LookupIsolateNameByPort(Dart_Port port) {
3455 MonitorLocker ml(isolate_creation_monitor_);
3456 std::unique_ptr<char[]> result;
3457 IsolateGroup::ForEach(action: [&](IsolateGroup* group) {
3458 group->ForEachIsolate(function: [&](Isolate* isolate) {
3459 if (isolate->main_port() == port) {
3460 const size_t len = strlen(s: isolate->name()) + 1;
3461 result = std::unique_ptr<char[]>(new char[len]);
3462 strncpy(dest: result.get(), src: isolate->name(), n: len);
3463 }
3464 });
3465 });
3466 return result;
3467}
3468
3469bool Isolate::TryMarkIsolateReady(Isolate* isolate) {
3470 MonitorLocker ml(isolate_creation_monitor_);
3471 if (!creation_enabled_) {
3472 return false;
3473 }
3474 isolate->accepts_messages_ = true;
3475 return true;
3476}
3477
3478void Isolate::UnMarkIsolateReady(Isolate* isolate) {
3479 MonitorLocker ml(isolate_creation_monitor_);
3480 isolate->accepts_messages_ = false;
3481}
3482
3483void Isolate::DisableIsolateCreation() {
3484 MonitorLocker ml(isolate_creation_monitor_);
3485 creation_enabled_ = false;
3486}
3487
3488void Isolate::EnableIsolateCreation() {
3489 MonitorLocker ml(isolate_creation_monitor_);
3490 creation_enabled_ = true;
3491}
3492
3493bool Isolate::IsolateCreationEnabled() {
3494 MonitorLocker ml(isolate_creation_monitor_);
3495 return creation_enabled_;
3496}
3497
3498bool IsolateGroup::IsSystemIsolateGroup(const IsolateGroup* group) {
3499 return group->source()->flags.is_system_isolate;
3500}
3501
3502bool Isolate::IsVMInternalIsolate(const Isolate* isolate) {
3503 return isolate->is_kernel_isolate() || isolate->is_service_isolate() ||
3504 (Dart::vm_isolate() == isolate);
3505}
3506
3507void Isolate::KillLocked(LibMsgId msg_id) {
3508 Dart_CObject kill_msg;
3509 Dart_CObject* list_values[4];
3510 kill_msg.type = Dart_CObject_kArray;
3511 kill_msg.value.as_array.length = 4;
3512 kill_msg.value.as_array.values = list_values;
3513
3514 Dart_CObject oob;
3515 oob.type = Dart_CObject_kInt32;
3516 oob.value.as_int32 = Message::kIsolateLibOOBMsg;
3517 list_values[0] = &oob;
3518
3519 Dart_CObject msg_type;
3520 msg_type.type = Dart_CObject_kInt32;
3521 msg_type.value.as_int32 = msg_id;
3522 list_values[1] = &msg_type;
3523
3524 Dart_CObject cap;
3525 cap.type = Dart_CObject_kCapability;
3526 cap.value.as_capability.id = terminate_capability();
3527 list_values[2] = &cap;
3528
3529 Dart_CObject imm;
3530 imm.type = Dart_CObject_kInt32;
3531 imm.value.as_int32 = Isolate::kImmediateAction;
3532 list_values[3] = &imm;
3533
3534 {
3535 AllocOnlyStackZone zone;
3536 std::unique_ptr<Message> message = WriteApiMessage(
3537 zone: zone.GetZone(), obj: &kill_msg, dest_port: main_port(), priority: Message::kOOBPriority);
3538 ASSERT(message != nullptr);
3539
3540 // Post the message at the given port.
3541 bool success = PortMap::PostMessage(message: std::move(message));
3542 ASSERT(success);
3543 }
3544}
3545
3546class IsolateKillerVisitor : public IsolateVisitor {
3547 public:
3548 explicit IsolateKillerVisitor(Isolate::LibMsgId msg_id)
3549 : target_(nullptr), msg_id_(msg_id) {}
3550
3551 IsolateKillerVisitor(Isolate* isolate, Isolate::LibMsgId msg_id)
3552 : target_(isolate), msg_id_(msg_id) {
3553 ASSERT(isolate != Dart::vm_isolate());
3554 }
3555
3556 virtual ~IsolateKillerVisitor() {}
3557
3558 void VisitIsolate(Isolate* isolate) {
3559 MonitorLocker ml(Isolate::isolate_creation_monitor_);
3560 ASSERT(isolate != nullptr);
3561 if (ShouldKill(isolate)) {
3562 if (isolate->AcceptsMessagesLocked()) {
3563 isolate->KillLocked(msg_id: msg_id_);
3564 }
3565 }
3566 }
3567
3568 private:
3569 bool ShouldKill(Isolate* isolate) {
3570 // If a target_ is specified, then only kill the target_.
3571 // Otherwise, don't kill the service isolate or vm isolate.
3572 return (((target_ != nullptr) && (isolate == target_)) ||
3573 ((target_ == nullptr) && !IsSystemIsolate(isolate)));
3574 }
3575
3576 Isolate* target_;
3577 Isolate::LibMsgId msg_id_;
3578};
3579
3580void Isolate::KillAllIsolates(LibMsgId msg_id) {
3581 IsolateKillerVisitor visitor(msg_id);
3582 VisitIsolates(visitor: &visitor);
3583}
3584
3585void Isolate::KillIfExists(Isolate* isolate, LibMsgId msg_id) {
3586 IsolateKillerVisitor visitor(isolate, msg_id);
3587 VisitIsolates(visitor: &visitor);
3588}
3589
3590void Isolate::IncrementSpawnCount() {
3591 MonitorLocker ml(&spawn_count_monitor_);
3592 spawn_count_++;
3593}
3594
3595void Isolate::DecrementSpawnCount() {
3596 MonitorLocker ml(&spawn_count_monitor_);
3597 ASSERT(spawn_count_ > 0);
3598 spawn_count_--;
3599 ml.Notify();
3600}
3601
3602void Isolate::WaitForOutstandingSpawns() {
3603 Thread* thread = Thread::Current();
3604 ASSERT(thread != nullptr);
3605 MonitorLocker ml(&spawn_count_monitor_);
3606 while (spawn_count_ > 0) {
3607 ml.WaitWithSafepointCheck(thread);
3608 }
3609}
3610
3611FfiCallbackMetadata::Trampoline Isolate::CreateSyncFfiCallback(
3612 Zone* zone,
3613 const Function& function) {
3614 return FfiCallbackMetadata::Instance()->CreateSyncFfiCallback(
3615 isolate: this, zone, function, list_head: &ffi_callback_list_head_);
3616}
3617
3618FfiCallbackMetadata::Trampoline Isolate::CreateAsyncFfiCallback(
3619 Zone* zone,
3620 const Function& send_function,
3621 Dart_Port send_port) {
3622 return FfiCallbackMetadata::Instance()->CreateAsyncFfiCallback(
3623 isolate: this, zone, function: send_function, send_port, list_head: &ffi_callback_list_head_);
3624}
3625
3626void Isolate::DeleteFfiCallback(FfiCallbackMetadata::Trampoline callback) {
3627 FfiCallbackMetadata::Instance()->DeleteCallback(trampoline: callback,
3628 list_head: &ffi_callback_list_head_);
3629}
3630
3631#if !defined(PRODUCT)
3632void IsolateGroup::CloneClassTableForReload() {
3633 RELEASE_ASSERT(class_table_ == heap_walk_class_table_);
3634 class_table_ = class_table_->Clone();
3635 set_cached_class_table_table(nullptr);
3636}
3637
3638void IsolateGroup::RestoreOriginalClassTable() {
3639 RELEASE_ASSERT(class_table_ != heap_walk_class_table_);
3640 class_table_allocator_.Free(table: class_table_);
3641 class_table_ = heap_walk_class_table_;
3642 set_cached_class_table_table(class_table_->table());
3643}
3644
3645void IsolateGroup::DropOriginalClassTable() {
3646 RELEASE_ASSERT(class_table_ != heap_walk_class_table_);
3647 class_table_allocator_.Free(table: heap_walk_class_table_);
3648 heap_walk_class_table_ = class_table_;
3649 set_cached_class_table_table(class_table_->table());
3650}
3651#endif
3652
3653} // namespace dart
3654

source code of flutter_engine/third_party/dart/runtime/vm/isolate.cc