Merge art-cache dex files into oat files

Change-Id: I5a327a4e0b678bd9dabb12de4e21ef05e3fefd0b
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 33a4fb0..3fe0477 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -61,6 +61,9 @@
   ART_TARGET_CFLAGS += -DANDROID_SMP=0
 endif
 
+# To use oprofile_android --callgraph, uncomment this and recompile with "mmm art -B -j16"
+# ART_TARGET_CFLAGS += -fno-omit-frame-pointer -marm -mapcs
+
 ART_HOST_NON_DEBUG_CFLAGS := $(art_non_debug_cflags)
 ART_TARGET_NON_DEBUG_CFLAGS := $(art_non_debug_cflags)
 
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index 616c1c2..52009ab 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -55,7 +55,7 @@
     LOCAL_MODULE := $$(art_executable)d
   endif
 
-  ifeq ($(art_target_or_host),target)
+  ifeq ($$(art_target_or_host),target)
     LOCAL_CFLAGS := $(ART_TARGET_CFLAGS)
     ifeq ($$(art_ndebug_or_debug),debug)
       LOCAL_CFLAGS += $(ART_TARGET_DEBUG_CFLAGS)
diff --git a/src/card_table.cc b/src/card_table.cc
index 13491d8..430918a 100644
--- a/src/card_table.cc
+++ b/src/card_table.cc
@@ -62,7 +62,8 @@
   /* Set up the card table */
   size_t length = heap_max_size / GC_CARD_SIZE;
   /* Allocate an extra 256 bytes to allow fixed low-byte of base */
-  mem_map_.reset(MemMap::Map("dalvik-card-table", NULL, length + 256, PROT_READ | PROT_WRITE));
+  mem_map_.reset(
+      MemMap::MapAnonymous("dalvik-card-table", NULL, length + 256, PROT_READ | PROT_WRITE));
   byte* alloc_base = mem_map_->GetAddress();
   if (alloc_base == NULL) {
     return false;
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 5a3887a..e3b30d7 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -733,7 +733,6 @@
 }
 
 void ClassLinker::InitFromImage() {
-  const Runtime* runtime = Runtime::Current();
   VLOG(startup) << "ClassLinker::InitFromImage entering";
   CHECK(!init_done_);
 
@@ -759,17 +758,13 @@
       for (int i = 0; i < dex_caches->GetLength(); i++) {
         SirtRef<DexCache> dex_cache(dex_caches->Get(i));
         const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
-
-        std::string dex_filename;
-        dex_filename += runtime->GetHostPrefix();
-        dex_filename += dex_file_location;
-        const DexFile* dex_file = DexFile::Open(dex_filename, runtime->GetHostPrefix());
+        const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location);
+        const DexFile* dex_file = oat_dex_file->OpenDexFile();
         if (dex_file == NULL) {
-          LOG(FATAL) << "Failed to open dex file " << dex_filename
-                     << " referenced from oat file as " << dex_file_location;
+          LOG(FATAL) << "Failed to open dex file " << dex_file_location
+                     << " from within oat file " << oat_file->GetLocation();
         }
 
-        const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file_location);
         CHECK_EQ(dex_file->GetHeader().checksum_, oat_dex_file->GetDexFileChecksum());
 
         AppendToBootClassPath(*dex_file, dex_cache);
@@ -1789,7 +1784,7 @@
       SirtRef<Method> prototype(methods->Get(i));
       CheckProxyMethod(klass->GetVirtualMethod(i), prototype);
     }
-    std::string throws_field_name = "java.lang.Class[][] ";
+    std::string throws_field_name("java.lang.Class[][] ");
     throws_field_name += name->ToModifiedUtf8();
     throws_field_name += ".throws";
     CHECK(PrettyField(klass->GetStaticField(0)) == throws_field_name);
diff --git a/src/dalvik_system_DexFile.cc b/src/dalvik_system_DexFile.cc
index f668cc9..36d4744 100644
--- a/src/dalvik_system_DexFile.cc
+++ b/src/dalvik_system_DexFile.cc
@@ -112,7 +112,7 @@
       return NULL;
     }
     UniquePtr<File> file(OS::OpenFile(outputName.c_str(), true));
-    bool success = zip_entry->Extract(*file);
+    bool success = zip_entry->ExtractToFile(*file);
     if (!success) {
       LOG(ERROR) << "Failed to extract classes.dex from " << sourceName.c_str();
       return NULL;
diff --git a/src/dex_file.cc b/src/dex_file.cc
index ce7dde6..a45455d 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -76,15 +76,25 @@
   }
 }
 
+const std::string StripLocationPrefix(const std::string& original_location,
+                                      const std::string& strip_location_prefix) {
+  StringPiece location = original_location;
+  if (!location.starts_with(strip_location_prefix)) {
+    LOG(ERROR) << location << " does not start with " << strip_location_prefix;
+    return "";
+  }
+  location.remove_prefix(strip_location_prefix.size());
+  return location.ToString();
+}
+
 const DexFile* DexFile::OpenFile(const std::string& filename,
                                  const std::string& original_location,
                                  const std::string& strip_location_prefix) {
-  StringPiece location = original_location;
-  if (!location.starts_with(strip_location_prefix)) {
-    LOG(ERROR) << filename << " does not start with " << strip_location_prefix;
+  std::string location(StripLocationPrefix(original_location, strip_location_prefix));
+  if (location.empty()) {
     return NULL;
   }
-  location.remove_prefix(strip_location_prefix.size());
+
   int fd = open(filename.c_str(), O_RDONLY);  // TODO: scoped_fd
   if (fd == -1) {
     PLOG(ERROR) << "open(\"" << filename << "\", O_RDONLY) failed";
@@ -98,15 +108,14 @@
     return NULL;
   }
   size_t length = sbuf.st_size;
-  UniquePtr<MemMap> map(MemMap::Map(length, PROT_READ, MAP_PRIVATE, fd, 0));
+  UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ, MAP_PRIVATE, fd, 0));
   if (map.get() == NULL) {
     LOG(ERROR) << "mmap \"" << filename << "\" failed";
     close(fd);
     return NULL;
   }
   close(fd);
-  byte* dex_file = map->GetAddress();
-  return OpenMemory(dex_file, length, location.ToString(), map.release());
+  return OpenMemory(location, map.release());
 }
 
 const char* DexFile::kClassesDex = "classes.dex";
@@ -168,44 +177,10 @@
 // Open classes.dex from within a .zip, .jar, .apk, ...
 const DexFile* DexFile::OpenZip(const std::string& filename,
                                 const std::string& strip_location_prefix) {
-  // First, look for a ".dex" alongside the jar file.  It will have
-  // the same name/path except for the extension.
-
-  // Example filename = dir/foo.jar
-  std::string adjacent_dex_filename(filename);
-  size_t found = adjacent_dex_filename.find_last_of(".");
-  if (found == std::string::npos) {
-    LOG(ERROR) << "No . in filename" << filename;
+  std::string location(StripLocationPrefix(filename, strip_location_prefix));
+  if (location.empty()) {
     return NULL;
   }
-  adjacent_dex_filename.replace(adjacent_dex_filename.begin() + found,
-                                adjacent_dex_filename.end(),
-                                ".dex");
-  // Example adjacent_dex_filename = dir/foo.dex
-  if (OS::FileExists(adjacent_dex_filename.c_str())) {
-    const DexFile* adjacent_dex_file = DexFile::OpenFile(adjacent_dex_filename,
-                                                         filename,
-                                                         strip_location_prefix);
-    if (adjacent_dex_file != NULL) {
-      // We don't verify anything in this case, because we aren't in
-      // the cache and typically the file is in the readonly /system
-      // area, so if something is wrong, there is nothing we can do.
-      return adjacent_dex_file;
-    }
-    return NULL;
-  }
-
-  UniquePtr<char[]> resolved(new char[PATH_MAX]);
-  char* absolute_path = realpath(filename.c_str(), resolved.get());
-  if (absolute_path == NULL) {
-      LOG(ERROR) << "Failed to create absolute path for " << filename
-                 << " when looking for classes.dex";
-      return NULL;
-  }
-  std::string cache_path_tmp(GetArtCacheFilenameOrDie(absolute_path));
-  cache_path_tmp.push_back('@');
-  cache_path_tmp.append(kClassesDex);
-  // Example cache_path_tmp = /data/art-cache/parent@dir@foo.jar@classes.dex
 
   UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(filename));
   if (zip_archive.get() == NULL) {
@@ -218,121 +193,32 @@
     return NULL;
   }
 
-  std::string cache_path(StringPrintf("%s.%08x", cache_path_tmp.c_str(), zip_entry->GetCrc32()));
-  // Example cache_path = /data/art-cache/parent@dir@foo.jar@classes.dex.1a2b3c4d
-
-  bool created = false;
-  while (true) {
-    if (OS::FileExists(cache_path.c_str())) {
-      const DexFile* cached_dex_file = DexFile::OpenFile(cache_path,
-                                                         filename,
-                                                         strip_location_prefix);
-      if (cached_dex_file != NULL) {
-        return cached_dex_file;
-      }
-      if (created) {
-        // We created the dex file with the correct checksum,
-        // there must be something wrong with the file itself.
-        return NULL;
-      }
-    }
-
-    // Try to open the temporary cache file, grabbing an exclusive
-    // lock. If somebody else is working on it, we'll block here until
-    // they complete.  Because we're waiting on an external resource,
-    // we go into native mode.
-    // Note that self can be NULL if we're parsing the bootclasspath
-    // during JNI_CreateJavaVM.
-    Thread* self = Thread::Current();
-    UniquePtr<ScopedThreadStateChange> state_changer;
-    if (self != NULL) {
-      state_changer.reset(new ScopedThreadStateChange(self, Thread::kNative));
-    }
-    UniquePtr<LockedFd> fd(LockedFd::CreateAndLock(cache_path_tmp, 0644));
-    state_changer.reset(NULL);
-    if (fd.get() == NULL) {
-      PLOG(ERROR) << "Failed to lock file '" << cache_path_tmp << "'";
-      return NULL;
-    }
-
-    // Check to see if the fd we opened and locked matches the file in
-    // the filesystem.  If they don't, then somebody else unlinked
-    // ours and created a new file, and we need to use that one
-    // instead.  (If we caught them between the unlink and the create,
-    // we'll get an ENOENT from the file stat.)
-    struct stat fd_stat;
-    int fd_stat_result = fstat(fd->GetFd(), &fd_stat);
-    if (fd_stat_result == -1) {
-      PLOG(ERROR) << "Failed to stat open file '" << cache_path_tmp << "'";
-      return NULL;
-    }
-    struct stat file_stat;
-    int file_stat_result = stat(cache_path_tmp.c_str(), &file_stat);
-    if (file_stat_result == -1 ||
-        fd_stat.st_dev != file_stat.st_dev || fd_stat.st_ino != file_stat.st_ino) {
-      LOG(WARNING) << "our open cache file is stale; sleeping and retrying";
-      usleep(250 * 1000);  // if something is hosed, don't peg machine
-      continue;
-    }
-
-    // We have the correct file open and locked. Extract classes.dex
-    TmpFile tmp_file(cache_path_tmp);
-    UniquePtr<File> file(OS::FileFromFd(cache_path_tmp.c_str(), fd->GetFd()));
-    if (file.get() == NULL) {
-      LOG(ERROR) << "Failed to create file for '" << cache_path_tmp << "'";
-      return NULL;
-    }
-    bool success = zip_entry->Extract(*file);
-    if (!success) {
-      LOG(ERROR) << "Failed to extract classes.dex to '" << cache_path_tmp << "'";
-      return NULL;
-    }
-
-    // TODO: restat and check length against zip_entry->GetUncompressedLength()?
-
-    // Compute checksum and compare to zip. If things look okay, rename from tmp.
-    off_t lseek_result = lseek(fd->GetFd(), 0, SEEK_SET);
-    if (lseek_result == -1) {
-      PLOG(ERROR) << "Failed to seek to start of '" << cache_path_tmp << "'";
-      return NULL;
-    }
-    const size_t kBufSize = 32768;
-    UniquePtr<uint8_t[]> buf(new uint8_t[kBufSize]);
-    if (buf.get() == NULL) {
-      LOG(ERROR) << "Failed to allocate buffer to checksum '" << cache_path_tmp << "'";
-      return NULL;
-    }
-    uint32_t computed_crc = crc32(0L, Z_NULL, 0);
-    while (true) {
-      ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd->GetFd(), buf.get(), kBufSize));
-      if (bytes_read == -1) {
-        PLOG(ERROR) << "Problem computing CRC of '" << cache_path_tmp << "'";
-        return NULL;
-      }
-      if (bytes_read == 0) {
-        break;
-      }
-      computed_crc = crc32(computed_crc, buf.get(), bytes_read);
-    }
-    if (computed_crc != zip_entry->GetCrc32()) {
-      LOG(ERROR) << "Failed to validate checksum for '" << cache_path_tmp << "'";
-      return NULL;
-    }
-    int rename_result = rename(cache_path_tmp.c_str(), cache_path.c_str());
-    if (rename_result == -1) {
-      PLOG(ERROR) << "Failed to install dex cache file '" << cache_path << "'"
-                  << " from '" << cache_path_tmp << "'";
-      unlink(cache_path.c_str());
-    } else {
-      created = true;
-    }
+  uint32_t length = zip_entry->GetUncompressedLength();
+  UniquePtr<MemMap> map(MemMap::MapAnonymous("classes.dex extracted in memory",
+                                             NULL,
+                                             length,
+                                             PROT_READ | PROT_WRITE));
+  if (map.get() == NULL) {
+    LOG(ERROR) << "mmap classes.dex for \"" << filename << "\" failed";
+    return NULL;
   }
-  // NOTREACHED
+
+  // Extract classes.dex
+  bool success = zip_entry->ExtractToMemory(*map.get());
+  if (!success) {
+    LOG(ERROR) << "Failed to extract classes.dex from '" << filename << "' to memory";
+    return NULL;
+  }
+
+  return OpenMemory(location, map.release());
 }
 
-const DexFile* DexFile::OpenMemory(const byte* dex_bytes, size_t length,
-                                   const std::string& location, MemMap* mem_map) {
-  UniquePtr<DexFile> dex_file(new DexFile(dex_bytes, length, location, mem_map));
+const DexFile* DexFile::OpenMemory(const byte* base,
+                                   size_t length,
+                                   const std::string& location,
+                                   MemMap* mem_map) {
+  CHECK_ALIGNED(base, 4); // various dex file structures must be word aligned
+  UniquePtr<DexFile> dex_file(new DexFile(base, length, location, mem_map));
   if (!dex_file->Init()) {
     return NULL;
   } else {
@@ -399,6 +285,7 @@
   method_ids_ = reinterpret_cast<const MethodId*>(b + h->method_ids_off_);
   proto_ids_ = reinterpret_cast<const ProtoId*>(b + h->proto_ids_off_);
   class_defs_ = reinterpret_cast<const ClassDef*>(b + h->class_defs_off_);
+  DCHECK_EQ(length_, header_->file_size_);
 }
 
 bool DexFile::IsMagicValid() {
diff --git a/src/dex_file.h b/src/dex_file.h
index 1356c8c..a0363b0 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -184,6 +184,11 @@
   static const DexFile* Open(const std::string& filename,
                              const std::string& strip_location_prefix);
 
+  // Opens .dex file, backed by existing memory
+  static const DexFile* Open(const uint8_t* base, size_t length, const std::string& location) {
+    return OpenMemory(base, length, location, NULL);
+  }
+
   // Closes a .dex file.
   virtual ~DexFile();
 
@@ -619,14 +624,23 @@
   static const DexFile* OpenZip(const std::string& filename,
                                 const std::string& strip_location_prefix);
 
-  // Opens a .dex file at the given address.
+  // Opens a .dex file at the given address backed by a MemMap
+  static const DexFile* OpenMemory(const std::string& location,
+                                   MemMap* mem_map) {
+    return OpenMemory(mem_map->GetAddress(),
+                      mem_map->GetLength(),
+                      location,
+                      mem_map);
+  }
+
+  // Opens a .dex file at the given address, optionally backed by a MemMap
   static const DexFile* OpenMemory(const byte* dex_file,
                                    size_t length,
                                    const std::string& location,
                                    MemMap* mem_map);
 
-  DexFile(const byte* addr, size_t length, const std::string& location, MemMap* mem_map)
-      : base_(addr),
+  DexFile(const byte* base, size_t length, const std::string& location, MemMap* mem_map)
+      : base_(base),
         length_(length),
         location_(location),
         mem_map_(mem_map),
@@ -639,9 +653,8 @@
         method_ids_(0),
         proto_ids_(0),
         class_defs_(0) {
-    CHECK(addr != NULL) << GetLocation();
-    CHECK_GT(length, 0U) << GetLocation();
-    CHECK(mem_map != NULL) << GetLocation();
+    CHECK(base_ != NULL) << GetLocation();
+    CHECK_GT(length_, 0U) << GetLocation();
   }
 
   // Top-level initializer that calls other Init methods.
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 2f91dcd..342453d 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -1049,6 +1049,10 @@
     if ((start >= end) || (start >= insns_size) || (end > insns_size)) {
       Fail(VERIFY_ERROR_GENERIC) << "bad exception entry: startAddr=" << start
                                  << " endAddr=" << end << " (size=" << insns_size << ")";
+      CHECK(false) << "XXX bdc "
+                   << PrettyMethod(method_)
+                   << "bad exception entry: startAddr=" << start
+                   << " endAddr=" << end << " (size=" << insns_size << ")";
       return false;
     }
     if (!insn_flags_[start].IsOpcode()) {
diff --git a/src/file.h b/src/file.h
index 3353602..babcb8b 100644
--- a/src/file.h
+++ b/src/file.h
@@ -27,11 +27,11 @@
 
   // Get the length of the file. Returns a negative value if the length cannot
   // be determined (e.g. not seekable device).
-  virtual off_t Length() = 0;
+  virtual off64_t Length() = 0;
 
   // Get the current position in the file.
   // Returns a negative value if position cannot be determined.
-  virtual off_t Position() = 0;
+  virtual off64_t Position() = 0;
 
   virtual int Fd() = 0;
 
diff --git a/src/file_linux.cc b/src/file_linux.cc
index 367dbe8..1f4be51 100644
--- a/src/file_linux.cc
+++ b/src/file_linux.cc
@@ -43,21 +43,21 @@
 }
 
 
-off_t LinuxFile::Position() {
+off64_t LinuxFile::Position() {
   DCHECK_GE(fd_, 0);
-  return lseek(fd_, 0, SEEK_CUR);
+  return lseek64(fd_, 0, SEEK_CUR);
 }
 
 
-off_t LinuxFile::Length() {
+off64_t LinuxFile::Length() {
   DCHECK_GE(fd_, 0);
-  off_t position = lseek(fd_, 0, SEEK_CUR);
+  off64_t position = lseek64(fd_, 0, SEEK_CUR);
   if (position < 0) {
     // The file is not capable of seeking. Return an error.
     return -1;
   }
-  off_t result = lseek(fd_, 0, SEEK_END);
-  lseek(fd_, position, SEEK_SET);
+  off64_t result = lseek64(fd_, 0, SEEK_END);
+  lseek64(fd_, position, SEEK_SET);
   return result;
 }
 
diff --git a/src/file_linux.h b/src/file_linux.h
index 3d381d5..51605e2 100644
--- a/src/file_linux.h
+++ b/src/file_linux.h
@@ -19,8 +19,8 @@
   virtual int64_t Read(void* buffer, int64_t num_bytes);
   virtual int64_t Write(const void* buffer, int64_t num_bytes);
 
-  virtual off_t Length();
-  virtual off_t Position();
+  virtual off64_t Length();
+  virtual off64_t Position();
 
   virtual int Fd() {
     return fd_;
diff --git a/src/heap_bitmap.cc b/src/heap_bitmap.cc
index 4bd191a..2adeedc 100644
--- a/src/heap_bitmap.cc
+++ b/src/heap_bitmap.cc
@@ -37,7 +37,7 @@
 bool HeapBitmap::Init(const char* name, const byte* base, size_t max_size) {
   CHECK(base != NULL);
   size_t length = HB_OFFSET_TO_INDEX(max_size) * kWordSize;
-  mem_map_.reset(MemMap::Map(name, NULL, length, PROT_READ | PROT_WRITE));
+  mem_map_.reset(MemMap::MapAnonymous(name, NULL, length, PROT_READ | PROT_WRITE));
   if (mem_map_.get() == NULL) {
     return false;
   }
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 8a03392..f6d144e 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -84,7 +84,7 @@
   size_t size = source_space_->Size();
   int prot = PROT_READ | PROT_WRITE;
   size_t length = RoundUp(size, kPageSize);
-  image_.reset(MemMap::Map("image-writer-image", NULL, length, prot));
+  image_.reset(MemMap::MapAnonymous("image-writer-image", NULL, length, prot));
   if (image_.get() == NULL) {
     LOG(ERROR) << "Failed to allocate memory for image file generation";
     return false;
diff --git a/src/mark_stack.cc b/src/mark_stack.cc
index a35fa2d..53a342b 100644
--- a/src/mark_stack.cc
+++ b/src/mark_stack.cc
@@ -18,7 +18,7 @@
 
 void MarkStack::Init() {
   size_t length = 64 * MB;
-  mem_map_.reset(MemMap::Map("dalvik-mark-stack", NULL, length, PROT_READ | PROT_WRITE));
+  mem_map_.reset(MemMap::MapAnonymous("dalvik-mark-stack", NULL, length, PROT_READ | PROT_WRITE));
   CHECK(mem_map_.get() != NULL) << "MemMap::Map() failed; aborting";
   byte* addr = mem_map_->GetAddress();
   base_ = reinterpret_cast<const Object**>(addr);
diff --git a/src/mem_map.cc b/src/mem_map.cc
index c5858c1..09391df 100644
--- a/src/mem_map.cc
+++ b/src/mem_map.cc
@@ -103,7 +103,7 @@
 #endif
 }
 
-MemMap* MemMap::Map(const char* name, byte* addr, size_t length, int prot) {
+MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t length, int prot) {
   CHECK_NE(0U, length);
   CHECK_NE(0, prot);
   size_t page_aligned_size = RoundUp(length, kPageSize);
@@ -129,7 +129,7 @@
   return new MemMap(actual, length, actual, page_aligned_size);
 }
 
-MemMap* MemMap::Map(byte* addr, size_t length, int prot, int flags, int fd, off_t start) {
+MemMap* MemMap::MapFileAtAddress(byte* addr, size_t length, int prot, int flags, int fd, off_t start) {
   CHECK_NE(0U, length);
   CHECK_NE(0, prot);
   CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE));
diff --git a/src/mem_map.h b/src/mem_map.h
index fa3904d..43e1cfd 100644
--- a/src/mem_map.h
+++ b/src/mem_map.h
@@ -36,14 +36,14 @@
   // a name.
   //
   // On success, returns returns a MemMap instance.  On failure, returns a NULL;
-  static MemMap* Map(const char* ashmem_name, byte* addr, size_t length, int prot);
+  static MemMap* MapAnonymous(const char* ashmem_name, byte* addr, size_t length, int prot);
 
   // Map part of a file, taking care of non-page aligned offsets.  The
   // "start" offset is absolute, not relative.
   //
   // On success, returns returns a MemMap instance.  On failure, returns a NULL;
-  static MemMap* Map(size_t length, int prot, int flags, int fd, off_t start) {
-    return Map(NULL, length, prot, flags, fd, start);
+  static MemMap* MapFile(size_t length, int prot, int flags, int fd, off_t start) {
+    return MapFileAtAddress(NULL, length, prot, flags, fd, start);
   }
 
   // Map part of a file, taking care of non-page aligned offsets.  The
@@ -51,7 +51,8 @@
   // requesting a specific address for the base of the mapping.
   //
   // On success, returns returns a MemMap instance.  On failure, returns a NULL;
-  static MemMap* Map(byte* addr, size_t length, int prot, int flags, int fd, off_t start);
+  static MemMap* MapFileAtAddress(
+      byte* addr, size_t length, int prot, int flags, int fd, off_t start);
 
   // Releases the memory mapping
   ~MemMap();
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 472a20c..c37c7a6 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -54,12 +54,13 @@
     return false;
   }
 
-  UniquePtr<MemMap> map(MemMap::Map(requested_base,
-                                    file->Length(),
-                                    PROT_READ,
-                                    MAP_PRIVATE | ((requested_base != NULL) ? MAP_FIXED : 0),
-                                    file->Fd(),
-                                    0));
+  int flags = MAP_PRIVATE | ((requested_base != NULL) ? MAP_FIXED : 0);
+  UniquePtr<MemMap> map(MemMap::MapFileAtAddress(requested_base,
+                                                 file->Length(),
+                                                 PROT_READ,
+                                                 flags,
+                                                 file->Fd(),
+                                                 0));
   if (map.get() == NULL) {
     LOG(WARNING) << "Failed to map oat file " << filename;
     return false;
@@ -67,7 +68,7 @@
   CHECK(requested_base == 0 || requested_base == map->GetAddress()) << map->GetAddress();
   DCHECK_EQ(0, memcmp(&oat_header, map->GetAddress(), sizeof(OatHeader)));
 
-  off_t code_offset = oat_header.GetExecutableOffset();
+  off64_t code_offset = oat_header.GetExecutableOffset();
   if (code_offset < file->Length()) {
     byte* code_address = map->GetAddress() + code_offset;
     size_t code_length = file->Length() - code_offset;
@@ -98,6 +99,14 @@
     oat += sizeof(dex_file_checksum);
     CHECK_LT(oat, map->GetLimit());
 
+    uint32_t dex_file_offset = *reinterpret_cast<const uint32_t*>(oat);
+    CHECK_GT(dex_file_offset, 0U);
+    CHECK_LT(dex_file_offset, static_cast<uint32_t>(file->Length()));
+    oat += sizeof(dex_file_offset);
+    CHECK_LT(oat, map->GetLimit());
+
+    uint8_t* dex_file_pointer = map->GetAddress() + dex_file_offset;
+
     uint32_t classes_offset = *reinterpret_cast<const uint32_t*>(oat);
     CHECK_GT(classes_offset, 0U);
     CHECK_LT(classes_offset, static_cast<uint32_t>(file->Length()));
@@ -109,6 +118,7 @@
     oat_dex_files_[dex_file_location] = new OatDexFile(this,
                                                        dex_file_location,
                                                        dex_file_checksum,
+                                                       dex_file_pointer,
                                                        classes_pointer);
   }
 
@@ -153,14 +163,21 @@
 OatFile::OatDexFile::OatDexFile(const OatFile* oat_file,
                                 std::string dex_file_location,
                                 uint32_t dex_file_checksum,
+                                byte* dex_file_pointer,
                                 uint32_t* classes_pointer)
     : oat_file_(oat_file),
       dex_file_location_(dex_file_location),
       dex_file_checksum_(dex_file_checksum),
+      dex_file_pointer_(dex_file_pointer),
       classes_pointer_(classes_pointer) {}
 
 OatFile::OatDexFile::~OatDexFile() {}
 
+const DexFile* OatFile::OatDexFile::OpenDexFile() const {
+  size_t length = reinterpret_cast<const DexFile::Header*>(dex_file_pointer_)->file_size_;
+  return DexFile::Open(dex_file_pointer_, length, dex_file_location_);
+}
+
 const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
   uint32_t methods_offset = classes_pointer_[class_def_index];
   const byte* methods_pointer = oat_file_->GetBase() + methods_offset;
diff --git a/src/oat_file.h b/src/oat_file.h
index 7bad2a1..a4d7534 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -132,6 +132,7 @@
 
   class OatDexFile {
    public:
+    const DexFile* OpenDexFile() const;
     const OatClass* GetOatClass(uint32_t class_def_index) const;
 
     const std::string& GetDexFileLocation() const {
@@ -147,11 +148,13 @@
     OatDexFile(const OatFile* oat_file,
                std::string dex_file_location,
                uint32_t dex_file_checksum,
+               byte* dex_file_pointer,
                uint32_t* classes_pointer);
 
     const OatFile* oat_file_;
     std::string dex_file_location_;
     uint32_t dex_file_checksum_;
+    const byte* dex_file_pointer_;
     const uint32_t* classes_pointer_;
 
     friend class OatFile;
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 32ba4b1..3ab2fb9 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -29,6 +29,7 @@
 
   size_t offset = InitOatHeader();
   offset = InitOatDexFiles(offset);
+  offset = InitDexFiles(offset);
   offset = InitOatClasses(offset);
   offset = InitOatMethods(offset);
   offset = InitOatCode(offset);
@@ -64,6 +65,21 @@
   return offset;
 }
 
+size_t OatWriter::InitDexFiles(size_t offset) {
+  // calculate the offsets within OatDexFiles to the DexFiles
+  for (size_t i = 0; i != dex_files_->size(); ++i) {
+    // dex files are required to be 4 byte aligned
+    offset = RoundUp(offset, 4);
+
+    // set offset in OatDexFile to DexFile
+    oat_dex_files_[i]->dex_file_offset_ = offset;
+
+    const DexFile* dex_file = (*dex_files_)[i];
+    offset += dex_file->GetHeader().file_size_;
+  }
+  return offset;
+}
+
 size_t OatWriter::InitOatClasses(size_t offset) {
   // create the OatClasses
   // calculate the offsets within OatDexFiles to OatClasses
@@ -305,7 +321,7 @@
 }
 
 #define DCHECK_CODE_OFFSET() \
-  DCHECK_EQ(static_cast<off_t>(code_offset), lseek(file->Fd(), 0, SEEK_CUR))
+  DCHECK_EQ(static_cast<off64_t>(code_offset), lseek64(file->Fd(), 0, SEEK_CUR))
 
 bool OatWriter::Write(File* file) {
   if (!file->WriteFully(oat_header_, sizeof(*oat_header_))) {
@@ -340,6 +356,21 @@
       return false;
     }
   }
+  for (size_t i = 0; i != oat_dex_files_.size(); ++i) {
+    uint32_t expected_offset = oat_dex_files_[i]->dex_file_offset_;
+    off64_t actual_offset = lseek64(file->Fd(), expected_offset, SEEK_SET);
+    if (static_cast<uint32_t>(actual_offset) != expected_offset) {
+      const DexFile* dex_file = (*dex_files_)[i];
+      PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
+                  << " Expected: " << expected_offset << " File: " << dex_file->GetLocation();
+      return false;
+    }
+    const DexFile* dex_file = (*dex_files_)[i];
+    if (!file->WriteFully(&dex_file->GetHeader(), dex_file->GetHeader().file_size_)) {
+      PLOG(ERROR) << "Failed to write dex file " << dex_file->GetLocation() << " to " << file->name();
+      return false;
+    }
+  }
   for (size_t i = 0; i != oat_classes_.size(); ++i) {
     if (!oat_classes_[i]->Write(file)) {
       PLOG(ERROR) << "Failed to write oat classes information to " << file->name();
@@ -357,7 +388,7 @@
 
 size_t OatWriter::WriteCode(File* file) {
   uint32_t code_offset = oat_header_->GetExecutableOffset();
-  off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
+  off64_t new_offset = lseek64(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
   if (static_cast<uint32_t>(new_offset) != code_offset) {
     PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
                 << " Expected: " << code_offset << " File: " << file->name();
@@ -458,7 +489,7 @@
     uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset);
     uint32_t aligned_code_delta = aligned_code_offset - code_offset;
     if (aligned_code_delta != 0) {
-      off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
+      off64_t new_offset = lseek64(file->Fd(), aligned_code_delta, SEEK_CUR);
       if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
         PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
                     << " Expected: " << aligned_code_offset << " File: " << file->name();
@@ -564,7 +595,7 @@
                                                              compiler_->GetInstructionSet());
     uint32_t aligned_code_delta = aligned_code_offset - code_offset;
     if (aligned_code_delta != 0) {
-      off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
+      off64_t new_offset = lseek64(file->Fd(), aligned_code_delta, SEEK_CUR);
       if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
         PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
                     << " Expected: " << aligned_code_offset;
@@ -605,6 +636,7 @@
   dex_file_location_size_ = location.size();
   dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data());
   dex_file_checksum_ = dex_file.GetHeader().checksum_;
+  dex_file_offset_ = 0;
   classes_offset_ = 0;
 }
 
@@ -612,6 +644,7 @@
   return sizeof(dex_file_location_size_)
           + dex_file_location_size_
           + sizeof(dex_file_checksum_)
+          + sizeof(dex_file_offset_)
           + sizeof(classes_offset_);
 }
 
@@ -619,6 +652,7 @@
   oat_header.UpdateChecksum(&dex_file_location_size_, sizeof(dex_file_location_size_));
   oat_header.UpdateChecksum(dex_file_location_data_, dex_file_location_size_);
   oat_header.UpdateChecksum(&dex_file_checksum_, sizeof(dex_file_checksum_));
+  oat_header.UpdateChecksum(&dex_file_offset_, sizeof(dex_file_offset_));
   oat_header.UpdateChecksum(&classes_offset_, sizeof(classes_offset_));
 }
 
@@ -635,6 +669,10 @@
     PLOG(ERROR) << "Failed to write dex file checksum to " << file->name();
     return false;
   }
+  if (!file->WriteFully(&dex_file_offset_, sizeof(dex_file_offset_))) {
+    PLOG(ERROR) << "Failed to write dex file offset to " << file->name();
+    return false;
+  }
   if (!file->WriteFully(&classes_offset_, sizeof(classes_offset_))) {
     PLOG(ERROR) << "Failed to write classes offset to " << file->name();
     return false;
diff --git a/src/oat_writer.h b/src/oat_writer.h
index 97cdb50..7d454a7 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -20,11 +20,16 @@
 
 // OatHeader         fixed length with count of D OatDexFiles
 //
-// OatDexFile[0]     each fixed length with offset to variable sized OatClasses
+// OatDexFile[0]     one variable sized OatDexFile with offsets to Dex and OatClasses
 // OatDexFile[1]
 // ...
 // OatDexFile[D]
 //
+// Dex[0]            one variable sized DexFile for each OatDexFile.
+// Dex[1]            these are literal copies of the input .dex files.
+// ...
+// Dex[D]
+//
 // OatClasses[0]     one variable sized OatClasses for each OatDexFile
 // OatClasses[1]     contains DexFile::NumClassDefs offsets to OatMethods for each ClassDef
 // ...
@@ -60,6 +65,7 @@
 
   size_t InitOatHeader();
   size_t InitOatDexFiles(size_t offset);
+  size_t InitDexFiles(size_t offset);
   size_t InitOatClasses(size_t offset);
   size_t InitOatMethods(size_t offset);
   size_t InitOatCode(size_t offset);
@@ -100,6 +106,7 @@
     uint32_t dex_file_location_size_;
     const uint8_t* dex_file_location_data_;
     uint32_t dex_file_checksum_;
+    uint32_t dex_file_offset_;
     uint32_t classes_offset_;
 
    private:
diff --git a/src/oatopt.cc b/src/oatopt.cc
index 314b7ee..5862431 100644
--- a/src/oatopt.cc
+++ b/src/oatopt.cc
@@ -29,7 +29,7 @@
     }
 
     UniquePtr<File> file(OS::FileFromFd("oatopt cache file descriptor", cache_fd));
-    bool success = zip_entry->Extract(*file);
+    bool success = zip_entry->ExtractToFile(*file);
     if (!success) {
       LOG(ERROR) << "Failed to extract classes.dex from " << zip_name;
       return -1;
diff --git a/src/space.cc b/src/space.cc
index 14731f1..053d2df 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -74,7 +74,7 @@
   }
   size_t length = RoundUp(maximum_size, kPageSize);
   int prot = PROT_READ | PROT_WRITE;
-  UniquePtr<MemMap> mem_map(MemMap::Map(name_.c_str(), requested_base, length, prot));
+  UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(name_.c_str(), requested_base, length, prot));
   if (mem_map.get() == NULL) {
     LOG(WARNING) << "Failed to allocate " << length << " bytes for space: " << name_;
     return false;
@@ -114,13 +114,13 @@
     LOG(WARNING) << "Invalid image header " << image_file_name;
     return false;
   }
-  UniquePtr<MemMap> map(MemMap::Map(image_header.GetImageBaseAddr(),
-                                    file->Length(),
-                                    // TODO: selectively PROT_EXEC an image subset containing stubs
-                                    PROT_READ | PROT_WRITE | PROT_EXEC,
-                                    MAP_PRIVATE | MAP_FIXED,
-                                    file->Fd(),
-                                    0));
+  UniquePtr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBaseAddr(),
+                                                 file->Length(),
+                                                 // TODO: selectively PROT_EXEC stubs
+                                                 PROT_READ | PROT_WRITE | PROT_EXEC,
+                                                 MAP_PRIVATE | MAP_FIXED,
+                                                 file->Fd(),
+                                                 0));
   if (map.get() == NULL) {
     LOG(WARNING) << "Failed to map " << image_file_name;
     return false;
diff --git a/src/utils.h b/src/utils.h
index 22afd5d..606f35d 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -35,14 +35,14 @@
 
 template<int n, typename T>
 static inline bool IsAligned(T* x) {
-  return IsAligned<n>(reinterpret_cast<uintptr_t>(x));
+  return IsAligned<n>(reinterpret_cast<const uintptr_t>(x));
 }
 
 #define CHECK_ALIGNED(value, alignment) \
-  CHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<void*>(value)
+  CHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<const void*>(value)
 
 #define DCHECK_ALIGNED(value, alignment) \
-  DCHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<void*>(value)
+  DCHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<const void*>(value)
 
 // Check whether an N-bit two's-complement representation can hold value.
 static inline bool IsInt(int N, word value) {
diff --git a/src/zip_archive.cc b/src/zip_archive.cc
index 69bc85b..666da23 100644
--- a/src/zip_archive.cc
+++ b/src/zip_archive.cc
@@ -120,21 +120,21 @@
   return data_offset;
 }
 
-static bool CopyFdToFile(File& file, int in, size_t count) {
+static bool CopyFdToMemory(MemMap& mem_map, int in, size_t count) {
+  uint8_t* dst = mem_map.GetAddress();
   std::vector<uint8_t> buf(kBufSize);
   while (count != 0) {
     size_t bytes_to_read = (count > kBufSize) ? kBufSize : count;
     ssize_t actual = TEMP_FAILURE_RETRY(read(in, &buf[0], bytes_to_read));
     if (actual != static_cast<ssize_t>(bytes_to_read)) {
-      PLOG(WARNING) << "Zip: short read writing to file " << file.name();
+      PLOG(WARNING) << "Zip: short read";
       return false;
     }
-    if (!file.WriteFully(&buf[0], bytes_to_read)) {
-      PLOG(WARNING) << "Zip: failed to write to file " << file.name();
-      return false;
-    }
+    memcpy(dst, &buf[0], bytes_to_read);
+    dst += bytes_to_read;
     count -= bytes_to_read;
   }
+  DCHECK_EQ(dst, mem_map.GetLimit());
   return true;
 }
 
@@ -164,11 +164,12 @@
   z_stream zstream_;
 };
 
-static bool InflateToFile(File& out, int in, size_t uncompressed_length, size_t compressed_length) {
+static bool InflateToMemory(MemMap& mem_map, int in, size_t uncompressed_length, size_t compressed_length) {
+  uint8_t* dst = mem_map.GetAddress();
   UniquePtr<uint8_t[]> read_buf(new uint8_t[kBufSize]);
   UniquePtr<uint8_t[]> write_buf(new uint8_t[kBufSize]);
   if (read_buf.get() == NULL || write_buf.get() == NULL) {
-    LOG(WARNING) << "Zip: failed to alloctate buffer to inflate to file " << out.name();
+    LOG(WARNING) << "Zip: failed to allocate buffer to inflate";
     return false;
   }
 
@@ -218,10 +219,8 @@
     if (zstream->Get().avail_out == 0 ||
         (zerr == Z_STREAM_END && zstream->Get().avail_out != kBufSize)) {
       size_t bytes_to_write = zstream->Get().next_out - write_buf.get();
-      if (!out.WriteFully(write_buf.get(), bytes_to_write)) {
-        PLOG(WARNING) << "Zip: failed to write to file " << out.name();
-        return false;
-      }
+      memcpy(dst, write_buf.get(), bytes_to_write);
+      dst += bytes_to_write;
       zstream->Get().next_out = write_buf.get();
       zstream->Get().avail_out = kBufSize;
     }
@@ -236,10 +235,28 @@
     return false;
   }
 
+  DCHECK_EQ(dst, mem_map.GetLimit());
   return true;
 }
 
-bool ZipEntry::Extract(File& file) {
+bool ZipEntry::ExtractToFile(File& file) {
+  uint32_t length = GetUncompressedLength();
+  int result = TEMP_FAILURE_RETRY(ftruncate(file.Fd(), length));
+  if (result == -1) {
+    PLOG(WARNING) << "Zip: failed to ftruncate " << file.name() << " to length " << length;
+    return false;
+  }
+
+  UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ | PROT_WRITE, MAP_SHARED, file.Fd(), 0));
+  if (map.get() == NULL) {
+    LOG(WARNING) << "Zip: failed to mmap space for " << file.name();
+    return false;
+  }
+
+  return ExtractToMemory(*map.get());
+}
+
+bool ZipEntry::ExtractToMemory(MemMap& mem_map) {
   off_t data_offset = GetDataOffset();
   if (data_offset == -1) {
     LOG(WARNING) << "Zip: data_offset=" << data_offset;
@@ -254,9 +271,9 @@
   // for uncompressed data).
   switch (GetCompressionMethod()) {
     case kCompressStored:
-      return CopyFdToFile(file, zip_archive_->fd_, GetUncompressedLength());
+      return CopyFdToMemory(mem_map, zip_archive_->fd_, GetUncompressedLength());
     case kCompressDeflated:
-      return InflateToFile(file, zip_archive_->fd_, GetUncompressedLength(), GetCompressedLength());
+      return InflateToMemory(mem_map, zip_archive_->fd_, GetUncompressedLength(), GetCompressedLength());
     default:
       LOG(WARNING) << "Zip: unknown compression method " << std::hex << GetCompressionMethod();
       return false;
@@ -395,7 +412,7 @@
   }
 
   // It all looks good.  Create a mapping for the CD.
-  dir_map_.reset(MemMap::Map(dir_size, PROT_READ, MAP_SHARED, fd_, dir_offset));
+  dir_map_.reset(MemMap::MapFile(dir_size, PROT_READ, MAP_SHARED, fd_, dir_offset));
   if (dir_map_.get() == NULL) {
     return false;
   }
diff --git a/src/zip_archive.h b/src/zip_archive.h
index 013a3da..e367773 100644
--- a/src/zip_archive.h
+++ b/src/zip_archive.h
@@ -38,9 +38,10 @@
 
 class ZipEntry {
  public:
-  // Uncompress an entry, in its entirety, to an open file descriptor.
-  bool Extract(File& file);
+  bool ExtractToFile(File& file);
+  bool ExtractToMemory(MemMap& mem_map);
 
+  uint32_t GetUncompressedLength();
   uint32_t GetCrc32();
 
  private:
@@ -58,8 +59,6 @@
 
   uint32_t GetCompressedLength();
 
-  uint32_t GetUncompressedLength();
-
   // returns -1 on error
   off_t GetDataOffset();
 
diff --git a/src/zip_archive_test.cc b/src/zip_archive_test.cc
index 051f096..747c219 100644
--- a/src/zip_archive_test.cc
+++ b/src/zip_archive_test.cc
@@ -24,7 +24,7 @@
   ASSERT_NE(-1, tmp.GetFd());
   UniquePtr<File> file(OS::FileFromFd(tmp.GetFilename(), tmp.GetFd()));
   ASSERT_TRUE(file.get() != NULL);
-  bool success = zip_entry->Extract(*file);
+  bool success = zip_entry->ExtractToFile(*file);
   ASSERT_TRUE(success);
   close(tmp.GetFd());