• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 
GetBytecodePc()145     size_t GetBytecodePc() const
146     {
147         return IsCFrame() ? 0 : GetIFrame()->GetBytecodeOffset();
148     }
149 
150 private:
151     FrameVariant GetTopFrameFromFp(void *ptr, bool isFrameCompiled);
152 
153     CFrameType CreateCFrame(SlotType *ptr);
154 
155     CFrameType CreateCFrameForC2IBridge(Frame *frame);
156 
157     void NextFromCFrame();
158 
159     void NextFromIFrame();
160 
161 private:
162     FrameVariant frame_ {nullptr};
163 };
164 
165 }  // namespace ark
166 
167 #endif  // PANDA_RUNTIME_TOOLING_SAMPLER_STACK_WALKER__BASE_H
168