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/api/api.h" 61cb0ef41Sopenharmony_ci#include "src/builtins/builtins-utils-gen.h" 71cb0ef41Sopenharmony_ci#include "src/codegen/code-stub-assembler.h" 81cb0ef41Sopenharmony_ci#include "src/execution/microtask-queue.h" 91cb0ef41Sopenharmony_ci#include "src/objects/js-weak-refs.h" 101cb0ef41Sopenharmony_ci#include "src/objects/microtask-inl.h" 111cb0ef41Sopenharmony_ci#include "src/objects/promise.h" 121cb0ef41Sopenharmony_ci#include "src/objects/smi-inl.h" 131cb0ef41Sopenharmony_ci 141cb0ef41Sopenharmony_cinamespace v8 { 151cb0ef41Sopenharmony_cinamespace internal { 161cb0ef41Sopenharmony_ci 171cb0ef41Sopenharmony_ciusing compiler::ScopedExceptionHandler; 181cb0ef41Sopenharmony_ci 191cb0ef41Sopenharmony_ciclass MicrotaskQueueBuiltinsAssembler : public CodeStubAssembler { 201cb0ef41Sopenharmony_ci public: 211cb0ef41Sopenharmony_ci explicit MicrotaskQueueBuiltinsAssembler(compiler::CodeAssemblerState* state) 221cb0ef41Sopenharmony_ci : CodeStubAssembler(state) {} 231cb0ef41Sopenharmony_ci 241cb0ef41Sopenharmony_ci TNode<RawPtrT> GetMicrotaskQueue(TNode<Context> context); 251cb0ef41Sopenharmony_ci TNode<RawPtrT> GetMicrotaskRingBuffer(TNode<RawPtrT> microtask_queue); 261cb0ef41Sopenharmony_ci TNode<IntPtrT> GetMicrotaskQueueCapacity(TNode<RawPtrT> microtask_queue); 271cb0ef41Sopenharmony_ci TNode<IntPtrT> GetMicrotaskQueueSize(TNode<RawPtrT> microtask_queue); 281cb0ef41Sopenharmony_ci void SetMicrotaskQueueSize(TNode<RawPtrT> microtask_queue, 291cb0ef41Sopenharmony_ci TNode<IntPtrT> new_size); 301cb0ef41Sopenharmony_ci TNode<IntPtrT> GetMicrotaskQueueStart(TNode<RawPtrT> microtask_queue); 311cb0ef41Sopenharmony_ci void SetMicrotaskQueueStart(TNode<RawPtrT> microtask_queue, 321cb0ef41Sopenharmony_ci TNode<IntPtrT> new_start); 331cb0ef41Sopenharmony_ci TNode<IntPtrT> CalculateRingBufferOffset(TNode<IntPtrT> capacity, 341cb0ef41Sopenharmony_ci TNode<IntPtrT> start, 351cb0ef41Sopenharmony_ci TNode<IntPtrT> index); 361cb0ef41Sopenharmony_ci 371cb0ef41Sopenharmony_ci void PrepareForContext(TNode<Context> microtask_context, Label* bailout); 381cb0ef41Sopenharmony_ci void RunSingleMicrotask(TNode<Context> current_context, 391cb0ef41Sopenharmony_ci TNode<Microtask> microtask); 401cb0ef41Sopenharmony_ci void IncrementFinishedMicrotaskCount(TNode<RawPtrT> microtask_queue); 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci TNode<Context> GetCurrentContext(); 431cb0ef41Sopenharmony_ci void SetCurrentContext(TNode<Context> context); 441cb0ef41Sopenharmony_ci 451cb0ef41Sopenharmony_ci TNode<IntPtrT> GetEnteredContextCount(); 461cb0ef41Sopenharmony_ci void EnterMicrotaskContext(TNode<Context> native_context); 471cb0ef41Sopenharmony_ci void RewindEnteredContext(TNode<IntPtrT> saved_entered_context_count); 481cb0ef41Sopenharmony_ci 491cb0ef41Sopenharmony_ci void RunAllPromiseHooks(PromiseHookType type, TNode<Context> context, 501cb0ef41Sopenharmony_ci TNode<HeapObject> promise_or_capability); 511cb0ef41Sopenharmony_ci void RunPromiseHook(Runtime::FunctionId id, TNode<Context> context, 521cb0ef41Sopenharmony_ci TNode<HeapObject> promise_or_capability, 531cb0ef41Sopenharmony_ci TNode<Uint32T> promiseHookFlags); 541cb0ef41Sopenharmony_ci}; 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ciTNode<RawPtrT> MicrotaskQueueBuiltinsAssembler::GetMicrotaskQueue( 571cb0ef41Sopenharmony_ci TNode<Context> native_context) { 581cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNativeContext(native_context)); 591cb0ef41Sopenharmony_ci return LoadExternalPointerFromObject(native_context, 601cb0ef41Sopenharmony_ci NativeContext::kMicrotaskQueueOffset, 611cb0ef41Sopenharmony_ci kNativeContextMicrotaskQueueTag); 621cb0ef41Sopenharmony_ci} 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ciTNode<RawPtrT> MicrotaskQueueBuiltinsAssembler::GetMicrotaskRingBuffer( 651cb0ef41Sopenharmony_ci TNode<RawPtrT> microtask_queue) { 661cb0ef41Sopenharmony_ci return Load<RawPtrT>(microtask_queue, 671cb0ef41Sopenharmony_ci IntPtrConstant(MicrotaskQueue::kRingBufferOffset)); 681cb0ef41Sopenharmony_ci} 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ciTNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::GetMicrotaskQueueCapacity( 711cb0ef41Sopenharmony_ci TNode<RawPtrT> microtask_queue) { 721cb0ef41Sopenharmony_ci return Load<IntPtrT>(microtask_queue, 731cb0ef41Sopenharmony_ci IntPtrConstant(MicrotaskQueue::kCapacityOffset)); 741cb0ef41Sopenharmony_ci} 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ciTNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::GetMicrotaskQueueSize( 771cb0ef41Sopenharmony_ci TNode<RawPtrT> microtask_queue) { 781cb0ef41Sopenharmony_ci return Load<IntPtrT>(microtask_queue, 791cb0ef41Sopenharmony_ci IntPtrConstant(MicrotaskQueue::kSizeOffset)); 801cb0ef41Sopenharmony_ci} 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_civoid MicrotaskQueueBuiltinsAssembler::SetMicrotaskQueueSize( 831cb0ef41Sopenharmony_ci TNode<RawPtrT> microtask_queue, TNode<IntPtrT> new_size) { 841cb0ef41Sopenharmony_ci StoreNoWriteBarrier(MachineType::PointerRepresentation(), microtask_queue, 851cb0ef41Sopenharmony_ci IntPtrConstant(MicrotaskQueue::kSizeOffset), new_size); 861cb0ef41Sopenharmony_ci} 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ciTNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::GetMicrotaskQueueStart( 891cb0ef41Sopenharmony_ci TNode<RawPtrT> microtask_queue) { 901cb0ef41Sopenharmony_ci return Load<IntPtrT>(microtask_queue, 911cb0ef41Sopenharmony_ci IntPtrConstant(MicrotaskQueue::kStartOffset)); 921cb0ef41Sopenharmony_ci} 931cb0ef41Sopenharmony_ci 941cb0ef41Sopenharmony_civoid MicrotaskQueueBuiltinsAssembler::SetMicrotaskQueueStart( 951cb0ef41Sopenharmony_ci TNode<RawPtrT> microtask_queue, TNode<IntPtrT> new_start) { 961cb0ef41Sopenharmony_ci StoreNoWriteBarrier(MachineType::PointerRepresentation(), microtask_queue, 971cb0ef41Sopenharmony_ci IntPtrConstant(MicrotaskQueue::kStartOffset), new_start); 981cb0ef41Sopenharmony_ci} 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ciTNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::CalculateRingBufferOffset( 1011cb0ef41Sopenharmony_ci TNode<IntPtrT> capacity, TNode<IntPtrT> start, TNode<IntPtrT> index) { 1021cb0ef41Sopenharmony_ci return TimesSystemPointerSize( 1031cb0ef41Sopenharmony_ci WordAnd(IntPtrAdd(start, index), IntPtrSub(capacity, IntPtrConstant(1)))); 1041cb0ef41Sopenharmony_ci} 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_civoid MicrotaskQueueBuiltinsAssembler::PrepareForContext( 1071cb0ef41Sopenharmony_ci TNode<Context> native_context, Label* bailout) { 1081cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNativeContext(native_context)); 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci // Skip the microtask execution if the associated context is shutdown. 1111cb0ef41Sopenharmony_ci GotoIf(WordEqual(GetMicrotaskQueue(native_context), IntPtrConstant(0)), 1121cb0ef41Sopenharmony_ci bailout); 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci EnterMicrotaskContext(native_context); 1151cb0ef41Sopenharmony_ci SetCurrentContext(native_context); 1161cb0ef41Sopenharmony_ci} 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_civoid MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask( 1191cb0ef41Sopenharmony_ci TNode<Context> current_context, TNode<Microtask> microtask) { 1201cb0ef41Sopenharmony_ci CSA_DCHECK(this, TaggedIsNotSmi(microtask)); 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci StoreRoot(RootIndex::kCurrentMicrotask, microtask); 1231cb0ef41Sopenharmony_ci TNode<IntPtrT> saved_entered_context_count = GetEnteredContextCount(); 1241cb0ef41Sopenharmony_ci TNode<Map> microtask_map = LoadMap(microtask); 1251cb0ef41Sopenharmony_ci TNode<Uint16T> microtask_type = LoadMapInstanceType(microtask_map); 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci TVARIABLE(Object, var_exception); 1281cb0ef41Sopenharmony_ci Label if_exception(this, Label::kDeferred); 1291cb0ef41Sopenharmony_ci Label is_callable(this), is_callback(this), 1301cb0ef41Sopenharmony_ci is_promise_fulfill_reaction_job(this), 1311cb0ef41Sopenharmony_ci is_promise_reject_reaction_job(this), 1321cb0ef41Sopenharmony_ci is_promise_resolve_thenable_job(this), 1331cb0ef41Sopenharmony_ci is_unreachable(this, Label::kDeferred), done(this); 1341cb0ef41Sopenharmony_ci 1351cb0ef41Sopenharmony_ci int32_t case_values[] = {CALLABLE_TASK_TYPE, CALLBACK_TASK_TYPE, 1361cb0ef41Sopenharmony_ci PROMISE_FULFILL_REACTION_JOB_TASK_TYPE, 1371cb0ef41Sopenharmony_ci PROMISE_REJECT_REACTION_JOB_TASK_TYPE, 1381cb0ef41Sopenharmony_ci PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE}; 1391cb0ef41Sopenharmony_ci Label* case_labels[] = { 1401cb0ef41Sopenharmony_ci &is_callable, &is_callback, &is_promise_fulfill_reaction_job, 1411cb0ef41Sopenharmony_ci &is_promise_reject_reaction_job, &is_promise_resolve_thenable_job}; 1421cb0ef41Sopenharmony_ci static_assert(arraysize(case_values) == arraysize(case_labels), ""); 1431cb0ef41Sopenharmony_ci Switch(microtask_type, &is_unreachable, case_values, case_labels, 1441cb0ef41Sopenharmony_ci arraysize(case_labels)); 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci BIND(&is_callable); 1471cb0ef41Sopenharmony_ci { 1481cb0ef41Sopenharmony_ci // Enter the context of the {microtask}. 1491cb0ef41Sopenharmony_ci TNode<Context> microtask_context = 1501cb0ef41Sopenharmony_ci LoadObjectField<Context>(microtask, CallableTask::kContextOffset); 1511cb0ef41Sopenharmony_ci TNode<NativeContext> native_context = LoadNativeContext(microtask_context); 1521cb0ef41Sopenharmony_ci PrepareForContext(native_context, &done); 1531cb0ef41Sopenharmony_ci 1541cb0ef41Sopenharmony_ci TNode<JSReceiver> callable = 1551cb0ef41Sopenharmony_ci LoadObjectField<JSReceiver>(microtask, CallableTask::kCallableOffset); 1561cb0ef41Sopenharmony_ci { 1571cb0ef41Sopenharmony_ci ScopedExceptionHandler handler(this, &if_exception, &var_exception); 1581cb0ef41Sopenharmony_ci Call(microtask_context, callable, UndefinedConstant()); 1591cb0ef41Sopenharmony_ci } 1601cb0ef41Sopenharmony_ci RewindEnteredContext(saved_entered_context_count); 1611cb0ef41Sopenharmony_ci SetCurrentContext(current_context); 1621cb0ef41Sopenharmony_ci Goto(&done); 1631cb0ef41Sopenharmony_ci } 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_ci BIND(&is_callback); 1661cb0ef41Sopenharmony_ci { 1671cb0ef41Sopenharmony_ci const TNode<Object> microtask_callback = 1681cb0ef41Sopenharmony_ci LoadObjectField(microtask, CallbackTask::kCallbackOffset); 1691cb0ef41Sopenharmony_ci const TNode<Object> microtask_data = 1701cb0ef41Sopenharmony_ci LoadObjectField(microtask, CallbackTask::kDataOffset); 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci // If this turns out to become a bottleneck because of the calls 1731cb0ef41Sopenharmony_ci // to C++ via CEntry, we can choose to speed them up using a 1741cb0ef41Sopenharmony_ci // similar mechanism that we use for the CallApiFunction stub, 1751cb0ef41Sopenharmony_ci // except that calling the MicrotaskCallback is even easier, since 1761cb0ef41Sopenharmony_ci // it doesn't accept any tagged parameters, doesn't return a value 1771cb0ef41Sopenharmony_ci // and ignores exceptions. 1781cb0ef41Sopenharmony_ci // 1791cb0ef41Sopenharmony_ci // But from our current measurements it doesn't seem to be a 1801cb0ef41Sopenharmony_ci // serious performance problem, even if the microtask is full 1811cb0ef41Sopenharmony_ci // of CallHandlerTasks (which is not a realistic use case anyways). 1821cb0ef41Sopenharmony_ci { 1831cb0ef41Sopenharmony_ci ScopedExceptionHandler handler(this, &if_exception, &var_exception); 1841cb0ef41Sopenharmony_ci CallRuntime(Runtime::kRunMicrotaskCallback, current_context, 1851cb0ef41Sopenharmony_ci microtask_callback, microtask_data); 1861cb0ef41Sopenharmony_ci } 1871cb0ef41Sopenharmony_ci Goto(&done); 1881cb0ef41Sopenharmony_ci } 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci BIND(&is_promise_resolve_thenable_job); 1911cb0ef41Sopenharmony_ci { 1921cb0ef41Sopenharmony_ci // Enter the context of the {microtask}. 1931cb0ef41Sopenharmony_ci TNode<Context> microtask_context = LoadObjectField<Context>( 1941cb0ef41Sopenharmony_ci microtask, PromiseResolveThenableJobTask::kContextOffset); 1951cb0ef41Sopenharmony_ci TNode<NativeContext> native_context = LoadNativeContext(microtask_context); 1961cb0ef41Sopenharmony_ci PrepareForContext(native_context, &done); 1971cb0ef41Sopenharmony_ci 1981cb0ef41Sopenharmony_ci const TNode<Object> promise_to_resolve = LoadObjectField( 1991cb0ef41Sopenharmony_ci microtask, PromiseResolveThenableJobTask::kPromiseToResolveOffset); 2001cb0ef41Sopenharmony_ci const TNode<Object> then = 2011cb0ef41Sopenharmony_ci LoadObjectField(microtask, PromiseResolveThenableJobTask::kThenOffset); 2021cb0ef41Sopenharmony_ci const TNode<Object> thenable = LoadObjectField( 2031cb0ef41Sopenharmony_ci microtask, PromiseResolveThenableJobTask::kThenableOffset); 2041cb0ef41Sopenharmony_ci 2051cb0ef41Sopenharmony_ci RunAllPromiseHooks(PromiseHookType::kBefore, microtask_context, 2061cb0ef41Sopenharmony_ci CAST(promise_to_resolve)); 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci { 2091cb0ef41Sopenharmony_ci ScopedExceptionHandler handler(this, &if_exception, &var_exception); 2101cb0ef41Sopenharmony_ci CallBuiltin(Builtin::kPromiseResolveThenableJob, native_context, 2111cb0ef41Sopenharmony_ci promise_to_resolve, thenable, then); 2121cb0ef41Sopenharmony_ci } 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci RunAllPromiseHooks(PromiseHookType::kAfter, microtask_context, 2151cb0ef41Sopenharmony_ci CAST(promise_to_resolve)); 2161cb0ef41Sopenharmony_ci 2171cb0ef41Sopenharmony_ci RewindEnteredContext(saved_entered_context_count); 2181cb0ef41Sopenharmony_ci SetCurrentContext(current_context); 2191cb0ef41Sopenharmony_ci Goto(&done); 2201cb0ef41Sopenharmony_ci } 2211cb0ef41Sopenharmony_ci 2221cb0ef41Sopenharmony_ci BIND(&is_promise_fulfill_reaction_job); 2231cb0ef41Sopenharmony_ci { 2241cb0ef41Sopenharmony_ci // Enter the context of the {microtask}. 2251cb0ef41Sopenharmony_ci TNode<Context> microtask_context = LoadObjectField<Context>( 2261cb0ef41Sopenharmony_ci microtask, PromiseReactionJobTask::kContextOffset); 2271cb0ef41Sopenharmony_ci TNode<NativeContext> native_context = LoadNativeContext(microtask_context); 2281cb0ef41Sopenharmony_ci PrepareForContext(native_context, &done); 2291cb0ef41Sopenharmony_ci 2301cb0ef41Sopenharmony_ci const TNode<Object> argument = 2311cb0ef41Sopenharmony_ci LoadObjectField(microtask, PromiseReactionJobTask::kArgumentOffset); 2321cb0ef41Sopenharmony_ci const TNode<Object> job_handler = 2331cb0ef41Sopenharmony_ci LoadObjectField(microtask, PromiseReactionJobTask::kHandlerOffset); 2341cb0ef41Sopenharmony_ci const TNode<HeapObject> promise_or_capability = CAST(LoadObjectField( 2351cb0ef41Sopenharmony_ci microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset)); 2361cb0ef41Sopenharmony_ci 2371cb0ef41Sopenharmony_ci TNode<Object> preserved_embedder_data = LoadObjectField( 2381cb0ef41Sopenharmony_ci microtask, 2391cb0ef41Sopenharmony_ci PromiseReactionJobTask::kContinuationPreservedEmbedderDataOffset); 2401cb0ef41Sopenharmony_ci Label preserved_data_done(this); 2411cb0ef41Sopenharmony_ci GotoIf(IsUndefined(preserved_embedder_data), &preserved_data_done); 2421cb0ef41Sopenharmony_ci StoreContextElement(native_context, 2431cb0ef41Sopenharmony_ci Context::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX, 2441cb0ef41Sopenharmony_ci preserved_embedder_data); 2451cb0ef41Sopenharmony_ci Goto(&preserved_data_done); 2461cb0ef41Sopenharmony_ci BIND(&preserved_data_done); 2471cb0ef41Sopenharmony_ci 2481cb0ef41Sopenharmony_ci // Run the promise before/debug hook if enabled. 2491cb0ef41Sopenharmony_ci RunAllPromiseHooks(PromiseHookType::kBefore, microtask_context, 2501cb0ef41Sopenharmony_ci promise_or_capability); 2511cb0ef41Sopenharmony_ci 2521cb0ef41Sopenharmony_ci { 2531cb0ef41Sopenharmony_ci ScopedExceptionHandler handler(this, &if_exception, &var_exception); 2541cb0ef41Sopenharmony_ci CallBuiltin(Builtin::kPromiseFulfillReactionJob, microtask_context, 2551cb0ef41Sopenharmony_ci argument, job_handler, promise_or_capability); 2561cb0ef41Sopenharmony_ci } 2571cb0ef41Sopenharmony_ci 2581cb0ef41Sopenharmony_ci // Run the promise after/debug hook if enabled. 2591cb0ef41Sopenharmony_ci RunAllPromiseHooks(PromiseHookType::kAfter, microtask_context, 2601cb0ef41Sopenharmony_ci promise_or_capability); 2611cb0ef41Sopenharmony_ci 2621cb0ef41Sopenharmony_ci Label preserved_data_reset_done(this); 2631cb0ef41Sopenharmony_ci GotoIf(IsUndefined(preserved_embedder_data), &preserved_data_reset_done); 2641cb0ef41Sopenharmony_ci StoreContextElement(native_context, 2651cb0ef41Sopenharmony_ci Context::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX, 2661cb0ef41Sopenharmony_ci UndefinedConstant()); 2671cb0ef41Sopenharmony_ci Goto(&preserved_data_reset_done); 2681cb0ef41Sopenharmony_ci BIND(&preserved_data_reset_done); 2691cb0ef41Sopenharmony_ci 2701cb0ef41Sopenharmony_ci RewindEnteredContext(saved_entered_context_count); 2711cb0ef41Sopenharmony_ci SetCurrentContext(current_context); 2721cb0ef41Sopenharmony_ci Goto(&done); 2731cb0ef41Sopenharmony_ci } 2741cb0ef41Sopenharmony_ci 2751cb0ef41Sopenharmony_ci BIND(&is_promise_reject_reaction_job); 2761cb0ef41Sopenharmony_ci { 2771cb0ef41Sopenharmony_ci // Enter the context of the {microtask}. 2781cb0ef41Sopenharmony_ci TNode<Context> microtask_context = LoadObjectField<Context>( 2791cb0ef41Sopenharmony_ci microtask, PromiseReactionJobTask::kContextOffset); 2801cb0ef41Sopenharmony_ci TNode<NativeContext> native_context = LoadNativeContext(microtask_context); 2811cb0ef41Sopenharmony_ci PrepareForContext(native_context, &done); 2821cb0ef41Sopenharmony_ci 2831cb0ef41Sopenharmony_ci const TNode<Object> argument = 2841cb0ef41Sopenharmony_ci LoadObjectField(microtask, PromiseReactionJobTask::kArgumentOffset); 2851cb0ef41Sopenharmony_ci const TNode<Object> job_handler = 2861cb0ef41Sopenharmony_ci LoadObjectField(microtask, PromiseReactionJobTask::kHandlerOffset); 2871cb0ef41Sopenharmony_ci const TNode<HeapObject> promise_or_capability = CAST(LoadObjectField( 2881cb0ef41Sopenharmony_ci microtask, PromiseReactionJobTask::kPromiseOrCapabilityOffset)); 2891cb0ef41Sopenharmony_ci 2901cb0ef41Sopenharmony_ci TNode<Object> preserved_embedder_data = LoadObjectField( 2911cb0ef41Sopenharmony_ci microtask, 2921cb0ef41Sopenharmony_ci PromiseReactionJobTask::kContinuationPreservedEmbedderDataOffset); 2931cb0ef41Sopenharmony_ci Label preserved_data_done(this); 2941cb0ef41Sopenharmony_ci GotoIf(IsUndefined(preserved_embedder_data), &preserved_data_done); 2951cb0ef41Sopenharmony_ci StoreContextElement(native_context, 2961cb0ef41Sopenharmony_ci Context::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX, 2971cb0ef41Sopenharmony_ci preserved_embedder_data); 2981cb0ef41Sopenharmony_ci Goto(&preserved_data_done); 2991cb0ef41Sopenharmony_ci BIND(&preserved_data_done); 3001cb0ef41Sopenharmony_ci 3011cb0ef41Sopenharmony_ci // Run the promise before/debug hook if enabled. 3021cb0ef41Sopenharmony_ci RunAllPromiseHooks(PromiseHookType::kBefore, microtask_context, 3031cb0ef41Sopenharmony_ci promise_or_capability); 3041cb0ef41Sopenharmony_ci 3051cb0ef41Sopenharmony_ci { 3061cb0ef41Sopenharmony_ci ScopedExceptionHandler handler(this, &if_exception, &var_exception); 3071cb0ef41Sopenharmony_ci CallBuiltin(Builtin::kPromiseRejectReactionJob, microtask_context, 3081cb0ef41Sopenharmony_ci argument, job_handler, promise_or_capability); 3091cb0ef41Sopenharmony_ci } 3101cb0ef41Sopenharmony_ci 3111cb0ef41Sopenharmony_ci // Run the promise after/debug hook if enabled. 3121cb0ef41Sopenharmony_ci RunAllPromiseHooks(PromiseHookType::kAfter, microtask_context, 3131cb0ef41Sopenharmony_ci promise_or_capability); 3141cb0ef41Sopenharmony_ci 3151cb0ef41Sopenharmony_ci Label preserved_data_reset_done(this); 3161cb0ef41Sopenharmony_ci GotoIf(IsUndefined(preserved_embedder_data), &preserved_data_reset_done); 3171cb0ef41Sopenharmony_ci StoreContextElement(native_context, 3181cb0ef41Sopenharmony_ci Context::CONTINUATION_PRESERVED_EMBEDDER_DATA_INDEX, 3191cb0ef41Sopenharmony_ci UndefinedConstant()); 3201cb0ef41Sopenharmony_ci Goto(&preserved_data_reset_done); 3211cb0ef41Sopenharmony_ci BIND(&preserved_data_reset_done); 3221cb0ef41Sopenharmony_ci 3231cb0ef41Sopenharmony_ci RewindEnteredContext(saved_entered_context_count); 3241cb0ef41Sopenharmony_ci SetCurrentContext(current_context); 3251cb0ef41Sopenharmony_ci Goto(&done); 3261cb0ef41Sopenharmony_ci } 3271cb0ef41Sopenharmony_ci 3281cb0ef41Sopenharmony_ci BIND(&is_unreachable); 3291cb0ef41Sopenharmony_ci Unreachable(); 3301cb0ef41Sopenharmony_ci 3311cb0ef41Sopenharmony_ci BIND(&if_exception); 3321cb0ef41Sopenharmony_ci { 3331cb0ef41Sopenharmony_ci // Report unhandled exceptions from microtasks. 3341cb0ef41Sopenharmony_ci CallRuntime(Runtime::kReportMessageFromMicrotask, GetCurrentContext(), 3351cb0ef41Sopenharmony_ci var_exception.value()); 3361cb0ef41Sopenharmony_ci RewindEnteredContext(saved_entered_context_count); 3371cb0ef41Sopenharmony_ci SetCurrentContext(current_context); 3381cb0ef41Sopenharmony_ci Goto(&done); 3391cb0ef41Sopenharmony_ci } 3401cb0ef41Sopenharmony_ci 3411cb0ef41Sopenharmony_ci BIND(&done); 3421cb0ef41Sopenharmony_ci} 3431cb0ef41Sopenharmony_ci 3441cb0ef41Sopenharmony_civoid MicrotaskQueueBuiltinsAssembler::IncrementFinishedMicrotaskCount( 3451cb0ef41Sopenharmony_ci TNode<RawPtrT> microtask_queue) { 3461cb0ef41Sopenharmony_ci TNode<IntPtrT> count = Load<IntPtrT>( 3471cb0ef41Sopenharmony_ci microtask_queue, 3481cb0ef41Sopenharmony_ci IntPtrConstant(MicrotaskQueue::kFinishedMicrotaskCountOffset)); 3491cb0ef41Sopenharmony_ci TNode<IntPtrT> new_count = IntPtrAdd(count, IntPtrConstant(1)); 3501cb0ef41Sopenharmony_ci StoreNoWriteBarrier( 3511cb0ef41Sopenharmony_ci MachineType::PointerRepresentation(), microtask_queue, 3521cb0ef41Sopenharmony_ci IntPtrConstant(MicrotaskQueue::kFinishedMicrotaskCountOffset), new_count); 3531cb0ef41Sopenharmony_ci} 3541cb0ef41Sopenharmony_ci 3551cb0ef41Sopenharmony_ciTNode<Context> MicrotaskQueueBuiltinsAssembler::GetCurrentContext() { 3561cb0ef41Sopenharmony_ci auto ref = ExternalReference::Create(kContextAddress, isolate()); 3571cb0ef41Sopenharmony_ci // TODO(delphick): Add a checked cast. For now this is not possible as context 3581cb0ef41Sopenharmony_ci // can actually be Smi(0). 3591cb0ef41Sopenharmony_ci return TNode<Context>::UncheckedCast(LoadFullTagged(ExternalConstant(ref))); 3601cb0ef41Sopenharmony_ci} 3611cb0ef41Sopenharmony_ci 3621cb0ef41Sopenharmony_civoid MicrotaskQueueBuiltinsAssembler::SetCurrentContext( 3631cb0ef41Sopenharmony_ci TNode<Context> context) { 3641cb0ef41Sopenharmony_ci auto ref = ExternalReference::Create(kContextAddress, isolate()); 3651cb0ef41Sopenharmony_ci StoreFullTaggedNoWriteBarrier(ExternalConstant(ref), context); 3661cb0ef41Sopenharmony_ci} 3671cb0ef41Sopenharmony_ci 3681cb0ef41Sopenharmony_ciTNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::GetEnteredContextCount() { 3691cb0ef41Sopenharmony_ci auto ref = ExternalReference::handle_scope_implementer_address(isolate()); 3701cb0ef41Sopenharmony_ci TNode<RawPtrT> hsi = Load<RawPtrT>(ExternalConstant(ref)); 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_ci using ContextStack = DetachableVector<Context>; 3731cb0ef41Sopenharmony_ci TNode<IntPtrT> size_offset = 3741cb0ef41Sopenharmony_ci IntPtrConstant(HandleScopeImplementer::kEnteredContextsOffset + 3751cb0ef41Sopenharmony_ci ContextStack::kSizeOffset); 3761cb0ef41Sopenharmony_ci return Load<IntPtrT>(hsi, size_offset); 3771cb0ef41Sopenharmony_ci} 3781cb0ef41Sopenharmony_ci 3791cb0ef41Sopenharmony_civoid MicrotaskQueueBuiltinsAssembler::EnterMicrotaskContext( 3801cb0ef41Sopenharmony_ci TNode<Context> native_context) { 3811cb0ef41Sopenharmony_ci CSA_DCHECK(this, IsNativeContext(native_context)); 3821cb0ef41Sopenharmony_ci 3831cb0ef41Sopenharmony_ci auto ref = ExternalReference::handle_scope_implementer_address(isolate()); 3841cb0ef41Sopenharmony_ci TNode<RawPtrT> hsi = Load<RawPtrT>(ExternalConstant(ref)); 3851cb0ef41Sopenharmony_ci 3861cb0ef41Sopenharmony_ci using ContextStack = DetachableVector<Context>; 3871cb0ef41Sopenharmony_ci TNode<IntPtrT> capacity_offset = 3881cb0ef41Sopenharmony_ci IntPtrConstant(HandleScopeImplementer::kEnteredContextsOffset + 3891cb0ef41Sopenharmony_ci ContextStack::kCapacityOffset); 3901cb0ef41Sopenharmony_ci TNode<IntPtrT> size_offset = 3911cb0ef41Sopenharmony_ci IntPtrConstant(HandleScopeImplementer::kEnteredContextsOffset + 3921cb0ef41Sopenharmony_ci ContextStack::kSizeOffset); 3931cb0ef41Sopenharmony_ci 3941cb0ef41Sopenharmony_ci TNode<IntPtrT> capacity = Load<IntPtrT>(hsi, capacity_offset); 3951cb0ef41Sopenharmony_ci TNode<IntPtrT> size = Load<IntPtrT>(hsi, size_offset); 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ci Label if_append(this), if_grow(this, Label::kDeferred), done(this); 3981cb0ef41Sopenharmony_ci Branch(WordEqual(size, capacity), &if_grow, &if_append); 3991cb0ef41Sopenharmony_ci BIND(&if_append); 4001cb0ef41Sopenharmony_ci { 4011cb0ef41Sopenharmony_ci TNode<IntPtrT> data_offset = 4021cb0ef41Sopenharmony_ci IntPtrConstant(HandleScopeImplementer::kEnteredContextsOffset + 4031cb0ef41Sopenharmony_ci ContextStack::kDataOffset); 4041cb0ef41Sopenharmony_ci TNode<RawPtrT> data = Load<RawPtrT>(hsi, data_offset); 4051cb0ef41Sopenharmony_ci StoreFullTaggedNoWriteBarrier(data, TimesSystemPointerSize(size), 4061cb0ef41Sopenharmony_ci native_context); 4071cb0ef41Sopenharmony_ci 4081cb0ef41Sopenharmony_ci TNode<IntPtrT> new_size = IntPtrAdd(size, IntPtrConstant(1)); 4091cb0ef41Sopenharmony_ci StoreNoWriteBarrier(MachineType::PointerRepresentation(), hsi, size_offset, 4101cb0ef41Sopenharmony_ci new_size); 4111cb0ef41Sopenharmony_ci 4121cb0ef41Sopenharmony_ci using FlagStack = DetachableVector<int8_t>; 4131cb0ef41Sopenharmony_ci TNode<IntPtrT> flag_data_offset = 4141cb0ef41Sopenharmony_ci IntPtrConstant(HandleScopeImplementer::kIsMicrotaskContextOffset + 4151cb0ef41Sopenharmony_ci FlagStack::kDataOffset); 4161cb0ef41Sopenharmony_ci TNode<IntPtrT> flag_capacity_offset = 4171cb0ef41Sopenharmony_ci IntPtrConstant(HandleScopeImplementer::kIsMicrotaskContextOffset + 4181cb0ef41Sopenharmony_ci FlagStack::kCapacityOffset); 4191cb0ef41Sopenharmony_ci TNode<IntPtrT> flag_size_offset = 4201cb0ef41Sopenharmony_ci IntPtrConstant(HandleScopeImplementer::kIsMicrotaskContextOffset + 4211cb0ef41Sopenharmony_ci FlagStack::kSizeOffset); 4221cb0ef41Sopenharmony_ci // Ensure both stacks are in sync. 4231cb0ef41Sopenharmony_ci USE(flag_capacity_offset); 4241cb0ef41Sopenharmony_ci CSA_DCHECK(this, 4251cb0ef41Sopenharmony_ci WordEqual(capacity, Load<IntPtrT>(hsi, flag_capacity_offset))); 4261cb0ef41Sopenharmony_ci CSA_DCHECK(this, WordEqual(size, Load<IntPtrT>(hsi, flag_size_offset))); 4271cb0ef41Sopenharmony_ci 4281cb0ef41Sopenharmony_ci TNode<RawPtrT> flag_data = Load<RawPtrT>(hsi, flag_data_offset); 4291cb0ef41Sopenharmony_ci StoreNoWriteBarrier(MachineRepresentation::kWord8, flag_data, size, 4301cb0ef41Sopenharmony_ci BoolConstant(true)); 4311cb0ef41Sopenharmony_ci StoreNoWriteBarrier(MachineType::PointerRepresentation(), hsi, 4321cb0ef41Sopenharmony_ci flag_size_offset, new_size); 4331cb0ef41Sopenharmony_ci 4341cb0ef41Sopenharmony_ci Goto(&done); 4351cb0ef41Sopenharmony_ci } 4361cb0ef41Sopenharmony_ci 4371cb0ef41Sopenharmony_ci BIND(&if_grow); 4381cb0ef41Sopenharmony_ci { 4391cb0ef41Sopenharmony_ci TNode<ExternalReference> function = 4401cb0ef41Sopenharmony_ci ExternalConstant(ExternalReference::call_enter_context_function()); 4411cb0ef41Sopenharmony_ci CallCFunction(function, MachineType::Int32(), 4421cb0ef41Sopenharmony_ci std::make_pair(MachineType::Pointer(), hsi), 4431cb0ef41Sopenharmony_ci std::make_pair(MachineType::Pointer(), 4441cb0ef41Sopenharmony_ci BitcastTaggedToWord(native_context))); 4451cb0ef41Sopenharmony_ci Goto(&done); 4461cb0ef41Sopenharmony_ci } 4471cb0ef41Sopenharmony_ci 4481cb0ef41Sopenharmony_ci BIND(&done); 4491cb0ef41Sopenharmony_ci} 4501cb0ef41Sopenharmony_ci 4511cb0ef41Sopenharmony_civoid MicrotaskQueueBuiltinsAssembler::RewindEnteredContext( 4521cb0ef41Sopenharmony_ci TNode<IntPtrT> saved_entered_context_count) { 4531cb0ef41Sopenharmony_ci auto ref = ExternalReference::handle_scope_implementer_address(isolate()); 4541cb0ef41Sopenharmony_ci TNode<RawPtrT> hsi = Load<RawPtrT>(ExternalConstant(ref)); 4551cb0ef41Sopenharmony_ci 4561cb0ef41Sopenharmony_ci using ContextStack = DetachableVector<Context>; 4571cb0ef41Sopenharmony_ci TNode<IntPtrT> size_offset = 4581cb0ef41Sopenharmony_ci IntPtrConstant(HandleScopeImplementer::kEnteredContextsOffset + 4591cb0ef41Sopenharmony_ci ContextStack::kSizeOffset); 4601cb0ef41Sopenharmony_ci 4611cb0ef41Sopenharmony_ci if (DEBUG_BOOL) { 4621cb0ef41Sopenharmony_ci TNode<IntPtrT> size = Load<IntPtrT>(hsi, size_offset); 4631cb0ef41Sopenharmony_ci CSA_CHECK(this, IntPtrLessThan(IntPtrConstant(0), size)); 4641cb0ef41Sopenharmony_ci CSA_CHECK(this, IntPtrLessThanOrEqual(saved_entered_context_count, size)); 4651cb0ef41Sopenharmony_ci } 4661cb0ef41Sopenharmony_ci 4671cb0ef41Sopenharmony_ci StoreNoWriteBarrier(MachineType::PointerRepresentation(), hsi, size_offset, 4681cb0ef41Sopenharmony_ci saved_entered_context_count); 4691cb0ef41Sopenharmony_ci 4701cb0ef41Sopenharmony_ci using FlagStack = DetachableVector<int8_t>; 4711cb0ef41Sopenharmony_ci StoreNoWriteBarrier( 4721cb0ef41Sopenharmony_ci MachineType::PointerRepresentation(), hsi, 4731cb0ef41Sopenharmony_ci IntPtrConstant(HandleScopeImplementer::kIsMicrotaskContextOffset + 4741cb0ef41Sopenharmony_ci FlagStack::kSizeOffset), 4751cb0ef41Sopenharmony_ci saved_entered_context_count); 4761cb0ef41Sopenharmony_ci} 4771cb0ef41Sopenharmony_ci 4781cb0ef41Sopenharmony_civoid MicrotaskQueueBuiltinsAssembler::RunAllPromiseHooks( 4791cb0ef41Sopenharmony_ci PromiseHookType type, TNode<Context> context, 4801cb0ef41Sopenharmony_ci TNode<HeapObject> promise_or_capability) { 4811cb0ef41Sopenharmony_ci TNode<Uint32T> promiseHookFlags = PromiseHookFlags(); 4821cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS 4831cb0ef41Sopenharmony_ci Label hook(this, Label::kDeferred), done_hook(this); 4841cb0ef41Sopenharmony_ci Branch(NeedsAnyPromiseHooks(promiseHookFlags), &hook, &done_hook); 4851cb0ef41Sopenharmony_ci BIND(&hook); 4861cb0ef41Sopenharmony_ci { 4871cb0ef41Sopenharmony_ci#endif 4881cb0ef41Sopenharmony_ci switch (type) { 4891cb0ef41Sopenharmony_ci case PromiseHookType::kBefore: 4901cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS 4911cb0ef41Sopenharmony_ci RunContextPromiseHookBefore(context, promise_or_capability, 4921cb0ef41Sopenharmony_ci promiseHookFlags); 4931cb0ef41Sopenharmony_ci#endif 4941cb0ef41Sopenharmony_ci RunPromiseHook(Runtime::kPromiseHookBefore, context, 4951cb0ef41Sopenharmony_ci promise_or_capability, promiseHookFlags); 4961cb0ef41Sopenharmony_ci break; 4971cb0ef41Sopenharmony_ci case PromiseHookType::kAfter: 4981cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS 4991cb0ef41Sopenharmony_ci RunContextPromiseHookAfter(context, promise_or_capability, 5001cb0ef41Sopenharmony_ci promiseHookFlags); 5011cb0ef41Sopenharmony_ci#endif 5021cb0ef41Sopenharmony_ci RunPromiseHook(Runtime::kPromiseHookAfter, context, 5031cb0ef41Sopenharmony_ci promise_or_capability, promiseHookFlags); 5041cb0ef41Sopenharmony_ci break; 5051cb0ef41Sopenharmony_ci default: 5061cb0ef41Sopenharmony_ci UNREACHABLE(); 5071cb0ef41Sopenharmony_ci } 5081cb0ef41Sopenharmony_ci#ifdef V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS 5091cb0ef41Sopenharmony_ci Goto(&done_hook); 5101cb0ef41Sopenharmony_ci } 5111cb0ef41Sopenharmony_ci BIND(&done_hook); 5121cb0ef41Sopenharmony_ci#endif 5131cb0ef41Sopenharmony_ci} 5141cb0ef41Sopenharmony_ci 5151cb0ef41Sopenharmony_civoid MicrotaskQueueBuiltinsAssembler::RunPromiseHook( 5161cb0ef41Sopenharmony_ci Runtime::FunctionId id, TNode<Context> context, 5171cb0ef41Sopenharmony_ci TNode<HeapObject> promise_or_capability, 5181cb0ef41Sopenharmony_ci TNode<Uint32T> promiseHookFlags) { 5191cb0ef41Sopenharmony_ci Label hook(this, Label::kDeferred), done_hook(this); 5201cb0ef41Sopenharmony_ci Branch(IsIsolatePromiseHookEnabledOrDebugIsActiveOrHasAsyncEventDelegate( 5211cb0ef41Sopenharmony_ci promiseHookFlags), &hook, &done_hook); 5221cb0ef41Sopenharmony_ci BIND(&hook); 5231cb0ef41Sopenharmony_ci { 5241cb0ef41Sopenharmony_ci // Get to the underlying JSPromise instance. 5251cb0ef41Sopenharmony_ci TNode<HeapObject> promise = Select<HeapObject>( 5261cb0ef41Sopenharmony_ci IsPromiseCapability(promise_or_capability), 5271cb0ef41Sopenharmony_ci [=] { 5281cb0ef41Sopenharmony_ci return CAST(LoadObjectField(promise_or_capability, 5291cb0ef41Sopenharmony_ci PromiseCapability::kPromiseOffset)); 5301cb0ef41Sopenharmony_ci }, 5311cb0ef41Sopenharmony_ci 5321cb0ef41Sopenharmony_ci [=] { return promise_or_capability; }); 5331cb0ef41Sopenharmony_ci GotoIf(IsUndefined(promise), &done_hook); 5341cb0ef41Sopenharmony_ci CallRuntime(id, context, promise); 5351cb0ef41Sopenharmony_ci Goto(&done_hook); 5361cb0ef41Sopenharmony_ci } 5371cb0ef41Sopenharmony_ci BIND(&done_hook); 5381cb0ef41Sopenharmony_ci} 5391cb0ef41Sopenharmony_ci 5401cb0ef41Sopenharmony_ciTF_BUILTIN(EnqueueMicrotask, MicrotaskQueueBuiltinsAssembler) { 5411cb0ef41Sopenharmony_ci auto microtask = Parameter<Microtask>(Descriptor::kMicrotask); 5421cb0ef41Sopenharmony_ci auto context = Parameter<Context>(Descriptor::kContext); 5431cb0ef41Sopenharmony_ci TNode<NativeContext> native_context = LoadNativeContext(context); 5441cb0ef41Sopenharmony_ci TNode<RawPtrT> microtask_queue = GetMicrotaskQueue(native_context); 5451cb0ef41Sopenharmony_ci 5461cb0ef41Sopenharmony_ci // Do not store the microtask if MicrotaskQueue is not available, that may 5471cb0ef41Sopenharmony_ci // happen when the context shutdown. 5481cb0ef41Sopenharmony_ci Label if_shutdown(this, Label::kDeferred); 5491cb0ef41Sopenharmony_ci GotoIf(WordEqual(microtask_queue, IntPtrConstant(0)), &if_shutdown); 5501cb0ef41Sopenharmony_ci 5511cb0ef41Sopenharmony_ci TNode<RawPtrT> ring_buffer = GetMicrotaskRingBuffer(microtask_queue); 5521cb0ef41Sopenharmony_ci TNode<IntPtrT> capacity = GetMicrotaskQueueCapacity(microtask_queue); 5531cb0ef41Sopenharmony_ci TNode<IntPtrT> size = GetMicrotaskQueueSize(microtask_queue); 5541cb0ef41Sopenharmony_ci TNode<IntPtrT> start = GetMicrotaskQueueStart(microtask_queue); 5551cb0ef41Sopenharmony_ci 5561cb0ef41Sopenharmony_ci Label if_grow(this, Label::kDeferred); 5571cb0ef41Sopenharmony_ci GotoIf(IntPtrEqual(size, capacity), &if_grow); 5581cb0ef41Sopenharmony_ci 5591cb0ef41Sopenharmony_ci // |microtask_queue| has an unused slot to store |microtask|. 5601cb0ef41Sopenharmony_ci { 5611cb0ef41Sopenharmony_ci StoreNoWriteBarrier(MachineType::PointerRepresentation(), ring_buffer, 5621cb0ef41Sopenharmony_ci CalculateRingBufferOffset(capacity, start, size), 5631cb0ef41Sopenharmony_ci BitcastTaggedToWord(microtask)); 5641cb0ef41Sopenharmony_ci StoreNoWriteBarrier(MachineType::PointerRepresentation(), microtask_queue, 5651cb0ef41Sopenharmony_ci IntPtrConstant(MicrotaskQueue::kSizeOffset), 5661cb0ef41Sopenharmony_ci IntPtrAdd(size, IntPtrConstant(1))); 5671cb0ef41Sopenharmony_ci Return(UndefinedConstant()); 5681cb0ef41Sopenharmony_ci } 5691cb0ef41Sopenharmony_ci 5701cb0ef41Sopenharmony_ci // |microtask_queue| has no space to store |microtask|. Fall back to C++ 5711cb0ef41Sopenharmony_ci // implementation to grow the buffer. 5721cb0ef41Sopenharmony_ci BIND(&if_grow); 5731cb0ef41Sopenharmony_ci { 5741cb0ef41Sopenharmony_ci TNode<ExternalReference> isolate_constant = 5751cb0ef41Sopenharmony_ci ExternalConstant(ExternalReference::isolate_address(isolate())); 5761cb0ef41Sopenharmony_ci TNode<ExternalReference> function = 5771cb0ef41Sopenharmony_ci ExternalConstant(ExternalReference::call_enqueue_microtask_function()); 5781cb0ef41Sopenharmony_ci CallCFunction(function, MachineType::AnyTagged(), 5791cb0ef41Sopenharmony_ci std::make_pair(MachineType::Pointer(), isolate_constant), 5801cb0ef41Sopenharmony_ci std::make_pair(MachineType::IntPtr(), microtask_queue), 5811cb0ef41Sopenharmony_ci std::make_pair(MachineType::AnyTagged(), microtask)); 5821cb0ef41Sopenharmony_ci Return(UndefinedConstant()); 5831cb0ef41Sopenharmony_ci } 5841cb0ef41Sopenharmony_ci 5851cb0ef41Sopenharmony_ci Bind(&if_shutdown); 5861cb0ef41Sopenharmony_ci Return(UndefinedConstant()); 5871cb0ef41Sopenharmony_ci} 5881cb0ef41Sopenharmony_ci 5891cb0ef41Sopenharmony_ciTF_BUILTIN(RunMicrotasks, MicrotaskQueueBuiltinsAssembler) { 5901cb0ef41Sopenharmony_ci // Load the current context from the isolate. 5911cb0ef41Sopenharmony_ci TNode<Context> current_context = GetCurrentContext(); 5921cb0ef41Sopenharmony_ci 5931cb0ef41Sopenharmony_ci auto microtask_queue = 5941cb0ef41Sopenharmony_ci UncheckedParameter<RawPtrT>(Descriptor::kMicrotaskQueue); 5951cb0ef41Sopenharmony_ci 5961cb0ef41Sopenharmony_ci Label loop(this), done(this); 5971cb0ef41Sopenharmony_ci Goto(&loop); 5981cb0ef41Sopenharmony_ci BIND(&loop); 5991cb0ef41Sopenharmony_ci 6001cb0ef41Sopenharmony_ci TNode<IntPtrT> size = GetMicrotaskQueueSize(microtask_queue); 6011cb0ef41Sopenharmony_ci 6021cb0ef41Sopenharmony_ci // Exit if the queue is empty. 6031cb0ef41Sopenharmony_ci GotoIf(WordEqual(size, IntPtrConstant(0)), &done); 6041cb0ef41Sopenharmony_ci 6051cb0ef41Sopenharmony_ci TNode<RawPtrT> ring_buffer = GetMicrotaskRingBuffer(microtask_queue); 6061cb0ef41Sopenharmony_ci TNode<IntPtrT> capacity = GetMicrotaskQueueCapacity(microtask_queue); 6071cb0ef41Sopenharmony_ci TNode<IntPtrT> start = GetMicrotaskQueueStart(microtask_queue); 6081cb0ef41Sopenharmony_ci 6091cb0ef41Sopenharmony_ci TNode<IntPtrT> offset = 6101cb0ef41Sopenharmony_ci CalculateRingBufferOffset(capacity, start, IntPtrConstant(0)); 6111cb0ef41Sopenharmony_ci TNode<RawPtrT> microtask_pointer = Load<RawPtrT>(ring_buffer, offset); 6121cb0ef41Sopenharmony_ci TNode<Microtask> microtask = CAST(BitcastWordToTagged(microtask_pointer)); 6131cb0ef41Sopenharmony_ci 6141cb0ef41Sopenharmony_ci TNode<IntPtrT> new_size = IntPtrSub(size, IntPtrConstant(1)); 6151cb0ef41Sopenharmony_ci TNode<IntPtrT> new_start = WordAnd(IntPtrAdd(start, IntPtrConstant(1)), 6161cb0ef41Sopenharmony_ci IntPtrSub(capacity, IntPtrConstant(1))); 6171cb0ef41Sopenharmony_ci 6181cb0ef41Sopenharmony_ci // Remove |microtask| from |ring_buffer| before running it, since its 6191cb0ef41Sopenharmony_ci // invocation may add another microtask into |ring_buffer|. 6201cb0ef41Sopenharmony_ci SetMicrotaskQueueSize(microtask_queue, new_size); 6211cb0ef41Sopenharmony_ci SetMicrotaskQueueStart(microtask_queue, new_start); 6221cb0ef41Sopenharmony_ci 6231cb0ef41Sopenharmony_ci RunSingleMicrotask(current_context, microtask); 6241cb0ef41Sopenharmony_ci IncrementFinishedMicrotaskCount(microtask_queue); 6251cb0ef41Sopenharmony_ci Goto(&loop); 6261cb0ef41Sopenharmony_ci 6271cb0ef41Sopenharmony_ci BIND(&done); 6281cb0ef41Sopenharmony_ci { 6291cb0ef41Sopenharmony_ci // Reset the "current microtask" on the isolate. 6301cb0ef41Sopenharmony_ci StoreRoot(RootIndex::kCurrentMicrotask, UndefinedConstant()); 6311cb0ef41Sopenharmony_ci Return(UndefinedConstant()); 6321cb0ef41Sopenharmony_ci } 6331cb0ef41Sopenharmony_ci} 6341cb0ef41Sopenharmony_ci 6351cb0ef41Sopenharmony_ci} // namespace internal 6361cb0ef41Sopenharmony_ci} // namespace v8 637