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);
 };