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