Compiler: Spring cleaning
Significant restructuring of the Quick compiler to break out the
common frontend more cleanly. Additional C++'ification.
The goal is to move from the monolithic structure of the old
JIT towards a more modular model in which components - in
particular the compiler backend - can be replaced. This CL
focuses on moving MIR-related data from the CompilationUnit
struct into a new MIRGraph class. The next CL will isolate all
LIR-related data and code down into the Quick backend.
This change will happen in multiple steps, and may look uglier
before it starts looking better.
Among the changes:
o Moved all mir-related fields from CompilationUnit to new
MirGraph class.
o Moved the register promotion stuff into the Quick backend.
o Deleted the GBC to LIR conversion code.
o Replaced with old C-style function pointer dataflow analysis
dispatcher with a basic block iterator class.
o Renamed some files to make the name more consistent with what
the code actually does.
o Added the foundation for future inlining support.
o Stripped out the remains of the old fingerprinting mechanism.
Change-Id: I6c30facc642f8084b1c7b2075cf7014de387aa56
diff --git a/src/compiler/dex/compiler_utility.cc b/src/compiler/dex/compiler_utility.cc
index 9dc90ce..82a156d 100644
--- a/src/compiler/dex/compiler_utility.cc
+++ b/src/compiler/dex/compiler_utility.cc
@@ -203,6 +203,18 @@
#endif
}
+void ReallocGrowableList(CompilationUnit* cu, GrowableList* g_list, size_t new_length)
+{
+ if (new_length > g_list->num_allocated) {
+ uintptr_t *new_array =
+ static_cast<uintptr_t*>(NewMem(cu, sizeof(uintptr_t) * new_length, true,
+ kAllocGrowableList));
+ memcpy(new_array, g_list->elem_list, sizeof(uintptr_t) * g_list->num_allocated);
+ g_list->num_allocated = new_length;
+ g_list->elem_list = new_array;
+ }
+}
+
/* Expand the capacity of a growable list */
static void ExpandGrowableList(CompilationUnit* cu, GrowableList* g_list)
{
@@ -288,7 +300,7 @@
if (total > (10 * 1024 * 1024)) {
LOG(INFO) << "MEMUSAGE: " << total << " : "
<< PrettyMethod(cu->method_idx, *cu->dex_file);
- LOG(INFO) << "insns_size: " << cu->insns_size;
+ LOG(INFO) << "insns_size: " << cu->code_item->insns_size_in_code_units_;
if (cu->disable_dataflow) {
LOG(INFO) << " ** Dataflow disabled ** ";
}
@@ -330,10 +342,8 @@
LOG(INFO) << "Compiling " << PrettyMethod(cu->method_idx, *cu->dex_file);
LOG(INFO) << cu->insns << " insns";
- LOG(INFO) << cu->num_blocks << " blocks in total";
- GrowableListIterator iterator;
-
- GrowableListIteratorInit(&cu->block_list, &iterator);
+ LOG(INFO) << cu->mir_graph->GetNumBlocks() << " blocks in total";
+ GrowableListIterator iterator = cu->mir_graph->GetBasicBlockIterator();
while (true) {
bb = reinterpret_cast<BasicBlock*>(GrowableListIteratorNext(&iterator));
@@ -797,4 +807,171 @@
new_lir->next->prev = new_lir;
}
+/* Turn method name into a legal Linux file name */
+void ReplaceSpecialChars(std::string& str)
+{
+ static const struct { const char before; const char after; } match[] =
+ {{'/','-'}, {';','#'}, {' ','#'}, {'$','+'},
+ {'(','@'}, {')','@'}, {'<','='}, {'>','='}};
+ for (unsigned int i = 0; i < sizeof(match)/sizeof(match[0]); i++) {
+ std::replace(str.begin(), str.end(), match[i].before, match[i].after);
+ }
+}
+
+std::string GetSSAName(const CompilationUnit* cu, int ssa_reg)
+{
+ return StringPrintf("v%d_%d", cu->mir_graph->SRegToVReg(ssa_reg), cu->mir_graph->GetSSASubscript(ssa_reg));
+}
+
+// Similar to GetSSAName, but if ssa name represents an immediate show that as well.
+std::string GetSSANameWithConst(const CompilationUnit* cu, int ssa_reg, bool singles_only)
+{
+ if (cu->reg_location == NULL) {
+ // Pre-SSA - just use the standard name
+ return GetSSAName(cu, ssa_reg);
+ }
+ if (cu->mir_graph->IsConst(cu->reg_location[ssa_reg])) {
+ if (!singles_only && cu->reg_location[ssa_reg].wide) {
+ return StringPrintf("v%d_%d#0x%llx", cu->mir_graph->SRegToVReg(ssa_reg),
+ cu->mir_graph->GetSSASubscript(ssa_reg),
+ cu->mir_graph->ConstantValueWide(cu->reg_location[ssa_reg]));
+ } else {
+ return StringPrintf("v%d_%d#0x%x", cu->mir_graph->SRegToVReg(ssa_reg),
+ cu->mir_graph->GetSSASubscript(ssa_reg),
+ cu->mir_graph->ConstantValue(cu->reg_location[ssa_reg]));
+ }
+ } else {
+ return StringPrintf("v%d_%d", cu->mir_graph->SRegToVReg(ssa_reg),
+ cu->mir_graph->GetSSASubscript(ssa_reg));
+ }
+}
+
+char* GetDalvikDisassembly(CompilationUnit* cu, const MIR* mir)
+{
+ DecodedInstruction insn = mir->dalvikInsn;
+ std::string str;
+ int flags = 0;
+ int opcode = insn.opcode;
+ char* ret;
+ bool nop = false;
+ SSARepresentation* ssa_rep = mir->ssa_rep;
+ Instruction::Format dalvik_format = Instruction::k10x; // Default to no-operand format
+ int defs = (ssa_rep != NULL) ? ssa_rep->num_defs : 0;
+ int uses = (ssa_rep != NULL) ? ssa_rep->num_uses : 0;
+
+ // Handle special cases.
+ if ((opcode == kMirOpCheck) || (opcode == kMirOpCheckPart2)) {
+ str.append(extended_mir_op_names[opcode - kMirOpFirst]);
+ str.append(": ");
+ // Recover the original Dex instruction
+ insn = mir->meta.throw_insn->dalvikInsn;
+ ssa_rep = mir->meta.throw_insn->ssa_rep;
+ defs = ssa_rep->num_defs;
+ uses = ssa_rep->num_uses;
+ opcode = insn.opcode;
+ } else if (opcode == kMirOpNop) {
+ str.append("[");
+ insn.opcode = mir->meta.original_opcode;
+ opcode = mir->meta.original_opcode;
+ nop = true;
+ }
+
+ if (opcode >= kMirOpFirst) {
+ str.append(extended_mir_op_names[opcode - kMirOpFirst]);
+ } else {
+ dalvik_format = Instruction::FormatOf(insn.opcode);
+ flags = Instruction::FlagsOf(insn.opcode);
+ str.append(Instruction::Name(insn.opcode));
+ }
+
+ if (opcode == kMirOpPhi) {
+ int* incoming = reinterpret_cast<int*>(insn.vB);
+ str.append(StringPrintf(" %s = (%s",
+ GetSSANameWithConst(cu, ssa_rep->defs[0], true).c_str(),
+ GetSSANameWithConst(cu, ssa_rep->uses[0], true).c_str()));
+ str.append(StringPrintf(":%d",incoming[0]));
+ int i;
+ for (i = 1; i < uses; i++) {
+ str.append(StringPrintf(", %s:%d",
+ GetSSANameWithConst(cu, ssa_rep->uses[i], true).c_str(),
+ incoming[i]));
+ }
+ str.append(")");
+ } else if ((flags & Instruction::kBranch) != 0) {
+ // For branches, decode the instructions to print out the branch targets.
+ int offset = 0;
+ switch (dalvik_format) {
+ case Instruction::k21t:
+ str.append(StringPrintf(" %s,", GetSSANameWithConst(cu, ssa_rep->uses[0], false).c_str()));
+ offset = insn.vB;
+ break;
+ case Instruction::k22t:
+ str.append(StringPrintf(" %s, %s,", GetSSANameWithConst(cu, ssa_rep->uses[0], false).c_str(),
+ GetSSANameWithConst(cu, ssa_rep->uses[1], false).c_str()));
+ offset = insn.vC;
+ break;
+ case Instruction::k10t:
+ case Instruction::k20t:
+ case Instruction::k30t:
+ offset = insn.vA;
+ break;
+ default:
+ LOG(FATAL) << "Unexpected branch format " << dalvik_format << " from " << insn.opcode;
+ }
+ str.append(StringPrintf(" 0x%x (%c%x)", mir->offset + offset,
+ offset > 0 ? '+' : '-', offset > 0 ? offset : -offset));
+ } else {
+ // For invokes-style formats, treat wide regs as a pair of singles
+ bool show_singles = ((dalvik_format == Instruction::k35c) ||
+ (dalvik_format == Instruction::k3rc));
+ if (defs != 0) {
+ str.append(StringPrintf(" %s", GetSSANameWithConst(cu, ssa_rep->defs[0], false).c_str()));
+ if (uses != 0) {
+ str.append(", ");
+ }
+ }
+ for (int i = 0; i < uses; i++) {
+ str.append(
+ StringPrintf(" %s", GetSSANameWithConst(cu, ssa_rep->uses[i], show_singles).c_str()));
+ if (!show_singles && (cu->reg_location != NULL) && cu->reg_location[i].wide) {
+ // For the listing, skip the high sreg.
+ i++;
+ }
+ if (i != (uses -1)) {
+ str.append(",");
+ }
+ }
+ switch (dalvik_format) {
+ case Instruction::k11n: // Add one immediate from vB
+ case Instruction::k21s:
+ case Instruction::k31i:
+ case Instruction::k21h:
+ str.append(StringPrintf(", #%d", insn.vB));
+ break;
+ case Instruction::k51l: // Add one wide immediate
+ str.append(StringPrintf(", #%lld", insn.vB_wide));
+ break;
+ case Instruction::k21c: // One register, one string/type/method index
+ case Instruction::k31c:
+ str.append(StringPrintf(", index #%d", insn.vB));
+ break;
+ case Instruction::k22c: // Two registers, one string/type/method index
+ str.append(StringPrintf(", index #%d", insn.vC));
+ break;
+ case Instruction::k22s: // Add one immediate from vC
+ case Instruction::k22b:
+ str.append(StringPrintf(", #%d", insn.vC));
+ break;
+ default:
+ ; // Nothing left to print
+ }
+ }
+ if (nop) {
+ str.append("]--optimized away");
+ }
+ int length = str.length() + 1;
+ ret = static_cast<char*>(NewMem(cu, length, false, kAllocDFInfo));
+ strncpy(ret, str.c_str(), length);
+ return ret;
+}
} // namespace art