summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--adbconnection/adbconnection.cc9
-rw-r--r--compiler/Android.bp7
-rw-r--r--compiler/utils/test_dex_file_builder.h4
-rw-r--r--dex2oat/Android.bp12
-rw-r--r--dex2oat/dex2oat.cc6
-rw-r--r--dex2oat/dex2oat_image_test.cc14
-rw-r--r--dex2oat/dex2oat_test.cc7
-rw-r--r--dex2oat/linker/oat_writer.cc51
-rw-r--r--dexdump/dexdump.cc5
-rw-r--r--dexlayout/Android.bp7
-rw-r--r--dexlayout/dexlayout.cc22
-rw-r--r--dexlayout/dexlayout_test.cc27
-rw-r--r--dexlist/dexlist.cc4
-rw-r--r--openjdkjvmti/OpenjdkJvmTi.cc179
-rw-r--r--openjdkjvmti/art_jvmti.h68
-rw-r--r--openjdkjvmti/deopt_manager.cc31
-rw-r--r--openjdkjvmti/deopt_manager.h7
-rw-r--r--openjdkjvmti/fixed_up_dex_file.cc6
-rw-r--r--openjdkjvmti/ti_class.cc14
-rw-r--r--openjdkjvmti/ti_redefine.cc14
-rw-r--r--openjdkjvmti/ti_search.cc4
-rw-r--r--profman/profman.cc26
-rw-r--r--runtime/Android.bp65
-rw-r--r--runtime/art_method.cc15
-rw-r--r--runtime/class_linker.cc54
-rw-r--r--runtime/class_linker.h5
-rw-r--r--runtime/class_loader_context.cc14
-rw-r--r--runtime/common_runtime_test.cc15
-rw-r--r--runtime/dex/art_dex_file_loader.cc465
-rw-r--r--runtime/dex/art_dex_file_loader.h125
-rw-r--r--runtime/dex/code_item_accessors_test.cc15
-rw-r--r--runtime/dex/dex_file_loader.cc498
-rw-r--r--runtime/dex/dex_file_loader.h123
-rw-r--r--runtime/dex/dex_file_test.cc40
-rw-r--r--runtime/dex/dex_file_verifier_test.cc4
-rw-r--r--runtime/dex2oat_environment_test.h28
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc6
-rw-r--r--runtime/gc/space/image_space.cc4
-rw-r--r--runtime/globals.h6
-rw-r--r--runtime/instrumentation.cc8
-rw-r--r--runtime/native/dalvik_system_DexFile.cc14
-rw-r--r--runtime/oat_file.cc18
-rw-r--r--runtime/oat_file_assistant.cc10
-rw-r--r--runtime/oat_file_manager.cc25
-rw-r--r--runtime/runtime.cc28
-rw-r--r--runtime/runtime.h5
-rw-r--r--runtime/utils.cc5
-rw-r--r--runtime/vdex_file.cc18
-rw-r--r--test/626-checker-arm64-scratch-register/smali/Smali.smali2119
-rw-r--r--test/626-checker-arm64-scratch-register/src/Main.java61
-rw-r--r--test/983-source-transform-verify/source_transform.cc18
-rwxr-xr-xtest/etc/run-test-jar5
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