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