20#if defined(INCLUDE_IL_PRINTER)
22 display_sorted_ic_data,
24 "Calls display a unary, sorted-by count form of ICData");
25DEFINE_FLAG(
bool, print_environments,
false,
"Print SSA environments.");
27 print_flow_graph_as_json,
29 "Use machine readable output when printing IL graphs.");
30DEFINE_FLAG(
bool, print_redundant_il,
false,
"Print redundant IL instructions");
34static bool IsRedundant(Instruction* instr) {
35 if (
auto constant = instr->AsConstant()) {
36 return !constant->HasUses();
37 }
else if (
auto move = instr->AsParallelMove()) {
38 return move->IsRedundant();
44static bool ShouldPrintInstruction(Instruction* instr) {
45 return FLAG_print_redundant_il || !IsRedundant(instr);
48class IlTestPrinter :
public AllStatic {
50 static void PrintGraph(
const char* phase, FlowGraph* flow_graph) {
53 writer.PrintProperty(
"p", phase);
54 writer.PrintProperty(
"f", flow_graph->function().ToFullyQualifiedCString());
55 writer.OpenArray(
"b");
56 for (
auto block : flow_graph->reverse_postorder()) {
57 PrintBlock(&writer, block);
60 const auto& codegen_order = *flow_graph->CodegenBlockOrder();
61 if (!codegen_order.is_empty() &&
62 (&codegen_order != &flow_graph->reverse_postorder())) {
63 writer.OpenArray(
"cbo");
64 const auto block_count = flow_graph->reverse_postorder().length();
65 for (
auto block : codegen_order) {
66 writer.PrintValue64((
block_count - 1) - block->postorder_number());
70 writer.OpenObject(
"desc");
71 AttributesSerializer(&writer).WriteDescriptors();
73 writer.OpenObject(
"flags");
74 writer.PrintPropertyBool(
"nnbd",
true);
80 static void PrintBlock(JSONWriter* writer, BlockEntryInstr* block) {
82 writer->PrintProperty64(
"b", block->block_id());
83 writer->PrintProperty(
"o", block->DebugName());
84 if (
auto block_with_defs = block->AsBlockEntryWithInitialDefs()) {
85 if (block_with_defs->initial_definitions() !=
nullptr &&
86 block_with_defs->initial_definitions()->length() > 0) {
87 writer->OpenArray(
"d");
88 for (
auto defn : *block_with_defs->initial_definitions()) {
89 if (ShouldPrintInstruction(defn)) {
90 PrintInstruction(writer, defn);
96 writer->OpenArray(
"is");
97 if (
auto join = block->AsJoinEntry()) {
98 for (PhiIterator it(join); !it.Done(); it.Advance()) {
99 if (ShouldPrintInstruction(it.Current())) {
100 PrintInstruction(writer, it.Current());
104 for (
auto instr : block->instructions()) {
105 if (instr->ArgumentCount() != 0 && instr->GetMoveArguments() !=
nullptr) {
106 for (
auto move_arg : *(instr->GetMoveArguments())) {
107 PrintInstruction(writer, move_arg);
110 if (ShouldPrintInstruction(instr) && !instr->IsMoveArgument()) {
111 PrintInstruction(writer, instr);
114 writer->CloseArray();
115 writer->CloseObject();
118 static void PrintInstruction(JSONWriter* writer,
120 const char*
name =
nullptr) {
121 writer->OpenObject(
name);
122 if (
auto defn = instr->AsDefinition()) {
123 if (defn->ssa_temp_index() != -1) {
124 writer->PrintProperty(
"v", defn->ssa_temp_index());
127 if (defn->HasType()) {
128 writer->OpenObject(
"T");
129 defn->Type()->PrintTo(writer);
130 writer->CloseObject();
133 writer->PrintProperty(
"o", instr->DebugName());
134 if (
auto branch = instr->AsBranch()) {
135 PrintInstruction(writer, branch->comparison(),
"cc");
137 if (instr->InputCount() != 0) {
138 writer->OpenArray(
"i");
139 for (intptr_t i = 0; i < instr->InputCount(); i++) {
140 writer->PrintValue(instr->InputAt(i)->definition()->ssa_temp_index());
142 writer->CloseArray();
143 }
else if (instr->ArgumentCount() != 0 &&
144 instr->GetMoveArguments() !=
nullptr) {
145 writer->OpenArray(
"i");
146 for (intptr_t i = 0; i < instr->ArgumentCount(); i++) {
148 instr->ArgumentValueAt(i)->definition()->ssa_temp_index());
150 writer->CloseArray();
152 AttributesSerializer serializer(writer);
153 instr->Accept(&serializer);
155 if (instr->SuccessorCount() > 0) {
156 writer->OpenArray(
"s");
157 for (
auto succ : instr->successors()) {
158 writer->PrintValue(succ->block_id());
160 writer->CloseArray();
162 writer->CloseObject();
165 template <
typename T>
166 class HasGetAttributes {
167 template <
typename U>
168 static std::true_type
test(
decltype(&U::GetAttributes));
169 template <
typename U>
170 static std::false_type
test(...);
173 static constexpr bool value =
decltype(test<T>(
nullptr))::value;
176 class AttributesSerializer :
public InstructionVisitor {
178 explicit AttributesSerializer(JSONWriter* writer) : writer_(writer) {}
180 void WriteDescriptors() {
181#define DECLARE_VISIT_INSTRUCTION(ShortName, Attrs) \
182 WriteDescriptor<ShortName##Instr>(#ShortName);
186#undef DECLARE_VISIT_INSTRUCTION
189#define DECLARE_VISIT_INSTRUCTION(ShortName, Attrs) \
190 virtual void Visit##ShortName(ShortName##Instr* instr) { Write(instr); }
194#undef DECLARE_VISIT_INSTRUCTION
197 void WriteAttribute(
const char* value) { writer_->PrintValue(value); }
199 void WriteAttribute(intptr_t value) { writer_->PrintValue(value); }
201 void WriteAttribute(
bool value) { writer_->PrintValueBool(value); }
203 void WriteAttribute(Token::Kind kind) {
204 writer_->PrintValue(Token::Str(kind));
207 void WriteAttribute(Representation rep) {
208 writer_->PrintValue(RepresentationUtils::ToCString(rep));
211 static const char* LocationKindAsString(
const Location& loc) {
212 if (loc.IsConstant()) {
214 }
else if (loc.IsPairLocation()) {
215 auto pair = loc.AsPairLocation();
216 return Thread::Current()->zone()->PrintToString(
217 "(%s, %s)", LocationKindAsString(pair->At(0)),
218 LocationKindAsString(pair->At(0)));
220 switch (loc.kind()) {
221 case Location::kUnallocated:
223 case Location::kStackSlot:
224 return "stack(word)";
225 case Location::kDoubleStackSlot:
227 case Location::kQuadStackSlot:
228 return "stack(f128)";
229 case Location::kRegister:
231 case Location::kFpuRegister:
239 void WriteAttribute(
const Location& loc) {
240 writer_->PrintValue(LocationKindAsString(loc));
243 void WriteAttribute(
const Slot* slot) { writer_->PrintValue(slot->Name()); }
245 void WriteAttribute(
const Function*
function) {
246 writer_->PrintValue(
function->QualifiedUserVisibleNameCString());
249 void WriteAttribute(
const Object* obj) {
251 writer_->PrintValueNull();
252 }
else if (obj->IsBool()) {
253 writer_->PrintValueBool(Bool::Cast(*obj).value());
254 }
else if (obj->IsInteger()) {
255 auto value = Integer::Cast(*obj).AsInt64Value();
259 writer_->buffer()->Printf(
"%" Pd64 "", value);
260 }
else if (obj->IsString()) {
261 const auto& str = String::Cast(*obj);
262 writer_->PrintValueStr(str, 0, str.Length());
264 const auto& cls = Class::Handle(obj->clazz());
265 writer_->PrintfValue(
"Instance of %s", cls.UserVisibleNameCString());
269 template <
typename... Ts>
270 void WriteTuple(
const std::tuple<Ts...>& tuple) {
272 [&](Ts
const&... elements) { (WriteAttribute(elements), ...); },
276 template <
typename T,
277 typename =
typename std::enable_if_t<HasGetAttributes<T>::value>>
278 void Write(
T* instr) {
279 writer_->OpenArray(
"d");
280 WriteTuple(instr->GetAttributes());
281 writer_->CloseArray();
284 void Write(Instruction* instr) {
288 void WriteAttributeName(
const char* str) {
298 const intptr_t
start = str[0] ==
'&' ? 1 : 0;
299 intptr_t
end = strlen(str);
300 switch (str[
end - 1]) {
316 template <
typename... Ts>
317 void WriteAttributeNames(
const std::tuple<Ts...>& tuple) {
319 [&](Ts
const&... elements) { (WriteAttributeName(elements), ...); },
323 template <
typename T>
324 void WriteDescriptor(
326 typename std::enable_if_t<HasGetAttributes<T>::value>* =
nullptr) {
327 writer_->OpenArray(
name);
328 WriteAttributeNames(T::GetAttributeNames());
329 writer_->CloseArray();
332 template <
typename T>
333 void WriteDescriptor(
335 typename std::enable_if_t<!HasGetAttributes<T>::value>* =
nullptr) {}
343 uint8_t** compiler_pass_filter ) {
344 return compiler::PrintFilter::ShouldPrint(
function, compiler_pass_filter);
349 if (FLAG_print_flow_graph_as_json) {
350 IlTestPrinter::PrintGraph(phase, flow_graph);
354 printer.PrintBlocks();
361 bool print_locations) {
366 for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
367 Instruction* current = it.Current();
370 if (!ShouldPrintInstruction(current)) {
380 if (!function_.
IsNull()) {
387 const ArgumentsDescriptor args_desc(args_desc_array);
388 THR_Print(
", %s", args_desc.ToCString());
393 for (intptr_t i = 0; i < block_order_.length(); ++i) {
394 PrintBlock(block_order_[i], print_locations_);
403 bool print_locations) {
405 BufferFormatter
f(str,
sizeof(str));
407 if (FLAG_print_environments && (instr->env() !=
nullptr)) {
408 instr->env()->PrintTo(&f);
410 if (print_locations && (instr->HasLocs())) {
411 instr->locs()->PrintTo(&f);
416 if (!instr->IsBlockEntry())
THR_Print(
" ");
418 if (FLAG_trace_inlining_intervals) {
424 TokenPosition token_pos,
426 const AbstractType& dst_type,
427 const String& dst_name,
429 const char* compile_type_name =
"unknown";
430 if (value !=
nullptr &&
value->reaching_type_ !=
nullptr) {
431 compile_type_name =
value->reaching_type_->ToCString();
434 "%s type check: compile type %s is %s specific than "
435 "type '%s' of '%s'.\n",
436 eliminated ?
"Eliminated" :
"Generated", compile_type_name,
437 eliminated ?
"more" :
"not more", dst_type.NameCString(),
438 dst_name.ToCString());
441static void PrintTargetsHelper(BaseTextBuffer* f,
442 const CallTargets& targets,
443 intptr_t num_checks_to_print) {
444 f->AddString(
" Targets[");
445 f->Printf(
"%" Pd ": ", targets.length());
448 (num_checks_to_print > targets.length())) {
449 num_checks_to_print = targets.length();
451 for (intptr_t i = 0; i < num_checks_to_print; i++) {
452 const CidRange& range = targets[i];
453 const auto target_info = targets.TargetAt(i);
454 const intptr_t
count = target_info->count;
455 target = target_info->target->ptr();
459 if (range.IsSingleCid()) {
463 f->Printf(
" cid %" Pd " cnt:%" Pd " trgt:'%s'", range.cid_start,
count,
464 target.ToQualifiedCString());
467 f->Printf(
"cid %" Pd "-%" Pd " %s", range.cid_start, range.cid_end,
469 f->Printf(
" cnt:%" Pd " trgt:'%s'",
count,
target.ToQualifiedCString());
472 if (target_info->exactness.IsTracking()) {
473 f->Printf(
" %s", target_info->exactness.ToCString());
476 if (num_checks_to_print < targets.length()) {
482static void PrintCidsHelper(BaseTextBuffer* f,
484 intptr_t num_checks_to_print) {
485 f->AddString(
" Cids[");
486 f->Printf(
"%" Pd ": ", targets.length());
488 (num_checks_to_print > targets.length())) {
489 num_checks_to_print = targets.length();
491 for (intptr_t i = 0; i < num_checks_to_print; i++) {
492 const CidRange& range = targets[i];
499 if (range.IsSingleCid()) {
500 f->Printf(
" cid %" Pd, range.cid_start);
502 f->Printf(
" cid %" Pd "-%" Pd, range.cid_start, range.cid_end);
505 if (num_checks_to_print < targets.length()) {
511static void PrintICDataHelper(BaseTextBuffer* f,
512 const ICData& ic_data,
513 intptr_t num_checks_to_print) {
514 f->AddString(
" IC[");
515 if (ic_data.is_tracking_exactness()) {
520 f->Printf(
"%" Pd ": ", ic_data.NumberOfChecks());
523 (num_checks_to_print > ic_data.NumberOfChecks())) {
524 num_checks_to_print = ic_data.NumberOfChecks();
526 for (intptr_t i = 0; i < num_checks_to_print; i++) {
527 GrowableArray<intptr_t> class_ids;
528 ic_data.GetCheckAt(i, &class_ids, &
target);
529 const intptr_t
count = ic_data.GetCountAt(i);
533 for (intptr_t k = 0; k < class_ids.length(); k++) {
541 f->Printf(
" cnt:%" Pd " trgt:'%s'",
count,
target.ToQualifiedCString());
542 if (ic_data.is_tracking_exactness()) {
543 f->Printf(
" %s", ic_data.GetExactnessAt(i).ToCString());
546 if (num_checks_to_print < ic_data.NumberOfChecks()) {
552static void PrintICDataSortedHelper(BaseTextBuffer* f,
553 const ICData& ic_data_orig) {
554 const ICData& ic_data =
556 f->Printf(
" IC[n:%" Pd "; ", ic_data.NumberOfChecks());
557 for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
558 const intptr_t
count = ic_data.GetCountAt(i);
559 const intptr_t
cid = ic_data.GetReceiverClassIdAt(i);
568 intptr_t num_checks_to_print) {
571 PrintICDataHelper(&f, ic_data, num_checks_to_print);
578 intptr_t num_checks_to_print) {
581 PrintTargetsHelper(&f, targets, num_checks_to_print);
586static void PrintUse(BaseTextBuffer* f,
const Definition& definition) {
587 if (definition.HasSSATemp()) {
588 f->Printf(
"v%" Pd "", definition.ssa_temp_index());
589 }
else if (definition.HasTemp()) {
590 f->Printf(
"t%" Pd "", definition.temp_index());
601void Instruction::PrintTo(BaseTextBuffer* f)
const {
611void Instruction::PrintOperandsTo(BaseTextBuffer* f)
const {
613 if (i > 0)
f->AddString(
", ");
618void Definition::PrintTo(BaseTextBuffer* f)
const {
635 }
else if (type_ !=
nullptr) {
641void CheckNullInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
642 Definition::PrintOperandsTo(f);
645 f->AddString(
", NoSuchMethodError");
648 f->AddString(
", ArgumentError");
651 f->AddString(
", CastError");
656void Definition::PrintOperandsTo(BaseTextBuffer* f)
const {
658 if (i > 0)
f->AddString(
", ");
665void RedefinitionInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
666 Definition::PrintOperandsTo(f);
667 if (constrained_type_ !=
nullptr) {
668 f->Printf(
" ^ %s", constrained_type_->ToCString());
672void ReachabilityFenceInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
683void Value::PrintTo(BaseTextBuffer* f)
const {
686 if ((reaching_type_ !=
nullptr) && (reaching_type_ !=
definition()->type_)) {
692void ConstantInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
694 const char* new_line = strchr(cstr,
'\n');
695 if (new_line ==
nullptr) {
696 f->Printf(
"#%s", cstr);
698 const intptr_t
pos = new_line - cstr;
702 f->Printf(
"#%s\\n...",
buffer);
706void ConstraintInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
721 if (range ==
nullptr)
return "[_|_, _|_]";
732 f->Printf(
"v%" Pd "",
733 reinterpret_cast<Definition*
>(value_)->ssa_temp_index());
734 if (offset_ != 0)
f->Printf(
"%+" Pd64 "", offset_);
737 f->Printf(
"%" Pd64 "", value_);
752void MakeTempInstr::PrintOperandsTo(BaseTextBuffer* f)
const {}
754void DropTempsInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
756 if (
value() !=
nullptr) {
762void AssertAssignableInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
766 f->Printf(
", '%s',",
dst_name().ToCString());
767 f->AddString(
" instantiator_type_args(");
769 f->AddString(
"), function_type_args(");
774void AssertSubtypeInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
780 f->AddString(
", instantiator_type_args(");
782 f->AddString(
"), function_type_args(");
787void AssertBooleanInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
791void ClosureCallInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
792 if (FLAG_precompiled_mode) {
793 f->AddString(
" closure=");
795 f->AddString(
" function=");
805void InstanceCallInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
812 if (FLAG_display_sorted_ic_data) {
813 PrintICDataSortedHelper(f, *
ic_data());
821 if (
entry_kind() == Code::EntryKind::kUnchecked) {
822 f->AddString(
" using unchecked entrypoint");
826void PolymorphicInstanceCallInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
834 f->AddString(
" COMPLETE");
836 if (
entry_kind() == Code::EntryKind::kUnchecked) {
837 f->AddString(
" using unchecked entrypoint");
841void DispatchTableCallInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
844 f->AddString(
" cid=");
853void StrictCompareInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
859 f->Printf(
", with number check");
863void TestCidsInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
867 for (intptr_t i = 0; i <
length; i += 2) {
872 if (CanDeoptimize()) {
874 f->AddString(
"else deoptimize ");
881void TestRangeInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
883 f->Printf(
" %s [%" Pd "-%" Pd "]", kind() == Token::kIS ?
"in" :
"not in",
887void EqualityCompareInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
893void StaticCallInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
897 if (i > 0)
f->AddString(
", ");
900 if (
entry_kind() == Code::EntryKind::kUnchecked) {
901 f->AddString(
", using unchecked entrypoint");
904 f->Printf(
", recognized_kind = %s",
912void CachableIdempotentCallInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
916 if (i > 0)
f->AddString(
", ");
921void LoadLocalInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
925void StoreLocalInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
930void NativeCallInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
934void GuardFieldInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
936 field().GuardedPropertiesAsCString());
940void StoreFieldInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
944 if (
slot().representation() != kTagged) {
952 f->AddString(
", NoStoreBarrier");
955 f->AddString(
", MayStoreInnerPointer");
959void IfThenElseInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
961 f->Printf(
" ? %" Pd " : %" Pd, if_true_, if_false_);
964void LoadStaticFieldInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
967 f->AddString(
", CallsInitializer");
971void StoreStaticFieldInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
976void InstanceOfInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
978 f->Printf(
" IS %s,",
type().NameCString());
979 f->AddString(
" instantiator_type_args(");
981 f->AddString(
"), function_type_args(");
986void RelationalOpInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
993void AllocationInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
994 Definition::PrintOperandsTo(f);
999 f->AddString(
"<not-aliased>");
1003void AllocateObjectInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1004 f->Printf(
"cls=%s",
cls().ScrubbedNameCString());
1008 AllocationInstr::PrintOperandsTo(f);
1011void MaterializeObjectInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1012 f->Printf(
"%s", cls_.ScrubbedNameCString());
1013 for (intptr_t i = 0; i <
InputCount(); i++) {
1015 f->Printf(
"%s: ", slots_[i]->
Name());
1020void LoadFieldInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1024 f->AddString(
", CallsInitializer");
1027 f->AddString(
", MayLoadInnerPointer");
1031void LoadUntaggedInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1036void CalculateElementAddressInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1037 Definition::PrintOperandsTo(f);
1041void InstantiateTypeInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1043 f->Printf(
"%s,", type_name.ToCString());
1044 f->AddString(
" instantiator_type_args(");
1046 f->AddString(
"), function_type_args(");
1051void InstantiateTypeArgumentsInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1053 f->AddString(
", instantiator_type_args(");
1055 f->AddString(
"), function_type_args(");
1063void AllocateContextInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1068 TemplateAllocation::PrintOperandsTo(f);
1071void AllocateUninitializedContextInstr::PrintOperandsTo(
1072 BaseTextBuffer* f)
const {
1077 TemplateAllocation::PrintOperandsTo(f);
1080void TruncDivModInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1081 Definition::PrintOperandsTo(f);
1084void ExtractNthOutputInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1085 f->Printf(
"Extract %" Pd " from ",
index());
1086 Definition::PrintOperandsTo(f);
1089void UnboxLaneInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1090 Definition::PrintOperandsTo(f);
1091 f->Printf(
", lane %" Pd,
lane());
1094void BoxLanesInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1095 Definition::PrintOperandsTo(f);
1098void UnaryIntegerOpInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1100 value()->PrintTo(f);
1103void BinaryIntegerOpInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1106 f->AddString(
" [tr]");
1108 f->AddString(
" [-o]");
1113 right()->PrintTo(f);
1116void BinaryDoubleOpInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1120 right()->PrintTo(f);
1123void DoubleTestOpInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1125 case MethodRecognizer::kDouble_getIsNaN:
1126 f->AddString(
"IsNaN ");
1128 case MethodRecognizer::kDouble_getIsInfinite:
1129 f->AddString(
"IsInfinite ");
1131 case MethodRecognizer::kDouble_getIsNegative:
1132 f->AddString(
"IsNegative ");
1137 value()->PrintTo(f);
1140static const char*
const simd_op_kind_string[] = {
1141#define CASE(Arity, Mask, Name, ...) #Name,
1146void SimdOpInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1147 f->Printf(
"%s", simd_op_kind_string[
kind()]);
1149 f->Printf(
", mask = %" Pd "",
mask());
1151 for (intptr_t i = 0; i <
InputCount(); i++) {
1157void UnaryDoubleOpInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1159 value()->PrintTo(f);
1162void LoadClassIdInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1163 if (!input_can_be_smi_) {
1164 f->AddString(
"<non-smi> ");
1169void CheckClassIdInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1170 value()->PrintTo(f);
1175 if (
cids().IsSingleCid()) {
1176 f->Printf(
", %s",
name.ToCString());
1181 f->Printf(
", cid %" Pd "-%" Pd " %s-%s",
cids().cid_start,
cids().cid_end,
1182 name.ToCString(), name2.ToCString());
1186void HashIntegerOpInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1188 f->AddString(
"smi ");
1191 value()->PrintTo(f);
1194void CheckClassInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1195 value()->PrintTo(f);
1198 f->AddString(
" nullcheck");
1202void CheckConditionInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1206void InvokeMathCFunctionInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1208 Definition::PrintOperandsTo(f);
1212 BaseTextBuffer* f)
const {
1213 const GrowableArray<Definition*>& defns = initial_definitions_;
1214 if (defns.length() > 0) {
1216 for (intptr_t i = 0; i < defns.length(); ++i) {
1217 Definition* def = defns[i];
1219 if (!ShouldPrintInstruction(def)) {
1222 f->AddString(
"\n ");
1225 f->AddString(
"\n}");
1229void GraphEntryInstr::PrintTo(BaseTextBuffer* f)
const {
1230 f->Printf(
"B%" Pd "[graph]:%" Pd,
block_id(), GetDeoptId());
1234void JoinEntryInstr::PrintTo(BaseTextBuffer* f)
const {
1239 f->Printf(
"B%" Pd "[join]:%" Pd " pred(",
block_id(), GetDeoptId());
1242 if (i > 0)
f->AddString(
", ");
1246 if (phis_ !=
nullptr) {
1248 for (intptr_t i = 0; i < phis_->length(); ++i) {
1249 if ((*phis_)[i] ==
nullptr)
continue;
1250 f->AddString(
"\n ");
1251 (*phis_)[i]->PrintTo(f);
1253 f->AddString(
"\n}");
1261void IndirectEntryInstr::PrintTo(BaseTextBuffer* f)
const {
1266 f->Printf(
"]:%" Pd " pred(", GetDeoptId());
1268 if (i > 0)
f->AddString(
", ");
1272 if (phis_ !=
nullptr) {
1274 for (intptr_t i = 0; i < phis_->length(); ++i) {
1275 if ((*phis_)[i] ==
nullptr)
continue;
1276 f->AddString(
"\n ");
1277 (*phis_)[i]->PrintTo(f);
1279 f->AddString(
"\n}");
1287void PhiInstr::PrintTo(BaseTextBuffer* f)
const {
1294 f->AddString(
is_alive() ?
" alive" :
" dead");
1305 f->Printf(
" %s", TypeAsCString());
1309void UnboxIntegerInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1311 f->AddString(
"[tr], ");
1313 if (SpeculativeModeOfInputs() == kGuardInputs) {
1314 f->AddString(
"[guard-inputs], ");
1316 f->AddString(
"[non-speculative], ");
1318 Definition::PrintOperandsTo(f);
1321void IntConverterInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1325 Definition::PrintOperandsTo(f);
1328void BitCastInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1329 Definition::PrintOperandsTo(f);
1334void ParameterInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1335 f->Printf(
"%" Pd " @%s", env_index(),
location().ToCString());
1338void CheckStackOverflowInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1342void TargetEntryInstr::PrintTo(BaseTextBuffer* f)
const {
1347 f->Printf(
"B%" Pd "[target]:%" Pd,
block_id(), GetDeoptId());
1355void OsrEntryInstr::PrintTo(BaseTextBuffer* f)
const {
1365void FunctionEntryInstr::PrintTo(BaseTextBuffer* f)
const {
1366 f->Printf(
"B%" Pd "[function entry]:%" Pd,
block_id(), GetDeoptId());
1374void NativeEntryInstr::PrintTo(BaseTextBuffer* f)
const {
1375 f->Printf(
"B%" Pd "[native function entry]:%" Pd,
block_id(), GetDeoptId());
1383void FfiCallInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1384 f->AddString(
" pointer=");
1386 if (marshaller_.ReturnsCompound()) {
1387 f->AddString(
", compound_return_typed_data=");
1390 intptr_t def_index = 0;
1391 for (intptr_t arg_index = 0; arg_index < marshaller_.num_args();
1393 const auto& arg_location = marshaller_.Location(arg_index);
1394 const bool is_compound = arg_location.container_type().IsCompound();
1395 const intptr_t num_defs = marshaller_.NumDefinitions(arg_index);
1397 if (is_compound)
f->AddString(
"(");
1398 for (intptr_t i = 0; i < num_defs; i++) {
1399 InputAt(def_index)->PrintTo(f);
1400 if ((i + 1) < num_defs)
f->AddString(
", ");
1403 if (is_compound)
f->AddString(
")");
1404 f->AddString(
" (@");
1405 arg_location.PrintTo(f);
1410void LeafRuntimeCallInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1411 f->AddString(
"target_address=");
1413 for (intptr_t i = 0, n = argument_representations_.length(); i < n; ++i) {
1419void NativeReturnInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1420 if (marshaller_.NumReturnDefinitions() == 1) {
1431 f->AddString(
" (@");
1436void NativeParameterInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1438 marshaller_.Location(marshaller_.ArgumentIndex(def_index_)).PrintTo(f);
1439 f->AddString(
" at ");
1441 marshaller_.NativeLocationOfNativeParameter(def_index_).PrintTo(f);
1444void CatchBlockEntryInstr::PrintTo(BaseTextBuffer* f)
const {
1445 f->Printf(
"B%" Pd "[target catch try_idx %" Pd " catch_try_idx %" Pd "]",
1455void LoadIndexedUnsafeInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1457 index()->PrintTo(f);
1461void StoreIndexedUnsafeInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1463 index()->PrintTo(f);
1465 value()->PrintTo(f);
1468void LoadIndexedInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1471 if (!cls.IsNull()) {
1472 f->Printf(
"[%s] ", cls.ScrubbedNameCString());
1476 Instruction::PrintOperandsTo(f);
1479void StoreIndexedInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1482 if (!cls.IsNull()) {
1483 f->Printf(
"[%s] ", cls.ScrubbedNameCString());
1487 Instruction::PrintOperandsTo(f);
1489 f->AddString(
", NoStoreBarrier");
1493void MemoryCopyInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1494 Instruction::PrintOperandsTo(f);
1497 if (!cls.IsNull()) {
1498 f->Printf(
", dest_cid=%s (%d)", cls.ScrubbedNameCString(), dest_cid_);
1500 f->Printf(
", dest_cid=%d", dest_cid_);
1502 if (
dest()->definition()->representation() == kUntagged) {
1503 f->Printf(
" [untagged]");
1506 if (!cls.IsNull()) {
1507 f->Printf(
", src_cid=%s (%d)", cls.ScrubbedNameCString(), src_cid_);
1509 f->Printf(
", src_cid=%d", src_cid_);
1511 if (
src()->definition()->representation() == kUntagged) {
1512 f->Printf(
" [untagged]");
1518 f->AddString(
", unboxed_inputs");
1521 f->AddString(
", can_overlap");
1525void TailCallInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1526 const char*
name =
"<unknown code>";
1527 if (code_.IsStubCode()) {
1531 if (owner.IsFunction()) {
1533 .ToFullyQualifiedCString();
1536 f->Printf(
"%s(",
name);
1541void Call1ArgStubInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1542 const char*
name =
"";
1545 name =
"CloneSuspendState";
1551 name =
"InitAsyncStar";
1554 name =
"InitSyncStar";
1557 name =
"FfiAsyncCallbackSend";
1560 f->Printf(
"%s(",
name);
1565void SuspendInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1566 const char*
name =
"";
1572 name =
"AwaitWithTypeCheck";
1575 name =
"YieldAsyncStar";
1578 name =
"SuspendSyncStarAtStart";
1581 name =
"SuspendSyncStarAtYield";
1584 f->Printf(
"%s(",
name);
1585 Definition::PrintOperandsTo(f);
1589void MoveArgumentInstr::PrintOperandsTo(BaseTextBuffer* f)
const {
1590 f->Printf(
"%s <- ",
location().ToCString());
1591 value()->PrintTo(f);
1594void GotoInstr::PrintTo(BaseTextBuffer* f)
const {
1600 f->Printf(
"goto:%" Pd " B%" Pd "", GetDeoptId(),
successor()->block_id());
1606void IndirectGotoInstr::PrintTo(BaseTextBuffer* f)
const {
1608 f->Printf(
"igoto:%" Pd "(", GetDeoptId());
1610 f->AddString(
"igoto:(");
1616void BranchInstr::PrintTo(BaseTextBuffer* f)
const {
1618 f->AddString(
"if ");
1625void ParallelMoveInstr::PrintTo(BaseTextBuffer* f)
const {
1626 f->Printf(
"%s ", DebugName());
1627 for (intptr_t i = 0; i < moves_.length(); i++) {
1628 if (i != 0)
f->AddString(
", ");
1629 moves_[i]->dest().PrintTo(f);
1630 f->AddString(
" <- ");
1631 moves_[i]->src().PrintTo(f);
1635void Utf8ScanInstr::PrintTo(BaseTextBuffer* f)
const {
1636 Definition::PrintTo(f);
1637 f->Printf(
" [%s]", scan_flags_field_.Name());
1641 f->AddString(
" env={ ");
1643 for (intptr_t i = 0; i < values_.
length(); ++i) {
1644 if (i > 0)
f->AddString(
", ");
1645 if (values_[i]->definition()->IsMoveArgument()) {
1646 f->Printf(
"a%d", arg_count++);
1648 values_[i]->PrintTo(f);
1650 if ((locations_ !=
nullptr) && !locations_[i].IsInvalid()) {
1657 if (outer_ !=
nullptr) outer_->
PrintTo(f);
1662 BufferFormatter bf(
buffer, 1024);
1674 bool print_locations) {
1688 bool print_locations) {
1697 intptr_t num_checks_to_print) {
1703 uint8_t** compiler_pass_filter ) {
static int block_count(const SkSBlockAllocator< N > &pool)
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
#define ASSERT_EQUAL(expected, actual)
intptr_t num_context_variables() const
const Class & cls() const
virtual intptr_t InputCount() const
intptr_t num_context_variables() const
virtual AliasIdentity Identity() const
const String & dst_name() const
Value * function_type_arguments() const
Value * instantiator_type_arguments() const
Value * function_type_arguments() const
Value * super_type() const
Value * instantiator_type_arguments() const
Token::Kind op_kind() const
bool can_overflow() const
Token::Kind op_kind() const
bool is_truncating() const
Representation to() const
Representation from() const
intptr_t try_index() const
ParallelMoveInstr * parallel_move() const
bool HasParallelMove() const
intptr_t block_id() const
intptr_t stack_depth() const
void PrintInitialDefinitionsTo(BaseTextBuffer *f) const
TargetEntryInstr * false_successor() const
TargetEntryInstr * true_successor() const
ComparisonInstr * comparison() const
const Function & function() const
intptr_t index_scale() const
intptr_t catch_try_index() const
const CidRangeValue & cids() const
ComparisonInstr * comparison() const
ExceptionType exception_type() const
intptr_t stack_depth() const
intptr_t loop_depth() const
ClassPtr At(intptr_t cid) const
void PrintTo(BaseTextBuffer *f) const
const Object & value() const
Range * constraint() const
intptr_t ssa_temp_index() const
static constexpr intptr_t kNone
const Function & interface_target() const
MethodRecognizer::Kind op_kind() const
intptr_t num_temps() const
void PrintTo(BaseTextBuffer *f) const
const char * ToCString() const
intptr_t CompoundReturnTypedDataIndex() const
intptr_t TargetAddressIndex() const
static DART_FORCE_INLINE bool HasLifetimePosition(Instruction *instr)
static DART_FORCE_INLINE intptr_t GetLifetimePosition(const Instruction *instr)
static void PrintOneInstruction(Instruction *instr, bool print_locations)
static void PrintGraph(const char *phase, FlowGraph *flow_graph)
static void PrintCidRangeData(const CallTargets &ic_data, intptr_t num_checks_to_print=kPrintAll)
static bool ShouldPrint(const Function &function, uint8_t **compiler_pass_filter=nullptr)
static void PrintBlock(BlockEntryInstr *block, bool print_locations)
static constexpr intptr_t kPrintAll
FlowGraphPrinter(const FlowGraph &flow_graph, bool print_locations=false)
void PrintInstruction(Instruction *instr)
static void PrintICData(const ICData &ic_data, intptr_t num_checks_to_print=kPrintAll)
static void PrintTypeCheck(const ParsedFunction &parsed_function, TokenPosition token_pos, Value *value, const AbstractType &dst_type, const String &dst_name, bool eliminated)
const char * ToFullyQualifiedCString() const
static const char * KindToCString(UntaggedFunction::Kind kind)
bool HasSavedArgumentsDescriptor() const
UntaggedFunction::Kind kind() const
ArrayPtr saved_args_desc() const
ParallelMoveInstr * parallel_move() const
bool HasParallelMove() const
JoinEntryInstr * successor() const
const Field & field() const
ComparisonInstr * comparison() const
CompileType * result_type() const
Code::EntryKind entry_kind() const
const ICData * ic_data() const
const String & function_name() const
const AbstractType & type() const
Value * function_type_arguments() const
Value * instantiator_type_arguments() const
Value * type_arguments() const
Value * instantiator_type_arguments() const
Value * function_type_arguments() const
const Class & instantiator_class() const
Value * function_type_arguments() const
const AbstractType & type() const
Value * instantiator_type_arguments() const
virtual intptr_t InputCount() const =0
intptr_t GetDeoptId() const
virtual Value * InputAt(intptr_t i) const =0
const char * ToCString() const
virtual Representation representation() const
Value * ArgumentValueAt(intptr_t index) const
virtual const char * DebugName() const =0
bool is_truncating() const
Representation to() const
Representation from() const
static IsolateGroup * Current()
ClassTable * class_table() const
GrowableArray< BlockEntryInstr * > predecessors_
intptr_t TargetAddressIndex() const
const Slot & slot() const
bool IsImmutableLoad() const
InnerPointerAccess loads_inner_pointer() const
intptr_t class_id() const
Register base_reg() const
const LocalVariable & local() const
const Field & field() const
void PrintTo(BaseTextBuffer *f) const
bool unboxed_inputs() const
intptr_t element_size() const
static const char * KindToCString(Kind kind)
Location location() const
const String & native_name() const
virtual Value * InputAt(intptr_t i) const
virtual const char * ToCString() const
static ObjectPtr RawCast(ObjectPtr obj)
const Location & location() const
virtual Representation representation() const
const char * ToCString() const
void PrintTo(BaseTextBuffer *f) const
static const char * ToCString(const Range *range)
void PrintTo(BaseTextBuffer *f) const
static const char * RegisterName(Register reg)
virtual intptr_t InputCount() const
virtual Value * InputAt(intptr_t i) const
CompileType * result_type() const
const Function & function() const
Code::EntryKind entry_kind() const
InnerPointerAccess stores_inner_pointer() const
const Slot & slot() const
bool ShouldEmitStoreBarrier() const
intptr_t class_id() const
Register base_reg() const
const LocalVariable & local() const
const Field & field() const
bool needs_number_check() const
static const char * NameOfStub(uword entry_point)
@ kSuspendSyncStarAtYield
@ kSuspendSyncStarAtStart
virtual intptr_t InputCount() const
intptr_t type_args_len() const
intptr_t ArgumentCount() const
virtual Value * InputAt(intptr_t i) const
bool calls_initializer() const
const ZoneGrowableArray< intptr_t > & cid_results() const
static Thread * Current()
static const char * Str(Kind tok)
Token::Kind op_kind() const
Token::Kind op_kind() const
bool is_truncating() const
Definition * definition() const
const char * ToCString() const
intptr_t InputCount() const
Value * InputAt(intptr_t i) const
char * MakeCopyOfString(const char *str)
ElementType * Alloc(intptr_t length)
#define THR_Print(format,...)
static const uint8_t buffer[]
void PrintTo(FlValue *v, std::ostream *os)
#define DECLARE_FLAG(type, name)
#define DEFINE_FLAG(type, name, default_value, comment)
Dart_NativeFunction function
#define CASE(Arity, Mask, Name, Args, Result)
#define DECLARE_VISIT_INSTRUCTION(ShortName, Attrs)
#define FOR_EACH_INSTRUCTION(M)
#define SIMD_OP_LIST(M, BINARY_OP)
const intptr_t kResultIndex
DART_EXPORT bool IsNull(Dart_Handle object)
static constexpr intptr_t kInvalidTryIndex
static const char * ToCString(Representation rep)