Fix for implicit null test for oat.

This change also cleans up the notion of the callee save method with a
"IsPhony" call. Stack visitors check whether the frame they are on has a
legitimate method with "HasMethod".

Change-Id: I8ac0fdd595c1e764fdc22cfa9c6a394595f7e141
diff --git a/src/object.h b/src/object.h
index efdb424..2a4078d 100644
--- a/src/object.h
+++ b/src/object.h
@@ -902,7 +902,7 @@
 
   void SetInvokeStub(const ByteArray* invoke_stub_array);
 
-  uint32_t GetCoreSpillMask() {
+  uint32_t GetCoreSpillMask() const {
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, core_spill_mask_), false);
   }
 
@@ -912,7 +912,7 @@
                core_spill_mask, false);
   }
 
-  uint32_t GetFpSpillMask() {
+  uint32_t GetFpSpillMask() const {
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, fp_spill_mask_), false);
   }
 
@@ -922,6 +922,15 @@
                fp_spill_mask, false);
   }
 
+  // Is this a hand crafted method used for something like describing callee saves?
+  bool IsPhony() const {
+    bool result =
+        NULL == GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Method, declaring_class_), false);
+    // Check that if we do think it is phony it looks like the callee save method
+    DCHECK(!result || GetCoreSpillMask() != 0);
+    return result;
+  }
+
   // Converts a native PC to a dex PC.  TODO: this is a no-op
   // until we associate a PC mapping table with each method.
   uint32_t ToDexPC(const uintptr_t pc) const;
diff --git a/src/thread.cc b/src/thread.cc
index 153f20f..737faff 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -382,6 +382,10 @@
          (*sp_)->GetClass()->GetDescriptor()->Equals("Ljava/lang/reflect/Method;"));
 }
 
+bool Frame::HasMethod() const {
+  return GetMethod() != NULL && (!GetMethod()->IsPhony());
+}
+
 uintptr_t Frame::GetReturnPC() const {
   byte* pc_addr = reinterpret_cast<byte*>(sp_) +
       GetMethod()->GetReturnPcOffsetInBytes();
@@ -693,6 +697,9 @@
   }
 
   void VisitFrame(const Frame& frame, uintptr_t pc) {
+    if (!frame.HasMethod()) {
+      return;
+    }
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
     Method* m = frame.GetMethod();
@@ -1053,8 +1060,10 @@
 
   virtual void VisitFrame(const Frame& frame, uintptr_t pc) {
     // We want to skip frames up to and including the exception's constructor.
+    // Note we also skip the frame if it doesn't have a method (namely the callee
+    // save frame)
     DCHECK(gThrowable != NULL);
-    if (skipping_ && !gThrowable->IsAssignableFrom(frame.GetMethod()->GetDeclaringClass())) {
+    if (skipping_ && frame.HasMethod() && !gThrowable->IsAssignableFrom(frame.GetMethod()->GetDeclaringClass())) {
       skipping_ = false;
     }
     if (!skipping_) {
@@ -1307,17 +1316,17 @@
         return;
       }
       uint32_t dex_pc = DexFile::kDexNoIndex;
-      if (pc > 0) {
-        if (method->IsNative()) {
-          native_method_count_++;
-        } else {
-          // Move the PC back 2 bytes as a call will frequently terminate the
-          // decoding of a particular instruction and we want to make sure we
-          // get the Dex PC of the instruction with the call and not the
-          // instruction following.
-          pc -= 2;
-          dex_pc = method->ToDexPC(pc);
-        }
+      if (method->IsPhony()) {
+        // ignore callee save method
+      } else if (method->IsNative()) {
+        native_method_count_++;
+      } else {
+        // Move the PC back 2 bytes as a call will frequently terminate the
+        // decoding of a particular instruction and we want to make sure we
+        // get the Dex PC of the instruction with the call and not the
+        // instruction following.
+        pc -= 2;
+        dex_pc = method->ToDexPC(pc);
       }
       if (dex_pc != DexFile::kDexNoIndex) {
         uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc);
diff --git a/src/thread.h b/src/thread.h
index 6f1bcc3..0be4aa6 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -130,6 +130,9 @@
     sp_ = sp;
   }
 
+  // Is this a frame for a real method (native or with dex code)
+  bool HasMethod() const;
+
  private:
   Method* NextMethod() const;
 
diff --git a/test/IntMath/IntMath.java b/test/IntMath/IntMath.java
index f437f99..a38525e 100644
--- a/test/IntMath/IntMath.java
+++ b/test/IntMath/IntMath.java
@@ -961,7 +961,6 @@
             System.out.println("catchBlock(1000) FAILED: " + res);
             failure = true;
         }
-if (false) { // TODO: restore when fixed
         res = catchBlock(7000);
         if (res == 7777) {
             System.out.println("catchBlock(7000) PASSED");
@@ -969,7 +968,6 @@
             System.out.println("catchBlock(7000) FAILED: " + res);
             failure = true;
         }
-}
         res = catchBlockNoThrow(1000);
         if (res == 1123) {
             System.out.println("catchBlockNoThrow PASSED");