Adding oat_process

- Added oat_process, a version of app_process use to launch frameworks apps
- Added liboat_runtime, a version of libandroid_runtime that uses art instead of dvm
  This is just a special makefile, frameworks/base/core/jni code is used for source
- Added support for build a boot.oat with the full BOOTCLASSPATH
  The older smaller boat.oat is now core.oat
- Added mem_map code for making sure a requested memory region is available
  Moved mem_map code to cc file to make easier to debug with smaller rebuild
- Moved oat base address to 0x6000000 as a work around to host addres conflict
- Added -Xms and -Xmx options to dex2oat to allow build specific memory options
- Fixed miranda method initialization problem found compiling full bootclasspath
- Made compiler.cc tolerant of verification errors found compiling full bootclasspath
- Bumped arena block alloc warning to avoid noise when compiling full bootclasspath
- Marked implicit GC unimplemented to fail fast
- Added --output argument to oatdump
- Made many object asserts tolerate access in IsErroneous state
  now that verifier is failing validation of some classes during compilation
- Made runtime tolerate unknown access as short term solution for oat_process
- Workaround SSA issue to restore full bootclasspath compilation
- Added test-art-target-processs to excercise oat_process with "am"
  "am" found bug where class_linker was using Method::GetClass and not ::GetDeclaringClass

Change-Id: I1a645a142b163e06bab9e72eb094ae1f1dbfbd97
diff --git a/src/class_linker.cc b/src/class_linker.cc
index de70fa5..a9c2005 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -657,7 +657,7 @@
 
   Thread* self = Thread::Current();
   DCHECK(self != NULL);
-  CHECK(!self->IsExceptionPending());
+  CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
   // Find the class in the loaded classes table.
   Class* klass = LookupClass(descriptor, class_loader);
   if (klass == NULL) {
@@ -701,7 +701,6 @@
       LoadClass(dex_file, dex_class_def, klass, class_loader);
       // Check for a pending exception during load
       if (self->IsExceptionPending()) {
-        // TODO: free native allocations in klass
         return NULL;
       }
       ObjectLock lock(klass);
@@ -711,7 +710,6 @@
       if (!success) {
         // We may fail to insert if we raced with another thread.
         klass->SetClinitThreadId(0);
-        // TODO: free native allocations in klass
         klass = LookupClass(descriptor, class_loader);
         CHECK(klass != NULL);
         return klass;
@@ -1230,7 +1228,12 @@
     LOG(ERROR) << "Verification failed on class "
                << klass->GetDescriptor()->ToModifiedUtf8();
     Object* exception = Thread::Current()->GetException();
-    klass->SetVerifyErrorClass(exception->GetClass());
+    // CHECK(exception != NULL) << PrettyClass(klass);
+    if (exception == NULL) {
+      UNIMPLEMENTED(ERROR) << "null verification exception for " << PrettyClass(klass);
+    } else {
+      klass->SetVerifyErrorClass(exception->GetClass());
+    }
     klass->SetStatus(Class::kStatusError);
     return;
   }
@@ -1381,7 +1384,7 @@
       for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
         const Method* method = interface_entry->GetMethodArray()->Get(j);
         if (!HasSameMethodDescriptorClasses(method, interface,
-                                            method->GetClass())) {
+                                            method->GetDeclaringClass())) {
           ThrowLinkageError("Classes resolve differently in interface");
           return false;
         }
@@ -1394,7 +1397,7 @@
 bool ClassLinker::HasSameMethodDescriptorClasses(const Method* method,
                                                  const Class* klass1,
                                                  const Class* klass2) {
-  const DexFile& dex_file = FindDexFile(method->GetClass()->GetDexCache());
+  const DexFile& dex_file = FindDexFile(method->GetDeclaringClass()->GetDexCache());
   const DexFile::ProtoId& proto_id = dex_file.GetProtoId(method->GetProtoIdx());
   DexFile::ParameterIterator *it;
   for (it = dex_file.GetParameterIterator(proto_id); it->HasNext(); it->Next()) {
@@ -1865,8 +1868,9 @@
   if (miranda_count != 0) {
     int old_method_count = klass->NumVirtualMethods();
     int new_method_count = old_method_count + miranda_count;
-    klass->SetVirtualMethods(
-        klass->GetVirtualMethods()->CopyOf(new_method_count));
+    klass->SetVirtualMethods((old_method_count == 0)
+                             ? AllocObjectArray<Method>(new_method_count)
+                             : klass->GetVirtualMethods()->CopyOf(new_method_count));
 
     ObjectArray<Method>* vtable = klass->GetVTableDuringLinking();
     CHECK(vtable != NULL);
diff --git a/src/common_test.h b/src/common_test.h
index a291976..127cad6 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -2,6 +2,7 @@
 
 #include <dirent.h>
 #include <dlfcn.h>
+#include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -104,6 +105,8 @@
     Runtime::Options options;
     options.push_back(std::make_pair("bootclasspath", &boot_class_path_));
     options.push_back(std::make_pair("-Xcheck:jni", reinterpret_cast<void*>(NULL)));
+    options.push_back(std::make_pair("-Xms16m", reinterpret_cast<void*>(NULL)));
+    options.push_back(std::make_pair("-Xmx16m", reinterpret_cast<void*>(NULL)));
     runtime_.reset(Runtime::Create(options, false));
     ASSERT_TRUE(runtime_.get() != NULL);
     class_linker_ = runtime_->GetClassLinker();
diff --git a/src/compiler.cc b/src/compiler.cc
index 71727fd..54793ba 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -2,6 +2,8 @@
 
 #include "compiler.h"
 
+#include <sys/mman.h>
+
 #include "assembler.h"
 #include "class_linker.h"
 #include "class_loader.h"
@@ -72,7 +74,9 @@
   // Class derived values are more complicated, they require the linker and loader.
   for (size_t type_idx = 0; type_idx < dex_cache->NumResolvedTypes(); type_idx++) {
     Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
-    CHECK(klass->IsResolved());
+    if (klass == NULL) {
+      Thread::Current()->ClearException();
+    }
   }
 
   // Method and Field are the worst. We can't resolve without either
@@ -172,13 +176,19 @@
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
     const char* descriptor = dex_file.GetClassDescriptor(class_def);
     Class* klass = class_linker->FindClass(descriptor, class_loader);
-    class_linker->EnsureInitialized(klass, false);
+    if (klass != NULL) {
+      class_linker->EnsureInitialized(klass, false);
+    }
+    // clear any class not found or verification exceptions
+    Thread::Current()->ClearException();
   }
 
   DexCache* dex_cache = class_linker->FindDexCache(dex_file);
   for (size_t type_idx = 0; type_idx < dex_cache->NumResolvedTypes(); type_idx++) {
     Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
-    if (klass->IsInitialized()) {
+    if (klass == NULL) {
+      Thread::Current()->ClearException();
+    } else if (klass->IsInitialized()) {
       dex_cache->GetInitializedStaticStorage()->Set(type_idx, klass);
     }
   }
@@ -199,8 +209,15 @@
     const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
     const char* descriptor = dex_file.GetClassDescriptor(class_def);
     Class* klass = class_linker->FindClass(descriptor, class_loader);
-    CHECK(klass != NULL);
-    CompileClass(klass);
+    if (klass == NULL) {
+      // previous verification error will cause FindClass to throw
+      Thread* self = Thread::Current();
+      // CHECK(self->IsExceptionPending());
+      UNIMPLEMENTED(WARNING) << "CHECK for verification error after FindClass " << descriptor;
+      self->ClearException();
+    } else {
+      CompileClass(klass);
+    }
   }
 }
 
diff --git a/src/compiler/Utility.cc b/src/compiler/Utility.cc
index fbdf62c..7d3a887 100644
--- a/src/compiler/Utility.cc
+++ b/src/compiler/Utility.cc
@@ -78,7 +78,7 @@
         currentArena->next = newArena;
         currentArena = newArena;
         numArenaBlocks++;
-        if (numArenaBlocks > 1000) {
+        if (numArenaBlocks > 20000) {
             LOG(INFO) << "Total arena pages: " << numArenaBlocks;
         }
         goto retry;
@@ -373,7 +373,8 @@
 bool oatIntersectBitVectors(ArenaBitVector* dest, const ArenaBitVector* src1,
                             const ArenaBitVector* src2)
 {
-    if (dest->storageSize != src1->storageSize ||
+    if (src2 == NULL ||
+        dest->storageSize != src1->storageSize ||
         dest->storageSize != src2->storageSize ||
         dest->expandable != src1->expandable ||
         dest->expandable != src2->expandable)
@@ -392,7 +393,8 @@
 bool oatUnifyBitVectors(ArenaBitVector* dest, const ArenaBitVector* src1,
                         const ArenaBitVector* src2)
 {
-    if (dest->storageSize != src1->storageSize ||
+    if (src2 == NULL ||
+        dest->storageSize != src1->storageSize ||
         dest->storageSize != src2->storageSize ||
         dest->expandable != src1->expandable ||
         dest->expandable != src2->expandable)
diff --git a/src/compiler/codegen/arm/CodegenCommon.cc b/src/compiler/codegen/arm/CodegenCommon.cc
index 40494f3..08da8d8 100644
--- a/src/compiler/codegen/arm/CodegenCommon.cc
+++ b/src/compiler/codegen/arm/CodegenCommon.cc
@@ -280,8 +280,11 @@
                            int dest, int src1, int src2)
 {
     ArmLIR* insn = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
-    assert(isPseudoOpcode(opcode) ||
-           (EncodingMap[opcode].flags & IS_TERTIARY_OP));
+    DCHECK(isPseudoOpcode(opcode) ||
+           (EncodingMap[opcode].flags & IS_TERTIARY_OP))
+            << (int)opcode << " "
+            << PrettyMethod(cUnit->method) << " "
+            << cUnit->currentDalvikOffset;
     insn->opcode = opcode;
     insn->operands[0] = dest;
     insn->operands[1] = src1;
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index f60699c..053575a 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -39,7 +39,7 @@
   // TODO: remove this by making boot image contain boot DexFile information?
   fprintf(stderr,
           "  --boot-dex-file=<dex-file>: specifies a .dex file that is part of the boot\n"
-          "       image specified with --boot. \n"
+          "      image specified with --boot. \n"
           "      Example: --boot-dex-file=/system/framework/core.jar\n"
           "\n");
   fprintf(stderr,
@@ -48,9 +48,19 @@
           "\n");
   fprintf(stderr,
           "  --strip-prefix may be used to strip a path prefix from dex file names in the\n"
-          "       the generated image to match the target file system layout.\n"
+          "      the generated image to match the target file system layout.\n"
           "      Example: --strip-prefix=out/target/product/crespo\n"
           "\n");
+  fprintf(stderr,
+          "  -Xms<n> may be used to specify an initial heap size for the runtime used to\n"
+          "      run dex2oat\n"
+          "      Example: -Xms256m\n"
+          "\n");
+  fprintf(stderr,
+          "  -Xmx<n> may be used to specify a maximum heap size for the runtime used to\n"
+          "      run dex2oat\n"
+          "      Example: -Xmx256m\n"
+          "\n");
   exit(EXIT_FAILURE);
 }
 
@@ -71,6 +81,8 @@
   std::vector<const char*> boot_dex_filenames;
   uintptr_t image_base = 0;
   std::string strip_location_prefix;
+  const char* Xms = NULL;
+  const char* Xmx = NULL;
 
   for (int i = 0; i < argc; i++) {
     const StringPiece option(argv[i]);
@@ -85,7 +97,7 @@
       char* end;
       image_base = strtoul(image_base_str, &end, 16);
       if (end == image_base_str || *end != '\0') {
-        fprintf(stderr, "could not parse hexadecimal value for option %s\n", option.data());
+        fprintf(stderr, "Failed to parse hexadecimal value for option %s\n", option.data());
         usage();
       }
     } else if (option.starts_with("--boot=")) {
@@ -97,6 +109,10 @@
       boot_dex_filenames.push_back(option.substr(strlen("--boot-dex-file=")).data());
     } else if (option.starts_with("--strip-prefix=")) {
       strip_location_prefix = option.substr(strlen("--strip-prefix=")).data();
+    } else if (option.starts_with("-Xms")) {
+      Xms = option.data();
+    } else if (option.starts_with("-Xmx")) {
+      Xmx = option.data();
     } else {
       fprintf(stderr, "unknown argument %s\n", option.data());
       usage();
@@ -138,6 +154,12 @@
     options.push_back(std::make_pair("bootclasspath", &boot_dex_files));
     options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
   }
+  if (Xms != NULL) {
+    options.push_back(std::make_pair(Xms, reinterpret_cast<void*>(NULL)));
+  }
+  if (Xmx != NULL) {
+    options.push_back(std::make_pair(Xmx, reinterpret_cast<void*>(NULL)));
+  }
   UniquePtr<Runtime> runtime(Runtime::Create(options, false));
   if (runtime.get() == NULL) {
     fprintf(stderr, "could not create runtime\n");
diff --git a/src/heap.cc b/src/heap.cc
index 4d8d176..8311944 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -330,6 +330,7 @@
     ++Runtime::Current()->GetStats()->gc_for_alloc_count;
     ++Thread::Current()->GetStats()->gc_for_alloc_count;
   }
+  UNIMPLEMENTED(FATAL) << "No implicit GC, use larger -Xms -Xmx";
   CollectGarbageInternal();
   ptr = space->AllocWithoutGrowth(size);
   if (ptr != NULL) {
diff --git a/src/heap.h b/src/heap.h
index f39454a..ea05a73 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -35,9 +35,9 @@
 
 class Heap {
  public:
-  static const size_t kInitialSize = 64 * MB;  // TODO: lower to 4
+  static const size_t kInitialSize = 4 * MB;
 
-  static const size_t kMaximumSize = 64 * MB;  // TODO: lower to 16
+  static const size_t kMaximumSize = 16 * MB;
 
   typedef void (RootVisitor)(const Object* root, void* arg);
 
diff --git a/src/mem_map.cc b/src/mem_map.cc
new file mode 100644
index 0000000..e44a894
--- /dev/null
+++ b/src/mem_map.cc
@@ -0,0 +1,163 @@
+#include "mem_map.h"
+
+#include <sys/mman.h>
+
+#include "utils.h"
+
+/*
+ * Copyright (C) 2008 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 "mem_map.h"
+
+#include <sys/mman.h>
+
+namespace art {
+
+size_t ParseHex(const std::string& string) {
+  CHECK_EQ(8U, string.size());
+  const char* str = string.c_str();
+  char* end;
+  size_t value = strtoul(str, &end, 16);
+  CHECK(end != str) << "Failed to parse hexadecimal value from " << string;
+  CHECK(*end == '\0') << "Failed to parse hexadecimal value from " << string;
+  return value;
+}
+
+void CheckMapRequest(byte* addr, size_t length) {
+#ifndef NDEBUG
+  if (addr == NULL) {
+    return;
+  }
+  size_t base = reinterpret_cast<size_t>(addr);
+  size_t limit = base + length;
+
+  std::string maps;
+  bool read = ReadFileToString("/proc/self/maps", &maps);
+  if (!read) {
+    PLOG(FATAL) << "Failed to read /proc/self/maps";
+  }
+  // Quick and dirty parse of output like shown below. We only focus
+  // on grabbing the two 32-bit hex values at the start of each line
+  // and will fail on wider addresses found on 64-bit systems.
+
+  // 00008000-0001f000 r-xp 00000000 b3:01 273        /system/bin/toolbox
+  // 0001f000-00021000 rw-p 00017000 b3:01 273        /system/bin/toolbox
+  // 00021000-00029000 rw-p 00000000 00:00 0          [heap]
+  // 40011000-40053000 r-xp 00000000 b3:01 1050       /system/lib/libc.so
+  // 40053000-40056000 rw-p 00042000 b3:01 1050       /system/lib/libc.so
+  // 40056000-40061000 rw-p 00000000 00:00 0
+  // 40061000-40063000 r-xp 00000000 b3:01 1107       /system/lib/libusbhost.so
+  // 40063000-40064000 rw-p 00002000 b3:01 1107       /system/lib/libusbhost.so
+  // 4009d000-400a0000 r-xp 00000000 b3:01 1022       /system/lib/liblog.so
+  // 400a0000-400a1000 rw-p 00003000 b3:01 1022       /system/lib/liblog.so
+  // 400b7000-400cc000 r-xp 00000000 b3:01 932        /system/lib/libm.so
+  // 400cc000-400cd000 rw-p 00015000 b3:01 932        /system/lib/libm.so
+  // 400cf000-400d0000 r--p 00000000 00:00 0
+  // 400e4000-400ec000 r--s 00000000 00:0b 388        /dev/__properties__ (deleted)
+  // 400ec000-400fa000 r-xp 00000000 b3:01 1101       /system/lib/libcutils.so
+  // 400fa000-400fb000 rw-p 0000e000 b3:01 1101       /system/lib/libcutils.so
+  // 400fb000-4010a000 rw-p 00000000 00:00 0
+  // 4010d000-4010e000 r-xp 00000000 b3:01 929        /system/lib/libstdc++.so
+  // 4010e000-4010f000 rw-p 00001000 b3:01 929        /system/lib/libstdc++.so
+  // b0001000-b0009000 r-xp 00001000 b3:01 1098       /system/bin/linker
+  // b0009000-b000a000 rw-p 00009000 b3:01 1098       /system/bin/linker
+  // b000a000-b0015000 rw-p 00000000 00:00 0
+  // bee35000-bee56000 rw-p 00000000 00:00 0          [stack]
+  // ffff0000-ffff1000 r-xp 00000000 00:00 0          [vectors]
+
+  for (size_t i = 0; i < maps.size(); i++) {
+    size_t remaining = maps.size() - i;
+    if (remaining < 8+1+8) {  // 00008000-0001f000
+      LOG(FATAL) << "Failed to parse at pos " << i << "\n" << maps;
+    }
+    std::string start_str = maps.substr(i, 8);
+    std::string end_str = maps.substr(i+1+8, 8);
+    uint32_t start = ParseHex(start_str);
+    uint32_t end = ParseHex(end_str);
+    CHECK(!(base >= start && base < end)
+          && !(limit >= start && limit < end)
+          && !(base <= start && limit > end))
+        << StringPrintf("Requested region %08x-%08x overlaps with existing map %08x-%08x\n",
+                        base, limit, start, end)
+        << maps;
+    i += 8+1+8;
+    i = maps.find('\n', i);
+    CHECK(i != std::string::npos) << "Failed to find newline from pos " << i << "\n" << maps;
+  }
+#endif
+}
+
+MemMap* MemMap::Map(byte* addr, size_t length, int prot) {
+  CHECK_NE(0U, length);
+  CHECK_NE(0, prot);
+  size_t page_aligned_size = RoundUp(length, kPageSize);
+  CheckMapRequest(addr, page_aligned_size);
+  byte* actual = reinterpret_cast<byte*>(mmap(addr,
+                                              page_aligned_size,
+                                              prot,
+                                              MAP_PRIVATE | MAP_ANONYMOUS,
+                                              -1,
+                                              0));
+  if (actual == MAP_FAILED) {
+    PLOG(ERROR) << "mmap failed";
+    return NULL;
+  }
+  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) {
+  CHECK_NE(0U, length);
+  CHECK_NE(0, prot);
+  CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE));
+  // adjust to be page-aligned
+  int page_offset = start % kPageSize;
+  off_t page_aligned_offset = start - page_offset;
+  size_t page_aligned_size = RoundUp(length + page_offset, kPageSize);
+  CheckMapRequest(addr, page_aligned_size);
+  byte* actual = reinterpret_cast<byte*>(mmap(addr,
+                                              page_aligned_size,
+                                              prot,
+                                              flags,
+                                              fd,
+                                              page_aligned_offset));
+  if (actual == MAP_FAILED) {
+    PLOG(ERROR) << "mmap failed";
+    return NULL;
+  }
+  return new MemMap(actual + page_offset, length, actual, page_aligned_size);
+}
+
+MemMap::~MemMap() {
+  if (base_addr_ == NULL && base_length_ == 0) {
+    return;
+  }
+  int result = munmap(base_addr_, base_length_);
+  base_addr_ = NULL;
+  base_length_ = 0;
+  if (result == -1) {
+    PLOG(FATAL) << "munmap failed";
+  }
+}
+
+MemMap::MemMap(byte* addr, size_t length, void* base_addr, size_t base_length)
+    : addr_(addr), length_(length), base_addr_(base_addr), base_length_(base_length) {
+  CHECK(addr_ != NULL);
+  CHECK(length_ != 0);
+  CHECK(base_addr_ != NULL);
+  CHECK(base_length_ != 0);
+};
+
+}  // namespace art
diff --git a/src/mem_map.h b/src/mem_map.h
index f44939c..3c73613 100644
--- a/src/mem_map.h
+++ b/src/mem_map.h
@@ -17,9 +17,10 @@
 #ifndef ART_SRC_MEM_MAP_H_
 #define ART_SRC_MEM_MAP_H_
 
-#include <sys/mman.h>
+#include <stddef.h>
+#include <sys/types.h>
 
-#include "utils.h"
+#include "globals.h"
 
 namespace art {
 
@@ -37,22 +38,7 @@
   // Request an anonymous region of a specified length and a requested base address.
   //
   // On success, returns returns a MemMap instance.  On failure, returns a NULL;
-  static MemMap* Map(byte* addr, size_t length, int prot) {
-    CHECK_NE(0U, length);
-    CHECK_NE(0, prot);
-    size_t page_aligned_size = RoundUp(length, kPageSize);
-    byte* actual = reinterpret_cast<byte*>(mmap(addr,
-                                                page_aligned_size,
-                                                prot,
-                                                MAP_PRIVATE | MAP_ANONYMOUS,
-                                                -1,
-                                                0));
-    if (actual == MAP_FAILED) {
-      PLOG(ERROR) << "mmap failed";
-      return NULL;
-    }
-    return new MemMap(actual, length, actual, page_aligned_size);
-  }
+  static MemMap* Map(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.
@@ -67,44 +53,10 @@
   // 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) {
-    CHECK_NE(0U, length);
-    CHECK_NE(0, prot);
-    CHECK(flags & MAP_SHARED || flags & MAP_PRIVATE);
-    // adjust to be page-aligned
-    int page_offset = start % kPageSize;
-    off_t page_aligned_offset = start - page_offset;
-    size_t page_aligned_size = RoundUp(length + page_offset, kPageSize);
-    byte* actual = reinterpret_cast<byte*>(mmap(addr,
-                                                page_aligned_size,
-                                                prot,
-                                                flags,
-                                                fd,
-                                                page_aligned_offset));
-    if (actual == MAP_FAILED) {
-      PLOG(ERROR) << "mmap failed";
-      return NULL;
-    }
-    return new MemMap(actual + page_offset, length, actual, page_aligned_size);
-  }
+  static MemMap* Map(byte* addr, size_t length, int prot, int flags, int fd, off_t start);
 
-  ~MemMap() {
-    Unmap();
-  }
-
-  // Release a memory mapping, returning true on success or it was previously unmapped.
-  bool Unmap() {
-    if (base_addr_ == NULL && base_length_ == 0) {
-      return true;
-    }
-    int result = munmap(base_addr_, base_length_);
-    base_addr_ = NULL;
-    base_length_ = 0;
-    if (result == -1) {
-      return false;
-    }
-    return true;
-  }
+  // Releases the memory mapping
+  ~MemMap();
 
   byte* GetAddress() const {
     return addr_;
@@ -119,13 +71,7 @@
   }
 
  private:
-  MemMap(byte* addr, size_t length, void* base_addr, size_t base_length)
-      : addr_(addr), length_(length), base_addr_(base_addr), base_length_(base_length) {
-    CHECK(addr_ != NULL);
-    CHECK(length_ != 0);
-    CHECK(base_addr_ != NULL);
-    CHECK(base_length_ != 0);
-  };
+  MemMap(byte* addr, size_t length, void* base_addr, size_t base_length);
 
   byte*  addr_;              // start of data
   size_t length_;            // length of data
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 7578fb1..52cddb5 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -3,6 +3,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <fstream>
+#include <iostream>
 #include <string>
 #include <vector>
 
@@ -45,6 +47,10 @@
           "       the generated image to match the target file system layout.\n"
           "      Example: --strip-prefix=out/target/product/crespo\n"
           "\n");
+  fprintf(stderr,
+          "  --output=<file> may be used to send the output to a file.\n"
+          "      Example: --output=/tmp/oatdump.txt\n"
+          "\n");
   exit(EXIT_FAILURE);
 }
 
@@ -52,15 +58,32 @@
   "kJniStubArray",
 };
 
-struct OatDump {
-  const Space* dump_space;
+class OatDump {
 
-  bool InDumpSpace(const Object* object) {
-    DCHECK(dump_space != NULL);
-    const byte* o = reinterpret_cast<const byte*>(object);
-    return (o >= dump_space->GetBase() && o < dump_space->GetLimit());
+ public:
+  static void Dump(std::ostream& os, Space& image_space, const ImageHeader& image_header) {
+    os << "MAGIC:\n";
+    os << image_header.GetMagic() << "\n\n";
+
+    os << "ROOTS:\n";
+    for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
+      ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
+      os << StringPrintf("%s: %p\n",
+                         image_roots_descriptions_[i], image_header.GetImageRoot(image_root));
+    }
+    os << "\n";
+
+    os << "OBJECTS:\n" << std::flush;
+    OatDump state(image_space, os);
+    HeapBitmap* heap_bitmap = Heap::GetLiveBits();
+    DCHECK(heap_bitmap != NULL);
+    heap_bitmap->Walk(OatDump::Callback, &state);
   }
 
+ private:
+
+  OatDump(const Space& dump_space, std::ostream& os) : dump_space_(dump_space_), os_(os) {}
+
   static void Callback(Object* obj, void* arg) {
     DCHECK(obj != NULL);
     DCHECK(arg != NULL);
@@ -106,8 +129,15 @@
         }
       }
     }
-    std::cout << summary;
+    state->os_ << summary << std::flush;
   }
+
+  bool InDumpSpace(const Object* object) {
+    const byte* o = reinterpret_cast<const byte*>(object);
+    return (o >= dump_space_.GetBase() && o < dump_space_.GetLimit());
+  }
+  const Space& dump_space_;
+  std::ostream& os_;
 };
 
 int oatdump(int argc, char** argv) {
@@ -125,6 +155,8 @@
   const char* boot_image_filename = NULL;
   std::vector<const char*> boot_dex_filenames;
   std::string strip_location_prefix;
+  std::ostream* os = &std::cout;
+  UniquePtr<std::ofstream> out;
 
   for (int i = 0; i < argc; i++) {
     const StringPiece option(argv[i]);
@@ -138,6 +170,14 @@
       boot_dex_filenames.push_back(option.substr(strlen("--boot-dex-file=")).data());
     } else if (option.starts_with("--strip-prefix=")) {
       strip_location_prefix = option.substr(strlen("--strip-prefix=")).data();
+    } else if (option.starts_with("--output=")) {
+      const char* filename = option.substr(strlen("--output=")).data();
+      out.reset(new std::ofstream(filename));
+      if (!out->good()) {
+        fprintf(stderr, "failed to open output filename %s\n", filename);
+        usage();
+      }
+      os = out.get();
     } else {
       fprintf(stderr, "unknown argument %s\n", option.data());
       usage();
@@ -202,24 +242,7 @@
     fprintf(stderr, "invalid image header %s\n", image_filename);
     return EXIT_FAILURE;
   }
-
-  printf("MAGIC:\n");
-  printf("%s\n\n", image_header.GetMagic());
-
-  printf("ROOTS:\n");
-  for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
-    ImageHeader::ImageRoot image_root = static_cast<ImageHeader::ImageRoot>(i);
-    printf("%s: %p\n", image_roots_descriptions_[i], image_header.GetImageRoot(image_root));
-  }
-  printf("\n");
-
-  printf("OBJECTS:\n");
-  OatDump state;
-  state.dump_space = image_space;
-  HeapBitmap* heap_bitmap = Heap::GetLiveBits();
-  DCHECK(heap_bitmap != NULL);
-  heap_bitmap->Walk(OatDump::Callback, &state);
-
+  OatDump::Dump(*os, *image_space, image_header);
   return EXIT_SUCCESS;
 }
 
diff --git a/src/object.cc b/src/object.cc
index 756b8a7..40bc2e2 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -332,7 +332,7 @@
 }
 
 Class* Method::GetReturnType() const {
-  DCHECK(GetDeclaringClass()->IsResolved());
+  DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
   // Short-cut
   Class* result = GetDexCacheResolvedTypes()->Get(GetReturnTypeIdx());
   if (result == NULL) {
diff --git a/src/object.h b/src/object.h
index 2e3a791..eb11be7 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1536,7 +1536,7 @@
   }
 
   uint32_t GetSuperClassTypeIdx() const {
-    DCHECK(IsIdxLoaded());
+    DCHECK(IsIdxLoaded() || IsErroneous());
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, super_class_type_idx_),
                       false);
   }
@@ -1567,7 +1567,7 @@
   void SetDexCache(DexCache* new_dex_cache);
 
   ObjectArray<Method>* GetDirectMethods() const {
-    DCHECK(IsLoaded());
+    DCHECK(IsLoaded() || IsErroneous());
     return GetFieldObject<ObjectArray<Method>*>(
         OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false);
   }
@@ -1597,7 +1597,7 @@
   }
 
   ObjectArray<Method>* GetVirtualMethods() const {
-    DCHECK(IsLoaded());
+    DCHECK(IsLoaded() || IsErroneous());
     return GetFieldObject<ObjectArray<Method>*>(
         OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_), false);
   }
@@ -1616,12 +1616,12 @@
   }
 
   Method* GetVirtualMethod(uint32_t i) const {
-    DCHECK(IsResolved());
+    DCHECK(IsResolved() || IsErroneous());
     return GetVirtualMethods()->Get(i);
   }
 
   Method* GetVirtualMethodDuringLinking(uint32_t i) const {
-    DCHECK(IsLoaded());
+    DCHECK(IsLoaded() || IsErroneous());
     return GetVirtualMethods()->Get(i);
   }
 
@@ -1633,13 +1633,13 @@
   }
 
   ObjectArray<Method>* GetVTable() const {
-    DCHECK(IsResolved());
+    DCHECK(IsResolved() || IsErroneous());
     return GetFieldObject<ObjectArray<Method>*>(
         OFFSET_OF_OBJECT_MEMBER(Class, vtable_), false);
   }
 
   ObjectArray<Method>* GetVTableDuringLinking() const {
-    DCHECK(IsLoaded());
+    DCHECK(IsLoaded() || IsErroneous());
     return GetFieldObject<ObjectArray<Method>*>(
         OFFSET_OF_OBJECT_MEMBER(Class, vtable_), false);
   }
@@ -1690,14 +1690,14 @@
                            const StringPiece& signature);
 
   size_t NumInterfaces() const {
-    CHECK(IsIdxLoaded()); // used during loading
+    CHECK(IsIdxLoaded() || IsErroneous()); // used during loading
     ObjectArray<Class>* interfaces = GetFieldObject<ObjectArray<Class>*>(
         OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
     return (interfaces != NULL) ? interfaces->GetLength() : 0;
   }
 
   IntArray* GetInterfacesTypeIdx() const {
-    CHECK(IsIdxLoaded());
+    CHECK(IsIdxLoaded() || IsErroneous());
     return GetFieldObject<IntArray*>(
         OFFSET_OF_OBJECT_MEMBER(Class, interfaces_type_idx_), false);
   }
@@ -1705,7 +1705,7 @@
   void SetInterfacesTypeIdx(IntArray* new_interfaces_idx);
 
   ObjectArray<Class>* GetInterfaces() const {
-    CHECK(IsLoaded());
+    CHECK(IsLoaded() || IsErroneous());
     return GetFieldObject<ObjectArray<Class>*>(
         OFFSET_OF_OBJECT_MEMBER(Class, interfaces_), false);
   }
@@ -1739,7 +1739,7 @@
   }
 
   ObjectArray<InterfaceEntry>* GetIfTable() const {
-    DCHECK(IsResolved());
+    DCHECK(IsResolved() || IsErroneous());
     return GetFieldObject<ObjectArray<InterfaceEntry>*>(
         OFFSET_OF_OBJECT_MEMBER(Class, iftable_), false);
   }
@@ -1750,7 +1750,7 @@
 
   // Get instance fields
   ObjectArray<Field>* GetIFields() const {
-    DCHECK(IsLoaded());
+    DCHECK(IsLoaded() || IsErroneous());
     return GetFieldObject<ObjectArray<Field>*>(
         OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false);
   }
@@ -1779,14 +1779,14 @@
 
   // Returns the number of instance fields containing reference types.
   size_t NumReferenceInstanceFields() const {
-    DCHECK(IsResolved());
+    DCHECK(IsResolved() || IsErroneous());
     DCHECK(sizeof(size_t) == sizeof(int32_t));
     return GetField32(
         OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false);
   }
 
   size_t NumReferenceInstanceFieldsDuringLinking() const {
-    DCHECK(IsLoaded());
+    DCHECK(IsLoaded() || IsErroneous());
     DCHECK(sizeof(size_t) == sizeof(int32_t));
     return GetField32(
         OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), false);
@@ -1799,7 +1799,7 @@
   }
 
   uint32_t GetReferenceInstanceOffsets() const {
-    DCHECK(IsResolved());
+    DCHECK(IsResolved() || IsErroneous());
     return GetField32(
         OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_), false);
   }
@@ -1813,14 +1813,14 @@
 
   // Returns the number of static fields containing reference types.
   size_t NumReferenceStaticFields() const {
-    DCHECK(IsResolved());
+    DCHECK(IsResolved() || IsErroneous());
     DCHECK(sizeof(size_t) == sizeof(int32_t));
     return GetField32(
         OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false);
   }
 
   size_t NumReferenceStaticFieldsDuringLinking() const {
-    DCHECK(IsLoaded());
+    DCHECK(IsLoaded() || IsErroneous());
     DCHECK(sizeof(size_t) == sizeof(int32_t));
     return GetField32(
         OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), false);
@@ -1833,7 +1833,7 @@
   }
 
   ObjectArray<Field>* GetSFields() const {
-    DCHECK(IsLoaded());
+    DCHECK(IsLoaded() || IsErroneous());
     return GetFieldObject<ObjectArray<Field>*>(
         OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false);
   }
@@ -1877,7 +1877,7 @@
   Field* FindDeclaredStaticField(const StringPiece& name, Class* type);
 
   pid_t GetClinitThreadId() const {
-    DCHECK(IsIdxLoaded());
+    DCHECK(IsIdxLoaded() || IsErroneous());
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), false);
   }
 
@@ -2113,7 +2113,7 @@
 }
 
 inline void Field::SetOffset(MemberOffset num_bytes) {
-  DCHECK(GetDeclaringClass()->IsLoaded());
+  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   Class* type = GetTypeDuringLinking();
   if (type != NULL && (type->IsPrimitiveDouble() || type->IsPrimitiveLong())) {
     DCHECK(IsAligned(num_bytes.Uint32Value(), 8));
@@ -2126,7 +2126,7 @@
   Class* result = GetFieldObject<Class*>(
       OFFSET_OF_OBJECT_MEMBER(Field, declaring_class_), false);
   DCHECK(result != NULL);
-  DCHECK(result->IsLoaded());
+  DCHECK(result->IsLoaded() || result->IsErroneous());
   return result;
 }
 
@@ -2140,7 +2140,7 @@
       GetFieldObject<Class*>(
           OFFSET_OF_OBJECT_MEMBER(Method, declaring_class_), false);
   DCHECK(result != NULL);
-  DCHECK(result->IsLoaded());
+  DCHECK(result->IsLoaded() || result->IsErroneous());
   return result;
 }
 
@@ -2150,7 +2150,7 @@
 }
 
 inline uint32_t Method::GetReturnTypeIdx() const {
-  DCHECK(GetDeclaringClass()->IsResolved());
+  DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, java_return_type_idx_),
                     false);
 }
@@ -2442,7 +2442,7 @@
 };
 
 inline const String* Field::GetName() const {
-   DCHECK(GetDeclaringClass()->IsLoaded());
+   DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
    String* result =
        GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Field, name_), false);
    DCHECK(result != NULL);
@@ -2455,29 +2455,29 @@
 }
 
 inline uint32_t Field::GetAccessFlags() const {
-  DCHECK(GetDeclaringClass()->IsLoaded());
+  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, access_flags_), false);
 }
 
 inline uint32_t Field::GetTypeIdx() const {
-  DCHECK(GetDeclaringClass()->IsIdxLoaded());
+  DCHECK(GetDeclaringClass()->IsIdxLoaded() || GetDeclaringClass()->IsErroneous());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, type_idx_), false);
 }
 
 inline MemberOffset Field::GetOffset() const {
-  DCHECK(GetDeclaringClass()->IsResolved());
+  DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
   return MemberOffset(
       GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), false));
 }
 
 inline MemberOffset Field::GetOffsetDuringLinking() const {
-  DCHECK(GetDeclaringClass()->IsLoaded());
+  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   return MemberOffset(
       GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), false));
 }
 
 inline const String* Method::GetName() const {
-  DCHECK(GetDeclaringClass()->IsLoaded());
+  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   const String* result =
       GetFieldObject<const String*>(
           OFFSET_OF_OBJECT_MEMBER(Method, name_), false);
@@ -2512,7 +2512,7 @@
 }
 
 inline String* Method::GetShorty() const {
-  DCHECK(GetDeclaringClass()->IsLoaded());
+  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   return GetFieldObject<String*>(
       OFFSET_OF_OBJECT_MEMBER(Method, shorty_), false);
 }
@@ -2525,7 +2525,7 @@
 }
 
 inline const String* Method::GetSignature() const {
-  DCHECK(GetDeclaringClass()->IsLoaded());
+  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   const String* result =
       GetFieldObject<const String*>(
           OFFSET_OF_OBJECT_MEMBER(Method, signature_), false);
@@ -2541,7 +2541,8 @@
 inline uint32_t Class::GetAccessFlags() const {
   // Check class is loaded or this is java.lang.String that has a
   // circularity issue during loading the names of its members
-  DCHECK(IsLoaded() || this == String::GetJavaLangString() ||
+  DCHECK(IsLoaded() || IsErroneous() ||
+         this == String::GetJavaLangString() ||
          this == Field::GetJavaLangReflectField() ||
          this == Method::GetJavaLangReflectMethod()) << PrettyClass(this);
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), false);
@@ -2556,7 +2557,7 @@
 }
 
 inline String* Class::GetSourceFile() const {
-  DCHECK(IsLoaded());
+  DCHECK(IsLoaded() || IsErroneous());
   return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Class, source_file_), false);
 }
 
@@ -2565,32 +2566,32 @@
 }
 
 inline uint32_t Method::GetAccessFlags() const {
-  DCHECK(GetDeclaringClass()->IsLoaded());
+  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, access_flags_), false);
 }
 
 inline uint16_t Method::GetMethodIndex() const {
-  DCHECK(GetDeclaringClass()->IsResolved());
+  DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_index_), false);
 }
 
 inline uint16_t Method::NumRegisters() const {
-  DCHECK(GetDeclaringClass()->IsLoaded());
+  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_), false);
 }
 
 inline uint16_t Method::NumIns() const {
-  DCHECK(GetDeclaringClass()->IsLoaded());
+  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_), false);
 }
 
 inline uint16_t Method::NumOuts() const {
-  DCHECK(GetDeclaringClass()->IsLoaded());
+  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_), false);
 }
 
 inline uint32_t Method::GetProtoIdx() const {
-  DCHECK(GetDeclaringClass()->IsLoaded());
+  DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, proto_idx_), false);
 }
 
diff --git a/src/object_bitmap.cc b/src/object_bitmap.cc
index 4b4c5ee..06d86d6 100644
--- a/src/object_bitmap.cc
+++ b/src/object_bitmap.cc
@@ -18,6 +18,7 @@
 
 #include "UniquePtr.h"
 #include "logging.h"
+#include "utils.h"
 
 namespace art {
 
diff --git a/src/runtime.cc b/src/runtime.cc
index 0990851..e6bd6e2 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -300,8 +300,9 @@
     } else {
       if (!ignore_unrecognized) {
         // TODO: print usage via vfprintf
-        LOG(FATAL) << "Unrecognized option " << option;
-        return NULL;
+        LOG(ERROR) << "Unrecognized option " << option;
+        // TODO: this should exit, but for now tolerate unknown options
+        //return NULL;
       }
     }
   }
@@ -321,7 +322,9 @@
   if (parsed->boot_class_path_.empty()) {
     if (parsed->boot_class_path_string_ == NULL) {
       const char* BOOTCLASSPATH = getenv("BOOTCLASSPATH");
-      parsed->boot_class_path_string_ = BOOTCLASSPATH;
+      if (BOOTCLASSPATH != NULL) {
+        parsed->boot_class_path_string_ = BOOTCLASSPATH;
+      }
     }
     CreateClassPath(parsed->boot_class_path_string_, parsed->boot_class_path_);
   }