Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
stack_frame.cc
Go to the documentation of this file.
1// Copyright (c) 2012, 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#include "vm/stack_frame.h"
6
10#include "vm/heap/become.h"
11#include "vm/isolate.h"
12#include "vm/object.h"
13#include "vm/object_store.h"
14#include "vm/os.h"
15#include "vm/parser.h"
16#include "vm/raw_object.h"
17#include "vm/reusable_handles.h"
19#include "vm/scopes.h"
20#include "vm/stub_code.h"
21#include "vm/visitor.h"
22
23#if !defined(DART_PRECOMPILED_RUNTIME)
25#endif // !defined(DART_PRECOMPILED_RUNTIME)
26
27namespace dart {
28
30 /*.first_object_from_fp = */ -1,
31 /*.last_fixed_object_from_fp = */ -1,
32 /*.param_end_from_fp = */ -1,
33 /*.last_param_from_entry_sp = */ -1,
34 /*.first_local_from_fp = */ -1,
35 /*.dart_fixed_frame_size = */ -1,
36 /*.saved_caller_pp_from_fp = */ -1,
37 /*.saved_caller_fp_from_fp = */ -1,
38 /*.saved_caller_pc_from_fp = */ -1,
39 /*.code_from_fp = */ -1,
40 /*.exit_link_slot_from_entry_fp = */ -1,
41};
42
44 /*.first_object_from_fp = */ kFirstObjectSlotFromFp,
45 /*.last_fixed_object_from_fp = */ kLastFixedObjectSlotFromFp,
46 /*.param_end_from_fp = */ kParamEndSlotFromFp,
47 /*.last_param_from_entry_sp = */ kLastParamSlotFromEntrySp,
48 /*.first_local_from_fp = */ kFirstLocalSlotFromFp,
49 /*.dart_fixed_frame_size = */ kDartFrameFixedSize,
50 /*.saved_caller_pp_from_fp = */ kSavedCallerPpSlotFromFp,
51 /*.saved_caller_fp_from_fp = */ kSavedCallerFpSlotFromFp,
52 /*.saved_caller_pc_from_fp = */ kSavedCallerPcSlotFromFp,
53 /*.code_from_fp = */ kPcMarkerSlotFromFp,
54 /*.exit_link_slot_from_entry_fp = */ kExitLinkSlotFromEntryFp,
55};
57 /*.first_object_from_pc =*/kFirstObjectSlotFromFp, // No saved PP slot.
58 /*.last_fixed_object_from_fp = */ kLastFixedObjectSlotFromFp +
59 2, // No saved CODE, PP slots
60 /*.param_end_from_fp = */ kParamEndSlotFromFp,
61 /*.last_param_from_entry_sp = */ kLastParamSlotFromEntrySp,
62 /*.first_local_from_fp =*/kFirstLocalSlotFromFp +
63 2, // No saved CODE, PP slots.
64 /*.dart_fixed_frame_size =*/kDartFrameFixedSize -
65 2, // No saved CODE, PP slots.
66 /*.saved_caller_pp_from_fp = */ 0, // No saved PP slot.
67 /*.saved_caller_fp_from_fp = */ kSavedCallerFpSlotFromFp,
68 /*.saved_caller_pc_from_fp = */ kSavedCallerPcSlotFromFp,
69 /*.code_from_fp = */ 0, // No saved CODE
70 /*.exit_link_slot_from_entry_fp = */ kExitLinkSlotFromEntryFp,
71};
72
73namespace compiler {
74
75namespace target {
76FrameLayout frame_layout = invalid_frame_layout;
77}
78
79} // namespace compiler
80
82
84 const LocalVariable* variable) const {
85 ASSERT(!variable->is_captured());
86 return this->FrameSlotForVariableIndex(variable->index().value());
87}
88
89intptr_t FrameLayout::FrameSlotForVariableIndex(intptr_t variable_index) const {
90 // Variable indices are:
91 // [1, 2, ..., M] for the M parameters.
92 // [0, -1, -2, ... -(N-1)] for the N [LocalVariable]s
93 // See (runtime/vm/scopes.h)
94 return variable_index <= 0 ? (variable_index + first_local_from_fp)
95 : (variable_index + param_end_from_fp);
96}
97
99 // By default we use frames with CODE_REG/PP in the frame.
100 compiler::target::frame_layout = default_frame_layout;
102
103 if (FLAG_precompiled_mode) {
104 compiler::target::frame_layout = bare_instructions_frame_layout;
105 }
106#if defined(DART_PRECOMPILED_RUNTIME)
107 if (FLAG_precompiled_mode) {
108 compiler::target::frame_layout = invalid_frame_layout;
110 }
111#endif
112}
113
115 if (!FLAG_precompiled_mode) {
116 return false;
117 }
118 NoSafepointScope no_safepoint;
119
120 Code code;
121 code = ReversePc::Lookup(this->isolate_group(), pc(),
122 /*is_return_address=*/true);
123 if (!code.IsNull()) {
124 auto const cid = code.OwnerClassId();
125 ASSERT(cid == kNullCid || cid == kClassCid || cid == kFunctionCid);
126 return cid == kFunctionCid;
127 }
128
129 return false;
130}
131
133 if (!FLAG_precompiled_mode) {
134 return false;
135 }
136 NoSafepointScope no_safepoint;
137
138 Code code;
139 code = ReversePc::Lookup(this->isolate_group(), pc(),
140 /*is_return_address=*/true);
141 if (!code.IsNull()) {
142 auto const cid = code.OwnerClassId();
143 ASSERT(cid == kNullCid || cid == kClassCid || cid == kFunctionCid);
144 return cid == kNullCid || cid == kClassCid;
145 }
146
147 return false;
148}
149
151 if (FLAG_precompiled_mode) {
153 }
154
156#if !defined(DART_HOST_OS_WINDOWS) && !defined(DART_HOST_OS_FUCHSIA)
157 // On Windows and Fuchsia, the profiler calls this from a separate thread
158 // where Thread::Current() is nullptr, so we cannot create a NoSafepointScope.
159 NoSafepointScope no_safepoint;
160#endif
161
162 CodePtr code = GetCodeObject();
163 ASSERT(code != Object::null());
164 auto const cid = Code::OwnerClassIdOf(code);
165 ASSERT(cid == kNullCid || cid == kClassCid || cid == kFunctionCid);
166 return cid == kNullCid || cid == kClassCid;
167}
168
169const char* StackFrame::ToCString() const {
170 ASSERT(thread_ == Thread::Current());
171 Zone* zone = Thread::Current()->zone();
172 const Code& code = Code::Handle(zone, GetCodeObject());
173 const char* name =
174 code.IsNull()
175 ? "Cannot find code object"
176 : code.QualifiedName(NameFormattingParams(Object::kInternalName));
177 return zone->PrintToString(" pc 0x%" Pp " fp 0x%" Pp " sp 0x%" Pp " %s",
178 pc(), fp(), sp(), name);
179}
180
182 ASSERT(visitor != nullptr);
183 // Visit pc marker and saved pool pointer.
184 ObjectPtr* last_fixed = reinterpret_cast<ObjectPtr*>(fp()) +
186 ObjectPtr* first_fixed = reinterpret_cast<ObjectPtr*>(fp()) +
188 if (first_fixed <= last_fixed) {
189 visitor->VisitPointers(first_fixed, last_fixed);
190 } else {
193 }
194}
195
197 ASSERT(visitor != nullptr);
198 // Visit objects between SP and (FP - callee_save_area).
199 ObjectPtr* first = reinterpret_cast<ObjectPtr*>(sp());
200 ObjectPtr* last =
201 reinterpret_cast<ObjectPtr*>(fp()) + kExitLinkSlotFromEntryFp - 1;
202 // There may not be any pointer to visit; in this case, first > last.
203 visitor->VisitPointers(first, last);
204}
205
207 ASSERT(visitor != nullptr);
208 // NOTE: This code runs while GC is in progress and runs within
209 // a NoHandleScope block. Hence it is not ok to use regular Zone or
210 // Scope handles. We use direct stack handles, the raw pointers in
211 // these handles are not traversed. The use of handles is mainly to
212 // be able to reuse the handle based code and avoid having to add
213 // helper functions to the raw object interface.
214 NoSafepointScope no_safepoint;
215 Code code;
216
219
220 uword code_start;
221
222 if (FLAG_precompiled_mode) {
223 const UntaggedCompressedStackMaps::Payload* global_table_payload;
225 /*is_return_address=*/true, &code_start,
226 &global_table_payload);
227 global_table = global_table_payload;
228 } else {
229 ObjectPtr pc_marker = *(reinterpret_cast<ObjectPtr*>(
231 // May forward raw code. Note we don't just visit the pc marker slot first
232 // because the visitor's forwarding might not be idempotent.
233 visitor->VisitPointer(&pc_marker);
234 if (pc_marker->IsHeapObject() && (pc_marker->GetClassId() == kCodeCid)) {
235 code ^= pc_marker;
236 code_start = code.PayloadStart();
237 ASSERT(code.compressed_stackmaps() != CompressedStackMaps::null());
238 maps = code.compressed_stackmaps();
239 if (maps.UsesGlobalTable()) {
240 global_table =
241 isolate_group()->object_store()->canonicalized_stack_map_entries();
242 }
243 } else {
244 ASSERT(pc_marker == Object::null());
245 }
246 }
247
248 if (!maps.IsNull()) {
249 // Optimized frames have a stack map. We need to visit the frame based
250 // on the stack map.
252 maps, global_table);
253 const uint32_t pc_offset = pc() - code_start;
254 if (it.Find(pc_offset)) {
255 ObjectPtr* first = reinterpret_cast<ObjectPtr*>(sp());
256 ObjectPtr* last = reinterpret_cast<ObjectPtr*>(
258
259 // A stack map is present in the code object, use the stack map to
260 // visit frame slots which are marked as having objects.
261 //
262 // The layout of the frame is (lower addresses to the right):
263 // | spill slots | outgoing arguments | saved registers | slow-path args |
264 // |XXXXXXXXXXXXX|--------------------|XXXXXXXXXXXXXXXXX|XXXXXXXXXXXXXXXX|
265 //
266 // The spill slots and any saved registers are described in the stack
267 // map. The outgoing arguments are assumed to be tagged; the number
268 // of outgoing arguments is not explicitly tracked.
269
270 // Spill slots are at the 'bottom' of the frame.
271 intptr_t spill_slot_count = it.SpillSlotBitCount();
272 for (intptr_t bit = 0; bit < spill_slot_count; ++bit) {
273 if (it.IsObject(bit)) {
274 visitor->VisitPointer(last);
275 }
276 --last;
277 }
278
279 // The live registers at the 'top' of the frame comprise the rest of the
280 // stack map.
281 for (intptr_t bit = it.Length() - 1; bit >= spill_slot_count; --bit) {
282 if (it.IsObject(bit)) {
283 visitor->VisitPointer(first);
284 }
285 ++first;
286 }
287
288 // The last slot can be one slot (but not more) past the last slot
289 // in the case that all slots were covered by the stack map.
290 ASSERT((last + 1) >= first);
291 visitor->VisitPointers(first, last);
292
293 // Now visit other slots which might be part of the calling convention.
294 first = reinterpret_cast<ObjectPtr*>(
296 last = reinterpret_cast<ObjectPtr*>(
298 visitor->VisitPointers(first, last);
299 return;
300 }
301
302 // If we are missing a stack map for a given PC offset, this must either be
303 // unoptimized code, code with no stack map information at all, or the entry
304 // to an osr function. In each of these cases, all stack slots contain
305 // tagged pointers, so fall through.
306#if defined(DEBUG)
307 if (FLAG_precompiled_mode) {
309 } else {
310 ASSERT(!code.is_optimized() ||
311 (pc_offset == code.EntryPoint() - code.PayloadStart()));
312 }
313#endif // defined(DEBUG)
314 }
315
316 // For normal unoptimized Dart frames and Stub frames each slot
317 // between the first and last included are tagged objects.
318 ObjectPtr* first = reinterpret_cast<ObjectPtr*>(sp());
319 ObjectPtr* last = reinterpret_cast<ObjectPtr*>(
321
322 visitor->VisitPointers(first, last);
323}
324
326 const Code& code = Code::Handle(LookupDartCode());
327 if (!code.IsNull()) {
328 const Object& owner = Object::Handle(code.owner());
329 if (owner.IsFunction()) {
330 return Function::Cast(owner).ptr();
331 }
332 }
333 return Function::null();
334}
335
337// We add a no gc scope to ensure that the code below does not trigger
338// a GC as we are handling raw object references here. It is possible
339// that the code is called while a GC is in progress, that is ok.
340#if !defined(DART_HOST_OS_WINDOWS) && !defined(DART_HOST_OS_FUCHSIA)
341 // On Windows and Fuchsia, the profiler calls this from a separate thread
342 // where Thread::Current() is nullptr, so we cannot create a NoSafepointScope.
343 NoSafepointScope no_safepoint;
344#endif
345 CodePtr code = GetCodeObject();
346 if ((code != Code::null()) && Code::OwnerClassIdOf(code) == kFunctionCid) {
347 return code;
348 }
349 return Code::null();
350}
351
352CodePtr StackFrame::GetCodeObject() const {
353#if defined(DART_PRECOMPILED_RUNTIME)
354 if (FLAG_precompiled_mode) {
355 NoSafepointScope no_safepoint;
356 CodePtr code = ReversePc::Lookup(isolate_group(), pc(),
357 /*is_return_address=*/true);
358 ASSERT(code != Code::null());
359 return code;
360 }
361#endif // defined(DART_PRECOMPILED_RUNTIME)
362
363 ObjectPtr pc_marker = *(reinterpret_cast<ObjectPtr*>(
365 ASSERT((pc_marker == Object::null()) ||
366 (pc_marker->GetClassId() == kCodeCid));
367 return static_cast<CodePtr>(pc_marker);
368}
369
371 uword* handler_pc,
372 bool* needs_stacktrace,
373 bool* has_catch_all,
374 bool* is_optimized) const {
376 Code& code = reused_code_handle.Handle();
378 ExceptionHandlers& handlers = reused_exception_handlers_handle.Handle();
380 PcDescriptors& descriptors = reused_pc_descriptors_handle.Handle();
381 uword start;
382 code = LookupDartCode();
383 if (code.IsNull()) {
384 return false; // Stub frames do not have exception handlers.
385 }
386 start = code.PayloadStart();
387 handlers = code.exception_handlers();
388 descriptors = code.pc_descriptors();
389 *is_optimized = code.is_optimized();
391 ExceptionHandlerInfo* info = cache->Lookup(pc());
392 if (info != nullptr) {
393 *handler_pc = start + info->handler_pc_offset;
394 *needs_stacktrace = (info->needs_stacktrace != 0);
395 *has_catch_all = (info->has_catch_all != 0);
396 return true;
397 }
398
399 intptr_t try_index = -1;
400 if (handlers.num_entries() != 0) {
401 uword pc_offset = pc() - code.PayloadStart();
402 PcDescriptors::Iterator iter(descriptors, UntaggedPcDescriptors::kAnyKind);
403 while (iter.MoveNext()) {
404 const intptr_t current_try_index = iter.TryIndex();
405 if ((iter.PcOffset() == pc_offset) && (current_try_index != -1)) {
406 try_index = current_try_index;
407 break;
408 }
409 }
410 }
411 if (try_index == -1) {
412 if (handlers.has_async_handler()) {
413 *handler_pc = StubCode::AsyncExceptionHandler().EntryPoint();
414 *needs_stacktrace = true;
415 *has_catch_all = true;
416 return true;
417 }
418 return false;
419 }
420 ExceptionHandlerInfo handler_info;
421 handlers.GetHandlerInfo(try_index, &handler_info);
422 *handler_pc = start + handler_info.handler_pc_offset;
423 *needs_stacktrace = (handler_info.needs_stacktrace != 0);
424 *has_catch_all = (handler_info.has_catch_all != 0);
425 cache->Insert(pc(), handler_info);
426 return true;
427}
428
430 const Code& code = Code::Handle(LookupDartCode());
431 if (code.IsNull()) {
432 return TokenPosition::kNoSource; // Stub frames do not have token_pos.
433 }
434 uword pc_offset = pc() - code.PayloadStart();
435 const PcDescriptors& descriptors =
436 PcDescriptors::Handle(code.pc_descriptors());
437 ASSERT(!descriptors.IsNull());
438 PcDescriptors::Iterator iter(descriptors, UntaggedPcDescriptors::kAnyKind);
439 while (iter.MoveNext()) {
440 if (iter.PcOffset() == pc_offset) {
441 return TokenPosition(iter.TokenPos());
442 }
443 }
444 return TokenPosition::kNoSource;
445}
446
448 if (IsEntryFrame() || IsExitFrame() || IsStubFrame()) {
449 return true;
450 }
451 return (LookupDartCode() != Code::null());
452}
453
458 StackFrame* frame = frames.NextFrame();
459 while (frame != nullptr) {
460 OS::PrintErr("%s\n", frame->ToCString());
461 frame = frames.NextFrame();
462 }
463}
464
465void StackFrameIterator::SetupLastExitFrameData() {
466 ASSERT(thread_ != nullptr);
467 uword exit_marker = thread_->top_exit_frame_info();
468 frames_.fp_ = exit_marker;
469 frames_.sp_ = 0;
470 frames_.pc_ = 0;
471 frames_.Unpoison();
472}
473
474void StackFrameIterator::SetupNextExitFrameData() {
475 ASSERT(entry_.fp() != 0);
476 uword exit_address = entry_.fp() + (kExitLinkSlotFromEntryFp * kWordSize);
477 uword exit_marker = *reinterpret_cast<uword*>(exit_address);
478 frames_.fp_ = exit_marker;
479 frames_.sp_ = 0;
480 frames_.pc_ = 0;
481 frames_.Unpoison();
482}
483
485 Thread* thread,
486 CrossThreadPolicy cross_thread_policy)
487 : validate_(validation_policy == ValidationPolicy::kValidateFrames),
488 entry_(thread),
489 exit_(thread),
490 frames_(thread),
491 current_frame_(nullptr),
492 thread_(thread) {
493 ASSERT(cross_thread_policy == kAllowCrossThreadIteration ||
494 thread_ == Thread::Current());
495 SetupLastExitFrameData(); // Setup data for last exit frame.
496}
497
499 ValidationPolicy validation_policy,
500 Thread* thread,
501 CrossThreadPolicy cross_thread_policy)
502 : validate_(validation_policy == ValidationPolicy::kValidateFrames),
503 entry_(thread),
504 exit_(thread),
505 frames_(thread),
506 current_frame_(nullptr),
507 thread_(thread) {
508 ASSERT(cross_thread_policy == kAllowCrossThreadIteration ||
509 thread_ == Thread::Current());
510 frames_.fp_ = last_fp;
511 frames_.sp_ = 0;
512 frames_.pc_ = 0;
513 frames_.Unpoison();
514}
515
517 uword sp,
518 uword pc,
519 ValidationPolicy validation_policy,
520 Thread* thread,
521 CrossThreadPolicy cross_thread_policy)
522 : validate_(validation_policy == ValidationPolicy::kValidateFrames),
523 entry_(thread),
524 exit_(thread),
525 frames_(thread),
526 current_frame_(nullptr),
527 thread_(thread) {
528 ASSERT(cross_thread_policy == kAllowCrossThreadIteration ||
529 thread_ == Thread::Current());
530 frames_.fp_ = fp;
531 frames_.sp_ = sp;
532 frames_.pc_ = pc;
533 frames_.Unpoison();
534}
535
537 : validate_(orig.validate_),
538 entry_(orig.thread_),
539 exit_(orig.thread_),
540 frames_(orig.thread_),
541 current_frame_(nullptr),
542 thread_(orig.thread_) {
543 frames_.fp_ = orig.frames_.fp_;
544 frames_.sp_ = orig.frames_.sp_;
545 frames_.pc_ = orig.frames_.pc_;
546 frames_.Unpoison();
547}
548
550 // When we are at the start of iteration after having created an
551 // iterator object, current_frame_ will be nullptr as we haven't seen
552 // any frames yet (unless we start iterating in the simulator from a given
553 // triplet of fp, sp, and pc). At this point, if NextFrame is called, it tries
554 // to set up the next exit frame by reading the top_exit_frame_info
555 // from the isolate. If we do not have any dart invocations yet,
556 // top_exit_frame_info will be 0 and so we would return nullptr.
557
558 // current_frame_ will also be nullptr, when we are at the end of having
559 // iterated through all the frames. If NextFrame is called at this
560 // point, we will try and set up the next exit frame, but since we are
561 // at the end of the iteration, fp_ will be 0 and we would return nullptr.
562 if (current_frame_ == nullptr) {
563 if (!HasNextFrame()) {
564 return nullptr;
565 }
566 if (frames_.pc_ == 0) {
567 // Iteration starts from an exit frame given by its fp.
568 current_frame_ = NextExitFrame();
569 } else if (*(reinterpret_cast<uword*>(
570 frames_.fp_ + (kSavedCallerFpSlotFromFp * kWordSize))) ==
571 0) {
572 // Iteration starts from an entry frame given by its fp, sp, and pc.
573 current_frame_ = NextEntryFrame();
574 } else {
575 // Iteration starts from a Dart or stub frame given by its fp, sp, and pc.
576 current_frame_ = frames_.NextFrame(validate_);
577 }
578 return current_frame_;
579 }
580 ASSERT(!validate_ || current_frame_->IsValid());
581 if (current_frame_->IsEntryFrame()) {
582 if (HasNextFrame()) { // We have another chained block.
583 current_frame_ = NextExitFrame();
584 return current_frame_;
585 }
586 current_frame_ = nullptr; // No more frames.
587 return current_frame_;
588 }
589 ASSERT(!validate_ || current_frame_->IsExitFrame() ||
590 current_frame_->IsDartFrame(validate_) ||
591 current_frame_->IsStubFrame());
592
593 // Consume dart/stub frames using StackFrameIterator::FrameSetIterator
594 // until we are out of dart/stub frames at which point we return the
595 // corresponding entry frame for that set of dart/stub frames.
596 current_frame_ =
597 (frames_.HasNext()) ? frames_.NextFrame(validate_) : NextEntryFrame();
598 return current_frame_;
599}
600
601// Tell MemorySanitizer that generated code initializes part of the stack.
602void StackFrameIterator::FrameSetIterator::Unpoison() {
603 // When using a simulator, all writes to the stack happened from MSAN
604 // instrumented C++, so there is nothing to unpoison. Additionally,
605 // fp_ will be somewhere in the simulator's stack instead of the OSThread's
606 // stack.
607#if !defined(USING_SIMULATOR)
608 if (fp_ == 0) return;
609 // Note that Thread::os_thread_ is cleared when the thread is descheduled.
610 ASSERT((thread_->os_thread() == nullptr) ||
611 ((thread_->os_thread()->stack_limit() < fp_) &&
612 (thread_->os_thread()->stack_base() > fp_)));
613 uword lower;
614 if (sp_ == 0) {
615 // Exit frame: guess sp.
616 lower = fp_ - kDartFrameFixedSize * kWordSize;
617 } else {
618 lower = sp_;
619 }
621 // Both lower and upper are inclusive, so we add one word when computing size.
622 MSAN_UNPOISON(reinterpret_cast<void*>(lower), upper - lower + kWordSize);
623#endif // !defined(USING_SIMULATOR)
624}
625
626StackFrame* StackFrameIterator::FrameSetIterator::NextFrame(bool validate) {
627 StackFrame* frame;
628 ASSERT(HasNext());
629 frame = &stack_frame_;
630 frame->sp_ = sp_;
631 frame->fp_ = fp_;
632 frame->pc_ = pc_;
633 sp_ = frame->GetCallerSp();
634 fp_ = frame->GetCallerFp();
635 pc_ = frame->GetCallerPc();
636 Unpoison();
637 ASSERT(!validate || frame->IsValid());
638 return frame;
639}
640
641ExitFrame* StackFrameIterator::NextExitFrame() {
642 exit_.sp_ = frames_.sp_;
643 exit_.fp_ = frames_.fp_;
644 exit_.pc_ = frames_.pc_;
645 frames_.sp_ = exit_.GetCallerSp();
646 frames_.fp_ = exit_.GetCallerFp();
647 frames_.pc_ = exit_.GetCallerPc();
648 frames_.Unpoison();
649 ASSERT(!validate_ || exit_.IsValid());
650 return &exit_;
651}
652
653EntryFrame* StackFrameIterator::NextEntryFrame() {
654 ASSERT(!frames_.HasNext());
655 entry_.sp_ = frames_.sp_;
656 entry_.fp_ = frames_.fp_;
657 entry_.pc_ = frames_.pc_;
658 SetupNextExitFrameData(); // Setup data for next exit frame in chain.
659 ASSERT(!validate_ || entry_.IsValid());
660 return &entry_;
661}
662
664 : index_(0),
665 num_materializations_(0),
666 dest_frame_size_(0),
667 code_(Code::Handle(code.ptr())),
668 deopt_info_(TypedData::Handle()),
669 function_(Function::Handle()),
670 pc_(pc),
671 deopt_instructions_(),
672 object_table_(ObjectPool::Handle()) {
673 ASSERT(code_.is_optimized());
674 ASSERT(pc_ != 0);
675 ASSERT(code.ContainsInstructionAt(pc));
676#if defined(DART_PRECOMPILED_RUNTIME)
677 ASSERT(deopt_info_.IsNull());
678 function_ = code_.function();
679#else
680 ICData::DeoptReasonId deopt_reason = ICData::kDeoptUnknown;
681 uint32_t deopt_flags = 0;
682 deopt_info_ = code_.GetDeoptInfoAtPc(pc, &deopt_reason, &deopt_flags);
683 if (deopt_info_.IsNull()) {
684 // This is the case when a call without deopt info in optimized code
685 // throws an exception. (e.g. in the parameter copying prologue).
686 // In that case there won't be any inlined frames.
687 function_ = code_.function();
688 } else {
689 // Unpack deopt info into instructions (translate away suffixes).
690 const Array& deopt_table = Array::Handle(code_.deopt_info_array());
691 ASSERT(!deopt_table.IsNull());
692 DeoptInfo::Unpack(deopt_table, deopt_info_, &deopt_instructions_);
693 num_materializations_ = DeoptInfo::NumMaterializations(deopt_instructions_);
694 dest_frame_size_ = DeoptInfo::FrameSize(deopt_info_);
695 object_table_ = code_.GetObjectPool();
696 Advance();
697 }
698#endif // defined(DART_PRECOMPILED_RUNTIME)
699}
700
702 // Iterate over the deopt instructions and determine the inlined
703 // functions if any and iterate over them.
704 ASSERT(!Done());
705
706#if defined(DART_PRECOMPILED_RUNTIME)
707 ASSERT(deopt_info_.IsNull());
708 SetDone();
709 return;
710#else
711 if (deopt_info_.IsNull()) {
712 SetDone();
713 return;
714 }
715
716 ASSERT(deopt_instructions_.length() != 0);
717 while (index_ < deopt_instructions_.length()) {
718 DeoptInstr* deopt_instr = deopt_instructions_[index_++];
719 if (deopt_instr->kind() == DeoptInstr::kRetAddress) {
720 pc_ = DeoptInstr::GetRetAddress(deopt_instr, object_table_, &code_);
721 function_ = code_.function();
722 return;
723 }
724 }
725 SetDone();
726#endif // defined(DART_PRECOMPILED_RUNTIME)
727}
728
729#if !defined(DART_PRECOMPILED_RUNTIME)
730// Finds the potential offset for the current function's FP if the
731// current frame were to be deoptimized.
733 ASSERT(deopt_instructions_.length() != 0);
734 for (intptr_t index = index_; index < deopt_instructions_.length(); index++) {
735 DeoptInstr* deopt_instr = deopt_instructions_[index];
736 if (deopt_instr->kind() == DeoptInstr::kCallerFp) {
737 return index - num_materializations_ - kSavedCallerFpSlotFromFp;
738 }
739 }
740 UNREACHABLE();
741 return 0;
742}
743#endif // !defined(DART_PRECOMPILED_RUNTIME)
744
745#if defined(DEBUG)
746void ValidateFrames() {
750 StackFrame* frame = frames.NextFrame();
751 while (frame != nullptr) {
752 frame = frames.NextFrame();
753 }
754}
755#endif
756
757} // namespace dart
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
#define UNREACHABLE()
Definition assert.h:248
FunctionPtr function() const
Definition object.h:7101
ArrayPtr deopt_info_array() const
Definition object.h:6916
bool is_optimized() const
Definition object.h:6790
ObjectPoolPtr GetObjectPool() const
Definition object.cc:17773
static classid_t OwnerClassIdOf(CodePtr raw)
Definition object.h:7112
TypedDataPtr GetDeoptInfoAtPc(uword pc, ICData::DeoptReasonId *deopt_reason, uint32_t *deopt_flags) const
Definition object.cc:17790
bool Find(uint32_t pc_offset)
Definition object.h:6430
bool IsObject(intptr_t bit_index) const
Definition object.h:6461
intptr_t SpillSlotBitCount() const
Definition object.h:6455
static intptr_t NumMaterializations(const GrowableArray< DeoptInstr * > &)
static void Unpack(const Array &table, const TypedData &packed, GrowableArray< DeoptInstr * > *instructions)
static intptr_t FrameSize(const TypedData &packed)
virtual DeoptInstr::Kind kind() const =0
static uword GetRetAddress(DeoptInstr *instr, const ObjectPool &object_pool, Code *code)
virtual void VisitObjectPointers(ObjectPointerVisitor *visitor)
bool IsValid() const
void GetHandlerInfo(intptr_t try_index, ExceptionHandlerInfo *info) const
Definition object.cc:16236
bool has_async_handler() const
Definition object.cc:16204
intptr_t num_entries() const
Definition object.cc:16200
bool IsValid() const
virtual void VisitObjectPointers(ObjectPointerVisitor *visitor)
intptr_t GetDeoptFpOffset() const
InlinedFunctionsIterator(const Code &code, uword pc)
ObjectStore * object_store() const
Definition isolate.h:505
HandlerInfoCache * handler_info_cache()
Definition isolate.h:1403
VariableIndex index() const
Definition scopes.h:202
bool is_captured() const
Definition scopes.h:143
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
virtual void VisitPointers(ObjectPtr *first, ObjectPtr *last)=0
void VisitPointer(ObjectPtr *p)
Definition visitor.h:55
intptr_t GetClassId() const
Definition raw_object.h:864
@ kInternalName
Definition object.h:622
static ObjectPtr null()
Definition object.h:433
bool IsNull() const
Definition object.h:363
static Object & Handle()
Definition object.h:407
TokenPosition TokenPos() const
Definition object.h:6129
intptr_t TryIndex() const
Definition object.h:6132
static CodePtr Lookup(IsolateGroup *group, uword pc, bool is_return_address)
static const UntaggedCompressedStackMaps::Payload * FindStackMap(IsolateGroup *group, uword pc, bool is_return_address, uword *code_start, const UntaggedCompressedStackMaps::Payload **global_table)
StackFrameIterator(ValidationPolicy validation_policy, Thread *thread, CrossThreadPolicy cross_thread_policy)
uword pc() const
Definition stack_frame.h:43
virtual bool IsEntryFrame() const
virtual void VisitObjectPointers(ObjectPointerVisitor *visitor)
virtual bool IsExitFrame() const
const char * ToCString() const
CodePtr LookupDartCode() const
virtual bool IsStubFrame() const
bool IsBareInstructionsStubFrame() const
bool FindExceptionHandler(Thread *thread, uword *handler_pc, bool *needs_stacktrace, bool *is_catch_all, bool *is_optimized) const
TokenPosition GetTokenPos() const
uword fp() const
Definition stack_frame.h:42
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
uword GetCallerSp() const
static void DumpCurrentTrace()
IsolateGroup * isolate_group() const
virtual bool IsValid() const
Zone * zone() const
static Thread * Current()
Definition thread.h:361
uword top_exit_frame_info() const
Definition thread.h:678
Isolate * isolate() const
Definition thread.h:533
int value() const
Definition scopes.h:69
char * PrintToString(const char *format,...) PRINTF_ATTRIBUTE(2
Definition zone.cc:313
#define ASSERT(E)
double frame
Definition examples.cpp:31
uint32_t * target
#define MSAN_UNPOISON(ptr, len)
static constexpr int kExitLinkSlotFromEntryFp
const char *const name
static constexpr int kSavedCallerPcSlotFromFp
static constexpr int kLastParamSlotFromEntrySp
static constexpr int kFirstObjectSlotFromFp
static constexpr int kDartFrameFixedSize
static constexpr int kSavedCallerFpSlotFromFp
const FrameLayout default_frame_layout
@ kNullCid
Definition class_id.h:252
uintptr_t uword
Definition globals.h:501
static constexpr int kParamEndSlotFromFp
const uint32_t fp
const intptr_t cid
ValidationPolicy
Definition thread.h:271
FrameLayout runtime_frame_layout
const FrameLayout invalid_frame_layout
static constexpr int kPcMarkerSlotFromFp
static constexpr int kFirstLocalSlotFromFp
constexpr intptr_t kWordSize
Definition globals.h:509
static constexpr int kSavedCallerPpSlotFromFp
static constexpr int kLastFixedObjectSlotFromFp
const FrameLayout bare_instructions_frame_layout
#define Pp
Definition globals.h:425
#define REUSABLE_PC_DESCRIPTORS_HANDLESCOPE(thread)
#define REUSABLE_EXCEPTION_HANDLERS_HANDLESCOPE(thread)
#define REUSABLE_CODE_HANDLESCOPE(thread)
static void Init()
intptr_t last_fixed_object_from_fp
intptr_t param_end_from_fp
intptr_t code_from_fp
intptr_t first_local_from_fp
intptr_t FrameSlotForVariableIndex(intptr_t index) const
intptr_t FrameSlotForVariable(const LocalVariable *variable) const
intptr_t first_object_from_fp