Move rest of code related blobs from Method to oat
Change-Id: I55041b564ab65317c8b1f863005f20ba650a0322
diff --git a/build/Android.common.mk b/build/Android.common.mk
index ae713d0..605c48b 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -73,6 +73,7 @@
src/check_jni.cc \
src/class_linker.cc \
src/class_loader.cc \
+ src/compiled_method.cc \
src/compiler.cc \
src/compiler/Dataflow.cc \
src/compiler/Frontend.cc \
diff --git a/src/calling_convention.cc b/src/calling_convention.cc
index 17bfcff..5256ee1 100644
--- a/src/calling_convention.cc
+++ b/src/calling_convention.cc
@@ -17,7 +17,7 @@
// Managed runtime calling convention
ManagedRuntimeCallingConvention* ManagedRuntimeCallingConvention::Create(
- Method* native_method, InstructionSet instruction_set) {
+ const Method* native_method, InstructionSet instruction_set) {
if (instruction_set == kX86) {
return new x86::X86ManagedRuntimeCallingConvention(native_method);
} else {
@@ -67,7 +67,7 @@
// JNI calling convention
-JniCallingConvention* JniCallingConvention::Create(Method* native_method,
+JniCallingConvention* JniCallingConvention::Create(const Method* native_method,
InstructionSet instruction_set) {
if (instruction_set == kX86) {
return new x86::X86JniCallingConvention(native_method);
@@ -152,7 +152,7 @@
}
}
-size_t JniCallingConvention::NumberOfExtraArgumentsForJni(Method* method) {
+size_t JniCallingConvention::NumberOfExtraArgumentsForJni(const Method* method) {
// The first argument is the JNIEnv*.
// Static methods have an extra argument which is the jclass.
return method->IsStatic() ? 2 : 1;
diff --git a/src/calling_convention.h b/src/calling_convention.h
index b57fd4d..3a7cf1e 100644
--- a/src/calling_convention.h
+++ b/src/calling_convention.h
@@ -42,10 +42,10 @@
virtual ~CallingConvention() {}
protected:
- explicit CallingConvention(Method* method) : displacement_(0),
- method_(method) {}
+ explicit CallingConvention(const Method* method)
+ : displacement_(0), method_(const_cast<Method*>(method)) {}
- Method* GetMethod() const { return method_; }
+ const Method* GetMethod() const { return method_; }
// The slot number for current calling_convention argument.
// Note that each slot is 32-bit. When the current argument is bigger
@@ -74,8 +74,8 @@
// | { Method* } | <-- SP
class ManagedRuntimeCallingConvention : public CallingConvention {
public:
- static ManagedRuntimeCallingConvention* Create(Method* native_method,
- InstructionSet instruction_set);
+ static ManagedRuntimeCallingConvention* Create(const Method* native_method,
+ InstructionSet instruction_set);
size_t FrameSize();
@@ -97,7 +97,7 @@
virtual ~ManagedRuntimeCallingConvention() {}
protected:
- explicit ManagedRuntimeCallingConvention(Method* method) :
+ explicit ManagedRuntimeCallingConvention(const Method* method) :
CallingConvention(method) {}
};
@@ -117,7 +117,7 @@
// callee saves for frames above this one.
class JniCallingConvention : public CallingConvention {
public:
- static JniCallingConvention* Create(Method* native_method,
+ static JniCallingConvention* Create(const Method* native_method,
InstructionSet instruction_set);
// Size of frame excluding space for outgoing args (its assumed Method* is
@@ -186,7 +186,7 @@
kObjectOrClass = 1
};
- explicit JniCallingConvention(Method* native_method) :
+ explicit JniCallingConvention(const Method* native_method) :
CallingConvention(native_method) {}
// Number of stack slots for outgoing arguments, above which the SIRT is
@@ -194,7 +194,7 @@
virtual size_t NumberOfOutgoingStackArgs() = 0;
protected:
- static size_t NumberOfExtraArgumentsForJni(Method* method);
+ static size_t NumberOfExtraArgumentsForJni(const Method* method);
};
} // namespace art
diff --git a/src/calling_convention_arm.cc b/src/calling_convention_arm.cc
index e4f7b19f..29003a2 100644
--- a/src/calling_convention_arm.cc
+++ b/src/calling_convention_arm.cc
@@ -17,7 +17,7 @@
return ArmManagedRegister::FromCoreRegister(IP); // R12
}
-static ManagedRegister ReturnRegisterForMethod(Method* method) {
+static ManagedRegister ReturnRegisterForMethod(const Method* method) {
if (method->IsReturnAFloat()) {
return ArmManagedRegister::FromCoreRegister(R0);
} else if (method->IsReturnADouble()) {
@@ -99,7 +99,8 @@
// JNI calling convention
-ArmJniCallingConvention::ArmJniCallingConvention(Method* method) : JniCallingConvention(method) {
+ArmJniCallingConvention::ArmJniCallingConvention(const Method* method)
+ : JniCallingConvention(method) {
// Compute padding to ensure longs and doubles are not split in AAPCS
// TODO: in terms of outgoing argument size this may be overly generous
// due to padding appearing in the registers
@@ -159,7 +160,7 @@
// in even register numbers and stack slots
void ArmJniCallingConvention::Next() {
JniCallingConvention::Next();
- Method* method = GetMethod();
+ const Method* method = GetMethod();
size_t arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
if ((itr_args_ >= 2) &&
(arg_pos < GetMethod()->NumArgs()) &&
@@ -184,7 +185,7 @@
};
ManagedRegister ArmJniCallingConvention::CurrentParamRegister() {
CHECK_LT(itr_slots_, 4u);
- Method* method = GetMethod();
+ const Method* method = GetMethod();
int arg_pos = itr_args_ - NumberOfExtraArgumentsForJni(method);
if ((itr_args_ >= 2) && method->IsParamALongOrDouble(arg_pos)) {
CHECK_EQ(itr_slots_, 2u);
@@ -202,7 +203,7 @@
}
size_t ArmJniCallingConvention::NumberOfOutgoingStackArgs() {
- Method* method = GetMethod();
+ const Method* method = GetMethod();
size_t static_args = method->IsStatic() ? 1 : 0; // count jclass
// regular argument parameters and this
size_t param_args = method->NumArgs() +
diff --git a/src/calling_convention_arm.h b/src/calling_convention_arm.h
index 984250e..2a056a8 100644
--- a/src/calling_convention_arm.h
+++ b/src/calling_convention_arm.h
@@ -10,7 +10,7 @@
class ArmManagedRuntimeCallingConvention : public ManagedRuntimeCallingConvention {
public:
- explicit ArmManagedRuntimeCallingConvention(Method* method) :
+ explicit ArmManagedRuntimeCallingConvention(const Method* method) :
ManagedRuntimeCallingConvention(method) {}
virtual ~ArmManagedRuntimeCallingConvention() {}
// Calling convention
@@ -29,7 +29,7 @@
class ArmJniCallingConvention : public JniCallingConvention {
public:
- explicit ArmJniCallingConvention(Method* method);
+ explicit ArmJniCallingConvention(const Method* method);
virtual ~ArmJniCallingConvention() {}
// Calling convention
virtual ManagedRegister ReturnRegister();
diff --git a/src/calling_convention_x86.cc b/src/calling_convention_x86.cc
index ad7921d..da76e17 100644
--- a/src/calling_convention_x86.cc
+++ b/src/calling_convention_x86.cc
@@ -22,7 +22,7 @@
return ManagedRegister::NoRegister(); // No free regs, so assembler uses push/pop
}
-static ManagedRegister ReturnRegisterForMethod(Method* method) {
+static ManagedRegister ReturnRegisterForMethod(const Method* method) {
if (method->IsReturnAFloatOrDouble()) {
return X86ManagedRegister::FromX87Register(ST0);
} else if (method->IsReturnALong()) {
diff --git a/src/calling_convention_x86.h b/src/calling_convention_x86.h
index cb27ef6..b796ba0 100644
--- a/src/calling_convention_x86.h
+++ b/src/calling_convention_x86.h
@@ -10,7 +10,7 @@
class X86ManagedRuntimeCallingConvention : public ManagedRuntimeCallingConvention {
public:
- explicit X86ManagedRuntimeCallingConvention(Method* method) :
+ explicit X86ManagedRuntimeCallingConvention(const Method* method) :
ManagedRuntimeCallingConvention(method) {}
virtual ~X86ManagedRuntimeCallingConvention() {}
// Calling convention
@@ -29,7 +29,7 @@
class X86JniCallingConvention : public JniCallingConvention {
public:
- explicit X86JniCallingConvention(Method* method) :
+ explicit X86JniCallingConvention(const Method* method) :
JniCallingConvention(method) {}
virtual ~X86JniCallingConvention() {}
// Calling convention
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 1ec482a..2cbac12 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2034,13 +2034,13 @@
bool ClassLinker::LinkInstanceFields(Class* klass) {
CHECK(klass != NULL);
- return LinkFields(klass, true);
+ return LinkFields(klass, false);
}
bool ClassLinker::LinkStaticFields(Class* klass) {
CHECK(klass != NULL);
size_t allocated_class_size = klass->GetClassSize();
- bool success = LinkFields(klass, false);
+ bool success = LinkFields(klass, true);
CHECK_EQ(allocated_class_size, klass->GetClassSize());
return success;
}
@@ -2068,26 +2068,26 @@
}
};
-bool ClassLinker::LinkFields(Class* klass, bool instance) {
+bool ClassLinker::LinkFields(Class* klass, bool is_static) {
size_t num_fields =
- instance ? klass->NumInstanceFields() : klass->NumStaticFields();
+ is_static ? klass->NumStaticFields() : klass->NumInstanceFields();
ObjectArray<Field>* fields =
- instance ? klass->GetIFields() : klass->GetSFields();
+ is_static ? klass->GetSFields() : klass->GetIFields();
// Initialize size and field_offset
size_t size;
MemberOffset field_offset(0);
- if (instance) {
+ if (is_static) {
+ size = klass->GetClassSize();
+ field_offset = Class::FieldsOffset();
+ } else {
Class* super_class = klass->GetSuperClass();
if (super_class != NULL) {
CHECK(super_class->IsResolved());
field_offset = MemberOffset(super_class->GetObjectSize());
}
size = field_offset.Uint32Value();
- } else {
- size = klass->GetClassSize();
- field_offset = Class::FieldsOffset();
}
CHECK_EQ(num_fields == 0, fields == NULL);
@@ -2161,7 +2161,7 @@
}
// We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it.
- if (instance && klass->GetDescriptor()->Equals("Ljava/lang/ref/Reference;")) {
+ if (!is_static && klass->GetDescriptor()->Equals("Ljava/lang/ref/Reference;")) {
// We know there are no non-reference fields in the Reference classes, and we know
// that 'referent' is alphabetically last, so this is easy...
CHECK_EQ(num_reference_fields, num_fields);
@@ -2176,7 +2176,7 @@
for (size_t i = 0; i < num_fields; i++) {
Field* field = fields->Get(i);
if (false) { // enable to debug field layout
- LOG(INFO) << "LinkFields: " << (instance ? "instance" : "static")
+ LOG(INFO) << "LinkFields: " << (is_static ? "static" : "instance")
<< " class=" << PrettyClass(klass)
<< " field=" << PrettyField(field)
<< " offset=" << field->GetField32(MemberOffset(Field::OffsetOffset()), false);
@@ -2201,14 +2201,14 @@
#endif
size = field_offset.Uint32Value();
// Update klass
- if (instance) {
+ if (is_static) {
+ klass->SetNumReferenceStaticFields(num_reference_fields);
+ klass->SetClassSize(size);
+ } else {
klass->SetNumReferenceInstanceFields(num_reference_fields);
if (!klass->IsVariableSize()) {
klass->SetObjectSize(size);
}
- } else {
- klass->SetNumReferenceStaticFields(num_reference_fields);
- klass->SetClassSize(size);
}
return true;
}
@@ -2226,20 +2226,20 @@
return;
}
}
- CreateReferenceOffsets(klass, true, reference_offsets);
+ CreateReferenceOffsets(klass, false, reference_offsets);
}
void ClassLinker::CreateReferenceStaticOffsets(Class* klass) {
- CreateReferenceOffsets(klass, false, 0);
+ CreateReferenceOffsets(klass, true, 0);
}
-void ClassLinker::CreateReferenceOffsets(Class* klass, bool instance,
+void ClassLinker::CreateReferenceOffsets(Class* klass, bool is_static,
uint32_t reference_offsets) {
size_t num_reference_fields =
- instance ? klass->NumReferenceInstanceFieldsDuringLinking()
- : klass->NumReferenceStaticFieldsDuringLinking();
+ is_static ? klass->NumReferenceStaticFieldsDuringLinking()
+ : klass->NumReferenceInstanceFieldsDuringLinking();
const ObjectArray<Field>* fields =
- instance ? klass->GetIFields() : klass->GetSFields();
+ is_static ? klass->GetSFields() : klass->GetIFields();
// All of the fields that contain object references are guaranteed
// to be at the beginning of the fields list.
for (size_t i = 0; i < num_reference_fields; ++i) {
@@ -2258,10 +2258,10 @@
}
}
// Update fields in klass
- if (instance) {
- klass->SetReferenceInstanceOffsets(reference_offsets);
- } else {
+ if (is_static) {
klass->SetReferenceStaticOffsets(reference_offsets);
+ } else {
+ klass->SetReferenceInstanceOffsets(reference_offsets);
}
}
diff --git a/src/class_linker.h b/src/class_linker.h
index 304d37f..6d17a10 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -291,12 +291,12 @@
bool LinkStaticFields(Class* klass);
bool LinkInstanceFields(Class* klass);
- bool LinkFields(Class *klass, bool instance);
+ bool LinkFields(Class *klass, bool is_static);
void CreateReferenceInstanceOffsets(Class* klass);
void CreateReferenceStaticOffsets(Class* klass);
- void CreateReferenceOffsets(Class *klass, bool instance,
+ void CreateReferenceOffsets(Class *klass, bool is_static,
uint32_t reference_offsets);
// For use by ImageWriter to find DexCaches for its roots
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 9ae64a3..025f9e3 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -304,7 +304,9 @@
template <typename T>
struct CheckOffsets {
- bool instance;
+ CheckOffsets(bool is_static, const char* class_descriptor)
+ : is_static(is_static), class_descriptor(class_descriptor) {}
+ bool is_static;
std::string class_descriptor;
std::vector<CheckOffset> offsets;
@@ -314,8 +316,8 @@
bool error = false;
- if (!klass->IsClassClass() && instance) {
- size_t expected_size = instance ? klass->GetObjectSize() : klass->GetClassSize();
+ if (!klass->IsClassClass() && !is_static) {
+ size_t expected_size = is_static ? klass->GetClassSize(): klass->GetObjectSize();
if (sizeof(T) != expected_size) {
LG << "Class size mismatch:"
<< " class=" << class_descriptor
@@ -325,7 +327,7 @@
}
}
- size_t num_fields = instance ? klass->NumInstanceFields() : klass->NumStaticFields();
+ size_t num_fields = is_static ? klass->NumStaticFields() : klass->NumInstanceFields();
if (offsets.size() != num_fields) {
LG << "Field count mismatch:"
<< " class=" << class_descriptor
@@ -335,7 +337,7 @@
}
for (size_t i = 0; i < offsets.size(); i++) {
- Field* field = instance ? klass->GetInstanceField(i) : klass->GetStaticField(i);
+ Field* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i);
if (!field->GetName()->Equals(offsets[i].java_name)) {
error = true;
}
@@ -343,7 +345,7 @@
if (error) {
for (size_t i = 0; i < offsets.size(); i++) {
CheckOffset& offset = offsets[i];
- Field* field = instance ? klass->GetInstanceField(i) : klass->GetStaticField(i);
+ Field* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i);
if (!field->GetName()->Equals(offsets[i].java_name)) {
LG << "JAVA FIELD ORDER MISMATCH NEXT LINE:";
}
@@ -356,7 +358,7 @@
for (size_t i = 0; i < offsets.size(); i++) {
CheckOffset& offset = offsets[i];
- Field* field = instance ? klass->GetInstanceField(i) : klass->GetStaticField(i);
+ Field* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i);
if (field->GetOffset().Uint32Value() != offset.cpp_offset) {
error = true;
}
@@ -364,7 +366,7 @@
if (error) {
for (size_t i = 0; i < offsets.size(); i++) {
CheckOffset& offset = offsets[i];
- Field* field = instance ? klass->GetInstanceField(i) : klass->GetStaticField(i);
+ Field* field = is_static ? klass->GetStaticField(i) : klass->GetInstanceField(i);
if (field->GetOffset().Uint32Value() != offset.cpp_offset) {
LG << "OFFSET MISMATCH NEXT LINE:";
}
@@ -375,15 +377,16 @@
return !error;
};
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CheckOffsets);
};
// Note that ClassLinkerTest.ValidateFieldOrderOfJavaCppUnionClasses
// is first since if it is failing, others are unlikely to succeed.
struct ObjectOffsets : public CheckOffsets<Object> {
- ObjectOffsets() {
- instance = true;
- class_descriptor = "Ljava/lang/Object;";
+ ObjectOffsets() : CheckOffsets<Object>(false, "Ljava/lang/Object;") {
// alphabetical references
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Object, klass_), "shadow$_klass_"));
@@ -394,17 +397,14 @@
};
struct AccessibleObjectOffsets : public CheckOffsets<AccessibleObject> {
- AccessibleObjectOffsets() {
- instance = true;
- class_descriptor = "Ljava/lang/reflect/AccessibleObject;";
+ AccessibleObjectOffsets()
+ : CheckOffsets<AccessibleObject>(false, "Ljava/lang/reflect/AccessibleObject;") {
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(AccessibleObject, java_flag_), "flag"));
};
};
struct FieldOffsets : public CheckOffsets<Field> {
- FieldOffsets() {
- instance = true;
- class_descriptor = "Ljava/lang/reflect/Field;";
+ FieldOffsets() : CheckOffsets<Field>(false, "Ljava/lang/reflect/Field;") {
// alphabetical references
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Field, declaring_class_), "declaringClass"));
@@ -422,9 +422,7 @@
};
struct MethodOffsets : public CheckOffsets<Method> {
- MethodOffsets() {
- instance = true;
- class_descriptor = "Ljava/lang/reflect/Method;";
+ MethodOffsets() : CheckOffsets<Method>(false, "Ljava/lang/reflect/Method;") {
// alphabetical references
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, declaring_class_), "declaringClass"));
@@ -436,20 +434,16 @@
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, register_map_data_), "shadow$_register_map_data_"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, register_map_header_), "shadow$_register_map_header_"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, shorty_), "shadow$_shorty_"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, signature_), "shadow$_signature_"));
- offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, vmap_table_), "shadow$_vmap_table_"));
// alphabetical 32-bit
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_generic_types_are_initialized_), "genericTypesAreInitialized"));
@@ -461,6 +455,7 @@
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, mapping_table_), "shadow$_mapping_table_"));
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_"));
@@ -468,6 +463,7 @@
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, vmap_table_), "shadow$_vmap_table_"));
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Method, java_slot_), "slot"));
};
};
@@ -480,9 +476,7 @@
};
struct ClassOffsets : public CheckOffsets<Class> {
- ClassOffsets() {
- instance = true;
- class_descriptor = "Ljava/lang/Class;";
+ ClassOffsets() : CheckOffsets<Class>(false, "Ljava/lang/Class;") {
// alphabetical references
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Class, name_), "name"));
@@ -518,9 +512,7 @@
};
struct StringOffsets : public CheckOffsets<String> {
- StringOffsets() {
- instance = true;
- class_descriptor = "Ljava/lang/String;";
+ StringOffsets() : CheckOffsets<String>(false, "Ljava/lang/String;") {
// alphabetical references
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(String, array_), "value"));
@@ -533,9 +525,7 @@
};
struct ThrowableOffsets : public CheckOffsets<Throwable> {
- ThrowableOffsets() {
- instance = true;
- class_descriptor = "Ljava/lang/Throwable;";
+ ThrowableOffsets() : CheckOffsets<Throwable>(false, "Ljava/lang/Throwable;") {
// alphabetical references
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(Throwable, cause_), "cause"));
@@ -547,9 +537,7 @@
};
struct StackTraceElementOffsets : public CheckOffsets<StackTraceElement> {
- StackTraceElementOffsets() {
- instance = true;
- class_descriptor = "Ljava/lang/StackTraceElement;";
+ StackTraceElementOffsets() : CheckOffsets<StackTraceElement>(false, "Ljava/lang/StackTraceElement;") {
// alphabetical references
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StackTraceElement, declaring_class_), "declaringClass"));
@@ -560,9 +548,7 @@
};
struct ClassLoaderOffsets : public CheckOffsets<ClassLoader> {
- ClassLoaderOffsets() {
- instance = true;
- class_descriptor = "Ljava/lang/ClassLoader;";
+ ClassLoaderOffsets() : CheckOffsets<ClassLoader>(false, "Ljava/lang/ClassLoader;") {
// alphabetical references
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(ClassLoader, packages_), "packages"));
@@ -571,9 +557,8 @@
};
struct BaseDexClassLoaderOffsets : public CheckOffsets<BaseDexClassLoader> {
- BaseDexClassLoaderOffsets() {
- instance = true;
- class_descriptor = "Ldalvik/system/BaseDexClassLoader;";
+ BaseDexClassLoaderOffsets()
+ : CheckOffsets<BaseDexClassLoader>(false, "Ldalvik/system/BaseDexClassLoader;") {
// alphabetical references
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(BaseDexClassLoader, original_path_), "originalPath"));
@@ -582,16 +567,12 @@
};
struct PathClassLoaderOffsets : public CheckOffsets<PathClassLoader> {
- PathClassLoaderOffsets() {
- instance = true;
- class_descriptor = "Ldalvik/system/PathClassLoader;";
- };
+ PathClassLoaderOffsets()
+ : CheckOffsets<PathClassLoader>(false, "Ldalvik/system/PathClassLoader;") {};
};
struct ClassClassOffsets : public CheckOffsets<ClassClass> {
- ClassClassOffsets() {
- instance = false;
- class_descriptor = "Ljava/lang/Class;";
+ ClassClassOffsets() : CheckOffsets<ClassClass>(true, "Ljava/lang/Class;") {
// padding 32-bit
CHECK_EQ(OFFSETOF_MEMBER(ClassClass, padding_) + 4,
@@ -603,9 +584,7 @@
};
struct StringClassOffsets : public CheckOffsets<StringClass> {
- StringClassOffsets() {
- instance = false;
- class_descriptor = "Ljava/lang/String;";
+ StringClassOffsets() : CheckOffsets<StringClass>(true, "Ljava/lang/String;") {
// alphabetical references
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(StringClass, ASCII_), "ASCII"));
@@ -620,9 +599,7 @@
};
struct FieldClassOffsets : public CheckOffsets<FieldClass> {
- FieldClassOffsets() {
- instance = false;
- class_descriptor = "Ljava/lang/reflect/Field;";
+ FieldClassOffsets() : CheckOffsets<FieldClass>(true, "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"));
@@ -640,9 +617,7 @@
};
struct MethodClassOffsets : public CheckOffsets<MethodClass> {
- MethodClassOffsets() {
- instance = false;
- class_descriptor = "Ljava/lang/reflect/Method;";
+ MethodClassOffsets() : CheckOffsets<MethodClass>(true, "Ljava/lang/reflect/Method;") {
// alphabetical references
offsets.push_back(CheckOffset(OFFSETOF_MEMBER(MethodClass, ORDER_BY_SIGNATURE_), "ORDER_BY_SIGNATURE"));
diff --git a/src/common_test.h b/src/common_test.h
index 84b97e9..1039ff1 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -16,6 +16,7 @@
#include "file.h"
#include "gtest/gtest.h"
#include "heap.h"
+#include "oat_file.h"
#include "os.h"
#include "runtime.h"
#include "stl_util.h"
@@ -79,10 +80,68 @@
class CommonTest : public testing::Test {
public:
- static void MakeExecutable(const ByteArray* byte_array) {
- uintptr_t data = reinterpret_cast<uintptr_t>(byte_array->GetData());
+
+ static void MakeExecutable(const ByteArray* code_array) {
+ CHECK(code_array != NULL);
+ MakeExecutable(code_array->GetData(), code_array->GetLength());
+ }
+
+ static void MakeExecutable(const std::vector<uint8_t>& code) {
+ CHECK_NE(code.size(), 0U);
+ MakeExecutable(&code[0], code.size());
+ }
+
+ void MakeExecutable(Method* method) {
+ CHECK(method != NULL);
+
+ const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
+ CHECK(compiled_invoke_stub != NULL) << PrettyMethod(method);
+ const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
+ MakeExecutable(invoke_stub);
+ const Method::InvokeStub* method_invoke_stub
+ = reinterpret_cast<const Method::InvokeStub*>(&invoke_stub[0]);
+ LOG(INFO) << "MakeExecutable " << PrettyMethod(method)
+ << " invoke_stub=" << reinterpret_cast<void*>(method_invoke_stub);
+
+ if (!method->IsAbstract()) {
+ const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
+ CHECK(compiled_method != NULL) << PrettyMethod(method);
+ const std::vector<uint8_t>& code = compiled_method->GetCode();
+ MakeExecutable(code);
+ const void* method_code
+ = CompiledMethod::CodePointer(&code[0], compiled_method->GetInstructionSet());
+ LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
+ OatFile::OatMethod oat_method(method_code,
+ compiled_method->GetFrameSizeInBytes(),
+ compiled_method->GetReturnPcOffsetInBytes(),
+ compiled_method->GetCoreSpillMask(),
+ compiled_method->GetFpSpillMask(),
+ &compiled_method->GetMappingTable()[0],
+ &compiled_method->GetVmapTable()[0],
+ method_invoke_stub);
+ oat_method.LinkMethod(method);
+ } else {
+ MakeExecutable(runtime_->GetAbstractMethodErrorStubArray());
+ const void* method_code = runtime_->GetAbstractMethodErrorStubArray()->GetData();
+ LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
+ OatFile::OatMethod oat_method(method_code,
+ kStackAlignment,
+ 0,
+ 0,
+ 0,
+ NULL,
+ NULL,
+ method_invoke_stub);
+ oat_method.LinkMethod(method);
+ }
+ }
+
+ static void MakeExecutable(const void* code_start, size_t code_length) {
+ CHECK(code_start != NULL);
+ CHECK_NE(code_length, 0U);
+ uintptr_t data = reinterpret_cast<uintptr_t>(code_start);
uintptr_t base = RoundDown(data, kPageSize);
- uintptr_t limit = RoundUp(data + byte_array->GetLength(), kPageSize);
+ uintptr_t limit = RoundUp(data + code_length, kPageSize);
uintptr_t len = limit - base;
int result = mprotect(reinterpret_cast<void*>(base), len, PROT_READ | PROT_WRITE | PROT_EXEC);
CHECK_EQ(result, 0);
@@ -274,9 +333,9 @@
void CompileMethod(Method* method) {
CHECK(method != NULL);
compiler_->CompileOne(method);
+ MakeExecutable(method);
+
MakeExecutable(runtime_->GetJniStubArray());
- MakeExecutable(method->GetCodeArray());
- MakeExecutable(method->GetInvokeStubArray());
}
void CompileDirectMethod(const ClassLoader* class_loader,
diff --git a/src/compiled_method.cc b/src/compiled_method.cc
new file mode 100644
index 0000000..2846ab3
--- /dev/null
+++ b/src/compiled_method.cc
@@ -0,0 +1,157 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#include "compiled_method.h"
+
+namespace art {
+
+CompiledMethod::CompiledMethod(InstructionSet instruction_set,
+ std::vector<short>& short_code,
+ const size_t frame_size_in_bytes,
+ const size_t return_pc_offset_in_bytes,
+ const uint32_t core_spill_mask,
+ const uint32_t fp_spill_mask,
+ std::vector<uint32_t>& mapping_table,
+ std::vector<uint16_t>& vmap_table) {
+ CHECK_NE(short_code.size(), 0U);
+
+ size_t code_byte_count = short_code.size() * sizeof(short_code[0]);
+ std::vector<uint8_t> byte_code(code_byte_count);
+ memcpy(&byte_code[0], &short_code[0], code_byte_count);
+
+ std::vector<uint32_t> length_prefixed_mapping_table;
+ length_prefixed_mapping_table.push_back(mapping_table.size());
+ length_prefixed_mapping_table.insert(length_prefixed_mapping_table.end(),
+ mapping_table.begin(),
+ mapping_table.end());
+ DCHECK_EQ(mapping_table.size() + 1, length_prefixed_mapping_table.size());
+
+ std::vector<uint16_t> length_prefixed_vmap_table;
+ length_prefixed_vmap_table.push_back(vmap_table.size());
+ length_prefixed_vmap_table.insert(length_prefixed_vmap_table.end(),
+ vmap_table.begin(),
+ vmap_table.end());
+ DCHECK_EQ(vmap_table.size() + 1, length_prefixed_vmap_table.size());
+
+ instruction_set_ = instruction_set;
+ code_ = byte_code;
+ frame_size_in_bytes_ = frame_size_in_bytes;
+ return_pc_offset_in_bytes_ = return_pc_offset_in_bytes;
+ core_spill_mask_ = core_spill_mask;
+ fp_spill_mask_ = fp_spill_mask;
+ mapping_table_ = length_prefixed_mapping_table;
+ vmap_table_ = length_prefixed_vmap_table;
+}
+
+CompiledMethod::CompiledMethod(InstructionSet instruction_set,
+ std::vector<uint8_t>& code,
+ const size_t frame_size_in_bytes,
+ const size_t return_pc_offset_in_bytes,
+ const uint32_t core_spill_mask,
+ const uint32_t fp_spill_mask) {
+ CHECK_NE(code.size(), 0U);
+
+ instruction_set_ = instruction_set;
+ code_ = code;
+ frame_size_in_bytes_ = frame_size_in_bytes;
+ return_pc_offset_in_bytes_ = return_pc_offset_in_bytes;
+ core_spill_mask_ = core_spill_mask;
+ fp_spill_mask_ = fp_spill_mask;
+}
+
+CompiledMethod::~CompiledMethod() {}
+
+InstructionSet CompiledMethod::GetInstructionSet() const {
+ return instruction_set_;
+}
+
+const std::vector<uint8_t>& CompiledMethod::GetCode() const {
+ return code_;
+}
+
+size_t CompiledMethod::GetFrameSizeInBytes() const {
+ return frame_size_in_bytes_;
+}
+
+size_t CompiledMethod::GetReturnPcOffsetInBytes() const {
+ return return_pc_offset_in_bytes_;
+}
+
+uint32_t CompiledMethod::GetCoreSpillMask() const {
+ return core_spill_mask_;
+}
+
+uint32_t CompiledMethod::GetFpSpillMask() const {
+ return fp_spill_mask_;
+}
+
+const std::vector<uint32_t>& CompiledMethod::GetMappingTable() const {
+ return mapping_table_;
+}
+
+const std::vector<uint16_t>& CompiledMethod::GetVmapTable() const {
+ return vmap_table_;
+}
+
+uint32_t CompiledMethod::AlignCode(uint32_t offset) const {
+ return AlignCode(offset, instruction_set_);
+}
+
+uint32_t CompiledMethod::AlignCode(uint32_t offset, InstructionSet instruction_set) {
+ switch (instruction_set) {
+ case kArm:
+ case kThumb2:
+ return RoundUp(offset, kArmAlignment);
+ case kX86:
+ return offset;
+ default:
+ LOG(FATAL) << "Unknown InstructionSet " << (int) instruction_set;
+ return 0;
+ }
+}
+
+size_t CompiledMethod::CodeDelta() const {
+ switch (instruction_set_) {
+ case kArm:
+ case kX86:
+ return 0;
+ case kThumb2: {
+ // +1 to set the low-order bit so a BLX will switch to Thumb mode
+ return 1;
+ }
+ default:
+ LOG(FATAL) << "Unknown InstructionSet " << (int) instruction_set_;
+ return NULL;
+ }
+}
+
+const void* CompiledMethod::CodePointer(const void* code_pointer,
+ InstructionSet instruction_set) {
+ switch (instruction_set) {
+ case kArm:
+ case kX86:
+ return code_pointer;
+ case kThumb2: {
+ uintptr_t address = reinterpret_cast<uintptr_t>(code_pointer);
+ // Set the low-order bit so a BLX will switch to Thumb mode
+ address |= 0x1;
+ return reinterpret_cast<const void*>(address);
+ }
+ default:
+ LOG(FATAL) << "Unknown InstructionSet " << (int) instruction_set;
+ return NULL;
+ }
+}
+
+
+CompiledInvokeStub::CompiledInvokeStub(std::vector<uint8_t>& code) {
+ CHECK_NE(code.size(), 0U);
+ code_ = code;
+}
+
+CompiledInvokeStub::~CompiledInvokeStub() {}
+
+const std::vector<uint8_t>& CompiledInvokeStub::GetCode() const {
+ return code_;
+}
+
+} // namespace art
diff --git a/src/compiled_method.h b/src/compiled_method.h
new file mode 100644
index 0000000..e228ca8
--- /dev/null
+++ b/src/compiled_method.h
@@ -0,0 +1,83 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+
+#ifndef ART_SRC_COMPILED_METHOD_H_
+#define ART_SRC_COMPILED_METHOD_H_
+
+#include <vector>
+
+#include "constants.h"
+#include "utils.h"
+
+namespace art {
+
+class CompiledMethod {
+ public:
+ // Create an CompiledMethod from the oatCompileMethod
+ CompiledMethod(InstructionSet instruction_set,
+ std::vector<short>& code,
+ const size_t frame_size_in_bytes,
+ const size_t return_pc_offset_in_bytes,
+ const uint32_t core_spill_mask,
+ const uint32_t fp_spill_mask,
+ std::vector<uint32_t>& mapping_table,
+ std::vector<uint16_t>& vmap_table);
+
+ // Create an CompiledMethod from the JniCompiler
+ CompiledMethod(InstructionSet instruction_set,
+ std::vector<uint8_t>& code,
+ const size_t frame_size_in_bytes,
+ const size_t return_pc_offset_in_bytes,
+ const uint32_t core_spill_mask,
+ const uint32_t fp_spill_mask);
+
+ ~CompiledMethod();
+
+ InstructionSet GetInstructionSet() const;
+ const std::vector<uint8_t>& GetCode() const;
+ size_t GetFrameSizeInBytes() const;
+ size_t GetReturnPcOffsetInBytes() const;
+ uint32_t GetCoreSpillMask() const;
+ uint32_t GetFpSpillMask() const;
+ const std::vector<uint32_t>& GetMappingTable() const;
+ const std::vector<uint16_t>& GetVmapTable() const;
+
+ // Aligns an offset from a page aligned value to make it suitable
+ // for code storage. important to ensure that PC relative value
+ // computations work out as expected on ARM.
+ uint32_t AlignCode(uint32_t offset) const;
+ static uint32_t AlignCode(uint32_t offset, InstructionSet instruction_set);
+
+ // returns the difference between the code address and a usable PC.
+ // mainly to cope with kThumb2 where the lower bit must be set.
+ size_t CodeDelta() const;
+
+ // Returns a pointer suitable for invoking the code at the argument
+ // code_pointer address. Mainly to cope with kThumb2 where the
+ // lower bit must be set to indicate Thumb mode.
+ static const void* CodePointer(const void* code_pointer,
+ InstructionSet instruction_set);
+
+ private:
+ InstructionSet instruction_set_;
+ std::vector<uint8_t> code_;
+ size_t frame_size_in_bytes_;
+ size_t return_pc_offset_in_bytes_;
+ uint32_t core_spill_mask_;
+ uint32_t fp_spill_mask_;
+ std::vector<uint32_t> mapping_table_;
+ std::vector<uint16_t> vmap_table_;
+};
+
+class CompiledInvokeStub {
+ public:
+ CompiledInvokeStub(std::vector<uint8_t>& code);
+ ~CompiledInvokeStub();
+ const std::vector<uint8_t>& GetCode() const;
+ private:
+ std::vector<uint8_t> code_;
+};
+
+} // namespace art
+
+#endif // ART_SRC_COMPILED_METHOD_H_
+
diff --git a/src/compiler.cc b/src/compiler.cc
index 3b92267..3b98ea0 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -10,28 +10,37 @@
#include "dex_cache.h"
#include "jni_compiler.h"
#include "jni_internal.h"
+#include "oat_file.h"
#include "runtime.h"
+#include "stl_util.h"
-extern bool oatCompileMethod(const art::Compiler& compiler, art::Method*, art::InstructionSet);
+extern art::CompiledMethod* oatCompileMethod(const art::Compiler& compiler,
+ const art::Method*,
+ art::InstructionSet);
namespace art {
namespace arm {
ByteArray* CreateAbstractMethodErrorStub();
- void ArmCreateInvokeStub(Method* method);
+ CompiledInvokeStub* ArmCreateInvokeStub(const Method* method);
ByteArray* ArmCreateResolutionTrampoline(Runtime::TrampolineType type);
}
namespace x86 {
ByteArray* CreateAbstractMethodErrorStub();
- void X86CreateInvokeStub(Method* method);
+ CompiledInvokeStub* X86CreateInvokeStub(const Method* method);
ByteArray* X86CreateResolutionTrampoline(Runtime::TrampolineType type);
}
-Compiler::Compiler(InstructionSet insns) : instruction_set_(insns), jni_compiler_(insns),
- verbose_(false) {
+Compiler::Compiler(InstructionSet instruction_set)
+ : instruction_set_(instruction_set), jni_compiler_(instruction_set), verbose_(false) {
CHECK(!Runtime::Current()->IsStarted());
}
+Compiler::~Compiler() {
+ STLDeleteValues(&compiled_methods_);
+ STLDeleteValues(&compiled_invoke_stubs_);
+}
+
ByteArray* Compiler::CreateResolutionStub(InstructionSet instruction_set,
Runtime::TrampolineType type) {
if (instruction_set == kX86) {
@@ -62,7 +71,7 @@
SetCodeAndDirectMethods(class_loader);
}
-void Compiler::CompileOne(Method* method) {
+void Compiler::CompileOne(const Method* method) {
DCHECK(!Runtime::Current()->IsStarted());
const ClassLoader* class_loader = method->GetDeclaringClass()->GetClassLoader();
Resolve(class_loader);
@@ -276,7 +285,7 @@
}
}
-void Compiler::CompileClass(Class* klass) {
+void Compiler::CompileClass(const Class* klass) {
for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
CompileMethod(klass->GetDirectMethod(i));
}
@@ -285,35 +294,50 @@
}
}
-void Compiler::CompileMethod(Method* method) {
+void Compiler::CompileMethod(const Method* method) {
if (method->IsNative()) {
- jni_compiler_.Compile(method);
- // unregister will install the stub to lookup via dlsym
- // TODO: this is only necessary for tests
- if (!method->IsRegistered()) {
- method->UnregisterNative();
- }
+ CompiledMethod* compiled_method = jni_compiler_.Compile(method);
+ CHECK(compiled_method != NULL);
+ compiled_methods_[method] = compiled_method;
+ DCHECK_EQ(1U, compiled_methods_.count(method));
+ DCHECK(GetCompiledMethod(method) != NULL) << PrettyMethod(method);
} else if (method->IsAbstract()) {
- ByteArray* abstract_method_error_stub = Runtime::Current()->GetAbstractMethodErrorStubArray();
- if (instruction_set_ == kX86) {
- method->SetCodeArray(abstract_method_error_stub, kX86);
- } else {
- CHECK(instruction_set_ == kArm || instruction_set_ == kThumb2);
- method->SetCodeArray(abstract_method_error_stub, kArm);
- }
} else {
- oatCompileMethod(*this, method, kThumb2);
+ CompiledMethod* compiled_method = oatCompileMethod(*this, method, kThumb2);
+ CHECK(compiled_method != NULL);
+ compiled_methods_[method] = compiled_method;
+ DCHECK_EQ(1U, compiled_methods_.count(method));
+ DCHECK(GetCompiledMethod(method) != NULL) << PrettyMethod(method);
}
- CHECK(method->GetCode() != NULL) << PrettyMethod(method);
+ CompiledInvokeStub* compiled_invoke_stub = NULL;
if (instruction_set_ == kX86) {
- art::x86::X86CreateInvokeStub(method);
+ compiled_invoke_stub = art::x86::X86CreateInvokeStub(method);
} else {
CHECK(instruction_set_ == kArm || instruction_set_ == kThumb2);
// Generates invocation stub using ARM instruction set
- art::arm::ArmCreateInvokeStub(method);
+ compiled_invoke_stub = art::arm::ArmCreateInvokeStub(method);
}
- CHECK(method->GetInvokeStub() != NULL);
+ CHECK(compiled_invoke_stub != NULL);
+ compiled_invoke_stubs_[method] = compiled_invoke_stub;
+}
+
+const CompiledMethod* Compiler::GetCompiledMethod(const Method* method) const {
+ MethodTable::const_iterator it = compiled_methods_.find(method);
+ if (it == compiled_methods_.end()) {
+ return NULL;
+ }
+ CHECK(it->second != NULL);
+ return it->second;
+}
+
+const CompiledInvokeStub* Compiler::GetCompiledInvokeStub(const Method* method) const {
+ InvokeStubTable::const_iterator it = compiled_invoke_stubs_.find(method);
+ if (it == compiled_invoke_stubs_.end()) {
+ return NULL;
+ }
+ CHECK(it->second != NULL);
+ return it->second;
}
void Compiler::SetCodeAndDirectMethods(const ClassLoader* class_loader) {
@@ -332,17 +356,10 @@
CodeAndDirectMethods* code_and_direct_methods = dex_cache->GetCodeAndDirectMethods();
for (size_t i = 0; i < dex_cache->NumResolvedMethods(); i++) {
Method* method = dex_cache->GetResolvedMethod(i);
- if ((method == NULL) || (method->IsStatic() && !method->GetDeclaringClass()->IsInitialized())) {
+ if (method == NULL || method->IsDirect()) {
Runtime::TrampolineType type = Runtime::GetTrampolineType(method);
ByteArray* res_trampoline = runtime->GetResolutionStubArray(type);
- if (instruction_set_ == kX86) {
- code_and_direct_methods->SetResolvedDirectMethodTrampoline(i, res_trampoline, kX86);
- } else {
- CHECK(instruction_set_ == kArm || instruction_set_ == kThumb2);
- code_and_direct_methods->SetResolvedDirectMethodTrampoline(i, res_trampoline, kArm);
- }
- } else if (method->IsDirect()) {
- code_and_direct_methods->SetResolvedDirectMethod(i, method);
+ code_and_direct_methods->SetResolvedDirectMethodTrampoline(i, res_trampoline);
} else {
// TODO: we currently leave the entry blank for resolved
// non-direct methods. we could put in an error stub.
diff --git a/src/compiler.h b/src/compiler.h
index 0f6f02f..6059a2a 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -3,30 +3,37 @@
#ifndef ART_SRC_COMPILER_H_
#define ART_SRC_COMPILER_H_
+#include "compiled_method.h"
#include "constants.h"
#include "dex_file.h"
#include "jni_compiler.h"
+#include "oat_file.h"
#include "object.h"
#include "runtime.h"
-
-int oatVRegOffsetFromMethod(art::Method* method, int reg);
+#include "unordered_map.h"
namespace art {
class Compiler {
public:
- explicit Compiler(InstructionSet insns);
+ explicit Compiler(InstructionSet instruction_set);
+
+ ~Compiler();
// Compile all Methods of all the Classes of all the DexFiles that are part of a ClassLoader.
void CompileAll(const ClassLoader* class_loader);
// Compile a single Method
- void CompileOne(Method* method);
+ void CompileOne(const Method* method);
void SetVerbose(bool verbose) {
verbose_ = verbose;
}
+ InstructionSet GetInstructionSet() const {
+ return instruction_set_;
+ }
+
bool IsVerbose() const {
return verbose_;
}
@@ -34,10 +41,14 @@
// Stub to throw AbstractMethodError
static ByteArray* CreateAbstractMethodErrorStub(InstructionSet instruction_set);
+
// Generate the trampoline that's invoked by unresolved direct methods
static ByteArray* CreateResolutionStub(InstructionSet instruction_set,
Runtime::TrampolineType type);
+ const CompiledMethod* GetCompiledMethod(const Method* method) const;
+ const CompiledInvokeStub* GetCompiledInvokeStub(const Method* method) const;
+
private:
// Attempt to resolve all type, methods, fields, and strings
// referenced from code in the dex file following PathClassLoader
@@ -53,8 +64,8 @@
void Compile(const ClassLoader* class_loader);
void CompileDexFile(const ClassLoader* class_loader, const DexFile& dex_file);
- void CompileClass(Class* klass);
- void CompileMethod(Method* klass);
+ void CompileClass(const Class* klass);
+ void CompileMethod(const Method* method);
// After compiling, walk all the DexCaches and set the code and
// method pointers of CodeAndDirectMethods entries in the DexCaches.
@@ -64,6 +75,12 @@
InstructionSet instruction_set_;
JniCompiler jni_compiler_;
+ typedef std::tr1::unordered_map<const Method*, CompiledMethod*, ObjectIdentityHash> MethodTable;
+ MethodTable compiled_methods_;
+
+ typedef std::tr1::unordered_map<const Method*, CompiledInvokeStub*, ObjectIdentityHash> InvokeStubTable;
+ InvokeStubTable compiled_invoke_stubs_;
+
bool verbose_;
DISALLOW_COPY_AND_ASSIGN(Compiler);
diff --git a/src/compiler/Compiler.h b/src/compiler/Compiler.h
index f9e2478..28a689f 100644
--- a/src/compiler/Compiler.h
+++ b/src/compiler/Compiler.h
@@ -99,7 +99,9 @@
void oatArchDump(void);
bool oatStartup(void);
void oatShutdown(void);
-bool oatCompileMethod(const Compiler& compiler, Method* method, OatInstructionSetType);
+CompiledMethod* oatCompileMethod(const Compiler& compiler,
+ const Method* method,
+ OatInstructionSetType);
void oatDumpStats(void);
void oatScanAllClassPointers(void (*callback)(void* ptr));
void oatInitializeSSAConversion(struct CompilationUnit* cUnit);
diff --git a/src/compiler/Dalvik.h b/src/compiler/Dalvik.h
index 21b4297..422e20c0 100644
--- a/src/compiler/Dalvik.h
+++ b/src/compiler/Dalvik.h
@@ -60,6 +60,7 @@
typedef art::Field Field;
typedef art::JValue JValue;
typedef art::Method Method;
+typedef art::CompiledMethod CompiledMethod;
typedef art::Object Object;
typedef art::String String;
typedef art::Thread Thread;
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 880341a..429d155 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -691,7 +691,7 @@
/*
* Compile a method.
*/
-bool oatCompileMethod(const Compiler& compiler, Method* method, art::InstructionSet insnSet)
+CompiledMethod* oatCompileMethod(const Compiler& compiler, const Method* method, art::InstructionSet insnSet)
{
if (compiler.IsVerbose()) {
LOG(INFO) << "Compiling " << PrettyMethod(method) << "...";
@@ -894,17 +894,11 @@
}
}
- art::ByteArray* managed_code =
- art::ByteArray::Alloc(cUnit.codeBuffer.size() * sizeof(cUnit.codeBuffer[0]));
- memcpy(managed_code->GetData(),
- reinterpret_cast<const int8_t*>(&cUnit.codeBuffer[0]),
- managed_code->GetLength());
- art::IntArray* mapping_table =
- art::IntArray::Alloc(cUnit.mappingTable.size());
- DCHECK_EQ(mapping_table->GetClass()->GetComponentSize(), sizeof(cUnit.mappingTable[0]));
- memcpy(mapping_table->GetData(),
- reinterpret_cast<const int32_t*>(&cUnit.mappingTable[0]),
- mapping_table->GetLength() * sizeof(cUnit.mappingTable[0]));
+ // Combine vmap tables - core regs, then fp regs - into vmapTable
+ std::vector<uint16_t> vmapTable;
+ for (size_t i = 0 ; i < cUnit.coreVmapTable.size(); i++) {
+ vmapTable.push_back(cUnit.coreVmapTable[i]);
+ }
// Add a marker to take place of lr
cUnit.coreVmapTable.push_back(INVALID_VREG);
// Combine vmap tables - core regs, then fp regs
@@ -914,25 +908,25 @@
DCHECK(cUnit.coreVmapTable.size() == (uint32_t)
(__builtin_popcount(cUnit.coreSpillMask) +
__builtin_popcount(cUnit.fpSpillMask)));
- art::ShortArray* vmap_table =
- art::ShortArray::Alloc(cUnit.coreVmapTable.size());
- memcpy(vmap_table->GetData(),
- reinterpret_cast<const int16_t*>(&cUnit.coreVmapTable[0]),
- vmap_table->GetLength() * sizeof(cUnit.coreVmapTable[0]));
- method->SetCodeArray(managed_code, art::kThumb2);
- method->SetMappingTable(mapping_table);
- method->SetVMapTable(vmap_table);
- method->SetFrameSizeInBytes(cUnit.frameSize);
- method->SetReturnPcOffsetInBytes(cUnit.frameSize - sizeof(intptr_t));
- method->SetCoreSpillMask(cUnit.coreSpillMask);
- method->SetFpSpillMask(cUnit.fpSpillMask);
+ vmapTable.push_back(-1);
+ for (size_t i = 0; i < cUnit.fpVmapTable.size(); i++) {
+ vmapTable.push_back(cUnit.fpVmapTable[i]);
+ }
+ CompiledMethod* result = new CompiledMethod(art::kThumb2,
+ cUnit.codeBuffer,
+ cUnit.frameSize,
+ cUnit.frameSize - sizeof(intptr_t),
+ cUnit.coreSpillMask,
+ cUnit.fpSpillMask,
+ cUnit.mappingTable,
+ cUnit.coreVmapTable);
+
if (compiler.IsVerbose()) {
LOG(INFO) << "Compiled " << PrettyMethod(method)
- << " code at " << reinterpret_cast<void*>(managed_code->GetData())
- << " (" << managed_code->GetLength() << " bytes)";
+ << " (" << (cUnit.codeBuffer.size() * sizeof(cUnit.codeBuffer[0])) << " bytes)";
}
- return true;
+ return result;
}
void oatInit(const Compiler& compiler)
diff --git a/src/compiler_test.cc b/src/compiler_test.cc
index e951ade..f261406 100644
--- a/src/compiler_test.cc
+++ b/src/compiler_test.cc
@@ -18,34 +18,6 @@
class CompilerTest : public CommonTest {
protected:
- void AssertStaticIntMethod(jint expected, const ClassLoader* class_loader,
- const char* class_name, const char* method, const char* signature,
- ...) {
- EnsureCompiled(class_loader, class_name, method, signature, false);
-#if defined(__arm__)
- va_list args;
- va_start(args, signature);
- jint result = env_->CallStaticIntMethodV(class_, mid_, args);
- va_end(args);
- LOG(INFO) << class_name << "." << method << "(...) result is " << result;
- EXPECT_EQ(expected, result);
-#endif // __arm__
- }
-
- void AssertStaticLongMethod(jlong expected, const ClassLoader* class_loader,
- const char* class_name, const char* method, const char* signature,
- ...) {
- EnsureCompiled(class_loader, class_name, method, signature, false);
-#if defined(__arm__)
- va_list args;
- va_start(args, signature);
- jlong result = env_->CallStaticLongMethodV(class_, mid_, args);
- va_end(args);
- LOG(INFO) << class_name << "." << method << "(...) result is " << result;
- EXPECT_EQ(expected, result);
-#endif // __arm__
- }
-
void CompileAll(const ClassLoader* class_loader) {
compiler_->CompileAll(class_loader);
MakeAllExecutable(class_loader);
@@ -83,27 +55,14 @@
Class* c = class_linker->FindClass(descriptor, class_loader);
CHECK(c != NULL);
for (size_t i = 0; i < c->NumDirectMethods(); i++) {
- MakeMethodExecutable(c->GetDirectMethod(i));
+ MakeExecutable(c->GetDirectMethod(i));
}
for (size_t i = 0; i < c->NumVirtualMethods(); i++) {
- MakeMethodExecutable(c->GetVirtualMethod(i));
+ MakeExecutable(c->GetVirtualMethod(i));
}
}
}
- void MakeMethodExecutable(Method* m) {
- if (m->GetCodeArray() != NULL) {
- MakeExecutable(m->GetCodeArray());
- } else {
- LOG(WARNING) << "no code for " << PrettyMethod(m);
- }
- if (m->GetInvokeStubArray() != NULL) {
- MakeExecutable(m->GetInvokeStubArray());
- } else {
- LOG(WARNING) << "no invoke stub for " << PrettyMethod(m);
- }
- }
-
JNIEnv* env_;
jclass class_;
jmethodID mid_;
@@ -165,6 +124,8 @@
}
TEST_F(CompilerTest, AbstractMethodErrorStub) {
+ CompileDirectMethod(NULL, "java.lang.Object", "<init>", "()V");
+
const ClassLoader* class_loader = LoadDex("AbstractMethod");
ASSERT_TRUE(class_loader != NULL);
EnsureCompiled(class_loader, "AbstractClass", "foo", "()V", true);
@@ -177,7 +138,7 @@
#if defined(__arm__)
Class* jlame = class_linker_->FindClass("Ljava/lang/AbstractMethodError;", class_loader);
- // Force non-virtal call to AbstractClass foo, will throw AbstractMethodError exception.
+ // Force non-virtual call to AbstractClass foo, will throw AbstractMethodError exception.
env_->CallNonvirtualVoidMethod(jobj_, class_, mid_);
EXPECT_TRUE(Thread::Current()->IsExceptionPending());
EXPECT_TRUE(Thread::Current()->GetException()->InstanceOf(jlame));
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 8d181d6..d5db436 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -258,7 +258,7 @@
}
}
- if (!OatWriter::Create(oat_filename, class_loader)) {
+ if (!OatWriter::Create(oat_filename, class_loader, compiler)) {
fprintf(stderr, "Failed to create oat file %s\n", oat_filename.c_str());
return EXIT_FAILURE;
}
diff --git a/src/dex_cache.h b/src/dex_cache.h
index 7ca6825..a9776b7 100644
--- a/src/dex_cache.h
+++ b/src/dex_cache.h
@@ -26,22 +26,17 @@
return reinterpret_cast<Method*>(Get(MethodIndex(method_idx)));
}
- void SetResolvedDirectMethodTrampoline(uint32_t method_idx, ByteArray* code_array,
- InstructionSet instruction_set) {
- DCHECK(code_array != NULL);
+ void SetResolvedDirectMethodTrampoline(uint32_t method_idx, ByteArray* code_array) {
+ CHECK(code_array != NULL);
int32_t code = reinterpret_cast<int32_t>(code_array->GetData());
- if (instruction_set == kThumb2) {
- // Set the low-order bit so a BLX will switch to Thumb mode
- code = code | 0x1;
- }
Set(CodeIndex(method_idx), code);
Set(MethodIndex(method_idx), method_idx);
}
void SetResolvedDirectMethod(uint32_t method_idx, Method* method) {
CHECK(method != NULL);
- CHECK(method->IsDirect());
- // CHECK(method->GetCode() != NULL); // TODO enable when all code is compiling
+ CHECK(method->IsDirect()) << PrettyMethod(method);
+ CHECK(method->GetCode() != NULL) << PrettyMethod(method);
Set(CodeIndex(method_idx), reinterpret_cast<int32_t>(method->GetCode()));
Set(MethodIndex(method_idx), reinterpret_cast<int32_t>(method));
}
@@ -213,12 +208,6 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(DexCache);
};
-struct DexCacheHash {
- size_t operator()(art::DexCache* const& obj) const {
- return reinterpret_cast<size_t>(&obj);
- }
-};
-
} // namespace art
#endif // ART_SRC_DEX_CACHE_H_
diff --git a/src/exception_test.cc b/src/exception_test.cc
index 49a5266..4662119 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -25,30 +25,34 @@
dex_ = &Runtime::Current()->GetClassLinker()->FindDexFile(my_klass_->GetDexCache());
- ByteArray* fake_code = ByteArray::Alloc(12);
- ASSERT_TRUE(fake_code != NULL);
- IntArray* fake_mapping_data = IntArray::Alloc(2);
- ASSERT_TRUE(fake_mapping_data != NULL);
- fake_mapping_data->Set(0, 3); // offset 3
- fake_mapping_data->Set(1, 3); // maps to dex offset 3
+ for (size_t i = 0 ; i < 12; i++) {
+ fake_code_.push_back(0x70000000 | i);
+ }
+
+ fake_mapping_data_.push_back(2); // first element is count of remaining elements
+ fake_mapping_data_.push_back(3); // offset 3
+ fake_mapping_data_.push_back(3); // maps to dex offset 3
method_f_ = my_klass_->FindVirtualMethod("f", "()I");
ASSERT_TRUE(method_f_ != NULL);
method_f_->SetFrameSizeInBytes(kStackAlignment);
- method_f_->SetReturnPcOffsetInBytes(kStackAlignment-kPointerSize);
- method_f_->SetCodeArray(fake_code, kThumb2);
- method_f_->SetMappingTable(fake_mapping_data);
+ method_f_->SetReturnPcOffsetInBytes(kStackAlignment - kPointerSize);
+ method_f_->SetCode(CompiledMethod::CodePointer(&fake_code_[0], kThumb2));
+ method_f_->SetMappingTable(&fake_mapping_data_[0]);
method_g_ = my_klass_->FindVirtualMethod("g", "(I)V");
ASSERT_TRUE(method_g_ != NULL);
method_g_->SetFrameSizeInBytes(kStackAlignment);
- method_g_->SetReturnPcOffsetInBytes(kStackAlignment-kPointerSize);
- method_g_->SetCodeArray(fake_code, kThumb2);
- method_g_->SetMappingTable(fake_mapping_data);
+ method_g_->SetReturnPcOffsetInBytes(kStackAlignment - kPointerSize);
+ method_g_->SetCode(CompiledMethod::CodePointer(&fake_code_[0], kThumb2));
+ method_g_->SetMappingTable(&fake_mapping_data_[0]);
}
const DexFile* dex_;
+ std::vector<uint8_t> fake_code_;
+ std::vector<uint32_t> fake_mapping_data_;
+
Method* method_f_;
Method* method_g_;
diff --git a/src/image_test.cc b/src/image_test.cc
index 903457f..2ef7489 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -18,7 +18,7 @@
TEST_F(ImageTest, WriteRead) {
ScratchFile tmp_oat;
- bool success_oat = OatWriter::Create(tmp_oat.GetFilename(), NULL);
+ bool success_oat = OatWriter::Create(tmp_oat.GetFilename(), NULL, *compiler_.get());
ASSERT_TRUE(success_oat);
ImageWriter writer;
@@ -37,6 +37,7 @@
ASSERT_EQ(1U, Heap::GetSpaces().size());
Space* space = Heap::GetSpaces()[0];
+ ASSERT_FALSE(space->IsImageSpace());
ASSERT_TRUE(space != NULL);
ASSERT_GE(sizeof(image_header) + space->Size(), static_cast<size_t>(file->Length()));
}
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 8af9cf6..39f3e64 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -180,7 +180,7 @@
// Note that image_top_ is left at end of used space
oat_base_ = image_base_ + RoundUp(image_top_, kPageSize);
- byte* oat_limit = oat_base_ + oat_file_->GetSize();
+ const byte* oat_limit = oat_base_ + oat_file_->GetSize();
// return to write header at start of image with future location of image_roots
ImageHeader image_header(reinterpret_cast<uint32_t>(image_base_),
@@ -258,29 +258,42 @@
void ImageWriter::FixupMethod(const Method* orig, Method* copy) {
FixupInstanceFields(orig, copy);
- // OatWriter clears the code_array_ after writing the code.
- // It replaces the code_ with an offset value we now adjust to be a pointer.
- DCHECK(copy->code_array_ == NULL)
- << PrettyMethod(orig)
- << " orig_code_array_=" << orig->GetCodeArray() << " orig_code_=" << orig->GetCode()
- << " copy_code_array_=" << copy->code_array_ << " orig_code_=" << copy->code_
- << " jni_stub=" << Runtime::Current()->GetJniStubArray()
- << " ame_stub=" << Runtime::Current()->GetAbstractMethodErrorStubArray();
- copy->invoke_stub_ = reinterpret_cast<Method::InvokeStub*>(FixupCode(copy->invoke_stub_array_, reinterpret_cast<void*>(orig->invoke_stub_)));
+ // OatWriter replaces the code_ and invoke_stub_ with offset values.
+ // Here we readjust to a pointer relative to oat_base_
+
+ // Every type of method can have an invoke stub
+ uint32_t invoke_stub_offset = orig->GetOatInvokeStubOffset();
+ const byte* invoke_stub = (invoke_stub_offset != 0) ? (oat_base_ + invoke_stub_offset) : 0;
+ copy->invoke_stub_ = reinterpret_cast<const Method::InvokeStub*>(invoke_stub);
+
+ if (orig->IsAbstract()) {
+ // Abstract methods are pointed to a stub that will throw AbstractMethodError if they are called
+ ByteArray* orig_ame_stub_array_ = Runtime::Current()->GetAbstractMethodErrorStubArray();
+ ByteArray* copy_ame_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_ame_stub_array_));
+ copy->code_ = copy_ame_stub_array_->GetData();
+ return;
+ }
+
+ // Non-abstract methods typically have code
+ uint32_t code_offset = orig->GetOatCodeOffset();
+ const byte* code = (code_offset != 0) ? (oat_base_ + code_offset) : 0;
+ copy->code_ = code;
+
if (orig->IsNative()) {
+ // The native method's pointer is directed to a stub to lookup via dlsym.
+ // Note this is not the code_ pointer, that is handled above.
ByteArray* orig_jni_stub_array_ = Runtime::Current()->GetJniStubArray();
ByteArray* copy_jni_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_jni_stub_array_));
copy->native_method_ = copy_jni_stub_array_->GetData();
- copy->code_ = oat_base_ + orig->GetOatCodeOffset();
} else {
- DCHECK(copy->native_method_ == NULL) << copy->native_method_;
- if (orig->IsAbstract()) {
- ByteArray* orig_ame_stub_array_ = Runtime::Current()->GetAbstractMethodErrorStubArray();
- ByteArray* copy_ame_stub_array_ = down_cast<ByteArray*>(GetImageAddress(orig_ame_stub_array_));
- copy->code_ = copy_ame_stub_array_->GetData();
- } else {
- copy->code_ = oat_base_ + orig->GetOatCodeOffset();
- }
+ // normal (non-abstract non-native) methods have mapping tables to relocate
+ uint32_t mapping_table_off = orig->GetOatMappingTableOffset();
+ const byte* mapping_table = (mapping_table_off != 0) ? (oat_base_ + mapping_table_off) : 0;
+ copy->mapping_table_ = reinterpret_cast<const uint32_t*>(mapping_table);
+
+ uint32_t vmap_table_offset = orig->GetOatVmapTableOffset();
+ const byte* vmap_table = (vmap_table_offset != 0) ? (oat_base_ + vmap_table_offset) : 0;
+ copy->vmap_table_ = reinterpret_cast<const uint16_t*>(vmap_table);
}
}
diff --git a/src/image_writer.h b/src/image_writer.h
index fda33fe..3c17538 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -116,10 +116,10 @@
byte* image_base_;
// Target oat base address for the pointers from the output image to its oat file
- byte* oat_base_;
+ const byte* oat_base_;
// DexCaches seen while scanning for fixing up CodeAndDirectMethods
- typedef std::tr1::unordered_set<DexCache*, DexCacheHash> Set;
+ typedef std::tr1::unordered_set<DexCache*, ObjectIdentityHash> Set;
Set dex_caches_;
};
diff --git a/src/jni_compiler.cc b/src/jni_compiler.cc
index 83be88a..ffcbc11 100644
--- a/src/jni_compiler.cc
+++ b/src/jni_compiler.cc
@@ -7,11 +7,12 @@
#include "assembler.h"
#include "calling_convention.h"
+#include "compiled_method.h"
#include "constants.h"
#include "jni_internal.h"
+#include "logging.h"
#include "macros.h"
#include "managed_register.h"
-#include "logging.h"
#include "thread.h"
#include "UniquePtr.h"
@@ -38,12 +39,12 @@
}
}
-JniCompiler::JniCompiler(InstructionSet insns) {
- if (insns == kThumb2) {
+JniCompiler::JniCompiler(InstructionSet instruction_set) {
+ if (instruction_set == kThumb2) {
// currently only ARM code generation is supported
instruction_set_ = kArm;
} else {
- instruction_set_ = insns;
+ instruction_set_ = instruction_set;
}
}
@@ -54,7 +55,7 @@
// registers, a reference to the method object is supplied as part of this
// convention.
//
-void JniCompiler::Compile(Method* native_method) {
+CompiledMethod* JniCompiler::Compile(const Method* native_method) {
CHECK(native_method->IsNative());
// Calling conventions used to iterate over parameters to method
@@ -426,15 +427,15 @@
// 17. Finalize code generation
__ EmitSlowPaths();
size_t cs = __ CodeSize();
- ByteArray* managed_code = ByteArray::Alloc(cs);
- CHECK(managed_code != NULL);
- MemoryRegion code(managed_code->GetData(), managed_code->GetLength());
+ std::vector<uint8_t> managed_code(cs);
+ MemoryRegion code(&managed_code[0], managed_code.size());
__ FinalizeInstructions(code);
- native_method->SetCodeArray(managed_code, instruction_set_);
- native_method->SetFrameSizeInBytes(frame_size);
- native_method->SetReturnPcOffsetInBytes(jni_conv->ReturnPcOffset());
- native_method->SetCoreSpillMask(jni_conv->CoreSpillMask());
- native_method->SetFpSpillMask(jni_conv->FpSpillMask());
+ return new CompiledMethod(instruction_set_,
+ managed_code,
+ frame_size,
+ jni_conv->ReturnPcOffset(),
+ jni_conv->CoreSpillMask(),
+ jni_conv->FpSpillMask());
#undef __
}
diff --git a/src/jni_compiler.h b/src/jni_compiler.h
index 086d96e..a6d5602 100644
--- a/src/jni_compiler.h
+++ b/src/jni_compiler.h
@@ -3,6 +3,7 @@
#ifndef ART_SRC_JNI_COMPILER_H_
#define ART_SRC_JNI_COMPILER_H_
+#include "compiled_method.h"
#include "constants.h"
#include "macros.h"
#include "object.h"
@@ -10,6 +11,7 @@
namespace art {
class Assembler;
+class Compiler;
class JniCallingConvention;
class ManagedRegister;
class ManagedRuntimeCallingConvention;
@@ -20,10 +22,10 @@
// TODO: move the responsibility of managing memory to somewhere else
class JniCompiler {
public:
- explicit JniCompiler(InstructionSet insns);
+ explicit JniCompiler(InstructionSet instruction_set);
~JniCompiler();
- void Compile(Method* method);
+ CompiledMethod* Compile(const Method* method);
// Stub to perform native method symbol lookup via dlsym
// TODO: remove from JniCompiler
diff --git a/src/jni_internal_arm.cc b/src/jni_internal_arm.cc
index 8ba5717..ba13de7 100644
--- a/src/jni_internal_arm.cc
+++ b/src/jni_internal_arm.cc
@@ -5,6 +5,7 @@
#include <algorithm>
#include "assembler.h"
+#include "compiled_method.h"
#include "object.h"
namespace art {
@@ -27,7 +28,7 @@
// register and transfer arguments from the array into register and on
// the stack, if needed. On return, the thread register must be
// shuffled and the return value must be store into the result JValue.
-void ArmCreateInvokeStub(Method* method) {
+CompiledInvokeStub* ArmCreateInvokeStub(const Method* method) {
UniquePtr<ArmAssembler> assembler(
down_cast<ArmAssembler*>(Assembler::Create(kArm)));
#define __ assembler->
@@ -118,11 +119,10 @@
// Pop R4, R9 and the LR into PC
__ PopList(save | (1 << PC));
// TODO: store native_entry in the stub table
- ByteArray* code = ByteArray::Alloc(assembler->CodeSize());
- MemoryRegion region(code->GetData(), code->GetLength());
+ std::vector<uint8_t> code(assembler->CodeSize());
+ MemoryRegion region(&code[0], code.size());
assembler->FinalizeInstructions(region);
- method->SetInvokeStub(code);
- CHECK(method->GetInvokeStub() != NULL);
+ return new CompiledInvokeStub(code);
#undef __
}
diff --git a/src/jni_internal_x86.cc b/src/jni_internal_x86.cc
index 7128c6e..891971d 100644
--- a/src/jni_internal_x86.cc
+++ b/src/jni_internal_x86.cc
@@ -3,6 +3,7 @@
#include "jni_internal.h"
#include "assembler.h"
+#include "compiled_method.h"
#include "object.h"
namespace art {
@@ -24,7 +25,7 @@
// "running" state the remaining responsibilities of this routine are
// to save the native registers and set up the managed registers. On
// return, the return value must be store into the result JValue.
-void X86CreateInvokeStub(Method* method) {
+CompiledInvokeStub* X86CreateInvokeStub(const Method* method) {
UniquePtr<X86Assembler> assembler(
down_cast<X86Assembler*>(Assembler::Create(kX86)));
#define __ assembler->
@@ -79,11 +80,10 @@
}
__ ret();
// TODO: store native_entry in the stub table
- ByteArray* code = ByteArray::Alloc(assembler->CodeSize());
- MemoryRegion region(code->GetData(), code->GetLength());
+ std::vector<uint8_t> code(assembler->CodeSize());
+ MemoryRegion region(&code[0], code.size());
assembler->FinalizeInstructions(region);
- method->SetInvokeStub(code);
- CHECK(method->GetInvokeStub() != NULL);
+ return new CompiledInvokeStub(code);
#undef __
}
diff --git a/src/oat.cc b/src/oat.cc
index 191f26f..8bf8299 100644
--- a/src/oat.cc
+++ b/src/oat.cc
@@ -65,4 +65,33 @@
UpdateChecksum(&executable_offset_, sizeof(executable_offset));
}
+OatMethodOffsets::OatMethodOffsets()
+ : code_offset_(0),
+ frame_size_in_bytes_(0),
+ return_pc_offset_in_bytes_(0),
+ core_spill_mask_(0),
+ fp_spill_mask_(0),
+ mapping_table_offset_(0),
+ vmap_table_offset_(0),
+ invoke_stub_offset_(0) {}
+
+OatMethodOffsets::OatMethodOffsets(uint32_t code_offset,
+ uint32_t frame_size_in_bytes,
+ uint32_t return_pc_offset_in_bytes,
+ uint32_t core_spill_mask,
+ uint32_t fp_spill_mask,
+ uint32_t mapping_table_offset,
+ uint32_t vmap_table_offset,
+ uint32_t invoke_stub_offset)
+ : code_offset_(code_offset),
+ frame_size_in_bytes_(frame_size_in_bytes),
+ return_pc_offset_in_bytes_(return_pc_offset_in_bytes),
+ core_spill_mask_(core_spill_mask),
+ fp_spill_mask_(fp_spill_mask),
+ mapping_table_offset_(mapping_table_offset),
+ vmap_table_offset_(vmap_table_offset),
+ invoke_stub_offset_(invoke_stub_offset) {}
+
+OatMethodOffsets::~OatMethodOffsets() {}
+
} // namespace art
diff --git a/src/oat.h b/src/oat.h
index ca3e9e0..ff50599 100644
--- a/src/oat.h
+++ b/src/oat.h
@@ -36,6 +36,29 @@
DISALLOW_COPY_AND_ASSIGN(OatHeader);
};
+class PACKED OatMethodOffsets {
+ public:
+ OatMethodOffsets();
+ OatMethodOffsets(uint32_t code_offset,
+ uint32_t frame_size_in_bytes,
+ uint32_t return_pc_offset_in_bytes,
+ uint32_t core_spill_mask,
+ uint32_t fp_spill_mask,
+ uint32_t mapping_table_offset,
+ uint32_t vmap_table_offset,
+ uint32_t invoke_stub_offset);
+ ~OatMethodOffsets();
+
+ uint32_t code_offset_;
+ uint32_t frame_size_in_bytes_;
+ uint32_t return_pc_offset_in_bytes_;
+ uint32_t core_spill_mask_;
+ uint32_t fp_spill_mask_;
+ uint32_t mapping_table_offset_;
+ uint32_t vmap_table_offset_;
+ uint32_t invoke_stub_offset_;
+};
+
} // namespace art
#endif // ART_SRC_OAT_H_
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 15221a6..95ef64c 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -146,22 +146,56 @@
uint32_t methods_offset = classes_pointer_[class_def_index];
const byte* methods_pointer = oat_file_->GetBase() + methods_offset;
CHECK_LT(methods_pointer, oat_file_->GetLimit());
- return OatClass(oat_file_, reinterpret_cast<const uint32_t*>(methods_pointer));
+ return OatClass(oat_file_, reinterpret_cast<const OatMethodOffsets*>(methods_pointer));
}
-OatFile::OatClass::OatClass(const OatFile* oat_file, const uint32_t* methods_pointer)
+OatFile::OatClass::OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer)
: oat_file_(oat_file), methods_pointer_(methods_pointer) {}
OatFile::OatClass::~OatClass() {}
-const void* OatFile::OatClass::GetMethodCode(uint32_t method_index) const {
- uint32_t code_offset = methods_pointer_[method_index];
- if (code_offset == 0) {
- return NULL;
- }
- const void* code_pointer = reinterpret_cast<const void*>(oat_file_->GetBase() + code_offset);
- CHECK_LT(code_pointer, oat_file_->GetLimit());
- return code_pointer;
+const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
+ const OatMethodOffsets& oat_method_offsets = methods_pointer_[method_index];
+ return OatMethod(
+ GetOatPointer<const void*>(oat_method_offsets.code_offset_),
+ oat_method_offsets.frame_size_in_bytes_,
+ oat_method_offsets.return_pc_offset_in_bytes_,
+ oat_method_offsets.core_spill_mask_,
+ oat_method_offsets.fp_spill_mask_,
+ GetOatPointer<const uint32_t*>(oat_method_offsets.mapping_table_offset_),
+ GetOatPointer<const uint16_t*>(oat_method_offsets.vmap_table_offset_),
+ GetOatPointer<const Method::InvokeStub*>(oat_method_offsets.invoke_stub_offset_));
+}
+
+OatFile::OatMethod::OatMethod(const void* code,
+ const size_t frame_size_in_bytes,
+ const size_t return_pc_offset_in_bytes,
+ const uint32_t core_spill_mask,
+ const uint32_t fp_spill_mask,
+ const uint32_t* mapping_table,
+ const uint16_t* vmap_table,
+ const Method::InvokeStub* invoke_stub) :
+ code_(code),
+ frame_size_in_bytes_(frame_size_in_bytes),
+ return_pc_offset_in_bytes_(return_pc_offset_in_bytes),
+ core_spill_mask_(core_spill_mask),
+ fp_spill_mask_(fp_spill_mask),
+ mapping_table_(mapping_table),
+ vmap_table_(vmap_table),
+ invoke_stub_(invoke_stub) {}
+
+OatFile::OatMethod::~OatMethod() {}
+
+void OatFile::OatMethod::LinkMethod(Method* method) {
+ CHECK(method != NULL);
+ method->SetCode(code_);
+ method->SetFrameSizeInBytes(frame_size_in_bytes_);
+ method->SetReturnPcOffsetInBytes(return_pc_offset_in_bytes_);
+ method->SetCoreSpillMask(core_spill_mask_);
+ method->SetFpSpillMask(fp_spill_mask_);
+ method->SetMappingTable(mapping_table_);
+ method->SetVmapTable(vmap_table_);
+ method->SetInvokeStub(invoke_stub_);
}
} // namespace art
diff --git a/src/oat_file.h b/src/oat_file.h
index 6027dda..0472c16 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -5,9 +5,11 @@
#include <vector>
+#include "constants.h"
#include "dex_file.h"
#include "mem_map.h"
#include "oat.h"
+#include "object.h"
namespace art {
@@ -30,20 +32,57 @@
class OatDexFile;
+ class OatMethod {
+ public:
+ // Create an OatMethod backed by an OatFile
+ OatMethod(const void* code,
+ const size_t frame_size_in_bytes,
+ const size_t return_pc_offset_in_bytes,
+ const uint32_t core_spill_mask,
+ const uint32_t fp_spill_mask,
+ const uint32_t* mapping_table,
+ const uint16_t* vmap_table,
+ const Method::InvokeStub* invoke_stub);
+
+ ~OatMethod();
+
+ // Link Method using the contents of this OatMethod
+ void LinkMethod(Method* method);
+
+ const void* code_;
+ size_t frame_size_in_bytes_;
+ size_t return_pc_offset_in_bytes_;
+ uint32_t core_spill_mask_;
+ uint32_t fp_spill_mask_;
+ const uint32_t* mapping_table_;
+ const uint16_t* vmap_table_;
+ const Method::InvokeStub* invoke_stub_;
+ };
+
class OatClass {
public:
- // get the code for the method based on its index into the class
+ // get the OatMethod entry based on its index into the class
// defintion. direct methods come first, followed by virtual
// methods. note that runtime created methods such as miranda
// methods are not included.
- const void* GetMethodCode(uint32_t method_index) const;
+ const OatMethod GetOatMethod(uint32_t method_idx) const;
~OatClass();
private:
- OatClass(const OatFile* oat_file, const uint32_t* methods_pointer);
+ OatClass(const OatFile* oat_file, const OatMethodOffsets* methods_pointer);
+
+ template<class T>
+ T GetOatPointer(uint32_t offset) const {
+ if (offset == 0) {
+ return NULL;
+ }
+ T pointer = reinterpret_cast<T>(oat_file_->GetBase() + offset);
+ CHECK_LT(pointer, reinterpret_cast<T>(oat_file_->GetLimit()));
+ return pointer;
+ }
const OatFile* oat_file_;
- const uint32_t* methods_pointer_;
+ const OatMethodOffsets* methods_pointer_;
friend class OatDexFile;
};
diff --git a/src/oat_test.cc b/src/oat_test.cc
index c3d012e..3137728 100644
--- a/src/oat_test.cc
+++ b/src/oat_test.cc
@@ -14,11 +14,12 @@
const ClassLoader* class_loader = NULL;
if (compile) {
+ compiler_.reset(new Compiler(kThumb2));
compiler_->CompileAll(class_loader);
}
ScratchFile tmp;
- bool success = OatWriter::Create(tmp.GetFilename(), class_loader);
+ bool success = OatWriter::Create(tmp.GetFilename(), class_loader, *compiler_.get());
ASSERT_TRUE(success);
if (compile) { // OatWriter strips the code, regenerate to compare
@@ -29,10 +30,7 @@
const OatHeader& oat_header = oat_file->GetOatHeader();
ASSERT_EQ(1U, oat_header.GetDexFileCount());
- const Runtime* runtime = Runtime::Current();
- ClassLinker* class_linker = runtime->GetClassLinker();
- ByteArray* jni_stub_array = runtime->GetJniStubArray();
- ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
const DexFile& dex_file = *java_lang_dex_file_.get();
const OatFile::OatDexFile& oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
@@ -50,27 +48,57 @@
size_t method_index = 0;
for (size_t i = 0; i < klass->NumDirectMethods(); i++, method_index++) {
Method* method = klass->GetDirectMethod(i);
- const void* oat_code = oat_class.GetMethodCode(method_index);
- uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
- oat_code = reinterpret_cast<const void*>(oat_code_aligned);
- const ByteArray* code_array = method->GetCodeArray();
- if (code_array == NULL || code_array == jni_stub_array || code_array == ame_stub_array) {
- ASSERT_TRUE(oat_code == NULL);
+ const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+ const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
+
+ if (compiled_method == NULL) {
+ EXPECT_TRUE(oat_method.code_ == NULL) << PrettyMethod(method) << " " << oat_method.code_;
+ EXPECT_EQ(oat_method.frame_size_in_bytes_, static_cast<uint32_t>(kStackAlignment));
+ EXPECT_EQ(oat_method.return_pc_offset_in_bytes_, 0U);
+ EXPECT_EQ(oat_method.core_spill_mask_, 0U);
+ EXPECT_EQ(oat_method.fp_spill_mask_, 0U);
} else {
- ASSERT_EQ(0, memcmp(oat_code, code_array->GetData(), code_array->GetLength()));
+ const void* oat_code = oat_method.code_;
+ uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
+ oat_code = reinterpret_cast<const void*>(oat_code_aligned);
+
+ const std::vector<uint8_t>& code = compiled_method->GetCode();
+ size_t code_size = code.size() * sizeof(code[0]);
+ EXPECT_EQ(0, memcmp(oat_code, &code[0], code_size))
+ << PrettyMethod(method) << " " << code_size;
+ CHECK_EQ(0, memcmp(oat_code, &code[0], code_size));
+ EXPECT_EQ(oat_method.frame_size_in_bytes_, compiled_method->GetFrameSizeInBytes());
+ EXPECT_EQ(oat_method.return_pc_offset_in_bytes_, compiled_method->GetReturnPcOffsetInBytes());
+ EXPECT_EQ(oat_method.core_spill_mask_, compiled_method->GetCoreSpillMask());
+ EXPECT_EQ(oat_method.fp_spill_mask_, compiled_method->GetFpSpillMask());
}
}
for (size_t i = 0; i < num_virtual_methods; i++, method_index++) {
Method* method = klass->GetVirtualMethod(i);
- const void* oat_code = oat_class.GetMethodCode(method_index);
- uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
- oat_code = reinterpret_cast<const void*>(oat_code_aligned);
- const ByteArray* code_array = method->GetCodeArray();
- if (code_array == NULL || code_array == jni_stub_array || code_array == ame_stub_array) {
- ASSERT_TRUE(oat_code == NULL);
+ const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
+ const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
+
+ if (compiled_method == NULL) {
+ EXPECT_TRUE(oat_method.code_ == NULL) << PrettyMethod(method) << " " << oat_method.code_;
+ EXPECT_EQ(oat_method.frame_size_in_bytes_, static_cast<uint32_t>(kStackAlignment));
+ EXPECT_EQ(oat_method.return_pc_offset_in_bytes_, 0U);
+ EXPECT_EQ(oat_method.core_spill_mask_, 0U);
+ EXPECT_EQ(oat_method.fp_spill_mask_, 0U);
} else {
- ASSERT_TRUE(oat_code != NULL);
- ASSERT_EQ(0, memcmp(oat_code, code_array->GetData(), code_array->GetLength()));
+ const void* oat_code = oat_method.code_;
+ EXPECT_TRUE(oat_code != NULL) << PrettyMethod(method);
+ uintptr_t oat_code_aligned = RoundDown(reinterpret_cast<uintptr_t>(oat_code), 2);
+ oat_code = reinterpret_cast<const void*>(oat_code_aligned);
+
+ const std::vector<uint8_t>& code = compiled_method->GetCode();
+ size_t code_size = code.size() * sizeof(code[0]);
+ EXPECT_EQ(0, memcmp(oat_code, &code[0], code_size))
+ << PrettyMethod(method) << " " << code_size;
+ CHECK_EQ(0, memcmp(oat_code, &code[0], code_size));
+ EXPECT_EQ(oat_method.frame_size_in_bytes_, compiled_method->GetFrameSizeInBytes());
+ EXPECT_EQ(oat_method.return_pc_offset_in_bytes_, compiled_method->GetReturnPcOffsetInBytes());
+ EXPECT_EQ(oat_method.core_spill_mask_, compiled_method->GetCoreSpillMask());
+ EXPECT_EQ(oat_method.fp_spill_mask_, compiled_method->GetFpSpillMask());
}
}
}
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index b8232d9..0722520 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -10,13 +10,18 @@
namespace art {
-bool OatWriter::Create(const std::string& filename, const ClassLoader* class_loader) {
+bool OatWriter::Create(const std::string& filename,
+ const ClassLoader* class_loader,
+ const Compiler& compiler) {
const std::vector<const DexFile*>& dex_files = ClassLoader::GetClassPath(class_loader);
- OatWriter oat_writer(dex_files, class_loader);
+ OatWriter oat_writer(dex_files, class_loader, compiler);
return oat_writer.Write(filename);
}
-OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, const ClassLoader* class_loader) {
+OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files,
+ const ClassLoader* class_loader,
+ const Compiler& compiler) {
+ compiler_ = &compiler;
class_loader_ = class_loader;
dex_files_ = &dex_files;
@@ -141,7 +146,6 @@
CHECK_EQ(klass->GetClassLoader(), class_loader_);
CHECK_EQ(oat_methods_[oat_class_index]->method_offsets_.size(),
klass->NumDirectMethods() + num_virtual_methods);
- // Note that we leave the offset to the code in Method::code_
size_t class_def_method_index = 0;
for (size_t i = 0; i < klass->NumDirectMethods(); i++, class_def_method_index++) {
Method* method = klass->GetDirectMethod(i);
@@ -161,27 +165,99 @@
size_t oat_class_index,
size_t class_def_method_index,
Method* method) {
- Runtime* runtime = Runtime::Current();
- ByteArray* jni_stub_array = runtime->GetJniStubArray();
- ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
+ // derived from CompiledMethod if available
+ uint32_t code_offset = 0;
+ uint32_t frame_size_in_bytes = kStackAlignment;
+ uint32_t return_pc_offset_in_bytes = 0;
+ uint32_t core_spill_mask = 0;
+ uint32_t fp_spill_mask = 0;
+ uint32_t mapping_table_offset = 0;
+ uint32_t vmap_table_offset = 0;
+ // derived from CompiledInvokeStub if available
+ uint32_t invoke_stub_offset = 0;
- const ByteArray* code_array = method->GetCodeArray();
- if (code_array == NULL || code_array == jni_stub_array || code_array == ame_stub_array) {
- oat_methods_[oat_class_index]->method_offsets_[class_def_method_index] = 0;
- method->SetOatCodeOffset(0);
- } else {
- offset = RoundUp(offset, kArmAlignment);
- uint32_t thumb_offset = (reinterpret_cast<const int8_t*>(method->GetCode())
- - code_array->GetData());
- uint32_t code_offset = offset + thumb_offset;
- oat_methods_[oat_class_index]->method_offsets_[class_def_method_index] = code_offset;
- method->SetOatCodeOffset(code_offset);
- offset += code_array->GetLength();
- oat_header_->UpdateChecksum(code_array->GetData(), code_array->GetLength());
+ const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
+ if (compiled_method != NULL) {
+
+ offset = compiled_method->AlignCode(offset);
+ DCHECK(IsAligned(offset, kArmAlignment)) << std::hex << offset;
+ const std::vector<uint8_t>& code = compiled_method->GetCode();
+ size_t code_size = code.size() * sizeof(code[0]);
+ uint32_t thumb_offset = compiled_method->CodeDelta();
+ code_offset = (code_size == 0) ? 0 : offset + thumb_offset;
+ offset += code_size;
+ oat_header_->UpdateChecksum(&code[0], code_size);
+
+ frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
+ return_pc_offset_in_bytes = compiled_method->GetReturnPcOffsetInBytes();
+ core_spill_mask = compiled_method->GetCoreSpillMask();
+ fp_spill_mask = compiled_method->GetFpSpillMask();
}
+
+ offset += sizeof(frame_size_in_bytes);
+ oat_header_->UpdateChecksum(&frame_size_in_bytes, sizeof(frame_size_in_bytes));
+
+ offset += sizeof(return_pc_offset_in_bytes);
+ oat_header_->UpdateChecksum(&return_pc_offset_in_bytes, sizeof(return_pc_offset_in_bytes));
+
+ offset += sizeof(core_spill_mask);
+ oat_header_->UpdateChecksum(&core_spill_mask, sizeof(core_spill_mask));
+
+ offset += sizeof(fp_spill_mask);
+ oat_header_->UpdateChecksum(&fp_spill_mask, sizeof(fp_spill_mask));
+
+ if (compiled_method != NULL) {
+
+ const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
+ size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
+ mapping_table_offset = (mapping_table_size == 0) ? 0 : offset;
+ offset += mapping_table_size;
+ oat_header_->UpdateChecksum(&mapping_table[0], mapping_table_size);
+
+ const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
+ size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
+ vmap_table_offset = (vmap_table_size == 0) ? 0 : offset;
+ offset += vmap_table_size;
+ oat_header_->UpdateChecksum(&vmap_table[0], vmap_table_size);
+ }
+
+ const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
+ if (compiled_invoke_stub != NULL) {
+ offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
+ DCHECK(IsAligned(offset, kArmAlignment)) << std::hex << offset;
+ const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
+ size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
+ invoke_stub_offset = (invoke_stub_size == 0) ? 0 : offset;
+ offset += invoke_stub_size;
+ oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size);
+ }
+
+ oat_methods_[oat_class_index]->method_offsets_[class_def_method_index]
+ = OatMethodOffsets(code_offset,
+ frame_size_in_bytes,
+ return_pc_offset_in_bytes,
+ core_spill_mask,
+ fp_spill_mask,
+ mapping_table_offset,
+ vmap_table_offset,
+ invoke_stub_offset);
+
+ // Note that we leave the offset and values back in the Method where ImageWriter will find them
+ method->SetOatCodeOffset(code_offset);
+ method->SetFrameSizeInBytes(frame_size_in_bytes);
+ method->SetReturnPcOffsetInBytes(return_pc_offset_in_bytes);
+ method->SetCoreSpillMask(core_spill_mask);
+ method->SetFpSpillMask(fp_spill_mask);
+ method->SetOatMappingTableOffset(mapping_table_offset);
+ method->SetOatVmapTableOffset(vmap_table_offset);
+ method->SetOatInvokeStubOffset(invoke_stub_offset);
+
return offset;
}
+#define DCHECK_CODE_OFFSET() \
+ DCHECK_EQ(static_cast<off_t>(code_offset), lseek(file->Fd(), 0, SEEK_CUR))
+
bool OatWriter::Write(const std::string& filename) {
UniquePtr<File> file(OS::OpenFile(filename.c_str(), true));
@@ -240,9 +316,11 @@
uint32_t code_offset = oat_header_->GetExecutableOffset();
off_t new_offset = lseek(file->Fd(), executable_offset_padding_length_, SEEK_CUR);
if (static_cast<uint32_t>(new_offset) != code_offset) {
- PLOG(ERROR) << "Failed to seek to oat code section";
+ PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset
+ << " Expected: " << code_offset;
return 0;
}
+ DCHECK_CODE_OFFSET();
return code_offset;
}
@@ -277,14 +355,11 @@
size_t code_offset,
const DexFile& dex_file,
const DexFile::ClassDef& class_def) {
- const Runtime* runtime = Runtime::Current();
- ClassLinker* class_linker = runtime->GetClassLinker();
- ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
-
const byte* class_data = dex_file.GetClassData(class_def);
DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data);
size_t num_virtual_methods = header.virtual_methods_size_;
const char* descriptor = dex_file.GetClassDescriptor(class_def);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Class* klass = class_linker->FindClass(descriptor, class_loader_);
// TODO: deduplicate code arrays
@@ -306,11 +381,7 @@
}
for (size_t i = num_virtual_methods; i < klass->NumVirtualMethods(); i++) {
Method* method = klass->GetVirtualMethod(i);
- const ByteArray* code_array = method->GetCodeArray();
- CHECK(code_array == NULL // if compiler not run
- || code_array == ame_stub_array) // otherwise
- << PrettyMethod(method) << " " << code_array;
- method->SetCodeArray(NULL, kNone);
+ CHECK(compiler_->GetCompiledMethod(method) == NULL) << PrettyMethod(method);
}
return code_offset;
}
@@ -318,32 +389,110 @@
size_t OatWriter::WriteCodeMethod(File* file,
size_t code_offset,
Method* method) {
- const Runtime* runtime = Runtime::Current();
- ByteArray* jni_stub_array = runtime->GetJniStubArray();
- ByteArray* ame_stub_array = runtime->GetAbstractMethodErrorStubArray();
-
- const ByteArray* code_array = method->GetCodeArray();
- if (code_array != NULL && code_array != jni_stub_array && code_array != ame_stub_array) {
- uint32_t aligned_code_offset = RoundUp(code_offset, kArmAlignment);
+ const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method);
+ if (compiled_method != NULL) {
+ uint32_t aligned_code_offset = compiled_method->AlignCode(code_offset);
uint32_t aligned_code_delta = aligned_code_offset - code_offset;
if (aligned_code_delta != 0) {
off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
- PLOG(ERROR) << "Failed to seek to align oat code";
+ PLOG(ERROR) << "Failed to seek to align oat code. Actual: " << new_offset
+ << " Expected: " << aligned_code_offset;
return false;
}
code_offset += aligned_code_delta;
+ DCHECK_CODE_OFFSET();
}
- if (!file->WriteFully(code_array->GetData(), code_array->GetLength())) {
+ DCHECK(IsAligned(code_offset, kArmAlignment)) << std::hex << code_offset;
+ const std::vector<uint8_t>& code = compiled_method->GetCode();
+ size_t code_size = code.size() * sizeof(code[0]);
+ DCHECK((code_size == 0 && method->GetOatCodeOffset() == 0)
+ || code_offset + compiled_method->CodeDelta() == method->GetOatCodeOffset());
+ if (!file->WriteFully(&code[0], code_size)) {
PLOG(ERROR) << "Failed to write method code for " << PrettyMethod(method);
return false;
}
- code_offset += code_array->GetLength();
+ code_offset += code_size;
+ DCHECK_CODE_OFFSET();
}
- // preserve code offset around code clearing
- uint32_t offset = method->GetOatCodeOffset();
- method->SetCodeArray(NULL, kNone);
- method->SetOatCodeOffset(offset);
+
+ uint32_t frame_size_in_bytes = method->GetFrameSizeInBytes();
+ uint32_t return_pc_offset_in_bytes = method->GetReturnPcOffsetInBytes();
+ uint32_t core_spill_mask = method->GetCoreSpillMask();
+ uint32_t fp_spill_mask = method->GetFpSpillMask();
+ if (!file->WriteFully(&frame_size_in_bytes, sizeof(frame_size_in_bytes))) {
+ PLOG(ERROR) << "Failed to write method frame size for " << PrettyMethod(method);
+ return false;
+ }
+ code_offset += sizeof(frame_size_in_bytes);
+ if (!file->WriteFully(&return_pc_offset_in_bytes, sizeof(return_pc_offset_in_bytes))) {
+ PLOG(ERROR) << "Failed to write method return pc offset for " << PrettyMethod(method);
+ return false;
+ }
+ code_offset += sizeof(return_pc_offset_in_bytes);
+ if (!file->WriteFully(&core_spill_mask, sizeof(core_spill_mask))) {
+ PLOG(ERROR) << "Failed to write method core spill mask for " << PrettyMethod(method);
+ return false;
+ }
+ code_offset += sizeof(core_spill_mask);
+ if (!file->WriteFully(&fp_spill_mask, sizeof(fp_spill_mask))) {
+ PLOG(ERROR) << "Failed to write method fp spill mask for " << PrettyMethod(method);
+ return false;
+ }
+ code_offset += sizeof(fp_spill_mask);
+
+ if (compiled_method != NULL) {
+ const std::vector<uint32_t>& mapping_table = compiled_method->GetMappingTable();
+ size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]);
+ DCHECK((mapping_table_size == 0 && method->GetOatMappingTableOffset() == 0)
+ || code_offset == method->GetOatMappingTableOffset());
+ if (!file->WriteFully(&mapping_table[0], mapping_table_size)) {
+ PLOG(ERROR) << "Failed to write mapping table for " << PrettyMethod(method);
+ return false;
+ }
+ code_offset += mapping_table_size;
+ DCHECK_CODE_OFFSET();
+
+ const std::vector<uint16_t>& vmap_table = compiled_method->GetVmapTable();
+ size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]);
+ DCHECK((vmap_table_size == 0 && method->GetOatVmapTableOffset() == 0)
+ || code_offset == method->GetOatVmapTableOffset());
+ if (!file->WriteFully(&vmap_table[0], vmap_table_size)) {
+ PLOG(ERROR) << "Failed to write vmap table for " << PrettyMethod(method);
+ return false;
+ }
+ code_offset += vmap_table_size;
+ DCHECK_CODE_OFFSET();
+ }
+
+ const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method);
+ if (compiled_invoke_stub != NULL) {
+ uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset,
+ compiler_->GetInstructionSet());
+ uint32_t aligned_code_delta = aligned_code_offset - code_offset;
+ if (aligned_code_delta != 0) {
+ off_t new_offset = lseek(file->Fd(), aligned_code_delta, SEEK_CUR);
+ if (static_cast<uint32_t>(new_offset) != aligned_code_offset) {
+ PLOG(ERROR) << "Failed to seek to align invoke stub code. Actual: " << new_offset
+ << " Expected: " << aligned_code_offset;
+ return false;
+ }
+ code_offset += aligned_code_delta;
+ DCHECK_CODE_OFFSET();
+ }
+ DCHECK(IsAligned(code_offset, kArmAlignment)) << std::hex << code_offset;
+ const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
+ size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
+ DCHECK((invoke_stub_size == 0 && method->GetOatInvokeStubOffset() == 0)
+ || code_offset == method->GetOatInvokeStubOffset());
+ if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) {
+ PLOG(ERROR) << "Failed to write invoke stub code for " << PrettyMethod(method);
+ return false;
+ }
+ code_offset += invoke_stub_size;
+ DCHECK_CODE_OFFSET();
+ }
+
return code_offset;
}
diff --git a/src/oat_writer.h b/src/oat_writer.h
index 7cef892..a33ffc7 100644
--- a/src/oat_writer.h
+++ b/src/oat_writer.h
@@ -8,6 +8,7 @@
#include <cstddef>
#include "UniquePtr.h"
+#include "compiler.h"
#include "dex_cache.h"
#include "mem_map.h"
#include "oat.h"
@@ -30,29 +31,33 @@
// OatClasses[D]
//
// OatMethods[0] one variable sized OatMethods for each of C DexFile::ClassDefs
-// OatMethods[1] contains offsets to code
+// OatMethods[1] contains OatMethod entries with offsets to code, method properities, etc.
// ...
// OatMethods[C]
//
// padding if necessary so that the follow code will be page aligned
//
-// Method::GetCode() one variable sized code blob for each Method::GetCode() value
-// Method::GetCode()
-// Method::GetCode()
-// Method::GetCode()
-// Method::GetCode()
-// Method::GetCode()
+// CompiledMethod one variable sized blob with the contents of each CompiledMethod
+// CompiledMethod
+// CompiledMethod
+// CompiledMethod
+// CompiledMethod
+// CompiledMethod
// ...
-// Method::GetCode()
+// CompiledMethod
//
class OatWriter {
public:
// Write an oat file. Returns true on success, false on failure.
- static bool Create(const std::string& filename, const ClassLoader* class_loader);
+ static bool Create(const std::string& filename,
+ const ClassLoader* class_loader,
+ const Compiler& compiler);
private:
- OatWriter(const std::vector<const DexFile*>& dex_files, const ClassLoader* class_loader);
+ OatWriter(const std::vector<const DexFile*>& dex_files,
+ const ClassLoader* class_loader,
+ const Compiler& compiler);
~OatWriter();
size_t InitOatHeader();
@@ -128,12 +133,14 @@
bool Write(File* file) const;
// data to write
- std::vector<uint32_t> method_offsets_;
+ std::vector<OatMethodOffsets> method_offsets_;
private:
DISALLOW_COPY_AND_ASSIGN(OatMethods);
};
+ const Compiler* compiler_;
+
// TODO: remove the ClassLoader when the code storage moves out of Method
const ClassLoader* class_loader_;
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 27dbdee..8113c2b 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -165,34 +165,12 @@
// object_bytes, RoundUp(object_bytes, kObjectAlignment) - object_bytes);
if (obj->IsMethod()) {
Method* method = obj->AsMethod();
- if (!method->IsPhony()) {
- const ByteArray* code = method->GetCodeArray();
- const int8_t* code_base = NULL;
- const int8_t* code_limit = NULL;
- if (code != NULL) {
- size_t code_bytes = code->GetLength();
- code_base = code->GetData();
- code_limit = code_base + code_bytes;
- if (method->IsNative()) {
- state->stats_.managed_to_native_code_bytes += code_bytes;
- } else {
- state->stats_.managed_code_bytes += code_bytes;
- }
- } else {
- code_base = reinterpret_cast<const int8_t*>(method->GetCode());
- }
- StringAppendF(&summary, "\tCODE %p-%p\n", code_base, code_limit);
+ if (!method->IsCalleeSaveMethod()) {
+ const int8_t* code =reinterpret_cast<const int8_t*>(method->GetCode());
+ StringAppendF(&summary, "\tCODE %p\n", code);
- const ByteArray* invoke = method->GetInvokeStubArray();
- const int8_t* invoke_base = NULL;
- const int8_t* invoke_limit = NULL;
- if (invoke != NULL) {
- size_t native_to_managed_code_bytes = invoke->GetLength();
- invoke_base = invoke->GetData();
- invoke_limit = invoke_base + native_to_managed_code_bytes;
- state->stats_.native_to_managed_code_bytes += native_to_managed_code_bytes;
- StringAppendF(&summary, "\tJNI STUB %p-%p\n", invoke_base, invoke_limit);
- }
+ const Method::InvokeStub* invoke_stub = method->GetInvokeStub();
+ StringAppendF(&summary, "\tJNI STUB %p\n", invoke_stub);
}
if (method->IsNative()) {
if (method->IsRegistered()) {
@@ -200,26 +178,26 @@
} else {
StringAppendF(&summary, "\tNATIVE UNREGISTERED\n");
}
- DCHECK(method->GetRegisterMapHeader() == NULL);
- DCHECK(method->GetRegisterMapData() == NULL);
- DCHECK(method->GetMappingTable() == NULL);
+ DCHECK(method->GetRegisterMapHeader() == NULL) << PrettyMethod(method);
+ DCHECK(method->GetRegisterMapData() == NULL) << PrettyMethod(method);
+ DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
} else if (method->IsAbstract()) {
StringAppendF(&summary, "\tABSTRACT\n");
- DCHECK(method->GetRegisterMapHeader() == NULL);
- DCHECK(method->GetRegisterMapData() == NULL);
- DCHECK(method->GetMappingTable() == NULL);
- } else if (method->IsPhony()) {
- StringAppendF(&summary, "\tPHONY\n");
- DCHECK(method->GetRegisterMapHeader() == NULL);
- DCHECK(method->GetRegisterMapData() == NULL);
- DCHECK(method->GetMappingTable() == NULL);
+ DCHECK(method->GetRegisterMapHeader() == NULL) << PrettyMethod(method);
+ DCHECK(method->GetRegisterMapData() == NULL) << PrettyMethod(method);
+ DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
+ } else if (method->IsCalleeSaveMethod()) {
+ StringAppendF(&summary, "\tCALLEE SAVE METHOD\n");
+ DCHECK(method->GetRegisterMapHeader() == NULL) << PrettyMethod(method);
+ DCHECK(method->GetRegisterMapData() == NULL) << PrettyMethod(method);
+ DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
} else {
size_t register_map_bytes = (method->GetRegisterMapHeader()->GetLength() +
method->GetRegisterMapData()->GetLength());
state->stats_.register_map_bytes += register_map_bytes;
if (method->GetMappingTable() != NULL) {
- size_t pc_mapping_table_bytes = method->GetMappingTable()->GetLength();
+ size_t pc_mapping_table_bytes = method->GetMappingTableLength();
state->stats_.pc_mapping_table_bytes += pc_mapping_table_bytes;
}
diff --git a/src/oatexec.cc b/src/oatexec.cc
index 9632ca2..f1d63c3 100644
--- a/src/oatexec.cc
+++ b/src/oatexec.cc
@@ -17,20 +17,20 @@
static bool IsMethodPublic(JNIEnv* env, jclass clazz, jmethodID method_id) {
ScopedLocalRef<jobject> reflected(env, env->ToReflectedMethod(clazz, method_id, JNI_FALSE));
if (reflected.get() == NULL) {
- fprintf(stderr, "Unable to get reflected method\n");
+ fprintf(stderr, "Failed to get reflected method\n");
return false;
}
// We now have a Method instance. We need to call its
// getModifiers() method.
ScopedLocalRef<jclass> method(env, env->FindClass("java/lang/reflect/Method"));
if (method.get() == NULL) {
- fprintf(stderr, "Unable to find class Method\n");
+ fprintf(stderr, "Failed to find class Method\n");
return false;
}
static const int PUBLIC = 0x0001; // java.lang.reflect.Modifiers.PUBLIC
jmethodID get_modifiers = env->GetMethodID(method.get(), "getModifiers", "()I");
if (get_modifiers == NULL) {
- fprintf(stderr, "Unable to find reflect.Method.getModifiers\n");
+ fprintf(stderr, "Failed to find reflect.Method.getModifiers\n");
return false;
}
int modifiers = env->CallIntMethod(reflected.get(), get_modifiers);
diff --git a/src/object.cc b/src/object.cc
index c43fe49..99cdbc8 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -620,21 +620,18 @@
}
uint32_t Method::ToDexPC(const uintptr_t pc) const {
- IntArray* mapping_table = GetMappingTable();
+ const uint32_t* mapping_table = GetMappingTable();
if (mapping_table == NULL) {
DCHECK(IsNative());
return DexFile::kDexNoIndex; // Special no mapping case
}
- size_t mapping_table_length = mapping_table->GetLength();
+ size_t mapping_table_length = GetMappingTableLength();
uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(GetCode());
- if (GetCodeArray() != NULL) {
- CHECK_LT(sought_offset, static_cast<uint32_t>(GetCodeArray()->GetLength()));
- }
uint32_t best_offset = 0;
uint32_t best_dex_offset = 0;
for (size_t i = 0; i < mapping_table_length; i += 2) {
- uint32_t map_offset = mapping_table->Get(i);
- uint32_t map_dex_offset = mapping_table->Get(i + 1);
+ uint32_t map_offset = mapping_table[i];
+ uint32_t map_dex_offset = mapping_table[i + 1];
if (map_offset == sought_offset) {
best_offset = map_offset;
best_dex_offset = map_dex_offset;
@@ -649,19 +646,16 @@
}
uintptr_t Method::ToNativePC(const uint32_t dex_pc) const {
- IntArray* mapping_table = GetMappingTable();
+ const uint32_t* mapping_table = GetMappingTable();
if (mapping_table == NULL) {
DCHECK(dex_pc == 0);
return 0; // Special no mapping/pc == 0 case
}
- size_t mapping_table_length = mapping_table->GetLength();
+ size_t mapping_table_length = GetMappingTableLength();
for (size_t i = 0; i < mapping_table_length; i += 2) {
- uint32_t map_offset = mapping_table->Get(i);
- uint32_t map_dex_offset = mapping_table->Get(i + 1);
+ uint32_t map_offset = mapping_table[i];
+ uint32_t map_dex_offset = mapping_table[i + 1];
if (map_dex_offset == dex_pc) {
- if (GetCodeArray() != NULL) {
- DCHECK_LT(map_offset, static_cast<uint32_t>(GetCodeArray()->GetLength()));
- }
return reinterpret_cast<uintptr_t>(GetCode()) + map_offset;
}
}
@@ -694,58 +688,6 @@
return DexFile::kDexNoIndex;
}
-void Method::SetCodeArray(ByteArray* code_array, InstructionSet instruction_set) {
-// TODO: restore this check or warning when compile time code storage is moved out of Method
-// CHECK(GetCode() == NULL || IsNative()) << PrettyMethod(this);
-// if (GetCode() != NULL && !IsNative()) {
-// LOG(WARNING) << "Calling SetCode more than once for " << PrettyMethod(this);
-// }
- SetFieldPtr<ByteArray*>(OFFSET_OF_OBJECT_MEMBER(Method, code_array_), code_array, false);
-
- void* code;
- if (code_array != NULL) {
- code = code_array->GetData();
- if (instruction_set == kThumb2) {
- uintptr_t address = reinterpret_cast<uintptr_t>(code);
- // Set the low-order bit so a BLX will switch to Thumb mode
- address |= 0x1;
- code = reinterpret_cast<void*>(address);
- }
- } else {
- code = NULL;
- }
- SetCode(code);
-}
-
-bool Method::IsWithinCode(uintptr_t pc) const {
- if (pc == 0) {
- // PC of 0 represents the beginning of a stack trace either a native or where we have a callee
- // save method that has no code
- DCHECK(IsNative() || IsPhony());
- return true;
- } else {
-#if defined(__arm__)
- pc &= ~0x1; // clear any possible thumb instruction mode bit
-#endif
- if (GetCodeArray() == NULL) {
- return true;
- }
- uint32_t rel_offset = pc - reinterpret_cast<uintptr_t>(GetCodeArray()->GetData());
- // Strictly the following test should be a less-than, however, if the last
- // instruction is a call to an exception throw we may see return addresses
- // that are 1 beyond the end of code.
- return rel_offset <= static_cast<uint32_t>(GetCodeArray()->GetLength());
- }
-}
-
-void Method::SetInvokeStub(const ByteArray* invoke_stub_array) {
- const InvokeStub* invoke_stub = reinterpret_cast<InvokeStub*>(invoke_stub_array->GetData());
- SetFieldPtr<const ByteArray*>(
- OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_array_), invoke_stub_array, false);
- SetFieldPtr<const InvokeStub*>(
- OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_), invoke_stub, false);
-}
-
void Method::Invoke(Thread* self, Object* receiver, byte* args, JValue* result) const {
// Push a transition back into managed code onto the linked list in thread.
CHECK_EQ(Thread::kRunnable, self->GetState());
@@ -779,7 +721,7 @@
self->PopNativeToManagedRecord(record);
}
-bool Method::IsRegistered() {
+bool Method::IsRegistered() const {
void* native_method = GetFieldPtr<void*>(OFFSET_OF_OBJECT_MEMBER(Method, native_method_), false);
void* jni_stub = Runtime::Current()->GetJniStubArray()->GetData();
return native_method != jni_stub;
diff --git a/src/object.h b/src/object.h
index 03fa359..de3075b 100644
--- a/src/object.h
+++ b/src/object.h
@@ -404,6 +404,16 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Object);
};
+struct ObjectIdentityHash {
+ size_t operator()(const art::Object* const& obj) const {
+#ifdef MOVING_GARBAGE_COLLECTOR
+ // TODO: we'll need to use the Object's internal concept of identity
+ UNIMPLEMENTED(FATAL);
+#endif
+ return reinterpret_cast<size_t>(obj);
+ }
+};
+
// C++ mirror of java.lang.reflect.AccessibleObject
class MANAGED AccessibleObject : public Object {
private:
@@ -667,8 +677,7 @@
}
void SetMethodIndex(uint16_t new_method_index) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_index_),
- new_method_index, false);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_index_), new_method_index, false);
}
static MemberOffset MethodIndexOffset() {
@@ -680,8 +689,7 @@
}
void SetCodeItemOffset(uint32_t new_code_off) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Method, code_item_offset_),
- new_code_off, false);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, code_item_offset_), new_code_off, false);
}
// Number of 32bit registers that would be required to hold all the arguments
@@ -694,22 +702,19 @@
uint16_t NumRegisters() const;
void SetNumRegisters(uint16_t new_num_registers) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_),
- new_num_registers, false);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_registers_), new_num_registers, false);
}
uint16_t NumIns() const;
void SetNumIns(uint16_t new_num_ins) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_),
- new_num_ins, false);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_ins_), new_num_ins, false);
}
uint16_t NumOuts() const;
void SetNumOuts(uint16_t new_num_outs) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_),
- new_num_outs, false);
+ SetField32(OFFSET_OF_OBJECT_MEMBER(Method, num_outs_), new_num_outs, false);
}
uint32_t GetProtoIdx() const;
@@ -806,15 +811,11 @@
void Invoke(Thread* self, Object* receiver, byte* args, JValue* result) const;
- const ByteArray* GetCodeArray() const {
- return GetFieldPtr<const ByteArray*>(OFFSET_OF_OBJECT_MEMBER(Method, code_array_), false);
- }
-
const void* GetCode() const {
return GetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_), false);
}
- void SetCode(void* code) {
+ void SetCode(const void* code) {
SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_), code, false);
}
@@ -828,29 +829,77 @@
SetCode(reinterpret_cast<void*>(code_offset));
}
- void SetCodeArray(ByteArray* code_array, InstructionSet instruction_set);
-
static MemberOffset GetCodeOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, code_);
}
- // Is the given PC within the code array?
- bool IsWithinCode(uintptr_t pc) const;
-
- IntArray* GetMappingTable() const {
- return GetFieldObject<IntArray*>(OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_), false);
+ const uint32_t* GetMappingTable() const {
+ const uint32_t* map = GetMappingTableRaw();
+ if (map == NULL) {
+ return map;
+ }
+ return map + 1;
}
- void SetMappingTable(IntArray* mapping_table) {
- SetFieldPtr<IntArray*>(OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_), mapping_table, false);
+ uint32_t GetMappingTableLength() const {
+ const uint32_t* map = GetMappingTableRaw();
+ if (map == NULL) {
+ return 0;
+ }
+ return *map;
}
- ShortArray* GetVMapTable() const {
- return GetFieldObject<ShortArray*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), false);
+ const uint32_t* GetMappingTableRaw() const {
+ return GetFieldPtr<const uint32_t*>(OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_), false);
}
- void SetVMapTable(ShortArray* vmap_table) {
- SetFieldPtr<ShortArray*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), vmap_table, false);
+ void SetMappingTable(const uint32_t* mapping_table) {
+ SetFieldPtr<const uint32_t*>(OFFSET_OF_OBJECT_MEMBER(Method, mapping_table_),
+ mapping_table, false);
+ }
+
+ uint32_t GetOatMappingTableOffset() const {
+ CHECK(!Runtime::Current()->IsStarted());
+ return reinterpret_cast<uint32_t>(GetMappingTableRaw());
+ }
+
+ void SetOatMappingTableOffset(uint32_t mapping_table_offset) {
+ CHECK(!Runtime::Current()->IsStarted());
+ SetMappingTable(reinterpret_cast<const uint32_t*>(mapping_table_offset));
+ }
+
+ const uint16_t* GetVmapTable() const {
+ const uint16_t* vmap = GetVmapTableRaw();
+ if (vmap == NULL) {
+ return vmap;
+ }
+ return vmap + 1;
+ }
+
+ uint16_t GetVmapTableLength() const {
+ const uint16_t* vmap = GetVmapTableRaw();
+ if (vmap == NULL) {
+ return 0;
+ }
+ return *vmap;
+ }
+
+ const uint16_t* GetVmapTableRaw() const {
+ return GetFieldPtr<const uint16_t*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), false);
+ }
+
+ void SetVmapTable(const uint16_t* vmap_table) {
+ SetFieldPtr<const uint16_t*>(OFFSET_OF_OBJECT_MEMBER(Method, vmap_table_), vmap_table, false);
+ }
+
+ uint32_t GetOatVmapTableOffset() const {
+ CHECK(!Runtime::Current()->IsStarted());
+ return reinterpret_cast<uint32_t>(GetVmapTableRaw());
+ }
+
+ void SetOatVmapTableOffset(uint32_t vmap_table_offset) {
+ CHECK(!Runtime::Current()->IsStarted());
+ SetVmapTable(reinterpret_cast<uint16_t*>(vmap_table_offset));
}
size_t GetFrameSizeInBytes() const {
@@ -881,7 +930,7 @@
return_pc_offset_in_bytes, false);
}
- bool IsRegistered();
+ bool IsRegistered() const;
void RegisterNative(const void* native_method);
@@ -895,13 +944,6 @@
return reinterpret_cast<const void*>(GetField32(NativeMethodOffset(), false));
}
- ByteArray* GetInvokeStubArray() const {
- ByteArray* result = GetFieldPtr<ByteArray*>(
- OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_array_), false);
- // TODO: DCHECK(result != NULL); should be ahead of time compiled
- return result;
- }
-
// Native to managed invocation stub entry point
InvokeStub* GetInvokeStub() const {
InvokeStub* result = GetFieldPtr<InvokeStub*>(
@@ -910,6 +952,21 @@
return result;
}
+ void SetInvokeStub(InvokeStub* invoke_stub) {
+ SetFieldPtr<const InvokeStub*>(OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_),
+ invoke_stub, false);
+ }
+
+ uint32_t GetOatInvokeStubOffset() const {
+ CHECK(!Runtime::Current()->IsStarted());
+ return reinterpret_cast<uint32_t>(GetInvokeStub());
+ }
+
+ void SetOatInvokeStubOffset(uint32_t invoke_stub_offset) {
+ CHECK(!Runtime::Current()->IsStarted());
+ SetInvokeStub(reinterpret_cast<InvokeStub*>(invoke_stub_offset));
+ }
+
static MemberOffset GetInvokeStubOffset() {
return OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_);
}
@@ -926,8 +983,6 @@
return OFFSET_OF_OBJECT_MEMBER(Method, method_index_);
}
- void SetInvokeStub(const ByteArray* invoke_stub_array);
-
uint32_t GetCoreSpillMask() const {
return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, core_spill_mask_), false);
}
@@ -947,7 +1002,7 @@
}
// Is this a hand crafted method used for something like describing callee saves?
- bool IsPhony() const {
+ bool IsCalleeSaveMethod() const {
Runtime* runtime = Runtime::Current();
bool result = false;
for (int i=0; i < Runtime::kLastCalleeSaveType; i++) {
@@ -1005,9 +1060,6 @@
ObjectArray<Class>* java_parameter_types_;
Class* java_return_type_;
- // Storage for code_
- const ByteArray* code_array_;
-
// short cuts to declaring_class_->dex_cache_ member for fast compiled code access
CodeAndDirectMethods* dex_cache_code_and_direct_methods_;
@@ -1026,12 +1078,6 @@
// 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_
- IntArray* mapping_table_;
-
// Byte arrays that hold data for the register maps
const ByteArray* register_map_data_;
const ByteArray* register_map_header_;
@@ -1051,9 +1097,6 @@
// (IDLjava/lang/Thread;)Ljava/lang/Object;
String* signature_;
- // Storage for Dalvik virtual register mapping_table_
- ShortArray* vmap_table_;
-
uint32_t java_generic_types_are_initialized_;
// Access flags; low 16 bits are defined by spec.
@@ -1081,6 +1124,8 @@
// Index of the return type
uint32_t java_return_type_idx_;
+ const uint32_t* mapping_table_;
+
// For concrete virtual methods, this is the offset of the method
// in Class::vtable_.
//
@@ -1105,6 +1150,8 @@
// Offset of return PC within frame for compiled code (in bytes)
size_t return_pc_offset_in_bytes_;
+ const uint16_t* vmap_table_;
+
uint32_t java_slot_;
static Class* java_lang_reflect_Constructor_;
diff --git a/src/runtime.cc b/src/runtime.cc
index 7e27918..e46cf88 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -640,7 +640,7 @@
}
method->SetName(intern_table_->InternStrong(name));
method->SetSignature(intern_table_->InternStrong("()V"));
- method->SetCodeArray(NULL, insns);
+ method->SetCode(NULL);
if ((insns == kThumb2) || (insns == kArm)) {
uint32_t ref_spills = (1 << art::arm::R5) | (1 << art::arm::R6) | (1 << art::arm::R7) |
(1 << art::arm::R8) | (1 << art::arm::R10) | (1 << art::arm::R11);
diff --git a/src/space.cc b/src/space.cc
index 248f7e8..ae35f57 100644
--- a/src/space.cc
+++ b/src/space.cc
@@ -115,7 +115,7 @@
}
UniquePtr<MemMap> map(MemMap::Map(image_header.GetImageBaseAddr(),
file->Length(),
- // TODO: selectively PROT_EXEC when image contains a code space
+ // TODO: selectively PROT_EXEC an image subset containing stubs
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_FIXED,
file->Fd(),
diff --git a/src/stack.cc b/src/stack.cc
index 9f01dab..985fd38 100644
--- a/src/stack.cc
+++ b/src/stack.cc
@@ -19,10 +19,12 @@
#include "compiler.h"
#include "object.h"
+int oatVRegOffsetFromMethod(art::Method* method, int reg);
+
namespace art {
bool Frame::HasMethod() const {
- return GetMethod() != NULL && (!GetMethod()->IsPhony());
+ return GetMethod() != NULL && (!GetMethod()->IsCalleeSaveMethod());
}
void Frame::Next() {
diff --git a/src/stack_walk.cc b/src/stack_walk.cc
index 2c29e75..a1f6e0f 100644
--- a/src/stack_walk.cc
+++ b/src/stack_walk.cc
@@ -43,7 +43,7 @@
// pc == NULL: m is either a native method or a phony method
return;
}
- if (m->IsPhony()) {
+ if (m->IsCalleeSaveMethod()) {
LOG(WARNING) << "no PC for " << PrettyMethod(m);
return;
}
diff --git a/src/thread.cc b/src/thread.cc
index 532b581..c50bf0a 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -968,7 +968,7 @@
while (frame.GetSP() != 0) {
for ( ; frame.GetMethod() != 0; frame.Next()) {
- DCHECK(frame.GetMethod()->IsWithinCode(pc));
+ // DCHECK(frame.GetMethod()->IsWithinCode(pc)); // TODO: restore IsWithinCode
visitor->VisitFrame(frame, pc);
pc = frame.GetReturnPC();
// Move the PC back 2 bytes as a call will frequently terminate the
@@ -993,7 +993,7 @@
if (frame.GetSP() != 0) {
for ( ; frame.GetMethod() != 0; frame.Next()) {
- DCHECK(frame.GetMethod()->IsWithinCode(pc));
+ // DCHECK(frame.GetMethod()->IsWithinCode(pc)); // TODO: restore IsWithinCode
visitor->VisitFrame(frame, pc);
pc = frame.GetReturnPC();
// Move the PC back 2 bytes as a call will frequently terminate the
@@ -1143,7 +1143,7 @@
return;
}
uint32_t dex_pc = DexFile::kDexNoIndex;
- if (method->IsPhony()) {
+ if (method->IsCalleeSaveMethod()) {
// ignore callee save method
} else if (method->IsNative()) {
native_method_count_++;
@@ -1229,13 +1229,13 @@
void VisitFrame(const Frame& frame, uintptr_t pc) {
Method* m = frame.GetMethod();
// Process register map (which native and callee save methods don't have)
- if (!m->IsNative() && !m->IsPhony()) {
+ if (!m->IsNative() && !m->IsCalleeSaveMethod()) {
UniquePtr<art::DexVerifier::RegisterMap> map(art::DexVerifier::GetExpandedRegisterMap(m));
const uint8_t* reg_bitmap = art::DexVerifier::RegisterMapGetLine(map.get(), m->ToDexPC(pc));
LOG(INFO) << "Visiting stack roots in " << PrettyMethod(m, false)
<< "@ PC: " << m->ToDexPC(pc);
CHECK(reg_bitmap != NULL);
- ShortArray* vmap = m->GetVMapTable();
+ const uint16_t* vmap = m->GetVmapTable();
// For all dex registers
for (int reg = 0; reg < m->NumRegisters(); ++reg) {
// Does this register hold a reference?
@@ -1244,8 +1244,8 @@
bool in_context = false;
uint32_t vmap_offset = 0xEBAD0FF5;
// TODO: take advantage of the registers being ordered
- for (int i = 0; i < vmap->GetLength(); i++) {
- if (vmap->Get(i) == reg) {
+ for (int i = 0; i < m->GetVmapTableLength(); i++) {
+ if (vmap[i] == reg) {
in_context = true;
vmap_offset = i;
break;