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/Android.mk b/Android.mk
index a7d41d7..49e0706 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,7 +15,6 @@
 #
 
 LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
 
 # These can be overridden via the environment or by editing to
 # enable/disable certain build configuration.
@@ -95,11 +94,34 @@
 .PHONY: test-art-target-oat
 test-art-target-oat: $(ART_TEST_OAT_TARGETS)
 
+# $(1): name
+define build-art-framework-oat
+  $(call build-art-oat,$(1),$(TARGET_BOOT_OAT),$(TARGET_BOOT_DEX))
+endef
+
+$(eval $(call build-art-framework-oat,am))
+
+.PHONY: test-art-target-oat-process
+test-art-target-oat-process: $(TARGET_OUT_JAVA_LIBRARIES)/am.oat
+	adb remount
+	adb sync
+	adb shell sh -c "export CLASSPATH=/system/framework/am.jar && oat_process -Xbootimage:/system/framework/boot.oat -Ximage:/system/framework/am.oat /system/bin com.android.commands.am.Am && touch /sdcard/test-art-target-process"
+	$(hide) (adb pull /sdcard/test-art-target-process /tmp/ && echo test-art-target-process PASSED) || echo test-art-target-process FAILED
+	$(hide) rm /tmp/test-art-target-process
+
+.PHONY: dump-core-oat
+dump-core-oat: $(TARGET_CORE_OAT) $(OATDUMP)
+	$(OATDUMP) $(addprefix --dex-file=,$(TARGET_CORE_DEX)) --image=$(TARGET_CORE_OAT) --strip-prefix=$(PRODUCT_OUT) --output=/tmp/core.oatdump.txt
+	@echo Output in /tmp/core.oatdump.txt
+
 .PHONY: dump-boot-oat
 dump-boot-oat: $(TARGET_BOOT_OAT) $(OATDUMP)
-	$(OATDUMP) $(addprefix --dex-file=,$(TARGET_BOOT_DEX)) --image=$(TARGET_BOOT_OAT) --strip-prefix=$(PRODUCT_OUT)
+	$(OATDUMP) $(addprefix --dex-file=,$(TARGET_BOOT_DEX)) --image=$(TARGET_BOOT_OAT) --strip-prefix=$(PRODUCT_OUT) --output=/tmp/boot.oatdump.txt
+	@echo Output in /tmp/boot.oatdump.txt
 
 # "mm cpplint-art" to style check art source files
 .PHONY: cpplint-art
 cpplint-art:
 	$(LOCAL_PATH)/tools/cpplint.py $(LOCAL_PATH)/src/*.h $(LOCAL_PATH)/src/*.cc
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 6cdd203..a77d5a8 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -122,6 +122,7 @@
 	src/mark_sweep.cc \
 	src/managed_register_arm.cc \
 	src/managed_register_x86.cc \
+	src/mem_map.cc \
 	src/memory_region.cc \
 	src/monitor.cc \
 	src/mspace.c \
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index e027911..2ea132d 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -25,26 +25,37 @@
 OATDUMP := $(OATDUMPD)
 
 # start of oat reserved address space
-OAT_HOST_BASE_ADDRESS := 0x50000000
-OAT_TARGET_BASE_ADDRESS := 0x50000000
+OAT_HOST_BASE_ADDRESS   := 0x60000000
+OAT_TARGET_BASE_ADDRESS := 0x60000000
 
-HOST_BOOT_OAT := $(HOST_OUT_JAVA_LIBRARIES)/boot.oat
-TARGET_BOOT_OAT := $(TARGET_OUT_JAVA_LIBRARIES)/boot.oat
+########################################################################
+# A smaller libcore only oat file
+HOST_CORE_JARS := core-hostdex
+TARGET_CORE_JARS := core
 
-# TODO: just use libcore for now, not full bootclasspath.
-# eventually need to replace with full list based on DEXPREOPT_BOOT_JARS.
-HOST_BOOT_JARS := core-hostdex
-TARGET_BOOT_JARS := core
+HOST_CORE_DEX   := $(foreach jar,$(HOST_CORE_JARS),  $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
+TARGET_CORE_DEX := $(foreach jar,$(TARGET_CORE_JARS),$(TARGET_OUT_JAVA_LIBRARIES)/$(jar).jar)
 
-HOST_BOOT_DEX   := $(foreach jar,$(HOST_BOOT_JARS),  $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
-TARGET_BOOT_DEX := $(foreach jar,$(TARGET_BOOT_JARS),$(TARGET_OUT_JAVA_LIBRARIES)/$(jar).jar)
+HOST_CORE_OAT := $(HOST_OUT_JAVA_LIBRARIES)/core.oat
+TARGET_CORE_OAT := $(TARGET_OUT_JAVA_LIBRARIES)/core.oat
 
 # TODO: change DEX2OATD to order-only prerequisite when output is stable
-$(HOST_BOOT_OAT): $(HOST_BOOT_DEX) $(DEX2OAT)
+$(HOST_CORE_OAT): $(HOST_CORE_DEX) $(DEX2OAT)
 	@echo "host dex2oat: $@ ($<)"
-	$(hide) $(DEX2OAT) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --image=$@ --base=$(OAT_HOST_BASE_ADDRESS)
+	$(hide) $(DEX2OAT) -Xms16m -Xmx16m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --image=$@ --base=$(OAT_HOST_BASE_ADDRESS)
+
+# TODO: change DEX2OATD to order-only prerequisite when output is stable
+$(TARGET_CORE_OAT): $(TARGET_CORE_DEX) $(DEX2OAT)
+	@echo "target dex2oat: $@ ($<)"
+	$(hide) $(DEX2OAT) -Xms32m -Xmx32m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --image=$@ --base=$(OAT_TARGET_BASE_ADDRESS) --strip-prefix=$(PRODUCT_OUT)
+
+########################################################################
+# The full system boot classpath
+TARGET_BOOT_JARS := $(subst :, ,$(DEXPREOPT_BOOT_JARS))
+TARGET_BOOT_DEX := $(foreach jar,$(TARGET_BOOT_JARS),$(TARGET_OUT_JAVA_LIBRARIES)/$(jar).jar)
+TARGET_BOOT_OAT := $(TARGET_OUT_JAVA_LIBRARIES)/boot.oat
 
 # TODO: change DEX2OATD to order-only prerequisite when output is stable
 $(TARGET_BOOT_OAT): $(TARGET_BOOT_DEX) $(DEX2OAT)
 	@echo "target dex2oat: $@ ($<)"
-	$(hide) $(DEX2OAT) $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --image=$@ --base=$(OAT_TARGET_BASE_ADDRESS) --strip-prefix=$(PRODUCT_OUT)
+	$(hide) $(DEX2OAT) -Xms256m -Xmx256m $(addprefix --dex-file=,$(filter-out $(DEX2OAT),$^)) --image=$@ --base=$(OAT_TARGET_BASE_ADDRESS) --strip-prefix=$(PRODUCT_OUT)
diff --git a/build/Android.oattest.mk b/build/Android.oattest.mk
index 0b8cfa9..4605583 100644
--- a/build/Android.oattest.mk
+++ b/build/Android.oattest.mk
@@ -33,16 +33,23 @@
 
 ########################################################################
 
+# $(1): module
+# $(2): boot oat
+# $(3): boot dex files
+define build-art-oat
+# TODO: change DEX2OATD to order-only prerequisite when output is stable
+$(TARGET_OUT_JAVA_LIBRARIES)/$(1).oat: $(TARGET_OUT_JAVA_LIBRARIES)/$(1).jar $(2) $(DEX2OAT)
+	@echo "target dex2oat: $$@ ($$<)"
+	$(hide) $(DEX2OAT) -Xms16m -Xmx16m $(addprefix --boot-dex-file=,$(3)) --boot=$(2) $(addprefix --dex-file=,$$<) --image=$$@ --strip-prefix=$(PRODUCT_OUT)
+endef
+
+########################################################################
 ART_TEST_OAT_FILES :=
 
 # $(1): directory
 define build-art-test-oat
-# TODO: change DEX2OATD to order-only prerequisite when output is stable
-$(TARGET_OUT_JAVA_LIBRARIES)/art-test-dex-$(1).oat: $(TARGET_OUT_JAVA_LIBRARIES)/art-test-dex-$(1).jar $(TARGET_BOOT_OAT) $(DEX2OAT)
-	@echo "target dex2oat: $$@ ($$<)"
-	$(hide) $(DEX2OAT) $(addprefix --boot-dex-file=,$(TARGET_BOOT_DEX)) --boot=$(TARGET_BOOT_OAT) $(addprefix --dex-file=,$$<) --image=$$@ --strip-prefix=$(PRODUCT_OUT)
-
-ART_TEST_OAT_FILES += $(TARGET_OUT_JAVA_LIBRARIES)/art-test-dex-$(1).oat
+  $(call build-art-oat,art-test-dex-$(1),$(TARGET_CORE_OAT),$(TARGET_CORE_DEX))
+  ART_TEST_OAT_FILES += $(TARGET_OUT_JAVA_LIBRARIES)/art-test-dex-$(1).oat
 endef
 $(foreach dir,$(TEST_DEX_DIRECTORIES), $(eval $(call build-art-test-oat,$(dir))))
 
@@ -57,7 +64,7 @@
 test-art-target-oat-$(1): test-art-target-sync
 	adb shell touch /sdcard/test-art-target-oat-$(1)
 	adb shell rm /sdcard/test-art-target-oat-$(1)
-	adb shell sh -c "oatexecd -Xbootclasspath:/system/framework/core.jar -Xbootimage:/system/framework/boot.oat -classpath /system/framework/art-test-dex-$(1).jar -Ximage:/system/framework/art-test-dex-$(1).oat $(1) $(2) && touch /sdcard/test-art-target-oat-$(1)"
+	adb shell sh -c "oatexecd -Xbootclasspath:/system/framework/core.jar -Xbootimage:/system/framework/core.oat -classpath /system/framework/art-test-dex-$(1).jar -Ximage:/system/framework/art-test-dex-$(1).oat $(1) $(2) && touch /sdcard/test-art-target-oat-$(1)"
 	$(hide) (adb pull /sdcard/test-art-target-oat-$(1) /tmp/ && echo test-art-target-oat-$(1) PASSED) || (echo test-art-target-oat-$(1) FAILED && exit 1)
 	$(hide) rm /tmp/test-art-target-oat-$(1)
 
diff --git a/oat_process/Android.mk b/oat_process/Android.mk
new file mode 100644
index 0000000..9fb9401
--- /dev/null
+++ b/oat_process/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH:= $(call my-dir)
+
+local_src_files:= \
+	app_main.cpp
+
+local_shared_libraries := \
+	libcutils \
+	libutils \
+	libbinder
+
+include $(CLEAR_VARS)
+LOCAL_MODULE:= oat_process
+LOCAL_MODULE_TAGS:= optional
+LOCAL_SRC_FILES:= $(local_src_files)
+LOCAL_SHARED_LIBRARIES := liboat_runtimed $(local_shared_libraries)
+include $(BUILD_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE_TAGS:= optional
+LOCAL_MODULE:= oat_processd
+LOCAL_SRC_FILES:= $(local_src_files)
+LOCAL_SHARED_LIBRARIES := liboat_runtimed $(local_shared_libraries)
+include $(BUILD_EXECUTABLE)
diff --git a/oat_process/MODULE_LICENSE_APACHE2 b/oat_process/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/oat_process/MODULE_LICENSE_APACHE2
diff --git a/oat_process/NOTICE b/oat_process/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/oat_process/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/oat_process/app_main.cpp b/oat_process/app_main.cpp
new file mode 100644
index 0000000..bf827a8
--- /dev/null
+++ b/oat_process/app_main.cpp
@@ -0,0 +1,204 @@
+/*
+ * Main entry of app process.
+ *
+ * Starts the interpreted runtime, then starts up the application.
+ *
+ */
+
+#define LOG_TAG "appproc"
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <utils/Log.h>
+#include <cutils/process_name.h>
+#include <cutils/memory.h>
+#include <android_runtime/AndroidRuntime.h>
+
+#include <stdio.h>
+#include <unistd.h>
+
+namespace android {
+
+void app_usage()
+{
+    fprintf(stderr,
+        "Usage: oat_process [java-options] cmd-dir start-class-name [options]\n");
+}
+
+class AppRuntime : public AndroidRuntime
+{
+public:
+    AppRuntime()
+        : mParentDir(NULL)
+        , mClassName(NULL)
+        , mClass(NULL)
+        , mArgC(0)
+        , mArgV(NULL)
+    {
+    }
+
+#if 0
+    // this appears to be unused
+    const char* getParentDir() const
+    {
+        return mParentDir;
+    }
+#endif
+
+    const char* getClassName() const
+    {
+        return mClassName;
+    }
+
+    virtual void onVmCreated(JNIEnv* env)
+    {
+        if (mClassName == NULL) {
+            return; // Zygote. Nothing to do here.
+        }
+
+        /*
+         * This is a little awkward because the JNI FindClass call uses the
+         * class loader associated with the native method we're executing in.
+         * If called in onStarted (from RuntimeInit.finishInit because we're
+         * launching "am", for example), FindClass would see that we're calling
+         * from a boot class' native method, and so wouldn't look for the class
+         * we're trying to look up in CLASSPATH. Unfortunately it needs to,
+         * because the "am" classes are not boot classes.
+         *
+         * The easiest fix is to call FindClass here, early on before we start
+         * executing boot class Java code and thereby deny ourselves access to
+         * non-boot classes.
+         */
+        char* slashClassName = toSlashClassName(mClassName);
+        mClass = env->FindClass(slashClassName);
+        if (mClass == NULL) {
+            LOGE("ERROR: could not find class '%s'\n", mClassName);
+        }
+        free(slashClassName);
+
+        mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
+    }
+
+    virtual void onStarted()
+    {
+        sp<ProcessState> proc = ProcessState::self();
+        LOGV("App process: starting thread pool.\n");
+        proc->startThreadPool();
+
+        AndroidRuntime* ar = AndroidRuntime::getRuntime();
+        ar->callMain(mClassName, mClass, mArgC, mArgV);
+
+        IPCThreadState::self()->stopProcess();
+    }
+
+    virtual void onZygoteInit()
+    {
+        sp<ProcessState> proc = ProcessState::self();
+        LOGV("App process: starting thread pool.\n");
+        proc->startThreadPool();
+    }
+
+    virtual void onExit(int code)
+    {
+        if (mClassName == NULL) {
+            // if zygote
+            IPCThreadState::self()->stopProcess();
+        }
+
+        AndroidRuntime::onExit(code);
+    }
+
+
+    const char* mParentDir;
+    const char* mClassName;
+    jclass mClass;
+    int mArgC;
+    const char* const* mArgV;
+};
+
+}
+
+using namespace android;
+
+/*
+ * sets argv0 to as much of newArgv0 as will fit
+ */
+static void setArgv0(const char *argv0, const char *newArgv0)
+{
+    strlcpy(const_cast<char *>(argv0), newArgv0, strlen(argv0));
+}
+
+int main(int argc, const char* const argv[])
+{
+    // These are global variables in ProcessState.cpp
+    mArgC = argc;
+    mArgV = argv;
+
+    mArgLen = 0;
+    for (int i=0; i<argc; i++) {
+        mArgLen += strlen(argv[i]) + 1;
+    }
+    mArgLen--;
+
+    AppRuntime runtime;
+    const char* argv0 = argv[0];
+
+    // Process command line arguments
+    // ignore argv[0]
+    argc--;
+    argv++;
+
+    // Everything up to '--' or first non '-' arg goes to the vm
+
+    int i = runtime.addVmArguments(argc, argv);
+
+    // Parse runtime arguments.  Stop at first unrecognized option.
+    bool zygote = false;
+    bool startSystemServer = false;
+    bool application = false;
+    const char* parentDir = NULL;
+    const char* niceName = NULL;
+    const char* className = NULL;
+    while (i < argc) {
+        const char* arg = argv[i++];
+        if (!parentDir) {
+            parentDir = arg;
+        } else if (strcmp(arg, "--zygote") == 0) {
+            zygote = true;
+            niceName = "zygote";
+        } else if (strcmp(arg, "--start-system-server") == 0) {
+            startSystemServer = true;
+        } else if (strcmp(arg, "--application") == 0) {
+            application = true;
+        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
+            niceName = arg + 12;
+        } else {
+            className = arg;
+            break;
+        }
+    }
+
+    if (niceName && *niceName) {
+        setArgv0(argv0, niceName);
+        set_process_name(niceName);
+    }
+
+    runtime.mParentDir = parentDir;
+
+    if (zygote) {
+        runtime.start("com.android.internal.os.ZygoteInit",
+                startSystemServer ? "start-system-server" : "");
+    } else if (className) {
+        // Remainder of args get passed to startup class main()
+        runtime.mClassName = className;
+        runtime.mArgC = argc - i;
+        runtime.mArgV = argv + i;
+        runtime.start("com.android.internal.os.RuntimeInit",
+                application ? "application" : "tool");
+    } else {
+        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
+        app_usage();
+        LOG_ALWAYS_FATAL("oat_process: no class name or --zygote supplied.");
+        return 10;
+    }
+}
diff --git a/oat_runtime/Android.mk b/oat_runtime/Android.mk
new file mode 100644
index 0000000..4d5416a
--- /dev/null
+++ b/oat_runtime/Android.mk
@@ -0,0 +1,256 @@
+LOCAL_PATH:= $(call my-dir)/../../frameworks/base/core/jni
+
+local_cflags += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
+local_cflags += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
+local_cflags += -U__APPLE__
+
+ifeq ($(TARGET_ARCH), arm)
+	local_cflags += -DPACKED="__attribute__ ((packed))"
+else
+	local_cflags += -DPACKED=""
+endif
+
+ifeq ($(WITH_JIT),true)
+	local_cflags += -DWITH_JIT
+endif
+
+ifneq ($(USE_CUSTOM_RUNTIME_HEAP_MAX),)
+  local_cflags += -DCUSTOM_RUNTIME_HEAP_MAX=$(USE_CUSTOM_RUNTIME_HEAP_MAX)
+endif
+
+ifeq ($(USE_OPENGL_RENDERER),true)
+	local_cflags += -DUSE_OPENGL_RENDERER
+endif
+
+local_cflags += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+local_src_files:= \
+	ActivityManager.cpp \
+	AndroidRuntime.cpp \
+	Time.cpp \
+	com_android_internal_content_NativeLibraryHelper.cpp \
+	com_google_android_gles_jni_EGLImpl.cpp \
+	com_google_android_gles_jni_GLImpl.cpp.arm \
+	android_app_NativeActivity.cpp \
+	android_opengl_GLES10.cpp \
+	android_opengl_GLES10Ext.cpp \
+	android_opengl_GLES11.cpp \
+	android_opengl_GLES11Ext.cpp \
+	android_opengl_GLES20.cpp \
+	android_database_CursorWindow.cpp \
+	android_database_SQLiteCompiledSql.cpp \
+	android_database_SQLiteDebug.cpp \
+	android_database_SQLiteDatabase.cpp \
+	android_database_SQLiteProgram.cpp \
+	android_database_SQLiteQuery.cpp \
+	android_database_SQLiteStatement.cpp \
+	android_emoji_EmojiFactory.cpp \
+	android_view_Display.cpp \
+	android_view_Surface.cpp \
+	android_view_TextureView.cpp \
+	android_view_InputChannel.cpp \
+	android_view_InputQueue.cpp \
+	android_view_KeyEvent.cpp \
+	android_view_KeyCharacterMap.cpp \
+	android_view_GLES20Canvas.cpp \
+	android_view_MotionEvent.cpp \
+	android_view_PointerIcon.cpp \
+	android_view_VelocityTracker.cpp \
+	android_text_AndroidCharacter.cpp \
+	android_text_AndroidBidi.cpp \
+	android_os_Debug.cpp \
+	android_os_FileUtils.cpp \
+	android_os_MemoryFile.cpp \
+	android_os_MessageQueue.cpp \
+	android_os_ParcelFileDescriptor.cpp \
+	android_os_Power.cpp \
+	android_os_StatFs.cpp \
+	android_os_SystemClock.cpp \
+	android_os_SystemProperties.cpp \
+	android_os_UEventObserver.cpp \
+	android_net_LocalSocketImpl.cpp \
+	android_net_NetUtils.cpp \
+	android_net_TrafficStats.cpp \
+	android_net_wifi_Wifi.cpp \
+	android_nio_utils.cpp \
+	android_nfc_NdefMessage.cpp \
+	android_nfc_NdefRecord.cpp \
+	android_text_format_Time.cpp \
+	android_util_AssetManager.cpp \
+	android_util_Binder.cpp \
+	android_util_EventLog.cpp \
+	android_util_Log.cpp \
+	android_util_FloatMath.cpp \
+	android_util_Process.cpp \
+	android_util_StringBlock.cpp \
+	android_util_XmlBlock.cpp \
+	android/graphics/AutoDecodeCancel.cpp \
+	android/graphics/Bitmap.cpp \
+	android/graphics/BitmapFactory.cpp \
+	android/graphics/Camera.cpp \
+	android/graphics/Canvas.cpp \
+	android/graphics/ColorFilter.cpp \
+	android/graphics/DrawFilter.cpp \
+	android/graphics/CreateJavaOutputStreamAdaptor.cpp \
+	android/graphics/Graphics.cpp \
+	android/graphics/HarfbuzzSkia.cpp \
+	android/graphics/Interpolator.cpp \
+	android/graphics/LayerRasterizer.cpp \
+	android/graphics/MaskFilter.cpp \
+	android/graphics/Matrix.cpp \
+	android/graphics/Movie.cpp \
+	android/graphics/NinePatch.cpp \
+	android/graphics/NinePatchImpl.cpp \
+	android/graphics/NinePatchPeeker.cpp \
+	android/graphics/Paint.cpp \
+	android/graphics/Path.cpp \
+	android/graphics/PathMeasure.cpp \
+	android/graphics/PathEffect.cpp \
+	android_graphics_PixelFormat.cpp \
+	android/graphics/Picture.cpp \
+	android/graphics/PorterDuff.cpp \
+	android/graphics/BitmapRegionDecoder.cpp \
+	android/graphics/Rasterizer.cpp \
+	android/graphics/Region.cpp \
+	android/graphics/Shader.cpp \
+	android/graphics/SurfaceTexture.cpp \
+	android/graphics/TextLayout.cpp \
+	android/graphics/TextLayoutCache.cpp \
+	android/graphics/Typeface.cpp \
+	android/graphics/Utils.cpp \
+	android/graphics/Xfermode.cpp \
+	android/graphics/YuvToJpegEncoder.cpp \
+	android_media_AudioRecord.cpp \
+	android_media_AudioSystem.cpp \
+	android_media_AudioTrack.cpp \
+	android_media_JetPlayer.cpp \
+	android_media_ToneGenerator.cpp \
+	android_hardware_Camera.cpp \
+	android_hardware_SensorManager.cpp \
+	android_hardware_UsbDevice.cpp \
+	android_hardware_UsbDeviceConnection.cpp \
+	android_hardware_UsbRequest.cpp \
+	android_debug_JNITest.cpp \
+	android_util_FileObserver.cpp \
+	android/opengl/poly_clip.cpp.arm \
+	android/opengl/util.cpp.arm \
+	android_bluetooth_HeadsetBase.cpp \
+	android_bluetooth_common.cpp \
+	android_bluetooth_BluetoothAudioGateway.cpp \
+	android_bluetooth_BluetoothSocket.cpp \
+	android_bluetooth_c.c \
+	android_server_BluetoothService.cpp \
+	android_server_BluetoothEventLoop.cpp \
+	android_server_BluetoothA2dpService.cpp \
+	android_server_Watchdog.cpp \
+	android_ddm_DdmHandleNativeHeap.cpp \
+	com_android_internal_os_ZygoteInit.cpp \
+	android_backup_BackupDataInput.cpp \
+	android_backup_BackupDataOutput.cpp \
+	android_backup_FileBackupHelperBase.cpp \
+	android_backup_BackupHelperDispatcher.cpp \
+	android_app_backup_FullBackup.cpp \
+	android_content_res_ObbScanner.cpp \
+	android_content_res_Configuration.cpp \
+    android_animation_PropertyValuesHolder.cpp
+
+local_c_includes += \
+	$(LOCAL_PATH)/android/graphics \
+	$(LOCAL_PATH)/../../libs/hwui \
+	$(call include-path-for, bluedroid) \
+	$(call include-path-for, libhardware)/hardware \
+	$(call include-path-for, libhardware_legacy)/hardware_legacy \
+	$(LOCAL_PATH)/../../include/ui \
+	$(LOCAL_PATH)/../../include/utils \
+	external/skia/include/core \
+	external/skia/include/effects \
+	external/skia/include/images \
+	external/skia/src/ports \
+	external/skia/include/utils \
+	external/sqlite/dist \
+	external/sqlite/android \
+	external/expat/lib \
+	external/openssl/include \
+	external/tremor/Tremor \
+	external/icu4c/i18n \
+	external/icu4c/common \
+	external/jpeg \
+	external/harfbuzz/contrib \
+	external/harfbuzz/src \
+	external/zlib \
+	frameworks/opt/emoji
+
+local_shared_libraries := \
+	libexpat \
+	libnativehelper \
+	libcutils \
+	libutils \
+	libbinder \
+	libnetutils \
+	libui \
+	libgui \
+	libcamera_client \
+	libskia \
+	libsqlite \
+	libEGL \
+	libGLESv1_CM \
+	libGLESv2 \
+	libETC1 \
+	libhardware \
+	libhardware_legacy \
+	libsonivox \
+	libcrypto \
+	libssl \
+	libicuuc \
+	libicui18n \
+	libmedia \
+	libwpa_client \
+	libjpeg \
+	libnfc_ndef \
+	libusbhost \
+	libharfbuzz \
+	libz \
+
+ifeq ($(USE_OPENGL_RENDERER),true)
+	local_shared_libraries += libhwui
+endif
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+local_c_includes += \
+	external/dbus \
+	system/bluetooth/bluez-clean-headers
+local_cflags += -DHAVE_BLUETOOTH
+local_shared_libraries += libbluedroid libdbus
+endif
+
+local_shared_libraries += \
+	libdl
+# we need to access the private Bionic header
+# <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
+local_cflags += -I$(LOCAL_PATH)/../../../../bionic/libc/private
+
+local_ldlibs += -lpthread -ldl
+
+ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
+	local_cflags += -DMALLOC_LEAK_CHECK
+endif
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := $(local_cflags)
+LOCAL_SRC_FILES := $(local_src_files)
+LOCAL_C_INCLUDES := $(local_c_includes)
+LOCAL_SHARED_LIBRARIES := libart $(local_shared_libraries)
+LOCAL_LDLIBS := $(local_ldlibs)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE:= liboat_runtime
+include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := $(local_cflags)
+LOCAL_SRC_FILES := $(local_src_files)
+LOCAL_C_INCLUDES := $(local_c_includes)
+LOCAL_SHARED_LIBRARIES := libartd $(local_shared_libraries)
+LOCAL_LDLIBS := $(local_ldlibs)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE:= liboat_runtimed
+include $(BUILD_SHARED_LIBRARY)
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_);
   }