Flutter Engine
The Flutter Engine
deopt_instructions.cc
Go to the documentation of this file.
1// Copyright (c) 2013, 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#if !defined(DART_PRECOMPILED_RUNTIME)
6
8
9#include "vm/code_patcher.h"
15#include "vm/parser.h"
16#include "vm/stack_frame.h"
17#include "vm/thread.h"
18#include "vm/timeline.h"
19
20namespace dart {
21
23 compress_deopt_info,
24 true,
25 "Compress the size of the deoptimization info for optimized code.");
26DECLARE_FLAG(bool, trace_deoptimization);
27DECLARE_FLAG(bool, trace_deoptimization_verbose);
28
30 const Code& code,
31 DestFrameOptions dest_options,
32 fpu_register_t* fpu_registers,
33 intptr_t* cpu_registers,
34 bool is_lazy_deopt,
35 bool deoptimizing_code)
36 : code_(code.ptr()),
37 object_pool_(code.GetObjectPool()),
38 deopt_info_(TypedData::null()),
39 dest_frame_is_allocated_(false),
40 dest_frame_(nullptr),
41 dest_frame_size_(0),
42 source_frame_is_allocated_(false),
43 source_frame_(nullptr),
44 source_frame_size_(0),
45 cpu_registers_(cpu_registers),
46 fpu_registers_(fpu_registers),
47 num_args_(0),
48 deopt_reason_(ICData::kDeoptUnknown),
49 deopt_flags_(0),
50 thread_(Thread::Current()),
51 deopt_start_micros_(0),
52 deferred_slots_(nullptr),
53 deferred_objects_count_(0),
54 deferred_objects_(nullptr),
55 is_lazy_deopt_(is_lazy_deopt),
56 deoptimizing_code_(deoptimizing_code) {
58 code.GetDeoptInfoAtPc(frame->pc(), &deopt_reason_, &deopt_flags_));
59#if defined(DEBUG)
60 if (deopt_info.IsNull()) {
61 OS::PrintErr("Missing deopt info for pc %" Px "\n", frame->pc());
62 DisassembleToStdout formatter;
63 code.Disassemble(&formatter);
64 }
65#endif
66 ASSERT(!deopt_info.IsNull());
67 deopt_info_ = deopt_info.ptr();
68
69 const Function& function = Function::Handle(code.function());
70
71 // Do not include incoming arguments if there are optional arguments
72 // (they are copied into local space at method entry).
73 num_args_ =
74 function.MakesCopyOfParameters() ? 0 : function.num_fixed_parameters();
75
76 // The fixed size section of the (fake) Dart frame called via a stub by the
77 // optimized function contains FP, PP (ARM only), PC-marker and
78 // return-address. This section is copied as well, so that its contained
79 // values can be updated before returning to the deoptimized function.
80 ASSERT(frame->fp() >= frame->sp());
81 const intptr_t frame_size = (frame->fp() - frame->sp()) / kWordSize;
82
83 source_frame_size_ = +kDartFrameFixedSize // For saved values below sp.
84 + frame_size // For frame size incl. sp.
85 + 1 // For fp.
86 + kParamEndSlotFromFp // For saved values above fp.
87 + num_args_; // For arguments.
88
89 source_frame_ = FrameBase(frame);
90
91 if (dest_options == kDestIsOriginalFrame) {
92 // Work from a copy of the source frame.
93 intptr_t* original_frame = source_frame_;
94 source_frame_ = new intptr_t[source_frame_size_];
95 ASSERT(source_frame_ != nullptr);
96 for (intptr_t i = 0; i < source_frame_size_; i++) {
97 source_frame_[i] = original_frame[i];
98 }
99 source_frame_is_allocated_ = true;
100 }
101 caller_fp_ = GetSourceFp();
102
103 dest_frame_size_ = DeoptInfo::FrameSize(deopt_info);
104
105 if (dest_options == kDestIsAllocated) {
106 dest_frame_ = new intptr_t[dest_frame_size_];
107 ASSERT(source_frame_ != nullptr);
108 for (intptr_t i = 0; i < dest_frame_size_; i++) {
109 dest_frame_[i] = 0;
110 }
111 dest_frame_is_allocated_ = true;
112 }
113
114 if (dest_options != kDestIsAllocated) {
115 // kDestIsAllocated is used by the debugger to generate a stack trace
116 // and does not signal a real deopt.
117 deopt_start_micros_ = OS::GetCurrentMonotonicMicros();
118 }
119
120 if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
121 THR_Print(
122 "Deoptimizing (reason %d '%s') at "
123 "pc=%" Pp " fp=%" Pp " '%s' (count %d)\n",
125 frame->fp(), function.ToFullyQualifiedCString(),
126 function.deoptimization_counter());
127 }
128}
129
131 // Delete memory for source frame and registers.
132 if (source_frame_is_allocated_) {
133 delete[] source_frame_;
134 }
135 source_frame_ = nullptr;
136 delete[] fpu_registers_;
137 delete[] cpu_registers_;
138 fpu_registers_ = nullptr;
139 cpu_registers_ = nullptr;
140 if (dest_frame_is_allocated_) {
141 delete[] dest_frame_;
142 }
143 dest_frame_ = nullptr;
144
145 // Delete all deferred objects.
146 for (intptr_t i = 0; i < deferred_objects_count_; i++) {
147 delete deferred_objects_[i];
148 }
149 delete[] deferred_objects_;
150 deferred_objects_ = nullptr;
151 deferred_objects_count_ = 0;
152
153#if defined(SUPPORT_TIMELINE)
154 if (deopt_start_micros_ != 0) {
155 TimelineStream* compiler_stream = Timeline::GetCompilerStream();
156 ASSERT(compiler_stream != nullptr);
157 if (compiler_stream->enabled()) {
158 // Allocate all Dart objects needed before calling StartEvent,
159 // which blocks safe points until Complete is called.
160 const Code& code = Code::Handle(zone(), code_);
161 const Function& function = Function::Handle(zone(), code.function());
162 const String& function_name =
163 String::Handle(zone(), function.QualifiedScrubbedName());
164 const char* reason = DeoptReasonToCString(deopt_reason());
165 const int counter = function.deoptimization_counter();
166 TimelineEvent* timeline_event = compiler_stream->StartEvent();
167 if (timeline_event != nullptr) {
168 timeline_event->Duration("Deoptimize", deopt_start_micros_,
170 timeline_event->SetNumArguments(3);
171 timeline_event->CopyArgument(0, "function", function_name.ToCString());
172 timeline_event->CopyArgument(1, "reason", reason);
173 timeline_event->FormatArgument(2, "deoptimizationCount", "%d", counter);
174 timeline_event->Complete();
175 }
176 }
177 }
178#endif // !PRODUCT
179}
180
182 visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&code_));
183 visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&object_pool_));
184 visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&deopt_info_));
185
186 // Visit any object pointers on the destination stack.
187 if (dest_frame_is_allocated_) {
188 for (intptr_t i = 0; i < dest_frame_size_; i++) {
189 if (dest_frame_[i] != 0) {
190 visitor->VisitPointer(reinterpret_cast<ObjectPtr*>(&dest_frame_[i]));
191 }
192 }
193 }
194}
195
197 return dest_frame_size_ - kDartFrameFixedSize - num_args_ - 1 // For fp.
199}
200
202 return source_frame_[source_frame_size_ - 1 - num_args_ -
204}
205
207 return source_frame_[source_frame_size_ - 1 - num_args_ -
210}
211
213 return source_frame_[source_frame_size_ - num_args_ + kSavedPcSlotFromSp];
214}
215
217 return caller_fp_;
218}
219
220void DeoptContext::SetCallerFp(intptr_t caller_fp) {
221 caller_fp_ = caller_fp;
222}
223
225 switch (kind) {
227 case DeoptInstr::kPp:
240 return true;
241
246 return false;
247
249 default:
250 // We should not encounter these instructions when filling stack slots.
251 UNREACHABLE();
252 return false;
253 }
254 UNREACHABLE();
255 return false;
256}
257
259 const Code& code = Code::Handle(code_);
260 const TypedData& deopt_info = TypedData::Handle(deopt_info_);
261
262 GrowableArray<DeoptInstr*> deopt_instructions;
263 const Array& deopt_table = Array::Handle(code.deopt_info_array());
264 ASSERT(!deopt_table.IsNull());
265 DeoptInfo::Unpack(deopt_table, deopt_info, &deopt_instructions);
266
267 const intptr_t len = deopt_instructions.length();
268 const intptr_t frame_size = dest_frame_size_;
269
270 // For now, we never place non-objects in the deoptimized frame if
271 // the destination frame is a copy. This allows us to copy the
272 // deoptimized frame into an Array.
273 const bool objects_only = dest_frame_is_allocated_;
274
275 // All kMaterializeObject instructions are emitted before the instructions
276 // that describe stack frames. Skip them and defer materialization of
277 // objects until the frame is fully reconstructed and it is safe to perform
278 // GC.
279 // Arguments (class of the instance to allocate and field-value pairs) are
280 // described as part of the expression stack for the bottom-most deoptimized
281 // frame. They will be used during materialization and removed from the stack
282 // right before control switches to the unoptimized code.
283 const intptr_t num_materializations =
284 DeoptInfo::NumMaterializations(deopt_instructions);
285 PrepareForDeferredMaterialization(num_materializations);
286 for (intptr_t from_index = 0, to_index = kDartFrameFixedSize;
287 from_index < num_materializations; from_index++) {
288 const intptr_t field_count =
289 DeoptInstr::GetFieldCount(deopt_instructions[from_index]);
290 intptr_t* args = GetDestFrameAddressAt(to_index);
291 DeferredObject* obj = new DeferredObject(field_count, args);
292 SetDeferredObjectAt(from_index, obj);
293 to_index += obj->ArgumentCount();
294 }
295
296 // Populate stack frames.
297 for (intptr_t to_index = frame_size - 1, from_index = len - 1; to_index >= 0;
298 to_index--, from_index--) {
299 intptr_t* to_addr = GetDestFrameAddressAt(to_index);
300 DeoptInstr* instr = deopt_instructions[from_index];
301 if (!objects_only || IsObjectInstruction(instr->kind())) {
302 instr->Execute(this, to_addr);
303 } else {
304 *reinterpret_cast<ObjectPtr*>(to_addr) = Object::null();
305 }
306 }
307
308 if (FLAG_trace_deoptimization_verbose) {
309 for (intptr_t i = 0; i < frame_size; i++) {
310 intptr_t* to_addr = GetDestFrameAddressAt(i);
311 THR_Print("*%" Pd ". [%p] 0x%" Px " [%s]\n", i, to_addr, *to_addr,
312 deopt_instructions[i + (len - frame_size)]->ToCString());
313 }
314 }
315}
316
318 const Code& code = Code::Handle(code_);
319 const TypedData& deopt_info = TypedData::Handle(deopt_info_);
320 GrowableArray<DeoptInstr*> deopt_instructions;
321 const Array& deopt_table = Array::Handle(code.deopt_info_array());
322 ASSERT(!deopt_table.IsNull());
323 DeoptInfo::Unpack(deopt_table, deopt_info, &deopt_instructions);
324
326
327 Function& function = Function::Handle(zone(), code.function());
328 intptr_t params =
329 function.MakesCopyOfParameters() ? 0 : function.num_fixed_parameters();
330 for (intptr_t i = 0; i < num_vars; i++) {
331 const intptr_t len = deopt_instructions.length();
332 intptr_t slot = i < params ? i
335 DeoptInstr* instr = deopt_instructions[len - 1 - slot];
336 intptr_t dest_index = i - params;
337 moves->At(i) = instr->ToCatchEntryMove(this, dest_index);
338 }
339
340 return moves;
341}
342
343static void FillDeferredSlots(DeoptContext* deopt_context,
344 DeferredSlot** slot_list) {
345 DeferredSlot* slot = *slot_list;
346 *slot_list = nullptr;
347
348 while (slot != nullptr) {
349 DeferredSlot* current = slot;
350 slot = slot->next();
351
352 current->Materialize(deopt_context);
353
354 delete current;
355 }
356}
357
358// Materializes all deferred objects. Returns the total number of
359// artificial arguments used during deoptimization.
361 // Populate slots with references to all unboxed "primitive" values (doubles,
362 // mints, simd) and deferred objects. Deferred objects are only allocated
363 // but not filled with data. This is done later because deferred objects
364 // can references each other.
365 FillDeferredSlots(this, &deferred_slots_);
366
367 // Compute total number of artificial arguments used during deoptimization.
368 intptr_t deopt_arg_count = 0;
369 for (intptr_t i = 0; i < DeferredObjectsCount(); i++) {
371 deopt_arg_count += GetDeferredObject(i)->ArgumentCount();
372 }
373
374 // Since this is the only step where GC can occur during deoptimization,
375 // use it to report the source line where deoptimization occurred.
376 if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
379 StackFrame* top_frame = iterator.NextFrame();
380 ASSERT(top_frame != nullptr);
381 const Code& code = Code::Handle(top_frame->LookupDartCode());
382 const Function& top_function = Function::Handle(code.function());
383 const Script& script = Script::Handle(top_function.script());
384 const TokenPosition token_pos = code.GetTokenIndexOfPC(top_frame->pc());
385 THR_Print(" Function: %s\n", top_function.ToFullyQualifiedCString());
386 intptr_t line;
387 if (script.GetTokenLocation(token_pos, &line)) {
388 String& line_string = String::Handle(script.GetLine(line));
389 char line_buffer[80];
390 Utils::SNPrint(line_buffer, sizeof(line_buffer), " Line %" Pd ": '%s'",
391 line, line_string.ToCString());
392 THR_Print("%s\n", line_buffer);
393 }
394 THR_Print(" Deopt args: %" Pd "\n", deopt_arg_count);
395 }
396
397 return deopt_arg_count;
398}
399
401 ASSERT(dest_frame_ != nullptr && dest_frame_is_allocated_);
402 const Array& dest_array = Array::Handle(zone(), Array::New(dest_frame_size_));
404 for (intptr_t i = 0; i < dest_frame_size_; i++) {
405 obj = static_cast<ObjectPtr>(dest_frame_[i]);
406 dest_array.SetAt(i, obj);
407 }
408 return dest_array.ptr();
409}
410
411// Deoptimization instruction creating return address using function and
412// deopt-id stored at 'object_table_index'.
414 public:
416 : object_table_index_(object_table_index), deopt_id_(deopt_id) {
418 ASSERT(deopt_id >= 0);
419 }
420
422 : object_table_index_(ObjectTableIndex::decode(source_index)),
423 deopt_id_(DeoptId::decode(source_index)) {}
424
425 virtual intptr_t source_index() const {
426 return ObjectTableIndex::encode(object_table_index_) |
427 DeoptId::encode(deopt_id_);
428 }
429
430 virtual DeoptInstr::Kind kind() const { return kRetAddress; }
431
432 virtual const char* ArgumentsToCString() const {
434 "%" Pd ", %" Pd "", object_table_index_, deopt_id_);
435 }
436
437 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
438 *dest_addr = Smi::RawValue(0);
439 deopt_context->DeferRetAddrMaterialization(object_table_index_, deopt_id_,
440 dest_addr);
441 }
442
443 intptr_t object_table_index() const { return object_table_index_; }
444 intptr_t deopt_id() const { return deopt_id_; }
445
446 private:
447 static constexpr intptr_t kFieldWidth = kBitsPerWord / 2;
448 class ObjectTableIndex : public BitField<intptr_t, intptr_t, 0, kFieldWidth> {
449 };
450 class DeoptId
451 : public BitField<intptr_t, intptr_t, kFieldWidth, kFieldWidth> {};
452
453 const intptr_t object_table_index_;
454 const intptr_t deopt_id_;
455
456 DISALLOW_COPY_AND_ASSIGN(DeoptRetAddressInstr);
457};
458
459// Deoptimization instruction moving a constant stored at 'object_table_index'.
461 public:
462 explicit DeoptConstantInstr(intptr_t object_table_index)
463 : object_table_index_(object_table_index) {
464 ASSERT(object_table_index >= 0);
465 }
466
467 virtual intptr_t source_index() const { return object_table_index_; }
468 virtual DeoptInstr::Kind kind() const { return kConstant; }
469
470 virtual const char* ArgumentsToCString() const {
471 return Thread::Current()->zone()->PrintToString("%" Pd "",
472 object_table_index_);
473 }
474
475 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
477 deopt_context->zone(), deopt_context->ObjectAt(object_table_index_));
478 *reinterpret_cast<ObjectPtr*>(dest_addr) = obj.ptr();
479 }
480
482 intptr_t dest_slot) {
483 return CatchEntryMove::FromConstant(object_table_index_, dest_slot);
484 }
485
486 private:
487 const intptr_t object_table_index_;
488
489 DISALLOW_COPY_AND_ASSIGN(DeoptConstantInstr);
490};
491
492// Deoptimization instruction moving value from optimized frame at
493// 'source_index' to specified slots in the unoptimized frame.
494// 'source_index' represents the slot index of the frame (0 being
495// first argument) and accounts for saved return address, frame
496// pointer, pool pointer and pc marker.
497// Deoptimization instruction moving a CPU register.
499 public:
500 explicit DeoptWordInstr(intptr_t source_index) : source_(source_index) {}
501
502 explicit DeoptWordInstr(const CpuRegisterSource& source) : source_(source) {}
503
504 virtual intptr_t source_index() const { return source_.source_index(); }
505 virtual DeoptInstr::Kind kind() const { return kWord; }
506
507 virtual const char* ArgumentsToCString() const { return source_.ToCString(); }
508
509 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
510 *dest_addr = source_.Value<intptr_t>(deopt_context);
511 }
512
514 intptr_t dest_slot) {
516 source_.StackSlot(deopt_context),
517 dest_slot);
518 }
519
520 private:
521 const CpuRegisterSource source_;
522
523 DISALLOW_COPY_AND_ASSIGN(DeoptWordInstr);
524};
525
527 public:
529
530 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
531 const int64_t value = GetValue(deopt_context);
532 if (Smi::IsValid(value)) {
533 *dest_addr = Smi::RawValue(static_cast<intptr_t>(value));
534 } else {
535 *dest_addr = Smi::RawValue(0);
536 deopt_context->DeferMintMaterialization(
537 value, reinterpret_cast<MintPtr*>(dest_addr));
538 }
539 }
540
541 virtual int64_t GetValue(DeoptContext* deopt_context) = 0;
542
543 private:
544 DISALLOW_COPY_AND_ASSIGN(DeoptIntegerInstrBase);
545};
546
548 public:
551 lo_(LoRegister::decode(source_index)),
552 hi_(HiRegister::decode(source_index)) {}
553
555 : DeoptIntegerInstrBase(), lo_(lo), hi_(hi) {}
556
557 virtual intptr_t source_index() const {
558 return LoRegister::encode(lo_.source_index()) |
560 }
561 virtual DeoptInstr::Kind kind() const { return kMintPair; }
562
563 virtual const char* ArgumentsToCString() const {
564 return Thread::Current()->zone()->PrintToString("%s,%s", lo_.ToCString(),
565 hi_.ToCString());
566 }
567
568 virtual int64_t GetValue(DeoptContext* deopt_context) {
569 return Utils::LowHighTo64Bits(lo_.Value<uint32_t>(deopt_context),
570 hi_.Value<int32_t>(deopt_context));
571 }
572
574 intptr_t dest_slot) {
578 hi_.StackSlot(deopt_context)),
579 dest_slot);
580 }
581
582 private:
583 static constexpr intptr_t kFieldWidth = kBitsPerWord / 2;
584 class LoRegister : public BitField<intptr_t, intptr_t, 0, kFieldWidth> {};
585 class HiRegister
586 : public BitField<intptr_t, intptr_t, kFieldWidth, kFieldWidth> {};
587
588 const CpuRegisterSource lo_;
589 const CpuRegisterSource hi_;
590
591 DISALLOW_COPY_AND_ASSIGN(DeoptMintPairInstr);
592};
593
594template <DeoptInstr::Kind K, CatchEntryMove::SourceKind slot_kind, typename T>
596 public:
597 explicit DeoptIntInstr(intptr_t source_index)
598 : DeoptIntegerInstrBase(), source_(source_index) {}
599
601 : DeoptIntegerInstrBase(), source_(source) {}
602
603 virtual intptr_t source_index() const { return source_.source_index(); }
604 virtual DeoptInstr::Kind kind() const { return K; }
605
606 virtual const char* ArgumentsToCString() const { return source_.ToCString(); }
607
608 virtual int64_t GetValue(DeoptContext* deopt_context) {
609 return static_cast<int64_t>(source_.Value<T>(deopt_context));
610 }
611
613 intptr_t dest_slot) {
614 return CatchEntryMove::FromSlot(slot_kind, source_.StackSlot(deopt_context),
615 dest_slot);
616 }
617
618 private:
619 const CpuRegisterSource source_;
620
621 DISALLOW_COPY_AND_ASSIGN(DeoptIntInstr);
622};
623
624typedef DeoptIntInstr<DeoptInstr::kUint32,
626 uint32_t>
630 int32_t>
634 int64_t>
636
637template <DeoptInstr::Kind K,
639 typename Type,
640 typename PtrType>
641class DeoptFpuInstr : public DeoptInstr {
642 public:
643 explicit DeoptFpuInstr(intptr_t source_index) : source_(source_index) {}
644
645 explicit DeoptFpuInstr(const FpuRegisterSource& source) : source_(source) {}
646
647 virtual intptr_t source_index() const { return source_.source_index(); }
648 virtual DeoptInstr::Kind kind() const { return K; }
649
650 virtual const char* ArgumentsToCString() const { return source_.ToCString(); }
651
652 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
653 *dest_addr = Smi::RawValue(0);
654 deopt_context->DeferMaterialization(source_.Value<Type>(deopt_context),
655 reinterpret_cast<PtrType*>(dest_addr));
656 }
657
659 intptr_t dest_slot) {
660 return CatchEntryMove::FromSlot(slot_kind, source_.StackSlot(deopt_context),
661 dest_slot);
662 }
663
664 private:
665 const FpuRegisterSource source_;
666
667 DISALLOW_COPY_AND_ASSIGN(DeoptFpuInstr);
668};
669
670typedef DeoptFpuInstr<DeoptInstr::kFloat,
672 float,
673 DoublePtr>
675
678 double,
679 DoublePtr>
681
682// Simd128 types.
686 Float32x4Ptr>
691 Float64x2Ptr>
696 Int32x4Ptr>
698
699// Deoptimization instruction creating a PC marker for the code of
700// function at 'object_table_index'.
702 public:
703 explicit DeoptPcMarkerInstr(intptr_t object_table_index)
704 : object_table_index_(object_table_index) {
705 ASSERT(object_table_index >= 0);
706 }
707
708 virtual intptr_t source_index() const { return object_table_index_; }
709 virtual DeoptInstr::Kind kind() const { return kPcMarker; }
710
711 virtual const char* ArgumentsToCString() const {
712 return Thread::Current()->zone()->PrintToString("%" Pd "",
713 object_table_index_);
714 }
715
716 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
717 Function& function = Function::Handle(deopt_context->zone());
718 function ^= deopt_context->ObjectAt(object_table_index_);
719 if (function.IsNull()) {
720 *reinterpret_cast<ObjectPtr*>(dest_addr) =
721 deopt_context->is_lazy_deopt()
722 ? StubCode::DeoptimizeLazyFromReturn().ptr()
723 : StubCode::Deoptimize().ptr();
724 return;
725 }
726
727 // We don't always have the Code object for the frame's corresponding
728 // unoptimized code as it may have been collected. Use a stub as the pc
729 // marker until we can recreate that Code object during deferred
730 // materialization to maintain the invariant that Dart frames always have
731 // a pc marker.
732 *reinterpret_cast<ObjectPtr*>(dest_addr) =
733 StubCode::FrameAwaitingMaterialization().ptr();
734 deopt_context->DeferPcMarkerMaterialization(object_table_index_, dest_addr);
735 }
736
737 private:
738 intptr_t object_table_index_;
739
740 DISALLOW_COPY_AND_ASSIGN(DeoptPcMarkerInstr);
741};
742
743// Deoptimization instruction creating a pool pointer for the code of
744// function at 'object_table_index'.
745class DeoptPpInstr : public DeoptInstr {
746 public:
747 explicit DeoptPpInstr(intptr_t object_table_index)
748 : object_table_index_(object_table_index) {
749 ASSERT(object_table_index >= 0);
750 }
751
752 virtual intptr_t source_index() const { return object_table_index_; }
753 virtual DeoptInstr::Kind kind() const { return kPp; }
754
755 virtual const char* ArgumentsToCString() const {
756 return Thread::Current()->zone()->PrintToString("%" Pd "",
757 object_table_index_);
758 }
759
760 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
761 *dest_addr = Smi::RawValue(0);
762 deopt_context->DeferPpMaterialization(
763 object_table_index_, reinterpret_cast<ObjectPtr*>(dest_addr));
764 }
765
766 private:
767 intptr_t object_table_index_;
768
769 DISALLOW_COPY_AND_ASSIGN(DeoptPpInstr);
770};
771
772// Deoptimization instruction copying the caller saved FP from optimized frame.
774 public:
776
777 virtual intptr_t source_index() const { return 0; }
778 virtual DeoptInstr::Kind kind() const { return kCallerFp; }
779
780 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
781 *dest_addr = deopt_context->GetCallerFp();
782 deopt_context->SetCallerFp(
783 reinterpret_cast<intptr_t>(dest_addr - kSavedCallerFpSlotFromFp));
784 }
785
786 private:
787 DISALLOW_COPY_AND_ASSIGN(DeoptCallerFpInstr);
788};
789
790// Deoptimization instruction copying the caller saved PP from optimized frame.
792 public:
794
795 virtual intptr_t source_index() const { return 0; }
796 virtual DeoptInstr::Kind kind() const { return kCallerPp; }
797
798 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
799 *dest_addr = deopt_context->GetSourcePp();
800 }
801
802 private:
803 DISALLOW_COPY_AND_ASSIGN(DeoptCallerPpInstr);
804};
805
806// Deoptimization instruction copying the caller return address from optimized
807// frame.
809 public:
811
812 virtual intptr_t source_index() const { return 0; }
813 virtual DeoptInstr::Kind kind() const { return kCallerPc; }
814
815 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
816 *dest_addr = deopt_context->GetSourcePc();
817 }
818
819 private:
820 DISALLOW_COPY_AND_ASSIGN(DeoptCallerPcInstr);
821};
822
823// Write reference to a materialized object with the given index into the
824// stack slot.
826 public:
827 explicit DeoptMaterializedObjectRefInstr(intptr_t index) : index_(index) {
828 ASSERT(index >= 0);
829 }
830
831 virtual intptr_t source_index() const { return index_; }
832 virtual DeoptInstr::Kind kind() const { return kMaterializedObjectRef; }
833
834 virtual const char* ArgumentsToCString() const {
835 return Thread::Current()->zone()->PrintToString("#%" Pd "", index_);
836 }
837
838 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
839 *reinterpret_cast<SmiPtr*>(dest_addr) = Smi::New(0);
840 deopt_context->DeferMaterializedObjectRef(index_, dest_addr);
841 }
842
843 private:
844 intptr_t index_;
845
846 DISALLOW_COPY_AND_ASSIGN(DeoptMaterializedObjectRefInstr);
847};
848
849// Materialize object with the given number of fields.
850// Arguments for materialization (class and field-value pairs) are pushed
851// to the expression stack of the bottom-most frame.
853 public:
854 explicit DeoptMaterializeObjectInstr(intptr_t field_count)
855 : field_count_(field_count) {
856 ASSERT(field_count >= 0);
857 }
858
859 virtual intptr_t source_index() const { return field_count_; }
860 virtual DeoptInstr::Kind kind() const { return kMaterializeObject; }
861
862 virtual const char* ArgumentsToCString() const {
863 return Thread::Current()->zone()->PrintToString("%" Pd "", field_count_);
864 }
865
866 void Execute(DeoptContext* deopt_context, intptr_t* dest_addr) {
867 // This instructions are executed manually by the DeoptimizeWithDeoptInfo.
868 UNREACHABLE();
869 }
870
871 private:
872 intptr_t field_count_;
873
874 DISALLOW_COPY_AND_ASSIGN(DeoptMaterializeObjectInstr);
875};
876
878 const ObjectPool& object_table,
879 Code* code) {
880 ASSERT(instr->kind() == kRetAddress);
881 DeoptRetAddressInstr* ret_address_instr =
882 static_cast<DeoptRetAddressInstr*>(instr);
883 ASSERT(!object_table.IsNull());
884 Thread* thread = Thread::Current();
885 Zone* zone = thread->zone();
887 function ^= object_table.ObjectAt(ret_address_instr->object_table_index());
888 ASSERT(!function.ForceOptimize());
889 ASSERT(code != nullptr);
890 const Error& error =
892 if (!error.IsNull()) {
894 }
895 *code = function.unoptimized_code();
896 ASSERT(!code->IsNull());
897 uword res = code->GetPcForDeoptId(ret_address_instr->deopt_id(),
898 UntaggedPcDescriptors::kDeopt);
899 ASSERT(res != 0);
900 return res;
901}
902
903DeoptInstr* DeoptInstr::Create(intptr_t kind_as_int, intptr_t source_index) {
904 Kind kind = static_cast<Kind>(kind_as_int);
905 switch (kind) {
906 case kWord:
907 return new DeoptWordInstr(source_index);
908 case kFloat:
909 return new DeoptFloatInstr(source_index);
910 case kDouble:
911 return new DeoptDoubleInstr(source_index);
912 case kMint:
913 return new DeoptMintInstr(source_index);
914 case kMintPair:
916 case kInt32:
917 return new DeoptInt32Instr(source_index);
918 case kUint32:
919 return new DeoptUint32Instr(source_index);
920 case kFloat32x4:
922 case kFloat64x2:
924 case kInt32x4:
926 case kRetAddress:
928 case kConstant:
930 case kPcMarker:
932 case kPp:
933 return new DeoptPpInstr(source_index);
934 case kCallerFp:
935 return new DeoptCallerFpInstr();
936 case kCallerPp:
937 return new DeoptCallerPpInstr();
938 case kCallerPc:
939 return new DeoptCallerPcInstr();
944 }
945 UNREACHABLE();
946 return nullptr;
947}
948
949const char* DeoptInstr::KindToCString(Kind kind) {
950 switch (kind) {
951 case kWord:
952 return "word";
953 case kFloat:
954 return "float";
955 case kDouble:
956 return "double";
957 case kMint:
958 case kMintPair:
959 return "mint";
960 case kInt32:
961 return "int32";
962 case kUint32:
963 return "uint32";
964 case kFloat32x4:
965 return "float32x4";
966 case kFloat64x2:
967 return "float64x2";
968 case kInt32x4:
969 return "int32x4";
970 case kRetAddress:
971 return "retaddr";
972 case kConstant:
973 return "const";
974 case kPcMarker:
975 return "pc";
976 case kPp:
977 return "pp";
978 case kCallerFp:
979 return "callerfp";
980 case kCallerPp:
981 return "callerpp";
982 case kCallerPc:
983 return "callerpc";
985 return "ref";
987 return "mat";
988 }
989 UNREACHABLE();
990 return nullptr;
991}
992
994 public:
995 // Construct the root node representing the implicit "shared" terminator
996 // at the end of each deopt info.
997 TrieNode() : instruction_(nullptr), info_number_(-1), children_(16) {}
998
999 // Construct a node representing a written instruction.
1000 TrieNode(DeoptInstr* instruction, intptr_t info_number)
1001 : instruction_(instruction), info_number_(info_number), children_(4) {}
1002
1003 intptr_t info_number() const { return info_number_; }
1004
1005 void AddChild(TrieNode* child) {
1006 if (child != nullptr) children_.Add(child);
1007 }
1008
1009 TrieNode* FindChild(const DeoptInstr& instruction) {
1010 for (intptr_t i = 0; i < children_.length(); ++i) {
1011 TrieNode* child = children_[i];
1012 if (child->instruction_->Equals(instruction)) return child;
1013 }
1014 return nullptr;
1015 }
1016
1017 private:
1018 const DeoptInstr* instruction_; // Instruction that was written.
1019 const intptr_t info_number_; // Index of the deopt info it was written to.
1020
1021 GrowableArray<TrieNode*> children_;
1022};
1023
1025 const intptr_t num_args,
1026 compiler::Assembler* assembler)
1027 : zone_(zone),
1028 instructions_(),
1029 num_args_(num_args),
1030 assembler_(assembler),
1031 trie_root_(new(zone) TrieNode()),
1032 current_info_number_(0),
1033 frame_start_(-1),
1034 materializations_() {}
1035
1036intptr_t DeoptInfoBuilder::FindOrAddObjectInTable(const Object& obj) const {
1037 return assembler_->object_pool_builder().FindObject(obj);
1038}
1039
1040intptr_t DeoptInfoBuilder::CalculateStackIndex(
1041 const Location& source_loc) const {
1043 source_loc.stack_index());
1044 return index < 0 ? index + num_args_
1045 : index + num_args_ + kDartFrameFixedSize;
1046}
1047
1048CpuRegisterSource DeoptInfoBuilder::ToCpuRegisterSource(const Location& loc) {
1049 if (loc.IsRegister()) {
1051 } else {
1052 ASSERT(loc.IsStackSlot());
1054 CalculateStackIndex(loc));
1055 }
1056}
1057
1058FpuRegisterSource DeoptInfoBuilder::ToFpuRegisterSource(
1059 const Location& loc,
1060 Location::Kind stack_slot_kind) {
1061 if (loc.IsFpuRegister()) {
1062 return FpuRegisterSource(FpuRegisterSource::kRegister, loc.fpu_reg());
1063 } else {
1064 ASSERT((stack_slot_kind == Location::kQuadStackSlot) ||
1065 (stack_slot_kind == Location::kDoubleStackSlot));
1066 ASSERT(loc.kind() == stack_slot_kind);
1068 CalculateStackIndex(loc));
1069 }
1070}
1071
1073 intptr_t deopt_id,
1074 intptr_t dest_index) {
1075 const intptr_t object_table_index = FindOrAddObjectInTable(function);
1076 ASSERT(dest_index == FrameSize());
1077 instructions_.Add(new (zone())
1078 DeoptRetAddressInstr(object_table_index, deopt_id));
1079}
1080
1082 intptr_t dest_index) {
1083 intptr_t object_table_index = FindOrAddObjectInTable(function);
1084 ASSERT(dest_index == FrameSize());
1085 instructions_.Add(new (zone()) DeoptPcMarkerInstr(object_table_index));
1086}
1087
1088void DeoptInfoBuilder::AddPp(const Function& function, intptr_t dest_index) {
1089 intptr_t object_table_index = FindOrAddObjectInTable(function);
1090 ASSERT(dest_index == FrameSize());
1091 instructions_.Add(new (zone()) DeoptPpInstr(object_table_index));
1092}
1093
1095 const Location& source_loc,
1096 const intptr_t dest_index) {
1097 DeoptInstr* deopt_instr = nullptr;
1098 if (source_loc.IsConstant()) {
1099 intptr_t object_table_index = FindOrAddObjectInTable(source_loc.constant());
1100 deopt_instr = new (zone()) DeoptConstantInstr(object_table_index);
1101 } else if (source_loc.IsInvalid() &&
1102 value->definition()->IsMaterializeObject()) {
1103 const intptr_t index =
1104 FindMaterialization(value->definition()->AsMaterializeObject());
1105 ASSERT(index >= 0);
1106 deopt_instr = new (zone()) DeoptMaterializedObjectRefInstr(index);
1107 } else {
1108 ASSERT(!source_loc.IsInvalid());
1109 Representation rep = value->definition()->representation();
1110 switch (rep) {
1111 case kTagged:
1112 deopt_instr =
1113 new (zone()) DeoptWordInstr(ToCpuRegisterSource(source_loc));
1114 break;
1115#if defined(TARGET_ARCH_IS_64_BIT)
1116 case kUntagged:
1117#endif
1118 case kUnboxedInt64: {
1119 if (source_loc.IsPairLocation()) {
1120 PairLocation* pair = source_loc.AsPairLocation();
1121 deopt_instr =
1122 new (zone()) DeoptMintPairInstr(ToCpuRegisterSource(pair->At(0)),
1123 ToCpuRegisterSource(pair->At(1)));
1124 } else {
1125 ASSERT(!source_loc.IsPairLocation());
1126 deopt_instr =
1127 new (zone()) DeoptMintInstr(ToCpuRegisterSource(source_loc));
1128 }
1129 break;
1130 }
1131#if defined(TARGET_ARCH_IS_32_BIT)
1132 case kUntagged:
1133#endif
1134 case kUnboxedInt32:
1135 deopt_instr =
1136 new (zone()) DeoptInt32Instr(ToCpuRegisterSource(source_loc));
1137 break;
1138 case kUnboxedUint32:
1139 deopt_instr =
1140 new (zone()) DeoptUint32Instr(ToCpuRegisterSource(source_loc));
1141 break;
1142 case kUnboxedFloat:
1143 deopt_instr = new (zone()) DeoptFloatInstr(
1144 ToFpuRegisterSource(source_loc, Location::kDoubleStackSlot));
1145 break;
1146 case kUnboxedDouble:
1147 deopt_instr = new (zone()) DeoptDoubleInstr(
1148 ToFpuRegisterSource(source_loc, Location::kDoubleStackSlot));
1149 break;
1150 case kUnboxedFloat32x4:
1151 deopt_instr = new (zone()) DeoptFloat32x4Instr(
1152 ToFpuRegisterSource(source_loc, Location::kQuadStackSlot));
1153 break;
1154 case kUnboxedFloat64x2:
1155 deopt_instr = new (zone()) DeoptFloat64x2Instr(
1156 ToFpuRegisterSource(source_loc, Location::kQuadStackSlot));
1157 break;
1158 case kUnboxedInt32x4:
1159 deopt_instr = new (zone()) DeoptInt32x4Instr(
1160 ToFpuRegisterSource(source_loc, Location::kQuadStackSlot));
1161 break;
1162 default:
1163 UNREACHABLE();
1164 break;
1165 }
1166 }
1167 ASSERT(dest_index == FrameSize());
1168 ASSERT(deopt_instr != nullptr);
1169 instructions_.Add(deopt_instr);
1170}
1171
1172void DeoptInfoBuilder::AddCallerFp(intptr_t dest_index) {
1173 ASSERT(dest_index == FrameSize());
1174 instructions_.Add(new (zone()) DeoptCallerFpInstr());
1175}
1176
1177void DeoptInfoBuilder::AddCallerPp(intptr_t dest_index) {
1178 ASSERT(dest_index == FrameSize());
1179 instructions_.Add(new (zone()) DeoptCallerPpInstr());
1180}
1181
1182void DeoptInfoBuilder::AddCallerPc(intptr_t dest_index) {
1183 ASSERT(dest_index == FrameSize());
1184 instructions_.Add(new (zone()) DeoptCallerPcInstr());
1185}
1186
1187void DeoptInfoBuilder::AddConstant(const Object& obj, intptr_t dest_index) {
1188 ASSERT(dest_index == FrameSize());
1189 intptr_t object_table_index = FindOrAddObjectInTable(obj);
1190 instructions_.Add(new (zone()) DeoptConstantInstr(object_table_index));
1191}
1192
1194 const intptr_t index = FindMaterialization(mat);
1195 if (index >= 0) {
1196 return; // Already added.
1197 }
1198 materializations_.Add(mat);
1199
1200 // Count initialized fields and emit kMaterializeObject instruction.
1201 // There is no need to write nulls into fields because object is null
1202 // initialized by default.
1203 intptr_t non_null_fields = 0;
1204 for (intptr_t i = 0; i < mat->InputCount(); i++) {
1205 if (!mat->InputAt(i)->BindsToConstantNull()) {
1206 non_null_fields++;
1207 }
1208 }
1209
1210 instructions_.Add(new (zone()) DeoptMaterializeObjectInstr(non_null_fields));
1211
1212 for (intptr_t i = 0; i < mat->InputCount(); i++) {
1213 MaterializeObjectInstr* nested_mat =
1214 mat->InputAt(i)->definition()->AsMaterializeObject();
1215 if (nested_mat != nullptr) {
1216 AddMaterialization(nested_mat);
1217 }
1218 }
1219}
1220
1222 ASSERT(dest_index == kDartFrameFixedSize);
1223 for (intptr_t i = 0; i < materializations_.length(); i++) {
1224 MaterializeObjectInstr* mat = materializations_[i];
1225 // Class of the instance to allocate.
1226 AddConstant(mat->cls(), dest_index++);
1227 AddConstant(Smi::ZoneHandle(Smi::New(mat->length_or_shape())),
1228 dest_index++);
1229 for (intptr_t i = 0; i < mat->InputCount(); i++) {
1230 if (!mat->InputAt(i)->BindsToConstantNull()) {
1231 // Emit offset-value pair.
1232 AddConstant(Smi::ZoneHandle(Smi::New(mat->FieldOffsetAt(i))),
1233 dest_index++);
1234 AddCopy(mat->InputAt(i), mat->LocationAt(i), dest_index++);
1235 }
1236 }
1237 }
1238 return dest_index;
1239}
1240
1241intptr_t DeoptInfoBuilder::FindMaterialization(
1242 MaterializeObjectInstr* mat) const {
1243 for (intptr_t i = 0; i < materializations_.length(); i++) {
1244 if (materializations_[i] == mat) {
1245 return i;
1246 }
1247 }
1248 return -1;
1249}
1250
1251TypedDataPtr DeoptInfoBuilder::CreateDeoptInfo(const Array& deopt_table) {
1252 intptr_t length = instructions_.length();
1253
1254 // Count the number of instructions that are a shared suffix of some deopt
1255 // info already written.
1256 TrieNode* suffix = trie_root_;
1257 intptr_t suffix_length = 0;
1258 if (FLAG_compress_deopt_info) {
1259 for (intptr_t i = length - 1; i >= 0; --i) {
1260 TrieNode* node = suffix->FindChild(*instructions_[i]);
1261 if (node == nullptr) break;
1262 suffix = node;
1263 ++suffix_length;
1264 }
1265 }
1266
1267 // Allocate space for the translation. If the shared suffix is longer
1268 // than one instruction, we replace it with a single suffix instruction.
1269 const bool use_suffix = suffix_length > 1;
1270 if (use_suffix) {
1271 length -= (suffix_length - 1);
1272 }
1273
1274 typedef ZoneWriteStream::Raw<sizeof(intptr_t), intptr_t> Writer;
1275 ZoneWriteStream stream(zone(), 2 * length * kWordSize);
1276
1277 Writer::Write(&stream, FrameSize());
1278
1279 if (use_suffix) {
1280 Writer::Write(&stream, suffix_length);
1281 Writer::Write(&stream, suffix->info_number());
1282 } else {
1283 Writer::Write(&stream, 0);
1284 }
1285
1286 // Write the unshared instructions and build their sub-tree.
1287 TrieNode* node = use_suffix ? suffix : trie_root_;
1288 const intptr_t write_count = use_suffix ? length - 1 : length;
1289 for (intptr_t i = write_count - 1; i >= 0; --i) {
1290 DeoptInstr* instr = instructions_[i];
1291 Writer::Write(&stream, instr->kind());
1292 Writer::Write(&stream, instr->source_index());
1293
1294 TrieNode* child = new (zone()) TrieNode(instr, current_info_number_);
1295 node->AddChild(child);
1296 node = child;
1297 }
1298
1299 const TypedData& deopt_info = TypedData::Handle(
1300 zone(), TypedData::New(kTypedDataUint8ArrayCid, stream.bytes_written(),
1301 Heap::kOld));
1302 {
1303 NoSafepointScope no_safepoint;
1304 memmove(deopt_info.DataAddr(0), stream.buffer(), stream.bytes_written());
1305 }
1306
1307 ASSERT(
1308 DeoptInfo::VerifyDecompression(instructions_, deopt_table, deopt_info));
1309 instructions_.Clear();
1310 materializations_.Clear();
1311 frame_start_ = -1;
1312
1313 ++current_info_number_;
1314 return deopt_info.ptr();
1315}
1316
1317intptr_t DeoptTable::SizeFor(intptr_t length) {
1318 return length * kEntrySize;
1319}
1320
1322 intptr_t index,
1323 const Smi& offset,
1324 const TypedData& info,
1325 const Smi& reason) {
1326 ASSERT((table.Length() % kEntrySize) == 0);
1327 intptr_t i = index * kEntrySize;
1328 table.SetAt(i, offset);
1329 table.SetAt(i + 1, info);
1330 table.SetAt(i + 2, reason);
1331}
1332
1334 ASSERT((table.Length() % kEntrySize) == 0);
1335 return table.Length() / kEntrySize;
1336}
1337
1339 intptr_t index,
1340 Smi* offset,
1341 TypedData* info,
1342 Smi* reason) {
1343 intptr_t i = index * kEntrySize;
1344 *offset ^= table.At(i);
1345 *info ^= table.At(i + 1);
1346 *reason ^= table.At(i + 2);
1347}
1348
1349intptr_t DeoptInfo::FrameSize(const TypedData& packed) {
1350 NoSafepointScope no_safepoint;
1351 typedef ReadStream::Raw<sizeof(intptr_t), intptr_t> Reader;
1352 ReadStream read_stream(reinterpret_cast<uint8_t*>(packed.DataAddr(0)),
1353 packed.LengthInBytes());
1354 return Reader::Read(&read_stream);
1355}
1356
1358 const GrowableArray<DeoptInstr*>& unpacked) {
1359 intptr_t num = 0;
1360 while (unpacked[num]->kind() == DeoptInstr::kMaterializeObject) {
1361 num++;
1362 }
1363 return num;
1364}
1365
1366void DeoptInfo::UnpackInto(const Array& table,
1367 const TypedData& packed,
1369 intptr_t length) {
1370 NoSafepointScope no_safepoint;
1371 typedef ReadStream::Raw<sizeof(intptr_t), intptr_t> Reader;
1372 ReadStream read_stream(reinterpret_cast<uint8_t*>(packed.DataAddr(0)),
1373 packed.LengthInBytes());
1374 const intptr_t frame_size = Reader::Read(&read_stream); // Skip frame size.
1375 USE(frame_size);
1376
1377 const intptr_t suffix_length = Reader::Read(&read_stream);
1378 if (suffix_length != 0) {
1379 ASSERT(suffix_length > 1);
1380 const intptr_t info_number = Reader::Read(&read_stream);
1381
1383 Smi& offset = Smi::Handle();
1384 Smi& reason_and_flags = Smi::Handle();
1385 DeoptTable::GetEntry(table, info_number, &offset, &suffix,
1386 &reason_and_flags);
1387 UnpackInto(table, suffix, unpacked, suffix_length);
1388 }
1389
1390 while ((read_stream.PendingBytes() > 0) && (unpacked->length() < length)) {
1391 const intptr_t instruction = Reader::Read(&read_stream);
1392 const intptr_t from_index = Reader::Read(&read_stream);
1393 unpacked->Add(DeoptInstr::Create(instruction, from_index));
1394 }
1395}
1396
1398 const TypedData& packed,
1399 GrowableArray<DeoptInstr*>* unpacked) {
1400 ASSERT(unpacked->is_empty());
1401
1402 // Pass kMaxInt32 as the length to unpack all instructions from the
1403 // packed stream.
1404 UnpackInto(table, packed, unpacked, kMaxInt32);
1405
1406 unpacked->Reverse();
1407}
1408
1409const char* DeoptInfo::ToCString(const Array& deopt_table,
1410 const TypedData& packed) {
1411#define FORMAT "[%s]"
1412 GrowableArray<DeoptInstr*> deopt_instrs;
1413 Unpack(deopt_table, packed, &deopt_instrs);
1414
1415 // Compute the buffer size required.
1416 intptr_t len = 1; // Trailing '\0'.
1417 for (intptr_t i = 0; i < deopt_instrs.length(); i++) {
1418 len += Utils::SNPrint(nullptr, 0, FORMAT, deopt_instrs[i]->ToCString());
1419 }
1420
1421 // Allocate the buffer.
1422 char* buffer = Thread::Current()->zone()->Alloc<char>(len);
1423
1424 // Layout the fields in the buffer.
1425 intptr_t index = 0;
1426 for (intptr_t i = 0; i < deopt_instrs.length(); i++) {
1427 index += Utils::SNPrint((buffer + index), (len - index), FORMAT,
1428 deopt_instrs[i]->ToCString());
1429 }
1430
1431 return buffer;
1432#undef FORMAT
1433}
1434
1435// Returns a bool so it can be asserted.
1437 const Array& deopt_table,
1438 const TypedData& packed) {
1440 Unpack(deopt_table, packed, &unpacked);
1441 ASSERT(unpacked.length() == original.length());
1442 for (intptr_t i = 0; i < unpacked.length(); ++i) {
1443 ASSERT(unpacked[i]->Equals(*original[i]));
1444 }
1445 return true;
1446}
1447
1448} // namespace dart
1449
1450#endif // !defined(DART_PRECOMPILED_RUNTIME)
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
static void encode(uint8_t output[16], const uint32_t input[4])
Definition: SkMD5.cpp:240
Type
Definition: SortBench.cpp:56
SI F table(const skcms_Curve *curve, F v)
#define UNREACHABLE()
Definition: assert.h:248
static ArrayPtr New(intptr_t len, Heap::Space space=Heap::kNew)
Definition: object.h:10959
void SetAt(intptr_t index, const Object &value) const
Definition: object.h:10880
void Add(const T &value)
intptr_t length() const
static CatchEntryMove FromSlot(SourceKind kind, intptr_t src_slot, intptr_t dest_slot)
Definition: exceptions.h:188
static CatchEntryMove FromConstant(intptr_t pool_id, intptr_t dest_slot)
Definition: exceptions.h:184
static intptr_t EncodePairSource(intptr_t src_lo_slot, intptr_t src_hi_slot)
Definition: exceptions.h:196
static CatchEntryMoves * Allocate(intptr_t num_moves)
Definition: exceptions.h:254
CatchEntryMove & At(intptr_t i)
Definition: exceptions.h:266
static ErrorPtr EnsureUnoptimizedCode(Thread *thread, const Function &function)
Definition: compiler.cc:854
StackFrame * NextFrame()
Definition: stack_frame.h:352
intptr_t ArgumentCount() const
virtual void Materialize(DeoptContext *deopt_context)=0
DeferredSlot * next() const
virtual DeoptInstr::Kind kind() const
virtual intptr_t source_index() const
void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)
virtual intptr_t source_index() const
virtual DeoptInstr::Kind kind() const
void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)
void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)
virtual DeoptInstr::Kind kind() const
virtual intptr_t source_index() const
CatchEntryMove ToCatchEntryMove(DeoptContext *deopt_context, intptr_t dest_slot)
virtual DeoptInstr::Kind kind() const
virtual const char * ArgumentsToCString() const
void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)
virtual intptr_t source_index() const
DeoptConstantInstr(intptr_t object_table_index)
intptr_t GetSourceFp() const
intptr_t MaterializeDeferredObjects()
DeoptContext(const StackFrame *frame, const Code &code, DestFrameOptions dest_options, fpu_register_t *fpu_registers, intptr_t *cpu_registers, bool is_lazy_deopt, bool deoptimizing_code)
bool is_lazy_deopt() const
intptr_t GetSourcePp() const
intptr_t GetCallerFp() const
ObjectPtr ObjectAt(intptr_t index) const
void DeferRetAddrMaterialization(intptr_t index, intptr_t deopt_id, intptr_t *slot)
void DeferMaterialization(float value, DoublePtr *slot)
ICData::DeoptReasonId deopt_reason() const
intptr_t GetSourcePc() const
CodePtr code() const
intptr_t * FrameBase(const StackFrame *frame)
void DeferPcMarkerMaterialization(intptr_t index, intptr_t *slot)
void VisitObjectPointers(ObjectPointerVisitor *visitor)
void DeferPpMaterialization(intptr_t index, ObjectPtr *slot)
const CatchEntryMoves * ToCatchEntryMoves(intptr_t num_vars)
TypedDataPtr deopt_info() const
intptr_t DestStackAdjustment() const
void SetCallerFp(intptr_t callers_fp)
void DeferMaterializedObjectRef(intptr_t idx, intptr_t *slot)
void DeferMintMaterialization(int64_t value, MintPtr *slot)
DeferredObject * GetDeferredObject(intptr_t idx) const
virtual const char * ArgumentsToCString() const
DeoptFpuInstr(const FpuRegisterSource &source)
void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)
virtual intptr_t source_index() const
virtual DeoptInstr::Kind kind() const
CatchEntryMove ToCatchEntryMove(DeoptContext *deopt_context, intptr_t dest_slot)
DeoptFpuInstr(intptr_t source_index)
TrieNode * FindChild(const DeoptInstr &instruction)
TrieNode(DeoptInstr *instruction, intptr_t info_number)
DeoptInfoBuilder(Zone *zone, const intptr_t num_args, compiler::Assembler *assembler)
void AddCopy(Value *value, const Location &source_loc, intptr_t dest_index)
TypedDataPtr CreateDeoptInfo(const Array &deopt_table)
void AddMaterialization(MaterializeObjectInstr *mat)
void AddPcMarker(const Function &function, intptr_t dest_index)
void AddReturnAddress(const Function &function, intptr_t deopt_id, intptr_t dest_index)
void AddCallerFp(intptr_t dest_index)
void AddCallerPp(intptr_t dest_index)
intptr_t EmitMaterializationArguments(intptr_t dest_index)
void AddPp(const Function &function, intptr_t dest_index)
void AddCallerPc(intptr_t dest_index)
static intptr_t NumMaterializations(const GrowableArray< DeoptInstr * > &)
static void Unpack(const Array &table, const TypedData &packed, GrowableArray< DeoptInstr * > *instructions)
static const char * ToCString(const Array &table, const TypedData &packed)
static intptr_t FrameSize(const TypedData &packed)
static bool VerifyDecompression(const GrowableArray< DeoptInstr * > &original, const Array &deopt_table, const TypedData &packed)
static DeoptInstr * Create(intptr_t kind_as_int, intptr_t source_index)
virtual void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)=0
virtual DeoptInstr::Kind kind() const =0
virtual intptr_t source_index() const =0
static intptr_t GetFieldCount(DeoptInstr *instr)
bool Equals(const DeoptInstr &other) const
virtual CatchEntryMove ToCatchEntryMove(DeoptContext *deopt_context, intptr_t dest_slot)
static uword GetRetAddress(DeoptInstr *instr, const ObjectPool &object_pool, Code *code)
virtual intptr_t source_index() const
virtual const char * ArgumentsToCString() const
DeoptIntInstr(const CpuRegisterSource &source)
virtual int64_t GetValue(DeoptContext *deopt_context)
CatchEntryMove ToCatchEntryMove(DeoptContext *deopt_context, intptr_t dest_slot)
virtual DeoptInstr::Kind kind() const
DeoptIntInstr(intptr_t source_index)
void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)
virtual int64_t GetValue(DeoptContext *deopt_context)=0
virtual intptr_t source_index() const
DeoptMaterializeObjectInstr(intptr_t field_count)
void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)
virtual const char * ArgumentsToCString() const
virtual DeoptInstr::Kind kind() const
virtual const char * ArgumentsToCString() const
virtual DeoptInstr::Kind kind() const
void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)
DeoptMintPairInstr(const CpuRegisterSource &lo, const CpuRegisterSource &hi)
virtual intptr_t source_index() const
virtual const char * ArgumentsToCString() const
virtual DeoptInstr::Kind kind() const
DeoptMintPairInstr(intptr_t source_index)
CatchEntryMove ToCatchEntryMove(DeoptContext *deopt_context, intptr_t dest_slot)
virtual int64_t GetValue(DeoptContext *deopt_context)
virtual intptr_t source_index() const
virtual const char * ArgumentsToCString() const
DeoptPcMarkerInstr(intptr_t object_table_index)
virtual DeoptInstr::Kind kind() const
void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)
virtual intptr_t source_index() const
void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)
virtual DeoptInstr::Kind kind() const
virtual const char * ArgumentsToCString() const
DeoptPpInstr(intptr_t object_table_index)
DeoptRetAddressInstr(intptr_t object_table_index, intptr_t deopt_id)
virtual intptr_t source_index() const
void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)
virtual const char * ArgumentsToCString() const
virtual DeoptInstr::Kind kind() const
DeoptRetAddressInstr(intptr_t source_index)
static void GetEntry(const Array &table, intptr_t index, Smi *offset, TypedData *info, Smi *reason_and_flags)
static intptr_t GetLength(const Array &table)
static intptr_t SizeFor(intptr_t length)
static void SetEntry(const Array &table, intptr_t index, const Smi &offset, const TypedData &info, const Smi &reason_and_flags)
DeoptWordInstr(intptr_t source_index)
void Execute(DeoptContext *deopt_context, intptr_t *dest_addr)
virtual intptr_t source_index() const
DeoptWordInstr(const CpuRegisterSource &source)
virtual const char * ArgumentsToCString() const
CatchEntryMove ToCatchEntryMove(DeoptContext *deopt_context, intptr_t dest_slot)
virtual DeoptInstr::Kind kind() const
static DART_NORETURN void PropagateError(const Error &error)
Definition: exceptions.cc:1003
const char * ToFullyQualifiedCString() const
Definition: object.cc:9762
ScriptPtr script() const
Definition: object.cc:10881
@ kOld
Definition: heap.h:39
bool IsInvalid() const
Definition: locations.h:289
bool IsConstant() const
Definition: locations.h:292
PairLocation * AsPairLocation() const
Definition: locations.cc:280
bool IsPairLocation() const
Definition: locations.h:316
const Object & constant() const
Definition: locations.cc:373
intptr_t FieldOffsetAt(intptr_t i) const
Definition: il.h:7726
const Class & cls() const
Definition: il.h:7722
intptr_t length_or_shape() const
Definition: il.h:7724
const Location & LocationAt(intptr_t i)
Definition: il.h:7730
static int64_t GetCurrentMonotonicMicros()
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
void VisitPointer(ObjectPtr *p)
Definition: visitor.h:55
ObjectPtr ObjectAt(intptr_t index) const
Definition: object.h:5628
static ObjectPtr null()
Definition: object.h:433
ObjectPtr ptr() const
Definition: object.h:332
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
static Object & ZoneHandle()
Definition: object.h:419
Location At(intptr_t i) const
Definition: locations.h:618
static PassiveObject & Handle()
Definition: object.h:1077
T Value(DeoptContext *context) const
intptr_t source_index() const
intptr_t StackSlot(DeoptContext *context) const
const char * ToCString() const
static SmiPtr New(intptr_t value)
Definition: object.h:10006
static intptr_t RawValue(intptr_t value)
Definition: object.h:10022
static bool IsValid(int64_t value)
Definition: object.h:10026
uword pc() const
Definition: stack_frame.h:43
CodePtr LookupDartCode() const
Definition: stack_frame.cc:336
static int SavedCallerPpSlotFromFp()
Definition: stack_frame.h:46
static const char * ToCString(Thread *thread, StringPtr ptr)
Definition: object.cc:24126
Zone * zone() const
Definition: thread_state.h:37
static Thread * Current()
Definition: thread.h:362
TimelineEvent * StartEvent()
intptr_t LengthInBytes() const
Definition: object.h:11523
void * DataAddr(intptr_t byte_offset) const
Definition: object.h:11571
static TypedDataPtr New(intptr_t class_id, intptr_t len, Heap::Space space=Heap::kNew)
Definition: object.cc:25587
static int SNPrint(char *str, size_t size, const char *format,...) PRINTF_ATTRIBUTE(3
static int64_t LowHighTo64Bits(uint32_t low, int32_t high)
Definition: utils.h:377
Definition: il.h:75
bool BindsToConstantNull() const
Definition: il.cc:1196
Definition * definition() const
Definition: il.h:103
intptr_t InputCount() const
Definition: il.h:2794
Value * InputAt(intptr_t i) const
Definition: il.h:2795
char * PrintToString(const char *format,...) PRINTF_ATTRIBUTE(2
Definition: zone.cc:313
ElementType * Alloc(intptr_t length)
ObjectPoolBuilder & object_pool_builder()
intptr_t FindObject(const Object &obj, ObjectPoolBuilderEntry::Patchability patchable=ObjectPoolBuilderEntry::kNotPatchable, ObjectPoolBuilderEntry::SnapshotBehavior snapshot_behavior=ObjectPoolBuilderEntry::kSnapshotable)
static const int K
Definition: daa.cpp:21
#define THR_Print(format,...)
Definition: log.h:20
#define FORMAT
const EmbeddedViewParams * params
#define ASSERT(E)
SkBitmap source
Definition: examples.cpp:28
double frame
Definition: examples.cpp:31
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
Dart_NativeFunction function
Definition: fuchsia.cc:51
size_t length
SK_API bool Read(SkStreamSeekable *src, SkDocumentPage *dstArray, int dstArrayCount, const SkDeserialProcs *=nullptr)
FrameLayout frame_layout
Definition: stack_frame.cc:76
Definition: dart_vm.cc:33
static bool Equals(const Object &expected, const Object &actual)
DeoptFpuInstr< DeoptInstr::kInt32x4, CatchEntryMove::SourceKind::kInt32x4Slot, simd128_value_t, Int32x4Ptr > DeoptInt32x4Instr
static void FillDeferredSlots(DeoptContext *deopt_context, DeferredSlot **slot_list)
DeoptFpuInstr< DeoptInstr::kFloat64x2, CatchEntryMove::SourceKind::kFloat64x2Slot, simd128_value_t, Float64x2Ptr > DeoptFloat64x2Instr
constexpr intptr_t kBitsPerWord
Definition: globals.h:514
static constexpr int kDartFrameFixedSize
DeoptIntInstr< DeoptInstr::kUint32, CatchEntryMove::SourceKind::kUint32Slot, uint32_t > DeoptUint32Instr
static constexpr int kSavedCallerFpSlotFromFp
Representation
Definition: locations.h:66
RegisterSource< Register > CpuRegisterSource
uintptr_t uword
Definition: globals.h:501
static constexpr int kParamEndSlotFromFp
static constexpr int kSavedPcSlotFromSp
static void USE(T &&)
Definition: globals.h:618
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
DeoptIntInstr< DeoptInstr::kInt32, CatchEntryMove::SourceKind::kInt32Slot, int32_t > DeoptInt32Instr
FrameLayout runtime_frame_layout
Definition: stack_frame.cc:81
DeoptFpuInstr< DeoptInstr::kFloat32x4, CatchEntryMove::SourceKind::kFloat32x4Slot, simd128_value_t, Float32x4Ptr > DeoptFloat32x4Instr
constexpr int32_t kMaxInt32
Definition: globals.h:483
DeoptFpuInstr< DeoptInstr::kDouble, CatchEntryMove::SourceKind::kDoubleSlot, double, DoublePtr > DeoptDoubleInstr
constexpr intptr_t kWordSize
Definition: globals.h:509
DeoptIntInstr< DeoptInstr::kMint, CatchEntryMove::SourceKind::kInt64Slot, int64_t > DeoptMintInstr
static bool IsObjectInstruction(DeoptInstr::Kind kind)
const char *const function_name
RegisterSource< FpuRegister > FpuRegisterSource
const char * DeoptReasonToCString(ICData::DeoptReasonId deopt_reason)
DeoptFpuInstr< DeoptInstr::kFloat, CatchEntryMove::SourceKind::kFloatSlot, float, DoublePtr > DeoptFloatInstr
DECLARE_FLAG(bool, show_invisible_frames)
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 buffer
Definition: switches.h:126
AsciiTrie::TrieNode TrieNode
Definition: ascii_trie.cc:10
#define Pp
Definition: globals.h:425
#define Px
Definition: globals.h:410
#define Pd
Definition: globals.h:408
static DecodeResult decode(std::string path)
Definition: png_codec.cpp:124
#define T
Definition: precompiler.cc:65
SeparatedVector2 offset
intptr_t first_local_from_fp
Definition: frame_layout.h:37
intptr_t VariableIndexForFrameSlot(intptr_t frame_slot) const
Definition: frame_layout.h:70