Add slow path access routines for static fields
Change-Id: Iaa3239130410995c342cbc22f8d406925bd3361f
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);