ART世界探險(15) - Compiler,ClassLinker,Runtime三大組件

ART世界探險(15) - Compiler,ClassLinker,Runtime三大組件

CompilerDriver

調(diào)用編譯器的接口是CompilerDriver愕贡。
我們看一看CompilerDriver的結(jié)構(gòu)圖吧:

CompilerDriver

這是我們在ART里能遇見的第一個復(fù)雜的大類。但凡編譯相關(guān)徙瓶,都要通過它來打交道昆庇。結(jié)果躲胳,它就把自己搞成了一個大雜燴上沐。

ClassLinker

Java是門面向?qū)ο蟮恼Z言婶芭,導(dǎo)致類相關(guān)的操作比較復(fù)雜乘陪。
在應(yīng)用層有ClassLoader,在運行環(huán)境層就有ClassLinker雕擂。
我們看一下ClassLinker的公開方法啡邑,私有的還有同樣多的,汗井赌。

ClassLinker

ClassLinker相對于CompilerDriver谤逼,邏輯上更為集中一些。
它主要是提供跟類相關(guān)的操作仇穗,包括類級的分配對象等流部。
CompilerDriver提供的主要是編譯期底層代碼的功能,而ClassLinker在面向?qū)ο蟮倪壿媽犹峁┓?wù)纹坐。

Runtime

ART是Android Runtime的縮寫枝冀,我們終于可以揭開Android Runtime的面紗了。

Runtime

Runtime主要是提供一些運行時的服務(wù)耘子,最重要的當然就是GC果漾。另外,還有多線程和線程安全相關(guān)的支持谷誓,事務(wù)相關(guān)的支持等绒障。

有了上面三個大組件的支持,不管是編譯期還是運行時捍歪,我們都可以找到支持Java方法運行的基礎(chǔ)設(shè)施户辱。

最后鸵钝,我們再復(fù)習(xí)一下上節(jié)最后出現(xiàn)的編譯單元類:

CompilationUnit

CompilationUnit的作用是連接前端和后端。

將前端的DexFile通過CompilerDriver進行編譯之后庐镐,我們先得到中間層中間代碼MIR恩商,MIRGraph就是這一步要做的工作。很多優(yōu)化也是在這一步完成的必逆。
然后痕届,再通過Mir2Lir,將MIR轉(zhuǎn)化成更接近于機器指令的低層中間代碼LIR末患。
最后研叫,再將LIR落地成目標機器的指令。

dex2oat編譯流程(續(xù))

首先我們復(fù)習(xí)一下之前學(xué)到的璧针,dex2oat做為入口點嚷炉,會調(diào)用CompilerDriver的方法對dex文件進行編譯。

dex2oat-1

下面該開始CompilerDriver的CompileClass探橱,看了CompilerDriver的大圖之后申屹,對于它是不是更親切了呢?

CompileClass

編譯類的重頭戲還在于編譯方法隧膏。
CompileClass類的主要邏輯哗讥,就是針對直接方法和虛擬方法,分別遍歷然后編譯胞枕。

我們將前面的判斷和校驗等細節(jié)都略過杆煞,這個函數(shù)的框架如下面所示:

void CompilerDriver::CompileClass(const ParallelCompilationManager* manager,
                                  size_t class_def_index) {
...
  CompilerDriver* const driver = manager->GetCompiler();
...

  // Compile direct methods
  int64_t previous_direct_method_idx = -1;
  while (it.HasNextDirectMethod()) {
    uint32_t method_idx = it.GetMemberIndex();
    if (method_idx == previous_direct_method_idx) {
      // smali can create dex files with two encoded_methods sharing the same method_idx
      // http://code.google.com/p/smali/issues/detail?id=119
      it.Next();
      continue;
    }
    previous_direct_method_idx = method_idx;
    driver->CompileMethod(self, it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
                          it.GetMethodInvokeType(class_def), class_def_index,
                          method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level,
                          compilation_enabled);
    it.Next();
  }
  // Compile virtual methods
  int64_t previous_virtual_method_idx = -1;
  while (it.HasNextVirtualMethod()) {
    uint32_t method_idx = it.GetMemberIndex();
    if (method_idx == previous_virtual_method_idx) {
      // smali can create dex files with two encoded_methods sharing the same method_idx
      // http://code.google.com/p/smali/issues/detail?id=119
      it.Next();
      continue;
    }
    previous_virtual_method_idx = method_idx;
    driver->CompileMethod(self, it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
                          it.GetMethodInvokeType(class_def), class_def_index,
                          method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level,
                          compilation_enabled);
    it.Next();
  }
  DCHECK(!it.HasNext());
}

CompileMethod

從這里開始,我們終于深入到可以生成代碼的程度了腐泻。

void CompilerDriver::CompileMethod(Thread* self, 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,
                                   DexToDexCompilationLevel dex_to_dex_compilation_level,
                                   bool compilation_enabled) {
  CompiledMethod* compiled_method = nullptr;
  uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0;
  MethodReference method_ref(&dex_file, method_idx);

首先是對JNI調(diào)用的處理决乎,我們之前曾經(jīng)看到過的序列。這里會調(diào)用JniCompile函數(shù)派桩。下面開始處理JNI:

  if ((access_flags & kAccNative) != 0) {
    // Are we interpreting only and have support for generic JNI down calls?
    if (!compiler_options_->IsCompilationEnabled() &&
        InstructionSetHasGenericJniStub(instruction_set_)) {
      // Leaving this empty will trigger the generic JNI version
    } else {
      compiled_method = compiler_->JniCompile(access_flags, method_idx, dex_file);
      CHECK(compiled_method != nullptr);
    }

抽象方法不需要生成代碼:

  } else if ((access_flags & kAccAbstract) != 0) {
    // Abstract methods don't have code.

下面再開始編普通方法构诚,通過調(diào)用Compile方法來完成。

  } else {
    bool has_verified_method = verification_results_->GetVerifiedMethod(method_ref) != nullptr;
    bool compile = compilation_enabled &&
                   // Basic checks, e.g., not <clinit>.
                   verification_results_->IsCandidateForCompilation(method_ref, access_flags) &&
                   // Did not fail to create VerifiedMethod metadata.
                   has_verified_method &&
                   // Is eligable for compilation by methods-to-compile filter.
                   IsMethodToCompile(method_ref);
    if (compile) {
      // NOTE: if compiler declines to compile this method, it will return null.
      compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx,
                                           method_idx, class_loader, dex_file);
    }
...
}

如上一講我們所介紹的铆惑,ART有兩種Compiler范嘱,QuickCompiler和OptimizationCompiler。
所以员魏,根據(jù)dex2oat參數(shù)的不同丑蛤,分別調(diào)用這兩種Compiler的Compile方法來實現(xiàn)真正的編譯。

我們看一個圖來復(fù)習(xí)一下:

QuickCompiler_Compile
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末逆趋,一起剝皮案震驚了整個濱河市盏阶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌闻书,老刑警劉巖名斟,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異魄眉,居然都是意外死亡砰盐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門坑律,熙熙樓的掌柜王于貴愁眉苦臉地迎上來岩梳,“玉大人,你說我怎么就攤上這事晃择〖街担” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵宫屠,是天一觀的道長列疗。 經(jīng)常有香客問我,道長浪蹂,這世上最難降的妖魔是什么抵栈? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮坤次,結(jié)果婚禮上古劲,老公的妹妹穿的比我還像新娘缰猴。我一直安慰自己,他們只是感情好胰舆,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布焰扳。 她就那樣靜靜地躺著吨悍,像睡著了一般葫隙。 火紅的嫁衣襯著肌膚如雪恋脚。 梳的紋絲不亂的頭發(fā)上糟描,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音聊闯,去河邊找鬼。 笑死,一個胖子當著我的面吹牛弛针,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茧跋,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼粥烁,長吁一口氣:“原來是場噩夢啊……” “哼讨阻!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起奇瘦,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤瓶您,失蹤者是張志新(化名)和其女友劉穎贸毕,沒想到半個月后明棍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體摊腋,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡兴蒸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了岛啸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坚踩。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡芬首,死狀恐怖郁稍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布略步,位于F島的核電站趟薄,受9級特大地震影響绽诚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜杭煎,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一恩够、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧羡铲,春花似錦蜂桶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贾费,卻和暖如春钦购,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背褂萧。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工押桃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人导犹。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓唱凯,卻偏偏與公主長得像,于是被迫代替她去往敵國和親谎痢。 傳聞我的和親對象是個殘疾皇子磕昼,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,544評論 33 466
  • 參考鏈接: http://www.cnblogs.com/ioshe/p/5489086.html 簡介 Runt...
    樂樂的簡書閱讀 2,131評論 0 9
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,527評論 25 707
  • 今天好像沒有什么能說的了…… 哦哦,今天打掃了衛(wèi)生节猿,但是按照之前的計劃好想一個都沒有完成呢票从。真的是房間里面太冷了啊...
    淡淡的好嗎閱讀 145評論 0 0
  • 今天這個題目是馨兒給起的漫雕。見玩兒眼開,只要有機會玩兒馨兒就抓住不放峰鄙。也不知道這個叫什么浸间,馨兒說叫勇敢者之路,紅姑姑...
    yanzuliu閱讀 331評論 0 1