ART: Add compiled-methods
Add a dex2oat option for compiled-methods, a more granular filter
than compiled-classes. Add compiler-driver support for it.
Refactor dex2oat to reuse file reading.
Add a test to oat_test.
Change-Id: I78d0d040bce7738b4bb7aabe7768b5788d2587ac
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 1832647..e665e1d 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -76,8 +76,8 @@
// Whether to produce 64-bit ELF files for 64-bit targets. Leave this off for now.
static constexpr bool kProduce64BitELFFiles = false;
-// Whether classes-to-compile is only applied to the boot image, or, when given, too all
-// compilations.
+// Whether classes-to-compile and methods-to-compile are only applied to the boot image, or, when
+// given, too all compilations.
static constexpr bool kRestrictCompilationFiltersToImage = true;
static double Percentage(size_t x, size_t y) {
@@ -349,6 +349,7 @@
const InstructionSetFeatures* instruction_set_features,
bool image, std::unordered_set<std::string>* image_classes,
std::unordered_set<std::string>* compiled_classes,
+ std::unordered_set<std::string>* compiled_methods,
size_t thread_count, bool dump_stats, bool dump_passes,
const std::string& dump_cfg_file_name, CumulativeLogger* timer,
int swap_fd, const std::string& profile_file)
@@ -369,6 +370,7 @@
image_(image),
image_classes_(image_classes),
classes_to_compile_(compiled_classes),
+ methods_to_compile_(compiled_methods),
had_hard_verifier_failure_(false),
thread_count_(thread_count),
stats_(new AOTCompilationStats),
@@ -670,6 +672,19 @@
return classes_to_compile_->find(descriptor) != classes_to_compile_->end();
}
+bool CompilerDriver::IsMethodToCompile(const MethodReference& method_ref) const {
+ if (kRestrictCompilationFiltersToImage && !IsImage()) {
+ return true;
+ }
+
+ if (methods_to_compile_ == nullptr) {
+ return true;
+ }
+
+ std::string tmp = PrettyMethod(method_ref.dex_method_index, *method_ref.dex_file, true);
+ return methods_to_compile_->find(tmp.c_str()) != methods_to_compile_->end();
+}
+
static void ResolveExceptionsForMethod(MutableHandle<mirror::ArtMethod> method_handle,
std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -2232,7 +2247,9 @@
// Basic checks, e.g., not <clinit>.
verification_results_->IsCandidateForCompilation(method_ref, access_flags) &&
// Did not fail to create VerifiedMethod metadata.
- has_verified_method;
+ 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 nullptr.
compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx,
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index ce13a17..50e1fb1 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -104,6 +104,7 @@
const InstructionSetFeatures* instruction_set_features,
bool image, std::unordered_set<std::string>* image_classes,
std::unordered_set<std::string>* compiled_classes,
+ std::unordered_set<std::string>* compiled_methods,
size_t thread_count, bool dump_stats, bool dump_passes,
const std::string& dump_cfg_file_name,
CumulativeLogger* timer, int swap_fd,
@@ -428,6 +429,9 @@
// Checks whether the provided class should be compiled, i.e., is in classes_to_compile_.
bool IsClassToCompile(const char* descriptor) const;
+ // Checks whether the provided method should be compiled, i.e., is in method_to_compile_.
+ bool IsMethodToCompile(const MethodReference& method_ref) const;
+
void RecordClassStatus(ClassReference ref, mirror::Class::Status status)
LOCKS_EXCLUDED(compiled_classes_lock_);
@@ -597,6 +601,11 @@
// This option may be restricted to the boot image, depending on a flag in the implementation.
std::unique_ptr<std::unordered_set<std::string>> classes_to_compile_;
+ // Specifies the methods that will be compiled. Note that if methods_to_compile_ is nullptr,
+ // all methods are eligible for compilation (compilation filters etc. will still apply).
+ // This option may be restricted to the boot image, depending on a flag in the implementation.
+ std::unique_ptr<std::unordered_set<std::string>> methods_to_compile_;
+
bool had_hard_verifier_failure_;
size_t thread_count_;
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index e78ff90..ded50ca 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -175,6 +175,60 @@
}
}
+class CompilerDriverMethodsTest : public CompilerDriverTest {
+ protected:
+ std::unordered_set<std::string>* GetCompiledMethods() OVERRIDE {
+ return new std::unordered_set<std::string>({
+ "byte StaticLeafMethods.identity(byte)",
+ "int StaticLeafMethods.sum(int, int, int)",
+ "double StaticLeafMethods.sum(double, double, double, double)"
+ });
+ }
+};
+
+TEST_F(CompilerDriverMethodsTest, Selection) {
+ Thread* self = Thread::Current();
+ jobject class_loader;
+ {
+ ScopedObjectAccess soa(self);
+ class_loader = LoadDex("StaticLeafMethods");
+ }
+ ASSERT_NE(class_loader, nullptr);
+
+ // Need to enable dex-file writability. Methods rejected to be compiled will run through the
+ // dex-to-dex compiler.
+ for (const DexFile* dex_file : GetDexFiles(class_loader)) {
+ ASSERT_TRUE(dex_file->EnableWrite());
+ }
+
+ CompileAll(class_loader);
+
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ StackHandleScope<1> hs(self);
+ ScopedObjectAccess soa(self);
+ Handle<mirror::ClassLoader> h_loader(hs.NewHandle(
+ reinterpret_cast<mirror::ClassLoader*>(self->DecodeJObject(class_loader))));
+ mirror::Class* klass = class_linker->FindClass(self, "LStaticLeafMethods;", h_loader);
+ ASSERT_NE(klass, nullptr);
+
+ std::unique_ptr<std::unordered_set<std::string>> expected(GetCompiledMethods());
+
+ for (int32_t i = 0; static_cast<uint32_t>(i) < klass->NumDirectMethods(); i++) {
+ mirror::ArtMethod* m = klass->GetDirectMethod(i);
+ std::string name = PrettyMethod(m, true);
+ const void* code =
+ m->GetEntryPointFromQuickCompiledCodePtrSize(InstructionSetPointerSize(kRuntimeISA));
+ ASSERT_NE(code, nullptr);
+ if (expected->find(name) != expected->end()) {
+ expected->erase(name);
+ EXPECT_FALSE(class_linker->IsQuickToInterpreterBridge(code));
+ } else {
+ EXPECT_TRUE(class_linker->IsQuickToInterpreterBridge(code));
+ }
+ }
+ EXPECT_TRUE(expected->empty());
+}
+
// TODO: need check-cast test (when stub complete & we can throw/catch
} // namespace art