diff options
47 files changed, 1814 insertions, 1315 deletions
diff --git a/build/Android.common.mk b/build/Android.common.mk index 968228bf48..4b0cdfec0e 100644 --- a/build/Android.common.mk +++ b/build/Android.common.mk @@ -247,7 +247,7 @@ TEST_HOST_SRC_FILES := \ TEST_DEX_DIRECTORIES := \ AbstractMethod \ AllFields \ - CreateMethodDescriptor \ + CreateMethodSignature \ ExceptionHandle \ ExceptionTest \ Fibonacci \ diff --git a/src/calling_convention.h b/src/calling_convention.h index 3a7cf1ed1e..7e87264159 100644 --- a/src/calling_convention.h +++ b/src/calling_convention.h @@ -124,8 +124,6 @@ class JniCallingConvention : public CallingConvention { // always at the bottom of a frame, but this doesn't work for outgoing // native args). Includes alignment. virtual size_t FrameSize() = 0; - // Offset within the frame of the return pc - virtual size_t ReturnPcOffset() = 0; // Size of outgoing arguments, including alignment virtual size_t OutArgSize() = 0; // Number of references in stack indirect reference table diff --git a/src/calling_convention_arm.cc b/src/calling_convention_arm.cc index 89d41700f8..fc8c662f73 100644 --- a/src/calling_convention_arm.cc +++ b/src/calling_convention_arm.cc @@ -146,11 +146,6 @@ size_t ArmJniCallingConvention::OutArgSize() { kStackAlignment); } -size_t ArmJniCallingConvention::ReturnPcOffset() { - // Link register is always the first value pushed when the frame is constructed - return FrameSize() - kPointerSize; -} - // Will reg be crushed by an outgoing argument? bool ArmJniCallingConvention::IsMethodRegisterClobberedPreCall() { return true; // The method register R0 is always clobbered by the JNIEnv diff --git a/src/calling_convention_arm.h b/src/calling_convention_arm.h index 2a056a82c3..4ecf9df562 100644 --- a/src/calling_convention_arm.h +++ b/src/calling_convention_arm.h @@ -37,7 +37,6 @@ class ArmJniCallingConvention : public JniCallingConvention { // JNI calling convention virtual void Next(); // Override default behavior for AAPCS virtual size_t FrameSize(); - virtual size_t ReturnPcOffset(); virtual size_t OutArgSize(); virtual const std::vector<ManagedRegister>& CalleeSaveRegisters() const { return callee_save_regs_; diff --git a/src/calling_convention_x86.cc b/src/calling_convention_x86.cc index da76e177c7..07ccece956 100644 --- a/src/calling_convention_x86.cc +++ b/src/calling_convention_x86.cc @@ -84,11 +84,6 @@ size_t X86JniCallingConvention::OutArgSize() { return RoundUp(NumberOfOutgoingStackArgs() * kPointerSize, kStackAlignment); } -size_t X86JniCallingConvention::ReturnPcOffset() { - // Return PC is pushed at the top of the frame by the call into the method - return FrameSize() - kPointerSize; -} - bool X86JniCallingConvention::IsMethodRegisterClobberedPreCall() { return GetMethod()->IsSynchronized(); // Monitor enter crushes the method register } diff --git a/src/calling_convention_x86.h b/src/calling_convention_x86.h index b796ba0d5a..f3c85e92f5 100644 --- a/src/calling_convention_x86.h +++ b/src/calling_convention_x86.h @@ -37,7 +37,6 @@ class X86JniCallingConvention : public JniCallingConvention { virtual ManagedRegister InterproceduralScratchRegister(); // JNI calling convention virtual size_t FrameSize(); - virtual size_t ReturnPcOffset(); virtual size_t OutArgSize(); virtual const std::vector<ManagedRegister>& CalleeSaveRegisters() const { DCHECK(callee_save_regs_.empty()); diff --git a/src/class_linker.cc b/src/class_linker.cc index 4f387db472..584c53ebf0 100644 --- a/src/class_linker.cc +++ b/src/class_linker.cc @@ -14,6 +14,7 @@ #include "dex_verifier.h" #include "heap.h" #include "intern_table.h" +#include "leb128.h" #include "logging.h" #include "monitor.h" #include "oat_file.h" @@ -1070,17 +1071,12 @@ Class* ClassLinker::DefineClass(const std::string& descriptor, size_t ClassLinker::SizeOfClass(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def) { const byte* class_data = dex_file.GetClassData(dex_class_def); - DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data); - size_t num_static_fields = header.static_fields_size_; size_t num_ref = 0; size_t num_32 = 0; size_t num_64 = 0; - if (num_static_fields != 0) { - uint32_t last_idx = 0; - for (size_t i = 0; i < num_static_fields; ++i) { - DexFile::Field dex_field; - dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx); - const DexFile::FieldId& field_id = dex_file.GetFieldId(dex_field.field_idx_); + if (class_data != NULL) { + for (ClassDataItemIterator it(dex_file, class_data); it.HasNextStaticField(); it.Next()) { + const DexFile::FieldId& field_id = dex_file.GetFieldId(it.GetMemberIndex()); const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id); char c = descriptor[0]; if (c == 'L' || c == '[') { @@ -1092,7 +1088,6 @@ size_t ClassLinker::SizeOfClass(const DexFile& dex_file, } } } - // start with generic class data size_t size = sizeof(Class); // follow with reference fields which must be contiguous at start @@ -1137,9 +1132,6 @@ void ClassLinker::LoadClass(const DexFile& dex_file, CHECK(klass.get() != NULL); CHECK(klass->GetDexCache() != NULL); CHECK_EQ(Class::kStatusNotReady, klass->GetStatus()); - const byte* class_data = dex_file.GetClassData(dex_class_def); - DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data); - const char* descriptor = dex_file.GetClassDescriptor(dex_class_def); CHECK(descriptor != NULL); @@ -1164,12 +1156,7 @@ void ClassLinker::LoadClass(const DexFile& dex_file, klass->SetSuperClassTypeIdx(dex_class_def.superclass_idx_); klass->SetAnnotationsOffset(dex_class_def.annotations_off_); - size_t num_static_fields = header.static_fields_size_; - size_t num_instance_fields = header.instance_fields_size_; - size_t num_direct_methods = header.direct_methods_size_; - size_t num_virtual_methods = header.virtual_methods_size_; - - const char* source_file = dex_file.dexGetSourceFile(dex_class_def); + const char* source_file = dex_file.GetSourceFile(dex_class_def); if (source_file != NULL) { String* source_file_string = intern_table_->InternStrong(source_file); if (source_file_string == NULL) { @@ -1181,30 +1168,27 @@ void ClassLinker::LoadClass(const DexFile& dex_file, // Load class interfaces. LoadInterfaces(dex_file, dex_class_def, klass); - // Load static fields. - if (num_static_fields != 0) { - klass->SetSFields(AllocObjectArray<Field>(num_static_fields)); - uint32_t last_idx = 0; - for (size_t i = 0; i < num_static_fields; ++i) { - DexFile::Field dex_field; - dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx); - SirtRef<Field> sfield(AllocField()); - klass->SetStaticField(i, sfield.get()); - LoadField(dex_file, dex_field, klass, sfield); - } + // Load fields fields. + const byte* class_data = dex_file.GetClassData(dex_class_def); + if (class_data == NULL) { + return; // no fields or methods - for example a marker interface } - - // Load instance fields. - if (num_instance_fields != 0) { - klass->SetIFields(AllocObjectArray<Field>(num_instance_fields)); - uint32_t last_idx = 0; - for (size_t i = 0; i < num_instance_fields; ++i) { - DexFile::Field dex_field; - dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx); - SirtRef<Field> ifield(AllocField()); - klass->SetInstanceField(i, ifield.get()); - LoadField(dex_file, dex_field, klass, ifield); - } + ClassDataItemIterator it(dex_file, class_data); + if (it.NumStaticFields() != 0) { + klass->SetSFields(AllocObjectArray<Field>(it.NumStaticFields())); + } + if (it.NumInstanceFields() != 0) { + klass->SetIFields(AllocObjectArray<Field>(it.NumInstanceFields())); + } + for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) { + SirtRef<Field> sfield(AllocField()); + klass->SetStaticField(i, sfield.get()); + LoadField(dex_file, it, klass, sfield); + } + for (size_t i = 0; it.HasNextInstanceField(); i++, it.Next()) { + SirtRef<Field> ifield(AllocField()); + klass->SetInstanceField(i, ifield.get()); + LoadField(dex_file, it, klass, ifield); } UniquePtr<const OatFile::OatClass> oat_class; @@ -1221,41 +1205,35 @@ void ClassLinker::LoadClass(const DexFile& dex_file, } } } - size_t method_index = 0; - - // Load direct methods. - if (num_direct_methods != 0) { + // Load methods. + if (it.NumDirectMethods() != 0) { // TODO: append direct methods to class object - klass->SetDirectMethods(AllocObjectArray<Method>(num_direct_methods)); - uint32_t last_idx = 0; - for (size_t i = 0; i < num_direct_methods; ++i, ++method_index) { - DexFile::Method dex_method; - dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx); - SirtRef<Method> method(AllocMethod()); - klass->SetDirectMethod(i, method.get()); - LoadMethod(dex_file, dex_method, klass, method); - if (oat_class.get() != NULL) { - LinkCode(method, oat_class.get(), method_index); - } + klass->SetDirectMethods(AllocObjectArray<Method>(it.NumDirectMethods())); + } + if (it.NumVirtualMethods() != 0) { + // TODO: append direct methods to class object + klass->SetVirtualMethods(AllocObjectArray<Method>(it.NumVirtualMethods())); + } + size_t method_index = 0; + for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) { + SirtRef<Method> method(AllocMethod()); + klass->SetDirectMethod(i, method.get()); + LoadMethod(dex_file, it, klass, method); + if (oat_class.get() != NULL) { + LinkCode(method, oat_class.get(), method_index); } + method_index++; } - - // Load virtual methods. - if (num_virtual_methods != 0) { - // TODO: append virtual methods to class object - klass->SetVirtualMethods(AllocObjectArray<Method>(num_virtual_methods)); - uint32_t last_idx = 0; - for (size_t i = 0; i < num_virtual_methods; ++i, ++method_index) { - DexFile::Method dex_method; - dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx); - SirtRef<Method> method(AllocMethod()); - klass->SetVirtualMethod(i, method.get()); - LoadMethod(dex_file, dex_method, klass, method); - if (oat_class.get() != NULL) { - LinkCode(method, oat_class.get(), method_index); - } + for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) { + SirtRef<Method> method(AllocMethod()); + klass->SetVirtualMethod(i, method.get()); + LoadMethod(dex_file, it, klass, method); + if (oat_class.get() != NULL) { + LinkCode(method, oat_class.get(), method_index); } + method_index++; } + DCHECK(!it.HasNext()); } void ClassLinker::LoadInterfaces(const DexFile& dex_file, @@ -1273,15 +1251,13 @@ void ClassLinker::LoadInterfaces(const DexFile& dex_file, } } -void ClassLinker::LoadField(const DexFile& dex_file, - const DexFile::Field& src, - SirtRef<Class>& klass, - SirtRef<Field>& dst) { - const DexFile::FieldId& field_id = dex_file.GetFieldId(src.field_idx_); +void ClassLinker::LoadField(const DexFile& dex_file, const ClassDataItemIterator& it, + SirtRef<Class>& klass, SirtRef<Field>& dst) { + const DexFile::FieldId& field_id = dex_file.GetFieldId(it.GetMemberIndex()); dst->SetDeclaringClass(klass.get()); dst->SetName(ResolveString(dex_file, field_id.name_idx_, klass->GetDexCache())); dst->SetTypeIdx(field_id.type_idx_); - dst->SetAccessFlags(src.access_flags_); + dst->SetAccessFlags(it.GetMemberAccessFlags()); // In order to access primitive types using GetTypeDuringLinking we need to // ensure they are resolved into the dex cache @@ -1293,11 +1269,9 @@ void ClassLinker::LoadField(const DexFile& dex_file, } } -void ClassLinker::LoadMethod(const DexFile& dex_file, - const DexFile::Method& src, - SirtRef<Class>& klass, - SirtRef<Method>& dst) { - const DexFile::MethodId& method_id = dex_file.GetMethodId(src.method_idx_); +void ClassLinker::LoadMethod(const DexFile& dex_file, const ClassDataItemIterator& it, + SirtRef<Class>& klass, SirtRef<Method>& dst) { + const DexFile::MethodId& method_id = dex_file.GetMethodId(it.GetMemberIndex()); dst->SetDeclaringClass(klass.get()); String* method_name = ResolveString(dex_file, method_id.name_idx_, klass->GetDexCache()); @@ -1310,7 +1284,7 @@ void ClassLinker::LoadMethod(const DexFile& dex_file, } int32_t utf16_length; - std::string signature(dex_file.CreateMethodDescriptor(method_id.proto_idx_, &utf16_length)); + std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, &utf16_length)); String* signature_string = intern_table_->InternStrong(utf16_length, signature.c_str()); if (signature_string == NULL) { return; @@ -1333,14 +1307,14 @@ void ClassLinker::LoadMethod(const DexFile& dex_file, } dst->SetProtoIdx(method_id.proto_idx_); - dst->SetCodeItemOffset(src.code_off_); + dst->SetCodeItemOffset(it.GetMethodCodeItemOffset()); const char* shorty = dex_file.GetShorty(method_id.proto_idx_); String* shorty_string = intern_table_->InternStrong(shorty); dst->SetShorty(shorty_string); if (shorty_string == NULL) { return; } - dst->SetAccessFlags(src.access_flags_); + dst->SetAccessFlags(it.GetMemberAccessFlags()); uint32_t return_type_idx = dex_file.GetProtoId(method_id.proto_idx_).return_type_idx_; DCHECK_LT(return_type_idx, dex_file.NumTypeIds()); dst->SetReturnTypeIdx(return_type_idx); @@ -1354,14 +1328,14 @@ void ClassLinker::LoadMethod(const DexFile& dex_file, // TODO: check for finalize method - const DexFile::CodeItem* code_item = dex_file.GetCodeItem(src); + const DexFile::CodeItem* code_item = it.GetMethodCodeItem(); if (code_item != NULL) { dst->SetNumRegisters(code_item->registers_size_); dst->SetNumIns(code_item->ins_size_); dst->SetNumOuts(code_item->outs_size_); } else { uint16_t num_args = Method::NumArgRegisters(shorty); - if ((src.access_flags_ & kAccStatic) != 0) { + if ((it.GetMemberAccessFlags() & kAccStatic) != 0) { ++num_args; } dst->SetNumRegisters(num_args); @@ -1944,9 +1918,8 @@ bool ClassLinker::HasSameMethodDescriptorClasses(const Method* method, } const DexFile& dex_file = FindDexFile(method->GetDeclaringClass()->GetDexCache()); const DexFile::ProtoId& proto_id = dex_file.GetProtoId(method->GetProtoIdx()); - DexFile::ParameterIterator *it; - for (it = dex_file.GetParameterIterator(proto_id); it->HasNext(); it->Next()) { - const char* descriptor = it->GetDescriptor(); + for (DexFileParameterIterator it(dex_file, proto_id); it.HasNext(); it.Next()) { + const char* descriptor = it.GetDescriptor(); if (descriptor == NULL) { break; } @@ -2031,15 +2004,12 @@ bool ClassLinker::EnsureInitialized(Class* c, bool can_run_clinit) { } void ClassLinker::ConstructFieldMap(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, - Class* c, std::map<int, Field*>& field_map) { + Class* c, std::map<uint32_t, Field*>& field_map) { const ClassLoader* cl = c->GetClassLoader(); const byte* class_data = dex_file.GetClassData(dex_class_def); - DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data); - uint32_t last_idx = 0; - for (size_t i = 0; i < header.static_fields_size_; ++i) { - DexFile::Field dex_field; - dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx); - field_map[i] = ResolveField(dex_file, dex_field.field_idx_, c->GetDexCache(), cl, true); + ClassDataItemIterator it(dex_file, class_data); + for (size_t i = 0; it.HasNextStaticField(); i++, it.Next()) { + field_map[i] = ResolveField(dex_file, it.GetMemberIndex(), c->GetDexCache(), cl, true); } } @@ -2053,61 +2023,18 @@ void ClassLinker::InitializeStaticFields(Class* klass) { if (dex_cache == NULL) { return; } - const std::string descriptor(klass->GetDescriptor()->ToModifiedUtf8()); const DexFile& dex_file = FindDexFile(dex_cache); + const std::string descriptor(klass->GetDescriptor()->ToModifiedUtf8()); const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor); CHECK(dex_class_def != NULL); + EncodedStaticFieldValueIterator it(dex_file, dex_cache, this, *dex_class_def); - // We reordered the fields, so we need to be able to map the field indexes to the right fields. - std::map<int, Field*> field_map; - ConstructFieldMap(dex_file, *dex_class_def, klass, field_map); - - const byte* addr = dex_file.GetEncodedArray(*dex_class_def); - if (addr == NULL) { - // All this class' static fields have default values. - return; - } - size_t array_size = DecodeUnsignedLeb128(&addr); - for (size_t i = 0; i < array_size; ++i) { - Field* field = field_map[i]; - JValue value; - DexFile::ValueType type = dex_file.ReadEncodedValue(&addr, &value); - switch (type) { - case DexFile::kByte: - field->SetByte(NULL, value.b); - break; - case DexFile::kShort: - field->SetShort(NULL, value.s); - break; - case DexFile::kChar: - field->SetChar(NULL, value.c); - break; - case DexFile::kInt: - field->SetInt(NULL, value.i); - break; - case DexFile::kLong: - field->SetLong(NULL, value.j); - break; - case DexFile::kFloat: - field->SetFloat(NULL, value.f); - break; - case DexFile::kDouble: - field->SetDouble(NULL, value.d); - break; - case DexFile::kString: { - uint32_t string_idx = value.i; - const String* resolved = ResolveString(dex_file, string_idx, klass->GetDexCache()); - field->SetObject(NULL, resolved); - break; - } - case DexFile::kBoolean: - field->SetBoolean(NULL, value.z); - break; - case DexFile::kNull: - field->SetObject(NULL, value.l); - break; - default: - LOG(FATAL) << "Unknown type " << static_cast<int>(type); + if (it.HasNext()) { + // We reordered the fields, so we need to be able to map the field indexes to the right fields. + std::map<uint32_t, Field*> field_map; + ConstructFieldMap(dex_file, *dex_class_def, klass, field_map); + for (size_t i = 0; it.HasNext(); i++, it.Next()) { + it.ReadValueToField(field_map[i]); } } } @@ -2135,7 +2062,7 @@ bool ClassLinker::LinkClass(SirtRef<Class>& klass) { bool ClassLinker::LoadSuperAndInterfaces(SirtRef<Class>& klass, const DexFile& dex_file) { CHECK_EQ(Class::kStatusIdx, klass->GetStatus()); - if (klass->GetSuperClassTypeIdx() != DexFile::kDexNoIndex) { + if (klass->GetSuperClassTypeIdx() != DexFile::kDexNoIndex16) { Class* super_class = ResolveType(dex_file, klass->GetSuperClassTypeIdx(), klass.get()); if (super_class == NULL) { DCHECK(Thread::Current()->IsExceptionPending()); @@ -2691,7 +2618,7 @@ Class* ClassLinker::ResolveType(const DexFile& dex_file, const ClassLoader* class_loader) { Class* resolved = dex_cache->GetResolvedType(type_idx); if (resolved == NULL) { - const char* descriptor = dex_file.dexStringByTypeIdx(type_idx); + const char* descriptor = dex_file.StringByTypeIdx(type_idx); resolved = FindClass(descriptor, class_loader); if (resolved != NULL) { Class* check = resolved; @@ -2731,8 +2658,8 @@ Method* ClassLinker::ResolveMethod(const DexFile& dex_file, return NULL; } - const char* name = dex_file.dexStringById(method_id.name_idx_); - std::string signature(dex_file.CreateMethodDescriptor(method_id.proto_idx_, NULL)); + const char* name = dex_file.StringDataByIdx(method_id.name_idx_); + std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL)); if (is_direct) { resolved = klass->FindDirectMethod(name, signature); } else if (klass->IsInterface()) { diff --git a/src/class_linker.h b/src/class_linker.h index 03c8341d3a..478a26041e 100644 --- a/src/class_linker.h +++ b/src/class_linker.h @@ -282,7 +282,7 @@ class ClassLinker { void AppendToBootClassPath(const DexFile& dex_file, SirtRef<DexCache>& dex_cache); void ConstructFieldMap(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def, - Class* c, std::map<int, Field*>& field_map); + Class* c, std::map<uint32_t, Field*>& field_map); size_t SizeOfClass(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def); @@ -296,15 +296,11 @@ class ClassLinker { const DexFile::ClassDef& dex_class_def, SirtRef<Class>& klass); - void LoadField(const DexFile& dex_file, - const DexFile::Field& dex_field, - SirtRef<Class>& klass, + void LoadField(const DexFile& dex_file, const ClassDataItemIterator& it, SirtRef<Class>& klass, SirtRef<Field>& dst); - void LoadMethod(const DexFile& dex_file, - const DexFile::Method& dex_method, - SirtRef<Class>& klass, - SirtRef<Method>& dst); + void LoadMethod(const DexFile& dex_file, const ClassDataItemIterator& dex_method, + SirtRef<Class>& klass, SirtRef<Method>& dst); // Inserts a class into the class table. Returns true if the class // was inserted. diff --git a/src/common_test.h b/src/common_test.h index 3966742017..56b54a3851 100644 --- a/src/common_test.h +++ b/src/common_test.h @@ -100,7 +100,9 @@ class CommonTest : public testing::Test { void MakeExecutable(Method* method) { CHECK(method != NULL); - const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method); + const CompiledInvokeStub* compiled_invoke_stub = + compiler_->FindInvokeStub(method->IsStatic(), + method->GetShorty()->ToModifiedUtf8().c_str()); CHECK(compiled_invoke_stub != NULL) << PrettyMethod(method); const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode(); MakeExecutable(invoke_stub); @@ -110,7 +112,11 @@ class CommonTest : public testing::Test { << " invoke_stub=" << reinterpret_cast<void*>(method_invoke_stub); if (!method->IsAbstract()) { - const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method); + const DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache(); + const DexFile& dex_file = Runtime::Current()->GetClassLinker()->FindDexFile(dex_cache); + const CompiledMethod* compiled_method = + compiler_->GetCompiledMethod(Compiler::MethodReference(&dex_file, + method->GetDexMethodIndex())); CHECK(compiled_method != NULL) << PrettyMethod(method); const std::vector<uint8_t>& code = compiled_method->GetCode(); MakeExecutable(code); @@ -119,7 +125,6 @@ class CommonTest : public testing::Test { 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], @@ -134,7 +139,6 @@ class CommonTest : public testing::Test { kStackAlignment, 0, 0, - 0, NULL, NULL, method_invoke_stub); diff --git a/src/compiled_method.cc b/src/compiled_method.cc index 082600f5ab..500a62bd82 100644 --- a/src/compiled_method.cc +++ b/src/compiled_method.cc @@ -7,7 +7,6 @@ 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, @@ -37,7 +36,6 @@ CompiledMethod::CompiledMethod(InstructionSet instruction_set, 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; @@ -49,7 +47,6 @@ CompiledMethod::CompiledMethod(InstructionSet instruction_set, 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); @@ -57,7 +54,6 @@ CompiledMethod::CompiledMethod(InstructionSet instruction_set, 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; } @@ -76,10 +72,6 @@ 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_; } @@ -146,7 +138,6 @@ const void* CompiledMethod::CodePointer(const void* code_pointer, } } - CompiledInvokeStub::CompiledInvokeStub(std::vector<uint8_t>& code) { CHECK_NE(code.size(), 0U); code_ = code; diff --git a/src/compiled_method.h b/src/compiled_method.h index 1a5c34dc17..4e0870bbc0 100644 --- a/src/compiled_method.h +++ b/src/compiled_method.h @@ -16,7 +16,6 @@ class CompiledMethod { 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, @@ -26,7 +25,6 @@ class 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); @@ -35,12 +33,10 @@ class 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. @@ -61,7 +57,6 @@ class CompiledMethod { 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_; diff --git a/src/compiler.cc b/src/compiler.cc index ba61b4d968..96beaa6148 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -14,20 +14,20 @@ #include "runtime.h" #include "stl_util.h" -extern art::CompiledMethod* oatCompileMethod(const art::Compiler& compiler, - const art::Method*, - art::InstructionSet); +art::CompiledMethod* oatCompileMethod(const art::Compiler& compiler, bool is_direct, + uint32_t method_idx, const art::ClassLoader* class_loader, + const art::DexFile& dex_file, art::InstructionSet); namespace art { namespace arm { ByteArray* CreateAbstractMethodErrorStub(); - CompiledInvokeStub* ArmCreateInvokeStub(const Method* method); + CompiledInvokeStub* ArmCreateInvokeStub(bool is_static, const char* shorty); ByteArray* ArmCreateResolutionTrampoline(Runtime::TrampolineType type); } namespace x86 { ByteArray* CreateAbstractMethodErrorStub(); - CompiledInvokeStub* X86CreateInvokeStub(const Method* method); + CompiledInvokeStub* X86CreateInvokeStub(bool is_static, const char* shorty); ByteArray* X86CreateResolutionTrampoline(Runtime::TrampolineType type); } @@ -80,7 +80,12 @@ void Compiler::CompileOne(const Method* method) { Resolve(class_loader); Verify(class_loader); InitializeClassesWithoutClinit(class_loader); - CompileMethod(method); + // Find the dex_file + const DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache(); + const DexFile& dex_file = Runtime::Current()->GetClassLinker()->FindDexFile(dex_cache); + uint32_t method_idx = method->GetDexMethodIndex(); + CompileMethod(method->IsDirect(), method->IsNative(), method->IsStatic(), method->IsAbstract(), + method_idx, class_loader, dex_file); SetCodeAndDirectMethods(class_loader); } @@ -127,69 +132,52 @@ void Compiler::ResolveDexFile(const ClassLoader* class_loader, const DexFile& de // static fields, instance fields, direct methods, and virtual // methods. const byte* class_data = dex_file.GetClassData(class_def); - - DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data); - size_t num_static_fields = header.static_fields_size_; - size_t num_instance_fields = header.instance_fields_size_; - size_t num_direct_methods = header.direct_methods_size_; - size_t num_virtual_methods = header.virtual_methods_size_; - - if (num_static_fields != 0) { - uint32_t last_idx = 0; - for (size_t i = 0; i < num_static_fields; ++i) { - DexFile::Field dex_field; - dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx); - Field* field = class_linker->ResolveField(dex_file, dex_field.field_idx_, dex_cache, - class_loader, true); - if (field == NULL) { - Thread* self = Thread::Current(); - CHECK(self->IsExceptionPending()); - self->ClearException(); - } + if (class_data == NULL) { + // empty class such as a marker interface + continue; + } + ClassDataItemIterator it(dex_file, class_data); + while (it.HasNextStaticField()) { + Field* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache, + class_loader, true); + if (field == NULL) { + Thread* self = Thread::Current(); + CHECK(self->IsExceptionPending()); + self->ClearException(); } + it.Next(); } - if (num_instance_fields != 0) { - uint32_t last_idx = 0; - for (size_t i = 0; i < num_instance_fields; ++i) { - DexFile::Field dex_field; - dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx); - Field* field = class_linker->ResolveField(dex_file, dex_field.field_idx_, dex_cache, - class_loader, false); - if (field == NULL) { - Thread* self = Thread::Current(); - CHECK(self->IsExceptionPending()); - self->ClearException(); - } + while (it.HasNextInstanceField()) { + Field* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache, + class_loader, false); + if (field == NULL) { + Thread* self = Thread::Current(); + CHECK(self->IsExceptionPending()); + self->ClearException(); } + it.Next(); } - if (num_direct_methods != 0) { - uint32_t last_idx = 0; - for (size_t i = 0; i < num_direct_methods; ++i) { - DexFile::Method dex_method; - dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx); - Method* method = class_linker->ResolveMethod(dex_file, dex_method.method_idx_, dex_cache, - class_loader, true); - if (method == NULL) { - Thread* self = Thread::Current(); - CHECK(self->IsExceptionPending()); - self->ClearException(); - } + while (it.HasNextDirectMethod()) { + Method* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache, + class_loader, true); + if (method == NULL) { + Thread* self = Thread::Current(); + CHECK(self->IsExceptionPending()); + self->ClearException(); } + it.Next(); } - if (num_virtual_methods != 0) { - uint32_t last_idx = 0; - for (size_t i = 0; i < num_virtual_methods; ++i) { - DexFile::Method dex_method; - dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx); - Method* method = class_linker->ResolveMethod(dex_file, dex_method.method_idx_, dex_cache, - class_loader, false); - if (method == NULL) { - Thread* self = Thread::Current(); - CHECK(self->IsExceptionPending()); - self->ClearException(); - } + while (it.HasNextVirtualMethod()) { + Method* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(), dex_cache, + class_loader, false); + if (method == NULL) { + Thread* self = Thread::Current(); + CHECK(self->IsExceptionPending()); + self->ClearException(); } + it.Next(); } + DCHECK(!it.HasNext()); } } @@ -278,78 +266,118 @@ void Compiler::Compile(const ClassLoader* class_loader) { } void Compiler::CompileDexFile(const ClassLoader* class_loader, const DexFile& dex_file) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); class_def_index++) { const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); - const char* descriptor = dex_file.GetClassDescriptor(class_def); - Class* klass = class_linker->FindClass(descriptor, class_loader); - if (klass == NULL) { - // previous verification error will cause FindClass to throw - Thread* self = Thread::Current(); - CHECK(self->IsExceptionPending()); - self->ClearException(); - } else { - CompileClass(klass); - } + CompileClass(class_def, class_loader, dex_file); } } -void Compiler::CompileClass(const Class* klass) { - for (size_t i = 0; i < klass->NumDirectMethods(); i++) { - CompileMethod(klass->GetDirectMethod(i)); +void Compiler::CompileClass(const DexFile::ClassDef& class_def, const ClassLoader* class_loader, + const DexFile& dex_file) { + const byte* class_data = dex_file.GetClassData(class_def); + if (class_data == NULL) { + // empty class, probably a marker interface + return; + } + ClassDataItemIterator it(dex_file, class_data); + // Skip fields + while (it.HasNextStaticField()) { + it.Next(); + } + while (it.HasNextInstanceField()) { + it.Next(); + } + // Compile direct methods + while (it.HasNextDirectMethod()) { + bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0; + bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0; + bool is_abstract = (it.GetMemberAccessFlags() & kAccAbstract) != 0; + CompileMethod(true, is_native, is_static, is_abstract, it.GetMemberIndex(), class_loader, + dex_file); + it.Next(); } - for (size_t i = 0; i < klass->NumVirtualMethods(); i++) { - CompileMethod(klass->GetVirtualMethod(i)); + // Compile virtual methods + while (it.HasNextVirtualMethod()) { + bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0; + bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0; + bool is_abstract = (it.GetMemberAccessFlags() & kAccAbstract) != 0; + CompileMethod(false, is_native, is_static, is_abstract, it.GetMemberIndex(), class_loader, + dex_file); + it.Next(); } + DCHECK(!it.HasNext()); } -void Compiler::CompileMethod(const Method* method) { +void Compiler::CompileMethod(bool is_direct, bool is_native, bool is_static, bool is_abstract, + uint32_t method_idx, const ClassLoader* class_loader, + const DexFile& dex_file) { CompiledMethod* compiled_method = NULL; - if (method->IsNative()) { - compiled_method = jni_compiler_.Compile(method); + if (is_native) { + compiled_method = jni_compiler_.Compile(is_direct, method_idx, class_loader, dex_file); CHECK(compiled_method != NULL); - } else if (method->IsAbstract()) { + } else if (is_abstract) { } else { - compiled_method = oatCompileMethod(*this, method, kThumb2); - CHECK(compiled_method != NULL); + compiled_method = oatCompileMethod(*this, is_direct, method_idx, class_loader, dex_file, + kThumb2); + // TODO: assert compiled_method is not NULL, currently NULL may be returned if the method + // wasn't resolved } if (compiled_method != NULL) { - CHECK(compiled_methods_.find(method) == compiled_methods_.end()) << PrettyMethod(method); - compiled_methods_[method] = compiled_method; - DCHECK(compiled_methods_.find(method) != compiled_methods_.end()) << PrettyMethod(method); - DCHECK(GetCompiledMethod(method) != NULL) << PrettyMethod(method); + MethodReference ref(&dex_file, method_idx); + CHECK(compiled_methods_.find(ref) == compiled_methods_.end()) + << PrettyMethod(method_idx, dex_file); + compiled_methods_[ref] = compiled_method; + DCHECK(compiled_methods_.find(ref) != compiled_methods_.end()) + << PrettyMethod(method_idx, dex_file); + DCHECK(GetCompiledMethod(ref) != NULL) + << PrettyMethod(method_idx, dex_file); } - CompiledInvokeStub* compiled_invoke_stub = NULL; - if (instruction_set_ == kX86) { - compiled_invoke_stub = art::x86::X86CreateInvokeStub(method); - } else { - CHECK(instruction_set_ == kArm || instruction_set_ == kThumb2); - // Generates invocation stub using ARM instruction set - compiled_invoke_stub = art::arm::ArmCreateInvokeStub(method); + const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); + const CompiledInvokeStub* compiled_invoke_stub = FindInvokeStub(is_static, shorty); + if (compiled_invoke_stub == NULL) { + if (instruction_set_ == kX86) { + compiled_invoke_stub = art::x86::X86CreateInvokeStub(is_static, shorty); + } else { + CHECK(instruction_set_ == kArm || instruction_set_ == kThumb2); + // Generates invocation stub using ARM instruction set + compiled_invoke_stub = art::arm::ArmCreateInvokeStub(is_static, shorty); + } + CHECK(compiled_invoke_stub != NULL); + InsertInvokeStub(is_static, shorty, compiled_invoke_stub); } - CHECK(compiled_invoke_stub != NULL); - // TODO: this fails if we have an abstract method defined in more than one input dex file. - CHECK(compiled_invoke_stubs_.find(method) == compiled_invoke_stubs_.end()) << PrettyMethod(method); - compiled_invoke_stubs_[method] = compiled_invoke_stub; + CHECK(!Thread::Current()->IsExceptionPending()) << PrettyMethod(method_idx, dex_file); +} - Thread* self = Thread::Current(); - CHECK(!self->IsExceptionPending()) << PrettyMethod(method); +static std::string MakeInvokeStubKey(bool is_static, const char* shorty) { + std::string key(shorty); + if (is_static) { + key += "$"; // musn't be a shorty type character + } + return key; } -const CompiledMethod* Compiler::GetCompiledMethod(const Method* method) const { - MethodTable::const_iterator it = compiled_methods_.find(method); - if (it == compiled_methods_.end()) { +const CompiledInvokeStub* Compiler::FindInvokeStub(bool is_static, const char* shorty) const { + std::string key = MakeInvokeStubKey(is_static, shorty); + InvokeStubTable::const_iterator it = compiled_invoke_stubs_.find(key); + if (it == compiled_invoke_stubs_.end()) { return NULL; + } else { + DCHECK(it->second != NULL); + return it->second; } - 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()) { +void Compiler::InsertInvokeStub(bool is_static, const char* shorty, + const CompiledInvokeStub* compiled_invoke_stub) { + std::string key = MakeInvokeStubKey(is_static, shorty); + compiled_invoke_stubs_[key] = compiled_invoke_stub; +} + +CompiledMethod* Compiler::GetCompiledMethod(MethodReference ref) const { + MethodTable::const_iterator it = compiled_methods_.find(ref); + if (it == compiled_methods_.end()) { return NULL; } CHECK(it->second != NULL); diff --git a/src/compiler.h b/src/compiler.h index 55bab59e6b..f29fbbc94a 100644 --- a/src/compiler.h +++ b/src/compiler.h @@ -12,6 +12,8 @@ #include "runtime.h" #include "unordered_map.h" +#include <string> + namespace art { class Compiler { @@ -52,8 +54,11 @@ class Compiler { static ByteArray* CreateResolutionStub(InstructionSet instruction_set, Runtime::TrampolineType type); - const CompiledMethod* GetCompiledMethod(const Method* method) const; - const CompiledInvokeStub* GetCompiledInvokeStub(const Method* method) const; + // A method is uniquely located by its DexFile and index into the method_id table of that dex file + typedef std::pair<const DexFile*, uint32_t> MethodReference; + + CompiledMethod* GetCompiledMethod(MethodReference ref) const; + const CompiledInvokeStub* FindInvokeStub(bool is_static, const char* shorty) const; // Callbacks from OAT/ART compiler to see what runtime checks must be generated bool CanAssumeTypeIsPresentInDexCache(const Method* referrer, uint32_t type_idx) const { @@ -70,6 +75,7 @@ class Compiler { DCHECK(resolved_class == NULL || referrer->GetDeclaringClass()->CanAccess(resolved_class)); return resolved_class != NULL; } + private: // Attempt to resolve all type, methods, fields, and strings // referenced from code in the dex file following PathClassLoader @@ -85,21 +91,41 @@ class Compiler { void Compile(const ClassLoader* class_loader); void CompileDexFile(const ClassLoader* class_loader, const DexFile& dex_file); - void CompileClass(const Class* klass); - void CompileMethod(const Method* method); + void CompileClass(const DexFile::ClassDef& class_def, const ClassLoader* class_loader, + const DexFile& dex_file); + void CompileMethod(bool is_direct, bool is_native, bool is_static, bool is_abstract, + uint32_t method_idx, const ClassLoader* class_loader, const DexFile& dex_file); // After compiling, walk all the DexCaches and set the code and // method pointers of CodeAndDirectMethods entries in the DexCaches. void SetCodeAndDirectMethods(const ClassLoader* class_loader); void SetCodeAndDirectMethodsDexFile(const DexFile& dex_file); + void InsertInvokeStub(bool is_static, const char* shorty, + const CompiledInvokeStub* compiled_invoke_stub); + InstructionSet instruction_set_; JniCompiler jni_compiler_; - typedef std::tr1::unordered_map<const Method*, CompiledMethod*, ObjectIdentityHash> MethodTable; + struct MethodReferenceHash { + size_t operator()(const MethodReference id) const { + size_t dex = reinterpret_cast<size_t>(id.first); + DCHECK_NE(dex, static_cast<size_t>(0)); + dex += 33; // dex is an aligned pointer, get some non-zero low bits + size_t idx = id.second; + if (idx == 0) { // special case of a method index of 0 + return dex * 5381; + } else { + return dex * idx; + } + } + }; + typedef std::tr1::unordered_map<const MethodReference, CompiledMethod*, MethodReferenceHash> MethodTable; + // All method references that this compiler has compiled MethodTable compiled_methods_; - typedef std::tr1::unordered_map<const Method*, CompiledInvokeStub*, ObjectIdentityHash> InvokeStubTable; + typedef std::tr1::unordered_map<std::string, const CompiledInvokeStub*> InvokeStubTable; + // Invocation stubs created to allow invocation of the compiled methods InvokeStubTable compiled_invoke_stubs_; bool image_; diff --git a/src/compiler/Compiler.h b/src/compiler/Compiler.h index 28a689fb4b..917e3fda03 100644 --- a/src/compiler/Compiler.h +++ b/src/compiler/Compiler.h @@ -17,6 +17,8 @@ #ifndef ART_SRC_COMPILER_COMPILER_H_ #define ART_SRC_COMPILER_COMPILER_H_ +#include "dex_file.h" + #define COMPILER_TRACED(X) #define COMPILER_TRACEE(X) @@ -99,9 +101,9 @@ bool oatArchInit(void); void oatArchDump(void); bool oatStartup(void); void oatShutdown(void); -CompiledMethod* oatCompileMethod(const Compiler& compiler, - const Method* method, - OatInstructionSetType); +CompiledMethod* oatCompileMethod(const Compiler& compiler, bool is_direct, + uint32_t method_idx, const art::ClassLoader* class_loader, + const art::DexFile& dex_file, OatInstructionSetType); void oatDumpStats(void); void oatScanAllClassPointers(void (*callback)(void* ptr)); void oatInitializeSSAConversion(struct CompilationUnit* cUnit); diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc index d4f1b27b4b..9a2cc31079 100644 --- a/src/compiler/Frontend.cc +++ b/src/compiler/Frontend.cc @@ -18,6 +18,7 @@ #include "CompilerInternals.h" #include "Dataflow.h" #include "constants.h" +#include "leb128.h" #include "object.h" #include "runtime.h" @@ -432,7 +433,7 @@ STATIC void processTryCatchBlocks(CompilationUnit* cUnit) for (int i = 0; i < triesSize; i++) { const art::DexFile::TryItem* pTry = - art::DexFile::dexGetTryItems(*code_item, i); + art::DexFile::GetTryItems(*code_item, i); int startOffset = pTry->start_addr_; int endOffset = startOffset + pTry->insn_count_; for (offset = startOffset; offset < endOffset; offset++) { @@ -442,16 +443,15 @@ STATIC void processTryCatchBlocks(CompilationUnit* cUnit) // Iterate over each of the handlers to enqueue the empty Catch blocks const art::byte* handlers_ptr = - art::DexFile::dexGetCatchHandlerData(*code_item, 0); + art::DexFile::GetCatchHandlerData(*code_item, 0); uint32_t handlers_size = art::DecodeUnsignedLeb128(&handlers_ptr); for (uint32_t idx = 0; idx < handlers_size; idx++) { - art::DexFile::CatchHandlerIterator iterator(handlers_ptr); - - for (; !iterator.HasNext(); iterator.Next()) { - uint32_t address = iterator.Get().address_; + art::CatchHandlerIterator iterator(handlers_ptr); + for (; iterator.HasNext(); iterator.Next()) { + uint32_t address = iterator.GetHandlerAddress(); findBlock(cUnit, address, false /* split */, true /*create*/); } - handlers_ptr = iterator.GetData(); + handlers_ptr = iterator.EndDataPointer(); } } @@ -625,8 +625,7 @@ STATIC void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock, /* In try block */ if (oatIsBitSet(tryBlockAddr, curOffset)) { - art::DexFile::CatchHandlerIterator iterator = - art::DexFile::dexFindCatchHandler(*code_item, curOffset); + art::CatchHandlerIterator iterator(*code_item, curOffset); if (curBlock->successorBlockList.blockListType != kNotUsed) { LOG(FATAL) << "Successor block list already in use: " << @@ -636,8 +635,8 @@ STATIC void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock, curBlock->successorBlockList.blockListType = kCatch; oatInitGrowableList(&curBlock->successorBlockList.blocks, 2); - for (;!iterator.HasNext(); iterator.Next()) { - BasicBlock *catchBlock = findBlock(cUnit, iterator.Get().address_, + for (;iterator.HasNext(); iterator.Next()) { + BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(), false /* split*/, false /* creat */); catchBlock->catchEntry = true; @@ -645,7 +644,7 @@ STATIC void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock, (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo), false); successorBlockInfo->block = catchBlock; - successorBlockInfo->key = iterator.Get().type_idx_; + successorBlockInfo->key = iterator.GetHandlerTypeIndex(); oatInsertGrowableList(&curBlock->successorBlockList.blocks, (intptr_t) successorBlockInfo); oatSetBit(catchBlock->predecessors, curBlock->id); @@ -692,16 +691,26 @@ STATIC void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock, /* * Compile a method. */ -CompiledMethod* oatCompileMethod(const Compiler& compiler, const Method* method, art::InstructionSet insnSet) +CompiledMethod* oatCompileMethod(const Compiler& compiler, bool is_direct, + uint32_t method_idx, const art::ClassLoader* class_loader, + const art::DexFile& dex_file, art::InstructionSet insnSet) { + art::ClassLinker* linker = art::Runtime::Current()->GetClassLinker(); + art::DexCache* dex_cache = linker->FindDexCache(dex_file); + art::Method* method = linker->ResolveMethod(dex_file, method_idx, dex_cache, + class_loader, is_direct); + if (method == NULL) { + CHECK(Thread::Current()->IsExceptionPending()); + Thread::Current()->ClearException(); + LOG(INFO) << "Couldn't resolve " << PrettyMethod(method_idx, dex_file, true) + << " for compilation"; + return NULL; + } if (compiler.IsVerbose()) { LOG(INFO) << "Compiling " << PrettyMethod(method) << "..."; } oatArenaReset(); - art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker(); - const art::DexFile& dex_file = class_linker->FindDexFile( - method->GetDeclaringClass()->GetDexCache()); const art::DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset()); const u2* codePtr = code_item->insns_; @@ -907,9 +916,10 @@ CompiledMethod* oatCompileMethod(const Compiler& compiler, const Method* method, + __builtin_popcount(cUnit->fpSpillMask))); DCHECK_GE(vmapTable.size(), 1U); // should always at least one INVALID_VREG for lr - CompiledMethod* result = new CompiledMethod(art::kThumb2, - cUnit->codeBuffer, cUnit->frameSize, cUnit->frameSize - sizeof(intptr_t), - cUnit->coreSpillMask, cUnit->fpSpillMask, cUnit->mappingTable, vmapTable); + CompiledMethod* result = new CompiledMethod(art::kThumb2, cUnit->codeBuffer, + cUnit->frameSize, cUnit->coreSpillMask, + cUnit->fpSpillMask, cUnit->mappingTable, + vmapTable); if (compiler.IsVerbose()) { LOG(INFO) << "Compiled " << PrettyMethod(method) diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc index bff53beb06..006be694bd 100644 --- a/src/compiler/codegen/arm/Thumb2/Gen.cc +++ b/src/compiler/codegen/arm/Thumb2/Gen.cc @@ -39,8 +39,8 @@ std::string fieldNameFromIndex(const Method* method, uint32_t fieldIdx) const art::DexFile& dex_file = class_linker->FindDexFile( method->GetDeclaringClass()->GetDexCache()); const art::DexFile::FieldId& field_id = dex_file.GetFieldId(fieldIdx); - std::string class_name = dex_file.dexStringByTypeIdx(field_id.class_idx_); - std::string field_name = dex_file.dexStringById(field_id.name_idx_); + std::string class_name = dex_file.StringByTypeIdx(field_id.class_idx_); + std::string field_name = dex_file.StringDataByIdx(field_id.name_idx_); return class_name + "." + field_name; } diff --git a/src/dex_cache.cc b/src/dex_cache.cc index 4eb18a565b..c43f5bf573 100644 --- a/src/dex_cache.cc +++ b/src/dex_cache.cc @@ -9,6 +9,14 @@ namespace art { +void CodeAndDirectMethods::SetResolvedDirectMethod(uint32_t method_idx, Method* method) { + CHECK(method != NULL); + 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)); +} + void DexCache::Init(String* location, ObjectArray<String>* strings, ObjectArray<Class>* resolved_types, diff --git a/src/dex_cache.h b/src/dex_cache.h index ee1731a8de..8cd9b1202f 100644 --- a/src/dex_cache.h +++ b/src/dex_cache.h @@ -33,13 +33,7 @@ class MANAGED CodeAndDirectMethods : public IntArray { Set(MethodIndex(method_idx), method_idx); } - void SetResolvedDirectMethod(uint32_t method_idx, Method* method) { - CHECK(method != NULL); - 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)); - } + void SetResolvedDirectMethod(uint32_t method_idx, Method* method); static size_t LengthAsArray(size_t elements) { return kMax * elements; diff --git a/src/dex_file.cc b/src/dex_file.cc index 21489dd2f5..e9a883c9e3 100644 --- a/src/dex_file.cc +++ b/src/dex_file.cc @@ -14,12 +14,15 @@ #include <map> #include "UniquePtr.h" +#include "class_linker.h" #include "globals.h" +#include "leb128.h" #include "logging.h" #include "object.h" #include "os.h" #include "stringprintf.h" #include "thread.h" +#include "utf.h" #include "utils.h" #include "zip_archive.h" @@ -421,6 +424,19 @@ uint32_t DexFile::GetVersion() const { return atoi(version); } +int32_t DexFile::GetStringLength(const StringId& string_id) const { + const byte* ptr = base_ + string_id.string_data_off_; + return DecodeUnsignedLeb128(&ptr); +} + +// Returns a pointer to the UTF-8 string data referred to by the given string_id. +const char* DexFile::GetStringDataAndLength(const StringId& string_id, int32_t* length) const { + CHECK(length != NULL); + const byte* ptr = base_ + string_id.string_data_off_; + *length = DecodeUnsignedLeb128(&ptr); + return reinterpret_cast<const char*>(ptr); +} + void DexFile::InitIndex() { CHECK_EQ(index_.size(), 0U); for (size_t i = 0; i < NumClassDefs(); ++i) { @@ -447,11 +463,172 @@ const DexFile::ClassDef* DexFile::FindClassDef(const StringPiece& descriptor) co return NULL; } +const DexFile::MethodId* DexFile::FindMethodId(const DexFile::TypeId& klass, + const DexFile::StringId& name, + const DexFile::ProtoId& signature) const { + // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx + const uint16_t class_idx = GetIndexForTypeId(klass); + const uint32_t name_idx = GetIndexForStringId(name); + const uint16_t proto_idx = GetIndexForProtoId(signature); + uint32_t lo = 0; + uint32_t hi = NumMethodIds() - 1; + while (hi >= lo) { + uint32_t mid = (hi + lo) / 2; + const DexFile::MethodId& method = GetMethodId(mid); + if (class_idx > method.class_idx_) { + lo = mid + 1; + } else if (class_idx < method.class_idx_) { + hi = mid - 1; + } else { + if (name_idx > method.name_idx_) { + lo = mid + 1; + } else if (name_idx < method.name_idx_) { + hi = mid - 1; + } else { + if (proto_idx > method.proto_idx_) { + lo = mid + 1; + } else if (proto_idx < method.proto_idx_) { + hi = mid - 1; + } else { + return &method; + } + } + } + } + return NULL; +} + +const DexFile::StringId* DexFile::FindStringId(const std::string& string) const { + uint32_t lo = 0; + uint32_t hi = NumStringIds() - 1; + while (hi >= lo) { + uint32_t mid = (hi + lo) / 2; + int32_t length; + const DexFile::StringId& str_id = GetStringId(mid); + const char* str = GetStringDataAndLength(str_id, &length); + int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string.c_str(), str); + if (compare > 0) { + lo = mid + 1; + } else if (compare < 0) { + hi = mid - 1; + } else { + return &str_id; + } + } + return NULL; +} + +const DexFile::TypeId* DexFile::FindTypeId(uint32_t string_idx) const { + uint32_t lo = 0; + uint32_t hi = NumTypeIds() - 1; + while (hi >= lo) { + uint32_t mid = (hi + lo) / 2; + const TypeId& type_id = GetTypeId(mid); + if (string_idx > type_id.descriptor_idx_) { + lo = mid + 1; + } else if (string_idx < type_id.descriptor_idx_) { + hi = mid - 1; + } else { + return &type_id; + } + } + return NULL; +} + +const DexFile::ProtoId* DexFile::FindProtoId(uint16_t return_type_idx, + const std::vector<uint16_t>& signature_type_ids) const { + uint32_t lo = 0; + uint32_t hi = NumProtoIds() - 1; + while (hi >= lo) { + uint32_t mid = (hi + lo) / 2; + const DexFile::ProtoId& proto = GetProtoId(mid); + int compare = return_type_idx - proto.return_type_idx_; + if (compare == 0) { + DexFileParameterIterator it(*this, proto); + size_t i = 0; + while (it.HasNext() && i < signature_type_ids.size() && compare == 0) { + compare = signature_type_ids[i] - it.GetTypeId(); + it.Next(); + i++; + } + if (compare == 0) { + if (it.HasNext()) { + compare = -1; + } else if (i < signature_type_ids.size()) { + compare = 1; + } + } + } + if (compare > 0) { + lo = mid + 1; + } else if (compare < 0) { + hi = mid - 1; + } else { + return &proto; + } + } + return NULL; +} + +// Given a signature place the type ids into the given vector +bool DexFile::CreateTypeList(uint16_t* return_type_idx, std::vector<uint16_t>* param_type_idxs, + const std::string& signature) const { + if (signature[0] != '(') { + return false; + } + size_t offset = 1; + size_t end = signature.size(); + bool process_return = false; + while (offset < end) { + char c = signature[offset]; + offset++; + if (c == ')') { + process_return = true; + continue; + } + std::string descriptor; + descriptor += c; + while (c == '[') { // process array prefix + if (offset >= end) { // expect some descriptor following [ + return false; + } + c = signature[offset]; + offset++; + descriptor += c; + } + if (c == 'L') { // process type descriptors + do { + if (offset >= end) { // unexpected early termination of descriptor + return false; + } + c = signature[offset]; + offset++; + descriptor += c; + } while (c != ';'); + } + const DexFile::StringId* string_id = FindStringId(descriptor); + if (string_id == NULL) { + return false; + } + const DexFile::TypeId* type_id = FindTypeId(GetIndexForStringId(*string_id)); + if (type_id == NULL) { + return false; + } + uint16_t type_idx = GetIndexForTypeId(*type_id); + if (!process_return) { + param_type_idxs->push_back(type_idx); + } else { + *return_type_idx = type_idx; + return offset == end; // return true if the signature had reached a sensible end + } + } + return false; // failed to correctly parse return type +} + // Materializes the method descriptor for a method prototype. Method // descriptors are not stored directly in the dex file. Instead, one // must assemble the descriptor from references in the prototype. -std::string DexFile::CreateMethodDescriptor(uint32_t proto_idx, - int32_t* unicode_length) const { +std::string DexFile::CreateMethodSignature(uint32_t proto_idx, int32_t* unicode_length) const { const ProtoId& proto_id = GetProtoId(proto_idx); std::string descriptor; descriptor.push_back('('); @@ -463,7 +640,7 @@ std::string DexFile::CreateMethodDescriptor(uint32_t proto_idx, const TypeItem& type_item = type_list->GetTypeItem(i); uint32_t type_idx = type_item.type_idx_; int32_t type_length; - const char* name = dexStringByTypeIdx(type_idx, &type_length); + const char* name = StringByTypeIdx(type_idx, &type_length); parameter_length += type_length; descriptor.append(name); } @@ -471,7 +648,7 @@ std::string DexFile::CreateMethodDescriptor(uint32_t proto_idx, descriptor.push_back(')'); uint32_t return_type_idx = proto_id.return_type_idx_; int32_t return_type_length; - const char* name = dexStringByTypeIdx(return_type_idx, &return_type_length); + const char* name = StringByTypeIdx(return_type_idx, &return_type_length); descriptor.append(name); if (unicode_length != NULL) { *unicode_length = parameter_length + return_type_length + 2; // 2 for ( and ) @@ -479,127 +656,6 @@ std::string DexFile::CreateMethodDescriptor(uint32_t proto_idx, return descriptor; } -// Read a signed integer. "zwidth" is the zero-based byte count. -static int32_t ReadSignedInt(const byte* ptr, int zwidth) -{ - int32_t val = 0; - for (int i = zwidth; i >= 0; --i) { - val = ((uint32_t)val >> 8) | (((int32_t)*ptr++) << 24); - } - val >>= (3 - zwidth) * 8; - return val; -} - -// Read an unsigned integer. "zwidth" is the zero-based byte count, -// "fill_on_right" indicates which side we want to zero-fill from. -static uint32_t ReadUnsignedInt(const byte* ptr, int zwidth, - bool fill_on_right) { - uint32_t val = 0; - if (!fill_on_right) { - for (int i = zwidth; i >= 0; --i) { - val = (val >> 8) | (((uint32_t)*ptr++) << 24); - } - val >>= (3 - zwidth) * 8; - } else { - for (int i = zwidth; i >= 0; --i) { - val = (val >> 8) | (((uint32_t)*ptr++) << 24); - } - } - return val; -} - -// Read a signed long. "zwidth" is the zero-based byte count. -static int64_t ReadSignedLong(const byte* ptr, int zwidth) { - int64_t val = 0; - for (int i = zwidth; i >= 0; --i) { - val = ((uint64_t)val >> 8) | (((int64_t)*ptr++) << 56); - } - val >>= (7 - zwidth) * 8; - return val; -} - -// Read an unsigned long. "zwidth" is the zero-based byte count, -// "fill_on_right" indicates which side we want to zero-fill from. -static uint64_t ReadUnsignedLong(const byte* ptr, int zwidth, - bool fill_on_right) { - uint64_t val = 0; - if (!fill_on_right) { - for (int i = zwidth; i >= 0; --i) { - val = (val >> 8) | (((uint64_t)*ptr++) << 56); - } - val >>= (7 - zwidth) * 8; - } else { - for (int i = zwidth; i >= 0; --i) { - val = (val >> 8) | (((uint64_t)*ptr++) << 56); - } - } - return val; -} - -DexFile::ValueType DexFile::ReadEncodedValue(const byte** stream, - JValue* value) const { - const byte* ptr = *stream; - byte value_type = *ptr++; - byte value_arg = value_type >> kEncodedValueArgShift; - size_t width = value_arg + 1; // assume and correct later - int type = value_type & kEncodedValueTypeMask; - switch (type) { - case DexFile::kByte: { - int32_t b = ReadSignedInt(ptr, value_arg); - CHECK(IsInt(8, b)); - value->i = b; - break; - } - case DexFile::kShort: { - int32_t s = ReadSignedInt(ptr, value_arg); - CHECK(IsInt(16, s)); - value->i = s; - break; - } - case DexFile::kChar: { - uint32_t c = ReadUnsignedInt(ptr, value_arg, false); - CHECK(IsUint(16, c)); - value->i = c; - break; - } - case DexFile::kInt: - value->i = ReadSignedInt(ptr, value_arg); - break; - case DexFile::kLong: - value->j = ReadSignedLong(ptr, value_arg); - break; - case DexFile::kFloat: - value->i = ReadUnsignedInt(ptr, value_arg, true); - break; - case DexFile::kDouble: - value->j = ReadUnsignedLong(ptr, value_arg, true); - break; - case DexFile::kBoolean: - value->i = (value_arg != 0); - width = 0; - break; - case DexFile::kString: - case DexFile::kType: - case DexFile::kMethod: - case DexFile::kEnum: - value->i = ReadUnsignedInt(ptr, value_arg, false); - break; - case DexFile::kField: - case DexFile::kArray: - case DexFile::kAnnotation: - UNIMPLEMENTED(FATAL) << ": type " << type; - break; - case DexFile::kNull: - value->i = 0; - width = 0; - break; - default: - LOG(FATAL) << "Unreached"; - } - ptr += width; - *stream = ptr; - return static_cast<ValueType>(type); -} int32_t DexFile::GetLineNumFromPC(const art::Method* method, uint32_t rel_pc) const { // For native method, lineno should be -2 to indicate it is native. Note that @@ -613,13 +669,38 @@ int32_t DexFile::GetLineNumFromPC(const art::Method* method, uint32_t rel_pc) co // A method with no line number info should return -1 LineNumFromPcContext context(rel_pc, -1); - dexDecodeDebugInfo(code_item, method, LineNumForPcCb, NULL, &context); + DecodeDebugInfo(code_item, method, LineNumForPcCb, NULL, &context); return context.line_num_; } -void DexFile::dexDecodeDebugInfo0(const CodeItem* code_item, const art::Method* method, - DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb, - void* cnxt, const byte* stream, LocalInfo* local_in_reg) const { +int32_t DexFile::FindCatchHandlerOffset(const CodeItem &code_item, int32_t tries_size, + uint32_t address){ + // Note: Signed type is important for max and min. + int32_t min = 0; + int32_t max = tries_size - 1; + + while (max >= min) { + int32_t mid = (min + max) / 2; + const TryItem* pTry = DexFile::GetTryItems(code_item, mid); + uint32_t start = pTry->start_addr_; + if (address < start) { + max = mid - 1; + } else { + uint32_t end = start + pTry->insn_count_; + if (address >= end) { + min = mid + 1; + } else { // We have a winner! + return (int32_t) pTry->handler_off_; + } + } + } + // No match. + return -1; +} + +void DexFile::DecodeDebugInfo0(const CodeItem* code_item, const Method* method, + DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb, + void* cnxt, const byte* stream, LocalInfo* local_in_reg) const { uint32_t line = DecodeUnsignedLeb128(&stream); uint32_t parameters_size = DecodeUnsignedLeb128(&stream); uint16_t arg_reg = code_item->registers_size_ - code_item->ins_size_; @@ -639,17 +720,17 @@ void DexFile::dexDecodeDebugInfo0(const CodeItem* code_item, const art::Method* arg_reg++; } - ParameterIterator* it = GetParameterIterator(GetProtoId(method->GetProtoIdx())); - for (uint32_t i = 0; i < parameters_size && it->HasNext(); ++i, it->Next()) { + DexFileParameterIterator it(*this, GetProtoId(method->GetProtoIdx())); + for (uint32_t i = 0; i < parameters_size && it.HasNext(); ++i, it.Next()) { if (arg_reg >= code_item->registers_size_) { LOG(ERROR) << "invalid stream - arg reg >= reg size (" << arg_reg << " >= " << code_item->registers_size_ << ")"; return; } int32_t id = DecodeUnsignedLeb128P1(&stream); - const char* descriptor = it->GetDescriptor(); + const char* descriptor = it.GetDescriptor(); if (need_locals) { - const char* name = dexStringById(id); + const char* name = StringDataByIdx(id); local_in_reg[arg_reg].name_ = name; local_in_reg[arg_reg].descriptor_ = descriptor; local_in_reg[arg_reg].start_address_ = address; @@ -666,7 +747,7 @@ void DexFile::dexDecodeDebugInfo0(const CodeItem* code_item, const art::Method* } } - if (it->HasNext()) { + if (it.HasNext()) { LOG(ERROR) << "invalid stream - problem with parameter iterator"; return; } @@ -709,10 +790,10 @@ void DexFile::dexDecodeDebugInfo0(const CodeItem* code_item, const art::Method* if (need_locals) { InvokeLocalCbIfLive(cnxt, reg, address, local_in_reg, local_cb); - local_in_reg[reg].name_ = dexStringById(name_idx); - local_in_reg[reg].descriptor_ = dexStringByTypeIdx(descriptor_idx); + local_in_reg[reg].name_ = StringDataByIdx(name_idx); + local_in_reg[reg].descriptor_ = StringByTypeIdx(descriptor_idx); if (opcode == DBG_START_LOCAL_EXTENDED) { - local_in_reg[reg].signature_ = dexStringById(signature_idx); + local_in_reg[reg].signature_ = StringDataByIdx(signature_idx); } local_in_reg[reg].start_address_ = address; local_in_reg[reg].is_live_ = true; @@ -779,4 +860,270 @@ void DexFile::dexDecodeDebugInfo0(const CodeItem* code_item, const art::Method* } } +void DexFile::DecodeDebugInfo(const CodeItem* code_item, const art::Method* method, + DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb, + void* cnxt) const { + const byte* stream = GetDebugInfoStream(code_item); + LocalInfo local_in_reg[code_item->registers_size_]; + + if (stream != NULL) { + DecodeDebugInfo0(code_item, method, posCb, local_cb, cnxt, stream, local_in_reg); + } + for (int reg = 0; reg < code_item->registers_size_; reg++) { + InvokeLocalCbIfLive(cnxt, reg, code_item->insns_size_in_code_units_, local_in_reg, local_cb); + } +} + +bool DexFile::LineNumForPcCb(void* cnxt, uint32_t address, uint32_t line_num) { + LineNumFromPcContext* context = (LineNumFromPcContext*) cnxt; + + // We know that this callback will be called in + // ascending address order, so keep going until we find + // a match or we've just gone past it. + if (address > context->address_) { + // The line number from the previous positions callback + // wil be the final result. + return true; + } else { + context->line_num_ = line_num; + return address == context->address_; + } +} + +// Decodes the header section from the class data bytes. +void ClassDataItemIterator::ReadClassDataHeader() { + CHECK(ptr_pos_ != NULL); + header_.static_fields_size_ = DecodeUnsignedLeb128(&ptr_pos_); + header_.instance_fields_size_ = DecodeUnsignedLeb128(&ptr_pos_); + header_.direct_methods_size_ = DecodeUnsignedLeb128(&ptr_pos_); + header_.virtual_methods_size_ = DecodeUnsignedLeb128(&ptr_pos_); +} + +void ClassDataItemIterator::ReadClassDataField() { + field_.field_idx_delta_ = DecodeUnsignedLeb128(&ptr_pos_); + field_.access_flags_ = DecodeUnsignedLeb128(&ptr_pos_); +} + +void ClassDataItemIterator::ReadClassDataMethod() { + method_.method_idx_delta_ = DecodeUnsignedLeb128(&ptr_pos_); + method_.access_flags_ = DecodeUnsignedLeb128(&ptr_pos_); + method_.code_off_ = DecodeUnsignedLeb128(&ptr_pos_); +} + +// Read a signed integer. "zwidth" is the zero-based byte count. +static int32_t ReadSignedInt(const byte* ptr, int zwidth) { + int32_t val = 0; + for (int i = zwidth; i >= 0; --i) { + val = ((uint32_t)val >> 8) | (((int32_t)*ptr++) << 24); + } + val >>= (3 - zwidth) * 8; + return val; +} + +// Read an unsigned integer. "zwidth" is the zero-based byte count, +// "fill_on_right" indicates which side we want to zero-fill from. +static uint32_t ReadUnsignedInt(const byte* ptr, int zwidth, bool fill_on_right) { + uint32_t val = 0; + if (!fill_on_right) { + for (int i = zwidth; i >= 0; --i) { + val = (val >> 8) | (((uint32_t)*ptr++) << 24); + } + val >>= (3 - zwidth) * 8; + } else { + for (int i = zwidth; i >= 0; --i) { + val = (val >> 8) | (((uint32_t)*ptr++) << 24); + } + } + return val; +} + +// Read a signed long. "zwidth" is the zero-based byte count. +static int64_t ReadSignedLong(const byte* ptr, int zwidth) { + int64_t val = 0; + for (int i = zwidth; i >= 0; --i) { + val = ((uint64_t)val >> 8) | (((int64_t)*ptr++) << 56); + } + val >>= (7 - zwidth) * 8; + return val; +} + +// Read an unsigned long. "zwidth" is the zero-based byte count, +// "fill_on_right" indicates which side we want to zero-fill from. +static uint64_t ReadUnsignedLong(const byte* ptr, int zwidth, bool fill_on_right) { + uint64_t val = 0; + if (!fill_on_right) { + for (int i = zwidth; i >= 0; --i) { + val = (val >> 8) | (((uint64_t)*ptr++) << 56); + } + val >>= (7 - zwidth) * 8; + } else { + for (int i = zwidth; i >= 0; --i) { + val = (val >> 8) | (((uint64_t)*ptr++) << 56); + } + } + return val; +} + +EncodedStaticFieldValueIterator::EncodedStaticFieldValueIterator(const DexFile& dex_file, + DexCache* dex_cache, ClassLinker* linker, const DexFile::ClassDef& class_def) : + dex_file_(dex_file), dex_cache_(dex_cache), linker_(linker), array_size_(), pos_(-1), type_(0) { + ptr_ = dex_file.GetEncodedStaticFieldValuesArray(class_def); + if (ptr_ == NULL) { + array_size_ = 0; + } else { + array_size_ = DecodeUnsignedLeb128(&ptr_); + } + if (array_size_ > 0) { + Next(); + } +} + +void EncodedStaticFieldValueIterator::Next() { + pos_++; + if (pos_ >= array_size_) { + return; + } + byte value_type = *ptr_++; + byte value_arg = value_type >> kEncodedValueArgShift; + size_t width = value_arg + 1; // assume and correct later + type_ = value_type & kEncodedValueTypeMask; + switch (type_) { + case kBoolean: + jval_.i = (value_arg != 0) ? 1 : 0; + width = 0; + break; + case kByte: + jval_.i = ReadSignedInt(ptr_, value_arg); + CHECK(IsInt(8, jval_.i)); + break; + case kShort: + jval_.i = ReadSignedInt(ptr_, value_arg); + CHECK(IsInt(16, jval_.i)); + break; + case kChar: + jval_.i = ReadUnsignedInt(ptr_, value_arg, false); + CHECK(IsUint(16, jval_.i)); + break; + case kInt: + jval_.i = ReadSignedInt(ptr_, value_arg); + break; + case kLong: + jval_.j = ReadSignedLong(ptr_, value_arg); + break; + case kFloat: + jval_.i = ReadUnsignedInt(ptr_, value_arg, true); + break; + case kDouble: + jval_.j = ReadUnsignedLong(ptr_, value_arg, true); + break; + case kString: + case kType: + case kMethod: + case kEnum: + jval_.i = ReadUnsignedInt(ptr_, value_arg, false); + break; + case kField: + case kArray: + case kAnnotation: + UNIMPLEMENTED(FATAL) << ": type " << type_; + break; + case kNull: + jval_.l = NULL; + width = 0; + break; + default: + LOG(FATAL) << "Unreached"; + } + ptr_ += width; +} + +void EncodedStaticFieldValueIterator::ReadValueToField(Field* field) const { + switch (type_) { + case kBoolean: field->SetBoolean(NULL, jval_.z); break; + case kByte: field->SetByte(NULL, jval_.b); break; + case kShort: field->SetShort(NULL, jval_.s); break; + case kChar: field->SetChar(NULL, jval_.c); break; + case kInt: field->SetInt(NULL, jval_.i); break; + case kLong: field->SetLong(NULL, jval_.j); break; + case kFloat: field->SetFloat(NULL, jval_.f); break; + case kDouble: field->SetDouble(NULL, jval_.d); break; + case kNull: field->SetObject(NULL, NULL); break; + case kString: { + String* resolved = linker_->ResolveString(dex_file_, jval_.i, dex_cache_); + field->SetObject(NULL, resolved); + break; + } + default: UNIMPLEMENTED(FATAL) << ": type " << type_; + } +} + +CatchHandlerIterator::CatchHandlerIterator(const DexFile::CodeItem& code_item, uint32_t address) { + handler_.address_ = -1; + int32_t offset = -1; + + // Short-circuit the overwhelmingly common cases. + switch (code_item.tries_size_) { + case 0: + break; + case 1: { + const DexFile::TryItem* tries = DexFile::GetTryItems(code_item, 0); + uint32_t start = tries->start_addr_; + if (address >= start) { + uint32_t end = start + tries->insn_count_; + if (address < end) { + offset = tries->handler_off_; + } + } + break; + } + default: + offset = DexFile::FindCatchHandlerOffset(code_item, code_item.tries_size_, address); + } + if (offset >= 0) { + const byte* handler_data = DexFile::GetCatchHandlerData(code_item, offset); + Init(handler_data); + } else { + // Not found, initialize as empty + current_data_ = NULL; + remaining_count_ = -1; + catch_all_ = false; + DCHECK(!HasNext()); + } +} + +void CatchHandlerIterator::Init(const byte* handler_data) { + current_data_ = handler_data; + remaining_count_ = DecodeSignedLeb128(¤t_data_); + + // If remaining_count_ is non-positive, then it is the negative of + // the number of catch types, and the catches are followed by a + // catch-all handler. + if (remaining_count_ <= 0) { + catch_all_ = true; + remaining_count_ = -remaining_count_; + } else { + catch_all_ = false; + } + Next(); +} + +void CatchHandlerIterator::Next() { + if (remaining_count_ > 0) { + handler_.type_idx_ = DecodeUnsignedLeb128(¤t_data_); + handler_.address_ = DecodeUnsignedLeb128(¤t_data_); + remaining_count_--; + return; + } + + if (catch_all_) { + handler_.type_idx_ = DexFile::kDexNoIndex16; + handler_.address_ = DecodeUnsignedLeb128(¤t_data_); + catch_all_ = false; + return; + } + + // no more handler + remaining_count_ = -1; +} + } // namespace art diff --git a/src/dex_file.h b/src/dex_file.h index 3acd79f916..62b99ab28b 100644 --- a/src/dex_file.h +++ b/src/dex_file.h @@ -10,20 +10,14 @@ #include "UniquePtr.h" #include "globals.h" #include "jni.h" -#include "leb128.h" #include "logging.h" #include "mem_map.h" #include "mutex.h" #include "stringpiece.h" -#include "strutil.h" #include "utils.h" namespace art { -union JValue; -class String; -class Method; - // TODO: move all of the macro functionality into the DexCache class. class DexFile { public: @@ -34,30 +28,11 @@ class DexFile { // name of the DexFile entry within a zip archive static const char* kClassesDex; - static const byte kEncodedValueTypeMask = 0x1f; // 0b11111 - static const byte kEncodedValueArgShift = 5; - // The value of an invalid index. static const uint32_t kDexNoIndex = 0xFFFFFFFF; - enum ValueType { - kByte = 0x00, - kShort = 0x02, - kChar = 0x03, - kInt = 0x04, - kLong = 0x06, - kFloat = 0x10, - kDouble = 0x11, - kString = 0x17, - kType = 0x18, - kField = 0x19, - kMethod = 0x1a, - kEnum = 0x1b, - kArray = 0x1c, - kAnnotation = 0x1d, - kNull = 0x1e, - kBoolean = 0x1f - }; + // The value of an invalid index. + static const uint16_t kDexNoIndex16 = 0xFFFF; // Raw header_item. struct Header { @@ -67,23 +42,23 @@ class DexFile { uint32_t file_size_; // length of entire file uint32_t header_size_; // offset to start of next section uint32_t endian_tag_; - uint32_t link_size_; - uint32_t link_off_; - uint32_t map_off_; - uint32_t string_ids_size_; - uint32_t string_ids_off_; - uint32_t type_ids_size_; - uint32_t type_ids_off_; - uint32_t proto_ids_size_; - uint32_t proto_ids_off_; - uint32_t field_ids_size_; - uint32_t field_ids_off_; - uint32_t method_ids_size_; - uint32_t method_ids_off_; - uint32_t class_defs_size_; - uint32_t class_defs_off_; - uint32_t data_size_; - uint32_t data_off_; + uint32_t link_size_; // unused + uint32_t link_off_; // unused + uint32_t map_off_; // unused + uint32_t string_ids_size_; // number of StringIds + uint32_t string_ids_off_; // file offset of StringIds array + uint32_t type_ids_size_; // number of TypeIds, we don't support more than 65535 + uint32_t type_ids_off_; // file offset of TypeIds array + uint32_t proto_ids_size_; // number of ProtoIds, we don't support more than 65535 + uint32_t proto_ids_off_; // file offset of ProtoIds array + uint32_t field_ids_size_; // number of FieldIds + uint32_t field_ids_off_; // file offset of FieldIds array + uint32_t method_ids_size_; // number of MethodIds + uint32_t method_ids_off_; // file offset of MethodIds array + uint32_t class_defs_size_; // number of ClassDefs + uint32_t class_defs_off_; // file offset of ClassDef array + uint32_t data_size_; // unused + uint32_t data_off_; // unused private: DISALLOW_COPY_AND_ASSIGN(Header); }; @@ -104,26 +79,27 @@ class DexFile { // Raw field_id_item. struct FieldId { - uint16_t class_idx_; // index into type_ids_ list for defining class - uint16_t type_idx_; // index into type_ids_ for field type - uint32_t name_idx_; // index into string_ids_ for field name + uint16_t class_idx_; // index into type_ids_ array for defining class + uint16_t type_idx_; // index into type_ids_ array for field type + uint32_t name_idx_; // index into string_ids_ array for field name private: DISALLOW_COPY_AND_ASSIGN(FieldId); }; // Raw method_id_item. struct MethodId { - uint16_t class_idx_; // index into type_ids_ list for defining class - uint16_t proto_idx_; // index into proto_ids_ for method prototype - uint32_t name_idx_; // index into string_ids_ for method name + uint16_t class_idx_; // index into type_ids_ array for defining class + uint16_t proto_idx_; // index into proto_ids_ array for method prototype + uint32_t name_idx_; // index into string_ids_ array for method name private: DISALLOW_COPY_AND_ASSIGN(MethodId); }; // Raw proto_id_item. struct ProtoId { - uint32_t shorty_idx_; // index into string_ids for shorty descriptor - uint32_t return_type_idx_; // index into type_ids list for return type + uint32_t shorty_idx_; // index into string_ids array for shorty descriptor + uint16_t return_type_idx_; // index into type_ids array for return type + uint16_t pad_; // padding = 0 uint32_t parameters_off_; // file offset to type_list for parameter types private: DISALLOW_COPY_AND_ASSIGN(ProtoId); @@ -131,9 +107,11 @@ class DexFile { // Raw class_def_item. struct ClassDef { - uint32_t class_idx_; // index into type_ids_ for this class + uint16_t class_idx_; // index into type_ids_ array for this class + uint16_t pad1_; // padding = 0 uint32_t access_flags_; - uint32_t superclass_idx_; // index into type_ids_ for superclass + uint16_t superclass_idx_; // index into type_ids_ array for superclass + uint16_t pad2_; // padding = 0 uint32_t interfaces_off_; // file offset to TypeList uint32_t source_file_idx_; // index into string_ids_ for source file name uint32_t annotations_off_; // file offset to annotations_directory_item @@ -168,37 +146,6 @@ class DexFile { DISALLOW_COPY_AND_ASSIGN(TypeList); }; - class ParameterIterator { // TODO: stream - public: - ParameterIterator(const DexFile& dex_file, const ProtoId& proto_id) - : dex_file_(dex_file), size_(0), pos_(0) { - type_list_ = dex_file_.GetProtoParameters(proto_id); - if (type_list_ != NULL) { - size_ = type_list_->Size(); - } - } - bool HasNext() const { return pos_ != size_; } - void Next() { ++pos_; } - const char* GetDescriptor() { - uint32_t type_idx = type_list_->GetTypeItem(pos_).type_idx_; - return dex_file_.dexStringByTypeIdx(type_idx); - } - private: - const DexFile& dex_file_; - const TypeList* type_list_; - uint32_t size_; - uint32_t pos_; - DISALLOW_IMPLICIT_CONSTRUCTORS(ParameterIterator); - }; - - ParameterIterator* GetParameterIterator(const ProtoId& proto_id) const { - return new ParameterIterator(*this, proto_id); - } - - const char* GetReturnTypeDescriptor(const ProtoId& proto_id) const { - return dexStringByTypeIdx(proto_id.return_type_idx_); - } - // Raw code_item. struct CodeItem { uint16_t registers_size_; @@ -212,11 +159,6 @@ class DexFile { DISALLOW_COPY_AND_ASSIGN(CodeItem); }; - struct CatchHandlerItem { - uint32_t type_idx_; // type index of the caught exception type - uint32_t address_; // handler address - }; - // Raw try_item. struct TryItem { uint32_t start_addr_; @@ -226,95 +168,6 @@ class DexFile { DISALLOW_COPY_AND_ASSIGN(TryItem); }; - class CatchHandlerIterator { - public: - CatchHandlerIterator() { - remaining_count_ = -1; - catch_all_ = false; - } - - explicit CatchHandlerIterator(const byte* handler_data) { - current_data_ = handler_data; - remaining_count_ = DecodeSignedLeb128(¤t_data_); - - // If remaining_count_ is non-positive, then it is the negative of - // the number of catch types, and the catches are followed by a - // catch-all handler. - if (remaining_count_ <= 0) { - catch_all_ = true; - remaining_count_ = -remaining_count_; - } else { - catch_all_ = false; - } - Next(); - } - - const CatchHandlerItem& Get() const { - return handler_; - } - - const byte* GetData() const { - return current_data_; - } - - void Next() { - if (remaining_count_ > 0) { - handler_.type_idx_ = DecodeUnsignedLeb128(¤t_data_); - handler_.address_ = DecodeUnsignedLeb128(¤t_data_); - remaining_count_--; - return; - } - - if (catch_all_) { - handler_.type_idx_ = kDexNoIndex; - handler_.address_ = DecodeUnsignedLeb128(¤t_data_); - catch_all_ = false; - return; - } - - // no more handler - remaining_count_ = -1; - } - - bool HasNext() const { - return remaining_count_ == -1 && catch_all_ == false; - } - - private: - CatchHandlerItem handler_; - const byte *current_data_; // the current handler in dex file. - int32_t remaining_count_; // number of handlers not read. - bool catch_all_; // is there a handler that will catch all exceptions in case - // that all typed handler does not match. - }; - - // Partially decoded form of class_data_item. - struct ClassDataHeader { - uint32_t static_fields_size_; // the number of static fields - uint32_t instance_fields_size_; // the number of instance fields - uint32_t direct_methods_size_; // the number of direct methods - uint32_t virtual_methods_size_; // the number of virtual methods - }; - - // Decoded form of encoded_field. - struct Field { - uint32_t field_idx_; // index into the field_ids list for the identity of this field - uint32_t access_flags_; // access flags for the field - Field() {} - private: - DISALLOW_COPY_AND_ASSIGN(Field); - }; - - // Decoded form of encoded_method. - struct Method { - uint32_t method_idx_; - uint32_t access_flags_; - uint32_t code_off_; - Method() {} - private: - DISALLOW_COPY_AND_ASSIGN(Method); - }; - typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry; typedef std::vector<const DexFile*> ClassPath; @@ -347,82 +200,104 @@ class DexFile { return *header_; } - // Looks up a class definition index by its class descriptor. - bool FindClassDefIndex(const StringPiece& descriptor, uint32_t& idx) const; - + // Decode the dex magic version uint32_t GetVersion() const; - // Looks up a class definition by its class descriptor. - const ClassDef* FindClassDef(const StringPiece& descriptor) const; - // Returns the number of string identifiers in the .dex file. size_t NumStringIds() const { CHECK(header_ != NULL); return header_->string_ids_size_; } - // Returns the number of type identifiers in the .dex file. - size_t NumTypeIds() const { - CHECK(header_ != NULL); - return header_->type_ids_size_; + // Returns the StringId at the specified index. + const StringId& GetStringId(uint32_t idx) const { + CHECK_LT(idx, NumStringIds()); + return string_ids_[idx]; } - // Returns the number of prototype identifiers in the .dex file. - size_t NumProtoIds() const { - CHECK(header_ != NULL); - return header_->proto_ids_size_; + uint32_t GetIndexForStringId(const StringId& string_id) const { + CHECK_GE(&string_id, string_ids_); + CHECK_LT(&string_id, string_ids_ + header_->string_ids_size_); + return &string_id - string_ids_; } - // Returns the number of field identifiers in the .dex file. - size_t NumFieldIds() const { - CHECK(header_ != NULL); - return header_->field_ids_size_; + int32_t GetStringLength(const StringId& string_id) const; + + // Returns a pointer to the UTF-8 string data referred to by the given string_id. + const char* GetStringDataAndLength(const StringId& string_id, int32_t* length) const; + + const char* GetStringData(const StringId& string_id) const { + int32_t length; + return GetStringDataAndLength(string_id, &length); } - // Returns the number of method identifiers in the .dex file. - size_t NumMethodIds() const { - CHECK(header_ != NULL); - return header_->method_ids_size_; + // return the UTF-8 encoded string with the specified string_id index + const char* StringDataAndLengthByIdx(uint32_t idx, int32_t* unicode_length) const { + if (idx == kDexNoIndex) { + *unicode_length = 0; + return NULL; + } + const StringId& string_id = GetStringId(idx); + return GetStringDataAndLength(string_id, unicode_length); } - // Returns the number of class definitions in the .dex file. - size_t NumClassDefs() const { + const char* StringDataByIdx(uint32_t idx) const { + int32_t unicode_length; + return StringDataAndLengthByIdx(idx, &unicode_length); + } + + // Looks up a string id for a given string + const StringId* FindStringId(const std::string& string) const; + + // Returns the number of type identifiers in the .dex file. + size_t NumTypeIds() const { CHECK(header_ != NULL); - return header_->class_defs_size_; + return header_->type_ids_size_; } - // Returns a pointer to the memory mapped class data. - // TODO: return a stream - const byte* GetClassData(const ClassDef& class_def) const { - if (class_def.class_data_off_ == 0) { - return NULL; - } else { - return base_ + class_def.class_data_off_; - } + // Returns the TypeId at the specified index. + const TypeId& GetTypeId(uint32_t idx) const { + CHECK_LT(idx, NumTypeIds()); + return type_ids_[idx]; } - // Decodes the header section from the class data bytes. - ClassDataHeader ReadClassDataHeader(const byte** class_data) const { - CHECK(class_data != NULL); - ClassDataHeader header; - memset(&header, 0, sizeof(ClassDataHeader)); - if (*class_data != NULL) { - header.static_fields_size_ = DecodeUnsignedLeb128(class_data); - header.instance_fields_size_ = DecodeUnsignedLeb128(class_data); - header.direct_methods_size_ = DecodeUnsignedLeb128(class_data); - header.virtual_methods_size_ = DecodeUnsignedLeb128(class_data); - } - return header; + uint16_t GetIndexForTypeId(const TypeId& type_id) const { + CHECK_GE(&type_id, type_ids_); + CHECK_LT(&type_id, type_ids_ + header_->type_ids_size_); + size_t result = &type_id - type_ids_; + DCHECK(result < 65536); + return static_cast<uint16_t>(result); } - // Returns the class descriptor string of a class definition. - const char* GetClassDescriptor(const ClassDef& class_def) const { - return dexStringByTypeIdx(class_def.class_idx_); + // Get the descriptor string associated with a given type index. + const char* StringByTypeIdx(uint32_t idx, int32_t* unicode_length) const { + const TypeId& type_id = GetTypeId(idx); + return StringDataAndLengthByIdx(type_id.descriptor_idx_, unicode_length); + } + + const char* StringByTypeIdx(uint32_t idx) const { + const TypeId& type_id = GetTypeId(idx); + return StringDataByIdx(type_id.descriptor_idx_); } // Returns the type descriptor string of a type id. const char* GetTypeDescriptor(const TypeId& type_id) const { - return dexStringById(type_id.descriptor_idx_); + return StringDataByIdx(type_id.descriptor_idx_); + } + + // Looks up a type for the given string index + const TypeId* FindTypeId(uint32_t string_idx) const; + + // Returns the number of field identifiers in the .dex file. + size_t NumFieldIds() const { + CHECK(header_ != NULL); + return header_->field_ids_size_; + } + + // Returns the FieldId at the specified index. + const FieldId& GetFieldId(uint32_t idx) const { + CHECK_LT(idx, NumFieldIds()); + return field_ids_[idx]; } // Returns the declaring class descriptor string of a field id. @@ -439,9 +314,31 @@ class DexFile { // Returns the name of a field id. const char* GetFieldName(const FieldId& field_id) const { - return dexStringById(field_id.name_idx_); + return StringDataByIdx(field_id.name_idx_); + } + + // Returns the number of method identifiers in the .dex file. + size_t NumMethodIds() const { + CHECK(header_ != NULL); + return header_->method_ids_size_; + } + + // Returns the MethodId at the specified index. + const MethodId& GetMethodId(uint32_t idx) const { + CHECK_LT(idx, NumMethodIds()); + return method_ids_[idx]; } + uint32_t GetIndexForMethodId(const MethodId& method_id) const { + CHECK_GE(&method_id, method_ids_); + CHECK_LT(&method_id, method_ids_ + header_->method_ids_size_); + return &method_id - method_ids_; + } + + // Looks up a method by its class_dex, name and proto_id + const MethodId* FindMethodId(const DexFile::TypeId& klass, const DexFile::StringId& name, + const DexFile::ProtoId& signature) const; + // Returns the declaring class descriptor string of a method id. const char* GetMethodDeclaringClassDescriptor(const MethodId& method_id) const { const DexFile::TypeId& type_id = GetTypeId(method_id.class_idx_); @@ -455,49 +352,47 @@ class DexFile { // Returns the signature of a method id. const std::string GetMethodSignature(const MethodId& method_id) const { - return CreateMethodDescriptor(method_id.proto_idx_, NULL); + return CreateMethodSignature(method_id.proto_idx_, NULL); } // Returns the name of a method id. const char* GetMethodName(const MethodId& method_id) const { - return dexStringById(method_id.name_idx_); + return StringDataByIdx(method_id.name_idx_); } - // Returns the StringId at the specified index. - const StringId& GetStringId(uint32_t idx) const { - CHECK_LT(idx, NumStringIds()); - return string_ids_[idx]; + // Returns the shorty of a method id. + const char* GetMethodShorty(const MethodId& method_id) const { + return StringDataByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_); } - // Returns the TypeId at the specified index. - const TypeId& GetTypeId(uint32_t idx) const { - CHECK_LT(idx, NumTypeIds()); - return type_ids_[idx]; + // Returns the number of class definitions in the .dex file. + size_t NumClassDefs() const { + CHECK(header_ != NULL); + return header_->class_defs_size_; } - // Returns the FieldId at the specified index. - const FieldId& GetFieldId(uint32_t idx) const { - CHECK_LT(idx, NumFieldIds()); - return field_ids_[idx]; + // Returns the ClassDef at the specified index. + const ClassDef& GetClassDef(uint32_t idx) const { + CHECK_LT(idx, NumClassDefs()); + return class_defs_[idx]; } - // Returns the MethodId at the specified index. - const MethodId& GetMethodId(uint32_t idx) const { - CHECK_LT(idx, NumMethodIds()); - return method_ids_[idx]; + uint32_t GetIndexForClassDef(const ClassDef& class_def) const { + CHECK_GE(&class_def, class_defs_); + CHECK_LT(&class_def, class_defs_ + header_->class_defs_size_); + return &class_def - class_defs_; } - // Returns the ProtoId at the specified index. - const ProtoId& GetProtoId(uint32_t idx) const { - CHECK_LT(idx, NumProtoIds()); - return proto_ids_[idx]; + // Returns the class descriptor string of a class definition. + const char* GetClassDescriptor(const ClassDef& class_def) const { + return StringByTypeIdx(class_def.class_idx_); } - // Returns the ClassDef at the specified index. - const ClassDef& GetClassDef(uint32_t idx) const { - CHECK_LT(idx, NumClassDefs()); - return class_defs_[idx]; - } + // Looks up a class definition by its class descriptor. + const ClassDef* FindClassDef(const StringPiece& descriptor) const; + + // Looks up a class definition index by its class descriptor. + bool FindClassDefIndex(const StringPiece& descriptor, uint32_t& idx) const; const TypeList* GetInterfacesList(const ClassDef& class_def) const { if (class_def.interfaces_off_ == 0) { @@ -508,10 +403,16 @@ class DexFile { } } - const CodeItem* GetCodeItem(const Method& method) const { - return GetCodeItem(method.code_off_); + // Returns a pointer to the raw memory mapped class_data_item + const byte* GetClassData(const ClassDef& class_def) const { + if (class_def.class_data_off_ == 0) { + return NULL; + } else { + return base_ + class_def.class_data_off_; + } } + // const CodeItem* GetCodeItem(const uint32_t code_off_) const { if (code_off_ == 0) { return NULL; // native or abstract method @@ -521,10 +422,43 @@ class DexFile { } } + const char* GetReturnTypeDescriptor(const ProtoId& proto_id) const { + return StringByTypeIdx(proto_id.return_type_idx_); + } + + // Returns the number of prototype identifiers in the .dex file. + size_t NumProtoIds() const { + CHECK(header_ != NULL); + return header_->proto_ids_size_; + } + + // Returns the ProtoId at the specified index. + const ProtoId& GetProtoId(uint32_t idx) const { + CHECK_LT(idx, NumProtoIds()); + return proto_ids_[idx]; + } + + uint16_t GetIndexForProtoId(const ProtoId& proto_id) const { + CHECK_GE(&proto_id, proto_ids_); + CHECK_LT(&proto_id, proto_ids_ + header_->proto_ids_size_); + return &proto_id - proto_ids_; + } + + // Looks up a proto id for a given return type and signature type list + const ProtoId* FindProtoId(uint16_t return_type_id, + const std::vector<uint16_t>& signature_type_ids_) const; + + // Given a signature place the type ids into the given vector, returns true on success + bool CreateTypeList(uint16_t* return_type_idx, std::vector<uint16_t>* param_type_idxs, + const std::string& signature) const; + + // Given a proto_idx decode the type list and return type into a method signature + std::string CreateMethodSignature(uint32_t proto_idx, int32_t* unicode_length) const; + // Returns the short form method descriptor for the given prototype. const char* GetShorty(uint32_t proto_idx) const { const ProtoId& proto_id = GetProtoId(proto_idx); - return dexStringById(proto_id.shorty_idx_); + return StringDataByIdx(proto_id.shorty_idx_); } const TypeList* GetProtoParameters(const ProtoId& proto_id) const { @@ -536,9 +470,7 @@ class DexFile { } } - std::string CreateMethodDescriptor(uint32_t proto_idx, int32_t* unicode_length) const; - - const byte* GetEncodedArray(const ClassDef& class_def) const { + const byte* GetEncodedStaticFieldValuesArray(const ClassDef& class_def) const { if (class_def.static_values_off_ == 0) { return 0; } else { @@ -546,158 +478,27 @@ class DexFile { } } - int32_t GetStringLength(const StringId& string_id) const { - const byte* ptr = base_ + string_id.string_data_off_; - return DecodeUnsignedLeb128(&ptr); - } - - ValueType ReadEncodedValue(const byte** encoded_value, JValue* value) const; - - // From libdex... - - // Returns a pointer to the UTF-8 string data referred to by the - // given string_id. - const char* GetStringData(const StringId& string_id, int32_t* length) const { - CHECK(length != NULL); - const byte* ptr = base_ + string_id.string_data_off_; - *length = DecodeUnsignedLeb128(&ptr); - return reinterpret_cast<const char*>(ptr); - } - - const char* GetStringData(const StringId& string_id) const { - int32_t length; - return GetStringData(string_id, &length); - } - - // return the UTF-8 encoded string with the specified string_id index - const char* dexStringById(uint32_t idx, int32_t* unicode_length) const { - if (idx == kDexNoIndex) { - *unicode_length = 0; - return NULL; - } - const StringId& string_id = GetStringId(idx); - return GetStringData(string_id, unicode_length); - } - - const char* dexStringById(uint32_t idx) const { - int32_t unicode_length; - return dexStringById(idx, &unicode_length); - } - - // Get the descriptor string associated with a given type index. - const char* dexStringByTypeIdx(uint32_t idx, int32_t* unicode_length) const { - const TypeId& type_id = GetTypeId(idx); - return dexStringById(type_id.descriptor_idx_, unicode_length); - } - - const char* dexStringByTypeIdx(uint32_t idx) const { - const TypeId& type_id = GetTypeId(idx); - return dexStringById(type_id.descriptor_idx_); - } - - // TODO: encoded_field is actually a stream of bytes - void dexReadClassDataField(const byte** encoded_field, - DexFile::Field* field, - uint32_t* last_idx) const { - uint32_t idx = *last_idx + DecodeUnsignedLeb128(encoded_field); - field->access_flags_ = DecodeUnsignedLeb128(encoded_field); - field->field_idx_ = idx; - *last_idx = idx; - } - - // TODO: encoded_method is actually a stream of bytes - void dexReadClassDataMethod(const byte** encoded_method, - DexFile::Method* method, - uint32_t* last_idx) const { - uint32_t idx = *last_idx + DecodeUnsignedLeb128(encoded_method); - method->access_flags_ = DecodeUnsignedLeb128(encoded_method); - method->code_off_ = DecodeUnsignedLeb128(encoded_method); - method->method_idx_ = idx; - *last_idx = idx; - } - - static const TryItem* dexGetTryItems(const CodeItem& code_item, uint32_t offset) { + static const TryItem* GetTryItems(const CodeItem& code_item, uint32_t offset) { const uint16_t* insns_end_ = &code_item.insns_[code_item.insns_size_in_code_units_]; return reinterpret_cast<const TryItem*> (RoundUp(reinterpret_cast<uint32_t>(insns_end_), 4)) + offset; } // Get the base of the encoded data for the given DexCode. - static const byte* dexGetCatchHandlerData(const CodeItem& code_item, uint32_t offset) { - const byte* handler_data = reinterpret_cast<const byte*> - (dexGetTryItems(code_item, code_item.tries_size_)); + static const byte* GetCatchHandlerData(const CodeItem& code_item, uint32_t offset) { + const byte* handler_data = + reinterpret_cast<const byte*>(GetTryItems(code_item, code_item.tries_size_)); return handler_data + offset; } // Find the handler associated with a given address, if any. // Initializes the given iterator and returns true if a match is // found. Returns end if there is no applicable handler. - static CatchHandlerIterator dexFindCatchHandler(const CodeItem& code_item, uint32_t address) { - CatchHandlerItem handler; - handler.address_ = -1; - int32_t offset = -1; - - // Short-circuit the overwhelmingly common cases. - switch (code_item.tries_size_) { - case 0: - break; - case 1: { - const TryItem* tries = dexGetTryItems(code_item, 0); - uint32_t start = tries->start_addr_; - if (address < start) - break; - - uint32_t end = start + tries->insn_count_; - if (address >= end) - break; - - offset = tries->handler_off_; - break; - } - default: - offset = dexFindCatchHandlerOffset0(code_item, code_item.tries_size_, address); - } - - if (offset >= 0) { - const byte* handler_data = dexGetCatchHandlerData(code_item, offset); - return CatchHandlerIterator(handler_data); - } - return CatchHandlerIterator(); - } - - static int32_t dexFindCatchHandlerOffset0(const CodeItem &code_item, - int32_t tries_size, - uint32_t address) { - // Note: Signed type is important for max and min. - int32_t min = 0; - int32_t max = tries_size - 1; - - while (max >= min) { - int32_t guess = (min + max) >> 1; - const TryItem* pTry = dexGetTryItems(code_item, guess); - uint32_t start = pTry->start_addr_; - - if (address < start) { - max = guess - 1; - continue; - } - - uint32_t end = start + pTry->insn_count_; - if (address >= end) { - min = guess + 1; - continue; - } - - // We have a winner! - return (int32_t) pTry->handler_off_; - } - - // No match. - return -1; - } + static int32_t FindCatchHandlerOffset(const CodeItem &code_item, int32_t tries_size, + uint32_t address); // Get the pointer to the start of the debugging data - const byte* dexGetDebugInfoStream(const CodeItem* code_item) const { + const byte* GetDebugInfoStream(const CodeItem* code_item) const { if (code_item->debug_info_off_ == 0) { return NULL; } else { @@ -718,22 +519,7 @@ class DexFile { const char* descriptor, const char* signature); - static bool LineNumForPcCb(void* cnxt, uint32_t address, uint32_t line_num) { - LineNumFromPcContext* context = (LineNumFromPcContext*) cnxt; - - // We know that this callback will be called in - // ascending address order, so keep going until we find - // a match or we've just gone past it. - if (address > context->address_) { - // The line number from the previous positions callback - // wil be the final result. - return true; - } else { - context->line_num_ = line_num; - return address == context->address_; - } - } - + static bool LineNumForPcCb(void* cnxt, uint32_t address, uint32_t line_num); // Debug info opcodes and constants enum { @@ -753,22 +539,14 @@ class DexFile { }; struct LocalInfo { - LocalInfo() : name_(NULL), start_address_(0), is_live_(false) {} - - // E.g., list - const char* name_; - - // E.g., Ljava/util/LinkedList; - const char* descriptor_; + LocalInfo() : name_(NULL), descriptor_(NULL), signature_(NULL), start_address_(0), + is_live_(false) {} - // E.g., java.util.LinkedList<java.lang.Integer> - const char* signature_; - - // PC location where the local is first defined. - uint16_t start_address_; - - // Is the local defined and live. - bool is_live_; + const char* name_; // E.g., list + const char* descriptor_; // E.g., Ljava/util/LinkedList; + const char* signature_; // E.g., java.util.LinkedList<java.lang.Integer> + uint16_t start_address_; // PC location where the local is first defined. + bool is_live_; // Is the local defined and live. private: DISALLOW_COPY_AND_ASSIGN(LocalInfo); @@ -800,38 +578,21 @@ class DexFile { // Returns -2 for native methods (as expected in exception traces). // // This is used by runtime; therefore use art::Method not art::DexFile::Method. - int32_t GetLineNumFromPC(const art::Method* method, uint32_t rel_pc) const; + int32_t GetLineNumFromPC(const Method* method, uint32_t rel_pc) const; - void dexDecodeDebugInfo0(const CodeItem* code_item, const art::Method* method, - DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb, - void* cnxt, const byte* stream, LocalInfo* local_in_reg) const; + void DecodeDebugInfo0(const CodeItem* code_item, const Method* method, + DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb, + void* cnxt, const byte* stream, LocalInfo* local_in_reg) const; - void dexDecodeDebugInfo(const CodeItem* code_item, const art::Method* method, - DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb, - void* cnxt) const { - const byte* stream = dexGetDebugInfoStream(code_item); - LocalInfo local_in_reg[code_item->registers_size_]; + void DecodeDebugInfo(const CodeItem* code_item, const Method* method, + DexDebugNewPositionCb posCb, DexDebugNewLocalCb local_cb, + void* cnxt) const; - if (stream != NULL) { - dexDecodeDebugInfo0(code_item, method, posCb, local_cb, cnxt, stream, local_in_reg); - } - for (int reg = 0; reg < code_item->registers_size_; reg++) { - InvokeLocalCbIfLive(cnxt, reg, code_item->insns_size_in_code_units_, local_in_reg, local_cb); - } - } - - // TODO: const reference - uint32_t dexGetIndexForClassDef(const ClassDef* class_def) const { - CHECK_GE(class_def, class_defs_); - CHECK_LT(class_def, class_defs_ + header_->class_defs_size_); - return class_def - class_defs_; - } - - const char* dexGetSourceFile(const ClassDef& class_def) const { + const char* GetSourceFile(const ClassDef& class_def) const { if (class_def.source_file_idx_ == 0xffffffff) { return NULL; } else { - return dexStringById(class_def.source_file_idx_); + return StringDataByIdx(class_def.source_file_idx_); } } @@ -889,6 +650,8 @@ class DexFile { bool IsMagicValid(); // The index of descriptors to class definition indexes. + // TODO: given type_ids are sorted by string_id index, and string_ids are alphabetically, class + // lookup can be done with a binary search. Is the index necessary? typedef std::map<const StringPiece, uint32_t> Index; Index index_; @@ -933,6 +696,261 @@ class DexFile { const ClassDef* class_defs_; }; +// Iterate over a dex file's ProtoId's paramters +class DexFileParameterIterator { + public: + DexFileParameterIterator(const DexFile& dex_file, const DexFile::ProtoId& proto_id) + : dex_file_(dex_file), size_(0), pos_(0) { + type_list_ = dex_file_.GetProtoParameters(proto_id); + if (type_list_ != NULL) { + size_ = type_list_->Size(); + } + } + bool HasNext() const { return pos_ < size_; } + void Next() { ++pos_; } + uint16_t GetTypeId() { + return type_list_->GetTypeItem(pos_).type_idx_; + } + const char* GetDescriptor() { + return dex_file_.StringByTypeIdx(GetTypeId()); + } + private: + const DexFile& dex_file_; + const DexFile::TypeList* type_list_; + uint32_t size_; + uint32_t pos_; + DISALLOW_IMPLICIT_CONSTRUCTORS(DexFileParameterIterator); +}; + +// Iterate and decode class_data_item +class ClassDataItemIterator { + public: + ClassDataItemIterator(const DexFile& dex_file, const byte* raw_class_data_item) + : dex_file_(dex_file), pos_(0), ptr_pos_(raw_class_data_item), last_idx_(0) { + ReadClassDataHeader(); + if (EndOfInstanceFieldsPos() > 0) { + ReadClassDataField(); + } else if (EndOfVirtualMethodsPos() > 0) { + ReadClassDataMethod(); + } + } + uint32_t NumStaticFields() const { + return header_.static_fields_size_; + } + uint32_t NumInstanceFields() const { + return header_.instance_fields_size_; + } + uint32_t NumDirectMethods() const { + return header_.direct_methods_size_; + } + uint32_t NumVirtualMethods() const { + return header_.virtual_methods_size_; + } + bool HasNextStaticField() const { + return pos_ < EndOfStaticFieldsPos(); + } + bool HasNextInstanceField() const { + return pos_ >= EndOfStaticFieldsPos() && pos_ < EndOfInstanceFieldsPos(); + } + bool HasNextDirectMethod() const { + return pos_ >= EndOfInstanceFieldsPos() && pos_ < EndOfDirectMethodsPos(); + } + bool HasNextVirtualMethod() const { + return pos_ >= EndOfDirectMethodsPos() && pos_ < EndOfVirtualMethodsPos(); + } + bool HasNext() const { + return pos_ < EndOfVirtualMethodsPos(); + } + void Next() { + pos_++; + if (pos_ < EndOfStaticFieldsPos()) { + last_idx_ = GetMemberIndex(); + ReadClassDataField(); + } else if (pos_ == EndOfStaticFieldsPos() && NumInstanceFields() > 0) { + last_idx_ = 0; // transition to next array, reset last index + ReadClassDataField(); + } else if (pos_ < EndOfInstanceFieldsPos()) { + last_idx_ = GetMemberIndex(); + ReadClassDataField(); + } else if (pos_ == EndOfInstanceFieldsPos() && NumDirectMethods() > 0) { + last_idx_ = 0; // transition to next array, reset last index + ReadClassDataMethod(); + } else if (pos_ < EndOfDirectMethodsPos()) { + last_idx_ = GetMemberIndex(); + ReadClassDataMethod(); + } else if (pos_ == EndOfDirectMethodsPos() && NumVirtualMethods() > 0) { + last_idx_ = 0; // transition to next array, reset last index + ReadClassDataMethod(); + } else if (pos_ < EndOfVirtualMethodsPos()) { + last_idx_ = GetMemberIndex(); + ReadClassDataMethod(); + } else { + DCHECK(!HasNext()); + } + } + uint32_t GetMemberIndex() const { + if (pos_ < EndOfInstanceFieldsPos()) { + return last_idx_ + field_.field_idx_delta_; + } else { + CHECK_LT(pos_, EndOfVirtualMethodsPos()); + return last_idx_ + method_.method_idx_delta_; + } + } + uint32_t GetMemberAccessFlags() const { + if (pos_ < EndOfInstanceFieldsPos()) { + return field_.access_flags_; + } else { + CHECK_LT(pos_, EndOfVirtualMethodsPos()); + return method_.access_flags_; + } + } + const DexFile::CodeItem* GetMethodCodeItem() const { + return dex_file_.GetCodeItem(method_.code_off_); + } + uint32_t GetMethodCodeItemOffset() const { + return method_.code_off_; + } + private: + // A dex file's class_data_item is leb128 encoded, this structure holds a decoded form of the + // header for a class_data_item + struct ClassDataHeader { + uint32_t static_fields_size_; // the number of static fields + uint32_t instance_fields_size_; // the number of instance fields + uint32_t direct_methods_size_; // the number of direct methods + uint32_t virtual_methods_size_; // the number of virtual methods + } header_; + + // Read and decode header from a class_data_item stream into header + void ReadClassDataHeader(); + + uint32_t EndOfStaticFieldsPos() const { + return header_.static_fields_size_; + } + uint32_t EndOfInstanceFieldsPos() const { + return EndOfStaticFieldsPos() + header_.instance_fields_size_; + } + uint32_t EndOfDirectMethodsPos() const { + return EndOfInstanceFieldsPos() + header_.direct_methods_size_; + } + uint32_t EndOfVirtualMethodsPos() const { + return EndOfDirectMethodsPos() + header_.virtual_methods_size_; + } + + // A decoded version of the field of a class_data_item + struct ClassDataField { + uint32_t field_idx_delta_; // delta of index into the field_ids array for FieldId + uint32_t access_flags_; // access flags for the field + ClassDataField() : field_idx_delta_(0), access_flags_(0) {} + private: + DISALLOW_COPY_AND_ASSIGN(ClassDataField); + } field_; + + // Read and decode a field from a class_data_item stream into field + void ReadClassDataField(); + + // A decoded version of the method of a class_data_item + struct ClassDataMethod { + uint32_t method_idx_delta_; // delta of index into the method_ids array for MethodId + uint32_t access_flags_; + uint32_t code_off_; + ClassDataMethod() : method_idx_delta_(0), access_flags_(0), code_off_(0) {} + private: + DISALLOW_COPY_AND_ASSIGN(ClassDataMethod); + } method_; + + // Read and decode a method from a class_data_item stream into method + void ReadClassDataMethod(); + + const DexFile& dex_file_; + size_t pos_; // integral number of items passed + const byte* ptr_pos_; // pointer into stream of class_data_item + uint32_t last_idx_; // last read field or method index to apply delta to + DISALLOW_IMPLICIT_CONSTRUCTORS(ClassDataItemIterator); +}; + +class ClassLinker; +class DexCache; +class Field; + +class EncodedStaticFieldValueIterator { + public: + EncodedStaticFieldValueIterator(const DexFile& dex_file, DexCache* dex_cache, + ClassLinker* linker, const DexFile::ClassDef& class_def); + + void ReadValueToField(Field* field) const; + + bool HasNext() { return pos_ < array_size_; } + + void Next(); + private: + enum ValueType { + kByte = 0x00, + kShort = 0x02, + kChar = 0x03, + kInt = 0x04, + kLong = 0x06, + kFloat = 0x10, + kDouble = 0x11, + kString = 0x17, + kType = 0x18, + kField = 0x19, + kMethod = 0x1a, + kEnum = 0x1b, + kArray = 0x1c, + kAnnotation = 0x1d, + kNull = 0x1e, + kBoolean = 0x1f + }; + + static const byte kEncodedValueTypeMask = 0x1f; // 0b11111 + static const byte kEncodedValueArgShift = 5; + + const DexFile& dex_file_; + DexCache* dex_cache_; // dex cache to resolve literal objects + ClassLinker* linker_; // linker to resolve literal objects + size_t array_size_; // size of array + size_t pos_; // current position + const byte* ptr_; // pointer into encoded data array + byte type_; // type of current encoded value + jvalue jval_; // value of current encoded value + DISALLOW_IMPLICIT_CONSTRUCTORS(EncodedStaticFieldValueIterator); +}; + +class CatchHandlerIterator { + public: + CatchHandlerIterator(const DexFile::CodeItem& code_item, uint32_t address); + explicit CatchHandlerIterator(const byte* handler_data) { + Init(handler_data); + } + + uint16_t GetHandlerTypeIndex() const { + return handler_.type_idx_; + } + uint32_t GetHandlerAddress() const { + return handler_.address_; + } + void Next(); + bool HasNext() const { + return remaining_count_ != -1 || catch_all_; + } + // End of this set of catch blocks, convenience method to locate next set of catch blocks + const byte* EndDataPointer() const { + CHECK(!HasNext()); + return current_data_; + } + private: + void Init(const byte* handler_data); + + struct CatchHandlerItem { + uint16_t type_idx_; // type index of the caught exception type + uint32_t address_; // handler address + } handler_; + const byte *current_data_; // the current handler in dex file. + int32_t remaining_count_; // number of handlers not read. + bool catch_all_; // is there a handler that will catch all exceptions in case + // that all typed handler does not match. +}; + } // namespace art #endif // ART_SRC_DEX_FILE_H_ diff --git a/src/dex_file_test.cc b/src/dex_file_test.cc index e33276b881..6f99551e1a 100644 --- a/src/dex_file_test.cc +++ b/src/dex_file_test.cc @@ -81,65 +81,118 @@ TEST_F(DexFileTest, ClassDefs) { EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c1)); } -TEST_F(DexFileTest, CreateMethodDescriptor) { - UniquePtr<const DexFile> raw(OpenTestDexFile("CreateMethodDescriptor")); +TEST_F(DexFileTest, CreateMethodSignature) { + UniquePtr<const DexFile> raw(OpenTestDexFile("CreateMethodSignature")); ASSERT_TRUE(raw.get() != NULL); EXPECT_EQ(1U, raw->NumClassDefs()); const DexFile::ClassDef& class_def = raw->GetClassDef(0); - ASSERT_STREQ("LCreateMethodDescriptor;", raw->GetClassDescriptor(class_def)); + ASSERT_STREQ("LCreateMethodSignature;", raw->GetClassDescriptor(class_def)); const byte* class_data = raw->GetClassData(class_def); ASSERT_TRUE(class_data != NULL); - DexFile::ClassDataHeader header = raw->ReadClassDataHeader(&class_data); + ClassDataItemIterator it(*raw.get(), class_data); - EXPECT_EQ(1u, header.direct_methods_size_); + EXPECT_EQ(1u, it.NumDirectMethods()); - // Check the descriptor for the static initializer. + // Check the signature for the static initializer. { - uint32_t last_idx = 0; - ASSERT_EQ(1U, header.direct_methods_size_); - DexFile::Method method; - raw->dexReadClassDataMethod(&class_data, &method, &last_idx); - const DexFile::MethodId& method_id = raw->GetMethodId(method.method_idx_); + ASSERT_EQ(1U, it.NumDirectMethods()); + const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); uint32_t proto_idx = method_id.proto_idx_; - const char* name = raw->dexStringById(method_id.name_idx_); + const char* name = raw->StringDataByIdx(method_id.name_idx_); ASSERT_STREQ("<init>", name); int32_t length; - std::string descriptor(raw->CreateMethodDescriptor(proto_idx, &length)); - ASSERT_EQ("()V", descriptor); + std::string signature(raw->CreateMethodSignature(proto_idx, &length)); + ASSERT_EQ("()V", signature); } // Check both virtual methods. - ASSERT_EQ(2U, header.virtual_methods_size_); - uint32_t last_idx = 0; - + ASSERT_EQ(2U, it.NumVirtualMethods()); { - DexFile::Method method; - raw->dexReadClassDataMethod(&class_data, &method, &last_idx); - const DexFile::MethodId& method_id = raw->GetMethodId(method.method_idx_); + it.Next(); + const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); - const char* name = raw->dexStringById(method_id.name_idx_); + const char* name = raw->StringDataByIdx(method_id.name_idx_); ASSERT_STREQ("m1", name); uint32_t proto_idx = method_id.proto_idx_; int32_t length; - std::string descriptor(raw->CreateMethodDescriptor(proto_idx, &length)); - ASSERT_EQ("(IDJLjava/lang/Object;)Ljava/lang/Float;", descriptor); + std::string signature(raw->CreateMethodSignature(proto_idx, &length)); + ASSERT_EQ("(IDJLjava/lang/Object;)Ljava/lang/Float;", signature); } { - DexFile::Method method; - raw->dexReadClassDataMethod(&class_data, &method, &last_idx); - const DexFile::MethodId& method_id = raw->GetMethodId(method.method_idx_); + it.Next(); + const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex()); - const char* name = raw->dexStringById(method_id.name_idx_); + const char* name = raw->StringDataByIdx(method_id.name_idx_); ASSERT_STREQ("m2", name); uint32_t proto_idx = method_id.proto_idx_; int32_t length; - std::string descriptor(raw->CreateMethodDescriptor(proto_idx, &length)); - ASSERT_EQ("(ZSC)LCreateMethodDescriptor;", descriptor); + std::string signature(raw->CreateMethodSignature(proto_idx, &length)); + ASSERT_EQ("(ZSC)LCreateMethodSignature;", signature); + } +} + +TEST_F(DexFileTest, FindStringId) { + UniquePtr<const DexFile> raw(OpenTestDexFile("CreateMethodSignature")); + ASSERT_TRUE(raw.get() != NULL); + EXPECT_EQ(1U, raw->NumClassDefs()); + + const char* strings[] = { "LCreateMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;", + "D", "I", "J", NULL }; + for (size_t i = 0; strings[i] != NULL; i++) { + const char* str = strings[i]; + const DexFile::StringId* str_id = raw->FindStringId(str); + const char* dex_str = raw->GetStringData(*str_id); + EXPECT_STREQ(dex_str, str); + } +} + +TEST_F(DexFileTest, FindTypeId) { + for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) { + const char* type_str = java_lang_dex_file_->StringByTypeIdx(i); + const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str); + ASSERT_TRUE(type_str_id != NULL); + uint32_t type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id); + const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx); + ASSERT_TRUE(type_id != NULL); + EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id), i); + } +} + +TEST_F(DexFileTest, FindProtoId) { + for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) { + const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i); + const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find); + std::vector<uint16_t> to_find_types; + if (to_find_tl != NULL) { + for (size_t j = 0; j < to_find_tl->Size(); j++) { + to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_); + } + } + const DexFile::ProtoId* found = + java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types); + ASSERT_TRUE(found != NULL); + EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i); + } +} + +TEST_F(DexFileTest, FindMethodId) { + for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) { + const DexFile::MethodId& to_find = java_lang_dex_file_->GetMethodId(i); + const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_); + const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_); + const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_); + const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature); + int32_t length; + ASSERT_TRUE(found != NULL) << "Didn't find method " << i << ": " + << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "." + << java_lang_dex_file_->GetStringData(name) + << java_lang_dex_file_->CreateMethodSignature(to_find.proto_idx_, &length); + EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i); } } diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc index 3ad9996995..d162aec730 100644 --- a/src/dex_verifier.cc +++ b/src/dex_verifier.cc @@ -11,6 +11,7 @@ #include "dex_instruction_visitor.h" #include "dex_verifier.h" #include "intern_table.h" +#include "leb128.h" #include "logging.h" #include "runtime.h" #include "stringpiece.h" @@ -1031,7 +1032,7 @@ bool DexVerifier::ScanTryCatchBlocks() { return true; } uint32_t insns_size = code_item_->insns_size_in_code_units_; - const DexFile::TryItem* tries = DexFile::dexGetTryItems(*code_item_, 0); + const DexFile::TryItem* tries = DexFile::GetTryItems(*code_item_, 0); for (uint32_t idx = 0; idx < tries_size; idx++) { const DexFile::TryItem* try_item = &tries[idx]; @@ -1052,14 +1053,13 @@ bool DexVerifier::ScanTryCatchBlocks() { } } /* Iterate over each of the handlers to verify target addresses. */ - const byte* handlers_ptr = DexFile::dexGetCatchHandlerData(*code_item_, 0); + const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0); uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr); ClassLinker* linker = Runtime::Current()->GetClassLinker(); for (uint32_t idx = 0; idx < handlers_size; idx++) { - DexFile::CatchHandlerIterator iterator(handlers_ptr); - for (; !iterator.HasNext(); iterator.Next()) { - const DexFile::CatchHandlerItem& handler = iterator.Get(); - uint32_t dex_pc= handler.address_; + CatchHandlerIterator iterator(handlers_ptr); + for (; iterator.HasNext(); iterator.Next()) { + uint32_t dex_pc= iterator.GetHandlerAddress(); if (!insn_flags_[dex_pc].IsOpcode()) { Fail(VERIFY_ERROR_GENERIC) << "exception handler starts at bad address (" << dex_pc << ")"; return false; @@ -1067,15 +1067,15 @@ bool DexVerifier::ScanTryCatchBlocks() { insn_flags_[dex_pc].SetBranchTarget(); // Ensure exception types are resolved so that they don't need resolution to be delivered, // unresolved exception types will be ignored by exception delivery - if (handler.type_idx_ != DexFile::kDexNoIndex) { - Class* exception_type = linker->ResolveType(handler.type_idx_, method_); + if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) { + Class* exception_type = linker->ResolveType(iterator.GetHandlerTypeIndex(), method_); if (exception_type == NULL) { DCHECK(Thread::Current()->IsExceptionPending()); Thread::Current()->ClearException(); } } } - handlers_ptr = iterator.GetData(); + handlers_ptr = iterator.EndDataPointer(); } return true; } @@ -1221,7 +1221,7 @@ bool DexVerifier::CheckNewInstance(uint32_t idx) { return false; } // We don't need the actual class, just a pointer to the class name. - const char* descriptor = dex_file_->dexStringByTypeIdx(idx); + const char* descriptor = dex_file_->StringByTypeIdx(idx); if (descriptor[0] != 'L') { Fail(VERIFY_ERROR_GENERIC) << "can't call new-instance on type '" << descriptor << "'"; return false; @@ -1254,7 +1254,7 @@ bool DexVerifier::CheckNewArray(uint32_t idx) { return false; } int bracket_count = 0; - const char* descriptor = dex_file_->dexStringByTypeIdx(idx); + const char* descriptor = dex_file_->StringByTypeIdx(idx); const char* cp = descriptor; while (*cp++ == '[') { bracket_count++; @@ -1575,7 +1575,7 @@ bool DexVerifier::SetTypesFromSignature() { } const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(method_->GetProtoIdx()); - DexFile::ParameterIterator iterator(*dex_file_, proto_id); + DexFileParameterIterator iterator(*dex_file_, proto_id); for (; iterator.HasNext(); iterator.Next()) { const char* descriptor = iterator.GetDescriptor(); @@ -2364,7 +2364,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { uint32_t method_idx = dec_insn.vB_; const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_; - descriptor = dex_file_->dexStringByTypeIdx(return_type_idx); + descriptor = dex_file_->StringByTypeIdx(return_type_idx); } else { descriptor = called_method->GetReturnTypeDescriptor(); } @@ -2442,7 +2442,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { uint32_t method_idx = dec_insn.vB_; const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_; - descriptor = dex_file_->dexStringByTypeIdx(return_type_idx); + descriptor = dex_file_->StringByTypeIdx(return_type_idx); } else { descriptor = called_method->GetReturnTypeDescriptor(); } @@ -2463,7 +2463,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { uint32_t method_idx = dec_insn.vB_; const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_; - descriptor = dex_file_->dexStringByTypeIdx(return_type_idx); + descriptor = dex_file_->StringByTypeIdx(return_type_idx); } else { descriptor = called_method->GetReturnTypeDescriptor(); } @@ -2518,7 +2518,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { uint32_t method_idx = dec_insn.vB_; const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_; - descriptor = dex_file_->dexStringByTypeIdx(return_type_idx); + descriptor = dex_file_->StringByTypeIdx(return_type_idx); } else { descriptor = abs_method->GetReturnTypeDescriptor(); } @@ -2891,11 +2891,10 @@ bool DexVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { */ if ((opcode_flag & Instruction::kThrow) != 0 && insn_flags_[work_insn_idx_].IsInTry()) { bool within_catch_all = false; - DexFile::CatchHandlerIterator iterator = - DexFile::dexFindCatchHandler(*code_item_, work_insn_idx_); + CatchHandlerIterator iterator(*code_item_, work_insn_idx_); - for (; !iterator.HasNext(); iterator.Next()) { - if (iterator.Get().type_idx_ == DexFile::kDexNoIndex) { + for (; iterator.HasNext(); iterator.Next()) { + if (iterator.GetHandlerTypeIndex() == DexFile::kDexNoIndex16) { within_catch_all = true; } /* @@ -2903,7 +2902,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { * "work_regs", because at runtime the exception will be thrown before the instruction * modifies any registers. */ - if (!UpdateRegisters(iterator.Get().address_, saved_line_.get())) { + if (!UpdateRegisters(iterator.GetHandlerAddress(), saved_line_.get())) { return false; } } @@ -2953,7 +2952,7 @@ bool DexVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { } const RegType& DexVerifier::ResolveClassAndCheckAccess(uint32_t class_idx) { - const char* descriptor = dex_file_->dexStringByTypeIdx(class_idx); + const char* descriptor = dex_file_->StringByTypeIdx(class_idx); Class* referrer = method_->GetDeclaringClass(); Class* klass = method_->GetDexCacheResolvedTypes()->Get(class_idx); const RegType& result = @@ -2977,17 +2976,16 @@ const RegType& DexVerifier::ResolveClassAndCheckAccess(uint32_t class_idx) { const RegType& DexVerifier::GetCaughtExceptionType() { const RegType* common_super = NULL; if (code_item_->tries_size_ != 0) { - const byte* handlers_ptr = DexFile::dexGetCatchHandlerData(*code_item_, 0); + const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item_, 0); uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr); for (uint32_t i = 0; i < handlers_size; i++) { - DexFile::CatchHandlerIterator iterator(handlers_ptr); - for (; !iterator.HasNext(); iterator.Next()) { - DexFile::CatchHandlerItem handler = iterator.Get(); - if (handler.address_ == (uint32_t) work_insn_idx_) { - if (handler.type_idx_ == DexFile::kDexNoIndex) { + CatchHandlerIterator iterator(handlers_ptr); + for (; iterator.HasNext(); iterator.Next()) { + if (iterator.GetHandlerAddress() == (uint32_t) work_insn_idx_) { + if (iterator.GetHandlerTypeIndex() == DexFile::kDexNoIndex16) { common_super = ®_types_.JavaLangThrowable(); } else { - const RegType& exception = ResolveClassAndCheckAccess(handler.type_idx_); + const RegType& exception = ResolveClassAndCheckAccess(iterator.GetHandlerTypeIndex()); /* TODO: on error do we want to keep going? If we don't fail this we run the risk of * having a non-Throwable introduced at runtime. However, that won't pass an instanceof * test, so is essentially harmless. @@ -3006,7 +3004,7 @@ const RegType& DexVerifier::GetCaughtExceptionType() { } } } - handlers_ptr = iterator.GetData(); + handlers_ptr = iterator.EndDataPointer(); } } if (common_super == NULL) { @@ -3028,7 +3026,7 @@ Method* DexVerifier::ResolveMethodAndCheckAccess(uint32_t method_idx, bool is_di } Class* klass = klass_type.GetClass(); const char* name = dex_file_->GetMethodName(method_id); - std::string signature(dex_file_->CreateMethodDescriptor(method_id.proto_idx_, NULL)); + std::string signature(dex_file_->CreateMethodSignature(method_id.proto_idx_, NULL)); if (is_direct) { res_method = klass->FindDirectMethod(name, signature); } else if (klass->IsInterface()) { diff --git a/src/exception_test.cc b/src/exception_test.cc index df6432923a..559636f417 100644 --- a/src/exception_test.cc +++ b/src/exception_test.cc @@ -67,28 +67,30 @@ TEST_F(ExceptionTest, FindCatchHandler) { ASSERT_NE(0u, code_item->insns_size_in_code_units_); const struct DexFile::TryItem *t0, *t1; - t0 = dex_->dexGetTryItems(*code_item, 0); - t1 = dex_->dexGetTryItems(*code_item, 1); + t0 = dex_->GetTryItems(*code_item, 0); + t1 = dex_->GetTryItems(*code_item, 1); EXPECT_LE(t0->start_addr_, t1->start_addr_); - - DexFile::CatchHandlerIterator iter = - dex_->dexFindCatchHandler(*code_item, 4 /* Dex PC in the first try block */); - ASSERT_EQ(false, iter.HasNext()); - EXPECT_STREQ("Ljava/io/IOException;", dex_->dexStringByTypeIdx(iter.Get().type_idx_)); - iter.Next(); - ASSERT_EQ(false, iter.HasNext()); - EXPECT_STREQ("Ljava/lang/Exception;", dex_->dexStringByTypeIdx(iter.Get().type_idx_)); - iter.Next(); - ASSERT_EQ(true, iter.HasNext()); - - iter = dex_->dexFindCatchHandler(*code_item, 8 /* Dex PC in the second try block */); - ASSERT_EQ(false, iter.HasNext()); - EXPECT_STREQ("Ljava/io/IOException;", dex_->dexStringByTypeIdx(iter.Get().type_idx_)); - iter.Next(); - ASSERT_EQ(true, iter.HasNext()); - - iter = dex_->dexFindCatchHandler(*code_item, 11 /* Dex PC not in any try block */); - ASSERT_EQ(true, iter.HasNext()); + { + CatchHandlerIterator iter(*code_item, 4 /* Dex PC in the first try block */); + EXPECT_STREQ("Ljava/io/IOException;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex())); + ASSERT_TRUE(iter.HasNext()); + iter.Next(); + EXPECT_STREQ("Ljava/lang/Exception;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex())); + ASSERT_TRUE(iter.HasNext()); + iter.Next(); + EXPECT_FALSE(iter.HasNext()); + } + { + CatchHandlerIterator iter(*code_item, 8 /* Dex PC in the second try block */); + EXPECT_STREQ("Ljava/io/IOException;", dex_->StringByTypeIdx(iter.GetHandlerTypeIndex())); + ASSERT_TRUE(iter.HasNext()); + iter.Next(); + EXPECT_FALSE(iter.HasNext()); + } + { + CatchHandlerIterator iter(*code_item, 11 /* Dex PC not in any try block */); + EXPECT_FALSE(iter.HasNext()); + } } TEST_F(ExceptionTest, StackTraceElement) { diff --git a/src/image_test.cc b/src/image_test.cc index 3e64d95666..88ddae9da0 100644 --- a/src/image_test.cc +++ b/src/image_test.cc @@ -21,6 +21,14 @@ TEST_F(ImageTest, WriteRead) { bool success_oat = OatWriter::Create(tmp_oat.GetFile(), NULL, *compiler_.get()); ASSERT_TRUE(success_oat); + // Force all system classes into memory + for (size_t i = 0; i < java_lang_dex_file_->NumClassDefs(); i++) { + const DexFile::ClassDef& class_def = java_lang_dex_file_->GetClassDef(i); + const char* descriptor = java_lang_dex_file_->GetClassDescriptor(class_def); + Class* klass = class_linker_->FindSystemClass(descriptor); + EXPECT_TRUE(klass != NULL) << descriptor; + } + ImageWriter writer; ScratchFile tmp_image; const uintptr_t requested_image_base = 0x60000000; diff --git a/src/jni_compiler.cc b/src/jni_compiler.cc index 127b53d548..5a4056aee9 100644 --- a/src/jni_compiler.cc +++ b/src/jni_compiler.cc @@ -7,6 +7,7 @@ #include "assembler.h" #include "calling_convention.h" +#include "class_linker.h" #include "compiled_method.h" #include "constants.h" #include "jni_internal.h" @@ -55,7 +56,12 @@ JniCompiler::~JniCompiler() {} // registers, a reference to the method object is supplied as part of this // convention. // -CompiledMethod* JniCompiler::Compile(const Method* native_method) { +CompiledMethod* JniCompiler::Compile(bool is_direct, uint32_t method_idx, + const ClassLoader* class_loader, const DexFile& dex_file) { + ClassLinker* linker = Runtime::Current()->GetClassLinker(); + DexCache* dex_cache = linker->FindDexCache(dex_file); + Method* native_method = linker->ResolveMethod(dex_file, method_idx, dex_cache, + class_loader, is_direct); CHECK(native_method->IsNative()); // Calling conventions used to iterate over parameters to method @@ -435,7 +441,6 @@ CompiledMethod* JniCompiler::Compile(const Method* native_method) { 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 a6d56026ab..dbdfa68e3a 100644 --- a/src/jni_compiler.h +++ b/src/jni_compiler.h @@ -25,7 +25,8 @@ class JniCompiler { explicit JniCompiler(InstructionSet instruction_set); ~JniCompiler(); - CompiledMethod* Compile(const Method* method); + CompiledMethod* Compile(bool is_direct, uint32_t method_idx, const ClassLoader* class_loader, + const DexFile& dex_file); // Stub to perform native method symbol lookup via dlsym // TODO: remove from JniCompiler diff --git a/src/jni_internal.cc b/src/jni_internal.cc index 5787c652b1..9936f259f1 100644 --- a/src/jni_internal.cc +++ b/src/jni_internal.cc @@ -101,6 +101,42 @@ T AddLocalReference(JNIEnv* public_env, const Object* const_obj) { return reinterpret_cast<T>(ref); } +size_t NumArgArrayBytes(const char* shorty) { + size_t num_bytes = 0; + size_t end = strlen(shorty); + for (size_t i = 1; i < end; ++i) { + char ch = shorty[i]; + if (ch == 'D' || ch == 'J') { + num_bytes += 8; + } else if (ch == 'L') { + // Argument is a reference or an array. The shorty descriptor + // does not distinguish between these types. + num_bytes += sizeof(Object*); + } else { + num_bytes += 4; + } + } + return num_bytes; +} + +static size_t NumArgArrayBytes(const String* shorty) { + size_t num_bytes = 0; + size_t end = shorty->GetLength(); + for (size_t i = 1; i < end; ++i) { + char ch = shorty->CharAt(i); + if (ch == 'D' || ch == 'J') { + num_bytes += 8; + } else if (ch == 'L') { + // Argument is a reference or an array. The shorty descriptor + // does not distinguish between these types. + num_bytes += sizeof(Object*); + } else { + num_bytes += 4; + } + } + return num_bytes; +} + // For external use. template<typename T> T Decode(JNIEnv* public_env, jobject obj) { @@ -139,11 +175,11 @@ T Decode(ScopedJniThreadState& ts, jobject obj) { return reinterpret_cast<T>(ts.Self()->DecodeJObject(obj)); } -byte* CreateArgArray(JNIEnv* public_env, Method* method, va_list ap) { +static byte* CreateArgArray(JNIEnv* public_env, Method* method, va_list ap) { JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); - size_t num_bytes = method->NumArgArrayBytes(); - UniquePtr<byte[]> arg_array(new byte[num_bytes]); const String* shorty = method->GetShorty(); + size_t num_bytes = NumArgArrayBytes(shorty); + UniquePtr<byte[]> arg_array(new byte[num_bytes]); for (int i = 1, offset = 0; i < shorty->GetLength(); ++i) { switch (shorty->CharAt(i)) { case 'Z': @@ -177,9 +213,9 @@ byte* CreateArgArray(JNIEnv* public_env, Method* method, va_list ap) { return arg_array.release(); } -byte* CreateArgArray(JNIEnv* public_env, Method* method, jvalue* args) { +static byte* CreateArgArray(JNIEnv* public_env, Method* method, jvalue* args) { JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); - size_t num_bytes = method->NumArgArrayBytes(); + size_t num_bytes = NumArgArrayBytes(method->GetShorty()); UniquePtr<byte[]> arg_array(new byte[num_bytes]); const String* shorty = method->GetShorty(); for (int i = 1, offset = 0; i < shorty->GetLength(); ++i) { @@ -215,14 +251,14 @@ byte* CreateArgArray(JNIEnv* public_env, Method* method, jvalue* args) { return arg_array.release(); } -JValue InvokeWithArgArray(JNIEnv* public_env, Object* receiver, Method* method, byte* args) { +static JValue InvokeWithArgArray(JNIEnv* public_env, Object* receiver, Method* method, byte* args) { JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); JValue result; method->Invoke(env->self, receiver, args, &result); return result; } -JValue InvokeWithVarArgs(JNIEnv* public_env, jobject obj, jmethodID mid, va_list args) { +static JValue InvokeWithVarArgs(JNIEnv* public_env, jobject obj, jmethodID mid, va_list args) { JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); Object* receiver = Decode<Object*>(env, obj); Method* method = DecodeMethod(mid); @@ -230,11 +266,12 @@ JValue InvokeWithVarArgs(JNIEnv* public_env, jobject obj, jmethodID mid, va_list return InvokeWithArgArray(env, receiver, method, arg_array.get()); } -Method* FindVirtualMethod(Object* receiver, Method* method) { +static Method* FindVirtualMethod(Object* receiver, Method* method) { return receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(method); } -JValue InvokeVirtualOrInterfaceWithJValues(JNIEnv* public_env, jobject obj, jmethodID mid, jvalue* args) { +static JValue InvokeVirtualOrInterfaceWithJValues(JNIEnv* public_env, jobject obj, jmethodID mid, + jvalue* args) { JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); Object* receiver = Decode<Object*>(env, obj); Method* method = FindVirtualMethod(receiver, DecodeMethod(mid)); @@ -242,7 +279,8 @@ JValue InvokeVirtualOrInterfaceWithJValues(JNIEnv* public_env, jobject obj, jmet return InvokeWithArgArray(env, receiver, method, arg_array.get()); } -JValue InvokeVirtualOrInterfaceWithVarArgs(JNIEnv* public_env, jobject obj, jmethodID mid, va_list args) { +static JValue InvokeVirtualOrInterfaceWithVarArgs(JNIEnv* public_env, jobject obj, jmethodID mid, + va_list args) { JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env); Object* receiver = Decode<Object*>(env, obj); Method* method = FindVirtualMethod(receiver, DecodeMethod(mid)); @@ -255,7 +293,7 @@ JValue InvokeVirtualOrInterfaceWithVarArgs(JNIEnv* public_env, jobject obj, jmet // (i.e. "a/b/C" rather than "La/b/C;"). Arrays of reference types are an // exception; there the "L;" must be present ("[La/b/C;"). Historically we've // supported names with dots too (such as "a.b.C"). -std::string NormalizeJniClassDescriptor(const char* name) { +static std::string NormalizeJniClassDescriptor(const char* name) { std::string result; // Add the missing "L;" if necessary. if (name[0] == '[') { @@ -274,13 +312,13 @@ std::string NormalizeJniClassDescriptor(const char* name) { return result; } -void ThrowNoSuchMethodError(ScopedJniThreadState& ts, Class* c, const char* name, const char* sig, const char* kind) { +static void ThrowNoSuchMethodError(ScopedJniThreadState& ts, Class* c, const char* name, const char* sig, const char* kind) { std::string class_descriptor(c->GetDescriptor()->ToModifiedUtf8()); ts.Self()->ThrowNewExceptionF("Ljava/lang/NoSuchMethodError;", "no %s method \"%s.%s%s\"", kind, class_descriptor.c_str(), name, sig); } -jmethodID FindMethodID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) { +static jmethodID FindMethodID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) { Class* c = Decode<Class*>(ts, jni_class); if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) { return NULL; @@ -308,7 +346,7 @@ jmethodID FindMethodID(ScopedJniThreadState& ts, jclass jni_class, const char* n return EncodeMethod(method); } -const ClassLoader* GetClassLoader(Thread* self) { +static const ClassLoader* GetClassLoader(Thread* self) { Frame frame = self->GetTopOfStack(); Method* method = frame.GetMethod(); if (method == NULL || PrettyMethod(method, false) == "java.lang.Runtime.nativeLoad") { @@ -317,7 +355,7 @@ const ClassLoader* GetClassLoader(Thread* self) { return method->GetDeclaringClass()->GetClassLoader(); } -jfieldID FindFieldID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) { +static jfieldID FindFieldID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) { Class* c = Decode<Class*>(ts, jni_class); if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) { return NULL; @@ -359,13 +397,13 @@ jfieldID FindFieldID(ScopedJniThreadState& ts, jclass jni_class, const char* nam return EncodeField(field); } -void PinPrimitiveArray(ScopedJniThreadState& ts, const Array* array) { +static void PinPrimitiveArray(ScopedJniThreadState& ts, const Array* array) { JavaVMExt* vm = ts.Vm(); MutexLock mu(vm->pins_lock); vm->pin_table.Add(array); } -void UnpinPrimitiveArray(ScopedJniThreadState& ts, const Array* array) { +static void UnpinPrimitiveArray(ScopedJniThreadState& ts, const Array* array) { JavaVMExt* vm = ts.Vm(); MutexLock mu(vm->pins_lock); vm->pin_table.Remove(array); @@ -396,13 +434,14 @@ void ReleasePrimitiveArray(ScopedJniThreadState& ts, ArrayT java_array, jint mod } } -void ThrowAIOOBE(ScopedJniThreadState& ts, Array* array, jsize start, jsize length, const char* identifier) { +static void ThrowAIOOBE(ScopedJniThreadState& ts, Array* array, jsize start, jsize length, const char* identifier) { std::string type(PrettyTypeOf(array)); ts.Self()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;", "%s offset=%d length=%d %s.length=%d", type.c_str(), start, length, identifier, array->GetLength()); } -void ThrowSIOOBE(ScopedJniThreadState& ts, jsize start, jsize length, jsize array_length) { + +static void ThrowSIOOBE(ScopedJniThreadState& ts, jsize start, jsize length, jsize array_length) { ts.Self()->ThrowNewExceptionF("Ljava/lang/StringIndexOutOfBoundsException;", "offset=%d length=%d string.length()=%d", start, length, array_length); } @@ -429,18 +468,18 @@ void SetPrimitiveArrayRegion(ScopedJniThreadState& ts, JavaArrayT java_array, js } } -jclass InitDirectByteBufferClass(JNIEnv* env) { +static jclass InitDirectByteBufferClass(JNIEnv* env) { ScopedLocalRef<jclass> buffer_class(env, env->FindClass("java/nio/ReadWriteDirectByteBuffer")); CHECK(buffer_class.get() != NULL); return reinterpret_cast<jclass>(env->NewGlobalRef(buffer_class.get())); } -jclass GetDirectByteBufferClass(JNIEnv* env) { +static jclass GetDirectByteBufferClass(JNIEnv* env) { static jclass buffer_class = InitDirectByteBufferClass(env); return buffer_class; } -jint JII_AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool as_daemon) { +static jint JII_AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool as_daemon) { if (vm == NULL || p_env == NULL) { return JNI_ERR; } diff --git a/src/jni_internal.h b/src/jni_internal.h index 25e9e62ce7..6950dae847 100644 --- a/src/jni_internal.h +++ b/src/jni_internal.h @@ -60,6 +60,7 @@ inline jmethodID EncodeMethod(Method* method) { return reinterpret_cast<jmethodID>(method); } +size_t NumArgArrayBytes(const char* shorty); JValue InvokeWithJValues(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args); struct JavaVMExt : public JavaVM { diff --git a/src/jni_internal_arm.cc b/src/jni_internal_arm.cc index f1ed092d1b..dadf7b4220 100644 --- a/src/jni_internal_arm.cc +++ b/src/jni_internal_arm.cc @@ -29,14 +29,15 @@ namespace arm { // 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. -CompiledInvokeStub* ArmCreateInvokeStub(const Method* method) { +CompiledInvokeStub* ArmCreateInvokeStub(bool is_static, const char* shorty) { UniquePtr<ArmAssembler> assembler( down_cast<ArmAssembler*>(Assembler::Create(kArm))); #define __ assembler-> + size_t num_arg_array_bytes = NumArgArrayBytes(shorty); // Size of frame - spill of R4,R9/LR + Method* + possible receiver + arg array size_t unpadded_frame_size = (4 * kPointerSize) + - (method->IsStatic() ? 0 : kPointerSize) + - method->NumArgArrayBytes(); + (is_static ? 0 : kPointerSize) + + num_arg_array_bytes; size_t frame_size = RoundUp(unpadded_frame_size, kStackAlignment); // Spill R4,R9 and LR @@ -53,14 +54,14 @@ CompiledInvokeStub* ArmCreateInvokeStub(const Method* method) { __ AddConstant(SP, -frame_size + (3 * kPointerSize)); // Can either get 3 or 2 arguments into registers - size_t reg_bytes = (method->IsStatic() ? 3 : 2) * kPointerSize; + size_t reg_bytes = (is_static ? 3 : 2) * kPointerSize; // Bytes passed by stack size_t stack_bytes; - if (method->NumArgArrayBytes() > reg_bytes) { - stack_bytes = method->NumArgArrayBytes() - reg_bytes; + if (num_arg_array_bytes > reg_bytes) { + stack_bytes = num_arg_array_bytes - reg_bytes; } else { stack_bytes = 0; - reg_bytes = method->NumArgArrayBytes(); + reg_bytes = num_arg_array_bytes; } // Method* at bottom of frame is null thereby terminating managed stack crawls @@ -75,12 +76,12 @@ CompiledInvokeStub* ArmCreateInvokeStub(const Method* method) { // we're displaced off of the arguments by the spill space for the incoming // arguments, the Method* and possibly the receiver - int sp_offset = reg_bytes + (method->IsStatic() ? 1 : 2) * kPointerSize + off; + int sp_offset = reg_bytes + (is_static ? 1 : 2) * kPointerSize + off; __ StoreToOffset(kStoreWord, IP, SP, sp_offset); } // Move all the register arguments into place. - if (method->IsStatic()) { + if (is_static) { if (reg_bytes > 0) { __ LoadFromOffset(kLoadWord, R1, R3, 0); if (reg_bytes > 4) { @@ -100,16 +101,17 @@ CompiledInvokeStub* ArmCreateInvokeStub(const Method* method) { } // Load the code pointer we are about to call. - __ LoadFromOffset(kLoadWord, IP, R0, method->GetCodeOffset().Int32Value()); + __ LoadFromOffset(kLoadWord, IP, R0, Method::GetCodeOffset().Int32Value()); // Do the call. __ blx(IP); // If the method returns a value, store it to the result pointer. - if (!method->IsReturnVoid()) { + if (shorty[0] != 'V') { // Load the result JValue pointer of the stub caller's out args. __ LoadFromOffset(kLoadWord, IP, SP, frame_size); - __ StoreToOffset(method->IsReturnALongOrDouble() ? kStoreWordPair : kStoreWord, R0, IP, 0); + StoreOperandType type = (shorty[0] == 'J' || shorty[0] == 'D') ? kStoreWordPair : kStoreWord; + __ StoreToOffset(type, R0, IP, 0); } // Remove the frame less the spilled R4, R9 and LR diff --git a/src/jni_internal_x86.cc b/src/jni_internal_x86.cc index 891971d22f..7d931bab8c 100644 --- a/src/jni_internal_x86.cc +++ b/src/jni_internal_x86.cc @@ -25,14 +25,15 @@ namespace x86 { // "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. -CompiledInvokeStub* X86CreateInvokeStub(const Method* method) { +CompiledInvokeStub* X86CreateInvokeStub(bool is_static, const char* shorty) { UniquePtr<X86Assembler> assembler( down_cast<X86Assembler*>(Assembler::Create(kX86))); #define __ assembler-> + size_t num_arg_array_bytes = NumArgArrayBytes(shorty); // Size of frame - return address + Method* + possible receiver + arg array size_t frame_size = (2 * kPointerSize) + - (method->IsStatic() ? 0 : kPointerSize) + - method->NumArgArrayBytes(); + (is_static ? 0 : kPointerSize) + + num_arg_array_bytes; size_t pad_size = RoundUp(frame_size, kStackAlignment) - frame_size; __ movl(EAX, Address(ESP, 4)); // EAX = method @@ -45,20 +46,20 @@ CompiledInvokeStub* X86CreateInvokeStub(const Method* method) { } // Push/copy arguments - for (size_t off = method->NumArgArrayBytes(); off > 0; off -= kPointerSize) { + for (size_t off = num_arg_array_bytes; off > 0; off -= kPointerSize) { __ pushl(Address(EDX, off - kPointerSize)); } - if (!method->IsStatic()) { + if (!is_static) { __ pushl(ECX); } // Push 0 as NULL Method* thereby terminating managed stack crawls __ pushl(Immediate(0)); - __ call(Address(EAX, method->GetCodeOffset())); // Call code off of method + __ call(Address(EAX, Method::GetCodeOffset())); // Call code off of method // pop arguments up to the return address __ addl(ESP, Immediate(frame_size + pad_size - kPointerSize)); - char ch = method->GetShorty()->CharAt(0); + char ch = shorty[0]; if (ch != 'V') { // Load the result JValue pointer. __ movl(ECX, Address(ESP, 20)); diff --git a/src/monitor.cc b/src/monitor.cc index b9a94590f3..3f041e4e83 100644 --- a/src/monitor.cc +++ b/src/monitor.cc @@ -831,7 +831,7 @@ void Monitor::TranslateLocation(const Method* method, uint32_t pc, const DexFile& dex_file = class_linker->FindDexFile(dex_cache); const DexFile::ClassDef* class_def = dex_file.FindClassDef(c->GetDescriptor()->ToModifiedUtf8()); - source_file = dex_file.dexGetSourceFile(*class_def); + source_file = dex_file.GetSourceFile(*class_def); line_number = dex_file.GetLineNumFromPC(method, method->ToDexPC(pc)); } diff --git a/src/oat.cc b/src/oat.cc index 1a615fe83e..0089410ee4 100644 --- a/src/oat.cc +++ b/src/oat.cc @@ -68,7 +68,6 @@ void OatHeader::SetExecutableOffset(uint32_t 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), @@ -77,7 +76,6 @@ OatMethodOffsets::OatMethodOffsets() 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, @@ -85,7 +83,6 @@ OatMethodOffsets::OatMethodOffsets(uint32_t code_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), @@ -41,7 +41,6 @@ class PACKED OatMethodOffsets { 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, @@ -51,7 +50,6 @@ class PACKED 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_; diff --git a/src/oat_file.cc b/src/oat_file.cc index 8af22b03c6..383bc2a6e2 100644 --- a/src/oat_file.cc +++ b/src/oat_file.cc @@ -175,7 +175,6 @@ const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t 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_), @@ -185,7 +184,6 @@ const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) 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, @@ -193,7 +191,6 @@ OatFile::OatMethod::OatMethod(const void* code, 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), diff --git a/src/oat_file.h b/src/oat_file.h index 1ee8c919c4..2c39e9d8b5 100644 --- a/src/oat_file.h +++ b/src/oat_file.h @@ -40,7 +40,6 @@ class OatFile { // 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, @@ -54,7 +53,6 @@ class OatFile { 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_; diff --git a/src/oat_test.cc b/src/oat_test.cc index e90d2ede98..e3186de2ee 100644 --- a/src/oat_test.cc +++ b/src/oat_test.cc @@ -37,8 +37,11 @@ TEST_F(OatTest, WriteRead) { for (size_t i = 0; i < dex_file.NumClassDefs(); i++) { const DexFile::ClassDef& class_def = dex_file.GetClassDef(i); 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_; + size_t num_virtual_methods =0; + if (class_data != NULL) { + ClassDataItemIterator it(dex_file, class_data); + num_virtual_methods = it.NumVirtualMethods(); + } const char* descriptor = dex_file.GetClassDescriptor(class_def); UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(i)); @@ -49,12 +52,13 @@ TEST_F(OatTest, WriteRead) { for (size_t i = 0; i < klass->NumDirectMethods(); i++, method_index++) { Method* method = klass->GetDirectMethod(i); const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index); - const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method); + const CompiledMethod* compiled_method = + compiler_->GetCompiledMethod(Compiler::MethodReference(&dex_file, + method->GetDexMethodIndex())); 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 { @@ -68,7 +72,6 @@ TEST_F(OatTest, WriteRead) { << 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()); } @@ -76,12 +79,13 @@ TEST_F(OatTest, WriteRead) { for (size_t i = 0; i < num_virtual_methods; i++, method_index++) { Method* method = klass->GetVirtualMethod(i); const OatFile::OatMethod oat_method = oat_class->GetOatMethod(method_index); - const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method); + const CompiledMethod* compiled_method = + compiler_->GetCompiledMethod(Compiler::MethodReference(&dex_file, + method->GetDexMethodIndex())); 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 { @@ -96,7 +100,6 @@ TEST_F(OatTest, WriteRead) { << 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 664dcfe09c..f3e78e6250 100644 --- a/src/oat_writer.cc +++ b/src/oat_writer.cc @@ -24,6 +24,8 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, compiler_ = &compiler; class_loader_ = class_loader; dex_files_ = &dex_files; + oat_header_ = NULL; + executable_offset_padding_length_ = 0; size_t offset = InitOatHeader(); offset = InitOatDexFiles(offset); @@ -36,6 +38,13 @@ OatWriter::OatWriter(const std::vector<const DexFile*>& dex_files, CHECK_EQ(dex_files_->size(), oat_classes_.size()); } +OatWriter::~OatWriter() { + delete oat_header_; + STLDeleteElements(&oat_dex_files_); + STLDeleteElements(&oat_classes_); + STLDeleteElements(&oat_methods_); +} + size_t OatWriter::InitOatHeader() { // create the OatHeader oat_header_ = new OatHeader(dex_files_); @@ -83,10 +92,13 @@ size_t OatWriter::InitOatMethods(size_t offset) { oat_classes_[i]->methods_offsets_[class_def_index] = offset; const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); const byte* class_data = dex_file->GetClassData(class_def); - DexFile::ClassDataHeader header = dex_file->ReadClassDataHeader(&class_data); - size_t num_direct_methods = header.direct_methods_size_; - size_t num_virtual_methods = header.virtual_methods_size_; - uint32_t num_methods = num_direct_methods + num_virtual_methods; + uint32_t num_methods = 0; + if (class_data != NULL) { // ie not an empty class, such as a marker interface + ClassDataItemIterator it(*dex_file, class_data); + size_t num_direct_methods = it.NumDirectMethods(); + size_t num_virtual_methods = it.NumVirtualMethods(); + num_methods = num_direct_methods + num_virtual_methods; + } OatMethods* oat_methods = new OatMethods(num_methods); oat_methods_.push_back(oat_methods); offset += oat_methods->SizeOf(); @@ -135,46 +147,46 @@ size_t OatWriter::InitOatCodeClassDef(size_t offset, const DexFile& dex_file, const DexFile::ClassDef& class_def) { 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); - - // TODO: remove code ByteArrays from Class/Method (and therefore ClassLoader) - // TODO: don't write code for shared stubs - Class* klass = Runtime::Current()->GetClassLinker()->FindClass(descriptor, class_loader_); - if (klass == NULL) { - LOG(WARNING) << "Didn't find class '" << descriptor << "' in dex file " << dex_file.GetLocation(); - Thread* thread = Thread::Current(); - DCHECK(thread->IsExceptionPending()); - thread->ClearException(); + if (class_data == NULL) { + // empty class, such as a marker interface return offset; } - CHECK_EQ(klass->GetClassLoader(), class_loader_); + ClassDataItemIterator it(dex_file, class_data); CHECK_EQ(oat_methods_[oat_class_index]->method_offsets_.size(), - klass->NumDirectMethods() + num_virtual_methods); - 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); - CHECK(method != NULL) << descriptor << " direct " << i; - offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, method); + it.NumDirectMethods() + it.NumVirtualMethods()); + // Skip fields + while (it.HasNextStaticField()) { + it.Next(); } - // note that num_virtual_methods != klass->NumVirtualMethods() because of miranda methods - for (size_t i = 0; i < num_virtual_methods; i++, class_def_method_index++) { - Method* method = klass->GetVirtualMethod(i); - CHECK(method != NULL) << descriptor << " virtual " << i; - offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, method); + while (it.HasNextInstanceField()) { + it.Next(); } + // Process methods + size_t class_def_method_index = 0; + while (it.HasNextDirectMethod()) { + bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0; + offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, is_static, true, + it.GetMemberIndex(), &dex_file); + class_def_method_index++; + it.Next(); + } + while (it.HasNextVirtualMethod()) { + CHECK_EQ(it.GetMemberAccessFlags() & kAccStatic, 0U); + offset = InitOatCodeMethod(offset, oat_class_index, class_def_method_index, false, false, + it.GetMemberIndex(), &dex_file); + class_def_method_index++; + it.Next(); + } + DCHECK(!it.HasNext()); return offset; } -size_t OatWriter::InitOatCodeMethod(size_t offset, - size_t oat_class_index, - size_t class_def_method_index, - Method* method) { +size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, + size_t class_def_method_index, bool is_static, bool is_direct, + uint32_t method_idx, const DexFile* dex_file) { // 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; @@ -182,7 +194,8 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, // derived from CompiledInvokeStub if available uint32_t invoke_stub_offset = 0; - const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method); + CompiledMethod* compiled_method = + compiler_->GetCompiledMethod(art::Compiler::MethodReference(dex_file, method_idx)); if (compiled_method != NULL) { offset = compiled_method->AlignCode(offset); DCHECK_ALIGNED(offset, kArmAlignment); @@ -202,7 +215,6 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, } 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(); } @@ -210,9 +222,6 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, 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)); @@ -249,7 +258,8 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, } } - const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method); + const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx)); + const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty); if (compiled_invoke_stub != NULL) { offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet()); DCHECK_ALIGNED(offset, kArmAlignment); @@ -271,22 +281,26 @@ size_t OatWriter::InitOatCodeMethod(size_t offset, 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->SetCoreSpillMask(core_spill_mask); - method->SetFpSpillMask(fp_spill_mask); - method->SetOatMappingTableOffset(mapping_table_offset); - method->SetOatVmapTableOffset(vmap_table_offset); - method->SetOatInvokeStubOffset(invoke_stub_offset); - + if (compiler_->IsImage()) { + ClassLinker* linker = Runtime::Current()->GetClassLinker(); + DexCache* dex_cache = linker->FindDexCache(*dex_file); + Method* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader_, + is_direct); + CHECK(method != NULL); + method->SetFrameSizeInBytes(frame_size_in_bytes); + method->SetCoreSpillMask(core_spill_mask); + method->SetFpSpillMask(fp_spill_mask); + method->SetOatMappingTableOffset(mapping_table_offset); + method->SetOatCodeOffset(code_offset); + method->SetOatVmapTableOffset(vmap_table_offset); + method->SetOatInvokeStubOffset(invoke_stub_offset); + } return offset; } @@ -354,10 +368,11 @@ size_t OatWriter::WriteCode(File* file) { } size_t OatWriter::WriteCodeDexFiles(File* file, size_t code_offset) { + size_t oat_class_index = 0; for (size_t i = 0; i != oat_classes_.size(); ++i) { const DexFile* dex_file = (*dex_files_)[i]; CHECK(dex_file != NULL); - code_offset = WriteCodeDexFile(file, code_offset, *dex_file); + code_offset = WriteCodeDexFile(file, code_offset, oat_class_index, *dex_file); if (code_offset == 0) { return 0; } @@ -365,10 +380,12 @@ size_t OatWriter::WriteCodeDexFiles(File* file, size_t code_offset) { return code_offset; } -size_t OatWriter::WriteCodeDexFile(File* file, size_t code_offset, const DexFile& dex_file) { - for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); class_def_index++) { +size_t OatWriter::WriteCodeDexFile(File* file, size_t code_offset, size_t& oat_class_index, + const DexFile& dex_file) { + for (size_t class_def_index = 0; class_def_index < dex_file.NumClassDefs(); + class_def_index++, oat_class_index++) { const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); - code_offset = WriteCodeClassDef(file, code_offset, dex_file, class_def); + code_offset = WriteCodeClassDef(file, code_offset, oat_class_index, dex_file, class_def); if (code_offset == 0) { return 0; } @@ -376,54 +393,68 @@ size_t OatWriter::WriteCodeDexFile(File* file, size_t code_offset, const DexFile return code_offset; } -void OatWriter::ReportWriteFailure(const char* what, Method* m, File* f) { - PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(m) << " to " << f->name(); +void OatWriter::ReportWriteFailure(const char* what, uint32_t method_idx, + const DexFile& dex_file, File* f) const { + PLOG(ERROR) << "Failed to write " << what << " for " << PrettyMethod(method_idx, dex_file) + << " to " << f->name(); } size_t OatWriter::WriteCodeClassDef(File* file, - size_t code_offset, + size_t code_offset, size_t oat_class_index, const DexFile& dex_file, const DexFile::ClassDef& class_def) { 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_); - if (klass == NULL) { - LOG(WARNING) << "Didn't find class '" << descriptor << "' in dex file " << dex_file.GetLocation(); - Thread* thread = Thread::Current(); - DCHECK(thread->IsExceptionPending()); - thread->ClearException(); + if (class_data == NULL) { + // ie. an empty class such as a marker interface return code_offset; } - - // Note that we clear the code array here, image_writer will use GetCodeOffset to find it - for (size_t i = 0; i < klass->NumDirectMethods(); i++) { - Method* method = klass->GetDirectMethod(i); - code_offset = WriteCodeMethod(file, code_offset, method); + ClassDataItemIterator it(dex_file, class_data); + // Skip fields + while (it.HasNextStaticField()) { + it.Next(); + } + while (it.HasNextInstanceField()) { + it.Next(); + } + // Process methods + size_t class_def_method_index = 0; + while (it.HasNextDirectMethod()) { + bool is_static = (it.GetMemberAccessFlags() & kAccStatic) != 0; + code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index, + is_static, it.GetMemberIndex(), dex_file); if (code_offset == 0) { return 0; } + class_def_method_index++; + it.Next(); } - // note that num_virtual_methods != klass->NumVirtualMethods() because of miranda methods - for (size_t i = 0; i < num_virtual_methods; i++) { - Method* method = klass->GetVirtualMethod(i); - code_offset = WriteCodeMethod(file, code_offset, method); + while (it.HasNextVirtualMethod()) { + code_offset = WriteCodeMethod(file, code_offset, oat_class_index, class_def_method_index, + false, it.GetMemberIndex(), dex_file); if (code_offset == 0) { return 0; } - } - for (size_t i = num_virtual_methods; i < klass->NumVirtualMethods(); i++) { - Method* method = klass->GetVirtualMethod(i); - CHECK(compiler_->GetCompiledMethod(method) == NULL) << PrettyMethod(method); + class_def_method_index++; + it.Next(); } return code_offset; } -size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, Method* method) { - const CompiledMethod* compiled_method = compiler_->GetCompiledMethod(method); - if (compiled_method != NULL) { +size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, size_t oat_class_index, + size_t class_def_method_index, bool is_static, + uint32_t method_idx, const DexFile& dex_file) { + const CompiledMethod* compiled_method = + compiler_->GetCompiledMethod(art::Compiler::MethodReference(&dex_file, method_idx)); + + uint32_t frame_size_in_bytes = 0; + uint32_t core_spill_mask = 0; + uint32_t fp_spill_mask = 0; + + OatMethodOffsets method_offsets = + oat_methods_[oat_class_index]->method_offsets_[class_def_method_index]; + + + if (compiled_method != NULL) { // ie. not an abstract method 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) { @@ -443,42 +474,38 @@ size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, Method* method // Deduplicate code arrays size_t offset = code_offset + compiled_method->CodeDelta(); std::map<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code); - if (code_iter != code_offsets_.end() && offset != method->GetOatCodeOffset()) { - DCHECK((code_size == 0 && method->GetOatCodeOffset() == 0) - || code_iter->second == method->GetOatCodeOffset()) << PrettyMethod(method); + if (code_iter != code_offsets_.end() && offset != method_offsets.code_offset_) { + DCHECK((code_size == 0 && method_offsets.code_offset_ == 0) + || code_iter->second == method_offsets.code_offset_) + << PrettyMethod(method_idx, dex_file); } else { - DCHECK((code_size == 0 && method->GetOatCodeOffset() == 0) - || offset == method->GetOatCodeOffset()) << PrettyMethod(method); + DCHECK((code_size == 0 && method_offsets.code_offset_ == 0) + || offset == method_offsets.code_offset_) + << PrettyMethod(method_idx, dex_file); if (!file->WriteFully(&code[0], code_size)) { - ReportWriteFailure("method code", method, file); + ReportWriteFailure("method code", method_idx, dex_file, file); return false; } code_offset += code_size; } DCHECK_CODE_OFFSET(); + frame_size_in_bytes = compiled_method->GetFrameSizeInBytes(); + core_spill_mask = compiled_method->GetCoreSpillMask(); + fp_spill_mask = compiled_method->GetFpSpillMask(); } - 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))) { - ReportWriteFailure("method frame size", method, file); + ReportWriteFailure("method frame size", method_idx, dex_file, file); return false; } code_offset += sizeof(frame_size_in_bytes); - if (!file->WriteFully(&return_pc_offset_in_bytes, sizeof(return_pc_offset_in_bytes))) { - ReportWriteFailure("method return pc", method, file); - return false; - } - code_offset += sizeof(return_pc_offset_in_bytes); if (!file->WriteFully(&core_spill_mask, sizeof(core_spill_mask))) { - ReportWriteFailure("method core spill mask", method, file); + ReportWriteFailure("method core spill mask", method_idx, dex_file, file); return false; } code_offset += sizeof(core_spill_mask); if (!file->WriteFully(&fp_spill_mask, sizeof(fp_spill_mask))) { - ReportWriteFailure("method fp spill mask", method, file); + ReportWriteFailure("method fp spill mask", method_idx, dex_file, file); return false; } code_offset += sizeof(fp_spill_mask); @@ -488,15 +515,19 @@ size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, Method* method size_t mapping_table_size = mapping_table.size() * sizeof(mapping_table[0]); // Deduplicate mapping tables - std::map<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = mapping_table_offsets_.find(&mapping_table); - if (mapping_iter != mapping_table_offsets_.end() && code_offset != method->GetOatMappingTableOffset()) { - DCHECK((mapping_table_size == 0 && method->GetOatMappingTableOffset() == 0) - || mapping_iter->second == method->GetOatMappingTableOffset()) << PrettyMethod(method); + std::map<const std::vector<uint32_t>*, uint32_t>::iterator mapping_iter = + mapping_table_offsets_.find(&mapping_table); + if (mapping_iter != mapping_table_offsets_.end() && + code_offset != method_offsets.mapping_table_offset_) { + DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0) + || mapping_iter->second == method_offsets.mapping_table_offset_) + << PrettyMethod(method_idx, dex_file); } else { - DCHECK((mapping_table_size == 0 && method->GetOatMappingTableOffset() == 0) - || code_offset == method->GetOatMappingTableOffset()) << PrettyMethod(method); + DCHECK((mapping_table_size == 0 && method_offsets.mapping_table_offset_ == 0) + || code_offset == method_offsets.mapping_table_offset_) + << PrettyMethod(method_idx, dex_file); if (!file->WriteFully(&mapping_table[0], mapping_table_size)) { - ReportWriteFailure("mapping table", method, file); + ReportWriteFailure("mapping table", method_idx, dex_file, file); return false; } code_offset += mapping_table_size; @@ -507,23 +538,27 @@ size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, Method* method size_t vmap_table_size = vmap_table.size() * sizeof(vmap_table[0]); // Deduplicate vmap tables - std::map<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = vmap_table_offsets_.find(&vmap_table); - if (vmap_iter != vmap_table_offsets_.end() && code_offset != method->GetOatVmapTableOffset()) { - DCHECK((vmap_table_size == 0 && method->GetOatVmapTableOffset() == 0) - || vmap_iter->second == method->GetOatVmapTableOffset()) << PrettyMethod(method); + std::map<const std::vector<uint16_t>*, uint32_t>::iterator vmap_iter = + vmap_table_offsets_.find(&vmap_table); + if (vmap_iter != vmap_table_offsets_.end() && + code_offset != method_offsets.vmap_table_offset_) { + DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0) + || vmap_iter->second == method_offsets.vmap_table_offset_) + << PrettyMethod(method_idx, dex_file); } else { - DCHECK((vmap_table_size == 0 && method->GetOatVmapTableOffset() == 0) - || code_offset == method->GetOatVmapTableOffset()) << PrettyMethod(method); + DCHECK((vmap_table_size == 0 && method_offsets.vmap_table_offset_ == 0) + || code_offset == method_offsets.vmap_table_offset_) + << PrettyMethod(method_idx, dex_file); if (!file->WriteFully(&vmap_table[0], vmap_table_size)) { - ReportWriteFailure("vmap table", method, file); + ReportWriteFailure("vmap table", method_idx, dex_file, file); return false; } code_offset += vmap_table_size; } DCHECK_CODE_OFFSET(); } - - const CompiledInvokeStub* compiled_invoke_stub = compiler_->GetCompiledInvokeStub(method); + const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); + const CompiledInvokeStub* compiled_invoke_stub = compiler_->FindInvokeStub(is_static, shorty); if (compiled_invoke_stub != NULL) { uint32_t aligned_code_offset = CompiledMethod::AlignCode(code_offset, compiler_->GetInstructionSet()); @@ -543,37 +578,34 @@ size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, Method* method size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]); // Deduplicate invoke stubs - std::map<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = code_offsets_.find(&invoke_stub); - if (stub_iter != code_offsets_.end() && code_offset != method->GetOatInvokeStubOffset()) { - DCHECK((invoke_stub_size == 0 && method->GetOatInvokeStubOffset() == 0) - || stub_iter->second == method->GetOatInvokeStubOffset()) << PrettyMethod(method); + std::map<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = + code_offsets_.find(&invoke_stub); + if (stub_iter != code_offsets_.end() && + code_offset != method_offsets.invoke_stub_offset_) { + DCHECK((invoke_stub_size == 0 && method_offsets.invoke_stub_offset_ == 0) + || stub_iter->second == method_offsets.invoke_stub_offset_) + << PrettyMethod(method_idx, dex_file); } else { - DCHECK((invoke_stub_size == 0 && method->GetOatInvokeStubOffset() == 0) - || code_offset == method->GetOatInvokeStubOffset()) << PrettyMethod(method); + DCHECK((invoke_stub_size == 0 && method_offsets.invoke_stub_offset_ == 0) + || code_offset == method_offsets.invoke_stub_offset_) + << PrettyMethod(method_idx, dex_file); if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) { - ReportWriteFailure("invoke stub code", method, file); + ReportWriteFailure("invoke stub code", method_idx, dex_file, file); return false; } code_offset += invoke_stub_size; } DCHECK_CODE_OFFSET(); } - return code_offset; } -OatWriter::~OatWriter() { - delete oat_header_; - STLDeleteElements(&oat_dex_files_); - STLDeleteElements(&oat_classes_); - STLDeleteElements(&oat_methods_); -} - OatWriter::OatDexFile::OatDexFile(const DexFile& dex_file) { const std::string& location = dex_file.GetLocation(); dex_file_location_size_ = location.size(); dex_file_location_data_ = reinterpret_cast<const uint8_t*>(location.data()); dex_file_checksum_ = dex_file.GetHeader().checksum_; + classes_offset_ = 0; } size_t OatWriter::OatDexFile::SizeOf() const { diff --git a/src/oat_writer.h b/src/oat_writer.h index 0642fa4d5c..97cdb50ec0 100644 --- a/src/oat_writer.h +++ b/src/oat_writer.h @@ -71,28 +71,23 @@ class OatWriter { size_t oat_class_index, const DexFile& dex_file, const DexFile::ClassDef& class_def); - size_t InitOatCodeMethod(size_t offset, - size_t oat_class_index, - size_t class_def_method_index, - Method* method); + size_t InitOatCodeMethod(size_t offset, size_t oat_class_index, size_t class_def_method_index, + bool is_static, bool is_direct, uint32_t method_idx, const DexFile*); bool Write(File* file); bool WriteTables(File* file); size_t WriteCode(File* file); - size_t WriteCodeDexFiles(File* file, - size_t offset); - size_t WriteCodeDexFile(File* file, - size_t offset, + size_t WriteCodeDexFiles(File* file, size_t offset); + size_t WriteCodeDexFile(File* file, size_t offset, size_t& oat_class_index, const DexFile& dex_file); - size_t WriteCodeClassDef(File* file, - size_t offset, - const DexFile& dex_file, - const DexFile::ClassDef& class_def); - size_t WriteCodeMethod(File* file, - size_t offset, - Method* method); - - void ReportWriteFailure(const char* what, Method* m, File* f); + size_t WriteCodeClassDef(File* file, size_t offset, size_t oat_class_index, + const DexFile& dex_file, const DexFile::ClassDef& class_def); + size_t WriteCodeMethod(File* file, size_t offset, size_t oat_class_index, + size_t class_def_method_index, bool is_static, uint32_t method_idx, + const DexFile& dex_file); + + void ReportWriteFailure(const char* what, uint32_t method_idx, const DexFile& dex_file, + File* f) const; class OatDexFile { public: diff --git a/src/oatdump.cc b/src/oatdump.cc index 61f352e41c..8b0ada4fa1 100644 --- a/src/oatdump.cc +++ b/src/oatdump.cc @@ -136,47 +136,33 @@ class OatDump { const DexFile& dex_file, const DexFile::ClassDef& class_def) { const byte* class_data = dex_file.GetClassData(class_def); - DexFile::ClassDataHeader header = dex_file.ReadClassDataHeader(&class_data); - size_t num_static_fields = header.static_fields_size_; - size_t num_instance_fields = header.instance_fields_size_; - size_t num_direct_methods = header.direct_methods_size_; - size_t num_virtual_methods = header.virtual_methods_size_; - uint32_t method_index = 0; + if (class_data == NULL) { // empty class such as a marker interface? + return; + } + ClassDataItemIterator it(dex_file, class_data); // just skipping through the fields to advance class_data - if (num_static_fields != 0) { - uint32_t last_idx = 0; - for (size_t i = 0; i < num_static_fields; ++i) { - DexFile::Field dex_field; - dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx); - } + while (it.HasNextStaticField()) { + it.Next(); } - if (num_instance_fields != 0) { - uint32_t last_idx = 0; - for (size_t i = 0; i < num_instance_fields; ++i) { - DexFile::Field dex_field; - dex_file.dexReadClassDataField(&class_data, &dex_field, &last_idx); - } + while (it.HasNextInstanceField()) { + it.Next(); } - if (num_direct_methods != 0) { - uint32_t last_idx = 0; - for (size_t i = 0; i < num_direct_methods; ++i, method_index++) { - DexFile::Method dex_method; - dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx); - const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index); - DumpOatMethod(os, method_index, oat_file, oat_method, dex_file, dex_method); - } + uint32_t method_index = 0; + while (it.HasNextDirectMethod()) { + const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index); + DumpOatMethod(os, method_index, oat_file, oat_method, dex_file, it.GetMemberIndex()); + method_index++; + it.Next(); } - if (num_virtual_methods != 0) { - uint32_t last_idx = 0; - for (size_t i = 0; i < num_virtual_methods; ++i, method_index++) { - DexFile::Method dex_method; - dex_file.dexReadClassDataMethod(&class_data, &dex_method, &last_idx); - const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index); - DumpOatMethod(os, method_index, oat_file, oat_method, dex_file, dex_method); - } + while (it.HasNextVirtualMethod()) { + const OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index); + DumpOatMethod(os, method_index, oat_file, oat_method, dex_file, it.GetMemberIndex()); + method_index++; + it.Next(); } + DCHECK(!it.HasNext()); os << std::flush; } static void DumpOatMethod(std::ostream& os, @@ -184,19 +170,17 @@ class OatDump { const OatFile& oat_file, const OatFile::OatMethod& oat_method, const DexFile& dex_file, - const DexFile::Method& dex_method) { - const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method.method_idx_); + uint32_t method_idx) { + const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); const char* name = dex_file.GetMethodName(method_id); std::string signature = dex_file.GetMethodSignature(method_id); os << StringPrintf("\t%d: %s %s (method_idx=%d)\n", - method_index, name, signature.c_str(), dex_method.method_idx_); + method_index, name, signature.c_str(), method_idx); os << StringPrintf("\t\tcode: %p (offset=%08x)\n", oat_method.code_, reinterpret_cast<const byte*>(oat_method.code_) - oat_file.GetBase()); os << StringPrintf("\t\tframe_size_in_bytes: %d\n", oat_method.frame_size_in_bytes_); - os << StringPrintf("\t\treturn_pc_offset_in_bytes: %d\n", - oat_method.return_pc_offset_in_bytes_); os << StringPrintf("\t\tcore_spill_mask: %08x\n", oat_method.core_spill_mask_); os << StringPrintf("\t\tfp_spill_mask: %08x\n", diff --git a/src/object.cc b/src/object.cc index 9cc0e3add6..3954b3df2c 100644 --- a/src/object.cc +++ b/src/object.cc @@ -20,6 +20,7 @@ #include "monitor.h" #include "runtime.h" #include "stack.h" +#include "utils.h" namespace art { @@ -122,7 +123,7 @@ size_t Field::PrimitiveSize() const { const char* Field::GetTypeDescriptor() const { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); const DexFile& dex_file = class_linker->FindDexFile(GetDeclaringClass()->GetDexCache()); - const char* descriptor = dex_file.dexStringByTypeIdx(GetTypeIdx()); + const char* descriptor = dex_file.StringByTypeIdx(GetTypeIdx()); DCHECK(descriptor != NULL); return descriptor; } @@ -136,6 +137,15 @@ Class* Field::GetType() { return type; } +void Field::SetOffset(MemberOffset num_bytes) { + DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous()); + Primitive::Type type = GetPrimitiveType(); + if (type == Primitive::kPrimDouble || type == Primitive::kPrimLong) { + DCHECK_ALIGNED(num_bytes.Uint32Value(), 8); + } + SetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), num_bytes.Uint32Value(), false); +} + void Field::InitJavaFields() { Thread* self = Thread::Current(); ScopedThreadStateChange tsc(self, Thread::kRunnable); @@ -405,12 +415,43 @@ void Method::SetReturnTypeIdx(uint32_t new_return_type_idx) { new_return_type_idx, false); } +uint32_t Method::GetDexMethodIndex() const { + // TODO: add the method index to Method - which will also mean a number of Method fields can + // become dex file lookups (which will then mean we may want faster access to the dex file) + // Find the dex file + const DexCache* dex_cache = GetDeclaringClass()->GetDexCache(); + const DexFile& dex_file = Runtime::Current()->GetClassLinker()->FindDexFile(dex_cache); + // Find the class_def in the dex file + uint32_t class_def_idx; + bool found_class_def = + dex_file.FindClassDefIndex(GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8(), + class_def_idx); + CHECK(found_class_def); + const DexFile::TypeId& type_id = + dex_file.GetTypeId(dex_file.GetClassDef(class_def_idx).class_idx_); + const DexFile::StringId* name_str_id = dex_file.FindStringId(GetName()->ToModifiedUtf8()); + CHECK(name_str_id != NULL); // Failed to find method's name? + uint16_t return_type_idx; + std::vector<uint16_t> param_type_idxs; + std::string signature = GetSignature()->ToModifiedUtf8(); + bool found_type_list = dex_file.CreateTypeList(&return_type_idx, ¶m_type_idxs, signature); + CHECK(found_type_list); // Failed to parse signature + const DexFile::ProtoId* sig_proto_id = dex_file.FindProtoId(return_type_idx, param_type_idxs); + CHECK(sig_proto_id != NULL); // Failed to find method's prototype + const DexFile::MethodId* method_id = + dex_file.FindMethodId(type_id, *name_str_id, *sig_proto_id); + CHECK(method_id != NULL); // Failed to find method? + uint32_t method_idx = dex_file.GetIndexForMethodId(*method_id); + DCHECK_EQ(PrettyMethod(method_idx, dex_file), PrettyMethod(this)); + return method_idx; +} + const char* Method::GetReturnTypeDescriptor() const { Class* declaring_class = GetDeclaringClass(); DexCache* dex_cache = declaring_class->GetDexCache(); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); const DexFile& dex_file = class_linker->FindDexFile(dex_cache); - const char* descriptor = dex_file.dexStringByTypeIdx(GetReturnTypeIdx()); + const char* descriptor = dex_file.StringByTypeIdx(GetReturnTypeIdx()); DCHECK(descriptor != NULL); return descriptor; } @@ -504,24 +545,6 @@ size_t Method::NumArgRegisters(const StringPiece& shorty) { return num_registers; } -size_t Method::NumArgArrayBytes() const { - const String* shorty = GetShorty(); - size_t num_bytes = 0; - for (int i = 1; i < shorty->GetLength(); ++i) { - char ch = shorty->CharAt(i); - if (ch == 'D' || ch == 'J') { - num_bytes += 8; - } else if (ch == 'L') { - // Argument is a reference or an array. The shorty descriptor - // does not distinguish between these types. - num_bytes += sizeof(Object*); - } else { - num_bytes += 4; - } - } - return num_bytes; -} - size_t Method::NumArgs() const { // "1 +" because the first in Args is the receiver. // "- 1" because we don't count the return type. @@ -677,12 +700,11 @@ uint32_t Method::FindCatchBlock(Class* exception_type, uint32_t dex_pc) const { const DexFile& dex_file = class_linker->FindDexFile(dex_cache); const DexFile::CodeItem* code_item = dex_file.GetCodeItem(GetCodeItemOffset()); // Iterate over the catch handlers associated with dex_pc - for (DexFile::CatchHandlerIterator iter = dex_file.dexFindCatchHandler(*code_item, dex_pc); - !iter.HasNext(); iter.Next()) { - uint32_t iter_type_idx = iter.Get().type_idx_; + for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) { + uint16_t iter_type_idx = it.GetHandlerTypeIndex(); // Catch all case - if (iter_type_idx == DexFile::kDexNoIndex) { - return iter.Get().address_; + if (iter_type_idx == DexFile::kDexNoIndex16) { + return it.GetHandlerAddress(); } // Does this catch exception type apply? Class* iter_exception_type = dex_cache->GetResolvedType(iter_type_idx); @@ -691,7 +713,7 @@ uint32_t Method::FindCatchBlock(Class* exception_type, uint32_t dex_pc) const { LOG(WARNING) << "Unresolved exception class when finding catch block: " << dex_file.GetTypeDescriptor(dex_file.GetTypeId(iter_type_idx)); } else if (iter_exception_type->IsAssignableFrom(exception_type)) { - return iter.Get().address_; + return it.GetHandlerAddress(); } } // Handler not found @@ -778,6 +800,11 @@ Object* Class::AllocObject() { return Heap::AllocObject(this, this->object_size_); } +void Class::SetClassSize(size_t new_class_size) { + DCHECK_GE(new_class_size, GetClassSize()) << " class=" << PrettyTypeOf(this); + SetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size, false); +} + void Class::DumpClass(std::ostream& os, int flags) const { if ((flags & kDumpClassFullDetail) == 0) { os << PrettyClass(this); diff --git a/src/object.h b/src/object.h index dd2c1ca6e8..6a91970c74 100644 --- a/src/object.h +++ b/src/object.h @@ -619,6 +619,8 @@ class MANAGED Method : public AccessibleObject { return (GetAccessFlags() & kAccSynthetic) != 0; } + uint32_t GetDexMethodIndex() const; + uint16_t GetMethodIndex() const; size_t GetVtableIndex() const { @@ -644,10 +646,6 @@ class MANAGED Method : public AccessibleObject { // Number of 32bit registers that would be required to hold all the arguments static size_t NumArgRegisters(const StringPiece& shorty); - // Number of argument bytes required for densely packing the - // arguments into an array of arguments. - size_t NumArgArrayBytes() const; - uint16_t NumRegisters() const; void SetNumRegisters(uint16_t new_num_registers) { @@ -1088,7 +1086,8 @@ class MANAGED Method : public AccessibleObject { // Native invocation stub entry point for calling from native to managed code. const InvokeStub* invoke_stub_; - // Index of the return type + // Index of the return type in the declaring classes dex cache or dex file's type ids + // TODO: value is really just 16bit uint32_t java_return_type_idx_; // Mapping from native pc to dex pc @@ -1498,10 +1497,7 @@ class MANAGED Class : public StaticStorageBase { return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), false); } - void SetClassSize(size_t new_class_size) { - DCHECK_GE(new_class_size, GetClassSize()) << " class=" << PrettyTypeOf(this); - SetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size, false); - } + void SetClassSize(size_t new_class_size); size_t GetObjectSize() const { CHECK(!IsVariableSize()) << " class=" << PrettyTypeOf(this); @@ -2092,9 +2088,11 @@ class MANAGED Class : public StaticStorageBase { // Set in LoadClass, used to LinkClass // see also super_class_ + // TODO: really 16bits uint32_t super_class_type_idx_; // type index from dex file + // TODO: really 16bits uint32_t type_idx_; // TODO: ? @@ -2199,15 +2197,6 @@ inline size_t Object::SizeOf() const { return result; } -inline void Field::SetOffset(MemberOffset num_bytes) { - DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous()); - Primitive::Type type = GetPrimitiveType(); - if (type == Primitive::kPrimDouble || type == Primitive::kPrimLong) { - DCHECK_ALIGNED(num_bytes.Uint32Value(), 8); - } - SetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), num_bytes.Uint32Value(), false); -} - inline Class* Field::GetDeclaringClass() const { Class* result = GetFieldObject<Class*>(OFFSET_OF_OBJECT_MEMBER(Field, declaring_class_), false); DCHECK(result != NULL); @@ -2480,6 +2469,9 @@ class MANAGED String : public Object { bool Equals(const String* that) const; + // Compare UTF-16 code point values not in a locale-sensitive manner + int Compare(int32_t utf16_length, const char* utf8_data_in); + // TODO: do we need this overload? give it a more intention-revealing name. bool Equals(const uint16_t* that_chars, int32_t that_offset, int32_t that_length) const; @@ -2615,7 +2607,7 @@ inline uint32_t Class::GetAccessFlags() const { this == String::GetJavaLangString() || this == Field::GetJavaLangReflectField() || this == Method::GetConstructorClass() || - this == Method::GetMethodClass()) << PrettyClass(this); + this == Method::GetMethodClass()); return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), false); } diff --git a/src/runtime_support.cc b/src/runtime_support.cc index 7ae5da572b..e6011daba9 100644 --- a/src/runtime_support.cc +++ b/src/runtime_support.cc @@ -49,7 +49,7 @@ extern "C" uint32_t artObjectInitFromCode(Object* o, Thread* self, Method** sp) /* * NOTE: once debugger/profiler support is added, we'll need to check * here and branch to actual compiled object.<init> to handle any - * breakpoint/logging activites if either is active. + * breakpoint/logging activities if either is active. */ return self->IsExceptionPending() ? -1 : 0; } @@ -163,7 +163,7 @@ static std::string ClassNameFromIndex(Method* method, uint32_t ref, CHECK(false) << static_cast<int>(ref_type); } - std::string class_name(PrettyDescriptor(dex_file.dexStringByTypeIdx(type_idx))); + std::string class_name(PrettyDescriptor(dex_file.StringByTypeIdx(type_idx))); if (!access) { return class_name; } @@ -185,7 +185,7 @@ static std::string FieldNameFromIndex(const Method* method, uint32_t ref, const DexFile::FieldId& id = dex_file.GetFieldId(ref); std::string class_name(PrettyDescriptor(dex_file.GetFieldDeclaringClassDescriptor(id))); - const char* field_name = dex_file.dexStringById(id.name_idx_); + const char* field_name = dex_file.StringDataByIdx(id.name_idx_); if (!access) { return class_name + "." + field_name; } @@ -207,7 +207,7 @@ static std::string MethodNameFromIndex(const Method* method, uint32_t ref, const DexFile::MethodId& id = dex_file.GetMethodId(ref); std::string class_name(PrettyDescriptor(dex_file.GetMethodDeclaringClassDescriptor(id))); - const char* method_name = dex_file.dexStringById(id.name_idx_); + const char* method_name = dex_file.StringDataByIdx(id.name_idx_); if (!access) { return class_name + "." + method_name; } @@ -215,7 +215,7 @@ static std::string MethodNameFromIndex(const Method* method, uint32_t ref, std::string result; result += "tried to access method "; result += class_name + "." + method_name + ":" + - dex_file.CreateMethodDescriptor(id.proto_idx_, NULL); + dex_file.CreateMethodSignature(id.proto_idx_, NULL); result += " from class "; result += PrettyDescriptor(method->GetDeclaringClass()->GetDescriptor()); return result; diff --git a/src/utf.cc b/src/utf.cc index 31fbe97da0..52f03a95a1 100644 --- a/src/utf.cc +++ b/src/utf.cc @@ -87,6 +87,20 @@ uint16_t GetUtf16FromUtf8(const char** utf8_data_in) { return ((one & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f); } +int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* utf8_1, const char* utf8_2) { + for (;;) { + uint16_t c1 = GetUtf16FromUtf8(&utf8_1); + uint16_t c2 = GetUtf16FromUtf8(&utf8_2); + if (c1 == 0) { + return (c2 == 0) ? 0 : -1; + } else if (c2 == 0) { + return 1; + } else if (c1 != c2) { + return c1 > c2 ? 1 : -1; + } + } +} + size_t CountUtf8Bytes(const uint16_t* chars, size_t char_count) { size_t result = 0; while (char_count--) { @@ -34,6 +34,11 @@ size_t CountUtf8Bytes(const uint16_t* chars, size_t char_count); void ConvertModifiedUtf8ToUtf16(uint16_t* utf16_out, const char* utf8_in); /* + * Compare two modified UTF-8 strings as UTF-16 code point values in a non-locale sensitive manner + */ +int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* utf8_1, const char* utf8_2); + +/* * Convert from UTF-16 to Modified UTF-8. Note that the output is _not_ * NUL-terminated. You probably need to call CountUtf8Bytes before calling * this anyway, so if you want a NUL-terminated string, you know where to diff --git a/src/utils.cc b/src/utils.cc index c37343ce74..c528f1ca10 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -153,6 +153,19 @@ std::string PrettyMethod(const Method* m, bool with_signature) { return result; } +std::string PrettyMethod(uint32_t method_idx, const DexFile& dex_file, bool with_signature) { + const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); + std::string result(PrettyDescriptor(dex_file.GetMethodDeclaringClassDescriptor(method_id))); + result += '.'; + result += dex_file.GetMethodName(method_id); + if (with_signature) { + // TODO: iterate over the signature's elements and pass them all to + // PrettyDescriptor? We'd need to pull out the return type specially, too. + result += dex_file.GetMethodSignature(method_id); + } + return result; +} + std::string PrettyTypeOf(const Object* obj) { if (obj == NULL) { return "null"; diff --git a/src/utils.h b/src/utils.h index f747ae82e1..f5e0c490fb 100644 --- a/src/utils.h +++ b/src/utils.h @@ -16,6 +16,7 @@ namespace art { class Class; +class DexFile; class Field; class Method; class Object; @@ -166,6 +167,7 @@ std::string PrettyField(const Field* f, bool with_type = true); // Returns a human-readable signature for 'm'. Something like "a.b.C.m" or // "a.b.C.m(II)V" (depending on the value of 'with_signature'). std::string PrettyMethod(const Method* m, bool with_signature = true); +std::string PrettyMethod(uint32_t method_idx, const DexFile& dex_file, bool with_signature = true); // Returns a human-readable form of the name of the *class* of the given object. // So given an instance of java.lang.String, the output would diff --git a/test/CreateMethodDescriptor/CreateMethodDescriptor.java b/test/CreateMethodSignature/CreateMethodSignature.java index aa1f3de309..32338f1779 100644 --- a/test/CreateMethodDescriptor/CreateMethodDescriptor.java +++ b/test/CreateMethodSignature/CreateMethodSignature.java @@ -1,6 +1,6 @@ // Copyright 2011 Google Inc. All Rights Reserved. -class CreateMethodDescriptor { +class CreateMethodSignature { Float m1(int a, double b, long c, Object d) { return null; } - CreateMethodDescriptor m2(boolean x, short y, char z) { return null; } + CreateMethodSignature m2(boolean x, short y, char z) { return null; } } |