ART世界探险(15) - Compiler,ClassLinker,Runtime三大组件

ART世界探险(15) - Compiler,ClassLinker,Runtime三大组件

CompilerDriver

调用编译器的接口是CompilerDriver。
我们看一看CompilerDriver的结构图吧:

CompilerDriver

这是我们在ART里能遇见的第一个复杂的大类。但凡编译相关,都要通过它来打交道。结果,它就把自己搞成了一个大杂烩。

ClassLinker

Java是门面向对象的语言,导致类相关的操作比较复杂。
在应用层有ClassLoader,在运行环境层就有ClassLinker。
我们看一下ClassLinker的公开方法,私有的还有同样多的,汗。

ClassLinker

ClassLinker相对于CompilerDriver,逻辑上更为集中一些。
它主要是提供跟类相关的操作,包括类级的分配对象等。
CompilerDriver提供的主要是编译期底层代码的功能,而ClassLinker在面向对象的逻辑层提供服务。

Runtime

ART是Android Runtime的缩写,我们终于可以揭开Android Runtime的面纱了。

Runtime

Runtime主要是提供一些运行时的服务,最重要的当然就是GC。另外,还有多线程和线程安全相关的支持,事务相关的支持等。

有了上面三个大组件的支持,不管是编译期还是运行时,我们都可以找到支持Java方法运行的基础设施。

最后,我们再复习一下上节最后出现的编译单元类:

CompilationUnit

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

将前端的DexFile通过CompilerDriver进行编译之后,我们先得到中间层中间代码MIR,MIRGraph就是这一步要做的工作。很多优化也是在这一步完成的。
然后,再通过Mir2Lir,将MIR转化成更接近于机器指令的低层中间代码LIR。
最后,再将LIR落地成目标机器的指令。

dex2oat编译流程(续)

首先我们复习一下之前学到的,dex2oat做为入口点,会调用CompilerDriver的方法对dex文件进行编译。

dex2oat-1

下面该开始CompilerDriver的CompileClass,看了CompilerDriver的大图之后,对于它是不是更亲切了呢?

CompileClass

编译类的重头戏还在于编译方法。
CompileClass类的主要逻辑,就是针对直接方法和虚拟方法,分别遍历然后编译。

我们将前面的判断和校验等细节都略过,这个函数的框架如下面所示:

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调用的处理,我们之前曾经看到过的序列。这里会调用JniCompile函数。下面开始处理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.

下面再开始编普通方法,通过调用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。
所以,根据dex2oat参数的不同,分别调用这两种Compiler的Compile方法来实现真正的编译。

我们看一个图来复习一下:

QuickCompiler_Compile
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容

  • 这篇文章完全是基于南峰子老师博客的转载 这篇文章完全是基于南峰子老师博客的转载 这篇文章完全是基于南峰子老师博客的...
    西木阅读 30,554评论 33 466
  • 参考链接: http://www.cnblogs.com/ioshe/p/5489086.html 简介 Runt...
    乐乐的简书阅读 2,135评论 0 9
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,072评论 25 707
  • 今天好像没有什么能说的了…… 哦哦,今天打扫了卫生,但是按照之前的计划好想一个都没有完成呢。真的是房间里面太冷了啊...
    淡淡的好吗阅读 151评论 0 0
  • 今天这个题目是馨儿给起的。见玩儿眼开,只要有机会玩儿馨儿就抓住不放。也不知道这个叫什么,馨儿说叫勇敢者之路,红姑姑...
    yanzuliu阅读 333评论 0 1