• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/dfx/stackinfo/async_stack_trace.h"
17 
18 #include "ecmascript/dfx/stackinfo/js_stackinfo.h"
19 #include "ecmascript/js_promise.h"
20 #include "ecmascript/ecma_vm.h"
21 #include "ecmascript/platform/async_detect.h"
22 #include "ecmascript/debugger/js_debugger_manager.h"
23 
24 namespace panda::ecmascript {
AsyncStackTrace(EcmaVM * vm)25 AsyncStackTrace::AsyncStackTrace(EcmaVM *vm) : vm_(vm)
26 {
27     jsThread_ = vm->GetJSThread();
28 }
29 
RegisterAsyncDetectCallBack()30 void AsyncStackTrace::RegisterAsyncDetectCallBack()
31 {
32     panda::ecmascript::RegisterAsyncDetectCallBack(vm_);
33 }
34 
InsertAsyncStackTrace(const JSHandle<JSPromise> & promise)35 bool AsyncStackTrace::InsertAsyncStackTrace(const JSHandle<JSPromise> &promise)
36 {
37     std::string stack = JsStackInfo::BuildJsStackTrace(jsThread_, false, false);
38     if (stack.empty()) {
39         return false;
40     }
41     auto now = std::chrono::system_clock::now();
42     auto currentTime = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
43     asyncStackTrace_.emplace(promise->GetAsyncTaskId(), std::make_pair(stack, currentTime));
44     return true;
45 }
46 
RemoveAsyncStackTrace(const JSHandle<JSPromise> & promise)47 bool AsyncStackTrace::RemoveAsyncStackTrace(const JSHandle<JSPromise> &promise)
48 {
49     auto asyncStackTrace = asyncStackTrace_.find(promise->GetAsyncTaskId());
50     if (asyncStackTrace == asyncStackTrace_.end()) {
51         LOG_ECMA(INFO) << "Not find promise: " << promise->GetAsyncTaskId();
52         return false;
53     }
54     asyncStackTrace_.erase(asyncStackTrace);
55     return true;
56 }
57 
GetCurrentAsyncParent()58 std::shared_ptr<AsyncStack> AsyncStackTrace::GetCurrentAsyncParent()
59 {
60     return currentAsyncParent_.empty() ? nullptr : currentAsyncParent_.back();
61 }
62 
InsertAsyncTaskStacks(const JSHandle<JSPromise> & promise,const std::string & description)63 bool AsyncStackTrace::InsertAsyncTaskStacks(const JSHandle<JSPromise> &promise, const std::string &description)
64 {
65     uint32_t asyncTaskId = promise->GetAsyncTaskId();
66     std::shared_ptr<AsyncStack> asyncStack = std::make_shared<AsyncStack>();
67     auto notificationManager = vm_->GetJsDebuggerManager()->GetNotificationManager();
68     // await need to skip top frame
69     if (description == "await") {
70         notificationManager->GenerateAsyncFramesEvent(asyncStack, true);
71     } else {
72         notificationManager->GenerateAsyncFramesEvent(asyncStack, false);
73     }
74     asyncStack->SetDescription(description);
75     std::shared_ptr<AsyncStack> currentAsyncParent = GetCurrentAsyncParent();
76     if (currentAsyncParent) {
77         asyncStack->SetAsyncParent(currentAsyncParent);
78     }
79     asyncTaskStacks_.emplace(asyncTaskId, asyncStack);
80     return true;
81 }
82 
InsertCurrentAsyncTaskStack(const JSTaggedValue & PromiseReaction)83 bool AsyncStackTrace::InsertCurrentAsyncTaskStack(const JSTaggedValue &PromiseReaction)
84 {
85     if (PromiseReaction.IsPromiseReaction()) {
86         JSTaggedValue promiseCapability = PromiseReaction::Cast(PromiseReaction)->GetPromiseCapability(jsThread_);
87         JSTaggedValue promise = PromiseCapability::Cast(promiseCapability)->GetPromise(jsThread_);
88         uint32_t asyncTaskId = JSPromise::Cast(promise)->GetAsyncTaskId();
89         auto stackIt = asyncTaskStacks_.find(asyncTaskId);
90         if (stackIt != asyncTaskStacks_.end()) {
91             currentAsyncParent_.emplace_back(stackIt->second);
92         } else {
93             currentAsyncParent_.emplace_back();
94             LOG_DEBUGGER(ERROR) << "Promise: " << asyncTaskId << " is not in asyncTaskStacks";
95         }
96     }
97     return true;
98 }
99 
RemoveAsyncTaskStack(const JSTaggedValue & PromiseReaction)100 bool AsyncStackTrace::RemoveAsyncTaskStack(const JSTaggedValue &PromiseReaction)
101 {
102     if (PromiseReaction.IsPromiseReaction() && !currentAsyncParent_.empty()) {
103         currentAsyncParent_.pop_back();
104     }
105     return true;
106 }
107 }  // namespace panda::ecmascript