ART世界探險(16) - 快速編譯器下的方法編譯
我們對三大組件有了了解之后,下面終于可以開始正餐,開始分析兩種Compiler下的Compile函數。
我們先看一張圖,對于整個流程有個整體的印象,然后我們再去看代碼:
quick_compile
QuickCompiler的Compile
CompiledMethod* QuickCompiler::Compile(const DexFile::CodeItem* code_item,
uint32_t access_flags,
InvokeType invoke_type,
uint16_t class_def_idx,
uint32_t method_idx,
jobject class_loader,
const DexFile& dex_file) const {
...
CompilerDriver* driver = GetCompilerDriver();
上來就是老朋友,先獲取CompilerDriver對象。前面我們介紹過,它是調用編譯器的驅動接口,大雜燴類。
然后下面判斷是不是病態情況,值不值得編譯。是不是經過校驗。是不是打開了編譯開關。
...
if (Compiler::IsPathologicalCase(*code_item, method_idx, dex_file)) {
return nullptr;
}
if (driver->GetVerifiedMethod(&dex_file, method_idx)->HasRuntimeThrow()) {
return nullptr;
}
DCHECK(driver->GetCompilerOptions().IsCompilationEnabled());
下面是Runtime和ClassLinker出場,三大組件齊了。
然后是大管家CompliationUnit開始工作。
Runtime* const runtime = Runtime::Current();
ClassLinker* const class_linker = runtime->GetClassLinker();
InstructionSet instruction_set = driver->GetInstructionSet();
if (instruction_set == kArm) {
instruction_set = kThumb2;
}
CompilationUnit cu(runtime->GetArenaPool(), instruction_set, driver, class_linker);
cu.dex_file = &dex_file;
cu.class_def_idx = class_def_idx;
cu.method_idx = method_idx;
cu.access_flags = access_flags;
cu.invoke_type = invoke_type;
cu.shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
CHECK((cu.instruction_set == kThumb2) ||
(cu.instruction_set == kArm64) ||
(cu.instruction_set == kX86) ||
(cu.instruction_set == kX86_64) ||
(cu.instruction_set == kMips) ||
(cu.instruction_set == kMips64));
...
InitCompilationUnit(cu);
上面都是在做CompilationUnit的初始化工作,例如這個InitCompilationUnit:
void QuickCompiler::InitCompilationUnit(CompilationUnit& cu) const {
// Disable optimizations according to instruction set.
cu.disable_opt |= kDisabledOptimizationsPerISA[cu.instruction_set];
if (Runtime::Current()->UseJit()) {
// Disable these optimizations for JIT until quickened byte codes are done being implemented.
// TODO: Find a cleaner way to do this.
cu.disable_opt |= 1u << kLocalValueNumbering;
}
}
然后開始構建MIRGraph.
cu.mir_graph.reset(new MIRGraph(&cu, &cu.arena));
/*
* After creation of the MIR graph, also create the code generator.
* The reason we do this is that optimizations on the MIR graph may need to get information
* that is only available if a CG exists.
*/
cu.cg.reset(GetCodeGenerator(&cu, nullptr));
/* Build the raw MIR graph */
cu.mir_graph->InlineMethod(code_item, access_flags, invoke_type, class_def_idx, method_idx,
class_loader, dex_file);
...
下面創建Pass驅動,然后調用它來做優化。
/* Create the pass driver and launch it */
PassDriverMEOpts pass_driver(GetPreOptPassManager(), GetPostOptPassManager(), &cu);
pass_driver.Launch();
...
寄存器重新映射
/* Reassociate sreg names with original Dalvik vreg names. */
cu.mir_graph->RemapRegLocations();
清理內存,以便下次復用
/* Free Arenas from the cu.arena_stack for reuse by the cu.arena in the codegen. */
...
cu.arena_stack.Reset();
CompiledMethod* result = nullptr;
...
生成機器指令
cu.cg->Materialize();
...
消除重復數據,并重復結果
result = cu.cg->GetCompiledMethod();
...
return result;
}
我們為下一章節做個小小的預告,下面我們將深入到MIRGraph,CodeGenerator,優化的Pass還有Mir2Lir的激動人心的過程中。
先上一個預告圖,順便復習一下之前所學的流程:
Paste_Image.png