• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_RUNTIME_STACK_H_
18 #define ART_RUNTIME_STACK_H_
19 
20 #include <stdint.h>
21 #include <string>
22 
23 #include "base/locks.h"
24 #include "base/macros.h"
25 #include "quick/quick_method_frame_info.h"
26 #include "stack_map.h"
27 
28 namespace art {
29 
30 namespace mirror {
31 class Object;
32 }  // namespace mirror
33 
34 class ArtMethod;
35 class Context;
36 class HandleScope;
37 class OatQuickMethodHeader;
38 class ShadowFrame;
39 class Thread;
40 union JValue;
41 
42 // The kind of vreg being accessed in calls to Set/GetVReg.
43 enum VRegKind {
44   kReferenceVReg,
45   kIntVReg,
46   kFloatVReg,
47   kLongLoVReg,
48   kLongHiVReg,
49   kDoubleLoVReg,
50   kDoubleHiVReg,
51   kConstant,
52   kImpreciseConstant,
53   kUndefined,
54 };
55 std::ostream& operator<<(std::ostream& os, const VRegKind& rhs);
56 
57 // Size in bytes of the should_deoptimize flag on stack.
58 // We just need 4 bytes for our purpose regardless of the architecture. Frame size
59 // calculation will automatically do alignment for the final frame size.
60 static constexpr size_t kShouldDeoptimizeFlagSize = 4;
61 
62 /*
63  * Our current stack layout.
64  * The Dalvik registers come first, followed by the
65  * Method*, followed by other special temporaries if any, followed by
66  * regular compiler temporary. As of now we only have the Method* as
67  * as a special compiler temporary.
68  * A compiler temporary can be thought of as a virtual register that
69  * does not exist in the dex but holds intermediate values to help
70  * optimizations and code generation. A special compiler temporary is
71  * one whose location in frame is well known while non-special ones
72  * do not have a requirement on location in frame as long as code
73  * generator itself knows how to access them.
74  *
75  * TODO: Update this documentation?
76  *
77  *     +-------------------------------+
78  *     | IN[ins-1]                     |  {Note: resides in caller's frame}
79  *     |       .                       |
80  *     | IN[0]                         |
81  *     | caller's ArtMethod            |  ... ArtMethod*
82  *     +===============================+  {Note: start of callee's frame}
83  *     | core callee-save spill        |  {variable sized}
84  *     +-------------------------------+
85  *     | fp callee-save spill          |
86  *     +-------------------------------+
87  *     | filler word                   |  {For compatibility, if V[locals-1] used as wide
88  *     +-------------------------------+
89  *     | V[locals-1]                   |
90  *     | V[locals-2]                   |
91  *     |      .                        |
92  *     |      .                        |  ... (reg == 2)
93  *     | V[1]                          |  ... (reg == 1)
94  *     | V[0]                          |  ... (reg == 0) <---- "locals_start"
95  *     +-------------------------------+
96  *     | stack alignment padding       |  {0 to (kStackAlignWords-1) of padding}
97  *     +-------------------------------+
98  *     | Compiler temp region          |  ... (reg >= max_num_special_temps)
99  *     |      .                        |
100  *     |      .                        |
101  *     | V[max_num_special_temps + 1]  |
102  *     | V[max_num_special_temps + 0]  |
103  *     +-------------------------------+
104  *     | OUT[outs-1]                   |
105  *     | OUT[outs-2]                   |
106  *     |       .                       |
107  *     | OUT[0]                        |
108  *     | ArtMethod*                    |  ... (reg == num_total_code_regs == special_temp_value) <<== sp, 16-byte aligned
109  *     +===============================+
110  */
111 
112 class StackVisitor {
113  public:
114   // This enum defines a flag to control whether inlined frames are included
115   // when walking the stack.
116   enum class StackWalkKind {
117     kIncludeInlinedFrames,
118     kSkipInlinedFrames,
119   };
120 
121  protected:
122   StackVisitor(Thread* thread,
123                Context* context,
124                StackWalkKind walk_kind,
125                bool check_suspended = true);
126 
127   bool GetRegisterIfAccessible(uint32_t reg, VRegKind kind, uint32_t* val) const
128       REQUIRES_SHARED(Locks::mutator_lock_);
129 
130  public:
~StackVisitor()131   virtual ~StackVisitor() {}
132   StackVisitor(const StackVisitor&) = default;
133   StackVisitor(StackVisitor&&) = default;
134 
135   // Return 'true' if we should continue to visit more frames, 'false' to stop.
136   virtual bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) = 0;
137 
138   enum class CountTransitions {
139     kYes,
140     kNo,
141   };
142 
143   template <CountTransitions kCount = CountTransitions::kYes>
144   void WalkStack(bool include_transitions = false) REQUIRES_SHARED(Locks::mutator_lock_);
145 
146   // Convenience helper function to walk the stack with a lambda as a visitor.
147   template <CountTransitions kCountTransitions = CountTransitions::kYes,
148             typename T>
149   ALWAYS_INLINE static void WalkStack(const T& fn,
150                                       Thread* thread,
151                                       Context* context,
152                                       StackWalkKind walk_kind,
153                                       bool check_suspended = true,
154                                       bool include_transitions = false)
REQUIRES_SHARED(Locks::mutator_lock_)155       REQUIRES_SHARED(Locks::mutator_lock_) {
156     class LambdaStackVisitor : public StackVisitor {
157      public:
158       LambdaStackVisitor(const T& fn,
159                          Thread* thread,
160                          Context* context,
161                          StackWalkKind walk_kind,
162                          bool check_suspended = true)
163           : StackVisitor(thread, context, walk_kind, check_suspended), fn_(fn) {}
164 
165       bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
166         return fn_(this);
167       }
168 
169      private:
170       T fn_;
171     };
172     LambdaStackVisitor visitor(fn, thread, context, walk_kind, check_suspended);
173     visitor.template WalkStack<kCountTransitions>(include_transitions);
174   }
175 
GetThread()176   Thread* GetThread() const {
177     return thread_;
178   }
179 
180   ArtMethod* GetMethod() const REQUIRES_SHARED(Locks::mutator_lock_);
181 
182   // Sets this stack frame's method pointer. This requires a full lock of the MutatorLock. This
183   // doesn't work with inlined methods.
184   void SetMethod(ArtMethod* method) REQUIRES(Locks::mutator_lock_);
185 
GetOuterMethod()186   ArtMethod* GetOuterMethod() const {
187     return *GetCurrentQuickFrame();
188   }
189 
IsShadowFrame()190   bool IsShadowFrame() const {
191     return cur_shadow_frame_ != nullptr;
192   }
193 
194   uint32_t GetDexPc(bool abort_on_failure = true) const REQUIRES_SHARED(Locks::mutator_lock_);
195 
196   mirror::Object* GetThisObject() const REQUIRES_SHARED(Locks::mutator_lock_);
197 
198   size_t GetNativePcOffset() const REQUIRES_SHARED(Locks::mutator_lock_);
199 
200   // Returns the height of the stack in the managed stack frames, including transitions.
GetFrameHeight()201   size_t GetFrameHeight() REQUIRES_SHARED(Locks::mutator_lock_) {
202     return GetNumFrames() - cur_depth_ - 1;
203   }
204 
205   // Returns a frame ID for JDWP use, starting from 1.
GetFrameId()206   size_t GetFrameId() REQUIRES_SHARED(Locks::mutator_lock_) {
207     return GetFrameHeight() + 1;
208   }
209 
GetNumFrames()210   size_t GetNumFrames() REQUIRES_SHARED(Locks::mutator_lock_) {
211     if (num_frames_ == 0) {
212       num_frames_ = ComputeNumFrames(thread_, walk_kind_);
213     }
214     return num_frames_;
215   }
216 
GetFrameDepth()217   size_t GetFrameDepth() const REQUIRES_SHARED(Locks::mutator_lock_) {
218     return cur_depth_;
219   }
220 
221   // Get the method and dex pc immediately after the one that's currently being visited.
222   bool GetNextMethodAndDexPc(ArtMethod** next_method, uint32_t* next_dex_pc)
223       REQUIRES_SHARED(Locks::mutator_lock_);
224 
225   bool GetVReg(ArtMethod* m, uint16_t vreg, VRegKind kind, uint32_t* val) const
226       REQUIRES_SHARED(Locks::mutator_lock_);
227 
228   bool GetVRegPair(ArtMethod* m, uint16_t vreg, VRegKind kind_lo, VRegKind kind_hi,
229                    uint64_t* val) const
230       REQUIRES_SHARED(Locks::mutator_lock_);
231 
232   // Values will be set in debugger shadow frames. Debugger will make sure deoptimization
233   // is triggered to make the values effective.
234   bool SetVReg(ArtMethod* m, uint16_t vreg, uint32_t new_value, VRegKind kind)
235       REQUIRES_SHARED(Locks::mutator_lock_);
236 
237   // Values will be set in debugger shadow frames. Debugger will make sure deoptimization
238   // is triggered to make the values effective.
239   bool SetVRegPair(ArtMethod* m,
240                    uint16_t vreg,
241                    uint64_t new_value,
242                    VRegKind kind_lo,
243                    VRegKind kind_hi)
244       REQUIRES_SHARED(Locks::mutator_lock_);
245 
246   uintptr_t* GetGPRAddress(uint32_t reg) const;
247 
248   uintptr_t GetReturnPc() const REQUIRES_SHARED(Locks::mutator_lock_);
249 
250   void SetReturnPc(uintptr_t new_ret_pc) REQUIRES_SHARED(Locks::mutator_lock_);
251 
IsInInlinedFrame()252   bool IsInInlinedFrame() const {
253     return !current_inline_frames_.empty();
254   }
255 
GetCurrentInlinedFrame()256   InlineInfo GetCurrentInlinedFrame() const {
257     return current_inline_frames_.back();
258   }
259 
GetCurrentQuickFramePc()260   uintptr_t GetCurrentQuickFramePc() const {
261     return cur_quick_frame_pc_;
262   }
263 
GetCurrentQuickFrame()264   ArtMethod** GetCurrentQuickFrame() const {
265     return cur_quick_frame_;
266   }
267 
GetCurrentShadowFrame()268   ShadowFrame* GetCurrentShadowFrame() const {
269     return cur_shadow_frame_;
270   }
271 
GetCurrentHandleScope(size_t pointer_size)272   HandleScope* GetCurrentHandleScope(size_t pointer_size) const {
273     ArtMethod** sp = GetCurrentQuickFrame();
274     // Skip ArtMethod*; handle scope comes next;
275     return reinterpret_cast<HandleScope*>(reinterpret_cast<uintptr_t>(sp) + pointer_size);
276   }
277 
278   std::string DescribeLocation() const REQUIRES_SHARED(Locks::mutator_lock_);
279 
280   static size_t ComputeNumFrames(Thread* thread, StackWalkKind walk_kind)
281       REQUIRES_SHARED(Locks::mutator_lock_);
282 
283   static void DescribeStack(Thread* thread) REQUIRES_SHARED(Locks::mutator_lock_);
284 
GetCurrentOatQuickMethodHeader()285   const OatQuickMethodHeader* GetCurrentOatQuickMethodHeader() const {
286     return cur_oat_quick_method_header_;
287   }
288 
289   QuickMethodFrameInfo GetCurrentQuickFrameInfo() const REQUIRES_SHARED(Locks::mutator_lock_);
290 
291  private:
292   // Private constructor known in the case that num_frames_ has already been computed.
293   StackVisitor(Thread* thread,
294                Context* context,
295                StackWalkKind walk_kind,
296                size_t num_frames,
297                bool check_suspended = true)
298       REQUIRES_SHARED(Locks::mutator_lock_);
299 
IsAccessibleRegister(uint32_t reg,bool is_float)300   bool IsAccessibleRegister(uint32_t reg, bool is_float) const {
301     return is_float ? IsAccessibleFPR(reg) : IsAccessibleGPR(reg);
302   }
GetRegister(uint32_t reg,bool is_float)303   uintptr_t GetRegister(uint32_t reg, bool is_float) const {
304     DCHECK(IsAccessibleRegister(reg, is_float));
305     return is_float ? GetFPR(reg) : GetGPR(reg);
306   }
307 
308   bool IsAccessibleGPR(uint32_t reg) const;
309   uintptr_t GetGPR(uint32_t reg) const;
310 
311   bool IsAccessibleFPR(uint32_t reg) const;
312   uintptr_t GetFPR(uint32_t reg) const;
313 
314   bool GetVRegFromDebuggerShadowFrame(uint16_t vreg, VRegKind kind, uint32_t* val) const
315       REQUIRES_SHARED(Locks::mutator_lock_);
316   bool GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKind kind,
317                                 uint32_t* val) const
318       REQUIRES_SHARED(Locks::mutator_lock_);
319 
320   bool GetVRegPairFromDebuggerShadowFrame(uint16_t vreg, VRegKind kind_lo, VRegKind kind_hi,
321                                           uint64_t* val) const
322       REQUIRES_SHARED(Locks::mutator_lock_);
323   bool GetVRegPairFromOptimizedCode(ArtMethod* m, uint16_t vreg,
324                                     VRegKind kind_lo, VRegKind kind_hi,
325                                     uint64_t* val) const
326       REQUIRES_SHARED(Locks::mutator_lock_);
327   bool GetRegisterPairIfAccessible(uint32_t reg_lo, uint32_t reg_hi, VRegKind kind_lo,
328                                    uint64_t* val) const
329       REQUIRES_SHARED(Locks::mutator_lock_);
330 
331   void SanityCheckFrame() const REQUIRES_SHARED(Locks::mutator_lock_);
332 
333   Thread* const thread_;
334   const StackWalkKind walk_kind_;
335   ShadowFrame* cur_shadow_frame_;
336   ArtMethod** cur_quick_frame_;
337   uintptr_t cur_quick_frame_pc_;
338   const OatQuickMethodHeader* cur_oat_quick_method_header_;
339   // Lazily computed, number of frames in the stack.
340   size_t num_frames_;
341   // Depth of the frame we're currently at.
342   size_t cur_depth_;
343   // Current inlined frames of the method we are currently at.
344   // We keep poping frames from the end as we visit the frames.
345   CodeInfo current_code_info_;
346   BitTableRange<InlineInfo> current_inline_frames_;
347 
348  protected:
349   Context* const context_;
350   const bool check_suspended_;
351 };
352 
353 }  // namespace art
354 
355 #endif  // ART_RUNTIME_STACK_H_
356