Cleanup resolution of type, field, method indexes

When resolving a type_idx of a static field, you cannot assume the
type_idx refers to the class that actually provides the storage, it
might be a subclass. The compiler now resolves to the storage class if
possible at compile time, otherwise it reverts to the slow path.

When resolve field and method indexes, you need to know if a field is
static or instance and if a method is direct or virtual. Previously we
tried to guess, which led to problems in classes that had one of
each. Now the compiler resolves which kind of field and method based
on the context of class definitions and dex instructions.

Change-Id: I31826dc90562057eadd81f39d6369aa1216509af
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 5e05439..2adcd11 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1450,7 +1450,7 @@
   }
   if (!class_linker->EnsureInitialized(klass, true)) {
     CHECK(Thread::Current()->IsExceptionPending());
-    UNIMPLEMENTED(FATAL) << "throw exception due to class initialization problem";
+    UNIMPLEMENTED(FATAL) << "throw class initialization error " << PrettyClass(klass);
   }
   referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass);
   return klass;
@@ -1963,7 +1963,7 @@
   for (size_t i = 0; i < num_fields; i++) {
     Field* field = fields->Get(i);
     if (false) {  // enable to debug field layout
-      LOG(INFO) << "LinkFields:"
+      LOG(INFO) << "LinkFields: " << (instance ? "instance" : "static")
                 << " class=" << klass->GetDescriptor()->ToModifiedUtf8()
                 << " field=" << field->GetName()->ToModifiedUtf8()
                 << " offset=" << field->GetField32(MemberOffset(Field::OffsetOffset()), false);
diff --git a/src/class_linker.h b/src/class_linker.h
index ca71b1f..bb38f00 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -115,13 +115,13 @@
     return ResolveMethod(dex_file, method_idx, dex_cache, class_loader, is_direct);
   }
 
-  Field* ResolveField(uint32_t field_idx, const Method* referrer) {
+  Field* ResolveField(uint32_t field_idx, const Method* referrer, bool is_static) {
     Class* declaring_class = referrer->GetDeclaringClass();
     DexCache* dex_cache = declaring_class->GetDexCache();
     // TODO: we could check for a dex cache hit here
     const ClassLoader* class_loader = declaring_class->GetClassLoader();
     const DexFile& dex_file = FindDexFile(dex_cache);
-    return ResolveField(dex_file, field_idx, dex_cache, class_loader, true);
+    return ResolveField(dex_file, field_idx, dex_cache, class_loader, is_static);
   }
 
   // Resolve a field with a given ID from the DexFile, storing the
diff --git a/src/compiler.cc b/src/compiler.cc
index 4d7ad19..454c8f8 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -69,23 +69,66 @@
     class_linker->ResolveString(dex_file, string_idx, dex_cache);
   }
 
-  // Class derived values are more complicated, they require the linker and loader
+  // Class derived values are more complicated, they require the linker and loader.
   for (size_t type_idx = 0; type_idx < dex_cache->NumResolvedTypes(); type_idx++) {
     Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
     CHECK(klass->IsResolved());
   }
-  for (size_t method_idx = 0; method_idx < dex_cache->NumResolvedMethods(); method_idx++) {
-    // unknown if direct or virtual, try both
-    Method* method = class_linker->ResolveMethod(dex_file, method_idx, dex_cache, class_loader, false);
-    if (method == NULL) {
-      class_linker->ResolveMethod(dex_file, method_idx, dex_cache, class_loader, true);
+
+  // Method and Field are the worst. We can't resolve without either
+  // context from the code use (to disambiguate virtual vs direct
+  // method and instance vs static field) or from class
+  // definitions. While the compiler will resolve what it can as it
+  // needs it, here we try to resolve fields and methods used in class
+  // definitions, since many of them many never be referenced by
+  // generated code.
+  for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); class_def_index++) {
+    const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
+
+    // Note the class_data pointer advances through the headers,
+    // static fields, instance fields, direct methods, and virtual
+    // methods.
+    const byte* class_data = dex_file.GetClassData(class_def);
+
+    DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
+    size_t num_static_fields = header.static_fields_size_;
+    size_t num_instance_fields = header.instance_fields_size_;
+    size_t num_direct_methods = header.direct_methods_size_;
+    size_t num_virtual_methods = header.virtual_methods_size_;
+
+    if (num_static_fields != 0) {
+      uint32_t last_idx = 0;
+      for (size_t i = 0; i < num_static_fields; ++i) {
+        DexFile::Field dex_field;
+        dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx);
+        class_linker->ResolveField(dex_file, dex_field.field_idx_, dex_cache, class_loader, true);
+      }
     }
-  }
-  for (size_t field_idx = 0; field_idx < dex_cache->NumResolvedFields(); field_idx++) {
-    // unknown if instance or static, try both
-    Field* field = class_linker->ResolveField(dex_file, field_idx, dex_cache, class_loader, false);
-    if (field == NULL) {
-      class_linker->ResolveField(dex_file, field_idx, dex_cache, class_loader, true);
+    if (num_instance_fields != 0) {
+      uint32_t last_idx = 0;
+      for (size_t i = 0; i < num_instance_fields; ++i) {
+        DexFile::Field dex_field;
+        dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx);
+        class_linker->ResolveField(dex_file, dex_field.field_idx_, dex_cache, class_loader, false);
+      }
+    }
+    if (num_direct_methods != 0) {
+      uint32_t last_idx = 0;
+      for (size_t i = 0; i < num_direct_methods; ++i) {
+        DexFile::Method dex_method;
+        dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
+        class_linker->ResolveMethod(dex_file, dex_method.method_idx_, dex_cache, class_loader,
+                                    true);
+      }
+    }
+    if (num_virtual_methods != 0) {
+      uint32_t last_idx = 0;
+      for (size_t i = 0; i < num_virtual_methods; ++i) {
+        DexFile::Method dex_method;
+        dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx);
+        class_linker->ResolveMethod(dex_file, dex_method.method_idx_, dex_cache, class_loader,
+                                    false);
+      }
     }
   }
 }
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index f42237a..0af213f 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -130,13 +130,47 @@
     }
 }
 
+Field* FindFieldWithResolvedStaticStorage(const Method* method,
+                                          const uint32_t fieldIdx,
+                                          uint32_t& resolvedTypeIdx) {
+    art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
+    Field* field = class_linker->ResolveField(fieldIdx, method, true);
+    if (field == NULL) {
+        return NULL;
+    }
+    const art::DexFile& dex_file = class_linker->
+            FindDexFile(method->GetDeclaringClass()->GetDexCache());
+    const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
+    int type_idx = field_id.class_idx_;
+    Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
+    // Check if storage class is the same as class referred to by type idx.
+    // They may not be if the FieldId refers a subclass, but storage is in super
+    if (field->GetDeclaringClass() == klass) {
+        resolvedTypeIdx = type_idx;
+        return field;
+    }
+    // See if we can find a dex reference for the storage class.
+    // we may not if the dex file never references the super class,
+    // but usually it will.
+    std::string descriptor = field->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8();
+    for (size_t type_idx = 0; type_idx < dex_file.NumTypeIds(); type_idx++) {
+        const art::DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx);
+        if (descriptor == dex_file.GetTypeDescriptor(type_id)) {
+            resolvedTypeIdx = type_idx;
+            return field;
+        }
+    }
+    return NULL;  // resort to slow path
+}
+
 static void genSput(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
 {
     bool isObject = ((mir->dalvikInsn.opcode == OP_SPUT_OBJECT) ||
                      (mir->dalvikInsn.opcode == OP_SPUT_OBJECT_VOLATILE));
     int fieldIdx = mir->dalvikInsn.vB;
-    Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
-    if (field == NULL) {
+    uint32_t typeIdx;
+    Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
+    if (SLOW_FIELD_PATH || field == NULL) {
         // Slow path
         LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
             << " unresolved at compile time";
@@ -152,12 +186,6 @@
     } else {
         // fast path
         int fieldOffset = field->GetOffset().Int32Value();
-        art::ClassLinker* class_linker = art::Runtime::Current()->
-            GetClassLinker();
-        const art::DexFile& dex_file = class_linker->
-            FindDexFile(cUnit->method->GetDeclaringClass()->GetDexCache());
-        const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
-        int typeIdx = field_id.class_idx_;
         // Using fixed register to sync with slow path
         int rMethod = r1;
         oatLockTemp(cUnit, rMethod);
@@ -196,7 +224,8 @@
 static void genSputWide(CompilationUnit* cUnit, MIR* mir, RegLocation rlSrc)
 {
     int fieldIdx = mir->dalvikInsn.vB;
-    Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
+    uint32_t typeIdx;
+    Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
     if (SLOW_FIELD_PATH || field == NULL) {
         LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
             << " unresolved at compile time";
@@ -210,12 +239,6 @@
     } else {
         // fast path
         int fieldOffset = field->GetOffset().Int32Value();
-        art::ClassLinker* class_linker = art::Runtime::Current()->
-            GetClassLinker();
-        const art::DexFile& dex_file = class_linker->
-            FindDexFile(cUnit->method->GetDeclaringClass()->GetDexCache());
-        const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
-        int typeIdx = field_id.class_idx_;
         // Using fixed register to sync with slow path
         int rMethod = r1;
         oatLockTemp(cUnit, rMethod);
@@ -254,7 +277,8 @@
                  RegLocation rlResult, RegLocation rlDest)
 {
     int fieldIdx = mir->dalvikInsn.vB;
-    Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
+    uint32_t typeIdx;
+    Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
     if (SLOW_FIELD_PATH || field == NULL) {
         LOG(INFO) << "Field " << fieldNameFromIndex(cUnit->method, fieldIdx)
             << " unresolved at compile time";
@@ -268,12 +292,6 @@
     } else {
         // Fast path
         int fieldOffset = field->GetOffset().Int32Value();
-        art::ClassLinker* class_linker = art::Runtime::Current()->
-            GetClassLinker();
-        const art::DexFile& dex_file = class_linker->
-            FindDexFile(cUnit->method->GetDeclaringClass()->GetDexCache());
-        const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
-        int typeIdx = field_id.class_idx_;
         // Using fixed register to sync with slow path
         int rMethod = r1;
         oatLockTemp(cUnit, rMethod);
@@ -312,7 +330,8 @@
              RegLocation rlResult, RegLocation rlDest)
 {
     int fieldIdx = mir->dalvikInsn.vB;
-    Field* field = cUnit->method->GetDexCacheResolvedFields()->Get(fieldIdx);
+    uint32_t typeIdx;
+    Field* field = FindFieldWithResolvedStaticStorage(cUnit->method, fieldIdx, typeIdx);
     bool isObject = ((mir->dalvikInsn.opcode == OP_SGET_OBJECT) ||
                      (mir->dalvikInsn.opcode == OP_SGET_OBJECT_VOLATILE));
     if (SLOW_FIELD_PATH || field == NULL) {
@@ -331,12 +350,6 @@
     } else {
         // Fast path
         int fieldOffset = field->GetOffset().Int32Value();
-        art::ClassLinker* class_linker = art::Runtime::Current()->
-            GetClassLinker();
-        const art::DexFile& dex_file = class_linker->
-            FindDexFile(cUnit->method->GetDeclaringClass()->GetDexCache());
-        const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx);
-        int typeIdx = field_id.class_idx_;
         // Using fixed register to sync with slow path
         int rMethod = r1;
         oatLockTemp(cUnit, rMethod);
@@ -421,8 +434,8 @@
      * This is the fast path in which the target virtual method is
      * fully resolved at compile time.
      */
-    Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
-        Get(dInsn->vB);
+    art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
+    Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
     CHECK(baseMethod != NULL);
     uint32_t target_idx = baseMethod->GetMethodIndex();
     switch(state) {
@@ -575,8 +588,8 @@
      * that the check to verify that the target method index falls
      * within the size of the super's vtable has been done at compile-time.
      */
-    Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
-        Get(dInsn->vB);
+    art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
+    Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
     CHECK(baseMethod != NULL);
     Class* superClass = cUnit->method->GetDeclaringClass()->GetSuperClass();
     CHECK(superClass != NULL);
@@ -950,8 +963,8 @@
     int callState = 0;
     ArmLIR* nullCk;
     ArmLIR* rollback;
-    Method* baseMethod = cUnit->method->GetDexCacheResolvedMethods()->
-        Get(dInsn->vB);
+    art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
+    Method* baseMethod = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
     NextCallInsn nextCallInsn;
     bool fastPath = true;
 
@@ -1002,8 +1015,8 @@
     int callState = 0;
     ArmLIR* nullCk;
     ArmLIR* rollback;
-    Method* method = cUnit->method->GetDexCacheResolvedMethods()->
-        Get(dInsn->vB);
+    art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
+    Method* method = class_linker->ResolveMethod(dInsn->vB, cUnit->method, false);
     NextCallInsn nextCallInsn;
 
     // Explicit register usage
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 4d95c52..52d67de 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -435,7 +435,7 @@
 #endif
     // Resolve
     loadWordDisp(cUnit, rSELF,
-                 OFFSETOF_MEMBER(Thread, pFindFieldFromCode), rLR);
+                 OFFSETOF_MEMBER(Thread, pFindInstanceFieldFromCode), rLR);
     loadConstant(cUnit, r0, fieldIdx);
     callUnwindableHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
     ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
diff --git a/src/object.cc b/src/object.cc
index b94d392..756b8a7 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -107,9 +107,17 @@
   return Runtime::Current()->GetClassLinker()->ResolveType(GetTypeIdx(), this);
 }
 
-Field* Field::FindFieldFromCode(uint32_t field_idx, const Method* referrer) {
+Field* Field::FindInstanceFieldFromCode(uint32_t field_idx, const Method* referrer) {
+  return FindFieldFromCode(field_idx, referrer, false);
+}
+
+Field* Field::FindStaticFieldFromCode(uint32_t field_idx, const Method* referrer) {
+  return FindFieldFromCode(field_idx, referrer, true);
+}
+
+Field* Field::FindFieldFromCode(uint32_t field_idx, const Method* referrer, bool is_static) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Field* f = class_linker->ResolveField(field_idx, referrer);
+  Field* f = class_linker->ResolveField(field_idx, referrer, is_static);
   if (f != NULL) {
     Class* c = f->GetDeclaringClass();
     // If the class is already initializing, we must be inside <clinit>, or
@@ -123,32 +131,32 @@
 }
 
 uint32_t Field::Get32StaticFromCode(uint32_t field_idx, const Method* referrer) {
-  Field* field = FindFieldFromCode(field_idx, referrer);
+  Field* field = FindStaticFieldFromCode(field_idx, referrer);
   DCHECK(field->GetType()->PrimitiveSize() == sizeof(int32_t));
   return field->Get32(NULL);
 }
 void Field::Set32StaticFromCode(uint32_t field_idx, const Method* referrer, uint32_t new_value) {
-  Field* field = FindFieldFromCode(field_idx, referrer);
+  Field* field = FindStaticFieldFromCode(field_idx, referrer);
   DCHECK(field->GetType()->PrimitiveSize() == sizeof(int32_t));
   field->Set32(NULL, new_value);
 }
 uint64_t Field::Get64StaticFromCode(uint32_t field_idx, const Method* referrer) {
-  Field* field = FindFieldFromCode(field_idx, referrer);
+  Field* field = FindStaticFieldFromCode(field_idx, referrer);
   DCHECK(field->GetType()->PrimitiveSize() == sizeof(int64_t));
   return field->Get64(NULL);
 }
 void Field::Set64StaticFromCode(uint32_t field_idx, const Method* referrer, uint64_t new_value) {
-  Field* field = FindFieldFromCode(field_idx, referrer);
+  Field* field = FindStaticFieldFromCode(field_idx, referrer);
   DCHECK(field->GetType()->PrimitiveSize() == sizeof(int64_t));
   field->Set64(NULL, new_value);
 }
 Object* Field::GetObjStaticFromCode(uint32_t field_idx, const Method* referrer) {
-  Field* field = FindFieldFromCode(field_idx, referrer);
+  Field* field = FindStaticFieldFromCode(field_idx, referrer);
   DCHECK(!field->GetType()->IsPrimitive());
   return field->GetObj(NULL);
 }
 void Field::SetObjStaticFromCode(uint32_t field_idx, const Method* referrer, Object* new_value) {
-  Field* field = FindFieldFromCode(field_idx, referrer);
+  Field* field = FindStaticFieldFromCode(field_idx, referrer);
   DCHECK(!field->GetType()->IsPrimitive());
   field->SetObj(NULL, new_value);
 }
diff --git a/src/object.h b/src/object.h
index 6f37d5a..2e3a791 100644
--- a/src/object.h
+++ b/src/object.h
@@ -469,7 +469,9 @@
     return MemberOffset(OFFSETOF_MEMBER(Field, offset_));
   }
 
-  static Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer);
+  static Field* FindInstanceFieldFromCode(uint32_t field_idx, const Method* referrer);
+  static Field* FindStaticFieldFromCode(uint32_t field_idx, const Method* referrer);
+  static Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, bool is_static);
 
   MemberOffset GetOffsetDuringLinking() const;
 
diff --git a/src/thread.cc b/src/thread.cc
index 737faff..3d68802 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -354,7 +354,7 @@
   pCheckCastFromCode = CheckCastFromCode;
   pLockObjectFromCode = LockObjectFromCode;
   pUnlockObjectFromCode = UnlockObjectFromCode;
-  pFindFieldFromCode = Field::FindFieldFromCode;
+  pFindInstanceFieldFromCode = Field::FindInstanceFieldFromCode;
   pCheckSuspendFromCode = CheckSuspendFromCode;
   pStackOverflowFromCode = StackOverflowFromCode;
   pThrowNullPointerFromCode = ThrowNullPointerFromCode;
diff --git a/src/thread.h b/src/thread.h
index 5a0c4f0..4e1db6f 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -222,7 +222,7 @@
   void (*pResolveMethodFromCode)(Method*, uint32_t);
   void (*pInvokeInterfaceTrampoline)(void*, void*, void*, void*);
   StaticStorageBase* (*pInitializeStaticStorage)(uint32_t, const Method*);
-  Field* (*pFindFieldFromCode)(uint32_t, const Method*);
+  Field* (*pFindInstanceFieldFromCode)(uint32_t, const Method*);
   void (*pCheckSuspendFromCode)(Thread*);
   void (*pStackOverflowFromCode)(Method*);
   void (*pThrowNullPointerFromCode)();