您的位置:首页 > 其它

art 是怎么把 dalvik 指令编译成 native code 第一篇(雾里看花)

2016-06-20 16:22 267 查看
compiler_kind :这个选项很重要,表示了用什么后端模式去编译 dalvik 指令

static int dex2oat(int argc, char** argv)
{
b13564922();

original_argc = argc;
original_argv = argv;

TimingLogger timings("compiler", false, false);
CumulativeLogger compiler_phases_timings("compilation times");

InitLogging(argv);

// Skip over argv[0].
argv++;
argc--;

if (argc == 0) {
Usage("No arguments specified");
}

std::vector<const char*> dex_filenames;
std::vector<const char*> dex_locations;
int zip_fd = -1;
std::string zip_location;
std::string oat_filename;
std::string oat_symbols;
std::string oat_location;
int oat_fd = -1;
std::string bitcode_filename;
const char* image_classes_zip_filename = nullptr;
const char* image_classes_filename = nullptr;
const char* compiled_classes_zip_filename = nullptr;
const char* compiled_classes_filename = nullptr;
std::string image_filename;
std::string boot_image_filename;
uintptr_t image_base = 0;
std::string android_root;
std::vector<const char*> runtime_args;
int thread_count = sysconf(_SC_NPROCESSORS_CONF);
/********************************************************
(runtime) Globals.h 中,ART_USE_PORTABLE_COMPILER 在编
译中默认是未开启的。 所以是false ,默认是 Compiler::kQuick
#if defined(ART_USE_PORTABLE_COMPILER)
static constexpr bool kUsePortableCompiler = true;
#else
static constexpr bool kUsePortableCompiler = false;
#endif
********************************************************/
Compiler::Kind ***compiler_kind*** = kUsePortableCompiler
? Compiler::kPortable
: Compiler::kQuick;

.......
//我了个去,省去了好大堆参数解析,记住自己要分析的选项,这里就不说了。

// Set the compilation target's implicit checks options.

switch (instruction_set) {
case kArm:
case kThumb2:
case kArm64:
case kX86:
case kX86_64:
implicit_null_checks = true;
implicit_so_checks = true;
break;

default:
// Defaults are correct.
break;
}
//把编译选项都堆在里面去,不管身材怎么样,穿上一身华丽的衣服。
std::unique_ptr<CompilerOptions> compiler_options(new CompilerOptions(compiler_filter,
huge_method_threshold,
large_method_threshold,
small_method_threshold,
tiny_method_threshold,
num_dex_methods_threshold,
generate_gdb_information,
include_patch_information,
top_k_profile_threshold,
include_debug_symbols,
implicit_null_checks,
implicit_so_checks,
implicit_suspend_checks,
compile_pic
#ifdef ART_SEA_IR_MODE
, compiler_options.sea_ir_ =
true;
#endif
));  // NOLINT(whitespace/parens)

.........

Dex2Oat* p_dex2oat;
//这里开始进入主题了。
if (!Dex2Oat::Create(&p_dex2oat,
runtime_options,
*compiler_options,
compiler_kind,
instruction_set,
instruction_set_features,
verification_results.get(),
&method_inliner_map,
thread_count)) {
LOG(ERROR) << "Failed to create dex2oat";
timings.EndTiming();
oat_file->Erase();
return EXIT_FAILURE;
}
std::unique_ptr<Dex2Oat> dex2oat(p_dex2oat);

// Runtime::Create acquired the mutator_lock_ that is normally given away when we Runtime::Start,
// give it away now so that we don't starve GC.
Thread* self = Thread::Current();
self->TransitionFromRunnableToSuspended(kNative);
// If we're doing the image, override the compiler filter to force full compilation. Must be
// done ahead of WellKnownClasses::Init that causes verification.  Note: doesn't force
// compilation of class initializers.
// Whilst we're in native take the opportunity to initialize well known
4000
classes.
WellKnownClasses::Init(self->GetJniEnv());

// If --image-classes was specified, calculate the full list of classes to include in the image
std::unique_ptr<std::set<std::string>> image_classes(nullptr);
if (image_classes_filename != nullptr) {
std::string error_msg;
if (image_classes_zip_filename != nullptr) {
image_classes.reset(dex2oat->ReadImageClassesFromZip(image_classes_zip_filename,
image_classes_filename,
&error_msg));
} else {
image_classes.reset(dex2oat->ReadImageClassesFromFile(image_classes_filename));
}
if (image_classes.get() == nullptr) {
LOG(ERROR) << "Failed to create list of image classes from '" << image_classes_filename <<
"': " << error_msg;
timings.EndTiming();
oat_file->Erase();
return EXIT_FAILURE;
}
} else if (image) {
image_classes.reset(new std::set<std::string>);
}
// If --compiled-classes was specified, calculate the full list of classes to compile in the
// image.
std::unique_ptr<std::set<std::string>> compiled_classes(nullptr);
if (compiled_classes_filename != nullptr) {
std::string error_msg;
if (compiled_classes_zip_filename != nullptr) {
compiled_classes.reset(dex2oat->ReadImageClassesFromZip(compiled_classes_zip_filename,
compiled_classes_filename,
&error_msg));
} else {
compiled_classes.reset(dex2oat->ReadImageClassesFromFile(compiled_classes_filename));
}
if (compiled_classes.get() == nullptr) {
LOG(ERROR) << "Failed to create list of compiled classes from '" << compiled_classes_filename
<< "': " << error_msg;
timings.EndTiming();
oat_file->Erase();
return EXIT_FAILURE;
}
} else if (image) {
compiled_classes.reset(nullptr);  // By default compile everything.
}

std::vector<const DexFile*> dex_files;
if (boot_image_option.empty()) {
dex_files = Runtime::Current()->GetClassLinker()->GetBootClassPath();
} else {
if (dex_filenames.empty()) {
ATRACE_BEGIN("Opening zip archive from file descriptor");
std::string error_msg;
std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(zip_fd, zip_location.c_str(),
&error_msg));
if (zip_archive.get() == nullptr) {
LOG(ERROR) << "Failed to open zip from file descriptor for '" << zip_location << "': "
<< error_msg;
timings.EndTiming();
oat_file->Erase();
return EXIT_FAILURE;
}
if (!DexFile::OpenFromZip(*zip_archive.get(), zip_location, &error_msg, &dex_files)) {
LOG(ERROR) << "Failed to open dex from file descriptor for zip file '" << zip_location
<< "': " << error_msg;
timings.EndTiming();
oat_file->Erase();
return EXIT_FAILURE;
}
ATRACE_END();
} else {
size_t failure_count = OpenDexFiles(dex_filenames, dex_locations, dex_files);
if (failure_count > 0) {
LOG(ERROR) << "Failed to open some dex files: " << failure_count;
timings.EndTiming();
oat_file->Erase();
return EXIT_FAILURE;
}
}

const bool kSaveDexInput = false;
if (kSaveDexInput) {
for (size_t i = 0; i < dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
std::string tmp_file_name(StringPrintf("/data/local/tmp/dex2oat.%d.%zd.dex", getpid(), i));
std::unique_ptr<File> tmp_file(OS::CreateEmptyFile(tmp_file_name.c_str()));
if (tmp_file.get() == nullptr) {
PLOG(ERROR) << "Failed to open file " << tmp_file_name
<< ". Try: adb shell chmod 777 /data/local/tmp";
continue;
}
// This is just dumping files for debugging. Ignore errors, and leave remnants.
UNUSED(tmp_file->WriteFully(dex_file->Begin(), dex_file->Size()));
UNUSED(tmp_file->Flush());
UNUSED(tmp_file->Close());
LOG(INFO) << "Wrote input to " << tmp_file_name;
}
}
}
// Ensure opened dex files are writable for dex-to-dex transformations.
for (const auto& dex_file : dex_files) {
if (!dex_file->EnableWrite()) {
PLOG(ERROR) << "Failed to make .dex file writeable '" << dex_file->GetLocation() << "'\n";
}
}
// If we use a swap file, ensure we are above the threshold to make it necessary.
if (swap_fd != -1) {
if (!UseSwap(image, dex_files)) {
close(swap_fd);
swap_fd = -1;
LOG(INFO) << "Decided to run without swap.";
} else {
LOG(INFO) << "Accepted running with swap.";
}
}

/*
* If we're not in interpret-only or verify-none mode, go ahead and compile small applications.
* Don't bother to check if we're doing the image.
*/
if (!image && compiler_options->IsCompilationEnabled()) {
size_t num_methods = 0;
for (size_t i = 0; i != dex_files.size(); ++i) {
const DexFile* dex_file = dex_files[i];
CHECK(dex_file != nullptr);
num_methods += dex_file->NumMethodIds();
}
if (num_methods <= compiler_options->GetNumDexMethodsThreshold()) {
compiler_options->SetCompilerFilter(CompilerOptions::kSpeed);
VLOG(compiler) << "Below method threshold, compiling anyways";
}
}

// Fill some values into the key-value store for the oat header.
std::unique_ptr<SafeMap<std::string, std::string> > key_value_store(
new SafeMap<std::string, std::string>());

// Insert some compiler things.
{
std::ostringstream oss;
for (int i = 0; i < argc; ++i) {
if (i > 0) {
oss << ' ';
}
oss << argv[i];
}
key_value_store->Put(OatHeader::kDex2OatCmdLineKey, oss.str());
oss.str("");  // Reset.
oss << kRuntimeISA;
key_value_store->Put(OatHeader::kDex2OatHostKey, oss.str());
key_value_store->Put(OatHeader::kPicKey, compile_pic ? "true" : "false");
}
//在这里对dex 文件进行编译,创建 oat file。
std::unique_ptr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option,
android_root,
is_host,
dex_files,
oat_file.get(),
oat_location,
bitcode_filename,
image,
image_classes,
compiled_classes,
dump_stats,
dump_passes,
timings,
compiler_phases_timings,
swap_fd,
profile_file,
key_value_store.get()));
if (compiler.get() == nullptr) {
LOG(ERROR) << "Failed to create oat file: " << oat_location;
timings.EndTiming();
return EXIT_FAILURE;
}

if (!kUsePortableCompiler) {
if (oat_file->FlushCloseOrErase() != 0) {
PLOG(ERROR) << "Failed to flush and close oat file: " << oat_location;
timings.EndTiming();
return EXIT_FAILURE;
}
oat_file.reset();
}

.........

return EXIT_SUCCESS;
}


const CompilerDriver* CreateOatFile(const std::string& boot_image_option,
const std::string& android_root,
bool is_host,
const std::vector<const DexFile*>& dex_files,
File* oat_file,
const std::string& oat_location,
const std::string& bitcode_filename,
bool image,
std::unique_ptr<std::set<std::string>>& image_classes,
std::unique_ptr<std::set<std::string>>& compiled_classes,
bool dump_stats,
bool dump_passes,
TimingLogger& timings,
CumulativeLogger& compiler_phases_timings,
int swap_fd,
std::string profile_file,
SafeMap<std::string, std::string>* key_value_store)
{
CHECK(key_value_store != nullptr);

// Handle and ClassLoader creation needs to come after Runtime::Create
jobject class_loader = nullptr;
Thread* self = Thread::Current();
if (!boot_image_option.empty())
{
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
std::vector<const DexFile*> class_path_files(dex_files);
OpenClassPathFiles(runtime_->GetClassPathString(), class_path_files);
ScopedObjectAccess soa(self);
for (size_t i = 0; i < class_path_files.size(); i++)
{
class_linker->RegisterDexFile(*class_path_files[i]);
}
soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader);
ScopedLocalRef<jobject> class_loader_local(soa.Env(),
soa.Env()->AllocObject(WellKnownClasses::dalvik_system_PathClassLoader));
class_loader = soa.Env()->NewGlobalRef(class_loader_local.get());
Runtime::Current()->SetCompileTimeClassPath(class_loader, class_path_files);
}

std::unique_ptr<CompilerDriver> driver(new CompilerDriver(compiler_options_,
verification_results_,
method_inliner_map_,
compiler_kind_,
instruction_set_,
instruction_set_features_,
image,
image_classes.release(),
compiled_classes.release(),
thread_count_,
dump_stats,
dump_passes,
&compiler_phases_timings,
swap_fd,
profile_file));

driver->GetCompiler()->SetBitcodeFileName(*driver.get(), bitcode_filename);

driver->CompileAll(class_loader, dex_files, &timings);

TimingLogger::ScopedTiming t2("dex2oat OatWriter", &timings);
std::string image_file_location;
uint32_t image_file_location_oat_checksum = 0;
uintptr_t image_file_location_oat_data_begin = 0;
int32_t image_patch_delta = 0;
if (!driver->IsImage()) {
TimingLogger::ScopedTiming t3("Loading image checksum", &timings);
gc::space::ImageSpace* image_space = Runtime::Current()->GetHeap()->GetImageSpace();
image_file_location_oat_checksum = image_space->GetImageHeader().GetOatChecksum();
image_file_location_oat_data_begin =
reinterpret_cast<uintptr_t>(image_space->GetImageHeader().GetOatDataBegin());
image_file_location = image_space->GetImageFilename();
image_patch_delta = image_space->GetImageHeader().GetPatchDelta();
}

if (!image_file_location.empty()) {
key_value_store->Put(OatHeader::kImageLocationKey, image_file_location);
}

OatWriter oat_writer(dex_files, image_file_location_oat_checksum,
image_file_location_oat_data_begin,
image_patch_delta,
driver.get(),
&timings,
key_value_store);

t2.NewTiming("Writing ELF");
if (!driver->WriteElf(android_root, is_host, dex_files, &oat_writer, oat_file)) {
LOG(ERROR) << "Failed to write ELF file " << oat_file->GetPath();
oat_file->Erase();
return nullptr;
}

// Flush result to disk. Patching code will re-open the file (mmap), so ensure that our view
// of the file already made it there and won't be re-ordered with writes from PatchOat or
// image patching.
if (oat_file->Flush() != 0) {
PLOG(ERROR) << "Failed flushing oat file " << oat_file->GetPath();
oat_file->Erase();
return nullptr;
}

if (!driver->IsImage() && driver->GetCompilerOptions().GetIncludePatchInformation()) {
t2.NewTiming("Patching ELF");
std::string error_msg;
if (!PatchOatCode(driver.get(), oat_file, oat_location, &error_msg)) {
LOG(ERROR) << "Failed to fixup ELF file " << oat_file->GetPath() << ": " << error_msg;
oat_file->Erase();
return nullptr;
}
}

return driver.release();
}


Compiler* Compiler::Create(CompilerDriver* driver, Compiler::Kind kind) {
switch (kind) {
case kQuick:
return new QuickCompiler(driver);
break;
case kOptimizing:
return new OptimizingCompiler(driver);
break;
case kPortable:
#ifdef ART_USE_PORTABLE_COMPILER
return new LLVMCompiler(driver);
#else
LOG(FATAL) << "Portable compiler not compiled";
#endif
break;
default:
LOG(FATAL) << "UNREACHABLE";
}
return nullptr;
}


CreateOatFile 中创建了一个 CompilerDriver 类的对象,它是整个编译过程中的一个驱动者,它处理前面设置好的参数把编译事项吩咐下去。

在构造CompilerDriver 过程中,有我们关心的一点就是根据 CompilerDriver 传进去的 Compiler::Kind compiler_kind 去设置具体的 compiler_(Compiler::Create(this, compiler_kind)) 具体可以看代码片段 Compiler* Compiler::Create(CompilerDriver* driver, Compiler::Kind kind) 函数。

默认是 return new QuickCompiler(driver); Quick 后端。这里说个体外话(很多人以为 art 是通过 llvm 对dex 做的编译,其实不是,源码目录 compiler 目录下的 portable 就是用的llvm,可自从android 4.4 加入art以来,这个就没有用过。那么Quick 从哪里来的呢?我在网上看到有人说是从Dalvik 本身的 JIT

编译器改造而来,我也没去证实过)

去给我干活。编译dex。

driver->CompileAll(class_loader, dex_files, &timings);

后面还有会陆续分析,也是业余爱好,没什么水平,谢谢批评。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  art-分析