From 401c33fd0af55bee6c027f0352963c46e8832aa0 Mon Sep 17 00:00:00 2001 From: hanweiqi Date: Wed, 21 Aug 2024 18:52:28 +0800 Subject: [PATCH] Avoid Sendable's DropFrame Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IALL34 Signed-off-by: hanweiqi --- ecmascript/debugger/debugger_api.cpp | 5 ++ ecmascript/debugger/debugger_api.h | 1 + ecmascript/debugger/dropframe_manager.cpp | 103 +++++++++++++++------- ecmascript/debugger/dropframe_manager.h | 14 +++ ecmascript/debugger/js_debugger_manager.h | 5 ++ 5 files changed, 98 insertions(+), 30 deletions(-) diff --git a/ecmascript/debugger/debugger_api.cpp b/ecmascript/debugger/debugger_api.cpp index e0527a7e34..cc18ed2a0f 100644 --- a/ecmascript/debugger/debugger_api.cpp +++ b/ecmascript/debugger/debugger_api.cpp @@ -1300,6 +1300,11 @@ bool DebuggerApi::CheckPromiseQueueSize(const EcmaVM *ecmaVm) return queueSizeEntry == queueSizeCurrent; } +bool DebuggerApi::CheckIsSendableMethod(const EcmaVM *ecmaVm) +{ + auto *debuggerMgr = ecmaVm->GetJsDebuggerManager(); + return debuggerMgr->CheckIsSendableMethod(); +} bool DebuggerApi::IsMainThread() { return JSThread::IsMainThread(); diff --git a/ecmascript/debugger/debugger_api.h b/ecmascript/debugger/debugger_api.h index a10643cfda..36443ca123 100644 --- a/ecmascript/debugger/debugger_api.h +++ b/ecmascript/debugger/debugger_api.h @@ -197,6 +197,7 @@ public: Global internalObjects); static bool CheckPromiseQueueSize(const EcmaVM *ecmaVm); + static bool CheckIsSendableMethod(const EcmaVM *ecmaVm); static bool IsMainThread(); static void DropLastFrame(const EcmaVM *ecmaVm); }; diff --git a/ecmascript/debugger/dropframe_manager.cpp b/ecmascript/debugger/dropframe_manager.cpp index 51000cf7f8..1c78712e56 100644 --- a/ecmascript/debugger/dropframe_manager.cpp +++ b/ecmascript/debugger/dropframe_manager.cpp @@ -72,48 +72,62 @@ std::pair DropframeManager::ReadStlexvarParams(const uint8_t void DropframeManager::MethodEntry(JSThread *thread, JSHandle method, JSHandle envHandle) { std::set> modifiedLexVarPos; - NewLexModifyRecordLevel(); const JSPandaFile* methodJsPandaFile = method->GetJSPandaFile(); panda_file::File::EntityId methodId = method->GetMethodId(); PushMethodInfo(std::make_tuple(const_cast(methodJsPandaFile), methodId)); - if (!envHandle->IsLexicalEnv()) { + if (method->IsSendableMethod()) { + PushMethodType(MethodType::SENDABLE_METHOD); return; } + NewLexModifyRecordLevel(); + PushPromiseQueueSizeRecord(thread); + if (!envHandle->IsLexicalEnv()) { + PushMethodType(MethodType::OTHER_METHOD); + return; + } + PushMethodType(MethodType::NORMAL_METHOD); uint32_t codeSize = method->GetCodeSize(); uint16_t newEnvCount = 0; auto bcIns = BytecodeInstruction(method->GetBytecodeArray()); auto bcInsLast = bcIns.JumpTo(codeSize); while (bcIns.GetAddress() != bcInsLast.GetAddress()) { - BytecodeInstruction::Opcode op = bcIns.GetOpcode(); - if (IsNewlexenvOpcode(op)) { - newEnvCount++; - } else if (IsStlexvarOpcode(op)) { - std::pair lexVarPos = ReadStlexvarParams(bcIns.GetAddress(), op); - uint16_t level; - uint16_t slot; - std::tie(level, slot) = lexVarPos; - JSTaggedValue env = envHandle.GetTaggedValue(); - for (uint16_t i = 0; ; i++) { - if ((level < newEnvCount || i >= level - newEnvCount) && - slot < LexicalEnv::Cast(env.GetTaggedObject())->GetLength() - LexicalEnv::RESERVED_ENV_LENGTH && - !modifiedLexVarPos.count({i, slot})) { - JSTaggedValue value = LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot); - EmplaceLexModifyRecord(thread, env, slot, value); - modifiedLexVarPos.insert({i, slot}); - } - if (i >= level) { - break; - } - JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); - if (!taggedParentEnv.IsLexicalEnv()) { - break; - } - env = taggedParentEnv; - } - } + AddLexPropertiesToRecord(thread, bcIns, newEnvCount, modifiedLexVarPos, envHandle); bcIns = bcIns.GetNext(); } - PushPromiseQueueSizeRecord(thread); +} + +void DropframeManager::AddLexPropertiesToRecord(JSThread *thread, BytecodeInstruction &bcIns, uint16_t &newEnvCount, + std::set> &modifiedLexVarPos, JSHandle envHandle) +{ + BytecodeInstruction::Opcode op = bcIns.GetOpcode(); + if (IsNewlexenvOpcode(op)) { + newEnvCount++; + return; + } + if (IsStlexvarOpcode(op)) { + std::pair lexVarPos = ReadStlexvarParams(bcIns.GetAddress(), op); + uint16_t level; + uint16_t slot; + std::tie(level, slot) = lexVarPos; + JSTaggedValue env = envHandle.GetTaggedValue(); + for (uint16_t i = 0; ; i++) { + if ((level < newEnvCount || i >= level - newEnvCount) && + slot < LexicalEnv::Cast(env.GetTaggedObject())->GetLength() - LexicalEnv::RESERVED_ENV_LENGTH && + !modifiedLexVarPos.count({i, slot})) { + JSTaggedValue value = LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot); + EmplaceLexModifyRecord(thread, env, slot, value); + modifiedLexVarPos.insert({i, slot}); + } + if (i >= level) { + break; + } + JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); + if (!taggedParentEnv.IsLexicalEnv()) { + break; + } + env = taggedParentEnv; + } + } } void DropframeManager::MethodExit(JSThread *thread, [[maybe_unused]] JSHandle method) @@ -124,6 +138,11 @@ void DropframeManager::MethodExit(JSThread *thread, [[maybe_unused]] JSHandleSetProperties(thread, slot, valueHandle.GetTaggedValue()); } PopMethodInfo(); + PopMethodType(); RemoveLexModifyRecordOfTopFrame(thread); PopPromiseQueueSizeRecord(); @@ -226,6 +246,11 @@ void DropframeManager::MergeLexModifyRecordOfTopFrame(JSThread *thread) std::vector, uint16_t, JSHandle>> lexModifyRecord; lexModifyRecord = modifiedLexVar_.top(); modifiedLexVar_.pop(); + if (!modifiedLexVar_.empty() && modifiedLexVar_.top().empty()) { + modifiedLexVar_.pop(); + modifiedLexVar_.push(lexModifyRecord); + return; + } for (const auto &item : lexModifyRecord) { JSHandle envHandle; uint16_t slot; @@ -295,4 +320,22 @@ void DropframeManager::PopMethodInfo() methodInfo_.pop(); } } + +void DropframeManager::PushMethodType(MethodType methodType) +{ + methodType_.push(methodType); +} + +bool DropframeManager::CheckIsSendableMethod() +{ + ASSERT(!methodType_.empty()); + return methodType_.top() == MethodType::SENDABLE_METHOD; +} + +void DropframeManager::PopMethodType() +{ + if (!methodType_.empty()) { + methodType_.pop(); + } +} } \ No newline at end of file diff --git a/ecmascript/debugger/dropframe_manager.h b/ecmascript/debugger/dropframe_manager.h index db5d0f7324..af17da1ffc 100644 --- a/ecmascript/debugger/dropframe_manager.h +++ b/ecmascript/debugger/dropframe_manager.h @@ -22,6 +22,12 @@ #include "libpandafile/bytecode_instruction.h" namespace panda::ecmascript::tooling { +enum class MethodType : uint8_t { + OTHER_METHOD = 0, + NORMAL_METHOD, + SENDABLE_METHOD +}; + class DropframeManager { public: DropframeManager() = default; @@ -33,6 +39,7 @@ public: void MethodExit(JSThread *thread, JSHandle method); void DropLastFrame(JSThread *thread); uint32_t GetPromiseQueueSizeRecordOfTopFrame(); + bool CheckIsSendableMethod(); private: bool IsNewlexenvOpcode(BytecodeInstruction::Opcode op); bool IsStlexvarOpcode(BytecodeInstruction::Opcode op); @@ -52,8 +59,15 @@ private: bool CheckExitMethodInfo(std::tuple methodInfo); void PopMethodInfo(); + void PushMethodType(MethodType methodType); + void PopMethodType(); + + void AddLexPropertiesToRecord(JSThread *thread, BytecodeInstruction &bcIns, uint16_t &newEnvCount, + std::set> &modifiedLexVarPos, JSHandle envHandle); + std::stack, uint16_t, JSHandle>>> modifiedLexVar_; std::stack promiseQueueSizeRecord_; + std::stack methodType_; std::stack> methodInfo_; }; } diff --git a/ecmascript/debugger/js_debugger_manager.h b/ecmascript/debugger/js_debugger_manager.h index b4b32b3e60..5314c71e5e 100644 --- a/ecmascript/debugger/js_debugger_manager.h +++ b/ecmascript/debugger/js_debugger_manager.h @@ -206,6 +206,11 @@ public: return dropframeManager_.GetPromiseQueueSizeRecordOfTopFrame(); } + bool CheckIsSendableMethod() + { + return dropframeManager_.CheckIsSendableMethod(); + } + void EnableObjectHashDisplay() { isObjHashDisplayEnabled_ = true;