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 #ifndef ECMASCRIPT_STACKINFO_STACK_TRACE_H 17 #define ECMASCRIPT_STACKINFO_STACK_TRACE_H 18 19 #include <memory> 20 #include <string> 21 22 #include "ecmascript/js_promise.h" 23 #include "ecmascript/mem/c_containers.h" 24 25 namespace panda::ecmascript { 26 class JSPromise; 27 class EcmaVM; 28 class JSTaggedValue; 29 30 // for async stack trace 31 static constexpr int32_t MAX_CALL_STACK_SIZE_TO_CAPTURE = 200; 32 class PUBLIC_API StackFrame { 33 public: 34 StackFrame() = default; 35 ~StackFrame() = default; 36 GetFunctionName()37 const std::string &GetFunctionName() const 38 { 39 return functionName_; 40 } 41 SetFunctionName(std::string & functionName)42 void SetFunctionName(std::string &functionName) 43 { 44 functionName_ = functionName; 45 } 46 GetUrl()47 const std::string &GetUrl() const 48 { 49 return url_; 50 } 51 SetUrl(std::string & url)52 void SetUrl(std::string &url) 53 { 54 url_ = url; 55 } 56 GetLineNumber()57 int32_t GetLineNumber() const 58 { 59 return lineNumber_; 60 } 61 SetLineNumber(int32_t lineNumber)62 void SetLineNumber(int32_t lineNumber) 63 { 64 lineNumber_ = lineNumber; 65 } 66 GetColumnNumber()67 int32_t GetColumnNumber() const 68 { 69 return columnNumber_; 70 } 71 SetColumnNumber(int32_t columnNumber)72 void SetColumnNumber(int32_t columnNumber) 73 { 74 columnNumber_ = columnNumber; 75 } 76 GetScriptId()77 int32_t GetScriptId() const 78 { 79 return scriptId_; 80 } 81 SetScriptId(int32_t scriptId)82 void SetScriptId(int32_t scriptId) 83 { 84 scriptId_ = scriptId; 85 } 86 87 private: 88 std::string functionName_; 89 std::string url_; 90 int32_t lineNumber_; 91 int32_t columnNumber_; 92 // For debugger 93 int32_t scriptId_; 94 }; 95 96 class AsyncStack { 97 public: 98 AsyncStack() = default; 99 GetDescription()100 const std::string &GetDescription() const 101 { 102 return description_; 103 } 104 SetDescription(const std::string & description)105 void SetDescription(const std::string &description) 106 { 107 description_ = description; 108 } 109 GetAsyncParent()110 const std::weak_ptr<AsyncStack> &GetAsyncParent() const 111 { 112 return asyncParent_; 113 } 114 SetAsyncParent(const std::shared_ptr<AsyncStack> & asyncParent)115 void SetAsyncParent(const std::shared_ptr<AsyncStack> &asyncParent) 116 { 117 asyncParent_ = asyncParent; 118 } 119 GetFrames()120 const std::vector<std::shared_ptr<StackFrame>> &GetFrames() const 121 { 122 return frames_; 123 } 124 SetFrames(const std::vector<std::shared_ptr<StackFrame>> & frames)125 void SetFrames(const std::vector<std::shared_ptr<StackFrame>> &frames) 126 { 127 frames_ = frames; 128 } 129 private: 130 std::string description_; 131 std::vector<std::shared_ptr<StackFrame>> frames_; 132 std::weak_ptr<AsyncStack> asyncParent_; 133 }; 134 135 class AsyncStackTrace { 136 public: 137 explicit AsyncStackTrace(EcmaVM *vm); 138 139 ~AsyncStackTrace() = default; 140 141 void RegisterAsyncDetectCallBack(); 142 143 bool InsertAsyncStackTrace(const JSHandle<JSPromise> &promise); 144 145 bool RemoveAsyncStackTrace(const JSHandle<JSPromise> &promise); 146 147 bool InsertAsyncTaskStacks(const JSHandle<JSPromise> &promise, const std::string &description); 148 149 bool InsertCurrentAsyncTaskStack(const JSTaggedValue &PromiseReaction); 150 151 bool RemoveAsyncTaskStack(const JSTaggedValue &PromiseReaction); 152 153 std::shared_ptr<AsyncStack> GetCurrentAsyncParent(); 154 GetAsyncStackTrace()155 CMap<uint32_t, std::pair<std::string, int64_t>> GetAsyncStackTrace() 156 { 157 return asyncStackTrace_; 158 } 159 GetAsyncTaskId()160 uint32_t GetAsyncTaskId() 161 { 162 if (asyncTaskId_ == MAX_ASYNC_TASK_ID) { 163 asyncTaskId_ = 0; 164 } 165 return ++asyncTaskId_; 166 } 167 168 static constexpr uint32_t PROMISE_PENDING_TIME_MS = 5000; 169 170 NO_COPY_SEMANTIC(AsyncStackTrace); 171 NO_MOVE_SEMANTIC(AsyncStackTrace); 172 private: 173 static constexpr uint32_t MAX_ASYNC_TASK_ID = (1u << JSPromise::ASYNC_TASK_ID_BITS) - 1; 174 175 EcmaVM *vm_ {nullptr}; 176 JSThread *jsThread_ {nullptr}; 177 uint32_t asyncTaskId_ {0}; 178 179 // { promiseid , (jsStack, time) } 180 CMap<uint32_t, std::pair<std::string, int64_t>> asyncStackTrace_; 181 182 std::vector<std::shared_ptr<AsyncStack>> currentAsyncParent_; 183 CMap<uint32_t, std::shared_ptr<AsyncStack>> asyncTaskStacks_; 184 }; 185 } // namespace panda::ecmascript 186 #endif // ECMASCRIPT_STACKINFO_STACK_TRACE_H