Flutter Engine
The Flutter Engine
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.
50 }
52 return 0;
53 }
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
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:
223 };
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)
Definition: stack_frame.h:336
DartFrameIterator(Thread *thread, StackFrameIterator::CrossThreadPolicy cross_thread_policy)
Definition: stack_frame.h:321
StackFrame * NextFrame()
Definition: stack_frame.h:352
DartFrameIterator(uword last_fp, Thread *thread, StackFrameIterator::CrossThreadPolicy cross_thread_policy)
Definition: stack_frame.h:327
DartFrameIterator(const DartFrameIterator &orig)
Definition: stack_frame.h:348
virtual const char * GetName() const
Definition: stack_frame.h:204
bool IsStubFrame() const
Definition: stack_frame.h:197
virtual void VisitObjectPointers(ObjectPointerVisitor *visitor)
Definition: stack_frame.cc:196
bool IsValid() const
Definition: stack_frame.h:195
bool IsEntryFrame() const
Definition: stack_frame.h:198
bool IsDartFrame(bool validate=true) const
Definition: stack_frame.h:196
bool IsValid() const
Definition: stack_frame.h:173
virtual void VisitObjectPointers(ObjectPointerVisitor *visitor)
Definition: stack_frame.cc:181
bool IsDartFrame(bool validate=true) const
Definition: stack_frame.h:174
bool IsExitFrame() const
Definition: stack_frame.h:176
virtual const char * GetName() const
Definition: stack_frame.h:182
bool IsStubFrame() const
Definition: stack_frame.h:175
intptr_t GetDeoptFpOffset() const
Definition: stack_frame.cc:732
InlinedFunctionsIterator(const Code &code, uword pc)
Definition: stack_frame.cc:663
FunctionPtr function() const
Definition: stack_frame.h:373
ObjectPtr ptr() const
Definition: object.h:332
uword FindPendingDeopt(uword fp)
bool HasNextFrame() const
Definition: stack_frame.h:247
StackFrameIterator(ValidationPolicy validation_policy, Thread *thread, CrossThreadPolicy cross_thread_policy)
Definition: stack_frame.cc:484
StackFrame * NextFrame()
Definition: stack_frame.cc:549
uword pc() const
Definition: stack_frame.h:43
virtual bool IsEntryFrame() const
Definition: stack_frame.h:102
virtual void VisitObjectPointers(ObjectPointerVisitor *visitor)
Definition: stack_frame.cc:206
Isolate * isolate() const
Definition: stack_frame.h:130
virtual bool IsExitFrame() const
Definition: stack_frame.h:103
const char * ToCString() const
Definition: stack_frame.cc:169
CodePtr LookupDartCode() const
Definition: stack_frame.cc:336
virtual bool IsStubFrame() const
Definition: stack_frame.cc:150
void set_pc(uword value)
Definition: stack_frame.h:72
bool IsBareInstructionsStubFrame() const
Definition: stack_frame.cc:132
bool FindExceptionHandler(Thread *thread, uword *handler_pc, bool *needs_stacktrace, bool *is_catch_all, bool *is_optimized) const
Definition: stack_frame.cc:370
void MarkForLazyDeopt()
Definition: stack_frame.h:60
static int SavedCallerPpSlotFromFp()
Definition: stack_frame.h:46
TokenPosition GetTokenPos() const
Definition: stack_frame.cc:429
uword fp() const
Definition: stack_frame.h:42
void UnmarkForLazyDeopt()
Definition: stack_frame.h:63
bool IsBareInstructionsDartFrame() const
Definition: stack_frame.cc:114
uword sp() const
Definition: stack_frame.h:41
Thread * thread() const
Definition: stack_frame.h:133
virtual bool IsDartFrame(bool validate=true) const
Definition: stack_frame.h:97
FunctionPtr LookupDartFunction() const
Definition: stack_frame.cc:325
bool IsMarkedForLazyDeopt() const
Definition: stack_frame.h:55
virtual const char * GetName() const
Definition: stack_frame.h:124
StackFrame(Thread *thread)
Definition: stack_frame.h:120
virtual ~StackFrame()
Definition: stack_frame.h:38
void set_pc_marker(CodePtr code)
Definition: stack_frame.h:77
uword GetCallerSp() const
Definition: stack_frame.h:117
static void DumpCurrentTrace()
Definition: stack_frame.cc:454
IsolateGroup * isolate_group() const
Definition: stack_frame.h:131
friend class FrameSetIterator
Definition: stack_frame.h:160
virtual bool IsValid() const
Definition: stack_frame.cc:447
static bool InInvocationStub(uword pc)
Definition: stub_code.cc:132
PendingDeopts & pending_deopts()
Definition: thread.h:1144
Isolate * isolate() const
Definition: thread.h:534
IsolateGroup * isolate_group() const
Definition: thread.h:541
#define ASSERT(E)
double frame
Definition: examples.cpp:31
uint8_t value
Definition: dart_vm.cc:33
static constexpr int kSavedCallerPcSlotFromFp
static DART_FORCE_INLINE intptr_t LocalVarIndex(intptr_t fp_offset, intptr_t var_index)
Definition: stack_frame.h:412
static constexpr int kSavedCallerFpSlotFromFp
static constexpr uword kInterruptStackLimit
Definition: stack_frame.h:427
static DART_FORCE_INLINE uword ParamAddress(uword fp, intptr_t reverse_index)
Definition: stack_frame.h:417
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
Definition: stack_frame.cc:81
static DART_FORCE_INLINE uword LocalVarAddress(uword fp, intptr_t index)
Definition: stack_frame.h:429
constexpr intptr_t kWordSize
Definition: globals.h:509
static DART_FORCE_INLINE bool IsCalleeFrameOf(uword fp, uword other_fp)
Definition: stack_frame.h:422
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581
intptr_t code_from_fp
Definition: frame_layout.h:52
intptr_t saved_caller_pp_from_fp
Definition: frame_layout.h:43