Better unresolved type support.

Also fix bug where miranda methods were changing their declaring class
and thereby breaking their return type indices.
Add support for dumping stacks on abort.

Change-Id: I3782864736b12d1f81ab9aea4909213d3344ba13
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 0232ee3..f49f546 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1328,7 +1328,9 @@
     return;
   }
   dst->SetAccessFlags(src.access_flags_);
-  dst->SetReturnTypeIdx(dex_file.GetProtoId(method_id.proto_idx_).return_type_idx_);
+  uint32_t return_type_idx = dex_file.GetProtoId(method_id.proto_idx_).return_type_idx_;
+  DCHECK_LT(return_type_idx, dex_file.NumTypeIds());
+  dst->SetReturnTypeIdx(return_type_idx);
 
   dst->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
   dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
@@ -1910,8 +1912,8 @@
 bool ClassLinker::HasSameMethodDescriptorClasses(const Method* method,
                                                  const Class* klass1,
                                                  const Class* klass2) {
-  if (method->IsMiranda()) {
-      return true;
+  if (klass1 == klass2) {
+    return true;
   }
   const DexFile& dex_file = FindDexFile(method->GetDeclaringClass()->GetDexCache());
   const DexFile::ProtoId& proto_id = dex_file.GetProtoId(method->GetProtoIdx());
@@ -1946,6 +1948,9 @@
   CHECK(descriptor != NULL);
   CHECK(klass1 != NULL);
   CHECK(klass2 != NULL);
+  if (klass1 == klass2) {
+    return true;
+  }
   Class* found1 = FindClass(descriptor, klass1->GetClassLoader());
   // TODO: found1 == NULL
   Class* found2 = FindClass(descriptor, klass2->GetClassLoader());
@@ -1953,13 +1958,10 @@
   // TODO: lookup found1 in initiating loader list
   if (found1 == NULL || found2 == NULL) {
     Thread::Current()->ClearException();
-    if (found1 == found2) {
-      return true;
-    } else {
-      return false;
-    }
+    return found1 == found2;
+  } else {
+    return true;
   }
-  return true;
 }
 
 bool ClassLinker::InitializeSuperClass(Class* klass, bool can_run_clinit) {
@@ -2393,7 +2395,7 @@
     vtable = vtable->CopyOf(new_vtable_count);
     for (size_t i = 0; i < miranda_list.size(); ++i) {
       Method* method = miranda_list[i];
-      method->SetDeclaringClass(klass.get());
+      // Leave the declaring class alone as type indices are relative to it
       method->SetAccessFlags(method->GetAccessFlags() | kAccMiranda);
       method->SetMethodIndex(0xFFFF & (old_vtable_count + i));
       klass->SetVirtualMethod(old_method_count + i, method);
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index 6cb7104..85c4182 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -156,31 +156,30 @@
     return true;
   } else {
     switch (GetType()) {
-      case RegType::kRegTypeBoolean:  return IsBooleanTypes();
-      case RegType::kRegTypeByte:     return IsByteTypes();
-      case RegType::kRegTypeShort:    return IsShortTypes();
-      case RegType::kRegTypeChar:     return IsCharTypes();
-      case RegType::kRegTypeInteger:  return IsIntegralTypes();
-      case RegType::kRegTypeFloat:    return IsFloatTypes();
-      case RegType::kRegTypeLongLo:   return IsLongTypes();
-      case RegType::kRegTypeDoubleLo: return IsDoubleTypes();
+      case RegType::kRegTypeBoolean:  return src.IsBooleanTypes();
+      case RegType::kRegTypeByte:     return src.IsByteTypes();
+      case RegType::kRegTypeShort:    return src.IsShortTypes();
+      case RegType::kRegTypeChar:     return src.IsCharTypes();
+      case RegType::kRegTypeInteger:  return src.IsIntegralTypes();
+      case RegType::kRegTypeFloat:    return src.IsFloatTypes();
+      case RegType::kRegTypeLongLo:   return src.IsLongTypes();
+      case RegType::kRegTypeDoubleLo: return src.IsDoubleTypes();
       default:
         if (!IsReferenceTypes()) {
           LOG(FATAL) << "Unexpected register type in IsAssignableFrom: '" << src << "'";
         }
         if (src.IsZero()) {
-          return true;
-        } else if (IsUninitializedReference()) {
-          return false;  // Nonsensical to Join two uninitialized classes
-        } else if (GetClass()->IsInterface()) {
+          return true;  // all reference types can be assigned null
+        } else if (!src.IsReferenceTypes()) {
+          return false;  // expect src to be a reference type
+        } else if (IsJavaLangObject()) {
+          return true;  // all reference types can be assigned to Object
+        } else if (!IsUnresolvedTypes() && GetClass()->IsInterface()) {
           return true;  // We allow assignment to any interface, see comment in ClassJoin
-        } else if (IsReference() && src.IsReference() &&
+        } else if (!IsUnresolvedTypes() && !src.IsUnresolvedTypes() &&
                    GetClass()->IsAssignableFrom(src.GetClass())) {
           // We're assignable from the Class point-of-view
           return true;
-        } else if (src.IsUnresolvedReference() && IsReference() && GetClass()->IsObjectClass()) {
-          // We're an object being assigned an unresolved reference, which is ok
-          return true;
         } else {
           return false;
         }
@@ -263,12 +262,14 @@
     // float/long/double MERGE float/long/double_constant => float/long/double
     return SelectNonConstant(*this, incoming_type);
   } else if (IsReferenceTypes() && incoming_type.IsReferenceTypes()) {
-    if (IsZero() | incoming_type.IsZero()) {
+    if (IsZero() || incoming_type.IsZero()) {
       return SelectNonConstant(*this, incoming_type);  // 0 MERGE ref => ref
-    } else  if (IsUnresolvedReference() || IsUninitializedReference() ||
-                IsUninitializedThisReference()) {
-      // Can only merge an uninitialized or unresolved type with itself or 0, we've already checked
-      // these so => Conflict
+    } else if (IsJavaLangObject() || incoming_type.IsJavaLangObject()) {
+      return reg_types->JavaLangObject();  // Object MERGE ref => Object
+    } else if (IsUninitializedTypes() || incoming_type.IsUninitializedTypes() ||
+               IsUnresolvedTypes() || incoming_type.IsUnresolvedTypes()) {
+      // Can only merge an unresolved or uninitialized type with itself, 0 or Object, we've already
+      // checked these so => Conflict
       return reg_types->Conflict();
     } else {  // Two reference types, compute Join
       Class* c1 = GetClass();
@@ -1865,18 +1866,14 @@
           /* return_type is the *expected* return type, not register value */
           DCHECK(!return_type.IsZero());
           DCHECK(!return_type.IsUninitializedReference());
-          // Verify that the reference in vAA is an instance of the type in "return_type". The Zero
-          // type is allowed here. If the method is declared to return an interface, then any
-          // initialized reference is acceptable.
-          // Note GetClassFromRegister fails if the register holds an uninitialized reference, so
-          // we do not allow them to be returned.
-          Class* decl_class = return_type.GetClass();
-          Class* res_class = work_line_->GetClassFromRegister(dec_insn.vA_);
-          if (res_class != NULL && failure_ == VERIFY_ERROR_NONE) {
-            if (!decl_class->IsInterface() && !decl_class->IsAssignableFrom(res_class)) {
-              Fail(VERIFY_ERROR_GENERIC) << "returning " << PrettyClassAndClassLoader(res_class)
-                                         << ", declared " << PrettyClassAndClassLoader(res_class);
-            }
+          const RegType& reg_type = work_line_->GetRegisterType(dec_insn.vA_);
+          // Disallow returning uninitialized values and verify that the reference in vAA is an
+          // instance of the "return_type"
+          if (reg_type.IsUninitializedTypes()) {
+            Fail(VERIFY_ERROR_GENERIC) << "returning uninitialized object '" << reg_type << "'";
+          } else if (!return_type.IsAssignableFrom(reg_type)) {
+            Fail(VERIFY_ERROR_GENERIC) << "returning '" << reg_type
+                << "', but expected from declaration '" << return_type << "'";
           }
         }
       }
@@ -2332,7 +2329,9 @@
                         dec_insn.opcode_ == Instruction::INVOKE_SUPER_RANGE);
       Method* called_method = VerifyInvocationArgs(dec_insn, METHOD_VIRTUAL, is_range, is_super);
       if (failure_ == VERIFY_ERROR_NONE) {
-        const RegType& return_type = reg_types_.FromClass(called_method->GetReturnType());
+        const RegType& return_type =
+            reg_types_.FromDescriptor(called_method->GetDeclaringClass()->GetClassLoader(),
+                                      called_method->GetReturnTypeDescriptor());
         work_line_->SetResultRegisterType(return_type);
         just_set_result = true;
       }
@@ -2390,7 +2389,9 @@
           if (failure_ != VERIFY_ERROR_NONE)
             break;
         }
-        const RegType& return_type = reg_types_.FromClass(called_method->GetReturnType());
+        const RegType& return_type =
+            reg_types_.FromDescriptor(called_method->GetDeclaringClass()->GetClassLoader(),
+                                      called_method->GetReturnTypeDescriptor());
         work_line_->SetResultRegisterType(return_type);
         just_set_result = true;
       }
@@ -2401,7 +2402,9 @@
         bool is_range = (dec_insn.opcode_ == Instruction::INVOKE_STATIC_RANGE);
         Method* called_method = VerifyInvocationArgs(dec_insn, METHOD_STATIC, is_range, false);
         if (failure_ == VERIFY_ERROR_NONE) {
-          const RegType& return_type =  reg_types_.FromClass(called_method->GetReturnType());
+          const RegType& return_type =
+              reg_types_.FromDescriptor(called_method->GetDeclaringClass()->GetClassLoader(),
+                                        called_method->GetReturnTypeDescriptor());
           work_line_->SetResultRegisterType(return_type);
           just_set_result = true;
         }
@@ -2445,7 +2448,9 @@
          * We don't have an object instance, so we can't find the concrete method. However, all of
          * the type information is in the abstract method, so we're good.
          */
-        const RegType& return_type = reg_types_.FromClass(abs_method->GetReturnType());
+        const RegType& return_type =
+            reg_types_.FromDescriptor(abs_method->GetDeclaringClass()->GetClassLoader(),
+                                      abs_method->GetReturnTypeDescriptor());
         work_line_->SetResultRegisterType(return_type);
         just_set_result = true;
       }
@@ -3057,11 +3062,10 @@
       return NULL;
     }
     if (method_type != METHOD_INTERFACE && !actual_arg_type.IsZero()) {
-      Class* actual_this_ref = actual_arg_type.GetClass();
-      if (!res_method->GetDeclaringClass()->IsAssignableFrom(actual_this_ref)) {
-        Fail(VERIFY_ERROR_GENERIC) << "'this' arg '"
-            << PrettyDescriptor(actual_this_ref->GetDescriptor()) << "' not instance of '"
-            << PrettyDescriptor(res_method->GetDeclaringClass()->GetDescriptor()) << "'";
+      const RegType& res_method_class = reg_types_.FromClass(res_method->GetDeclaringClass());
+      if (!res_method_class.IsAssignableFrom(actual_arg_type)) {
+        Fail(VERIFY_ERROR_GENERIC) << "'this' arg '" << actual_arg_type << "' not instance of '"
+            << res_method_class << "'";
         return NULL;
       }
     }
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index d12e14f..b1e6e29 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -92,7 +92,9 @@
     return IsUninitializedReference() || IsUninitializedThisReference() ||
         IsUnresolvedAndUninitializedReference();
   }
-
+  bool IsUnresolvedTypes() const {
+    return IsUnresolvedReference() || IsUnresolvedAndUninitializedReference();
+  }
   bool IsLowHalf() const { return type_ == kRegTypeLongLo ||
                                   type_ == kRegTypeDoubleLo ||
                                   type_ == kRegTypeConstLo; }
@@ -191,6 +193,9 @@
     return down_cast<Class*>(klass_or_descriptor_);
   }
 
+  bool IsJavaLangObject() const {
+    return IsReference() && GetClass()->IsObjectClass();
+  }
   String* GetDescriptor() const {
     DCHECK(IsUnresolvedReference());
     DCHECK(klass_or_descriptor_ != NULL);
@@ -1125,7 +1130,8 @@
    * Returned references are assumed to be initialized. Returns kRegTypeUnknown for "void".
    */
   const RegType& GetMethodReturnType() {
-    return reg_types_.FromClass(method_->GetReturnType());
+    return reg_types_.FromDescriptor(method_->GetDeclaringClass()->GetClassLoader(),
+                                     method_->GetReturnTypeDescriptor());
   }
 
   /*
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index 81d070f..eccf977 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -78,7 +78,7 @@
   if (public_only && !m->IsPublic()) {
     return false;
   }
-  if (m->IsMiranda() || m->IsStatic()) {
+  if (m->IsStatic()) {
     return false;
   }
   if (m->GetName()->CharAt(0) != '<') {
@@ -134,9 +134,6 @@
   if (public_only && !m->IsPublic()) {
     return false;
   }
-  if (m->IsMiranda()) {
-    return false;
-  }
   if (m->GetName()->CharAt(0) == '<') {
     return false;
   }
diff --git a/src/object.cc b/src/object.cc
index 91328aa..78a1976 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -400,6 +400,16 @@
              new_return_type_idx, false);
 }
 
+const char* Method::GetReturnTypeDescriptor() const {
+  Class* declaring_class = GetDeclaringClass();
+  DexCache* dex_cache = declaring_class->GetDexCache();
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
+  const char* descriptor = dex_file.dexStringByTypeIdx(GetReturnTypeIdx());
+  DCHECK(descriptor != NULL);
+  return descriptor;
+}
+
 Class* Method::GetReturnType() const {
   DCHECK(GetDeclaringClass()->IsResolved() || GetDeclaringClass()->IsErroneous())
       << PrettyMethod(this);
@@ -1468,6 +1478,25 @@
   return !InstanceOf(jlre);
 }
 
+std::string Throwable::Dump() const {
+  Object* stack_state = GetStackState();
+  if (stack_state == NULL || !stack_state->IsObjectArray()) {
+    // missing or corrupt stack state
+    return "";
+  }
+  // Decode the internal stack trace into the depth and method trace
+  ObjectArray<Object>* method_trace = down_cast<ObjectArray<Object>*>(stack_state);
+  int32_t depth = method_trace->GetLength() - 1;
+  std::string result;
+  for (int32_t i = 0; i < depth; ++i) {
+    Method* method = down_cast<Method*>(method_trace->Get(i));
+    result += "  at ";
+    result += PrettyMethod(method, true);
+    result += "\n";
+  }
+  return result;
+}
+
 Class* StackTraceElement::java_lang_StackTraceElement_ = NULL;
 
 void StackTraceElement::SetClass(Class* java_lang_StackTraceElement) {
diff --git a/src/object.h b/src/object.h
index cabaac2..58c6ba7 100644
--- a/src/object.h
+++ b/src/object.h
@@ -712,6 +712,8 @@
 
   void SetReturnTypeIdx(uint32_t new_return_type_idx);
 
+  const char* GetReturnTypeDescriptor() const;
+
   Class* GetReturnType() const;
 
   bool IsReturnAReference() const;
@@ -2026,9 +2028,10 @@
   // virtual methods defined in this class; invoked through vtable
   ObjectArray<Method>* virtual_methods_;
 
-  // Virtual method table (vtable), for use by "invoke-virtual".  The
-  // vtable from the superclass is copied in, and virtual methods from
-  // our class either replace those from the super or are appended.
+  // Virtual method table (vtable), for use by "invoke-virtual".  The vtable from the superclass is
+  // copied in, and virtual methods from our class either replace those from the super or are
+  // appended. For abstract classes, methods may be created in the vtable that aren't in
+  // virtual_ methods_ for miranda methods.
   ObjectArray<Method>* vtable_;
 
   // access flags; low 16 bits are defined by VM spec
@@ -2207,23 +2210,24 @@
 }
 
 inline bool Method::IsReturnAReference() const {
-  return !GetReturnType()->IsPrimitive();
+  char d = GetReturnTypeDescriptor()[0];
+  return d == 'L' || d == '[';
 }
 
 inline bool Method::IsReturnAFloat() const {
-  return GetReturnType()->IsPrimitiveFloat();
+  return GetReturnTypeDescriptor()[0] == 'F';
 }
 
 inline bool Method::IsReturnADouble() const {
-  return GetReturnType()->IsPrimitiveDouble();
+  return GetReturnTypeDescriptor()[0] == 'D';
 }
 
 inline bool Method::IsReturnALong() const {
-  return GetReturnType()->IsPrimitiveLong();
+  return GetReturnTypeDescriptor()[0] == 'J';
 }
 
 inline bool Method::IsReturnVoid() const {
-  return GetReturnType()->IsPrimitiveVoid();
+  return GetReturnTypeDescriptor()[0] == 'V';
 }
 
 inline size_t Array::SizeOf() const {
@@ -2628,9 +2632,14 @@
     SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_),
                    new_detail_message, false);
   }
+  std::string Dump() const;
 
   bool IsCheckedException() const;
  private:
+  Object* GetStackState() const {
+    return GetFieldObject<Object*>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), true);
+  }
+
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   Throwable* cause_;
   String* detail_message_;
diff --git a/src/runtime.cc b/src/runtime.cc
index 9e8b28b..7aa4f51 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -82,7 +82,21 @@
 
   // Many people have difficulty distinguish aborts from crashes,
   // so be explicit.
-  LogMessage(file, line, ERROR, -1).stream() << "Runtime aborting...";
+  {
+    LogMessage log(file, line, ERROR, -1);
+    log.stream() << "Runtime aborting..." << std::endl;
+    // Add Java stack trace if possible
+    Thread* thread = Thread::Current();
+    if (thread != NULL) {
+      log.stream() << "Java stack trace of aborting thread:" << std::endl;
+      thread->DumpStack(log.stream());
+      if (thread->IsExceptionPending()) {
+        Throwable* e = thread->GetException();
+        log.stream() << "Pending exception on thread: " << PrettyTypeOf(e) << std::endl;
+        log.stream() << e->Dump();
+      }
+    }
+  }
 
   // Perform any platform-specific pre-abort actions.
   PlatformAbort(file, line);
diff --git a/src/thread.cc b/src/thread.cc
index d9edd60..fc7fadb 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1081,11 +1081,10 @@
     jobjectArray output_array, int* stack_depth) {
   // Transition into runnable state to work on Object*/Array*
   ScopedJniThreadState ts(env);
-
   // Decode the internal stack trace into the depth, method trace and PC trace
   ObjectArray<Object>* method_trace =
       down_cast<ObjectArray<Object>*>(Decode<Object*>(ts.Env(), internal));
-  int32_t depth = method_trace->GetLength()-1;
+  int32_t depth = method_trace->GetLength() - 1;
   IntArray* pc_trace = down_cast<IntArray*>(method_trace->Get(depth));
 
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();