11cb0ef41Sopenharmony_ci// Copyright 2018 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/execution/microtask-queue.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include <algorithm> 81cb0ef41Sopenharmony_ci#include <cstddef> 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci#include "src/api/api-inl.h" 111cb0ef41Sopenharmony_ci#include "src/base/logging.h" 121cb0ef41Sopenharmony_ci#include "src/execution/isolate.h" 131cb0ef41Sopenharmony_ci#include "src/handles/handles-inl.h" 141cb0ef41Sopenharmony_ci#include "src/objects/microtask-inl.h" 151cb0ef41Sopenharmony_ci#include "src/objects/visitors.h" 161cb0ef41Sopenharmony_ci#include "src/roots/roots-inl.h" 171cb0ef41Sopenharmony_ci#include "src/tracing/trace-event.h" 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_cinamespace v8 { 201cb0ef41Sopenharmony_cinamespace internal { 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ciconst size_t MicrotaskQueue::kRingBufferOffset = 231cb0ef41Sopenharmony_ci OFFSET_OF(MicrotaskQueue, ring_buffer_); 241cb0ef41Sopenharmony_ciconst size_t MicrotaskQueue::kCapacityOffset = 251cb0ef41Sopenharmony_ci OFFSET_OF(MicrotaskQueue, capacity_); 261cb0ef41Sopenharmony_ciconst size_t MicrotaskQueue::kSizeOffset = OFFSET_OF(MicrotaskQueue, size_); 271cb0ef41Sopenharmony_ciconst size_t MicrotaskQueue::kStartOffset = OFFSET_OF(MicrotaskQueue, start_); 281cb0ef41Sopenharmony_ciconst size_t MicrotaskQueue::kFinishedMicrotaskCountOffset = 291cb0ef41Sopenharmony_ci OFFSET_OF(MicrotaskQueue, finished_microtask_count_); 301cb0ef41Sopenharmony_ci 311cb0ef41Sopenharmony_ciconst intptr_t MicrotaskQueue::kMinimumCapacity = 8; 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_ci// static 341cb0ef41Sopenharmony_civoid MicrotaskQueue::SetUpDefaultMicrotaskQueue(Isolate* isolate) { 351cb0ef41Sopenharmony_ci DCHECK_NULL(isolate->default_microtask_queue()); 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci MicrotaskQueue* microtask_queue = new MicrotaskQueue; 381cb0ef41Sopenharmony_ci microtask_queue->next_ = microtask_queue; 391cb0ef41Sopenharmony_ci microtask_queue->prev_ = microtask_queue; 401cb0ef41Sopenharmony_ci isolate->set_default_microtask_queue(microtask_queue); 411cb0ef41Sopenharmony_ci} 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci// static 441cb0ef41Sopenharmony_cistd::unique_ptr<MicrotaskQueue> MicrotaskQueue::New(Isolate* isolate) { 451cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(isolate->default_microtask_queue()); 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci std::unique_ptr<MicrotaskQueue> microtask_queue(new MicrotaskQueue); 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci // Insert the new instance to the next of last MicrotaskQueue instance. 501cb0ef41Sopenharmony_ci MicrotaskQueue* last = isolate->default_microtask_queue()->prev_; 511cb0ef41Sopenharmony_ci microtask_queue->next_ = last->next_; 521cb0ef41Sopenharmony_ci microtask_queue->prev_ = last; 531cb0ef41Sopenharmony_ci last->next_->prev_ = microtask_queue.get(); 541cb0ef41Sopenharmony_ci last->next_ = microtask_queue.get(); 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci return microtask_queue; 571cb0ef41Sopenharmony_ci} 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ciMicrotaskQueue::MicrotaskQueue() = default; 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ciMicrotaskQueue::~MicrotaskQueue() { 621cb0ef41Sopenharmony_ci if (next_ != this) { 631cb0ef41Sopenharmony_ci DCHECK_NE(prev_, this); 641cb0ef41Sopenharmony_ci next_->prev_ = prev_; 651cb0ef41Sopenharmony_ci prev_->next_ = next_; 661cb0ef41Sopenharmony_ci } 671cb0ef41Sopenharmony_ci delete[] ring_buffer_; 681cb0ef41Sopenharmony_ci} 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci// static 711cb0ef41Sopenharmony_ciAddress MicrotaskQueue::CallEnqueueMicrotask(Isolate* isolate, 721cb0ef41Sopenharmony_ci intptr_t microtask_queue_pointer, 731cb0ef41Sopenharmony_ci Address raw_microtask) { 741cb0ef41Sopenharmony_ci Microtask microtask = Microtask::cast(Object(raw_microtask)); 751cb0ef41Sopenharmony_ci reinterpret_cast<MicrotaskQueue*>(microtask_queue_pointer) 761cb0ef41Sopenharmony_ci ->EnqueueMicrotask(microtask); 771cb0ef41Sopenharmony_ci return Smi::zero().ptr(); 781cb0ef41Sopenharmony_ci} 791cb0ef41Sopenharmony_ci 801cb0ef41Sopenharmony_civoid MicrotaskQueue::EnqueueMicrotask(v8::Isolate* v8_isolate, 811cb0ef41Sopenharmony_ci v8::Local<Function> function) { 821cb0ef41Sopenharmony_ci Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 831cb0ef41Sopenharmony_ci HandleScope scope(isolate); 841cb0ef41Sopenharmony_ci Handle<CallableTask> microtask = isolate->factory()->NewCallableTask( 851cb0ef41Sopenharmony_ci Utils::OpenHandle(*function), isolate->native_context()); 861cb0ef41Sopenharmony_ci EnqueueMicrotask(*microtask); 871cb0ef41Sopenharmony_ci} 881cb0ef41Sopenharmony_ci 891cb0ef41Sopenharmony_civoid MicrotaskQueue::EnqueueMicrotask(v8::Isolate* v8_isolate, 901cb0ef41Sopenharmony_ci v8::MicrotaskCallback callback, 911cb0ef41Sopenharmony_ci void* data) { 921cb0ef41Sopenharmony_ci Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 931cb0ef41Sopenharmony_ci HandleScope scope(isolate); 941cb0ef41Sopenharmony_ci Handle<CallbackTask> microtask = isolate->factory()->NewCallbackTask( 951cb0ef41Sopenharmony_ci isolate->factory()->NewForeign(reinterpret_cast<Address>(callback)), 961cb0ef41Sopenharmony_ci isolate->factory()->NewForeign(reinterpret_cast<Address>(data))); 971cb0ef41Sopenharmony_ci EnqueueMicrotask(*microtask); 981cb0ef41Sopenharmony_ci} 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_civoid MicrotaskQueue::EnqueueMicrotask(Microtask microtask) { 1011cb0ef41Sopenharmony_ci if (size_ == capacity_) { 1021cb0ef41Sopenharmony_ci // Keep the capacity of |ring_buffer_| power of 2, so that the JIT 1031cb0ef41Sopenharmony_ci // implementation can calculate the modulo easily. 1041cb0ef41Sopenharmony_ci intptr_t new_capacity = std::max(kMinimumCapacity, capacity_ << 1); 1051cb0ef41Sopenharmony_ci ResizeBuffer(new_capacity); 1061cb0ef41Sopenharmony_ci } 1071cb0ef41Sopenharmony_ci 1081cb0ef41Sopenharmony_ci DCHECK_LT(size_, capacity_); 1091cb0ef41Sopenharmony_ci ring_buffer_[(start_ + size_) % capacity_] = microtask.ptr(); 1101cb0ef41Sopenharmony_ci ++size_; 1111cb0ef41Sopenharmony_ci} 1121cb0ef41Sopenharmony_ci 1131cb0ef41Sopenharmony_civoid MicrotaskQueue::PerformCheckpointInternal(v8::Isolate* v8_isolate) { 1141cb0ef41Sopenharmony_ci DCHECK(ShouldPerfomCheckpoint()); 1151cb0ef41Sopenharmony_ci std::unique_ptr<MicrotasksScope> microtasks_scope; 1161cb0ef41Sopenharmony_ci if (microtasks_policy_ == v8::MicrotasksPolicy::kScoped) { 1171cb0ef41Sopenharmony_ci // If we're using microtask scopes to schedule microtask execution, V8 1181cb0ef41Sopenharmony_ci // API calls will check that there's always a microtask scope on the 1191cb0ef41Sopenharmony_ci // stack. As the microtasks we're about to execute could invoke embedder 1201cb0ef41Sopenharmony_ci // callbacks which then calls back into V8, we create an artificial 1211cb0ef41Sopenharmony_ci // microtask scope here to avoid running into the CallDepthScope check. 1221cb0ef41Sopenharmony_ci microtasks_scope.reset(new v8::MicrotasksScope( 1231cb0ef41Sopenharmony_ci v8_isolate, this, v8::MicrotasksScope::kDoNotRunMicrotasks)); 1241cb0ef41Sopenharmony_ci } 1251cb0ef41Sopenharmony_ci Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 1261cb0ef41Sopenharmony_ci RunMicrotasks(isolate); 1271cb0ef41Sopenharmony_ci isolate->ClearKeptObjects(); 1281cb0ef41Sopenharmony_ci} 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_cinamespace { 1311cb0ef41Sopenharmony_ci 1321cb0ef41Sopenharmony_ciclass SetIsRunningMicrotasks { 1331cb0ef41Sopenharmony_ci public: 1341cb0ef41Sopenharmony_ci explicit SetIsRunningMicrotasks(bool* flag) : flag_(flag) { 1351cb0ef41Sopenharmony_ci DCHECK(!*flag_); 1361cb0ef41Sopenharmony_ci *flag_ = true; 1371cb0ef41Sopenharmony_ci } 1381cb0ef41Sopenharmony_ci 1391cb0ef41Sopenharmony_ci ~SetIsRunningMicrotasks() { 1401cb0ef41Sopenharmony_ci DCHECK(*flag_); 1411cb0ef41Sopenharmony_ci *flag_ = false; 1421cb0ef41Sopenharmony_ci } 1431cb0ef41Sopenharmony_ci 1441cb0ef41Sopenharmony_ci private: 1451cb0ef41Sopenharmony_ci bool* flag_; 1461cb0ef41Sopenharmony_ci}; 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_ci} // namespace 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ciint MicrotaskQueue::RunMicrotasks(Isolate* isolate) { 1511cb0ef41Sopenharmony_ci if (!size()) { 1521cb0ef41Sopenharmony_ci OnCompleted(isolate); 1531cb0ef41Sopenharmony_ci return 0; 1541cb0ef41Sopenharmony_ci } 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci intptr_t base_count = finished_microtask_count_; 1571cb0ef41Sopenharmony_ci 1581cb0ef41Sopenharmony_ci HandleScope handle_scope(isolate); 1591cb0ef41Sopenharmony_ci MaybeHandle<Object> maybe_exception; 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci MaybeHandle<Object> maybe_result; 1621cb0ef41Sopenharmony_ci 1631cb0ef41Sopenharmony_ci int processed_microtask_count; 1641cb0ef41Sopenharmony_ci { 1651cb0ef41Sopenharmony_ci SetIsRunningMicrotasks scope(&is_running_microtasks_); 1661cb0ef41Sopenharmony_ci v8::Isolate::SuppressMicrotaskExecutionScope suppress( 1671cb0ef41Sopenharmony_ci reinterpret_cast<v8::Isolate*>(isolate)); 1681cb0ef41Sopenharmony_ci HandleScopeImplementer::EnteredContextRewindScope rewind_scope( 1691cb0ef41Sopenharmony_ci isolate->handle_scope_implementer()); 1701cb0ef41Sopenharmony_ci TRACE_EVENT_BEGIN0("v8.execute", "RunMicrotasks"); 1711cb0ef41Sopenharmony_ci { 1721cb0ef41Sopenharmony_ci TRACE_EVENT_CALL_STATS_SCOPED(isolate, "v8", "V8.RunMicrotasks"); 1731cb0ef41Sopenharmony_ci maybe_result = Execution::TryRunMicrotasks(isolate, this, 1741cb0ef41Sopenharmony_ci &maybe_exception); 1751cb0ef41Sopenharmony_ci processed_microtask_count = 1761cb0ef41Sopenharmony_ci static_cast<int>(finished_microtask_count_ - base_count); 1771cb0ef41Sopenharmony_ci } 1781cb0ef41Sopenharmony_ci TRACE_EVENT_END1("v8.execute", "RunMicrotasks", "microtask_count", 1791cb0ef41Sopenharmony_ci processed_microtask_count); 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci 1821cb0ef41Sopenharmony_ci // If execution is terminating, clean up and propagate that to TryCatch scope. 1831cb0ef41Sopenharmony_ci if (maybe_result.is_null() && maybe_exception.is_null()) { 1841cb0ef41Sopenharmony_ci delete[] ring_buffer_; 1851cb0ef41Sopenharmony_ci ring_buffer_ = nullptr; 1861cb0ef41Sopenharmony_ci capacity_ = 0; 1871cb0ef41Sopenharmony_ci size_ = 0; 1881cb0ef41Sopenharmony_ci start_ = 0; 1891cb0ef41Sopenharmony_ci DCHECK(isolate->has_scheduled_exception()); 1901cb0ef41Sopenharmony_ci isolate->OnTerminationDuringRunMicrotasks(); 1911cb0ef41Sopenharmony_ci OnCompleted(isolate); 1921cb0ef41Sopenharmony_ci return -1; 1931cb0ef41Sopenharmony_ci } 1941cb0ef41Sopenharmony_ci DCHECK_EQ(0, size()); 1951cb0ef41Sopenharmony_ci OnCompleted(isolate); 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ci return processed_microtask_count; 1981cb0ef41Sopenharmony_ci} 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_civoid MicrotaskQueue::IterateMicrotasks(RootVisitor* visitor) { 2011cb0ef41Sopenharmony_ci if (size_) { 2021cb0ef41Sopenharmony_ci // Iterate pending Microtasks as root objects to avoid the write barrier for 2031cb0ef41Sopenharmony_ci // all single Microtask. If this hurts the GC performance, use a FixedArray. 2041cb0ef41Sopenharmony_ci visitor->VisitRootPointers( 2051cb0ef41Sopenharmony_ci Root::kStrongRoots, nullptr, FullObjectSlot(ring_buffer_ + start_), 2061cb0ef41Sopenharmony_ci FullObjectSlot(ring_buffer_ + std::min(start_ + size_, capacity_))); 2071cb0ef41Sopenharmony_ci visitor->VisitRootPointers( 2081cb0ef41Sopenharmony_ci Root::kStrongRoots, nullptr, FullObjectSlot(ring_buffer_), 2091cb0ef41Sopenharmony_ci FullObjectSlot(ring_buffer_ + std::max(start_ + size_ - capacity_, 2101cb0ef41Sopenharmony_ci static_cast<intptr_t>(0)))); 2111cb0ef41Sopenharmony_ci } 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_ci if (capacity_ <= kMinimumCapacity) { 2141cb0ef41Sopenharmony_ci return; 2151cb0ef41Sopenharmony_ci } 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ci intptr_t new_capacity = capacity_; 2181cb0ef41Sopenharmony_ci while (new_capacity > 2 * size_) { 2191cb0ef41Sopenharmony_ci new_capacity >>= 1; 2201cb0ef41Sopenharmony_ci } 2211cb0ef41Sopenharmony_ci new_capacity = std::max(new_capacity, kMinimumCapacity); 2221cb0ef41Sopenharmony_ci if (new_capacity < capacity_) { 2231cb0ef41Sopenharmony_ci ResizeBuffer(new_capacity); 2241cb0ef41Sopenharmony_ci } 2251cb0ef41Sopenharmony_ci} 2261cb0ef41Sopenharmony_ci 2271cb0ef41Sopenharmony_civoid MicrotaskQueue::AddMicrotasksCompletedCallback( 2281cb0ef41Sopenharmony_ci MicrotasksCompletedCallbackWithData callback, void* data) { 2291cb0ef41Sopenharmony_ci CallbackWithData callback_with_data(callback, data); 2301cb0ef41Sopenharmony_ci auto pos = 2311cb0ef41Sopenharmony_ci std::find(microtasks_completed_callbacks_.begin(), 2321cb0ef41Sopenharmony_ci microtasks_completed_callbacks_.end(), callback_with_data); 2331cb0ef41Sopenharmony_ci if (pos != microtasks_completed_callbacks_.end()) return; 2341cb0ef41Sopenharmony_ci microtasks_completed_callbacks_.push_back(callback_with_data); 2351cb0ef41Sopenharmony_ci} 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_civoid MicrotaskQueue::RemoveMicrotasksCompletedCallback( 2381cb0ef41Sopenharmony_ci MicrotasksCompletedCallbackWithData callback, void* data) { 2391cb0ef41Sopenharmony_ci CallbackWithData callback_with_data(callback, data); 2401cb0ef41Sopenharmony_ci auto pos = 2411cb0ef41Sopenharmony_ci std::find(microtasks_completed_callbacks_.begin(), 2421cb0ef41Sopenharmony_ci microtasks_completed_callbacks_.end(), callback_with_data); 2431cb0ef41Sopenharmony_ci if (pos == microtasks_completed_callbacks_.end()) return; 2441cb0ef41Sopenharmony_ci microtasks_completed_callbacks_.erase(pos); 2451cb0ef41Sopenharmony_ci} 2461cb0ef41Sopenharmony_ci 2471cb0ef41Sopenharmony_civoid MicrotaskQueue::OnCompleted(Isolate* isolate) const { 2481cb0ef41Sopenharmony_ci std::vector<CallbackWithData> callbacks(microtasks_completed_callbacks_); 2491cb0ef41Sopenharmony_ci for (auto& callback : callbacks) { 2501cb0ef41Sopenharmony_ci callback.first(reinterpret_cast<v8::Isolate*>(isolate), callback.second); 2511cb0ef41Sopenharmony_ci } 2521cb0ef41Sopenharmony_ci} 2531cb0ef41Sopenharmony_ci 2541cb0ef41Sopenharmony_ciMicrotask MicrotaskQueue::get(intptr_t index) const { 2551cb0ef41Sopenharmony_ci DCHECK_LT(index, size_); 2561cb0ef41Sopenharmony_ci Object microtask(ring_buffer_[(index + start_) % capacity_]); 2571cb0ef41Sopenharmony_ci return Microtask::cast(microtask); 2581cb0ef41Sopenharmony_ci} 2591cb0ef41Sopenharmony_ci 2601cb0ef41Sopenharmony_civoid MicrotaskQueue::ResizeBuffer(intptr_t new_capacity) { 2611cb0ef41Sopenharmony_ci DCHECK_LE(size_, new_capacity); 2621cb0ef41Sopenharmony_ci Address* new_ring_buffer = new Address[new_capacity]; 2631cb0ef41Sopenharmony_ci for (intptr_t i = 0; i < size_; ++i) { 2641cb0ef41Sopenharmony_ci new_ring_buffer[i] = ring_buffer_[(start_ + i) % capacity_]; 2651cb0ef41Sopenharmony_ci } 2661cb0ef41Sopenharmony_ci 2671cb0ef41Sopenharmony_ci delete[] ring_buffer_; 2681cb0ef41Sopenharmony_ci ring_buffer_ = new_ring_buffer; 2691cb0ef41Sopenharmony_ci capacity_ = new_capacity; 2701cb0ef41Sopenharmony_ci start_ = 0; 2711cb0ef41Sopenharmony_ci} 2721cb0ef41Sopenharmony_ci 2731cb0ef41Sopenharmony_ci} // namespace internal 2741cb0ef41Sopenharmony_ci} // namespace v8 275