Merge "Change IsMethodTracingActive to GetMethodTracingMode for art." into dalvik-dev
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
index 7831cf6..90cec75 100644
--- a/compiler/dex/portable/mir_to_gbc.cc
+++ b/compiler/dex/portable/mir_to_gbc.cc
@@ -1972,7 +1972,7 @@
 
     ::llvm::OwningPtr< ::llvm::tool_output_file> out_file(
         new ::llvm::tool_output_file(fname.c_str(), errmsg,
-                                   ::llvm::raw_fd_ostream::F_Binary));
+                                   ::llvm::sys::fs::F_Binary));
 
     if (!errmsg.empty()) {
       LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 106ef9a..60bc3cc 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -85,6 +85,8 @@
     ImageHeader image_header;
     file->ReadFully(&image_header, sizeof(image_header));
     ASSERT_TRUE(image_header.IsValid());
+    ASSERT_GE(image_header.GetImageBitmapOffset(), sizeof(image_header));
+    ASSERT_NE(0U, image_header.GetImageBitmapSize());
 
     gc::Heap* heap = Runtime::Current()->GetHeap();
     ASSERT_EQ(1U, heap->GetContinuousSpaces().size());
@@ -136,6 +138,7 @@
   ASSERT_TRUE(heap->GetContinuousSpaces()[1]->IsDlMallocSpace());
 
   gc::space::ImageSpace* image_space = heap->GetImageSpace();
+  image_space->VerifyImageAllocations();
   byte* image_begin = image_space->Begin();
   byte* image_end = image_space->End();
   CHECK_EQ(requested_image_base, reinterpret_cast<uintptr_t>(image_begin));
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 548ea9e..d1859e6 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -29,6 +29,7 @@
 #include "elf_writer.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/accounting/heap_bitmap.h"
+#include "gc/accounting/space_bitmap-inl.h"
 #include "gc/heap.h"
 #include "gc/space/large_object_space.h"
 #include "gc/space/space-inl.h"
@@ -136,9 +137,12 @@
   CalculateNewObjectOffsets(oat_loaded_size, oat_data_offset);
   CopyAndFixupObjects();
   PatchOatCodeAndMethods();
+  // Record allocations into the image bitmap.
+  RecordImageAllocations();
   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
 
   UniquePtr<File> image_file(OS::CreateEmptyFile(image_filename.c_str()));
+  ImageHeader* image_header = reinterpret_cast<ImageHeader*>(image_->Begin());
   if (image_file.get() == NULL) {
     LOG(ERROR) << "Failed to open image file " << image_filename;
     return false;
@@ -147,14 +151,37 @@
     PLOG(ERROR) << "Failed to make image file world readable: " << image_filename;
     return EXIT_FAILURE;
   }
-  bool success = image_file->WriteFully(image_->Begin(), image_end_);
-  if (!success) {
+
+  // Write out the image.
+  CHECK_EQ(image_end_, image_header->GetImageSize());
+  if (!image_file->WriteFully(image_->Begin(), image_end_)) {
     PLOG(ERROR) << "Failed to write image file " << image_filename;
     return false;
   }
+
+  // Write out the image bitmap at the page aligned start of the image end.
+  CHECK_ALIGNED(image_header->GetImageBitmapOffset(), kPageSize);
+  if (!image_file->Write(reinterpret_cast<char*>(image_bitmap_->Begin()),
+                         image_header->GetImageBitmapSize(),
+                         image_header->GetImageBitmapOffset())) {
+    PLOG(ERROR) << "Failed to write image file " << image_filename;
+    return false;
+  }
+
   return true;
 }
 
+void ImageWriter::RecordImageAllocations() {
+  uint64_t start_time = NanoTime();
+  CHECK(image_bitmap_.get() != nullptr);
+  for (const auto& it : offsets_) {
+    mirror::Object* obj = reinterpret_cast<mirror::Object*>(image_->Begin() + it.second);
+    DCHECK_ALIGNED(obj, kObjectAlignment);
+    image_bitmap_->Set(obj);
+  }
+  LOG(INFO) << "RecordImageAllocations took " << PrettyDuration(NanoTime() - start_time);
+}
+
 bool ImageWriter::AllocMemory() {
   size_t size = 0;
   for (const auto& space : Runtime::Current()->GetHeap()->GetContinuousSpaces()) {
@@ -388,7 +415,7 @@
   DCHECK(!spaces.empty());
   DCHECK_EQ(0U, image_end_);
 
-  // leave space for the header, but do not write it yet, we need to
+  // Leave space for the header, but do not write it yet, we need to
   // know where image_roots is going to end up
   image_end_ += RoundUp(sizeof(ImageHeader), 8);  // 64-bit-alignment
 
@@ -406,13 +433,20 @@
     self->EndAssertNoThreadSuspension(old);
   }
 
+  // Create the image bitmap.
+  image_bitmap_.reset(gc::accounting::SpaceBitmap::Create("image bitmap", image_->Begin(),
+                                                          image_end_));
   const byte* oat_file_begin = image_begin_ + RoundUp(image_end_, kPageSize);
   const byte* oat_file_end = oat_file_begin + oat_loaded_size;
   oat_data_begin_ = oat_file_begin + oat_data_offset;
   const byte* oat_data_end = oat_data_begin_ + oat_file_->Size();
 
-  // return to write header at start of image with future location of image_roots
+  // Return to write header at start of image with future location of image_roots. At this point,
+  // image_end_ is the size of the image (excluding bitmaps).
   ImageHeader image_header(reinterpret_cast<uint32_t>(image_begin_),
+                           static_cast<uint32_t>(image_end_),
+                           RoundUp(image_end_, kPageSize),
+                           image_bitmap_->Size(),
                            reinterpret_cast<uint32_t>(GetImageAddress(image_roots.get())),
                            oat_file_->GetOatHeader().GetChecksum(),
                            reinterpret_cast<uint32_t>(oat_file_begin),
diff --git a/compiler/image_writer.h b/compiler/image_writer.h
index 6a126b8..0d85f36 100644
--- a/compiler/image_writer.h
+++ b/compiler/image_writer.h
@@ -58,7 +58,10 @@
  private:
   bool AllocMemory();
 
-  // we use the lock word to store the offset of the object in the image
+  // Mark the objects defined in this space in the given live bitmap.
+  void RecordImageAllocations() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // We use the lock word to store the offset of the object in the image.
   void AssignImageOffset(mirror::Object* object)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(object != NULL);
@@ -194,6 +197,9 @@
   // Beginning target oat address for the pointers from the output image to its oat file.
   const byte* oat_data_begin_;
 
+  // Image bitmap which lets us know where the objects inside of the image reside.
+  UniquePtr<gc::accounting::SpaceBitmap> image_bitmap_;
+
   // Offset from oat_data_begin_ to the stubs.
   uint32_t interpreter_to_interpreter_bridge_offset_;
   uint32_t interpreter_to_compiled_code_bridge_offset_;
diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc
index aa439cc..139100b 100644
--- a/compiler/llvm/llvm_compilation_unit.cc
+++ b/compiler/llvm/llvm_compilation_unit.cc
@@ -214,7 +214,6 @@
   ::llvm::TargetOptions target_options;
   target_options.FloatABIType = ::llvm::FloatABI::Soft;
   target_options.NoFramePointerElim = true;
-  target_options.NoFramePointerElimNonLeaf = true;
   target_options.UseSoftFloat = false;
   target_options.EnableFastISel = false;
 
@@ -258,7 +257,7 @@
 
     ::llvm::OwningPtr< ::llvm::tool_output_file> out_file(
       new ::llvm::tool_output_file(bitcode_filename_.c_str(), errmsg,
-                                 ::llvm::raw_fd_ostream::F_Binary));
+                                 ::llvm::sys::fs::F_Binary));
 
 
     if (!errmsg.empty()) {
@@ -278,7 +277,6 @@
   // pm_builder.Inliner = ::llvm::createAlwaysInlinerPass();
   // pm_builder.Inliner = ::llvm::createPartialInliningPass();
   pm_builder.OptLevel = 3;
-  pm_builder.DisableSimplifyLibCalls = 1;
   pm_builder.DisableUnitAtATime = 1;
   pm_builder.populateFunctionPassManager(fpm);
   pm_builder.populateModulePassManager(pm);
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 0227381..d683c8e 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -675,6 +675,9 @@
 
     os << "IMAGE BEGIN: " << reinterpret_cast<void*>(image_header_.GetImageBegin()) << "\n\n";
 
+    os << "IMAGE BITMAP OFFSET: " << reinterpret_cast<void*>(image_header_.GetImageBitmapOffset())
+       << " SIZE: " << reinterpret_cast<void*>(image_header_.GetImageBitmapSize()) << "\n\n";
+
     os << "OAT CHECKSUM: " << StringPrintf("0x%08x\n\n", image_header_.GetOatChecksum());
 
     os << "OAT FILE BEGIN:" << reinterpret_cast<void*>(image_header_.GetOatFileBegin()) << "\n\n";
diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc
index 702e162..63b24ff 100644
--- a/runtime/gc/accounting/space_bitmap.cc
+++ b/runtime/gc/accounting/space_bitmap.cc
@@ -45,11 +45,19 @@
 }
 
 void SpaceSetMap::Walk(SpaceBitmap::Callback* callback, void* arg) {
-  for (Objects::iterator it = contained_.begin(); it != contained_.end(); ++it) {
-    callback(const_cast<mirror::Object*>(*it), arg);
+  for (const mirror::Object* obj : contained_) {
+    callback(const_cast<mirror::Object*>(obj), arg);
   }
 }
 
+SpaceBitmap* SpaceBitmap::CreateFromMemMap(const std::string& name, MemMap* mem_map,
+                                           byte* heap_begin, size_t heap_capacity) {
+  CHECK(mem_map != nullptr);
+  word* bitmap_begin = reinterpret_cast<word*>(mem_map->Begin());
+  size_t bitmap_size = OffsetToIndex(RoundUp(heap_capacity, kAlignment * kBitsPerWord)) * kWordSize;
+  return new SpaceBitmap(name, mem_map, bitmap_begin, bitmap_size, heap_begin);
+}
+
 SpaceBitmap* SpaceBitmap::Create(const std::string& name, byte* heap_begin, size_t heap_capacity) {
   CHECK(heap_begin != NULL);
   // Round up since heap_capacity is not necessarily a multiple of kAlignment * kBitsPerWord.
@@ -59,8 +67,7 @@
     LOG(ERROR) << "Failed to allocate bitmap " << name;
     return NULL;
   }
-  word* bitmap_begin = reinterpret_cast<word*>(mem_map->Begin());
-  return new SpaceBitmap(name, mem_map.release(), bitmap_begin, bitmap_size, heap_begin);
+  return CreateFromMemMap(name, mem_map.release(), heap_begin, heap_capacity);
 }
 
 // Clean up any resources associated with the bitmap.
@@ -74,14 +81,11 @@
   }
   // Not sure if doing this trim is necessary, since nothing past the end of the heap capacity
   // should be marked.
-  // TODO: Fix this code is, it broken and causes rare heap corruption!
-  // mem_map_->Trim(reinterpret_cast<byte*>(heap_begin_ + bitmap_size_));
 }
 
 void SpaceBitmap::Clear() {
   if (bitmap_begin_ != NULL) {
-    // This returns the memory to the system.  Successive page faults
-    // will return zeroed memory.
+    // This returns the memory to the system.  Successive page faults will return zeroed memory.
     int result = madvise(bitmap_begin_, bitmap_size_, MADV_DONTNEED);
     if (result == -1) {
       PLOG(FATAL) << "madvise failed";
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index 26ab1de..f975692 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -48,10 +48,16 @@
 
   typedef void SweepCallback(size_t ptr_count, mirror::Object** ptrs, void* arg);
 
-  // Initialize a HeapBitmap so that it points to a bitmap large enough to cover a heap at
+  // Initialize a space bitmap so that it points to a bitmap large enough to cover a heap at
   // heap_begin of heap_capacity bytes, where objects are guaranteed to be kAlignment-aligned.
   static SpaceBitmap* Create(const std::string& name, byte* heap_begin, size_t heap_capacity);
 
+  // Initialize a space bitmap using the provided mem_map as the live bits. Takes ownership of the
+  // mem map. The address range covered starts at heap_begin and is of size equal to heap_capacity.
+  // Objects are kAlignement-aligned.
+  static SpaceBitmap* CreateFromMemMap(const std::string& name, MemMap* mem_map,
+                                       byte* heap_begin, size_t heap_capacity);
+
   ~SpaceBitmap();
 
   // <offset> is the difference from .base to a pointer address.
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index e20c2c5..e0048a0 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -187,14 +187,6 @@
     heap_capacity += continuous_spaces_.back()->AsDlMallocSpace()->NonGrowthLimitCapacity();
   }
 
-  // Mark image objects in the live bitmap.
-  for (const auto& space : continuous_spaces_) {
-    if (space->IsImageSpace()) {
-      space::ImageSpace* image_space = space->AsImageSpace();
-      image_space->RecordImageAllocations(image_space->GetLiveBitmap());
-    }
-  }
-
   // Allocate the card table.
   card_table_.reset(accounting::CardTable::Create(heap_begin, heap_capacity));
   CHECK(card_table_.get() != NULL) << "Failed to create card table";
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index f959cff..e2e5bf7 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -35,15 +35,13 @@
 namespace gc {
 namespace space {
 
-size_t ImageSpace::bitmap_index_ = 0;
+AtomicInteger ImageSpace::bitmap_index_(0);
 
-ImageSpace::ImageSpace(const std::string& name, MemMap* mem_map)
-: MemMapSpace(name, mem_map, mem_map->Size(), kGcRetentionPolicyNeverCollect) {
-  const size_t bitmap_index = bitmap_index_++;
-  live_bitmap_.reset(accounting::SpaceBitmap::Create(
-      StringPrintf("imagespace %s live-bitmap %d", name.c_str(), static_cast<int>(bitmap_index)),
-      Begin(), Capacity()));
-  DCHECK(live_bitmap_.get() != NULL) << "could not create imagespace live bitmap #" << bitmap_index;
+ImageSpace::ImageSpace(const std::string& name, MemMap* mem_map,
+                       accounting::SpaceBitmap* live_bitmap)
+    : MemMapSpace(name, mem_map, mem_map->Size(), kGcRetentionPolicyNeverCollect) {
+  DCHECK(live_bitmap != NULL);
+  live_bitmap_.reset(live_bitmap);
 }
 
 static bool GenerateImage(const std::string& image_file_name) {
@@ -151,6 +149,17 @@
   return space::ImageSpace::Init(image_file_name, true);
 }
 
+void ImageSpace::VerifyImageAllocations() {
+  byte* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
+  while (current < End()) {
+    DCHECK_ALIGNED(current, kObjectAlignment);
+    const mirror::Object* obj = reinterpret_cast<const mirror::Object*>(current);
+    CHECK(live_bitmap_->Test(obj));
+    CHECK(obj->GetClass() != nullptr) << "Image object at address " << obj << " has null class";
+    current += RoundUp(obj->SizeOf(), kObjectAlignment);
+  }
+}
+
 ImageSpace* ImageSpace::Init(const std::string& image_file_name, bool validate_oat_file) {
   CHECK(!image_file_name.empty());
 
@@ -171,8 +180,10 @@
     LOG(ERROR) << "Invalid image header " << image_file_name;
     return NULL;
   }
+
+  // Note: The image header is part of the image due to mmap page alignment required of offset.
   UniquePtr<MemMap> map(MemMap::MapFileAtAddress(image_header.GetImageBegin(),
-                                                 file->GetLength(),
+                                                 image_header.GetImageSize(),
                                                  PROT_READ | PROT_WRITE,
                                                  MAP_PRIVATE | MAP_FIXED,
                                                  file->Fd(),
@@ -185,6 +196,20 @@
   CHECK_EQ(image_header.GetImageBegin(), map->Begin());
   DCHECK_EQ(0, memcmp(&image_header, map->Begin(), sizeof(ImageHeader)));
 
+  UniquePtr<MemMap> image_map(MemMap::MapFileAtAddress(nullptr, image_header.GetImageBitmapSize(),
+                                                       PROT_READ, MAP_PRIVATE,
+                                                       file->Fd(), image_header.GetBitmapOffset(),
+                                                       false));
+  CHECK(image_map.get() != nullptr) << "failed to map image bitmap";
+  size_t bitmap_index = bitmap_index_.fetch_add(1);
+  std::string bitmap_name(StringPrintf("imagespace %s live-bitmap %u", image_file_name.c_str(),
+                                       bitmap_index));
+  UniquePtr<accounting::SpaceBitmap> bitmap(
+      accounting::SpaceBitmap::CreateFromMemMap(bitmap_name, image_map.release(),
+                                                reinterpret_cast<byte*>(map->Begin()),
+                                                map->Size()));
+  CHECK(bitmap.get() != nullptr) << "could not create " << bitmap_name;
+
   Runtime* runtime = Runtime::Current();
   mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod);
   runtime->SetResolutionMethod(down_cast<mirror::ArtMethod*>(resolution_method));
@@ -196,7 +221,10 @@
   callee_save_method = image_header.GetImageRoot(ImageHeader::kRefsAndArgsSaveMethod);
   runtime->SetCalleeSaveMethod(down_cast<mirror::ArtMethod*>(callee_save_method), Runtime::kRefsAndArgs);
 
-  UniquePtr<ImageSpace> space(new ImageSpace(image_file_name, map.release()));
+  UniquePtr<ImageSpace> space(new ImageSpace(image_file_name, map.release(), bitmap.release()));
+  if (kIsDebugBuild) {
+    space->VerifyImageAllocations();
+  }
 
   space->oat_file_.reset(space->OpenOatFile());
   if (space->oat_file_.get() == NULL) {
@@ -245,9 +273,7 @@
 
 bool ImageSpace::ValidateOatFile() const {
   CHECK(oat_file_.get() != NULL);
-  std::vector<const OatFile::OatDexFile*> oat_dex_files = oat_file_->GetOatDexFiles();
-  for (size_t i = 0; i < oat_dex_files.size(); i++) {
-    const OatFile::OatDexFile* oat_dex_file = oat_dex_files[i];
+  for (const OatFile::OatDexFile* oat_dex_file : oat_file_->GetOatDexFiles()) {
     const std::string& dex_file_location = oat_dex_file->GetDexFileLocation();
     uint32_t dex_file_location_checksum;
     if (!DexFile::GetChecksum(dex_file_location.c_str(), dex_file_location_checksum)) {
@@ -270,28 +296,6 @@
   return *oat_file_.release();
 }
 
-void ImageSpace::RecordImageAllocations(accounting::SpaceBitmap* live_bitmap) const {
-  uint64_t start_time = 0;
-  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
-    LOG(INFO) << "ImageSpace::RecordImageAllocations entering";
-    start_time = NanoTime();
-  }
-  DCHECK(!Runtime::Current()->IsStarted());
-  CHECK(live_bitmap != NULL);
-  byte* current = Begin() + RoundUp(sizeof(ImageHeader), kObjectAlignment);
-  byte* end = End();
-  while (current < end) {
-    DCHECK_ALIGNED(current, kObjectAlignment);
-    const mirror::Object* obj = reinterpret_cast<const mirror::Object*>(current);
-    live_bitmap->Set(obj);
-    current += RoundUp(obj->SizeOf(), kObjectAlignment);
-  }
-  if (VLOG_IS_ON(heap) || VLOG_IS_ON(startup)) {
-    LOG(INFO) << "ImageSpace::RecordImageAllocations exiting ("
-        << PrettyDuration(NanoTime() - start_time) << ")";
-  }
-}
-
 void ImageSpace::Dump(std::ostream& os) const {
   os << GetType()
       << "begin=" << reinterpret_cast<void*>(Begin())
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index bdda9fa..381a98e 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -53,6 +53,9 @@
   OatFile& ReleaseOatFile()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  void VerifyImageAllocations()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   const ImageHeader& GetImageHeader() const {
     return *reinterpret_cast<ImageHeader*>(Begin());
   }
@@ -61,10 +64,6 @@
     return GetName();
   }
 
-  // Mark the objects defined in this space in the given live bitmap
-  void RecordImageAllocations(accounting::SpaceBitmap* live_bitmap) const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   accounting::SpaceBitmap* GetLiveBitmap() const {
     return live_bitmap_.get();
   }
@@ -96,11 +95,11 @@
 
   friend class Space;
 
-  static size_t bitmap_index_;
+  static AtomicInteger bitmap_index_;
 
   UniquePtr<accounting::SpaceBitmap> live_bitmap_;
 
-  ImageSpace(const std::string& name, MemMap* mem_map);
+  ImageSpace(const std::string& name, MemMap* mem_map, accounting::SpaceBitmap* live_bitmap);
 
   // The OatFile associated with the image during early startup to
   // reserve space contiguous to the image. It is later released to
diff --git a/runtime/image.cc b/runtime/image.cc
index 686a117..d11594c 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -24,9 +24,12 @@
 namespace art {
 
 const byte ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const byte ImageHeader::kImageVersion[] = { '0', '0', '4', '\0' };
+const byte ImageHeader::kImageVersion[] = { '0', '0', '5', '\0' };
 
 ImageHeader::ImageHeader(uint32_t image_begin,
+                         uint32_t image_size,
+                         uint32_t image_bitmap_offset,
+                         uint32_t image_bitmap_size,
                          uint32_t image_roots,
                          uint32_t oat_checksum,
                          uint32_t oat_file_begin,
@@ -34,6 +37,9 @@
                          uint32_t oat_data_end,
                          uint32_t oat_file_end)
   : image_begin_(image_begin),
+    image_size_(image_size),
+    image_bitmap_offset_(image_bitmap_offset),
+    image_bitmap_size_(image_bitmap_size),
     oat_checksum_(oat_checksum),
     oat_file_begin_(oat_file_begin),
     oat_data_begin_(oat_data_begin),
diff --git a/runtime/image.h b/runtime/image.h
index 35e4c5c..5119e3a 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -21,6 +21,7 @@
 
 #include "globals.h"
 #include "mirror/object.h"
+#include "utils.h"
 
 namespace art {
 
@@ -30,6 +31,9 @@
   ImageHeader() {}
 
   ImageHeader(uint32_t image_begin,
+              uint32_t image_size_,
+              uint32_t image_bitmap_offset,
+              uint32_t image_bitmap_size,
               uint32_t image_roots,
               uint32_t oat_checksum,
               uint32_t oat_file_begin,
@@ -56,6 +60,18 @@
     return reinterpret_cast<byte*>(image_begin_);
   }
 
+  size_t GetImageSize() const {
+    return static_cast<uint32_t>(image_size_);
+  }
+
+  size_t GetImageBitmapOffset() const {
+    return image_bitmap_offset_;
+  }
+
+  size_t GetImageBitmapSize() const {
+    return image_bitmap_size_;
+  }
+
   uint32_t GetOatChecksum() const {
     return oat_checksum_;
   }
@@ -80,6 +96,10 @@
     return reinterpret_cast<byte*>(oat_file_end_);
   }
 
+  size_t GetBitmapOffset() const {
+    return RoundUp(image_size_, kPageSize);
+  }
+
   enum ImageRoot {
     kResolutionMethod,
     kCalleeSaveMethod,
@@ -106,6 +126,15 @@
   // Required base address for mapping the image.
   uint32_t image_begin_;
 
+  // Image size, not page aligned.
+  uint32_t image_size_;
+
+  // Image bitmap offset in the file.
+  uint32_t image_bitmap_offset_;
+
+  // Size of the image bitmap.
+  uint32_t image_bitmap_size_;
+
   // Checksum of the oat file we link to for load time sanity check.
   uint32_t oat_checksum_;