52cb60b34e
Previously, ComparisonInstr base class represented arbitrary conditions used in Branch, IfThenElse and CheckCondition instructions and included subclasses TestInt, TestCids, TestRange and unary DoubleTestOp which are not comparisons. So this refactoring renames ComparisonInstr to ConditionInstr. In addition, a new Comparison instruction is added as a base class for StrictCompare, EqualityCompare and RelationalOp. TEST=ci (pure refactoring) Change-Id: Ic8756ee5913ff2bc974c95cea8004370c9f5527f Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/393420 Reviewed-by: Slava Egorov <vegorov@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
1721 lines
52 KiB
C++
1721 lines
52 KiB
C++
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "vm/compiler/backend/il_printer.h"
|
|
|
|
#include <tuple>
|
|
|
|
#include "vm/class_id.h"
|
|
#include "vm/compiler/api/print_filter.h"
|
|
#include "vm/compiler/backend/il.h"
|
|
#include "vm/compiler/backend/linearscan.h"
|
|
#include "vm/compiler/backend/range_analysis.h"
|
|
#include "vm/compiler/ffi/native_calling_convention.h"
|
|
#include "vm/os.h"
|
|
#include "vm/parser.h"
|
|
|
|
namespace dart {
|
|
|
|
#if defined(INCLUDE_IL_PRINTER)
|
|
DEFINE_FLAG(bool,
|
|
display_sorted_ic_data,
|
|
false,
|
|
"Calls display a unary, sorted-by count form of ICData");
|
|
DEFINE_FLAG(bool, print_environments, false, "Print SSA environments.");
|
|
DEFINE_FLAG(bool,
|
|
print_flow_graph_as_json,
|
|
false,
|
|
"Use machine readable output when printing IL graphs.");
|
|
DEFINE_FLAG(bool, print_redundant_il, false, "Print redundant IL instructions");
|
|
|
|
DECLARE_FLAG(bool, trace_inlining_intervals);
|
|
|
|
static bool IsRedundant(Instruction* instr) {
|
|
if (auto constant = instr->AsConstant()) {
|
|
return !constant->HasUses();
|
|
} else if (auto move = instr->AsParallelMove()) {
|
|
return move->IsRedundant();
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool ShouldPrintInstruction(Instruction* instr) {
|
|
return FLAG_print_redundant_il || !IsRedundant(instr);
|
|
}
|
|
|
|
class IlTestPrinter : public AllStatic {
|
|
public:
|
|
static void PrintGraph(const char* phase, FlowGraph* flow_graph) {
|
|
JSONWriter writer;
|
|
writer.OpenObject();
|
|
writer.PrintProperty("p", phase);
|
|
writer.PrintProperty("f", flow_graph->function().ToFullyQualifiedCString());
|
|
writer.OpenArray("b");
|
|
for (auto block : flow_graph->reverse_postorder()) {
|
|
PrintBlock(&writer, block);
|
|
}
|
|
writer.CloseArray();
|
|
const auto& codegen_order = *flow_graph->CodegenBlockOrder();
|
|
if (!codegen_order.is_empty() &&
|
|
(&codegen_order != &flow_graph->reverse_postorder())) {
|
|
writer.OpenArray("cbo");
|
|
const auto block_count = flow_graph->reverse_postorder().length();
|
|
for (auto block : codegen_order) {
|
|
writer.PrintValue64((block_count - 1) - block->postorder_number());
|
|
}
|
|
writer.CloseArray();
|
|
}
|
|
writer.OpenObject("desc");
|
|
AttributesSerializer(&writer).WriteDescriptors();
|
|
writer.CloseObject();
|
|
writer.OpenObject("flags");
|
|
writer.PrintPropertyBool("nnbd", true);
|
|
writer.CloseObject();
|
|
writer.CloseObject();
|
|
THR_Print("%s\n", writer.ToCString());
|
|
}
|
|
|
|
static void PrintBlock(JSONWriter* writer, BlockEntryInstr* block) {
|
|
writer->OpenObject();
|
|
writer->PrintProperty64("b", block->block_id());
|
|
writer->PrintProperty("o", block->DebugName());
|
|
if (auto block_with_defs = block->AsBlockEntryWithInitialDefs()) {
|
|
if (block_with_defs->initial_definitions() != nullptr &&
|
|
block_with_defs->initial_definitions()->length() > 0) {
|
|
writer->OpenArray("d");
|
|
for (auto defn : *block_with_defs->initial_definitions()) {
|
|
if (ShouldPrintInstruction(defn)) {
|
|
PrintInstruction(writer, defn);
|
|
}
|
|
}
|
|
writer->CloseArray();
|
|
}
|
|
}
|
|
writer->OpenArray("is");
|
|
if (auto join = block->AsJoinEntry()) {
|
|
for (PhiIterator it(join); !it.Done(); it.Advance()) {
|
|
if (ShouldPrintInstruction(it.Current())) {
|
|
PrintInstruction(writer, it.Current());
|
|
}
|
|
}
|
|
}
|
|
for (auto instr : block->instructions()) {
|
|
if (instr->ArgumentCount() != 0 && instr->GetMoveArguments() != nullptr) {
|
|
for (auto move_arg : *(instr->GetMoveArguments())) {
|
|
PrintInstruction(writer, move_arg);
|
|
}
|
|
}
|
|
if (ShouldPrintInstruction(instr) && !instr->IsMoveArgument()) {
|
|
PrintInstruction(writer, instr);
|
|
}
|
|
}
|
|
writer->CloseArray();
|
|
writer->CloseObject();
|
|
}
|
|
|
|
static void PrintInstruction(JSONWriter* writer,
|
|
Instruction* instr,
|
|
const char* name = nullptr) {
|
|
writer->OpenObject(name);
|
|
if (auto defn = instr->AsDefinition()) {
|
|
if (defn->ssa_temp_index() != -1) {
|
|
writer->PrintProperty("v", defn->ssa_temp_index());
|
|
}
|
|
|
|
if (defn->HasType()) {
|
|
writer->OpenObject("T");
|
|
defn->Type()->PrintTo(writer);
|
|
writer->CloseObject();
|
|
}
|
|
}
|
|
writer->PrintProperty("o", instr->DebugName());
|
|
if (auto branch = instr->AsBranch()) {
|
|
PrintInstruction(writer, branch->condition(), "cc");
|
|
} else {
|
|
if (instr->InputCount() != 0) {
|
|
writer->OpenArray("i");
|
|
for (intptr_t i = 0; i < instr->InputCount(); i++) {
|
|
writer->PrintValue(instr->InputAt(i)->definition()->ssa_temp_index());
|
|
}
|
|
writer->CloseArray();
|
|
} else if (instr->ArgumentCount() != 0 &&
|
|
instr->GetMoveArguments() != nullptr) {
|
|
writer->OpenArray("i");
|
|
for (intptr_t i = 0; i < instr->ArgumentCount(); i++) {
|
|
writer->PrintValue(
|
|
instr->ArgumentValueAt(i)->definition()->ssa_temp_index());
|
|
}
|
|
writer->CloseArray();
|
|
}
|
|
AttributesSerializer serializer(writer);
|
|
instr->Accept(&serializer);
|
|
}
|
|
if (instr->SuccessorCount() > 0) {
|
|
writer->OpenArray("s");
|
|
for (auto succ : instr->successors()) {
|
|
writer->PrintValue(succ->block_id());
|
|
}
|
|
writer->CloseArray();
|
|
}
|
|
writer->CloseObject();
|
|
}
|
|
|
|
template <typename T>
|
|
class HasGetAttributes {
|
|
template <typename U>
|
|
static std::true_type test(decltype(&U::GetAttributes));
|
|
template <typename U>
|
|
static std::false_type test(...);
|
|
|
|
public:
|
|
static constexpr bool value = decltype(test<T>(nullptr))::value;
|
|
};
|
|
|
|
class AttributesSerializer : public InstructionVisitor {
|
|
public:
|
|
explicit AttributesSerializer(JSONWriter* writer) : writer_(writer) {}
|
|
|
|
void WriteDescriptors() {
|
|
#define DECLARE_VISIT_INSTRUCTION(ShortName, Attrs) \
|
|
WriteDescriptor<ShortName##Instr>(#ShortName);
|
|
|
|
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
|
|
|
|
#undef DECLARE_VISIT_INSTRUCTION
|
|
}
|
|
|
|
#define DECLARE_VISIT_INSTRUCTION(ShortName, Attrs) \
|
|
virtual void Visit##ShortName(ShortName##Instr* instr) { Write(instr); }
|
|
|
|
FOR_EACH_CONCRETE_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
|
|
|
|
#undef DECLARE_VISIT_INSTRUCTION
|
|
|
|
private:
|
|
void WriteAttribute(const char* value) { writer_->PrintValue(value); }
|
|
|
|
void WriteAttribute(intptr_t value) { writer_->PrintValue(value); }
|
|
|
|
void WriteAttribute(bool value) { writer_->PrintValueBool(value); }
|
|
|
|
void WriteAttribute(Token::Kind kind) {
|
|
writer_->PrintValue(Token::Str(kind));
|
|
}
|
|
|
|
void WriteAttribute(Representation rep) {
|
|
writer_->PrintValue(RepresentationUtils::ToCString(rep));
|
|
}
|
|
|
|
static const char* LocationKindAsString(const Location& loc) {
|
|
if (loc.IsConstant()) {
|
|
return "C";
|
|
} else if (loc.IsPairLocation()) {
|
|
auto pair = loc.AsPairLocation();
|
|
return Thread::Current()->zone()->PrintToString(
|
|
"(%s, %s)", LocationKindAsString(pair->At(0)),
|
|
LocationKindAsString(pair->At(0)));
|
|
} else {
|
|
switch (loc.kind()) {
|
|
case Location::kUnallocated:
|
|
return ".";
|
|
case Location::kStackSlot:
|
|
return "stack(word)";
|
|
case Location::kDoubleStackSlot:
|
|
return "stack(f64)";
|
|
case Location::kQuadStackSlot:
|
|
return "stack(f128)";
|
|
case Location::kRegister:
|
|
return "reg(cpu)";
|
|
case Location::kFpuRegister:
|
|
return "reg(fpu)";
|
|
default:
|
|
return "?";
|
|
}
|
|
}
|
|
}
|
|
|
|
void WriteAttribute(const Location& loc) {
|
|
writer_->PrintValue(LocationKindAsString(loc));
|
|
}
|
|
|
|
void WriteAttribute(const Slot* slot) { writer_->PrintValue(slot->Name()); }
|
|
|
|
void WriteAttribute(const Function* function) {
|
|
writer_->PrintValue(function->QualifiedUserVisibleNameCString());
|
|
}
|
|
|
|
void WriteAttribute(const Object* obj) {
|
|
if (obj->IsNull()) {
|
|
writer_->PrintValueNull();
|
|
} else if (obj->IsBool()) {
|
|
writer_->PrintValueBool(Bool::Cast(*obj).value());
|
|
} else if (obj->IsInteger()) {
|
|
auto value = Integer::Cast(*obj).Value();
|
|
// PrintValue64 and PrintValue will check if integer is representable
|
|
// as a JS number, which is too strict. We don't actually need
|
|
// such checks because we only load resulting JSON in Dart.
|
|
writer_->buffer()->Printf("%" Pd64 "", value);
|
|
} else if (obj->IsString()) {
|
|
const auto& str = String::Cast(*obj);
|
|
writer_->PrintValueStr(str, 0, str.Length());
|
|
} else {
|
|
const auto& cls = Class::Handle(obj->clazz());
|
|
writer_->PrintfValue("Instance of %s", cls.UserVisibleNameCString());
|
|
}
|
|
}
|
|
|
|
template <typename... Ts>
|
|
void WriteTuple(const std::tuple<Ts...>& tuple) {
|
|
std::apply(
|
|
[&](Ts const&... elements) { (WriteAttribute(elements), ...); },
|
|
tuple);
|
|
}
|
|
|
|
template <typename T,
|
|
typename = typename std::enable_if_t<HasGetAttributes<T>::value>>
|
|
void Write(T* instr) {
|
|
writer_->OpenArray("d");
|
|
WriteTuple(instr->GetAttributes());
|
|
writer_->CloseArray();
|
|
}
|
|
|
|
void Write(Instruction* instr) {
|
|
// Default, do nothing.
|
|
}
|
|
|
|
void WriteAttributeName(const char* str) {
|
|
ASSERT(str != nullptr);
|
|
// To simplify the declaring side, we assume the string might be directly
|
|
// stringized from one of the following expression forms:
|
|
//
|
|
// * &name()
|
|
// * name()
|
|
// * name_
|
|
//
|
|
// Remove the non-name parts of the above before printing.
|
|
const intptr_t start = str[0] == '&' ? 1 : 0;
|
|
intptr_t end = strlen(str);
|
|
switch (str[end - 1]) {
|
|
case ')':
|
|
ASSERT(end >= 2);
|
|
ASSERT_EQUAL(str[end - 2], '(');
|
|
end -= 2;
|
|
break;
|
|
case '_':
|
|
// Strip off the final _ from a direct private field access.
|
|
end -= 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
writer_->PrintValue(str + start, end - start);
|
|
}
|
|
|
|
template <typename... Ts>
|
|
void WriteAttributeNames(const std::tuple<Ts...>& tuple) {
|
|
std::apply(
|
|
[&](Ts const&... elements) { (WriteAttributeName(elements), ...); },
|
|
tuple);
|
|
}
|
|
|
|
template <typename T>
|
|
void WriteDescriptor(
|
|
const char* name,
|
|
typename std::enable_if_t<HasGetAttributes<T>::value>* = nullptr) {
|
|
writer_->OpenArray(name);
|
|
WriteAttributeNames(T::GetAttributeNames());
|
|
writer_->CloseArray();
|
|
}
|
|
|
|
template <typename T>
|
|
void WriteDescriptor(
|
|
const char* name,
|
|
typename std::enable_if_t<!HasGetAttributes<T>::value>* = nullptr) {}
|
|
|
|
JSONWriter* writer_;
|
|
};
|
|
};
|
|
|
|
bool FlowGraphPrinter::ShouldPrint(
|
|
const Function& function,
|
|
uint8_t** compiler_pass_filter /* = nullptr */) {
|
|
return compiler::PrintFilter::ShouldPrint(function, compiler_pass_filter);
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintGraph(const char* phase, FlowGraph* flow_graph) {
|
|
LogBlock lb;
|
|
if (FLAG_print_flow_graph_as_json) {
|
|
IlTestPrinter::PrintGraph(phase, flow_graph);
|
|
} else {
|
|
THR_Print("*** BEGIN CFG\n%s\n", phase);
|
|
FlowGraphPrinter printer(*flow_graph);
|
|
printer.PrintBlocks();
|
|
THR_Print("*** END CFG\n");
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintBlock(BlockEntryInstr* block,
|
|
bool print_locations) {
|
|
// Print the block entry.
|
|
PrintOneInstruction(block, print_locations);
|
|
THR_Print("\n");
|
|
// And all the successors in the block.
|
|
for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
|
|
Instruction* current = it.Current();
|
|
|
|
// Skip redundant parallel moves.
|
|
if (!ShouldPrintInstruction(current)) {
|
|
continue;
|
|
}
|
|
|
|
PrintOneInstruction(current, print_locations);
|
|
THR_Print("\n");
|
|
}
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintBlocks() {
|
|
if (!function_.IsNull()) {
|
|
THR_Print("==== %s (%s", function_.ToFullyQualifiedCString(),
|
|
Function::KindToCString(function_.kind()));
|
|
// Output saved arguments descriptor information for dispatchers that
|
|
// have it, so it's easy to see which dispatcher this graph represents.
|
|
if (function_.HasSavedArgumentsDescriptor()) {
|
|
const auto& args_desc_array = Array::Handle(function_.saved_args_desc());
|
|
const ArgumentsDescriptor args_desc(args_desc_array);
|
|
THR_Print(", %s", args_desc.ToCString());
|
|
}
|
|
THR_Print(")\n");
|
|
}
|
|
|
|
for (intptr_t i = 0; i < block_order_.length(); ++i) {
|
|
PrintBlock(block_order_[i], print_locations_);
|
|
}
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintInstruction(Instruction* instr) {
|
|
PrintOneInstruction(instr, print_locations_);
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintOneInstruction(Instruction* instr,
|
|
bool print_locations) {
|
|
char str[4000];
|
|
BufferFormatter f(str, sizeof(str));
|
|
if (FlowGraphAllocator::HasLifetimePosition(instr)) {
|
|
f.Printf("%3" Pd ": ", FlowGraphAllocator::GetLifetimePosition(instr));
|
|
}
|
|
if (!instr->IsBlockEntry()) {
|
|
f.Printf(" ");
|
|
}
|
|
if (auto* const block = instr->AsBlockEntryWithInitialDefs()) {
|
|
block->PrintBlockHeaderTo(&f);
|
|
// Output and clear the buffer after each internal definition, as otherwise
|
|
// too many internal definitions could cause truncation in the output.
|
|
auto callback = [](BaseTextBuffer* f) {
|
|
THR_Print("%s", f->buffer());
|
|
f->Clear();
|
|
};
|
|
block->PrintInitialDefinitionsTo(&f, callback);
|
|
} else {
|
|
instr->PrintTo(&f);
|
|
}
|
|
if (FLAG_print_environments && (instr->env() != nullptr)) {
|
|
instr->env()->PrintTo(&f);
|
|
}
|
|
if (print_locations && (instr->HasLocs())) {
|
|
instr->locs()->PrintTo(&f);
|
|
}
|
|
if (FLAG_trace_inlining_intervals) {
|
|
f.Printf(" iid: %" Pd "", instr->inlining_id());
|
|
}
|
|
THR_Print("%s", f.buffer());
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintTypeCheck(const ParsedFunction& parsed_function,
|
|
TokenPosition token_pos,
|
|
Value* value,
|
|
const AbstractType& dst_type,
|
|
const String& dst_name,
|
|
bool eliminated) {
|
|
const char* compile_type_name = "unknown";
|
|
if (value != nullptr && value->reaching_type_ != nullptr) {
|
|
compile_type_name = value->reaching_type_->ToCString();
|
|
}
|
|
THR_Print(
|
|
"%s type check: compile type %s is %s specific than "
|
|
"type '%s' of '%s'.\n",
|
|
eliminated ? "Eliminated" : "Generated", compile_type_name,
|
|
eliminated ? "more" : "not more", dst_type.NameCString(),
|
|
dst_name.ToCString());
|
|
}
|
|
|
|
static void PrintTargetsHelper(BaseTextBuffer* f,
|
|
const CallTargets& targets,
|
|
intptr_t num_checks_to_print) {
|
|
f->AddString(" Targets[");
|
|
f->Printf("%" Pd ": ", targets.length());
|
|
Function& target = Function::Handle();
|
|
if ((num_checks_to_print == FlowGraphPrinter::kPrintAll) ||
|
|
(num_checks_to_print > targets.length())) {
|
|
num_checks_to_print = targets.length();
|
|
}
|
|
for (intptr_t i = 0; i < num_checks_to_print; i++) {
|
|
const CidRange& range = targets[i];
|
|
const auto target_info = targets.TargetAt(i);
|
|
const intptr_t count = target_info->count;
|
|
target = target_info->target->ptr();
|
|
if (i > 0) {
|
|
f->AddString(" | ");
|
|
}
|
|
if (range.IsSingleCid()) {
|
|
const Class& cls = Class::Handle(
|
|
IsolateGroup::Current()->class_table()->At(range.cid_start));
|
|
f->Printf("%s", String::Handle(cls.Name()).ToCString());
|
|
f->Printf(" cid %" Pd " cnt:%" Pd " trgt:'%s'", range.cid_start, count,
|
|
target.ToQualifiedCString());
|
|
} else {
|
|
const Class& cls = Class::Handle(target.Owner());
|
|
f->Printf("cid %" Pd "-%" Pd " %s", range.cid_start, range.cid_end,
|
|
String::Handle(cls.Name()).ToCString());
|
|
f->Printf(" cnt:%" Pd " trgt:'%s'", count, target.ToQualifiedCString());
|
|
}
|
|
|
|
if (target_info->exactness.IsTracking()) {
|
|
f->Printf(" %s", target_info->exactness.ToCString());
|
|
}
|
|
}
|
|
if (num_checks_to_print < targets.length()) {
|
|
f->AddString("...");
|
|
}
|
|
f->AddString("]");
|
|
}
|
|
|
|
static void PrintCidsHelper(BaseTextBuffer* f,
|
|
const Cids& targets,
|
|
intptr_t num_checks_to_print) {
|
|
f->AddString(" Cids[");
|
|
f->Printf("%" Pd ": ", targets.length());
|
|
if ((num_checks_to_print == FlowGraphPrinter::kPrintAll) ||
|
|
(num_checks_to_print > targets.length())) {
|
|
num_checks_to_print = targets.length();
|
|
}
|
|
for (intptr_t i = 0; i < num_checks_to_print; i++) {
|
|
const CidRange& range = targets[i];
|
|
if (i > 0) {
|
|
f->AddString(" | ");
|
|
}
|
|
const Class& cls = Class::Handle(
|
|
IsolateGroup::Current()->class_table()->At(range.cid_start));
|
|
f->Printf("%s etc. ", String::Handle(cls.Name()).ToCString());
|
|
if (range.IsSingleCid()) {
|
|
f->Printf(" cid %" Pd, range.cid_start);
|
|
} else {
|
|
f->Printf(" cid %" Pd "-%" Pd, range.cid_start, range.cid_end);
|
|
}
|
|
}
|
|
if (num_checks_to_print < targets.length()) {
|
|
f->AddString("...");
|
|
}
|
|
f->AddString("]");
|
|
}
|
|
|
|
static void PrintICDataHelper(BaseTextBuffer* f,
|
|
const ICData& ic_data,
|
|
intptr_t num_checks_to_print) {
|
|
f->AddString(" IC[");
|
|
if (ic_data.is_tracking_exactness()) {
|
|
f->Printf(
|
|
"(%s) ",
|
|
AbstractType::Handle(ic_data.receivers_static_type()).ToCString());
|
|
}
|
|
f->Printf("%" Pd ": ", ic_data.NumberOfChecks());
|
|
Function& target = Function::Handle();
|
|
if ((num_checks_to_print == FlowGraphPrinter::kPrintAll) ||
|
|
(num_checks_to_print > ic_data.NumberOfChecks())) {
|
|
num_checks_to_print = ic_data.NumberOfChecks();
|
|
}
|
|
for (intptr_t i = 0; i < num_checks_to_print; i++) {
|
|
GrowableArray<intptr_t> class_ids;
|
|
ic_data.GetCheckAt(i, &class_ids, &target);
|
|
const intptr_t count = ic_data.GetCountAt(i);
|
|
if (i > 0) {
|
|
f->AddString(" | ");
|
|
}
|
|
for (intptr_t k = 0; k < class_ids.length(); k++) {
|
|
if (k > 0) {
|
|
f->AddString(", ");
|
|
}
|
|
const Class& cls = Class::Handle(
|
|
IsolateGroup::Current()->class_table()->At(class_ids[k]));
|
|
f->Printf("%s", String::Handle(cls.Name()).ToCString());
|
|
}
|
|
f->Printf(" cnt:%" Pd " trgt:'%s'", count, target.ToQualifiedCString());
|
|
if (ic_data.is_tracking_exactness()) {
|
|
f->Printf(" %s", ic_data.GetExactnessAt(i).ToCString());
|
|
}
|
|
}
|
|
if (num_checks_to_print < ic_data.NumberOfChecks()) {
|
|
f->AddString("...");
|
|
}
|
|
f->AddString("]");
|
|
}
|
|
|
|
static void PrintICDataSortedHelper(BaseTextBuffer* f,
|
|
const ICData& ic_data_orig) {
|
|
const ICData& ic_data =
|
|
ICData::Handle(ic_data_orig.AsUnaryClassChecksSortedByCount());
|
|
f->Printf(" IC[n:%" Pd "; ", ic_data.NumberOfChecks());
|
|
for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
|
|
const intptr_t count = ic_data.GetCountAt(i);
|
|
const intptr_t cid = ic_data.GetReceiverClassIdAt(i);
|
|
const Class& cls =
|
|
Class::Handle(IsolateGroup::Current()->class_table()->At(cid));
|
|
f->Printf("%s : %" Pd ", ", String::Handle(cls.Name()).ToCString(), count);
|
|
}
|
|
f->AddString("]");
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintICData(const ICData& ic_data,
|
|
intptr_t num_checks_to_print) {
|
|
char buffer[1024];
|
|
BufferFormatter f(buffer, sizeof(buffer));
|
|
PrintICDataHelper(&f, ic_data, num_checks_to_print);
|
|
THR_Print("%s ", buffer);
|
|
const Array& a = Array::Handle(ic_data.arguments_descriptor());
|
|
THR_Print(" arg-desc %" Pd "\n", a.Length());
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintCidRangeData(const CallTargets& targets,
|
|
intptr_t num_checks_to_print) {
|
|
char buffer[1024];
|
|
BufferFormatter f(buffer, sizeof(buffer));
|
|
PrintTargetsHelper(&f, targets, num_checks_to_print);
|
|
THR_Print("%s ", buffer);
|
|
// TODO(erikcorry): Print args descriptor.
|
|
}
|
|
|
|
static void PrintUse(BaseTextBuffer* f, const Definition& definition) {
|
|
if (definition.HasSSATemp()) {
|
|
f->Printf("v%" Pd "", definition.ssa_temp_index());
|
|
} else if (definition.HasTemp()) {
|
|
f->Printf("t%" Pd "", definition.temp_index());
|
|
}
|
|
}
|
|
|
|
const char* Instruction::ToCString() const {
|
|
char buffer[1024];
|
|
BufferFormatter f(buffer, sizeof(buffer));
|
|
PrintTo(&f);
|
|
return Thread::Current()->zone()->MakeCopyOfString(buffer);
|
|
}
|
|
|
|
void Instruction::PrintTo(BaseTextBuffer* f) const {
|
|
if (GetDeoptId() != DeoptId::kNone) {
|
|
f->Printf("%s:%" Pd "(", DebugName(), GetDeoptId());
|
|
} else {
|
|
f->Printf("%s(", DebugName());
|
|
}
|
|
PrintOperandsTo(f);
|
|
f->AddString(")");
|
|
}
|
|
|
|
void Instruction::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
for (int i = 0; i < InputCount(); ++i) {
|
|
if (i > 0) f->AddString(", ");
|
|
if (InputAt(i) != nullptr) InputAt(i)->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void Definition::PrintTo(BaseTextBuffer* f) const {
|
|
PrintUse(f, *this);
|
|
if (HasSSATemp() || HasTemp()) f->AddString(" <- ");
|
|
if (GetDeoptId() != DeoptId::kNone) {
|
|
f->Printf("%s:%" Pd "(", DebugName(), GetDeoptId());
|
|
} else {
|
|
f->Printf("%s(", DebugName());
|
|
}
|
|
PrintOperandsTo(f);
|
|
f->AddString(")");
|
|
if (range_ != nullptr) {
|
|
f->AddString(" ");
|
|
range_->PrintTo(f);
|
|
}
|
|
|
|
if (representation() != kNoRepresentation && representation() != kTagged) {
|
|
f->Printf(" %s", RepresentationUtils::ToCString(representation()));
|
|
} else if (type_ != nullptr) {
|
|
f->AddString(" ");
|
|
type_->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void CheckNullInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
Definition::PrintOperandsTo(f);
|
|
switch (exception_type()) {
|
|
case kNoSuchMethod:
|
|
f->AddString(", NoSuchMethodError");
|
|
break;
|
|
case kArgumentError:
|
|
f->AddString(", ArgumentError");
|
|
break;
|
|
case kCastError:
|
|
f->AddString(", CastError");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Definition::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
for (int i = 0; i < InputCount(); ++i) {
|
|
if (i > 0) f->AddString(", ");
|
|
if (InputAt(i) != nullptr) {
|
|
InputAt(i)->PrintTo(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
void RedefinitionInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
Definition::PrintOperandsTo(f);
|
|
if (constrained_type_ != nullptr) {
|
|
f->Printf(" ^ %s", constrained_type_->ToCString());
|
|
}
|
|
}
|
|
|
|
void ReachabilityFenceInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
value()->PrintTo(f);
|
|
}
|
|
|
|
const char* Value::ToCString() const {
|
|
char buffer[1024];
|
|
BufferFormatter f(buffer, sizeof(buffer));
|
|
PrintTo(&f);
|
|
return Thread::Current()->zone()->MakeCopyOfString(buffer);
|
|
}
|
|
|
|
void Value::PrintTo(BaseTextBuffer* f) const {
|
|
PrintUse(f, *definition());
|
|
|
|
if ((reaching_type_ != nullptr) && (reaching_type_ != definition()->type_)) {
|
|
f->AddString(" ");
|
|
reaching_type_->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void ConstantInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
const char* cstr = value().ToCString();
|
|
const char* new_line = strchr(cstr, '\n');
|
|
if (new_line == nullptr) {
|
|
f->Printf("#%s", cstr);
|
|
} else {
|
|
const intptr_t pos = new_line - cstr;
|
|
char* buffer = Thread::Current()->zone()->Alloc<char>(pos + 1);
|
|
strncpy(buffer, cstr, pos);
|
|
buffer[pos] = '\0';
|
|
f->Printf("#%s\\n...", buffer);
|
|
}
|
|
}
|
|
|
|
void ConstraintInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
value()->PrintTo(f);
|
|
f->AddString(" ^ ");
|
|
constraint()->PrintTo(f);
|
|
}
|
|
|
|
void Range::PrintTo(BaseTextBuffer* f) const {
|
|
f->AddString("[");
|
|
min_.PrintTo(f);
|
|
f->AddString(", ");
|
|
max_.PrintTo(f);
|
|
f->AddString("]");
|
|
}
|
|
|
|
const char* Range::ToCString(const Range* range) {
|
|
if (range == nullptr) return "[_|_, _|_]";
|
|
|
|
char buffer[256];
|
|
BufferFormatter f(buffer, sizeof(buffer));
|
|
range->PrintTo(&f);
|
|
return Thread::Current()->zone()->MakeCopyOfString(buffer);
|
|
}
|
|
|
|
void RangeBoundary::PrintTo(BaseTextBuffer* f) const {
|
|
switch (kind_) {
|
|
case kSymbol:
|
|
f->Printf("v%" Pd "",
|
|
reinterpret_cast<Definition*>(value_)->ssa_temp_index());
|
|
if (offset_ != 0) f->Printf("%+" Pd64 "", offset_);
|
|
break;
|
|
case kConstant:
|
|
f->Printf("%" Pd64 "", value_);
|
|
break;
|
|
case kUnknown:
|
|
f->AddString("_|_");
|
|
break;
|
|
}
|
|
}
|
|
|
|
const char* RangeBoundary::ToCString() const {
|
|
char buffer[256];
|
|
BufferFormatter f(buffer, sizeof(buffer));
|
|
PrintTo(&f);
|
|
return Thread::Current()->zone()->MakeCopyOfString(buffer);
|
|
}
|
|
|
|
void MakeTempInstr::PrintOperandsTo(BaseTextBuffer* f) const {}
|
|
|
|
void DropTempsInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%" Pd "", num_temps());
|
|
if (value() != nullptr) {
|
|
f->AddString(", ");
|
|
value()->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void AssertAssignableInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
value()->PrintTo(f);
|
|
f->AddString(", ");
|
|
dst_type()->PrintTo(f);
|
|
f->Printf(", '%s',", dst_name().ToCString());
|
|
f->AddString(" instantiator_type_args(");
|
|
instantiator_type_arguments()->PrintTo(f);
|
|
f->AddString("), function_type_args(");
|
|
function_type_arguments()->PrintTo(f);
|
|
f->AddString(")");
|
|
}
|
|
|
|
void AssertSubtypeInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
sub_type()->PrintTo(f);
|
|
f->AddString(", ");
|
|
super_type()->PrintTo(f);
|
|
f->AddString(", ");
|
|
dst_name()->PrintTo(f);
|
|
f->AddString(", instantiator_type_args(");
|
|
instantiator_type_arguments()->PrintTo(f);
|
|
f->AddString("), function_type_args(");
|
|
function_type_arguments()->PrintTo(f);
|
|
f->AddString(")");
|
|
}
|
|
|
|
void ClosureCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
if (FLAG_precompiled_mode) {
|
|
f->AddString(" closure=");
|
|
} else {
|
|
f->AddString(" function=");
|
|
}
|
|
InputAt(InputCount() - 1)->PrintTo(f);
|
|
f->Printf("<%" Pd ">", type_args_len());
|
|
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
|
|
f->AddString(", ");
|
|
ArgumentValueAt(i)->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void InstanceCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf(" %s<%" Pd ">", function_name().ToCString(), type_args_len());
|
|
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
|
|
f->AddString(", ");
|
|
ArgumentValueAt(i)->PrintTo(f);
|
|
}
|
|
if (HasICData()) {
|
|
if (FLAG_display_sorted_ic_data) {
|
|
PrintICDataSortedHelper(f, *ic_data());
|
|
} else {
|
|
PrintICDataHelper(f, *ic_data(), FlowGraphPrinter::kPrintAll);
|
|
}
|
|
}
|
|
if (result_type() != nullptr) {
|
|
f->Printf(", result_type = %s", result_type()->ToCString());
|
|
}
|
|
if (entry_kind() == Code::EntryKind::kUnchecked) {
|
|
f->AddString(" using unchecked entrypoint");
|
|
}
|
|
}
|
|
|
|
void PolymorphicInstanceCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf(" %s<%" Pd ">", function_name().ToCString(), type_args_len());
|
|
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
|
|
f->AddString(", ");
|
|
ArgumentValueAt(i)->PrintTo(f);
|
|
}
|
|
PrintTargetsHelper(f, targets_, FlowGraphPrinter::kPrintAll);
|
|
if (complete()) {
|
|
f->AddString(" COMPLETE");
|
|
}
|
|
if (entry_kind() == Code::EntryKind::kUnchecked) {
|
|
f->AddString(" using unchecked entrypoint");
|
|
}
|
|
}
|
|
|
|
void DispatchTableCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
const String& name =
|
|
String::Handle(interface_target().QualifiedUserVisibleName());
|
|
f->AddString(" cid=");
|
|
class_id()->PrintTo(f);
|
|
f->Printf(" %s<%" Pd ">", name.ToCString(), type_args_len());
|
|
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
|
|
f->AddString(", ");
|
|
ArgumentValueAt(i)->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void StrictCompareInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s, ", Token::Str(kind()));
|
|
left()->PrintTo(f);
|
|
f->AddString(", ");
|
|
right()->PrintTo(f);
|
|
if (needs_number_check()) {
|
|
f->Printf(", with number check");
|
|
}
|
|
}
|
|
|
|
void TestCidsInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
value()->PrintTo(f);
|
|
f->Printf(" %s [", Token::Str(kind()));
|
|
intptr_t length = cid_results().length();
|
|
for (intptr_t i = 0; i < length; i += 2) {
|
|
f->Printf("0x%" Px ":%s ", cid_results()[i],
|
|
cid_results()[i + 1] == 0 ? "false" : "true");
|
|
}
|
|
f->AddString("] ");
|
|
if (CanDeoptimize()) {
|
|
ASSERT(deopt_id() != DeoptId::kNone);
|
|
f->AddString("else deoptimize ");
|
|
} else {
|
|
ASSERT(deopt_id() == DeoptId::kNone);
|
|
f->Printf("else %s ", cid_results()[length - 1] != 0 ? "false" : "true");
|
|
}
|
|
}
|
|
|
|
void TestRangeInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
value()->PrintTo(f);
|
|
f->Printf(" %s [%" Pd "-%" Pd "]", kind() == Token::kIS ? "in" : "not in",
|
|
lower_, upper_);
|
|
}
|
|
|
|
void EqualityCompareInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
left()->PrintTo(f);
|
|
f->Printf(" %s ", Token::Str(kind()));
|
|
right()->PrintTo(f);
|
|
}
|
|
|
|
void StaticCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf(" %s<%" Pd "> ", String::Handle(function().name()).ToCString(),
|
|
type_args_len());
|
|
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
|
|
if (i > 0) f->AddString(", ");
|
|
ArgumentValueAt(i)->PrintTo(f);
|
|
}
|
|
if (entry_kind() == Code::EntryKind::kUnchecked) {
|
|
f->AddString(", using unchecked entrypoint");
|
|
}
|
|
if (function().recognized_kind() != MethodRecognizer::kUnknown) {
|
|
f->Printf(", recognized_kind = %s",
|
|
MethodRecognizer::KindToCString(function().recognized_kind()));
|
|
}
|
|
if (result_type() != nullptr) {
|
|
f->Printf(", result_type = %s", result_type()->ToCString());
|
|
}
|
|
}
|
|
|
|
void CachableIdempotentCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf(" %s<%" Pd "> ", String::Handle(function().name()).ToCString(),
|
|
type_args_len());
|
|
for (intptr_t i = 0; i < ArgumentCount(); ++i) {
|
|
if (i > 0) f->AddString(", ");
|
|
ArgumentValueAt(i)->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void LoadLocalInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s @%d", local().name().ToCString(), local().index().value());
|
|
}
|
|
|
|
void StoreLocalInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s @%d, ", local().name().ToCString(), local().index().value());
|
|
value()->PrintTo(f);
|
|
}
|
|
|
|
void NativeCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s", native_name().ToCString());
|
|
}
|
|
|
|
void GuardFieldInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s %s, ", String::Handle(field().name()).ToCString(),
|
|
field().GuardedPropertiesAsCString());
|
|
value()->PrintTo(f);
|
|
}
|
|
|
|
void StoreFieldInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
instance()->PrintTo(f);
|
|
f->Printf(" . %s = ", slot().Name());
|
|
value()->PrintTo(f);
|
|
if (slot().representation() != kTagged) {
|
|
f->Printf(" <%s>", RepresentationUtils::ToCString(slot().representation()));
|
|
}
|
|
|
|
// Here, we just print the value of the enum field. We would prefer to get
|
|
// the final decision on whether a store barrier will be emitted by calling
|
|
// ShouldEmitStoreBarrier(), but that can change parts of the flow graph.
|
|
if (emit_store_barrier_ == kNoStoreBarrier) {
|
|
f->AddString(", NoStoreBarrier");
|
|
}
|
|
if (stores_inner_pointer() == InnerPointerAccess::kMayBeInnerPointer) {
|
|
f->AddString(", MayStoreInnerPointer");
|
|
}
|
|
}
|
|
|
|
void IfThenElseInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
condition()->PrintOperandsTo(f);
|
|
f->Printf(" ? %" Pd " : %" Pd, if_true_, if_false_);
|
|
}
|
|
|
|
void LoadStaticFieldInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s", String::Handle(field().name()).ToCString());
|
|
if (calls_initializer()) {
|
|
f->AddString(", CallsInitializer");
|
|
}
|
|
}
|
|
|
|
void StoreStaticFieldInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s, ", String::Handle(field().name()).ToCString());
|
|
value()->PrintTo(f);
|
|
}
|
|
|
|
void InstanceOfInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
value()->PrintTo(f);
|
|
f->Printf(" IS %s,", type().NameCString());
|
|
f->AddString(" instantiator_type_args(");
|
|
instantiator_type_arguments()->PrintTo(f);
|
|
f->AddString("), function_type_args(");
|
|
function_type_arguments()->PrintTo(f);
|
|
f->AddString(")");
|
|
}
|
|
|
|
void RelationalOpInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s, ", Token::Str(kind()));
|
|
left()->PrintTo(f);
|
|
f->AddString(", ");
|
|
right()->PrintTo(f);
|
|
}
|
|
|
|
void AllocationInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
Definition::PrintOperandsTo(f);
|
|
if (Identity().IsNotAliased()) {
|
|
if (InputCount() > 0) {
|
|
f->AddString(", ");
|
|
}
|
|
f->AddString("<not-aliased>");
|
|
}
|
|
}
|
|
|
|
void AllocateObjectInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("cls=%s", cls().ScrubbedNameCString());
|
|
if (InputCount() > 0 || Identity().IsNotAliased()) {
|
|
f->AddString(", ");
|
|
}
|
|
AllocationInstr::PrintOperandsTo(f);
|
|
}
|
|
|
|
void MaterializeObjectInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s", cls_.ScrubbedNameCString());
|
|
for (intptr_t i = 0; i < InputCount(); i++) {
|
|
f->AddString(", ");
|
|
f->Printf("%s: ", slots_[i]->Name());
|
|
InputAt(i)->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void LoadFieldInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
instance()->PrintTo(f);
|
|
f->Printf(" . %s%s", slot().Name(), IsImmutableLoad() ? " {final}" : "");
|
|
if (calls_initializer()) {
|
|
f->AddString(", CallsInitializer");
|
|
}
|
|
if (loads_inner_pointer() == InnerPointerAccess::kMayBeInnerPointer) {
|
|
f->AddString(", MayLoadInnerPointer");
|
|
}
|
|
}
|
|
|
|
void LoadUntaggedInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
object()->PrintTo(f);
|
|
f->Printf(", %" Pd, offset());
|
|
}
|
|
|
|
void CalculateElementAddressInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
Definition::PrintOperandsTo(f);
|
|
f->Printf(", index_scale=%" Pd "", index_scale());
|
|
}
|
|
|
|
void InstantiateTypeInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
const String& type_name = String::Handle(type().Name());
|
|
f->Printf("%s,", type_name.ToCString());
|
|
f->AddString(" instantiator_type_args(");
|
|
instantiator_type_arguments()->PrintTo(f);
|
|
f->AddString("), function_type_args(");
|
|
function_type_arguments()->PrintTo(f);
|
|
f->AddString(")");
|
|
}
|
|
|
|
void InstantiateTypeArgumentsInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
type_arguments()->PrintTo(f);
|
|
f->AddString(", instantiator_type_args(");
|
|
instantiator_type_arguments()->PrintTo(f);
|
|
f->AddString("), function_type_args(");
|
|
function_type_arguments()->PrintTo(f);
|
|
f->Printf(")");
|
|
if (!instantiator_class().IsNull()) {
|
|
f->Printf(", instantiator_class(%s)", instantiator_class().ToCString());
|
|
}
|
|
}
|
|
|
|
void AllocateContextInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("num_variables=%" Pd "", num_context_variables());
|
|
if (InputCount() > 0 || Identity().IsNotAliased()) {
|
|
f->AddString(", ");
|
|
}
|
|
TemplateAllocation::PrintOperandsTo(f);
|
|
}
|
|
|
|
void AllocateUninitializedContextInstr::PrintOperandsTo(
|
|
BaseTextBuffer* f) const {
|
|
f->Printf("num_variables=%" Pd "", num_context_variables());
|
|
if (InputCount() > 0 || Identity().IsNotAliased()) {
|
|
f->AddString(", ");
|
|
}
|
|
TemplateAllocation::PrintOperandsTo(f);
|
|
}
|
|
|
|
void TruncDivModInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
Definition::PrintOperandsTo(f);
|
|
}
|
|
|
|
void ExtractNthOutputInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("Extract %" Pd " from ", index());
|
|
Definition::PrintOperandsTo(f);
|
|
}
|
|
|
|
void UnboxLaneInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
Definition::PrintOperandsTo(f);
|
|
f->Printf(", lane %" Pd, lane());
|
|
}
|
|
|
|
void BoxLanesInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
Definition::PrintOperandsTo(f);
|
|
}
|
|
|
|
void UnaryIntegerOpInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s, ", Token::Str(op_kind()));
|
|
value()->PrintTo(f);
|
|
}
|
|
|
|
void BinaryIntegerOpInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s", Token::Str(op_kind()));
|
|
if (is_truncating()) {
|
|
f->AddString(" [tr]");
|
|
} else if (!can_overflow()) {
|
|
f->AddString(" [-o]");
|
|
}
|
|
f->AddString(", ");
|
|
left()->PrintTo(f);
|
|
f->AddString(", ");
|
|
right()->PrintTo(f);
|
|
}
|
|
|
|
void BinaryDoubleOpInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s, ", Token::Str(op_kind()));
|
|
left()->PrintTo(f);
|
|
f->AddString(", ");
|
|
right()->PrintTo(f);
|
|
}
|
|
|
|
void DoubleTestOpInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
switch (op_kind()) {
|
|
case MethodRecognizer::kDouble_getIsNaN:
|
|
f->AddString("IsNaN ");
|
|
break;
|
|
case MethodRecognizer::kDouble_getIsInfinite:
|
|
f->AddString("IsInfinite ");
|
|
break;
|
|
case MethodRecognizer::kDouble_getIsNegative:
|
|
f->AddString("IsNegative ");
|
|
break;
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
value()->PrintTo(f);
|
|
}
|
|
|
|
static const char* const simd_op_kind_string[] = {
|
|
#define CASE(Arity, Mask, Name, ...) #Name,
|
|
SIMD_OP_LIST(CASE, CASE)
|
|
#undef CASE
|
|
};
|
|
|
|
void SimdOpInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s", simd_op_kind_string[kind()]);
|
|
if (HasMask()) {
|
|
f->Printf(", mask = %" Pd "", mask());
|
|
}
|
|
for (intptr_t i = 0; i < InputCount(); i++) {
|
|
f->AddString(", ");
|
|
InputAt(i)->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void UnaryDoubleOpInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s, ", Token::Str(op_kind()));
|
|
value()->PrintTo(f);
|
|
}
|
|
|
|
void LoadClassIdInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
if (!input_can_be_smi_) {
|
|
f->AddString("<non-smi> ");
|
|
}
|
|
object()->PrintTo(f);
|
|
}
|
|
|
|
void CheckClassIdInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
value()->PrintTo(f);
|
|
|
|
const Class& cls = Class::Handle(
|
|
IsolateGroup::Current()->class_table()->At(cids().cid_start));
|
|
const String& name = String::Handle(cls.ScrubbedName());
|
|
if (cids().IsSingleCid()) {
|
|
f->Printf(", %s", name.ToCString());
|
|
} else {
|
|
const Class& cls2 = Class::Handle(
|
|
IsolateGroup::Current()->class_table()->At(cids().cid_end));
|
|
const String& name2 = String::Handle(cls2.ScrubbedName());
|
|
f->Printf(", cid %" Pd "-%" Pd " %s-%s", cids().cid_start, cids().cid_end,
|
|
name.ToCString(), name2.ToCString());
|
|
}
|
|
}
|
|
|
|
void HashIntegerOpInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
if (smi_) {
|
|
f->AddString("smi ");
|
|
}
|
|
|
|
value()->PrintTo(f);
|
|
}
|
|
|
|
void CheckClassInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
value()->PrintTo(f);
|
|
PrintCidsHelper(f, cids_, FlowGraphPrinter::kPrintAll);
|
|
if (IsNullCheck()) {
|
|
f->AddString(" nullcheck");
|
|
}
|
|
}
|
|
|
|
void CheckConditionInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
condition()->PrintOperandsTo(f);
|
|
}
|
|
|
|
void InvokeMathCFunctionInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s, ", MethodRecognizer::KindToCString(recognized_kind_));
|
|
Definition::PrintOperandsTo(f);
|
|
}
|
|
|
|
void GraphEntryInstr::PrintBlockHeaderTo(BaseTextBuffer* f) const {
|
|
f->Printf("B%" Pd "[graph]:%" Pd, block_id(), GetDeoptId());
|
|
}
|
|
|
|
void JoinEntryInstr::PrintTo(BaseTextBuffer* f) const {
|
|
if (try_index() != kInvalidTryIndex) {
|
|
f->Printf("B%" Pd "[join try_idx %" Pd "]:%" Pd " pred(", block_id(),
|
|
try_index(), GetDeoptId());
|
|
} else {
|
|
f->Printf("B%" Pd "[join]:%" Pd " pred(", block_id(), GetDeoptId());
|
|
}
|
|
for (intptr_t i = 0; i < predecessors_.length(); ++i) {
|
|
if (i > 0) f->AddString(", ");
|
|
f->Printf("B%" Pd, predecessors_[i]->block_id());
|
|
}
|
|
f->AddString(")");
|
|
if (phis_ != nullptr) {
|
|
f->AddString(" {");
|
|
for (intptr_t i = 0; i < phis_->length(); ++i) {
|
|
if ((*phis_)[i] == nullptr) continue;
|
|
f->AddString("\n ");
|
|
(*phis_)[i]->PrintTo(f);
|
|
}
|
|
f->AddString("\n}");
|
|
}
|
|
if (HasParallelMove()) {
|
|
f->AddString(" ");
|
|
parallel_move()->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void IndirectEntryInstr::PrintTo(BaseTextBuffer* f) const {
|
|
f->Printf("B%" Pd "[join indirect", block_id());
|
|
if (try_index() != kInvalidTryIndex) {
|
|
f->Printf(" try_idx %" Pd, try_index());
|
|
}
|
|
f->Printf("]:%" Pd " pred(", GetDeoptId());
|
|
for (intptr_t i = 0; i < predecessors_.length(); ++i) {
|
|
if (i > 0) f->AddString(", ");
|
|
f->Printf("B%" Pd, predecessors_[i]->block_id());
|
|
}
|
|
f->AddString(")");
|
|
if (phis_ != nullptr) {
|
|
f->AddString(" {");
|
|
for (intptr_t i = 0; i < phis_->length(); ++i) {
|
|
if ((*phis_)[i] == nullptr) continue;
|
|
f->AddString("\n ");
|
|
(*phis_)[i]->PrintTo(f);
|
|
}
|
|
f->AddString("\n}");
|
|
}
|
|
if (HasParallelMove()) {
|
|
f->AddString(" ");
|
|
parallel_move()->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void PhiInstr::PrintTo(BaseTextBuffer* f) const {
|
|
f->Printf("v%" Pd " <- phi(", ssa_temp_index());
|
|
for (intptr_t i = 0; i < inputs_.length(); ++i) {
|
|
if (inputs_[i] != nullptr) inputs_[i]->PrintTo(f);
|
|
if (i < inputs_.length() - 1) f->AddString(", ");
|
|
}
|
|
f->AddString(")");
|
|
f->AddString(is_alive() ? " alive" : " dead");
|
|
if (range_ != nullptr) {
|
|
f->AddString(" ");
|
|
range_->PrintTo(f);
|
|
}
|
|
|
|
if (representation() != kNoRepresentation && representation() != kTagged) {
|
|
f->Printf(" %s", RepresentationUtils::ToCString(representation()));
|
|
}
|
|
|
|
if (HasType()) {
|
|
f->Printf(" %s", TypeAsCString());
|
|
}
|
|
}
|
|
|
|
void UnboxIntegerInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
if (value_mode() == ValueMode::kCheckType) {
|
|
f->AddString("[check-type], ");
|
|
}
|
|
Definition::PrintOperandsTo(f);
|
|
}
|
|
|
|
void IntConverterInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s->%s, ", RepresentationUtils::ToCString(from()),
|
|
RepresentationUtils::ToCString(to()));
|
|
Definition::PrintOperandsTo(f);
|
|
}
|
|
|
|
void BitCastInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
Definition::PrintOperandsTo(f);
|
|
f->Printf(" (%s -> %s)", RepresentationUtils::ToCString(from()),
|
|
RepresentationUtils::ToCString(to()));
|
|
}
|
|
|
|
void ParameterInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%" Pd " @%s", env_index(), location().ToCString());
|
|
}
|
|
|
|
void CheckStackOverflowInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("stack=%" Pd ", loop=%" Pd, stack_depth(), loop_depth());
|
|
}
|
|
|
|
void TargetEntryInstr::PrintTo(BaseTextBuffer* f) const {
|
|
if (try_index() != kInvalidTryIndex) {
|
|
f->Printf("B%" Pd "[target try_idx %" Pd "]:%" Pd, block_id(), try_index(),
|
|
GetDeoptId());
|
|
} else {
|
|
f->Printf("B%" Pd "[target]:%" Pd, block_id(), GetDeoptId());
|
|
}
|
|
if (HasParallelMove()) {
|
|
f->AddString(" ");
|
|
parallel_move()->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void BlockEntryWithInitialDefs::PrintTo(BaseTextBuffer* f) const {
|
|
PrintBlockHeaderTo(f);
|
|
PrintInitialDefinitionsTo(f, [](BaseTextBuffer* f) {});
|
|
}
|
|
|
|
void BlockEntryWithInitialDefs::PrintInitialDefinitionsTo(
|
|
BaseTextBuffer* f,
|
|
std::function<void(BaseTextBuffer* f)> callback) const {
|
|
const GrowableArray<Definition*>& defns = initial_definitions_;
|
|
if (defns.length() > 0) {
|
|
f->AddString(" {");
|
|
for (intptr_t i = 0; i < defns.length(); ++i) {
|
|
Definition* const def = defns[i];
|
|
// Skip constants which are not used in the graph.
|
|
if (!ShouldPrintInstruction(def)) {
|
|
continue;
|
|
}
|
|
f->AddString("\n ");
|
|
def->PrintTo(f);
|
|
callback(f);
|
|
}
|
|
f->AddString("\n}");
|
|
}
|
|
}
|
|
|
|
void OsrEntryInstr::PrintBlockHeaderTo(BaseTextBuffer* f) const {
|
|
f->Printf("B%" Pd "[osr entry]:%" Pd " stack_depth=%" Pd, block_id(),
|
|
GetDeoptId(), stack_depth());
|
|
if (HasParallelMove()) {
|
|
f->AddString("\n");
|
|
parallel_move()->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void FunctionEntryInstr::PrintBlockHeaderTo(BaseTextBuffer* f) const {
|
|
f->Printf("B%" Pd "[function entry]:%" Pd, block_id(), GetDeoptId());
|
|
if (HasParallelMove()) {
|
|
f->AddString("\n");
|
|
parallel_move()->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void NativeEntryInstr::PrintBlockHeaderTo(BaseTextBuffer* f) const {
|
|
f->Printf("B%" Pd "[native function entry]:%" Pd, block_id(), GetDeoptId());
|
|
if (HasParallelMove()) {
|
|
f->AddString("\n");
|
|
parallel_move()->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void FfiCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->AddString(" pointer=");
|
|
InputAt(TargetAddressIndex())->PrintTo(f);
|
|
if (marshaller_.ReturnsCompound()) {
|
|
f->AddString(", compound_return_typed_data=");
|
|
InputAt(CompoundReturnTypedDataIndex())->PrintTo(f);
|
|
}
|
|
intptr_t def_index = 0;
|
|
for (intptr_t arg_index = 0; arg_index < marshaller_.num_args();
|
|
arg_index++) {
|
|
const auto& arg_location = marshaller_.Location(arg_index);
|
|
const bool is_compound = arg_location.container_type().IsCompound();
|
|
const intptr_t num_defs = marshaller_.NumDefinitions(arg_index);
|
|
f->AddString(", ");
|
|
if (is_compound) f->AddString("(");
|
|
for (intptr_t i = 0; i < num_defs; i++) {
|
|
InputAt(def_index)->PrintTo(f);
|
|
if ((i + 1) < num_defs) f->AddString(", ");
|
|
def_index++;
|
|
}
|
|
if (is_compound) f->AddString(")");
|
|
f->AddString(" (@");
|
|
arg_location.PrintTo(f);
|
|
f->AddString(")");
|
|
}
|
|
}
|
|
|
|
void LeafRuntimeCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->AddString("target_address=");
|
|
InputAt(TargetAddressIndex())->PrintTo(f);
|
|
for (intptr_t i = 0, n = argument_representations_.length(); i < n; ++i) {
|
|
f->AddString(", ");
|
|
InputAt(i)->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void NativeReturnInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
if (marshaller_.NumReturnDefinitions() == 1) {
|
|
InputAt(0)->PrintTo(f);
|
|
} else {
|
|
ASSERT_EQUAL(marshaller_.NumReturnDefinitions(), 2);
|
|
f->AddString("(");
|
|
InputAt(0)->PrintTo(f);
|
|
f->AddString(", ");
|
|
InputAt(1)->PrintTo(f);
|
|
f->AddString(")");
|
|
}
|
|
|
|
f->AddString(" (@");
|
|
marshaller_.Location(compiler::ffi::kResultIndex).PrintTo(f);
|
|
f->AddString(")");
|
|
}
|
|
|
|
void NativeParameterInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
// Where the calling convention puts it.
|
|
marshaller_.Location(marshaller_.ArgumentIndex(def_index_)).PrintTo(f);
|
|
f->AddString(" at ");
|
|
// Where the arguments are when pushed on the stack.
|
|
marshaller_.NativeLocationOfNativeParameter(def_index_).PrintTo(f);
|
|
}
|
|
|
|
void CatchBlockEntryInstr::PrintBlockHeaderTo(BaseTextBuffer* f) const {
|
|
f->Printf("B%" Pd "[target catch try_idx %" Pd " catch_try_idx %" Pd "]",
|
|
block_id(), try_index(), catch_try_index());
|
|
if (HasParallelMove()) {
|
|
f->AddString("\n");
|
|
parallel_move()->PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void LoadIndexedUnsafeInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s[", RegisterNames::RegisterName(base_reg()));
|
|
index()->PrintTo(f);
|
|
f->Printf(" + %" Pd "]", offset());
|
|
}
|
|
|
|
void StoreIndexedUnsafeInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s[", RegisterNames::RegisterName(base_reg()));
|
|
index()->PrintTo(f);
|
|
f->Printf(" + %" Pd "], ", offset());
|
|
value()->PrintTo(f);
|
|
}
|
|
|
|
void LoadIndexedInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
auto& cls =
|
|
Class::Handle(IsolateGroup::Current()->class_table()->At(class_id()));
|
|
if (!cls.IsNull()) {
|
|
f->Printf("[%s] ", cls.ScrubbedNameCString());
|
|
} else {
|
|
f->Printf("[cid %" Pd "] ", class_id());
|
|
}
|
|
Instruction::PrintOperandsTo(f);
|
|
}
|
|
|
|
void StoreIndexedInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
auto& cls =
|
|
Class::Handle(IsolateGroup::Current()->class_table()->At(class_id()));
|
|
if (!cls.IsNull()) {
|
|
f->Printf("[%s] ", cls.ScrubbedNameCString());
|
|
} else {
|
|
f->Printf("[cid %" Pd "] ", class_id());
|
|
}
|
|
Instruction::PrintOperandsTo(f);
|
|
if (!ShouldEmitStoreBarrier()) {
|
|
f->AddString(", NoStoreBarrier");
|
|
}
|
|
}
|
|
|
|
void MemoryCopyInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
Instruction::PrintOperandsTo(f);
|
|
auto& cls =
|
|
Class::Handle(IsolateGroup::Current()->class_table()->At(dest_cid_));
|
|
if (!cls.IsNull()) {
|
|
f->Printf(", dest_cid=%s (%d)", cls.ScrubbedNameCString(), dest_cid_);
|
|
} else {
|
|
f->Printf(", dest_cid=%d", dest_cid_);
|
|
}
|
|
if (dest()->definition()->representation() == kUntagged) {
|
|
f->Printf(" [untagged]");
|
|
}
|
|
cls = IsolateGroup::Current()->class_table()->At(src_cid_);
|
|
if (!cls.IsNull()) {
|
|
f->Printf(", src_cid=%s (%d)", cls.ScrubbedNameCString(), src_cid_);
|
|
} else {
|
|
f->Printf(", src_cid=%d", src_cid_);
|
|
}
|
|
if (src()->definition()->representation() == kUntagged) {
|
|
f->Printf(" [untagged]");
|
|
}
|
|
if (element_size() != 1) {
|
|
f->Printf(", element_size=%" Pd "", element_size());
|
|
}
|
|
if (unboxed_inputs()) {
|
|
f->AddString(", unboxed_inputs");
|
|
}
|
|
if (can_overlap()) {
|
|
f->AddString(", can_overlap");
|
|
}
|
|
}
|
|
|
|
void TailCallInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
const char* name = "<unknown code>";
|
|
if (code_.IsStubCode()) {
|
|
name = StubCode::NameOfStub(code_.EntryPoint());
|
|
} else {
|
|
const Object& owner = Object::Handle(code_.owner());
|
|
if (owner.IsFunction()) {
|
|
name = Function::Handle(Function::RawCast(owner.ptr()))
|
|
.ToFullyQualifiedCString();
|
|
}
|
|
}
|
|
f->Printf("%s(", name);
|
|
InputAt(0)->PrintTo(f);
|
|
f->AddString(")");
|
|
}
|
|
|
|
void Call1ArgStubInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
const char* name = "";
|
|
switch (stub_id_) {
|
|
case StubId::kCloneSuspendState:
|
|
name = "CloneSuspendState";
|
|
break;
|
|
case StubId::kInitAsync:
|
|
name = "InitAsync";
|
|
break;
|
|
case StubId::kInitAsyncStar:
|
|
name = "InitAsyncStar";
|
|
break;
|
|
case StubId::kInitSyncStar:
|
|
name = "InitSyncStar";
|
|
break;
|
|
case StubId::kFfiAsyncCallbackSend:
|
|
name = "FfiAsyncCallbackSend";
|
|
break;
|
|
}
|
|
f->Printf("%s(", name);
|
|
operand()->PrintTo(f);
|
|
f->AddString(")");
|
|
}
|
|
|
|
void SuspendInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
const char* name = "";
|
|
switch (stub_id_) {
|
|
case StubId::kAwait:
|
|
name = "Await";
|
|
break;
|
|
case StubId::kAwaitWithTypeCheck:
|
|
name = "AwaitWithTypeCheck";
|
|
break;
|
|
case StubId::kYieldAsyncStar:
|
|
name = "YieldAsyncStar";
|
|
break;
|
|
case StubId::kSuspendSyncStarAtStart:
|
|
name = "SuspendSyncStarAtStart";
|
|
break;
|
|
case StubId::kSuspendSyncStarAtYield:
|
|
name = "SuspendSyncStarAtYield";
|
|
break;
|
|
}
|
|
f->Printf("%s(", name);
|
|
Definition::PrintOperandsTo(f);
|
|
f->AddString(")");
|
|
}
|
|
|
|
void MoveArgumentInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s <- ", location().ToCString());
|
|
value()->PrintTo(f);
|
|
}
|
|
|
|
void GenericCheckBoundInstr::PrintOperandsTo(BaseTextBuffer* f) const {
|
|
Definition::PrintOperandsTo(f);
|
|
if (IsPhantom()) {
|
|
f->AddString(", phantom");
|
|
}
|
|
}
|
|
|
|
void GotoInstr::PrintTo(BaseTextBuffer* f) const {
|
|
if (HasParallelMove()) {
|
|
parallel_move()->PrintTo(f);
|
|
f->AddString(" ");
|
|
}
|
|
if (GetDeoptId() != DeoptId::kNone) {
|
|
f->Printf("goto:%" Pd " B%" Pd "", GetDeoptId(), successor()->block_id());
|
|
} else {
|
|
f->Printf("goto: B%" Pd "", successor()->block_id());
|
|
}
|
|
}
|
|
|
|
void IndirectGotoInstr::PrintTo(BaseTextBuffer* f) const {
|
|
if (GetDeoptId() != DeoptId::kNone) {
|
|
f->Printf("igoto:%" Pd "(", GetDeoptId());
|
|
} else {
|
|
f->AddString("igoto:(");
|
|
}
|
|
InputAt(0)->PrintTo(f);
|
|
f->AddString(")");
|
|
}
|
|
|
|
void BranchInstr::PrintTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s ", DebugName());
|
|
f->AddString("if ");
|
|
condition()->PrintTo(f);
|
|
|
|
f->Printf(" goto (%" Pd ", %" Pd ")", true_successor()->block_id(),
|
|
false_successor()->block_id());
|
|
}
|
|
|
|
void ParallelMoveInstr::PrintTo(BaseTextBuffer* f) const {
|
|
f->Printf("%s ", DebugName());
|
|
for (intptr_t i = 0; i < moves_.length(); i++) {
|
|
if (i != 0) f->AddString(", ");
|
|
moves_[i]->dest().PrintTo(f);
|
|
f->AddString(" <- ");
|
|
moves_[i]->src().PrintTo(f);
|
|
}
|
|
}
|
|
|
|
void Utf8ScanInstr::PrintTo(BaseTextBuffer* f) const {
|
|
Definition::PrintTo(f);
|
|
f->Printf(" [%s]", scan_flags_field_.Name());
|
|
}
|
|
|
|
void Environment::PrintTo(BaseTextBuffer* f) const {
|
|
f->AddString(" env={ ");
|
|
int arg_count = 0;
|
|
for (intptr_t i = 0; i < values_.length(); ++i) {
|
|
if (i > 0) f->AddString(", ");
|
|
if (values_[i]->definition()->IsMoveArgument()) {
|
|
f->Printf("a%d", arg_count++);
|
|
} else {
|
|
values_[i]->PrintTo(f);
|
|
}
|
|
if ((locations_ != nullptr) && !locations_[i].IsInvalid()) {
|
|
f->AddString(" [");
|
|
locations_[i].PrintTo(f);
|
|
f->AddString("]");
|
|
}
|
|
}
|
|
f->AddString(" }");
|
|
if (outer_ != nullptr) outer_->PrintTo(f);
|
|
}
|
|
|
|
const char* Environment::ToCString() const {
|
|
char buffer[1024];
|
|
BufferFormatter bf(buffer, 1024);
|
|
PrintTo(&bf);
|
|
return Thread::Current()->zone()->MakeCopyOfString(buffer);
|
|
}
|
|
|
|
#else // defined(INCLUDE_IL_PRINTER)
|
|
|
|
const char* Instruction::ToCString() const {
|
|
return DebugName();
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintOneInstruction(Instruction* instr,
|
|
bool print_locations) {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintTypeCheck(const ParsedFunction& parsed_function,
|
|
TokenPosition token_pos,
|
|
Value* value,
|
|
const AbstractType& dst_type,
|
|
const String& dst_name,
|
|
bool eliminated) {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintBlock(BlockEntryInstr* block,
|
|
bool print_locations) {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintGraph(const char* phase, FlowGraph* flow_graph) {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
void FlowGraphPrinter::PrintICData(const ICData& ic_data,
|
|
intptr_t num_checks_to_print) {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
bool FlowGraphPrinter::ShouldPrint(
|
|
const Function& function,
|
|
uint8_t** compiler_pass_filter /* = nullptr */) {
|
|
return false;
|
|
}
|
|
|
|
#endif // defined(INCLUDE_IL_PRINTER)
|
|
|
|
} // namespace dart
|