Merge "Fix test 086-classloader" into dalvik-dev
diff --git a/src/compiled_class.h b/src/compiled_class.h
new file mode 100644
index 0000000..98f0d9f
--- /dev/null
+++ b/src/compiled_class.h
@@ -0,0 +1,24 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_COMPILED_CLASS_H_
+#define ART_SRC_COMPILED_CLASS_H_
+
+#include "object.h"
+
+namespace art {
+
+class CompiledClass {
+ public:
+  CompiledClass(Class::Status status) : status_(status) {};
+  ~CompiledClass() {};
+  Class::Status GetStatus() const {
+    return status_;
+  }
+ private:
+  const Class::Status status_;
+};
+
+}  // namespace art
+
+#endif  // ART_SRC_COMPILED_CLASS_H_
+
diff --git a/src/compiled_method.h b/src/compiled_method.h
index b09a762..4b5a78b 100644
--- a/src/compiled_method.h
+++ b/src/compiled_method.h
@@ -12,7 +12,7 @@
 
 class CompiledMethod {
  public:
-  // Create an CompiledMethod from the oatCompileMethod
+  // Create a CompiledMethod from the oatCompileMethod
   CompiledMethod(InstructionSet instruction_set,
                  std::vector<short>& code,
                  const size_t frame_size_in_bytes,
@@ -21,7 +21,7 @@
                  std::vector<uint32_t>& mapping_table,
                  std::vector<uint16_t>& vmap_table);
 
-  // Create an CompiledMethod from the JniCompiler
+  // Create a CompiledMethod from the JniCompiler
   CompiledMethod(InstructionSet instruction_set,
                  std::vector<uint8_t>& code,
                  const size_t frame_size_in_bytes,
diff --git a/src/compiler.cc b/src/compiler.cc
index e01ab74..88e156d 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -50,6 +50,7 @@
 }
 
 Compiler::~Compiler() {
+  STLDeleteValues(&compiled_classes_);
   STLDeleteValues(&compiled_methods_);
   STLDeleteValues(&compiled_invoke_stubs_);
 }
@@ -323,9 +324,20 @@
     Class* klass = class_linker->FindClass(descriptor, class_loader);
     if (klass != NULL) {
       class_linker->EnsureInitialized(klass, false);
+      // record the final class status if necessary
+      Class::Status status = klass->GetStatus();
+      ClassReference ref(&dex_file, class_def_index);
+      CompiledClass* compiled_class = GetCompiledClass(ref);
+      if (compiled_class == NULL) {
+        compiled_class = new CompiledClass(status);
+        compiled_classes_[ref] = compiled_class;
+      } else {
+        DCHECK_EQ(status, compiled_class->GetStatus());
+      }
     }
     // clear any class not found or verification exceptions
     Thread::Current()->ClearException();
+
   }
 
   DexCache* dex_cache = class_linker->FindDexCache(dex_file);
@@ -404,13 +416,9 @@
 
   if (compiled_method != NULL) {
     MethodReference ref(&dex_file, method_idx);
-    CHECK(compiled_methods_.find(ref) == compiled_methods_.end())
-        << PrettyMethod(method_idx, dex_file);
+    CHECK(GetCompiledMethod(ref) == NULL) << PrettyMethod(method_idx, dex_file);
     compiled_methods_[ref] = compiled_method;
-    DCHECK(compiled_methods_.find(ref) != compiled_methods_.end())
-        << PrettyMethod(method_idx, dex_file);
-    DCHECK(GetCompiledMethod(ref) != NULL)
-        << PrettyMethod(method_idx, dex_file);
+    DCHECK(GetCompiledMethod(ref) != NULL) << PrettyMethod(method_idx, dex_file);
   }
 
   const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
@@ -455,6 +463,15 @@
   compiled_invoke_stubs_[key] = compiled_invoke_stub;
 }
 
+CompiledClass* Compiler::GetCompiledClass(ClassReference ref) const {
+  ClassTable::const_iterator it = compiled_classes_.find(ref);
+  if (it == compiled_classes_.end()) {
+    return NULL;
+  }
+  CHECK(it->second != NULL);
+  return it->second;
+}
+
 CompiledMethod* Compiler::GetCompiledMethod(MethodReference ref) const {
   MethodTable::const_iterator it = compiled_methods_.find(ref);
   if (it == compiled_methods_.end()) {
diff --git a/src/compiler.h b/src/compiler.h
index f05f80b..f59587f 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -3,6 +3,7 @@
 #ifndef ART_SRC_COMPILER_H_
 #define ART_SRC_COMPILER_H_
 
+#include "compiled_class.h"
 #include "compiled_method.h"
 #include "constants.h"
 #include "dex_cache.h"
@@ -55,10 +56,14 @@
 
   static ByteArray* CreateJniDlysmLookupStub(InstructionSet instruction_set);
 
-  // A method is uniquely located by its DexFile and index into the method_id table of that dex file
-  typedef std::pair<const DexFile*, uint32_t> MethodReference;
+  // A class is uniquely located by its DexFile and the class_defs_ table index into that DexFile
+  typedef std::pair<const DexFile*, uint32_t> ClassReference;
+  CompiledClass* GetCompiledClass(ClassReference ref) const;
 
+  // A method is uniquely located by its DexFile and the method_ids_ table index into that DexFile
+  typedef std::pair<const DexFile*, uint32_t> MethodReference;
   CompiledMethod* GetCompiledMethod(MethodReference ref) const;
+
   const CompiledInvokeStub* FindInvokeStub(bool is_static, const char* shorty) const;
 
   // Callbacks from OAT/ART compiler to see what runtime checks must be generated
@@ -122,8 +127,25 @@
   InstructionSet instruction_set_;
   JniCompiler jni_compiler_;
 
+  struct ClassReferenceHash {
+    size_t operator()(const ClassReference& id) const {
+      size_t dex = reinterpret_cast<size_t>(id.first);
+      DCHECK_NE(dex, static_cast<size_t>(0));
+      dex += 33;  // dex is an aligned pointer, get some non-zero low bits
+      size_t idx = id.second;
+      if (idx == 0) {  // special case of a method index of 0
+        return dex * 5381;
+      } else {
+        return dex * idx;
+      }
+    }
+  };
+  typedef std::tr1::unordered_map<const ClassReference, CompiledClass*, ClassReferenceHash> ClassTable;
+  // All class references that this compiler has compiled
+  ClassTable compiled_classes_;
+
   struct MethodReferenceHash {
-    size_t operator()(const MethodReference id) const {
+    size_t operator()(const MethodReference& id) const {
       size_t dex = reinterpret_cast<size_t>(id.first);
       DCHECK_NE(dex, static_cast<size_t>(0));
       dex += 33;  // dex is an aligned pointer, get some non-zero low bits
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 3f8d900..08a53bd 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -545,6 +545,7 @@
             loadWordDisp(cUnit, rSELF,
                          OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
             loadConstant(cUnit, r1, dInsn->vB);
+            loadConstant(cUnit, r2, false);
             callRuntimeHelper(cUnit, rLR);
             genUnconditionalBranch(cUnit, rollback);
             // Resume normal slow path
@@ -729,6 +730,7 @@
             loadWordDisp(cUnit, rSELF,
                          OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
             loadConstant(cUnit, r1, dInsn->vB);
+            loadConstant(cUnit, r2, true);
             callRuntimeHelper(cUnit, rLR);
             genUnconditionalBranch(cUnit, rollback);
             // Resume normal slow path
@@ -1085,6 +1087,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
         loadConstant(cUnit, r1, dInsn->vB);
+        loadConstant(cUnit, r2, true);
         callRuntimeHelper(cUnit, rLR);
     }
 
@@ -1157,6 +1160,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
         loadConstant(cUnit, r1, dInsn->vB);
+        loadConstant(cUnit, r2, false);
         callRuntimeHelper(cUnit, rLR);
     }
 
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 4d6b4a5..646f1c5 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -166,12 +166,12 @@
                                 std::string dex_file_location,
                                 uint32_t dex_file_checksum,
                                 byte* dex_file_pointer,
-                                const uint32_t* methods_offsets_pointer)
+                                const uint32_t* oat_class_offsets_pointer)
     : oat_file_(oat_file),
       dex_file_location_(dex_file_location),
       dex_file_checksum_(dex_file_checksum),
       dex_file_pointer_(dex_file_pointer),
-      methods_offsets_pointer_(methods_offsets_pointer) {}
+      oat_class_offsets_pointer_(oat_class_offsets_pointer) {}
 
 OatFile::OatDexFile::~OatDexFile() {}
 
@@ -181,17 +181,31 @@
 }
 
 const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const {
-  uint32_t methods_offset = methods_offsets_pointer_[class_def_index];
-  const byte* methods_pointer = oat_file_->GetBase() + methods_offset;
+  uint32_t oat_class_offset = oat_class_offsets_pointer_[class_def_index];
+
+  const byte* oat_class_pointer = oat_file_->GetBase() + oat_class_offset;
+  CHECK_LT(oat_class_pointer, oat_file_->GetLimit());
+  Class::Status status = *reinterpret_cast<const Class::Status*>(oat_class_pointer);
+
+  const byte* methods_pointer = oat_class_pointer + sizeof(status);
   CHECK_LT(methods_pointer, oat_file_->GetLimit());
-  return new OatClass(oat_file_, reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
+
+  return new OatClass(oat_file_,
+                      status,
+                      reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
 }
 
-OatFile::OatClass::OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer)
-    : oat_file_(oat_file), methods_pointer_(methods_pointer) {}
+OatFile::OatClass::OatClass(const OatFile* oat_file,
+                            Class::Status status,
+                            const OatMethodOffsets* methods_pointer)
+    : oat_file_(oat_file), status_(status), methods_pointer_(methods_pointer) {}
 
 OatFile::OatClass::~OatClass() {}
 
+Class::Status OatFile::OatClass::GetStatus() const {
+  return status_;
+}
+
 const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
   const OatMethodOffsets& oat_method_offsets = methods_pointer_[method_index];
   return OatMethod(
diff --git a/src/oat_file.h b/src/oat_file.h
index 5b05ad6..5c011fd 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -114,6 +114,8 @@
 
   class OatClass {
    public:
+    Class::Status GetStatus() const;
+
     // get the OatMethod entry based on its index into the class
     // defintion. direct methods come first, followed by virtual
     // methods. note that runtime created methods such as miranda
@@ -122,9 +124,12 @@
     ~OatClass();
 
    private:
-    OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer);
+    OatClass(const OatFile* oat_file,
+             Class::Status status,
+             const OatMethodOffsets* methods_pointer);
 
     const OatFile* oat_file_;
+    const Class::Status status_;
     const OatMethodOffsets* methods_pointer_;
 
     friend class OatDexFile;
@@ -149,13 +154,13 @@
                std::string dex_file_location,
                uint32_t dex_file_checksum,
                byte* dex_file_pointer,
-               const uint32_t* methods_offsets_pointer);
+               const uint32_t* oat_class_offsets_pointer);
 
     const OatFile* oat_file_;
     std::string dex_file_location_;
     uint32_t dex_file_checksum_;
     const byte* dex_file_pointer_;
-    const uint32_t* methods_offsets_pointer_;
+    const uint32_t* oat_class_offsets_pointer_;
 
     friend class OatFile;
     DISALLOW_COPY_AND_ASSIGN(OatDexFile);
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index fa27737..806ac71 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -96,7 +96,13 @@
         size_t num_virtual_methods = it.NumVirtualMethods();
         num_methods = num_direct_methods + num_virtual_methods;
       }
-      OatClass* oat_class = new OatClass(num_methods);
+
+      CompiledClass* compiled_class =
+          compiler_->GetCompiledClass(art::Compiler::MethodReference(dex_file, class_def_index));
+      Class::Status status =
+          (compiled_class != NULL) ? compiled_class->GetStatus() : Class::kStatusNotReady;
+
+      OatClass* oat_class = new OatClass(status, num_methods);
       oat_classes_.push_back(oat_class);
       offset += oat_class->SizeOf();
     }
@@ -656,20 +662,29 @@
   return true;
 }
 
-OatWriter::OatClass::OatClass(uint32_t methods_count) {
+OatWriter::OatClass::OatClass(Class::Status status, uint32_t methods_count) {
+  status_ = status;
   method_offsets_.resize(methods_count);
 }
 
 size_t OatWriter::OatClass::SizeOf() const {
-  return (sizeof(method_offsets_[0]) * method_offsets_.size());
+  return sizeof(status_)
+          + (sizeof(method_offsets_[0]) * method_offsets_.size());
 }
 
 void OatWriter::OatClass::UpdateChecksum(OatHeader& oat_header) const {
-  oat_header.UpdateChecksum(&method_offsets_[0], SizeOf());
+  oat_header.UpdateChecksum(&status_, sizeof(status_));
+  oat_header.UpdateChecksum(&method_offsets_[0],
+                            sizeof(method_offsets_[0]) * method_offsets_.size());
 }
 
 bool OatWriter::OatClass::Write(File* file) const {
-  if (!file->WriteFully(&method_offsets_[0], SizeOf())) {
+  if (!file->WriteFully(&status_, sizeof(status_))) {
+    PLOG(ERROR) << "Failed to write class status to " << file->name();
+    return false;
+  }
+  if (!file->WriteFully(&method_offsets_[0],
+                        sizeof(method_offsets_[0]) * method_offsets_.size())) {
     PLOG(ERROR) << "Failed to write method offsets to " << file->name();
     return false;
   }
diff --git a/src/oat_writer.h b/src/oat_writer.h
index a5de14e..6ae0f4e 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -109,12 +109,13 @@
 
   class OatClass {
    public:
-    explicit OatClass(uint32_t methods_count);
+    explicit OatClass(Class::Status status, uint32_t methods_count);
     size_t SizeOf() const;
     void UpdateChecksum(OatHeader& oat_header) const;
     bool Write(File* file) const;
 
     // data to write
+    Class::Status status_;
     std::vector<OatMethodOffsets> method_offsets_;
 
    private:
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 223ea7e..1a6d2e6 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -854,17 +854,22 @@
   return InitializeStaticStorageAndVerifyAccess(type_idx, referrer, self);
 }
 
-// TODO: placeholder.  Helper function to resolve virtual method
-void ResolveMethodFromCode(Method* method, uint32_t method_idx) {
+// Helper function to resolve virtual method
+extern "C" Method* artResolveMethodFromCode(Method* referrer,
+                                            uint32_t method_idx,
+                                            bool is_direct,
+                                            Thread* self,
+                                            Method** sp) {
     /*
      * Slow-path handler on invoke virtual method path in which
-     * base method is unresolved at compile-time.  Doesn't need to
-     * return anything - just either ensure that
-     * method->dex_cache_resolved_methods_(method_idx) != NULL or
-     * throw and unwind.  The caller will restart call sequence
-     * from the beginning.
+     * base method is unresolved at compile-time.  Caller will
+     * unwind if can't resolve.
      */
-    UNIMPLEMENTED(FATAL);
+    FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+    Method* method = class_linker->ResolveMethod(method_idx, referrer, is_direct);
+    referrer->GetDexCacheResolvedMethods()->Set(method_idx, method);
+    return method;
 }
 
 String* ResolveStringFromCode(const Method* referrer, uint32_t string_idx) {
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 2ebfc22..876abd7 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -25,7 +25,6 @@
 extern Class* InitializeTypeFromCode(uint32_t type_idx, Method* method);
 uint32_t IsAssignableFromCode(const Class* klass, const Class* ref_class);
 void ObjectInitFromCode(Object* o);
-extern void ResolveMethodFromCode(Method* method, uint32_t method_idx);
 extern void LockObjectFromCode(Thread* thread, Object* obj);
 uint32_t artTraceMethodUnwindFromCode(Thread* self);
 extern int64_t D2L(double d);
@@ -73,6 +72,7 @@
   extern "C" void art_trace_entry_from_code(void*);
   extern "C" void art_trace_exit_from_code();
   extern "C" void* art_resolve_string_from_code(void*, uint32_t);
+  extern "C" void* art_resolve_method_from_code(void* referrer, uint32_t method_idx, bool is_direct);
 
   /* Conversions */
   extern "C" float __aeabi_i2f(int op1);             // OP_INT_TO_FLOAT
diff --git a/src/runtime_support_arm.S b/src/runtime_support_arm.S
index 38337a3..c73588e 100644
--- a/src/runtime_support_arm.S
+++ b/src/runtime_support_arm.S
@@ -421,6 +421,22 @@
     bxeq   lr                            @ return on success
     DELIVER_PENDING_EXCEPTION
 
+   .global art_resolve_method_from_code
+    .extern artResolveMethodFromCode
+    /*
+     * Entry from managed code to resolve a method.
+     */
+art_resolve_method_from_code:
+    SETUP_REF_ONLY_CALLEE_SAVE_FRAME  @ save callee saves in case of GC
+    mov    r3, r9                     @ pass Thread::Current
+    str    sp, [sp, #0]               @ pass SP
+    @ artResolveMethodFromCode(Method* referrer, uint32_t method_idx, bool is_direct, Thread*, SP)
+    bl     artResolveMethodFromCode
+    RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
+    cmp    r0, #0                     @ success if result is non-null
+    bxne   lr                         @ return on success
+    DELIVER_PENDING_EXCEPTION
+
     .global art_resolve_string_from_code
     .extern artResolveStringFromCode
     /*
diff --git a/src/thread.cc b/src/thread.cc
index 4adf1e0..b065533 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -127,6 +127,7 @@
   pThrowStackOverflowFromCode = art_throw_stack_overflow_from_code;
   pThrowVerificationErrorFromCode = art_throw_verification_error_from_code;
   pUnlockObjectFromCode = art_unlock_object_from_code;
+  pResolveMethodFromCode = art_resolve_method_from_code;
 #endif
   pF2l = F2L;
   pD2l = D2L;
@@ -137,7 +138,6 @@
   pDeliverException = art_deliver_exception_from_code;
   pFindNativeMethod = FindNativeMethod;
   pInstanceofNonTrivialFromCode = IsAssignableFromCode;
-  pResolveMethodFromCode = ResolveMethodFromCode;
   pThrowAbstractMethodErrorFromCode = ThrowAbstractMethodErrorFromCode;
   pUnresolvedDirectMethodTrampolineFromCode = UnresolvedDirectMethodTrampolineFromCode;
 }
diff --git a/src/thread.h b/src/thread.h
index c5fb914..aee784d 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -143,7 +143,7 @@
   void* (*pInitializeTypeAndVerifyAccessFromCode)(uint32_t, void*);
   void (*pLockObjectFromCode)(void*);
   void (*pObjectInit)(void*);
-  void (*pResolveMethodFromCode)(Method*, uint32_t);
+  void* (*pResolveMethodFromCode)(void*, uint32_t, bool);
   void* (*pResolveStringFromCode)(void*, uint32_t);
   int (*pSet32Static)(uint32_t, void*, int32_t);
   int (*pSet64Static)(uint32_t, void*, int64_t);