summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/jit/jit_compiler.cc8
-rw-r--r--compiler/jit/jit_compiler.h2
-rw-r--r--compiler/optimizing/intrinsics.h3
-rw-r--r--libdexfile/Android.bp65
-rw-r--r--libdexfile/dex/art_dex_file_loader.cc20
-rw-r--r--libdexfile/dex/art_dex_file_loader.h18
-rw-r--r--libdexfile/dex/dex_file_loader.cc20
-rw-r--r--libdexfile/dex/dex_file_loader.h18
-rw-r--r--libdexfile/external/dex_file_ext.cc346
-rw-r--r--libdexfile/external/dex_file_supp.cc34
-rw-r--r--libdexfile/external/include/art_api/ext_dex_file.h248
-rw-r--r--libdexfile/external/libdexfile_external.map.txt13
-rw-r--r--runtime/Android.bp2
-rw-r--r--runtime/jit/jit.cc9
-rw-r--r--runtime/jit/jit.h4
-rw-r--r--test/566-polymorphic-inlining/polymorphic_inline.cc2
-rw-r--r--test/570-checker-osr/osr.cc2
-rw-r--r--test/common/runtime_state.cc2
18 files changed, 768 insertions, 48 deletions
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 9b8bb3e90e..e57bbfa1e1 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -126,11 +126,11 @@ extern "C" void jit_unload(void* handle) {
}
extern "C" bool jit_compile_method(
- void* handle, ArtMethod* method, Thread* self, bool osr)
+ void* handle, ArtMethod* method, Thread* self, bool baseline, bool osr)
REQUIRES_SHARED(Locks::mutator_lock_) {
auto* jit_compiler = reinterpret_cast<JitCompiler*>(handle);
DCHECK(jit_compiler != nullptr);
- return jit_compiler->CompileMethod(self, method, osr);
+ return jit_compiler->CompileMethod(self, method, baseline, osr);
}
extern "C" void jit_types_loaded(void* handle, mirror::Class** types, size_t count)
@@ -181,7 +181,7 @@ JitCompiler::~JitCompiler() {
}
}
-bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method, bool osr) {
+bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method, bool baseline, bool osr) {
SCOPED_TRACE << "JIT compiling " << method->PrettyMethod();
DCHECK(!method->IsProxyMethod());
@@ -198,7 +198,7 @@ bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method, bool osr) {
TimingLogger::ScopedTiming t2("Compiling", &logger);
JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache();
success = compiler_driver_->GetCompiler()->JitCompile(
- self, code_cache, method, /* baseline= */ false, osr, jit_logger_.get());
+ self, code_cache, method, baseline, osr, jit_logger_.get());
}
// Trim maps to reduce memory usage.
diff --git a/compiler/jit/jit_compiler.h b/compiler/jit/jit_compiler.h
index d201611d79..29d2761348 100644
--- a/compiler/jit/jit_compiler.h
+++ b/compiler/jit/jit_compiler.h
@@ -37,7 +37,7 @@ class JitCompiler {
virtual ~JitCompiler();
// Compilation entrypoint. Returns whether the compilation succeeded.
- bool CompileMethod(Thread* self, ArtMethod* method, bool osr)
+ bool CompileMethod(Thread* self, ArtMethod* method, bool baseline, bool osr)
REQUIRES_SHARED(Locks::mutator_lock_);
const CompilerOptions& GetCompilerOptions() const {
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index 5bd1122698..50b13c842b 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -243,7 +243,8 @@ void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNU
// compilation.
#define UNREACHABLE_INTRINSIC(Arch, Name) \
void IntrinsicLocationsBuilder ## Arch::Visit ## Name(HInvoke* invoke) { \
- if (!codegen_->GetCompilerOptions().IsBaseline()) { \
+ if (Runtime::Current()->IsAotCompiler() && \
+ !codegen_->GetCompilerOptions().IsBaseline()) { \
LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic() \
<< " should have been converted to HIR"; \
} \
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index 7f25f02dea..4d6aa5c8ac 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -131,6 +131,71 @@ art_cc_library {
],
}
+cc_library_headers {
+ name: "libdexfile_external_headers",
+ host_supported: true,
+ header_libs: ["libbase_headers"],
+ export_header_lib_headers: ["libbase_headers"],
+ export_include_dirs: ["external/include"],
+
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+}
+
+cc_library {
+ name: "libdexfile_external",
+ host_supported: true,
+ srcs: [
+ "external/dex_file_ext.cc",
+ ],
+ header_libs: ["libdexfile_external_headers"],
+ shared_libs: [
+ "libbase",
+ "libdexfile",
+ ],
+
+ // TODO(b/120670568): Enable this when linking bug is fixed.
+ // stubs: {
+ // symbol_file: "external/libdexfile_external.map.txt",
+ // versions: ["1"],
+ // },
+
+ // Hide symbols using version scripts for targets that support it, i.e. all
+ // but Darwin.
+ // TODO(b/120670568): Clean this up when stubs above is enabled.
+ target: {
+ android: {
+ version_script: "external/libdexfile_external.map.txt",
+ },
+ linux_bionic: {
+ version_script: "external/libdexfile_external.map.txt",
+ },
+ linux_glibc: {
+ version_script: "external/libdexfile_external.map.txt",
+ },
+ windows: {
+ version_script: "external/libdexfile_external.map.txt",
+ },
+ },
+}
+
+// Support library with a C++ API for accessing the libdexfile API for external
+// (non-ART) users. They should link to their own instance of this (either
+// statically or through linker namespaces).
+cc_library {
+ name: "libdexfile_support",
+ host_supported: true,
+ srcs: [
+ "external/dex_file_supp.cc",
+ ],
+ header_libs: ["libdexfile_external_headers"],
+ shared_libs: ["libdexfile_external"],
+ export_header_lib_headers: ["libdexfile_external_headers"],
+}
+
art_cc_test {
name: "art_libdexfile_tests",
defaults: [
diff --git a/libdexfile/dex/art_dex_file_loader.cc b/libdexfile/dex/art_dex_file_loader.cc
index 20a519bf99..ae1322d059 100644
--- a/libdexfile/dex/art_dex_file_loader.cc
+++ b/libdexfile/dex/art_dex_file_loader.cc
@@ -156,14 +156,16 @@ bool ArtDexFileLoader::GetMultiDexChecksums(const char* 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 {
+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,
+ std::unique_ptr<DexFileContainer> container) const {
ScopedTrace trace(std::string("Open dex file from RAM ") + location);
return OpenCommon(base,
size,
@@ -175,7 +177,7 @@ std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const uint8_t* base,
verify,
verify_checksum,
error_msg,
- /*container=*/ nullptr,
+ std::move(container),
/*verify_result=*/ nullptr);
}
diff --git a/libdexfile/dex/art_dex_file_loader.h b/libdexfile/dex/art_dex_file_loader.h
index 40d4673625..d41eac5329 100644
--- a/libdexfile/dex/art_dex_file_loader.h
+++ b/libdexfile/dex/art_dex_file_loader.h
@@ -54,14 +54,16 @@ class ArtDexFileLoader : public DexFileLoader {
bool* only_contains_uncompressed_dex = nullptr) 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;
+ 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,
+ std::unique_ptr<DexFileContainer> container = nullptr) const override;
// Opens .dex file that has been memory-mapped by the caller.
std::unique_ptr<const DexFile> Open(const std::string& location,
diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc
index 3667c8c289..1884bcf3f8 100644
--- a/libdexfile/dex/dex_file_loader.cc
+++ b/libdexfile/dex/dex_file_loader.cc
@@ -212,14 +212,16 @@ bool DexFileLoader::GetMultiDexChecksums(
return false;
}
-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) const {
+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,
+ std::unique_ptr<DexFileContainer> container) const {
return OpenCommon(base,
size,
/*data_base=*/ nullptr,
@@ -230,7 +232,7 @@ std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base,
verify,
verify_checksum,
error_msg,
- /*container=*/ nullptr,
+ std::move(container),
/*verify_result=*/ nullptr);
}
diff --git a/libdexfile/dex/dex_file_loader.h b/libdexfile/dex/dex_file_loader.h
index 8fc836e0f5..49e177fce6 100644
--- a/libdexfile/dex/dex_file_loader.h
+++ b/libdexfile/dex/dex_file_loader.h
@@ -121,14 +121,16 @@ class DexFileLoader {
bool* zip_file_only_contains_uncompress_dex = nullptr) const;
// Opens .dex file, backed by existing memory
- 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;
+ 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,
+ std::unique_ptr<DexFileContainer> container = nullptr) const;
// Open a dex file with a separate data section.
virtual std::unique_ptr<const DexFile> OpenWithDataSection(
diff --git a/libdexfile/external/dex_file_ext.cc b/libdexfile/external/dex_file_ext.cc
new file mode 100644
index 0000000000..3c193f4eb5
--- /dev/null
+++ b/libdexfile/external/dex_file_ext.cc
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2018 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 <inttypes.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <cstring>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/mapped_file.h>
+#include <android-base/stringprintf.h>
+
+#include <dex/class_accessor-inl.h>
+#include <dex/code_item_accessors-inl.h>
+#include <dex/dex_file-inl.h>
+#include <dex/dex_file_loader.h>
+
+#include "art_api/ext_dex_file.h"
+
+extern "C" class ExtDexFileString {
+ public:
+ const std::string str_;
+};
+
+namespace art {
+namespace {
+
+const ExtDexFileString empty_string{""};
+
+struct MethodCacheEntry {
+ int32_t offset; // Offset relative to the start of the dex file header.
+ int32_t len;
+ int32_t index; // Method index.
+ std::string name; // Method name. Not filled in for all cache entries.
+};
+
+class MappedFileContainer : public DexFileContainer {
+ public:
+ explicit MappedFileContainer(std::unique_ptr<android::base::MappedFile>&& map)
+ : map_(std::move(map)) {}
+ ~MappedFileContainer() override {}
+ int GetPermissions() override { return 0; }
+ bool IsReadOnly() override { return true; }
+ bool EnableWrite() override { return false; }
+ bool DisableWrite() override { return false; }
+
+ private:
+ std::unique_ptr<android::base::MappedFile> map_;
+ DISALLOW_COPY_AND_ASSIGN(MappedFileContainer);
+};
+
+} // namespace
+} // namespace art
+
+extern "C" {
+
+const ExtDexFileString* ExtDexFileMakeString(const char* str) {
+ if (str[0] == '\0') {
+ return &art::empty_string;
+ }
+ return new ExtDexFileString{str};
+}
+
+const char* ExtDexFileGetString(const ExtDexFileString* ext_string, /*out*/ size_t* size) {
+ DCHECK(ext_string != nullptr);
+ *size = ext_string->str_.size();
+ return ext_string->str_.data();
+}
+
+void ExtDexFileFreeString(const ExtDexFileString* ext_string) {
+ DCHECK(ext_string != nullptr);
+ if (ext_string != &art::empty_string) {
+ delete (ext_string);
+ }
+}
+
+// Wraps DexFile to add the caching needed by the external interface. This is
+// what gets passed over as ExtDexFile*.
+class ExtDexFile {
+ // Method cache for GetMethodInfoForOffset. This is populated as we iterate
+ // sequentially through the class defs. MethodCacheEntry.name is only set for
+ // methods returned by GetMethodInfoForOffset.
+ std::map<int32_t, art::MethodCacheEntry> method_cache_;
+
+ // Index of first class def for which method_cache_ isn't complete.
+ uint32_t class_def_index_ = 0;
+
+ public:
+ std::unique_ptr<const art::DexFile> dex_file_;
+ explicit ExtDexFile(std::unique_ptr<const art::DexFile>&& dex_file)
+ : dex_file_(std::move(dex_file)) {}
+
+ art::MethodCacheEntry* GetMethodCacheEntryForOffset(int64_t dex_offset) {
+ // First look in the method cache.
+ auto it = method_cache_.upper_bound(dex_offset);
+ if (it != method_cache_.end() && dex_offset >= it->second.offset) {
+ return &it->second;
+ }
+
+ for (; class_def_index_ < dex_file_->NumClassDefs(); class_def_index_++) {
+ art::ClassAccessor accessor(*dex_file_, class_def_index_);
+
+ for (const art::ClassAccessor::Method& method : accessor.GetMethods()) {
+ art::CodeItemInstructionAccessor code = method.GetInstructions();
+ if (!code.HasCodeItem()) {
+ continue;
+ }
+
+ int32_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
+ int32_t len = code.InsnsSizeInBytes();
+ int32_t index = method.GetIndex();
+ auto res =
+ method_cache_.emplace(offset + len, art::MethodCacheEntry{offset, len, index, ""});
+ if (offset <= dex_offset && dex_offset < offset + len) {
+ return &res.first->second;
+ }
+ }
+ }
+
+ return nullptr;
+ }
+
+ const std::string& GetMethodName(art::MethodCacheEntry& entry) {
+ if (entry.name.empty()) {
+ entry.name = dex_file_->PrettyMethod(entry.index, false);
+ }
+ return entry.name;
+ }
+};
+
+int ExtDexFileOpenFromMemory(const void* addr,
+ /*inout*/ size_t* size,
+ const char* location,
+ /*out*/ const ExtDexFileString** ext_error_msg,
+ /*out*/ ExtDexFile** ext_dex_file) {
+ if (*size < sizeof(art::DexFile::Header)) {
+ *size = sizeof(art::DexFile::Header);
+ *ext_error_msg = nullptr;
+ return false;
+ }
+
+ const art::DexFile::Header* header = reinterpret_cast<const art::DexFile::Header*>(addr);
+ uint32_t file_size = header->file_size_;
+ if (art::CompactDexFile::IsMagicValid(header->magic_)) {
+ // Compact dex files store the data section separately so that it can be shared.
+ // Therefore we need to extend the read memory range to include it.
+ // TODO: This might be wasteful as we might read data in between as well.
+ // In practice, this should be fine, as such sharing only happens on disk.
+ uint32_t computed_file_size;
+ if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) {
+ *ext_error_msg = new ExtDexFileString{
+ android::base::StringPrintf("Corrupt CompactDexFile header in '%s'", location)};
+ return false;
+ }
+ if (computed_file_size > file_size) {
+ file_size = computed_file_size;
+ }
+ } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) {
+ *ext_error_msg = new ExtDexFileString{
+ android::base::StringPrintf("Unrecognized dex file header in '%s'", location)};
+ return false;
+ }
+
+ if (*size < file_size) {
+ *size = file_size;
+ *ext_error_msg = nullptr;
+ return false;
+ }
+
+ std::string loc_str(location);
+ art::DexFileLoader loader;
+ std::string error_msg;
+ std::unique_ptr<const art::DexFile> dex_file = loader.Open(static_cast<const uint8_t*>(addr),
+ *size,
+ loc_str,
+ header->checksum_,
+ /*oat_dex_file=*/nullptr,
+ /*verify=*/false,
+ /*verify_checksum=*/false,
+ &error_msg);
+ if (dex_file == nullptr) {
+ *ext_error_msg = new ExtDexFileString{std::move(error_msg)};
+ return false;
+ }
+
+ *ext_dex_file = new ExtDexFile(std::move(dex_file));
+ return true;
+}
+
+int ExtDexFileOpenFromFd(int fd,
+ off_t offset,
+ const char* location,
+ /*out*/ const ExtDexFileString** ext_error_msg,
+ /*out*/ ExtDexFile** ext_dex_file) {
+ size_t length;
+ {
+ struct stat sbuf;
+ std::memset(&sbuf, 0, sizeof(sbuf));
+ if (fstat(fd, &sbuf) == -1) {
+ *ext_error_msg = new ExtDexFileString{
+ android::base::StringPrintf("fstat '%s' failed: %s", location, std::strerror(errno))};
+ return false;
+ }
+ if (S_ISDIR(sbuf.st_mode)) {
+ *ext_error_msg = new ExtDexFileString{
+ android::base::StringPrintf("Attempt to mmap directory '%s'", location)};
+ return false;
+ }
+ length = sbuf.st_size;
+ }
+
+ if (length < offset + sizeof(art::DexFile::Header)) {
+ *ext_error_msg = new ExtDexFileString{android::base::StringPrintf(
+ "Offset %" PRId64 " too large for '%s' of size %zu", int64_t{offset}, location, length)};
+ return false;
+ }
+
+ // Cannot use MemMap in libartbase here, because it pulls in dlopen which we
+ // can't have when being compiled statically.
+ std::unique_ptr<android::base::MappedFile> map =
+ android::base::MappedFile::FromFd(fd, offset, length, PROT_READ);
+ if (map == nullptr) {
+ *ext_error_msg = new ExtDexFileString{
+ android::base::StringPrintf("mmap '%s' failed: %s", location, std::strerror(errno))};
+ return false;
+ }
+
+ const art::DexFile::Header* header = reinterpret_cast<const art::DexFile::Header*>(map->data());
+ uint32_t file_size;
+ if (__builtin_add_overflow(offset, header->file_size_, &file_size)) {
+ *ext_error_msg =
+ new ExtDexFileString{android::base::StringPrintf("Corrupt header in '%s'", location)};
+ return false;
+ }
+ if (length < file_size) {
+ *ext_error_msg = new ExtDexFileString{
+ android::base::StringPrintf("Dex file '%s' too short: expected %" PRIu32 ", got %" PRIu64,
+ location,
+ file_size,
+ uint64_t{length})};
+ return false;
+ }
+
+ void* addr = map->data();
+ size_t size = map->size();
+ auto container = std::make_unique<art::MappedFileContainer>(std::move(map));
+
+ std::string loc_str(location);
+ std::string error_msg;
+ art::DexFileLoader loader;
+ std::unique_ptr<const art::DexFile> dex_file = loader.Open(reinterpret_cast<const uint8_t*>(addr),
+ size,
+ loc_str,
+ header->checksum_,
+ /*oat_dex_file=*/nullptr,
+ /*verify=*/false,
+ /*verify_checksum=*/false,
+ &error_msg,
+ std::move(container));
+ if (dex_file == nullptr) {
+ *ext_error_msg = new ExtDexFileString{std::move(error_msg)};
+ return false;
+ }
+ *ext_dex_file = new ExtDexFile(std::move(dex_file));
+ return true;
+}
+
+int ExtDexFileGetMethodInfoForOffset(ExtDexFile* ext_dex_file,
+ int64_t dex_offset,
+ /*out*/ ExtDexFileMethodInfo* method_info) {
+ if (!ext_dex_file->dex_file_->IsInDataSection(ext_dex_file->dex_file_->Begin() + dex_offset)) {
+ return false; // The DEX offset is not within the bytecode of this dex file.
+ }
+
+ if (ext_dex_file->dex_file_->IsCompactDexFile()) {
+ // The data section of compact dex files might be shared.
+ // Check the subrange unique to this compact dex.
+ const art::CompactDexFile::Header& cdex_header =
+ ext_dex_file->dex_file_->AsCompactDexFile()->GetHeader();
+ uint32_t begin = cdex_header.data_off_ + cdex_header.OwnedDataBegin();
+ uint32_t end = cdex_header.data_off_ + cdex_header.OwnedDataEnd();
+ if (dex_offset < begin || dex_offset >= end) {
+ return false; // The DEX offset is not within the bytecode of this dex file.
+ }
+ }
+
+ art::MethodCacheEntry* entry = ext_dex_file->GetMethodCacheEntryForOffset(dex_offset);
+ if (entry != nullptr) {
+ method_info->offset = entry->offset;
+ method_info->len = entry->len;
+ method_info->name = new ExtDexFileString{ext_dex_file->GetMethodName(*entry)};
+ return true;
+ }
+
+ return false;
+}
+
+void ExtDexFileGetAllMethodInfos(ExtDexFile* ext_dex_file,
+ int with_signature,
+ ExtDexFileMethodInfoCallback* method_info_cb,
+ void* user_data) {
+ for (art::ClassAccessor accessor : ext_dex_file->dex_file_->GetClasses()) {
+ for (const art::ClassAccessor::Method& method : accessor.GetMethods()) {
+ art::CodeItemInstructionAccessor code = method.GetInstructions();
+ if (!code.HasCodeItem()) {
+ continue;
+ }
+
+ ExtDexFileMethodInfo method_info;
+ method_info.offset = static_cast<int32_t>(reinterpret_cast<const uint8_t*>(code.Insns()) -
+ ext_dex_file->dex_file_->Begin());
+ method_info.len = code.InsnsSizeInBytes();
+ method_info.name = new ExtDexFileString{
+ ext_dex_file->dex_file_->PrettyMethod(method.GetIndex(), with_signature)};
+ method_info_cb(&method_info, user_data);
+ }
+ }
+}
+
+void ExtDexFileFree(ExtDexFile* ext_dex_file) { delete (ext_dex_file); }
+
+} // extern "C"
diff --git a/libdexfile/external/dex_file_supp.cc b/libdexfile/external/dex_file_supp.cc
new file mode 100644
index 0000000000..6514c8abf3
--- /dev/null
+++ b/libdexfile/external/dex_file_supp.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 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_api/ext_dex_file.h"
+
+namespace art_api {
+namespace dex {
+
+DexFile::~DexFile() { ExtDexFileFree(ext_dex_file_); }
+
+MethodInfo DexFile::AbsorbMethodInfo(const ExtDexFileMethodInfo& ext_method_info) {
+ return {ext_method_info.offset, ext_method_info.len, DexString(ext_method_info.name)};
+}
+
+void DexFile::AddMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info, void* ctx) {
+ auto vect = static_cast<MethodInfoVector*>(ctx);
+ vect->emplace_back(AbsorbMethodInfo(*ext_method_info));
+}
+
+} // namespace dex
+} // namespace art_api
diff --git a/libdexfile/external/include/art_api/ext_dex_file.h b/libdexfile/external/include/art_api/ext_dex_file.h
new file mode 100644
index 0000000000..5f64ab1f9e
--- /dev/null
+++ b/libdexfile/external/include/art_api/ext_dex_file.h
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 2018 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_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_EXT_DEX_FILE_H_
+#define ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_EXT_DEX_FILE_H_
+
+// Dex file external API
+
+#include <sys/types.h>
+
+#include <cstring>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include <android-base/macros.h>
+
+extern "C" {
+
+// This is the stable C ABI that backs art_api::dex below. Structs and functions
+// may only be added here.
+// TODO(b/120978655): Move this to a separate pure C header.
+//
+// Clients should use the C++ wrappers in art_api::dex instead.
+
+// Opaque wrapper for an std::string allocated in libdexfile which must be freed
+// using ExtDexFileFreeString.
+class ExtDexFileString;
+
+// Returns an ExtDexFileString initialized to the given string.
+const ExtDexFileString* ExtDexFileMakeString(const char* str);
+
+// Returns a pointer to the underlying null-terminated character array and its
+// size for the given ExtDexFileString.
+const char* ExtDexFileGetString(const ExtDexFileString* ext_string, /*out*/ size_t* size);
+
+// Frees an ExtDexFileString.
+void ExtDexFileFreeString(const ExtDexFileString* ext_string);
+
+struct ExtDexFileMethodInfo {
+ int32_t offset;
+ int32_t len;
+ const ExtDexFileString* name;
+};
+
+class ExtDexFile;
+
+// See art_api::dex::DexFile::OpenFromMemory. Returns true on success.
+int ExtDexFileOpenFromMemory(const void* addr,
+ /*inout*/ size_t* size,
+ const char* location,
+ /*out*/ const ExtDexFileString** error_msg,
+ /*out*/ ExtDexFile** ext_dex_file);
+
+// See art_api::dex::DexFile::OpenFromFd. Returns true on success.
+int ExtDexFileOpenFromFd(int fd,
+ off_t offset,
+ const char* location,
+ /*out*/ const ExtDexFileString** error_msg,
+ /*out*/ ExtDexFile** ext_dex_file);
+
+// See art_api::dex::DexFile::GetMethodInfoForOffset. Returns true on success.
+int ExtDexFileGetMethodInfoForOffset(ExtDexFile* ext_dex_file,
+ int64_t dex_offset,
+ /*out*/ ExtDexFileMethodInfo* method_info);
+
+typedef void ExtDexFileMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info,
+ void* user_data);
+
+// See art_api::dex::DexFile::GetAllMethodInfos.
+void ExtDexFileGetAllMethodInfos(ExtDexFile* ext_dex_file,
+ int with_signature,
+ ExtDexFileMethodInfoCallback* method_info_cb,
+ void* user_data);
+
+// Frees an ExtDexFile.
+void ExtDexFileFree(ExtDexFile* ext_dex_file);
+
+} // extern "C"
+
+namespace art_api {
+namespace dex {
+
+// Minimal std::string look-alike for a string returned from libdexfile.
+class DexString final {
+ public:
+ DexString(DexString&& dex_str) { ReplaceExtString(std::move(dex_str)); }
+ explicit DexString(const char* str = "") : ext_string_(ExtDexFileMakeString(str)) {}
+ ~DexString() { ExtDexFileFreeString(ext_string_); }
+
+ DexString& operator=(DexString&& dex_str) {
+ ReplaceExtString(std::move(dex_str));
+ return *this;
+ }
+
+ const char* data() const {
+ size_t ignored;
+ return ExtDexFileGetString(ext_string_, &ignored);
+ }
+ const char* c_str() const { return data(); }
+
+ size_t size() const {
+ size_t len;
+ (void)ExtDexFileGetString(ext_string_, &len);
+ return len;
+ }
+ size_t length() const { return size(); }
+
+ operator std::string_view() const {
+ size_t len;
+ const char* chars = ExtDexFileGetString(ext_string_, &len);
+ return std::string_view(chars, len);
+ }
+
+ private:
+ friend class DexFile;
+ friend bool operator==(const DexString&, const DexString&);
+ explicit DexString(const ExtDexFileString* ext_string) : ext_string_(ext_string) {}
+ const ExtDexFileString* ext_string_; // Owned instance. Never nullptr.
+
+ void ReplaceExtString(DexString&& dex_str) {
+ ext_string_ = dex_str.ext_string_;
+ dex_str.ext_string_ = ExtDexFileMakeString("");
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(DexString);
+};
+
+inline bool operator==(const DexString& s1, const DexString& s2) {
+ size_t l1, l2;
+ const char* str1 = ExtDexFileGetString(s1.ext_string_, &l1);
+ const char* str2 = ExtDexFileGetString(s2.ext_string_, &l2);
+ // Use memcmp to avoid assumption about absence of null characters in the strings.
+ return l1 == l2 && !std::memcmp(str1, str2, l1);
+}
+
+struct MethodInfo {
+ int32_t offset; // Code offset relative to the start of the dex file header
+ int32_t len; // Code length
+ DexString name;
+};
+
+inline bool operator==(const MethodInfo& s1, const MethodInfo& s2) {
+ return s1.offset == s2.offset && s1.len == s2.len && s1.name == s2.name;
+}
+
+// External stable API to access ordinary dex files and CompactDex. This wraps
+// the stable C ABI and handles instance ownership. Thread-compatible but not
+// thread-safe.
+class DexFile {
+ public:
+ DexFile(DexFile&& dex_file) {
+ ext_dex_file_ = dex_file.ext_dex_file_;
+ dex_file.ext_dex_file_ = nullptr;
+ }
+ virtual ~DexFile();
+
+ // Interprets a chunk of memory as a dex file. As long as *size is too small,
+ // returns nullptr, sets *size to a new size to try again with, and sets
+ // *error_msg to "". That might happen repeatedly. Also returns nullptr
+ // on error in which case *error_msg is set to a nonempty string.
+ //
+ // location is a string that describes the dex file, and is preferably its
+ // path. It is mostly used to make error messages better, and may be "".
+ //
+ // The caller must retain the memory.
+ static std::unique_ptr<DexFile> OpenFromMemory(const void* addr,
+ size_t* size,
+ const std::string& location,
+ /*out*/ std::string* error_msg) {
+ ExtDexFile* ext_dex_file;
+ const ExtDexFileString* ext_error_msg = nullptr;
+ if (ExtDexFileOpenFromMemory(addr, size, location.c_str(), &ext_error_msg, &ext_dex_file)) {
+ return std::unique_ptr<DexFile>(new DexFile(ext_dex_file));
+ }
+ *error_msg = (ext_error_msg == nullptr) ? "" : std::string(DexString(ext_error_msg));
+ return nullptr;
+ }
+
+ // mmaps the given file offset in the open fd and reads a dexfile from there.
+ // Returns nullptr on error in which case *error_msg is set.
+ //
+ // location is a string that describes the dex file, and is preferably its
+ // path. It is mostly used to make error messages better, and may be "".
+ static std::unique_ptr<DexFile> OpenFromFd(int fd,
+ off_t offset,
+ const std::string& location,
+ /*out*/ std::string* error_msg) {
+ ExtDexFile* ext_dex_file;
+ const ExtDexFileString* ext_error_msg = nullptr;
+ if (ExtDexFileOpenFromFd(fd, offset, location.c_str(), &ext_error_msg, &ext_dex_file)) {
+ return std::unique_ptr<DexFile>(new DexFile(ext_dex_file));
+ }
+ *error_msg = std::string(DexString(ext_error_msg));
+ return nullptr;
+ }
+
+ // Given an offset relative to the start of the dex file header, if there is a
+ // method whose instruction range includes that offset then returns info about
+ // it, otherwise returns a struct with offset == 0.
+ MethodInfo GetMethodInfoForOffset(int64_t dex_offset) {
+ ExtDexFileMethodInfo ext_method_info;
+ if (ExtDexFileGetMethodInfoForOffset(ext_dex_file_, dex_offset, &ext_method_info)) {
+ return AbsorbMethodInfo(ext_method_info);
+ }
+ return {/*offset=*/0, /*len=*/0, /*name=*/DexString()};
+ }
+
+ // Returns info structs about all methods in the dex file. MethodInfo.name
+ // receives the full function signature if with_signature is set, otherwise it
+ // gets the class and method name only.
+ std::vector<MethodInfo> GetAllMethodInfos(bool with_signature = true) {
+ MethodInfoVector res;
+ ExtDexFileGetAllMethodInfos(
+ ext_dex_file_, with_signature, AddMethodInfoCallback, static_cast<void*>(&res));
+ return res;
+ }
+
+ private:
+ explicit DexFile(ExtDexFile* ext_dex_file) : ext_dex_file_(ext_dex_file) {}
+ ExtDexFile* ext_dex_file_; // Owned instance. nullptr only in moved-from zombies.
+
+ typedef std::vector<MethodInfo> MethodInfoVector;
+
+ static MethodInfo AbsorbMethodInfo(const ExtDexFileMethodInfo& ext_method_info);
+ static void AddMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info, void* user_data);
+
+ DISALLOW_COPY_AND_ASSIGN(DexFile);
+};
+
+} // namespace dex
+} // namespace art_api
+
+#endif // ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_EXT_DEX_FILE_H_
diff --git a/libdexfile/external/libdexfile_external.map.txt b/libdexfile/external/libdexfile_external.map.txt
new file mode 100644
index 0000000000..450b633d32
--- /dev/null
+++ b/libdexfile/external/libdexfile_external.map.txt
@@ -0,0 +1,13 @@
+LIBDEXFILE_EXTERNAL_1 {
+ global:
+ ExtDexFileFree;
+ ExtDexFileFreeString;
+ ExtDexFileGetAllMethodInfos;
+ ExtDexFileGetMethodInfoForOffset;
+ ExtDexFileGetString;
+ ExtDexFileMakeString;
+ ExtDexFileOpenFromFd;
+ ExtDexFileOpenFromMemory;
+ local:
+ *;
+};
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 60f1af1aea..4780f16910 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -420,6 +420,8 @@ libart_static_cc_defaults {
"libbacktrace",
"libbase",
"libcutils",
+ "libdexfile_external", // libunwindstack dependency
+ "libdexfile_support", // libunwindstack dependency
"liblog",
"libnativebridge",
"libnativeloader",
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index de4dd82ef9..03c97f47f0 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -58,7 +58,7 @@ void* Jit::jit_library_handle_ = nullptr;
void* Jit::jit_compiler_handle_ = nullptr;
void* (*Jit::jit_load_)(void) = nullptr;
void (*Jit::jit_unload_)(void*) = nullptr;
-bool (*Jit::jit_compile_method_)(void*, ArtMethod*, Thread*, bool) = nullptr;
+bool (*Jit::jit_compile_method_)(void*, ArtMethod*, Thread*, bool, bool) = nullptr;
void (*Jit::jit_types_loaded_)(void*, mirror::Class**, size_t count) = nullptr;
bool (*Jit::jit_generate_debug_info_)(void*) = nullptr;
void (*Jit::jit_update_options_)(void*) = nullptr;
@@ -242,7 +242,7 @@ bool Jit::LoadCompilerLibrary(std::string* error_msg) {
return true;
}
-bool Jit::CompileMethod(ArtMethod* method, Thread* self, bool osr) {
+bool Jit::CompileMethod(ArtMethod* method, Thread* self, bool baseline, bool osr) {
DCHECK(Runtime::Current()->UseJitCompilation());
DCHECK(!method->IsRuntimeMethod());
@@ -272,7 +272,7 @@ bool Jit::CompileMethod(ArtMethod* method, Thread* self, bool osr) {
VLOG(jit) << "Compiling method "
<< ArtMethod::PrettyMethod(method_to_compile)
<< " osr=" << std::boolalpha << osr;
- bool success = jit_compile_method_(jit_compiler_handle_, method_to_compile, self, osr);
+ bool success = jit_compile_method_(jit_compiler_handle_, method_to_compile, self, baseline, osr);
code_cache_->DoneCompiling(method_to_compile, self, osr);
if (!success) {
VLOG(jit) << "Failed to compile method "
@@ -555,6 +555,7 @@ class JitCompileTask final : public Task {
enum class TaskKind {
kAllocateProfile,
kCompile,
+ kCompileBaseline,
kCompileOsr,
};
@@ -574,10 +575,12 @@ class JitCompileTask final : public Task {
ScopedObjectAccess soa(self);
switch (kind_) {
case TaskKind::kCompile:
+ case TaskKind::kCompileBaseline:
case TaskKind::kCompileOsr: {
Runtime::Current()->GetJit()->CompileMethod(
method_,
self,
+ /* baseline= */ (kind_ == TaskKind::kCompileBaseline),
/* osr= */ (kind_ == TaskKind::kCompileOsr));
break;
}
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 1cfbb9c282..e5c976669e 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -161,7 +161,7 @@ class Jit {
// Create JIT itself.
static Jit* Create(JitCodeCache* code_cache, JitOptions* options);
- bool CompileMethod(ArtMethod* method, Thread* self, bool osr)
+ bool CompileMethod(ArtMethod* method, Thread* self, bool baseline, bool osr)
REQUIRES_SHARED(Locks::mutator_lock_);
const JitCodeCache* GetCodeCache() const {
@@ -305,7 +305,7 @@ class Jit {
static void* jit_compiler_handle_;
static void* (*jit_load_)(void);
static void (*jit_unload_)(void*);
- static bool (*jit_compile_method_)(void*, ArtMethod*, Thread*, bool);
+ static bool (*jit_compile_method_)(void*, ArtMethod*, Thread*, bool, bool);
static void (*jit_types_loaded_)(void*, mirror::Class**, size_t count);
static void (*jit_update_options_)(void*);
static bool (*jit_generate_debug_info_)(void*);
diff --git a/test/566-polymorphic-inlining/polymorphic_inline.cc b/test/566-polymorphic-inlining/polymorphic_inline.cc
index 17ccd9a781..00827cf8d5 100644
--- a/test/566-polymorphic-inlining/polymorphic_inline.cc
+++ b/test/566-polymorphic-inlining/polymorphic_inline.cc
@@ -46,7 +46,7 @@ static void do_checks(jclass cls, const char* method_name) {
usleep(1000);
}
// Will either ensure it's compiled or do the compilation itself.
- jit->CompileMethod(method, soa.Self(), /* osr */ false);
+ jit->CompileMethod(method, soa.Self(), /*baseline=*/ false, /*osr=*/ false);
}
CodeInfo info(header);
diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc
index b2b363447f..dc0e94cbc7 100644
--- a/test/570-checker-osr/osr.cc
+++ b/test/570-checker-osr/osr.cc
@@ -128,7 +128,7 @@ extern "C" JNIEXPORT void JNICALL Java_Main_ensureHasOsrCode(JNIEnv* env,
// Sleep to yield to the compiler thread.
usleep(1000);
// Will either ensure it's compiled or do the compilation itself.
- jit->CompileMethod(m, Thread::Current(), /* osr */ true);
+ jit->CompileMethod(m, Thread::Current(), /*baseline=*/ false, /*osr=*/ true);
}
});
}
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index 65127fcab1..55631a9651 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -227,7 +227,7 @@ static void ForceJitCompiled(Thread* self, ArtMethod* method) REQUIRES(!Locks::m
// Make sure there is a profiling info, required by the compiler.
ProfilingInfo::Create(self, method, /* retry_allocation */ true);
// Will either ensure it's compiled or do the compilation itself.
- jit->CompileMethod(method, self, /* osr */ false);
+ jit->CompileMethod(method, self, /*baseline=*/ false, /*osr=*/ false);
}
}
}