diff --git a/ecmascript/builtins/builtins_weak_ref.cpp b/ecmascript/builtins/builtins_weak_ref.cpp index ad4b85a330..ff5701b362 100644 --- a/ecmascript/builtins/builtins_weak_ref.cpp +++ b/ecmascript/builtins/builtins_weak_ref.cpp @@ -42,7 +42,7 @@ JSTaggedValue BuiltinsWeakRef::WeakRefConstructor(EcmaRuntimeCallInfo *argv) JSHandle obj = factory->NewJSObjectByConstructor(JSHandle(constructor), newTarget); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 4. Perform ! AddToKeptObjects(target). - thread->GetEcmaVM()->GetHeap()->AddToKeptObjects(target); + thread->GetCurrentEcmaContext()->AddToKeptObjects(target); // 5. Set weakRef.[[WeakRefTarget]] to target. // 6. Return weakRef. JSHandle weakRef = JSHandle::Cast(obj); diff --git a/ecmascript/checkpoint/thread_state_transition.h b/ecmascript/checkpoint/thread_state_transition.h index 19b73282d9..1154408925 100644 --- a/ecmascript/checkpoint/thread_state_transition.h +++ b/ecmascript/checkpoint/thread_state_transition.h @@ -32,6 +32,8 @@ public: oldState_ = self_->GetState(); if constexpr (std::is_same_v) { if (oldState_ != newState) { + ASSERT(hasSwitchState_ == false); + hasSwitchState_ = true; if constexpr (newState == ThreadState::RUNNING) { self_->TransferDaemonThreadToRunning(); } else { @@ -52,6 +54,8 @@ public: vm->IncreaseUpdateThreadStateTransCount(); } #endif + ASSERT(hasSwitchState_ == false); + hasSwitchState_ = true; self_->UpdateState(newState); } } @@ -59,7 +63,7 @@ public: ~ThreadStateTransitionScope() { - if (oldState_ != self_->GetState()) { + if (hasSwitchState_) { if constexpr (std::is_same_v) { if (oldState_ == ThreadState::RUNNING) { self_->TransferDaemonThreadToRunning(); @@ -75,6 +79,7 @@ public: private: T* self_; ThreadState oldState_; + bool hasSwitchState_ {false}; NO_COPY_SEMANTIC(ThreadStateTransitionScope); }; diff --git a/ecmascript/ecma_context.cpp b/ecmascript/ecma_context.cpp index 75f2a925b4..5365e2c1c8 100644 --- a/ecmascript/ecma_context.cpp +++ b/ecmascript/ecma_context.cpp @@ -37,6 +37,7 @@ #include "ecmascript/jspandafile/program_object.h" #include "ecmascript/js_function.h" #include "ecmascript/js_thread.h" +#include "ecmascript/linked_hash_table.h" #include "ecmascript/log.h" #include "ecmascript/log_wrapper.h" #include "ecmascript/module/module_path_helper.h" @@ -192,7 +193,10 @@ EcmaContext::~EcmaContext() } handleStorageNodes_.clear(); currentHandleStorageIndex_ = -1; +#ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK handleScopeCount_ = 0; + primitiveScopeCount_ = 0; +#endif handleScopeStorageNext_ = handleScopeStorageEnd_ = nullptr; for (auto n : primitiveStorageNodes_) { @@ -200,7 +204,6 @@ EcmaContext::~EcmaContext() } primitiveStorageNodes_.clear(); currentPrimitiveStorageIndex_ = -1; - primitiveScopeCount_ = 0; primitiveScopeStorageNext_ = primitiveScopeStorageEnd_ = nullptr; if (vm_->IsEnableBaselineJit() || vm_->IsEnableFastJit()) { @@ -779,10 +782,12 @@ void EcmaContext::PrintJSErrorInfo(JSThread *thread, const JSHandleHasTerminated())) { return false; } - return job::MicroJobQueue::HasPendingJob(thread_, GetMicroJobQueue()); + TaggedQueue* promiseQueue = TaggedQueue::Cast(GetMicroJobQueue()->GetPromiseJobQueue().GetTaggedObject()); + return !promiseQueue->Empty(); } bool EcmaContext::ExecutePromisePendingJob() @@ -1184,4 +1189,28 @@ void EcmaContext::RemoveSustainingJSHandle(SustainingJSHandle *sustainingHandle) sustainingJSHandleList_->RemoveSustainingJSHandle(sustainingHandle); } } + +void EcmaContext::ClearKeptObjects() +{ + if (LIKELY(GetGlobalEnv()->GetTaggedWeakRefKeepObjects().IsUndefined())) { + return; + } + GetGlobalEnv()->SetWeakRefKeepObjects(thread_, JSTaggedValue::Undefined()); + hasKeptObjects_ = false; +} + +void EcmaContext::AddToKeptObjects(JSHandle value) +{ + JSHandle globalEnv = GetGlobalEnv(); + JSHandle linkedSet; + if (globalEnv->GetWeakRefKeepObjects()->IsUndefined()) { + linkedSet = LinkedHashSet::Create(thread_); + } else { + linkedSet = JSHandle(thread_, + LinkedHashSet::Cast(globalEnv->GetWeakRefKeepObjects()->GetTaggedObject())); + } + linkedSet = LinkedHashSet::Add(thread_, linkedSet, value); + globalEnv->SetWeakRefKeepObjects(thread_, linkedSet); + hasKeptObjects_ = true; +} } // namespace panda::ecmascript diff --git a/ecmascript/ecma_context.h b/ecmascript/ecma_context.h index d015b4f1d1..67da01b0cc 100644 --- a/ecmascript/ecma_context.h +++ b/ecmascript/ecma_context.h @@ -370,6 +370,7 @@ public: return currentHandleStorageIndex_; } +#ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK void HandleScopeCountAdd() { handleScopeCount_++; @@ -380,6 +381,17 @@ public: handleScopeCount_--; } + void PrimitiveScopeCountAdd() + { + primitiveScopeCount_++; + } + + void PrimitiveScopeCountDec() + { + primitiveScopeCount_--; + } +#endif + void SetLastHandleScope(EcmaHandleScope *scope) { lastHandleScope_ = scope; @@ -415,16 +427,6 @@ public: return currentPrimitiveStorageIndex_; } - void PrimitiveScopeCountAdd() - { - primitiveScopeCount_++; - } - - void PrimitiveScopeCountDec() - { - primitiveScopeCount_--; - } - void SetLastPrimitiveScope(EcmaHandleScope *scope) { lastPrimitiveScope_ = scope; @@ -561,6 +563,12 @@ public: void AddSustainingJSHandle(SustainingJSHandle*); void RemoveSustainingJSHandle(SustainingJSHandle*); + void ClearKeptObjects(); + void AddToKeptObjects(JSHandle value); + inline bool HasKeptObjects() const + { + return hasKeptObjects_; + } private: void CJSExecution(JSHandle &func, JSHandle &thisArg, const JSPandaFile *jsPandaFile, std::string_view entryPoint); @@ -658,7 +666,10 @@ private: JSTaggedType *handleScopeStorageEnd_ {nullptr}; std::vector *> handleStorageNodes_ {}; int32_t currentHandleStorageIndex_ {-1}; +#ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK int32_t handleScopeCount_ {0}; + int32_t primitiveScopeCount_ {0}; +#endif EcmaHandleScope *lastHandleScope_ {nullptr}; // PrimitveScope static constexpr int32_t MIN_PRIMITIVE_STORAGE_SIZE = 2; @@ -666,7 +677,6 @@ private: JSTaggedType *primitiveScopeStorageEnd_ {nullptr}; std::vector *> primitiveStorageNodes_ {}; int32_t currentPrimitiveStorageIndex_ {-1}; - int32_t primitiveScopeCount_ {0}; EcmaHandleScope *lastPrimitiveScope_ {nullptr}; // Frame pointer @@ -688,6 +698,8 @@ private: // SustainingJSHandleList for jit compile hold ref SustainingJSHandleList *sustainingJSHandleList_ {nullptr}; + bool hasKeptObjects_ {false}; + friend class EcmaHandleScope; friend class JSPandaFileExecutor; friend class ObjectFactory; diff --git a/ecmascript/global_env_constants.cpp b/ecmascript/global_env_constants.cpp index f3f83fe0b8..6b926a270c 100644 --- a/ecmascript/global_env_constants.cpp +++ b/ecmascript/global_env_constants.cpp @@ -275,6 +275,7 @@ void GlobalEnvConstants::InitSharedMiscellanious(JSThread *thread, ObjectFactory // Specials SetConstant(ConstantIndex::UNDEFINED_INDEX, JSTaggedValue::Undefined()); SetConstant(ConstantIndex::NULL_INDEX, JSTaggedValue::Null()); + SetConstant(ConstantIndex::HOLE_INDEX, JSTaggedValue::Hole()); SetConstant(ConstantIndex::TRUE_INDEX, JSTaggedValue::True()); SetConstant(ConstantIndex::FALSE_INDEX, JSTaggedValue::False()); // Emptys diff --git a/ecmascript/global_env_constants.h b/ecmascript/global_env_constants.h index 6fdf9823c8..b903c66378 100644 --- a/ecmascript/global_env_constants.h +++ b/ecmascript/global_env_constants.h @@ -626,6 +626,7 @@ class ObjectFactory; #define SHARED_GLOBAL_ENV_CONSTANT_SPECIAL(V) \ V(JSTaggedValue, Undefined, UNDEFINED_INDEX, ecma_roots_special) \ V(JSTaggedValue, Null, NULL_INDEX, ecma_roots_special) \ + V(JSTaggedValue, Hole, HOLE_INDEX, ecma_roots_special) \ V(JSTaggedValue, True, TRUE_INDEX, ecma_roots_special) \ V(JSTaggedValue, False, FALSE_INDEX, ecma_roots_special) \ V(JSTaggedValue, EmptyString, EMPTY_STRING_OBJECT_INDEX, ecma_roots_special) \ diff --git a/ecmascript/jobs/micro_job_queue.cpp b/ecmascript/jobs/micro_job_queue.cpp index 391dde935b..85f91746e8 100644 --- a/ecmascript/jobs/micro_job_queue.cpp +++ b/ecmascript/jobs/micro_job_queue.cpp @@ -126,11 +126,4 @@ void MicroJobQueue::ExecutePendingJob(JSThread *thread, JSHandle } } } - -bool MicroJobQueue::HasPendingJob(JSThread *thread, JSHandle jobQueue) -{ - [[maybe_unused]] EcmaHandleScope handleScope(thread); - JSHandle promiseQueue(thread, jobQueue->GetPromiseJobQueue()); - return !promiseQueue->Empty(); -} } // namespace panda::ecmascript::job diff --git a/ecmascript/jobs/micro_job_queue.h b/ecmascript/jobs/micro_job_queue.h index 35f04c5499..5f483329a6 100644 --- a/ecmascript/jobs/micro_job_queue.h +++ b/ecmascript/jobs/micro_job_queue.h @@ -39,7 +39,6 @@ public: static void EnqueueJob(JSThread *thread, JSHandle jobQueue, QueueType queueType, const JSHandle &job, const JSHandle &argv); static void ExecutePendingJob(JSThread *thread, JSHandle jobQueue); - static bool HasPendingJob(JSThread *thread, JSHandle jobQueue); static constexpr size_t PROMISE_JOB_QUEUE_OFFSET = Record::SIZE; ACCESSORS(PromiseJobQueue, PROMISE_JOB_QUEUE_OFFSET, SCRIPT_JOB_QUEUE_OFFSET); diff --git a/ecmascript/js_thread.cpp b/ecmascript/js_thread.cpp index 5fdc32736f..14844e2ecc 100644 --- a/ecmascript/js_thread.cpp +++ b/ecmascript/js_thread.cpp @@ -629,21 +629,23 @@ size_t JSThread::GetBuiltinPrototypeHClassOffset(BuiltinTypeId type, bool isArch void JSThread::CheckSwitchDebuggerBCStub() { auto isDebug = GetEcmaVM()->GetJsDebuggerManager()->IsDebugMode(); - if (isDebug && - glueData_.bcDebuggerStubEntries_.Get(0) == glueData_.bcDebuggerStubEntries_.Get(1)) { - for (size_t i = 0; i < BCStubEntries::BC_HANDLER_COUNT; i++) { - auto stubEntry = glueData_.bcStubEntries_.Get(i); - auto debuggerStubEbtry = glueData_.bcDebuggerStubEntries_.Get(i); - glueData_.bcDebuggerStubEntries_.Set(i, stubEntry); - glueData_.bcStubEntries_.Set(i, debuggerStubEbtry); + if (LIKELY(!isDebug)) { + if (glueData_.bcStubEntries_.Get(0) == glueData_.bcStubEntries_.Get(1)) { + for (size_t i = 0; i < BCStubEntries::BC_HANDLER_COUNT; i++) { + auto stubEntry = glueData_.bcDebuggerStubEntries_.Get(i); + auto debuggerStubEbtry = glueData_.bcStubEntries_.Get(i); + glueData_.bcStubEntries_.Set(i, stubEntry); + glueData_.bcDebuggerStubEntries_.Set(i, debuggerStubEbtry); + } } - } else if (!isDebug && - glueData_.bcStubEntries_.Get(0) == glueData_.bcStubEntries_.Get(1)) { - for (size_t i = 0; i < BCStubEntries::BC_HANDLER_COUNT; i++) { - auto stubEntry = glueData_.bcDebuggerStubEntries_.Get(i); - auto debuggerStubEbtry = glueData_.bcStubEntries_.Get(i); - glueData_.bcStubEntries_.Set(i, stubEntry); - glueData_.bcDebuggerStubEntries_.Set(i, debuggerStubEbtry); + } else { + if (glueData_.bcDebuggerStubEntries_.Get(0) == glueData_.bcDebuggerStubEntries_.Get(1)) { + for (size_t i = 0; i < BCStubEntries::BC_HANDLER_COUNT; i++) { + auto stubEntry = glueData_.bcStubEntries_.Get(i); + auto debuggerStubEbtry = glueData_.bcDebuggerStubEntries_.Get(i); + glueData_.bcDebuggerStubEntries_.Set(i, stubEntry); + glueData_.bcStubEntries_.Set(i, debuggerStubEbtry); + } } } } diff --git a/ecmascript/js_thread.h b/ecmascript/js_thread.h index 3dbdb717b7..bb4a29acae 100644 --- a/ecmascript/js_thread.h +++ b/ecmascript/js_thread.h @@ -849,14 +849,13 @@ public: volatile auto interruptValue = reinterpret_cast *>(&glueData_.interruptVector_); uint64_t oldValue = interruptValue->load(std::memory_order_relaxed); - uint64_t oldValueBeforeCAS; + auto newValue = oldValue; do { - auto newValue = oldValue; + newValue = oldValue; T::Set(value, &newValue); - oldValueBeforeCAS = oldValue; - std::atomic_compare_exchange_strong_explicit(interruptValue, &oldValue, newValue, - std::memory_order_release, std::memory_order_relaxed); - } while (oldValue != oldValueBeforeCAS); + } while (!std::atomic_compare_exchange_strong_explicit(interruptValue, &oldValue, newValue, + std::memory_order_release, + std::memory_order_relaxed)); } void InvokeWeakNodeFreeGlobalCallBack(); diff --git a/ecmascript/js_weak_ref.h b/ecmascript/js_weak_ref.h index 4d099122af..b935fe68ec 100644 --- a/ecmascript/js_weak_ref.h +++ b/ecmascript/js_weak_ref.h @@ -38,7 +38,7 @@ public: // 3. Return undefined. JSHandle target(thread, weakRef->GetFromWeak()); if (!target->IsUndefined()) { - thread->GetEcmaVM()->GetHeap()->AddToKeptObjects(target); + thread->GetCurrentEcmaContext()->AddToKeptObjects(target); } return target.GetTaggedValue(); } diff --git a/ecmascript/mem/heap.cpp b/ecmascript/mem/heap.cpp index a9457f9121..a56a0a6dfb 100644 --- a/ecmascript/mem/heap.cpp +++ b/ecmascript/mem/heap.cpp @@ -25,7 +25,6 @@ #include "ecmascript/free_object.h" #include "ecmascript/js_finalization_registry.h" #include "ecmascript/js_native_pointer.h" -#include "ecmascript/linked_hash_table.h" #include "ecmascript/mem/assert_scope.h" #include "ecmascript/mem/concurrent_marker.h" #include "ecmascript/mem/concurrent_sweeper.h" @@ -1336,20 +1335,6 @@ void Heap::OnMoveEvent([[maybe_unused]] uintptr_t address, [[maybe_unused]] Tagg #endif } -void Heap::AddToKeptObjects(JSHandle value) const -{ - JSHandle env = ecmaVm_->GetGlobalEnv(); - JSHandle linkedSet; - if (env->GetWeakRefKeepObjects()->IsUndefined()) { - linkedSet = LinkedHashSet::Create(thread_); - } else { - linkedSet = - JSHandle(thread_, LinkedHashSet::Cast(env->GetWeakRefKeepObjects()->GetTaggedObject())); - } - linkedSet = LinkedHashSet::Add(thread_, linkedSet, value); - env->SetWeakRefKeepObjects(thread_, linkedSet); -} - void Heap::AdjustSpaceSizeForAppSpawn() { SetHeapMode(HeapMode::SPAWN); @@ -1390,11 +1375,6 @@ void Heap::ClearAllocationInspectorFromAllSpaces() hugeMachineCodeSpace_->ClearAllocationInspector(); } -void Heap::ClearKeptObjects() const -{ - ecmaVm_->GetGlobalEnv()->SetWeakRefKeepObjects(thread_, JSTaggedValue::Undefined()); -} - void Heap::RecomputeLimits() { double gcSpeed = memController_->CalculateMarkCompactSpeedPerMS(); diff --git a/ecmascript/mem/heap.h b/ecmascript/mem/heap.h index c274e0aadb..d1a9e1e432 100644 --- a/ecmascript/mem/heap.h +++ b/ecmascript/mem/heap.h @@ -1166,8 +1166,6 @@ public: } #endif void OnMoveEvent(uintptr_t address, TaggedObject* forwardAddress, size_t size); - void AddToKeptObjects(JSHandle value) const; - void ClearKeptObjects() const; // add allocationInspector to each space void AddAllocationInspectorToAllSpaces(AllocationInspector *inspector); diff --git a/ecmascript/napi/include/jsnapi_expo.h b/ecmascript/napi/include/jsnapi_expo.h index d925e0692b..f302cd1d78 100644 --- a/ecmascript/napi/include/jsnapi_expo.h +++ b/ecmascript/napi/include/jsnapi_expo.h @@ -384,6 +384,7 @@ class ECMA_PUBLIC_API JSValueRef { public: static Local Undefined(const EcmaVM *vm); static Local Null(const EcmaVM *vm); + static Local Hole(const EcmaVM *vm); static Local True(const EcmaVM *vm); static Local False(const EcmaVM *vm); @@ -926,10 +927,6 @@ protected: inline LocalScope(const EcmaVM *vm, JSTaggedType value); private: - void OpenLocalScope(EcmaContext *context); - void OpenPrimitiveScope(EcmaContext *context); - void CloseLocalScope(EcmaContext *context); - void ClosePrimitiveScope(EcmaContext *context); void *prevNext_ = nullptr; void *prevEnd_ = nullptr; int prevHandleStorageIndex_ {-1}; diff --git a/ecmascript/napi/jsnapi_expo.cpp b/ecmascript/napi/jsnapi_expo.cpp index 6f438a8496..3a71655aef 100644 --- a/ecmascript/napi/jsnapi_expo.cpp +++ b/ecmascript/napi/jsnapi_expo.cpp @@ -225,6 +225,12 @@ Local JSValueRef::Null(const EcmaVM *vm) vm->GetJSThread()->GlobalConstants()->GetHandledNull()); } +Local JSValueRef::Hole(const EcmaVM *vm) +{ + return JSNApiHelper::ToLocal( + vm->GetJSThread()->GlobalConstants()->GetHandledHole()); +} + Local JSValueRef::True(const EcmaVM *vm) { return JSNApiHelper::ToLocal( @@ -1514,7 +1520,7 @@ bool PromiseCapabilityRef::Resolve(const EcmaVM *vm, uintptr_t value) thread->GetCurrentEcmaContext()->ExecutePromisePendingJob(); RETURN_VALUE_IF_ABRUPT(thread, false); - vm->GetHeap()->ClearKeptObjects(); + thread->GetCurrentEcmaContext()->ClearKeptObjects(); return true; } @@ -1538,7 +1544,7 @@ bool PromiseCapabilityRef::Resolve(const EcmaVM *vm, Local value) thread->GetCurrentEcmaContext()->ExecutePromisePendingJob(); RETURN_VALUE_IF_ABRUPT(thread, false); - vm->GetHeap()->ClearKeptObjects(); + thread->GetCurrentEcmaContext()->ClearKeptObjects(); return true; } @@ -1563,7 +1569,7 @@ bool PromiseCapabilityRef::Reject(const EcmaVM *vm, uintptr_t reason) thread->GetCurrentEcmaContext()->ExecutePromisePendingJob(); RETURN_VALUE_IF_ABRUPT(thread, false); - vm->GetHeap()->ClearKeptObjects(); + thread->GetCurrentEcmaContext()->ClearKeptObjects(); return true; } @@ -1588,7 +1594,7 @@ bool PromiseCapabilityRef::Reject(const EcmaVM *vm, Local reason) thread->GetCurrentEcmaContext()->ExecutePromisePendingJob(); RETURN_VALUE_IF_ABRUPT(thread, false); - vm->GetHeap()->ClearKeptObjects(); + thread->GetCurrentEcmaContext()->ClearKeptObjects(); return true; } @@ -1872,61 +1878,62 @@ LocalScope::LocalScope(const EcmaVM *vm) : thread_(vm->GetJSThread()) { // Only get handle ptr here. Do not need to swtich state. auto context = reinterpret_cast(thread_)->GetCurrentEcmaContext(); - OpenLocalScope(context); - OpenPrimitiveScope(context); -} - -void LocalScope::OpenLocalScope(EcmaContext *context) -{ prevNext_ = context->GetHandleScopeStorageNext(); prevEnd_ = context->GetHandleScopeStorageEnd(); prevHandleStorageIndex_ = context->GetCurrentHandleStorageIndex(); - context->HandleScopeCountAdd(); -} -void LocalScope::OpenPrimitiveScope(EcmaContext *context) -{ prevPrimitiveNext_ = context->GetPrimitiveScopeStorageNext(); prevPrimitiveEnd_ = context->GetPrimitiveScopeStorageEnd(); prevPrimitiveStorageIndex_ = context->GetCurrentPrimitiveStorageIndex(); +#ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK + context->HandleScopeCountAdd(); context->PrimitiveScopeCountAdd(); +#endif } LocalScope::LocalScope(const EcmaVM *vm, JSTaggedType value) : thread_(vm->GetJSThread()) { ecmascript::ThreadManagedScope managedScope(reinterpret_cast(thread_)); - auto context = reinterpret_cast(thread_)->GetCurrentEcmaContext(); // Simply reserve a slot on the handlescope. The escaped handle will still be retained in this slot. ecmascript::EcmaHandleScope::NewHandle(reinterpret_cast(thread_), value); - OpenLocalScope(context); - OpenPrimitiveScope(context); + auto context = reinterpret_cast(thread_)->GetCurrentEcmaContext(); + prevNext_ = context->GetHandleScopeStorageNext(); + prevEnd_ = context->GetHandleScopeStorageEnd(); + prevHandleStorageIndex_ = context->GetCurrentHandleStorageIndex(); + + prevPrimitiveNext_ = context->GetPrimitiveScopeStorageNext(); + prevPrimitiveEnd_ = context->GetPrimitiveScopeStorageEnd(); + prevPrimitiveStorageIndex_ = context->GetCurrentPrimitiveStorageIndex(); +#ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK + context->HandleScopeCountAdd(); + context->PrimitiveScopeCountAdd(); +#endif } LocalScope::~LocalScope() { - ecmascript::ThreadManagedScope managedScope(reinterpret_cast(thread_)); auto context = reinterpret_cast(thread_)->GetCurrentEcmaContext(); - CloseLocalScope(context); - ClosePrimitiveScope(context); -} - -void LocalScope::CloseLocalScope(EcmaContext *context) -{ +#ifdef ECMASCRIPT_ENABLE_HANDLE_LEAK_CHECK context->HandleScopeCountDec(); - context->SetHandleScopeStorageNext(static_cast(prevNext_)); - if (context->GetHandleScopeStorageEnd() != prevEnd_) { - context->SetHandleScopeStorageEnd(static_cast(prevEnd_)); - context->ShrinkHandleStorage(prevHandleStorageIndex_); - } -} - -void LocalScope::ClosePrimitiveScope(EcmaContext *context) -{ context->PrimitiveScopeCountDec(); +#endif + context->SetHandleScopeStorageNext(static_cast(prevNext_)); context->SetPrimitiveScopeStorageNext(static_cast(prevPrimitiveNext_)); - if (context->GetPrimitiveScopeStorageEnd() != prevPrimitiveEnd_) { - context->SetPrimitiveScopeStorageEnd(static_cast(prevPrimitiveEnd_)); - context->ShrinkPrimitiveStorage(prevPrimitiveStorageIndex_); + bool handleScopeNeedShrink = (context->GetHandleScopeStorageEnd() != prevEnd_); + bool primitiveScopeNeedShrink = (context->GetPrimitiveScopeStorageEnd() != prevPrimitiveEnd_); + if (LIKELY(!handleScopeNeedShrink && !primitiveScopeNeedShrink)) { + return; + } + { + ecmascript::ThreadManagedScope managedScope(reinterpret_cast(thread_)); + if (handleScopeNeedShrink) { + context->SetHandleScopeStorageEnd(static_cast(prevEnd_)); + context->ShrinkHandleStorage(prevHandleStorageIndex_); + } + if (primitiveScopeNeedShrink) { + context->SetPrimitiveScopeStorageEnd(static_cast(prevPrimitiveEnd_)); + context->ShrinkPrimitiveStorage(prevPrimitiveStorageIndex_); + } } } @@ -2995,7 +3002,7 @@ Local FunctionRef::Call(const EcmaVM *vm, Local thisObj, RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle resultValue(thread, result); - vm->GetHeap()->ClearKeptObjects(); + thread->GetCurrentEcmaContext()->ClearKeptObjects(); vm->GetJsDebuggerManager()->NotifyReturnNative(); return scope.Escape(JSNApiHelper::ToLocal(resultValue)); } @@ -3004,7 +3011,7 @@ JSValueRef* FunctionRef::CallForNapi(const EcmaVM *vm, JSValueRef *thisObj, JSValueRef *const argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t length) { - CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, *JSValueRef::Undefined(vm)); + CROSS_THREAD_AND_EXCEPTION_CHECK_WITH_RETURN(vm, *JSValueRef::Hole(vm)); ecmascript::ThreadManagedScope managedScope(thread); JSTaggedValue result; FunctionCallScope callScope(EcmaVM::ConstCast(vm)); @@ -3012,7 +3019,8 @@ JSValueRef* FunctionRef::CallForNapi(const EcmaVM *vm, JSValueRef *thisObj, { LocalScope scope(vm); ecmascript::tooling::JsDebuggerManager *dm = vm->GetJsDebuggerManager(); - if (dm->IsDebugApp()) { + bool isDebugApp = dm->IsDebugApp(); + if (isDebugApp) { dm->ClearSingleStepper(); } JSTaggedValue func = *reinterpret_cast(this); @@ -3023,30 +3031,30 @@ JSValueRef* FunctionRef::CallForNapi(const EcmaVM *vm, JSValueRef *thisObj, } EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisValue, undefined, length); - RETURN_VALUE_IF_ABRUPT(thread, *JSValueRef::Undefined(vm)); + RETURN_VALUE_IF_ABRUPT(thread, *JSValueRef::Hole(vm)); for (int32_t i = 0; i < length; i++) { - JSTaggedValue arg = - argv[i] == nullptr ? JSTaggedValue::Undefined() : JSNApiHelper::ToJSTaggedValue(argv[i]); - info->SetCallArg(i, arg); + if (argv[i]) { + // NewRuntimeCallInfo has set Undefined defaultly in Argv's slot. + info->SetCallArg(i, JSNApiHelper::ToJSTaggedValue(argv[i])); + } } - if (thread->IsAsmInterpreter()) { - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, reinterpret_cast( - JSHandle(thread, JSTaggedValue::Exception()).GetAddress())); - STACK_LIMIT_CHECK(thread, reinterpret_cast( - JSHandle(thread, JSTaggedValue::Exception()).GetAddress())); + if (LIKELY(thread->IsAsmInterpreter())) { + STACK_LIMIT_CHECK(thread, reinterpret_cast(*JSValueRef::Hole(vm))); auto *hclass = func.GetTaggedObject()->GetClass(); if (hclass->IsClassConstructor()) { RETURN_STACK_BEFORE_THROW_IF_ASM(thread); THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot call", - reinterpret_cast(JSHandle(thread, undefined).GetAddress())); + reinterpret_cast(*JSValueRef::Hole(vm))); } result = ecmascript::InterpreterAssembly::Execute(info); } else { result = JSFunction::Call(info); } - RETURN_VALUE_IF_ABRUPT(thread, *JSValueRef::Undefined(vm)); - vm->GetHeap()->ClearKeptObjects(); - if (dm->IsMixedDebugEnabled()) { + RETURN_VALUE_IF_ABRUPT(thread, *JSValueRef::Hole(vm)); + if (thread->GetCurrentEcmaContext()->HasKeptObjects()) { + thread->GetCurrentEcmaContext()->ClearKeptObjects(); + } + if (isDebugApp && dm->IsMixedDebugEnabled()) { dm->NotifyReturnNative(); } } diff --git a/ecmascript/tests/glue_regs_test.cpp b/ecmascript/tests/glue_regs_test.cpp index 575f78df38..625de2228c 100644 --- a/ecmascript/tests/glue_regs_test.cpp +++ b/ecmascript/tests/glue_regs_test.cpp @@ -36,9 +36,14 @@ HWTEST_F_L0(GlueRegsTest, ConstantClassTest) ASSERT_NE(globalConst, nullptr); const JSTaggedValue *address = globalConst->BeginSlot(); + size_t curIndex = static_cast(ConstantIndex::CONSTANT_BEGIN); + size_t holeIndex = static_cast(ConstantIndex::HOLE_INDEX); while (address < globalConst->EndSlot()) { - EXPECT_TRUE(!(*address).IsHole()); // Visit barely + if (curIndex != holeIndex) { + EXPECT_TRUE(!(*address).IsHole()); // Visit barely + } address += 1; + curIndex += 1; } }