Move static field storage to end of Class instance

Change-Id: I90061999c9eef9d900e4269508b983a61f48b264
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 63791135..92cf4de 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -65,14 +65,14 @@
   CHECK(!init_done_);
 
   // java_lang_Class comes first, its needed for AllocClass
-  Class* java_lang_Class = down_cast<Class*>(Heap::AllocObject(NULL, sizeof(Class)));
+  Class* java_lang_Class = down_cast<Class*>(Heap::AllocObject(NULL, sizeof(ClassClass)));
   CHECK(java_lang_Class != NULL);
-  java_lang_Class->object_size_ = sizeof(Class);
+  java_lang_Class->class_size_ = sizeof(ClassClass);
   java_lang_Class->klass_ = java_lang_Class;
   // AllocClass(Class*) can now be used
 
   // java_lang_Object comes next so that object_array_class can be created
-  Class* java_lang_Object = AllocClass(java_lang_Class);
+  Class* java_lang_Object = AllocClass(java_lang_Class, sizeof(Class));
   CHECK(java_lang_Object != NULL);
   // backfill Object as the super class of Class
   java_lang_Class->super_class_ = java_lang_Object;
@@ -80,17 +80,17 @@
   java_lang_Object->primitive_type_ = Class::kPrimNot;
 
   // object_array_class is for root_classes to provide the storage for these classes
-  Class* object_array_class = AllocClass(java_lang_Class);
+  Class* object_array_class = AllocClass(java_lang_Class, sizeof(Class));
   CHECK(object_array_class != NULL);
   object_array_class->component_type_ = java_lang_Object;
 
   // String and char[] are necessary so that FindClass can assign names to members
-  Class* java_lang_String = AllocClass(java_lang_Class);
+  Class* java_lang_String = AllocClass(java_lang_Class, sizeof(StringClass));
   CHECK(java_lang_String != NULL);
   CHECK_LT(java_lang_String->object_size_, sizeof(String));
   java_lang_String->object_size_ = sizeof(String);
   String::SetClass(java_lang_String);
-  Class* char_array_class = AllocClass(java_lang_Class);
+  Class* char_array_class = AllocClass(java_lang_Class, sizeof(Class));
   CHECK(char_array_class != NULL);
   CharArray::SetArrayClass(char_array_class);
   // Now String::Alloc* can be used
@@ -102,23 +102,13 @@
   java_lang_String->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/String;");
   char_array_class->descriptor_ = String::AllocFromModifiedUtf8("[C");
 
-  // int[] and long[] are used for static field storage
-  Class* int_array_class = AllocClass(java_lang_Class);
-  CHECK(int_array_class != NULL);
-  int_array_class->descriptor_ = String::AllocFromModifiedUtf8("[I");
-  IntArray::SetArrayClass(int_array_class);
-  Class* long_array_class = AllocClass(java_lang_Class);
-  CHECK(long_array_class != NULL);
-  long_array_class->descriptor_ = String::AllocFromModifiedUtf8("[J");
-  LongArray::SetArrayClass(long_array_class);
-
   // Field and Method are necessary so that FindClass can link members
-  Class* java_lang_reflect_Field = AllocClass(java_lang_Class);
+  Class* java_lang_reflect_Field = AllocClass(java_lang_Class, sizeof(FieldClass));
   CHECK(java_lang_reflect_Field != NULL);
   java_lang_reflect_Field->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/reflect/Field;");
   CHECK_LT(java_lang_reflect_Field->object_size_, sizeof(Field));
   java_lang_reflect_Field->object_size_ = sizeof(Field);
-  Class* java_lang_reflect_Method = AllocClass(java_lang_Class);
+  Class* java_lang_reflect_Method = AllocClass(java_lang_Class, sizeof(MethodClass));
   java_lang_reflect_Method->descriptor_ = String::AllocFromModifiedUtf8("Ljava/lang/reflect/Method;");
   CHECK(java_lang_reflect_Method != NULL);
   CHECK_LT(java_lang_reflect_Method->object_size_, sizeof(Method));
@@ -131,8 +121,6 @@
   SetClassRoot(kObjectArrayClass, object_array_class);
   SetClassRoot(kJavaLangString, java_lang_String);
   SetClassRoot(kCharArrayClass, char_array_class);
-  SetClassRoot(kIntArrayClass, int_array_class);
-  SetClassRoot(kLongArrayClass, long_array_class);
   SetClassRoot(kJavaLangReflectField, java_lang_reflect_Field);
   SetClassRoot(kJavaLangReflectMethod, java_lang_reflect_Method);
   // now that these are registered, we can use AllocClass() and AllocObjectArray
@@ -225,10 +213,6 @@
   // 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);
 
   // Initialize all the other primitive array types for PrimitiveArray::Alloc.
   // These are easy because everything we need has already been set up.
@@ -236,11 +220,15 @@
   SetClassRoot(kByteArrayClass, FindSystemClass("[B"));
   SetClassRoot(kDoubleArrayClass, FindSystemClass("[D"));
   SetClassRoot(kFloatArrayClass, FindSystemClass("[F"));
+  SetClassRoot(kIntArrayClass, FindSystemClass("[I"));
+  SetClassRoot(kLongArrayClass, FindSystemClass("[J"));
   SetClassRoot(kShortArrayClass, FindSystemClass("[S"));
   BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
   ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
   DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
   FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
+  IntArray::SetArrayClass(GetClassRoot(kIntArrayClass));
+  LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
   ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
 
   FinishInit();
@@ -343,7 +331,7 @@
   FinishInit();
 }
 
-void ClassLinker::InitCallback(Object *obj, void *arg) {
+void ClassLinker::InitCallback(Object* obj, void *arg) {
   DCHECK(obj != NULL);
   DCHECK(arg != NULL);
   InitCallbackState* state = reinterpret_cast<InitCallbackState*>(arg);
@@ -410,12 +398,15 @@
   return dex_cache;
 }
 
-Class* ClassLinker::AllocClass(Class* java_lang_Class) {
-  return java_lang_Class->NewInstance()->AsClass();
+Class* ClassLinker::AllocClass(Class* java_lang_Class, size_t class_size) {
+  DCHECK_GE(class_size, sizeof(Class));
+  Class* klass = Heap::AllocObject(java_lang_Class, class_size)->AsClass();
+  klass->class_size_ = class_size;
+  return klass;
 }
 
-Class* ClassLinker::AllocClass() {
-  return AllocClass(GetClassRoot(kJavaLangClass));
+Class* ClassLinker::AllocClass(size_t class_size) {
+  return AllocClass(GetClassRoot(kJavaLangClass), class_size);
 }
 
 Field* ClassLinker::AllocField() {
@@ -476,10 +467,10 @@
       } else if (descriptor == "Ljava/lang/reflect/Method;") {
         klass = GetClassRoot(kJavaLangReflectMethod);
       } else {
-        klass = AllocClass();
+        klass = AllocClass(SizeOfClass(dex_file, dex_class_def));
       }
     } else {
-      klass = AllocClass();
+      klass = AllocClass(SizeOfClass(dex_file, dex_class_def));
     }
     klass->dex_cache_ = dex_cache;
     LoadClass(dex_file, dex_class_def, klass, class_loader);
@@ -542,6 +533,53 @@
   return klass;
 }
 
+// Precomputes size that will be needed for Class, matching LinkStaticFields
+size_t ClassLinker::SizeOfClass(const DexFile& dex_file,
+                                const DexFile::ClassDef& dex_class_def) {
+  const byte* class_data = dex_file.GetClassData(dex_class_def);
+  DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
+  size_t num_static_fields = header.static_fields_size_;
+  size_t num_ref = 0;
+  size_t num_32 = 0;
+  size_t num_64 = 0;
+  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);
+      const DexFile::FieldId& field_id = dex_file.GetFieldId(dex_field.field_idx_);
+      const char* descriptor = dex_file.dexStringByTypeIdx(field_id.type_idx_);
+      char c = descriptor[0];
+      if (c == 'L' || c == '[') {
+        num_ref++;
+      } else if (c == 'J' || c == 'D') {
+        num_64++;
+      } else {
+        num_32++;
+      }
+    }
+  }
+
+  // start with generic class data
+  size_t size = sizeof(Class);
+  // follow with reference fields which must be contiguous at start
+  size += (num_ref * sizeof(uint32_t));
+  // if there are 64-bit fields to add, make sure they are aligned
+  if (num_64 != 0 && size != RoundUp(size, 8)) { // for 64-bit alignment
+    if (num_32 != 0) {
+      // use an available 32-bit field for padding
+      num_32--;
+    }
+    size += sizeof(uint32_t);  // either way, we are adding a word
+    DCHECK_EQ(size, RoundUp(size, 8));
+  }
+  // tack on any 64-bit fields now that alignment is assured
+  size += (num_64 * sizeof(uint64_t));
+  // tack on any remaining 32-bit fields
+  size += (num_32 * sizeof(uint32_t));
+  return size;
+}
+
 void ClassLinker::LoadClass(const DexFile& dex_file,
                             const DexFile::ClassDef& dex_class_def,
                             Class* klass,
@@ -750,7 +788,7 @@
 }
 
 Class* ClassLinker::CreatePrimitiveClass(const char* descriptor) {
-  Class* klass = AllocClass();
+  Class* klass = AllocClass(sizeof(Class));
   CHECK(klass != NULL);
   klass->super_class_ = NULL;
   klass->access_flags_ = kAccPublic | kAccFinal | kAccAbstract;
@@ -849,14 +887,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) {
-    new_class = AllocClass();
+    new_class = AllocClass(sizeof(Class));
     if (new_class == NULL) {
       return NULL;
     }
@@ -1205,6 +1239,7 @@
     return;
   }
   DexCache* dex_cache = klass->GetDexCache();
+  // TODO: this seems like the wrong check. do we really want !IsPrimitive && !IsArray?
   if (dex_cache == NULL) {
     return;
   }
@@ -1224,37 +1259,37 @@
     DexFile::ValueType type = dex_file.ReadEncodedValue(&addr, &value);
     switch (type) {
       case DexFile::kByte:
-        field->SetByte(value.b);
+        field->SetByte(NULL, value.b);
         break;
       case DexFile::kShort:
-        field->SetShort(value.s);
+        field->SetShort(NULL, value.s);
         break;
       case DexFile::kChar:
-        field->SetChar(value.c);
+        field->SetChar(NULL, value.c);
         break;
       case DexFile::kInt:
-        field->SetInt(value.i);
+        field->SetInt(NULL, value.i);
         break;
       case DexFile::kLong:
-        field->SetLong(value.j);
+        field->SetLong(NULL, value.j);
         break;
       case DexFile::kFloat:
-        field->SetFloat(value.f);
+        field->SetFloat(NULL, value.f);
         break;
       case DexFile::kDouble:
-        field->SetDouble(value.d);
+        field->SetDouble(NULL, value.d);
         break;
       case DexFile::kString: {
         uint32_t string_idx = value.i;
         String* resolved = ResolveString(klass, string_idx, dex_file);
-        field->SetObject(resolved);
+        field->SetObject(NULL, resolved);
         break;
       }
       case DexFile::kBoolean:
-        field->SetBoolean(value.z);
+        field->SetBoolean(NULL, value.z);
         break;
       case DexFile::kNull:
-        field->SetObject(value.l);
+        field->SetObject(NULL, value.l);
         break;
       default:
         LOG(FATAL) << "Unknown type " << static_cast<int>(type);
@@ -1270,13 +1305,14 @@
   if (!LinkMethods(klass)) {
     return false;
   }
-  if (!LinkStaticFields(klass)) {
-    return false;
-  }
   if (!LinkInstanceFields(klass)) {
     return false;
   }
-  CreateReferenceOffsets(klass);
+  if (!LinkStaticFields(klass)) {
+    return false;
+  }
+  CreateReferenceInstanceOffsets(klass);
+  CreateReferenceStaticOffsets(klass);
   CHECK_EQ(Class::kStatusLoaded, klass->status_);
   klass->status_ = Class::kStatusResolved;
   return true;
@@ -1557,68 +1593,61 @@
   }
 }
 
-// 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++) {
-    Field* field = klass->GetStaticField(i);
-    char type = field->GetType();
-    if (type == '[' || type == 'L') {
-      field->offset_ = next_reference_slot++;
-    } else if (type == 'J' || type == 'D') {
-      field->offset_ = next_64bit_primitive_slot++;
-    } else {
-      field->offset_ = 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) {
-    klass->static_32bit_primitives_ = IntArray::Alloc(next_32bit_primitive_slot);
-  }
-  if (next_64bit_primitive_slot > 0) {
-    klass->static_64bit_primitives_ = LongArray::Alloc(next_64bit_primitive_slot);
-  }
-
-  return true;
-}
-
 bool ClassLinker::LinkInstanceFields(Class* klass) {
-  int field_offset;
+  CHECK(klass != NULL);
+  size_t field_offset;
   if (klass->GetSuperClass() != NULL) {
     field_offset = klass->GetSuperClass()->object_size_;
   } else {
     field_offset = OFFSETOF_MEMBER(DataObject, fields_);
   }
+  return LinkFields(field_offset,
+                    klass->num_reference_instance_fields_,
+                    klass->NumInstanceFields(),
+                    klass->ifields_,
+                    klass->object_size_);
+}
+
+bool ClassLinker::LinkStaticFields(Class* klass) {
+  CHECK(klass != NULL);
+  size_t allocated_class_size = klass->class_size_;
+  size_t field_offset = OFFSETOF_MEMBER(Class, fields_);
+  bool success = LinkFields(field_offset,
+                            klass->num_reference_static_fields_,
+                            klass->NumStaticFields(),
+                            klass->sfields_,
+                            klass->class_size_);
+  CHECK_EQ(allocated_class_size, klass->class_size_);
+  return success;
+}
+
+bool ClassLinker::LinkFields(size_t field_offset,
+                             size_t& num_reference_fields,
+                             size_t num_fields,
+                             ObjectArray<Field>* fields,
+                             size_t& size) {
+  CHECK((num_fields == 0) == (fields == NULL));
   // Move references to the front.
-  klass->num_reference_instance_fields_ = 0;
+  num_reference_fields = 0;
   size_t i = 0;
-  for ( ; i < klass->NumInstanceFields(); i++) {
-    Field* pField = klass->GetInstanceField(i);
+  for ( ; i < num_fields; i++) {
+    Field* pField = fields->Get(i);
     char c = pField->GetType();
     if (c != '[' && c != 'L') {
-      for (size_t j = klass->NumInstanceFields() - 1; j > i; j--) {
-        Field* refField = klass->GetInstanceField(j);
+      for (size_t j = num_fields - 1; j > i; j--) {
+        Field* refField = fields->Get(j);
         char rc = refField->GetType();
         if (rc == '[' || rc == 'L') {
-          klass->SetInstanceField(i, refField);
-          klass->SetInstanceField(j, pField);
+          fields->Set(i, refField);
+          fields->Set(j, pField);
           pField = refField;
           c = rc;
-          klass->num_reference_instance_fields_++;
+          num_reference_fields++;
           break;
         }
       }
     } else {
-      klass->num_reference_instance_fields_++;
+      num_reference_fields++;
     }
     if (c != '[' && c != 'L') {
       break;
@@ -1630,8 +1659,8 @@
   // Now we want to pack all of the double-wide fields together.  If
   // we're not aligned, though, we want to shuffle one 32-bit field
   // into place.  If we can't find one, we'll have to pad it.
-  if (i != klass->NumInstanceFields() && (field_offset & 0x04) != 0) {
-    Field* pField = klass->GetInstanceField(i);
+  if (i != num_fields && (field_offset & 0x04) != 0) {
+    Field* pField = fields->Get(i);
     char c = pField->GetType();
 
     if (c != 'J' && c != 'D') {
@@ -1645,12 +1674,12 @@
       // Next field is 64-bit, so search for a 32-bit field we can
       // swap into it.
       bool found = false;
-      for (size_t j = klass->NumInstanceFields() - 1; j > i; j--) {
-        Field* singleField = klass->GetInstanceField(j);
+      for (size_t j = num_fields - 1; j > i; j--) {
+        Field* singleField = fields->Get(j);
         char rc = singleField->GetType();
         if (rc != 'J' && rc != 'D') {
-          klass->SetInstanceField(i, singleField);
-          klass->SetInstanceField(j, pField);
+          fields->Set(i, singleField);
+          fields->Set(j, pField);
           pField = singleField;
           pField->SetOffset(field_offset);
           field_offset += sizeof(uint32_t);
@@ -1667,17 +1696,17 @@
 
   // Alignment is good, shuffle any double-wide fields forward, and
   // finish assigning field offsets to all fields.
-  DCHECK(i == klass->NumInstanceFields() || (field_offset & 0x04) == 0);
-  for ( ; i < klass->NumInstanceFields(); i++) {
-    Field* pField = klass->GetInstanceField(i);
+  DCHECK(i == num_fields || (field_offset & 0x04) == 0);
+  for ( ; i < num_fields; i++) {
+    Field* pField = fields->Get(i);
     char c = pField->GetType();
     if (c != 'D' && c != 'J') {
-      for (size_t j = klass->NumInstanceFields() - 1; j > i; j--) {
-        Field* doubleField = klass->GetInstanceField(j);
+      for (size_t j = num_fields - 1; j > i; j--) {
+        Field* doubleField = fields->Get(j);
         char rc = doubleField->GetType();
         if (rc == 'D' || rc == 'J') {
-          klass->SetInstanceField(i, doubleField);
-          klass->SetInstanceField(j, pField);
+          fields->Set(i, doubleField);
+          fields->Set(j, pField);
           pField = doubleField;
           c = rc;
           break;
@@ -1689,16 +1718,17 @@
 
     pField->SetOffset(field_offset);
     field_offset += sizeof(uint32_t);
-    if (c == 'J' || c == 'D')
+    if (c == 'J' || c == 'D') {
       field_offset += sizeof(uint32_t);
+    }
   }
 
 #ifndef NDEBUG
   // Make sure that all reference fields appear before
   // non-reference fields, and all double-wide fields are aligned.
   bool seen_non_ref = false;
-  for (i = 0; i < klass->NumInstanceFields(); i++) {
-    Field *pField = klass->GetInstanceField(i);
+  for (i = 0; i < num_fields; i++) {
+    Field *pField = fields->Get(i);
     char c = pField->GetType();
 
     if (c == 'D' || c == 'J') {
@@ -1708,50 +1738,64 @@
     if (c != '[' && c != 'L') {
       if (!seen_non_ref) {
         seen_non_ref = true;
-        DCHECK_EQ(klass->NumReferenceInstanceFields(), i);
+        DCHECK_EQ(num_reference_fields, i);
       }
     } else {
       DCHECK(!seen_non_ref);
     }
   }
   if (!seen_non_ref) {
-    DCHECK_EQ(klass->NumInstanceFields(), klass->NumReferenceInstanceFields());
+    DCHECK_EQ(num_fields, num_reference_fields);
   }
 #endif
-  klass->object_size_ = field_offset;
+  size = field_offset;
   return true;
 }
 
 //  Set the bitmap of reference offsets, refOffsets, from the ifields
 //  list.
-void ClassLinker::CreateReferenceOffsets(Class* klass) {
-  uint32_t reference_offsets = 0;
+void ClassLinker::CreateReferenceInstanceOffsets(Class* klass) {
+  klass->reference_instance_offsets_ = 0;
   if (klass->HasSuperClass()) {
-    reference_offsets = klass->GetSuperClass()->GetReferenceOffsets();
-  }
-  // If our superclass overflowed, we don't stand a chance.
-  if (reference_offsets != CLASS_WALK_SUPER) {
-    // All of the fields that contain object references are guaranteed
-    // to be at the beginning of the ifields list.
-    for (size_t i = 0; i < klass->NumReferenceInstanceFields(); ++i) {
-      // Note that, per the comment on struct InstField, f->byteOffset
-      // is the offset from the beginning of obj, not the offset into
-      // obj->instanceData.
-      const Field* field = klass->GetInstanceField(i);
-      size_t byte_offset = field->GetOffset();
-      CHECK_GE(byte_offset, CLASS_SMALLEST_OFFSET);
-      CHECK_EQ(byte_offset & (CLASS_OFFSET_ALIGNMENT - 1), 0U);
-      if (CLASS_CAN_ENCODE_OFFSET(byte_offset)) {
-        uint32_t new_bit = CLASS_BIT_FROM_OFFSET(byte_offset);
-        CHECK_NE(new_bit, 0U);
-        reference_offsets |= new_bit;
-      } else {
-        reference_offsets = CLASS_WALK_SUPER;
-        break;
-      }
+    klass->reference_instance_offsets_ = klass->GetSuperClass()->GetReferenceInstanceOffsets();
+    // If our superclass overflowed, we don't stand a chance.
+    if (klass->reference_instance_offsets_ == CLASS_WALK_SUPER) {
+      return;
     }
   }
-  klass->SetReferenceOffsets(reference_offsets);
+  CreateReferenceOffsets(klass->reference_instance_offsets_,
+                         klass->NumReferenceInstanceFields(),
+                         klass->ifields_);
+}
+
+void ClassLinker::CreateReferenceStaticOffsets(Class* klass) {
+  klass->reference_static_offsets_ = 0;
+  CreateReferenceOffsets(klass->reference_static_offsets_,
+                         klass->NumReferenceStaticFields(),
+                         klass->sfields_);
+}
+
+void ClassLinker::CreateReferenceOffsets(uint32_t& reference_offsets,
+                                         size_t num_reference_fields,
+                                         const ObjectArray<Field>* fields) {
+  // All of the fields that contain object references are guaranteed
+  // to be at the beginning of the fields list.
+  for (size_t i = 0; i < num_reference_fields; ++i) {
+    // Note that byte_offset is the offset from the beginning of
+    // object, not the offset into instance data
+    const Field* field = fields->Get(i);
+    size_t byte_offset = field->GetOffset();
+    CHECK_GE(byte_offset, CLASS_SMALLEST_OFFSET);
+    CHECK_EQ(byte_offset & (CLASS_OFFSET_ALIGNMENT - 1), 0U);
+    if (CLASS_CAN_ENCODE_OFFSET(byte_offset)) {
+      uint32_t new_bit = CLASS_BIT_FROM_OFFSET(byte_offset);
+      CHECK_NE(new_bit, 0U);
+      reference_offsets |= new_bit;
+    } else {
+      reference_offsets = CLASS_WALK_SUPER;
+      break;
+    }
+  }
 }
 
 Class* ClassLinker::ResolveClass(const Class* referrer,
diff --git a/src/class_linker.h b/src/class_linker.h
index 13754db..5b629d5 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -75,7 +75,7 @@
 
   // Initialize class linker from pre-initialized space.
   void Init(const std::vector<DexFile*>& boot_class_path_, Space* space);
-  static void InitCallback(Object *obj, void *arg);
+  static void InitCallback(Object* obj, void *arg);
   struct InitCallbackState;
 
   void FinishInit();
@@ -83,12 +83,12 @@
   bool InitializeClass(Class* klass);
 
   // For early bootstrapping by Init
-  Class* AllocClass(Class* java_lang_Class);
+  Class* AllocClass(Class* java_lang_Class, size_t class_size);
 
   // Alloc* convenience functions to avoid needing to pass in Class*
   // values that are known to the ClassLinker such as
   // kObjectArrayClass and kJavaLangString etc.
-  Class* AllocClass();
+  Class* AllocClass(size_t class_size);
   DexCache* AllocDexCache(const DexFile* dex_file);
   Field* AllocField();
   Method* AllocMethod();
@@ -108,6 +108,9 @@
   void AppendToBootClassPath(const DexFile* dex_file);
   void AppendToBootClassPath(const DexFile* dex_file, DexCache* dex_cache);
 
+  size_t SizeOfClass(const DexFile& dex_file,
+                     const DexFile::ClassDef& dex_class_def);
+
   void LoadClass(const DexFile& dex_file,
                  const DexFile::ClassDef& dex_class_def,
                  Class* klass,
@@ -170,10 +173,18 @@
   void LinkAbstractMethods(Class* klass);
 
   bool LinkStaticFields(Class* klass);
-
   bool LinkInstanceFields(Class* klass);
+  bool LinkFields(size_t field_offset,
+                  size_t& num_reference_fields,
+                  size_t num_fields,
+                  ObjectArray<Field>* fields,
+                  size_t& size);
 
-  void CreateReferenceOffsets(Class* klass);
+  void CreateReferenceInstanceOffsets(Class* klass);
+  void CreateReferenceStaticOffsets(Class* klass);
+  void CreateReferenceOffsets(uint32_t& reference_offsets,
+                              size_t num_reference_fields,
+                              const ObjectArray<Field>* fields);
 
   std::vector<const DexFile*> boot_class_path_;
 
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index ca305f1..2583fcf 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -198,7 +198,7 @@
       total_num_reference_instance_fields += k->NumReferenceInstanceFields();
       k = k->GetSuperClass();
     }
-    EXPECT_EQ(klass->GetReferenceOffsets() == 0,
+    EXPECT_EQ(klass->GetReferenceInstanceOffsets() == 0,
               total_num_reference_instance_fields == 0);
   }
 
@@ -412,70 +412,70 @@
   scoped_ptr<DexFile> dex(OpenDexFileBase64(kStatics, "kStatics"));
   PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
   Class* statics = class_linker_->FindClass("LStatics;", class_loader);
-  // class_linker_->InitializeClass(statics);  // TODO: uncomment this
+  class_linker_->EnsureInitialized(statics);
 
   EXPECT_EQ(10U, statics->NumStaticFields());
 
-  Field* s0 = statics->GetStaticField(0);
+  Field* s0 = statics->FindStaticField("s0", "Z");
   EXPECT_TRUE(s0->GetClass()->descriptor_->Equals("Ljava/lang/reflect/Field;"));
   EXPECT_EQ('Z', s0->GetType());
-//  EXPECT_EQ(true, s0->GetBoolean());  // TODO: uncomment this
-  s0->SetBoolean(false);
+  // EXPECT_EQ(true, s0->GetBoolean(NULL)); // TODO: needs clinit to be run?
+  s0->SetBoolean(NULL, false);
 
-  Field* s1 = statics->GetStaticField(1);
+  Field* s1 = statics->FindStaticField("s1", "B");
   EXPECT_EQ('B', s1->GetType());
-//  EXPECT_EQ(5, s1->GetByte());  // TODO: uncomment this
-  s1->SetByte(6);
+  // EXPECT_EQ(5, s1->GetByte(NULL));  // TODO: needs clinit to be run?
+  s1->SetByte(NULL, 6);
 
-  Field* s2 = statics->GetStaticField(2);
+  Field* s2 = statics->FindStaticField("s2", "C");
   EXPECT_EQ('C', s2->GetType());
-//  EXPECT_EQ('a', s2->GetChar());  // TODO: uncomment this
-  s2->SetChar('b');
+  // EXPECT_EQ('a', s2->GetChar(NULL));  // TODO: needs clinit to be run?
+  s2->SetChar(NULL, 'b');
 
-  Field* s3 = statics->GetStaticField(3);
+  Field* s3 = statics->FindStaticField("s3", "S");
   EXPECT_EQ('S', s3->GetType());
-//  EXPECT_EQ(65000, s3->GetShort());  // TODO: uncomment this
-  s3->SetShort(65001);
+  // EXPECT_EQ(65000, s3->GetShort(NULL));  // TODO: needs clinit to be run?
+  s3->SetShort(NULL, 65001);
 
-  Field* s4 = statics->GetStaticField(4);
+  Field* s4 = statics->FindStaticField("s4", "I");
   EXPECT_EQ('I', s4->GetType());
-//  EXPECT_EQ(2000000000, s4->GetInt());  // TODO: uncomment this
-  s4->SetInt(2000000001);
+  // EXPECT_EQ(2000000000, s4->GetInt(NULL));  // TODO: needs clinit to be run?
+  s4->SetInt(NULL, 2000000001);
 
-  Field* s5 = statics->GetStaticField(5);
+  Field* s5 = statics->FindStaticField("s5", "J");
   EXPECT_EQ('J', s5->GetType());
-//  EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong());  // TODO: uncomment this
-  s5->SetLong(0x34567890abcdef12LL);
+  // EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(NULL));  // TODO: needs clinit to be run?
+  s5->SetLong(NULL, 0x34567890abcdef12LL);
 
-  Field* s6 = statics->GetStaticField(6);
+  Field* s6 = statics->FindStaticField("s6", "F");
   EXPECT_EQ('F', s6->GetType());
-//  EXPECT_EQ(0.5, s6->GetFloat());  // TODO: uncomment this
-  s6->SetFloat(0.75);
+  // EXPECT_EQ(0.5, s6->GetFloat(NULL));  // TODO: needs clinit to be run?
+  s6->SetFloat(NULL, 0.75);
 
-  Field* s7 = statics->GetStaticField(7);
+  Field* s7 = statics->FindStaticField("s7", "D");
   EXPECT_EQ('D', s7->GetType());
-//  EXPECT_EQ(16777217, s7->GetDouble());  // TODO: uncomment this
-  s7->SetDouble(16777219);
+  // EXPECT_EQ(16777217, s7->GetDouble(NULL));  // TODO: needs clinit to be run?
+  s7->SetDouble(NULL, 16777219);
 
-  Field* s8 = statics->GetStaticField(8);
+  Field* s8 = statics->FindStaticField("s8", "Ljava/lang/Object;");
   EXPECT_EQ('L', s8->GetType());
-//  EXPECT_TRUE(s8->GetObject()->AsString()->Equals("android"));  // TODO: uncomment this
-  s8->SetObject(String::AllocFromModifiedUtf8("robot"));
+  // EXPECT_TRUE(s8->GetObject(NULL)->AsString()->Equals("android"));  // TODO: needs clinit to be run?
+  s8->SetObject(NULL, String::AllocFromModifiedUtf8("robot"));
 
-  Field* s9 = statics->GetStaticField(9);
+  Field* s9 = statics->FindStaticField("s9", "[Ljava/lang/Object;");
   EXPECT_EQ('[', s9->GetType());
-//  EXPECT_EQ(NULL, s9->GetObject());  // TODO: uncomment this
-  s9->SetObject(NULL);
+  // EXPECT_EQ(NULL, s9->GetObject(NULL));  // TODO: needs clinit to be run?
+  s9->SetObject(NULL, 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(s8->GetObject()->AsString()->Equals("robot"));
+  EXPECT_EQ(false,                s0->GetBoolean(NULL));
+  EXPECT_EQ(6,                    s1->GetByte(NULL));
+  EXPECT_EQ('b',                  s2->GetChar(NULL));
+  EXPECT_EQ(65001,                s3->GetShort(NULL));
+  EXPECT_EQ(2000000001,           s4->GetInt(NULL));
+  EXPECT_EQ(0x34567890abcdef12LL, s5->GetLong(NULL));
+  EXPECT_EQ(0.75,                 s6->GetFloat(NULL));
+  EXPECT_EQ(16777219,             s7->GetDouble(NULL));
+  EXPECT_TRUE(s8->GetObject(NULL)->AsString()->Equals("robot"));
 }
 
 }  // namespace art
diff --git a/src/heap.cc b/src/heap.cc
index 7369804..f86f556 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -103,6 +103,7 @@
 Object* Heap::AllocObject(Class* klass, size_t num_bytes) {
   DCHECK(klass == NULL
          || klass->descriptor_ == NULL
+         || (klass->IsClassClass() && num_bytes >= sizeof(Class))
          || (klass->object_size_ == (klass->IsArray() ? 0 : num_bytes)));
   Object* obj = Allocate(num_bytes);
   if (obj != NULL) {
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 1c7acff..3998140 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -79,7 +79,7 @@
 
 } // namespace
 
-void ImageWriter::CalculateNewObjectOffsetsCallback(Object *obj, void *arg) {
+void ImageWriter::CalculateNewObjectOffsetsCallback(Object* obj, void *arg) {
   DCHECK(obj != NULL);
   DCHECK(arg != NULL);
   ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
@@ -116,14 +116,15 @@
   heap_bitmap->Walk(CopyAndFixupObjectsCallback, this);
 }
 
-void ImageWriter::CopyAndFixupObjectsCallback(Object *obj, void *arg) {
-  DCHECK(obj != NULL);
+void ImageWriter::CopyAndFixupObjectsCallback(Object* object, void *arg) {
+  DCHECK(object != NULL);
   DCHECK(arg != NULL);
+  const Object* obj = object;
   ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
 
   size_t offset = image_writer->GetImageOffset(obj);
   byte* dst = image_writer->image_->GetAddress() + offset;
-  byte* src = reinterpret_cast<byte*>(obj);
+  const byte* src = reinterpret_cast<const byte*>(obj);
   size_t n = obj->SizeOf();
   DCHECK_LT(offset + n, image_writer->image_->GetLength());
   memcpy(dst, src, n);
@@ -131,7 +132,7 @@
   image_writer->FixupObject(obj, copy);
 }
 
-void ImageWriter::FixupObject(Object* orig, Object* copy) {
+void ImageWriter::FixupObject(const Object* orig, Object* copy) {
   DCHECK(orig != NULL);
   DCHECK(copy != NULL);
   copy->klass_ = down_cast<Class*>(GetImageAddress(orig->klass_));
@@ -149,7 +150,7 @@
   }
 }
 
-void ImageWriter::FixupClass(Class* orig, Class* copy) {
+void ImageWriter::FixupClass(const Class* orig, Class* copy) {
   FixupInstanceFields(orig, copy);
   copy->descriptor_ = down_cast<String*>(GetImageAddress(orig->descriptor_));
   copy->dex_cache_ = down_cast<DexCache*>(GetImageAddress(orig->dex_cache_));
@@ -163,12 +164,13 @@
   copy->vtable_ = down_cast<ObjectArray<Method>*>(GetImageAddress(orig->vtable_));
   // TODO: convert iftable_ to heap allocated storage
   copy->ifields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->ifields_));
+  // TODO: convert source_file_ to heap allocated storage
   copy->sfields_ = down_cast<ObjectArray<Field>*>(GetImageAddress(orig->sfields_));
-  copy->static_references_ = down_cast<ObjectArray<Object>*>(GetImageAddress(orig->static_references_));
+  FixupStaticFields(orig, copy);
 }
 
 // TODO: remove this slow path
-void ImageWriter::FixupMethod(Method* orig, Method* copy) {
+void ImageWriter::FixupMethod(const Method* orig, Method* copy) {
   FixupInstanceFields(orig, copy);
   // TODO: remove need for this by adding "signature" to java.lang.reflect.Method
   copy->signature_ = down_cast<String*>(GetImageAddress(orig->signature_));
@@ -176,20 +178,42 @@
   // TODO: convert shorty_ to heap allocated storage
 }
 
-void ImageWriter::FixupField(Field* orig, Field* copy) {
+void ImageWriter::FixupField(const Field* orig, Field* copy) {
   FixupInstanceFields(orig, copy);
   // TODO: convert descriptor_ to heap allocated storage
 }
 
-void ImageWriter::FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy) {
+void ImageWriter::FixupObjectArray(const ObjectArray<Object>* orig, ObjectArray<Object>* copy) {
   for (int32_t i = 0; i < orig->GetLength(); ++i) {
     const Object* element = orig->Get(i);
     copy->Set(i, GetImageAddress(element));
   }
 }
 
-void ImageWriter::FixupInstanceFields(Object* orig, Object* copy) {
-  uint32_t ref_offsets = orig->GetClass()->GetReferenceOffsets();
+void ImageWriter::FixupInstanceFields(const Object* orig, Object* copy) {
+  DCHECK(orig != NULL);
+  DCHECK(copy != NULL);
+  Class* klass = orig->GetClass();
+  DCHECK(klass != NULL);
+  FixupFields(orig,
+              copy,
+              klass->GetReferenceInstanceOffsets(),
+              false);
+}
+
+void ImageWriter::FixupStaticFields(const Class* orig, Class* copy) {
+  DCHECK(orig != NULL);
+  DCHECK(copy != NULL);
+  FixupFields(orig,
+              copy,
+              orig->GetReferenceStaticOffsets(),
+              true);
+}
+
+void ImageWriter::FixupFields(const Object* orig,
+                              Object* copy,
+                              uint32_t ref_offsets,
+                              bool is_static) {
   if (ref_offsets != CLASS_WALK_SUPER) {
     // Found a reference offset bitmap.  Fixup the specified offsets.
     while (ref_offsets != 0) {
@@ -200,14 +224,21 @@
       ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
     }
   } else {
-    // There is no reference offset bitmap for this class.  Walk up
-    // the class inheritance hierarchy and find reference offsets the
-    // hard way.
-    for (Class *klass = orig->GetClass();
+    // There is no reference offset bitmap.  In the non-static case,
+    // walk up the class inheritance hierarchy and find reference
+    // offsets the hard way. In the static case, just consider this
+    // class.
+    for (const Class *klass = is_static ? orig->AsClass() : orig->GetClass();
          klass != NULL;
-         klass = klass->GetSuperClass()) {
-      for (size_t i = 0; i < klass->NumReferenceInstanceFields(); ++i) {
-        size_t field_offset = klass->GetInstanceField(i)->GetOffset();
+         klass = is_static ? NULL : klass->GetSuperClass()) {
+      size_t num_reference_fields = (is_static
+                                     ? klass->NumReferenceStaticFields()
+                                     : klass->NumReferenceInstanceFields());
+      for (size_t i = 0; i < num_reference_fields; ++i) {
+        Field* field = (is_static
+                        ? klass->GetStaticField(i)
+                        : klass->GetInstanceField(i));
+        size_t field_offset = field->GetOffset();
         const Object* ref = orig->GetFieldObject(field_offset);
         copy->SetFieldObject(field_offset, GetImageAddress(ref));
       }
diff --git a/src/image_writer.h b/src/image_writer.h
index 8e9ac10..ebd86a5 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -46,16 +46,18 @@
   }
 
   void CalculateNewObjectOffsets();
-  static void CalculateNewObjectOffsetsCallback(Object *obj, void *arg);
+  static void CalculateNewObjectOffsetsCallback(Object* obj, void *arg);
 
   void CopyAndFixupObjects();
-  static void CopyAndFixupObjectsCallback(Object *obj, void *arg);
-  void FixupClass(Class* orig, Class* copy);
-  void FixupMethod(Method* orig, Method* copy);
-  void FixupField(Field* orig, Field* copy);
-  void FixupObject(Object* orig, Object* copy);
-  void FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy);
-  void FixupInstanceFields(Object* orig, Object* copy);
+  static void CopyAndFixupObjectsCallback(Object* obj, void *arg);
+  void FixupClass(const Class* orig, Class* copy);
+  void FixupMethod(const Method* orig, Method* copy);
+  void FixupField(const Field* orig, Field* copy);
+  void FixupObject(const Object* orig, Object* copy);
+  void FixupObjectArray(const ObjectArray<Object>* orig, ObjectArray<Object>* copy);
+  void FixupInstanceFields(const Object* orig, Object* copy);
+  void FixupStaticFields(const Class* orig, Class* copy);
+  void FixupFields(const Object* orig, Object* copy, uint32_t ref_offsets, bool is_static);
 
   // memory mapped for generating the image
   scoped_ptr<MemMap> image_;
diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc
index 8541f76..179d954 100644
--- a/src/mark_sweep.cc
+++ b/src/mark_sweep.cc
@@ -126,8 +126,24 @@
 // Scans instance fields.
 void MarkSweep::ScanInstanceFields(const Object* obj) {
   DCHECK(obj != NULL);
-  DCHECK(obj->GetClass() != NULL);
-  uint32_t ref_offsets = obj->GetClass()->GetReferenceOffsets();
+  Class* klass = obj->GetClass();
+  DCHECK(klass != NULL);
+  ScanFields(obj,
+             klass->GetReferenceInstanceOffsets(),
+             false);
+}
+
+// Scans static storage on a Class.
+void MarkSweep::ScanStaticFields(const Class* klass) {
+  DCHECK(klass != NULL);
+  ScanFields(klass,
+             klass->GetReferenceStaticOffsets(),
+             true);
+}
+
+void MarkSweep::ScanFields(const Object* obj,
+                           uint32_t ref_offsets,
+                           bool is_static) {
   if (ref_offsets != CLASS_WALK_SUPER) {
     // Found a reference offset bitmap.  Mark the specified offsets.
     while (ref_offsets != 0) {
@@ -138,14 +154,21 @@
       ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
     }
   } else {
-    // There is no reference offset bitmap for this class.  Walk up
-    // the class inheritance hierarchy and find reference offsets the
-    // hard way.
-    for (Class *klass = obj->GetClass();
+    // There is no reference offset bitmap.  In the non-static case,
+    // walk up the class inheritance hierarchy and find reference
+    // offsets the hard way. In the static case, just consider this
+    // class.
+    for (const Class* klass = is_static ? obj->AsClass() : obj->GetClass();
          klass != NULL;
-         klass = klass->GetSuperClass()) {
-      for (size_t i = 0; i < klass->NumReferenceInstanceFields(); ++i) {
-        size_t field_offset = klass->GetInstanceField(i)->GetOffset();
+         klass = is_static ? NULL : klass->GetSuperClass()) {
+      size_t num_reference_fields = (is_static
+                                     ? klass->NumReferenceStaticFields()
+                                     : klass->NumReferenceInstanceFields());
+      for (size_t i = 0; i < num_reference_fields; ++i) {
+        Field* field = (is_static
+                        ? klass->GetStaticField(i)
+                        : klass->GetInstanceField(i));
+        size_t field_offset = field->GetOffset();
         const Object* ref = obj->GetFieldObject(field_offset);
         MarkObject(ref);
       }
@@ -153,19 +176,6 @@
   }
 }
 
-// Scans the static fields of a class object.
-void MarkSweep::ScanStaticFields(const Class* klass) {
-  DCHECK(klass != NULL);
-  for (size_t i = 0; i < klass->NumStaticFields(); ++i) {
-    const Field* static_field = klass->GetStaticField(i);
-    char ch = static_field->GetType();
-    if (ch == '[' || ch == 'L') {
-      const Object* obj = static_field->GetObject();
-      MarkObject(obj);
-    }
-  }
-}
-
 void MarkSweep::ScanInterfaces(const Class* klass) {
   DCHECK(klass != NULL);
   for (size_t i = 0; i < klass->NumInterfaces(); ++i) {
@@ -198,7 +208,7 @@
 
 // Scans the header of all array objects.  If the array object is
 // specialized to a reference type, scans the array data as well.
-void MarkSweep::ScanArray(const Object *obj) {
+void MarkSweep::ScanArray(const Object* obj) {
   DCHECK(obj != NULL);
   DCHECK(obj->GetClass() != NULL);
   MarkObject(obj->GetClass());
@@ -219,7 +229,7 @@
     ref->SetFieldObject(offset, ref);
     *list = ref;
   } else {
-    Object *head = (*list)->GetFieldObject(offset);
+    Object* head = (*list)->GetFieldObject(offset);
     ref->SetFieldObject(offset, head);
     (*list)->SetFieldObject(offset, ref);
   }
@@ -235,7 +245,7 @@
     ref = *list;
     *list = NULL;
   } else {
-    Object *next = head->GetFieldObject(offset);
+    Object* next = head->GetFieldObject(offset);
     (*list)->SetFieldObject(offset, next);
     ref = head;
   }
@@ -253,7 +263,7 @@
   Object* pending = obj->GetFieldObject(reference_pendingNext_offset_);
   Object* referent = obj->GetFieldObject(reference_referent_offset_);
   if (pending == NULL && referent != NULL && !IsMarked(referent)) {
-    Object **list = NULL;
+    Object** list = NULL;
     if (obj->IsSoftReference()) {
       list = &soft_reference_list_;
     } else if (obj->IsWeakReference()) {
@@ -300,7 +310,7 @@
 // anymore, so use a finger that points past the end of them.
 void MarkSweep::ProcessMarkStack() {
   while (!mark_stack_->IsEmpty()) {
-    const Object *obj = mark_stack_->Pop();
+    const Object* obj = mark_stack_->Pop();
     ScanObject(obj);
   }
 }
@@ -367,8 +377,8 @@
   DCHECK(list != NULL);
   size_t offset = reference_referent_offset_;
   while (*list != NULL) {
-    Object *ref = DequeuePendingReference(list);
-    Object *referent = ref->GetFieldObject(offset);
+    Object* ref = DequeuePendingReference(list);
+    Object* referent = ref->GetFieldObject(offset);
     if (referent != NULL && !IsMarked(referent)) {
       // Referent is white, clear it.
       ClearReference(ref);
@@ -456,7 +466,7 @@
     // TODO: Method *meth = gDvm.methJavaLangRefReferenceQueueAdd;
     // DCHECK(meth != NULL);
     // JValue unused;
-    // Object *reference = *cleared;
+    // Object* reference = *cleared;
     // TODO: dvmCallMethod(self, meth, NULL, &unused, reference);
     UNIMPLEMENTED(FATAL);
     *cleared = NULL;
diff --git a/src/mark_sweep.h b/src/mark_sweep.h
index 47a703a..5f374ae 100644
--- a/src/mark_sweep.h
+++ b/src/mark_sweep.h
@@ -70,6 +70,9 @@
   // Grays references in static fields.
   void ScanStaticFields(const Class* klass);
 
+  // Used by ScanInstanceFields and ScanStaticFields
+  void ScanFields(const Object* obj, uint32_t ref_offsets, bool is_static);
+
   // Grays interface class objects.
   void ScanInterfaces(const Class* klass);
 
diff --git a/src/object.cc b/src/object.cc
index 3200e4d..9316660 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -161,128 +161,160 @@
   return IsInSamePackage(klass1->descriptor_, klass2->descriptor_);
 }
 
-bool Field::GetBoolean() {
-  CHECK_EQ(GetType(), 'Z');
-  CHECK(IsStatic());
-  return declaring_class_->static_32bit_primitives_->Get(offset_);
+uint32_t Field::Get32(const Object* object) const {
+  CHECK((object == NULL) == IsStatic());
+  if (IsStatic()) {
+    object = declaring_class_;
+  }
+  return object->GetField32(GetOffset());
 }
 
-void Field::SetBoolean(bool z) {
-  CHECK_EQ(GetType(), 'Z');
-  CHECK(IsStatic());
-  declaring_class_->static_32bit_primitives_->Set(offset_, z);
+void Field::Set32(Object* object, uint32_t new_value) const {
+  CHECK((object == NULL) == IsStatic());
+  if (IsStatic()) {
+    object = declaring_class_;
+  }
+  object->SetField32(GetOffset(), new_value);
 }
 
-int8_t Field::GetByte() {
+uint64_t Field::Get64(const Object* object) const {
+  CHECK((object == NULL) == IsStatic());
+  if (IsStatic()) {
+    object = declaring_class_;
+  }
+  return object->GetField64(GetOffset());
+}
+
+void Field::Set64(Object* object, uint64_t new_value) const {
+  CHECK((object == NULL) == IsStatic());
+  if (IsStatic()) {
+    object = declaring_class_;
+  }
+  object->SetField64(GetOffset(), new_value);
+}
+
+Object* Field::GetObj(const Object* object) const {
+  CHECK((object == NULL) == IsStatic());
+  if (IsStatic()) {
+    object = declaring_class_;
+  }
+  return object->GetFieldObject(GetOffset());
+}
+
+void Field::SetObj(Object* object, Object* new_value) const {
+  CHECK((object == NULL) == IsStatic());
+  if (IsStatic()) {
+    object = declaring_class_;
+  }
+  object->SetFieldObject(GetOffset(), new_value);
+}
+
+bool Field::GetBoolean(const Object* object) const {
+  CHECK_EQ(GetType(), 'Z');
+  return Get32(object);
+}
+
+void Field::SetBoolean(Object* object, bool z) const {
+  CHECK_EQ(GetType(), 'Z');
+  Set32(object, z);
+}
+
+int8_t Field::GetByte(const Object* object) const {
+  CHECK_EQ(GetType(), 'B');
+  return Get32(object);
+}
+
+void Field::SetByte(Object* object, int8_t b) const {
   CHECK_EQ(GetType(), 'B');
   CHECK(IsStatic());
-  return declaring_class_->static_32bit_primitives_->Get(offset_);
+  Set32(object, b);
 }
 
-void Field::SetByte(int8_t b) {
-  CHECK_EQ(GetType(), 'B');
-  CHECK(IsStatic());
-  declaring_class_->static_32bit_primitives_->Set(offset_, b);
+uint16_t Field::GetChar(const Object* object) const {
+  CHECK_EQ(GetType(), 'C');
+  return Get32(object);
 }
 
-uint16_t Field::GetChar() {
+void Field::SetChar(Object* object, uint16_t c) const {
   CHECK_EQ(GetType(), 'C');
   CHECK(IsStatic());
-  return declaring_class_->static_32bit_primitives_->Get(offset_);
+  Set32(object, c);
 }
 
-void Field::SetChar(uint16_t c) {
-  CHECK_EQ(GetType(), 'C');
-  CHECK(IsStatic());
-  declaring_class_->static_32bit_primitives_->Set(offset_, c);
+uint16_t Field::GetShort(const Object* object) const {
+  CHECK_EQ(GetType(), 'S');
+  return Get32(object);
 }
 
-uint16_t Field::GetShort() {
+void Field::SetShort(Object* object, uint16_t s) const {
   CHECK_EQ(GetType(), 'S');
   CHECK(IsStatic());
-  return declaring_class_->static_32bit_primitives_->Get(offset_);
+  Set32(object, s);
 }
 
-void Field::SetShort(uint16_t s) {
-  CHECK_EQ(GetType(), 'S');
-  CHECK(IsStatic());
-  declaring_class_->static_32bit_primitives_->Set(offset_, s);
+int32_t Field::GetInt(const Object* object) const {
+  CHECK_EQ(GetType(), 'I');
+  return Get32(object);
 }
 
-int32_t Field::GetInt() {
+void Field::SetInt(Object* object, int32_t i) const {
   CHECK_EQ(GetType(), 'I');
   CHECK(IsStatic());
-  return declaring_class_->static_32bit_primitives_->Get(offset_);
+  Set32(object, i);
 }
 
-void Field::SetInt(int32_t i) {
-  CHECK_EQ(GetType(), 'I');
-  CHECK(IsStatic());
-  declaring_class_->static_32bit_primitives_->Set(offset_, i);
+int64_t Field::GetLong(const Object* object) const {
+  CHECK_EQ(GetType(), 'J');
+  return Get64(object);
 }
 
-int64_t Field::GetLong() {
+void Field::SetLong(Object* object, int64_t j) const {
   CHECK_EQ(GetType(), 'J');
   CHECK(IsStatic());
-  return declaring_class_->static_64bit_primitives_->Get(offset_);
+  Set64(object, j);
 }
 
-void Field::SetLong(int64_t j) {
-  CHECK_EQ(GetType(), 'J');
-  CHECK(IsStatic());
-  declaring_class_->static_64bit_primitives_->Set(offset_, j);
-}
-
-float Field::GetFloat() {
+float Field::GetFloat(const Object* object) const {
   CHECK_EQ(GetType(), 'F');
-  CHECK(IsStatic());
   JValue float_bits;
-  float_bits.i = declaring_class_->static_32bit_primitives_->Get(offset_);
+  float_bits.i = Get32(object);
   return float_bits.f;
 }
 
-void Field::SetFloat(float f) {
+void Field::SetFloat(Object* object, float f) const {
   CHECK_EQ(GetType(), 'F');
   CHECK(IsStatic());
   JValue float_bits;
   float_bits.f = f;
-  declaring_class_->static_32bit_primitives_->Set(offset_, float_bits.i);
+  Set32(object, float_bits.i);
 }
 
-double Field::GetDouble() {
+double Field::GetDouble(const Object* object) const {
   CHECK_EQ(GetType(), 'D');
-  CHECK(IsStatic());
   JValue double_bits;
-  double_bits.j = declaring_class_->static_64bit_primitives_->Get(offset_);
+  double_bits.j = Get64(object);
   return double_bits.d;
 }
 
-void Field::SetDouble(double d) {
+void Field::SetDouble(Object* object, double d) const {
   CHECK_EQ(GetType(), 'D');
   CHECK(IsStatic());
   JValue double_bits;
   double_bits.d = d;
-  declaring_class_->static_64bit_primitives_->Set(offset_, double_bits.j);
+  Set64(object, double_bits.j);
 }
 
-Object* Field::GetObject() {
+Object* Field::GetObject(const Object* object) const {
   CHECK(GetType() == 'L' || GetType() == '[');
-  CHECK(IsStatic());
-  return declaring_class_->static_references_->Get(offset_);
+  return GetObj(object);
 }
 
-const Object* Field::GetObject() const {
+void Field::SetObject(Object* object, Object* l) const {
   CHECK(GetType() == 'L' || GetType() == '[');
-  CHECK(IsStatic());
-  return declaring_class_->static_references_->Get(offset_);
+  SetObj(object, l);
 }
 
-void Field::SetObject(Object* l) {
-  CHECK(GetType() == 'L' || GetType() == '[');
-  declaring_class_->static_references_->Set(offset_, l);  // TODO: write barrier
-}
-
-uint32_t Method::NumArgRegisters() {
+uint32_t Method::NumArgRegisters() const {
   CHECK(shorty_ != NULL);
   uint32_t num_registers = 0;
   for (int i = 1; i < shorty_.length(); ++i) {
@@ -296,7 +328,7 @@
   return num_registers;
 }
 
-size_t Method::NumArgArrayBytes() {
+size_t Method::NumArgArrayBytes() const {
   const StringPiece& shorty = GetShorty();
   size_t num_bytes = 0;
   for (int i = 1; i < shorty.size(); ++i) {
diff --git a/src/object.h b/src/object.h
index 6322b8d..840c966 100644
--- a/src/object.h
+++ b/src/object.h
@@ -158,15 +158,9 @@
     monitor_->Wait(timeout, nanos);
   }
 
-  const Object* GetFieldObject(size_t field_offset) const {
-    Object* that = const_cast<Object*>(this);
-    Object* other = that->GetFieldObject(field_offset);
-    return const_cast<const Object*>(other);
-  }
-
-  Object* GetFieldObject(size_t field_offset) {
-    byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset;
-    return *reinterpret_cast<Object**>(raw_addr);
+  Object* GetFieldObject(size_t field_offset) const {
+    const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset;
+    return *reinterpret_cast<Object* const *>(raw_addr);
   }
 
   void SetFieldObject(size_t offset, Object* new_value) {
@@ -175,6 +169,26 @@
     // TODO: write barrier
   }
 
+  uint32_t GetField32(size_t field_offset) const {
+    const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset;
+    return *reinterpret_cast<const uint32_t*>(raw_addr);
+  }
+
+  void SetField32(size_t offset, uint32_t new_value) {
+    byte* raw_addr = reinterpret_cast<byte*>(this) + offset;
+    *reinterpret_cast<uint32_t*>(raw_addr) = new_value;
+  }
+
+  uint64_t GetField64(size_t field_offset) const {
+    const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset;
+    return *reinterpret_cast<const uint64_t*>(raw_addr);
+  }
+
+  void SetField64(size_t offset, uint64_t new_value) {
+    byte* raw_addr = reinterpret_cast<byte*>(this) + offset;
+    *reinterpret_cast<uint64_t*>(raw_addr) = new_value;
+  }
+
   bool IsClass() const;
 
   Class* AsClass() {
@@ -187,6 +201,8 @@
     return down_cast<const Class*>(this);
   }
 
+  bool IsClassClass() const;
+
   bool IsObjectArray() const;
 
   template<class T>
@@ -252,6 +268,11 @@
     return down_cast<Method*>(this);
   }
 
+  const Method* AsMethod() const {
+    DCHECK(IsMethod());
+    return down_cast<const Method*>(this);
+  }
+
   bool IsField() const;
 
   Field* AsField() {
@@ -259,6 +280,11 @@
     return down_cast<Field*>(this);
   }
 
+  const Field* AsField() const {
+    DCHECK(IsField());
+    return down_cast<const Field*>(this);
+  }
+
  public:
   Class* klass_;
 
@@ -335,28 +361,36 @@
     offset_ = num_bytes;
   }
 
-  // static field access
-  bool GetBoolean();
-  void SetBoolean(bool z);
-  int8_t GetByte();
-  void SetByte(int8_t b);
-  uint16_t GetChar();
-  void SetChar(uint16_t c);
-  uint16_t GetShort();
-  void SetShort(uint16_t s);
-  int32_t GetInt();
-  void SetInt(int32_t i);
-  int64_t GetLong();
-  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);
+  // field access, null object for static fields
+  bool GetBoolean(const Object* object) const;
+  void SetBoolean(Object* object, bool z) const;
+  int8_t GetByte(const Object* object) const;
+  void SetByte(Object* object, int8_t b) const;
+  uint16_t GetChar(const Object* object) const;
+  void SetChar(Object* object, uint16_t c) const;
+  uint16_t GetShort(const Object* object) const;
+  void SetShort(Object* object, uint16_t s) const;
+  int32_t GetInt(const Object* object) const;
+  void SetInt(Object* object, int32_t i) const;
+  int64_t GetLong(const Object* object) const;
+  void SetLong(Object* object, int64_t j) const;
+  float GetFloat(const Object* object) const;
+  void SetFloat(Object* object, float f) const;
+  double GetDouble(const Object* object) const;
+  void SetDouble(Object* object, double d) const;
+  Object* GetObject(const Object* object) const;
+  void SetObject(Object* object, Object* l) const;
 
  public:  // TODO: private
+
+  // private implemention of field access using raw data
+  uint32_t Get32(const Object* object) const;
+  void Set32(Object* object, uint32_t new_value) const;
+  uint64_t Get64(const Object* object) const;
+  void Set64(Object* object, uint64_t new_value) const;
+  Object* GetObj(const Object* object) const;
+  void SetObj(Object* object, Object* new_value) const;
+
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   // The class in which this field is declared.
   Class* declaring_class_;
@@ -445,11 +479,11 @@
   }
 
   // Number of argument registers required by the prototype.
-  uint32_t NumArgRegisters();
+  uint32_t NumArgRegisters() const;
 
   // Number of argument bytes required for densely packing the
   // arguments into an array of arguments.
-  size_t NumArgArrayBytes();
+  size_t NumArgArrayBytes() const;
 
  public:  // TODO: private
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
@@ -912,6 +946,10 @@
     return descriptor_;
   }
 
+  size_t SizeOf() const {
+    return class_size_;
+  }
+
   Status GetStatus() const {
     return status_;
   }
@@ -1046,6 +1084,11 @@
     return num_reference_instance_fields_;
   }
 
+  // Returns the number of static fields containing reference types.
+  size_t NumReferenceStaticFields() const {
+    return num_reference_static_fields_;
+  }
+
   // Finds the given instance field in this class or a superclass.
   Field* FindInstanceField(const StringPiece& name,
       const StringPiece& descriptor);
@@ -1084,12 +1127,20 @@
     sfields_->Set(i, f);
   }
 
-  uint32_t GetReferenceOffsets() const {
-    return reference_offsets_;
+  uint32_t GetReferenceInstanceOffsets() const {
+    return reference_instance_offsets_;
   }
 
-  void SetReferenceOffsets(uint32_t new_reference_offsets) {
-    reference_offsets_ = new_reference_offsets;
+  void SetReferenceInstanceOffsets(uint32_t new_reference_offsets) {
+    reference_instance_offsets_ = new_reference_offsets;
+  }
+
+  uint32_t GetReferenceStaticOffsets() const {
+    return reference_static_offsets_;
+  }
+
+  void SetReferenceStaticOffsets(uint32_t new_reference_offsets) {
+    reference_static_offsets_ = new_reference_offsets;
   }
 
   size_t NumInterfaces() const {
@@ -1220,11 +1271,11 @@
   // specifies the number of reference fields.
   ObjectArray<Field>* ifields_;
 
-  // number of fields that are object refs
+  // number of instance fields that are object refs
   size_t num_reference_instance_fields_;
 
   // Bitmap of offsets of ifields.
-  uint32_t reference_offsets_;
+  uint32_t reference_instance_offsets_;
 
   // source file name, if known.  Otherwise, NULL.
   const char* source_file_;
@@ -1232,18 +1283,17 @@
   // Static fields
   ObjectArray<Field>* 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_;
+  // number of static fields that are object refs
+  size_t num_reference_static_fields_;
+
+  // Bitmap of offsets of sfields.
+  uint32_t reference_static_offsets_;
+
+  // Total class size; used when allocating storage on gc heap.
+  size_t class_size_;
+
+  // Location of first static field.
+  uint32_t fields_[0];
 
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(Class);
@@ -1261,6 +1311,11 @@
   return klass_ == java_lang_Class;
 }
 
+inline bool Object::IsClassClass() const {
+  Class* java_lang_Class = klass_->klass_;
+  return this == java_lang_Class;
+}
+
 inline bool Object::IsObjectArray() const {
   return IsArray() && !klass_->component_type_->IsPrimitive();
 }
@@ -1285,6 +1340,9 @@
   if (IsArray()) {
     return AsArray()->SizeOf();
   }
+  if (IsClass()) {
+    return AsClass()->SizeOf();
+  }
   return klass_->object_size_;
 }
 
@@ -1292,8 +1350,47 @@
   return SizeOf(GetLength(), klass_->GetComponentSize());
 }
 
+class ClassClass : public Class {
+ private:
+  // Padding to ensure the 64-bit serialVersionUID_ begins on a 8-byte boundary
+  int32_t padding_;
+  int64_t serialVersionUID_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ClassClass);
+};
+
+class StringClass : public Class {
+ private:
+  CharArray* ASCII_;
+  Object* CASE_INSENSITIVE_ORDER_;
+  uint32_t REPLACEMENT_CHAR_;
+  int64_t serialVersionUID;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StringClass);
+};
+
+class FieldClass : public Class {
+ private:
+  Object* ORDER_BY_NAME_AND_DECLARING_CLASS_;
+  uint32_t TYPE_BOOLEAN_;
+  uint32_t TYPE_BYTE_;
+  uint32_t TYPE_CHAR_;
+  uint32_t TYPE_DOUBLE_;
+  uint32_t TYPE_FLOAT_;
+  uint32_t TYPE_INTEGER_;
+  uint32_t TYPE_LONG_;
+  uint32_t TYPE_SHORT_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(FieldClass);
+};
+
+class MethodClass : public Class {
+ private:
+  int32_t DECLARED_;
+  int32_t PUBLIC_;
+  DISALLOW_IMPLICIT_CONSTRUCTORS(MethodClass);
+};
+
 class DataObject : public Object {
  public:
+  // Location of first instance field.
   uint32_t fields_[0];
  private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(DataObject);
diff --git a/src/object_bitmap.cc b/src/object_bitmap.cc
index 7de4988..40dd41d 100644
--- a/src/object_bitmap.cc
+++ b/src/object_bitmap.cc
@@ -89,7 +89,7 @@
       uintptr_t ptr_base = HB_INDEX_TO_OFFSET(i) + base_;
       while (word != 0) {
         const int shift = CLZ(word);
-        Object* obj = (Object *)(ptr_base + shift * kAlignment);
+        Object* obj = (Object*) (ptr_base + shift * kAlignment);
         (*callback)(obj, arg);
         word &= ~(high_bit >> shift);
       }
diff --git a/src/object_bitmap.h b/src/object_bitmap.h
index 3cc973c..3cb1aad 100644
--- a/src/object_bitmap.h
+++ b/src/object_bitmap.h
@@ -48,9 +48,9 @@
  public:
   static const size_t kAlignment = 8;
 
-  typedef void Callback(Object *obj, void *arg);
+  typedef void Callback(Object* obj, void *arg);
 
-  typedef void ScanCallback(Object *obj, void *finger, void *arg);
+  typedef void ScanCallback(Object* obj, void *finger, void *arg);
 
   typedef void SweepCallback(size_t numPtrs, void **ptrs, void *arg);
 
diff --git a/src/thread.cc b/src/thread.cc
index 15382b9..d4b7008 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -144,7 +144,7 @@
 }
 
 bool Thread::ShbContains(jobject obj) {
-  Object **shb_entry = reinterpret_cast<Object**>(obj);
+  Object** shb_entry = reinterpret_cast<Object**>(obj);
   for (StackHandleBlock* cur = top_shb_; cur; cur = cur->Link()) {
     size_t num_refs = cur->NumberOfReferences();
     DCHECK_GT(num_refs, 0u); // A SHB should always have a jobject/jclass