Flutter Engine
The Flutter Engine
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 {
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.
102
103 if (FLAG_precompiled_mode) {
105 }
106#if defined(DART_PRECOMPILED_RUNTIME)
107 if (FLAG_precompiled_mode) {
110 }
111#endif
112}
113
115 if (!FLAG_precompiled_mode) {
116 return false;
117 }
118 NoSafepointScope no_safepoint;
119
120 Code code;
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;
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();
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"
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
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;
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
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.
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:7130
ArrayPtr deopt_info_array() const
Definition: object.h:6943
bool is_optimized() const
Definition: object.h:6817
ObjectPoolPtr GetObjectPool() const
Definition: object.cc:17723
static classid_t OwnerClassIdOf(CodePtr raw)
Definition: object.h:7141
TypedDataPtr GetDeoptInfoAtPc(uword pc, ICData::DeoptReasonId *deopt_reason, uint32_t *deopt_flags) const
Definition: object.cc:17740
bool Find(uint32_t pc_offset)
Definition: object.h:6457
bool IsObject(intptr_t bit_index) const
Definition: object.h:6488
intptr_t SpillSlotBitCount() const
Definition: object.h:6482
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)
Definition: stack_frame.cc:196
bool IsValid() const
Definition: stack_frame.h:195
void GetHandlerInfo(intptr_t try_index, ExceptionHandlerInfo *info) const
Definition: object.cc:16189
bool has_async_handler() const
Definition: object.cc:16157
intptr_t num_entries() const
Definition: object.cc:16153
bool IsValid() const
Definition: stack_frame.h:173
virtual void VisitObjectPointers(ObjectPointerVisitor *visitor)
Definition: stack_frame.cc:181
intptr_t GetDeoptFpOffset() const
Definition: stack_frame.cc:732
InlinedFunctionsIterator(const Code &code, uword pc)
Definition: stack_frame.cc:663
ObjectStore * object_store() const
Definition: isolate.h:510
HandlerInfoCache * handler_info_cache()
Definition: isolate.h:1450
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:885
@ 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:6156
intptr_t TryIndex() const
Definition: object.h:6159
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)
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
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
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
TokenPosition GetTokenPos() const
Definition: stack_frame.cc:429
uword fp() const
Definition: stack_frame.h:42
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
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
virtual bool IsValid() const
Definition: stack_frame.cc:447
Zone * zone() const
Definition: thread_state.h:37
static Thread * Current()
Definition: thread.h:362
uword top_exit_frame_info() const
Definition: thread.h:691
Isolate * isolate() const
Definition: thread.h:534
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
if(end==-1)
uint32_t * target
#define MSAN_UNPOISON(ptr, len)
FrameLayout frame_layout
Definition: stack_frame.cc:76
Definition: dart_vm.cc:33
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
Definition: stack_frame.cc:43
@ 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
Definition: stack_frame.cc:81
const FrameLayout invalid_frame_layout
Definition: stack_frame.cc:29
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
Definition: stack_frame.cc:56
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
Definition: switches.h:191
#define Pp
Definition: globals.h:425
#define REUSABLE_PC_DESCRIPTORS_HANDLESCOPE(thread)
#define REUSABLE_EXCEPTION_HANDLERS_HANDLESCOPE(thread)
#define REUSABLE_CODE_HANDLESCOPE(thread)
intptr_t last_fixed_object_from_fp
Definition: frame_layout.h:27
intptr_t param_end_from_fp
Definition: frame_layout.h:30
intptr_t code_from_fp
Definition: frame_layout.h:52
intptr_t first_local_from_fp
Definition: frame_layout.h:37
intptr_t FrameSlotForVariable(const LocalVariable *variable) const
Definition: stack_frame.cc:83
intptr_t first_object_from_fp
Definition: frame_layout.h:24
static void Init()
Definition: stack_frame.cc:98
intptr_t FrameSlotForVariableIndex(intptr_t index) const
Definition: stack_frame.cc:89