diff --git a/ecmascript/ecma_handle_scope-inl.h b/ecmascript/ecma_handle_scope-inl.h index 53bbceb2cd958ece6e8cb20012929b4d0df4b0dc..981007e76fe08586526b264514903d564888bf4c 100644 --- a/ecmascript/ecma_handle_scope-inl.h +++ b/ecmascript/ecma_handle_scope-inl.h @@ -24,10 +24,12 @@ inline EcmaHandleScope::EcmaHandleScope(JSThread *thread) : thread_(thread), prevNext_(thread->handleScopeStorageNext_), prevEnd_(thread->handleScopeStorageEnd_), prevHandleStorageIndex_(thread->currentHandleStorageIndex_) { + thread->HandleScopeCountAdd(); } inline EcmaHandleScope::~EcmaHandleScope() { + thread_->HandleScopeCountDec(); thread_->handleScopeStorageNext_ = prevNext_; if (thread_->handleScopeStorageEnd_ != prevEnd_) { thread_->handleScopeStorageEnd_ = prevEnd_; @@ -37,6 +39,8 @@ inline EcmaHandleScope::~EcmaHandleScope() uintptr_t EcmaHandleScope::NewHandle(JSThread *thread, JSTaggedType value) { + // Each Handle must be managed by HandleScope, otherwise it may cause Handle leakage. + ASSERT(thread->HandleScopeCount_ > 0); auto result = thread->handleScopeStorageNext_; if (result == thread->handleScopeStorageEnd_) { result = reinterpret_cast(thread->ExpandHandleStorage()); diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index 31bb8274e624a0672003da22504623473a4e518e..080cccf076f16114c37e162076d603316a30fdce 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -132,9 +132,9 @@ bool EcmaVM::Initialize() UNREACHABLE(); } + [[maybe_unused]] EcmaHandleScope scope(thread_); if (!snapshotDeserializeEnable_ || !VerifyFilePath(fileName_)) { LOG_ECMA(DEBUG) << "EcmaVM::Initialize run builtins"; - [[maybe_unused]] EcmaHandleScope scope(thread_); JSHandle dynClassClassHandle = factory_->NewEcmaDynClass(nullptr, JSHClass::SIZE, JSType::HCLASS); JSHClass *dynclass = reinterpret_cast(dynClassClassHandle.GetTaggedValue().GetTaggedObject()); diff --git a/ecmascript/js_thread.cpp b/ecmascript/js_thread.cpp index f2352867b9ef8d99579a91b8946df96b78b13597..305c69df346039ebf2d00ad32c242fd11f87bc17 100644 --- a/ecmascript/js_thread.cpp +++ b/ecmascript/js_thread.cpp @@ -52,6 +52,7 @@ JSThread::~JSThread() } handleStorageNodes_.clear(); currentHandleStorageIndex_ = -1; + handleScopeCount_ = 0; handleScopeStorageNext_ = handleScopeStorageEnd_ = nullptr; EcmaVM::Cast(GetVM())->GetChunk()->Delete(globalStorage_); @@ -190,6 +191,14 @@ uintptr_t *JSThread::ExpandHandleStorage() void JSThread::ShrinkHandleStorage(int prevIndex) { currentHandleStorageIndex_ = prevIndex; + int32_t lastIndex = handleStorageNodes_.size() - 1; + if (lastIndex > MIN_HANDLE_STORAGE_SIZE && currentHandleStorageIndex_ < MIN_HANDLE_STORAGE_SIZE) { + for (int i = MIN_HANDLE_STORAGE_SIZE; i < lastIndex; i++) { + auto node = handleStorageNodes_.back(); + delete node; + handleStorageNodes_.pop_back(); + } + } } void JSThread::NotifyStableArrayElementsGuardians(JSHandle receiver) diff --git a/ecmascript/js_thread.h b/ecmascript/js_thread.h index eef175a525e535a575b3759f799927c91aea043a..c771970edf28a1e7f0b13ee06211cee3c718429e 100644 --- a/ecmascript/js_thread.h +++ b/ecmascript/js_thread.h @@ -122,6 +122,16 @@ public: return currentHandleStorageIndex_; } + void HandleScopeCountAdd() + { + handleScopeCount_++; + } + + void HandleScopeCountDec() + { + handleScopeCount_--; + } + void SetException(JSTaggedValue exception); JSTaggedValue GetException() const @@ -192,6 +202,7 @@ private: static const uint32_t NODE_BLOCK_SIZE = 1U << NODE_BLOCK_SIZE_LOG2; static constexpr uint32_t MAX_RUNTIME_FUNCTIONS = kungfu::EXTERN_RUNTIME_STUB_MAXCOUNT - kungfu::EXTERNAL_RUNTIME_STUB_BEGIN - 1; + static constexpr int32_t MIN_HANDLE_STORAGE_SIZE = 2; EcmaGlobalStorage *globalStorage_ {nullptr}; @@ -207,6 +218,7 @@ private: JSTaggedType *handleScopeStorageEnd_ {nullptr}; std::vector *> handleStorageNodes_ {}; int32_t currentHandleStorageIndex_ {-1}; + int32_t handleScopeCount_ {0}; JSTaggedValue exception_ {JSTaggedValue::Hole()}; bool stableArrayElementsGuardians_ {true}; GlobalEnvConstants globalConst_; // Place-Holder diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h index 4bf334dd88b8f6f6a223b5ce6004fb519431c144..e5b48ae4333910c688b7f160f17d58143268fe69 100644 --- a/ecmascript/napi/include/jsnapi.h +++ b/ecmascript/napi/include/jsnapi.h @@ -73,6 +73,7 @@ public: } Local(const EcmaVM *vm, const Global ¤t); + Local(const EcmaVM *vm, const Local ¤t) : Local(current) {}; ~Local() = default; @@ -86,6 +87,11 @@ public: return GetAddress(); } + inline Local ToLocal(const EcmaVM *vm) const + { + return Local(*this); + } + inline bool IsEmpty() const { return GetAddress() == nullptr; @@ -106,6 +112,8 @@ public: return IsEmpty() || GetAddress()->IsHole(); } + void FreeGlobalHandleAddr() {} + private: explicit inline Local(uintptr_t addr) : address_(addr) {} inline T *GetAddress() const @@ -230,18 +238,6 @@ private: uintptr_t escapeHandle_ = 0U; }; -class PUBLIC_API JSExecutionScope { -public: - explicit JSExecutionScope(const EcmaVM *vm); - ~JSExecutionScope(); - DISALLOW_COPY(JSExecutionScope); - DISALLOW_MOVE(JSExecutionScope); - -private: - void *last_current_thread_ = nullptr; - bool is_revert_ = false; -}; - class PUBLIC_API JSValueRef { public: static Local Undefined(const EcmaVM *vm); diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 4ab3e3ad293b811593eb9c4ee31c9cf95affc24a..eb3f4a1bc72c2386d57fe8cd7dabdb3e0988d1c0 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -377,20 +377,23 @@ LocalScope::LocalScope(const EcmaVM *vm) : thread_(vm->GetJSThread()) prevNext_ = thread->GetHandleScopeStorageNext(); prevEnd_ = thread->GetHandleScopeStorageEnd(); prevHandleStorageIndex_ = thread->GetCurrentHandleStorageIndex(); + thread->HandleScopeCountAdd(); } LocalScope::LocalScope(const EcmaVM *vm, JSTaggedType value) : thread_(vm->GetJSThread()) { auto thread = reinterpret_cast(thread_); + ecmascript::EcmaHandleScope::NewHandle(thread, value); prevNext_ = thread->GetHandleScopeStorageNext(); prevEnd_ = thread->GetHandleScopeStorageEnd(); prevHandleStorageIndex_ = thread->GetCurrentHandleStorageIndex(); - ecmascript::EcmaHandleScope::NewHandle(thread, value); + thread->HandleScopeCountAdd(); } LocalScope::~LocalScope() { auto thread = reinterpret_cast(thread_); + thread->HandleScopeCountDec(); thread->SetHandleScopeStorageNext(static_cast(prevNext_)); if (thread->GetHandleScopeStorageEnd() != prevEnd_) { thread->SetHandleScopeStorageEnd(static_cast(prevEnd_)); @@ -1340,18 +1343,6 @@ JSTaggedValue Callback::RegisterCallbackWithNewTarget(ecmascript::EcmaRuntimeCal return JSNApiHelper::ToJSHandle(result).GetTaggedValue(); } -// ------------------------------------- JSExecutionScope ------------------------------ -JSExecutionScope::JSExecutionScope(const EcmaVM *vm) -{ - (void)vm; -} - -JSExecutionScope::~JSExecutionScope() -{ - last_current_thread_ = nullptr; - is_revert_ = false; -} - // ----------------------------------- JSValueRef -------------------------------------- Local JSValueRef::Undefined(const EcmaVM *vm) {