1 /** 2 * Copyright (c) 2021-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 #ifndef PANDA_RUNTIME_TOOLING_SAMPLER_STACK_WALKER__BASE_H 16 #define PANDA_RUNTIME_TOOLING_SAMPLER_STACK_WALKER__BASE_H 17 18 #include <variant> 19 20 #include "runtime/include/cframe.h" 21 #include "runtime/interpreter/frame.h" 22 23 namespace ark { 24 25 class StackWalkerBase { 26 public: 27 using SlotType = std::conditional_t<ArchTraits<RUNTIME_ARCH>::IS_64_BITS, uint64_t, uint32_t>; 28 using FrameVariant = std::variant<Frame *, CFrame>; 29 using CFrameType = CFrame; 30 31 StackWalkerBase() = default; 32 StackWalkerBase(void *fp, bool isFrameCompiled); 33 34 virtual ~StackWalkerBase() = default; 35 36 NO_COPY_SEMANTIC(StackWalkerBase); 37 NO_MOVE_SEMANTIC(StackWalkerBase); 38 39 void NextFrame(); 40 GetIFrame()41 Frame *GetIFrame() 42 { 43 return std::get<Frame *>(frame_); 44 } 45 GetIFrame()46 const Frame *GetIFrame() const 47 { 48 return std::get<Frame *>(frame_); 49 } 50 GetCFrame()51 CFrameType &GetCFrame() 52 { 53 ASSERT(IsCFrame()); 54 return std::get<CFrameType>(frame_); 55 } 56 GetCFrame()57 const CFrameType &GetCFrame() const 58 { 59 ASSERT(IsCFrame()); 60 return std::get<CFrameType>(frame_); 61 } 62 IsCFrame()63 bool IsCFrame() const 64 { 65 return std::holds_alternative<CFrameType>(frame_); 66 } 67 HasFrame()68 bool HasFrame() const 69 { 70 return IsCFrame() || GetIFrame() != nullptr; 71 } 72 GetMethod()73 Method *GetMethod() 74 { 75 ASSERT(HasFrame()); 76 return IsCFrame() ? GetCFrame().GetMethod() : GetIFrame()->GetMethod(); 77 } 78 GetMethod()79 const Method *GetMethod() const 80 { 81 ASSERT(HasFrame()); 82 return IsCFrame() ? GetCFrame().GetMethod() : GetIFrame()->GetMethod(); 83 } 84 85 template <FrameKind KIND> IsBoundaryFrame(const void * ptr)86 static bool IsBoundaryFrame(const void *ptr) 87 { 88 if constexpr (KIND == FrameKind::INTERPRETER) { // NOLINT 89 return GetBoundaryFrameMethod<KIND>(ptr) == COMPILED_CODE_TO_INTERPRETER; 90 } else { // NOLINT 91 return GetBoundaryFrameMethod<KIND>(ptr) == INTERPRETER_TO_COMPILED_CODE; 92 } 93 } 94 95 template <FrameKind KIND> GetBoundaryFrameMethod(const void * ptr)96 static uintptr_t GetBoundaryFrameMethod(const void *ptr) 97 { 98 auto frameMethod = reinterpret_cast<uintptr_t>(GetMethodFromBoundary<KIND>(ptr)); 99 return frameMethod; 100 } 101 102 template <FrameKind KIND> GetMethodFromBoundary(void * ptr)103 static Method *GetMethodFromBoundary(void *ptr) 104 { 105 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 106 return *(reinterpret_cast<Method **>(ptr) + BoundaryFrame<KIND>::METHOD_OFFSET); 107 } 108 109 template <FrameKind KIND> GetMethodFromBoundary(const void * ptr)110 static const Method *GetMethodFromBoundary(const void *ptr) 111 { 112 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 113 return *(reinterpret_cast<Method *const *>(ptr) + BoundaryFrame<KIND>::METHOD_OFFSET); 114 } 115 116 template <FrameKind KIND> GetPrevFromBoundary(void * ptr)117 static SlotType *GetPrevFromBoundary(void *ptr) 118 { 119 // In current implementation fp must point to previous fp 120 static_assert(BoundaryFrame<KIND>::FP_OFFSET == 0); 121 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 122 return *(reinterpret_cast<SlotType **>(ptr)); 123 } 124 IsMethodInBoundaryFrame(const Method * method)125 static bool IsMethodInBoundaryFrame(const Method *method) 126 { 127 return IsMethodInI2CFrame(method) || IsMethodInC2IFrame(method) || IsMethodInBPFrame(method); 128 } 129 IsMethodInI2CFrame(const Method * method)130 static bool IsMethodInI2CFrame(const Method *method) 131 { 132 return method == reinterpret_cast<void *>(FrameBridgeKind::INTERPRETER_TO_COMPILED_CODE); 133 } 134 IsMethodInC2IFrame(const Method * method)135 static bool IsMethodInC2IFrame(const Method *method) 136 { 137 return method == reinterpret_cast<void *>(FrameBridgeKind::COMPILED_CODE_TO_INTERPRETER); 138 } 139 IsMethodInBPFrame(const Method * method)140 static bool IsMethodInBPFrame(const Method *method) 141 { 142 return method == reinterpret_cast<void *>(FrameBridgeKind::BYPASS); 143 } 144 145 private: 146 FrameVariant GetTopFrameFromFp(void *ptr, bool isFrameCompiled); 147 148 CFrameType CreateCFrame(SlotType *ptr); 149 150 CFrameType CreateCFrameForC2IBridge(Frame *frame); 151 152 void NextFromCFrame(); 153 154 void NextFromIFrame(); 155 156 private: 157 FrameVariant frame_ {nullptr}; 158 }; 159 160 } // namespace ark 161 162 #endif // PANDA_RUNTIME_TOOLING_SAMPLER_STACK_WALKER__BASE_H 163