Merge "Add instance field get/put test" into dalvik-dev
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 8236739..a42ab72 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1279,7 +1279,8 @@
   return !Thread::Current()->IsExceptionPending();
 }
 
-StaticStorageBase* ClassLinker::InitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer) {
+StaticStorageBase* ClassLinker::InitializeStaticStorageFromCode(uint32_t type_idx,
+                                                                const Method* referrer) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   Class* klass = class_linker->ResolveType(type_idx, referrer);
   if (klass == NULL) {
diff --git a/src/class_linker.h b/src/class_linker.h
index d9716ee..c85fb4e 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -61,7 +61,7 @@
   // Resolve a Type with the given index from the DexFile, storing the
   // result in the DexCache. The referrer is used to identity the
   // target DexCache and ClassLoader to use for resolution.
-  Class* ResolveType(uint32_t type_idx, Method* referrer) {
+  Class* ResolveType(uint32_t type_idx, const Method* referrer) {
     Class* declaring_class = referrer->GetDeclaringClass();
     DexCache* dex_cache = declaring_class->GetDexCache();
     const ClassLoader* class_loader = declaring_class->GetClassLoader();
@@ -78,7 +78,8 @@
                      DexCache* dex_cache,
                      const ClassLoader* class_loader);
 
-  static StaticStorageBase* InitializeStaticStorageFromCode(uint32_t type_idx, Method* referrer);
+  static StaticStorageBase* InitializeStaticStorageFromCode(uint32_t type_idx,
+                                                            const Method* referrer);
 
   // Resolve a method with a given ID from the DexFile, storing the
   // result in DexCache. The ClassLinker and ClassLoader are used as
@@ -91,6 +92,14 @@
                         const ClassLoader* class_loader,
                         bool is_direct);
 
+  Field* ResolveField(uint32_t field_idx, const Method* referrer) {
+    Class* declaring_class = referrer->GetDeclaringClass();
+    DexCache* dex_cache = declaring_class->GetDexCache();
+    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);
+  }
+
   // Resolve a method with a given ID from the DexFile, storing the
   // result in DexCache. The ClassLinker and ClassLoader are used as
   // in ResolveType. What is unique is the is_static argument which is
diff --git a/src/dex_file.h b/src/dex_file.h
index db7a54b..4fb1442 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -414,6 +414,17 @@
     return dexStringById(type_id.descriptor_idx_);
   }
 
+  // Returns the class descriptor string of a field id.
+  const char* GetFieldClassDescriptor(const FieldId& field_id) const {
+    const DexFile::TypeId& type_id = GetTypeId(field_id.class_idx_);
+    return GetTypeDescriptor(type_id);
+  }
+
+  // Returns the name of a field id.
+  const char* GetFieldName(const FieldId& field_id) const {
+    return dexStringById(field_id.name_idx_);
+  }
+
   // Returns the StringId at the specified index.
   const StringId& GetStringId(uint32_t idx) const {
     CHECK_LT(idx, NumStringIds());
diff --git a/src/object.cc b/src/object.cc
index f938bc2..9bb1cb7 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -198,6 +198,55 @@
   return IsInSamePackage(klass1->descriptor_, klass2->descriptor_);
 }
 
+uint32_t Field::Get32StaticFromCode(uint32_t field_idx, const Method* referrer) {
+  Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
+  if (field == NULL) {
+    UNIMPLEMENTED(FATAL) << "throw an error";
+    return 0;
+  }
+  return field->Get32(NULL);
+}
+void Field::Set32StaticFromCode(uint32_t field_idx, const Method* referrer, uint32_t new_value) {
+  Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
+  if (field == NULL) {
+    UNIMPLEMENTED(FATAL) << "throw an error";
+    return;
+  }
+  field->Set32(NULL, new_value);
+}
+uint64_t Field::Get64StaticFromCode(uint32_t field_idx, const Method* referrer) {
+  Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
+  if (field == NULL) {
+    UNIMPLEMENTED(FATAL) << "throw an error";
+    return 0;
+  }
+  return field->Get64(NULL);
+}
+void Field::Set64StaticFromCode(uint32_t field_idx, const Method* referrer, uint64_t new_value) {
+  Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
+  if (field == NULL) {
+    UNIMPLEMENTED(FATAL) << "throw an error";
+    return;
+  }
+  field->Set64(NULL, new_value);
+}
+Object* Field::GetObjStaticFromCode(uint32_t field_idx, const Method* referrer) {
+  Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
+  if (field == NULL) {
+    UNIMPLEMENTED(FATAL) << "throw an error";
+    return 0;
+  }
+  return field->GetObj(NULL);
+}
+void Field::SetObjStaticFromCode(uint32_t field_idx, const Method* referrer, Object* new_value) {
+  Field* field = Runtime::Current()->GetClassLinker()->ResolveField(field_idx, referrer);
+  if (field == NULL) {
+    UNIMPLEMENTED(FATAL) << "throw an error";
+    return;
+  }
+  field->SetObj(NULL, new_value);
+}
+
 uint32_t Field::Get32(const Object* object) const {
   CHECK((object == NULL) == IsStatic());
   if (IsStatic()) {
diff --git a/src/object.h b/src/object.h
index d299c5b..8a186e1 100644
--- a/src/object.h
+++ b/src/object.h
@@ -384,6 +384,14 @@
   Object* GetObject(const Object* object) const;
   void SetObject(Object* object, Object* l) const;
 
+  // slow path routines for static field access when field was unresolved at compile time
+  static uint32_t Get32StaticFromCode(uint32_t field_idx, const Method* referrer);
+  static void Set32StaticFromCode(uint32_t field_idx, const Method* referrer, uint32_t new_value);
+  static uint64_t Get64StaticFromCode(uint32_t field_idx, const Method* referrer);
+  static void Set64StaticFromCode(uint32_t field_idx, const Method* referrer, uint64_t new_value);
+  static Object* GetObjStaticFromCode(uint32_t field_idx, const Method* referrer);
+  static void SetObjStaticFromCode(uint32_t field_idx, const Method* referrer, Object* new_value);
+
  public:  // TODO: private
 
   // private implemention of field access using raw data
diff --git a/src/object_test.cc b/src/object_test.cc
index c7ddde9..8979e8d 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -49,6 +49,19 @@
     return 0;
   }
 
+  uint32_t FindFieldIdxByDescriptorAndName(const DexFile& dex_file,
+                                           const StringPiece& class_descriptor,
+                                           const StringPiece& field_name) {
+    for (size_t i = 0; i < dex_file.NumFieldIds(); i++) {
+      const DexFile::FieldId& field_id = dex_file.GetFieldId(i);
+      if (class_descriptor == dex_file.GetFieldClassDescriptor(field_id)
+          && field_name == dex_file.GetFieldName(field_id)) {
+        return i;
+      }
+    }
+    CHECK(false) << "Could not find field index for " << class_descriptor << " " << field_name;
+    return 0;
+  }
 };
 
 TEST_F(ObjectTest, IsInSamePackage) {
@@ -187,6 +200,25 @@
   EXPECT_TRUE(array->GetClass()->GetComponentType()->IsPrimitive());
 }
 
+TEST_F(ObjectTest, StaticFieldFromCode) {
+  // pretend we are trying to call 'new String' from Object.toString
+  Class* java_lang_String = class_linker_->FindSystemClass("Ljava/lang/String;");
+  Method* clinit = java_lang_String->FindDirectMethod("<clinit>", "()V");
+  uint32_t field_idx = FindFieldIdxByDescriptorAndName(*java_lang_dex_file_.get(),
+                                                       "Ljava/lang/String;", "ASCII");
+  Object* ASCII = Field::GetObjStaticFromCode(field_idx, clinit);
+  EXPECT_EQ(NULL, ASCII);
+
+  CharArray* char_array = CharArray::Alloc(0);
+  Field::SetObjStaticFromCode(field_idx, clinit, char_array);
+  EXPECT_EQ(char_array, Field::GetObjStaticFromCode(field_idx, clinit));
+
+  Field::SetObjStaticFromCode(field_idx, clinit, NULL);
+  EXPECT_EQ(NULL, Field::GetObjStaticFromCode(field_idx, clinit));
+  
+  // TODO: more exhaustive tests of all 6 cases of Field::*FromCode
+}
+
 TEST_F(ObjectTest, String) {
   // Test the empty string.
   AssertString(0, "",     "", 0);