Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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
333 : i + kParamEndSlotFromFp -
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
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
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:
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
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
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
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
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
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:
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:
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:
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
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
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 {
1042 intptr_t index = -compiler::target::frame_layout.VariableIndexForFrameSlot(
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
1382 TypedData& suffix = TypedData::Handle();
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
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:10933
void SetAt(intptr_t index, const Object &value) const
Definition object.h:10858
void Add(const T &value)
intptr_t length() const
static constexpr intptr_t encode(intptr_t value)
Definition bitfield.h:167
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:855
StackFrame * NextFrame()
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)
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
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)
const char * ToFullyQualifiedCString() const
Definition object.cc:9820
ScriptPtr script() const
Definition object.cc:10939
@ 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:7687
const Class & cls() const
Definition il.h:7683
intptr_t length_or_shape() const
Definition il.h:7685
const Location & LocationAt(intptr_t i)
Definition il.h:7691
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:5599
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:9985
static intptr_t RawValue(intptr_t value)
Definition object.h:10001
static bool IsValid(int64_t value)
Definition object.h:10005
uword pc() const
Definition stack_frame.h:43
CodePtr LookupDartCode() const
static int SavedCallerPpSlotFromFp()
Definition stack_frame.h:46
static const char * ToCString(Thread *thread, StringPtr ptr)
Definition object.cc:24205
Zone * zone() const
static Thread * Current()
Definition thread.h:361
TimelineEvent * StartEvent()
intptr_t LengthInBytes() const
Definition object.h:11497
void * DataAddr(intptr_t byte_offset) const
Definition object.h:11545
static TypedDataPtr New(intptr_t class_id, intptr_t len, Heap::Space space=Heap::kNew)
Definition object.cc:25666
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:362
bool BindsToConstantNull() const
Definition il.cc:1194
Definition * definition() const
Definition il.h:103
intptr_t InputCount() const
Definition il.h:2776
Value * InputAt(intptr_t i) const
Definition il.h:2777
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
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
#define DECLARE_FLAG(type, name)
Definition flags.h:14
#define DEFINE_FLAG(type, name, default_value, comment)
Definition flags.h:16
Dart_NativeFunction function
Definition fuchsia.cc:51
size_t length
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
DeoptIntInstr< DeoptInstr::kInt32, CatchEntryMove::SourceKind::kInt32Slot, int32_t > DeoptInt32Instr
FrameLayout runtime_frame_layout
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
#define Pp
Definition globals.h:425
#define Px
Definition globals.h:410
#define Pd
Definition globals.h:408
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581
static DecodeResult decode(std::string path)
#define T
Point offset
intptr_t first_local_from_fp