Add oatopt drop in replacement for dexopt
Change-Id: I094375230af2d9a88e30245b390cac71be7b50f4
diff --git a/Android.mk b/Android.mk
index 06b7ebe..5b1d13b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -186,12 +186,15 @@
zygote-artd-target-sync: $(ART_TARGET_DEPENDENCIES) $(TARGET_BOOT_OAT) $(ART_CACHE_OATS)
cp $(TARGET_OUT_SHARED_LIBRARIES)/libartd.so $(TARGET_OUT_SHARED_LIBRARIES)/libdvm.so
cp $(TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED)/libartd.so $(TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED)/libdvm.so
+ cp $(TARGET_OUT_EXECUTABLES)/oatoptd $(TARGET_OUT_EXECUTABLES)/dexopt
+ cp $(TARGET_OUT_EXECUTABLES_UNSTRIPPED)/oatoptd $(TARGET_OUT_EXECUTABLES_UNSTRIPPED)/dexopt
adb remount
adb sync
.PHONY: zygote-artd
zygote-artd: zygote-artd-target-sync
- sed 's/--start-system-server/--start-system-server --no-preload/' < system/core/rootdir/init.rc > $(ANDROID_PRODUCT_OUT)/root/init.rc
+ sed -e 's/--start-system-server/--start-system-server --no-preload/' -e 's/art-cache 0771/art-cache 0777/' < system/core/rootdir/init.rc > $(ANDROID_PRODUCT_OUT)/root/init.rc
+ adb shell rm -f $(ART_CACHE_DIR)
rm -f $(ANDROID_PRODUCT_OUT)/boot.img
unset ONE_SHOT_MAKEFILE && $(MAKE) showcommands bootimage
adb reboot bootloader
@@ -202,6 +205,8 @@
zygote-dalvik:
cp $(TARGET_OUT_INTERMEDIATE_LIBRARIES)/libdvm.so $(TARGET_OUT_SHARED_LIBRARIES)/libdvm.so
cp $(call intermediates-dir-for,SHARED_LIBRARIES,libdvm)/LINKED/libdvm.so $(TARGET_OUT_SHARED_LIBRARIES_UNSTRIPPED)/libdvm.so
+ cp $(call intermediates-dir-for,EXECUTABLES,dexopt)/dexopt $(TARGET_OUT_EXECUTABLES)/dexopt
+ cp $(call intermediates-dir-for,EXECUTABLES,dexopt)/LINKED/dexopt $(TARGET_OUT_EXECUTABLES_UNSTRIPPED)/dexopt
adb remount
adb sync
cp system/core/rootdir/init.rc $(ANDROID_PRODUCT_OUT)/root/init.rc
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 7875ee9..319d673 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -67,6 +67,9 @@
OATEXEC_SRC_FILES := \
src/oatexec.cc
+OATOPT_SRC_FILES := \
+ src/oatopt.cc
+
LIBART_COMMON_SRC_FILES := \
src/assembler.cc \
src/assembler_arm.cc \
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index 7619f74..d00002a 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -91,20 +91,24 @@
$(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),target,ndebug))
$(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),target,ndebug))
$(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),target,ndebug))
+ $(eval $(call build-art-executable,oatopt,$(OATOPT_SRC_FILES),target,ndebug))
endif
ifeq ($(ART_BUILD_TARGET_DEBUG),true)
$(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),target,debug))
$(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),target,debug))
$(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),target,debug))
+ $(eval $(call build-art-executable,oatopt,$(OATOPT_SRC_FILES),target,debug))
endif
ifeq ($(ART_BUILD_HOST_NDEBUG),true)
$(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),host,ndebug))
$(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),host,ndebug))
$(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),host,ndebug))
+ $(eval $(call build-art-executable,oatopt,$(OATOPT_SRC_FILES),host,ndebug))
endif
ifeq ($(ART_BUILD_HOST_DEBUG),true)
$(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),host,debug))
$(eval $(call build-art-executable,oatdump,$(OATDUMP_SRC_FILES),host,debug))
$(eval $(call build-art-executable,oatexec,$(OATEXEC_SRC_FILES),host,debug))
+ $(eval $(call build-art-executable,oatopt,$(OATOPT_SRC_FILES),host,debug))
endif
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 59bb771..846cda3 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -20,8 +20,8 @@
DEX2OAT := $(DEX2OATD)
# TODO: change DEX2OAT_DEPENDENCY to order-only prerequisite when output is stable
+# DEX2OAT_DEPENDENCY := | $(DEX2OAT) # only build dex2oat if needed to build oat files
DEX2OAT_DEPENDENCY := $(DEX2OAT) # when dex2oat changes, rebuild all oat files
-DEX2OAT_DEPENDENCY := | $(DEX2OAT) # only build dex2oat if needed to build oat files
OATDUMP := $(HOST_OUT_EXECUTABLES)/oatdump$(HOST_EXECUTABLE_SUFFIX)
OATDUMPD := $(HOST_OUT_EXECUTABLES)/oatdumpd$(HOST_EXECUTABLE_SUFFIX)
diff --git a/src/class_linker.cc b/src/class_linker.cc
index f610f31..9fd8f0b 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -573,16 +573,8 @@
const OatFile* ClassLinker::FindOatFile(const DexFile& dex_file) {
MutexLock mu(lock_);
- std::string dex_file_location = dex_file.GetLocation();
- std::string location(dex_file_location);
- CHECK(StringPiece(location).ends_with(".dex")
- || StringPiece(location).ends_with(".zip")
- || StringPiece(location).ends_with(".jar")
- || StringPiece(location).ends_with(".apk"));
- location.erase(location.size()-3);
- location += "oat";
// TODO: check if dex_file matches an OatDexFile location and checksum
- return FindOatFile(location);
+ return FindOatFile(OatFile::DexFileToOatFilename(dex_file));
}
const OatFile* ClassLinker::FindOatFile(const std::string& location) {
@@ -601,10 +593,7 @@
return NULL;
}
// not found in /foo/bar/baz.oat? try /data/art-cache/foo@bar@baz.oat
- std::string art_cache = GetArtCacheOrDie();
- std::string cache_file(location, 1); // skip leading slash
- std::replace(cache_file.begin(), cache_file.end(), '/', '@');
- std::string cache_location = art_cache + "/" + cache_file;
+ std::string cache_location = GetArtCacheOatFilenameOrDie(location);
oat_file = OatFile::Open(cache_location, "", NULL);
if (oat_file == NULL) {
LOG(ERROR) << "Failed to open oat file from " << location << " or " << cache_location << ".";
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index e8cd26d..a4d7449 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -86,6 +86,9 @@
for (int i = 0; i < argc; i++) {
const StringPiece option(argv[i]);
+ if (false) {
+ LOG(INFO) << "dex2oat: option[" << i << "]=" << argv[i];
+ }
if (option.starts_with("--dex-file=")) {
dex_filenames.push_back(option.substr(strlen("--dex-file=")).data());
} else if (option.starts_with("--method=")) {
@@ -142,7 +145,7 @@
}
Runtime::Options options;
- std::string boot_class_path_string;
+ std::string boot_class_path_string;
if (boot_image_option.empty()) {
boot_class_path_string += "-Xbootclasspath:";
for (size_t i = 0; i < dex_filenames.size()-1; i++) {
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 235c734..a11744d 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -107,7 +107,7 @@
return OpenMemory(dex_file, length, location.ToString(), map.release());
}
-static const char* kClassesDex = "classes.dex";
+const char* DexFile::kClassesDex = "classes.dex";
class LockedFd {
public:
@@ -643,7 +643,7 @@
ParameterIterator* it = GetParameterIterator(GetProtoId(method->GetProtoIdx()));
for (uint32_t i = 0; i < parameters_size && it->HasNext(); ++i, it->Next()) {
if (arg_reg >= code_item->registers_size_) {
- LOG(FATAL) << "invalid stream";
+ LOG(ERROR) << "invalid stream";
return;
}
int32_t id = DecodeUnsignedLeb128P1(&stream);
@@ -669,7 +669,7 @@
}
if (it->HasNext()) {
- LOG(FATAL) << "invalid stream";
+ LOG(ERROR) << "invalid stream";
return;
}
@@ -695,7 +695,7 @@
case DBG_START_LOCAL_EXTENDED:
reg = DecodeUnsignedLeb128(&stream);
if (reg > code_item->registers_size_) {
- LOG(FATAL) << "invalid stream";
+ LOG(ERROR) << "invalid stream";
return;
}
@@ -718,7 +718,7 @@
case DBG_END_LOCAL:
reg = DecodeUnsignedLeb128(&stream);
if (reg > code_item->registers_size_) {
- LOG(FATAL) << "invalid stream";
+ LOG(ERROR) << "invalid stream";
return;
}
@@ -731,13 +731,13 @@
case DBG_RESTART_LOCAL:
reg = DecodeUnsignedLeb128(&stream);
if (reg > code_item->registers_size_) {
- LOG(FATAL) << "invalid stream";
+ LOG(ERROR) << "invalid stream";
return;
}
if (need_locals) {
if (local_in_reg[reg].name_ == NULL || local_in_reg[reg].descriptor_ == NULL) {
- LOG(FATAL) << "invalid stream";
+ LOG(ERROR) << "invalid stream";
return;
}
diff --git a/src/dex_file.h b/src/dex_file.h
index 77189f8..7d9e6f9 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -31,6 +31,9 @@
static const byte kDexMagicVersion[];
static const size_t kSha1DigestSize = 20;
+ // name of the DexFile entry within a zip archive
+ static const char* kClassesDex;
+
static const byte kEncodedValueTypeMask = 0x1f; // 0b11111
static const byte kEncodedValueArgShift = 5;
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 8a4aa9a..23eae7c 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -10,6 +10,17 @@
namespace art {
+std::string OatFile::DexFileToOatFilename(const DexFile& dex_file) {
+ std::string location(dex_file.GetLocation());
+ CHECK(StringPiece(location).ends_with(".dex")
+ || StringPiece(location).ends_with(".zip")
+ || StringPiece(location).ends_with(".jar")
+ || StringPiece(location).ends_with(".apk"));
+ location.erase(location.size()-3);
+ location += "oat";
+ return location;
+}
+
OatFile* OatFile::Open(const std::string& filename,
const std::string& strip_location_prefix,
byte* requested_base) {
diff --git a/src/oat_file.h b/src/oat_file.h
index 9f95b3b..1d3367c 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -16,6 +16,9 @@
class OatFile {
public:
+ // Returns an OatFile name based on a DexFile location
+ static std::string DexFileToOatFilename(const DexFile& dex_file);
+
// Open an oat file. Returns NULL on failure. Requested base can
// optionally be used to request where the file should be loaded.
static OatFile* Open(const std::string& filename,
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 46f6c24..a5c8c7b 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -109,8 +109,9 @@
os << "location: " << dex_file_location;
if (!host_prefix.empty()) {
dex_file_location = host_prefix + dex_file_location;
- os << " (" << dex_file_location << ")\n";
+ os << " (" << dex_file_location << ")";
}
+ os << "\n";
os << StringPrintf("checksum: %08x\n", oat_dex_file.GetDexFileChecksum());
const DexFile* dex_file = DexFile::Open(dex_file_location, "");
if (dex_file == NULL) {
@@ -282,8 +283,9 @@
os << oat_location;
if (!host_prefix.empty()) {
oat_location = host_prefix + oat_location;
- os << " (" << oat_location << ")\n";
+ os << " (" << oat_location << ")";
}
+ os << "\n";
const OatFile* oat_file = class_linker->FindOatFile(oat_location);
if (oat_file == NULL) {
os << "NOT FOUND\n";
diff --git a/src/oatopt.cc b/src/oatopt.cc
new file mode 100644
index 0000000..367e5bf
--- /dev/null
+++ b/src/oatopt.cc
@@ -0,0 +1,144 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "dex_file.h"
+#include "file.h"
+#include "logging.h"
+#include "oat_file.h"
+#include "os.h"
+#include "UniquePtr.h"
+#include "zip_archive.h"
+
+namespace art {
+
+int ProcessZipFile(int zip_fd, int cache_fd, const char* zip_name, const char *flags) {
+ // TODO: need to read/write to installd opened file descriptors
+ if (false) {
+ UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(zip_fd));
+ if (zip_archive.get() == NULL) {
+ LOG(ERROR) << "Failed to open " << zip_name << " when looking for classes.dex";
+ return -1;
+ }
+
+ UniquePtr<ZipEntry> zip_entry(zip_archive->Find(DexFile::kClassesDex));
+ if (zip_entry.get() == NULL) {
+ LOG(ERROR) << "Failed to find classes.dex within " << zip_name;
+ return -1;
+ }
+
+ UniquePtr<File> file(OS::FileFromFd("oatopt cache file descriptor", cache_fd));
+ bool success = zip_entry->Extract(*file);
+ if (!success) {
+ LOG(ERROR) << "Failed to extract classes.dex from " << zip_name;
+ return -1;
+ }
+ }
+
+ // Opening a zip file for a dex will extract to art-cache
+ UniquePtr<const DexFile> dex_file(DexFile::Open(zip_name, ""));
+ if (dex_file.get() == NULL) {
+ LOG(ERROR) << "Failed to open " << zip_name;
+ return -1;
+ }
+
+ std::string dex_file_option("--dex-file=");
+ dex_file_option += zip_name;
+
+ std::string oat_file_option("--oat=");
+ oat_file_option += GetArtCacheOatFilenameOrDie(OatFile::DexFileToOatFilename(*dex_file.get()));
+
+ execl("/system/bin/dex2oatd",
+ "/system/bin/dex2oatd",
+ "-Xms64m",
+ "-Xmx64m",
+ "--boot-image=/data/art-cache/boot.art",
+ dex_file_option.c_str(),
+ oat_file_option.c_str(),
+ NULL);
+ PLOG(FATAL) << "execl(dex2oatd) failed";
+ return -1;
+}
+
+// Parse arguments. We want:
+// 0. (name of command -- ignored)
+// 1. "--zip"
+// 2. zip fd (input, read-only)
+// 3. cache fd (output, read-write, locked with flock)
+// 4. filename of zipfile
+// 5. flags
+int FromZip(const int argc, const char* const argv[]) {
+ if (argc != 6) {
+ LOG(ERROR) << "Wrong number of args for --zip (found " << argc << ")";
+ return -1;
+ }
+
+ // ignore program name
+
+ // verify --zip
+ CHECK_STREQ(argv[1], "--zip");
+
+ char* zip_end;
+ int zip_fd = strtol(argv[2], &zip_end, 0);
+ if (*zip_end != '\0') {
+ LOG(ERROR) << "bad zip fd: " << argv[2];
+ return -1;
+ }
+#ifndef NDEBUG
+ LOG(INFO) << "zip_fd=" << zip_fd;
+#endif
+
+ char* cache_end;
+ int cache_fd = strtol(argv[3], &cache_end, 0);
+ if (*cache_end != '\0') {
+ LOG(ERROR) << "bad cache fd: " << argv[3];
+ return -1;
+ }
+#ifndef NDEBUG
+ LOG(INFO) << "cache_fd=" << cache_fd;
+#endif
+
+ const char* zip_name = argv[4];
+#ifndef NDEBUG
+ LOG(INFO) << "zip_name=" << zip_name;
+#endif
+
+ const char* flags = argv[5];
+#ifndef NDEBUG
+ LOG(INFO) << "flags=" << flags;
+#endif
+
+ return ProcessZipFile(zip_fd, cache_fd, zip_name, flags);
+}
+
+int oatopt(int argc, char** argv) {
+
+ setvbuf(stdout, NULL, _IONBF, 0);
+
+ if (true) {
+ for (int i = 0; i < argc; ++i) {
+ LOG(INFO) << "oatopt: option[" << i << "]=" << argv[i];
+ }
+ }
+
+ if (argc > 1) {
+ if (strcmp(argv[1], "--zip") == 0) {
+ return FromZip(argc, argv);
+ }
+ }
+
+ fprintf(stderr,
+ "Usage:\n\n"
+ "Short version: Don't use this.\n\n"
+ "Slightly longer version: This system-internal tool is used to extract\n"
+ "dex files and produce oat files. See the source code for details.\n");
+
+ return 1;
+}
+
+} // namespace art
+
+int main(int argc, char** argv) {
+ return art::oatopt(argc, argv);
+}
diff --git a/src/utils.cc b/src/utils.cc
index bc51c2a..4f4cd8f 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -514,6 +514,14 @@
return art_cache;
}
+std::string GetArtCacheOatFilenameOrDie(const std::string& location) {
+ std::string art_cache = GetArtCacheOrDie();
+ CHECK_EQ(location[0], '/');
+ std::string cache_file(location, 1); // skip leading slash
+ std::replace(cache_file.begin(), cache_file.end(), '/', '@');
+ return art_cache + "/" + cache_file;
+}
+
} // namespace art
// Neither bionic nor glibc exposes gettid(2).
diff --git a/src/utils.h b/src/utils.h
index 7778918..35b350b 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -212,9 +212,12 @@
// implementation-defined limit.
void SetThreadName(const char* name);
-// Returns the art-cache location or dies trying
+// Returns the art-cache location, or dies trying.
std::string GetArtCacheOrDie();
+// Returns the art-cache location for an OatFile, or dies trying.
+std::string GetArtCacheOatFilenameOrDie(const std::string& location);
+
} // namespace art
#endif // ART_SRC_UTILS_H_
diff --git a/src/zip_archive.cc b/src/zip_archive.cc
index 82d97ec..41a25de 100644
--- a/src/zip_archive.cc
+++ b/src/zip_archive.cc
@@ -257,7 +257,6 @@
}
}
-// return new ZipArchive instance on success, NULL on error.
ZipArchive* ZipArchive::Open(const std::string& filename) {
DCHECK(!filename.empty());
int fd = open(filename.c_str(), O_RDONLY | O_CLOEXEC, 0);
@@ -265,6 +264,10 @@
PLOG(WARNING) << "Unable to open '" << filename << "'";
return NULL;
}
+ return Open(fd);
+}
+
+ZipArchive* ZipArchive::Open(int fd) {
UniquePtr<ZipArchive> zip_archive(new ZipArchive(fd));
if (zip_archive.get() == NULL) {
return NULL;
diff --git a/src/zip_archive.h b/src/zip_archive.h
index 0c9e6c2..13a22cc 100644
--- a/src/zip_archive.h
+++ b/src/zip_archive.h
@@ -102,7 +102,10 @@
static const int32_t kCDECommentLen = 32; // offset to comment length
static const int32_t kCDELocalOffset = 42; // offset to local hdr
+ // return new ZipArchive instance on success, NULL on error.
static ZipArchive* Open(const std::string& filename);
+ static ZipArchive* Open(int fd);
+
ZipEntry* Find(const char * name);
~ZipArchive() {