diff options
52 files changed, 3504 insertions, 836 deletions
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc index a5c885a933..80cfc83d3c 100644 --- a/adbconnection/adbconnection.cc +++ b/adbconnection/adbconnection.cc @@ -63,9 +63,7 @@ static constexpr int kControlSockSendTimeout = 10; static AdbConnectionState* gState; static bool IsDebuggingPossible() { - // TODO We need to do this on IsJdwpAllowed not IsDebuggable in order to support userdebug - // workloads. For now we will only allow it when we are debuggable so that testing is easier. - return art::Runtime::Current()->IsJavaDebuggable() && art::Dbg::IsJdwpAllowed(); + return art::Dbg::IsJdwpAllowed(); } // Begin running the debugger. @@ -581,11 +579,14 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) { DCHECK(!agent_has_socket_); if (!agent_loaded_) { DCHECK(!agent_listening_); + // TODO Should we check in some other way if we are userdebug/eng? + CHECK(art::Dbg::IsJdwpAllowed()); // Load the agent now! self->AssertNoPendingException(); art::Runtime::Current()->AttachAgent(/* JNIEnv* */ nullptr, MakeAgentArg(), - /* classloader */ nullptr); + /* classloader */ nullptr, + /*allow_non_debuggable_tooling*/ true); if (self->IsExceptionPending()) { LOG(ERROR) << "Failed to load agent " << agent_name_; art::ScopedObjectAccess soa(self); diff --git a/compiler/Android.bp b/compiler/Android.bp index 164f9c1e8f..d4d72f380b 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -249,6 +249,13 @@ art_cc_library { shared_libs: [ "libart", ], + + pgo: { + instrumentation: true, + profile_file: "dex2oat.profdata", + benchmarks: ["dex2oat"], + enable_profile_use: false, + } } art_cc_library { diff --git a/compiler/utils/test_dex_file_builder.h b/compiler/utils/test_dex_file_builder.h index 04fba51dc1..58f1ec7b08 100644 --- a/compiler/utils/test_dex_file_builder.h +++ b/compiler/utils/test_dex_file_builder.h @@ -27,6 +27,7 @@ #include <android-base/logging.h> #include "base/bit_utils.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file_loader.h" #include "dex/standard_dex_file.h" @@ -233,7 +234,8 @@ class TestDexFileBuilder { static constexpr bool kVerify = false; static constexpr bool kVerifyChecksum = false; std::string error_msg; - std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open( + const ArtDexFileLoader dex_file_loader; + std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open( &dex_file_data_[0], dex_file_data_.size(), dex_location, diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp index 6bebf7d2da..dc71b9ba3e 100644 --- a/dex2oat/Android.bp +++ b/dex2oat/Android.bp @@ -129,6 +129,18 @@ art_cc_binary { static_libs: [ "libart-dex2oat", ], + + pgo: { + instrumentation: true, + profile_file: "dex2oat.profdata", + benchmarks: ["dex2oat"], + enable_profile_use: false, + cflags: [ + // Ignore frame-size increase resulting from instrumentation. + "-Wno-frame-larger-than=", + "-DART_PGO_INSTRUMENTATION", + ], + } } art_cc_binary { diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 8d0d89ed5c..23af2ab6e3 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -3063,9 +3063,9 @@ static dex2oat::ReturnCode Dex2oat(int argc, char** argv) { int main(int argc, char** argv) { int result = static_cast<int>(art::Dex2oat(argc, argv)); // Everything was done, do an explicit exit here to avoid running Runtime destructors that take - // time (bug 10645725) unless we're a debug build or running on valgrind. Note: The Dex2Oat class - // should not destruct the runtime in this case. - if (!art::kIsDebugBuild && (RUNNING_ON_MEMORY_TOOL == 0)) { + // time (bug 10645725) unless we're a debug or instrumented build or running on valgrind. Note: + // The Dex2Oat class should not destruct the runtime in this case. + if (!art::kIsDebugBuild && !art::kIsPGOInstrumentation && (RUNNING_ON_MEMORY_TOOL == 0)) { _exit(result); } return result; diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc index 980363b1bb..05592f1806 100644 --- a/dex2oat/dex2oat_image_test.cc +++ b/dex2oat/dex2oat_image_test.cc @@ -29,6 +29,7 @@ #include "base/file_utils.h" #include "base/macros.h" #include "base/unix_file/fd_file.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" #include "jit/profile_compilation_info.h" @@ -65,12 +66,13 @@ class Dex2oatImageTest : public CommonRuntimeTest { for (const std::string& dex : GetLibCoreDexFileNames()) { std::vector<std::unique_ptr<const DexFile>> dex_files; std::string error_msg; - CHECK(DexFileLoader::Open(dex.c_str(), - dex, - /*verify*/ true, - /*verify_checksum*/ false, - &error_msg, - &dex_files)) + const ArtDexFileLoader dex_file_loader; + CHECK(dex_file_loader.Open(dex.c_str(), + dex, + /*verify*/ true, + /*verify_checksum*/ false, + &error_msg, + &dex_files)) << error_msg; for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { for (size_t i = 0; i < dex_file->NumMethodIds(); ++i) { diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index e98cb743a9..8799540fd3 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -30,6 +30,7 @@ #include "base/macros.h" #include "base/mutex-inl.h" #include "bytecode_utils.h" +#include "dex/art_dex_file_loader.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" @@ -684,7 +685,8 @@ class Dex2oatLayoutTest : public Dex2oatTest { const char* location = dex_location.c_str(); std::string error_msg; std::vector<std::unique_ptr<const DexFile>> dex_files; - ASSERT_TRUE(DexFileLoader::Open( + const ArtDexFileLoader dex_file_loader; + ASSERT_TRUE(dex_file_loader.Open( location, location, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files)); EXPECT_EQ(dex_files.size(), 1U); std::unique_ptr<const DexFile>& dex_file = dex_files[0]; @@ -819,7 +821,8 @@ class Dex2oatLayoutTest : public Dex2oatTest { const char* location = dex_location.c_str(); std::vector<std::unique_ptr<const DexFile>> dex_files; - ASSERT_TRUE(DexFileLoader::Open( + const ArtDexFileLoader dex_file_loader; + ASSERT_TRUE(dex_file_loader.Open( location, location, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files)); EXPECT_EQ(dex_files.size(), 1U); std::unique_ptr<const DexFile>& old_dex_file = dex_files[0]; diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 16d70daddf..cecd376be5 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -33,6 +33,7 @@ #include "class_table-inl.h" #include "compiled_method-inl.h" #include "debug/method_debug_info.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" #include "dex/dex_file_types.h" @@ -3392,6 +3393,7 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil std::string error_msg; std::string location(oat_dex_file->GetLocation()); std::unique_ptr<const DexFile> dex_file; + const ArtDexFileLoader dex_file_loader; if (oat_dex_file->source_.IsZipEntry()) { ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry(); std::unique_ptr<MemMap> mem_map( @@ -3400,12 +3402,12 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil LOG(ERROR) << "Failed to extract dex file to mem map for layout: " << error_msg; return false; } - dex_file = DexFileLoader::Open(location, - zip_entry->GetCrc32(), - std::move(mem_map), - /* verify */ true, - /* verify_checksum */ true, - &error_msg); + dex_file = dex_file_loader.Open(location, + zip_entry->GetCrc32(), + std::move(mem_map), + /* verify */ true, + /* verify_checksum */ true, + &error_msg); } else if (oat_dex_file->source_.IsRawFile()) { File* raw_file = oat_dex_file->source_.GetRawFile(); int dup_fd = dup(raw_file->Fd()); @@ -3413,7 +3415,7 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil PLOG(ERROR) << "Failed to dup dex file descriptor (" << raw_file->Fd() << ") at " << location; return false; } - dex_file = DexFileLoader::OpenDex( + dex_file = dex_file_loader.OpenDex( dup_fd, location, /* verify */ true, /* verify_checksum */ true, &error_msg); } else { // The source data is a vdex file. @@ -3426,14 +3428,14 @@ bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_fil DCHECK(ValidateDexFileHeader(raw_dex_file, oat_dex_file->GetLocation())); const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(raw_dex_file); // Since the source may have had its layout changed, or may be quickened, don't verify it. - dex_file = DexFileLoader::Open(raw_dex_file, - header->file_size_, - location, - oat_dex_file->dex_file_location_checksum_, - nullptr, - /* verify */ false, - /* verify_checksum */ false, - &error_msg); + dex_file = dex_file_loader.Open(raw_dex_file, + header->file_size_, + location, + oat_dex_file->dex_file_location_checksum_, + nullptr, + /* verify */ false, + /* verify_checksum */ false, + &error_msg); } if (dex_file == nullptr) { LOG(ERROR) << "Failed to open dex file for layout: " << error_msg; @@ -3653,6 +3655,7 @@ bool OatWriter::OpenDexFiles( << " error: " << error_msg; return false; } + const ArtDexFileLoader dex_file_loader; std::vector<std::unique_ptr<const DexFile>> dex_files; for (OatDexFile& oat_dex_file : oat_dex_files_) { const uint8_t* raw_dex_file = @@ -3674,14 +3677,14 @@ bool OatWriter::OpenDexFiles( } // Now, open the dex file. - dex_files.emplace_back(DexFileLoader::Open(raw_dex_file, - oat_dex_file.dex_file_size_, - oat_dex_file.GetLocation(), - oat_dex_file.dex_file_location_checksum_, - /* oat_dex_file */ nullptr, - verify, - verify, - &error_msg)); + dex_files.emplace_back(dex_file_loader.Open(raw_dex_file, + oat_dex_file.dex_file_size_, + oat_dex_file.GetLocation(), + oat_dex_file.dex_file_location_checksum_, + /* oat_dex_file */ nullptr, + verify, + verify, + &error_msg)); if (dex_files.back() == nullptr) { LOG(ERROR) << "Failed to open dex file from oat file. File: " << oat_dex_file.GetLocation() << " Error: " << error_msg; @@ -3689,7 +3692,7 @@ bool OatWriter::OpenDexFiles( } // Set the class_offsets size now that we have easy access to the DexFile and - // it has been verified in DexFileLoader::Open. + // it has been verified in dex_file_loader.Open. oat_dex_file.class_offsets_.resize(dex_files.back()->GetHeader().class_defs_size_); } diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc index 2c98e12741..8132323203 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -44,6 +44,7 @@ #include "android-base/stringprintf.h" +#include "dex/art_dex_file_loader.h" #include "dex/code_item_accessors-no_art-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_exception_helpers.h" @@ -1879,8 +1880,10 @@ int processFile(const char* fileName) { // all of which are Zip archives with "classes.dex" inside. const bool kVerifyChecksum = !gOptions.ignoreBadChecksum; std::string error_msg; + // TODO: Use DexFileLoader when that is implemented. + const ArtDexFileLoader dex_file_loader; std::vector<std::unique_ptr<const DexFile>> dex_files; - if (!DexFileLoader::Open( + if (!dex_file_loader.Open( fileName, fileName, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) { // Display returned error message to user. Note that this error behavior // differs from the error messages shown by the original Dalvik dexdump. diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp index a02f75ad00..4f5d81095f 100644 --- a/dexlayout/Android.bp +++ b/dexlayout/Android.bp @@ -34,6 +34,13 @@ art_cc_library { name: "libart-dexlayout", defaults: ["libart-dexlayout-defaults"], shared_libs: ["libart"], + + pgo: { + instrumentation: true, + profile_file: "dex2oat.profdata", + benchmarks: ["dex2oat"], + enable_profile_use: false, + } } art_cc_library { diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index 000d1356b9..a43dd074f8 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -34,6 +34,7 @@ #include "android-base/stringprintf.h" #include "base/logging.h" // For VLOG_IS_ON. +#include "dex/art_dex_file_loader.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_layout.h" #include "dex/dex_file_loader.h" @@ -1923,14 +1924,16 @@ void DexLayout::ProcessDexFile(const char* file_name, if (options_.verify_output_) { std::string error_msg; std::string location = "memory mapped file for " + std::string(file_name); - std::unique_ptr<const DexFile> output_dex_file(DexFileLoader::Open(mem_map_->Begin(), - file_size, - location, - /* checksum */ 0, - /*oat_dex_file*/ nullptr, - /*verify*/ true, - /*verify_checksum*/ false, - &error_msg)); + const ArtDexFileLoader dex_file_loader; + std::unique_ptr<const DexFile> output_dex_file( + dex_file_loader.Open(mem_map_->Begin(), + file_size, + location, + /* checksum */ 0, + /*oat_dex_file*/ nullptr, + /*verify*/ true, + /*verify_checksum*/ false, + &error_msg)); CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg; // Do IR-level comparison between input and output. This check ignores potential differences @@ -1961,8 +1964,9 @@ int DexLayout::ProcessFile(const char* file_name) { // all of which are Zip archives with "classes.dex" inside. const bool verify_checksum = !options_.ignore_bad_checksum_; std::string error_msg; + const ArtDexFileLoader dex_file_loader; std::vector<std::unique_ptr<const DexFile>> dex_files; - if (!DexFileLoader::Open( + if (!dex_file_loader.Open( file_name, file_name, /* verify */ true, verify_checksum, &error_msg, &dex_files)) { // Display returned error message to user. Note that this error behavior // differs from the error messages shown by the original Dalvik dexdump. diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc index 5da3b1d366..3a7f9eeda6 100644 --- a/dexlayout/dexlayout_test.cc +++ b/dexlayout/dexlayout_test.cc @@ -23,6 +23,7 @@ #include "base/unix_file/fd_file.h" #include "common_runtime_test.h" +#include "dex/art_dex_file_loader.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" @@ -318,12 +319,13 @@ class DexLayoutTest : public CommonRuntimeTest { bool MutateDexFile(File* output_dex, const std::string& input_jar, const Mutator& mutator) { std::vector<std::unique_ptr<const DexFile>> dex_files; std::string error_msg; - CHECK(DexFileLoader::Open(input_jar.c_str(), - input_jar.c_str(), - /*verify*/ true, - /*verify_checksum*/ true, - &error_msg, - &dex_files)) << error_msg; + const ArtDexFileLoader dex_file_loader; + CHECK(dex_file_loader.Open(input_jar.c_str(), + input_jar.c_str(), + /*verify*/ true, + /*verify_checksum*/ true, + &error_msg, + &dex_files)) << error_msg; EXPECT_EQ(dex_files.size(), 1u) << "Only one input dex is supported"; for (const std::unique_ptr<const DexFile>& dex : dex_files) { CHECK(dex->EnableWrite()) << "Failed to enable write"; @@ -344,12 +346,13 @@ class DexLayoutTest : public CommonRuntimeTest { const std::string& dex_location) { std::vector<std::unique_ptr<const DexFile>> dex_files; std::string error_msg; - bool result = DexFileLoader::Open(input_dex.c_str(), - input_dex, - /*verify*/ true, - /*verify_checksum*/ false, - &error_msg, - &dex_files); + const ArtDexFileLoader dex_file_loader; + bool result = dex_file_loader.Open(input_dex.c_str(), + input_dex, + /*verify*/ true, + /*verify_checksum*/ false, + &error_msg, + &dex_files); ASSERT_TRUE(result) << error_msg; ASSERT_GE(dex_files.size(), 1u); diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc index 556938b563..e452e98c7c 100644 --- a/dexlist/dexlist.cc +++ b/dexlist/dexlist.cc @@ -27,6 +27,7 @@ #include <stdlib.h> #include "base/logging.h" // For InitLogging. +#include "dex/art_dex_file_loader.h" #include "dex/code_item_accessors-no_art-inl.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" @@ -174,7 +175,8 @@ static int processFile(const char* fileName) { static constexpr bool kVerifyChecksum = true; std::string error_msg; std::vector<std::unique_ptr<const DexFile>> dex_files; - if (!DexFileLoader::Open( + const ArtDexFileLoader dex_file_loader; + if (!dex_file_loader.Open( fileName, fileName, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) { fputs(error_msg.c_str(), stderr); fputc('\n', stderr); diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc index aae805569f..027635bbb5 100644 --- a/openjdkjvmti/OpenjdkJvmTi.cc +++ b/openjdkjvmti/OpenjdkJvmTi.cc @@ -83,6 +83,12 @@ DeoptManager gDeoptManager; } \ } while (false) +// Returns whether we are able to use all jvmti features. +static bool IsFullJvmtiAvailable() { + art::Runtime* runtime = art::Runtime::Current(); + return runtime->GetInstrumentation()->IsForcedInterpretOnly() || runtime->IsJavaDebuggable(); +} + class JvmtiFunctions { private: static jvmtiError getEnvironmentError(jvmtiEnv* env) { @@ -1092,10 +1098,64 @@ class JvmtiFunctions { &gEventHandler); } +#define FOR_ALL_CAPABILITIES(FUN) \ + FUN(can_tag_objects) \ + FUN(can_generate_field_modification_events) \ + FUN(can_generate_field_access_events) \ + FUN(can_get_bytecodes) \ + FUN(can_get_synthetic_attribute) \ + FUN(can_get_owned_monitor_info) \ + FUN(can_get_current_contended_monitor) \ + FUN(can_get_monitor_info) \ + FUN(can_pop_frame) \ + FUN(can_redefine_classes) \ + FUN(can_signal_thread) \ + FUN(can_get_source_file_name) \ + FUN(can_get_line_numbers) \ + FUN(can_get_source_debug_extension) \ + FUN(can_access_local_variables) \ + FUN(can_maintain_original_method_order) \ + FUN(can_generate_single_step_events) \ + FUN(can_generate_exception_events) \ + FUN(can_generate_frame_pop_events) \ + FUN(can_generate_breakpoint_events) \ + FUN(can_suspend) \ + FUN(can_redefine_any_class) \ + FUN(can_get_current_thread_cpu_time) \ + FUN(can_get_thread_cpu_time) \ + FUN(can_generate_method_entry_events) \ + FUN(can_generate_method_exit_events) \ + FUN(can_generate_all_class_hook_events) \ + FUN(can_generate_compiled_method_load_events) \ + FUN(can_generate_monitor_events) \ + FUN(can_generate_vm_object_alloc_events) \ + FUN(can_generate_native_method_bind_events) \ + FUN(can_generate_garbage_collection_events) \ + FUN(can_generate_object_free_events) \ + FUN(can_force_early_return) \ + FUN(can_get_owned_monitor_stack_depth_info) \ + FUN(can_get_constant_pool) \ + FUN(can_set_native_method_prefix) \ + FUN(can_retransform_classes) \ + FUN(can_retransform_any_class) \ + FUN(can_generate_resource_exhaustion_heap_events) \ + FUN(can_generate_resource_exhaustion_threads_events) + static jvmtiError GetPotentialCapabilities(jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr) { ENSURE_VALID_ENV(env); ENSURE_NON_NULL(capabilities_ptr); *capabilities_ptr = kPotentialCapabilities; + if (UNLIKELY(!IsFullJvmtiAvailable())) { +#define REMOVE_NONDEBUGGABLE_UNSUPPORTED(e) \ + do { \ + if (kNonDebuggableUnsupportedCapabilities.e == 1) { \ + capabilities_ptr->e = 0; \ + } \ + } while (false); + + FOR_ALL_CAPABILITIES(REMOVE_NONDEBUGGABLE_UNSUPPORTED); +#undef REMOVE_NONDEBUGGABLE_UNSUPPORTED + } return OK; } @@ -1122,49 +1182,9 @@ class JvmtiFunctions { ret = ERR(NOT_AVAILABLE); \ } \ } \ - } while (false) - - ADD_CAPABILITY(can_tag_objects); - ADD_CAPABILITY(can_generate_field_modification_events); - ADD_CAPABILITY(can_generate_field_access_events); - ADD_CAPABILITY(can_get_bytecodes); - ADD_CAPABILITY(can_get_synthetic_attribute); - ADD_CAPABILITY(can_get_owned_monitor_info); - ADD_CAPABILITY(can_get_current_contended_monitor); - ADD_CAPABILITY(can_get_monitor_info); - ADD_CAPABILITY(can_pop_frame); - ADD_CAPABILITY(can_redefine_classes); - ADD_CAPABILITY(can_signal_thread); - ADD_CAPABILITY(can_get_source_file_name); - ADD_CAPABILITY(can_get_line_numbers); - ADD_CAPABILITY(can_get_source_debug_extension); - ADD_CAPABILITY(can_access_local_variables); - ADD_CAPABILITY(can_maintain_original_method_order); - ADD_CAPABILITY(can_generate_single_step_events); - ADD_CAPABILITY(can_generate_exception_events); - ADD_CAPABILITY(can_generate_frame_pop_events); - ADD_CAPABILITY(can_generate_breakpoint_events); - ADD_CAPABILITY(can_suspend); - ADD_CAPABILITY(can_redefine_any_class); - ADD_CAPABILITY(can_get_current_thread_cpu_time); - ADD_CAPABILITY(can_get_thread_cpu_time); - ADD_CAPABILITY(can_generate_method_entry_events); - ADD_CAPABILITY(can_generate_method_exit_events); - ADD_CAPABILITY(can_generate_all_class_hook_events); - ADD_CAPABILITY(can_generate_compiled_method_load_events); - ADD_CAPABILITY(can_generate_monitor_events); - ADD_CAPABILITY(can_generate_vm_object_alloc_events); - ADD_CAPABILITY(can_generate_native_method_bind_events); - ADD_CAPABILITY(can_generate_garbage_collection_events); - ADD_CAPABILITY(can_generate_object_free_events); - ADD_CAPABILITY(can_force_early_return); - ADD_CAPABILITY(can_get_owned_monitor_stack_depth_info); - ADD_CAPABILITY(can_get_constant_pool); - ADD_CAPABILITY(can_set_native_method_prefix); - ADD_CAPABILITY(can_retransform_classes); - ADD_CAPABILITY(can_retransform_any_class); - ADD_CAPABILITY(can_generate_resource_exhaustion_heap_events); - ADD_CAPABILITY(can_generate_resource_exhaustion_threads_events); + } while (false); + + FOR_ALL_CAPABILITIES(ADD_CAPABILITY); #undef ADD_CAPABILITY gEventHandler.HandleChangedCapabilities(ArtJvmTiEnv::AsArtJvmTiEnv(env), changed, @@ -1186,49 +1206,9 @@ class JvmtiFunctions { changed.e = 1; \ } \ } \ - } while (false) - - DEL_CAPABILITY(can_tag_objects); - DEL_CAPABILITY(can_generate_field_modification_events); - DEL_CAPABILITY(can_generate_field_access_events); - DEL_CAPABILITY(can_get_bytecodes); - DEL_CAPABILITY(can_get_synthetic_attribute); - DEL_CAPABILITY(can_get_owned_monitor_info); - DEL_CAPABILITY(can_get_current_contended_monitor); - DEL_CAPABILITY(can_get_monitor_info); - DEL_CAPABILITY(can_pop_frame); - DEL_CAPABILITY(can_redefine_classes); - DEL_CAPABILITY(can_signal_thread); - DEL_CAPABILITY(can_get_source_file_name); - DEL_CAPABILITY(can_get_line_numbers); - DEL_CAPABILITY(can_get_source_debug_extension); - DEL_CAPABILITY(can_access_local_variables); - DEL_CAPABILITY(can_maintain_original_method_order); - DEL_CAPABILITY(can_generate_single_step_events); - DEL_CAPABILITY(can_generate_exception_events); - DEL_CAPABILITY(can_generate_frame_pop_events); - DEL_CAPABILITY(can_generate_breakpoint_events); - DEL_CAPABILITY(can_suspend); - DEL_CAPABILITY(can_redefine_any_class); - DEL_CAPABILITY(can_get_current_thread_cpu_time); - DEL_CAPABILITY(can_get_thread_cpu_time); - DEL_CAPABILITY(can_generate_method_entry_events); - DEL_CAPABILITY(can_generate_method_exit_events); - DEL_CAPABILITY(can_generate_all_class_hook_events); - DEL_CAPABILITY(can_generate_compiled_method_load_events); - DEL_CAPABILITY(can_generate_monitor_events); - DEL_CAPABILITY(can_generate_vm_object_alloc_events); - DEL_CAPABILITY(can_generate_native_method_bind_events); - DEL_CAPABILITY(can_generate_garbage_collection_events); - DEL_CAPABILITY(can_generate_object_free_events); - DEL_CAPABILITY(can_force_early_return); - DEL_CAPABILITY(can_get_owned_monitor_stack_depth_info); - DEL_CAPABILITY(can_get_constant_pool); - DEL_CAPABILITY(can_set_native_method_prefix); - DEL_CAPABILITY(can_retransform_classes); - DEL_CAPABILITY(can_retransform_any_class); - DEL_CAPABILITY(can_generate_resource_exhaustion_heap_events); - DEL_CAPABILITY(can_generate_resource_exhaustion_threads_events); + } while (false); + + FOR_ALL_CAPABILITIES(DEL_CAPABILITY); #undef DEL_CAPABILITY gEventHandler.HandleChangedCapabilities(ArtJvmTiEnv::AsArtJvmTiEnv(env), changed, @@ -1236,6 +1216,8 @@ class JvmtiFunctions { return OK; } +#undef FOR_ALL_CAPABILITIES + static jvmtiError GetCapabilities(jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr) { ENSURE_VALID_ENV(env); ENSURE_NON_NULL(capabilities_ptr); @@ -1341,7 +1323,7 @@ class JvmtiFunctions { static jvmtiError GetVersionNumber(jvmtiEnv* env, jint* version_ptr) { ENSURE_VALID_ENV(env); - *version_ptr = JVMTI_VERSION; + *version_ptr = ArtJvmTiEnv::AsArtJvmTiEnv(env)->ti_version; return OK; } @@ -1495,9 +1477,10 @@ static bool IsJvmtiVersion(jint version) { extern const jvmtiInterface_1 gJvmtiInterface; -ArtJvmTiEnv::ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler) +ArtJvmTiEnv::ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler, jint version) : art_vm(runtime), local_data(nullptr), + ti_version(version), capabilities(), event_info_mutex_("jvmtiEnv_EventInfoMutex") { object_tag_table = std::unique_ptr<ObjectTagTable>(new ObjectTagTable(event_handler, this)); @@ -1506,8 +1489,8 @@ ArtJvmTiEnv::ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler) // Creates a jvmtiEnv and returns it with the art::ti::Env that is associated with it. new_art_ti // is a pointer to the uninitialized memory for an art::ti::Env. -static void CreateArtJvmTiEnv(art::JavaVMExt* vm, /*out*/void** new_jvmtiEnv) { - struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm, &gEventHandler); +static void CreateArtJvmTiEnv(art::JavaVMExt* vm, jint version, /*out*/void** new_jvmtiEnv) { + struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm, &gEventHandler, version); *new_jvmtiEnv = env; gEventHandler.RegisterArtJvmTiEnv(env); @@ -1520,8 +1503,14 @@ static void CreateArtJvmTiEnv(art::JavaVMExt* vm, /*out*/void** new_jvmtiEnv) { // places the return value in 'env' if this library can handle the GetEnv request. Otherwise // returns false and does not modify the 'env' pointer. static jint GetEnvHandler(art::JavaVMExt* vm, /*out*/void** env, jint version) { - if (IsJvmtiVersion(version)) { - CreateArtJvmTiEnv(vm, env); + // JavaDebuggable will either be set by the runtime as it is starting up or the plugin if it's + // loaded early enough. If this is false we cannot guarantee conformance to all JVMTI behaviors + // due to optimizations. We will only allow agents to get ArtTiEnvs using the kArtTiVersion. + if (IsFullJvmtiAvailable() && IsJvmtiVersion(version)) { + CreateArtJvmTiEnv(vm, JVMTI_VERSION, env); + return JNI_OK; + } else if (version == kArtTiVersion) { + CreateArtJvmTiEnv(vm, kArtTiVersion, env); return JNI_OK; } else { printf("version 0x%x is not valid!", version); @@ -1547,6 +1536,12 @@ extern "C" bool ArtPlugin_Initialize() { SearchUtil::Register(); HeapUtil::Register(); + { + // Make sure we can deopt anything we need to. + art::ScopedObjectAccess soa(art::Thread::Current()); + gDeoptManager.FinishSetup(); + } + runtime->GetJavaVM()->AddEnvironmentHook(GetEnvHandler); return true; diff --git a/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h index 2a8c2e91df..73cc601e3e 100644 --- a/openjdkjvmti/art_jvmti.h +++ b/openjdkjvmti/art_jvmti.h @@ -62,10 +62,22 @@ namespace openjdkjvmti { class ObjectTagTable; +// A special version that we use to identify special tooling interface versions which mostly matches +// the jvmti spec but everything is best effort. This is used to implement the userdebug +// 'debug-anything' behavior. +// +// This is the value 0x70010200. +static constexpr jint kArtTiVersion = JVMTI_VERSION_1_2 | 0x40000000; + // A structure that is a jvmtiEnv with additional information for the runtime. struct ArtJvmTiEnv : public jvmtiEnv { art::JavaVMExt* art_vm; void* local_data; + + // The ti_version we are compatible with. This is only for giving the correct value for GetVersion + // when running on a userdebug/eng device. + jint ti_version; + jvmtiCapabilities capabilities; EventMasks event_masks; @@ -90,7 +102,7 @@ struct ArtJvmTiEnv : public jvmtiEnv { // RW lock to protect access to all of the event data. art::ReaderWriterMutex event_info_mutex_ DEFAULT_MUTEX_ACQUIRED_AFTER; - ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler); + ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler, jint ti_version); static ArtJvmTiEnv* AsArtJvmTiEnv(jvmtiEnv* env) { return art::down_cast<ArtJvmTiEnv*>(env); @@ -272,6 +284,60 @@ const jvmtiCapabilities kPotentialCapabilities = { .can_generate_resource_exhaustion_threads_events = 0, }; +// These are capabilities that are disabled if we were loaded without being debuggable. +// +// This includes the following capabilities: +// can_retransform_any_class: +// can_retransform_classes: +// can_redefine_any_class: +// can_redefine_classes: +// We need to ensure that inlined code is either not present or can always be deoptimized. This +// is not guaranteed for non-debuggable processes since we might have inlined bootclasspath code +// on a threads stack. +const jvmtiCapabilities kNonDebuggableUnsupportedCapabilities = { + .can_tag_objects = 0, + .can_generate_field_modification_events = 0, + .can_generate_field_access_events = 0, + .can_get_bytecodes = 0, + .can_get_synthetic_attribute = 0, + .can_get_owned_monitor_info = 0, + .can_get_current_contended_monitor = 0, + .can_get_monitor_info = 0, + .can_pop_frame = 0, + .can_redefine_classes = 1, + .can_signal_thread = 0, + .can_get_source_file_name = 0, + .can_get_line_numbers = 0, + .can_get_source_debug_extension = 0, + .can_access_local_variables = 0, + .can_maintain_original_method_order = 0, + .can_generate_single_step_events = 0, + .can_generate_exception_events = 0, + .can_generate_frame_pop_events = 0, + .can_generate_breakpoint_events = 0, + .can_suspend = 0, + .can_redefine_any_class = 1, + .can_get_current_thread_cpu_time = 0, + .can_get_thread_cpu_time = 0, + .can_generate_method_entry_events = 0, + .can_generate_method_exit_events = 0, + .can_generate_all_class_hook_events = 0, + .can_generate_compiled_method_load_events = 0, + .can_generate_monitor_events = 0, + .can_generate_vm_object_alloc_events = 0, + .can_generate_native_method_bind_events = 0, + .can_generate_garbage_collection_events = 0, + .can_generate_object_free_events = 0, + .can_force_early_return = 0, + .can_get_owned_monitor_stack_depth_info = 0, + .can_get_constant_pool = 0, + .can_set_native_method_prefix = 0, + .can_retransform_classes = 1, + .can_retransform_any_class = 1, + .can_generate_resource_exhaustion_heap_events = 0, + .can_generate_resource_exhaustion_threads_events = 0, +}; + } // namespace openjdkjvmti #endif // ART_OPENJDKJVMTI_ART_JVMTI_H_ diff --git a/openjdkjvmti/deopt_manager.cc b/openjdkjvmti/deopt_manager.cc index aced769cb5..53d84836fc 100644 --- a/openjdkjvmti/deopt_manager.cc +++ b/openjdkjvmti/deopt_manager.cc @@ -68,7 +68,9 @@ bool JvmtiMethodInspectionCallback::IsMethodSafeToJit(art::ArtMethod* method) { } DeoptManager::DeoptManager() - : deoptimization_status_lock_("JVMTI_DeoptimizationStatusLock"), + : deoptimization_status_lock_("JVMTI_DeoptimizationStatusLock", + static_cast<art::LockLevel>( + art::LockLevel::kClassLinkerClassesLock + 1)), deoptimization_condition_("JVMTI_DeoptimizationCondition", deoptimization_status_lock_), performing_deoptimization_(false), global_deopt_count_(0), @@ -91,6 +93,33 @@ void DeoptManager::Shutdown() { callbacks->RemoveMethodInspectionCallback(&inspection_callback_); } +void DeoptManager::FinishSetup() { + art::Thread* self = art::Thread::Current(); + art::MutexLock mu(self, deoptimization_status_lock_); + + art::Runtime* runtime = art::Runtime::Current(); + // See if we need to do anything. + if (!runtime->IsJavaDebuggable()) { + // See if we can enable all JVMTI functions. If this is false, only kArtTiVersion agents can be + // retrieved and they will all be best-effort. + if (PhaseUtil::GetPhaseUnchecked() == JVMTI_PHASE_ONLOAD) { + // We are still early enough to change the compiler options and get full JVMTI support. + LOG(INFO) << "Openjdkjvmti plugin loaded on a non-debuggable runtime. Changing runtime to " + << "debuggable state. Please pass '--debuggable' to dex2oat and " + << "'-Xcompiler-option --debuggable' to dalvikvm in the future."; + DCHECK(runtime->GetJit() == nullptr) << "Jit should not be running yet!"; + runtime->AddCompilerOption("--debuggable"); + runtime->SetJavaDebuggable(true); + } else { + LOG(WARNING) << "Openjdkjvmti plugin was loaded on a non-debuggable Runtime. Plugin was " + << "loaded too late to change runtime state to DEBUGGABLE. Only kArtTiVersion " + << "(0x" << std::hex << kArtTiVersion << ") environments are available. Some " + << "functionality might not work properly."; + } + runtime->DeoptimizeBootImage(); + } +} + bool DeoptManager::MethodHasBreakpoints(art::ArtMethod* method) { art::MutexLock lk(art::Thread::Current(), deoptimization_status_lock_); return MethodHasBreakpointsLocked(method); diff --git a/openjdkjvmti/deopt_manager.h b/openjdkjvmti/deopt_manager.h index b265fa8ec2..a495b6835c 100644 --- a/openjdkjvmti/deopt_manager.h +++ b/openjdkjvmti/deopt_manager.h @@ -101,6 +101,10 @@ class DeoptManager { void DeoptimizeThread(art::Thread* target) REQUIRES_SHARED(art::Locks::mutator_lock_); void DeoptimizeAllThreads() REQUIRES_SHARED(art::Locks::mutator_lock_); + void FinishSetup() + REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_) + REQUIRES_SHARED(art::Locks::mutator_lock_); + static DeoptManager* Get(); private: @@ -141,9 +145,8 @@ class DeoptManager { REQUIRES(!art::Roles::uninterruptible_, !art::Locks::mutator_lock_); static constexpr const char* kDeoptManagerInstrumentationKey = "JVMTI_DeoptManager"; - // static constexpr const char* kDeoptManagerThreadName = "JVMTI_DeoptManagerWorkerThread"; - art::Mutex deoptimization_status_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; + art::Mutex deoptimization_status_lock_ ACQUIRED_BEFORE(art::Locks::classlinker_classes_lock_); art::ConditionVariable deoptimization_condition_ GUARDED_BY(deoptimization_status_lock_); bool performing_deoptimization_ GUARDED_BY(deoptimization_status_lock_); diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc index da7d60ac2f..963c6f8444 100644 --- a/openjdkjvmti/fixed_up_dex_file.cc +++ b/openjdkjvmti/fixed_up_dex_file.cc @@ -30,6 +30,7 @@ */ #include "fixed_up_dex_file.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" @@ -72,7 +73,8 @@ std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& origi data.resize(original.Size()); memcpy(data.data(), original.Begin(), original.Size()); std::string error; - std::unique_ptr<const art::DexFile> new_dex_file(art::DexFileLoader::Open( + const art::ArtDexFileLoader dex_file_loader; + std::unique_ptr<const art::DexFile> new_dex_file(dex_file_loader.Open( data.data(), data.size(), /*location*/"Unquickening_dexfile.dex", @@ -103,7 +105,7 @@ std::unique_ptr<FixedUpDexFile> FixedUpDexFile::Create(const art::DexFile& origi // Overwrite the dex file stored in data with the new result. data.clear(); data.insert(data.end(), mem_map->Begin(), mem_map->Begin() + dex_file_size); - new_dex_file = art::DexFileLoader::Open( + new_dex_file = dex_file_loader.Open( data.data(), data.size(), /*location*/"Unquickening_dexfile.dex", diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc index f9eb008af2..b3f5c1886e 100644 --- a/openjdkjvmti/ti_class.cc +++ b/openjdkjvmti/ti_class.cc @@ -42,6 +42,7 @@ #include "class_linker.h" #include "class_table-inl.h" #include "common_throws.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file_annotations.h" #include "dex/dex_file_loader.h" #include "events-inl.h" @@ -107,12 +108,13 @@ static std::unique_ptr<const art::DexFile> MakeSingleDexFile(art::Thread* self, } uint32_t checksum = reinterpret_cast<const art::DexFile::Header*>(map->Begin())->checksum_; std::string map_name = map->GetName(); - std::unique_ptr<const art::DexFile> dex_file(art::DexFileLoader::Open(map_name, - checksum, - std::move(map), - /*verify*/true, - /*verify_checksum*/true, - &error_msg)); + const art::ArtDexFileLoader dex_file_loader; + std::unique_ptr<const art::DexFile> dex_file(dex_file_loader.Open(map_name, + checksum, + std::move(map), + /*verify*/true, + /*verify_checksum*/true, + &error_msg)); if (dex_file.get() == nullptr) { LOG(WARNING) << "Unable to load modified dex file for " << descriptor << ": " << error_msg; art::ThrowClassFormatError(nullptr, diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index 6194d1e42c..717b2ba669 100644 --- a/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc @@ -43,6 +43,7 @@ #include "base/stringpiece.h" #include "class_linker-inl.h" #include "debugger.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "dex/dex_file_types.h" @@ -426,12 +427,13 @@ jvmtiError Redefiner::AddRedefinition(ArtJvmTiEnv* env, const ArtClassDefinition return ERR(INVALID_CLASS_FORMAT); } uint32_t checksum = reinterpret_cast<const art::DexFile::Header*>(map->Begin())->checksum_; - std::unique_ptr<const art::DexFile> dex_file(art::DexFileLoader::Open(map->GetName(), - checksum, - std::move(map), - /*verify*/true, - /*verify_checksum*/true, - error_msg_)); + const art::ArtDexFileLoader dex_file_loader; + std::unique_ptr<const art::DexFile> dex_file(dex_file_loader.Open(map->GetName(), + checksum, + std::move(map), + /*verify*/true, + /*verify_checksum*/true, + error_msg_)); if (dex_file.get() == nullptr) { os << "Unable to load modified dex file for " << def.GetName() << ": " << *error_msg_; *error_msg_ = os.str(); diff --git a/openjdkjvmti/ti_search.cc b/openjdkjvmti/ti_search.cc index 9d5f4ea3f9..cbb7b53bff 100644 --- a/openjdkjvmti/ti_search.cc +++ b/openjdkjvmti/ti_search.cc @@ -38,6 +38,7 @@ #include "base/enums.h" #include "base/macros.h" #include "class_linker.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "jni_internal.h" @@ -227,7 +228,8 @@ jvmtiError SearchUtil::AddToBootstrapClassLoaderSearch(jvmtiEnv* env ATTRIBUTE_U std::string error_msg; std::vector<std::unique_ptr<const art::DexFile>> dex_files; - if (!art::DexFileLoader::Open( + const art::ArtDexFileLoader dex_file_loader; + if (!dex_file_loader.Open( segment, segment, /* verify */ true, /* verify_checksum */ true, &error_msg, &dex_files)) { LOG(WARNING) << "Could not open " << segment << " for boot classpath extension: " << error_msg; return ERR(ILLEGAL_ARGUMENT); diff --git a/profman/profman.cc b/profman/profman.cc index c4216fab99..9f3e3b6ac5 100644 --- a/profman/profman.cc +++ b/profman/profman.cc @@ -39,6 +39,7 @@ #include "base/unix_file/fd_file.h" #include "boot_image_profile.h" #include "bytecode_utils.h" +#include "dex/art_dex_file_loader.h" #include "dex/code_item_accessors-inl.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" @@ -329,25 +330,26 @@ class ProfMan FINAL { static constexpr bool kVerifyChecksum = true; for (size_t i = 0; i < dex_locations_.size(); ++i) { std::string error_msg; + const ArtDexFileLoader dex_file_loader; std::vector<std::unique_ptr<const DexFile>> dex_files_for_location; if (use_apk_fd_list) { - if (DexFileLoader::OpenZip(apks_fd_[i], - dex_locations_[i], - /* verify */ true, - kVerifyChecksum, - &error_msg, - &dex_files_for_location)) { + if (dex_file_loader.OpenZip(apks_fd_[i], + dex_locations_[i], + /* verify */ true, + kVerifyChecksum, + &error_msg, + &dex_files_for_location)) { } else { LOG(WARNING) << "OpenZip failed for '" << dex_locations_[i] << "' " << error_msg; continue; } } else { - if (DexFileLoader::Open(apk_files_[i].c_str(), - dex_locations_[i], - /* verify */ true, - kVerifyChecksum, - &error_msg, - &dex_files_for_location)) { + if (dex_file_loader.Open(apk_files_[i].c_str(), + dex_locations_[i], + /* verify */ true, + kVerifyChecksum, + &error_msg, + &dex_files_for_location)) { } else { LOG(WARNING) << "Open failed for '" << dex_locations_[i] << "' " << error_msg; continue; diff --git a/runtime/Android.bp b/runtime/Android.bp index 2657f4fa86..78cb3b6165 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -21,6 +21,70 @@ JIT_DEBUG_REGISTER_CODE_LDFLAGS = ["-Wl,--keep-unique,__jit_debug_register_code"] cc_defaults { + name: "libdexfile_defaults", + defaults: ["art_defaults"], + host_supported: true, + srcs: [ + "dex/compact_dex_file.cc", + "dex/dex_file.cc", + "dex/dex_file_exception_helpers.cc", + "dex/dex_file_loader.cc", + "dex/dex_file_tracking_registrar.cc", + "dex/dex_file_verifier.cc", + "dex/dex_instruction.cc", + "dex/standard_dex_file.cc", + "utf.cc", + "utils.cc", + ], + + target: { + android: { + shared_libs: [ + "libutils", + ], + static_libs: [ + "libz", + "libbase", + ], + }, + host: { + shared_libs: [ + "libz", + ], + }, + }, + generated_sources: ["art_operator_srcs"], + // asm_support_gen.h (used by asm_support.h) is generated with cpp-define-generator + generated_headers: ["cpp-define-generator-asm-support"], + // export our headers so the libart-gtest targets can use it as well. + export_generated_headers: ["cpp-define-generator-asm-support"], + include_dirs: [ + "external/icu/icu4c/source/common", + "external/zlib", + ], + shared_libs: [ + "liblog", + // For common macros. + "libbase", + ], + export_include_dirs: ["."], + // ART's macros.h depends on libbase's macros.h. + // Note: runtime_options.h depends on cmdline. But we don't really want to export this + // generically. dex2oat takes care of it itself. + export_shared_lib_headers: ["libbase"], +} + +art_cc_library { + name: "libdexfile", + defaults: ["libdexfile_defaults"], + // Leave the symbols in the shared library so that stack unwinders can + // produce meaningful name resolution. + strip: { + keep_symbols: true, + }, +} + +cc_defaults { name: "libart_defaults", defaults: ["art_defaults"], host_supported: true, @@ -62,6 +126,7 @@ cc_defaults { "dex/dex_file_exception_helpers.cc", "dex/dex_file_layout.cc", "dex/dex_file_loader.cc", + "dex/art_dex_file_loader.cc", "dex/dex_file_tracking_registrar.cc", "dex/dex_file_verifier.cc", "dex/dex_instruction.cc", diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 44a5dde485..f9eedae23e 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -319,6 +319,21 @@ void ArtMethod::Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* self->AssertThreadSuspensionIsAllowable(); CHECK_EQ(kRunnable, self->GetState()); CHECK_STREQ(GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(), shorty); + + if (!IsNative() && + !IsObsolete() && + !IsProxyMethod() && + IsInvokable() && + ClassLinker::ShouldUseInterpreterEntrypoint(this, GetEntryPointFromQuickCompiledCode())) { + ClassLinker* cl = Runtime::Current()->GetClassLinker(); + const void* entry_point = GetEntryPointFromQuickCompiledCode(); + DCHECK(cl->IsQuickToInterpreterBridge(entry_point) || + cl->IsQuickResolutionStub(entry_point) || + entry_point == GetQuickInstrumentationEntryPoint()) + << PrettyMethod() << " is expected to be interpreted but has an unexpected entrypoint." + << " The entrypoint is " << entry_point << " (incorrect) oat entrypoint would be " + << GetOatMethodQuickCode(cl->GetImagePointerSize()); + } } // Push a transition back into managed code onto the linked list in thread. diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 877654247c..c487808161 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1296,22 +1296,32 @@ void AppImageClassLoadersAndDexCachesHelper::Update( } for (ArtMethod& m : klass->GetDirectMethods(kRuntimePointerSize)) { const void* code = m.GetEntryPointFromQuickCompiledCode(); - const void* oat_code = m.IsInvokable() ? class_linker->GetQuickOatCodeFor(&m) : code; - if (!class_linker->IsQuickResolutionStub(code) && - !class_linker->IsQuickGenericJniStub(code) && + if (!m.IsProxyMethod() && + !m.IsNative() && + !class_linker->IsQuickResolutionStub(code) && !class_linker->IsQuickToInterpreterBridge(code) && - !m.IsNative()) { - DCHECK_EQ(code, oat_code) << m.PrettyMethod(); + m.IsInvokable()) { + // Since this is just a sanity check it's okay to get the oat code here regardless + // of whether it's usable. + const void* oat_code = m.GetOatMethodQuickCode(class_linker->GetImagePointerSize()); + if (oat_code != nullptr) { + DCHECK_EQ(code, oat_code) << m.PrettyMethod(); + } } } for (ArtMethod& m : klass->GetVirtualMethods(kRuntimePointerSize)) { const void* code = m.GetEntryPointFromQuickCompiledCode(); - const void* oat_code = m.IsInvokable() ? class_linker->GetQuickOatCodeFor(&m) : code; - if (!class_linker->IsQuickResolutionStub(code) && - !class_linker->IsQuickGenericJniStub(code) && + if (!m.IsProxyMethod() && + !m.IsNative() && + !class_linker->IsQuickResolutionStub(code) && !class_linker->IsQuickToInterpreterBridge(code) && - !m.IsNative()) { - DCHECK_EQ(code, oat_code) << m.PrettyMethod(); + m.IsInvokable()) { + // Since this is just a sanity check it's okay to get the oat code here regardless + // of whether it's usable. + const void* oat_code = m.GetOatMethodQuickCode(class_linker->GetImagePointerSize()); + if (oat_code != nullptr) { + DCHECK_EQ(code, oat_code) << m.PrettyMethod(); + } } } } @@ -2899,21 +2909,25 @@ uint32_t ClassLinker::SizeOfClassWithoutEmbeddedTables(const DexFile& dex_file, image_pointer_size_); } -// Special case to get oat code without overwriting a trampoline. -const void* ClassLinker::GetQuickOatCodeFor(ArtMethod* method) { +const void* ClassLinker::GetQuickEntrypointFor(ArtMethod* method) { CHECK(method->IsInvokable()) << method->PrettyMethod(); if (method->IsProxyMethod()) { return GetQuickProxyInvokeHandler(); } - auto* code = method->GetOatMethodQuickCode(GetImagePointerSize()); - if (code != nullptr) { - return code; - } - if (method->IsNative()) { - // No code and native? Use generic trampoline. - return GetQuickGenericJniStub(); + const void* oat_code = method->GetOatMethodQuickCode(GetImagePointerSize()); + if (oat_code == nullptr) { + // We need either the generic jni or interpreter bridge. + if (method->IsNative()) { + return GetQuickGenericJniStub(); + } else { + return GetQuickToInterpreterBridge(); + } + } else if (ClassLinker::ShouldUseInterpreterEntrypoint(method, oat_code)) { + // We have oat code but we cannot use it for some reason. + return GetQuickToInterpreterBridge(); + } else { + return oat_code; } - return GetQuickToInterpreterBridge(); } bool ClassLinker::ShouldUseInterpreterEntrypoint(ArtMethod* method, const void* quick_code) { diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 3e3425f5ac..62804e79c5 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -498,9 +498,8 @@ class ClassLinker { std::string GetDescriptorForProxy(ObjPtr<mirror::Class> proxy_class) REQUIRES_SHARED(Locks::mutator_lock_); - // Get the oat code for a method when its class isn't yet initialized. - const void* GetQuickOatCodeFor(ArtMethod* method) - REQUIRES_SHARED(Locks::mutator_lock_); + // Get the correct entrypoint for a method as far as the class-linker is concerned. + const void* GetQuickEntrypointFor(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); pid_t GetClassesLockOwner(); // For SignalCatcher. pid_t GetDexLockOwner(); // For SignalCatcher. diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc index 3ec5335a80..e646520f3d 100644 --- a/runtime/class_loader_context.cc +++ b/runtime/class_loader_context.cc @@ -21,6 +21,7 @@ #include "base/stl_util.h" #include "class_linker.h" #include "class_loader_utils.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "handle_scope-inl.h" @@ -203,6 +204,7 @@ bool ClassLoaderContext::OpenDexFiles(InstructionSet isa, const std::string& cla // We may get resource-only apks which we cannot load. // TODO(calin): Refine the dex opening interface to be able to tell if an archive contains // no dex files. So that we can distinguish the real failures... + const ArtDexFileLoader dex_file_loader; for (ClassLoaderInfo& info : class_loader_chain_) { size_t opened_dex_files_index = info.opened_dex_files.size(); for (const std::string& cp_elem : info.classpath) { @@ -215,12 +217,12 @@ bool ClassLoaderContext::OpenDexFiles(InstructionSet isa, const std::string& cla std::string error_msg; // When opening the dex files from the context we expect their checksum to match their // contents. So pass true to verify_checksum. - if (!DexFileLoader::Open(location.c_str(), - location.c_str(), - Runtime::Current()->IsVerificationEnabled(), - /*verify_checksum*/ true, - &error_msg, - &info.opened_dex_files)) { + if (!dex_file_loader.Open(location.c_str(), + location.c_str(), + Runtime::Current()->IsVerificationEnabled(), + /*verify_checksum*/ true, + &error_msg, + &info.opened_dex_files)) { // If we fail to open the dex file because it's been stripped, try to open the dex file // from its corresponding oat file. // This could happen when we need to recompile a pre-build whose dex code has been stripped. diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index 96d660fd64..39dbebfdf2 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -35,6 +35,7 @@ #include "base/unix_file/fd_file.h" #include "class_linker.h" #include "compiler_callbacks.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" #include "gc/heap.h" @@ -375,7 +376,8 @@ std::unique_ptr<const DexFile> CommonRuntimeTestImpl::LoadExpectSingleDexFile( std::string error_msg; MemMap::Init(); static constexpr bool kVerifyChecksum = true; - if (!DexFileLoader::Open( + const ArtDexFileLoader dex_file_loader; + if (!dex_file_loader.Open( location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) { LOG(FATAL) << "Could not open .dex file '" << location << "': " << error_msg << "\n"; UNREACHABLE(); @@ -574,12 +576,13 @@ std::vector<std::unique_ptr<const DexFile>> CommonRuntimeTestImpl::OpenTestDexFi std::string filename = GetTestDexFileName(name); static constexpr bool kVerifyChecksum = true; std::string error_msg; + const ArtDexFileLoader dex_file_loader; std::vector<std::unique_ptr<const DexFile>> dex_files; - bool success = DexFileLoader::Open(filename.c_str(), - filename.c_str(), - /* verify */ true, - kVerifyChecksum, - &error_msg, &dex_files); + bool success = dex_file_loader.Open(filename.c_str(), + filename.c_str(), + /* verify */ true, + kVerifyChecksum, + &error_msg, &dex_files); CHECK(success) << "Failed to open '" << filename << "': " << error_msg; for (auto& dex_file : dex_files) { CHECK_EQ(PROT_READ, dex_file->GetPermissions()); diff --git a/runtime/dex/art_dex_file_loader.cc b/runtime/dex/art_dex_file_loader.cc new file mode 100644 index 0000000000..282b282707 --- /dev/null +++ b/runtime/dex/art_dex_file_loader.cc @@ -0,0 +1,465 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "art_dex_file_loader.h" + +#include <sys/mman.h> // For the PROT_* and MAP_* constants. +#include <sys/stat.h> + +#include "android-base/stringprintf.h" + +#include "base/file_magic.h" +#include "base/stl_util.h" +#include "base/systrace.h" +#include "base/unix_file/fd_file.h" +#include "compact_dex_file.h" +#include "dex_file.h" +#include "dex_file_verifier.h" +#include "standard_dex_file.h" +#include "zip_archive.h" + +namespace art { + +namespace { + +class MemMapContainer : public DexFileContainer { + public: + explicit MemMapContainer(std::unique_ptr<MemMap>&& mem_map) : mem_map_(std::move(mem_map)) { } + virtual ~MemMapContainer() OVERRIDE { } + + int GetPermissions() OVERRIDE { + if (mem_map_.get() == nullptr) { + return 0; + } else { + return mem_map_->GetProtect(); + } + } + + bool IsReadOnly() OVERRIDE { + return GetPermissions() == PROT_READ; + } + + bool EnableWrite() OVERRIDE { + CHECK(IsReadOnly()); + if (mem_map_.get() == nullptr) { + return false; + } else { + return mem_map_->Protect(PROT_READ | PROT_WRITE); + } + } + + bool DisableWrite() OVERRIDE { + CHECK(!IsReadOnly()); + if (mem_map_.get() == nullptr) { + return false; + } else { + return mem_map_->Protect(PROT_READ); + } + } + + private: + std::unique_ptr<MemMap> mem_map_; + DISALLOW_COPY_AND_ASSIGN(MemMapContainer); +}; + +} // namespace + +using android::base::StringPrintf; + +static constexpr OatDexFile* kNoOatDexFile = nullptr; + + +bool ArtDexFileLoader::GetMultiDexChecksums(const char* filename, + std::vector<uint32_t>* checksums, + std::string* error_msg, + int zip_fd) const { + CHECK(checksums != nullptr); + uint32_t magic; + + File fd; + if (zip_fd != -1) { + if (ReadMagicAndReset(zip_fd, &magic, error_msg)) { + fd = File(zip_fd, false /* check_usage */); + } + } else { + fd = OpenAndReadMagic(filename, &magic, error_msg); + } + if (fd.Fd() == -1) { + DCHECK(!error_msg->empty()); + return false; + } + if (IsZipMagic(magic)) { + std::unique_ptr<ZipArchive> zip_archive( + ZipArchive::OpenFromFd(fd.Release(), filename, error_msg)); + if (zip_archive.get() == nullptr) { + *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename, + error_msg->c_str()); + return false; + } + + uint32_t i = 0; + std::string zip_entry_name = GetMultiDexClassesDexName(i++); + std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg)); + if (zip_entry.get() == nullptr) { + *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename, + zip_entry_name.c_str(), error_msg->c_str()); + return false; + } + + do { + checksums->push_back(zip_entry->GetCrc32()); + zip_entry_name = GetMultiDexClassesDexName(i++); + zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg)); + } while (zip_entry.get() != nullptr); + return true; + } + if (IsMagicValid(magic)) { + std::unique_ptr<const DexFile> dex_file( + OpenFile(fd.Release(), filename, false, false, error_msg)); + if (dex_file == nullptr) { + return false; + } + checksums->push_back(dex_file->GetHeader().checksum_); + return true; + } + *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename); + return false; +} + +std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const uint8_t* base, + size_t size, + const std::string& location, + uint32_t location_checksum, + const OatDexFile* oat_dex_file, + bool verify, + bool verify_checksum, + std::string* error_msg) const { + ScopedTrace trace(std::string("Open dex file from RAM ") + location); + return OpenCommon(base, + size, + location, + location_checksum, + oat_dex_file, + verify, + verify_checksum, + error_msg, + /*container*/ nullptr, + /*verify_result*/ nullptr); +} + +std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const std::string& location, + uint32_t location_checksum, + std::unique_ptr<MemMap> map, + bool verify, + bool verify_checksum, + std::string* error_msg) const { + ScopedTrace trace(std::string("Open dex file from mapped-memory ") + location); + CHECK(map.get() != nullptr); + + if (map->Size() < sizeof(DexFile::Header)) { + *error_msg = StringPrintf( + "DexFile: failed to open dex file '%s' that is too short to have a header", + location.c_str()); + return nullptr; + } + + std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(), + map->Size(), + location, + location_checksum, + kNoOatDexFile, + verify, + verify_checksum, + error_msg, + new MemMapContainer(std::move(map)), + /*verify_result*/ nullptr); + return dex_file; +} + +bool ArtDexFileLoader::Open(const char* filename, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files) const { + ScopedTrace trace(std::string("Open dex file ") + std::string(location)); + DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr"; + uint32_t magic; + File fd = OpenAndReadMagic(filename, &magic, error_msg); + if (fd.Fd() == -1) { + DCHECK(!error_msg->empty()); + return false; + } + if (IsZipMagic(magic)) { + return OpenZip(fd.Release(), location, verify, verify_checksum, error_msg, dex_files); + } + if (IsMagicValid(magic)) { + std::unique_ptr<const DexFile> dex_file(OpenFile(fd.Release(), + location, + verify, + verify_checksum, + error_msg)); + if (dex_file.get() != nullptr) { + dex_files->push_back(std::move(dex_file)); + return true; + } else { + return false; + } + } + *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename); + return false; +} + +std::unique_ptr<const DexFile> ArtDexFileLoader::OpenDex(int fd, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg) const { + ScopedTrace trace("Open dex file " + std::string(location)); + return OpenFile(fd, location, verify, verify_checksum, error_msg); +} + +bool ArtDexFileLoader::OpenZip(int fd, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files) const { + ScopedTrace trace("Dex file open Zip " + std::string(location)); + DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is nullptr"; + std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg)); + if (zip_archive.get() == nullptr) { + DCHECK(!error_msg->empty()); + return false; + } + return OpenAllDexFilesFromZip( + *zip_archive, location, verify, verify_checksum, error_msg, dex_files); +} + +std::unique_ptr<const DexFile> ArtDexFileLoader::OpenFile(int fd, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg) const { + ScopedTrace trace(std::string("Open dex file ") + std::string(location)); + CHECK(!location.empty()); + std::unique_ptr<MemMap> map; + { + File delayed_close(fd, /* check_usage */ false); + struct stat sbuf; + memset(&sbuf, 0, sizeof(sbuf)); + if (fstat(fd, &sbuf) == -1) { + *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(), + strerror(errno)); + return nullptr; + } + if (S_ISDIR(sbuf.st_mode)) { + *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str()); + return nullptr; + } + size_t length = sbuf.st_size; + map.reset(MemMap::MapFile(length, + PROT_READ, + MAP_PRIVATE, + fd, + 0, + /*low_4gb*/false, + location.c_str(), + error_msg)); + if (map == nullptr) { + DCHECK(!error_msg->empty()); + return nullptr; + } + } + + if (map->Size() < sizeof(DexFile::Header)) { + *error_msg = StringPrintf( + "DexFile: failed to open dex file '%s' that is too short to have a header", + location.c_str()); + return nullptr; + } + + const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(map->Begin()); + + std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(), + map->Size(), + location, + dex_header->checksum_, + kNoOatDexFile, + verify, + verify_checksum, + error_msg, + new MemMapContainer(std::move(map)), + /*verify_result*/ nullptr); + + return dex_file; +} + +std::unique_ptr<const DexFile> ArtDexFileLoader::OpenOneDexFileFromZip( + const ZipArchive& zip_archive, + const char* entry_name, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + ZipOpenErrorCode* error_code) const { + ScopedTrace trace("Dex file open from Zip Archive " + std::string(location)); + CHECK(!location.empty()); + std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg)); + if (zip_entry == nullptr) { + *error_code = ZipOpenErrorCode::kEntryNotFound; + return nullptr; + } + if (zip_entry->GetUncompressedLength() == 0) { + *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str()); + *error_code = ZipOpenErrorCode::kDexFileError; + return nullptr; + } + + std::unique_ptr<MemMap> map; + if (zip_entry->IsUncompressed()) { + if (!zip_entry->IsAlignedTo(alignof(DexFile::Header))) { + // Do not mmap unaligned ZIP entries because + // doing so would fail dex verification which requires 4 byte alignment. + LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; " + << "please zipalign to " << alignof(DexFile::Header) << " bytes. " + << "Falling back to extracting file."; + } else { + // Map uncompressed files within zip as file-backed to avoid a dirty copy. + map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg)); + if (map == nullptr) { + LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; " + << "is your ZIP file corrupted? Falling back to extraction."; + // Try again with Extraction which still has a chance of recovery. + } + } + } + + if (map == nullptr) { + // Default path for compressed ZIP entries, + // and fallback for stored ZIP entries. + map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg)); + } + + if (map == nullptr) { + *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(), + error_msg->c_str()); + *error_code = ZipOpenErrorCode::kExtractToMemoryError; + return nullptr; + } + VerifyResult verify_result; + std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(), + map->Size(), + location, + zip_entry->GetCrc32(), + kNoOatDexFile, + verify, + verify_checksum, + error_msg, + new MemMapContainer(std::move(map)), + &verify_result); + if (dex_file == nullptr) { + if (verify_result == VerifyResult::kVerifyNotAttempted) { + *error_code = ZipOpenErrorCode::kDexFileError; + } else { + *error_code = ZipOpenErrorCode::kVerifyError; + } + return nullptr; + } + if (!dex_file->DisableWrite()) { + *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str()); + *error_code = ZipOpenErrorCode::kMakeReadOnlyError; + return nullptr; + } + CHECK(dex_file->IsReadOnly()) << location; + if (verify_result != VerifyResult::kVerifySucceeded) { + *error_code = ZipOpenErrorCode::kVerifyError; + return nullptr; + } + *error_code = ZipOpenErrorCode::kNoError; + return dex_file; +} + +// Technically we do not have a limitation with respect to the number of dex files that can be in a +// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols +// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what +// seems an excessive number. +static constexpr size_t kWarnOnManyDexFilesThreshold = 100; + +bool ArtDexFileLoader::OpenAllDexFilesFromZip( + const ZipArchive& zip_archive, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files) const { + ScopedTrace trace("Dex file open from Zip " + std::string(location)); + DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr"; + ZipOpenErrorCode error_code; + std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive, + kClassesDex, + location, + verify, + verify_checksum, + error_msg, + &error_code)); + if (dex_file.get() == nullptr) { + return false; + } else { + // Had at least classes.dex. + dex_files->push_back(std::move(dex_file)); + + // Now try some more. + + // We could try to avoid std::string allocations by working on a char array directly. As we + // do not expect a lot of iterations, this seems too involved and brittle. + + for (size_t i = 1; ; ++i) { + std::string name = GetMultiDexClassesDexName(i); + std::string fake_location = GetMultiDexLocation(i, location.c_str()); + std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive, + name.c_str(), + fake_location, + verify, + verify_checksum, + error_msg, + &error_code)); + if (next_dex_file.get() == nullptr) { + if (error_code != ZipOpenErrorCode::kEntryNotFound) { + LOG(WARNING) << "Zip open failed: " << *error_msg; + } + break; + } else { + dex_files->push_back(std::move(next_dex_file)); + } + + if (i == kWarnOnManyDexFilesThreshold) { + LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold + << " dex files. Please consider coalescing and shrinking the number to " + " avoid runtime overhead."; + } + + if (i == std::numeric_limits<size_t>::max()) { + LOG(ERROR) << "Overflow in number of dex files!"; + break; + } + } + + return true; + } +} + +} // namespace art diff --git a/runtime/dex/art_dex_file_loader.h b/runtime/dex/art_dex_file_loader.h new file mode 100644 index 0000000000..a6191d9f54 --- /dev/null +++ b/runtime/dex/art_dex_file_loader.h @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_ +#define ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_ + +#include <cstdint> +#include <memory> +#include <string> +#include <vector> + +#include "dex_file_loader.h" +#include "base/macros.h" + +namespace art { + +class DexFile; +class DexFileContainer; +class MemMap; +class OatDexFile; +class ZipArchive; + +// Class that is used to open dex files and deal with corresponding multidex and location logic. +class ArtDexFileLoader : public DexFileLoader { + public: + virtual ~ArtDexFileLoader() { } + + // Returns the checksums of a file for comparison with GetLocationChecksum(). + // For .dex files, this is the single header checksum. + // For zip files, this is the zip entry CRC32 checksum for classes.dex and + // each additional multidex entry classes2.dex, classes3.dex, etc. + // If a valid zip_fd is provided the file content will be read directly from + // the descriptor and `filename` will be used as alias for error logging. If + // zip_fd is -1, the method will try to open the `filename` and read the + // content from it. + // Return true if the checksums could be found, false otherwise. + bool GetMultiDexChecksums(const char* filename, + std::vector<uint32_t>* checksums, + std::string* error_msg, + int zip_fd = -1) const OVERRIDE; + + // Opens .dex file, backed by existing memory + std::unique_ptr<const DexFile> Open(const uint8_t* base, + size_t size, + const std::string& location, + uint32_t location_checksum, + const OatDexFile* oat_dex_file, + bool verify, + bool verify_checksum, + std::string* error_msg) const OVERRIDE; + + // Opens .dex file that has been memory-mapped by the caller. + std::unique_ptr<const DexFile> Open(const std::string& location, + uint32_t location_checkum, + std::unique_ptr<MemMap> mem_map, + bool verify, + bool verify_checksum, + std::string* error_msg) const OVERRIDE; + + // Opens all .dex files found in the file, guessing the container format based on file extension. + bool Open(const char* filename, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files) const OVERRIDE; + + // Open a single dex file from an fd. This function closes the fd. + std::unique_ptr<const DexFile> OpenDex(int fd, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg) const OVERRIDE; + + // Opens dex files from within a .jar, .zip, or .apk file + bool OpenZip(int fd, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files) const OVERRIDE; + + private: + std::unique_ptr<const DexFile> OpenFile(int fd, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg) const OVERRIDE; + + // Open all classesXXX.dex files from a zip archive. + bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files) + const OVERRIDE; + + // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null + // return. + std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive, + const char* entry_name, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + ZipOpenErrorCode* error_code) const OVERRIDE; +}; + +} // namespace art + +#endif // ART_RUNTIME_DEX_ART_DEX_FILE_LOADER_H_ diff --git a/runtime/dex/code_item_accessors_test.cc b/runtime/dex/code_item_accessors_test.cc index b29d10b113..2e219562e9 100644 --- a/runtime/dex/code_item_accessors_test.cc +++ b/runtime/dex/code_item_accessors_test.cc @@ -19,6 +19,7 @@ #include <memory> #include "common_runtime_test.h" +#include "art_dex_file_loader.h" #include "dex_file_loader.h" #include "mem_map.h" @@ -44,13 +45,13 @@ std::unique_ptr<const DexFile> CreateFakeDex(bool compact_dex) { StandardDexFile::WriteMagic(map->Begin()); StandardDexFile::WriteCurrentVersion(map->Begin()); } - std::unique_ptr<const DexFile> dex( - DexFileLoader::Open("location", - /*location_checksum*/ 123, - std::move(map), - /*verify*/false, - /*verify_checksum*/false, - &error_msg)); + const ArtDexFileLoader dex_file_loader; + std::unique_ptr<const DexFile> dex(dex_file_loader.Open("location", + /*location_checksum*/ 123, + std::move(map), + /*verify*/false, + /*verify_checksum*/false, + &error_msg)); CHECK(dex != nullptr) << error_msg; return dex; } diff --git a/runtime/dex/dex_file_loader.cc b/runtime/dex/dex_file_loader.cc index fafd69889d..10aef56125 100644 --- a/runtime/dex/dex_file_loader.cc +++ b/runtime/dex/dex_file_loader.cc @@ -16,72 +16,25 @@ #include "dex_file_loader.h" -#include <sys/mman.h> // For the PROT_* and MAP_* constants. -#include <sys/stat.h> +// #include <sys/mman.h> // For the PROT_* and MAP_* constants. +// #include <sys/stat.h> #include "android-base/stringprintf.h" #include "base/file_magic.h" #include "base/stl_util.h" -#include "base/systrace.h" -#include "base/unix_file/fd_file.h" +// #include "base/systrace.h" +// #include "base/unix_file/fd_file.h" #include "compact_dex_file.h" #include "dex_file.h" #include "dex_file_verifier.h" #include "standard_dex_file.h" -#include "zip_archive.h" +// #include "zip_archive.h" namespace art { -namespace { - -class MemMapContainer : public DexFileContainer { - public: - explicit MemMapContainer(std::unique_ptr<MemMap>&& mem_map) : mem_map_(std::move(mem_map)) { } - virtual ~MemMapContainer() OVERRIDE { } - - int GetPermissions() OVERRIDE { - if (mem_map_.get() == nullptr) { - return 0; - } else { - return mem_map_->GetProtect(); - } - } - - bool IsReadOnly() OVERRIDE { - return GetPermissions() == PROT_READ; - } - - bool EnableWrite() OVERRIDE { - CHECK(IsReadOnly()); - if (mem_map_.get() == nullptr) { - return false; - } else { - return mem_map_->Protect(PROT_READ | PROT_WRITE); - } - } - - bool DisableWrite() OVERRIDE { - CHECK(!IsReadOnly()); - if (mem_map_.get() == nullptr) { - return false; - } else { - return mem_map_->Protect(PROT_READ); - } - } - - private: - std::unique_ptr<MemMap> mem_map_; - DISALLOW_COPY_AND_ASSIGN(MemMapContainer); -}; - -} // namespace - using android::base::StringPrintf; -static constexpr OatDexFile* kNoOatDexFile = nullptr; - - bool DexFileLoader::IsMagicValid(uint32_t magic) { return IsMagicValid(reinterpret_cast<uint8_t*>(&magic)); } @@ -101,63 +54,6 @@ bool DexFileLoader::IsVersionAndMagicValid(const uint8_t* magic) { return false; } -bool DexFileLoader::GetMultiDexChecksums(const char* filename, - std::vector<uint32_t>* checksums, - std::string* error_msg, - int zip_fd) { - CHECK(checksums != nullptr); - uint32_t magic; - - File fd; - if (zip_fd != -1) { - if (ReadMagicAndReset(zip_fd, &magic, error_msg)) { - fd = File(zip_fd, false /* check_usage */); - } - } else { - fd = OpenAndReadMagic(filename, &magic, error_msg); - } - if (fd.Fd() == -1) { - DCHECK(!error_msg->empty()); - return false; - } - if (IsZipMagic(magic)) { - std::unique_ptr<ZipArchive> zip_archive( - ZipArchive::OpenFromFd(fd.Release(), filename, error_msg)); - if (zip_archive.get() == nullptr) { - *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename, - error_msg->c_str()); - return false; - } - - uint32_t i = 0; - std::string zip_entry_name = GetMultiDexClassesDexName(i++); - std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg)); - if (zip_entry.get() == nullptr) { - *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename, - zip_entry_name.c_str(), error_msg->c_str()); - return false; - } - - do { - checksums->push_back(zip_entry->GetCrc32()); - zip_entry_name = GetMultiDexClassesDexName(i++); - zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg)); - } while (zip_entry.get() != nullptr); - return true; - } - if (IsMagicValid(magic)) { - std::unique_ptr<const DexFile> dex_file( - OpenFile(fd.Release(), filename, false, false, error_msg)); - if (dex_file == nullptr) { - return false; - } - checksums->push_back(dex_file->GetHeader().checksum_); - return true; - } - *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename); - return false; -} - bool DexFileLoader::IsMultiDexLocation(const char* location) { return strrchr(location, kMultiDexSeparator) != nullptr; } @@ -187,326 +83,102 @@ std::string DexFileLoader::GetDexCanonicalLocation(const char* dex_location) { } } -std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base, - size_t size, - const std::string& location, - uint32_t location_checksum, - const OatDexFile* oat_dex_file, - bool verify, - bool verify_checksum, - std::string* error_msg) { - ScopedTrace trace(std::string("Open dex file from RAM ") + location); - return OpenCommon(base, - size, - location, - location_checksum, - oat_dex_file, - verify, - verify_checksum, - error_msg, - /*container*/ nullptr, - /*verify_result*/ nullptr); -} +// All of the implementations here should be independent of the runtime. +// TODO: implement all the virtual methods. -std::unique_ptr<const DexFile> DexFileLoader::Open(const std::string& location, - uint32_t location_checksum, - std::unique_ptr<MemMap> map, - bool verify, - bool verify_checksum, - std::string* error_msg) { - ScopedTrace trace(std::string("Open dex file from mapped-memory ") + location); - CHECK(map.get() != nullptr); - - if (map->Size() < sizeof(DexFile::Header)) { - *error_msg = StringPrintf( - "DexFile: failed to open dex file '%s' that is too short to have a header", - location.c_str()); - return nullptr; - } - - std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(), - map->Size(), - location, - location_checksum, - kNoOatDexFile, - verify, - verify_checksum, - error_msg, - new MemMapContainer(std::move(map)), - /*verify_result*/ nullptr); - return dex_file; +bool DexFileLoader::GetMultiDexChecksums(const char* filename ATTRIBUTE_UNUSED, + std::vector<uint32_t>* checksums ATTRIBUTE_UNUSED, + std::string* error_msg, + int zip_fd ATTRIBUTE_UNUSED) const { + *error_msg = "UNIMPLEMENTED"; + return false; } -bool DexFileLoader::Open(const char* filename, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files) { - ScopedTrace trace(std::string("Open dex file ") + std::string(location)); - DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr"; - uint32_t magic; - File fd = OpenAndReadMagic(filename, &magic, error_msg); - if (fd.Fd() == -1) { - DCHECK(!error_msg->empty()); - return false; - } - if (IsZipMagic(magic)) { - return OpenZip(fd.Release(), location, verify, verify_checksum, error_msg, dex_files); - } - if (IsMagicValid(magic)) { - std::unique_ptr<const DexFile> dex_file(OpenFile(fd.Release(), - location, - verify, - verify_checksum, - error_msg)); - if (dex_file.get() != nullptr) { - dex_files->push_back(std::move(dex_file)); - return true; - } else { - return false; - } - } - *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename); +std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base ATTRIBUTE_UNUSED, + size_t size ATTRIBUTE_UNUSED, + const std::string& location ATTRIBUTE_UNUSED, + uint32_t location_checksum ATTRIBUTE_UNUSED, + const OatDexFile* oat_dex_file ATTRIBUTE_UNUSED, + bool verify ATTRIBUTE_UNUSED, + bool verify_checksum ATTRIBUTE_UNUSED, + std::string* error_msg) const { + *error_msg = "UNIMPLEMENTED"; + return nullptr; +} + +std::unique_ptr<const DexFile> DexFileLoader::Open(const std::string& location ATTRIBUTE_UNUSED, + uint32_t location_checksum ATTRIBUTE_UNUSED, + std::unique_ptr<MemMap> map ATTRIBUTE_UNUSED, + bool verify ATTRIBUTE_UNUSED, + bool verify_checksum ATTRIBUTE_UNUSED, + std::string* error_msg) const { + *error_msg = "UNIMPLEMENTED"; + return nullptr; +} + +bool DexFileLoader::Open( + const char* filename ATTRIBUTE_UNUSED, + const std::string& location ATTRIBUTE_UNUSED, + bool verify ATTRIBUTE_UNUSED, + bool verify_checksum ATTRIBUTE_UNUSED, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const { + *error_msg = "UNIMPLEMENTED"; return false; } -std::unique_ptr<const DexFile> DexFileLoader::OpenDex(int fd, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg) { - ScopedTrace trace("Open dex file " + std::string(location)); - return OpenFile(fd, location, verify, verify_checksum, error_msg); +std::unique_ptr<const DexFile> DexFileLoader::OpenDex( + int fd ATTRIBUTE_UNUSED, + const std::string& location ATTRIBUTE_UNUSED, + bool verify ATTRIBUTE_UNUSED, + bool verify_checksum ATTRIBUTE_UNUSED, + std::string* error_msg) const { + *error_msg = "UNIMPLEMENTED"; + return nullptr; } -bool DexFileLoader::OpenZip(int fd, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files) { - ScopedTrace trace("Dex file open Zip " + std::string(location)); - DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is nullptr"; - std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg)); - if (zip_archive.get() == nullptr) { - DCHECK(!error_msg->empty()); - return false; - } - return OpenAllDexFilesFromZip( - *zip_archive, location, verify, verify_checksum, error_msg, dex_files); +bool DexFileLoader::OpenZip( + int fd ATTRIBUTE_UNUSED, + const std::string& location ATTRIBUTE_UNUSED, + bool verify ATTRIBUTE_UNUSED, + bool verify_checksum ATTRIBUTE_UNUSED, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const { + *error_msg = "UNIMPLEMENTED"; + return false; } -std::unique_ptr<const DexFile> DexFileLoader::OpenFile(int fd, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg) { - ScopedTrace trace(std::string("Open dex file ") + std::string(location)); - CHECK(!location.empty()); - std::unique_ptr<MemMap> map; - { - File delayed_close(fd, /* check_usage */ false); - struct stat sbuf; - memset(&sbuf, 0, sizeof(sbuf)); - if (fstat(fd, &sbuf) == -1) { - *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(), - strerror(errno)); - return nullptr; - } - if (S_ISDIR(sbuf.st_mode)) { - *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str()); - return nullptr; - } - size_t length = sbuf.st_size; - map.reset(MemMap::MapFile(length, - PROT_READ, - MAP_PRIVATE, - fd, - 0, - /*low_4gb*/false, - location.c_str(), - error_msg)); - if (map == nullptr) { - DCHECK(!error_msg->empty()); - return nullptr; - } - } - - if (map->Size() < sizeof(DexFile::Header)) { - *error_msg = StringPrintf( - "DexFile: failed to open dex file '%s' that is too short to have a header", - location.c_str()); - return nullptr; - } - - const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(map->Begin()); - - std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(), - map->Size(), - location, - dex_header->checksum_, - kNoOatDexFile, - verify, - verify_checksum, - error_msg, - new MemMapContainer(std::move(map)), - /*verify_result*/ nullptr); - - return dex_file; +std::unique_ptr<const DexFile> DexFileLoader::OpenFile( + int fd ATTRIBUTE_UNUSED, + const std::string& location ATTRIBUTE_UNUSED, + bool verify ATTRIBUTE_UNUSED, + bool verify_checksum ATTRIBUTE_UNUSED, + std::string* error_msg) const { + *error_msg = "UNIMPLEMENTED"; + return nullptr; } std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip( - const ZipArchive& zip_archive, - const char* entry_name, - const std::string& location, - bool verify, - bool verify_checksum, + const ZipArchive& zip_archive ATTRIBUTE_UNUSED, + const char* entry_name ATTRIBUTE_UNUSED, + const std::string& location ATTRIBUTE_UNUSED, + bool verify ATTRIBUTE_UNUSED, + bool verify_checksum ATTRIBUTE_UNUSED, std::string* error_msg, - ZipOpenErrorCode* error_code) { - ScopedTrace trace("Dex file open from Zip Archive " + std::string(location)); - CHECK(!location.empty()); - std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg)); - if (zip_entry == nullptr) { - *error_code = ZipOpenErrorCode::kEntryNotFound; - return nullptr; - } - if (zip_entry->GetUncompressedLength() == 0) { - *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str()); - *error_code = ZipOpenErrorCode::kDexFileError; - return nullptr; - } - - std::unique_ptr<MemMap> map; - if (zip_entry->IsUncompressed()) { - if (!zip_entry->IsAlignedTo(alignof(DexFile::Header))) { - // Do not mmap unaligned ZIP entries because - // doing so would fail dex verification which requires 4 byte alignment. - LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; " - << "please zipalign to " << alignof(DexFile::Header) << " bytes. " - << "Falling back to extracting file."; - } else { - // Map uncompressed files within zip as file-backed to avoid a dirty copy. - map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg)); - if (map == nullptr) { - LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; " - << "is your ZIP file corrupted? Falling back to extraction."; - // Try again with Extraction which still has a chance of recovery. - } - } - } - - if (map == nullptr) { - // Default path for compressed ZIP entries, - // and fallback for stored ZIP entries. - map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg)); - } - - if (map == nullptr) { - *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(), - error_msg->c_str()); - *error_code = ZipOpenErrorCode::kExtractToMemoryError; - return nullptr; - } - VerifyResult verify_result; - std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(), - map->Size(), - location, - zip_entry->GetCrc32(), - kNoOatDexFile, - verify, - verify_checksum, - error_msg, - new MemMapContainer(std::move(map)), - &verify_result); - if (dex_file == nullptr) { - if (verify_result == VerifyResult::kVerifyNotAttempted) { - *error_code = ZipOpenErrorCode::kDexFileError; - } else { - *error_code = ZipOpenErrorCode::kVerifyError; - } - return nullptr; - } - if (!dex_file->DisableWrite()) { - *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str()); - *error_code = ZipOpenErrorCode::kMakeReadOnlyError; - return nullptr; - } - CHECK(dex_file->IsReadOnly()) << location; - if (verify_result != VerifyResult::kVerifySucceeded) { - *error_code = ZipOpenErrorCode::kVerifyError; - return nullptr; - } - *error_code = ZipOpenErrorCode::kNoError; - return dex_file; + ZipOpenErrorCode* error_code ATTRIBUTE_UNUSED) const { + *error_msg = "UNIMPLEMENTED"; + return nullptr; } -// Technically we do not have a limitation with respect to the number of dex files that can be in a -// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols -// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what -// seems an excessive number. -static constexpr size_t kWarnOnManyDexFilesThreshold = 100; - -bool DexFileLoader::OpenAllDexFilesFromZip(const ZipArchive& zip_archive, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files) { - ScopedTrace trace("Dex file open from Zip " + std::string(location)); - DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr"; - ZipOpenErrorCode error_code; - std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive, - kClassesDex, - location, - verify, - verify_checksum, - error_msg, - &error_code)); - if (dex_file.get() == nullptr) { - return false; - } else { - // Had at least classes.dex. - dex_files->push_back(std::move(dex_file)); - - // Now try some more. - - // We could try to avoid std::string allocations by working on a char array directly. As we - // do not expect a lot of iterations, this seems too involved and brittle. - - for (size_t i = 1; ; ++i) { - std::string name = GetMultiDexClassesDexName(i); - std::string fake_location = GetMultiDexLocation(i, location.c_str()); - std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive, - name.c_str(), - fake_location, - verify, - verify_checksum, - error_msg, - &error_code)); - if (next_dex_file.get() == nullptr) { - if (error_code != ZipOpenErrorCode::kEntryNotFound) { - LOG(WARNING) << "Zip open failed: " << *error_msg; - } - break; - } else { - dex_files->push_back(std::move(next_dex_file)); - } - - if (i == kWarnOnManyDexFilesThreshold) { - LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold - << " dex files. Please consider coalescing and shrinking the number to " - " avoid runtime overhead."; - } - - if (i == std::numeric_limits<size_t>::max()) { - LOG(ERROR) << "Overflow in number of dex files!"; - break; - } - } - - return true; - } +bool DexFileLoader::OpenAllDexFilesFromZip( + const ZipArchive& zip_archive ATTRIBUTE_UNUSED, + const std::string& location ATTRIBUTE_UNUSED, + bool verify ATTRIBUTE_UNUSED, + bool verify_checksum ATTRIBUTE_UNUSED, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const { + *error_msg = "UNIMPLEMENTED"; + return false; } std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base, diff --git a/runtime/dex/dex_file_loader.h b/runtime/dex/dex_file_loader.h index 7db8d8e08e..6f1afd636f 100644 --- a/runtime/dex/dex_file_loader.h +++ b/runtime/dex/dex_file_loader.h @@ -46,6 +46,8 @@ class DexFileLoader { // Return true if the corresponding version and magic is valid. static bool IsVersionAndMagicValid(const uint8_t* magic); + virtual ~DexFileLoader() { } + // Returns the checksums of a file for comparison with GetLocationChecksum(). // For .dex files, this is the single header checksum. // For zip files, this is the zip entry CRC32 checksum for classes.dex and @@ -55,55 +57,55 @@ class DexFileLoader { // zip_fd is -1, the method will try to open the `filename` and read the // content from it. // Return true if the checksums could be found, false otherwise. - static bool GetMultiDexChecksums(const char* filename, - std::vector<uint32_t>* checksums, - std::string* error_msg, - int zip_fd = -1); + virtual bool GetMultiDexChecksums(const char* filename, + std::vector<uint32_t>* checksums, + std::string* error_msg, + int zip_fd = -1) const; // Check whether a location denotes a multidex dex file. This is a very simple check: returns // whether the string contains the separator character. static bool IsMultiDexLocation(const char* location); // Opens .dex file, backed by existing memory - static std::unique_ptr<const DexFile> Open(const uint8_t* base, - size_t size, - const std::string& location, - uint32_t location_checksum, - const OatDexFile* oat_dex_file, - bool verify, - bool verify_checksum, - std::string* error_msg); + virtual std::unique_ptr<const DexFile> Open(const uint8_t* base, + size_t size, + const std::string& location, + uint32_t location_checksum, + const OatDexFile* oat_dex_file, + bool verify, + bool verify_checksum, + std::string* error_msg) const; // Opens .dex file that has been memory-mapped by the caller. - static std::unique_ptr<const DexFile> Open(const std::string& location, - uint32_t location_checkum, - std::unique_ptr<MemMap> mem_map, - bool verify, - bool verify_checksum, - std::string* error_msg); + virtual std::unique_ptr<const DexFile> Open(const std::string& location, + uint32_t location_checkum, + std::unique_ptr<MemMap> mem_map, + bool verify, + bool verify_checksum, + std::string* error_msg) const; // Opens all .dex files found in the file, guessing the container format based on file extension. - static bool Open(const char* filename, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files); + virtual bool Open(const char* filename, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files) const; // Open a single dex file from an fd. This function closes the fd. - static std::unique_ptr<const DexFile> OpenDex(int fd, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg); + virtual std::unique_ptr<const DexFile> OpenDex(int fd, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg) const; // Opens dex files from within a .jar, .zip, or .apk file - static bool OpenZip(int fd, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files); + virtual bool OpenZip(int fd, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files) const; // Return the name of the index-th classes.dex in a multidex zip file. This is classes.dex for // index == 0, and classes{index + 1}.dex else. @@ -148,13 +150,7 @@ class DexFileLoader { return (pos == std::string::npos) ? std::string() : location.substr(pos); } - private: - static std::unique_ptr<const DexFile> OpenFile(int fd, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg); - + protected: enum class ZipOpenErrorCode { kNoError, kEntryNotFound, @@ -164,24 +160,6 @@ class DexFileLoader { kVerifyError }; - // Open all classesXXX.dex files from a zip archive. - static bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg, - std::vector<std::unique_ptr<const DexFile>>* dex_files); - - // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null - // return. - static std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive, - const char* entry_name, - const std::string& location, - bool verify, - bool verify_checksum, - std::string* error_msg, - ZipOpenErrorCode* error_code); - enum class VerifyResult { // private kVerifyNotAttempted, kVerifySucceeded, @@ -198,6 +176,31 @@ class DexFileLoader { std::string* error_msg, DexFileContainer* container, VerifyResult* verify_result); + + private: + virtual std::unique_ptr<const DexFile> OpenFile(int fd, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg) const; + + // Open all classesXXX.dex files from a zip archive. + virtual bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + std::vector<std::unique_ptr<const DexFile>>* dex_files) const; + + // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null + // return. + virtual std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive, + const char* entry_name, + const std::string& location, + bool verify, + bool verify_checksum, + std::string* error_msg, + ZipOpenErrorCode* error_code) const; }; } // namespace art diff --git a/runtime/dex/dex_file_test.cc b/runtime/dex/dex_file_test.cc index 3ee115c01b..1c8b3e4180 100644 --- a/runtime/dex/dex_file_test.cc +++ b/runtime/dex/dex_file_test.cc @@ -20,6 +20,7 @@ #include <memory> +#include "art_dex_file_loader.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "code_item_accessors-inl.h" @@ -237,7 +238,8 @@ static bool OpenDexFilesBase64(const char* base64, ScopedObjectAccess soa(Thread::Current()); static constexpr bool kVerifyChecksum = true; std::vector<std::unique_ptr<const DexFile>> tmp; - bool success = DexFileLoader::Open( + const ArtDexFileLoader dex_file_loader; + bool success = dex_file_loader.Open( location, location, /* verify */ true, kVerifyChecksum, error_msg, &tmp); if (success) { for (std::unique_ptr<const DexFile>& dex_file : tmp) { @@ -277,12 +279,13 @@ static std::unique_ptr<const DexFile> OpenDexFileInMemoryBase64(const char* base /* reuse */ false, &error_message)); memcpy(region->Begin(), dex_bytes.data(), dex_bytes.size()); - std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(location, - location_checksum, - std::move(region), - /* verify */ true, - /* verify_checksum */ true, - &error_message)); + const ArtDexFileLoader dex_file_loader; + std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(location, + location_checksum, + std::move(region), + /* verify */ true, + /* verify_checksum */ true, + &error_message)); if (expect_success) { CHECK(dex_file != nullptr) << error_message; } else { @@ -368,7 +371,8 @@ TEST_F(DexFileTest, Version40Rejected) { static constexpr bool kVerifyChecksum = true; std::string error_msg; std::vector<std::unique_ptr<const DexFile>> dex_files; - ASSERT_FALSE(DexFileLoader::Open( + const ArtDexFileLoader dex_file_loader; + ASSERT_FALSE(dex_file_loader.Open( location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)); } @@ -381,7 +385,8 @@ TEST_F(DexFileTest, Version41Rejected) { static constexpr bool kVerifyChecksum = true; std::string error_msg; std::vector<std::unique_ptr<const DexFile>> dex_files; - ASSERT_FALSE(DexFileLoader::Open( + const ArtDexFileLoader dex_file_loader; + ASSERT_FALSE(dex_file_loader.Open( location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)); } @@ -394,7 +399,8 @@ TEST_F(DexFileTest, ZeroLengthDexRejected) { static constexpr bool kVerifyChecksum = true; std::string error_msg; std::vector<std::unique_ptr<const DexFile>> dex_files; - ASSERT_FALSE(DexFileLoader::Open( + const ArtDexFileLoader dex_file_loader; + ASSERT_FALSE(dex_file_loader.Open( location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)); } @@ -408,9 +414,10 @@ TEST_F(DexFileTest, GetChecksum) { std::vector<uint32_t> checksums; ScopedObjectAccess soa(Thread::Current()); std::string error_msg; - EXPECT_TRUE(DexFileLoader::GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(), - &checksums, - &error_msg)) + const ArtDexFileLoader dex_file_loader; + EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(), + &checksums, + &error_msg)) << error_msg; ASSERT_EQ(1U, checksums.size()); EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksums[0]); @@ -420,9 +427,10 @@ TEST_F(DexFileTest, GetMultiDexChecksums) { std::string error_msg; std::vector<uint32_t> checksums; std::string multidex_file = GetTestDexFileName("MultiDex"); - EXPECT_TRUE(DexFileLoader::GetMultiDexChecksums(multidex_file.c_str(), - &checksums, - &error_msg)) << error_msg; + const ArtDexFileLoader dex_file_loader; + EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(multidex_file.c_str(), + &checksums, + &error_msg)) << error_msg; std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex"); ASSERT_EQ(2U, dexes.size()); diff --git a/runtime/dex/dex_file_verifier_test.cc b/runtime/dex/dex_file_verifier_test.cc index d4d912cbfb..9759685961 100644 --- a/runtime/dex/dex_file_verifier_test.cc +++ b/runtime/dex/dex_file_verifier_test.cc @@ -22,6 +22,7 @@ #include <functional> #include <memory> +#include "art_dex_file_loader.h" #include "base/bit_utils.h" #include "base/macros.h" #include "base/unix_file/fd_file.h" @@ -114,7 +115,8 @@ static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64, // read dex file ScopedObjectAccess soa(Thread::Current()); std::vector<std::unique_ptr<const DexFile>> tmp; - bool success = DexFileLoader::Open( + const ArtDexFileLoader dex_file_loader; + bool success = dex_file_loader.Open( location, location, /* verify */ true, /* verify_checksum */ true, error_msg, &tmp); CHECK(success) << *error_msg; EXPECT_EQ(1U, tmp.size()); diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h index e459f09e95..20cde530c2 100644 --- a/runtime/dex2oat_environment_test.h +++ b/runtime/dex2oat_environment_test.h @@ -27,6 +27,7 @@ #include "base/stl_util.h" #include "common_runtime_test.h" #include "compiler_callbacks.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file_loader.h" #include "exec_utils.h" #include "gc/heap.h" @@ -43,6 +44,7 @@ class Dex2oatEnvironmentTest : public CommonRuntimeTest { public: virtual void SetUp() OVERRIDE { CommonRuntimeTest::SetUp(); + const ArtDexFileLoader dex_file_loader; // Create a scratch directory to work from. @@ -74,7 +76,7 @@ class Dex2oatEnvironmentTest : public CommonRuntimeTest { ASSERT_TRUE(OS::FileExists(GetStrippedDexSrc1().c_str())) << "Expected stripped dex file to be at: " << GetStrippedDexSrc1(); ASSERT_FALSE( - DexFileLoader::GetMultiDexChecksums(GetStrippedDexSrc1().c_str(), &checksums, &error_msg)) + dex_file_loader.GetMultiDexChecksums(GetStrippedDexSrc1().c_str(), &checksums, &error_msg)) << "Expected stripped dex file to be stripped: " << GetStrippedDexSrc1(); ASSERT_TRUE(OS::FileExists(GetDexSrc2().c_str())) << "Expected dex file to be at: " << GetDexSrc2(); @@ -83,21 +85,21 @@ class Dex2oatEnvironmentTest : public CommonRuntimeTest { // GetMultiDexSrc1, but a different secondary dex checksum. static constexpr bool kVerifyChecksum = true; std::vector<std::unique_ptr<const DexFile>> multi1; - ASSERT_TRUE(DexFileLoader::Open(GetMultiDexSrc1().c_str(), - GetMultiDexSrc1().c_str(), - /* verify */ true, - kVerifyChecksum, - &error_msg, - &multi1)) << error_msg; + ASSERT_TRUE(dex_file_loader.Open(GetMultiDexSrc1().c_str(), + GetMultiDexSrc1().c_str(), + /* verify */ true, + kVerifyChecksum, + &error_msg, + &multi1)) << error_msg; ASSERT_GT(multi1.size(), 1u); std::vector<std::unique_ptr<const DexFile>> multi2; - ASSERT_TRUE(DexFileLoader::Open(GetMultiDexSrc2().c_str(), - GetMultiDexSrc2().c_str(), - /* verify */ true, - kVerifyChecksum, - &error_msg, - &multi2)) << error_msg; + ASSERT_TRUE(dex_file_loader.Open(GetMultiDexSrc2().c_str(), + GetMultiDexSrc2().c_str(), + /* verify */ true, + kVerifyChecksum, + &error_msg, + &multi2)) << error_msg; ASSERT_GT(multi2.size(), 1u); ASSERT_EQ(multi1[0]->GetLocationChecksum(), multi2[0]->GetLocationChecksum()); diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index f727690c11..a32c717ffe 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -1294,9 +1294,9 @@ extern "C" const void* artQuickResolutionTrampoline( // with the interpreter. code = GetQuickToInterpreterBridge(); } else if (invoke_type == kStatic) { - // Class is still initializing, go to oat and grab code (trampoline must be left in place - // until class is initialized to stop races between threads). - code = linker->GetQuickOatCodeFor(called); + // Class is still initializing. The entrypoint contains the trampoline, so we cannot return + // it. Instead, ask the class linker what is the actual code that needs to be invoked. + code = linker->GetQuickEntrypointFor(called); } else { // No trampoline for non-static methods. code = called->GetEntryPointFromQuickCompiledCode(); diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 251d94ca25..ca5a3eeb17 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -36,6 +36,7 @@ #include "base/stl_util.h" #include "base/systrace.h" #include "base/time_utils.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file_loader.h" #include "exec_utils.h" #include "gc/accounting/space_bitmap-inl.h" @@ -1828,6 +1829,7 @@ std::string ImageSpace::GetMultiImageBootClassPath( } bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg) { + const ArtDexFileLoader dex_file_loader; for (const OatFile::OatDexFile* oat_dex_file : oat_file.GetOatDexFiles()) { const std::string& dex_file_location = oat_dex_file->GetDexFileLocation(); @@ -1838,7 +1840,7 @@ bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg } std::vector<uint32_t> checksums; - if (!DexFileLoader::GetMultiDexChecksums(dex_file_location.c_str(), &checksums, error_msg)) { + if (!dex_file_loader.GetMultiDexChecksums(dex_file_location.c_str(), &checksums, error_msg)) { *error_msg = StringPrintf("ValidateOatFile failed to get checksums of dex file '%s' " "referenced by oat file %s: %s", dex_file_location.c_str(), diff --git a/runtime/globals.h b/runtime/globals.h index f14d6e95a6..ca4040d777 100644 --- a/runtime/globals.h +++ b/runtime/globals.h @@ -62,6 +62,12 @@ static constexpr bool kIsDebugBuild = GlobalsReturnSelf(false); static constexpr bool kIsDebugBuild = GlobalsReturnSelf(true); #endif +#if defined(ART_PGO_INSTRUMENTATION) +static constexpr bool kIsPGOInstrumentation = true; +#else +static constexpr bool kIsPGOInstrumentation = false; +#endif + // ART_TARGET - Defined for target builds of ART. // ART_TARGET_LINUX - Defined for target Linux builds of ART. // ART_TARGET_ANDROID - Defined for target Android builds of ART. diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index 4524448916..2a1f219fae 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -167,7 +167,7 @@ void Instrumentation::InstallStubsForMethod(ArtMethod* method) { if (NeedDebugVersionFor(method)) { new_quick_code = GetQuickToInterpreterBridge(); } else { - new_quick_code = class_linker->GetQuickOatCodeFor(method); + new_quick_code = class_linker->GetQuickEntrypointFor(method); } } else { new_quick_code = GetQuickResolutionStub(); @@ -188,7 +188,7 @@ void Instrumentation::InstallStubsForMethod(ArtMethod* method) { } else if (entry_exit_stubs_installed_) { new_quick_code = GetQuickInstrumentationEntryPoint(); } else { - new_quick_code = class_linker->GetQuickOatCodeFor(method); + new_quick_code = class_linker->GetQuickEntrypointFor(method); } } else { new_quick_code = GetQuickResolutionStub(); @@ -877,7 +877,7 @@ void Instrumentation::Undeoptimize(ArtMethod* method) { } else { const void* quick_code = NeedDebugVersionFor(method) ? GetQuickToInterpreterBridge() - : class_linker->GetQuickOatCodeFor(method); + : class_linker->GetQuickEntrypointFor(method); UpdateEntrypoints(method, quick_code); } @@ -971,7 +971,7 @@ const void* Instrumentation::GetQuickCodeFor(ArtMethod* method, PointerSize poin return code; } } - return class_linker->GetQuickOatCodeFor(method); + return class_linker->GetQuickEntrypointFor(method); } void Instrumentation::MethodEnterEventImpl(Thread* thread, diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index a992b5cb5b..0f430874cf 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -27,6 +27,7 @@ #include <class_loader_context.h> #include "common_throws.h" #include "compiler_filter.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" #include "jni_internal.h" @@ -188,12 +189,13 @@ static const DexFile* CreateDexFile(JNIEnv* env, std::unique_ptr<MemMap> dex_mem dex_mem_map->Begin(), dex_mem_map->End()); std::string error_message; - std::unique_ptr<const DexFile> dex_file(DexFileLoader::Open(location, - 0, - std::move(dex_mem_map), - /* verify */ true, - /* verify_location */ true, - &error_message)); + const ArtDexFileLoader dex_file_loader; + std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(location, + 0, + std::move(dex_mem_map), + /* verify */ true, + /* verify_location */ true, + &error_message)); if (dex_file == nullptr) { ScopedObjectAccess soa(env); ThrowWrappedIOException("%s", error_message.c_str()); diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index c6664411e4..446a004244 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -43,6 +43,7 @@ #include "base/stl_util.h" #include "base/systrace.h" #include "base/unix_file/fd_file.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file_loader.h" #include "dex/dex_file_types.h" #include "dex/standard_dex_file.h" @@ -1666,14 +1667,15 @@ std::unique_ptr<const DexFile> OatFile::OatDexFile::OpenDexFile(std::string* err ScopedTrace trace(__PRETTY_FUNCTION__); static constexpr bool kVerify = false; static constexpr bool kVerifyChecksum = false; - return DexFileLoader::Open(dex_file_pointer_, - FileSize(), - dex_file_location_, - dex_file_location_checksum_, - this, - kVerify, - kVerifyChecksum, - error_msg); + const ArtDexFileLoader dex_file_loader; + return dex_file_loader.Open(dex_file_pointer_, + FileSize(), + dex_file_location_, + dex_file_location_checksum_, + this, + kVerify, + kVerifyChecksum, + error_msg); } uint32_t OatFile::OatDexFile::GetOatClassOffset(uint16_t class_def_index) const { diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 240030cf5b..73ca19a363 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -28,6 +28,7 @@ #include "base/stl_util.h" #include "class_linker.h" #include "compiler_filter.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file_loader.h" #include "exec_utils.h" #include "gc/heap.h" @@ -869,10 +870,11 @@ const std::vector<uint32_t>* OatFileAssistant::GetRequiredDexChecksums() { required_dex_checksums_found_ = false; cached_required_dex_checksums_.clear(); std::string error_msg; - if (DexFileLoader::GetMultiDexChecksums(dex_location_.c_str(), - &cached_required_dex_checksums_, - &error_msg, - zip_fd_)) { + const ArtDexFileLoader dex_file_loader; + if (dex_file_loader.GetMultiDexChecksums(dex_location_.c_str(), + &cached_required_dex_checksums_, + &error_msg, + zip_fd_)) { required_dex_checksums_found_ = true; has_original_dex_files_ = true; } else { diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index 29b9bfcf7f..9503360167 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -31,6 +31,7 @@ #include "base/systrace.h" #include "class_linker.h" #include "class_loader_context.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" #include "dex/dex_file_tracking_registrar.h" @@ -40,6 +41,7 @@ #include "jni_internal.h" #include "mirror/class_loader.h" #include "mirror/object-inl.h" +#include "oat_file.h" #include "oat_file_assistant.h" #include "obj_ptr-inl.h" #include "scoped_thread_state_change-inl.h" @@ -527,8 +529,14 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( if (source_oat_file != nullptr) { bool added_image_space = false; if (source_oat_file->IsExecutable()) { - std::unique_ptr<gc::space::ImageSpace> image_space = - kEnableAppImage ? oat_file_assistant.OpenImageSpace(source_oat_file) : nullptr; + // We need to throw away the image space if we are debuggable but the oat-file source of the + // image is not otherwise we might get classes with inlined methods or other such things. + std::unique_ptr<gc::space::ImageSpace> image_space; + if (kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable())) { + image_space = oat_file_assistant.OpenImageSpace(source_oat_file); + } else { + image_space = nullptr; + } if (image_space != nullptr) { ScopedObjectAccess soa(self); StackHandleScope<1> hs(self); @@ -606,12 +614,13 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( if (oat_file_assistant.HasOriginalDexFiles()) { if (Runtime::Current()->IsDexFileFallbackEnabled()) { static constexpr bool kVerifyChecksum = true; - if (!DexFileLoader::Open(dex_location, - dex_location, - Runtime::Current()->IsVerificationEnabled(), - kVerifyChecksum, - /*out*/ &error_msg, - &dex_files)) { + const ArtDexFileLoader dex_file_loader; + if (!dex_file_loader.Open(dex_location, + dex_location, + Runtime::Current()->IsVerificationEnabled(), + kVerifyChecksum, + /*out*/ &error_msg, + &dex_files)) { LOG(WARNING) << error_msg; error_msgs->push_back("Failed to open dex files from " + std::string(dex_location) + " because: " + error_msg); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 38c2bfd96f..377e0a3fca 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -69,6 +69,7 @@ #include "class_linker-inl.h" #include "compiler_callbacks.h" #include "debugger.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file_loader.h" #include "elf_file.h" #include "entrypoints/runtime_asm_entrypoints.h" @@ -1041,6 +1042,7 @@ static size_t OpenDexFiles(const std::vector<std::string>& dex_filenames, if (!image_location.empty() && OpenDexFilesFromImage(image_location, dex_files, &failure_count)) { return failure_count; } + const ArtDexFileLoader dex_file_loader; failure_count = 0; for (size_t i = 0; i < dex_filenames.size(); i++) { const char* dex_filename = dex_filenames[i].c_str(); @@ -1051,12 +1053,12 @@ static size_t OpenDexFiles(const std::vector<std::string>& dex_filenames, LOG(WARNING) << "Skipping non-existent dex file '" << dex_filename << "'"; continue; } - if (!DexFileLoader::Open(dex_filename, - dex_location, - Runtime::Current()->IsVerificationEnabled(), - kVerifyChecksum, - &error_msg, - dex_files)) { + if (!dex_file_loader.Open(dex_filename, + dex_location, + Runtime::Current()->IsVerificationEnabled(), + kVerifyChecksum, + &error_msg, + dex_files)) { LOG(WARNING) << "Failed to open .dex from file '" << dex_filename << "': " << error_msg; ++failure_count; } @@ -1551,6 +1553,7 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { } static bool EnsureJvmtiPlugin(Runtime* runtime, + bool allow_non_debuggable_tooling, std::vector<Plugin>* plugins, std::string* error_msg) { constexpr const char* plugin_name = kIsDebugBuild ? "libopenjdkjvmtid.so" : "libopenjdkjvmti.so"; @@ -1562,9 +1565,9 @@ static bool EnsureJvmtiPlugin(Runtime* runtime, } } - // Is the process debuggable? Otherwise, do not attempt to load the plugin. - // TODO Support a crimped jvmti for non-debuggable runtimes. - if (!runtime->IsJavaDebuggable()) { + // Is the process debuggable? Otherwise, do not attempt to load the plugin unless we are + // specifically allowed. + if (!allow_non_debuggable_tooling && !runtime->IsJavaDebuggable()) { *error_msg = "Process is not debuggable."; return false; } @@ -1585,9 +1588,12 @@ static bool EnsureJvmtiPlugin(Runtime* runtime, // revisit this and make sure we're doing this on the right thread // (and we synchronize access to any shared data structures like "agents_") // -void Runtime::AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader) { +void Runtime::AttachAgent(JNIEnv* env, + const std::string& agent_arg, + jobject class_loader, + bool allow_non_debuggable_tooling) { std::string error_msg; - if (!EnsureJvmtiPlugin(this, &plugins_, &error_msg)) { + if (!EnsureJvmtiPlugin(this, allow_non_debuggable_tooling, &plugins_, &error_msg)) { LOG(WARNING) << "Could not load plugin: " << error_msg; ScopedObjectAccess soa(Thread::Current()); ThrowIOException("%s", error_msg.c_str()); diff --git a/runtime/runtime.h b/runtime/runtime.h index c8edabce09..3e055c3f84 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -661,7 +661,10 @@ class Runtime { void AddSystemWeakHolder(gc::AbstractSystemWeakHolder* holder); void RemoveSystemWeakHolder(gc::AbstractSystemWeakHolder* holder); - void AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader); + void AttachAgent(JNIEnv* env, + const std::string& agent_arg, + jobject class_loader, + bool allow_non_debuggable_tooling = false); const std::list<std::unique_ptr<ti::Agent>>& GetAgents() const { return agents_; diff --git a/runtime/utils.cc b/runtime/utils.cc index bd4175f5fd..79ddcb9bff 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -26,10 +26,10 @@ #include <memory> +#include "android-base/file.h" #include "android-base/stringprintf.h" #include "android-base/strings.h" -#include "base/file_utils.h" #include "dex/dex_file-inl.h" #include "os.h" #include "utf-inl.h" @@ -46,6 +46,7 @@ namespace art { +using android::base::ReadFileToString; using android::base::StringAppendF; using android::base::StringPrintf; @@ -63,6 +64,7 @@ pid_t GetTid() { std::string GetThreadName(pid_t tid) { std::string result; + // TODO: make this less Linux-specific. if (ReadFileToString(StringPrintf("/proc/self/task/%d/comm", tid), &result)) { result.resize(result.size() - 1); // Lose the trailing '\n'. } else { @@ -611,6 +613,7 @@ void SetThreadName(const char* thread_name) { void GetTaskStats(pid_t tid, char* state, int* utime, int* stime, int* task_cpu) { *utime = *stime = *task_cpu = 0; std::string stats; + // TODO: make this less Linux-specific. if (!ReadFileToString(StringPrintf("/proc/self/task/%d/stat", tid), &stats)) { return; } diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc index c536054883..c16cfb6578 100644 --- a/runtime/vdex_file.cc +++ b/runtime/vdex_file.cc @@ -25,6 +25,7 @@ #include "base/bit_utils.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "dex_to_dex_decompiler.h" @@ -171,6 +172,7 @@ const uint8_t* VdexFile::GetNextDexFileData(const uint8_t* cursor) const { bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_files, std::string* error_msg) { + const ArtDexFileLoader dex_file_loader; size_t i = 0; for (const uint8_t* dex_file_start = GetNextDexFileData(nullptr); dex_file_start != nullptr; @@ -179,14 +181,14 @@ bool VdexFile::OpenAllDexFiles(std::vector<std::unique_ptr<const DexFile>>* dex_ // TODO: Supply the location information for a vdex file. static constexpr char kVdexLocation[] = ""; std::string location = DexFileLoader::GetMultiDexLocation(i, kVdexLocation); - std::unique_ptr<const DexFile> dex(DexFileLoader::Open(dex_file_start, - size, - location, - GetLocationChecksum(i), - nullptr /*oat_dex_file*/, - false /*verify*/, - false /*verify_checksum*/, - error_msg)); + std::unique_ptr<const DexFile> dex(dex_file_loader.Open(dex_file_start, + size, + location, + GetLocationChecksum(i), + nullptr /*oat_dex_file*/, + false /*verify*/, + false /*verify_checksum*/, + error_msg)); if (dex == nullptr) { return false; } diff --git a/test/626-checker-arm64-scratch-register/smali/Smali.smali b/test/626-checker-arm64-scratch-register/smali/Smali.smali new file mode 100644 index 0000000000..e6943cf717 --- /dev/null +++ b/test/626-checker-arm64-scratch-register/smali/Smali.smali @@ -0,0 +1,2119 @@ +# Copyright (C) 2017 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.class public LSmali; +.super Ljava/lang/Object; +.field b00:Z +.field b01:Z +.field b02:Z +.field b03:Z +.field b04:Z +.field b05:Z +.field b06:Z +.field b07:Z +.field b08:Z +.field b09:Z +.field b10:Z +.field b11:Z +.field b12:Z +.field b13:Z +.field b14:Z +.field b15:Z +.field b16:Z +.field b17:Z +.field b18:Z +.field b19:Z +.field b20:Z +.field b21:Z +.field b22:Z +.field b23:Z +.field b24:Z +.field b25:Z +.field b26:Z +.field b27:Z +.field b28:Z +.field b29:Z +.field b30:Z +.field b31:Z +.field b32:Z +.field b33:Z +.field b34:Z +.field b35:Z +.field b36:Z + +.field conditionA:Z +.field conditionB:Z +.field conditionC:Z + +.method public constructor <init>()V + .registers 1 + invoke-direct {p0}, Ljava/lang/Object;-><init>()V + return-void +.end method + +## CHECK-START-ARM64: void Smali.test() register (after) +## CHECK: begin_block +## CHECK: name "B0" +## CHECK: <<This:l\d+>> ParameterValue +## CHECK: end_block +## CHECK: begin_block +## CHECK: successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>" +## CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Smali.conditionB +## CHECK: If [<<CondB>>] +## CHECK: end_block +## CHECK: begin_block +## CHECK: name "<<ElseBlock>>" +## CHECK: ParallelMove moves:[40(sp)->d0,24(sp)->32(sp),28(sp)->36(sp),d0->d3,d3->d4,d2->d5,d4->d6,d5->d7,d6->d18,d7->d19,d18->d20,d19->d21,d20->d22,d21->d23,d22->d10,d23->d11,16(sp)->24(sp),20(sp)->28(sp),d10->d14,d11->d12,d12->d13,d13->d1,d14->d2,32(sp)->16(sp),36(sp)->20(sp)] +## CHECK: end_block + +## CHECK-START-ARM64: void Smali.test() disassembly (after) +## CHECK: begin_block +## CHECK: name "B0" +## CHECK: <<This:l\d+>> ParameterValue +## CHECK: end_block +## CHECK: begin_block +## CHECK: successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>" +## CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Smali.conditionB +## CHECK: If [<<CondB>>] +## CHECK: end_block +## CHECK: begin_block +## CHECK: name "<<ElseBlock>>" +## CHECK: ParallelMove moves:[invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid] +## CHECK: fmov d31, d2 +## CHECK: ldr s2, [sp, #36] +## CHECK: ldr w16, [sp, #16] +## CHECK: str w16, [sp, #36] +## CHECK: str s14, [sp, #16] +## CHECK: ldr s14, [sp, #28] +## CHECK: str s1, [sp, #28] +## CHECK: ldr s1, [sp, #32] +## CHECK: str s31, [sp, #32] +## CHECK: ldr s31, [sp, #20] +## CHECK: str s31, [sp, #40] +## CHECK: str s12, [sp, #20] +## CHECK: fmov d12, d11 +## CHECK: fmov d11, d10 +## CHECK: fmov d10, d23 +## CHECK: fmov d23, d22 +## CHECK: fmov d22, d21 +## CHECK: fmov d21, d20 +## CHECK: fmov d20, d19 +## CHECK: fmov d19, d18 +## CHECK: fmov d18, d7 +## CHECK: fmov d7, d6 +## CHECK: fmov d6, d5 +## CHECK: fmov d5, d4 +## CHECK: fmov d4, d3 +## CHECK: fmov d3, d13 +## CHECK: ldr s13, [sp, #24] +## CHECK: str s3, [sp, #24] +## CHECK: ldr s3, pc+{{\d+}} (addr {{0x[0-9a-f]+}}) (100) +## CHECK: end_block +.method public test()V + .registers 45 + + const-string v39, "" + + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b17:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_367 + + const/16 v19, 0x0 + + :goto_c + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b16:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_36b + + const/16 v18, 0x0 + + :goto_16 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b18:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_36f + + const/16 v20, 0x0 + + :goto_20 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b19:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_373 + + const/16 v21, 0x0 + + :goto_2a + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b20:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_377 + + const/16 v22, 0x0 + + :goto_34 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b21:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_37b + + const/16 v23, 0x0 + + :goto_3e + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b15:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_37f + + const/16 v17, 0x0 + + :goto_48 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b00:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_383 + + const/4 v2, 0x0 + + :goto_51 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b22:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_387 + + const/16 v24, 0x0 + + :goto_5b + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b23:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_38b + + const/16 v25, 0x0 + + :goto_65 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b24:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_38f + + const/16 v26, 0x0 + + :goto_6f + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b25:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_393 + + const/16 v27, 0x0 + + :goto_79 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b26:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_397 + + const/16 v28, 0x0 + + :goto_83 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b27:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_39b + + const/16 v29, 0x0 + + :goto_8d + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b29:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_39f + + const/16 v31, 0x0 + + :goto_97 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b28:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3a3 + + const/16 v30, 0x0 + + :goto_a1 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b01:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3a7 + + const/4 v3, 0x0 + + :goto_aa + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b02:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3ab + + const/4 v4, 0x0 + + :goto_b3 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b03:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3af + + const/4 v5, 0x0 + + :goto_bc + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b04:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3b3 + + const/4 v6, 0x0 + + :goto_c5 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b05:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3b7 + + const/4 v7, 0x0 + + :goto_ce + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b07:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3bb + + const/4 v9, 0x0 + + :goto_d7 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b06:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3bf + + const/4 v8, 0x0 + + :goto_e0 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b30:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3c3 + + const/16 v32, 0x0 + + :goto_ea + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b31:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3c7 + + const/16 v33, 0x0 + + :goto_f4 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b32:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3cb + + const/16 v34, 0x0 + + :goto_fe + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b33:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3cf + + const/16 v35, 0x0 + + :goto_108 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b34:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3d3 + + const/16 v36, 0x0 + + :goto_112 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b36:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3d7 + + const/16 v38, 0x0 + + :goto_11c + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b35:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3db + + const/16 v37, 0x0 + + :goto_126 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b08:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3df + + const/4 v10, 0x0 + + :goto_12f + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b09:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3e3 + + const/4 v11, 0x0 + + :goto_138 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b10:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3e7 + + const/4 v12, 0x0 + + :goto_141 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b11:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3eb + + const/4 v13, 0x0 + + :goto_14a + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b12:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3ef + + const/4 v14, 0x0 + + :goto_153 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b14:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3f3 + + const/16 v16, 0x0 + + :goto_15d + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->b13:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_3f7 + + const/4 v15, 0x0 + + :goto_166 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->conditionA:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_202 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v18, v18, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v19, v19, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v20, v20, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v21, v21, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v22, v22, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v23, v23, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v17, v17, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v10, v10, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v11, v11, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v12, v12, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v13, v13, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v14, v14, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v32, v32, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v33, v33, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v34, v34, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v35, v35, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v36, v36, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v3, v3, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v4, v4, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v5, v5, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v6, v6, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v7, v7, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v25, v25, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v26, v26, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v27, v27, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v28, v28, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v29, v29, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v24, v24, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v2, v2, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v16, v16, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v15, v15, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v38, v38, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v37, v37, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v9, v9, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v8, v8, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v31, v31, v42 + + const/high16 v42, 0x447a0000 # 1000.0f + + div-float v30, v30, v42 + + :cond_202 + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->conditionB:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_29e + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v18, v18, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v19, v19, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v20, v20, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v21, v21, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v22, v22, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v23, v23, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v17, v17, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v10, v10, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v11, v11, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v12, v12, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v13, v13, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v14, v14, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v32, v32, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v33, v33, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v34, v34, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v35, v35, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v36, v36, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v3, v3, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v4, v4, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v5, v5, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v6, v6, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v7, v7, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v25, v25, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v26, v26, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v27, v27, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v28, v28, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v29, v29, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v24, v24, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v2, v2, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v16, v16, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v15, v15, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v38, v38, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v37, v37, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v9, v9, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v8, v8, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v31, v31, v42 + + const/high16 v42, 0x42c80000 # 100.0f + + div-float v30, v30, v42 + + :cond_29e + move-object/from16 v0, p0 + + iget-boolean v0, v0, LSmali;->conditionC:Z + + move/from16 v42, v0 + + if-eqz v42, :cond_33a + + const/high16 v42, 0x41400000 # 12.0f + + div-float v18, v18, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v19, v19, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v20, v20, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v21, v21, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v22, v22, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v23, v23, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v17, v17, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v10, v10, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v11, v11, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v12, v12, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v13, v13, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v14, v14, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v32, v32, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v33, v33, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v34, v34, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v35, v35, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v36, v36, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v3, v3, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v4, v4, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v5, v5, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v6, v6, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v7, v7, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v25, v25, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v26, v26, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v27, v27, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v28, v28, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v29, v29, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v24, v24, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v2, v2, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v16, v16, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v15, v15, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v38, v38, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v37, v37, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v9, v9, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v8, v8, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v31, v31, v42 + + const/high16 v42, 0x41400000 # 12.0f + + div-float v30, v30, v42 + + :cond_33a + const/16 v41, 0x0 + + const/high16 v42, 0x42c80000 # 100.0f + + mul-float v42, v42, v41 + + invoke-static/range {v42 .. v42}, Ljava/lang/Math;->round(F)I + + move-result v42 + + move/from16 v0, v42 + + int-to-float v0, v0 + + move/from16 v42, v0 + + const/high16 v43, 0x42c80000 # 100.0f + + div-float v41, v42, v43 + + new-instance v42, Ljava/lang/StringBuilder; + + invoke-direct/range {v42 .. v42}, Ljava/lang/StringBuilder;-><init>()V + + move-object/from16 v0, v42 + + move/from16 v1, v41 + + invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(F)Ljava/lang/StringBuilder; + + move-result-object v42 + + move-object/from16 v0, v42 + + move-object/from16 v1, v39 + + invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + move-result-object v42 + + invoke-virtual/range {v42 .. v42}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + + move-result-object v40 + + return-void + + :cond_367 + const/high16 v19, 0x3f800000 # 1.0f + + goto/16 :goto_c + + :cond_36b + const/high16 v18, 0x3f800000 # 1.0f + + goto/16 :goto_16 + + :cond_36f + const/high16 v20, 0x3f800000 # 1.0f + + goto/16 :goto_20 + + :cond_373 + const/high16 v21, 0x3f800000 # 1.0f + + goto/16 :goto_2a + + :cond_377 + const/high16 v22, 0x3f800000 # 1.0f + + goto/16 :goto_34 + + :cond_37b + const/high16 v23, 0x3f800000 # 1.0f + + goto/16 :goto_3e + + :cond_37f + const/high16 v17, 0x3f800000 # 1.0f + + goto/16 :goto_48 + + :cond_383 + const/high16 v2, 0x3f800000 # 1.0f + + goto/16 :goto_51 + + :cond_387 + const/high16 v24, 0x3f800000 # 1.0f + + goto/16 :goto_5b + + :cond_38b + const/high16 v25, 0x3f800000 # 1.0f + + goto/16 :goto_65 + + :cond_38f + const/high16 v26, 0x3f800000 # 1.0f + + goto/16 :goto_6f + + :cond_393 + const/high16 v27, 0x3f800000 # 1.0f + + goto/16 :goto_79 + + :cond_397 + const/high16 v28, 0x3f800000 # 1.0f + + goto/16 :goto_83 + + :cond_39b + const/high16 v29, 0x3f800000 # 1.0f + + goto/16 :goto_8d + + :cond_39f + const/high16 v31, 0x3f800000 # 1.0f + + goto/16 :goto_97 + + :cond_3a3 + const/high16 v30, 0x3f800000 # 1.0f + + goto/16 :goto_a1 + + :cond_3a7 + const/high16 v3, 0x3f800000 # 1.0f + + goto/16 :goto_aa + + :cond_3ab + const/high16 v4, 0x3f800000 # 1.0f + + goto/16 :goto_b3 + + :cond_3af + const/high16 v5, 0x3f800000 # 1.0f + + goto/16 :goto_bc + + :cond_3b3 + const/high16 v6, 0x3f800000 # 1.0f + + goto/16 :goto_c5 + + :cond_3b7 + const/high16 v7, 0x3f800000 # 1.0f + + goto/16 :goto_ce + + :cond_3bb + const/high16 v9, 0x3f800000 # 1.0f + + goto/16 :goto_d7 + + :cond_3bf + const/high16 v8, 0x3f800000 # 1.0f + + goto/16 :goto_e0 + + :cond_3c3 + const/high16 v32, 0x3f800000 # 1.0f + + goto/16 :goto_ea + + :cond_3c7 + const/high16 v33, 0x3f800000 # 1.0f + + goto/16 :goto_f4 + + :cond_3cb + const/high16 v34, 0x3f800000 # 1.0f + + goto/16 :goto_fe + + :cond_3cf + const/high16 v35, 0x3f800000 # 1.0f + + goto/16 :goto_108 + + :cond_3d3 + const/high16 v36, 0x3f800000 # 1.0f + + goto/16 :goto_112 + + :cond_3d7 + const/high16 v38, 0x3f800000 # 1.0f + + goto/16 :goto_11c + + :cond_3db + const/high16 v37, 0x3f800000 # 1.0f + + goto/16 :goto_126 + + :cond_3df + const/high16 v10, 0x3f800000 # 1.0f + + goto/16 :goto_12f + + :cond_3e3 + const/high16 v11, 0x3f800000 # 1.0f + + goto/16 :goto_138 + + :cond_3e7 + const/high16 v12, 0x3f800000 # 1.0f + + goto/16 :goto_141 + + :cond_3eb + const/high16 v13, 0x3f800000 # 1.0f + + goto/16 :goto_14a + + :cond_3ef + const/high16 v14, 0x3f800000 # 1.0f + + goto/16 :goto_153 + + :cond_3f3 + const/high16 v16, 0x3f800000 # 1.0f + + goto/16 :goto_15d + + :cond_3f7 + const/high16 v15, 0x3f800000 # 1.0f + + goto/16 :goto_166 +.end method + +## CHECK-START-ARM64: void Smali.testD8() register (after) +## CHECK: begin_block +## CHECK: name "B0" +## CHECK: <<This:l\d+>> ParameterValue +## CHECK: end_block + +## CHECK: begin_block +## CHECK: successors "<<ThenBlockA:B\d+>>" "<<ElseBlockA:B\d+>>" +## CHECK: <<CondA:z\d+>> InstanceFieldGet [<<This>>] field_name:Smali.conditionA +## CHECK: If [<<CondA>>] +## CHECK: end_block + +## CHECK: begin_block +## CHECK: name "<<ThenBlockA>>" +## CHECK: end_block +## CHECK: begin_block +## CHECK: name "<<ElseBlockA>>" +## CHECK: ParallelMove moves:[d2->d0,40(sp)->d17,d20->d26,d19->d27,d27->d1,d26->d2,d14->d20,d13->d19,d17->d14,d0->d13] +## CHECK: end_block + +## CHECK: begin_block +## CHECK: successors "<<ThenBlockB:B\d+>>" "<<ElseBlockB:B\d+>>" +## CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Smali.conditionB +## CHECK: If [<<CondB>>] +## CHECK: end_block + +## CHECK: begin_block +## CHECK: name "<<ThenBlockB>>" +## CHECK: end_block +## CHECK: begin_block +## CHECK: name "<<ElseBlockB>>" +## CHECK: ParallelMove moves:[#100->d13,16(sp)->d1,20(sp)->d2,28(sp)->d19,24(sp)->d20,36(sp)->d14,32(sp)->16(sp),d1->20(sp),d2->24(sp),d20->28(sp),d19->32(sp),d14->36(sp),d13->40(sp)] +## CHECK: end_block + +## CHECK-START-ARM64: void Smali.testD8() disassembly (after) +## CHECK: begin_block +## CHECK: name "B0" +## CHECK: <<This:l\d+>> ParameterValue +## CHECK: end_block + +## CHECK: begin_block +## CHECK: successors "<<ThenBlockA:B\d+>>" "<<ElseBlockA:B\d+>>" +## CHECK: <<CondA:z\d+>> InstanceFieldGet [<<This>>] field_name:Smali.conditionA +## CHECK: If [<<CondA>>] +## CHECK: end_block + +## CHECK: begin_block +## CHECK: name "<<ThenBlockA>>" +## CHECK: end_block +## CHECK: begin_block +## CHECK: name "<<ElseBlockA>>" +## CHECK: end_block + +## CHECK: begin_block +## CHECK: successors "<<ThenBlockB:B\d+>>" "<<ElseBlockB:B\d+>>" +## CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Smali.conditionB +## CHECK: If [<<CondB>>] +## CHECK: end_block + +## CHECK: begin_block +## CHECK: name "<<ThenBlockB>>" +## CHECK: end_block +## CHECK: begin_block +## CHECK: name "<<ElseBlockB>>" +## CHECK: ParallelMove moves:[invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid] +## CHECK: ldr w16, [sp, #32] +## CHECK: str s19, [sp, #32] +## CHECK: ldr s19, [sp, #28] +## CHECK: str s20, [sp, #28] +## CHECK: ldr s20, [sp, #24] +## CHECK: str s2, [sp, #24] +## CHECK: ldr s2, [sp, #20] +## CHECK: str s1, [sp, #20] +## CHECK: ldr s1, [sp, #16] +## CHECK: str w16, [sp, #16] +## CHECK: fmov d31, d14 +## CHECK: ldr s14, [sp, #36] +## CHECK: str s31, [sp, #36] +## CHECK: str s13, [sp, #40] +## CHECK: ldr s13, pc+580 (addr 0x61c) (100) +## CHECK: end_block +.method public testD8()V + .registers 47 + + move-object/from16 v0, p0 + + const-string v1, "" + + iget-boolean v2, v0, LSmali;->b17:Z + + if-eqz v2, :cond_a + + const/4 v2, 0x0 + + goto :goto_c + + :cond_a + const/high16 v2, 0x3f800000 # 1.0f + + :goto_c + iget-boolean v5, v0, LSmali;->b16:Z + + if-eqz v5, :cond_12 + + const/4 v5, 0x0 + + goto :goto_14 + + :cond_12 + const/high16 v5, 0x3f800000 # 1.0f + + :goto_14 + iget-boolean v6, v0, LSmali;->b18:Z + + if-eqz v6, :cond_1a + + const/4 v6, 0x0 + + goto :goto_1c + + :cond_1a + const/high16 v6, 0x3f800000 # 1.0f + + :goto_1c + iget-boolean v7, v0, LSmali;->b19:Z + + if-eqz v7, :cond_22 + + const/4 v7, 0x0 + + goto :goto_24 + + :cond_22 + const/high16 v7, 0x3f800000 # 1.0f + + :goto_24 + iget-boolean v8, v0, LSmali;->b20:Z + + if-eqz v8, :cond_2a + + const/4 v8, 0x0 + + goto :goto_2c + + :cond_2a + const/high16 v8, 0x3f800000 # 1.0f + + :goto_2c + iget-boolean v9, v0, LSmali;->b21:Z + + if-eqz v9, :cond_32 + + const/4 v9, 0x0 + + goto :goto_34 + + :cond_32 + const/high16 v9, 0x3f800000 # 1.0f + + :goto_34 + iget-boolean v10, v0, LSmali;->b15:Z + + if-eqz v10, :cond_3a + + const/4 v10, 0x0 + + goto :goto_3c + + :cond_3a + const/high16 v10, 0x3f800000 # 1.0f + + :goto_3c + iget-boolean v11, v0, LSmali;->b00:Z + + if-eqz v11, :cond_42 + + const/4 v11, 0x0 + + goto :goto_44 + + :cond_42 + const/high16 v11, 0x3f800000 # 1.0f + + :goto_44 + iget-boolean v12, v0, LSmali;->b22:Z + + if-eqz v12, :cond_4a + + const/4 v12, 0x0 + + goto :goto_4c + + :cond_4a + const/high16 v12, 0x3f800000 # 1.0f + + :goto_4c + iget-boolean v13, v0, LSmali;->b23:Z + + if-eqz v13, :cond_52 + + const/4 v13, 0x0 + + goto :goto_54 + + :cond_52 + const/high16 v13, 0x3f800000 # 1.0f + + :goto_54 + iget-boolean v14, v0, LSmali;->b24:Z + + if-eqz v14, :cond_5a + + const/4 v14, 0x0 + + goto :goto_5c + + :cond_5a + const/high16 v14, 0x3f800000 # 1.0f + + :goto_5c + iget-boolean v15, v0, LSmali;->b25:Z + + if-eqz v15, :cond_62 + + const/4 v15, 0x0 + + goto :goto_64 + + :cond_62 + const/high16 v15, 0x3f800000 # 1.0f + + :goto_64 + iget-boolean v3, v0, LSmali;->b26:Z + + if-eqz v3, :cond_6a + + const/4 v3, 0x0 + + goto :goto_6c + + :cond_6a + const/high16 v3, 0x3f800000 # 1.0f + + :goto_6c + iget-boolean v4, v0, LSmali;->b27:Z + + if-eqz v4, :cond_72 + + const/4 v4, 0x0 + + goto :goto_74 + + :cond_72 + const/high16 v4, 0x3f800000 # 1.0f + + :goto_74 + move-object/from16 v18, v1 + + iget-boolean v1, v0, LSmali;->b29:Z + + if-eqz v1, :cond_7c + + const/4 v1, 0x0 + + goto :goto_7e + + :cond_7c + const/high16 v1, 0x3f800000 # 1.0f + + :goto_7e + move/from16 v19, v1 + + iget-boolean v1, v0, LSmali;->b28:Z + + if-eqz v1, :cond_86 + + const/4 v1, 0x0 + + goto :goto_88 + + :cond_86 + const/high16 v1, 0x3f800000 # 1.0f + + :goto_88 + move/from16 v20, v1 + + iget-boolean v1, v0, LSmali;->b01:Z + + if-eqz v1, :cond_90 + + const/4 v1, 0x0 + + goto :goto_92 + + :cond_90 + const/high16 v1, 0x3f800000 # 1.0f + + :goto_92 + move/from16 v21, v11 + + iget-boolean v11, v0, LSmali;->b02:Z + + if-eqz v11, :cond_9a + + const/4 v11, 0x0 + + goto :goto_9c + + :cond_9a + const/high16 v11, 0x3f800000 # 1.0f + + :goto_9c + move/from16 v22, v12 + + iget-boolean v12, v0, LSmali;->b03:Z + + if-eqz v12, :cond_a4 + + const/4 v12, 0x0 + + goto :goto_a6 + + :cond_a4 + const/high16 v12, 0x3f800000 # 1.0f + + :goto_a6 + move/from16 v23, v4 + + iget-boolean v4, v0, LSmali;->b04:Z + + if-eqz v4, :cond_ae + + const/4 v4, 0x0 + + goto :goto_b0 + + :cond_ae + const/high16 v4, 0x3f800000 # 1.0f + + :goto_b0 + move/from16 v24, v3 + + iget-boolean v3, v0, LSmali;->b05:Z + + if-eqz v3, :cond_b8 + + const/4 v3, 0x0 + + goto :goto_ba + + :cond_b8 + const/high16 v3, 0x3f800000 # 1.0f + + :goto_ba + move/from16 v25, v15 + + iget-boolean v15, v0, LSmali;->b07:Z + + if-eqz v15, :cond_c2 + + const/4 v15, 0x0 + + goto :goto_c4 + + :cond_c2 + const/high16 v15, 0x3f800000 # 1.0f + + :goto_c4 + move/from16 v26, v15 + + iget-boolean v15, v0, LSmali;->b06:Z + + if-eqz v15, :cond_cc + + const/4 v15, 0x0 + + goto :goto_ce + + :cond_cc + const/high16 v15, 0x3f800000 # 1.0f + + :goto_ce + move/from16 v27, v15 + + iget-boolean v15, v0, LSmali;->b30:Z + + if-eqz v15, :cond_d6 + + const/4 v15, 0x0 + + goto :goto_d8 + + :cond_d6 + const/high16 v15, 0x3f800000 # 1.0f + + :goto_d8 + move/from16 v28, v14 + + iget-boolean v14, v0, LSmali;->b31:Z + + if-eqz v14, :cond_e0 + + const/4 v14, 0x0 + + goto :goto_e2 + + :cond_e0 + const/high16 v14, 0x3f800000 # 1.0f + + :goto_e2 + move/from16 v29, v13 + + iget-boolean v13, v0, LSmali;->b32:Z + + if-eqz v13, :cond_ea + + const/4 v13, 0x0 + + goto :goto_ec + + :cond_ea + const/high16 v13, 0x3f800000 # 1.0f + + :goto_ec + move/from16 v30, v3 + + iget-boolean v3, v0, LSmali;->b33:Z + + if-eqz v3, :cond_f4 + + const/4 v3, 0x0 + + goto :goto_f6 + + :cond_f4 + const/high16 v3, 0x3f800000 # 1.0f + + :goto_f6 + move/from16 v31, v4 + + iget-boolean v4, v0, LSmali;->b34:Z + + if-eqz v4, :cond_fe + + const/4 v4, 0x0 + + goto :goto_100 + + :cond_fe + const/high16 v4, 0x3f800000 # 1.0f + + :goto_100 + move/from16 v32, v12 + + iget-boolean v12, v0, LSmali;->b36:Z + + if-eqz v12, :cond_108 + + const/4 v12, 0x0 + + goto :goto_10a + + :cond_108 + const/high16 v12, 0x3f800000 # 1.0f + + :goto_10a + move/from16 v33, v12 + + iget-boolean v12, v0, LSmali;->b35:Z + + if-eqz v12, :cond_112 + + const/4 v12, 0x0 + + goto :goto_114 + + :cond_112 + const/high16 v12, 0x3f800000 # 1.0f + + :goto_114 + move/from16 v34, v12 + + iget-boolean v12, v0, LSmali;->b08:Z + + if-eqz v12, :cond_11c + + const/4 v12, 0x0 + + goto :goto_11e + + :cond_11c + const/high16 v12, 0x3f800000 # 1.0f + + :goto_11e + move/from16 v35, v11 + + iget-boolean v11, v0, LSmali;->b09:Z + + if-eqz v11, :cond_126 + + const/4 v11, 0x0 + + goto :goto_128 + + :cond_126 + const/high16 v11, 0x3f800000 # 1.0f + + :goto_128 + move/from16 v36, v1 + + iget-boolean v1, v0, LSmali;->b10:Z + + if-eqz v1, :cond_130 + + const/4 v1, 0x0 + + goto :goto_132 + + :cond_130 + const/high16 v1, 0x3f800000 # 1.0f + + :goto_132 + move/from16 v37, v4 + + iget-boolean v4, v0, LSmali;->b11:Z + + if-eqz v4, :cond_13a + + const/4 v4, 0x0 + + goto :goto_13c + + :cond_13a + const/high16 v4, 0x3f800000 # 1.0f + + :goto_13c + move/from16 v38, v3 + + iget-boolean v3, v0, LSmali;->b12:Z + + if-eqz v3, :cond_144 + + const/4 v3, 0x0 + + goto :goto_146 + + :cond_144 + const/high16 v3, 0x3f800000 # 1.0f + + :goto_146 + move/from16 v39, v13 + + iget-boolean v13, v0, LSmali;->b14:Z + + if-eqz v13, :cond_14e + + const/4 v13, 0x0 + + goto :goto_150 + + :cond_14e + const/high16 v13, 0x3f800000 # 1.0f + + :goto_150 + move/from16 v40, v13 + + iget-boolean v13, v0, LSmali;->b13:Z + + if-eqz v13, :cond_159 + + const/16 v16, 0x0 + + goto :goto_15b + + :cond_159 + const/high16 v16, 0x3f800000 # 1.0f + + :goto_15b + move/from16 v13, v16 + + move/from16 v41, v13 + + iget-boolean v13, v0, LSmali;->conditionA:Z + + if-eqz v13, :cond_1a2 + + const/high16 v13, 0x447a0000 # 1000.0f + + div-float/2addr v5, v13 + + div-float/2addr v2, v13 + + div-float/2addr v6, v13 + + div-float/2addr v7, v13 + + div-float/2addr v8, v13 + + div-float/2addr v9, v13 + + div-float/2addr v10, v13 + + div-float/2addr v12, v13 + + div-float/2addr v11, v13 + + div-float/2addr v1, v13 + + div-float/2addr v4, v13 + + div-float/2addr v3, v13 + + div-float/2addr v15, v13 + + div-float/2addr v14, v13 + + div-float v16, v39, v13 + + div-float v38, v38, v13 + + div-float v37, v37, v13 + + div-float v36, v36, v13 + + div-float v35, v35, v13 + + div-float v32, v32, v13 + + div-float v31, v31, v13 + + div-float v30, v30, v13 + + div-float v29, v29, v13 + + div-float v28, v28, v13 + + div-float v25, v25, v13 + + div-float v24, v24, v13 + + div-float v23, v23, v13 + + div-float v22, v22, v13 + + div-float v21, v21, v13 + + div-float v39, v40, v13 + + div-float v40, v41, v13 + + div-float v33, v33, v13 + + div-float v34, v34, v13 + + div-float v26, v26, v13 + + div-float v27, v27, v13 + + div-float v19, v19, v13 + + div-float v13, v20, v13 + + goto :goto_1aa + + :cond_1a2 + move/from16 v13, v20 + + move/from16 v16, v39 + + move/from16 v39, v40 + + move/from16 v40, v41 + + :goto_1aa + move/from16 v42, v13 + + iget-boolean v13, v0, LSmali;->conditionB:Z + + const/high16 v20, 0x42c80000 # 100.0f + + if-eqz v13, :cond_1fd + + div-float v5, v5, v20 + + div-float v2, v2, v20 + + div-float v6, v6, v20 + + div-float v7, v7, v20 + + div-float v8, v8, v20 + + div-float v9, v9, v20 + + div-float v10, v10, v20 + + div-float v12, v12, v20 + + div-float v11, v11, v20 + + div-float v1, v1, v20 + + div-float v4, v4, v20 + + div-float v3, v3, v20 + + div-float v15, v15, v20 + + div-float v14, v14, v20 + + div-float v16, v16, v20 + + div-float v38, v38, v20 + + div-float v37, v37, v20 + + div-float v36, v36, v20 + + div-float v35, v35, v20 + + div-float v32, v32, v20 + + div-float v31, v31, v20 + + div-float v30, v30, v20 + + div-float v29, v29, v20 + + div-float v28, v28, v20 + + div-float v25, v25, v20 + + div-float v24, v24, v20 + + div-float v23, v23, v20 + + div-float v22, v22, v20 + + div-float v21, v21, v20 + + div-float v39, v39, v20 + + div-float v40, v40, v20 + + div-float v33, v33, v20 + + div-float v34, v34, v20 + + div-float v26, v26, v20 + + div-float v27, v27, v20 + + div-float v19, v19, v20 + + div-float v13, v42, v20 + + goto :goto_1ff + + :cond_1fd + move/from16 v13, v42 + + :goto_1ff + move/from16 v43, v13 + + iget-boolean v13, v0, LSmali;->conditionC:Z + + if-eqz v13, :cond_244 + + const/high16 v13, 0x41400000 # 12.0f + + div-float/2addr v5, v13 + + div-float/2addr v2, v13 + + div-float/2addr v6, v13 + + div-float/2addr v7, v13 + + div-float/2addr v8, v13 + + div-float/2addr v9, v13 + + div-float/2addr v10, v13 + + div-float/2addr v12, v13 + + div-float/2addr v11, v13 + + div-float/2addr v1, v13 + + div-float/2addr v4, v13 + + div-float/2addr v3, v13 + + div-float/2addr v15, v13 + + div-float/2addr v14, v13 + + div-float v16, v16, v13 + + div-float v38, v38, v13 + + div-float v37, v37, v13 + + div-float v36, v36, v13 + + div-float v35, v35, v13 + + div-float v32, v32, v13 + + div-float v31, v31, v13 + + div-float v30, v30, v13 + + div-float v29, v29, v13 + + div-float v28, v28, v13 + + div-float v25, v25, v13 + + div-float v24, v24, v13 + + div-float v23, v23, v13 + + div-float v22, v22, v13 + + div-float v21, v21, v13 + + div-float v39, v39, v13 + + div-float v40, v40, v13 + + div-float v33, v33, v13 + + div-float v34, v34, v13 + + div-float v26, v26, v13 + + div-float v27, v27, v13 + + div-float v19, v19, v13 + + div-float v13, v43, v13 + + goto :goto_246 + + :cond_244 + move/from16 v13, v43 + + :goto_246 + const/16 v17, 0x0 + + mul-float v0, v20, v17 + + invoke-static {v0}, Ljava/lang/Math;->round(F)I + + move-result v0 + + int-to-float v0, v0 + + div-float v0, v0, v20 + + move/from16 v44, v1 + + new-instance v1, Ljava/lang/StringBuilder; + + invoke-direct {v1}, Ljava/lang/StringBuilder;-><init>()V + + invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(F)Ljava/lang/StringBuilder; + + move/from16 v45, v0 + + move-object/from16 v0, v18 + + invoke-virtual {v1, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder; + + invoke-virtual {v1}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String; + + move-result-object v1 + + return-void +.end method diff --git a/test/626-checker-arm64-scratch-register/src/Main.java b/test/626-checker-arm64-scratch-register/src/Main.java index 139491769e..cf94b87666 100644 --- a/test/626-checker-arm64-scratch-register/src/Main.java +++ b/test/626-checker-arm64-scratch-register/src/Main.java @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; public class Main { @@ -63,14 +65,17 @@ public class Main { /// CHECK: name "B0" /// CHECK: <<This:l\d+>> ParameterValue /// CHECK: end_block + /// CHECK: begin_block - /// CHECK: successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>" + /// CHECK: successors "<<ThenBlockA:B\d+>>" "<<ElseBlockA:B\d+>>" + /// CHECK: <<CondA:z\d+>> InstanceFieldGet [<<This>>] field_name:Main.conditionA + /// CHECK: If [<<CondA>>] + /// CHECK: end_block + + /// CHECK: begin_block + /// CHECK: successors "<<ThenBlockB:B\d+>>" "<<ElseBlockB:B\d+>>" /// CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Main.conditionB /// CHECK: If [<<CondB>>] - /// CHECK: end_block - /// CHECK: begin_block - /// CHECK: name "<<ElseBlock>>" - /// CHECK: ParallelMove moves:[40(sp)->d0,24(sp)->32(sp),28(sp)->36(sp),d0->d3,d3->d4,d2->d5,d4->d6,d5->d7,d6->d18,d7->d19,d18->d20,d19->d21,d20->d22,d21->d23,d22->d10,d23->d11,16(sp)->24(sp),20(sp)->28(sp),d10->d14,d11->d12,d12->d13,d13->d1,d14->d2,32(sp)->16(sp),36(sp)->20(sp)] /// CHECK: end_block /// CHECK-START-ARM64: void Main.test() disassembly (after) @@ -82,39 +87,6 @@ public class Main { /// CHECK: successors "<<ThenBlock:B\d+>>" "<<ElseBlock:B\d+>>" /// CHECK: <<CondB:z\d+>> InstanceFieldGet [<<This>>] field_name:Main.conditionB /// CHECK: If [<<CondB>>] - /// CHECK: end_block - /// CHECK: begin_block - /// CHECK: name "<<ElseBlock>>" - /// CHECK: ParallelMove moves:[invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid,invalid->invalid] - /// CHECK: fmov d31, d2 - /// CHECK: ldr s2, [sp, #36] - /// CHECK: ldr w16, [sp, #16] - /// CHECK: str w16, [sp, #36] - /// CHECK: str s14, [sp, #16] - /// CHECK: ldr s14, [sp, #28] - /// CHECK: str s1, [sp, #28] - /// CHECK: ldr s1, [sp, #32] - /// CHECK: str s31, [sp, #32] - /// CHECK: ldr s31, [sp, #20] - /// CHECK: str s31, [sp, #40] - /// CHECK: str s12, [sp, #20] - /// CHECK: fmov d12, d11 - /// CHECK: fmov d11, d10 - /// CHECK: fmov d10, d23 - /// CHECK: fmov d23, d22 - /// CHECK: fmov d22, d21 - /// CHECK: fmov d21, d20 - /// CHECK: fmov d20, d19 - /// CHECK: fmov d19, d18 - /// CHECK: fmov d18, d7 - /// CHECK: fmov d7, d6 - /// CHECK: fmov d6, d5 - /// CHECK: fmov d5, d4 - /// CHECK: fmov d4, d3 - /// CHECK: fmov d3, d13 - /// CHECK: ldr s13, [sp, #24] - /// CHECK: str s3, [sp, #24] - /// CHECK: ldr s3, pc+{{\d+}} (addr {{0x[0-9a-f]+}}) (100) /// CHECK: end_block public void test() { @@ -289,9 +261,20 @@ public class Main { String res = s + r; } - public static void main(String[] args) { + public static void main(String[] args) throws Exception { Main main = new Main(); main.test(); + + Class<?> cl = Class.forName("Smali"); + Constructor<?> cons = cl.getConstructor(); + Object o = cons.newInstance(); + + Method test = cl.getMethod("test"); + test.invoke(o); + + Method testD8 = cl.getMethod("testD8"); + testD8.invoke(o); + System.out.println("passed"); } } diff --git a/test/983-source-transform-verify/source_transform.cc b/test/983-source-transform-verify/source_transform.cc index e9cb35e944..c076d1521f 100644 --- a/test/983-source-transform-verify/source_transform.cc +++ b/test/983-source-transform-verify/source_transform.cc @@ -28,6 +28,7 @@ #include "base/macros.h" #include "bytecode_utils.h" #include "dex/code_item_accessors-inl.h" +#include "dex/art_dex_file_loader.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "dex/dex_instruction.h" @@ -66,15 +67,16 @@ void JNICALL CheckDexFileHook(jvmtiEnv* jvmti_env ATTRIBUTE_UNUSED, if (IsJVM()) { return; } + const ArtDexFileLoader dex_file_loader; std::string error; - std::unique_ptr<const DexFile> dex(DexFileLoader::Open(class_data, - class_data_len, - "fake_location.dex", - /*location_checksum*/ 0, - /*oat_dex_file*/ nullptr, - /*verify*/ true, - /*verify_checksum*/ true, - &error)); + std::unique_ptr<const DexFile> dex(dex_file_loader.Open(class_data, + class_data_len, + "fake_location.dex", + /*location_checksum*/ 0, + /*oat_dex_file*/ nullptr, + /*verify*/ true, + /*verify_checksum*/ true, + &error)); if (dex.get() == nullptr) { std::cout << "Failed to verify dex file for " << name << " because " << error << std::endl; return; diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index 132099a45d..631b14afc8 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -466,10 +466,9 @@ if [ "$USE_JVMTI" = "y" ]; then if [[ "$TEST_IS_NDEBUG" = "y" ]]; then plugin=libopenjdkjvmti.so fi + # We used to add flags here that made the runtime debuggable but that is not + # needed anymore since the plugin can do it for us now. FLAGS="${FLAGS} -Xplugin:${plugin}" - FLAGS="${FLAGS} -Xcompiler-option --debuggable" - # Always make the compilation be debuggable. - COMPILE_FLAGS="${COMPILE_FLAGS} --debuggable" fi fi |