Store static field values in arrays.
Each static field is stored in one of three arrays:
- references are stored in static_references_
- 64 bit primitives are stored in static_64bit_primitives_
- everything else is in static_32bit_primitives_
Change-Id: I1c0e182582f776c62edbd9bd97ffd4fd7e516c99
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 925a3b3..3f9f7ab 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -58,6 +58,12 @@
Class* char_array_class = AllocClass(java_lang_Class);
CHECK(char_array_class != NULL);
+ // int[] and long[] are used for static field storage
+ Class* int_array_class = AllocClass(java_lang_Class);
+ CHECK(int_array_class != NULL);
+ Class* long_array_class = AllocClass(java_lang_Class);
+ CHECK(long_array_class != NULL);
+
// Field and Method are necessary so that FindClass can link members
Class* java_lang_reflect_Field = AllocClass(java_lang_Class);
CHECK(java_lang_reflect_Field != NULL);
@@ -77,6 +83,8 @@
class_roots_->Set(kObjectArrayClass, object_array_class);
class_roots_->Set(kJavaLangString, java_lang_String);
class_roots_->Set(kCharArrayClass, char_array_class);
+ class_roots_->Set(kIntArrayClass, int_array_class);
+ class_roots_->Set(kLongArrayClass, long_array_class);
class_roots_->Set(kJavaLangReflectField, java_lang_reflect_Field);
class_roots_->Set(kJavaLangReflectMethod, java_lang_reflect_Method);
// now that these are registered, we can use AllocClass() and AllocObjectArray
@@ -169,9 +177,13 @@
class_roots_->Set(kPrimitiveVoid, CreatePrimitiveClass("V"));
// now we can use FindSystemClass for anything, including for "[C"
- // run char[] through FindClass to complete initialization
+ // run char[], int[] and long[] through FindClass to complete initialization
Class* found_char_array_class = FindSystemClass("[C");
CHECK_EQ(char_array_class, found_char_array_class);
+ Class* found_int_array_class = FindSystemClass("[I");
+ CHECK_EQ(int_array_class, found_int_array_class);
+ Class* found_long_array_class = FindSystemClass("[J");
+ CHECK_EQ(long_array_class, found_long_array_class);
// ensure all class_roots_ were initialized
for (size_t i = 0; i < kClassRootsMax; i++) {
@@ -460,7 +472,8 @@
Class* klass,
Field* dst) {
const DexFile::FieldId& field_id = dex_file.GetFieldId(src.field_idx_);
- dst->klass_ = klass;
+ dst->java_declaring_class_ = klass;
+ dst->declaring_class_ = klass;
dst->name_ = ResolveString(klass, field_id.name_idx_, dex_file);
dst->descriptor_.set(dex_file.dexStringByTypeIdx(field_id.type_idx_));
dst->access_flags_ = src.access_flags_;
@@ -471,7 +484,8 @@
Class* klass,
Method* dst) {
const DexFile::MethodId& method_id = dex_file.GetMethodId(src.method_idx_);
- dst->klass_ = klass;
+ dst->java_declaring_class_ = klass;
+ dst->declaring_class_ = klass;
dst->name_ = ResolveString(klass, method_id.name_idx_, dex_file);
{
int32_t utf16_length;
@@ -640,6 +654,10 @@
new_class = GetClassRoot(kObjectArrayClass);
} else if (descriptor == "[C") {
new_class = GetClassRoot(kCharArrayClass);
+ } else if (descriptor == "[I") {
+ new_class = GetClassRoot(kIntArrayClass);
+ } else if (descriptor == "[J") {
+ new_class = GetClassRoot(kLongArrayClass);
}
}
if (new_class == NULL) {
@@ -1046,6 +1064,9 @@
if (!LinkMethods(klass)) {
return false;
}
+ if (!LinkStaticFields(klass)) {
+ return false;
+ }
if (!LinkInstanceFields(klass)) {
return false;
}
@@ -1329,6 +1350,42 @@
}
}
+// Each static field will be stored in one of three arrays: static_references_,
+// static_32bit_primitives_, or static_64bit_primitives_. This assigns each
+// field a slot in its array and create the arrays.
+bool ClassLinker::LinkStaticFields(Class* klass) {
+ size_t next_reference_slot = 0;
+ size_t next_32bit_primitive_slot = 0;
+ size_t next_64bit_primitive_slot = 0;
+
+ for (size_t i = 0; i < klass->NumStaticFields(); i++) {
+ StaticField* field = klass->GetStaticField(i);
+ char type = field->GetType();
+ if (type == '[' || type == 'L') {
+ field->java_slot_ = next_reference_slot++;
+ } else if (type == 'J' || type == 'D') {
+ field->java_slot_ = next_64bit_primitive_slot++;
+ } else {
+ field->java_slot_ = next_32bit_primitive_slot++;
+ }
+ }
+
+ if (next_reference_slot > 0) {
+ Class* array_class = GetClassRoot(kObjectArrayClass);
+ klass->static_references_ = ObjectArray<Object>::Alloc(array_class, next_reference_slot);
+ }
+ if (next_32bit_primitive_slot > 0) {
+ Class* array_class = GetClassRoot(kIntArrayClass);
+ klass->static_32bit_primitives_ = IntArray::Alloc(array_class, next_32bit_primitive_slot);
+ }
+ if (next_64bit_primitive_slot > 0) {
+ Class* array_class = GetClassRoot(kLongArrayClass);
+ klass->static_64bit_primitives_ = LongArray::Alloc(array_class, next_64bit_primitive_slot);
+ }
+
+ return true;
+}
+
bool ClassLinker::LinkInstanceFields(Class* klass) {
int field_offset;
if (klass->GetSuperClass() != NULL) {
diff --git a/src/class_linker.h b/src/class_linker.h
index 15bd054..4720f46 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -139,6 +139,8 @@
void LinkAbstractMethods(Class* klass);
+ bool LinkStaticFields(Class* klass);
+
bool LinkInstanceFields(Class* klass);
void CreateReferenceOffsets(Class* klass);
@@ -165,6 +167,8 @@
kObjectArrayClass,
kJavaLangString,
kCharArrayClass,
+ kIntArrayClass,
+ kLongArrayClass,
kJavaLangReflectField,
kJavaLangReflectMethod,
kJavaLangClassLoader,
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index a8e1df1..03b6dfb 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -133,6 +133,7 @@
for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
Method* method = klass->GetDirectMethod(i);
EXPECT_TRUE(method != NULL);
+ EXPECT_EQ(klass, method->GetDeclaringClass());
}
for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
@@ -144,12 +145,14 @@
InstanceField* field = klass->GetInstanceField(i);
EXPECT_TRUE(field != NULL);
EXPECT_FALSE(field->IsStatic());
+ EXPECT_EQ(klass, field->GetDeclaringClass());
}
for (size_t i = 0; i < klass->NumStaticFields(); i++) {
StaticField* field = klass->GetStaticField(i);
EXPECT_TRUE(field != NULL);
EXPECT_TRUE(field->IsStatic());
+ EXPECT_EQ(klass, field->GetDeclaringClass());
}
// Confirm that all instances fields are packed together at the start
@@ -388,4 +391,75 @@
EXPECT_NE(MyClass_1, MyClass_2);
}
+TEST_F(ClassLinkerTest, StaticFields) {
+ // TODO: uncomment expectations of initial values when InitializeClass works
+ scoped_ptr<DexFile> dex(OpenDexFileBase64(kStatics));
+ PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ Class* statics = class_linker_->FindClass("LStatics;", class_loader);
+ // class_linker_->InitializeClass(statics); // TODO uncomment this
+
+ EXPECT_EQ(10U, statics->NumStaticFields());
+
+ StaticField* s0 = statics->GetStaticField(0);
+ EXPECT_EQ("Ljava/lang/reflect/Field;", s0->GetClass()->descriptor_);
+ EXPECT_EQ('Z', s0->GetType());
+// EXPECT_EQ(true, s0->GetBoolean()); // TODO uncomment this
+ s0->SetBoolean(false);
+
+ StaticField* s1 = statics->GetStaticField(1);
+ EXPECT_EQ('B', s1->GetType());
+// EXPECT_EQ(5, s1->GetByte()); // TODO uncomment this
+ s1->SetByte(6);
+
+ StaticField* s2 = statics->GetStaticField(2);
+ EXPECT_EQ('C', s2->GetType());
+// EXPECT_EQ('a', s2->GetChar()); // TODO uncomment this
+ s2->SetChar('b');
+
+ StaticField* s3 = statics->GetStaticField(3);
+ EXPECT_EQ('S', s3->GetType());
+// EXPECT_EQ(65000, s3->GetShort()); // TODO uncomment this
+ s3->SetShort(65001);
+
+ StaticField* s4 = statics->GetStaticField(4);
+ EXPECT_EQ('I', s4->GetType());
+// EXPECT_EQ(2000000000, s4->GetInt()); // TODO uncomment this
+ s4->SetInt(2000000001);
+
+ StaticField* s5 = statics->GetStaticField(5);
+ EXPECT_EQ('J', s5->GetType());
+// EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong()); // TODO uncomment this
+ s5->SetLong(0x34567890abcdef12LL);
+
+ StaticField* s6 = statics->GetStaticField(6);
+ EXPECT_EQ('F', s6->GetType());
+// EXPECT_EQ(0.5, s6->GetFloat()); // TODO uncomment this
+ s6->SetFloat(0.75);
+
+ StaticField* s7 = statics->GetStaticField(7);
+ EXPECT_EQ('D', s7->GetType());
+// EXPECT_EQ(16777217, s7->GetDouble()); // TODO uncomment this
+ s7->SetDouble(16777219);
+
+ StaticField* s8 = statics->GetStaticField(8);
+ EXPECT_EQ('L', s8->GetType());
+// EXPECT_TRUE(down_cast<String*>(s8->GetObject())->Equals("android")); // TODO uncomment this
+ s8->SetObject(String::AllocFromAscii("robot"));
+
+ StaticField* s9 = statics->GetStaticField(9);
+ EXPECT_EQ('[', s9->GetType());
+// EXPECT_EQ(NULL, s9->GetObject()); // TODO uncomment this
+ s9->SetObject(NULL);
+
+ EXPECT_EQ(false, s0->GetBoolean());
+ EXPECT_EQ(6, s1->GetByte());
+ EXPECT_EQ('b', s2->GetChar());
+ EXPECT_EQ(65001, s3->GetShort());
+ EXPECT_EQ(2000000001, s4->GetInt());
+ EXPECT_EQ(0x34567890abcdef12LL, s5->GetLong());
+ EXPECT_EQ(0.75, s6->GetFloat());
+ EXPECT_EQ(16777219, s7->GetDouble());
+ EXPECT_TRUE(down_cast<String*>(s8->GetObject())->Equals("robot"));
+}
+
} // namespace art
diff --git a/src/common_test.h b/src/common_test.h
index 2555005..f1c952c 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -235,6 +235,37 @@
"ASAAAAIAAAD8AAAAAiAAAAYAAAAsAQAAAyAAAAIAAABdAQAAACAAAAIAAABnAQAAABAAAAEAAAB8"
"AQAA";
+// class Statics {
+// static boolean s0 = true;
+// static byte s1 = 5;
+// static char s2 = 'a';
+// static short s3 = (short) 65000;
+// static int s4 = 2000000000;
+// static long s5 = 0x123456789abcdefL;
+// static float s6 = 0.5f;
+// static double s7 = 16777217;
+// static Object s8 = "android";
+// static Object[] s9 = { "a", "b" };
+// }
+static const char kStatics[] =
+ "ZGV4CjAzNQAYalInXcX4y0OBgb2yCw2/jGzZBSe34zmwAwAAcAAAAHhWNBIAAAAAAAAAABwDAAAc"
+ "AAAAcAAAAAwAAADgAAAAAQAAABABAAAKAAAAHAEAAAMAAABsAQAAAQAAAIQBAAAMAgAApAEAADwC"
+ "AABGAgAATgIAAFECAABUAgAAVwIAAFoCAABdAgAAYAIAAGsCAAB/AgAAggIAAJACAACTAgAAlgIA"
+ "AKsCAACuAgAAtwIAALoCAAC+AgAAwgIAAMYCAADKAgAAzgIAANICAADWAgAA2gIAAN4CAAACAAAA"
+ "AwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAoAAAAMAAAADQAAAA4AAAAMAAAACQAAAAAAAAAG"
+ "AAoAEgAAAAYAAAATAAAABgABABQAAAAGAAgAFQAAAAYABAAWAAAABgAFABcAAAAGAAMAGAAAAAYA"
+ "AgAZAAAABgAHABoAAAAGAAsAGwAAAAYAAAAAAAAABgAAAAEAAAAHAAAAAQAAAAYAAAAAAAAABwAA"
+ "AAAAAAALAAAAAAAAAPUCAAAAAAAABAAAAAAAAADiAgAAOAAAABITagMAABJQawABABMAYQBsAAIA"
+ "EwDo/W0AAwAUAACUNXdnAAQAGADvzauJZ0UjAWgABQAVAAA/ZwAGABgAAAAAEAAAcEFoAAcAGgAQ"
+ "AGkACAASICMACwASARoCDwBNAgABGgERAE0BAANpAAkADgABAAEAAQAAAPACAAAEAAAAcBACAAAA"
+ "DgAIPGNsaW5pdD4ABjxpbml0PgABQgABQwABRAABRgABSQABSgAJTFN0YXRpY3M7ABJMamF2YS9s"
+ "YW5nL09iamVjdDsAAVMADFN0YXRpY3MuamF2YQABVgABWgATW0xqYXZhL2xhbmcvT2JqZWN0OwAB"
+ "YQAHYW5kcm9pZAABYgACczAAAnMxAAJzMgACczMAAnM0AAJzNQACczYAAnM3AAJzOAACczkAAgAH"
+ "HS08S0taeEt4SwABAAcOAAoAAgAACAEIAQgBCAEIAQgBCAEIAQgBCACIgASkAwGAgASkBAAAAAwA"
+ "AAAAAAAAAQAAAAAAAAABAAAAHAAAAHAAAAACAAAADAAAAOAAAAADAAAAAQAAABABAAAEAAAACgAA"
+ "ABwBAAAFAAAAAwAAAGwBAAAGAAAAAQAAAIQBAAABIAAAAgAAAKQBAAACIAAAHAAAADwCAAADIAAA"
+ "AgAAAOICAAAAIAAAAQAAAPUCAAAAEAAAAQAAABwDAAA=";
+
static inline DexFile* OpenDexFileBase64(const char* base64) {
CHECK(base64 != NULL);
size_t length;
diff --git a/src/object.cc b/src/object.cc
index 514eef5..409ff61 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -153,6 +153,107 @@
return IsInSamePackage(klass1->descriptor_, klass2->descriptor_);
}
+bool StaticField::GetBoolean() {
+ CHECK_EQ(GetType(), 'Z');
+ return declaring_class_->static_32bit_primitives_->Get(java_slot_);
+}
+
+void StaticField::SetBoolean(bool z) {
+ CHECK_EQ(GetType(), 'Z');
+ declaring_class_->static_32bit_primitives_->Set(java_slot_, z);
+}
+
+int8_t StaticField::GetByte() {
+ CHECK_EQ(GetType(), 'B');
+ return declaring_class_->static_32bit_primitives_->Get(java_slot_);
+}
+
+void StaticField::SetByte(int8_t b) {
+ CHECK_EQ(GetType(), 'B');
+ declaring_class_->static_32bit_primitives_->Set(java_slot_, b);
+}
+
+uint16_t StaticField::GetChar() {
+ CHECK_EQ(GetType(), 'C');
+ return declaring_class_->static_32bit_primitives_->Get(java_slot_);
+}
+
+void StaticField::SetChar(uint16_t c) {
+ CHECK_EQ(GetType(), 'C');
+ declaring_class_->static_32bit_primitives_->Set(java_slot_, c);
+}
+
+uint16_t StaticField::GetShort() {
+ CHECK_EQ(GetType(), 'S');
+ return declaring_class_->static_32bit_primitives_->Get(java_slot_);
+}
+
+void StaticField::SetShort(uint16_t s) {
+ CHECK_EQ(GetType(), 'S');
+ declaring_class_->static_32bit_primitives_->Set(java_slot_, s);
+}
+
+int32_t StaticField::GetInt() {
+ CHECK_EQ(GetType(), 'I');
+ return declaring_class_->static_32bit_primitives_->Get(java_slot_);
+}
+
+void StaticField::SetInt(int32_t i) {
+ CHECK_EQ(GetType(), 'I');
+ declaring_class_->static_32bit_primitives_->Set(java_slot_, i);
+}
+
+int64_t StaticField::GetLong() {
+ CHECK_EQ(GetType(), 'J');
+ return declaring_class_->static_64bit_primitives_->Get(java_slot_);
+}
+
+void StaticField::SetLong(int64_t j) {
+ CHECK_EQ(GetType(), 'J');
+ declaring_class_->static_64bit_primitives_->Set(java_slot_, j);
+}
+
+float StaticField::GetFloat() {
+ CHECK_EQ(GetType(), 'F');
+ JValue float_bits;
+ float_bits.i = declaring_class_->static_32bit_primitives_->Get(java_slot_);
+ return float_bits.f;
+}
+
+void StaticField::SetFloat(float f) {
+ CHECK_EQ(GetType(), 'F');
+ JValue float_bits;
+ float_bits.f = f;
+ declaring_class_->static_32bit_primitives_->Set(java_slot_, float_bits.i);
+}
+
+double StaticField::GetDouble() {
+ CHECK_EQ(GetType(), 'D');
+ JValue double_bits;
+ double_bits.j = declaring_class_->static_64bit_primitives_->Get(java_slot_);
+ return double_bits.d;
+}
+
+void StaticField::SetDouble(double d) {
+ CHECK_EQ(GetType(), 'D');
+ JValue double_bits;
+ double_bits.d = d;
+ declaring_class_->static_64bit_primitives_->Set(java_slot_, double_bits.j);
+}
+
+Object* StaticField::GetObject() {
+ return declaring_class_->static_references_->Get(java_slot_);
+}
+
+const Object* StaticField::GetObject() const {
+ return declaring_class_->static_references_->Get(java_slot_);
+}
+
+void StaticField::SetObject(Object* l) {
+ CHECK(GetType() == 'L' || GetType() == '[');
+ declaring_class_->static_references_->Set(java_slot_, l); // TODO: write barrier
+}
+
uint32_t Method::NumArgRegisters() {
CHECK(shorty_ != NULL);
uint32_t num_registers = 0;
diff --git a/src/object.h b/src/object.h
index c1682ec..5cb884c 100644
--- a/src/object.h
+++ b/src/object.h
@@ -325,68 +325,45 @@
// Static fields.
class StaticField : public Field {
public:
- void SetBoolean(bool z) {
- CHECK_EQ(GetType(), 'Z');
- value_.z = z;
- }
+ bool GetBoolean();
- void SetByte(int8_t b) {
- CHECK_EQ(GetType(), 'B');
- value_.b = b;
- }
+ void SetBoolean(bool z);
- void SetChar(uint16_t c) {
- CHECK_EQ(GetType(), 'C');
- value_.c = c;
- }
+ int8_t GetByte();
- void SetShort(uint16_t s) {
- CHECK_EQ(GetType(), 'S');
- value_.s = s;
- }
+ void SetByte(int8_t b);
- void SetInt(int32_t i) {
- CHECK_EQ(GetType(), 'I');
- value_.i = i;
- }
+ uint16_t GetChar();
- int64_t GetLong() {
- CHECK_EQ(GetType(), 'J');
- return value_.j;
- }
+ void SetChar(uint16_t c);
- void SetLong(int64_t j) {
- CHECK_EQ(GetType(), 'J');
- value_.j = j;
- }
+ uint16_t GetShort();
- void SetFloat(float f) {
- CHECK_EQ(GetType(), 'F');
- value_.f = f;
- }
+ void SetShort(uint16_t s);
- void SetDouble(double d) {
- CHECK_EQ(GetType(), 'D');
- value_.d = d;
- }
+ int32_t GetInt();
- Object* GetObject() {
- return value_.l;
- }
+ void SetInt(int32_t i);
- const Object* GetObject() const {
- return value_.l;
- }
+ int64_t GetLong();
- void SetObject(Object* l) {
- CHECK(GetType() == 'L' || GetType() == '[');
- value_.l = l;
- // TODO: write barrier
- }
+ void SetLong(int64_t j);
+
+ float GetFloat();
+
+ void SetFloat(float f);
+
+ double GetDouble();
+
+ void SetDouble(double d);
+
+ Object* GetObject();
+
+ const Object* GetObject() const;
+
+ void SetObject(Object* l);
private:
- JValue value_;
-
DISALLOW_IMPLICIT_CONSTRUCTORS(StaticField);
};
@@ -1101,13 +1078,22 @@
// source file name, if known. Otherwise, NULL.
const char* source_file_;
+ // Static fields
+ ObjectArray<StaticField>* sfields_;
+
+ // static field storage
+ //
+ // Each static field is stored in one of three arrays:
+ // o references are stored in static_references_
+ // o doubles and longs are stored in static_64bit_primitives_
+ // o everything else is in static_32bit_primitives_
+ // Static fields select their array using their type and their index using the
+ // Field->slot_ member. Storing static fields in arrays avoids the need for a
+ // special case in the GC.
ObjectArray<Object>* static_references_;
IntArray* static_32bit_primitives_;
LongArray* static_64bit_primitives_;
- // Static fields
- ObjectArray<StaticField>* sfields_;
-
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Class);
};