Merge "Make CommonTest.compiler_ a UniquePtr" into dalvik-dev
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 01e283e..6d5c643 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2,6 +2,7 @@
 
 #include "class_linker.h"
 
+#include <deque>
 #include <string>
 #include <utility>
 #include <vector>
@@ -1834,14 +1835,35 @@
   return success;
 }
 
+struct LinkFieldsComparator {
+  bool operator()(const Field* field1, const Field* field2){
+
+    // First come reference fields, then 64-bit, and finally 32-bit
+    const Class* type1 = field1->GetTypeDuringLinking();
+    const Class* type2 = field2->GetTypeDuringLinking();
+    bool isPrimitive1 = type1 != NULL && type1->IsPrimitive();
+    bool isPrimitive2 = type2 != NULL && type2->IsPrimitive();
+    bool is64bit1 = isPrimitive1 && (type1->IsPrimitiveLong() || type1->IsPrimitiveDouble());
+    bool is64bit2 = isPrimitive2 && (type2->IsPrimitiveLong() || type2->IsPrimitiveDouble());
+    int order1 = (!isPrimitive1 ? 0 : (is64bit1 ? 1 : 2));
+    int order2 = (!isPrimitive2 ? 0 : (is64bit2 ? 1 : 2));
+    if (order1 != order2) {
+      return order1 < order2;
+    }
+
+    // same basic group? then sort by string.
+    std::string name1 = field1->GetName()->ToModifiedUtf8();
+    std::string name2 = field2->GetName()->ToModifiedUtf8();
+    return name1 < name2;
+  }
+};
+
 bool ClassLinker::LinkFields(Class* klass, bool instance) {
   size_t num_fields =
       instance ? klass->NumInstanceFields() : klass->NumStaticFields();
 
   ObjectArray<Field>* fields =
       instance ? klass->GetIFields() : klass->GetSFields();
-  // Fields updated at end of LinkFields
-  size_t num_reference_fields;
 
   // Initialize size and field_offset
   size_t size;
@@ -1858,34 +1880,32 @@
     field_offset = Class::FieldsOffset();
   }
 
-  CHECK((num_fields == 0) == (fields == NULL));
+  CHECK_EQ(num_fields == 0, fields == NULL);
 
-  // Move references to the front.
-  size_t i = 0;
-  num_reference_fields = 0;
-  for (; i < num_fields; i++) {
-    Field* field = fields->Get(i);
-    const Class* field_type = field->GetTypeDuringLinking();
+  // we want a relatively stable order so that adding new fields
+  // minimizes distruption of C++ version such as Class and Method.
+  std::deque<Field*> grouped_and_sorted_fields;
+  for (size_t i = 0; i < num_fields; i++) {
+    grouped_and_sorted_fields.push_back(fields->Get(i));
+  }
+  std::sort(grouped_and_sorted_fields.begin(),
+            grouped_and_sorted_fields.end(),
+            LinkFieldsComparator());
+
+  // References should be at the front.
+  size_t current_field = 0;
+  size_t num_reference_fields = 0;
+  for (; current_field < num_fields; current_field++) {
+    Field* field = grouped_and_sorted_fields.front();
+    const Class* type = field->GetTypeDuringLinking();
     // if a field's type at this point is NULL it isn't primitive
-    if (field_type != NULL && field_type->IsPrimitive()) {
-      for (size_t j = num_fields - 1; j > i; j--) {
-        Field* ref_field = fields->Get(j);
-        const Class* ref_field_type = ref_field->GetTypeDuringLinking();
-        if (ref_field_type == NULL || !ref_field_type->IsPrimitive()) {
-          fields->Set(i, ref_field);
-          fields->Set(j, field);
-          field = ref_field;
-          field_type = ref_field_type;
-          num_reference_fields++;
-          break;
-        }
-      }
-    } else {
-      num_reference_fields++;
+    bool isPrimitive = type != NULL && type->IsPrimitive();
+    if (isPrimitive) {
+      break; // past last reference, move on to the next phase
     }
-    if (field_type != NULL && field_type->IsPrimitive()) {
-      break;
-    }
+    grouped_and_sorted_fields.pop_front();
+    num_reference_fields++;
+    fields->Set(current_field, field);
     field->SetOffset(field_offset);
     field_offset = MemberOffset(field_offset.Uint32Value() + sizeof(uint32_t));
   }
@@ -1893,86 +1913,57 @@
   // 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 != num_fields && !IsAligned(field_offset.Uint32Value(), 8)) {
-    Field* field = fields->Get(i);
-    const Class* c = field->GetTypeDuringLinking();
-    CHECK(c != NULL);  // should only be working on primitive types
-    if (!c->IsPrimitiveLong() && !c->IsPrimitiveDouble()) {
-      // The field that comes next is 32-bit, so just advance past it.
-      DCHECK(c->IsPrimitive());
+  if (current_field != num_fields && !IsAligned(field_offset.Uint32Value(), 8)) {
+    for (size_t i = 0; i < grouped_and_sorted_fields.size(); i++) {
+      Field* field = grouped_and_sorted_fields[i];
+      const Class* type = field->GetTypeDuringLinking();
+      CHECK(type != NULL);  // should only be working on primitive types
+      DCHECK(type->IsPrimitive());
+      if (type->IsPrimitiveLong() || type->IsPrimitiveDouble()) {
+        continue;
+      }
+      fields->Set(current_field++, field);
       field->SetOffset(field_offset);
-      field_offset = MemberOffset(field_offset.Uint32Value() +
-                                  sizeof(uint32_t));
-      i++;
-    } else {
-      // Next field is 64-bit, so search for a 32-bit field we can
-      // swap into it.
-      bool found = false;
-      for (size_t j = num_fields - 1; j > i; j--) {
-        Field* single_field = fields->Get(j);
-        const Class* rc = single_field->GetTypeDuringLinking();
-        CHECK(rc != NULL);  // should only be working on primitive types
-        if (!rc->IsPrimitiveLong() && !rc->IsPrimitiveDouble()) {
-          fields->Set(i, single_field);
-          fields->Set(j, field);
-          field = single_field;
-          field->SetOffset(field_offset);
-          field_offset = MemberOffset(field_offset.Uint32Value() +
-                                      sizeof(uint32_t));
-          found = true;
-          i++;
-          break;
-        }
-      }
-      if (!found) {
-        field_offset = MemberOffset(field_offset.Uint32Value() +
-                                    sizeof(uint32_t));
-      }
+      // drop the consumed field
+      grouped_and_sorted_fields.erase(grouped_and_sorted_fields.begin() + i);
+      break;
     }
+    // whether we found a 32-bit field for padding or not, we advance
+    field_offset = MemberOffset(field_offset.Uint32Value() + sizeof(uint32_t));
   }
 
   // Alignment is good, shuffle any double-wide fields forward, and
   // finish assigning field offsets to all fields.
-  DCHECK(i == num_fields || IsAligned(field_offset.Uint32Value(), 4));
-  for ( ; i < num_fields; i++) {
-    Field* field = fields->Get(i);
-    const Class* c = field->GetTypeDuringLinking();
-    CHECK(c != NULL);  // should only be working on primitive types
-    if (!c->IsPrimitiveDouble() && !c->IsPrimitiveLong()) {
-      for (size_t j = num_fields - 1; j > i; j--) {
-        Field* double_field = fields->Get(j);
-        const Class* rc = double_field->GetTypeDuringLinking();
-        CHECK(rc != NULL);  // should only be working on primitive types
-        if (rc->IsPrimitiveDouble() || rc->IsPrimitiveLong()) {
-          fields->Set(i, double_field);
-          fields->Set(j, field);
-          field = double_field;
-          c = rc;
-          break;
-        }
-      }
-    } else {
-      // This is a double-wide field, leave it be.
-    }
-
+  DCHECK(current_field == num_fields || IsAligned(field_offset.Uint32Value(), 8));
+  while (!grouped_and_sorted_fields.empty()) {
+    Field* field = grouped_and_sorted_fields.front();
+    grouped_and_sorted_fields.pop_front();
+    const Class* type = field->GetTypeDuringLinking();
+    CHECK(type != NULL);  // should only be working on primitive types
+    DCHECK(type->IsPrimitive());
+    fields->Set(current_field, field);
     field->SetOffset(field_offset);
-    if (c->IsPrimitiveLong() || c->IsPrimitiveDouble()) {
-      field_offset = MemberOffset(field_offset.Uint32Value() +
-                                  sizeof(uint64_t));
-    } else {
-      field_offset = MemberOffset(field_offset.Uint32Value() +
-                                  sizeof(uint32_t));
-    }
+    field_offset = MemberOffset(field_offset.Uint32Value() +
+                                ((type->IsPrimitiveLong() || type->IsPrimitiveDouble())
+                                 ? sizeof(uint64_t)
+                                 : sizeof(uint32_t)));
+    current_field++;
   }
 
 #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 < num_fields; i++) {
+  for (size_t i = 0; i < num_fields; i++) {
     Field* field = fields->Get(i);
-    const Class* c = field->GetTypeDuringLinking();
-    if (c != NULL && c->IsPrimitive()) {
+    if (false) {  // enable to debug field layout
+      LOG(INFO) << "LinkFields:"
+                << " class=" << klass->GetDescriptor()->ToModifiedUtf8()
+                << " field=" << field->GetName()->ToModifiedUtf8()
+                << " offset=" << field->GetField32(MemberOffset(Field::OffsetOffset()), false);
+    }
+    const Class* type = field->GetTypeDuringLinking();
+    if (type != NULL && type->IsPrimitive()) {
       if (!seen_non_ref) {
         seen_non_ref = true;
         DCHECK_EQ(num_reference_fields, i);
@@ -1987,9 +1978,9 @@
 #endif
   size = field_offset.Uint32Value();
   // Update klass
-  if(instance) {
+  if (instance) {
     klass->SetNumReferenceInstanceFields(num_reference_fields);
-    if(!klass->IsVariableSize()) {
+    if (!klass->IsVariableSize()) {
       klass->SetObjectSize(size);
     }
   } else {
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 3362fdc..cb1cd8d 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -379,61 +379,62 @@
 };
 
 struct CheckOffsets {
-  size_t s;
-  std::string c;
-  std::vector<CheckOffset> o;
+  bool instance;
+  size_t size;
+  std::string class_descriptor;
+  std::vector<CheckOffset> offsets;
 
   bool Check() {
-    Class* klass = Runtime::Current()->GetClassLinker()->FindSystemClass(c);
-    CHECK(klass != NULL) << c;
+    Class* klass = Runtime::Current()->GetClassLinker()->FindSystemClass(class_descriptor);
+    CHECK(klass != NULL) << class_descriptor;
 
     bool error = false;
 
-    if (!klass->IsClassClass())
-      if (s != klass->GetObjectSize()) {
+    if (!klass->IsClassClass() && instance)
+      if (size != (instance ? klass->GetObjectSize() : klass->GetClassSize())) {
         LG << "Class size mismatch:"
-           << " class=" << c
+           << " class=" << class_descriptor
            << " Java=" << klass->GetObjectSize()
-           << " C++=" << s;
+           << " C++=" << (instance ? klass->GetObjectSize() : klass->GetClassSize());
       error = true;
     }
 
-    CHECK_EQ(o.size(), klass->NumInstanceFields());
-    for (size_t i = 0; i < o.size(); i++) {
-      Field* field = klass->GetInstanceField(i);
-      if (!field->GetName()->Equals(o[i].java_name)) {
+    CHECK_EQ(offsets.size(), instance ? klass->NumInstanceFields() : klass->NumStaticFields());
+    for (size_t i = 0; i < offsets.size(); i++) {
+      Field* field = instance ? klass->GetInstanceField(i) : klass->GetStaticField(i);
+      if (!field->GetName()->Equals(offsets[i].java_name)) {
         error = true;
       }
     }
     if (error) {
-      for (size_t i = 0; i < o.size(); i++) {
-        CheckOffset& offset = o[i];
-        Field* field = klass->GetInstanceField(i);
-        if (!field->GetName()->Equals(o[i].java_name)) {
+      for (size_t i = 0; i < offsets.size(); i++) {
+        CheckOffset& offset = offsets[i];
+        Field* field = instance ? klass->GetInstanceField(i) : klass->GetStaticField(i);
+        if (!field->GetName()->Equals(offsets[i].java_name)) {
           LG << "JAVA FIELD ORDER MISMATCH NEXT LINE:";
         }
         LG << "Java field order:"
-           << " i=" << i << " class=" << c
+           << " i=" << i << " class=" << class_descriptor
            << " Java=" << field->GetName()->ToModifiedUtf8()
            << " CheckOffsets=" << offset.java_name;
       }
     }
 
-    for (size_t i = 0; i < o.size(); i++) {
-      CheckOffset& offset = o[i];
-      Field* field = klass->GetInstanceField(i);
+    for (size_t i = 0; i < offsets.size(); i++) {
+      CheckOffset& offset = offsets[i];
+      Field* field = instance ? klass->GetInstanceField(i) : klass->GetStaticField(i);
       if (field->GetOffset().Uint32Value() != offset.cpp_offset) {
         error = true;
       }
     }
     if (error) {
-      for (size_t i = 0; i < o.size(); i++) {
-        CheckOffset& offset = o[i];
-        Field* field = klass->GetInstanceField(i);
+      for (size_t i = 0; i < offsets.size(); i++) {
+        CheckOffset& offset = offsets[i];
+        Field* field = instance ? klass->GetInstanceField(i) : klass->GetStaticField(i);
         if (field->GetOffset().Uint32Value() != offset.cpp_offset) {
           LG << "OFFSET MISMATCH NEXT LINE:";
         }
-        LG << "Offset: class=" << c << " field=" << offset.java_name
+        LG << "Offset: class=" << class_descriptor << " field=" << offset.java_name
            << " Java=" << field->GetOffset().Uint32Value() << " C++=" << offset.cpp_offset;
       }
     }
@@ -444,175 +445,279 @@
 
 struct ObjectOffsets : public CheckOffsets {
   ObjectOffsets() {
-    s = sizeof(Object);
-    c = "Ljava/lang/Object;";
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Object, klass_),   "shadow$_klass_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Object, monitor_), "shadow$_monitor_"));
+    instance = true;
+    size = sizeof(Object);
+    class_descriptor = "Ljava/lang/Object;";
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Object, klass_),   "shadow$_klass_"));
+
+    // alphabetical 32-bit
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Object, monitor_), "shadow$_monitor_"));
   };
 };
 
 struct AccessibleObjectOffsets : public CheckOffsets {
   AccessibleObjectOffsets() {
-    s = sizeof(AccessibleObject);
-    c = "Ljava/lang/reflect/AccessibleObject;";
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(AccessibleObject, java_flag_), "flag"));
+    instance = true;
+    size = sizeof(AccessibleObject);
+    class_descriptor = "Ljava/lang/reflect/AccessibleObject;";
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AccessibleObject, java_flag_), "flag"));
   };
 };
 
 struct FieldOffsets : public CheckOffsets {
   FieldOffsets() {
-    s = sizeof(Field);
-    c = "Ljava/lang/reflect/Field;";
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, declaring_class_),               "declaringClass"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, generic_type_),                  "genericType"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, type_),                          "type"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, name_),                          "name"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, access_flags_),                  "shadow$_access_flags_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, offset_),                        "shadow$_offset_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, type_idx_),                      "shadow$_type_idx_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, slot_),                          "slot"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Field, generic_types_are_initialized_), "genericTypesAreInitialized"));
+    instance = true;
+    size = sizeof(Field);
+    class_descriptor = "Ljava/lang/reflect/Field;";
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, declaring_class_),               "declaringClass"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, generic_type_),                  "genericType"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, name_),                          "name"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, type_),                          "type"));
+
+    // alphabetical 32-bit
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, generic_types_are_initialized_), "genericTypesAreInitialized"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, access_flags_),                  "shadow$_access_flags_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, offset_),                        "shadow$_offset_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, type_idx_),                      "shadow$_type_idx_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, slot_),                          "slot"));
   };
 };
 
 struct MethodOffsets : public CheckOffsets {
   MethodOffsets() {
-    s = sizeof(Method);
-    c = "Ljava/lang/reflect/Method;";
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, declaring_class_),                      "declaringClass"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_exception_types_),                 "exceptionTypes"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_formal_type_parameters_),          "formalTypeParameters"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_exception_types_),         "genericExceptionTypes"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_parameter_types_),         "genericParameterTypes"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_return_type_),             "genericReturnType"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, signature_),                            "shadow$_signature_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, name_),                                 "name"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_parameter_types_),                 "parameterTypes"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_return_type_),                     "returnType"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, mapping_table_),                        "shadow$_mapping_table_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, invoke_stub_array_),                    "shadow$_invoke_stub_array_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_array_),                           "shadow$_code_array_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_strings_),                    "shadow$_dex_cache_strings_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_types_),             "shadow$_dex_cache_resolved_types_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_code_and_direct_methods_),    "shadow$_dex_cache_code_and_direct_methods_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_initialized_static_storage_), "shadow$_dex_cache_initialized_static_storage_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_fields_),            "shadow$_dex_cache_resolved_fields_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_methods_),           "shadow$_dex_cache_resolved_methods_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, core_spill_mask_),                      "shadow$_core_spill_mask_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_item_offset_),                     "shadow$_code_item_offset_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, fp_spill_mask_),                        "shadow$_fp_spill_mask_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, frame_size_in_bytes_),                  "shadow$_frame_size_in_bytes_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, invoke_stub_),                          "shadow$_invoke_stub_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_),                                 "shadow$_code_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_return_type_idx_),                 "shadow$_java_return_type_idx_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, access_flags_),                         "shadow$_access_flags_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, method_index_),                         "shadow$_method_index_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, native_method_),                        "shadow$_native_method_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_ins_),                              "shadow$_num_ins_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_outs_),                             "shadow$_num_outs_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_registers_),                        "shadow$_num_registers_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, proto_idx_),                            "shadow$_proto_idx_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, return_pc_offset_in_bytes_),            "shadow$_return_pc_offset_in_bytes_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, shorty_),                               "shadow$_shorty_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_types_are_initialized_),   "genericTypesAreInitialized"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_slot_),                            "slot"));
+    instance = true;
+    size = sizeof(Method);
+    class_descriptor = "Ljava/lang/reflect/Method;";
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, declaring_class_),                      "declaringClass"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_exception_types_),                 "exceptionTypes"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_formal_type_parameters_),          "formalTypeParameters"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_exception_types_),         "genericExceptionTypes"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_parameter_types_),         "genericParameterTypes"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_return_type_),             "genericReturnType"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, name_),                                 "name"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_parameter_types_),                 "parameterTypes"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_return_type_),                     "returnType"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_array_),                           "shadow$_code_array_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_code_and_direct_methods_),    "shadow$_dex_cache_code_and_direct_methods_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_initialized_static_storage_), "shadow$_dex_cache_initialized_static_storage_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_fields_),            "shadow$_dex_cache_resolved_fields_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_methods_),           "shadow$_dex_cache_resolved_methods_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_resolved_types_),             "shadow$_dex_cache_resolved_types_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, dex_cache_strings_),                    "shadow$_dex_cache_strings_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, invoke_stub_array_),                    "shadow$_invoke_stub_array_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, mapping_table_),                        "shadow$_mapping_table_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, signature_),                            "shadow$_signature_"));
+
+    // alphabetical 32-bit
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_types_are_initialized_),   "genericTypesAreInitialized"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, access_flags_),                         "shadow$_access_flags_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_),                                 "shadow$_code_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, code_item_offset_),                     "shadow$_code_item_offset_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, core_spill_mask_),                      "shadow$_core_spill_mask_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, fp_spill_mask_),                        "shadow$_fp_spill_mask_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, frame_size_in_bytes_),                  "shadow$_frame_size_in_bytes_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, invoke_stub_),                          "shadow$_invoke_stub_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_return_type_idx_),                 "shadow$_java_return_type_idx_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, method_index_),                         "shadow$_method_index_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, native_method_),                        "shadow$_native_method_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_ins_),                              "shadow$_num_ins_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_outs_),                             "shadow$_num_outs_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, num_registers_),                        "shadow$_num_registers_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, proto_idx_),                            "shadow$_proto_idx_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, return_pc_offset_in_bytes_),            "shadow$_return_pc_offset_in_bytes_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, shorty_),                               "shadow$_shorty_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_slot_),                            "slot"));
   };
 };
 
 struct ClassOffsets : public CheckOffsets {
   ClassOffsets() {
-    s = sizeof(Class);
-    c = "Ljava/lang/Class;";
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, name_),                          "name"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, vtable_),                        "shadow$_vtable_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, virtual_methods_),               "shadow$_virtual_methods_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_loader_),                  "shadow$_class_loader_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, verify_error_class_),            "shadow$_verify_error_class_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, super_class_),                   "shadow$_super_class_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, component_type_),                "shadow$_component_type_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, descriptor_),                    "shadow$_descriptor_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, dex_cache_),                     "shadow$_dex_cache_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, direct_methods_),                "shadow$_direct_methods_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, ifields_),                       "shadow$_ifields_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, sfields_),                       "shadow$_sfields_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, interfaces_type_idx_),           "shadow$_interfaces_type_idx_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, interfaces_),                    "shadow$_interfaces_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, ifvi_pool_count_),               "shadow$_ifvi_pool_count_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, ifvi_pool_),                     "shadow$_ifvi_pool_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, iftable_count_),                 "shadow$_iftable_count_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, num_reference_instance_fields_), "shadow$_num_reference_instance_fields_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, num_reference_static_fields_),   "shadow$_num_reference_static_fields_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, object_size_),                   "shadow$_object_size_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, primitive_type_),                "shadow$_primitive_type_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, reference_instance_offsets_),    "shadow$_reference_instance_offsets_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, reference_static_offsets_),      "shadow$_reference_static_offsets_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, iftable_),                       "shadow$_iftable_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, source_file_),                   "shadow$_source_file_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, status_),                        "shadow$_status_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, clinit_thread_id_),              "shadow$_clinit_thread_id_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, super_class_type_idx_),          "shadow$_super_class_type_idx_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_size_),                    "shadow$_class_size_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, array_rank_),                    "shadow$_array_rank_"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Class, access_flags_),                  "shadow$_access_flags_"));
+    instance = true;
+    size = sizeof(Class);
+    class_descriptor = "Ljava/lang/Class;";
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, name_),                          "name"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_loader_),                  "shadow$_class_loader_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, component_type_),                "shadow$_component_type_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, descriptor_),                    "shadow$_descriptor_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, dex_cache_),                     "shadow$_dex_cache_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, direct_methods_),                "shadow$_direct_methods_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, ifields_),                       "shadow$_ifields_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, interfaces_),                    "shadow$_interfaces_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, interfaces_type_idx_),           "shadow$_interfaces_type_idx_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, sfields_),                       "shadow$_sfields_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, super_class_),                   "shadow$_super_class_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, verify_error_class_),            "shadow$_verify_error_class_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, virtual_methods_),               "shadow$_virtual_methods_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, vtable_),                        "shadow$_vtable_"));
+
+    // alphabetical 32-bit
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, access_flags_),                  "shadow$_access_flags_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, array_rank_),                    "shadow$_array_rank_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, class_size_),                    "shadow$_class_size_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, clinit_thread_id_),              "shadow$_clinit_thread_id_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, iftable_),                       "shadow$_iftable_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, iftable_count_),                 "shadow$_iftable_count_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, ifvi_pool_),                     "shadow$_ifvi_pool_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, ifvi_pool_count_),               "shadow$_ifvi_pool_count_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, num_reference_instance_fields_), "shadow$_num_reference_instance_fields_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, num_reference_static_fields_),   "shadow$_num_reference_static_fields_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, object_size_),                   "shadow$_object_size_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, primitive_type_),                "shadow$_primitive_type_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, reference_instance_offsets_),    "shadow$_reference_instance_offsets_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, reference_static_offsets_),      "shadow$_reference_static_offsets_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, source_file_),                   "shadow$_source_file_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, status_),                        "shadow$_status_"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, super_class_type_idx_),          "shadow$_super_class_type_idx_"));
   };
 };
 
 struct StringOffsets : public CheckOffsets {
   StringOffsets() {
-    s = sizeof(String);
-    c = "Ljava/lang/String;";
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(String, array_),     "value"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(String, hash_code_), "hashCode"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(String, offset_),    "offset"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(String, count_),     "count"));
+    instance = true;
+    size = sizeof(String);
+    class_descriptor = "Ljava/lang/String;";
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(String, array_),     "value"));
+
+    // alphabetical 32-bit
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(String, count_),     "count"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(String, hash_code_), "hashCode"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(String, offset_),    "offset"));
   };
 };
 
 struct ThrowableOffsets : public CheckOffsets {
   ThrowableOffsets() {
-    s = sizeof(Throwable);
-    c = "Ljava/lang/Throwable;";
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, cause_),                 "cause"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, detail_message_),        "detailMessage"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, stack_state_),           "stackState"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, stack_trace_),           "stackTrace"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, suppressed_exceptions_), "suppressedExceptions"));
+    instance = true;
+    size = sizeof(Throwable);
+    class_descriptor = "Ljava/lang/Throwable;";
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, cause_),                 "cause"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, detail_message_),        "detailMessage"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, stack_state_),           "stackState"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, stack_trace_),           "stackTrace"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, suppressed_exceptions_), "suppressedExceptions"));
   };
 };
 
 struct StackTraceElementOffsets : public CheckOffsets {
   StackTraceElementOffsets() {
-    s = sizeof(StackTraceElement);
-    c = "Ljava/lang/StackTraceElement;";
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, declaring_class_), "declaringClass"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, file_name_),       "fileName"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, method_name_),     "methodName"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, line_number_),     "lineNumber"));
+    instance = true;
+    size = sizeof(StackTraceElement);
+    class_descriptor = "Ljava/lang/StackTraceElement;";
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, declaring_class_), "declaringClass"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, file_name_),       "fileName"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, method_name_),     "methodName"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, line_number_),     "lineNumber"));
   };
 };
 
 struct ClassLoaderOffsets : public CheckOffsets {
   ClassLoaderOffsets() {
-    s = sizeof(ClassLoader);
-    c = "Ljava/lang/ClassLoader;";
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(ClassLoader, packages_), "packages"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(ClassLoader, parent_),   "parent"));
+    instance = true;
+    size = sizeof(ClassLoader);
+    class_descriptor = "Ljava/lang/ClassLoader;";
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(ClassLoader, packages_), "packages"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(ClassLoader, parent_),   "parent"));
   };
 };
 
 struct BaseDexClassLoaderOffsets : public CheckOffsets {
   BaseDexClassLoaderOffsets() {
-    s = sizeof(BaseDexClassLoader);
-    c = "Ldalvik/system/BaseDexClassLoader;";
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(BaseDexClassLoader, original_path_), "originalPath"));
-    o.push_back(CheckOffset(OFFSETOF_MEMBER(BaseDexClassLoader, path_list_),   "pathList"));
+    instance = true;
+    size = sizeof(BaseDexClassLoader);
+    class_descriptor = "Ldalvik/system/BaseDexClassLoader;";
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(BaseDexClassLoader, original_path_), "originalPath"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(BaseDexClassLoader, path_list_),     "pathList"));
   };
 };
 
 struct PathClassLoaderOffsets : public CheckOffsets {
   PathClassLoaderOffsets() {
-    s = sizeof(PathClassLoader);
-    c = "Ldalvik/system/PathClassLoader;";
+    instance = true;
+    size = sizeof(PathClassLoader);
+    class_descriptor = "Ldalvik/system/PathClassLoader;";
+  };
+};
+
+struct ClassClassOffsets : public CheckOffsets {
+  ClassClassOffsets() {
+    instance = false;
+    size = sizeof(ClassClass);
+    class_descriptor = "Ljava/lang/Class;";
+
+    // padding 32-bit
+    // this space intentionally left blank
+
+    // alphabetical 64-bit
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(ClassClass, serialVersionUID_), "serialVersionUID"));
+  };
+};
+
+struct StringClassOffsets : public CheckOffsets {
+  StringClassOffsets() {
+    instance = false;
+    size = sizeof(StringClass);
+    class_descriptor = "Ljava/lang/String;";
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StringClass, ASCII_),                  "ASCII"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StringClass, CASE_INSENSITIVE_ORDER_), "CASE_INSENSITIVE_ORDER"));
+
+    // padding 32-bit
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StringClass, REPLACEMENT_CHAR_),       "REPLACEMENT_CHAR"));
+
+    // alphabetical 64-bit
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StringClass, serialVersionUID_),       "serialVersionUID"));
+  };
+};
+
+struct FieldClassOffsets : public CheckOffsets {
+  FieldClassOffsets() {
+    instance = false;
+    size = sizeof(FieldClass);
+    class_descriptor = "Ljava/lang/reflect/Field;";
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, ORDER_BY_NAME_AND_DECLARING_CLASS_), "ORDER_BY_NAME_AND_DECLARING_CLASS"));
+
+    // alphabetical 32-bit
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_BOOLEAN_), "TYPE_BOOLEAN"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_BYTE_),    "TYPE_BYTE"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_CHAR_),    "TYPE_CHAR"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_DOUBLE_),  "TYPE_DOUBLE"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_FLOAT_),   "TYPE_FLOAT"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_INTEGER_), "TYPE_INTEGER"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_LONG_),    "TYPE_LONG"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(FieldClass, TYPE_SHORT_),   "TYPE_SHORT"));
+  };
+};
+
+struct MethodClassOffsets : public CheckOffsets {
+  MethodClassOffsets() {
+    instance = false;
+    size = sizeof(MethodClass);
+    class_descriptor = "Ljava/lang/reflect/Method;";
+
+    // alphabetical references
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(MethodClass, NO_ANNOTATIONS_),     "NO_ANNOTATIONS"));
+    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(MethodClass, ORDER_BY_SIGNATURE_), "ORDER_BY_SIGNATURE"));
   };
 };
 
@@ -631,6 +736,11 @@
   EXPECT_TRUE(ClassLoaderOffsets().Check());
   EXPECT_TRUE(BaseDexClassLoaderOffsets().Check());
   EXPECT_TRUE(PathClassLoaderOffsets().Check());
+
+  EXPECT_TRUE(ClassClassOffsets().Check());
+  EXPECT_TRUE(StringClassOffsets().Check());
+  EXPECT_TRUE(FieldClassOffsets().Check());
+  EXPECT_TRUE(MethodClassOffsets().Check());
 }
 
 // The first reference array element must be a multiple of 8 bytes from the
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index 4ce3177..9c9bcb0 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -263,6 +263,7 @@
     int frameSize;
     unsigned int coreSpillMask;
     unsigned int fpSpillMask;
+    unsigned int attrs;
     /*
      * CLEANUP/RESTRUCTURE: The code generation utilities don't have a built-in
      * mechanism to propogate the original Dalvik opcode address to the
diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc
index 4e3c9c4..cb208a5 100644
--- a/src/compiler/Dataflow.cc
+++ b/src/compiler/Dataflow.cc
@@ -1989,6 +1989,16 @@
         int dfAttributes =
             oatDataFlowAttributes[mir->dalvikInsn.opcode];
 
+        int flags = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode);
+
+        if (flags & kInstrCanThrow) {
+            cUnit->attrs &= ~METHOD_IS_THROW_FREE;
+        }
+
+        if (flags & kInstrInvoke) {
+            cUnit->attrs &= ~METHOD_IS_LEAF;
+        }
+
         int numUses = 0;
 
         if (dfAttributes & DF_FORMAT_35C) {
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 702611d..2f86c48 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -707,6 +707,9 @@
          0;
 #endif
 
+    /* Assume non-throwing leaf */
+    cUnit.attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
+
     /* Initialize the block list */
     oatInitGrowableList(&cUnit.blockList, 40);
 
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index cf1ad04..2319a71 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -1809,14 +1809,42 @@
         oatLockTemp(cUnit, r1);
         oatLockTemp(cUnit, r2);
         oatLockTemp(cUnit, r3);
+
+        /*
+         * We can safely skip the stack overflow check if we're
+         * a leaf *and* our frame size < fudge factor.
+         */
+        bool skipOverflowCheck = ((cUnit->attrs & METHOD_IS_LEAF) &&
+                                  ((size_t)cUnit->frameSize <
+                                  art::Thread::kStackOverflowReservedBytes));
         newLIR0(cUnit, kArmPseudoMethodEntry);
+        if (!skipOverflowCheck) {
+            /* Load stack limit */
+            loadWordDisp(cUnit, rSELF,
+                         art::Thread::StackEndOffset().Int32Value(), r12);
+        }
         /* Spill core callee saves */
         newLIR1(cUnit, kThumb2Push, cUnit->coreSpillMask);
         /* Need to spill any FP regs? */
         if (cUnit->numFPSpills) {
             newLIR1(cUnit, kThumb2VPushCS, cUnit->numFPSpills);
         }
-        opRegImm(cUnit, kOpSub, rSP, cUnit->frameSize - (cUnit->numSpills * 4));
+        if (!skipOverflowCheck) {
+            opRegRegImm(cUnit, kOpSub, rLR, rSP,
+                        cUnit->frameSize - (cUnit->numSpills * 4));
+            opRegReg(cUnit, kOpCmp, rLR, r12);   // Stack overflow?
+            /* Begin conditional skip */
+            genIT(cUnit, kArmCondCc, "TT"); // Carry clear; unsigned <
+            loadWordDisp(cUnit, rSELF,
+                         OFFSETOF_MEMBER(Thread, pStackOverflowFromCode), rLR);
+            newLIR2(cUnit, kThumbAddRI8, rSP, cUnit->numSpills * 4);
+            opReg(cUnit, kOpBlx, rLR);
+            /* End conditional skip */
+            genRegCopy(cUnit, rSP, rLR);         // Establish stack
+        } else {
+            opRegImm(cUnit, kOpSub, rSP,
+                     cUnit->frameSize - (cUnit->numSpills * 4));
+        }
         storeBaseDisp(cUnit, rSP, 0, r0, kWord);
         flushIns(cUnit);
         oatFreeTemp(cUnit, r0);
diff --git a/src/heap.cc b/src/heap.cc
index d80f437..7f6b106 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -186,7 +186,7 @@
       LOG(FATAL) << "Object is dead: " << obj;
     }
     // Ignore early dawn of the universe verifications
-    if(num_objects_allocated_ > 10) {
+    if (num_objects_allocated_ > 10) {
       const byte* raw_addr = reinterpret_cast<const byte*>(obj) +
           Object::ClassOffset().Int32Value();
       const Class* c = *reinterpret_cast<Class* const *>(raw_addr);
diff --git a/src/object.h b/src/object.h
index 72a03ba..bc9ec7e 100644
--- a/src/object.h
+++ b/src/object.h
@@ -597,10 +597,12 @@
 
   Object* generic_type_;
 
+  const String* name_;
+
   // Type of the field
   Class* type_;
 
-  const String* name_;
+  uint32_t generic_types_are_initialized_;
 
   uint32_t access_flags_;
 
@@ -612,8 +614,6 @@
 
   int32_t slot_;
 
-  uint32_t generic_types_are_initialized_;
-
   static Class* java_lang_reflect_Field_;
 
   friend struct FieldOffsets;  // for verifying offset information
@@ -1006,40 +1006,16 @@
   Object* java_generic_parameter_types_;
   Object* java_generic_return_type_;
 
-  // The method descriptor.  This represents the parameters a method
-  // takes and value it returns.  This string is a list of the type
-  // descriptors for the parameters enclosed in parenthesis followed
-  // by the return type descriptor.  For example, for the method
-  //
-  //   Object mymethod(int i, double d, Thread t)
-  //
-  // the method descriptor would be
-  //
-  //   (IDLjava/lang/Thread;)Ljava/lang/Object;
-  String* signature_;
-
   String* name_;
 
   ObjectArray<Class>* java_parameter_types_;
 
   Class* java_return_type_;  // Unused by ART
 
-  // Storage for mapping_table_
-  const ByteArray* mapping_table_;
-
-  // Storage for invoke_stub_
-  const ByteArray* invoke_stub_array_;
-
   // Storage for code_
   const ByteArray* code_array_;
 
   // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
-  ObjectArray<String>* dex_cache_strings_;
-
-  // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
-  ObjectArray<Class>* dex_cache_resolved_types_;
-
-  // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
   CodeAndDirectMethods* dex_cache_code_and_direct_methods_;
 
   // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
@@ -1051,13 +1027,46 @@
   // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
   ObjectArray<Method>* dex_cache_resolved_methods_;
 
-  // Architecture-dependent register spill mask
-  uint32_t core_spill_mask_;
+  // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
+  ObjectArray<Class>* dex_cache_resolved_types_;
+
+  // short cuts to declaring_class_->dex_cache_ member for fast compiled code access
+  ObjectArray<String>* dex_cache_strings_;
+
+  // Storage for invoke_stub_
+  const ByteArray* invoke_stub_array_;
+
+  // Storage for mapping_table_
+  const ByteArray* mapping_table_;
+
+  // The method descriptor.  This represents the parameters a method
+  // takes and value it returns.  This string is a list of the type
+  // descriptors for the parameters enclosed in parenthesis followed
+  // by the return type descriptor.  For example, for the method
+  //
+  //   Object mymethod(int i, double d, Thread t)
+  //
+  // the method descriptor would be
+  //
+  //   (IDLjava/lang/Thread;)Ljava/lang/Object;
+  String* signature_;
+
+  uint32_t java_generic_types_are_initialized_;
+
+  // access flags; low 16 bits are defined by spec (could be uint16_t?)
+  uint32_t access_flags_;
+
+  // Compiled code associated with this method for callers from managed code.
+  // May be compiled managed code or a bridge for invoking a native method.
+  const void* code_;
 
   // Offset to the CodeItem.
   uint32_t code_item_offset_;
 
   // Architecture-dependent register spill mask
+  uint32_t core_spill_mask_;
+
+  // Architecture-dependent register spill mask
   uint32_t fp_spill_mask_;
 
   // Total size in bytes of the frame
@@ -1066,16 +1075,9 @@
   // Native invocation stub entry point for calling from native to managed code.
   const InvokeStub* invoke_stub_;
 
-  // Compiled code associated with this method for callers from managed code.
-  // May be compiled managed code or a bridge for invoking a native method.
-  const void* code_;
-
   // Index of the return type
   uint32_t java_return_type_idx_;
 
-  // access flags; low 16 bits are defined by spec (could be uint16_t?)
-  uint32_t access_flags_;
-
   // For concrete virtual methods, this is the offset of the method
   // in Class::vtable_.
   //
@@ -1103,8 +1105,6 @@
   // The short-form method descriptor string. TODO: make String*
   const char* shorty_;
 
-  uint32_t java_generic_types_are_initialized_;
-
   uint32_t java_slot_;
 
   static Class* java_lang_reflect_Method_;
@@ -1549,7 +1549,7 @@
     if (this == klass) {
       // Can always assign to things of the same type
       return true;
-    } else if(IsObjectClass()) {
+    } else if (IsObjectClass()) {
       // Can assign any reference to java.lang.Object
       return !klass->IsPrimitive();
     } else if (IsInterface()) {
@@ -1988,25 +1988,8 @@
   // descriptor for the class such as "java.lang.Class" or "[C"
   String* name_;  // TODO initialize
 
-  // Virtual method table (vtable), for use by "invoke-virtual".  The
-  // vtable from the superclass is copied in, and virtual methods from
-  // our class either replace those from the super or are appended.
-  ObjectArray<Method>* vtable_;
-
-  // virtual methods defined in this class; invoked through vtable
-  ObjectArray<Method>* virtual_methods_;
-
   // defining class loader, or NULL for the "bootstrap" system loader
-  const ClassLoader* class_loader_;  // TODO: make an instance field
-
-  // If class verify fails, we must return same error on subsequent tries.
-  // Update with SetVerifyErrorClass to ensure a write barrier is used.
-  const Class* verify_error_class_;
-
-  // The superclass, or NULL if this is java.lang.Object or a
-  // primitive type.
-  // see also super_class_type_idx_;
-  Class* super_class_;
+  const ClassLoader* class_loader_;
 
   // For array classes, the class object for base element, for
   // instanceof/checkcast (for String[][][], this will be String).
@@ -2035,50 +2018,46 @@
   // specifies the number of reference fields.
   ObjectArray<Field>* ifields_;
 
-  // Static fields
-  ObjectArray<Field>* sfields_;
+  // array of interfaces this class implements directly
+  // see also interfaces_type_idx_
+  ObjectArray<Class>* interfaces_;
 
   // array of type_idx's for interfaces this class implements directly
   // see also interfaces_
   IntArray* interfaces_type_idx_;
 
-  // array of interfaces this class implements directly
-  // see also interfaces_type_idx_
-  ObjectArray<Class>* interfaces_;
+  // Static fields
+  ObjectArray<Field>* sfields_;
 
-  // size of ifvi_pool_
-  size_t ifvi_pool_count_;
+  // The superclass, or NULL if this is java.lang.Object or a
+  // primitive type.
+  // see also super_class_type_idx_;
+  Class* super_class_;
 
-  // The interface vtable indices for iftable get stored here.  By
-  // placing them all in a single pool for each class that implements
-  // interfaces, we decrease the number of allocations.
-  //
-  // see also ifvi_pool_count_
-  //
-  // TODO convert to IntArray
-  uint32_t* ifvi_pool_;
+  // If class verify fails, we must return same error on subsequent tries.
+  // Update with SetVerifyErrorClass to ensure a write barrier is used.
+  const Class* verify_error_class_;
 
-  // size of iftable_
-  size_t iftable_count_;
+  // virtual methods defined in this class; invoked through vtable
+  ObjectArray<Method>* virtual_methods_;
 
-  // number of instance fields that are object refs
-  size_t num_reference_instance_fields_;
+  // Virtual method table (vtable), for use by "invoke-virtual".  The
+  // vtable from the superclass is copied in, and virtual methods from
+  // our class either replace those from the super or are appended.
+  ObjectArray<Method>* vtable_;
 
-  // number of static fields that are object refs
-  size_t num_reference_static_fields_;
+  // access flags; low 16 bits are defined by VM spec
+  uint32_t access_flags_;
 
-  // Total object size; used when allocating storage on gc heap.
-  // (For interfaces and abstract classes this will be zero.)
-  size_t object_size_;
+  // For array classes, the number of array dimensions, e.g. int[][]
+  // is 2.  Otherwise 0.
+  int32_t array_rank_;
 
-  // primitive type index, or kPrimNot (0); set for generated prim classes
-  PrimitiveType primitive_type_;
+  // Total class size; used when allocating storage on gc heap.
+  size_t class_size_;
 
-  // Bitmap of offsets of ifields.
-  uint32_t reference_instance_offsets_;
-
-  // Bitmap of offsets of sfields.
-  uint32_t reference_static_offsets_;
+  // threadId, used to check for recursive <clinit> invocation
+  pid_t clinit_thread_id_;
 
   // Interface table (iftable_), one entry per interface supported by
   // this class.  That means one entry for each interface we support
@@ -2099,29 +2078,50 @@
   //
   InterfaceEntry* iftable_;
 
+  // size of iftable_
+  size_t iftable_count_;
+
+  // The interface vtable indices for iftable get stored here.  By
+  // placing them all in a single pool for each class that implements
+  // interfaces, we decrease the number of allocations.
+  //
+  // see also ifvi_pool_count_
+  //
+  // TODO convert to IntArray
+  uint32_t* ifvi_pool_;
+
+  // size of ifvi_pool_
+  size_t ifvi_pool_count_;
+
+  // number of instance fields that are object refs
+  size_t num_reference_instance_fields_;
+
+  // number of static fields that are object refs
+  size_t num_reference_static_fields_;
+
+  // Total object size; used when allocating storage on gc heap.
+  // (For interfaces and abstract classes this will be zero.)
+  size_t object_size_;
+
+  // primitive type index, or kPrimNot (0); set for generated prim classes
+  PrimitiveType primitive_type_;
+
+  // Bitmap of offsets of ifields.
+  uint32_t reference_instance_offsets_;
+
+  // Bitmap of offsets of sfields.
+  uint32_t reference_static_offsets_;
+
   // source file name, if known.  Otherwise, NULL.
   const char* source_file_;
 
   // state of class initialization
   Status status_;
 
-  // threadId, used to check for recursive <clinit> invocation
-  uint32_t clinit_thread_id_;
-
   // Set in LoadClass, used to LinkClass
   // see also super_class_
   uint32_t super_class_type_idx_;
 
-  // Total class size; used when allocating storage on gc heap.
-  size_t class_size_;
-
-  // For array classes, the number of array dimensions, e.g. int[][]
-  // is 2.  Otherwise 0.
-  int32_t array_rank_;
-
-  // access flags; low 16 bits are defined by VM spec
-  uint32_t access_flags_;
-
   // TODO: ?
   // initiating class loader list
   // NOTE: for classes with low serialNumber, these are unused, and the
@@ -2344,6 +2344,7 @@
   // Padding to ensure the 64-bit serialVersionUID_ begins on a 8-byte boundary
   int32_t padding_;
   int64_t serialVersionUID_;
+  friend struct ClassClassOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(ClassClass);
 };
 
@@ -2352,7 +2353,8 @@
   CharArray* ASCII_;
   Object* CASE_INSENSITIVE_ORDER_;
   uint32_t REPLACEMENT_CHAR_;
-  int64_t serialVersionUID;
+  int64_t serialVersionUID_;
+  friend struct StringClassOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(StringClass);
 };
 
@@ -2367,13 +2369,15 @@
   uint32_t TYPE_INTEGER_;
   uint32_t TYPE_LONG_;
   uint32_t TYPE_SHORT_;
+  friend struct FieldClassOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(FieldClass);
 };
 
 class MethodClass : public Class {
  private:
-  int32_t DECLARED_;
-  int32_t PUBLIC_;
+  ObjectArray<Object>* NO_ANNOTATIONS_;
+  Object* ORDER_BY_SIGNATURE_;
+  friend struct MethodClassOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(MethodClass);
 };
 
@@ -2528,12 +2532,12 @@
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   CharArray* array_;
 
+  int32_t count_;
+
   uint32_t hash_code_;
 
   int32_t offset_;
 
-  int32_t count_;
-
   static Class* java_lang_String_;
 
   friend struct StringOffsets;  // for verifying offset information
diff --git a/src/thread.cc b/src/thread.cc
index c771c5b..45ff6dd 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -136,6 +136,12 @@
      */
 }
 
+// TODO: placeholder
+static void StackOverflowFromCode(Method* method) {
+    //NOTE: to save code space, this handler needs to look up its own Thread*
+    UNIMPLEMENTED(FATAL) << "Stack overflow: " << PrettyMethod(method);
+}
+
 void Thread::InitFunctionPointers() {
 #if defined(__arm__)
   pShlLong = art_shl_long;
@@ -188,6 +194,7 @@
   pUnlockObjectFromCode = UnlockObjectFromCode;
   pFindFieldFromCode = Field::FindFieldFromCode;
   pCheckSuspendFromCode = CheckSuspendFromCode;
+  pStackOverflowFromCode = StackOverflowFromCode;
   pDebugMe = DebugMe;
 }
 
@@ -373,7 +380,6 @@
     PLOG(FATAL) << "pthread_getattr_np failed";
   }
 
-  // stack_base is the "lowest addressable byte" of the stack.
   void* stack_base;
   size_t stack_size;
   errno = pthread_attr_getstack(&attributes, &stack_base, &stack_size);
@@ -381,11 +387,18 @@
     PLOG(FATAL) << "pthread_attr_getstack failed";
   }
 
-  const size_t kStackOverflowReservedBytes = 1024; // Space to throw a StackOverflowError in.
   if (stack_size <= kStackOverflowReservedBytes) {
     LOG(FATAL) << "attempt to attach a thread with a too-small stack (" << stack_size << " bytes)";
   }
-  stack_hwm_ = reinterpret_cast<byte*>(stack_base) + stack_size - kStackOverflowReservedBytes;
+
+  // stack_base is the "lowest addressable byte" of the stack.
+  // Our stacks grow down, so we want stack_end_ to be near there, but reserving enough room
+  // to throw a StackOverflowError.
+  stack_end_ = reinterpret_cast<byte*>(stack_base) + kStackOverflowReservedBytes;
+
+  // Sanity check.
+  int stack_variable;
+  CHECK_GT(&stack_variable, (void*) stack_end_);
 
   errno = pthread_attr_destroy(&attributes);
   if (errno != 0) {
diff --git a/src/thread.h b/src/thread.h
index b9df711..9573458 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -166,6 +166,7 @@
     kTerminated,
   };
 
+  static const size_t kStackOverflowReservedBytes = 1024; // Space to throw a StackOverflowError in.
 
   static const size_t kDefaultStackSize = 64 * KB;
 
@@ -222,6 +223,7 @@
   StaticStorageBase* (*pInitializeStaticStorage)(uint32_t, const Method*);
   Field* (*pFindFieldFromCode)(uint32_t, const Method*);
   void (*pCheckSuspendFromCode)(Thread*);
+  void (*pStackOverflowFromCode)(Method*);
 
   class StackVisitor {
    public:
@@ -410,8 +412,8 @@
     return ThreadOffset(OFFSETOF_MEMBER(Thread, state_));
   }
 
-  static ThreadOffset StackHwmOffset() {
-    return ThreadOffset(OFFSETOF_MEMBER(Thread, stack_hwm_));
+  static ThreadOffset StackEndOffset() {
+    return ThreadOffset(OFFSETOF_MEMBER(Thread, stack_end_));
   }
 
   static ThreadOffset JniEnvOffset() {
@@ -475,8 +477,9 @@
   // FIXME: placeholder for the gc cardTable
   uint32_t card_table_;
 
-  // The high water mark for this thread's stack.
-  byte* stack_hwm_;
+  // The end of this thread's stack. This is the lowest safely-addressable address on the stack.
+  // We leave extra space so there's room for the code that throws StackOverflowError.
+  byte* stack_end_;
 
   // Top of the managed stack, written out prior to the state transition from
   // kRunnable to kNative. Uses include to give the starting point for scanning