Android-P-JIT 学习笔记(2)

96
十八垧
2019.03.19 11:28* 字数 1034

Android安全交流群:478084054

在上篇笔记的最后贴了一段代码,是JIT的创建。


但我当时可能理解错了,以为CreateJit是创建JIT,而下面的RegisterAppInfo是用来启动“save profiling info”工作的,因为RegisterAppInfo的代码是这样的:

但今天在Android P手机上抓日志时,没有看到RegisterAppInfo函数中打印的信息,然后又去扫了一下ART启动参数,貌似也没有设置“profile-path:”命令行参数,所以jit_options_->GetProfileSaverOptions().GetProfilePath().empty()可能是返回了true,所以根本没调RegisterAppInfo。

再结合注释:“This is used when testing profiles with dalvikvm command as there is no framework to register the dex files for profiling.”,可能这块调用RegisterAppInfo只是为了测试,在使用的时候通过dalvikvm command命令行进行设置。

先不纠结,边学习边摸索吧。以后如果有大块的时间,能够调试Android系统源码或者自己编译系统并加上更多的日志,那样就能理解的更清楚了。先继续扫代码。

在Runtime::CreateJit中调用Jit::Create。

Jit::Create先DCHECK了一下options->UseJitCompilation和options->GetProfileSaverOptions。如果既不需要JIT编译,又不需要“save profiling info(为了支援Profile-guided compilation)”,那就没必要创建JIT,代码流程不应该走到这里。

然后主要做三件事:

1)调用LoadCompiler加载编译器。

2)调用JitCodeCache::Create创建code_cache(JIT编译的结果要存储到code_cache中)。

3)调用CreateThreadPool创建线程池。

另外,如果options->UseJitCompilation返回false的话,那么创建JIT就只是为了“save profiling info”,所以将变量code_cache_only_for_profile_data置为true。

我这截了一份JIT运行日志,看一下Jit::Create相关的这一行(主要是profile_saver_options):

JIT created with initial_capacity=64KB, max_capacity=64MB, compile_threshold=10000, profile_saver_options=enabled_1, min_save_period_ms_40000, save_resolved_classes_delay_ms_5000, hot_startup_method_samples_4294967295, min_methods_to_save_10, min_classes_to_save_10, min_notification_before_wake_10, max_notification_before_wake_50, profile_boot_class_path_0, profile_aot_code_0, wait_for_jit_notifications_to_save_1

来看Jit::LoadCompiler:

在Jit::LoadCompiler中先调用LoadCompilerLibrary加载libart-compiler.so,并从中找到“jit_load”等符号,然后再调用jit_load来加载JIT。

在Jit::LoadCompilerLibrary中,除了符号“jit_load”之外,还找了“jit_unload”、“jit_compile_method”和“jit_types_loaded”。其中“jit_compile_method”应该就是具体用来对某个Java方法进行编译的了。

libart-compiler.so对应的源码在art/compiler,上述4个符号在art/compiler/jit/jit_compiler.cc中导出。

jit_load会调用JitCompiler::Create,JitCompiler::Create的源码在art/compiler/jit/jit_compiler.cc中。

在JitCompiler::Create中new了一个JitCompiler类的对象。jit_compile_method就是调用JitCompiler对象的CompileMethod成员函数完成method编译的。这些Compiler部分的代码先看到这,后面有时间再继续跟。

回到Jit::Create,接着看一下JitCodeCache::Create。

首先分配一块大小为max_capacity的内存,然后前半部分作为“data-code-cache”,后半部分重新映射为“jit-code-cache”。看这意思貌似是前半部分存data,后半部分存code。

如果JIT只是为了“save profiling info”,那“jit-code-cache”就不需要PROT_EXEC,因为运行时不会去执行JIT编译代码。

然后计算初始的data_size和code_size(将initial_capacity一分为2),再加上code_map/data_map地址等作为参数去创建一个JitCodeCache对象。这个JitCodeCache对象内部持有一份内存缓冲区,用来存放JIT产生的数据和代码。

再回到Jit::Create,最后看一下Jit::CreateThreadPool。

先创建了一个线程池,然后调用Jit::Start。

接着看ThreadPool::StartWorkers。

JIT的工作就是通过这个线程池来完成的。

例如:在Jit::AddSamples中向线程池中添加JitCompileTask::kCompile或者JitCompileTask::kCompileOsr任务,这两个任务都是用来编译method的。

文/十八垧

日记本
Web note ad 1