Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
stack_frame.h
Go to the documentation of this file.
1// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_STACK_FRAME_H_
6#define RUNTIME_VM_STACK_FRAME_H_
7
8#include "vm/allocation.h"
9#include "vm/frame_layout.h"
10#include "vm/object.h"
11#include "vm/stub_code.h"
12
13#if defined(TARGET_ARCH_IA32)
14#include "vm/stack_frame_ia32.h"
15#elif defined(TARGET_ARCH_X64)
16#include "vm/stack_frame_x64.h"
17#elif defined(TARGET_ARCH_ARM)
18#include "vm/stack_frame_arm.h"
19#elif defined(TARGET_ARCH_ARM64)
21#elif defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64)
23#else
24#error Unknown architecture.
25#endif
26
27namespace dart {
28
29// Forward declarations.
30class ObjectPointerVisitor;
31class LocalVariable;
32
33extern FrameLayout runtime_frame_layout;
34
35// Generic stack frame.
36class StackFrame : public ValueObject {
37 public:
38 virtual ~StackFrame() {}
39
40 // Accessors to get the pc, sp and fp of a frame.
41 uword sp() const { return sp_; }
42 uword fp() const { return fp_; }
43 uword pc() const { return pc_; }
44
45 // The pool pointer is not implemented on all architectures.
54
55 bool IsMarkedForLazyDeopt() const {
56 uword raw_pc =
57 *reinterpret_cast<uword*>(sp() + (kSavedPcSlotFromSp * kWordSize));
58 return raw_pc == StubCode::DeoptimizeLazyFromReturn().EntryPoint();
59 }
61 set_pc(StubCode::DeoptimizeLazyFromReturn().EntryPoint());
62 }
64 // If this frame was marked for lazy deopt, pc_ was computed to be the
65 // original return address using the pending deopts table in GetCallerPc.
66 // Write this value back into the frame.
67 uword original_pc = pc();
68 ASSERT(original_pc != StubCode::DeoptimizeLazyFromReturn().EntryPoint());
69 set_pc(original_pc);
70 }
71
72 void set_pc(uword value) {
73 *reinterpret_cast<uword*>(sp() + (kSavedPcSlotFromSp * kWordSize)) = value;
74 pc_ = value;
75 }
76
77 void set_pc_marker(CodePtr code) {
78 *reinterpret_cast<CodePtr*>(
80 }
81
82 // Visit objects in the frame.
83 virtual void VisitObjectPointers(ObjectPointerVisitor* visitor);
84
85 const char* ToCString() const;
86
87 // Check validity of a frame, used for assertion purposes.
88 virtual bool IsValid() const;
89
90 // Returns true iff the current frame is a bare instructions dart frame.
91 bool IsBareInstructionsDartFrame() const;
92
93 // Returns true iff the current frame is a bare instructions stub frame.
94 bool IsBareInstructionsStubFrame() const;
95
96 // Frame type.
97 virtual bool IsDartFrame(bool validate = true) const {
98 ASSERT(!validate || IsValid());
99 return !(IsEntryFrame() || IsExitFrame() || IsStubFrame());
100 }
101 virtual bool IsStubFrame() const;
102 virtual bool IsEntryFrame() const { return false; }
103 virtual bool IsExitFrame() const { return false; }
104
105 FunctionPtr LookupDartFunction() const;
106 CodePtr LookupDartCode() const;
108 uword* handler_pc,
109 bool* needs_stacktrace,
110 bool* is_catch_all,
111 bool* is_optimized) const;
112 // Returns token_pos of the pc(), or -1 if none exists.
114
115 static void DumpCurrentTrace();
116
118
119 protected:
121 : fp_(0), sp_(0), pc_(0), thread_(thread) {}
122
123 // Name of the frame, used for generic frame printing functionality.
124 virtual const char* GetName() const {
125 if (IsBareInstructionsStubFrame()) return "bare-stub";
126 if (IsStubFrame()) return "stub";
127 return IsBareInstructionsDartFrame() ? "bare-dart" : "dart";
128 }
129
130 Isolate* isolate() const { return thread_->isolate(); }
131 IsolateGroup* isolate_group() const { return thread_->isolate_group(); }
132
133 Thread* thread() const { return thread_; }
134
135 private:
136 CodePtr GetCodeObject() const;
137
138 uword GetCallerFp() const {
139 return *(reinterpret_cast<uword*>(fp() +
141 }
142
143 uword GetCallerPc() const {
144 uword raw_pc = *(reinterpret_cast<uword*>(
146 ASSERT(raw_pc != StubCode::DeoptimizeLazyFromThrow().EntryPoint());
147 if (raw_pc == StubCode::DeoptimizeLazyFromReturn().EntryPoint()) {
148 return thread_->pending_deopts().FindPendingDeopt(GetCallerFp());
149 }
150 return raw_pc;
151 }
152
153 uword fp_;
154 uword sp_;
155 uword pc_;
156 Thread* thread_;
157
158 // The iterators FrameSetIterator and StackFrameIterator set the private
159 // fields fp_ and sp_ when they return the respective frame objects.
160 friend class FrameSetIterator;
161 friend class StackFrameIterator;
162 // UntaggedSuspendState::VisitSuspendStatePointers creates a temporary
163 // StackFrame objects for the copied frames of the suspended functions.
167};
168
169// Exit frame is used to mark the transition from dart code into dart VM
170// runtime code.
171class ExitFrame : public StackFrame {
172 public:
173 bool IsValid() const { return sp() == 0; }
174 bool IsDartFrame(bool validate = true) const { return false; }
175 bool IsStubFrame() const { return false; }
176 bool IsExitFrame() const { return true; }
177
178 // Visit objects in the frame.
179 virtual void VisitObjectPointers(ObjectPointerVisitor* visitor);
180
181 protected:
182 virtual const char* GetName() const { return "exit"; }
183
184 private:
185 explicit ExitFrame(Thread* thread) : StackFrame(thread) {}
186
187 friend class StackFrameIterator;
189};
190
191// Entry Frame is used to mark the transition from dart VM runtime code into
192// dart code.
193class EntryFrame : public StackFrame {
194 public:
195 bool IsValid() const { return StubCode::InInvocationStub(pc()); }
196 bool IsDartFrame(bool validate = true) const { return false; }
197 bool IsStubFrame() const { return false; }
198 bool IsEntryFrame() const { return true; }
199
200 // Visit objects in the frame.
201 virtual void VisitObjectPointers(ObjectPointerVisitor* visitor);
202
203 protected:
204 virtual const char* GetName() const { return "entry"; }
205
206 private:
207 explicit EntryFrame(Thread* thread) : StackFrame(thread) {}
208
209 friend class StackFrameIterator;
211};
212
213// A StackFrameIterator can be initialized with a thread other than the
214// current thread. Because this is generally a bad idea, it is only allowed on
215// Windows- where it is needed for the profiler. It is the responsibility of
216// users of StackFrameIterator to ensure that the thread given is not running
217// concurrently.
219 public:
224
225 // Iterators for iterating over all frames from the last ExitFrame to the
226 // first EntryFrame.
227 StackFrameIterator(ValidationPolicy validation_policy,
228 Thread* thread,
229 CrossThreadPolicy cross_thread_policy);
231 ValidationPolicy validation_policy,
232 Thread* thread,
233 CrossThreadPolicy cross_thread_policy);
234
235 // Iterator for iterating over all frames from the current frame (given by its
236 // fp, sp, and pc) to the first EntryFrame.
238 uword sp,
239 uword pc,
240 ValidationPolicy validation_policy,
241 Thread* thread,
242 CrossThreadPolicy cross_thread_policy);
243
244 explicit StackFrameIterator(const StackFrameIterator& orig);
245
246 // Checks if a next frame exists.
247 bool HasNextFrame() const { return frames_.fp_ != 0; }
248
249 // Get next frame. Becomes invalid after the next call to NextFrame.
251
252 bool validate() const { return validate_; }
253
254 private:
255 // Iterator for iterating over the set of frames (dart or stub) which exist
256 // in one EntryFrame and ExitFrame block.
257 class FrameSetIterator : public ValueObject {
258 public:
259 // Checks if a next non entry/exit frame exists in the set.
260 bool HasNext() const {
261 if (fp_ == 0) {
262 return false;
263 }
264 const uword pc =
265 *(reinterpret_cast<uword*>(sp_ + (kSavedPcSlotFromSp * kWordSize)));
266 return !StubCode::InInvocationStub(pc);
267 }
268
269 // Get next non entry/exit frame in the set (assumes a next frame exists).
270 StackFrame* NextFrame(bool validate);
271
272 private:
273 explicit FrameSetIterator(Thread* thread)
274 : fp_(0), sp_(0), pc_(0), stack_frame_(thread), thread_(thread) {}
275 void Unpoison();
276
277 uword fp_;
278 uword sp_;
279 uword pc_;
280 StackFrame stack_frame_; // Singleton frame returned by NextFrame().
281 Thread* thread_;
282
283 friend class StackFrameIterator;
284 DISALLOW_COPY_AND_ASSIGN(FrameSetIterator);
285 };
286
287 // Get next exit frame.
288 ExitFrame* NextExitFrame();
289
290 // Get next entry frame.
291 EntryFrame* NextEntryFrame();
292
293 // Get an iterator to the next set of frames between an entry and exit
294 // frame.
295 FrameSetIterator* NextFrameSet() { return &frames_; }
296
297 // Setup last or next exit frames so that we are ready to iterate over
298 // stack frames.
299 void SetupLastExitFrameData();
300 void SetupNextExitFrameData();
301
302 bool validate_; // Validate each frame as we traverse the frames.
303 EntryFrame entry_; // Singleton entry frame returned by NextEntryFrame().
304 ExitFrame exit_; // Singleton exit frame returned by NextExitFrame().
305 FrameSetIterator frames_;
306 StackFrame* current_frame_; // Points to the current frame in the iterator.
307 Thread* thread_;
308
310};
311
312// Iterator for iterating over all dart frames (skips over exit frames,
313// entry frames and stub frames).
314// A DartFrameIterator can be initialized with an isolate other than the
315// current thread's isolate. Because this is generally a bad idea,
316// it is only allowed on Windows- where it is needed for the profiler.
317// It is the responsibility of users of DartFrameIterator to ensure that the
318// isolate given is not running concurrently on another thread.
320 public:
322 Thread* thread,
323 StackFrameIterator::CrossThreadPolicy cross_thread_policy)
325 thread,
326 cross_thread_policy) {}
328 uword last_fp,
329 Thread* thread,
330 StackFrameIterator::CrossThreadPolicy cross_thread_policy)
331 : frames_(last_fp,
333 thread,
334 cross_thread_policy) {}
335
337 uword sp,
338 uword pc,
339 Thread* thread,
340 StackFrameIterator::CrossThreadPolicy cross_thread_policy)
341 : frames_(fp,
342 sp,
343 pc,
345 thread,
346 cross_thread_policy) {}
347
349 : frames_(orig.frames_) {}
350
351 // Get next dart frame.
353 StackFrame* frame = frames_.NextFrame();
354 while (frame != nullptr && !frame->IsDartFrame(frames_.validate())) {
355 frame = frames_.NextFrame();
356 }
357 return frame;
358 }
359
360 private:
361 StackFrameIterator frames_;
362};
363
364// Iterator for iterating over all inlined dart functions in an optimized
365// dart frame (the iteration includes the function that is inlining the
366// other functions).
368 public:
370 bool Done() const { return index_ == -1; }
371 void Advance();
372
373 FunctionPtr function() const {
374 ASSERT(!Done());
375 return function_.ptr();
376 }
377
378 uword pc() const {
379 ASSERT(!Done());
380 return pc_;
381 }
382
383 CodePtr code() const {
384 ASSERT(!Done());
385 return code_.ptr();
386 }
387
388#if !defined(DART_PRECOMPILED_RUNTIME)
389 intptr_t GetDeoptFpOffset() const;
390#endif // !defined(DART_PRECOMPILED_RUNTIME)
391
392 private:
393 void SetDone() { index_ = -1; }
394
395 intptr_t index_;
396 intptr_t num_materializations_;
397 intptr_t dest_frame_size_;
398 Code& code_;
399 TypedData& deopt_info_;
400 Function& function_;
401 uword pc_;
402 GrowableArray<DeoptInstr*> deopt_instructions_;
403 ObjectPool& object_table_;
404
405 DISALLOW_COPY_AND_ASSIGN(InlinedFunctionsIterator);
406};
407
408#if defined(DEBUG)
409void ValidateFrames();
410#endif
411
412DART_FORCE_INLINE static intptr_t LocalVarIndex(intptr_t fp_offset,
413 intptr_t var_index) {
414 return fp_offset + var_index;
415}
416
417DART_FORCE_INLINE static uword ParamAddress(uword fp, intptr_t reverse_index) {
418 return fp + (kParamEndSlotFromFp * kWordSize) + (reverse_index * kWordSize);
419}
420
421// Both fp and other_fp are compiled code frame pointers.
422DART_FORCE_INLINE static bool IsCalleeFrameOf(uword fp, uword other_fp) {
423 return other_fp < fp;
424}
425
426// Value for stack limit that is used to cause an interrupt.
427static constexpr uword kInterruptStackLimit = ~static_cast<uword>(0);
428
429DART_FORCE_INLINE static uword LocalVarAddress(uword fp, intptr_t index) {
430 return fp + LocalVarIndex(0, index) * kWordSize;
431}
432
433} // namespace dart
434
435#endif // RUNTIME_VM_STACK_FRAME_H_
#define UNREACHABLE()
Definition assert.h:248
DartFrameIterator(uword fp, uword sp, uword pc, Thread *thread, StackFrameIterator::CrossThreadPolicy cross_thread_policy)
DartFrameIterator(Thread *thread, StackFrameIterator::CrossThreadPolicy cross_thread_policy)
StackFrame * NextFrame()
DartFrameIterator(uword last_fp, Thread *thread, StackFrameIterator::CrossThreadPolicy cross_thread_policy)
DartFrameIterator(const DartFrameIterator &orig)
virtual const char * GetName() const
bool IsStubFrame() const
virtual void VisitObjectPointers(ObjectPointerVisitor *visitor)
bool IsValid() const
bool IsEntryFrame() const
bool IsDartFrame(bool validate=true) const
bool IsValid() const
virtual void VisitObjectPointers(ObjectPointerVisitor *visitor)
bool IsDartFrame(bool validate=true) const
bool IsExitFrame() const
virtual const char * GetName() const
bool IsStubFrame() const
intptr_t GetDeoptFpOffset() const
FunctionPtr function() const
ObjectPtr ptr() const
Definition object.h:332
uword FindPendingDeopt(uword fp)
uword pc() const
Definition stack_frame.h:43
virtual bool IsEntryFrame() const
virtual void VisitObjectPointers(ObjectPointerVisitor *visitor)
Isolate * isolate() const
virtual bool IsExitFrame() const
const char * ToCString() const
CodePtr LookupDartCode() const
virtual bool IsStubFrame() const
void set_pc(uword value)
Definition stack_frame.h:72
bool IsBareInstructionsStubFrame() const
bool FindExceptionHandler(Thread *thread, uword *handler_pc, bool *needs_stacktrace, bool *is_catch_all, bool *is_optimized) const
void MarkForLazyDeopt()
Definition stack_frame.h:60
static int SavedCallerPpSlotFromFp()
Definition stack_frame.h:46
TokenPosition GetTokenPos() const
uword fp() const
Definition stack_frame.h:42
void UnmarkForLazyDeopt()
Definition stack_frame.h:63
bool IsBareInstructionsDartFrame() const
uword sp() const
Definition stack_frame.h:41
Thread * thread() const
virtual bool IsDartFrame(bool validate=true) const
Definition stack_frame.h:97
FunctionPtr LookupDartFunction() const
bool IsMarkedForLazyDeopt() const
Definition stack_frame.h:55
virtual const char * GetName() const
StackFrame(Thread *thread)
virtual ~StackFrame()
Definition stack_frame.h:38
void set_pc_marker(CodePtr code)
Definition stack_frame.h:77
uword GetCallerSp() const
static void DumpCurrentTrace()
IsolateGroup * isolate_group() const
friend class FrameSetIterator
virtual bool IsValid() const
static bool InInvocationStub(uword pc)
Definition stub_code.cc:132
PendingDeopts & pending_deopts()
Definition thread.h:1131
Isolate * isolate() const
Definition thread.h:533
IsolateGroup * isolate_group() const
Definition thread.h:540
#define ASSERT(E)
double frame
Definition examples.cpp:31
uint8_t value
static constexpr int kSavedCallerPcSlotFromFp
static DART_FORCE_INLINE intptr_t LocalVarIndex(intptr_t fp_offset, intptr_t var_index)
static constexpr int kSavedCallerFpSlotFromFp
static constexpr uword kInterruptStackLimit
static DART_FORCE_INLINE uword ParamAddress(uword fp, intptr_t reverse_index)
uintptr_t uword
Definition globals.h:501
static constexpr int kParamEndSlotFromFp
const uint32_t fp
static constexpr int kCallerSpSlotFromFp
static constexpr int kSavedPcSlotFromSp
ValidationPolicy
Definition thread.h:271
FrameLayout runtime_frame_layout
static DART_FORCE_INLINE uword LocalVarAddress(uword fp, intptr_t index)
constexpr intptr_t kWordSize
Definition globals.h:509
static DART_FORCE_INLINE bool IsCalleeFrameOf(uword fp, uword other_fp)
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581
intptr_t code_from_fp
intptr_t saved_caller_pp_from_fp