Merge "Add one last memory barrier." into dalvik-dev
diff --git a/Android.mk b/Android.mk
index a27d526..a27b2f2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -156,7 +156,7 @@
 # oatdump targets
 
 .PHONY: dump-oat
-dump-oat: dump-oat-core dump-oat-boot
+dump-oat: dump-oat-core dump-oat-boot dump-oat-Calculator
 
 .PHONY: dump-oat-core
 dump-oat-core: $(TARGET_CORE_OAT) $(OATDUMP)
diff --git a/src/check_jni.cc b/src/check_jni.cc
index 6ff0fd7..2208d14 100644
--- a/src/check_jni.cc
+++ b/src/check_jni.cc
@@ -236,9 +236,10 @@
       return;
     }
 
+    CHECK(fid != NULL) << PrettyTypeOf(o);
     Field* f = DecodeField(fid);
     Class* f_type = f->GetType();
-    // check invariant that all jfieldIDs have resovled types
+    // check invariant that all jfieldIDs have resolved types
     DCHECK(f_type != NULL);
     Class* c = o->GetClass();
     if (c->FindInstanceField(f->GetName()->ToModifiedUtf8(), f_type) == NULL) {
diff --git a/src/compiler/codegen/CodegenFactory.cc b/src/compiler/codegen/CodegenFactory.cc
index 108bc83..55ed8af 100644
--- a/src/compiler/codegen/CodegenFactory.cc
+++ b/src/compiler/codegen/CodegenFactory.cc
@@ -131,8 +131,9 @@
     rlDest = oatUpdateLoc(cUnit, rlDest);
     if (rlSrc.location == kLocPhysReg) {
         if (oatIsLive(cUnit, rlSrc.lowReg) ||
+            oatIsPromoted(cUnit, rlSrc.lowReg) ||
             (rlDest.location == kLocPhysReg)) {
-            // Src is live or Dest has assigned reg.
+            // Src is live/promoted or Dest has assigned reg.
             rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
             genRegCopy(cUnit, rlDest.lowReg, rlSrc.lowReg);
         } else {
@@ -192,8 +193,10 @@
     if (rlSrc.location == kLocPhysReg) {
         if (oatIsLive(cUnit, rlSrc.lowReg) ||
             oatIsLive(cUnit, rlSrc.highReg) ||
+            oatIsPromoted(cUnit, rlSrc.lowReg) ||
+            oatIsPromoted(cUnit, rlSrc.highReg) ||
             (rlDest.location == kLocPhysReg)) {
-            // Src is live or Dest has assigned reg.
+            // Src is live or promoted or Dest has assigned reg.
             rlDest = oatEvalLoc(cUnit, rlDest, kAnyReg, false);
             genRegCopyWide(cUnit, rlDest.lowReg, rlDest.highReg,
                            rlSrc.lowReg, rlSrc.highReg);
diff --git a/src/compiler/codegen/Ralloc.h b/src/compiler/codegen/Ralloc.h
index 0c3fbca..e2cb1ce 100644
--- a/src/compiler/codegen/Ralloc.h
+++ b/src/compiler/codegen/Ralloc.h
@@ -141,6 +141,8 @@
 
 extern RegisterInfo *oatIsTemp(CompilationUnit* cUnit, int reg);
 
+extern RegisterInfo *oatIsPromoted(CompilationUnit* cUnit, int reg);
+
 extern bool oatIsDirty(CompilationUnit* cUnit, int reg);
 
 extern void oatMarkInUse(CompilationUnit* cUnit, int reg);
diff --git a/src/compiler/codegen/RallocUtil.cc b/src/compiler/codegen/RallocUtil.cc
index 6875718..69b98d4 100644
--- a/src/compiler/codegen/RallocUtil.cc
+++ b/src/compiler/codegen/RallocUtil.cc
@@ -547,6 +547,12 @@
     return (p->isTemp) ? p : NULL;
 }
 
+extern RegisterInfo* oatIsPromoted(CompilationUnit* cUnit, int reg)
+{
+    RegisterInfo* p = getRegInfo(cUnit, reg);
+    return (p->isTemp) ? NULL : p;
+}
+
 extern bool oatIsDirty(CompilationUnit* cUnit, int reg)
 {
     RegisterInfo* p = getRegInfo(cUnit, reg);
@@ -849,7 +855,7 @@
 /*
  * Return an updated location record with current in-register status.
  * If the value lives in live temps, reflect that fact.  No code
- * is generated.  The the live value is part of an older pair,
+ * is generated.  If the live value is part of an older pair,
  * clobber both low and high.
  * TUNING: clobbering both is a bit heavy-handed, but the alternative
  * is a bit complex when dealing with FP regs.  Examine code to see
diff --git a/src/compiler/codegen/arm/ArchUtility.cc b/src/compiler/codegen/arm/ArchUtility.cc
index ccafecb..be1ab1e 100644
--- a/src/compiler/codegen/arm/ArchUtility.cc
+++ b/src/compiler/codegen/arm/ArchUtility.cc
@@ -456,30 +456,6 @@
         ToModifiedUtf8();
 
     char buf[256];
-#if 0
-    int linebreak = 0;
-    //TODO: delete when we're sure it's no longer necessary
-    LOG(INFO) << "*/";
-    sprintf(buf,"\n    u1 %s%s_%s_code[] = {", descriptor.c_str(),
-            name.c_str(), signature.c_str());
-    for (unsigned int i = 0; i < strlen(buf); i++)
-        if (buf[i] == ';') buf[i] = '_';
-    LOG(INFO) << buf;
-    strcpy(buf,"        ");
-    u1* pLiterals = (u1*)&cUnit->codeBuffer[0];
-    for (int i = 0; i < cUnit->totalSize; i++) {
-        sprintf(buf+strlen(buf),"0x%02x,", pLiterals[i]);
-        if (++linebreak == 8) {
-            linebreak = 0;
-            LOG(INFO) << buf;
-            strcpy(buf,"        ");
-        }
-    }
-    if (strlen(buf) > 8) {
-        LOG(INFO) << buf;
-    }
-    LOG(INFO) << "    };\n\n";
-#endif
 
     // Dump mapping table
     if (cUnit->mappingTable.size() > 0) {
@@ -498,6 +474,4 @@
         }
         LOG(INFO) <<"    };\n\n";
     }
-
-    // Dump vmap table
 }
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 0a5fc7e..aeb0134 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -1817,8 +1817,14 @@
         }
         if (loc.location == kLocPhysReg) {
             if (loc.wide) {
-                loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
-                                 loc.lowReg, loc.highReg, INVALID_SREG);
+                if (loc.fp && (loc.lowReg & 1) != 0) {
+                    // Misaligned - need to load as a pair of singles
+                    loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
+                    loadWordDisp(cUnit, rSP, loc.spOffset + 4, loc.highReg);
+                } else {
+                    loadBaseDispWide(cUnit, NULL, rSP, loc.spOffset,
+                                     loc.lowReg, loc.highReg, INVALID_SREG);
+                }
                 i++;
             } else {
                 loadWordDisp(cUnit, rSP, loc.spOffset, loc.lowReg);
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index c247fe7..e3893d3 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -707,6 +707,7 @@
     // At this point, r2 has class
     loadValueDirectFixed(cUnit, rlSrc, r3);  /* Ref */
     /* When taken r0 has NULL which can be used for store directly */
+    loadConstant(cUnit, r0, 0);                /* Assume false */
     ArmLIR* branch1 = genCmpImmBranch(cUnit, kArmCondEq, r3, 0);
     /* load object->clazz */
     DCHECK_EQ(Object::ClassOffset().Int32Value(), 0);
@@ -830,7 +831,6 @@
     rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
     // The longs may overlap - use intermediate temp if so
     if (rlResult.lowReg == rlSrc1.highReg) {
-        //FIXME: review all long arithmetic ops - there may be more of these
         int tReg = oatAllocTemp(cUnit);
         genRegCopy(cUnit, tReg, rlSrc1.highReg);
         opRegRegReg(cUnit, firstOp, rlResult.lowReg, rlSrc1.lowReg,
@@ -1044,32 +1044,34 @@
                        RegLocation rlDest, RegLocation rlSrc1,
                        RegLocation rlSrc2)
 {
-    RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
     ArmLIR* target1;
     ArmLIR* target2;
     rlSrc1 = loadValueWide(cUnit, rlSrc1, kCoreReg);
     rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
-    rlTemp.lowReg = oatAllocTemp(cUnit);
-    loadConstant(cUnit, rlTemp.lowReg, -1);
+    int tReg = oatAllocTemp(cUnit);
+    loadConstant(cUnit, tReg, -1);
     opRegReg(cUnit, kOpCmp, rlSrc1.highReg, rlSrc2.highReg);
     ArmLIR* branch1 = opCondBranch(cUnit, kArmCondLt);
     ArmLIR* branch2 = opCondBranch(cUnit, kArmCondGt);
-    opRegRegReg(cUnit, kOpSub, rlTemp.lowReg, rlSrc1.lowReg, rlSrc2.lowReg);
+    opRegRegReg(cUnit, kOpSub, tReg, rlSrc1.lowReg, rlSrc2.lowReg);
     ArmLIR* branch3 = opCondBranch(cUnit, kArmCondEq);
 
     genIT(cUnit, kArmCondHi, "E");
-    newLIR2(cUnit, kThumb2MovImmShift, rlTemp.lowReg, modifiedImmediate(-1));
-    loadConstant(cUnit, rlTemp.lowReg, 1);
+    newLIR2(cUnit, kThumb2MovImmShift, tReg, modifiedImmediate(-1));
+    loadConstant(cUnit, tReg, 1);
     genBarrier(cUnit);
 
     target2 = newLIR0(cUnit, kArmPseudoTargetLabel);
     target2->defMask = -1;
-    opRegReg(cUnit, kOpNeg, rlTemp.lowReg, rlTemp.lowReg);
+    opRegReg(cUnit, kOpNeg, tReg, tReg);
 
     target1 = newLIR0(cUnit, kArmPseudoTargetLabel);
     target1->defMask = -1;
 
+    RegLocation rlTemp = LOC_C_RETURN; // Just using as template, will change
+    rlTemp.lowReg = tReg;
     storeValue(cUnit, rlDest, rlTemp);
+    oatFreeTemp(cUnit, tReg);
 
     branch1->generic.target = (LIR*)target1;
     branch2->generic.target = (LIR*)target2;
@@ -1498,8 +1500,17 @@
         case OP_NOT_LONG:
             rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
             rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
-            opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
+            // Check for destructive overlap
+            if (rlResult.lowReg == rlSrc2.highReg) {
+                int tReg = oatAllocTemp(cUnit);
+                genRegCopy(cUnit, tReg, rlSrc2.highReg);
+                opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
+                opRegReg(cUnit, kOpMvn, rlResult.highReg, tReg);
+                oatFreeTemp(cUnit, tReg);
+            } else {
+                opRegReg(cUnit, kOpMvn, rlResult.lowReg, rlSrc2.lowReg);
+                opRegReg(cUnit, kOpMvn, rlResult.highReg, rlSrc2.highReg);
+            }
             storeValueWide(cUnit, rlDest, rlResult);
             return false;
             break;
@@ -1548,15 +1559,25 @@
             secondOp = kOpXor;
             break;
         case OP_NEG_LONG: {
-            //TUNING: can improve this using Thumb2 code
-            int tReg = oatAllocTemp(cUnit);
             rlSrc2 = loadValueWide(cUnit, rlSrc2, kCoreReg);
             rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
-            loadConstantNoClobber(cUnit, tReg, 0);
-            opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
-                        tReg, rlSrc2.lowReg);
-            opRegReg(cUnit, kOpSbc, tReg, rlSrc2.highReg);
-            genRegCopy(cUnit, rlResult.highReg, tReg);
+            int zReg = oatAllocTemp(cUnit);
+            loadConstantNoClobber(cUnit, zReg, 0);
+            // Check for destructive overlap
+            if (rlResult.lowReg == rlSrc2.highReg) {
+                int tReg = oatAllocTemp(cUnit);
+                opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
+                            zReg, rlSrc2.lowReg);
+                opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
+                            zReg, tReg);
+                oatFreeTemp(cUnit, tReg);
+            } else {
+                opRegRegReg(cUnit, kOpSub, rlResult.lowReg,
+                            zReg, rlSrc2.lowReg);
+                opRegRegReg(cUnit, kOpSbc, rlResult.highReg,
+                            zReg, rlSrc2.highReg);
+            }
+            oatFreeTemp(cUnit, zReg);
             storeValueWide(cUnit, rlDest, rlResult);
             return false;
         }
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index 4fe3191..68b83f2 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -327,7 +327,7 @@
   if (o == NULL) {
     return JNI_FALSE;
   }
-  return Object::InstanceOf(o, c) ? JNI_TRUE : JNI_FALSE;
+  return o->InstanceOf(c) ? JNI_TRUE : JNI_FALSE;
 }
 
 jboolean Class_isInterface(JNIEnv* env, jobject javaThis) {
diff --git a/src/java_lang_reflect_Constructor.cc b/src/java_lang_reflect_Constructor.cc
index 10a8f07..6cc8ea7 100644
--- a/src/java_lang_reflect_Constructor.cc
+++ b/src/java_lang_reflect_Constructor.cc
@@ -40,6 +40,11 @@
     return NULL;
   }
 
+  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
+    DCHECK(Thread::Current()->IsExceptionPending());
+    return NULL;
+  }
+
   Object* receiver = c->AllocObject();
   if (receiver == NULL) {
     return NULL;
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index fd6d314..0436500 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -691,12 +691,12 @@
     ScopedJniThreadState ts(env);
     CHECK_NE(static_cast<jclass>(NULL), clazz); // TODO: ReportJniError
     if (jobj == NULL) {
-      // NB. JNI is different from regular Java instanceof in this respect
+      // Note: JNI is different from regular Java instanceof in this respect
       return JNI_TRUE;
     } else {
       Object* obj = Decode<Object*>(ts, jobj);
       Class* klass = Decode<Class*>(ts, clazz);
-      return Object::InstanceOf(obj, klass) ? JNI_TRUE : JNI_FALSE;
+      return obj->InstanceOf(klass) ? JNI_TRUE : JNI_FALSE;
     }
   }
 
diff --git a/src/object.cc b/src/object.cc
index cfc18bf..5017c23 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -807,6 +807,7 @@
   DCHECK(!IsAbstract()) << PrettyClass(this);
   DCHECK(!IsInterface()) << PrettyClass(this);
   DCHECK(!IsPrimitive()) << PrettyClass(this);
+  DCHECK(!Runtime::Current()->IsStarted() || IsInitializing()) << PrettyClass(this);
   return Heap::AllocObject(this, this->object_size_);
 }
 
diff --git a/src/object.h b/src/object.h
index 1a137bd..47aa98d 100644
--- a/src/object.h
+++ b/src/object.h
@@ -191,11 +191,9 @@
 // C++ mirror of java.lang.Object
 class MANAGED Object {
  public:
-  static bool InstanceOf(const Object* object, const Class* klass) {
-    if (object == NULL) {
-      return false;
-    }
-    return object->InstanceOf(klass);
+  static uint32_t InstanceOfFromCode(const Object* object, const Class* klass) {
+    DCHECK(object != NULL);
+    return object->InstanceOf(klass) ? 1 : 0;
   }
 
   static MemberOffset ClassOffset() {
@@ -1295,6 +1293,11 @@
     return GetStatus() >= kStatusVerified;
   }
 
+  // Returns true if the class is initializing.
+  bool IsInitializing() const {
+    return GetStatus() >= kStatusInitializing;
+  }
+
   // Returns true if the class is initialized.
   bool IsInitialized() const {
     return GetStatus() == kStatusInitialized;
diff --git a/src/object_test.cc b/src/object_test.cc
index d6705d7..f263872 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -328,18 +328,15 @@
   ASSERT_TRUE(X != NULL);
   ASSERT_TRUE(Y != NULL);
 
-  EXPECT_FALSE(Object::InstanceOf(NULL, X));
-  EXPECT_FALSE(Object::InstanceOf(NULL, Y));
-
   Object* x = X->AllocObject();
   Object* y = Y->AllocObject();
   ASSERT_TRUE(x != NULL);
   ASSERT_TRUE(y != NULL);
 
-  EXPECT_TRUE(Object::InstanceOf(x, X));
-  EXPECT_FALSE(Object::InstanceOf(x, Y));
-  EXPECT_TRUE(Object::InstanceOf(y, X));
-  EXPECT_TRUE(Object::InstanceOf(y, Y));
+  EXPECT_EQ(1U, Object::InstanceOfFromCode(x, X));
+  EXPECT_EQ(0U, Object::InstanceOfFromCode(x, Y));
+  EXPECT_EQ(1U, Object::InstanceOfFromCode(y, X));
+  EXPECT_EQ(1U, Object::InstanceOfFromCode(y, Y));
 
   EXPECT_TRUE(x->InstanceOf(X));
   EXPECT_FALSE(x->InstanceOf(Y));
diff --git a/src/runtime.cc b/src/runtime.cc
index ca1d4f8..eb5e498 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -359,14 +359,17 @@
 }
 
 void Runtime::Start() {
-  started_ = true;
-
   InitNativeMethods();
 
   Thread::FinishStartup();
 
   class_linker_->RunRootClinits();
 
+  // Class::AllocObject asserts that all objects allocated better be
+  // initialized after Runtime::IsStarted is true, so this needs to
+  // come after ClassLinker::RunRootClinits.
+  started_ = true;
+
   StartDaemonThreads();
 }
 
diff --git a/src/thread.cc b/src/thread.cc
index 4e3e8d1..d79e1c5 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -230,6 +230,11 @@
       return NULL;  // Failure
     }
   }
+  if (!klass->IsInitialized()
+      && !Runtime::Current()->GetClassLinker()->EnsureInitialized(klass, true)) {
+    DCHECK(Thread::Current()->IsExceptionPending());
+    return NULL;  // Failure
+  }
   return klass->AllocObject();
 }
 
@@ -497,7 +502,7 @@
   pSetObjStatic = Field::SetObjStaticFromCode;
   pInitializeTypeFromCode = InitializeTypeFromCode;
   pResolveMethodFromCode = ResolveMethodFromCode;
-  pInstanceofNonTrivialFromCode = Object::InstanceOf;
+  pInstanceofNonTrivialFromCode = Object::InstanceOfFromCode;
   pLockObjectFromCode = LockObjectFromCode;
   pFindInstanceFieldFromCode = Field::FindInstanceFieldFromCode;
   pCheckSuspendFromCode = artCheckSuspendFromCode;
diff --git a/src/thread.h b/src/thread.h
index 01cc1cc..123a376 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -210,7 +210,7 @@
   Object* (*pGetObjStatic)(uint32_t, const Method*);
   void (*pSetObjStatic)(uint32_t, const Method*, Object*);
   void (*pCanPutArrayElementFromCode)(void*, void*);
-  bool (*pInstanceofNonTrivialFromCode) (const Object*, const Class*);
+  uint32_t (*pInstanceofNonTrivialFromCode) (const Object*, const Class*);
   void (*pCheckCastFromCode) (void*, void*);
   Method* (*pFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, struct DvmDex*);
   void (*pUnlockObjectFromCode)(void*, void*);
diff --git a/test/IntMath/IntMath.java b/test/IntMath/IntMath.java
index 7b0d5f8..21f84bb 100644
--- a/test/IntMath/IntMath.java
+++ b/test/IntMath/IntMath.java
@@ -54,6 +54,10 @@
         IntMathBase a = new IntMathBase();
         IntMath b = new IntMath();
 
+        if (!(null instanceof IntMathBase)) {
+            x = x + 42;
+        }
+
         if (a instanceof IntMathBase) {
             x = x * 2;
         }
@@ -1116,7 +1120,7 @@
         }
 
         res = instanceTest(10);
-        if (res == 1352) {
+        if (res == 1436) {
             System.out.println("instanceTest PASSED");
         } else {
             System.out.println("instanceTest FAILED: " + res);