Interpret class initializers when building image.

We initialize all image classes with the interpreter if they have a
class/static initializer.
Black list classes whose initializers need access to on device native
code. If such classes are added to the image classes they will fail when
they attempt to enter JNI code. A number of "intrinsic" style JNI
routines are special cased to allow more than just trivial class
initializers to run.
Add a lock for initialization in the compiler to serialize the execution
of class initializers and avoid deadlock.
Remove InSourceSpace from image writer (cruft) and teach the image writer
to fix up referent fields in references.
Fix bugs in the interprerter and implement filled-new-array.
Factor some VM code to more easily share between the interpreter and
JNI entry points.

Change-Id: I6bb811dea84f1b82260b1a4e73ac7412179c0b41
diff --git a/src/class_linker.cc b/src/class_linker.cc
index abb6dcf..dc86aed 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -34,6 +34,7 @@
 #include "dex_file.h"
 #include "heap.h"
 #include "intern_table.h"
+#include "interpreter/interpreter.h"
 #include "leb128.h"
 #include "logging.h"
 #include "oat_file.h"
@@ -2574,7 +2575,6 @@
 
     clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
     if (clinit != NULL && !can_run_clinit) {
-      DCHECK_EQ(klass->GetStatus(), Class::kStatusVerified) << PrettyClass(klass);
       // if the class has a <clinit> but we can't run it during compilation,
       // don't bother going to kStatusInitializing. We return false so that
       // sub-classes don't believe this class is initialized.
@@ -2630,7 +2630,11 @@
   bool has_static_field_initializers = InitializeStaticFields(klass);
 
   if (clinit != NULL) {
-    clinit->Invoke(self, NULL, NULL, NULL);
+    if (Runtime::Current()->IsStarted()) {
+      clinit->Invoke(self, NULL, NULL, NULL);
+    } else {
+      art::interpreter::EnterInterpreterFromInvoke(self, clinit, NULL, NULL, NULL);
+    }
   }
 
   FixupStaticTrampolines(klass);
@@ -3432,8 +3436,8 @@
   }
 
   // We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it.
-  std::string descriptor(ClassHelper(klass.get(), this).GetDescriptor());
-  if (!is_static &&  descriptor == "Ljava/lang/ref/Reference;") {
+  if (!is_static &&
+      StringPiece(ClassHelper(klass.get(), this).GetDescriptor()) == "Ljava/lang/ref/Reference;") {
     // We know there are no non-reference fields in the Reference classes, and we know
     // that 'referent' is alphabetically last, so this is easy...
     CHECK_EQ(num_reference_fields, num_fields);
@@ -3457,7 +3461,8 @@
     fh.ChangeField(field);
     Primitive::Type type = fh.GetTypeAsPrimitiveType();
     bool is_primitive = type != Primitive::kPrimNot;
-    if (descriptor == "Ljava/lang/ref/Reference;" && StringPiece(fh.GetName()) == "referent") {
+    if (StringPiece(ClassHelper(klass.get(), this).GetDescriptor()) == "Ljava/lang/ref/Reference;" &&
+        StringPiece(fh.GetName()) == "referent") {
       is_primitive = true; // We lied above, so we have to expect a lie here.
     }
     if (is_primitive) {
diff --git a/src/compiler.cc b/src/compiler.cc
index 4029a01..09360c1 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -535,7 +535,7 @@
 
   Verify(class_loader, dex_files, timings);
 
-  InitializeClassesWithoutClinit(class_loader, dex_files, timings);
+  InitializeClasses(class_loader, dex_files, timings);
 }
 
 bool Compiler::IsImageClass(const std::string& descriptor) const {
@@ -1235,8 +1235,186 @@
   timings.AddSplit("Verify " + dex_file.GetLocation());
 }
 
-static void InitializeClassWithoutClinit(const CompilationContext* context,
-                                         size_t class_def_index)
+static const char* class_initializer_black_list[] = {
+  "Landroid/app/ActivityThread;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Landroid/bluetooth/BluetoothAudioGateway;", // Calls android.bluetooth.BluetoothAudioGateway.classInitNative().
+  "Landroid/bluetooth/HeadsetBase;", // Calls android.bluetooth.HeadsetBase.classInitNative().
+  "Landroid/content/res/CompatibilityInfo;", // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
+  "Landroid/content/res/CompatibilityInfo$1;", // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
+  "Landroid/content/UriMatcher;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Landroid/database/CursorWindow;", // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
+  "Landroid/database/sqlite/SQLiteConnection;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Landroid/database/sqlite/SQLiteConnection$Operation;", // Requires SimpleDateFormat -> java.util.Locale.
+  "Landroid/database/sqlite/SQLiteDatabaseConfiguration;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Landroid/database/sqlite/SQLiteDebug;", // Calls android.util.Log.isLoggable.
+  "Landroid/database/sqlite/SQLiteOpenHelper;", // Calls Class.getSimpleName -> Class.isAnonymousClass -> Class.getDex.
+  "Landroid/database/sqlite/SQLiteQueryBuilder;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Landroid/drm/DrmManagerClient;", // Calls System.loadLibrary.
+  "Landroid/graphics/drawable/AnimatedRotateDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/AnimationDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/BitmapDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/ClipDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/ColorDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/Drawable;", // Requires android.graphics.Rect.
+  "Landroid/graphics/drawable/DrawableContainer;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/GradientDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/LayerDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/NinePatchDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/RotateDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/ScaleDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/ShapeDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/StateListDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/drawable/TransitionDrawable;", // Sub-class of Drawable.
+  "Landroid/graphics/Matrix;", // Calls android.graphics.Matrix.native_create.
+  "Landroid/graphics/Matrix$1;", // Requires Matrix.
+  "Landroid/graphics/PixelFormat;", // Calls android.graphics.PixelFormat.nativeClassInit().
+  "Landroid/graphics/Rect;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Landroid/graphics/SurfaceTexture;", // Calls android.graphics.SurfaceTexture.nativeClassInit().
+  "Landroid/graphics/Typeface;", // Calls android.graphics.Typeface.nativeCreate.
+  "Landroid/inputmethodservice/ExtractEditText;", // Requires android.widget.TextView.
+  "Landroid/media/CameraProfile;", // Calls System.loadLibrary.
+  "Landroid/media/DecoderCapabilities;", // Calls System.loadLibrary.
+  "Landroid/media/MediaFile;", // Requires DecoderCapabilities.
+  "Landroid/media/MediaPlayer;", // Calls System.loadLibrary.
+  "Landroid/media/MediaRecorder;", // Calls System.loadLibrary.
+  "Landroid/media/MediaScanner;", // Calls System.loadLibrary.
+  "Landroid/net/NetworkInfo;", // Calls java.util.EnumMap.<init> -> java.lang.Enum.getSharedConstants -> System.identityHashCode.
+  "Landroid/net/Proxy;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Landroid/net/SSLCertificateSocketFactory;", // Requires javax.net.ssl.HttpsURLConnection.
+  "Landroid/net/Uri;", // Calls Class.getSimpleName -> Class.isAnonymousClass -> Class.getDex.
+  "Landroid/net/Uri$AbstractHierarchicalUri;", // Requires Uri.
+  "Landroid/net/Uri$HierarchicalUri;", // Requires Uri.
+  "Landroid/net/Uri$OpaqueUri;", // Requires Uri.
+  "Landroid/net/Uri$StringUri;", // Requires Uri.
+  "Landroid/net/WebAddress;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Landroid/nfc/NdefRecord;", // Calls String.getBytes -> java.nio.charset.Charset.
+  "Landroid/opengl/GLES10;", // Calls android.opengl.GLES10._nativeClassInit.
+  "Landroid/opengl/GLES10Ext;", // Calls android.opengl.GLES10Ext._nativeClassInit.
+  "Landroid/opengl/GLES11;", // Requires GLES10.
+  "Landroid/opengl/GLES11Ext;", // Calls android.opengl.GLES11Ext._nativeClassInit.
+  "Landroid/opengl/GLES20;", // Calls android.opengl.GLES20._nativeClassInit.
+  "Landroid/opengl/GLUtils;", // Calls android.opengl.GLUtils.nativeClassInit.
+  "Landroid/os/Build;", // Calls -..-> android.os.SystemProperties.native_get.
+  "Landroid/os/Build$VERSION;", // Requires Build.
+  "Landroid/os/Debug;", // Requires android.os.Environment.
+  "Landroid/os/Environment;", // Calls System.getenv.
+  "Landroid/os/FileUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Landroid/os/StrictMode;", // Calls android.util.Log.isLoggable.
+  "Landroid/os/StrictMode$VmPolicy;", // Requires StrictMode.
+  "Landroid/os/Trace;", // Calls android.os.Trace.nativeGetEnabledTags.
+  "Landroid/os/UEventObserver;", // Calls Class.getSimpleName -> Class.isAnonymousClass -> Class.getDex.
+  "Landroid/provider/Settings$Secure;", // Requires android.net.Uri.
+  "Landroid/provider/Settings$System;", // Requires android.net.Uri.
+  "Landroid/renderscript/RenderScript;", // Calls System.loadLibrary.
+  "Landroid/server/BluetoothService;", // Calls android.server.BluetoothService.classInitNative.
+  "Landroid/server/BluetoothEventLoop;", // Calls android.server.BluetoothEventLoop.classInitNative.
+  "Landroid/telephony/PhoneNumberUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Landroid/text/AutoText;", // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
+  "Landroid/text/Layout;", // Calls com.android.internal.util.ArrayUtils.emptyArray -> System.identityHashCode.
+  "Landroid/text/BoringLayout;", // Requires Layout.
+  "Landroid/text/DynamicLayout;", // Requires Layout.
+  "Landroid/text/Html$HtmlParser;", // Calls -..-> String.toLowerCase -> java.util.Locale.
+  "Landroid/text/StaticLayout;", // Requires Layout.
+  "Landroid/text/TextUtils;", // Requires android.util.DisplayMetrics.
+  "Landroid/util/DisplayMetrics;", // Calls SystemProperties.native_get_int.
+  "Landroid/util/Patterns;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Landroid/view/animation/Animation;", // Calls SystemProperties.native_get_boolean.
+  "Landroid/view/animation/AlphaAnimation;", // Requires Animation.
+  "Landroid/view/Choreographer;", // Calls SystemProperties.native_get_boolean.
+  "Landroid/view/GLES20Canvas;", // Calls android.view.GLES20Canvas.nIsAvailable.
+  "Landroid/view/GLES20RecordingCanvas;", // Requires android.view.GLES20Canvas.
+  "Landroid/view/HardwareRenderer$GlRenderer;", // Requires SystemProperties.native_get.
+  "Landroid/view/HardwareRenderer$Gl20Renderer;", // Requires SystemProperties.native_get.
+  "Landroid/view/InputEventConsistencyVerifier;", // Requires android.os.Build.
+  "Landroid/view/Surface;", // Requires SystemProperties.native_get.
+  "Landroid/webkit/JniUtil;", // Calls System.loadLibrary.
+  "Landroid/webkit/WebViewCore;", // Calls System.loadLibrary.
+  "Landroid/widget/AutoCompleteTextView;", // Requires TextView.
+  "Landroid/widget/Button;", // Requires TextView.
+  "Landroid/widget/CheckBox;", // Requires TextView.
+  "Landroid/widget/CheckedTextView;", // Requires TextView.
+  "Landroid/widget/CompoundButton;", // Requires TextView.
+  "Landroid/widget/EditText;", // Requires TextView.
+  "Landroid/widget/NumberPicker;", // Requires java.util.Locale.
+  "Landroid/widget/ScrollBarDrawable;", // Sub-class of Drawable.
+  "Landroid/widget/SearchView$SearchAutoComplete;", // Requires TextView.
+  "Landroid/widget/Switch;", // Requires TextView.
+  "Landroid/widget/TextView;", // Calls Paint.<init> -> Paint.native_init.
+  "Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Lcom/android/i18n/phonenumbers/PhoneNumberUtil;", // Requires java.util.logging.LogManager.
+  "Lcom/android/internal/os/SamplingProfilerIntegration;", // Calls SystemProperties.native_get_int.
+  "Lcom/android/internal/policy/impl/PhoneWindow;", // Calls android.os.Binder.init.
+  "Lcom/android/internal/view/menu/ActionMenuItemView;", // Requires TextView.
+  "Lcom/android/internal/widget/DialogTitle;", // Requires TextView.
+  "Lcom/android/org/bouncycastle/asn1/StreamUtil;", // Calls Runtime.getRuntime().maxMemory().
+  "Lcom/android/org/bouncycastle/crypto/digests/OpenSSLDigest$SHA1;", // Requires org.apache.harmony.xnet.provider.jsse.NativeCrypto.
+  "Lcom/android/org/bouncycastle/crypto/engines/RSABlindedEngine;", // Calls native ... -> java.math.NativeBN.BN_new().
+  "Lcom/android/org/bouncycastle/jce/provider/CertBlacklist;", // Calls System.getenv -> OsConstants.initConstants.
+  "Lcom/android/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi;", // Calls System.getenv -> OsConstants.initConstants.
+  "Lcom/google/android/gles_jni/EGLContextImpl;", // Calls com.google.android.gles_jni.EGLImpl._nativeClassInit.
+  "Lcom/google/android/gles_jni/EGLImpl;", // Calls com.google.android.gles_jni.EGLImpl._nativeClassInit.
+  "Lcom/google/android/gles_jni/GLImpl;", // Calls com.google.android.gles_jni.GLImpl._nativeClassInit.
+  "Ljava/io/Console;", // Has FileDescriptor(s).
+  "Ljava/io/File;", // Calls to Random.<init> -> System.currentTimeMillis -> OsConstants.initConstants.
+  "Ljava/io/FileDescriptor;", // Requires libcore.io.OsConstants.
+  "Ljava/io/ObjectInputStream;", // Requires java.lang.ClassLoader$SystemClassLoader.
+  "Ljava/io/ObjectStreamClass;",  // Calls to Class.forName -> java.io.FileDescriptor.
+  "Ljava/io/ObjectStreamConstants;", // Instance of non-image class SerializablePermission.
+  "Ljava/lang/ClassLoader$SystemClassLoader;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljava/lang/Runtime;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljava/lang/System;", // Calls OsConstants.initConstants.
+  "Ljava/math/BigDecimal;", // Calls native ... -> java.math.NativeBN.BN_new().
+  "Ljava/math/BigInteger;", // Calls native ... -> java.math.NativeBN.BN_new().
+  "Ljava/math/Multiplication;", // Calls native ... -> java.math.NativeBN.BN_new().
+  "Ljava/net/InetAddress;", // Requires libcore.io.OsConstants.
+  "Ljava/net/Inet4Address;", // Sub-class of InetAddress.
+  "Ljava/net/Inet6Address;", // Sub-class of InetAddress.
+  "Ljava/nio/charset/Charset;", // Calls Charset.getDefaultCharset -> System.getProperty -> OsConstants.initConstants.
+  "Ljava/nio/charset/CharsetICU;", // Sub-class of Charset.
+  "Ljava/nio/charset/Charsets;", // Calls Charset.forName.
+  "Ljava/security/Security;", // Tries to do disk IO for "security.properties".
+  "Ljava/util/Date;", // Calls Date.<init> -> System.currentTimeMillis -> OsConstants.initConstants.
+  "Ljava/util/Locale;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljava/util/SimpleTimeZone;", // Sub-class of TimeZone.
+  "Ljava/util/TimeZone;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+  "Ljava/util/concurrent/ConcurrentHashMap$Segment;", // Calls Runtime.getRuntime().availableProcessors().
+  "Ljava/util/logging/LogManager;", // Calls System.getProperty -> OsConstants.initConstants.
+  "Ljavax/microedition/khronos/egl/EGL10;", // Requires EGLContext.
+  "Ljavax/microedition/khronos/egl/EGLContext;", // Requires com.google.android.gles_jni.EGLImpl.
+  "Ljavax/net/ssl/HttpsURLConnection;", // Calls SSLSocketFactory.getDefault -> java.security.Security.getProperty.
+  "Llibcore/icu/LocaleData;", // Requires java.util.Locale.
+  "Llibcore/icu/TimeZones;", // Requires java.util.TimeZone.
+  "Llibcore/io/OsConstants;", // Platform specific.
+  "Llibcore/net/MimeUtils;", // Calls libcore.net.MimeUtils.getContentTypesPropertiesStream -> System.getProperty.
+  "Llibcore/util/ZoneInfo;", // Sub-class of TimeZone.
+  "Llibcore/util/ZoneInfoDB;", // Calls System.getenv -> OsConstants.initConstants.
+  "Lorg/apache/commons/logging/LogFactory;", // Calls System.getProperty.
+  "Lorg/apache/harmony/security/fortress/Services;", // Calls ClassLoader.getSystemClassLoader -> System.getProperty.
+  "Lorg/apache/harmony/security/provider/cert/X509CertFactoryImpl;", // Requires java.nio.charsets.Charsets.
+  "Lorg/apache/harmony/security/provider/crypto/RandomBitsSupplier;", // Requires java.io.File.
+  "Lorg/apache/harmony/security/utils/AlgNameMapper;", // Requires java.util.Locale.
+  "Lorg/apache/harmony/security/x501/AttributeTypeAndValue;", // Calls IntegralToString.convertInt -> Thread.currentThread.
+  "Lorg/apache/harmony/security/x501/DirectoryString;", // Requires BigInteger.
+  "Lorg/apache/harmony/security/x501/Name;", // Requires org.apache.harmony.security.x501.AttributeTypeAndValue.
+  "Lorg/apache/harmony/security/x509/Certificate;", // Requires org.apache.harmony.security.x509.TBSCertificate.
+  "Lorg/apache/harmony/security/x509/TBSCertificate;",  // Requires org.apache.harmony.security.x501.Name.
+  "Lorg/apache/harmony/security/x509/EDIPartyName;", // Calls native ... -> java.math.NativeBN.BN_new().
+  "Lorg/apache/harmony/security/x509/GeneralName;", // Requires org.apache.harmony.security.x501.Name.
+  "Lorg/apache/harmony/security/x509/GeneralNames;", // Requires GeneralName.
+  "Lorg/apache/harmony/security/x509/Time;", // Calls native ... -> java.math.NativeBN.BN_new().
+  "Lorg/apache/harmony/security/x509/Validity;", // Requires x509.Time.
+  "Lorg/apache/harmony/xml/ExpatParser;", // Calls native ExpatParser.staticInitialize.
+  "Lorg/apache/harmony/xnet/provider/jsse/NativeCrypto;", // Calls native NativeCrypto.clinit().
+  "Lorg/apache/harmony/xnet/provider/jsse/OpenSSLMessageDigestJDK$MD5;", // Requires org.apache.harmony.xnet.provider.jsse.NativeCrypto.
+  "Lorg/apache/harmony/xnet/provider/jsse/OpenSSLMessageDigestJDK$SHA1;", // Requires org.apache.harmony.xnet.provider.jsse.NativeCrypto.
+  "Lorg/apache/harmony/xnet/provider/jsse/OpenSSLMessageDigestJDK$SHA512;", // Requires org.apache.harmony.xnet.provider.jsse.NativeCrypto.
+  "Lorg/apache/harmony/xnet/provider/jsse/TrustedCertificateStore;", // Calls System.getenv -> OsConstants.initConstants.
+  "Lorg/apache/http/conn/params/ConnRouteParams;", // Requires java.util.Locale.
+  "Lorg/apache/http/conn/ssl/SSLSocketFactory;", // Calls java.security.Security.getProperty.
+  "Lorg/apache/http/conn/util/InetAddressUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
+};
+
+static void InitializeClass(const CompilationContext* context, size_t class_def_index)
     LOCKS_EXCLUDED(Locks::mutator_lock_) {
   const DexFile::ClassDef& class_def = context->GetDexFile()->GetClassDef(class_def_index);
   ScopedObjectAccess soa(Thread::Current());
@@ -1244,14 +1422,47 @@
   const char* descriptor = context->GetDexFile()->GetClassDescriptor(class_def);
   Class* klass = context->GetClassLinker()->FindClass(descriptor, class_loader);
   Thread* self = Thread::Current();
+  bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
+  bool can_init_static_fields = compiling_boot &&
+      context->GetCompiler()->IsImageClass(descriptor);
   if (klass != NULL) {
-    ObjectLock lock(self, klass);
+    // We don't want class initialization occurring on multiple threads due to deadlock problems.
+    // For example, a parent class is initialized (holding its lock) that refers to a sub-class
+    // in its static/class initializer causing it to try to acquire the sub-class' lock. While
+    // on a second thread the sub-class is initialized (holding its lock) after first initializing
+    // its parents, whose locks are acquired. This leads to a parent-to-child and a child-to-parent
+    // lock ordering and consequent potential deadlock.
+    static Mutex lock1("Initializer lock", kMonitorLock);
+    MutexLock mu(self, lock1);
+    // The lock required to initialize the class.
+    ObjectLock lock2(self, klass);
+    // Only try to initialize classes that were successfully verified.
     if (klass->IsVerified()) {
-      // Only try to initialize classes that were successfully verified.
-      bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
-      bool can_init_static_fields = compiling_boot &&
-          context->GetCompiler()->IsImageClass(descriptor);
       context->GetClassLinker()->EnsureInitialized(klass, false, can_init_static_fields);
+      if (!klass->IsInitialized()) {
+        if (can_init_static_fields) {
+          bool is_black_listed = false;
+          for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
+            if (StringPiece(descriptor) == class_initializer_black_list[i]) {
+              is_black_listed = true;
+              break;
+            }
+          }
+          if (!is_black_listed) {
+            LOG(INFO) << "Initializing: " << descriptor;
+            if (StringPiece(descriptor) == "Ljava/lang/Void;"){
+              // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
+              ObjectArray<Field>* fields = klass->GetSFields();
+              CHECK_EQ(fields->GetLength(), 1);
+              fields->Get(0)->SetObj(klass, context->GetClassLinker()->FindPrimitiveClass('V'));
+              klass->SetStatus(Class::kStatusInitialized);
+            } else {
+              context->GetClassLinker()->EnsureInitialized(klass, true, can_init_static_fields);
+            }
+            CHECK(!self->IsExceptionPending()) << self->GetException()->Dump();
+          }
+        }
+      }
       // If successfully initialized place in SSB array.
       if (klass->IsInitialized()) {
         klass->GetDexCache()->GetInitializedStaticStorage()->Set(klass->GetDexTypeIndex(), klass);
@@ -1272,21 +1483,27 @@
   self->ClearException();
 }
 
-void Compiler::InitializeClassesWithoutClinit(jobject jni_class_loader, const DexFile& dex_file,
+void Compiler::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file,
                                               TimingLogger& timings) {
+#ifndef NDEBUG
+  for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
+    const char* descriptor = class_initializer_black_list[i];
+    CHECK(IsValidDescriptor(descriptor)) << descriptor;
+  }
+#endif
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   CompilationContext context(class_linker, jni_class_loader, this, &dex_file, thread_pool_.get());
-  context.ForAll(0, dex_file.NumClassDefs(), InitializeClassWithoutClinit, thread_count_);
+  context.ForAll(0, dex_file.NumClassDefs(), InitializeClass, thread_count_);
   timings.AddSplit("InitializeNoClinit " + dex_file.GetLocation());
 }
 
-void Compiler::InitializeClassesWithoutClinit(jobject class_loader,
-                                              const std::vector<const DexFile*>& dex_files,
-                                              TimingLogger& timings) {
+void Compiler::InitializeClasses(jobject class_loader,
+                                 const std::vector<const DexFile*>& dex_files,
+                                 TimingLogger& timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
     CHECK(dex_file != NULL);
-    InitializeClassesWithoutClinit(class_loader, *dex_file, timings);
+    InitializeClasses(class_loader, *dex_file, timings);
   }
 }
 
diff --git a/src/compiler.h b/src/compiler.h
index ba56513..39ee5e4 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -281,11 +281,11 @@
   void VerifyDexFile(jobject class_loader, const DexFile& dex_file, TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
-  void InitializeClassesWithoutClinit(jobject class_loader,
+  void InitializeClasses(jobject class_loader,
                                       const std::vector<const DexFile*>& dex_files,
                                       TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
-  void InitializeClassesWithoutClinit(jobject class_loader, const DexFile& dex_file,
+  void InitializeClasses(jobject class_loader, const DexFile& dex_file,
                                       TimingLogger& timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_, compiled_classes_lock_);
 
diff --git a/src/heap.cc b/src/heap.cc
index cf13eae..d12d20e 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -1984,11 +1984,14 @@
 void Heap::EnqueueClearedReferences(Object** cleared) {
   DCHECK(cleared != NULL);
   if (*cleared != NULL) {
-    ScopedObjectAccess soa(Thread::Current());
-    JValue args[1];
-    args[0].SetL(*cleared);
-    soa.DecodeMethod(WellKnownClasses::java_lang_ref_ReferenceQueue_add)->Invoke(soa.Self(), NULL,
-                                                                                 args, NULL);
+    // When a runtime isn't started there are no reference queues to care about so ignore.
+    if (LIKELY(Runtime::Current()->IsStarted())) {
+      ScopedObjectAccess soa(Thread::Current());
+      JValue args[1];
+      args[0].SetL(*cleared);
+      soa.DecodeMethod(WellKnownClasses::java_lang_ref_ReferenceQueue_add)->Invoke(soa.Self(), NULL,
+                                                                                   args, NULL);
+    }
     *cleared = NULL;
   }
 }
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 642cee6..a9aa2e0 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -61,9 +61,7 @@
   const std::vector<DexCache*>& all_dex_caches = class_linker->GetDexCaches();
   for (size_t i = 0; i < all_dex_caches.size(); i++) {
     DexCache* dex_cache = all_dex_caches[i];
-    if (InSourceSpace(dex_cache)) {
-      dex_caches_.insert(dex_cache);
-    }
+    dex_caches_.insert(dex_cache);
   }
 
   oat_file_ = OatFile::Open(oat_filename, oat_location, NULL,
@@ -122,17 +120,6 @@
   return true;
 }
 
-bool ImageWriter::InSourceSpace(const Object* object) const {
-  const Spaces& spaces = Runtime::Current()->GetHeap()->GetSpaces();
-  // TODO: C++0x auto
-  for (Spaces::const_iterator cur = spaces.begin(); cur != spaces.end(); ++cur) {
-    if ((*cur)->IsAllocSpace() && (*cur)->Contains(object)) {
-      return true;
-    }
-  }
-  return false;
-}
-
 bool ImageWriter::AllocMemory() {
   const Spaces& spaces = Runtime::Current()->GetHeap()->GetSpaces();
   size_t size = 0;
@@ -307,9 +294,6 @@
   DCHECK(obj != NULL);
   DCHECK(arg != NULL);
   ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
-  if (!image_writer->InSourceSpace(obj)) {
-    return;
-  }
 
   // if it is a string, we want to intern it if its not interned.
   if (obj->GetClass()->IsStringClass()) {
@@ -439,9 +423,6 @@
   DCHECK(arg != NULL);
   const Object* obj = object;
   ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
-  if (!image_writer->InSourceSpace(object)) {
-    return;
-  }
 
   // see GetLocalAddress for similar computation
   size_t offset = image_writer->GetImageOffset(obj);
@@ -607,6 +588,14 @@
       }
     }
   }
+  if (!is_static && orig->IsReferenceInstance()) {
+    // Fix-up referent, that isn't marked as an object field, for References.
+    Field* field = orig->GetClass()->FindInstanceField("referent", "Ljava/lang/Object;");
+    MemberOffset field_offset = field->GetOffset();
+    const Object* ref = orig->GetFieldObject<const Object*>(field_offset, false);
+    // Use SetFieldPtr to avoid card marking since we are writing to the image.
+    copy->SetFieldPtr(field_offset, GetImageAddress(ref), false);
+  }
 }
 
 static AbstractMethod* GetTargetMethod(const Compiler::PatchInformation* patch)
diff --git a/src/image_writer.h b/src/image_writer.h
index 638add7..0a0854a 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -81,16 +81,10 @@
     return offsets_.find(object)->second;
   }
 
-  bool InSourceSpace(const Object* object) const;
-
   Object* GetImageAddress(const Object* object) const {
     if (object == NULL) {
       return NULL;
     }
-    // if object outside the relocating source_space_, assume unchanged
-    if (!InSourceSpace(object)) {
-      return const_cast<Object*>(object);
-    }
     return reinterpret_cast<Object*>(image_begin_ + GetImageOffset(object));
   }
 
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index 550c6ee..388eb85 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -22,6 +22,7 @@
 #include "dex_instruction.h"
 #include "invoke_arg_array_builder.h"
 #include "logging.h"
+#include "nth_caller_visitor.h"
 #include "object.h"
 #include "object_utils.h"
 #include "runtime_support.h"
@@ -32,6 +33,310 @@
 namespace art {
 namespace interpreter {
 
+static void UnstartedRuntimeInvoke(Thread* self, AbstractMethod* target_method,
+                                   Object* receiver, JValue* args, JValue* result)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  // In a runtime that's not started we intercept certain methods to avoid complicated dependency
+  // problems in core libraries.
+  std::string name(PrettyMethod(target_method));
+  if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
+    std::string descriptor(DotToDescriptor(args[0].GetL()->AsString()->ToModifiedUtf8().c_str()));
+    ClassLoader* class_loader = NULL; // shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
+    Class* found = Runtime::Current()->GetClassLinker()->FindClass(descriptor.c_str(),
+                                                                   class_loader);
+    CHECK(found != NULL) << "Class.forName failed in un-started runtime for class: "
+        << PrettyDescriptor(descriptor);
+    result->SetL(found);
+  } else if (name == "java.lang.Object java.lang.Class.newInstance()") {
+    Class* klass = receiver->AsClass();
+    AbstractMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V");
+    CHECK(c != NULL);
+    Object* obj = klass->AllocObject(self);
+    CHECK(obj != NULL);
+    EnterInterpreterFromInvoke(self, c, obj, NULL, NULL);
+    result->SetL(obj);
+  } else if (name == "java.lang.reflect.Field java.lang.Class.getDeclaredField(java.lang.String)") {
+    // Special managed code cut-out to allow field lookup in a un-started runtime that'd fail
+    // going the reflective Dex way.
+    Class* klass = receiver->AsClass();
+    String* name = args[0].GetL()->AsString();
+    Field* found = NULL;
+    FieldHelper fh;
+    ObjectArray<Field>* fields = klass->GetIFields();
+    for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) {
+      Field* f = fields->Get(i);
+      fh.ChangeField(f);
+      if (name->Equals(fh.GetName())) {
+        found = f;
+      }
+    }
+    if (found == NULL) {
+      fields = klass->GetSFields();
+      for (int32_t i = 0; i < fields->GetLength() && found == NULL; ++i) {
+        Field* f = fields->Get(i);
+        fh.ChangeField(f);
+        if (name->Equals(fh.GetName())) {
+          found = f;
+        }
+      }
+    }
+    CHECK(found != NULL)
+      << "Failed to find field in Class.getDeclaredField in un-started runtime. name="
+      << name->ToModifiedUtf8() << " class=" << PrettyDescriptor(klass);
+    // TODO: getDeclaredField calls GetType once the field is found to ensure a
+    //       NoClassDefFoundError is thrown if the field's type cannot be resolved.
+    result->SetL(found);
+  } else if (name == "void java.lang.System.arraycopy(java.lang.Object, int, java.lang.Object, int, int)") {
+    // Special case array copying without initializing System.
+    Class* ctype = args[0].GetL()->GetClass()->GetComponentType();
+    jint srcPos = args[1].GetI();
+    jint dstPos = args[3].GetI();
+    jint length = args[4].GetI();
+    if (!ctype->IsPrimitive()) {
+      ObjectArray<Object>* src = args[0].GetL()->AsObjectArray<Object>();
+      ObjectArray<Object>* dst = args[2].GetL()->AsObjectArray<Object>();
+      for (jint i = 0; i < length; ++i) {
+        dst->Set(dstPos + i, src->Get(srcPos + i));
+      }
+    } else if (ctype->IsPrimitiveChar()) {
+      CharArray* src = args[0].GetL()->AsCharArray();
+      CharArray* dst = args[2].GetL()->AsCharArray();
+      for (jint i = 0; i < length; ++i) {
+        dst->Set(dstPos + i, src->Get(srcPos + i));
+      }
+    } else if (ctype->IsPrimitiveInt()) {
+      IntArray* src = args[0].GetL()->AsIntArray();
+      IntArray* dst = args[2].GetL()->AsIntArray();
+      for (jint i = 0; i < length; ++i) {
+        dst->Set(dstPos + i, src->Get(srcPos + i));
+      }
+    } else {
+      UNIMPLEMENTED(FATAL) << "System.arraycopy of unexpected type: " << PrettyDescriptor(ctype);
+    }
+  } else {
+    // Not special, continue with regular interpreter execution.
+    EnterInterpreterFromInvoke(self, target_method, receiver, args, result);
+  }
+}
+
+// Hand select a number of methods to be run in a not yet started runtime without using JNI.
+static void UnstartedRuntimeJni(Thread* self, AbstractMethod* method,
+                                Object* receiver, JValue* args, JValue* result)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  std::string name(PrettyMethod(method));
+  if (name == "java.lang.ClassLoader dalvik.system.VMStack.getCallingClassLoader()") {
+    result->SetL(NULL);
+  } else if (name == "java.lang.Class dalvik.system.VMStack.getStackClass2()") {
+    NthCallerVisitor visitor(self->GetManagedStack(), NULL, 3);
+    visitor.WalkStack();
+    result->SetL(visitor.caller->GetDeclaringClass());
+  } else if (name == "double java.lang.Math.log(double)") {
+    result->SetD(log(args[0].GetD()));
+  } else if (name == "java.lang.String java.lang.Class.getNameNative()") {
+    result->SetL(receiver->AsClass()->ComputeName());
+  } else if (name == "int java.lang.Float.floatToRawIntBits(float)") {
+    result->SetI(args[0].GetI());
+  } else if (name == "float java.lang.Float.intBitsToFloat(int)") {
+    result->SetF(args[0].GetF());
+  } else if (name == "double java.lang.Math.exp(double)") {
+    result->SetD(exp(args[0].GetD()));
+  } else if (name == "java.lang.Object java.lang.Object.internalClone()") {
+    result->SetL(receiver->Clone(self));
+  } else if (name == "void java.lang.Object.notifyAll()") {
+    receiver->NotifyAll();
+  } else if (name == "int java.lang.String.compareTo(java.lang.String)") {
+    String* rhs = args[0].GetL()->AsString();
+    CHECK(rhs != NULL);
+    result->SetI(receiver->AsString()->CompareTo(rhs));
+  } else if (name == "java.lang.String java.lang.String.intern()") {
+    result->SetL(receiver->AsString()->Intern());
+  } else if (name == "int java.lang.String.fastIndexOf(int, int)") {
+    result->SetI(receiver->AsString()->FastIndexOf(args[0].GetI(), args[1].GetI()));
+  } else if (name == "java.lang.Object java.lang.reflect.Array.createMultiArray(java.lang.Class, int[])") {
+    result->SetL(Array::CreateMultiArray(self, args[0].GetL()->AsClass(), args[1].GetL()->AsIntArray()));
+  } else if (name == "java.lang.Object java.lang.Throwable.nativeFillInStackTrace()") {
+    ScopedObjectAccessUnchecked soa(self);
+    result->SetL(soa.Decode<Object*>(self->CreateInternalStackTrace(soa)));
+  } else if (name == "boolean java.nio.ByteOrder.isLittleEndian()") {
+    result->SetJ(JNI_TRUE);
+  } else if (name == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
+    Object* obj = args[0].GetL();
+    jlong offset = args[1].GetJ();
+    jint expectedValue = args[2].GetI();
+    jint newValue = args[3].GetI();
+    byte* raw_addr = reinterpret_cast<byte*>(obj) + offset;
+    volatile int32_t* address = reinterpret_cast<volatile int32_t*>(raw_addr);
+    // Note: android_atomic_release_cas() returns 0 on success, not failure.
+    int r = android_atomic_release_cas(expectedValue, newValue, address);
+    result->SetZ(r == 0);
+  } else if (name == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
+    Object* obj = args[0].GetL();
+    Object* newValue = args[2].GetL();
+    obj->SetFieldObject(MemberOffset(args[1].GetJ()), newValue, false);
+  } else {
+    LOG(FATAL) << "Attempt to invoke native method in non-started runtime: " << name;
+  }
+}
+
+static void InterpreterJni(Thread* self, AbstractMethod* method, StringPiece shorty,
+                           Object* receiver, JValue* args, JValue* result)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  // TODO: The following enters JNI code using a typedef-ed function rather than the JNI compiler,
+  //       it should be removed and JNI compiled stubs used instead.
+  ScopedObjectAccessUnchecked soa(self);
+  if (method->IsStatic()) {
+    if (shorty == "L") {
+      typedef jobject (fnptr)(JNIEnv*, jclass);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetL(soa.Decode<Object*>(fn(soa.Env(), klass.get())));
+    } else if (shorty == "V") {
+      typedef void (fnptr)(JNIEnv*, jclass);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedThreadStateChange tsc(self, kNative);
+      fn(soa.Env(), klass.get());
+    } else if (shorty == "Z") {
+      typedef jboolean (fnptr)(JNIEnv*, jclass);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetZ(fn(soa.Env(), klass.get()));
+    } else if (shorty == "BI") {
+      typedef jbyte (fnptr)(JNIEnv*, jclass, jint);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetB(fn(soa.Env(), klass.get(), args[0].GetI()));
+    } else if (shorty == "II") {
+      typedef jint (fnptr)(JNIEnv*, jclass, jint);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetI(fn(soa.Env(), klass.get(), args[0].GetI()));
+    } else if (shorty == "LL") {
+      typedef jobject (fnptr)(JNIEnv*, jclass, jobject);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedLocalRef<jobject> arg0(soa.Env(),
+                                   soa.AddLocalReference<jobject>(args[0].GetL()));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetL(soa.Decode<Object*>(fn(soa.Env(), klass.get(), arg0.get())));
+    } else if (shorty == "IIZ") {
+      typedef jint (fnptr)(JNIEnv*, jclass, jint, jboolean);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetI(fn(soa.Env(), klass.get(), args[0].GetI(), args[1].GetZ()));
+    } else if (shorty == "ILI") {
+      typedef jint (fnptr)(JNIEnv*, jclass, jobject, jint);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedLocalRef<jobject> arg0(soa.Env(),
+                                   soa.AddLocalReference<jobject>(args[0].GetL()));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetI(fn(soa.Env(), klass.get(), arg0.get(), args[1].GetI()));
+    } else if (shorty == "SIZ") {
+      typedef jshort (fnptr)(JNIEnv*, jclass, jint, jboolean);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetS(fn(soa.Env(), klass.get(), args[0].GetI(), args[1].GetZ()));
+    } else if (shorty == "VIZ") {
+      typedef void (fnptr)(JNIEnv*, jclass, jint, jboolean);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedThreadStateChange tsc(self, kNative);
+      fn(soa.Env(), klass.get(), args[0].GetI(), args[1].GetZ());
+    } else if (shorty == "ZLL") {
+      typedef jboolean (fnptr)(JNIEnv*, jclass, jobject, jobject);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedLocalRef<jobject> arg0(soa.Env(),
+                                   soa.AddLocalReference<jobject>(args[0].GetL()));
+      ScopedLocalRef<jobject> arg1(soa.Env(),
+                                   soa.AddLocalReference<jobject>(args[1].GetL()));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetZ(fn(soa.Env(), klass.get(), arg0.get(), arg1.get()));
+    } else if (shorty == "ZILL") {
+      typedef jboolean (fnptr)(JNIEnv*, jclass, jint, jobject, jobject);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedLocalRef<jobject> arg1(soa.Env(),
+                                   soa.AddLocalReference<jobject>(args[1].GetL()));
+      ScopedLocalRef<jobject> arg2(soa.Env(),
+                                   soa.AddLocalReference<jobject>(args[2].GetL()));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetZ(fn(soa.Env(), klass.get(), args[0].GetI(), arg1.get(), arg2.get()));
+    } else if (shorty == "VILII") {
+      typedef void (fnptr)(JNIEnv*, jclass, jint, jobject, jint, jint);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedLocalRef<jobject> arg1(soa.Env(),
+                                   soa.AddLocalReference<jobject>(args[1].GetL()));
+      ScopedThreadStateChange tsc(self, kNative);
+      fn(soa.Env(), klass.get(), args[0].GetI(), arg1.get(), args[2].GetI(), args[3].GetI());
+    } else if (shorty == "VLILII") {
+      typedef void (fnptr)(JNIEnv*, jclass, jobject, jint, jobject, jint, jint);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jclass> klass(soa.Env(),
+                                   soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
+      ScopedLocalRef<jobject> arg0(soa.Env(),
+                                   soa.AddLocalReference<jobject>(args[0].GetL()));
+      ScopedLocalRef<jobject> arg2(soa.Env(),
+                                   soa.AddLocalReference<jobject>(args[2].GetL()));
+      ScopedThreadStateChange tsc(self, kNative);
+      fn(soa.Env(), klass.get(), arg0.get(), args[1].GetI(), arg2.get(), args[3].GetI(),
+         args[4].GetI());
+    } else {
+      LOG(FATAL) << "Do something with static native method: " << PrettyMethod(method)
+          << " shorty: " << shorty;
+    }
+  } else {
+    if (shorty == "L") {
+      typedef jobject (fnptr)(JNIEnv*, jobject);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jobject> rcvr(soa.Env(),
+                                   soa.AddLocalReference<jobject>(receiver));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetL(soa.Decode<Object*>(fn(soa.Env(), rcvr.get())));
+    } else if (shorty == "LL") {
+      typedef jobject (fnptr)(JNIEnv*, jobject, jobject);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jobject> rcvr(soa.Env(),
+                                   soa.AddLocalReference<jobject>(receiver));
+      ScopedLocalRef<jobject> arg0(soa.Env(),
+                                   soa.AddLocalReference<jobject>(args[0].GetL()));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetL(soa.Decode<Object*>(fn(soa.Env(), rcvr.get(), arg0.get())));
+    } else if (shorty == "III") {
+      typedef jint (fnptr)(JNIEnv*, jobject, jint, jint);
+      fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
+      ScopedLocalRef<jobject> rcvr(soa.Env(),
+                                   soa.AddLocalReference<jobject>(receiver));
+      ScopedThreadStateChange tsc(self, kNative);
+      result->SetI(fn(soa.Env(), rcvr.get(), args[0].GetI(), args[1].GetI()));
+    } else {
+      LOG(FATAL) << "Do something with native method: " << PrettyMethod(method)
+          << " shorty: " << shorty;
+    }
+  }
+}
+
 static void DoMonitorEnter(Thread* self, Object* ref) NO_THREAD_SAFETY_ANALYSIS {
   ref->MonitorEnter(self);
 }
@@ -71,7 +376,11 @@
   } else {
     arg_array.BuildArgArray(shadow_frame, dec_insn.arg + (type != kStatic ? 1 : 0));
   }
-  target_method->Invoke(self, receiver, arg_array.get(), result);
+  if (LIKELY(Runtime::Current()->IsStarted())) {
+    target_method->Invoke(self, receiver, arg_array.get(), result);
+  } else {
+    UnstartedRuntimeInvoke(self, target_method, receiver, arg_array.get(), result);
+  }
   if (!mh.GetReturnType()->IsPrimitive() && result->GetL() != NULL) {
     CHECK(mh.GetReturnType()->IsAssignableFrom(result->GetL()->GetClass()));
   }
@@ -183,7 +492,7 @@
   while (true) {
     shadow_frame.SetDexPC(inst->GetDexPc(insns));
     DecodedInstruction dec_insn(inst);
-    const bool kTracing = true;
+    const bool kTracing = false;
     if (kTracing) {
       LOG(INFO) << PrettyMethod(shadow_frame.GetMethod())
                 << StringPrintf("\n0x%x: %s\nReferences:",
@@ -264,7 +573,7 @@
         return result;
       }
       case Instruction::CONST_4: {
-        int32_t val = (dec_insn.vB << 28) >> 28;
+        int32_t val = static_cast<int32_t>(dec_insn.vB << 28) >> 28;
         shadow_frame.SetVReg(dec_insn.vA, val);
         if (val == 0) {
           shadow_frame.SetReference(dec_insn.vA, NULL);
@@ -295,24 +604,17 @@
         }
         break;
       }
-      case Instruction::CONST_WIDE_16: {
-        int64_t val = static_cast<int16_t>(dec_insn.vB);
-        shadow_frame.SetVReg(dec_insn.vA, val);
-        shadow_frame.SetVReg(dec_insn.vA + 1, val >> 32);
+      case Instruction::CONST_WIDE_16:
+        shadow_frame.SetVRegLong(dec_insn.vA, static_cast<int16_t>(dec_insn.vB));
         break;
-      }
-      case Instruction::CONST_WIDE_32: {
-        int64_t val = static_cast<int32_t>(dec_insn.vB);
-        shadow_frame.SetVReg(dec_insn.vA, val);
-        shadow_frame.SetVReg(dec_insn.vA + 1, val >> 32);
+      case Instruction::CONST_WIDE_32:
+        shadow_frame.SetVRegLong(dec_insn.vA, static_cast<int32_t>(dec_insn.vB));
         break;
-      }
       case Instruction::CONST_WIDE:
-        shadow_frame.SetVReg(dec_insn.vA, dec_insn.vB_wide);
-        shadow_frame.SetVReg(dec_insn.vA + 1, dec_insn.vB_wide >> 32);
+        shadow_frame.SetVRegLong(dec_insn.vA, dec_insn.vB_wide);
         break;
       case Instruction::CONST_WIDE_HIGH16:
-        shadow_frame.SetVRegLong(dec_insn.vA + 1, static_cast<uint64_t>(dec_insn.vB) << 48);
+        shadow_frame.SetVRegLong(dec_insn.vA, static_cast<uint64_t>(dec_insn.vB) << 48);
         break;
       case Instruction::CONST_STRING:
       case Instruction::CONST_STRING_JUMBO: {
@@ -351,12 +653,12 @@
         break;
       }
       case Instruction::ARRAY_LENGTH:  {
-        Array* array = shadow_frame.GetReference(dec_insn.vB)->AsArray();
+        Object* array = shadow_frame.GetReference(dec_insn.vB);
         if (UNLIKELY(array == NULL)) {
           ThrowNullPointerExceptionFromDexPC(shadow_frame.GetMethod(), inst->GetDexPc(insns));
           break;
         }
-        shadow_frame.SetVReg(dec_insn.vA, array->GetLength());
+        shadow_frame.SetVReg(dec_insn.vA, array->AsArray()->GetLength());
         break;
       }
       case Instruction::NEW_INSTANCE: {
@@ -371,9 +673,30 @@
         break;
       }
       case Instruction::FILLED_NEW_ARRAY:
-      case Instruction::FILLED_NEW_ARRAY_RANGE:
-        UNIMPLEMENTED(FATAL) << inst->DumpString(&mh.GetDexFile());
+      case Instruction::FILLED_NEW_ARRAY_RANGE: {
+        bool is_range = (dec_insn.opcode == Instruction::FILLED_NEW_ARRAY_RANGE);
+        int32_t length = dec_insn.vA;
+        CHECK(is_range || length <= 5);
+        Class* arrayClass = mh.ResolveClass(dec_insn.vB);
+        CHECK(arrayClass->IsArrayClass());
+        if (arrayClass->GetComponentType()->IsPrimitiveInt()) {
+          IntArray* newArray = IntArray::Alloc(self, length);
+          if (newArray != NULL) {
+            for (int32_t i = 0; i < length; ++i) {
+              if (is_range) {
+                newArray->Set(i, shadow_frame.GetVReg(dec_insn.vC + i));
+              } else {
+                newArray->Set(i, shadow_frame.GetVReg(dec_insn.arg[i]));
+              }
+            }
+          }
+          result_register.SetL(newArray);
+        } else {
+          UNIMPLEMENTED(FATAL) << inst->DumpString(&mh.GetDexFile())
+              << " for array type: " << PrettyDescriptor(arrayClass);
+        }
         break;
+      }
       case Instruction::CMPL_FLOAT: {
         float val1 = shadow_frame.GetVRegFloat(dec_insn.vB);
         float val2 = shadow_frame.GetVRegFloat(dec_insn.vC);
@@ -408,7 +731,7 @@
         int32_t result;
         if (val1 == val2) {
           result = 0;
-        } else if (val1 > val2) {
+        } else if (val1 < val2) {
           result = 1;
         } else {
           result = -1;
@@ -423,7 +746,7 @@
         int32_t result;
         if (val1 == val2) {
           result = 0;
-        } else if (val1 < val2) {
+        } else if (val1 > val2) {
           result = -1;
         } else {
           result = 1;
@@ -436,11 +759,11 @@
         int64_t val2 = shadow_frame.GetVRegLong(dec_insn.vC);
         int32_t result;
         if (val1 < val2) {
-          result = -1;
+          result = 1;
         } else if (val1 == val2) {
           result = 0;
         } else {
-          result = 1;
+          result = -1;
         }
         shadow_frame.SetVReg(dec_insn.vA, result);
         break;
@@ -1124,7 +1447,7 @@
         break;
       case Instruction::MUL_LONG_2ADDR:
         shadow_frame.SetVRegLong(dec_insn.vA,
-                                 shadow_frame.GetVRegLong(dec_insn.vA) +
+                                 shadow_frame.GetVRegLong(dec_insn.vA) *
                                  shadow_frame.GetVRegLong(dec_insn.vB));
         break;
       case Instruction::DIV_LONG_2ADDR:
@@ -1282,6 +1605,7 @@
 
 void EnterInterpreterFromInvoke(Thread* self, AbstractMethod* method, Object* receiver,
                                 JValue* args, JValue* result) {
+  DCHECK_EQ(self, Thread::Current());
   MethodHelper mh(method);
   const DexFile::CodeItem* code_item = mh.GetCodeItem();
   uint16_t num_regs;
@@ -1313,7 +1637,7 @@
                                                             true, true);
     CHECK(method->GetDeclaringClass()->IsInitializing());
   }
-  StringPiece shorty(mh.GetShorty());
+  const char* shorty = mh.GetShorty();
   size_t arg_pos = 0;
   for (; cur_reg < num_regs; ++cur_reg, ++arg_pos) {
     DCHECK_LT(arg_pos + 1, mh.GetShortyLength());
@@ -1332,165 +1656,18 @@
         break;
     }
   }
-  if (!method->IsNative()) {
+  if (LIKELY(!method->IsNative())) {
     JValue r = Execute(self, mh, code_item, *shadow_frame.get());
     if (result != NULL) {
       *result = r;
     }
   } else {
-    // TODO: The following enters JNI code using a typedef-ed function rather than the JNI compiler,
-    //       it should be removed and JNI compiled stubs used instead.
-    ScopedObjectAccessUnchecked soa(self);
-    if (method->IsStatic()) {
-      if (shorty == "L") {
-        typedef jobject (fnptr)(JNIEnv*, jclass);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetL(soa.Decode<Object*>(fn(soa.Env(), klass.get())));
-      } else if (shorty == "V") {
-        typedef void (fnptr)(JNIEnv*, jclass);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedThreadStateChange tsc(self, kNative);
-        fn(soa.Env(), klass.get());
-      } else if (shorty == "Z") {
-        typedef jboolean (fnptr)(JNIEnv*, jclass);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetZ(fn(soa.Env(), klass.get()));
-      } else if (shorty == "BI") {
-        typedef jbyte (fnptr)(JNIEnv*, jclass, jint);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetB(fn(soa.Env(), klass.get(), args[0].GetI()));
-      } else if (shorty == "II") {
-        typedef jint (fnptr)(JNIEnv*, jclass, jint);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetI(fn(soa.Env(), klass.get(), args[0].GetI()));
-      } else if (shorty == "LL") {
-        typedef jobject (fnptr)(JNIEnv*, jclass, jobject);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedLocalRef<jobject> arg0(soa.Env(),
-                                     soa.AddLocalReference<jobject>(args[0].GetL()));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetL(soa.Decode<Object*>(fn(soa.Env(), klass.get(), arg0.get())));
-      } else if (shorty == "IIZ") {
-        typedef jint (fnptr)(JNIEnv*, jclass, jint, jboolean);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetI(fn(soa.Env(), klass.get(), args[0].GetI(), args[1].GetZ()));
-      } else if (shorty == "ILI") {
-        typedef jint (fnptr)(JNIEnv*, jclass, jobject, jint);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedLocalRef<jobject> arg0(soa.Env(),
-                                     soa.AddLocalReference<jobject>(args[0].GetL()));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetI(fn(soa.Env(), klass.get(), arg0.get(), args[1].GetI()));
-      } else if (shorty == "SIZ") {
-        typedef jshort (fnptr)(JNIEnv*, jclass, jint, jboolean);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetS(fn(soa.Env(), klass.get(), args[0].GetI(), args[1].GetZ()));
-      } else if (shorty == "VIZ") {
-        typedef void (fnptr)(JNIEnv*, jclass, jint, jboolean);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedThreadStateChange tsc(self, kNative);
-        fn(soa.Env(), klass.get(), args[0].GetI(), args[1].GetZ());
-      } else if (shorty == "ZLL") {
-        typedef jboolean (fnptr)(JNIEnv*, jclass, jobject, jobject);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedLocalRef<jobject> arg0(soa.Env(),
-                                     soa.AddLocalReference<jobject>(args[0].GetL()));
-        ScopedLocalRef<jobject> arg1(soa.Env(),
-                                     soa.AddLocalReference<jobject>(args[1].GetL()));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetZ(fn(soa.Env(), klass.get(), arg0.get(), arg1.get()));
-      } else if (shorty == "ZILL") {
-        typedef jboolean (fnptr)(JNIEnv*, jclass, jint, jobject, jobject);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedLocalRef<jobject> arg1(soa.Env(),
-                                     soa.AddLocalReference<jobject>(args[1].GetL()));
-        ScopedLocalRef<jobject> arg2(soa.Env(),
-                                     soa.AddLocalReference<jobject>(args[2].GetL()));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetZ(fn(soa.Env(), klass.get(), args[0].GetI(), arg1.get(), arg2.get()));
-      } else if (shorty == "VILII") {
-        typedef void (fnptr)(JNIEnv*, jclass, jint, jobject, jint, jint);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedLocalRef<jobject> arg1(soa.Env(),
-                                     soa.AddLocalReference<jobject>(args[1].GetL()));
-        ScopedThreadStateChange tsc(self, kNative);
-        fn(soa.Env(), klass.get(), args[0].GetI(), arg1.get(), args[2].GetI(), args[3].GetI());
-      } else if (shorty == "VLILII") {
-        typedef void (fnptr)(JNIEnv*, jclass, jobject, jint, jobject, jint, jint);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jclass> klass(soa.Env(),
-                                     soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
-        ScopedLocalRef<jobject> arg0(soa.Env(),
-                                     soa.AddLocalReference<jobject>(args[0].GetL()));
-        ScopedLocalRef<jobject> arg2(soa.Env(),
-                                     soa.AddLocalReference<jobject>(args[2].GetL()));
-        ScopedThreadStateChange tsc(self, kNative);
-        fn(soa.Env(), klass.get(), arg0.get(), args[1].GetI(), arg2.get(), args[3].GetI(),
-           args[4].GetI());
-      } else {
-        LOG(FATAL) << "Do something with static native method: " << PrettyMethod(method)
-            << " shorty: " << shorty;
-      }
+    // We don't expect to be asked to interpret native code (which is entered via a JNI compiler
+    // generated stub) except during testing and image writing.
+    if (!Runtime::Current()->IsStarted()) {
+      UnstartedRuntimeJni(self, method, receiver, args, result);
     } else {
-      if (shorty == "L") {
-        typedef jobject (fnptr)(JNIEnv*, jobject);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jobject> rcvr(soa.Env(),
-                                     soa.AddLocalReference<jobject>(receiver));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetL(soa.Decode<Object*>(fn(soa.Env(), rcvr.get())));
-      } else if (shorty == "LL") {
-        typedef jobject (fnptr)(JNIEnv*, jobject, jobject);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jobject> rcvr(soa.Env(),
-                                     soa.AddLocalReference<jobject>(receiver));
-        ScopedLocalRef<jobject> arg0(soa.Env(),
-                                     soa.AddLocalReference<jobject>(args[0].GetL()));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetL(soa.Decode<Object*>(fn(soa.Env(), rcvr.get(), arg0.get())));
-      } else if (shorty == "III") {
-        typedef jint (fnptr)(JNIEnv*, jobject, jint, jint);
-        fnptr* fn = reinterpret_cast<fnptr*>(method->GetNativeMethod());
-        ScopedLocalRef<jobject> rcvr(soa.Env(),
-                                     soa.AddLocalReference<jobject>(receiver));
-        ScopedThreadStateChange tsc(self, kNative);
-        result->SetI(fn(soa.Env(), rcvr.get(), args[0].GetI(), args[1].GetI()));
-      } else {
-        LOG(FATAL) << "Do something with native method: " << PrettyMethod(method)
-            << " shorty: " << shorty;
-      }
+      InterpreterJni(self, method, shorty, receiver, args, result);
     }
   }
   self->PopShadowFrame();
diff --git a/src/invoke_arg_array_builder.h b/src/invoke_arg_array_builder.h
index e965a1a..0664ef8 100644
--- a/src/invoke_arg_array_builder.h
+++ b/src/invoke_arg_array_builder.h
@@ -127,35 +127,35 @@
 
   void BuildArgArray(const ShadowFrame& shadow_frame, uint32_t range_start)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    for (size_t i = 1, offset = range_start; i < shorty_len_; ++i, ++offset) {
+    for (size_t i = 1, offset = 0; i < shorty_len_; ++i, ++offset) {
       switch (shorty_[i]) {
         case 'Z':
-          arg_array_[offset].SetZ(shadow_frame.GetVReg(offset));
+          arg_array_[offset].SetZ(shadow_frame.GetVReg(range_start + offset));
           break;
         case 'B':
-          arg_array_[offset].SetB(shadow_frame.GetVReg(offset));
+          arg_array_[offset].SetB(shadow_frame.GetVReg(range_start + offset));
           break;
         case 'C':
-          arg_array_[offset].SetC(shadow_frame.GetVReg(offset));
+          arg_array_[offset].SetC(shadow_frame.GetVReg(range_start + offset));
           break;
         case 'S':
-          arg_array_[offset].SetS(shadow_frame.GetVReg(offset));
+          arg_array_[offset].SetS(shadow_frame.GetVReg(range_start + offset));
           break;
         case 'I':
-          arg_array_[offset].SetI(shadow_frame.GetVReg(offset));
+          arg_array_[offset].SetI(shadow_frame.GetVReg(range_start + offset));
           break;
         case 'F':
-          arg_array_[offset].SetF(shadow_frame.GetVRegFloat(offset));
+          arg_array_[offset].SetF(shadow_frame.GetVRegFloat(range_start + offset));
           break;
         case 'L':
-          arg_array_[offset].SetL(shadow_frame.GetReference(offset));
+          arg_array_[offset].SetL(shadow_frame.GetReference(range_start + offset));
           break;
         case 'D':
-          arg_array_[offset].SetD(shadow_frame.GetVRegDouble(offset));
+          arg_array_[offset].SetD(shadow_frame.GetVRegDouble(range_start + offset));
           offset++;
           break;
         case 'J':
-          arg_array_[offset].SetJ(shadow_frame.GetVRegLong(offset));
+          arg_array_[offset].SetJ(shadow_frame.GetVRegLong(range_start + offset));
           offset++;
           break;
       }
diff --git a/src/native/java_lang_String.cc b/src/native/java_lang_String.cc
index bfdc31a..8b7a691 100644
--- a/src/native/java_lang_String.cc
+++ b/src/native/java_lang_String.cc
@@ -17,56 +17,19 @@
 #include "jni_internal.h"
 #include "object.h"
 #include "scoped_thread_state_change.h"
-
-#ifdef HAVE__MEMCMP16
-// "count" is in 16-bit units.
-extern "C" uint32_t __memcmp16(const uint16_t* s0, const uint16_t* s1, size_t count);
-#define MemCmp16 __memcmp16
-#else
-uint32_t MemCmp16(const uint16_t* s0, const uint16_t* s1, size_t count) {
-  for (size_t i = 0; i < count; i++) {
-    if (s0[i] != s1[i]) {
-      return static_cast<int32_t>(s0[i]) - static_cast<int32_t>(s1[i]);
-    }
-  }
-  return 0;
-}
-#endif
+#include "ScopedLocalRef.h"
 
 namespace art {
 
 static jint String_compareTo(JNIEnv* env, jobject javaThis, jobject javaRhs) {
-  ScopedObjectAccess soa(env);
-  String* lhs = soa.Decode<String*>(javaThis);
-  String* rhs = soa.Decode<String*>(javaRhs);
-
-  if (rhs == NULL) {
-    Thread::Current()->ThrowNewException("Ljava/lang/NullPointerException;", "rhs == null");
+  if (UNLIKELY(javaRhs == NULL)) {
+    ScopedLocalRef<jclass> npe(env, env->FindClass("java/lang/NullPointerException"));
+    env->ThrowNew(npe.get(), "rhs == null");
     return -1;
+  } else {
+    ScopedObjectAccess soa(env);
+    return soa.Decode<String*>(javaThis)->CompareTo(soa.Decode<String*>(javaRhs));
   }
-
-  // Quick test for comparison of a string with itself.
-  if (lhs == rhs) {
-    return 0;
-  }
-
-  // TODO: is this still true?
-  // The annoying part here is that 0x00e9 - 0xffff != 0x00ea,
-  // because the interpreter converts the characters to 32-bit integers
-  // *without* sign extension before it subtracts them (which makes some
-  // sense since "char" is unsigned).  So what we get is the result of
-  // 0x000000e9 - 0x0000ffff, which is 0xffff00ea.
-  int lhsCount = lhs->GetLength();
-  int rhsCount = rhs->GetLength();
-  int countDiff = lhsCount - rhsCount;
-  int minCount = (countDiff < 0) ? lhsCount : rhsCount;
-  const uint16_t* lhsChars = lhs->GetCharArray()->GetData() + lhs->GetOffset();
-  const uint16_t* rhsChars = rhs->GetCharArray()->GetData() + rhs->GetOffset();
-  int otherRes = MemCmp16(lhsChars, rhsChars, minCount);
-  if (otherRes != 0) {
-    return otherRes;
-  }
-  return countDiff;
 }
 
 static jint String_fastIndexOf(JNIEnv* env, jobject java_this, jint ch, jint start) {
@@ -75,24 +38,7 @@
   DCHECK_LE(ch, 0xffff);
 
   String* s = soa.Decode<String*>(java_this);
-
-  jint count = s->GetLength();
-  if (start < 0) {
-    start = 0;
-  } else if (start > count) {
-    start = count;
-  }
-
-  const uint16_t* chars = s->GetCharArray()->GetData() + s->GetOffset();
-  const uint16_t* p = chars + start;
-  const uint16_t* end = chars + count;
-  while (p < end) {
-    if (*p++ == ch) {
-      return (p - 1) - chars;
-    }
-  }
-
-  return -1;
+  return s->FastIndexOf(ch, start);
 }
 
 static jstring String_intern(JNIEnv* env, jobject javaThis) {
diff --git a/src/native/java_lang_reflect_Array.cc b/src/native/java_lang_reflect_Array.cc
index 863f9fc..15aeed2 100644
--- a/src/native/java_lang_reflect_Array.cc
+++ b/src/native/java_lang_reflect_Array.cc
@@ -23,55 +23,6 @@
 
 namespace art {
 
-// Recursively create an array with multiple dimensions.  Elements may be
-// Objects or primitive types.
-static Array* CreateMultiArray(Thread* self, Class* array_class, int current_dimension,
-                               IntArray* dimensions)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  int32_t array_length = dimensions->Get(current_dimension++);
-  SirtRef<Array> new_array(self, Array::Alloc(self, array_class, array_length));
-  if (new_array.get() == NULL) {
-    CHECK(self->IsExceptionPending());
-    return NULL;
-  }
-  if (current_dimension == dimensions->GetLength()) {
-    return new_array.get();
-  }
-
-  if (!array_class->GetComponentType()->IsArrayClass()) {
-    // TODO: throw an exception, not relying on class_linker->FindClass to throw.
-    // old code assumed this but if you recurse from "[Foo" to "Foo" to "oo",
-    // you shouldn't assume there isn't a class "oo".
-  }
-  std::string sub_array_descriptor(ClassHelper(array_class).GetDescriptor() + 1);
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Class* sub_array_class = class_linker->FindClass(sub_array_descriptor.c_str(),
-                                                   array_class->GetClassLoader());
-  if (sub_array_class == NULL) {
-    CHECK(self->IsExceptionPending());
-    return NULL;
-  }
-  DCHECK(sub_array_class->IsArrayClass());
-  // Create a new sub-array in every element of the array.
-  SirtRef<ObjectArray<Array> > object_array(self, new_array->AsObjectArray<Array>());
-  for (int32_t i = 0; i < array_length; i++) {
-    SirtRef<Array> sub_array(self, CreateMultiArray(self, sub_array_class, current_dimension,
-                                                    dimensions));
-    if (sub_array.get() == NULL) {
-      CHECK(self->IsExceptionPending());
-      return NULL;
-    }
-    object_array->Set(i, sub_array.get());
-  }
-  return new_array.get();
-}
-
-// Create a multi-dimensional array of Objects or primitive types.
-//
-// We have to generate the names for X[], X[][], X[][][], and so on.  The
-// easiest way to deal with that is to create the full name once and then
-// subtract pieces off.  Besides, we want to start with the outermost
-// piece and work our way in.
 static jobject Array_createMultiArray(JNIEnv* env, jclass, jclass javaElementClass, jobject javaDimArray) {
   ScopedObjectAccess soa(env);
   DCHECK(javaElementClass != NULL);
@@ -82,41 +33,7 @@
   DCHECK(dimensions_obj->IsArrayInstance());
   DCHECK_STREQ(ClassHelper(dimensions_obj->GetClass()).GetDescriptor(), "[I");
   IntArray* dimensions_array = down_cast<IntArray*>(dimensions_obj);
-
-  // Verify dimensions.
-  //
-  // The caller is responsible for verifying that "dimArray" is non-null
-  // and has a length > 0 and <= 255.
-  int num_dimensions = dimensions_array->GetLength();
-  DCHECK_GT(num_dimensions, 0);
-  DCHECK_LE(num_dimensions, 255);
-
-  for (int i = 0; i < num_dimensions; i++) {
-    int dimension = dimensions_array->Get(i);
-    if (dimension < 0) {
-      soa.Self()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;",
-          "Dimension %d: %d", i, dimension);
-      return NULL;
-    }
-  }
-
-  // Generate the full name of the array class.
-  std::string descriptor(num_dimensions, '[');
-  descriptor += ClassHelper(element_class).GetDescriptor();
-
-  // Find/generate the array class.
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Class* array_class = class_linker->FindClass(descriptor.c_str(), element_class->GetClassLoader());
-  if (array_class == NULL) {
-    CHECK(soa.Self()->IsExceptionPending());
-    return NULL;
-  }
-  // create the array
-  Array* new_array = CreateMultiArray(soa.Self(), array_class, 0, dimensions_array);
-  if (new_array == NULL) {
-    CHECK(soa.Self()->IsExceptionPending());
-    return NULL;
-  }
+  Array* new_array = Array::CreateMultiArray(soa.Self(), element_class, dimensions_array);
   return soa.AddLocalReference<jobject>(new_array);
 }
 
@@ -124,26 +41,21 @@
   ScopedObjectAccess soa(env);
   DCHECK(javaElementClass != NULL);
   Class* element_class = soa.Decode<Class*>(javaElementClass);
-  if (length < 0) {
+  if (UNLIKELY(length < 0)) {
     soa.Self()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", length);
     return NULL;
   }
-  std::string descriptor;
-  descriptor += '[';
+  std::string descriptor("[");
   descriptor += ClassHelper(element_class).GetDescriptor();
 
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Class* array_class = class_linker->FindClass(descriptor.c_str(), element_class->GetClassLoader());
-  if (array_class == NULL) {
+  if (UNLIKELY(array_class == NULL)) {
     CHECK(soa.Self()->IsExceptionPending());
     return NULL;
   }
   DCHECK(array_class->IsArrayClass());
   Array* new_array = Array::Alloc(soa.Self(), array_class, length);
-  if (new_array == NULL) {
-    CHECK(soa.Self()->IsExceptionPending());
-    return NULL;
-  }
   return soa.AddLocalReference<jobject>(new_array);
 }
 
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 0db71c9..a371d28 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -720,13 +720,13 @@
     } else if (type->IsStringClass()) {
       String* string = value->AsString();
       StringAppendF(&summary, "%p   String: \"%s\"\n", string, string->ToModifiedUtf8().c_str());
-    } else if (value->IsClass()) {
+    } else if (type->IsClassClass()) {
       Class* klass = value->AsClass();
       StringAppendF(&summary, "%p   Class: %s\n", klass, PrettyDescriptor(klass).c_str());
-    } else if (value->IsField()) {
+    } else if (type->IsFieldClass()) {
       Field* field = value->AsField();
       StringAppendF(&summary, "%p   Field: %s\n", field, PrettyField(field).c_str());
-    } else if (value->IsMethod()) {
+    } else if (type->IsMethodClass()) {
       AbstractMethod* method = value->AsMethod();
       StringAppendF(&summary, "%p   Method: %s\n", method, PrettyMethod(method).c_str());
     } else {
@@ -880,7 +880,7 @@
         summary += "\t\tSTATICS:\n";
         for (int32_t i = 0; i < sfields->GetLength(); i++) {
           Field* field = sfields->Get(i);
-          PrintField(summary, field, NULL);
+          PrintField(summary, field, field->GetDeclaringClass());
         }
       }
     } else if (obj->IsMethod()) {
diff --git a/src/object.cc b/src/object.cc
index 9189f03..9a4588a 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -29,8 +29,8 @@
 #include "dex_file.h"
 #include "globals.h"
 #include "heap.h"
-#include "interpreter/interpreter.h"
 #include "intern_table.h"
+#include "interpreter/interpreter.h"
 #include "logging.h"
 #include "monitor.h"
 #include "object_utils.h"
@@ -69,13 +69,15 @@
 
 IntArray* Object::AsIntArray() {
   DCHECK(GetClass()->IsArrayClass());
-  DCHECK(GetClass()->GetComponentType()->IsPrimitiveInt());
+  DCHECK(GetClass()->GetComponentType()->IsPrimitiveInt() ||
+         GetClass()->GetComponentType()->IsPrimitiveFloat());
   return down_cast<IntArray*>(this);
 }
 
 LongArray* Object::AsLongArray() {
   DCHECK(GetClass()->IsArrayClass());
-  DCHECK(GetClass()->GetComponentType()->IsPrimitiveLong());
+  DCHECK(GetClass()->GetComponentType()->IsPrimitiveLong() ||
+         GetClass()->GetComponentType()->IsPrimitiveDouble());
   return down_cast<LongArray*>(this);
 }
 
@@ -314,26 +316,34 @@
 }
 
 int32_t Field::GetInt(const Object* object) const {
-  DCHECK_EQ(Primitive::kPrimInt, FieldHelper(this).GetTypeAsPrimitiveType())
-       << PrettyField(this);
+#ifndef NDEBUG
+  Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+  CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this);
+#endif
   return Get32(object);
 }
 
 void Field::SetInt(Object* object, int32_t i) const {
-  DCHECK_EQ(Primitive::kPrimInt, FieldHelper(this).GetTypeAsPrimitiveType())
-       << PrettyField(this);
+#ifndef NDEBUG
+  Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+  CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this);
+#endif
   Set32(object, i);
 }
 
 int64_t Field::GetLong(const Object* object) const {
-  DCHECK_EQ(Primitive::kPrimLong, FieldHelper(this).GetTypeAsPrimitiveType())
-       << PrettyField(this);
+#ifndef NDEBUG
+  Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+  CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this);
+#endif
   return Get64(object);
 }
 
 void Field::SetLong(Object* object, int64_t j) const {
-  DCHECK_EQ(Primitive::kPrimLong, FieldHelper(this).GetTypeAsPrimitiveType())
-       << PrettyField(this);
+#ifndef NDEBUG
+  Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+  CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this);
+#endif
   Set64(object, j);
 }
 
@@ -1031,6 +1041,19 @@
   return WellKnownClasses::ToClass(WellKnownClasses::java_lang_Throwable)->IsAssignableFrom(this);
 }
 
+bool Class::IsFieldClass() const {
+  Class* java_lang_Class = GetClass();
+  Class* java_lang_reflect_Field = java_lang_Class->GetInstanceField(0)->GetClass();
+  return this == java_lang_reflect_Field;
+
+}
+
+bool Class::IsMethodClass() const {
+  return (this == AbstractMethod::GetMethodClass()) ||
+      (this == AbstractMethod::GetConstructorClass());
+
+}
+
 ClassLoader* Class::GetClassLoader() const {
   return GetFieldObject<ClassLoader*>(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), false);
 }
@@ -1358,6 +1381,76 @@
   return Alloc(self, array_class, component_count, array_class->GetComponentSize());
 }
 
+// Create a multi-dimensional array of Objects or primitive types.
+//
+// We have to generate the names for X[], X[][], X[][][], and so on.  The
+// easiest way to deal with that is to create the full name once and then
+// subtract pieces off.  Besides, we want to start with the outermost
+// piece and work our way in.
+// Recursively create an array with multiple dimensions.  Elements may be
+// Objects or primitive types.
+static Array* RecursiveCreateMultiArray(Thread* self, Class* array_class, int current_dimension,
+                                        IntArray* dimensions)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  int32_t array_length = dimensions->Get(current_dimension);
+  SirtRef<Array> new_array(self, Array::Alloc(self, array_class, array_length));
+  if (UNLIKELY(new_array.get() == NULL)) {
+    CHECK(self->IsExceptionPending());
+    return NULL;
+  }
+  if ((current_dimension + 1) < dimensions->GetLength()) {
+    // Create a new sub-array in every element of the array.
+    for (int32_t i = 0; i < array_length; i++) {
+      Array* sub_array = RecursiveCreateMultiArray(self, array_class->GetComponentType(),
+                                                   current_dimension + 1, dimensions);
+      if (UNLIKELY(sub_array == NULL)) {
+        CHECK(self->IsExceptionPending());
+        return NULL;
+      }
+      new_array->AsObjectArray<Array>()->Set(i, sub_array);
+    }
+  }
+  return new_array.get();
+}
+
+Array* Array::CreateMultiArray(Thread* self, Class* element_class, IntArray* dimensions) {
+  // Verify dimensions.
+  //
+  // The caller is responsible for verifying that "dimArray" is non-null
+  // and has a length > 0 and <= 255.
+  int num_dimensions = dimensions->GetLength();
+  DCHECK_GT(num_dimensions, 0);
+  DCHECK_LE(num_dimensions, 255);
+
+  for (int i = 0; i < num_dimensions; i++) {
+    int dimension = dimensions->Get(i);
+    if (UNLIKELY(dimension < 0)) {
+      self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;",
+                               "Dimension %d: %d", i, dimension);
+      return NULL;
+    }
+  }
+
+  // Generate the full name of the array class.
+  std::string descriptor(num_dimensions, '[');
+  descriptor += ClassHelper(element_class).GetDescriptor();
+
+  // Find/generate the array class.
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Class* array_class = class_linker->FindClass(descriptor.c_str(), element_class->GetClassLoader());
+  if (UNLIKELY(array_class == NULL)) {
+    CHECK(self->IsExceptionPending());
+    return NULL;
+  }
+  // create the array
+  Array* new_array = RecursiveCreateMultiArray(self, array_class, 0, dimensions);
+  if (UNLIKELY(new_array == NULL)) {
+    CHECK(self->IsExceptionPending());
+    return NULL;
+  }
+  return new_array;
+}
+
 bool Array::ThrowArrayIndexOutOfBoundsException(int32_t index) const {
   Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
       "length=%i; index=%i", length_, index);
@@ -1574,6 +1667,46 @@
   return result;
 }
 
+#ifdef HAVE__MEMCMP16
+// "count" is in 16-bit units.
+extern "C" uint32_t __memcmp16(const uint16_t* s0, const uint16_t* s1, size_t count);
+#define MemCmp16 __memcmp16
+#else
+static uint32_t MemCmp16(const uint16_t* s0, const uint16_t* s1, size_t count) {
+  for (size_t i = 0; i < count; i++) {
+    if (s0[i] != s1[i]) {
+      return static_cast<int32_t>(s0[i]) - static_cast<int32_t>(s1[i]);
+    }
+  }
+  return 0;
+}
+#endif
+
+int32_t String::CompareTo(String* rhs) const {
+  // Quick test for comparison of a string with itself.
+  const String* lhs = this;
+  if (lhs == rhs) {
+    return 0;
+  }
+  // TODO: is this still true?
+  // The annoying part here is that 0x00e9 - 0xffff != 0x00ea,
+  // because the interpreter converts the characters to 32-bit integers
+  // *without* sign extension before it subtracts them (which makes some
+  // sense since "char" is unsigned).  So what we get is the result of
+  // 0x000000e9 - 0x0000ffff, which is 0xffff00ea.
+  int lhsCount = lhs->GetLength();
+  int rhsCount = rhs->GetLength();
+  int countDiff = lhsCount - rhsCount;
+  int minCount = (countDiff < 0) ? lhsCount : rhsCount;
+  const uint16_t* lhsChars = lhs->GetCharArray()->GetData() + lhs->GetOffset();
+  const uint16_t* rhsChars = rhs->GetCharArray()->GetData() + rhs->GetOffset();
+  int otherRes = MemCmp16(lhsChars, rhsChars, minCount);
+  if (otherRes != 0) {
+    return otherRes;
+  }
+  return countDiff;
+}
+
 void Throwable::SetCause(Throwable* cause) {
   CHECK(cause != NULL);
   CHECK(cause != this);
diff --git a/src/object.h b/src/object.h
index 87f132e..79df4e2 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1070,6 +1070,9 @@
                       size_t component_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  static Array* CreateMultiArray(Thread* self, Class* element_class, IntArray* dimensions)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   size_t SizeOf() const;
 
   int32_t GetLength() const {
@@ -1493,6 +1496,10 @@
 
   bool IsThrowableClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  bool IsFieldClass() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  bool IsMethodClass() const;
+
   Class* GetComponentType() const {
     return GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Class, component_type_), false);
   }
@@ -2166,16 +2173,11 @@
 }
 
 inline bool Object::IsField() const {
-  Class* java_lang_Class = klass_->klass_;
-  Class* java_lang_reflect_Field = java_lang_Class->GetInstanceField(0)->GetClass();
-  return GetClass() == java_lang_reflect_Field;
+  return GetClass()->IsFieldClass();
 }
 
 inline bool Object::IsMethod() const {
-  Class* c = GetClass();
-  return
-      c == AbstractMethod::GetMethodClass() ||
-      c == AbstractMethod::GetConstructorClass();
+  return GetClass()->IsMethodClass();
 }
 
 inline bool Object::IsReferenceInstance() const {
@@ -2488,6 +2490,26 @@
   // Create a modified UTF-8 encoded std::string from a java/lang/String object.
   std::string ToModifiedUtf8() const;
 
+  int32_t FastIndexOf(int32_t ch, int32_t start) {
+    int32_t count = GetLength();
+    if (start < 0) {
+      start = 0;
+    } else if (start > count) {
+      start = count;
+    }
+    const uint16_t* chars = GetCharArray()->GetData() + GetOffset();
+    const uint16_t* p = chars + start;
+    const uint16_t* end = chars + count;
+    while (p < end) {
+      if (*p++ == ch) {
+        return (p - 1) - chars;
+      }
+    }
+    return -1;
+  }
+
+  int32_t CompareTo(String* other) const;
+
   static Class* GetJavaLangString() {
     DCHECK(java_lang_String_ != NULL);
     return java_lang_String_;
diff --git a/src/object_test.cc b/src/object_test.cc
index e0443d0..f3b6a19 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -206,6 +206,40 @@
   EXPECT_TRUE(array->GetClass()->GetComponentType()->IsPrimitive());
 }
 
+TEST_F(ObjectTest, CreateMultiArray) {
+  ScopedObjectAccess soa(Thread::Current());
+
+  SirtRef<Class> c(soa.Self(), class_linker_->FindSystemClass("I"));
+  SirtRef<IntArray> dims(soa.Self(), IntArray::Alloc(soa.Self(), 1));
+  dims->Set(0, 1);
+  Array* multi = Array::CreateMultiArray(soa.Self(), c.get(), dims.get());
+  EXPECT_TRUE(multi->GetClass() == class_linker_->FindSystemClass("[I"));
+  EXPECT_EQ(1, multi->GetLength());
+
+  dims->Set(0, -1);
+  multi = Array::CreateMultiArray(soa.Self(), c.get(), dims.get());
+  EXPECT_TRUE(soa.Self()->IsExceptionPending());
+  EXPECT_EQ(PrettyDescriptor(soa.Self()->GetException()->GetClass()),
+            "java.lang.NegativeArraySizeException");
+  soa.Self()->ClearException();
+
+  dims.reset(IntArray::Alloc(soa.Self(), 2));
+  for (int i = 1; i < 20; ++i) {
+    for (int j = 0; j < 20; ++j) {
+      dims->Set(0, i);
+      dims->Set(1, j);
+      multi = Array::CreateMultiArray(soa.Self(), c.get(), dims.get());
+      EXPECT_TRUE(multi->GetClass() == class_linker_->FindSystemClass("[[I"));
+      EXPECT_EQ(i, multi->GetLength());
+      for (int k = 0; k < i; ++k) {
+        Array* outer = multi->AsObjectArray<Array>()->Get(k);
+        EXPECT_TRUE(outer->GetClass() == class_linker_->FindSystemClass("[I"));
+        EXPECT_EQ(j, outer->GetLength());
+      }
+    }
+  }
+}
+
 TEST_F(ObjectTest, StaticFieldFromCode) {
   // pretend we are trying to access 'Static.s0' from StaticsFromCode.<clinit>
   ScopedObjectAccess soa(Thread::Current());
@@ -239,7 +273,7 @@
   Field* field = FindFieldFromCode(field_idx, clinit, Thread::Current(), StaticObjectRead,
                                    sizeof(Object*));
   Object* s0 = field->GetObj(klass);
-  EXPECT_EQ(NULL, s0);
+  EXPECT_TRUE(s0 != NULL);
 
   SirtRef<CharArray> char_array(soa.Self(), CharArray::Alloc(soa.Self(), 0));
   field->SetObj(field->GetDeclaringClass(), char_array.get());
@@ -306,6 +340,22 @@
   EXPECT_FALSE(empty->Equals("a"));
 }
 
+TEST_F(ObjectTest, StringCompareTo) {
+  ScopedObjectAccess soa(Thread::Current());
+  SirtRef<String> string(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "android"));
+  SirtRef<String> string_2(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "android"));
+  SirtRef<String> string_3(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "Android"));
+  SirtRef<String> string_4(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "and"));
+  SirtRef<String> string_5(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), ""));
+  EXPECT_EQ(0, string->CompareTo(string_2.get()));
+  EXPECT_LT(0, string->CompareTo(string_3.get()));
+  EXPECT_GT(0, string_3->CompareTo(string.get()));
+  EXPECT_LT(0, string->CompareTo(string_4.get()));
+  EXPECT_GT(0, string_4->CompareTo(string.get()));
+  EXPECT_LT(0, string->CompareTo(string_5.get()));
+  EXPECT_GT(0, string_5->CompareTo(string.get()));
+}
+
 TEST_F(ObjectTest, StringLength) {
   ScopedObjectAccess soa(Thread::Current());
   SirtRef<String> string(soa.Self(), String::AllocFromModifiedUtf8(soa.Self(), "android"));
diff --git a/src/thread.cc b/src/thread.cc
index 2f8a9a7..f6e7249 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1340,7 +1340,7 @@
   ObjectArray<Object>* method_trace_;
 };
 
-jobject Thread::CreateInternalStackTrace(const ScopedObjectAccess& soa) const {
+jobject Thread::CreateInternalStackTrace(const ScopedObjectAccessUnchecked& soa) const {
   // Compute depth of stack
   CountStackDepthVisitor count_visitor(GetManagedStack(), GetTraceStack());
   count_visitor.WalkStack();
@@ -1483,6 +1483,9 @@
       ScopedObjectAccessUnchecked soa(env);
       Throwable* t = reinterpret_cast<Throwable*>(soa.Self()->DecodeJObject(exception.get()));
       t->SetDetailMessage(String::AllocFromModifiedUtf8(soa.Self(), msg));
+      if (cause != NULL) {
+        t->SetCause(soa.Decode<Throwable*>(cause));
+      }
       soa.Self()->SetException(t);
     } else {
       LOG(ERROR) << "Couldn't throw new " << descriptor << " because JNI AllocObject failed: "
diff --git a/src/thread.h b/src/thread.h
index 798e96a..d281ea2 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -399,7 +399,7 @@
 
   // Create the internal representation of a stack trace, that is more time
   // and space efficient to compute than the StackTraceElement[]
-  jobject CreateInternalStackTrace(const ScopedObjectAccess& soa) const
+  jobject CreateInternalStackTrace(const ScopedObjectAccessUnchecked& soa) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Convert an internal stack trace representation (returned by CreateInternalStackTrace) to a
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 9a933bf..2149490 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -3258,6 +3258,7 @@
   MutexLock mu(Thread::Current(), *dex_gc_maps_lock_);
   DexGcMapTable::const_iterator it = dex_gc_maps_->find(ref);
   if (it == dex_gc_maps_->end()) {
+    LOG(WARNING) << "Didn't find GC map for: " << PrettyMethod(ref.second, *ref.first);
     return NULL;
   }
   CHECK(it->second != NULL);