From df6931437880e1f7da9f777f5e54474d7ed7a630 Mon Sep 17 00:00:00 2001 From: Anwar Ghuloum Date: Wed, 4 Sep 2013 12:22:30 -0700 Subject: Remove memory leaks Change-Id: I13a74791b1d39edfbba7c7884057fa163c343a9a --- compiler/driver/compiler_driver.cc | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index cbd9020df4..31aec63b02 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1585,13 +1585,11 @@ void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_fil if (IsImage()) { // For images we resolve all types, such as array, whereas for applications just those with // classdefs are resolved by ResolveClassFieldsAndMethods. - // TODO: strdup memory leak. - timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " Types").c_str())); + timings.NewSplit("Resolve Types"); context.ForAll(0, dex_file.NumTypeIds(), ResolveType, thread_count_); } - // TODO: strdup memory leak. - timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " MethodsAndFields").c_str())); + timings.NewSplit("Resolve MethodsAndFields"); context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_); } @@ -1652,8 +1650,7 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file, ThreadPool& thread_pool, base::TimingLogger& timings) { - // TODO: strdup memory leak. - timings.NewSplit(strdup(("Verify " + dex_file.GetLocation()).c_str())); + timings.NewSplit("Verify Dex File"); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool); context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_); @@ -2150,8 +2147,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file, ThreadPool& thread_pool, base::TimingLogger& timings) { - // TODO: strdup memory leak. - timings.NewSplit(strdup(("InitializeNoClinit " + dex_file.GetLocation()).c_str())); + timings.NewSplit("InitializeNoClinit"); #ifndef NDEBUG // Sanity check blacklist descriptors. if (IsImage()) { @@ -2258,8 +2254,7 @@ void CompilerDriver::CompileClass(const ParallelCompilationManager* manager, siz void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_file, ThreadPool& thread_pool, base::TimingLogger& timings) { - // TODO: strdup memory leak. - timings.NewSplit(strdup(("Compile " + dex_file.GetLocation()).c_str())); + timings.NewSplit("Compile Dex File"); ParallelCompilationManager context(Runtime::Current()->GetClassLinker(), class_loader, this, &dex_file, thread_pool); context.ForAll(0, dex_file.NumClassDefs(), CompilerDriver::CompileClass, thread_count_); -- cgit v1.2.3-59-g8ed1b From d133b97b1ccae88f6ee7040e288fd7a239ee4492 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 5 Sep 2013 11:01:30 -0700 Subject: Shard dedupe set locks. We're seeing contention during compilation on the dedupe locks, sharding 4 ways on an occam brings down contention by > 5x. Improve dedupe hash function to have a FNV hash function at its heart. Improve naming of dedupe locks. Tidy portable JNI compiler paramters to be pointers, given that's their primary use. Change-Id: I95d905f2ca5fee4e83a0034926a5f6501b4aeb79 --- compiler/driver/compiler_driver.cc | 6 +++- compiler/driver/compiler_driver.h | 36 ++++++++++++++-------- compiler/jni/portable/jni_compiler.cc | 4 +-- compiler/jni/portable/jni_compiler.h | 4 +-- compiler/llvm/compiler_llvm.cc | 2 +- compiler/utils/dedupe_set.h | 57 ++++++++++++++++++----------------- compiler/utils/dedupe_set_test.cc | 2 +- 7 files changed, 65 insertions(+), 46 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 31aec63b02..495458efab 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -355,7 +355,11 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet jni_compiler_(NULL), compiler_enable_auto_elf_loading_(NULL), compiler_get_method_code_addr_(NULL), - support_boot_image_fixup_(true) { + support_boot_image_fixup_(true), + dedupe_code_("dedupe code"), + dedupe_mapping_table_("dedupe mapping table"), + dedupe_vmap_table_("dedupe vmap table"), + dedupe_gc_map_("dedupe gc map") { CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key"); diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index cd6b5fab02..c5c53e387d 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -449,27 +449,39 @@ class CompilerDriver { class DedupeHashFunc { public: size_t operator()(const std::vector& array) const { - // Take a random sample of bytes. + // For small arrays compute a hash using every byte. static const size_t kSmallArrayThreshold = 16; - static const size_t kRandomHashCount = 16; - size_t hash = 0; - if (array.size() < kSmallArrayThreshold) { - for (auto c : array) { - hash = hash * 54 + c; + size_t hash = 0x811c9dc5; + if (array.size() <= kSmallArrayThreshold) { + for (uint8_t b : array) { + hash = (hash * 16777619) ^ b; } } else { - for (size_t i = 0; i < kRandomHashCount; ++i) { + // For larger arrays use the first 4 bytes and then select a number of other values at + // random. + static const size_t kRandomHashCount = 16; + for (size_t i = 0; i < 4; ++i) { + uint8_t b = array[i]; + hash = (hash * 16777619) ^ b; + } + for (size_t i = 4; i < kRandomHashCount; ++i) { size_t r = i * 1103515245 + 12345; - hash = hash * 54 + array[r % array.size()]; + uint8_t b = array[r % array.size()]; + hash = (hash * 16777619) ^ b; } } + hash += hash << 13; + hash ^= hash >> 7; + hash += hash << 3; + hash ^= hash >> 17; + hash += hash << 5; return hash; } }; - DedupeSet, size_t, DedupeHashFunc> dedupe_code_; - DedupeSet, size_t, DedupeHashFunc> dedupe_mapping_table_; - DedupeSet, size_t, DedupeHashFunc> dedupe_vmap_table_; - DedupeSet, size_t, DedupeHashFunc> dedupe_gc_map_; + DedupeSet, size_t, DedupeHashFunc, 4> dedupe_code_; + DedupeSet, size_t, DedupeHashFunc, 4> dedupe_mapping_table_; + DedupeSet, size_t, DedupeHashFunc, 4> dedupe_vmap_table_; + DedupeSet, size_t, DedupeHashFunc, 4> dedupe_gc_map_; DISALLOW_COPY_AND_ASSIGN(CompilerDriver); }; diff --git a/compiler/jni/portable/jni_compiler.cc b/compiler/jni/portable/jni_compiler.cc index 43408a7d64..0c14346ad8 100644 --- a/compiler/jni/portable/jni_compiler.cc +++ b/compiler/jni/portable/jni_compiler.cc @@ -50,9 +50,9 @@ using ::art::llvm::runtime_support::JniMethodStartSynchronized; using ::art::llvm::runtime_support::RuntimeId; JniCompiler::JniCompiler(LlvmCompilationUnit* cunit, - CompilerDriver& driver, + CompilerDriver* driver, const DexCompilationUnit* dex_compilation_unit) - : cunit_(cunit), driver_(&driver), module_(cunit_->GetModule()), + : cunit_(cunit), driver_(driver), module_(cunit_->GetModule()), context_(cunit_->GetLLVMContext()), irb_(*cunit_->GetIRBuilder()), dex_compilation_unit_(dex_compilation_unit), func_(NULL), elf_func_idx_(0) { diff --git a/compiler/jni/portable/jni_compiler.h b/compiler/jni/portable/jni_compiler.h index d20c63bc1e..ffabfe61c2 100644 --- a/compiler/jni/portable/jni_compiler.h +++ b/compiler/jni/portable/jni_compiler.h @@ -54,7 +54,7 @@ class IRBuilder; class JniCompiler { public: JniCompiler(LlvmCompilationUnit* cunit, - CompilerDriver& driver, + CompilerDriver* driver, const DexCompilationUnit* dex_compilation_unit); CompiledMethod* Compile(); @@ -67,7 +67,7 @@ class JniCompiler { private: LlvmCompilationUnit* cunit_; - CompilerDriver* driver_; + CompilerDriver* const driver_; ::llvm::Module* module_; ::llvm::LLVMContext* context_; diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc index fd440d5bf0..83b0c75e04 100644 --- a/compiler/llvm/compiler_llvm.cc +++ b/compiler/llvm/compiler_llvm.cc @@ -164,7 +164,7 @@ CompileNativeMethod(DexCompilationUnit* dex_compilation_unit) { UniquePtr cunit(AllocateCompilationUnit()); UniquePtr jni_compiler( - new JniCompiler(cunit.get(), *compiler_driver_, dex_compilation_unit)); + new JniCompiler(cunit.get(), compiler_driver_, dex_compilation_unit)); return jni_compiler->Compile(); } diff --git a/compiler/utils/dedupe_set.h b/compiler/utils/dedupe_set.h index f3d35d728c..53c1afa698 100644 --- a/compiler/utils/dedupe_set.h +++ b/compiler/utils/dedupe_set.h @@ -18,62 +18,65 @@ #define ART_COMPILER_UTILS_DEDUPE_SET_H_ #include +#include #include "base/mutex.h" #include "base/stl_util.h" namespace art { -// A simple data structure to handle hashed deduplication. Add is thread safe. -template +// A set of Keys that support a HashFunc returning HashType. Used to find duplicates of Key in the +// Add method. The data-structure is thread-safe through the use of internal locks, it also +// supports the lock being sharded. +template class DedupeSet { typedef std::pair HashedKey; class Comparator { public: bool operator()(const HashedKey& a, const HashedKey& b) const { - if (a.first < b.first) return true; - if (a.first > b.first) return true; - return *a.second < *b.second; + if (a.first != b.first) { + return a.first < b.first; + } else { + return *a.second < *b.second; + } } }; - typedef std::set Keys; - public: - typedef typename Keys::iterator iterator; - typedef typename Keys::const_iterator const_iterator; - typedef typename Keys::size_type size_type; - typedef typename Keys::value_type value_type; - - iterator begin() { return keys_.begin(); } - const_iterator begin() const { return keys_.begin(); } - iterator end() { return keys_.end(); } - const_iterator end() const { return keys_.end(); } - Key* Add(Thread* self, const Key& key) { - HashType hash = HashFunc()(key); - HashedKey hashed_key(hash, const_cast(&key)); - MutexLock lock(self, lock_); - auto it = keys_.find(hashed_key); - if (it != keys_.end()) { + HashType raw_hash = HashFunc()(key); + HashType shard_hash = raw_hash / kShard; + HashType shard_bin = raw_hash % kShard; + HashedKey hashed_key(shard_hash, const_cast(&key)); + MutexLock lock(self, *lock_[shard_bin]); + auto it = keys_[shard_bin].find(hashed_key); + if (it != keys_[shard_bin].end()) { return it->second; } hashed_key.second = new Key(key); - keys_.insert(hashed_key); + keys_[shard_bin].insert(hashed_key); return hashed_key.second; } - DedupeSet() : lock_("dedupe lock") { + explicit DedupeSet(const char* set_name) { + for (HashType i = 0; i < kShard; ++i) { + lock_name_[i] = StringPrintf("%s lock %d", set_name, i); + lock_[i].reset(new Mutex(lock_name_[i].c_str())); + } } ~DedupeSet() { - STLDeleteValues(&keys_); + for (HashType i = 0; i < kShard; ++i) { + STLDeleteValues(&keys_[i]); + } } private: - Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; - Keys keys_; + std::string lock_name_[kShard]; + UniquePtr lock_[kShard]; + std::set keys_[kShard]; + DISALLOW_COPY_AND_ASSIGN(DedupeSet); }; diff --git a/compiler/utils/dedupe_set_test.cc b/compiler/utils/dedupe_set_test.cc index 9f5e292f53..03d8b961fa 100644 --- a/compiler/utils/dedupe_set_test.cc +++ b/compiler/utils/dedupe_set_test.cc @@ -38,7 +38,7 @@ class DedupeHashFunc { TEST_F(DedupeSetTest, Test) { Thread* self = Thread::Current(); typedef std::vector ByteArray; - DedupeSet deduplicator; + DedupeSet deduplicator("test"); ByteArray* array1; { ByteArray test1; -- cgit v1.2.3-59-g8ed1b From 1e54d68ce8e77dfe63340275d11a072c5184c89a Mon Sep 17 00:00:00 2001 From: Sebastien Hertz Date: Fri, 6 Sep 2013 14:52:10 +0200 Subject: Disable devirtualization detection in DEX-to-DEX compiler. This CL allows the DEX-to-DEX compiler to disable devirtualization detection. This allows to quicken invoke-virtual/range instructions that used to be eligible for devirtualization. Bug: 10632943 Change-Id: I6c9f4d3249cf42b47f004be5825b3186fa83501e --- compiler/dex/dex_to_dex_compiler.cc | 5 +++-- compiler/dex/mir_dataflow.cc | 2 +- compiler/dex/quick/gen_invoke.cc | 2 +- compiler/driver/compiler_driver.cc | 10 +++++----- compiler/driver/compiler_driver.h | 3 ++- compiler/llvm/gbc_expander.cc | 2 +- 6 files changed, 13 insertions(+), 11 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index a0e2c1e9aa..2a4d3d5ee6 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -298,11 +298,12 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, int vtable_idx; uintptr_t direct_code; uintptr_t direct_method; + // TODO: support devirtualization. + const bool kEnableDevirtualization = false; bool fast_path = driver_.ComputeInvokeInfo(&unit_, dex_pc, invoke_type, target_method, vtable_idx, direct_code, direct_method, - false); - // TODO: support devirtualization. + false, kEnableDevirtualization); if (fast_path && original_invoke_type == invoke_type) { if (vtable_idx >= 0 && IsUint(16, vtable_idx)) { VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode()) diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc index 3a73717a7b..42ca5dcfdf 100644 --- a/compiler/dex/mir_dataflow.cc +++ b/compiler/dex/mir_dataflow.cc @@ -1224,7 +1224,7 @@ bool MIRGraph::InvokeUsesMethodStar(MIR* mir) { type, target_method, vtable_idx, direct_code, direct_method, - false) && + false, true) && !(cu_->enable_debug & (1 << kDebugSlowInvokePath)); return (((type == kDirect) || (type == kStatic)) && fast_path && ((direct_code == 0) || (direct_method == 0))); diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 073b550d78..a4ab15db5e 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -1359,7 +1359,7 @@ void Mir2Lir::GenInvoke(CallInfo* info) { info->type, target_method, vtable_idx, direct_code, direct_method, - true) && !SLOW_INVOKE_PATH; + true, true) && !SLOW_INVOKE_PATH; if (info->type == kInterface) { if (fast_path) { p_null_ck = &null_ck; diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 634d3bc9c0..1468b87e4e 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1099,7 +1099,7 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui MethodReference& target_method, int& vtable_idx, uintptr_t& direct_code, uintptr_t& direct_method, - bool update_stats) { + bool update_stats, bool enable_devirtualization) { ScopedObjectAccess soa(Thread::Current()); vtable_idx = -1; direct_code = 0; @@ -1130,7 +1130,7 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui } if (referrer_class->CanAccess(methods_class) && referrer_class->CanAccessMember(methods_class, resolved_method->GetAccessFlags())) { - const bool kEnableFinalBasedSharpening = true; + const bool enableFinalBasedSharpening = enable_devirtualization; // Sharpen a virtual call into a direct call when the target is known not to have been // overridden (ie is final). bool can_sharpen_virtual_based_on_type = @@ -1142,7 +1142,7 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui resolved_method->GetMethodIndex() < methods_class->GetVTable()->GetLength() && (methods_class->GetVTable()->Get(resolved_method->GetMethodIndex()) == resolved_method); - if (kEnableFinalBasedSharpening && (can_sharpen_virtual_based_on_type || + if (enableFinalBasedSharpening && (can_sharpen_virtual_based_on_type || can_sharpen_super_based_on_type)) { // Sharpen a virtual call into a direct call. The method_idx is into referrer's // dex cache, check that this resolved method is where we expect it. @@ -1157,8 +1157,8 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui invoke_type = kDirect; return true; } - const bool kEnableVerifierBasedSharpening = true; - if (kEnableVerifierBasedSharpening && (invoke_type == kVirtual || + const bool enableVerifierBasedSharpening = enable_devirtualization; + if (enableVerifierBasedSharpening && (invoke_type == kVirtual || invoke_type == kInterface)) { // Did the verifier record a more precise invoke target based on its type information? const MethodReference caller_method(mUnit->GetDexFile(), mUnit->GetDexMethodIndex()); diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index fa1b8f9854..c324590d13 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -183,7 +183,8 @@ class CompilerDriver { // index. bool ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc, InvokeType& type, MethodReference& target_method, int& vtable_idx, - uintptr_t& direct_code, uintptr_t& direct_method, bool update_stats) + uintptr_t& direct_code, uintptr_t& direct_method, bool update_stats, + bool enable_devirtualization) LOCKS_EXCLUDED(Locks::mutator_lock_); bool IsSafeCast(const MethodReference& mr, uint32_t dex_pc); diff --git a/compiler/llvm/gbc_expander.cc b/compiler/llvm/gbc_expander.cc index 4f6fa0a2df..19c80498bd 100644 --- a/compiler/llvm/gbc_expander.cc +++ b/compiler/llvm/gbc_expander.cc @@ -849,7 +849,7 @@ llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) { invoke_type, target_method, vtable_idx, direct_code, direct_method, - true); + true, true); // Load the method object llvm::Value* callee_method_object_addr = NULL; -- cgit v1.2.3-59-g8ed1b From 65ec92cf13c9d11c83711443a02e4249163d47f1 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 6 Sep 2013 10:49:58 -0700 Subject: Refactor CompilerDriver::ComputeInvokeInfo Don't use non-const reference arguments. Move ins before outs. Change-Id: I4a7b8099abe91ea60f93a56077f4989303fa4876 --- compiler/dex/dex_to_dex_compiler.cc | 9 +-- compiler/dex/mir_dataflow.cc | 8 +-- compiler/dex/quick/gen_invoke.cc | 8 +-- compiler/driver/compiler_driver.cc | 112 ++++++++++++++++++------------------ compiler/driver/compiler_driver.h | 10 ++-- compiler/llvm/gbc_expander.cc | 8 +-- 6 files changed, 78 insertions(+), 77 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index 3fa0eab96b..7eef62c6cf 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -248,10 +248,11 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, uintptr_t direct_method; // TODO: support devirtualization. const bool kEnableDevirtualization = false; - bool fast_path = driver_.ComputeInvokeInfo(&unit_, dex_pc, invoke_type, - target_method, vtable_idx, - direct_code, direct_method, - false, kEnableDevirtualization); + bool fast_path = driver_.ComputeInvokeInfo(&unit_, dex_pc, + false, kEnableDevirtualization, + &invoke_type, + &target_method, &vtable_idx, + &direct_code, &direct_method); if (fast_path && original_invoke_type == invoke_type) { if (vtable_idx >= 0 && IsUint(16, vtable_idx)) { VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode()) diff --git a/compiler/dex/mir_dataflow.cc b/compiler/dex/mir_dataflow.cc index 42ca5dcfdf..be622762b4 100644 --- a/compiler/dex/mir_dataflow.cc +++ b/compiler/dex/mir_dataflow.cc @@ -1221,10 +1221,10 @@ bool MIRGraph::InvokeUsesMethodStar(MIR* mir) { uint32_t current_offset = static_cast(current_offset_); bool fast_path = cu_->compiler_driver->ComputeInvokeInfo(&m_unit, current_offset, - type, target_method, - vtable_idx, - direct_code, direct_method, - false, true) && + false, true, + &type, &target_method, + &vtable_idx, + &direct_code, &direct_method) && !(cu_->enable_debug & (1 << kDebugSlowInvokePath)); return (((type == kDirect) || (type == kStatic)) && fast_path && ((direct_code == 0) || (direct_method == 0))); diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index a4ab15db5e..fa608183be 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -1356,10 +1356,10 @@ void Mir2Lir::GenInvoke(CallInfo* info) { bool fast_path = cu_->compiler_driver->ComputeInvokeInfo(mir_graph_->GetCurrentDexCompilationUnit(), current_dalvik_offset_, - info->type, target_method, - vtable_idx, - direct_code, direct_method, - true, true) && !SLOW_INVOKE_PATH; + true, true, + &info->type, &target_method, + &vtable_idx, + &direct_code, &direct_method) && !SLOW_INVOKE_PATH; if (info->type == kInterface) { if (fast_path) { p_null_ck = &null_ck; diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index dcf5fd9007..13e60acd27 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -916,9 +916,9 @@ static mirror::ArtField* ComputeFieldReferencedFromCompilingMethod(ScopedObjectA } static mirror::ArtMethod* ComputeMethodReferencedFromCompilingMethod(ScopedObjectAccess& soa, - const DexCompilationUnit* mUnit, - uint32_t method_idx, - InvokeType type) + const DexCompilationUnit* mUnit, + uint32_t method_idx, + InvokeType type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::DexCache* dex_cache = mUnit->GetClassLinker()->FindDexCache(*mUnit->GetDexFile()); mirror::ClassLoader* class_loader = soa.Decode(mUnit->GetClassLoader()); @@ -1062,15 +1062,15 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type, mirror::Class* referrer_class, mirror::ArtMethod* method, - uintptr_t& direct_code, - uintptr_t& direct_method, - bool update_stats) { + bool update_stats, + uintptr_t* direct_code, + uintptr_t* direct_method) { // For direct and static methods compute possible direct_code and direct_method values, ie // an address for the Method* being invoked and an address of the code for that Method*. // For interface calls compute a value for direct_method that is the interface method being // invoked, so this can be passed to the out-of-line runtime support code. - direct_code = 0; - direct_method = 0; + *direct_code = 0; + *direct_method = 0; if (compiler_backend_ == kPortable) { if (sharp_type != kStatic && sharp_type != kDirect) { return; @@ -1102,38 +1102,37 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s if (IsImageClass(mh.GetDeclaringClassDescriptor())) { // We can only branch directly to Methods that are resolved in the DexCache. // Otherwise we won't invoke the resolution trampoline. - direct_method = -1; - direct_code = -1; + *direct_method = -1; + *direct_code = -1; } } } else { if (Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace()) { - direct_method = reinterpret_cast(method); + *direct_method = reinterpret_cast(method); } - direct_code = reinterpret_cast(method->GetEntryPointFromCompiledCode()); + *direct_code = reinterpret_cast(method->GetEntryPointFromCompiledCode()); } } bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc, - InvokeType& invoke_type, - MethodReference& target_method, - int& vtable_idx, - uintptr_t& direct_code, uintptr_t& direct_method, - bool update_stats, bool enable_devirtualization) { + bool update_stats, bool enable_devirtualization, + InvokeType* invoke_type, MethodReference* target_method, + int* vtable_idx, uintptr_t* direct_code, + uintptr_t* direct_method) { ScopedObjectAccess soa(Thread::Current()); - vtable_idx = -1; - direct_code = 0; - direct_method = 0; + *vtable_idx = -1; + *direct_code = 0; + *direct_method = 0; mirror::ArtMethod* resolved_method = - ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method.dex_method_index, - invoke_type); + ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method->dex_method_index, + *invoke_type); if (resolved_method != NULL) { // Don't try to fast-path if we don't understand the caller's class or this appears to be an // Incompatible Class Change Error. mirror::Class* referrer_class = ComputeCompilingMethodsClass(soa, resolved_method->GetDeclaringClass()->GetDexCache(), mUnit); - bool icce = resolved_method->CheckIncompatibleClassChange(invoke_type); + bool icce = resolved_method->CheckIncompatibleClassChange(*invoke_type); if (referrer_class != NULL && !icce) { mirror::Class* methods_class = resolved_method->GetDeclaringClass(); if (!referrer_class->CanAccess(methods_class) || @@ -1144,8 +1143,8 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui // method public. Resort to the dex file to determine the correct class for the access // check. uint16_t class_idx = - target_method.dex_file->GetMethodId(target_method.dex_method_index).class_idx_; - methods_class = mUnit->GetClassLinker()->ResolveType(*target_method.dex_file, + target_method->dex_file->GetMethodId(target_method->dex_method_index).class_idx_; + methods_class = mUnit->GetClassLinker()->ResolveType(*target_method->dex_file, class_idx, referrer_class); } if (referrer_class->CanAccess(methods_class) && @@ -1154,10 +1153,10 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui // Sharpen a virtual call into a direct call when the target is known not to have been // overridden (ie is final). bool can_sharpen_virtual_based_on_type = - (invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal()); + (*invoke_type == kVirtual) && (resolved_method->IsFinal() || methods_class->IsFinal()); // For invoke-super, ensure the vtable index will be correct to dispatch in the vtable of // the super class. - bool can_sharpen_super_based_on_type = (invoke_type == kSuper) && + bool can_sharpen_super_based_on_type = (*invoke_type == kSuper) && (referrer_class != methods_class) && referrer_class->IsSubClass(methods_class) && resolved_method->GetMethodIndex() < methods_class->GetVTable()->GetLength() && (methods_class->GetVTable()->Get(resolved_method->GetMethodIndex()) == resolved_method); @@ -1166,20 +1165,20 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui can_sharpen_super_based_on_type)) { // Sharpen a virtual call into a direct call. The method_idx is into referrer's // dex cache, check that this resolved method is where we expect it. - CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method.dex_method_index) == + CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index) == resolved_method) << PrettyMethod(resolved_method); if (update_stats) { - stats_->ResolvedMethod(invoke_type); - stats_->VirtualMadeDirect(invoke_type); + stats_->ResolvedMethod(*invoke_type); + stats_->VirtualMadeDirect(*invoke_type); } - GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, resolved_method, - direct_code, direct_method, update_stats); - invoke_type = kDirect; + GetCodeAndMethodForDirectCall(*invoke_type, kDirect, referrer_class, resolved_method, + update_stats, direct_code, direct_method); + *invoke_type = kDirect; return true; } const bool enableVerifierBasedSharpening = enable_devirtualization; - if (enableVerifierBasedSharpening && (invoke_type == kVirtual || - invoke_type == kInterface)) { + if (enableVerifierBasedSharpening && (*invoke_type == kVirtual || + *invoke_type == kInterface)) { // Did the verifier record a more precise invoke target based on its type information? const MethodReference caller_method(mUnit->GetDexFile(), mUnit->GetDexMethodIndex()); const MethodReference* devirt_map_target = @@ -1196,14 +1195,14 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui kVirtual); CHECK(called_method != NULL); CHECK(!called_method->IsAbstract()); - GetCodeAndMethodForDirectCall(invoke_type, kDirect, referrer_class, called_method, - direct_code, direct_method, update_stats); + GetCodeAndMethodForDirectCall(*invoke_type, kDirect, referrer_class, called_method, + update_stats, direct_code, direct_method); bool compiler_needs_dex_cache = (GetCompilerBackend() == kPortable) || (GetCompilerBackend() == kQuick && instruction_set_ != kThumb2) || - (direct_code == 0) || (direct_code == static_cast(-1)) || - (direct_method == 0) || (direct_method == static_cast(-1)); - if ((devirt_map_target->dex_file != target_method.dex_file) && + (*direct_code == 0) || (*direct_code == static_cast(-1)) || + (*direct_method == 0) || (*direct_method == static_cast(-1)); + if ((devirt_map_target->dex_file != target_method->dex_file) && compiler_needs_dex_cache) { // We need to use the dex cache to find either the method or code, and the dex file // containing the method isn't the one expected for the target method. Try to find @@ -1213,7 +1212,7 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui // TODO: quick only supports direct pointers with Thumb2. // TODO: the following should be factored into a common helper routine to find // one dex file's method within another. - const DexFile* dexfile = target_method.dex_file; + const DexFile* dexfile = target_method->dex_file; const DexFile* cm_dexfile = called_method->GetDeclaringClass()->GetDexCache()->GetDexFile(); const DexFile::MethodId& cm_method_id = @@ -1239,12 +1238,13 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui *name, *sig); if (method_id != NULL) { if (update_stats) { - stats_->ResolvedMethod(invoke_type); - stats_->VirtualMadeDirect(invoke_type); + stats_->ResolvedMethod(*invoke_type); + stats_->VirtualMadeDirect(*invoke_type); stats_->PreciseTypeDevirtualization(); } - target_method.dex_method_index = dexfile->GetIndexForMethodId(*method_id); - invoke_type = kDirect; + target_method->dex_method_index = + dexfile->GetIndexForMethodId(*method_id); + *invoke_type = kDirect; return true; } } @@ -1256,28 +1256,28 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui // method in the referring method's dex cache/file. } else { if (update_stats) { - stats_->ResolvedMethod(invoke_type); - stats_->VirtualMadeDirect(invoke_type); + stats_->ResolvedMethod(*invoke_type); + stats_->VirtualMadeDirect(*invoke_type); stats_->PreciseTypeDevirtualization(); } - target_method = *devirt_map_target; - invoke_type = kDirect; + *target_method = *devirt_map_target; + *invoke_type = kDirect; return true; } } } - if (invoke_type == kSuper) { + if (*invoke_type == kSuper) { // Unsharpened super calls are suspicious so go slow-path. } else { // Sharpening failed so generate a regular resolved method dispatch. if (update_stats) { - stats_->ResolvedMethod(invoke_type); + stats_->ResolvedMethod(*invoke_type); } - if (invoke_type == kVirtual || invoke_type == kSuper) { - vtable_idx = resolved_method->GetMethodIndex(); + if (*invoke_type == kVirtual || *invoke_type == kSuper) { + *vtable_idx = resolved_method->GetMethodIndex(); } - GetCodeAndMethodForDirectCall(invoke_type, invoke_type, referrer_class, resolved_method, - direct_code, direct_method, update_stats); + GetCodeAndMethodForDirectCall(*invoke_type, *invoke_type, referrer_class, resolved_method, + update_stats, direct_code, direct_method); return true; } } @@ -1288,7 +1288,7 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui soa.Self()->ClearException(); } if (update_stats) { - stats_->UnresolvedMethod(invoke_type); + stats_->UnresolvedMethod(*invoke_type); } return false; // Incomplete knowledge needs slow path. } diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 87be9d7415..43218cf184 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -183,9 +183,9 @@ class CompilerDriver { // Can we fastpath a interface, super class or virtual method call? Computes method's vtable // index. bool ComputeInvokeInfo(const DexCompilationUnit* mUnit, const uint32_t dex_pc, - InvokeType& type, MethodReference& target_method, int& vtable_idx, - uintptr_t& direct_code, uintptr_t& direct_method, bool update_stats, - bool enable_devirtualization) + bool update_stats, bool enable_devirtualization, + InvokeType* type, MethodReference* target_method, int* vtable_idx, + uintptr_t* direct_code, uintptr_t* direct_method) LOCKS_EXCLUDED(Locks::mutator_lock_); bool IsSafeCast(const MethodReference& mr, uint32_t dex_pc); @@ -315,8 +315,8 @@ class CompilerDriver { void GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type, mirror::Class* referrer_class, mirror::ArtMethod* method, - uintptr_t& direct_code, uintptr_t& direct_method, - bool update_stats) + bool update_stats, + uintptr_t* direct_code, uintptr_t* direct_method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void PreCompile(jobject class_loader, const std::vector& dex_files, diff --git a/compiler/llvm/gbc_expander.cc b/compiler/llvm/gbc_expander.cc index 19c80498bd..2459fde114 100644 --- a/compiler/llvm/gbc_expander.cc +++ b/compiler/llvm/gbc_expander.cc @@ -846,10 +846,10 @@ llvm::Value* GBCExpanderPass::EmitInvoke(llvm::CallInst& call_inst) { uintptr_t direct_code = 0; uintptr_t direct_method = 0; bool is_fast_path = driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_pc, - invoke_type, target_method, - vtable_idx, - direct_code, direct_method, - true, true); + true, true, + &invoke_type, &target_method, + &vtable_idx, + &direct_code, &direct_method); // Load the method object llvm::Value* callee_method_object_addr = NULL; -- cgit v1.2.3-59-g8ed1b From 9b297bfc588c7d38efd12a6f38cd2710fc513ee3 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Fri, 6 Sep 2013 11:11:25 -0700 Subject: Refactor CompilerDriver::Compute..FieldInfo Don't use non-const reference arguments. Move ins before outs. Change-Id: I7b251156388d8f07513b3da62ebfd29e5fd9ff76 --- compiler/dex/dex_to_dex_compiler.cc | 4 ++-- compiler/dex/quick/arm/call_arm.cc | 4 ++-- compiler/dex/quick/codegen_util.cc | 4 ++-- compiler/dex/quick/gen_common.cc | 13 ++++++------ compiler/dex/quick/mir_to_lir.h | 2 +- compiler/driver/compiler_driver.cc | 41 ++++++++++++++++++------------------- compiler/driver/compiler_driver.h | 10 ++++----- compiler/llvm/gbc_expander.cc | 12 +++++------ 8 files changed, 44 insertions(+), 46 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index 7eef62c6cf..4a724b109a 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -216,8 +216,8 @@ void DexCompiler::CompileInstanceFieldAccess(Instruction* inst, uint32_t field_idx = inst->VRegC_22c(); int field_offset; bool is_volatile; - bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, field_offset, - is_volatile, is_put); + bool fast_path = driver_.ComputeInstanceFieldInfo(field_idx, &unit_, is_put, + &field_offset, &is_volatile); if (fast_path && !is_volatile && IsUint(16, field_offset)) { VLOG(compiler) << "Quickening " << Instruction::Name(inst->Opcode()) << " to " << Instruction::Name(new_opcode) diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index 2dbe5f5c36..e0e198a50d 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -130,7 +130,7 @@ MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir, int field_offset; bool is_volatile; uint32_t field_idx = mir->dalvikInsn.vC; - bool fast_path = FastInstance(field_idx, field_offset, is_volatile, false); + bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile); if (!fast_path || !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) { return NULL; } @@ -155,7 +155,7 @@ MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir, int field_offset; bool is_volatile; uint32_t field_idx = mir->dalvikInsn.vC; - bool fast_path = FastInstance(field_idx, field_offset, is_volatile, false); + bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile); if (!fast_path || !(mir->optimization_flags & MIR_IGNORE_NULL_CHECK)) { return NULL; } diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index e081c16bb5..dcb0a99d08 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -50,9 +50,9 @@ void Mir2Lir::MarkSafepointPC(LIR* inst) { DCHECK_EQ(safepoint_pc->def_mask, ENCODE_ALL); } -bool Mir2Lir::FastInstance(uint32_t field_idx, int& field_offset, bool& is_volatile, bool is_put) { +bool Mir2Lir::FastInstance(uint32_t field_idx, bool is_put, int* field_offset, bool* is_volatile) { return cu_->compiler_driver->ComputeInstanceFieldInfo( - field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, is_volatile, is_put); + field_idx, mir_graph_->GetCurrentDexCompilationUnit(), is_put, field_offset, is_volatile); } /* Convert an instruction to a NOP */ diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index f018c61819..aa45d98cf6 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -337,8 +337,8 @@ void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_do bool is_volatile; bool is_referrers_class; bool fast_path = cu_->compiler_driver->ComputeStaticFieldInfo( - field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, ssb_index, - is_referrers_class, is_volatile, true); + field_idx, mir_graph_->GetCurrentDexCompilationUnit(), true, + &field_offset, &ssb_index, &is_referrers_class, &is_volatile); if (fast_path && !SLOW_FIELD_PATH) { DCHECK_GE(field_offset, 0); int rBase; @@ -423,8 +423,8 @@ void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest, bool is_volatile; bool is_referrers_class; bool fast_path = cu_->compiler_driver->ComputeStaticFieldInfo( - field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, ssb_index, - is_referrers_class, is_volatile, false); + field_idx, mir_graph_->GetCurrentDexCompilationUnit(), false, + &field_offset, &ssb_index, &is_referrers_class, &is_volatile); if (fast_path && !SLOW_FIELD_PATH) { DCHECK_GE(field_offset, 0); int rBase; @@ -626,7 +626,7 @@ void Mir2Lir::GenIGet(uint32_t field_idx, int opt_flags, OpSize size, int field_offset; bool is_volatile; - bool fast_path = FastInstance(field_idx, field_offset, is_volatile, false); + bool fast_path = FastInstance(field_idx, false, &field_offset, &is_volatile); if (fast_path && !SLOW_FIELD_PATH) { RegLocation rl_result; @@ -687,8 +687,7 @@ void Mir2Lir::GenIPut(uint32_t field_idx, int opt_flags, OpSize size, int field_offset; bool is_volatile; - bool fast_path = FastInstance(field_idx, field_offset, is_volatile, - true); + bool fast_path = FastInstance(field_idx, true, &field_offset, &is_volatile); if (fast_path && !SLOW_FIELD_PATH) { RegisterClass reg_class = oat_reg_class_by_size(size); DCHECK_GE(field_offset, 0); diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index a37ebd173f..85d90c8657 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -250,7 +250,7 @@ class Mir2Lir : public Backend { virtual void Materialize(); virtual CompiledMethod* GetCompiledMethod(); void MarkSafepointPC(LIR* inst); - bool FastInstance(uint32_t field_idx, int& field_offset, bool& is_volatile, bool is_put); + bool FastInstance(uint32_t field_idx, bool is_put, int* field_offset, bool* is_volatile); void SetupResourceMasks(LIR* lir); void AssembleLIR(); void SetMemRefType(LIR* lir, bool is_load, int mem_type); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 13e60acd27..8d521de72f 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -927,11 +927,11 @@ static mirror::ArtMethod* ComputeMethodReferencedFromCompilingMethod(ScopedObjec } bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, - int& field_offset, bool& is_volatile, bool is_put) { + bool is_put, int* field_offset, bool* is_volatile) { ScopedObjectAccess soa(Thread::Current()); // Conservative defaults. - field_offset = -1; - is_volatile = true; + *field_offset = -1; + *is_volatile = true; // Try to resolve field and ignore if an Incompatible Class Change Error (ie is static). mirror::ArtField* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx); if (resolved_field != NULL && !resolved_field->IsStatic()) { @@ -958,8 +958,8 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi bool is_write_to_final_from_wrong_class = is_put && resolved_field->IsFinal() && fields_class != referrer_class; if (access_ok && !is_write_to_final_from_wrong_class) { - field_offset = resolved_field->GetOffset().Int32Value(); - is_volatile = resolved_field->IsVolatile(); + *field_offset = resolved_field->GetOffset().Int32Value(); + *is_volatile = resolved_field->IsVolatile(); stats_->ResolvedInstanceField(); return true; // Fast path. } @@ -974,15 +974,14 @@ bool CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompi } bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, - int& field_offset, int& ssb_index, - bool& is_referrers_class, bool& is_volatile, - bool is_put) { + bool is_put, int* field_offset, int* ssb_index, + bool* is_referrers_class, bool* is_volatile) { ScopedObjectAccess soa(Thread::Current()); // Conservative defaults. - field_offset = -1; - ssb_index = -1; - is_referrers_class = false; - is_volatile = true; + *field_offset = -1; + *ssb_index = -1; + *is_referrers_class = false; + *is_volatile = true; // Try to resolve field and ignore if an Incompatible Class Change Error (ie isn't static). mirror::ArtField* resolved_field = ComputeFieldReferencedFromCompilingMethod(soa, mUnit, field_idx); if (resolved_field != NULL && resolved_field->IsStatic()) { @@ -992,9 +991,9 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila if (referrer_class != NULL) { mirror::Class* fields_class = resolved_field->GetDeclaringClass(); if (fields_class == referrer_class) { - is_referrers_class = true; // implies no worrying about class initialization - field_offset = resolved_field->GetOffset().Int32Value(); - is_volatile = resolved_field->IsVolatile(); + *is_referrers_class = true; // implies no worrying about class initialization + *field_offset = resolved_field->GetOffset().Int32Value(); + *is_volatile = resolved_field->IsVolatile(); stats_->ResolvedLocalStaticField(); return true; // fast path } else { @@ -1025,9 +1024,9 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila if (fields_class->GetDexCache() == dex_cache) { // common case where the dex cache of both the referrer and the field are the same, // no need to search the dex file - ssb_index = fields_class->GetDexTypeIndex(); - field_offset = resolved_field->GetOffset().Int32Value(); - is_volatile = resolved_field->IsVolatile(); + *ssb_index = fields_class->GetDexTypeIndex(); + *field_offset = resolved_field->GetOffset().Int32Value(); + *is_volatile = resolved_field->IsVolatile(); stats_->ResolvedStaticField(); return true; } @@ -1040,9 +1039,9 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila mUnit->GetDexFile()->FindTypeId(mUnit->GetDexFile()->GetIndexForStringId(*string_id)); if (type_id != NULL) { // medium path, needs check of static storage base being initialized - ssb_index = mUnit->GetDexFile()->GetIndexForTypeId(*type_id); - field_offset = resolved_field->GetOffset().Int32Value(); - is_volatile = resolved_field->IsVolatile(); + *ssb_index = mUnit->GetDexFile()->GetIndexForTypeId(*type_id); + *field_offset = resolved_field->GetOffset().Int32Value(); + *is_volatile = resolved_field->IsVolatile(); stats_->ResolvedStaticField(); return true; } diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 43218cf184..b4ec0c134b 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -169,15 +169,15 @@ class CompilerDriver { LOCKS_EXCLUDED(Locks::mutator_lock_); // Can we fast path instance field access? Computes field's offset and volatility. - bool ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, - int& field_offset, bool& is_volatile, bool is_put) + bool ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put, + int* field_offset, bool* is_volatile) LOCKS_EXCLUDED(Locks::mutator_lock_); // Can we fastpath static field access? Computes field's offset, volatility and whether the // field is within the referrer (which can avoid checking class initialization). - bool ComputeStaticFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, - int& field_offset, int& ssb_index, - bool& is_referrers_class, bool& is_volatile, bool is_put) + bool ComputeStaticFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put, + int* field_offset, int* ssb_index, + bool* is_referrers_class, bool* is_volatile) LOCKS_EXCLUDED(Locks::mutator_lock_); // Can we fastpath a interface, super class or virtual method call? Computes method's vtable diff --git a/compiler/llvm/gbc_expander.cc b/compiler/llvm/gbc_expander.cc index 2459fde114..b206a25f25 100644 --- a/compiler/llvm/gbc_expander.cc +++ b/compiler/llvm/gbc_expander.cc @@ -1630,7 +1630,7 @@ llvm::Value* GBCExpanderPass::Expand_HLIGet(llvm::CallInst& call_inst, int field_offset; bool is_volatile; bool is_fast_path = driver_->ComputeInstanceFieldInfo( - field_idx, dex_compilation_unit_, field_offset, is_volatile, false); + field_idx, dex_compilation_unit_, false, &field_offset, &is_volatile); if (!is_fast_path) { llvm::Function* runtime_func; @@ -1692,7 +1692,7 @@ void GBCExpanderPass::Expand_HLIPut(llvm::CallInst& call_inst, int field_offset; bool is_volatile; bool is_fast_path = driver_->ComputeInstanceFieldInfo( - field_idx, dex_compilation_unit_, field_offset, is_volatile, true); + field_idx, dex_compilation_unit_, true, &field_offset, &is_volatile); if (!is_fast_path) { llvm::Function* runtime_func; @@ -1897,8 +1897,8 @@ llvm::Value* GBCExpanderPass::Expand_HLSget(llvm::CallInst& call_inst, bool is_volatile; bool is_fast_path = driver_->ComputeStaticFieldInfo( - field_idx, dex_compilation_unit_, field_offset, ssb_index, - is_referrers_class, is_volatile, false); + field_idx, dex_compilation_unit_, false, + &field_offset, &ssb_index, &is_referrers_class, &is_volatile); llvm::Value* static_field_value; @@ -1981,8 +1981,8 @@ void GBCExpanderPass::Expand_HLSput(llvm::CallInst& call_inst, bool is_volatile; bool is_fast_path = driver_->ComputeStaticFieldInfo( - field_idx, dex_compilation_unit_, field_offset, ssb_index, - is_referrers_class, is_volatile, true); + field_idx, dex_compilation_unit_, true, + &field_offset, &ssb_index, &is_referrers_class, &is_volatile); if (!is_fast_path) { llvm::Function* runtime_func; -- cgit v1.2.3-59-g8ed1b From 8b2c0b9abc3f520495f4387ea040132ba85cae69 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Thu, 19 Sep 2013 02:56:49 -0700 Subject: Use class def index from java.lang.Class. Bug: 10244719 Depends on: https://googleplex-android-review.git.corp.google.com/362363 This removes the computation of the dex file index, when necessary this is computed by searching the dex file. Its only necessary in dalvik.system.DexFile.defineClassNative and DexFile::FindInClassPath, the latter not showing up significantly in profiling with this change. Change-Id: I20c73a3b17d86286428ab0fd21bc13f51f36c85c --- compiler/dex/compiler_ir.h | 2 +- compiler/dex/dex_to_dex_compiler.cc | 2 +- compiler/dex/frontend.cc | 6 +- compiler/dex/frontend.h | 2 +- compiler/dex/mir_graph.cc | 2 +- compiler/dex/mir_graph.h | 2 +- compiler/dex/quick/codegen_util.cc | 22 ++-- compiler/driver/compiler_driver.cc | 49 +++++---- compiler/driver/compiler_driver.h | 27 +++-- compiler/driver/dex_compilation_unit.cc | 2 +- compiler/driver/dex_compilation_unit.h | 6 +- compiler/image_writer.cc | 1 + compiler/llvm/compiler_llvm.cc | 4 +- compiler/sea_ir/frontend.cc | 6 +- compiler/sea_ir/ir/sea.cc | 4 +- compiler/sea_ir/ir/sea.h | 6 +- oatdump/oatdump.cc | 32 +++--- runtime/Android.mk | 1 + runtime/class_linker.cc | 111 ++++++++++----------- runtime/class_linker.h | 4 +- runtime/class_linker_test.cc | 12 +-- runtime/dex_file.cc | 91 +++++------------ runtime/dex_file.h | 44 +++----- .../entrypoints/quick/quick_invoke_entrypoints.cc | 2 +- runtime/mirror/art_method-inl.h | 2 +- runtime/mirror/class.cc | 23 ++--- runtime/mirror/class.h | 31 ++++-- runtime/mirror/dex_cache.h | 1 + runtime/mirror/proxy.h | 3 + runtime/mirror/string.h | 2 +- runtime/native/dalvik_system_DexFile.cc | 2 +- runtime/native/java_lang_Class.cc | 31 ------ runtime/native/java_lang_DexCache.cc | 56 +++++++++++ runtime/oat_file.cc | 2 +- runtime/oat_file.h | 2 +- runtime/object_utils.h | 87 +++++++--------- runtime/runtime.cc | 5 +- runtime/thread.cc | 2 +- runtime/verifier/method_verifier.cc | 96 +++++++++--------- runtime/verifier/method_verifier.h | 19 ++-- runtime/verifier/method_verifier_test.cc | 3 +- test/100-reflect2/expected.txt | 2 +- 42 files changed, 397 insertions(+), 412 deletions(-) create mode 100644 runtime/native/java_lang_DexCache.cc (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h index 26d0923baa..6607562b13 100644 --- a/compiler/dex/compiler_ir.h +++ b/compiler/dex/compiler_ir.h @@ -77,7 +77,7 @@ struct CompilationUnit { ClassLinker* class_linker; // Linker to resolve fields and methods. const DexFile* dex_file; // DexFile containing the method being compiled. jobject class_loader; // compiling method's class loader. - uint32_t class_def_idx; // compiling method's defining class definition index. + uint16_t class_def_idx; // compiling method's defining class definition index. uint32_t method_idx; // compiling method's index into method_ids of DexFile. const DexFile::CodeItem* code_item; // compiling method's DexFile code_item. uint32_t access_flags; // compiling method's access flags. diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc index ffd7905dfe..abafbc5830 100644 --- a/compiler/dex/dex_to_dex_compiler.cc +++ b/compiler/dex/dex_to_dex_compiler.cc @@ -280,7 +280,7 @@ void DexCompiler::CompileInvokeVirtual(Instruction* inst, extern "C" void ArtCompileDEX(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file, art::DexToDexCompilationLevel dex_to_dex_compilation_level) { if (dex_to_dex_compilation_level != art::kDontDexToDexCompile) { diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc index 23036495ce..fefcab9e87 100644 --- a/compiler/dex/frontend.cc +++ b/compiler/dex/frontend.cc @@ -110,7 +110,7 @@ static CompiledMethod* CompileMethod(CompilerDriver& compiler, const CompilerBackend compiler_backend, const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file #if defined(ART_USE_PORTABLE_COMPILER) , llvm::LlvmCompilationUnit* llvm_compilation_unit @@ -273,7 +273,7 @@ CompiledMethod* CompileOneMethod(CompilerDriver& compiler, const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, @@ -292,7 +292,7 @@ extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file) { // TODO: check method fingerprint here to determine appropriate backend type. Until then, use build default art::CompilerBackend backend = compiler.GetCompilerBackend(); diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h index bafa46892c..6c33d109e3 100644 --- a/compiler/dex/frontend.h +++ b/compiler/dex/frontend.h @@ -117,7 +117,7 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_dex_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index c72283e689..c234298a88 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -504,7 +504,7 @@ BasicBlock* MIRGraph::ProcessCanThrow(BasicBlock* cur_block, MIR* insn, int cur_ /* Parse a Dex method and insert it into the MIRGraph at the current insert point. */ void MIRGraph::InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint32_t class_def_idx, + InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file) { current_code_item_ = code_item; method_stack_.push_back(std::make_pair(current_method_, current_offset_)); diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 0244daec9d..9d4ab98f67 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -357,7 +357,7 @@ class MIRGraph { * actually the index of the method in the m_units_ array). */ void InlineMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint32_t class_def_idx, + InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file); /* Find existing block */ diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index f13ab2db01..4ce752fb39 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -385,11 +385,12 @@ void Mir2Lir::InstallLiteralPools() { while (data_lir != NULL) { uint32_t target = data_lir->operands[0]; cu_->compiler_driver->AddCodePatch(cu_->dex_file, - cu_->method_idx, - cu_->invoke_type, - target, - static_cast(data_lir->operands[1]), - code_buffer_.size()); + cu_->class_def_idx, + cu_->method_idx, + cu_->invoke_type, + target, + static_cast(data_lir->operands[1]), + code_buffer_.size()); const DexFile::MethodId& id = cu_->dex_file->GetMethodId(target); // unique based on target to ensure code deduplication works uint32_t unique_patch_value = reinterpret_cast(&id); @@ -400,11 +401,12 @@ void Mir2Lir::InstallLiteralPools() { while (data_lir != NULL) { uint32_t target = data_lir->operands[0]; cu_->compiler_driver->AddMethodPatch(cu_->dex_file, - cu_->method_idx, - cu_->invoke_type, - target, - static_cast(data_lir->operands[1]), - code_buffer_.size()); + cu_->class_def_idx, + cu_->method_idx, + cu_->invoke_type, + target, + static_cast(data_lir->operands[1]), + code_buffer_.size()); const DexFile::MethodId& id = cu_->dex_file->GetMethodId(target); // unique based on target to ensure code deduplication works uint32_t unique_patch_value = reinterpret_cast(&id); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 8d521de72f..658370f1fd 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -293,7 +293,7 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); @@ -301,7 +301,7 @@ extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& compi const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); @@ -310,7 +310,7 @@ extern "C" art::CompiledMethod* ArtCompileDEX(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); @@ -319,7 +319,7 @@ extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file); @@ -540,7 +540,7 @@ void CompilerDriver::CompileOne(const mirror::ArtMethod* method, base::TimingLog Thread* self = Thread::Current(); jobject jclass_loader; const DexFile* dex_file; - uint32_t class_def_idx; + uint16_t class_def_idx; { ScopedObjectAccessUnchecked soa(self); ScopedLocalRef @@ -1304,13 +1304,15 @@ bool CompilerDriver::IsSafeCast(const MethodReference& mr, uint32_t dex_pc) { void CompilerDriver::AddCodePatch(const DexFile* dex_file, - uint32_t referrer_method_idx, - InvokeType referrer_invoke_type, - uint32_t target_method_idx, - InvokeType target_invoke_type, - size_t literal_offset) { + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + InvokeType referrer_invoke_type, + uint32_t target_method_idx, + InvokeType target_invoke_type, + size_t literal_offset) { MutexLock mu(Thread::Current(), compiled_methods_lock_); code_to_patch_.push_back(new PatchInformation(dex_file, + referrer_class_def_idx, referrer_method_idx, referrer_invoke_type, target_method_idx, @@ -1318,13 +1320,15 @@ void CompilerDriver::AddCodePatch(const DexFile* dex_file, literal_offset)); } void CompilerDriver::AddMethodPatch(const DexFile* dex_file, - uint32_t referrer_method_idx, - InvokeType referrer_invoke_type, - uint32_t target_method_idx, - InvokeType target_invoke_type, - size_t literal_offset) { + uint16_t referrer_class_def_idx, + uint32_t referrer_method_idx, + InvokeType referrer_invoke_type, + uint32_t target_method_idx, + InvokeType target_invoke_type, + size_t literal_offset) { MutexLock mu(Thread::Current(), compiled_methods_lock_); methods_to_patch_.push_back(new PatchInformation(dex_file, + referrer_class_def_idx, referrer_method_idx, referrer_invoke_type, target_method_idx, @@ -1625,10 +1629,12 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ */ mirror::DexCache* dex_cache = manager->GetClassLinker()->FindDexCache(*manager->GetDexFile()); std::string error_msg; - if (verifier::MethodVerifier::VerifyClass(manager->GetDexFile(), + const DexFile* dex_file = manager->GetDexFile(); + const DexFile::ClassDef* class_def = &dex_file->GetClassDef(class_def_index); + if (verifier::MethodVerifier::VerifyClass(dex_file, dex_cache, soa.Decode(manager->GetClassLoader()), - class_def_index, error_msg, true) == + class_def, true, &error_msg) == verifier::MethodVerifier::kHardFailure) { const DexFile::ClassDef& class_def = manager->GetDexFile()->GetClassDef(class_def_index); LOG(ERROR) << "Verification failed on class " @@ -2137,7 +2143,8 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl } // If successfully initialized place in SSB array. if (klass->IsInitialized()) { - klass->GetDexCache()->GetInitializedStaticStorage()->Set(klass->GetDexTypeIndex(), klass); + int32_t ssb_index = klass->GetDexTypeIndex(); + klass->GetDexCache()->GetInitializedStaticStorage()->Set(ssb_index, klass); } } // Record the final class status if necessary. @@ -2264,7 +2271,7 @@ void CompilerDriver::CompileDexFile(jobject class_loader, const DexFile& dex_fil } void CompilerDriver::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint32_t class_def_idx, + InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, DexToDexCompilationLevel dex_to_dex_compilation_level) { @@ -2387,13 +2394,13 @@ void CompilerDriver::SetBitcodeFileName(std::string const& filename) { void CompilerDriver::AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, - size_t class_def_index) { + uint16_t class_def_index) { WriterMutexLock mu(self, freezing_constructor_lock_); freezing_constructor_classes_.insert(ClassReference(dex_file, class_def_index)); } bool CompilerDriver::RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, - size_t class_def_index) { + uint16_t class_def_index) { ReaderMutexLock mu(self, freezing_constructor_lock_); return freezing_constructor_classes_.count(ClassReference(dex_file, class_def_index)) != 0; } diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index b4ec0c134b..66c9cbf91a 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -145,8 +145,9 @@ class CompilerDriver { CompiledMethod* GetCompiledMethod(MethodReference ref) const LOCKS_EXCLUDED(compiled_methods_lock_); - void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, size_t class_def_index); - bool RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, size_t class_def_index); + void AddRequiresConstructorBarrier(Thread* self, const DexFile* dex_file, + uint16_t class_def_index); + bool RequiresConstructorBarrier(Thread* self, const DexFile* dex_file, uint16_t class_def_index); // Callbacks from compiler to see what runtime checks must be generated. @@ -192,6 +193,7 @@ class CompilerDriver { // Record patch information for later fix up. void AddCodePatch(const DexFile* dex_file, + uint16_t referrer_class_def_idx, uint32_t referrer_method_idx, InvokeType referrer_invoke_type, uint32_t target_method_idx, @@ -199,6 +201,7 @@ class CompilerDriver { size_t literal_offset) LOCKS_EXCLUDED(compiled_methods_lock_); void AddMethodPatch(const DexFile* dex_file, + uint16_t referrer_class_def_idx, uint32_t referrer_method_idx, InvokeType referrer_invoke_type, uint32_t target_method_idx, @@ -249,6 +252,9 @@ class CompilerDriver { const DexFile& GetDexFile() const { return *dex_file_; } + uint16_t GetReferrerClassDefIdx() const { + return referrer_class_def_idx_; + } uint32_t GetReferrerMethodIdx() const { return referrer_method_idx_; } @@ -267,12 +273,14 @@ class CompilerDriver { private: PatchInformation(const DexFile* dex_file, + uint16_t referrer_class_def_idx, uint32_t referrer_method_idx, InvokeType referrer_invoke_type, uint32_t target_method_idx, InvokeType target_invoke_type, size_t literal_offset) : dex_file_(dex_file), + referrer_class_def_idx_(referrer_class_def_idx), referrer_method_idx_(referrer_method_idx), referrer_invoke_type_(referrer_invoke_type), target_method_idx_(target_method_idx), @@ -281,12 +289,13 @@ class CompilerDriver { CHECK(dex_file_ != NULL); } - const DexFile* dex_file_; - uint32_t referrer_method_idx_; - InvokeType referrer_invoke_type_; - uint32_t target_method_idx_; - InvokeType target_invoke_type_; - size_t literal_offset_; + const DexFile* const dex_file_; + const uint16_t referrer_class_def_idx_; + const uint32_t referrer_method_idx_; + const InvokeType referrer_invoke_type_; + const uint32_t target_method_idx_; + const InvokeType target_invoke_type_; + const size_t literal_offset_; friend class CompilerDriver; DISALLOW_COPY_AND_ASSIGN(PatchInformation); @@ -358,7 +367,7 @@ class CompilerDriver { ThreadPool& thread_pool, base::TimingLogger& timings) LOCKS_EXCLUDED(Locks::mutator_lock_); void CompileMethod(const DexFile::CodeItem* code_item, uint32_t access_flags, - InvokeType invoke_type, uint32_t class_def_idx, uint32_t method_idx, + InvokeType invoke_type, uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, DexToDexCompilationLevel dex_to_dex_compilation_level) LOCKS_EXCLUDED(compiled_methods_lock_); diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc index eb8941b15f..c441d09ab2 100644 --- a/compiler/driver/dex_compilation_unit.cc +++ b/compiler/driver/dex_compilation_unit.cc @@ -39,7 +39,7 @@ DexCompilationUnit::DexCompilationUnit(CompilationUnit* cu, ClassLinker* class_linker, const DexFile& dex_file, const DexFile::CodeItem* code_item, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, uint32_t access_flags) : cu_(cu), diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h index 465139b34f..3df50ffec6 100644 --- a/compiler/driver/dex_compilation_unit.h +++ b/compiler/driver/dex_compilation_unit.h @@ -36,7 +36,7 @@ class DexCompilationUnit { DexCompilationUnit(CompilationUnit* cu, jobject class_loader, ClassLinker* class_linker, const DexFile& dex_file, const DexFile::CodeItem* code_item, - uint32_t class_def_idx, uint32_t method_idx, uint32_t access_flags); + uint16_t class_def_idx, uint32_t method_idx, uint32_t access_flags); CompilationUnit* GetCompilationUnit() const { return cu_; @@ -54,7 +54,7 @@ class DexCompilationUnit { return dex_file_; } - uint32_t GetClassDefIndex() const { + uint16_t GetClassDefIndex() const { return class_def_idx_; } @@ -108,7 +108,7 @@ class DexCompilationUnit { const DexFile* const dex_file_; const DexFile::CodeItem* const code_item_; - const uint32_t class_def_idx_; + const uint16_t class_def_idx_; const uint32_t dex_method_idx_; const uint32_t access_flags_; diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index d1859e6f98..f82c6fb40f 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -699,6 +699,7 @@ void ImageWriter::PatchOatCodeAndMethods() { void ImageWriter::SetPatchLocation(const CompilerDriver::PatchInformation* patch, uint32_t value) { ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); const void* oat_code = class_linker->GetOatCodeFor(patch->GetDexFile(), + patch->GetReferrerClassDefIdx(), patch->GetReferrerMethodIdx()); OatHeader& oat_header = const_cast(oat_file_->GetOatHeader()); // TODO: make this Thumb2 specific diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc index 0df3c476fc..d59afd48b7 100644 --- a/compiler/llvm/compiler_llvm.cc +++ b/compiler/llvm/compiler_llvm.cc @@ -40,7 +40,7 @@ void CompileOneMethod(CompilerDriver& driver, const CompilerBackend compilerBackend, const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, llvm::LlvmCompilationUnit* llvm_info); } @@ -203,7 +203,7 @@ extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver, const art::DexFile::CodeItem* code_item, uint32_t access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file) { diff --git a/compiler/sea_ir/frontend.cc b/compiler/sea_ir/frontend.cc index 93f6f25461..3512911f43 100644 --- a/compiler/sea_ir/frontend.cc +++ b/compiler/sea_ir/frontend.cc @@ -41,7 +41,7 @@ static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler, const CompilerBackend compiler_backend, const DexFile::CodeItem* code_item, uint32_t method_access_flags, InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file #if defined(ART_USE_PORTABLE_COMPILER) , llvm::LlvmCompilationUnit* llvm_compilation_unit @@ -69,7 +69,7 @@ CompiledMethod* SeaIrCompileOneMethod(CompilerDriver& compiler, const DexFile::CodeItem* code_item, uint32_t method_access_flags, InvokeType invoke_type, - uint32_t class_def_idx, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const DexFile& dex_file, @@ -86,7 +86,7 @@ extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler, const art::DexFile::CodeItem* code_item, uint32_t method_access_flags, art::InvokeType invoke_type, - uint32_t class_def_idx, uint32_t method_idx, jobject class_loader, + uint16_t class_def_idx, uint32_t method_idx, jobject class_loader, const art::DexFile& dex_file) { // TODO: Check method fingerprint here to determine appropriate backend type. // Until then, use build default diff --git a/compiler/sea_ir/ir/sea.cc b/compiler/sea_ir/ir/sea.cc index 5ccaba6ad9..0734b21f12 100644 --- a/compiler/sea_ir/ir/sea.cc +++ b/compiler/sea_ir/ir/sea.cc @@ -191,7 +191,7 @@ void SeaGraph::InsertSignatureNodes(const art::DexFile::CodeItem* code_item, Reg } void SeaGraph::BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, - const art::DexFile& dex_file, uint32_t class_def_idx, + const art::DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx, uint32_t method_access_flags) { code_item_ = code_item; class_def_idx_ = class_def_idx; @@ -409,7 +409,7 @@ CodeGenData* SeaGraph::GenerateLLVM(const std::string& function_name, CodeGenData* SeaGraph::CompileMethod( const std::string& function_name, - const art::DexFile::CodeItem* code_item, uint32_t class_def_idx, + const art::DexFile::CodeItem* code_item, uint16_t class_def_idx, uint32_t method_idx, uint32_t method_access_flags, const art::DexFile& dex_file) { // Two passes: Builds the intermediate structure (non-SSA) of the sea-ir for the function. BuildMethodSeaGraph(code_item, dex_file, class_def_idx, method_idx, method_access_flags); diff --git a/compiler/sea_ir/ir/sea.h b/compiler/sea_ir/ir/sea.h index 92c2043dbd..26b16be019 100644 --- a/compiler/sea_ir/ir/sea.h +++ b/compiler/sea_ir/ir/sea.h @@ -262,7 +262,7 @@ class SeaGraph: IVisitable { static SeaGraph* GetGraph(const art::DexFile&); CodeGenData* CompileMethod(const std::string& function_name, - const art::DexFile::CodeItem* code_item, uint32_t class_def_idx, + const art::DexFile::CodeItem* code_item, uint16_t class_def_idx, uint32_t method_idx, uint32_t method_access_flags, const art::DexFile& dex_file); // Returns all regions corresponding to this SeaGraph. std::vector* GetRegions() { @@ -288,7 +288,7 @@ class SeaGraph: IVisitable { } TypeInference* ti_; - uint32_t class_def_idx_; + uint16_t class_def_idx_; uint32_t method_idx_; uint32_t method_access_flags_; @@ -311,7 +311,7 @@ class SeaGraph: IVisitable { // Builds the non-SSA sea-ir representation of the function @code_item from @dex_file // with class id @class_def_idx and method id @method_idx. void BuildMethodSeaGraph(const art::DexFile::CodeItem* code_item, - const art::DexFile& dex_file, uint32_t class_def_idx, + const art::DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx, uint32_t method_access_flags); // Computes immediate dominators for each region. // Precondition: ComputeMethodSeaGraph() diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index cf1b6af809..fc9e00c2cb 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -176,9 +176,10 @@ class OatDumper { CHECK(oat_dex_file != NULL); UniquePtr dex_file(oat_dex_file->OpenDexFile()); if (dex_file.get() != NULL) { - uint32_t class_def_index; - bool found = dex_file->FindClassDefIndex(mh.GetDeclaringClassDescriptor(), class_def_index); - if (found) { + const DexFile::ClassDef* class_def = + dex_file->FindClassDef(mh.GetDeclaringClassDescriptor()); + if (class_def != NULL) { + uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def); const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_index); CHECK(oat_class != NULL); size_t method_index = m->GetMethodIndex(); @@ -284,18 +285,17 @@ class OatDumper { } ClassDataItemIterator it(dex_file, class_data); SkipAllFields(it); - uint32_t class_def_idx = dex_file.GetIndexForClassDef(class_def); uint32_t class_method_idx = 0; while (it.HasNextDirectMethod()) { const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx); - DumpOatMethod(os, class_def_idx, class_method_idx, oat_method, dex_file, + DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetMemberAccessFlags()); class_method_idx++; it.Next(); } while (it.HasNextVirtualMethod()) { const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx); - DumpOatMethod(os, class_def_idx, class_method_idx, oat_method, dex_file, + DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetMemberAccessFlags()); class_method_idx++; it.Next(); @@ -304,7 +304,8 @@ class OatDumper { os << std::flush; } - void DumpOatMethod(std::ostream& os, uint32_t class_def_idx, uint32_t class_method_index, + void DumpOatMethod(std::ostream& os, const DexFile::ClassDef& class_def, + uint32_t class_method_index, const OatFile::OatMethod& oat_method, const DexFile& dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code_item, uint32_t method_access_flags) { @@ -323,7 +324,8 @@ class OatDumper { indent1_os << "VERIFIER TYPE ANALYSIS:\n"; Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count); std::ostream indent2_os(&indent2_filter); - DumpVerifier(indent2_os, dex_method_idx, &dex_file, class_def_idx, code_item, method_access_flags); + DumpVerifier(indent2_os, dex_method_idx, &dex_file, class_def, code_item, + method_access_flags); } { indent1_os << "OAT DATA:\n"; @@ -363,7 +365,7 @@ class OatDumper { oat_method.GetCode() != NULL ? "..." : ""); Indenter indent2_filter(indent1_os.rdbuf(), kIndentChar, kIndentBy1Count); std::ostream indent2_os(&indent2_filter); - DumpCode(indent2_os, oat_method, dex_method_idx, &dex_file, class_def_idx, code_item, + DumpCode(indent2_os, oat_method, dex_method_idx, &dex_file, class_def, code_item, method_access_flags); } } @@ -554,7 +556,7 @@ class OatDumper { void DumpVRegsAtDexPc(std::ostream& os, const OatFile::OatMethod& oat_method, uint32_t dex_method_idx, const DexFile* dex_file, - uint32_t class_def_idx, const DexFile::CodeItem* code_item, + const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item, uint32_t method_access_flags, uint32_t dex_pc) { static UniquePtr verifier; static const DexFile* verified_dex_file = NULL; @@ -563,7 +565,7 @@ class OatDumper { ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file); mirror::ClassLoader* class_loader = NULL; - verifier.reset(new verifier::MethodVerifier(dex_file, dex_cache, class_loader, class_def_idx, + verifier.reset(new verifier::MethodVerifier(dex_file, dex_cache, class_loader, &class_def, code_item, dex_method_idx, NULL, method_access_flags, true, true)); verifier->Verify(); @@ -615,21 +617,21 @@ class OatDumper { } void DumpVerifier(std::ostream& os, uint32_t dex_method_idx, const DexFile* dex_file, - uint32_t class_def_idx, const DexFile::CodeItem* code_item, + const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item, uint32_t method_access_flags) { if ((method_access_flags & kAccNative) == 0) { ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file); mirror::ClassLoader* class_loader = NULL; verifier::MethodVerifier::VerifyMethodAndDump(os, dex_method_idx, dex_file, dex_cache, - class_loader, class_def_idx, code_item, NULL, + class_loader, &class_def, code_item, NULL, method_access_flags); } } void DumpCode(std::ostream& os, const OatFile::OatMethod& oat_method, uint32_t dex_method_idx, const DexFile* dex_file, - uint32_t class_def_idx, const DexFile::CodeItem* code_item, + const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item, uint32_t method_access_flags) { const void* code = oat_method.GetCode(); size_t code_size = oat_method.GetCodeSize(); @@ -647,7 +649,7 @@ class OatDumper { if (dex_pc != DexFile::kDexNoIndex) { DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset); if (kDumpVRegs) { - DumpVRegsAtDexPc(os, oat_method, dex_method_idx, dex_file, class_def_idx, code_item, + DumpVRegsAtDexPc(os, oat_method, dex_method_idx, dex_file, class_def, code_item, method_access_flags, dex_pc); } } diff --git a/runtime/Android.mk b/runtime/Android.mk index e324060ecb..5edf7592d9 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -91,6 +91,7 @@ LIBART_COMMON_SRC_FILES := \ native/dalvik_system_VMStack.cc \ native/dalvik_system_Zygote.cc \ native/java_lang_Class.cc \ + native/java_lang_DexCache.cc \ native/java_lang_Object.cc \ native/java_lang_Runtime.cc \ native/java_lang_String.cc \ diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index c19f8724bb..15eab9d165 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -475,40 +475,33 @@ void ClassLinker::FinishInit() { // as the types of the field can't be resolved prior to the runtime being // fully initialized mirror::Class* java_lang_ref_Reference = GetClassRoot(kJavaLangRefReference); - mirror::Class* java_lang_ref_ReferenceQueue = FindSystemClass("Ljava/lang/ref/ReferenceQueue;"); - mirror::Class* java_lang_ref_FinalizerReference = FindSystemClass("Ljava/lang/ref/FinalizerReference;"); - - const DexFile& java_lang_dex = *java_lang_ref_Reference->GetDexCache()->GetDexFile(); + mirror::Class* java_lang_ref_FinalizerReference = + FindSystemClass("Ljava/lang/ref/FinalizerReference;"); mirror::ArtField* pendingNext = java_lang_ref_Reference->GetInstanceField(0); FieldHelper fh(pendingNext, this); CHECK_STREQ(fh.GetName(), "pendingNext"); - CHECK_EQ(java_lang_dex.GetFieldId(pendingNext->GetDexFieldIndex()).type_idx_, - java_lang_ref_Reference->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); mirror::ArtField* queue = java_lang_ref_Reference->GetInstanceField(1); fh.ChangeField(queue); CHECK_STREQ(fh.GetName(), "queue"); - CHECK_EQ(java_lang_dex.GetFieldId(queue->GetDexFieldIndex()).type_idx_, - java_lang_ref_ReferenceQueue->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/ref/ReferenceQueue;"); mirror::ArtField* queueNext = java_lang_ref_Reference->GetInstanceField(2); fh.ChangeField(queueNext); CHECK_STREQ(fh.GetName(), "queueNext"); - CHECK_EQ(java_lang_dex.GetFieldId(queueNext->GetDexFieldIndex()).type_idx_, - java_lang_ref_Reference->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/ref/Reference;"); mirror::ArtField* referent = java_lang_ref_Reference->GetInstanceField(3); fh.ChangeField(referent); CHECK_STREQ(fh.GetName(), "referent"); - CHECK_EQ(java_lang_dex.GetFieldId(referent->GetDexFieldIndex()).type_idx_, - GetClassRoot(kJavaLangObject)->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/Object;"); mirror::ArtField* zombie = java_lang_ref_FinalizerReference->GetInstanceField(2); fh.ChangeField(zombie); CHECK_STREQ(fh.GetName(), "zombie"); - CHECK_EQ(java_lang_dex.GetFieldId(zombie->GetDexFieldIndex()).type_idx_, - GetClassRoot(kJavaLangObject)->GetDexTypeIndex()); + CHECK_STREQ(fh.GetTypeDescriptor(), "Ljava/lang/Object;"); gc::Heap* heap = Runtime::Current()->GetHeap(); heap->SetReferenceOffsets(referent->GetOffset(), @@ -1234,8 +1227,10 @@ mirror::Class* ClassLinker::AllocClass(Thread* self, mirror::Class* java_lang_Cl return NULL; } mirror::Class* klass = k->AsClass(); - klass->SetPrimitiveType(Primitive::kPrimNot); // default to not being primitive + klass->SetPrimitiveType(Primitive::kPrimNot); // Default to not being primitive. klass->SetClassSize(class_size); + klass->SetDexClassDefIndex(DexFile::kDexNoIndex16); // Default to no valid class def index. + klass->SetDexTypeIndex(DexFile::kDexNoIndex16); // Default to no valid type index. return klass; } @@ -1499,26 +1494,21 @@ size_t ClassLinker::SizeOfClass(const DexFile& dex_file, return size; } -const OatFile::OatClass* ClassLinker::GetOatClass(const DexFile& dex_file, const char* descriptor) { - DCHECK(descriptor != NULL); +const OatFile::OatClass* ClassLinker::GetOatClass(const DexFile& dex_file, uint16_t class_def_idx) { + DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16); const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file); - CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << descriptor; + CHECK(oat_file != NULL) << dex_file.GetLocation(); const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation()); - CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << descriptor; - uint32_t class_def_index; - bool found = dex_file.FindClassDefIndex(descriptor, class_def_index); - CHECK(found) << dex_file.GetLocation() << " " << descriptor; - const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_index); - CHECK(oat_class != NULL) << dex_file.GetLocation() << " " << descriptor; + CHECK(oat_dex_file != NULL) << dex_file.GetLocation(); + const OatFile::OatClass* oat_class = oat_dex_file->GetOatClass(class_def_idx); + CHECK(oat_class != NULL) << dex_file.GetLocation() << " " << class_def_idx; return oat_class; } -static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint32_t method_idx) { - const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); - const DexFile::TypeId& type_id = dex_file.GetTypeId(method_id.class_idx_); - const DexFile::ClassDef* class_def = dex_file.FindClassDef(dex_file.GetTypeDescriptor(type_id)); - CHECK(class_def != NULL); - const byte* class_data = dex_file.GetClassData(*class_def); +static uint32_t GetOatMethodIndexFromMethodIndex(const DexFile& dex_file, uint16_t class_def_idx, + uint32_t method_idx) { + const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx); + const byte* class_data = dex_file.GetClassData(class_def); CHECK(class_data != NULL); ClassDataItemIterator it(dex_file, class_data); // Skip fields @@ -1572,11 +1562,13 @@ const OatFile::OatMethod ClassLinker::GetOatMethodFor(const mirror::ArtMethod* m } CHECK(found) << "Didn't find oat method index for virtual method: " << PrettyMethod(method); } - ClassHelper kh(declaring_class); - UniquePtr oat_class(GetOatClass(kh.GetDexFile(), kh.GetDescriptor())); + UniquePtr + oat_class(GetOatClass(*declaring_class->GetDexCache()->GetDexFile(), + declaring_class->GetDexClassDefIndex())); CHECK(oat_class.get() != NULL); DCHECK_EQ(oat_method_index, GetOatMethodIndexFromMethodIndex(*declaring_class->GetDexCache()->GetDexFile(), + method->GetDeclaringClass()->GetDexClassDefIndex(), method->GetDexMethodIndex())); return oat_class->GetOatMethod(oat_method_index); @@ -1600,12 +1592,11 @@ const void* ClassLinker::GetOatCodeFor(const mirror::ArtMethod* method) { return result; } -const void* ClassLinker::GetOatCodeFor(const DexFile& dex_file, uint32_t method_idx) { - const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); - const char* descriptor = dex_file.GetTypeDescriptor(dex_file.GetTypeId(method_id.class_idx_)); - uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, method_idx); - UniquePtr oat_class(GetOatClass(dex_file, descriptor)); - CHECK(oat_class.get() != NULL); +const void* ClassLinker::GetOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, + uint32_t method_idx) { + UniquePtr oat_class(GetOatClass(dex_file, class_def_idx)); + CHECK(oat_class.get() != nullptr); + uint32_t oat_method_idx = GetOatMethodIndexFromMethodIndex(dex_file, class_def_idx, method_idx); return oat_class->GetOatMethod(oat_method_idx).GetCode(); } @@ -1642,7 +1633,7 @@ void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) { // OAT file unavailable return; } - UniquePtr oat_class(GetOatClass(dex_file, kh.GetDescriptor())); + UniquePtr oat_class(GetOatClass(dex_file, klass->GetDexClassDefIndex())); CHECK(oat_class.get() != NULL); ClassDataItemIterator it(dex_file, class_data); // Skip fields @@ -1734,6 +1725,7 @@ void ClassLinker::LoadClass(const DexFile& dex_file, DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot); klass->SetStatus(mirror::Class::kStatusIdx, NULL); + klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def)); klass->SetDexTypeIndex(dex_class_def.class_idx_); // Load fields fields. @@ -1781,7 +1773,7 @@ void ClassLinker::LoadClass(const DexFile& dex_file, UniquePtr oat_class; if (Runtime::Current()->IsStarted() && !Runtime::Current()->UseCompileTimeClassPath()) { - oat_class.reset(GetOatClass(dex_file, descriptor)); + oat_class.reset(GetOatClass(dex_file, klass->GetDexClassDefIndex())); } // Load methods. @@ -1876,7 +1868,8 @@ mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file if (klass->GetClassLoader() != NULL) { // All non-boot finalizer methods are flagged klass->SetFinalizable(); } else { - StringPiece klass_descriptor(dex_file.StringByTypeIdx(klass->GetDexTypeIndex())); + ClassHelper kh(klass.get()); + StringPiece klass_descriptor(kh.GetDescriptor()); // The Enum class declares a "final" finalize() method to prevent subclasses from // introducing a finalizer. We don't want to set the finalizable flag for Enum or its // subclasses, so we exclude it here. @@ -2342,12 +2335,16 @@ mirror::Class* ClassLinker::LookupClassFromImage(const char* descriptor) { const DexFile* dex_file = dex_cache->GetDexFile(); // First search using the class def map, but don't bother for non-class types. if (descriptor[0] == 'L') { - const DexFile::ClassDef* class_def = dex_file->FindClassDef(descriptor); - if (class_def != NULL) { - mirror::Class* klass = dex_cache->GetResolvedType(class_def->class_idx_); - if (klass != NULL) { - self->EndAssertNoThreadSuspension(old_no_suspend_cause); - return klass; + const DexFile::StringId* descriptor_string_id = dex_file->FindStringId(descriptor); + if (descriptor_string_id != NULL) { + const DexFile::TypeId* type_id = + dex_file->FindTypeId(dex_file->GetIndexForStringId(*descriptor_string_id)); + if (type_id != NULL) { + mirror::Class* klass = dex_cache->GetResolvedType(dex_file->GetIndexForTypeId(*type_id)); + if (klass != NULL) { + self->EndAssertNoThreadSuspension(old_no_suspend_cause); + return klass; + } } } } @@ -2458,8 +2455,9 @@ void ClassLinker::VerifyClass(mirror::Class* klass) { verifier::MethodVerifier::FailureKind verifier_failure = verifier::MethodVerifier::kNoFailure; std::string error_msg; if (!preverified) { - verifier_failure = verifier::MethodVerifier::VerifyClass(klass, error_msg, - Runtime::Current()->IsCompiler()); + verifier_failure = verifier::MethodVerifier::VerifyClass(klass, + Runtime::Current()->IsCompiler(), + &error_msg); } if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) { if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) { @@ -2530,7 +2528,6 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class } } - const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file); // Make this work with gtests, which do not set up the image properly. // TODO: we should clean up gtests to set up the image path properly. @@ -2542,9 +2539,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation()); CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass); const char* descriptor = ClassHelper(klass).GetDescriptor(); - uint32_t class_def_index; - bool found = dex_file.FindClassDefIndex(descriptor, class_def_index); - CHECK(found) << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor; + uint16_t class_def_index = klass->GetDexClassDefIndex(); UniquePtr oat_class(oat_dex_file->GetOatClass(class_def_index)); CHECK(oat_class.get() != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor; @@ -2657,8 +2652,6 @@ mirror::Class* ClassLinker::CreateProxyClass(mirror::String* name, klass->SetStatus(mirror::Class::kStatusIdx, self); - klass->SetDexTypeIndex(DexFile::kDexNoIndex16); - // Instance fields are inherited, but we add a couple of static fields... { mirror::ObjectArray* sfields = AllocArtFieldArray(self, 2); @@ -3265,10 +3258,8 @@ bool ClassLinker::LinkClass(SirtRef& klass, bool ClassLinker::LoadSuperAndInterfaces(SirtRef& klass, const DexFile& dex_file) { CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus()); - StringPiece descriptor(dex_file.StringByTypeIdx(klass->GetDexTypeIndex())); - const DexFile::ClassDef* class_def = dex_file.FindClassDef(descriptor); - CHECK(class_def != NULL); - uint16_t super_class_idx = class_def->superclass_idx_; + const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex()); + uint16_t super_class_idx = class_def.superclass_idx_; if (super_class_idx != DexFile::kDexNoIndex16) { mirror::Class* super_class = ResolveType(dex_file, super_class_idx, klass.get()); if (super_class == NULL) { @@ -3284,7 +3275,7 @@ bool ClassLinker::LoadSuperAndInterfaces(SirtRef& klass, const De } klass->SetSuperClass(super_class); } - const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(*class_def); + const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(class_def); if (interfaces != NULL) { for (size_t i = 0; i < interfaces->Size(); i++) { uint16_t idx = interfaces->GetTypeItem(i).type_idx_; diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 20efbb43a9..3ffcf14447 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -329,7 +329,7 @@ class ClassLinker { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Get the oat code for a method from a method index. - const void* GetOatCodeFor(const DexFile& dex_file, uint32_t method_idx) + const void* GetOatCodeFor(const DexFile& dex_file, uint16_t class_def_idx, uint32_t method_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); pid_t GetClassesLockOwner(); // For SignalCatcher. @@ -424,7 +424,7 @@ class ClassLinker { void FixupStaticTrampolines(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Finds the associated oat class for a dex_file and descriptor - const OatFile::OatClass* GetOatClass(const DexFile& dex_file, const char* descriptor) + const OatFile::OatClass* GetOatClass(const DexFile& dex_file, uint16_t class_def_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void RegisterDexFileLocked(const DexFile& dex_file, SirtRef& dex_cache) diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 0fa0ffbc56..bea1139679 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -508,6 +508,7 @@ struct ClassOffsets : public CheckOffsets { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_), "dexClassDefIndex")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_), "dexTypeIndex")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_instance_fields_), "numReferenceInstanceFields")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_static_fields_), "numReferenceStaticFields")); @@ -570,10 +571,6 @@ struct ProxyOffsets : public CheckOffsets { struct ClassClassOffsets : public CheckOffsets { ClassClassOffsets() : CheckOffsets(true, "Ljava/lang/Class;") { - // padding 32-bit - CHECK_EQ(OFFSETOF_MEMBER(mirror::ClassClass, padding_) + 4, - OFFSETOF_MEMBER(mirror::ClassClass, serialVersionUID_)); - // alphabetical 64-bit offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassClass, serialVersionUID_), "serialVersionUID")); }; @@ -585,11 +582,11 @@ struct StringClassOffsets : public CheckOffsets { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, ASCII_), "ASCII")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, CASE_INSENSITIVE_ORDER_), "CASE_INSENSITIVE_ORDER")); - // padding 32-bit - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, REPLACEMENT_CHAR_), "REPLACEMENT_CHAR")); - // alphabetical 64-bit offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, serialVersionUID_), "serialVersionUID")); + + // alphabetical 32-bit + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, REPLACEMENT_CHAR_), "REPLACEMENT_CHAR")); }; }; @@ -606,6 +603,7 @@ struct ArtMethodClassOffsets : public CheckOffsets { struct DexCacheOffsets : public CheckOffsets { DexCacheOffsets() : CheckOffsets(false, "Ljava/lang/DexCache;") { // alphabetical references + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_), "dex")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, initialized_static_storage_), "initializedStaticStorage")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, location_), "location")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_), "resolvedFields")); diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 4fd9a608c1..e81c456ccf 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -48,7 +48,7 @@ namespace art { const byte DexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' }; const byte DexFile::kDexMagicVersion[] = { '0', '3', '5', '\0' }; -DexFile::ClassPathEntry DexFile::FindInClassPath(const StringPiece& descriptor, +DexFile::ClassPathEntry DexFile::FindInClassPath(const char* descriptor, const ClassPath& class_path) { for (size_t i = 0; i != class_path.size(); ++i) { const DexFile* dex_file = class_path[i]; @@ -251,56 +251,11 @@ DexFile::~DexFile() { // the global reference table is otherwise empty! } -class ScopedJniMonitorLock { - public: - ScopedJniMonitorLock(JNIEnv* env, jobject locked) : env_(env), locked_(locked) { - env->MonitorEnter(locked_); - } - ~ScopedJniMonitorLock() { - env_->MonitorExit(locked_); - } - private: - JNIEnv* const env_; - const jobject locked_; -}; - -jobject DexFile::GetDexObject(JNIEnv* env) const { - { - ScopedJniMonitorLock lock(env, WellKnownClasses::com_android_dex_Dex); - if (dex_object_ != NULL) { - return dex_object_; - } - } - void* address = const_cast(reinterpret_cast(begin_)); - jobject byte_buffer = env->NewDirectByteBuffer(address, size_); - if (byte_buffer == NULL) { - return NULL; - } - - ScopedJniMonitorLock lock(env, WellKnownClasses::com_android_dex_Dex); - // Re-test to see if someone beat us to the creation when we had the lock released. - if (dex_object_ != NULL) { - return dex_object_; - } - jvalue args[1]; - args[0].l = byte_buffer; - jobject local = env->CallStaticObjectMethodA(WellKnownClasses::com_android_dex_Dex, - WellKnownClasses::com_android_dex_Dex_create, - args); - if (local == NULL) { - return NULL; - } - - dex_object_ = env->NewGlobalRef(local); - return dex_object_; -} - bool DexFile::Init() { InitMembers(); if (!CheckMagicAndVersion()) { return false; } - InitIndex(); return true; } @@ -351,28 +306,36 @@ uint32_t DexFile::GetVersion() const { return atoi(version); } -void DexFile::InitIndex() { - CHECK_EQ(index_.size(), 0U) << GetLocation(); - for (size_t i = 0; i < NumClassDefs(); ++i) { - const ClassDef& class_def = GetClassDef(i); - const char* descriptor = GetClassDescriptor(class_def); - index_.Put(descriptor, i); +const DexFile::ClassDef* DexFile::FindClassDef(const char* descriptor) const { + size_t num_class_defs = NumClassDefs(); + if (num_class_defs == 0) { + return NULL; } -} - -bool DexFile::FindClassDefIndex(const StringPiece& descriptor, uint32_t& idx) const { - Index::const_iterator it = index_.find(descriptor); - if (it == index_.end()) { - return false; + const StringId* string_id = FindStringId(descriptor); + if (string_id == NULL) { + return NULL; } - idx = it->second; - return true; + const TypeId* type_id = FindTypeId(GetIndexForStringId(*string_id)); + if (type_id == NULL) { + return NULL; + } + uint16_t type_idx = GetIndexForTypeId(*type_id); + for (size_t i = 0; i < num_class_defs; ++i) { + const ClassDef& class_def = GetClassDef(i); + if (class_def.class_idx_ == type_idx) { + return &class_def; + } + } + return NULL; } -const DexFile::ClassDef* DexFile::FindClassDef(const StringPiece& descriptor) const { - uint32_t idx; - if (FindClassDefIndex(descriptor, idx)) { - return &GetClassDef(idx); +const DexFile::ClassDef* DexFile::FindClassDef(uint16_t type_idx) const { + size_t num_class_defs = NumClassDefs(); + for (size_t i = 0; i < num_class_defs; ++i) { + const ClassDef& class_def = GetClassDef(i); + if (class_def.class_idx_ == type_idx) { + return &class_def; + } } return NULL; } diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 26635ae255..7be5cb848f 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -339,7 +339,7 @@ class DexFile { typedef std::vector ClassPath; // Search a collection of DexFiles for a descriptor - static ClassPathEntry FindInClassPath(const StringPiece& descriptor, + static ClassPathEntry FindInClassPath(const char* descriptor, const ClassPath& class_path); // Returns the checksum of a file for comparison with GetLocationChecksum(). @@ -376,10 +376,6 @@ class DexFile { return location_checksum_; } - // Returns a com.android.dex.Dex object corresponding to the mapped-in dex file. - // Used by managed code to implement annotations. - jobject GetDexObject(JNIEnv* env) const; - const Header& GetHeader() const { DCHECK(header_ != NULL) << GetLocation(); return *header_; @@ -584,12 +580,12 @@ class DexFile { } // Returns the ClassDef at the specified index. - const ClassDef& GetClassDef(uint32_t idx) const { + const ClassDef& GetClassDef(uint16_t idx) const { DCHECK_LT(idx, NumClassDefs()) << GetLocation(); return class_defs_[idx]; } - uint32_t GetIndexForClassDef(const ClassDef& class_def) const { + uint16_t GetIndexForClassDef(const ClassDef& class_def) const { CHECK_GE(&class_def, class_defs_) << GetLocation(); CHECK_LT(&class_def, class_defs_ + header_->class_defs_size_) << GetLocation(); return &class_def - class_defs_; @@ -601,10 +597,10 @@ class DexFile { } // Looks up a class definition by its class descriptor. - const ClassDef* FindClassDef(const StringPiece& descriptor) const; + const ClassDef* FindClassDef(const char* descriptor) const; - // Looks up a class definition index by its class descriptor. - bool FindClassDefIndex(const StringPiece& descriptor, uint32_t& idx) const; + // Looks up a class definition by its type index. + const ClassDef* FindClassDef(uint16_t type_idx) const; const TypeList* GetInterfacesList(const ClassDef& class_def) const { if (class_def.interfaces_off_ == 0) { @@ -809,6 +805,14 @@ class DexFile { bool DisableWrite() const; + const byte* Begin() const { + return begin_; + } + + size_t Size() const { + return size_; + } + private: // Opens a .dex file static const DexFile* OpenFile(const std::string& filename, @@ -840,7 +844,6 @@ class DexFile { location_(location), location_checksum_(location_checksum), mem_map_(mem_map), - dex_object_(NULL), modification_lock("DEX modification lock"), header_(0), string_ids_(0), @@ -853,23 +856,12 @@ class DexFile { CHECK_GT(size_, 0U) << GetLocation(); } - const byte* Begin() const { - return begin_; - } - - size_t Size() const { - return size_; - } - // Top-level initializer that calls other Init methods. bool Init(); // Caches pointers into to the various file sections. void InitMembers(); - // Builds the index of descriptors to class definitions. - void InitIndex(); - // Returns true if the header magic and version numbers are of the expected values. bool CheckMagicAndVersion() const; @@ -877,10 +869,6 @@ class DexFile { DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb, void* context, const byte* stream, LocalInfo* local_in_reg) const; - // The index of descriptors to class definition indexes (as opposed to type id indexes) - typedef SafeMap Index; - Index index_; - // The base address of the memory mapping. const byte* const begin_; @@ -898,10 +886,6 @@ class DexFile { // Manages the underlying memory allocation. UniquePtr mem_map_; - // A cached com.android.dex.Dex instance, possibly NULL. Use GetDexObject. - // TODO: this is mutable as it shouldn't be here. We should move it to the dex cache or similar. - mutable jobject dex_object_; - // The DEX-to-DEX compiler uses this lock to ensure thread safety when // enabling write access to a read-only DEX file. // TODO: move to Locks::dex_file_modification_lock. diff --git a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc index 1d8022f803..07c1c015aa 100644 --- a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc @@ -32,7 +32,7 @@ extern "C" uint64_t artInvokeInterfaceTrampoline(mirror::ArtMethod* interface_me Thread* self, mirror::ArtMethod** sp) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::ArtMethod* method; - if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex16)) { + if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) { method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method); if (UNLIKELY(method == NULL)) { FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs); diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h index 224b2ba0d4..ccf3e59f18 100644 --- a/runtime/mirror/art_method-inl.h +++ b/runtime/mirror/art_method-inl.h @@ -178,7 +178,7 @@ inline uint32_t ArtMethod::GetOatNativeGcMapOffset() const { } inline bool ArtMethod::IsRuntimeMethod() const { - return GetDexMethodIndex() == DexFile::kDexNoIndex16; + return GetDexMethodIndex() == DexFile::kDexNoIndex; } inline bool ArtMethod::IsCalleeSaveMethod() const { diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 328c67deb1..c128eded0a 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -119,7 +119,10 @@ void Class::SetDexCache(DexCache* new_dex_cache) { } void Class::SetClassSize(size_t new_class_size) { - DCHECK_GE(new_class_size, GetClassSize()) << " class=" << PrettyTypeOf(this); + if (kIsDebugBuild && (new_class_size < GetClassSize())) { + DumpClass(LOG(ERROR), kDumpClassFullDetail); + CHECK_GE(new_class_size, GetClassSize()) << " class=" << PrettyTypeOf(this); + } SetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size, false); } @@ -291,22 +294,8 @@ bool Class::IsInSamePackage(const Class* that) const { return true; } // Compare the package part of the descriptor string. - if (LIKELY(!klass1->IsProxyClass() && !klass2->IsProxyClass())) { - ClassHelper kh(klass1); - const DexFile* dex_file1 = &kh.GetDexFile(); - const DexFile::TypeId* type_id1 = &dex_file1->GetTypeId(klass1->GetDexTypeIndex()); - const char* descriptor1 = dex_file1->GetTypeDescriptor(*type_id1); - kh.ChangeClass(klass2); - const DexFile* dex_file2 = &kh.GetDexFile(); - const DexFile::TypeId* type_id2 = &dex_file2->GetTypeId(klass2->GetDexTypeIndex()); - const char* descriptor2 = dex_file2->GetTypeDescriptor(*type_id2); - return IsInSamePackage(descriptor1, descriptor2); - } - ClassHelper kh(klass1); - std::string descriptor1(kh.GetDescriptor()); - kh.ChangeClass(klass2); - std::string descriptor2(kh.GetDescriptor()); - return IsInSamePackage(descriptor1, descriptor2); + return IsInSamePackage(ClassHelper(klass1).GetDescriptor(), + ClassHelper(klass2).GetDescriptor()); } bool Class::IsClassClass() const { diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 99f3850b9b..d97b603ad8 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -726,6 +726,14 @@ class MANAGED Class : public StaticStorageBase { return GetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), false); } + uint16_t GetDexClassDefIndex() const { + return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), false); + } + + void SetDexClassDefIndex(uint16_t class_def_idx) { + SetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), class_def_idx, false); + } + uint16_t GetDexTypeIndex() const { return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), false); } @@ -807,7 +815,7 @@ class MANAGED Class : public StaticStorageBase { // If class verify fails, we must return same error on subsequent tries. Class* verify_error_class_; - // virtual methods defined in this class; invoked through vtable + // Virtual methods defined in this class; invoked through vtable. ObjectArray* virtual_methods_; // Virtual method table (vtable), for use by "invoke-virtual". The vtable from the superclass is @@ -816,24 +824,28 @@ class MANAGED Class : public StaticStorageBase { // virtual_ methods_ for miranda methods. ObjectArray* vtable_; - // access flags; low 16 bits are defined by VM spec + // Access flags; low 16 bits are defined by VM spec. uint32_t access_flags_; // Total size of the Class instance; used when allocating storage on gc heap. // See also object_size_. size_t class_size_; - // tid used to check for recursive invocation + // Tid used to check for recursive invocation. pid_t clinit_thread_id_; - // type index from dex file + // ClassDef index in dex file, -1 if no class definition such as an array. + // TODO: really 16bits + int32_t dex_class_def_idx_; + + // Type index in dex file. // TODO: really 16bits - uint32_t dex_type_idx_; + int32_t dex_type_idx_; - // number of instance fields that are object refs + // Number of instance fields that are object refs. size_t num_reference_instance_fields_; - // number of static fields that are object refs + // Number of static fields that are object refs, size_t num_reference_static_fields_; // Total object size; used when allocating storage on gc heap. @@ -841,7 +853,7 @@ class MANAGED Class : public StaticStorageBase { // See also class_size_. size_t object_size_; - // primitive type value, or Primitive::kPrimNot (0); set for generated prim classes + // Primitive type value, or Primitive::kPrimNot (0); set for generated primitive classes. Primitive::Type primitive_type_; // Bitmap of offsets of ifields. @@ -850,7 +862,7 @@ class MANAGED Class : public StaticStorageBase { // Bitmap of offsets of sfields. uint32_t reference_static_offsets_; - // state of class initialization + // State of class initialization. Status status_; // TODO: ? @@ -873,7 +885,6 @@ std::ostream& operator<<(std::ostream& os, const Class::Status& rhs); class MANAGED ClassClass : public Class { private: - int32_t padding_; int64_t serialVersionUID_; friend struct art::ClassClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ClassClass); diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index 6cfab9e425..0522f134af 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -164,6 +164,7 @@ class MANAGED DexCache : public Object { } private: + Object* dex_; ObjectArray* initialized_static_storage_; String* location_; ObjectArray* resolved_fields_; diff --git a/runtime/mirror/proxy.h b/runtime/mirror/proxy.h index 7c5bc39429..18a84dcbdb 100644 --- a/runtime/mirror/proxy.h +++ b/runtime/mirror/proxy.h @@ -25,6 +25,8 @@ struct ProxyOffsets; namespace mirror { +// All proxy objects have a class which is a synthesized proxy class. The synthesized proxy class +// has the static fields used to implement reflection on proxy objects. class MANAGED SynthesizedProxyClass : public Class { public: ObjectArray* GetInterfaces() { @@ -41,6 +43,7 @@ class MANAGED SynthesizedProxyClass : public Class { DISALLOW_IMPLICIT_CONSTRUCTORS(SynthesizedProxyClass); }; +// C++ mirror of java.lang.reflect.Proxy. class MANAGED Proxy : public Object { private: Object* h_; diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index 01d8f318ff..1879f04bef 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -156,8 +156,8 @@ class MANAGED StringClass : public Class { private: CharArray* ASCII_; Object* CASE_INSENSITIVE_ORDER_; - uint32_t REPLACEMENT_CHAR_; int64_t serialVersionUID_; + uint32_t REPLACEMENT_CHAR_; friend struct art::StringClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(StringClass); }; diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 2f4e427bb6..d2a6c0edb4 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -150,7 +150,7 @@ static jclass DexFile_defineClassNative(JNIEnv* env, jclass, jstring javaName, j return NULL; } const std::string descriptor(DotToDescriptor(class_name.c_str())); - const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor); + const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor.c_str()); if (dex_class_def == NULL) { VLOG(class_linker) << "Failed to find dex_class_def"; return NULL; diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index a7296996da..d3011cb013 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -78,35 +78,6 @@ static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean return soa.AddLocalReference(c); } -static jint Class_getAnnotationDirectoryOffset(JNIEnv* env, jclass javaClass) { - ScopedObjectAccess soa(env); - mirror::Class* c = DecodeClass(soa, javaClass); - if (c->IsPrimitive() || c->IsArrayClass() || c->IsProxyClass()) { - return 0; // primitive, array and proxy classes don't have class definitions - } - const DexFile::ClassDef* class_def = ClassHelper(c).GetClassDef(); - if (class_def == NULL) { - return 0; // not found - } else { - return class_def->annotations_off_; - } -} - -static jobject Class_getDex(JNIEnv* env, jobject javaClass) { - ScopedObjectAccess soa(env); - mirror::Class* c = DecodeClass(soa, javaClass); - - mirror::DexCache* dex_cache = c->GetDexCache(); - if (dex_cache == NULL) { - return NULL; - } - const DexFile* dex_file = dex_cache->GetDexFile(); - if (dex_file == NULL) { - return NULL; - } - return dex_file->GetDexObject(env); -} - static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) { ScopedObjectAccess soa(env); mirror::Class* c = DecodeClass(soa, javaThis); @@ -122,8 +93,6 @@ static jobjectArray Class_getProxyInterfaces(JNIEnv* env, jobject javaThis) { static JNINativeMethod gMethods[] = { NATIVE_METHOD(Class, classForName, "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"), - NATIVE_METHOD(Class, getAnnotationDirectoryOffset, "()I"), - NATIVE_METHOD(Class, getDex, "()Lcom/android/dex/Dex;"), NATIVE_METHOD(Class, getNameNative, "()Ljava/lang/String;"), NATIVE_METHOD(Class, getProxyInterfaces, "()[Ljava/lang/Class;"), }; diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc new file mode 100644 index 0000000000..f8eeb2906e --- /dev/null +++ b/runtime/native/java_lang_DexCache.cc @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "dex_file.h" +#include "mirror/dex_cache.h" +#include "mirror/object-inl.h" +#include "scoped_thread_state_change.h" +#include "well_known_classes.h" + +namespace art { + +static jobject DexCache_getDexNative(JNIEnv* env, jobject javaDexCache) { + ScopedObjectAccess soa(env); + mirror::DexCache* dex_cache = soa.Decode(javaDexCache); + // Should only be called while holding the lock on the dex cache. + DCHECK_EQ(dex_cache->GetThinLockId(), soa.Self()->GetThinLockId()); + const DexFile* dex_file = dex_cache->GetDexFile(); + if (dex_file == NULL) { + return NULL; + } + void* address = const_cast(reinterpret_cast(dex_file->Begin())); + jobject byte_buffer = env->NewDirectByteBuffer(address, dex_file->Size()); + if (byte_buffer == NULL) { + DCHECK(soa.Self()->IsExceptionPending()); + return NULL; + } + + jvalue args[1]; + args[0].l = byte_buffer; + return env->CallStaticObjectMethodA(WellKnownClasses::com_android_dex_Dex, + WellKnownClasses::com_android_dex_Dex_create, + args); +} + +static JNINativeMethod gMethods[] = { + NATIVE_METHOD(DexCache, getDexNative, "()Lcom/android/dex/Dex;"), +}; + +void register_java_lang_DexCache(JNIEnv* env) { + REGISTER_NATIVE_METHODS("java/lang/DexCache"); +} + +} // namespace art diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index afa823dbd9..4c970172b4 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -365,7 +365,7 @@ const DexFile* OatFile::OatDexFile::OpenDexFile() const { dex_file_location_checksum_); } -const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint32_t class_def_index) const { +const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) const { uint32_t oat_class_offset = oat_class_offsets_pointer_[class_def_index]; const byte* oat_class_pointer = oat_file_->Begin() + oat_class_offset; diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 325ebb2914..bbd2615b66 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -183,7 +183,7 @@ class OatFile { } // Returns the OatClass for the class specified by the given DexFile class_def_index. - const OatClass* GetOatClass(uint32_t class_def_index) const; + const OatClass* GetOatClass(uint16_t class_def_index) const; ~OatDexFile(); diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 29102437a2..6ee3016179 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -68,8 +68,7 @@ class ClassHelper { public: ClassHelper(const mirror::Class* c = NULL, ClassLinker* l = NULL) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) - : class_def_(NULL), - class_linker_(l), + : class_linker_(l), dex_cache_(NULL), dex_file_(NULL), interface_type_list_(NULL), @@ -92,7 +91,6 @@ class ClassHelper { } klass_ = new_c; interface_type_list_ = NULL; - class_def_ = NULL; } // The returned const char* is only guaranteed to be valid for the lifetime of the ClassHelper. @@ -108,7 +106,7 @@ class ClassHelper { return descriptor_.c_str(); } else { const DexFile& dex_file = GetDexFile(); - const DexFile::TypeId& type_id = dex_file.GetTypeId(klass_->GetDexTypeIndex()); + const DexFile::TypeId& type_id = dex_file.GetTypeId(GetClassDef()->class_idx_); return dex_file.GetTypeDescriptor(type_id); } } @@ -124,14 +122,13 @@ class ClassHelper { return descriptor_.c_str(); } - const DexFile::ClassDef* GetClassDef() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const DexFile::ClassDef* result = class_def_; - if (result == NULL) { - result = GetDexFile().FindClassDef(GetDescriptor()); - class_def_ = result; + const DexFile::ClassDef* GetClassDef() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(klass_ != nullptr); + uint16_t class_def_idx = klass_->GetDexClassDefIndex(); + if (class_def_idx == DexFile::kDexNoIndex16) { + return nullptr; } - return result; + return &GetDexFile().GetClassDef(class_def_idx); } uint32_t NumDirectInterfaces() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -187,7 +184,7 @@ class ClassHelper { const char* GetSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { std::string descriptor(GetDescriptor()); const DexFile& dex_file = GetDexFile(); - const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor); + const DexFile::ClassDef* dex_class_def = GetClassDef(); CHECK(dex_class_def != NULL); return dex_file.GetSourceFile(*dex_class_def); } @@ -242,7 +239,6 @@ class ClassHelper { return result; } - const DexFile::ClassDef* class_def_; ClassLinker* class_linker_; mirror::DexCache* dex_cache_; const DexFile* dex_file_; @@ -327,12 +323,15 @@ class FieldHelper { // If you need it longer, copy it into a std::string. const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - uint16_t type_idx = field_->GetDeclaringClass()->GetDexTypeIndex(); - if (type_idx != DexFile::kDexNoIndex16) { + uint32_t field_index = field_->GetDexFieldIndex(); + if (!field_->GetDeclaringClass()->IsProxyClass()) { const DexFile& dex_file = GetDexFile(); - return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)); + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); + return dex_file.GetFieldDeclaringClassDescriptor(field_id); } else { - // Most likely a proxy class. + DCHECK(field_->IsStatic()); + DCHECK_LT(field_index, 2U); + // 0 == Class[] interfaces; 1 == Class[][] throws; ClassHelper kh(field_->GetDeclaringClass()); declaring_class_descriptor_ = kh.GetDescriptor(); return declaring_class_descriptor_.c_str(); @@ -418,7 +417,7 @@ class MethodHelper { const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); uint32_t dex_method_idx = method_->GetDexMethodIndex(); - if (dex_method_idx != DexFile::kDexNoIndex16) { + if (dex_method_idx != DexFile::kDexNoIndex) { return dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx)); } else { Runtime* runtime = Runtime::Current(); @@ -464,21 +463,19 @@ class MethodHelper { const std::string GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); uint32_t dex_method_idx = method_->GetDexMethodIndex(); - if (dex_method_idx != DexFile::kDexNoIndex16) { + if (dex_method_idx != DexFile::kDexNoIndex) { return dex_file.GetMethodSignature(dex_file.GetMethodId(dex_method_idx)); } else { return ""; } } - const DexFile::ProtoId& GetPrototype() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile::ProtoId& GetPrototype() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); return dex_file.GetMethodPrototype(dex_file.GetMethodId(method_->GetDexMethodIndex())); } - const DexFile::TypeList* GetParameterTypeList() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile::TypeList* GetParameterTypeList() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile::ProtoId& proto = GetPrototype(); return GetDexFile().GetProtoParameters(proto); } @@ -491,8 +488,7 @@ class MethodHelper { return GetClassFromTypeIdx(return_type_idx); } - const char* GetReturnTypeDescriptor() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const char* GetReturnTypeDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); const DexFile::MethodId& method_id = dex_file.GetMethodId(method_->GetDexMethodIndex()); const DexFile::ProtoId& proto_id = dex_file.GetMethodPrototype(method_id); @@ -500,8 +496,7 @@ class MethodHelper { return dex_file.GetTypeDescriptor(dex_file.GetTypeId(return_type_idx)); } - int32_t GetLineNumFromDexPC(uint32_t dex_pc) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + int32_t GetLineNumFromDexPC(uint32_t dex_pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (dex_pc == DexFile::kDexNoIndex) { return method_->IsNative() ? -2 : -1; } else { @@ -510,35 +505,29 @@ class MethodHelper { } } - const char* GetDeclaringClassDescriptor() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - mirror::Class* klass = method_->GetDeclaringClass(); - DCHECK(!klass->IsProxyClass()); - uint16_t type_idx = klass->GetDexTypeIndex(); + const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); - return dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)); + uint32_t dex_method_idx = method_->GetDexMethodIndex(); + if (dex_method_idx != DexFile::kDexNoIndex) { + return dex_file.GetMethodDeclaringClassDescriptor(dex_file.GetMethodId(dex_method_idx)); + } else { + return ""; + } } - const char* GetDeclaringClassSourceFile() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const char* descriptor = GetDeclaringClassDescriptor(); - const DexFile& dex_file = GetDexFile(); - const DexFile::ClassDef* dex_class_def = dex_file.FindClassDef(descriptor); - CHECK(dex_class_def != NULL); - return dex_file.GetSourceFile(*dex_class_def); + const char* GetDeclaringClassSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return ClassHelper(method_->GetDeclaringClass()).GetSourceFile(); } - uint32_t GetClassDefIndex() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const char* descriptor = GetDeclaringClassDescriptor(); - const DexFile& dex_file = GetDexFile(); - uint32_t index; - CHECK(dex_file.FindClassDefIndex(descriptor, index)); - return index; + uint16_t GetClassDefIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return method_->GetDeclaringClass()->GetDexClassDefIndex(); } - mirror::ClassLoader* GetClassLoader() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile::ClassDef& GetClassDef() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetDexFile().GetClassDef(GetClassDefIndex()); + } + + mirror::ClassLoader* GetClassLoader() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return method_->GetDeclaringClass()->GetClassLoader(); } diff --git a/runtime/runtime.cc b/runtime/runtime.cc index c37b7830c8..05f4566d85 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1007,6 +1007,7 @@ void Runtime::RegisterRuntimeNativeMethods(JNIEnv* env) { REGISTER(register_dalvik_system_VMStack); REGISTER(register_dalvik_system_Zygote); REGISTER(register_java_lang_Class); + REGISTER(register_java_lang_DexCache); REGISTER(register_java_lang_Object); REGISTER(register_java_lang_Runtime); REGISTER(register_java_lang_String); @@ -1175,7 +1176,7 @@ mirror::ArtMethod* Runtime::CreateResolutionMethod() { method(self, down_cast(method_class->AllocObject(self))); method->SetDeclaringClass(method_class); // TODO: use a special method for resolution method saves - method->SetDexMethodIndex(DexFile::kDexNoIndex16); + method->SetDexMethodIndex(DexFile::kDexNoIndex); // When compiling, the code pointer will get set later when the image is loaded. Runtime* r = Runtime::Current(); ClassLinker* cl = r->GetClassLinker(); @@ -1191,7 +1192,7 @@ mirror::ArtMethod* Runtime::CreateCalleeSaveMethod(InstructionSet instruction_se method(self, down_cast(method_class->AllocObject(self))); method->SetDeclaringClass(method_class); // TODO: use a special method for callee saves - method->SetDexMethodIndex(DexFile::kDexNoIndex16); + method->SetDexMethodIndex(DexFile::kDexNoIndex); method->SetEntryPointFromCompiledCode(NULL); if ((instruction_set == kThumb2) || (instruction_set == kArm)) { uint32_t ref_spills = (1 << art::arm::R5) | (1 << art::arm::R6) | (1 << art::arm::R7) | diff --git a/runtime/thread.cc b/runtime/thread.cc index d7d4b1fa97..68370508d3 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1816,7 +1816,7 @@ class CatchBlockStackVisitor : public StackVisitor { uint32_t new_dex_pc = dex_pc + inst->SizeInCodeUnits(); ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, m, new_dex_pc); verifier::MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), - mh.GetClassDefIndex(), code_item, + &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, true); verifier.Verify(); std::vector kinds = verifier.DescribeVRegs(dex_pc); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index fa00c61017..9811926b16 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -74,50 +74,51 @@ void PcToRegisterLineTable::Init(RegisterTrackingMode mode, InstructionFlags* fl } MethodVerifier::FailureKind MethodVerifier::VerifyClass(const mirror::Class* klass, - std::string& error, - bool allow_soft_failures) { + bool allow_soft_failures, + std::string* error) { if (klass->IsVerified()) { return kNoFailure; } mirror::Class* super = klass->GetSuperClass(); if (super == NULL && StringPiece(ClassHelper(klass).GetDescriptor()) != "Ljava/lang/Object;") { - error = "Verifier rejected class "; - error += PrettyDescriptor(klass); - error += " that has no super class"; + *error = "Verifier rejected class "; + *error += PrettyDescriptor(klass); + *error += " that has no super class"; return kHardFailure; } if (super != NULL && super->IsFinal()) { - error = "Verifier rejected class "; - error += PrettyDescriptor(klass); - error += " that attempts to sub-class final class "; - error += PrettyDescriptor(super); + *error = "Verifier rejected class "; + *error += PrettyDescriptor(klass); + *error += " that attempts to sub-class final class "; + *error += PrettyDescriptor(super); return kHardFailure; } ClassHelper kh(klass); const DexFile& dex_file = kh.GetDexFile(); - uint32_t class_def_idx; - if (!dex_file.FindClassDefIndex(kh.GetDescriptor(), class_def_idx)) { - error = "Verifier rejected class "; - error += PrettyDescriptor(klass); - error += " that isn't present in dex file "; - error += dex_file.GetLocation(); + const DexFile::ClassDef* class_def = kh.GetClassDef(); + if (class_def == NULL) { + *error = "Verifier rejected class "; + *error += PrettyDescriptor(klass); + *error += " that isn't present in dex file "; + *error += dex_file.GetLocation(); return kHardFailure; } return VerifyClass(&dex_file, kh.GetDexCache(), klass->GetClassLoader(), - class_def_idx, error, - allow_soft_failures); + class_def, + allow_soft_failures, + error); } MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, mirror::DexCache* dex_cache, mirror::ClassLoader* class_loader, - uint32_t class_def_idx, - std::string& error, - bool allow_soft_failures) { - const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_idx); - const byte* class_data = dex_file->GetClassData(class_def); + const DexFile::ClassDef* class_def, + bool allow_soft_failures, + std::string* error) { + DCHECK(class_def != nullptr); + const byte* class_data = dex_file->GetClassData(*class_def); if (class_data == NULL) { // empty class, probably a marker interface return kNoFailure; @@ -139,7 +140,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, continue; } previous_direct_method_idx = method_idx; - InvokeType type = it.GetMethodInvokeType(class_def); + InvokeType type = it.GetMethodInvokeType(*class_def); mirror::ArtMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader, NULL, type); if (method == NULL) { @@ -151,7 +152,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, dex_file, dex_cache, class_loader, - class_def_idx, + class_def, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags(), @@ -160,12 +161,12 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, if (result == kHardFailure) { hard_fail = true; if (error_count > 0) { - error += "\n"; + *error += "\n"; } - error = "Verifier rejected class "; - error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - error += " due to bad method "; - error += PrettyMethod(method_idx, *dex_file); + *error = "Verifier rejected class "; + *error += PrettyDescriptor(dex_file->GetClassDescriptor(*class_def)); + *error += " due to bad method "; + *error += PrettyMethod(method_idx, *dex_file); } ++error_count; } @@ -181,7 +182,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, continue; } previous_virtual_method_idx = method_idx; - InvokeType type = it.GetMethodInvokeType(class_def); + InvokeType type = it.GetMethodInvokeType(*class_def); mirror::ArtMethod* method = linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader, NULL, type); if (method == NULL) { @@ -193,7 +194,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, dex_file, dex_cache, class_loader, - class_def_idx, + class_def, it.GetMethodCodeItem(), method, it.GetMemberAccessFlags(), @@ -202,12 +203,12 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file, if (result == kHardFailure) { hard_fail = true; if (error_count > 0) { - error += "\n"; + *error += "\n"; } - error = "Verifier rejected class "; - error += PrettyDescriptor(dex_file->GetClassDescriptor(class_def)); - error += " due to bad method "; - error += PrettyMethod(method_idx, *dex_file); + *error = "Verifier rejected class "; + *error += PrettyDescriptor(dex_file->GetClassDescriptor(*class_def)); + *error += " due to bad method "; + *error += PrettyMethod(method_idx, *dex_file); } ++error_count; } @@ -224,7 +225,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, const DexFile* dex_file, mirror::DexCache* dex_cache, mirror::ClassLoader* class_loader, - uint32_t class_def_idx, + const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags, @@ -232,7 +233,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, MethodVerifier::FailureKind result = kNoFailure; uint64_t start_ns = NanoTime(); - MethodVerifier verifier_(dex_file, dex_cache, class_loader, class_def_idx, code_item, method_idx, + MethodVerifier verifier_(dex_file, dex_cache, class_loader, class_def, code_item, method_idx, method, method_access_flags, true, allow_soft_failures); if (verifier_.Verify()) { // Verification completed, however failures may be pending that didn't cause the verification @@ -267,11 +268,12 @@ MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx, void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_idx, const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, + mirror::ClassLoader* class_loader, + const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags) { - MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item, + MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def, code_item, dex_method_idx, method, method_access_flags, true, true); verifier.Verify(); verifier.DumpFailures(os); @@ -280,7 +282,8 @@ void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_i } MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, + mirror::ClassLoader* class_loader, + const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, uint32_t dex_method_idx, mirror::ArtMethod* method, uint32_t method_access_flags, bool can_load_classes, @@ -293,7 +296,7 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_ca dex_file_(dex_file), dex_cache_(dex_cache), class_loader_(class_loader), - class_def_idx_(class_def_idx), + class_def_(class_def), code_item_(code_item), declaring_class_(NULL), interesting_dex_pc_(-1), @@ -306,13 +309,14 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_ca allow_soft_failures_(allow_soft_failures), has_check_casts_(false), has_virtual_or_interface_invokes_(false) { + DCHECK(class_def != NULL); } void MethodVerifier::FindLocksAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc, std::vector& monitor_enter_dex_pcs) { MethodHelper mh(m); MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), - mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(), + &mh.GetClassDef(), mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, true); verifier.interesting_dex_pc_ = dex_pc; verifier.monitor_enter_dex_pcs_ = &monitor_enter_dex_pcs; @@ -334,7 +338,7 @@ mirror::ArtField* MethodVerifier::FindAccessedFieldAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc) { MethodHelper mh(m); MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), - mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(), + &mh.GetClassDef(), mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, true); return verifier.FindAccessedFieldAtDexPc(dex_pc); } @@ -362,7 +366,7 @@ mirror::ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(mirror::ArtMethod* m uint32_t dex_pc) { MethodHelper mh(m); MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(), - mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(), + &mh.GetClassDef(), mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false, true); return verifier.FindInvokedMethodAtDexPc(dex_pc); } @@ -448,7 +452,7 @@ std::ostream& MethodVerifier::Fail(VerifyError error) { // marked as rejected to prevent it from being compiled. case VERIFY_ERROR_BAD_CLASS_HARD: { if (Runtime::Current()->IsCompiler()) { - ClassReference ref(dex_file_, class_def_idx_); + ClassReference ref(dex_file_, dex_file_->GetIndexForClassDef(*class_def_)); AddRejectedClass(ref); } have_pending_hard_failure_ = true; diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 70442fbc04..073a2f76be 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -145,17 +145,19 @@ class MethodVerifier { }; /* Verify a class. Returns "kNoFailure" on success. */ - static FailureKind VerifyClass(const mirror::Class* klass, std::string& error, - bool allow_soft_failures) + static FailureKind VerifyClass(const mirror::Class* klass, bool allow_soft_failures, + std::string* error) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static FailureKind VerifyClass(const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, - std::string& error, bool allow_soft_failures) + mirror::ClassLoader* class_loader, + const DexFile::ClassDef* class_def, + bool allow_soft_failures, std::string* error) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static void VerifyMethodAndDump(std::ostream& os, uint32_t method_idx, const DexFile* dex_file, mirror::DexCache* dex_cache, mirror::ClassLoader* class_loader, - uint32_t class_def_idx, const DexFile::CodeItem* code_item, + const DexFile::ClassDef* class_def, + const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -222,7 +224,7 @@ class MethodVerifier { } MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, + mirror::ClassLoader* class_loader, const DexFile::ClassDef* class_def, const DexFile::CodeItem* code_item, uint32_t method_idx, mirror::ArtMethod* method, uint32_t access_flags, bool can_load_classes, bool allow_soft_failures) @@ -262,7 +264,8 @@ class MethodVerifier { */ static FailureKind VerifyMethod(uint32_t method_idx, const DexFile* dex_file, mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, uint32_t class_def_idx, + mirror::ClassLoader* class_loader, + const DexFile::ClassDef* class_def_idx, const DexFile::CodeItem* code_item, mirror::ArtMethod* method, uint32_t method_access_flags, bool allow_soft_failures) @@ -690,7 +693,7 @@ class MethodVerifier { mirror::DexCache* dex_cache_ GUARDED_BY(Locks::mutator_lock_); // The class loader for the declaring class of the method. mirror::ClassLoader* class_loader_ GUARDED_BY(Locks::mutator_lock_); - const uint32_t class_def_idx_; // The class def index of the declaring class of the method. + const DexFile::ClassDef* const class_def_; // The class def of the declaring class of the method. const DexFile::CodeItem* const code_item_; // The code item containing the code for the method. const RegType* declaring_class_; // Lazily computed reg type of the method's declaring class. // Instruction widths and flags, one entry per code unit. diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc index 611b7c06eb..a56abba3cf 100644 --- a/runtime/verifier/method_verifier_test.cc +++ b/runtime/verifier/method_verifier_test.cc @@ -34,7 +34,8 @@ class MethodVerifierTest : public CommonTest { // Verify the class std::string error_msg; - ASSERT_TRUE(MethodVerifier::VerifyClass(klass, error_msg, true) == MethodVerifier::kNoFailure) << error_msg; + ASSERT_TRUE(MethodVerifier::VerifyClass(klass, true, &error_msg) == MethodVerifier::kNoFailure) + << error_msg; } void VerifyDexFile(const DexFile* dex) diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt index 3d87ebc559..967f167f37 100644 --- a/test/100-reflect2/expected.txt +++ b/test/100-reflect2/expected.txt @@ -35,7 +35,7 @@ z (class java.lang.Character) 62 (class java.lang.Long) 14 (class java.lang.Short) [public java.lang.String(), java.lang.String(int,int,char[]), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int)] -[private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final char java.lang.String.REPLACEMENT_CHAR, private static final long java.lang.String.serialVersionUID] +[private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final long java.lang.String.serialVersionUID, private static final char java.lang.String.REPLACEMENT_CHAR] [void java.lang.String._getChars(int,int,char[],int), public char java.lang.String.charAt(int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public volatile int java.lang.String.compareTo(java.lang.Object), public native int java.lang.String.compareTo(java.lang.String), public int java.lang.String.compareToIgnoreCase(java.lang.String), public java.lang.String java.lang.String.concat(java.lang.String), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public void java.lang.String.getBytes(int,int,byte[],int), public [B java.lang.String.getBytes(), public [B java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public [B java.lang.String.getBytes(java.nio.charset.Charset), public void java.lang.String.getChars(int,int,char[],int), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public native java.lang.String java.lang.String.intern(), public boolean java.lang.String.isEmpty(), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public boolean java.lang.String.matches(java.lang.String), public int java.lang.String.offsetByCodePoints(int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public [C java.lang.String.toCharArray(), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.failedBoundsCheck(int,int,int), private native int java.lang.String.fastIndexOf(int,int), private char java.lang.String.foldCase(char), public static transient java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static transient java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), private java.lang.StringIndexOutOfBoundsException java.lang.String.indexAndLength(int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int,int,char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.startEndAndLength(int,int), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(long), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int)] [] [interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence] -- cgit v1.2.3-59-g8ed1b From fc0e94bed3f88ed7e50854fd8dfaf5dcb345250f Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 23 Sep 2013 23:51:32 -0700 Subject: StringPiece clean up. Profile guided clean up. Try to avoid creating StringPieces with the contents of a dex file where the length is known. Try to avoid RegTypeCache::FromDescriptor when there's a class available. Make ConstantType::ConstantValue inlinable. Saving of about 50ms from a 2 threaded ThinkFree compile on host. Change-Id: I47a12c3c76f46e2c9805be1c3a3e3870fe1f5d85 --- compiler/dex/quick/gen_invoke.cc | 4 +- compiler/driver/compiler_driver.cc | 27 +++--- compiler/driver/compiler_driver.h | 2 +- compiler/image_writer.cc | 4 +- oatdump/oatdump.cc | 2 +- runtime/class_linker.cc | 107 ++++++++++++----------- runtime/debugger.cc | 13 +-- runtime/debugger.h | 2 +- runtime/dex_file-inl.h | 11 +++ runtime/dex_file.h | 3 + runtime/gc/heap.cc | 2 +- runtime/interpreter/interpreter.cc | 2 +- runtime/jdwp/jdwp_handler.cc | 4 +- runtime/mirror/class.cc | 14 +-- runtime/object_utils.h | 167 ++++++++++++++++++++++++++++-------- runtime/reflection.cc | 4 +- runtime/verifier/method_verifier.cc | 155 +++++++++++++++++++++------------ runtime/verifier/method_verifier.h | 1 + runtime/verifier/reg_type.cc | 5 -- runtime/verifier/reg_type.h | 9 +- runtime/verifier/reg_type_cache.cc | 1 + 21 files changed, 350 insertions(+), 189 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 72ae91eebb..ed83863733 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -1219,8 +1219,10 @@ bool Mir2Lir::GenIntrinsic(CallInfo* info) { * method. By doing this during basic block construction, we can also * take advantage of/generate new useful dataflow info. */ + const DexFile::MethodId& target_mid = cu_->dex_file->GetMethodId(info->index); + const DexFile::TypeId& declaring_type = cu_->dex_file->GetTypeId(target_mid.class_idx_); StringPiece tgt_methods_declaring_class( - cu_->dex_file->GetMethodDeclaringClassDescriptor(cu_->dex_file->GetMethodId(info->index))); + cu_->dex_file->StringDataAsStringPieceByIdx(declaring_type.descriptor_idx_)); if (tgt_methods_declaring_class.starts_with("Ljava/lang/Double;")) { std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file)); if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") { diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index c12a7d964a..e227715605 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -600,12 +600,11 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vectorfind(descriptor) != image_classes_->end(); + return image_classes_->find(descriptor.data()) != image_classes_->end(); } } @@ -780,7 +779,8 @@ void CompilerDriver::UpdateImageClasses(base::TimingLogger& timings) { bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file, uint32_t type_idx) { - if (IsImage() && IsImageClass(dex_file.GetTypeDescriptor(dex_file.GetTypeId(type_idx)))) { + if (IsImage() && + IsImageClass(dex_file.StringDataAsStringPieceByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_))) { if (kIsDebugBuild) { ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file); @@ -1098,7 +1098,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s if (compiling_boot) { if (support_boot_image_fixup_) { MethodHelper mh(method); - if (IsImageClass(mh.GetDeclaringClassDescriptor())) { + if (IsImageClass(mh.GetDeclaringClassDescriptorAsStringPiece())) { // We can only branch directly to Methods that are resolved in the DexCache. // Otherwise we won't invoke the resolution trampoline. *direct_method = -1; @@ -1572,8 +1572,8 @@ static void ResolveType(const ParallelCompilationManager* manager, size_t type_i CHECK(soa.Self()->IsExceptionPending()); mirror::Throwable* exception = soa.Self()->GetException(NULL); VLOG(compiler) << "Exception during type resolution: " << exception->Dump(); - if (strcmp(ClassHelper(exception->GetClass()).GetDescriptor(), - "Ljava/lang/OutOfMemoryError;") == 0) { + if (ClassHelper(exception->GetClass()).GetDescriptorAsStringPiece() == + "Ljava/lang/OutOfMemoryError;") { // There's little point continuing compilation if the heap is exhausted. LOG(FATAL) << "Out of memory during type resolution for compilation"; } @@ -2084,11 +2084,14 @@ static const char* class_initializer_black_list[] = { static void InitializeClass(const ParallelCompilationManager* manager, size_t class_def_index) LOCKS_EXCLUDED(Locks::mutator_lock_) { ATRACE_CALL(); - const DexFile::ClassDef& class_def = manager->GetDexFile()->GetClassDef(class_def_index); + const DexFile* dex_file = manager->GetDexFile(); + const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); + const DexFile::TypeId& class_type_id = dex_file->GetTypeId(class_def.class_idx_); + StringPiece descriptor(dex_file->StringDataAsStringPieceByIdx(class_type_id.descriptor_idx_)); + ScopedObjectAccess soa(Thread::Current()); mirror::ClassLoader* class_loader = soa.Decode(manager->GetClassLoader()); - const char* descriptor = manager->GetDexFile()->GetClassDescriptor(class_def); - mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader); + mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor.data(), class_loader); if (klass != NULL) { // Only try to initialize classes that were successfully verified. if (klass->IsVerified()) { @@ -2118,7 +2121,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl bool is_black_listed = StringPiece(descriptor).ends_with("$NoPreloadHolder;"); if (!is_black_listed) { for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) { - if (StringPiece(descriptor) == class_initializer_black_list[i]) { + if (descriptor == class_initializer_black_list[i]) { is_black_listed = true; break; } @@ -2126,7 +2129,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl } if (!is_black_listed) { VLOG(compiler) << "Initializing: " << descriptor; - if (StringPiece(descriptor) == "Ljava/lang/Void;") { + if (descriptor == "Ljava/lang/Void;") { // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime. ObjectLock lock(soa.Self(), klass); mirror::ObjectArray* fields = klass->GetSFields(); diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 66c9cbf91a..7657af5cee 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -309,7 +309,7 @@ class CompilerDriver { } // Checks if class specified by type_idx is one of the image_classes_ - bool IsImageClass(const char* descriptor) const; + bool IsImageClass(const StringPiece& descriptor) const; void RecordClassStatus(ClassReference ref, mirror::Class::Status status) LOCKS_EXCLUDED(compiled_classes_lock_); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index f82c6fb40f..bcdc1c15c9 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -241,7 +241,7 @@ void ImageWriter::ComputeEagerResolvedStrings() } bool ImageWriter::IsImageClass(const Class* klass) { - return compiler_driver_.IsImageClass(ClassHelper(klass).GetDescriptor()); + return compiler_driver_.IsImageClass(ClassHelper(klass).GetDescriptorAsStringPiece()); } struct NonImageClasses { @@ -296,7 +296,7 @@ void ImageWriter::PruneNonImageClasses() { bool ImageWriter::NonImageClassesVisitor(Class* klass, void* arg) { NonImageClasses* context = reinterpret_cast(arg); if (!context->image_writer->IsImageClass(klass)) { - context->non_image_classes->insert(ClassHelper(klass).GetDescriptor()); + context->non_image_classes->insert(ClassHelper(klass).GetDescriptorAsStringPiece().as_string()); } return true; } diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index fc9e00c2cb..cc6b5d7866 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1119,7 +1119,7 @@ class ImageDumper { typedef SafeMap SizeAndCountTable; SizeAndCountTable sizes_and_counts; - void Update(const std::string& descriptor, size_t object_bytes) { + void Update(const char* descriptor, size_t object_bytes) { SizeAndCountTable::iterator it = sizes_and_counts.find(descriptor); if (it != sizes_and_counts.end()) { it->second.bytes += object_bytes; diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 91db8835a8..6aae63ee2c 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1840,7 +1840,7 @@ mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file SirtRef& klass) { uint32_t dex_method_idx = it.GetMemberIndex(); const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); - StringPiece method_name(dex_file.GetMethodName(method_id)); + StringPiece method_name(dex_file.StringDataAsStringPieceByIdx(method_id.name_idx_)); mirror::ArtMethod* dst = AllocArtMethod(self); if (UNLIKELY(dst == NULL)) { @@ -1869,7 +1869,7 @@ mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file klass->SetFinalizable(); } else { ClassHelper kh(klass.get()); - StringPiece klass_descriptor(kh.GetDescriptor()); + StringPiece klass_descriptor(kh.GetDescriptorAsStringPiece()); // The Enum class declares a "final" finalize() method to prevent subclasses from // introducing a finalizer. We don't want to set the finalizable flag for Enum or its // subclasses, so we exclude it here. @@ -2219,7 +2219,7 @@ bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* ++it) { mirror::Class* klass = it->second; kh.ChangeClass(klass); - if (strcmp(kh.GetDescriptor(), descriptor) == 0 && klass->GetClassLoader() == class_loader) { + if (kh.GetDescriptorAsStringPiece() == descriptor && klass->GetClassLoader() == class_loader) { class_table_.erase(it); return true; } @@ -2265,15 +2265,16 @@ mirror::Class* ClassLinker::LookupClassFromTableLocked(const char* descriptor, for (auto it = class_table_.lower_bound(hash); it != end && it->first == hash; ++it) { mirror::Class* klass = it->second; kh.ChangeClass(klass); - if (klass->GetClassLoader() == class_loader && strcmp(descriptor, kh.GetDescriptor()) == 0) { + if (klass->GetClassLoader() == class_loader && kh.GetDescriptorAsStringPiece() == descriptor) { if (kIsDebugBuild) { // Check for duplicates in the table. for (++it; it != end && it->first == hash; ++it) { mirror::Class* klass2 = it->second; kh.ChangeClass(klass2); - CHECK(!(strcmp(descriptor, kh.GetDescriptor()) == 0 && klass2->GetClassLoader() == class_loader)) - << PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " " - << PrettyClass(klass2) << " " << klass2 << " " << klass2->GetClassLoader(); + CHECK(!(kh.GetDescriptorAsStringPiece() == descriptor && + klass2->GetClassLoader() == class_loader)) + << PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " " + << PrettyClass(klass2) << " " << klass2 << " " << klass2->GetClassLoader(); } } return klass; @@ -2379,7 +2380,7 @@ void ClassLinker::LookupClasses(const char* descriptor, std::vectorfirst == hash; ++it) { mirror::Class* klass = it->second; kh.ChangeClass(klass); - if (strcmp(descriptor, kh.GetDescriptor()) == 0) { + if (kh.GetDescriptorAsStringPiece() == descriptor) { result.push_back(klass); } } @@ -2538,11 +2539,11 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass); const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation()); CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass); - const char* descriptor = ClassHelper(klass).GetDescriptor(); uint16_t class_def_index = klass->GetDexClassDefIndex(); UniquePtr oat_class(oat_dex_file->GetOatClass(class_def_index)); CHECK(oat_class.get() != NULL) - << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor; + << dex_file.GetLocation() << " " << PrettyClass(klass) << " " + << ClassHelper(klass).GetDescriptor(); oat_file_class_status = oat_class->GetStatus(); if (oat_file_class_status == mirror::Class::kStatusVerified || oat_file_class_status == mirror::Class::kStatusInitialized) { @@ -2581,7 +2582,8 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class return false; } LOG(FATAL) << "Unexpected class status: " << oat_file_class_status - << " " << dex_file.GetLocation() << " " << PrettyClass(klass) << " " << descriptor; + << " " << dex_file.GetLocation() << " " << PrettyClass(klass) << " " + << ClassHelper(klass).GetDescriptor(); return false; } @@ -3727,10 +3729,10 @@ struct LinkFieldsComparator { // same basic group? then sort by string. fh_->ChangeField(field1); - StringPiece name1(fh_->GetName()); + const char* name1 = fh_->GetName(); fh_->ChangeField(field2); - StringPiece name2(fh_->GetName()); - return name1 < name2; + const char* name2 = fh_->GetName(); + return strcmp(name1, name2) < 0; } FieldHelper* fh_; @@ -3764,7 +3766,9 @@ bool ClassLinker::LinkFields(SirtRef& klass, bool is_static) { // minimizes disruption of C++ version such as Class and Method. std::deque grouped_and_sorted_fields; for (size_t i = 0; i < num_fields; i++) { - grouped_and_sorted_fields.push_back(fields->Get(i)); + mirror::ArtField* f = fields->Get(i); + CHECK(f != NULL); + grouped_and_sorted_fields.push_back(f); } FieldHelper fh(NULL, this); std::sort(grouped_and_sorted_fields.begin(), @@ -3831,7 +3835,7 @@ bool ClassLinker::LinkFields(SirtRef& klass, bool is_static) { // We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it. if (!is_static && - StringPiece(ClassHelper(klass.get(), this).GetDescriptor()) == "Ljava/lang/ref/Reference;") { + (ClassHelper(klass.get(), this).GetDescriptorAsStringPiece() == "Ljava/lang/ref/Reference;")) { // We know there are no non-reference fields in the Reference classes, and we know // that 'referent' is alphabetically last, so this is easy... CHECK_EQ(num_reference_fields, num_fields); @@ -3840,39 +3844,39 @@ bool ClassLinker::LinkFields(SirtRef& klass, bool is_static) { --num_reference_fields; } -#ifndef NDEBUG - // Make sure that all reference fields appear before - // non-reference fields, and all double-wide fields are aligned. - bool seen_non_ref = false; - for (size_t i = 0; i < num_fields; i++) { - mirror::ArtField* field = fields->Get(i); - if (false) { // enable to debug field layout - LOG(INFO) << "LinkFields: " << (is_static ? "static" : "instance") - << " class=" << PrettyClass(klass.get()) - << " field=" << PrettyField(field) - << " offset=" << field->GetField32(MemberOffset(mirror::ArtField::OffsetOffset()), - false); - } - fh.ChangeField(field); - Primitive::Type type = fh.GetTypeAsPrimitiveType(); - bool is_primitive = type != Primitive::kPrimNot; - if (StringPiece(ClassHelper(klass.get(), this).GetDescriptor()) == "Ljava/lang/ref/Reference;" && - StringPiece(fh.GetName()) == "referent") { - is_primitive = true; // We lied above, so we have to expect a lie here. - } - if (is_primitive) { - if (!seen_non_ref) { - seen_non_ref = true; - DCHECK_EQ(num_reference_fields, i); + if (kIsDebugBuild) { + // Make sure that all reference fields appear before + // non-reference fields, and all double-wide fields are aligned. + bool seen_non_ref = false; + for (size_t i = 0; i < num_fields; i++) { + mirror::ArtField* field = fields->Get(i); + if (false) { // enable to debug field layout + LOG(INFO) << "LinkFields: " << (is_static ? "static" : "instance") + << " class=" << PrettyClass(klass.get()) + << " field=" << PrettyField(field) + << " offset=" << field->GetField32(MemberOffset(mirror::ArtField::OffsetOffset()), + false); + } + fh.ChangeField(field); + Primitive::Type type = fh.GetTypeAsPrimitiveType(); + bool is_primitive = type != Primitive::kPrimNot; + if (ClassHelper(klass.get(), this).GetDescriptorAsStringPiece() == "Ljava/lang/ref/Reference;" && + fh.GetNameAsStringPiece() == "referent") { + is_primitive = true; // We lied above, so we have to expect a lie here. + } + if (is_primitive) { + if (!seen_non_ref) { + seen_non_ref = true; + DCHECK_EQ(num_reference_fields, i); + } + } else { + DCHECK(!seen_non_ref); } - } else { - DCHECK(!seen_non_ref); + } + if (!seen_non_ref) { + DCHECK_EQ(num_fields, num_reference_fields); } } - if (!seen_non_ref) { - DCHECK_EQ(num_fields, num_reference_fields); - } -#endif size = field_offset.Uint32Value(); // Update klass if (is_static) { @@ -4175,9 +4179,9 @@ mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, } mirror::ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, - uint32_t field_idx, - mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader) { + uint32_t field_idx, + mirror::DexCache* dex_cache, + mirror::ClassLoader* class_loader) { DCHECK(dex_cache != NULL); mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx); if (resolved != NULL) { @@ -4190,8 +4194,9 @@ mirror::ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, return NULL; } - const char* name = dex_file.GetFieldName(field_id); - const char* type = dex_file.GetFieldTypeDescriptor(field_id); + StringPiece name(dex_file.StringDataAsStringPieceByIdx(field_id.name_idx_)); + StringPiece type(dex_file.StringDataAsStringPieceByIdx( + dex_file.GetTypeId(field_id.type_idx_).descriptor_idx_)); resolved = klass->FindField(name, type); if (resolved != NULL) { dex_cache->SetResolvedField(field_idx, resolved); diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 88269e5578..2eca734457 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -891,7 +891,7 @@ JDWP::JdwpError Dbg::GetClassInfo(JDWP::RefTypeId class_id, JDWP::JdwpTypeTag* p } if (pDescriptor != NULL) { - *pDescriptor = ClassHelper(c).GetDescriptor(); + *pDescriptor = ClassHelper(c).GetDescriptorAsStringPiece().as_string(); } return JDWP::ERR_NONE; } @@ -928,13 +928,13 @@ JDWP::JdwpError Dbg::GetReferenceType(JDWP::ObjectId object_id, JDWP::ExpandBuf* return JDWP::ERR_NONE; } -JDWP::JdwpError Dbg::GetSignature(JDWP::RefTypeId class_id, std::string& signature) { +JDWP::JdwpError Dbg::GetSignature(JDWP::RefTypeId class_id, std::string* signature) { JDWP::JdwpError status; mirror::Class* c = DecodeClass(class_id, status); if (c == NULL) { return status; } - signature = ClassHelper(c).GetDescriptor(); + *signature = ClassHelper(c).GetDescriptorAsStringPiece().as_string(); return JDWP::ERR_NONE; } @@ -1065,8 +1065,8 @@ JDWP::JdwpError Dbg::SetArrayElements(JDWP::ObjectId array_id, int offset, int c LOG(WARNING) << __FUNCTION__ << " access out of bounds: offset=" << offset << "; count=" << count; return JDWP::ERR_INVALID_LENGTH; } - std::string descriptor(ClassHelper(dst->GetClass()).GetDescriptor()); - JDWP::JdwpTag tag = BasicTagFromDescriptor(descriptor.c_str() + 1); + const char* descriptor = ClassHelper(dst->GetClass()).GetDescriptor(); + JDWP::JdwpTag tag = BasicTagFromDescriptor(descriptor + 1); if (IsPrimitiveTag(tag)) { size_t width = GetTagWidth(tag); @@ -2287,7 +2287,8 @@ void Dbg::PostClassPrepare(mirror::Class* c) { // since the class may not yet be verified. int state = JDWP::CS_VERIFIED | JDWP::CS_PREPARED; JDWP::JdwpTypeTag tag = c->IsInterface() ? JDWP::TT_INTERFACE : JDWP::TT_CLASS; - gJdwpState->PostClassPrepare(tag, gRegistry->Add(c), ClassHelper(c).GetDescriptor(), state); + gJdwpState->PostClassPrepare(tag, gRegistry->Add(c), + ClassHelper(c).GetDescriptorAsStringPiece().as_string(), state); } void Dbg::UpdateDebugger(Thread* thread, mirror::Object* this_object, diff --git a/runtime/debugger.h b/runtime/debugger.h index d0fe445df1..8574a3308f 100644 --- a/runtime/debugger.h +++ b/runtime/debugger.h @@ -149,7 +149,7 @@ class Dbg { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static JDWP::JdwpError GetReferenceType(JDWP::ObjectId object_id, JDWP::ExpandBuf* pReply) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - static JDWP::JdwpError GetSignature(JDWP::RefTypeId ref_type_id, std::string& signature) + static JDWP::JdwpError GetSignature(JDWP::RefTypeId ref_type_id, std::string* signature) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static JDWP::JdwpError GetSourceFile(JDWP::RefTypeId ref_type_id, std::string& source_file) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h index dee80269d6..2ee9244bf2 100644 --- a/runtime/dex_file-inl.h +++ b/runtime/dex_file-inl.h @@ -18,6 +18,7 @@ #define ART_RUNTIME_DEX_FILE_INL_H_ #include "base/logging.h" +#include "base/stringpiece.h" #include "dex_file.h" #include "leb128.h" #include "utils.h" @@ -36,6 +37,16 @@ inline const char* DexFile::GetStringDataAndLength(const StringId& string_id, ui return reinterpret_cast(ptr); } +inline StringPiece DexFile::StringDataAsStringPieceByIdx(uint32_t idx) const { + if (idx == kDexNoIndex) { + return StringPiece(); + } + const StringId& string_id = GetStringId(idx); + uint32_t length; + const char* data = GetStringDataAndLength(string_id, &length); + return StringPiece(data, static_cast(length)); +} + inline const DexFile::TryItem* DexFile::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 diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 7be5cb848f..4534b41e92 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -40,6 +40,7 @@ namespace mirror { class DexCache; } // namespace mirror class ClassLinker; +class StringPiece; class ZipArchive; // TODO: move all of the macro functionality into the DexCache class. @@ -432,6 +433,8 @@ class DexFile { return GetStringDataAndLength(string_id, unicode_length); } + StringPiece StringDataAsStringPieceByIdx(uint32_t idx) const; + const char* StringDataByIdx(uint32_t idx) const { uint32_t unicode_length; return StringDataAndLengthByIdx(idx, &unicode_length); diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index ccd9aaca81..2ad6117d75 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -557,7 +557,7 @@ static void MSpaceChunkCallback(void* start, void* end, size_t used_bytes, void* mirror::Object* Heap::AllocObject(Thread* self, mirror::Class* c, size_t byte_count) { DCHECK(c == NULL || (c->IsClassClass() && byte_count >= sizeof(mirror::Class)) || (c->IsVariableSize() || c->GetObjectSize() == byte_count) || - strlen(ClassHelper(c).GetDescriptor()) == 0); + ClassHelper(c).GetDescriptorAsStringPiece().length() == 0); DCHECK_GE(byte_count, sizeof(mirror::Object)); mirror::Object* obj = NULL; diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index f35cfa3bca..fd92e06fb3 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -82,7 +82,7 @@ static void UnstartedRuntimeJni(Thread* self, ArtMethod* method, } } -static void InterpreterJni(Thread* self, ArtMethod* method, StringPiece shorty, +static void InterpreterJni(Thread* self, ArtMethod* method, const StringPiece& shorty, Object* receiver, uint32_t* args, JValue* result) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { // TODO: The following enters JNI code using a typedef-ed function rather than the JNI compiler, diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc index a2efc48c84..523d89278a 100644 --- a/runtime/jdwp/jdwp_handler.cc +++ b/runtime/jdwp/jdwp_handler.cc @@ -47,7 +47,7 @@ std::string DescribeMethod(const MethodId& method_id) { std::string DescribeRefTypeId(const RefTypeId& ref_type_id) { std::string signature("unknown"); - Dbg::GetSignature(ref_type_id, signature); + Dbg::GetSignature(ref_type_id, &signature); return StringPrintf("%#llx (%s)", ref_type_id, signature.c_str()); } @@ -547,7 +547,7 @@ static JdwpError RT_Signature(JdwpState*, Request& request, ExpandBuf* pReply, b RefTypeId refTypeId = request.ReadRefTypeId(); std::string signature; - JdwpError status = Dbg::GetSignature(refTypeId, signature); + JdwpError status = Dbg::GetSignature(refTypeId, &signature); if (status != ERR_NONE) { return status; } diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index c128eded0a..287e8b0959 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -135,7 +135,7 @@ String* Class::ComputeName() { if (name != NULL) { return name; } - std::string descriptor(ClassHelper(this).GetDescriptor()); + std::string descriptor(ClassHelper(this).GetDescriptorAsStringPiece().as_string()); if ((descriptor[0] != 'L') && (descriptor[0] != '[')) { // The descriptor indicates that this is the class for // a primitive type; special-case the return value. @@ -294,8 +294,8 @@ bool Class::IsInSamePackage(const Class* that) const { return true; } // Compare the package part of the descriptor string. - return IsInSamePackage(ClassHelper(klass1).GetDescriptor(), - ClassHelper(klass2).GetDescriptor()); + return IsInSamePackage(ClassHelper(klass1).GetDescriptorAsStringPiece(), + ClassHelper(klass2).GetDescriptorAsStringPiece()); } bool Class::IsClassClass() const { @@ -367,7 +367,7 @@ ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const String for (size_t i = 0; i < NumDirectMethods(); ++i) { ArtMethod* method = GetDirectMethod(i); mh.ChangeMethod(method); - if (name == mh.GetName() && signature == mh.GetSignature()) { + if (name == mh.GetNameAsStringPiece() && signature == mh.GetSignature()) { return method; } } @@ -412,7 +412,7 @@ ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, for (size_t i = 0; i < NumVirtualMethods(); ++i) { ArtMethod* method = GetVirtualMethod(i); mh.ChangeMethod(method); - if (name == mh.GetName() && signature == mh.GetSignature()) { + if (name == mh.GetNameAsStringPiece() && signature == mh.GetSignature()) { return method; } } @@ -458,7 +458,7 @@ ArtField* Class::FindDeclaredInstanceField(const StringPiece& name, const String for (size_t i = 0; i < NumInstanceFields(); ++i) { ArtField* f = GetInstanceField(i); fh.ChangeField(f); - if (name == fh.GetName() && type == fh.GetTypeDescriptor()) { + if (name == fh.GetNameAsStringPiece() && type == fh.GetTypeDescriptorAsStringPiece()) { return f; } } @@ -507,7 +507,7 @@ ArtField* Class::FindDeclaredStaticField(const StringPiece& name, const StringPi for (size_t i = 0; i < NumStaticFields(); ++i) { ArtField* f = GetStaticField(i); fh.ChangeField(f); - if (name == fh.GetName() && type == fh.GetTypeDescriptor()) { + if (name == fh.GetNameAsStringPiece() && type == fh.GetTypeDescriptorAsStringPiece()) { return f; } } diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 6ee3016179..9e107a46d5 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -111,6 +111,17 @@ class ClassHelper { } } + StringPiece GetDescriptorAsStringPiece() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + CHECK(klass_ != NULL); + if (UNLIKELY(klass_->IsArrayClass() || klass_->IsPrimitive() || klass_->IsProxyClass())) { + return StringPiece(GetDescriptor()); + } else { + const DexFile& dex_file = GetDexFile(); + const DexFile::TypeId& type_id = dex_file.GetTypeId(GetClassDef()->class_idx_); + return dex_file.StringDataAsStringPieceByIdx(type_id.descriptor_idx_); + } + } + const char* GetArrayDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { std::string result("["); const mirror::Class* saved_klass = klass_; @@ -182,7 +193,7 @@ class ClassHelper { } const char* GetSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - std::string descriptor(GetDescriptor()); + std::string descriptor(GetDescriptorAsStringPiece().as_string()); const DexFile& dex_file = GetDexFile(); const DexFile::ClassDef* dex_class_def = GetClassDef(); CHECK(dex_class_def != NULL); @@ -267,53 +278,77 @@ class FieldHelper { } field_ = new_f; } + const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { uint32_t field_index = field_->GetDexFieldIndex(); - if (!field_->GetDeclaringClass()->IsProxyClass()) { - const DexFile& dex_file = GetDexFile(); - return dex_file.GetFieldName(dex_file.GetFieldId(field_index)); - } else { + if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { DCHECK(field_->IsStatic()); DCHECK_LT(field_index, 2U); return field_index == 0 ? "interfaces" : "throws"; } + const DexFile& dex_file = GetDexFile(); + return dex_file.GetFieldName(dex_file.GetFieldId(field_index)); } + + StringPiece GetNameAsStringPiece() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + uint32_t field_index = field_->GetDexFieldIndex(); + if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { + return StringPiece(GetName()); + } + const DexFile& dex_file = GetDexFile(); + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); + return dex_file.StringDataAsStringPieceByIdx(field_id.name_idx_); + } + mirror::Class* GetType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { uint32_t field_index = field_->GetDexFieldIndex(); - if (!field_->GetDeclaringClass()->IsProxyClass()) { - const DexFile& dex_file = GetDexFile(); - const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); - mirror::Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_); - if (resolve && (type == NULL)) { - type = GetClassLinker()->ResolveType(field_id.type_idx_, field_); - CHECK(type != NULL || Thread::Current()->IsExceptionPending()); - } - return type; - } else { + if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { return GetClassLinker()->FindSystemClass(GetTypeDescriptor()); } + const DexFile& dex_file = GetDexFile(); + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); + mirror::Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_); + if (resolve && (type == NULL)) { + type = GetClassLinker()->ResolveType(field_id.type_idx_, field_); + CHECK(type != NULL || Thread::Current()->IsExceptionPending()); + } + return type; } + const char* GetTypeDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { uint32_t field_index = field_->GetDexFieldIndex(); - if (!field_->GetDeclaringClass()->IsProxyClass()) { - const DexFile& dex_file = GetDexFile(); - const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); - return dex_file.GetFieldTypeDescriptor(field_id); - } else { + if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { DCHECK(field_->IsStatic()); DCHECK_LT(field_index, 2U); // 0 == Class[] interfaces; 1 == Class[][] throws; return field_index == 0 ? "[Ljava/lang/Class;" : "[[Ljava/lang/Class;"; } + const DexFile& dex_file = GetDexFile(); + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); + return dex_file.GetFieldTypeDescriptor(field_id); + } + + StringPiece GetTypeDescriptorAsStringPiece() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + uint32_t field_index = field_->GetDexFieldIndex(); + if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { + return StringPiece(GetTypeDescriptor()); + } + const DexFile& dex_file = GetDexFile(); + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); + const DexFile::TypeId& type_id = dex_file.GetTypeId(field_id.type_idx_); + return dex_file.StringDataAsStringPieceByIdx(type_id.descriptor_idx_); } + Primitive::Type GetTypeAsPrimitiveType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return Primitive::GetType(GetTypeDescriptor()[0]); } + bool IsPrimitiveType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Primitive::Type type = GetTypeAsPrimitiveType(); return type != Primitive::kPrimNot; } + size_t FieldSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Primitive::Type type = GetTypeAsPrimitiveType(); return Primitive::FieldSize(type); @@ -324,18 +359,17 @@ class FieldHelper { const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { uint32_t field_index = field_->GetDexFieldIndex(); - if (!field_->GetDeclaringClass()->IsProxyClass()) { - const DexFile& dex_file = GetDexFile(); - const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); - return dex_file.GetFieldDeclaringClassDescriptor(field_id); - } else { + if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { DCHECK(field_->IsStatic()); DCHECK_LT(field_index, 2U); // 0 == Class[] interfaces; 1 == Class[][] throws; ClassHelper kh(field_->GetDeclaringClass()); - declaring_class_descriptor_ = kh.GetDescriptor(); + declaring_class_descriptor_ = kh.GetDescriptorAsStringPiece().as_string(); return declaring_class_descriptor_.c_str(); } + const DexFile& dex_file = GetDexFile(); + const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); + return dex_file.GetFieldDeclaringClassDescriptor(field_id); } private: @@ -417,7 +451,7 @@ class MethodHelper { const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); uint32_t dex_method_idx = method_->GetDexMethodIndex(); - if (dex_method_idx != DexFile::kDexNoIndex) { + if (LIKELY(dex_method_idx != DexFile::kDexNoIndex)) { return dex_file.GetMethodName(dex_file.GetMethodId(dex_method_idx)); } else { Runtime* runtime = Runtime::Current(); @@ -435,6 +469,16 @@ class MethodHelper { } } + StringPiece GetNameAsStringPiece() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile& dex_file = GetDexFile(); + uint32_t dex_method_idx = method_->GetDexMethodIndex(); + if (UNLIKELY(dex_method_idx == DexFile::kDexNoIndex)) { + return StringPiece(GetName()); + } + const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); + return dex_file.StringDataAsStringPieceByIdx(method_id.name_idx_); + } + mirror::String* GetNameAsString() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); uint32_t dex_method_idx = method_->GetDexMethodIndex(); @@ -508,11 +552,22 @@ class MethodHelper { const char* GetDeclaringClassDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); uint32_t dex_method_idx = method_->GetDexMethodIndex(); - if (dex_method_idx != DexFile::kDexNoIndex) { - return dex_file.GetMethodDeclaringClassDescriptor(dex_file.GetMethodId(dex_method_idx)); - } else { + if (UNLIKELY(dex_method_idx == DexFile::kDexNoIndex)) { return ""; } + return dex_file.GetMethodDeclaringClassDescriptor(dex_file.GetMethodId(dex_method_idx)); + } + + StringPiece GetDeclaringClassDescriptorAsStringPiece() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile& dex_file = GetDexFile(); + uint32_t dex_method_idx = method_->GetDexMethodIndex(); + if (UNLIKELY(dex_method_idx == DexFile::kDexNoIndex)) { + return StringPiece(""); + } + const DexFile::MethodId& mid = dex_file.GetMethodId(dex_method_idx); + const DexFile::TypeId& type_id = dex_file.GetTypeId(mid.class_idx_); + return dex_file.StringDataAsStringPieceByIdx(type_id.descriptor_idx_); } const char* GetDeclaringClassSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -536,7 +591,7 @@ class MethodHelper { } bool IsClassInitializer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - return IsStatic() && StringPiece(GetName()) == ""; + return IsStatic() && GetNameAsStringPiece() == ""; } size_t NumArgs() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { @@ -569,16 +624,56 @@ class MethodHelper { bool HasSameNameAndSignature(MethodHelper* other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile& dex_file = GetDexFile(); + const DexFile::MethodId& mid = dex_file.GetMethodId(method_->GetDexMethodIndex()); if (GetDexCache() == other->GetDexCache()) { - const DexFile& dex_file = GetDexFile(); - const DexFile::MethodId& mid = dex_file.GetMethodId(method_->GetDexMethodIndex()); const DexFile::MethodId& other_mid = dex_file.GetMethodId(other->method_->GetDexMethodIndex()); return mid.name_idx_ == other_mid.name_idx_ && mid.proto_idx_ == other_mid.proto_idx_; } - StringPiece name(GetName()); - StringPiece other_name(other->GetName()); - return name == other_name && GetSignature() == other->GetSignature(); + const DexFile& other_dex_file = other->GetDexFile(); + const DexFile::MethodId& other_mid = + other_dex_file.GetMethodId(other->method_->GetDexMethodIndex()); + if (dex_file.StringDataAsStringPieceByIdx(mid.name_idx_) != + other_dex_file.StringDataAsStringPieceByIdx(other_mid.name_idx_)) { + return false; // Name mismatch. + } + const DexFile::ProtoId& proto_id = dex_file.GetMethodPrototype(mid); + const DexFile::ProtoId& other_proto_id = other_dex_file.GetMethodPrototype(other_mid); + if (dex_file.StringDataAsStringPieceByIdx(proto_id.shorty_idx_) != + other_dex_file.StringDataAsStringPieceByIdx(other_proto_id.shorty_idx_)) { + return false; // Shorty mismatch. + } + const DexFile::TypeId& return_type_id = dex_file.GetTypeId(proto_id.return_type_idx_); + const DexFile::TypeId& other_return_type_id = + other_dex_file.GetTypeId(other_proto_id.return_type_idx_); + if (dex_file.StringDataAsStringPieceByIdx(return_type_id.descriptor_idx_) != + other_dex_file.StringDataAsStringPieceByIdx(other_return_type_id.descriptor_idx_)) { + return false; // Return type mismatch. + } + const DexFile::TypeList* params = dex_file.GetProtoParameters(proto_id); + const DexFile::TypeList* other_params = other_dex_file.GetProtoParameters(other_proto_id); + if (params == nullptr) { + return other_params == nullptr; // Check both lists are empty. + } + if (other_params == nullptr) { + return false; // Parameter list size mismatch. + } + uint32_t params_size = params->Size(); + uint32_t other_params_size = other_params->Size(); + if (params_size != other_params_size) { + return false; // Parameter list size mismatch. + } + for (uint32_t i = 0; i < params_size; ++i) { + const DexFile::TypeId& param_id = dex_file.GetTypeId(params->GetTypeItem(i).type_idx_); + const DexFile::TypeId& other_param_id = + other_dex_file.GetTypeId(other_params->GetTypeItem(i).type_idx_); + if (dex_file.StringDataAsStringPieceByIdx(param_id.descriptor_idx_) != + other_dex_file.StringDataAsStringPieceByIdx(other_param_id.descriptor_idx_)) { + return false; // Parameter type mismatch. + } + } + return true; } const DexFile::CodeItem* GetCodeItem() diff --git a/runtime/reflection.cc b/runtime/reflection.cc index 3e58b4bd94..4ff7349833 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -323,7 +323,7 @@ static bool UnboxPrimitive(const ThrowLocation* throw_location, mirror::Object* } JValue boxed_value; - std::string src_descriptor(ClassHelper(o->GetClass()).GetDescriptor()); + const StringPiece src_descriptor(ClassHelper(o->GetClass()).GetDescriptorAsStringPiece()); mirror::Class* src_class = NULL; ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); mirror::ArtField* primitive_field = o->GetClass()->GetIFields()->Get(0); @@ -356,7 +356,7 @@ static bool UnboxPrimitive(const ThrowLocation* throw_location, mirror::Object* StringPrintf("%s has type %s, got %s", UnboxingFailureKind(m, index, f).c_str(), PrettyDescriptor(dst_class).c_str(), - PrettyDescriptor(src_descriptor.c_str()).c_str()).c_str()); + PrettyDescriptor(src_descriptor.data()).c_str()).c_str()); return false; } diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 924a1bb377..4442ee13d9 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -80,7 +80,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const mirror::Class* kla return kNoFailure; } mirror::Class* super = klass->GetSuperClass(); - if (super == NULL && StringPiece(ClassHelper(klass).GetDescriptor()) != "Ljava/lang/Object;") { + if (super == NULL && ClassHelper(klass).GetDescriptorAsStringPiece() != "Ljava/lang/Object;") { *error = "Verifier rejected class "; *error += PrettyDescriptor(klass); *error += " that has no super class"; @@ -293,6 +293,7 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_ca dex_method_idx_(dex_method_idx), mirror_method_(method), method_access_flags_(method_access_flags), + return_type_(nullptr), dex_file_(dex_file), dex_cache_(dex_cache), class_loader_(class_loader), @@ -300,7 +301,7 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_ca code_item_(code_item), declaring_class_(NULL), interesting_dex_pc_(-1), - monitor_enter_dex_pcs_(NULL), + monitor_enter_dex_pcs_(nullptr), have_pending_hard_failure_(false), have_pending_runtime_throw_failure_(false), new_instance_count_(0), @@ -309,7 +310,7 @@ MethodVerifier::MethodVerifier(const DexFile* dex_file, mirror::DexCache* dex_ca allow_soft_failures_(allow_soft_failures), has_check_casts_(false), has_virtual_or_interface_invokes_(false) { - DCHECK(class_def != NULL); + DCHECK(class_def != nullptr); } void MethodVerifier::FindLocksAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc, @@ -2131,20 +2132,30 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { inst->Opcode() == Instruction::INVOKE_SUPER_RANGE); mirror::ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_VIRTUAL, is_range, is_super); - const char* descriptor; - if (called_method == NULL) { + const RegType* return_type = nullptr; + if (called_method != nullptr) { + MethodHelper mh(called_method); + mirror::Class* return_type_class = mh.GetReturnType(); + if (return_type_class != nullptr) { + return_type = ®_types_.FromClass(mh.GetReturnTypeDescriptor(), return_type_class, + return_type_class->CannotBeAssignedFromOtherTypes()); + } else { + Thread* self = Thread::Current(); + DCHECK(self->IsExceptionPending()); + self->ClearException(); + } + } + if (return_type == nullptr) { uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); 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_->StringByTypeIdx(return_type_idx); - } else { - descriptor = MethodHelper(called_method).GetReturnTypeDescriptor(); + const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx); + return_type = ®_types_.FromDescriptor(class_loader_, descriptor, false); } - const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor, false); - if (!return_type.IsLowHalf()) { - work_line_->SetResultRegisterType(return_type); + if (!return_type->IsLowHalf()) { + work_line_->SetResultRegisterType(*return_type); } else { - work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(®_types_)); + work_line_->SetResultRegisterTypeWide(*return_type, return_type->HighHalf(®_types_)); } just_set_result = true; break; @@ -2159,7 +2170,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { if (called_method == NULL) { uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); - is_constructor = StringPiece(dex_file_->GetMethodName(method_id)) == ""; + is_constructor = dex_file_->StringDataAsStringPieceByIdx(method_id.name_idx_) == ""; uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_; return_type_descriptor = dex_file_->StringByTypeIdx(return_type_idx); } else { @@ -3497,22 +3508,26 @@ void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_ty const RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c()); field = GetInstanceField(object_type, field_idx); } - const char* descriptor; - mirror::ClassLoader* loader; + const RegType* field_type = nullptr; if (field != NULL) { - descriptor = FieldHelper(field).GetTypeDescriptor(); - loader = field->GetDeclaringClass()->GetClassLoader(); - } else { + FieldHelper fh(field); + mirror::Class* field_type_class = fh.GetType(false); + if (field_type_class != nullptr) { + field_type = ®_types_.FromClass(fh.GetTypeDescriptor(), field_type_class, + field_type_class->CannotBeAssignedFromOtherTypes()); + } + } + if (field_type == nullptr) { const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx); - descriptor = dex_file_->GetFieldTypeDescriptor(field_id); - loader = class_loader_; + const char* descriptor = dex_file_->GetFieldTypeDescriptor(field_id); + mirror::ClassLoader* loader = class_loader_; + field_type = ®_types_.FromDescriptor(loader, descriptor, false); } - const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false); const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c(); if (is_primitive) { - if (field_type.Equals(insn_type) || - (field_type.IsFloat() && insn_type.IsInteger()) || - (field_type.IsDouble() && insn_type.IsLong())) { + if (field_type->Equals(insn_type) || + (field_type->IsFloat() && insn_type.IsInteger()) || + (field_type->IsDouble() && insn_type.IsLong())) { // expected that read is of the correct primitive type or that int reads are reading // floats or long reads are reading doubles } else { @@ -3525,7 +3540,7 @@ void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_ty return; } } else { - if (!insn_type.IsAssignableFrom(field_type)) { + if (!insn_type.IsAssignableFrom(*field_type)) { Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field) << " to be compatible with type '" << insn_type << "' but found type '" << field_type @@ -3534,10 +3549,10 @@ void MethodVerifier::VerifyISGet(const Instruction* inst, const RegType& insn_ty return; } } - if (!field_type.IsLowHalf()) { - work_line_->SetRegisterType(vregA, field_type); + if (!field_type->IsLowHalf()) { + work_line_->SetRegisterType(vregA, *field_type); } else { - work_line_->SetRegisterTypeWide(vregA, field_type, field_type.HighHalf(®_types_)); + work_line_->SetRegisterTypeWide(vregA, *field_type, field_type->HighHalf(®_types_)); } } @@ -3551,36 +3566,38 @@ void MethodVerifier::VerifyISPut(const Instruction* inst, const RegType& insn_ty const RegType& object_type = work_line_->GetRegisterType(inst->VRegB_22c()); field = GetInstanceField(object_type, field_idx); } - const char* descriptor; - mirror::ClassLoader* loader; - if (field != NULL) { - descriptor = FieldHelper(field).GetTypeDescriptor(); - loader = field->GetDeclaringClass()->GetClassLoader(); - } else { - const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx); - descriptor = dex_file_->GetFieldTypeDescriptor(field_id); - loader = class_loader_; - } - const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false); + const RegType* field_type = nullptr; if (field != NULL) { if (field->IsFinal() && field->GetDeclaringClass() != GetDeclaringClass().GetClass()) { Fail(VERIFY_ERROR_ACCESS_FIELD) << "cannot modify final field " << PrettyField(field) << " from other class " << GetDeclaringClass(); return; } + FieldHelper fh(field); + mirror::Class* field_type_class = fh.GetType(false); + if (field_type_class != nullptr) { + field_type = ®_types_.FromClass(fh.GetTypeDescriptor(), field_type_class, + field_type_class->CannotBeAssignedFromOtherTypes()); + } + } + if (field_type == nullptr) { + const DexFile::FieldId& field_id = dex_file_->GetFieldId(field_idx); + const char* descriptor = dex_file_->GetFieldTypeDescriptor(field_id); + mirror::ClassLoader* loader = class_loader_; + field_type = ®_types_.FromDescriptor(loader, descriptor, false); } const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c(); if (is_primitive) { - VerifyPrimitivePut(field_type, insn_type, vregA); + VerifyPrimitivePut(*field_type, insn_type, vregA); } else { - if (!insn_type.IsAssignableFrom(field_type)) { + if (!insn_type.IsAssignableFrom(*field_type)) { Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field) << " to be compatible with type '" << insn_type << "' but found type '" << field_type << "' in put-object"; return; } - work_line_->VerifyRegisterType(vregA, field_type); + work_line_->VerifyRegisterType(vregA, *field_type); } } @@ -3648,14 +3665,21 @@ void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& ins Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name(); return; } - const char* descriptor = FieldHelper(field).GetTypeDescriptor(); - mirror::ClassLoader* loader = field->GetDeclaringClass()->GetClassLoader(); - const RegType& field_type = reg_types_.FromDescriptor(loader, descriptor, false); + FieldHelper fh(field); + mirror::Class* field_type_class = fh.GetType(false); + const RegType* field_type; + if (field_type_class != nullptr) { + field_type = ®_types_.FromClass(fh.GetTypeDescriptor(), field_type_class, + field_type_class->CannotBeAssignedFromOtherTypes()); + } else { + field_type = ®_types_.FromDescriptor(field->GetDeclaringClass()->GetClassLoader(), + fh.GetTypeDescriptor(), false); + } const uint32_t vregA = inst->VRegA_22c(); if (is_primitive) { - if (field_type.Equals(insn_type) || - (field_type.IsFloat() && insn_type.IsIntegralTypes()) || - (field_type.IsDouble() && insn_type.IsLongTypes())) { + if (field_type->Equals(insn_type) || + (field_type->IsFloat() && insn_type.IsIntegralTypes()) || + (field_type->IsDouble() && insn_type.IsLongTypes())) { // expected that read is of the correct primitive type or that int reads are reading // floats or long reads are reading doubles } else { @@ -3668,7 +3692,7 @@ void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& ins return; } } else { - if (!insn_type.IsAssignableFrom(field_type)) { + if (!insn_type.IsAssignableFrom(*field_type)) { Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field) << " to be compatible with type '" << insn_type << "' but found type '" << field_type @@ -3677,10 +3701,10 @@ void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& ins return; } } - if (!field_type.IsLowHalf()) { - work_line_->SetRegisterType(vregA, field_type); + if (!field_type->IsLowHalf()) { + work_line_->SetRegisterType(vregA, *field_type); } else { - work_line_->SetRegisterTypeWide(vregA, field_type, field_type.HighHalf(®_types_)); + work_line_->SetRegisterTypeWide(vregA, *field_type, field_type->HighHalf(®_types_)); } } @@ -3822,11 +3846,28 @@ InstructionFlags* MethodVerifier::CurrentInsnFlags() { } const RegType& MethodVerifier::GetMethodReturnType() { - const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_); - const DexFile::ProtoId& proto_id = dex_file_->GetMethodPrototype(method_id); - uint16_t return_type_idx = proto_id.return_type_idx_; - const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(return_type_idx)); - return reg_types_.FromDescriptor(class_loader_, descriptor, false); + if (return_type_ == nullptr) { + if (mirror_method_ != NULL) { + MethodHelper mh(mirror_method_); + mirror::Class* return_type_class = mh.GetReturnType(); + if (return_type_class != nullptr) { + return_type_ =®_types_.FromClass(mh.GetReturnTypeDescriptor(), return_type_class, + return_type_class->CannotBeAssignedFromOtherTypes()); + } else { + Thread* self = Thread::Current(); + DCHECK(self->IsExceptionPending()); + self->ClearException(); + } + } + if (return_type_ == nullptr) { + const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_); + const DexFile::ProtoId& proto_id = dex_file_->GetMethodPrototype(method_id); + uint16_t return_type_idx = proto_id.return_type_idx_; + const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(return_type_idx)); + return_type_ = ®_types_.FromDescriptor(class_loader_, descriptor, false); + } + } + return *return_type_; } const RegType& MethodVerifier::GetDeclaringClass() { diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 073a2f76be..f1437517e9 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -688,6 +688,7 @@ class MethodVerifier { // Its object representation if known. mirror::ArtMethod* mirror_method_ GUARDED_BY(Locks::mutator_lock_); const uint32_t method_access_flags_; // Method's access flags. + const RegType* return_type_; // Lazily computed return type of the method. const DexFile* const dex_file_; // The dex file containing the method. // The dex_cache for the declaring class of the method. mirror::DexCache* dex_cache_ GUARDED_BY(Locks::mutator_lock_); diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc index 857acb8743..50d1583bbb 100644 --- a/runtime/verifier/reg_type.cc +++ b/runtime/verifier/reg_type.cc @@ -761,11 +761,6 @@ bool RegType::IsStrictlyAssignableFrom(const RegType& src) const { return AssignableFrom(*this, src, true); } -int32_t ConstantType::ConstantValue() const { - DCHECK(IsConstantTypes()); - return constant_; -} - int32_t ConstantType::ConstantValueLo() const { DCHECK(IsConstantLo()); return constant_; diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h index 865ba20d44..f3717330eb 100644 --- a/runtime/verifier/reg_type.h +++ b/runtime/verifier/reg_type.h @@ -574,9 +574,12 @@ class ConstantType : public RegType { // If this is a 32-bit constant, what is the value? This value may be imprecise in which case // the value represents part of the integer range of values that may be held in the register. - virtual int32_t ConstantValue() const; - virtual int32_t ConstantValueLo() const; - virtual int32_t ConstantValueHi() const; + int32_t ConstantValue() const { + DCHECK(IsConstantTypes()); + return constant_; + } + int32_t ConstantValueLo() const; + int32_t ConstantValueHi() const; bool IsZero() const { return IsPreciseConstant() && ConstantValue() == 0; diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc index ce465a415d..fd7030011d 100644 --- a/runtime/verifier/reg_type_cache.cc +++ b/runtime/verifier/reg_type_cache.cc @@ -210,6 +210,7 @@ const RegType& RegTypeCache::From(mirror::ClassLoader* loader, const char* descr } const RegType& RegTypeCache::FromClass(const char* descriptor, mirror::Class* klass, bool precise) { + DCHECK(klass != nullptr); if (klass->IsPrimitive()) { // Note: precise isn't used for primitive classes. A char is assignable to an int. All // primitive classes are final. -- cgit v1.2.3-59-g8ed1b From d91d6d6a80748f277fd938a412211e5af28913b1 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 25 Sep 2013 20:26:14 -0700 Subject: Introduce Signature type to avoid string comparisons. Method resolution currently creates strings to then compare with strings formed from methods in other dex files. The temporary strings are purely created for the sake of comparisons. This change creates a new Signature type that represents a method signature but not as a string. This type supports comparisons and so can be used when searching for methods in resolution. With this change malloc is no longer the hottest method during dex2oat (now its memset) and allocations during verification have been reduced. The verifier is commonly what is populating the dex cache for methods and fields not declared in the dex file itself. Change-Id: I5ef0542823fbcae868aaa4a2457e8da7df0e9dae --- compiler/dex/quick/codegen_util.cc | 12 +-- compiler/dex/quick/mir_to_lir.h | 4 +- compiler/driver/compiler_driver.cc | 5 +- runtime/class_linker.cc | 22 ++--- runtime/class_linker_test.cc | 21 ++--- runtime/common_throws.cc | 2 +- runtime/common_throws.h | 3 +- runtime/debugger.cc | 2 +- runtime/dex_file-inl.h | 4 + runtime/dex_file.cc | 66 ++++++++------- runtime/dex_file.h | 95 ++++++++++++++++++++-- runtime/dex_file_test.cc | 27 +++--- runtime/jni_internal.cc | 1 + runtime/mirror/class.cc | 64 ++++++++++++++- runtime/mirror/class.h | 35 +++++--- runtime/object_utils.h | 41 +--------- runtime/trace.cc | 2 +- runtime/utils.cc | 22 +++-- runtime/verifier/method_verifier.cc | 4 +- test/Android.mk | 2 +- .../CreateMethodSignature.java | 20 ----- test/GetMethodSignature/GetMethodSignature.java | 20 +++++ 22 files changed, 301 insertions(+), 173 deletions(-) delete mode 100644 test/CreateMethodSignature/CreateMethodSignature.java create mode 100644 test/GetMethodSignature/GetMethodSignature.java (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 4ce752fb39..6e49f0bc54 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -248,12 +248,12 @@ void Mir2Lir::DumpPromotionMap() { } /* Dump a mapping table */ -void Mir2Lir::DumpMappingTable(const char* table_name, const std::string& descriptor, - const std::string& name, const std::string& signature, +void Mir2Lir::DumpMappingTable(const char* table_name, const char* descriptor, + const char* name, const Signature& signature, const std::vector& v) { if (v.size() > 0) { std::string line(StringPrintf("\n %s %s%s_%s_table[%zu] = {", table_name, - descriptor.c_str(), name.c_str(), signature.c_str(), v.size())); + descriptor, name, signature.ToString().c_str(), v.size())); std::replace(line.begin(), line.end(), ';', '_'); LOG(INFO) << line; for (uint32_t i = 0; i < v.size(); i+=2) { @@ -293,9 +293,9 @@ void Mir2Lir::CodegenDump() { const DexFile::MethodId& method_id = cu_->dex_file->GetMethodId(cu_->method_idx); - std::string signature(cu_->dex_file->GetMethodSignature(method_id)); - std::string name(cu_->dex_file->GetMethodName(method_id)); - std::string descriptor(cu_->dex_file->GetMethodDeclaringClassDescriptor(method_id)); + const Signature signature = cu_->dex_file->GetMethodSignature(method_id); + const char* name = cu_->dex_file->GetMethodName(method_id); + const char* descriptor(cu_->dex_file->GetMethodDeclaringClassDescriptor(method_id)); // Dump mapping tables DumpMappingTable("PC2Dex_MappingTable", descriptor, name, signature, pc2dex_mapping_table_); diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 401e3d5f93..7d6f968da5 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -283,8 +283,8 @@ class Mir2Lir : public Backend { bool EvaluateBranch(Instruction::Code opcode, int src1, int src2); bool IsInexpensiveConstant(RegLocation rl_src); ConditionCode FlipComparisonOrder(ConditionCode before); - void DumpMappingTable(const char* table_name, const std::string& descriptor, - const std::string& name, const std::string& signature, + void DumpMappingTable(const char* table_name, const char* descriptor, + const char* name, const Signature& signature, const std::vector& v); void InstallLiteralPools(); void InstallSwitchTables(); diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index e227715605..056be1fb04 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1227,8 +1227,9 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui if (name != NULL) { uint16_t return_type_idx; std::vector param_type_idxs; - bool success = dexfile->CreateTypeList(&return_type_idx, ¶m_type_idxs, - cm_dexfile->GetMethodSignature(cm_method_id)); + bool success = + dexfile->CreateTypeList(cm_dexfile->GetMethodSignature(cm_method_id).ToString(), + &return_type_idx, ¶m_type_idxs); if (success) { const DexFile::ProtoId* sig = dexfile->FindProtoId(return_type_idx, param_type_idxs); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 6aae63ee2c..17a179f2d9 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -2823,12 +2823,12 @@ static void CheckProxyConstructor(mirror::ArtMethod* constructor) CHECK(constructor->IsConstructor()); MethodHelper mh(constructor); CHECK_STREQ(mh.GetName(), ""); - CHECK_EQ(mh.GetSignature(), std::string("(Ljava/lang/reflect/InvocationHandler;)V")); + CHECK_STREQ(mh.GetSignature().ToString().c_str(), "(Ljava/lang/reflect/InvocationHandler;)V"); DCHECK(constructor->IsPublic()); } mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self, SirtRef& klass, - SirtRef& prototype) { + SirtRef& prototype) { // Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden // prototype method prototype->GetDeclaringClass()->GetDexCache()->SetResolvedMethod(prototype->GetDexMethodIndex(), @@ -2892,7 +2892,7 @@ static bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics, } if (!can_init_statics) { // Check if there's a class initializer. - mirror::ArtMethod* clinit = klass->FindDeclaredDirectMethod("", "()V"); + mirror::ArtMethod* clinit = klass->FindClassInitializer(); if (clinit != NULL) { return false; } @@ -3039,7 +3039,7 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics, } } - mirror::ArtMethod* clinit = klass->FindDeclaredDirectMethod("", "()V"); + mirror::ArtMethod* clinit = klass->FindClassInitializer(); if (clinit != NULL) { CHECK(can_init_statics); if (LIKELY(Runtime::Current()->IsStarted())) { @@ -3992,11 +3992,11 @@ mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, } mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, - uint32_t method_idx, - mirror::DexCache* dex_cache, - mirror::ClassLoader* class_loader, - const mirror::ArtMethod* referrer, - InvokeType type) { + uint32_t method_idx, + mirror::DexCache* dex_cache, + mirror::ClassLoader* class_loader, + const mirror::ArtMethod* referrer, + InvokeType type) { DCHECK(dex_cache != NULL); // Check for hit in the dex cache. mirror::ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx); @@ -4031,7 +4031,7 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, if (resolved == NULL) { // Search by name, which works across dex files. const char* name = dex_file.StringDataByIdx(method_id.name_idx_); - std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL)); + const Signature signature = dex_file.GetMethodSignature(method_id); switch (type) { case kDirect: // Fall-through. case kStatic: @@ -4061,7 +4061,7 @@ mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, // We failed to find the method which means either an access error, an incompatible class // change, or no such method. First try to find the method among direct and virtual methods. const char* name = dex_file.StringDataByIdx(method_id.name_idx_); - std::string signature(dex_file.CreateMethodSignature(method_id.proto_idx_, NULL)); + const Signature signature = dex_file.GetMethodSignature(method_id); switch (type) { case kDirect: case kStatic: diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index bea1139679..ad9347fee1 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -152,7 +152,7 @@ class ClassLinkerTest : public CommonTest { EXPECT_TRUE(method != NULL); EXPECT_TRUE(method->GetClass() != NULL); EXPECT_TRUE(mh.GetName() != NULL); - EXPECT_TRUE(mh.GetSignature() != NULL); + EXPECT_TRUE(mh.GetSignature() != Signature::NoSignature()); EXPECT_TRUE(method->GetDexCacheStrings() != NULL); EXPECT_TRUE(method->GetDexCacheResolvedMethods() != NULL); @@ -942,15 +942,16 @@ TEST_F(ClassLinkerTest, Interfaces) { EXPECT_TRUE(K->IsAssignableFrom(B)); EXPECT_TRUE(J->IsAssignableFrom(B)); - mirror::ArtMethod* Ii = I->FindVirtualMethod("i", "()V"); - mirror::ArtMethod* Jj1 = J->FindVirtualMethod("j1", "()V"); - mirror::ArtMethod* Jj2 = J->FindVirtualMethod("j2", "()V"); - mirror::ArtMethod* Kj1 = K->FindInterfaceMethod("j1", "()V"); - mirror::ArtMethod* Kj2 = K->FindInterfaceMethod("j2", "()V"); - mirror::ArtMethod* Kk = K->FindInterfaceMethod("k", "()V"); - mirror::ArtMethod* Ai = A->FindVirtualMethod("i", "()V"); - mirror::ArtMethod* Aj1 = A->FindVirtualMethod("j1", "()V"); - mirror::ArtMethod* Aj2 = A->FindVirtualMethod("j2", "()V"); + const Signature void_sig = I->GetDexCache()->GetDexFile()->CreateSignature("()V"); + mirror::ArtMethod* Ii = I->FindVirtualMethod("i", void_sig); + mirror::ArtMethod* Jj1 = J->FindVirtualMethod("j1", void_sig); + mirror::ArtMethod* Jj2 = J->FindVirtualMethod("j2", void_sig); + mirror::ArtMethod* Kj1 = K->FindInterfaceMethod("j1", void_sig); + mirror::ArtMethod* Kj2 = K->FindInterfaceMethod("j2", void_sig); + mirror::ArtMethod* Kk = K->FindInterfaceMethod("k", void_sig); + mirror::ArtMethod* Ai = A->FindVirtualMethod("i", void_sig); + mirror::ArtMethod* Aj1 = A->FindVirtualMethod("j1", void_sig); + mirror::ArtMethod* Aj2 = A->FindVirtualMethod("j2", void_sig); ASSERT_TRUE(Ii != NULL); ASSERT_TRUE(Jj1 != NULL); ASSERT_TRUE(Jj2 != NULL); diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index 26ce5be1ec..189e3edc0f 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -265,7 +265,7 @@ void ThrowNoSuchFieldError(const StringPiece& scope, mirror::Class* c, // NoSuchMethodError void ThrowNoSuchMethodError(InvokeType type, mirror::Class* c, const StringPiece& name, - const StringPiece& signature) { + const Signature& signature) { std::ostringstream msg; ClassHelper kh(c); msg << "No " << type << " method " << name << signature diff --git a/runtime/common_throws.h b/runtime/common_throws.h index 99c6343cdd..1d77e2d625 100644 --- a/runtime/common_throws.h +++ b/runtime/common_throws.h @@ -27,6 +27,7 @@ class ArtMethod; class Class; class Object; } // namespace mirror +class Signature; class StringPiece; class ThrowLocation; @@ -140,7 +141,7 @@ void ThrowNoSuchFieldError(const StringPiece& scope, mirror::Class* c, // NoSuchMethodError void ThrowNoSuchMethodError(InvokeType type, mirror::Class* c, const StringPiece& name, - const StringPiece& signature) + const Signature& signature) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void ThrowNoSuchMethodError(uint32_t method_idx) diff --git a/runtime/debugger.cc b/runtime/debugger.cc index e57137fb96..ae57aa34ec 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -1287,7 +1287,7 @@ JDWP::JdwpError Dbg::OutputDeclaredMethods(JDWP::RefTypeId class_id, bool with_g MethodHelper mh(m); expandBufAddMethodId(pReply, ToMethodId(m)); expandBufAddUtf8String(pReply, mh.GetName()); - expandBufAddUtf8String(pReply, mh.GetSignature()); + expandBufAddUtf8String(pReply, mh.GetSignature().ToString()); if (with_generic) { static const char genericSignature[1] = ""; expandBufAddUtf8String(pReply, genericSignature); diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h index 2ee9244bf2..c57a1e7582 100644 --- a/runtime/dex_file-inl.h +++ b/runtime/dex_file-inl.h @@ -47,6 +47,10 @@ inline StringPiece DexFile::StringDataAsStringPieceByIdx(uint32_t idx) const { return StringPiece(data, static_cast(length)); } +inline const Signature DexFile::GetMethodSignature(const MethodId& method_id) const { + return Signature(this, GetProtoId(method_id.proto_idx_)); +} + inline const DexFile::TryItem* DexFile::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 diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 098ab674f4..275dcc5a03 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -503,8 +503,8 @@ const DexFile::ProtoId* DexFile::FindProtoId(uint16_t return_type_idx, } // Given a signature place the type ids into the given vector -bool DexFile::CreateTypeList(uint16_t* return_type_idx, std::vector* param_type_idxs, - const std::string& signature) const { +bool DexFile::CreateTypeList(const StringPiece& signature, uint16_t* return_type_idx, + std::vector* param_type_idxs) const { if (signature[0] != '(') { return false; } @@ -518,6 +518,7 @@ bool DexFile::CreateTypeList(uint16_t* return_type_idx, std::vector* p process_return = true; continue; } + // TODO: avoid building a string. std::string descriptor; descriptor += c; while (c == '[') { // process array prefix @@ -557,35 +558,18 @@ bool DexFile::CreateTypeList(uint16_t* return_type_idx, std::vector* p 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::CreateMethodSignature(uint32_t proto_idx, int32_t* unicode_length) const { - const ProtoId& proto_id = GetProtoId(proto_idx); - std::string descriptor; - descriptor.push_back('('); - const TypeList* type_list = GetProtoParameters(proto_id); - size_t parameter_length = 0; - if (type_list != NULL) { - // A non-zero number of arguments. Append the type names. - for (size_t i = 0; i < type_list->Size(); ++i) { - const TypeItem& type_item = type_list->GetTypeItem(i); - uint32_t type_idx = type_item.type_idx_; - uint32_t type_length; - const char* name = StringByTypeIdx(type_idx, &type_length); - parameter_length += type_length; - descriptor.append(name); - } +const Signature DexFile::CreateSignature(const StringPiece& signature) const { + uint16_t return_type_idx; + std::vector param_type_indices; + bool success = CreateTypeList(signature, &return_type_idx, ¶m_type_indices); + if (!success) { + return Signature::NoSignature(); } - descriptor.push_back(')'); - uint32_t return_type_idx = proto_id.return_type_idx_; - uint32_t 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 ) + const ProtoId* proto_id = FindProtoId(return_type_idx, param_type_indices); + if (proto_id == NULL) { + return Signature::NoSignature(); } - return descriptor; + return Signature(this, *proto_id); } int32_t DexFile::GetLineNumFromPC(const mirror::ArtMethod* method, uint32_t rel_pc) const { @@ -831,6 +815,30 @@ bool DexFile::LineNumForPcCb(void* raw_context, uint32_t address, uint32_t line_ } } +std::string Signature::ToString() const { + if (dex_file_ == nullptr) { + CHECK(proto_id_ == nullptr); + return ""; + } + const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_); + std::string result; + if (params == nullptr) { + result += "()"; + } else { + result += "("; + for (uint32_t i = 0; i < params->Size(); ++i) { + result += dex_file_->StringByTypeIdx(params->GetTypeItem(i).type_idx_); + } + result += ")"; + } + result += dex_file_->StringByTypeIdx(proto_id_->return_type_idx_); + return result; +} + +std::ostream& operator<<(std::ostream& os, const Signature& sig) { + return os << sig.ToString(); +} + // Decodes the header section from the class data bytes. void ClassDataItemIterator::ReadClassDataHeader() { CHECK(ptr_pos_ != NULL); diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 4534b41e92..40e4c72772 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -40,6 +40,7 @@ namespace mirror { class DexCache; } // namespace mirror class ClassLinker; +class Signature; class StringPiece; class ZipArchive; @@ -559,10 +560,8 @@ class DexFile { return GetProtoId(method_id.proto_idx_); } - // Returns the signature of a method id. - const std::string GetMethodSignature(const MethodId& method_id) const { - return CreateMethodSignature(method_id.proto_idx_, NULL); - } + // Returns a representation of the signature of a method id. + const Signature GetMethodSignature(const MethodId& method_id) const; // Returns the name of a method id. const char* GetMethodName(const MethodId& method_id) const { @@ -656,15 +655,16 @@ class DexFile { } // Looks up a proto id for a given return type and signature type list - const ProtoId* FindProtoId(uint16_t return_type_id, + const ProtoId* FindProtoId(uint16_t return_type_idx, const std::vector& signature_type_idxs_) 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* param_type_idxs, - const std::string& signature) const; + bool CreateTypeList(const StringPiece& signature, uint16_t* return_type_idx, + std::vector* param_type_idxs) 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; + // Create a Signature from the given string signature or return Signature::NoSignature if not + // possible. + const Signature CreateSignature(const StringPiece& signature) const; // Returns the short form method descriptor for the given prototype. const char* GetShorty(uint32_t proto_idx) const { @@ -942,6 +942,83 @@ class DexFileParameterIterator { DISALLOW_IMPLICIT_CONSTRUCTORS(DexFileParameterIterator); }; +// Abstract the signature of a method. +class Signature { + public: + std::string ToString() const; + + static Signature NoSignature() { + return Signature(); + } + + bool operator==(const Signature& rhs) const { + if (dex_file_ == nullptr) { + return rhs.dex_file_ == nullptr; + } + if (rhs.dex_file_ == nullptr) { + return false; + } + if (dex_file_ == rhs.dex_file_) { + return proto_id_ == rhs.proto_id_; + } + StringPiece shorty(dex_file_->StringDataAsStringPieceByIdx(proto_id_->shorty_idx_)); + if (shorty != rhs.dex_file_->StringDataAsStringPieceByIdx(rhs.proto_id_->shorty_idx_)) { + return false; // Shorty mismatch. + } + if (shorty[0] == 'L') { + const DexFile::TypeId& return_type_id = dex_file_->GetTypeId(proto_id_->return_type_idx_); + const DexFile::TypeId& rhs_return_type_id = + rhs.dex_file_->GetTypeId(rhs.proto_id_->return_type_idx_); + if (dex_file_->StringDataAsStringPieceByIdx(return_type_id.descriptor_idx_) != + rhs.dex_file_->StringDataAsStringPieceByIdx(rhs_return_type_id.descriptor_idx_)) { + return false; // Return type mismatch. + } + } + if (shorty.find('L', 1) != StringPiece::npos) { + const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_); + const DexFile::TypeList* rhs_params = rhs.dex_file_->GetProtoParameters(*rhs.proto_id_); + // Both lists are empty or have contents, or else shorty is broken. + DCHECK_EQ(params == nullptr, rhs_params == nullptr); + if (params != nullptr) { + uint32_t params_size = params->Size(); + DCHECK_EQ(params_size, rhs_params->Size()); // Parameter list size must match. + for (uint32_t i = 0; i < params_size; ++i) { + const DexFile::TypeId& param_id = dex_file_->GetTypeId(params->GetTypeItem(i).type_idx_); + const DexFile::TypeId& rhs_param_id = + rhs.dex_file_->GetTypeId(rhs_params->GetTypeItem(i).type_idx_); + if (dex_file_->StringDataAsStringPieceByIdx(param_id.descriptor_idx_) != + rhs.dex_file_->StringDataAsStringPieceByIdx(rhs_param_id.descriptor_idx_)) { + return false; // Parameter type mismatch. + } + } + } + } + return true; + } + + bool operator!=(const Signature& rhs) const { + return !(*this == rhs); + } + + bool operator==(const StringPiece& rhs) const { + // TODO: Avoid temporary string allocation. + return ToString() == rhs; + } + + private: + Signature(const DexFile* dex, const DexFile::ProtoId& proto) : dex_file_(dex), proto_id_(&proto) { + } + + Signature() : dex_file_(nullptr), proto_id_(nullptr) { + } + + friend class DexFile; + + const DexFile* const dex_file_; + const DexFile::ProtoId* const proto_id_; +}; +std::ostream& operator<<(std::ostream& os, const Signature& sig); + // Iterate and decode class_data_item class ClassDataItemIterator { public: diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc index 32a8354d01..1b40529a08 100644 --- a/runtime/dex_file_test.cc +++ b/runtime/dex_file_test.cc @@ -137,14 +137,14 @@ TEST_F(DexFileTest, ClassDefs) { EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c1)); } -TEST_F(DexFileTest, CreateMethodSignature) { +TEST_F(DexFileTest, GetMethodSignature) { ScopedObjectAccess soa(Thread::Current()); - const DexFile* raw(OpenTestDexFile("CreateMethodSignature")); + const DexFile* raw(OpenTestDexFile("GetMethodSignature")); ASSERT_TRUE(raw != NULL); EXPECT_EQ(1U, raw->NumClassDefs()); const DexFile::ClassDef& class_def = raw->GetClassDef(0); - ASSERT_STREQ("LCreateMethodSignature;", raw->GetClassDescriptor(class_def)); + ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def)); const byte* class_data = raw->GetClassData(class_def); ASSERT_TRUE(class_data != NULL); @@ -156,11 +156,9 @@ TEST_F(DexFileTest, CreateMethodSignature) { { 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->StringDataByIdx(method_id.name_idx_); ASSERT_STREQ("", name); - int32_t length; - std::string signature(raw->CreateMethodSignature(proto_idx, &length)); + std::string signature(raw->GetMethodSignature(method_id).ToString()); ASSERT_EQ("()V", signature); } @@ -173,9 +171,7 @@ TEST_F(DexFileTest, CreateMethodSignature) { 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 signature(raw->CreateMethodSignature(proto_idx, &length)); + std::string signature(raw->GetMethodSignature(method_id).ToString()); ASSERT_EQ("(IDJLjava/lang/Object;)Ljava/lang/Float;", signature); } @@ -186,20 +182,18 @@ TEST_F(DexFileTest, CreateMethodSignature) { 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 signature(raw->CreateMethodSignature(proto_idx, &length)); - ASSERT_EQ("(ZSC)LCreateMethodSignature;", signature); + std::string signature(raw->GetMethodSignature(method_id).ToString()); + ASSERT_EQ("(ZSC)LGetMethodSignature;", signature); } } TEST_F(DexFileTest, FindStringId) { ScopedObjectAccess soa(Thread::Current()); - const DexFile* raw(OpenTestDexFile("CreateMethodSignature")); + const DexFile* raw(OpenTestDexFile("GetMethodSignature")); ASSERT_TRUE(raw != NULL); EXPECT_EQ(1U, raw->NumClassDefs()); - const char* strings[] = { "LCreateMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;", + const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;", "D", "I", "J", NULL }; for (size_t i = 0; strings[i] != NULL; i++) { const char* str = strings[i]; @@ -245,11 +239,10 @@ TEST_F(DexFileTest, FindMethodId) { 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); + << java_lang_dex_file_->GetMethodSignature(to_find); EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i); } } diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 60fad6ee48..8be9b21cdf 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -228,6 +228,7 @@ static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class, const char* name, const char* sig, bool is_static) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { Class* c = soa.Decode(jni_class); + DCHECK(c != nullptr); if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) { return NULL; } diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 287e8b0959..c6db5b9a61 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -325,7 +325,7 @@ void Class::SetClassLoader(ClassLoader* new_class_loader) { SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false); } -ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const StringPiece& signature) const { +ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const Signature& signature) const { // Check the current class before checking the interfaces. ArtMethod* method = FindDeclaredVirtualMethod(name, signature); if (method != NULL) { @@ -361,8 +361,19 @@ ArtMethod* Class::FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_me return NULL; } - ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) const { + MethodHelper mh; + for (size_t i = 0; i < NumDirectMethods(); ++i) { + ArtMethod* method = GetDirectMethod(i); + mh.ChangeMethod(method); + if (name == mh.GetNameAsStringPiece() && mh.GetSignature() == signature) { + return method; + } + } + return NULL; +} + +ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const Signature& signature) const { MethodHelper mh; for (size_t i = 0; i < NumDirectMethods(); ++i) { ArtMethod* method = GetDirectMethod(i); @@ -396,6 +407,16 @@ ArtMethod* Class::FindDirectMethod(const StringPiece& name, const StringPiece& s return NULL; } +ArtMethod* Class::FindDirectMethod(const StringPiece& name, const Signature& signature) const { + for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { + ArtMethod* method = klass->FindDeclaredDirectMethod(name, signature); + if (method != NULL) { + return method; + } + } + return NULL; +} + ArtMethod* Class::FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const { for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { ArtMethod* method = klass->FindDeclaredDirectMethod(dex_cache, dex_method_idx); @@ -406,8 +427,20 @@ ArtMethod* Class::FindDirectMethod(const DexCache* dex_cache, uint32_t dex_metho return NULL; } +ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const { + MethodHelper mh; + for (size_t i = 0; i < NumVirtualMethods(); ++i) { + ArtMethod* method = GetVirtualMethod(i); + mh.ChangeMethod(method); + if (name == mh.GetNameAsStringPiece() && mh.GetSignature() == signature) { + return method; + } + } + return NULL; +} + ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, - const StringPiece& signature) const { + const Signature& signature) const { MethodHelper mh; for (size_t i = 0; i < NumVirtualMethods(); ++i) { ArtMethod* method = GetVirtualMethod(i); @@ -441,6 +474,16 @@ ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const StringPiece& return NULL; } +ArtMethod* Class::FindVirtualMethod(const StringPiece& name, const Signature& signature) const { + for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { + ArtMethod* method = klass->FindDeclaredVirtualMethod(name, signature); + if (method != NULL) { + return method; + } + } + return NULL; +} + ArtMethod* Class::FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const { for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) { ArtMethod* method = klass->FindDeclaredVirtualMethod(dex_cache, dex_method_idx); @@ -451,6 +494,21 @@ ArtMethod* Class::FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_meth return NULL; } +ArtMethod* Class::FindClassInitializer() const { + for (size_t i = 0; i < NumDirectMethods(); ++i) { + ArtMethod* method = GetDirectMethod(i); + if (method->IsConstructor() && method->IsStatic()) { + if (kIsDebugBuild) { + MethodHelper mh(method); + CHECK_STREQ(mh.GetName(), ""); + CHECK_STREQ(mh.GetSignature().ToString().c_str(), "()V"); + } + return method; + } + } + return NULL; +} + ArtField* Class::FindDeclaredInstanceField(const StringPiece& name, const StringPiece& type) { // Is the field in this class? // Interfaces are not relevant because they can't contain instance fields. diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 4f8ab7d90a..586151de45 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -59,6 +59,7 @@ namespace art { struct ClassClassOffsets; struct ClassOffsets; +class Signature; class StringPiece; namespace mirror { @@ -565,39 +566,53 @@ class MANAGED Class : public StaticStorageBase { ArtMethod* FindVirtualMethodForInterface(ArtMethod* method) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE; - ArtMethod* FindInterfaceMethod(const StringPiece& name, const StringPiece& descriptor) const + ArtMethod* FindVirtualMethodForVirtualOrInterface(ArtMethod* method) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + ArtMethod* FindInterfaceMethod(const StringPiece& name, const Signature& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); ArtMethod* FindInterfaceMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindVirtualMethodForVirtualOrInterface(ArtMethod* method) const + ArtMethod* FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const + ArtMethod* FindDeclaredDirectMethod(const StringPiece& name, const Signature& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindVirtualMethod(const StringPiece& name, const StringPiece& descriptor) const + ArtMethod* FindDirectMethod(const StringPiece& name, const StringPiece& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindDirectMethod(const StringPiece& name, const Signature& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredDirectMethod(const StringPiece& name, const StringPiece& signature) const + ArtMethod* FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDeclaredDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDirectMethod(const StringPiece& name, const StringPiece& signature) const + ArtMethod* FindDeclaredVirtualMethod(const StringPiece& name, const Signature& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - ArtMethod* FindDirectMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + ArtMethod* FindDeclaredVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + ArtMethod* FindVirtualMethod(const StringPiece& name, const StringPiece& signature) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ArtMethod* FindVirtualMethod(const StringPiece& name, const Signature& signature) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + ArtMethod* FindVirtualMethod(const DexCache* dex_cache, uint32_t dex_method_idx) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + ArtMethod* FindClassInitializer() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + int32_t GetIfTableCount() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); IfTable* GetIfTable() const; diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 9e107a46d5..f83db903ff 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -504,13 +504,13 @@ class MethodHelper { return shorty_len_; } - const std::string GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const Signature GetSignature() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); uint32_t dex_method_idx = method_->GetDexMethodIndex(); if (dex_method_idx != DexFile::kDexNoIndex) { return dex_file.GetMethodSignature(dex_file.GetMethodId(dex_method_idx)); } else { - return ""; + return Signature::NoSignature(); } } @@ -638,42 +638,7 @@ class MethodHelper { other_dex_file.StringDataAsStringPieceByIdx(other_mid.name_idx_)) { return false; // Name mismatch. } - const DexFile::ProtoId& proto_id = dex_file.GetMethodPrototype(mid); - const DexFile::ProtoId& other_proto_id = other_dex_file.GetMethodPrototype(other_mid); - if (dex_file.StringDataAsStringPieceByIdx(proto_id.shorty_idx_) != - other_dex_file.StringDataAsStringPieceByIdx(other_proto_id.shorty_idx_)) { - return false; // Shorty mismatch. - } - const DexFile::TypeId& return_type_id = dex_file.GetTypeId(proto_id.return_type_idx_); - const DexFile::TypeId& other_return_type_id = - other_dex_file.GetTypeId(other_proto_id.return_type_idx_); - if (dex_file.StringDataAsStringPieceByIdx(return_type_id.descriptor_idx_) != - other_dex_file.StringDataAsStringPieceByIdx(other_return_type_id.descriptor_idx_)) { - return false; // Return type mismatch. - } - const DexFile::TypeList* params = dex_file.GetProtoParameters(proto_id); - const DexFile::TypeList* other_params = other_dex_file.GetProtoParameters(other_proto_id); - if (params == nullptr) { - return other_params == nullptr; // Check both lists are empty. - } - if (other_params == nullptr) { - return false; // Parameter list size mismatch. - } - uint32_t params_size = params->Size(); - uint32_t other_params_size = other_params->Size(); - if (params_size != other_params_size) { - return false; // Parameter list size mismatch. - } - for (uint32_t i = 0; i < params_size; ++i) { - const DexFile::TypeId& param_id = dex_file.GetTypeId(params->GetTypeItem(i).type_idx_); - const DexFile::TypeId& other_param_id = - other_dex_file.GetTypeId(other_params->GetTypeItem(i).type_idx_); - if (dex_file.StringDataAsStringPieceByIdx(param_id.descriptor_idx_) != - other_dex_file.StringDataAsStringPieceByIdx(other_param_id.descriptor_idx_)) { - return false; // Parameter type mismatch. - } - } - return true; + return dex_file.GetMethodSignature(mid) == other_dex_file.GetMethodSignature(other_mid); } const DexFile::CodeItem* GetCodeItem() diff --git a/runtime/trace.cc b/runtime/trace.cc index 7b25306177..ec95a87146 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -667,7 +667,7 @@ void Trace::DumpMethodList(std::ostream& os, const std::set& mh.ChangeMethod(method); os << StringPrintf("%p\t%s\t%s\t%s\t%s\n", method, PrettyDescriptor(mh.GetDeclaringClassDescriptor()).c_str(), mh.GetName(), - mh.GetSignature().c_str(), mh.GetDeclaringClassSourceFile()); + mh.GetSignature().ToString().c_str(), mh.GetDeclaringClassSourceFile()); } } diff --git a/runtime/utils.cc b/runtime/utils.cc index 23dcde3065..b97239fd18 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -367,11 +367,13 @@ std::string PrettyMethod(const mirror::ArtMethod* m, bool with_signature) { result += '.'; result += mh.GetName(); if (with_signature) { - std::string signature(mh.GetSignature()); - if (signature == "") { - return result + signature; + const Signature signature = mh.GetSignature(); + std::string sig_as_string(signature.ToString()); + if (signature == Signature::NoSignature()) { + return result + sig_as_string; } - result = PrettyReturnType(signature.c_str()) + " " + result + PrettyArguments(signature.c_str()); + result = PrettyReturnType(sig_as_string.c_str()) + " " + result + + PrettyArguments(sig_as_string.c_str()); } return result; } @@ -385,11 +387,13 @@ std::string PrettyMethod(uint32_t method_idx, const DexFile& dex_file, bool with result += '.'; result += dex_file.GetMethodName(method_id); if (with_signature) { - std::string signature(dex_file.GetMethodSignature(method_id)); - if (signature == "") { - return result + signature; + const Signature signature = dex_file.GetMethodSignature(method_id); + std::string sig_as_string(signature.ToString()); + if (signature == Signature::NoSignature()) { + return result + sig_as_string; } - result = PrettyReturnType(signature.c_str()) + " " + result + PrettyArguments(signature.c_str()); + result = PrettyReturnType(sig_as_string.c_str()) + " " + result + + PrettyArguments(sig_as_string.c_str()); } return result; } @@ -641,7 +645,7 @@ std::string JniLongName(const mirror::ArtMethod* m) { long_name += JniShortName(m); long_name += "__"; - std::string signature(MethodHelper(m).GetSignature()); + std::string signature(MethodHelper(m).GetSignature().ToString()); signature.erase(0, 1); signature.erase(signature.begin() + signature.find(')'), signature.end()); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 6b13517fdc..36b409d142 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -2910,7 +2910,7 @@ const RegType& MethodVerifier::GetCaughtExceptionType() { } mirror::ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(uint32_t dex_method_idx, - MethodType method_type) { + MethodType method_type) { const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx); const RegType& klass_type = ResolveClassAndCheckAccess(method_id.class_idx_); if (klass_type.IsConflict()) { @@ -2927,7 +2927,7 @@ mirror::ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess(uint32_t dex_meth mirror::ArtMethod* res_method = dex_cache_->GetResolvedMethod(dex_method_idx); if (res_method == NULL) { const char* name = dex_file_->GetMethodName(method_id); - std::string signature(dex_file_->CreateMethodSignature(method_id.proto_idx_, NULL)); + const Signature signature = dex_file_->GetMethodSignature(method_id); if (method_type == METHOD_DIRECT || method_type == METHOD_STATIC) { res_method = klass->FindDirectMethod(name, signature); diff --git a/test/Android.mk b/test/Android.mk index 6f498e8c02..08ec03a01a 100644 --- a/test/Android.mk +++ b/test/Android.mk @@ -23,8 +23,8 @@ include art/build/Android.common.mk TEST_DEX_DIRECTORIES := \ AbstractMethod \ AllFields \ - CreateMethodSignature \ ExceptionHandle \ + GetMethodSignature \ Interfaces \ Main \ MyClass \ diff --git a/test/CreateMethodSignature/CreateMethodSignature.java b/test/CreateMethodSignature/CreateMethodSignature.java deleted file mode 100644 index f6cd6ae6fd..0000000000 --- a/test/CreateMethodSignature/CreateMethodSignature.java +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -class CreateMethodSignature { - Float m1(int a, double b, long c, Object d) { return null; } - CreateMethodSignature m2(boolean x, short y, char z) { return null; } -} diff --git a/test/GetMethodSignature/GetMethodSignature.java b/test/GetMethodSignature/GetMethodSignature.java new file mode 100644 index 0000000000..c2ba948d60 --- /dev/null +++ b/test/GetMethodSignature/GetMethodSignature.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +class GetMethodSignature { + Float m1(int a, double b, long c, Object d) { return null; } + GetMethodSignature m2(boolean x, short y, char z) { return null; } +} -- cgit v1.2.3-59-g8ed1b From e732ef1c0192acd71925bd0ff1ab09640d45531d Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 9 Oct 2013 15:22:24 -0700 Subject: Make compiler stat dumping easier to use. Previous needed -verbose:compiler + a debug build. Now specify --dump-stats to dex2oat. Change-Id: Ifde379e7cd06bbb0fe20149ce89c3b3789221eac --- compiler/driver/compiler_driver.cc | 2 +- dex2oat/dex2oat.cc | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 056be1fb04..7c4a6ce785 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -64,7 +64,7 @@ static void DumpStat(size_t x, size_t y, const char* str) { if (x == 0 && y == 0) { return; } - VLOG(compiler) << Percentage(x, y) << "% of " << str << " for " << (x + y) << " cases"; + LOG(INFO) << Percentage(x, y) << "% of " << str << " for " << (x + y) << " cases"; } class AOTCompilationStats { diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index c4cce2ff73..d5d1303f55 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -604,7 +604,7 @@ static int dex2oat(int argc, char** argv) { #error "Unsupported architecture" #endif bool is_host = false; - bool dump_stats = kIsDebugBuild; + bool dump_stats = false; bool dump_timing = false; bool dump_slow_timing = kIsDebugBuild; bool watch_dog_enabled = !kIsTargetBuild; @@ -696,6 +696,8 @@ static int dex2oat(int argc, char** argv) { runtime_args.push_back(argv[i]); } else if (option == "--dump-timing") { dump_timing = true; + } else if (option == "--dump-stats") { + dump_stats = true; } else { Usage("Unknown argument %s", option.data()); } -- cgit v1.2.3-59-g8ed1b From 83883d7fddf30fdb8b6903560fa1337ab991e74c Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Mon, 21 Oct 2013 21:07:24 -0700 Subject: Populate dex cache for sharpened calls. We ensured the resolved method was in the dex cache, but for a sharpened call this is abstract. Ensure that the concrete method is also resolved. Limit the use of direct dex cache based dispatch to cases where we know how to patch the dex cache. Bug 11389002 Change-Id: I08252686a53b5948650632837c74bcd5cbf8a862 --- compiler/dex/quick/gen_invoke.cc | 14 +- compiler/driver/compiler_driver.cc | 210 ++++++++++----------- compiler/driver/compiler_driver.h | 4 +- .../quick/quick_trampoline_entrypoints.cc | 16 ++ runtime/object_utils.h | 40 ++++ 5 files changed, 168 insertions(+), 116 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 64938f3a73..62feadedcc 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -350,16 +350,13 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info, uintptr_t direct_code, uintptr_t direct_method, InvokeType type) { Mir2Lir* cg = static_cast(cu->cg.get()); - if (cu->instruction_set != kThumb2) { - // Disable sharpening - direct_code = 0; - direct_method = 0; - } if (direct_code != 0 && direct_method != 0) { switch (state) { case 0: // Get the current Method* [sets kArg0] if (direct_code != static_cast(-1)) { - cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code); + if (cu->instruction_set != kX86) { + cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code); + } } else { CHECK_EQ(cu->dex_file, target_method.dex_file); LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, @@ -405,6 +402,7 @@ static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info, cg->LoadConstant(cg->TargetReg(kInvokeTgt), direct_code); } else { CHECK_EQ(cu->dex_file, target_method.dex_file); + CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds()); LIR* data_target = cg->ScanLiteralPool(cg->code_literal_list_, target_method.dex_method_index, 0); if (data_target == NULL) { @@ -501,10 +499,6 @@ static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state, uint32_t unused, uintptr_t unused2, uintptr_t direct_method, InvokeType unused4) { Mir2Lir* cg = static_cast(cu->cg.get()); - if (cu->instruction_set != kThumb2) { - // Disable sharpening - direct_method = 0; - } ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline); if (direct_method != 0) { diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 7c4a6ce785..e618307e72 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -355,7 +355,7 @@ CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet jni_compiler_(NULL), compiler_enable_auto_elf_loading_(NULL), compiler_get_method_code_addr_(NULL), - support_boot_image_fixup_(true), + support_boot_image_fixup_(instruction_set == kThumb2), dedupe_code_("dedupe code"), dedupe_mapping_table_("dedupe mapping table"), dedupe_vmap_table_("dedupe vmap table"), @@ -1058,10 +1058,12 @@ bool CompilerDriver::ComputeStaticFieldInfo(uint32_t field_idx, const DexCompila return false; // Incomplete knowledge needs slow path. } -void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type, +void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType sharp_type, + bool no_guarantee_of_dex_cache_entry, mirror::Class* referrer_class, mirror::ArtMethod* method, bool update_stats, + MethodReference* target_method, uintptr_t* direct_code, uintptr_t* direct_method) { // For direct and static methods compute possible direct_code and direct_method values, ie @@ -1070,46 +1072,103 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType type, InvokeType s // invoked, so this can be passed to the out-of-line runtime support code. *direct_code = 0; *direct_method = 0; + bool use_dex_cache = false; + bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1; if (compiler_backend_ == kPortable) { if (sharp_type != kStatic && sharp_type != kDirect) { return; } + use_dex_cache = true; } else { if (sharp_type != kStatic && sharp_type != kDirect && sharp_type != kInterface) { return; } + // TODO: support patching on all architectures. + use_dex_cache = compiling_boot && !support_boot_image_fixup_; } - bool method_code_in_boot = method->GetDeclaringClass()->GetClassLoader() == NULL; - if (!method_code_in_boot) { - return; + bool method_code_in_boot = (method->GetDeclaringClass()->GetClassLoader() == nullptr); + if (!use_dex_cache) { + if (!method_code_in_boot) { + use_dex_cache = true; + } else { + bool has_clinit_trampoline = + method->IsStatic() && !method->GetDeclaringClass()->IsInitialized(); + if (has_clinit_trampoline && (method->GetDeclaringClass() != referrer_class)) { + // Ensure we run the clinit trampoline unless we are invoking a static method in the same + // class. + use_dex_cache = true; + } + } } - bool has_clinit_trampoline = method->IsStatic() && !method->GetDeclaringClass()->IsInitialized(); - if (has_clinit_trampoline && (method->GetDeclaringClass() != referrer_class)) { - // Ensure we run the clinit trampoline unless we are invoking a static method in the same class. - return; + if (update_stats && method_code_in_boot) { + if (sharp_type != kInterface) { // Interfaces always go via a trampoline until we get IMTs. + stats_->DirectCallsToBoot(*type); + } + stats_->DirectMethodsToBoot(*type); } - if (update_stats) { - if (sharp_type != kInterface) { // Interfaces always go via a trampoline. - stats_->DirectCallsToBoot(type); + if (!use_dex_cache && compiling_boot) { + MethodHelper mh(method); + if (!IsImageClass(mh.GetDeclaringClassDescriptorAsStringPiece())) { + // We can only branch directly to Methods that are resolved in the DexCache. + // Otherwise we won't invoke the resolution trampoline. + use_dex_cache = true; } - stats_->DirectMethodsToBoot(type); } - bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1; - if (compiling_boot) { - if (support_boot_image_fixup_) { - MethodHelper mh(method); - if (IsImageClass(mh.GetDeclaringClassDescriptorAsStringPiece())) { - // We can only branch directly to Methods that are resolved in the DexCache. - // Otherwise we won't invoke the resolution trampoline. - *direct_method = -1; - *direct_code = -1; + // The method is defined not within this dex file. We need a dex cache slot within the current + // dex file or direct pointers. + bool must_use_direct_pointers = false; + if (target_method->dex_file == method->GetDeclaringClass()->GetDexCache()->GetDexFile()) { + target_method->dex_method_index = method->GetDexMethodIndex(); + } else { + // TODO: support patching from one dex file to another in the boot image. + use_dex_cache = use_dex_cache || compiling_boot; + if (no_guarantee_of_dex_cache_entry) { + // See if the method is also declared in this dex cache. + uint32_t dex_method_idx = MethodHelper(method).FindDexMethodIndexInOtherDexFile( + *referrer_class->GetDexCache()->GetDexFile()); + if (dex_method_idx != DexFile::kDexNoIndex) { + target_method->dex_method_index = dex_method_idx; + } else { + must_use_direct_pointers = true; } } + } + if (use_dex_cache) { + if (must_use_direct_pointers) { + // Fail. Test above showed the only safe dispatch was via the dex cache, however, the direct + // pointers are required as the dex cache lacks an appropriate entry. + VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method); + } else { + *type = sharp_type; + } } else { - if (Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace()) { - *direct_method = reinterpret_cast(method); + if (compiling_boot) { + *type = sharp_type; + *direct_method = -1; + if (sharp_type != kInterface) { + *direct_code = -1; + } + } else { + bool method_in_image = + Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace(); + if (method_in_image) { + CHECK_EQ(method->IsAbstract(), sharp_type == kInterface); + *type = sharp_type; + *direct_method = reinterpret_cast(method); + if (*type != kInterface) { + *direct_code = reinterpret_cast(method->GetEntryPointFromCompiledCode()); + } + target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile(); + target_method->dex_method_index = method->GetDexMethodIndex(); + } else if (!must_use_direct_pointers) { + // Set the code and rely on the dex cache for the method. + *type = sharp_type; + *direct_code = reinterpret_cast(method->GetEntryPointFromCompiledCode()); + } else { + // Direct pointers were required but none were available. + VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method); + } } - *direct_code = reinterpret_cast(method->GetEntryPointFromCompiledCode()); } } @@ -1126,6 +1185,9 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui ComputeMethodReferencedFromCompilingMethod(soa, mUnit, target_method->dex_method_index, *invoke_type); if (resolved_method != NULL) { + if (*invoke_type == kVirtual || *invoke_type == kSuper) { + *vtable_idx = resolved_method->GetMethodIndex(); + } // Don't try to fast-path if we don't understand the caller's class or this appears to be an // Incompatible Class Change Error. mirror::Class* referrer_class = @@ -1166,13 +1228,14 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui // dex cache, check that this resolved method is where we expect it. CHECK(referrer_class->GetDexCache()->GetResolvedMethod(target_method->dex_method_index) == resolved_method) << PrettyMethod(resolved_method); - if (update_stats) { - stats_->ResolvedMethod(*invoke_type); - stats_->VirtualMadeDirect(*invoke_type); + InvokeType orig_invoke_type = *invoke_type; + GetCodeAndMethodForDirectCall(invoke_type, kDirect, false, referrer_class, resolved_method, + update_stats, target_method, direct_code, direct_method); + if (update_stats && (*invoke_type == kDirect)) { + stats_->ResolvedMethod(orig_invoke_type); + stats_->VirtualMadeDirect(orig_invoke_type); } - GetCodeAndMethodForDirectCall(*invoke_type, kDirect, referrer_class, resolved_method, - update_stats, direct_code, direct_method); - *invoke_type = kDirect; + DCHECK_NE(*invoke_type, kSuper) << PrettyMethod(resolved_method); return true; } const bool enableVerifierBasedSharpening = enable_devirtualization; @@ -1194,76 +1257,16 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui kVirtual); CHECK(called_method != NULL); CHECK(!called_method->IsAbstract()); - GetCodeAndMethodForDirectCall(*invoke_type, kDirect, referrer_class, called_method, - update_stats, direct_code, direct_method); - bool compiler_needs_dex_cache = - (GetCompilerBackend() == kPortable) || - (GetCompilerBackend() == kQuick && instruction_set_ != kThumb2) || - (*direct_code == 0) || (*direct_code == static_cast(-1)) || - (*direct_method == 0) || (*direct_method == static_cast(-1)); - if ((devirt_map_target->dex_file != target_method->dex_file) && - compiler_needs_dex_cache) { - // We need to use the dex cache to find either the method or code, and the dex file - // containing the method isn't the one expected for the target method. Try to find - // the method within the expected target dex file. - // TODO: the -1 could be handled as direct code if the patching new the target dex - // file. - // TODO: quick only supports direct pointers with Thumb2. - // TODO: the following should be factored into a common helper routine to find - // one dex file's method within another. - const DexFile* dexfile = target_method->dex_file; - const DexFile* cm_dexfile = - called_method->GetDeclaringClass()->GetDexCache()->GetDexFile(); - const DexFile::MethodId& cm_method_id = - cm_dexfile->GetMethodId(called_method->GetDexMethodIndex()); - const char* cm_descriptor = cm_dexfile->StringByTypeIdx(cm_method_id.class_idx_); - const DexFile::StringId* descriptor = dexfile->FindStringId(cm_descriptor); - if (descriptor != NULL) { - const DexFile::TypeId* type_id = - dexfile->FindTypeId(dexfile->GetIndexForStringId(*descriptor)); - if (type_id != NULL) { - const char* cm_name = cm_dexfile->GetMethodName(cm_method_id); - const DexFile::StringId* name = dexfile->FindStringId(cm_name); - if (name != NULL) { - uint16_t return_type_idx; - std::vector param_type_idxs; - bool success = - dexfile->CreateTypeList(cm_dexfile->GetMethodSignature(cm_method_id).ToString(), - &return_type_idx, ¶m_type_idxs); - if (success) { - const DexFile::ProtoId* sig = - dexfile->FindProtoId(return_type_idx, param_type_idxs); - if (sig != NULL) { - const DexFile::MethodId* method_id = dexfile->FindMethodId(*type_id, - *name, *sig); - if (method_id != NULL) { - if (update_stats) { - stats_->ResolvedMethod(*invoke_type); - stats_->VirtualMadeDirect(*invoke_type); - stats_->PreciseTypeDevirtualization(); - } - target_method->dex_method_index = - dexfile->GetIndexForMethodId(*method_id); - *invoke_type = kDirect; - return true; - } - } - } - } - } - } - // TODO: the stats for direct code and method are off as we failed to find the direct - // method in the referring method's dex cache/file. - } else { - if (update_stats) { - stats_->ResolvedMethod(*invoke_type); - stats_->VirtualMadeDirect(*invoke_type); - stats_->PreciseTypeDevirtualization(); - } - *target_method = *devirt_map_target; - *invoke_type = kDirect; - return true; + InvokeType orig_invoke_type = *invoke_type; + GetCodeAndMethodForDirectCall(invoke_type, kDirect, true, referrer_class, called_method, + update_stats, target_method, direct_code, direct_method); + if (update_stats && (*invoke_type == kDirect)) { + stats_->ResolvedMethod(orig_invoke_type); + stats_->VirtualMadeDirect(orig_invoke_type); + stats_->PreciseTypeDevirtualization(); } + DCHECK_NE(*invoke_type, kSuper); + return true; } } if (*invoke_type == kSuper) { @@ -1273,11 +1276,8 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui if (update_stats) { stats_->ResolvedMethod(*invoke_type); } - if (*invoke_type == kVirtual || *invoke_type == kSuper) { - *vtable_idx = resolved_method->GetMethodIndex(); - } - GetCodeAndMethodForDirectCall(*invoke_type, *invoke_type, referrer_class, resolved_method, - update_stats, direct_code, direct_method); + GetCodeAndMethodForDirectCall(invoke_type, *invoke_type, false, referrer_class, resolved_method, + update_stats, target_method, direct_code, direct_method); return true; } } diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 7657af5cee..971021f903 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -321,10 +321,12 @@ class CompilerDriver { private: // Compute constant code and method pointers when possible - void GetCodeAndMethodForDirectCall(InvokeType type, InvokeType sharp_type, + void GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType sharp_type, + bool no_guarantee_of_dex_cache_entry, mirror::Class* referrer_class, mirror::ArtMethod* method, bool update_stats, + MethodReference* target_method, uintptr_t* direct_code, uintptr_t* direct_method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 12291c39a9..01d3549985 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -19,6 +19,7 @@ #include "dex_file-inl.h" #include "dex_instruction-inl.h" #include "entrypoints/entrypoint_utils.h" +#include "gc/accounting/card_table-inl.h" #include "interpreter/interpreter.h" #include "invoke_arg_array_builder.h" #include "mirror/art_method-inl.h" @@ -547,6 +548,21 @@ extern "C" const void* artQuickResolutionTrampoline(mirror::ArtMethod* called, } else if (invoke_type == kInterface) { called = receiver->GetClass()->FindVirtualMethodForInterface(called); } + if ((invoke_type == kVirtual) || (invoke_type == kInterface)) { + // We came here because of sharpening. Ensure the dex cache is up-to-date on the method index + // of the sharpened method. + if (called->GetDexCacheResolvedMethods() == caller->GetDexCacheResolvedMethods()) { + caller->GetDexCacheResolvedMethods()->Set(called->GetDexMethodIndex(), called); + } else { + // Calling from one dex file to another, need to compute the method index appropriate to + // the caller's dex file. + uint32_t method_index = + MethodHelper(called).FindDexMethodIndexInOtherDexFile(MethodHelper(caller).GetDexFile()); + if (method_index != DexFile::kDexNoIndex) { + caller->GetDexCacheResolvedMethods()->Set(method_index, called); + } + } + } // Ensure that the called method's class is initialized. mirror::Class* called_class = called->GetDeclaringClass(); linker->EnsureInitialized(called_class, true, true); diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 8062a890c2..3ca3c0bcf3 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -700,6 +700,46 @@ class MethodHelper { return s; } + uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + const DexFile& dexfile = GetDexFile(); + if (&dexfile == &other_dexfile) { + return method_->GetDexMethodIndex(); + } + const DexFile::MethodId& mid = dexfile.GetMethodId(method_->GetDexMethodIndex()); + const char* mid_declaring_class_descriptor = dexfile.StringByTypeIdx(mid.class_idx_); + const DexFile::StringId* other_descriptor = + other_dexfile.FindStringId(mid_declaring_class_descriptor); + if (other_descriptor != nullptr) { + const DexFile::TypeId* other_type_id = + other_dexfile.FindTypeId(other_dexfile.GetIndexForStringId(*other_descriptor)); + if (other_type_id != nullptr) { + const char* mid_name = dexfile.GetMethodName(mid); + const DexFile::StringId* other_name = other_dexfile.FindStringId(mid_name); + if (other_name != nullptr) { + uint16_t other_return_type_idx; + std::vector other_param_type_idxs; + bool success = other_dexfile.CreateTypeList(dexfile.GetMethodSignature(mid).ToString(), + &other_return_type_idx, + &other_param_type_idxs); + if (success) { + const DexFile::ProtoId* other_sig = + other_dexfile.FindProtoId(other_return_type_idx, other_param_type_idxs); + if (other_sig != nullptr) { + const DexFile::MethodId* other_mid = other_dexfile.FindMethodId(*other_type_id, + *other_name, + *other_sig); + if (other_mid != nullptr) { + return other_dexfile.GetIndexForMethodId(*other_mid); + } + } + } + } + } + } + return DexFile::kDexNoIndex; + } + private: // Set the method_ field, for proxy methods looking up the interface method via the resolved // methods table. -- cgit v1.2.3-59-g8ed1b From 39d0c0d02dc11d10974d368ffd18068ad7d2029a Mon Sep 17 00:00:00 2001 From: Brian Carlstrom Date: Mon, 28 Oct 2013 12:13:34 -0700 Subject: Update black list with android.os.Bundle Bug: 11415283 Change-Id: I5a8c580f0e1d029c995faac3ec332083de7b8646 --- compiler/driver/compiler_driver.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 6eabeed34b..bea94a74df 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1746,6 +1746,7 @@ static const char* class_initializer_black_list[] = { "Landroid/opengl/GLUtils;", // Calls android.opengl.GLUtils.nativeClassInit. "Landroid/os/Build;", // Calls -..-> android.os.SystemProperties.native_get. "Landroid/os/Build$VERSION;", // Requires Build. + "Landroid/os/Bundle;", // Calls android.os.Parcel.obtain -..> Parcel.nativeCreate. "Landroid/os/Debug;", // Requires android.os.Environment. "Landroid/os/Environment;", // Calls System.getenv. "Landroid/os/FileUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl. -- cgit v1.2.3-59-g8ed1b From 88474b416eb257078e590bf9bc7957cee604a186 Mon Sep 17 00:00:00 2001 From: Jeff Hao Date: Wed, 23 Oct 2013 16:24:40 -0700 Subject: Implement Interface Method Tables (IMT). Change-Id: Idf7fe85e1293453a8ad862ff2380dcd5db4e3a39 --- compiler/dex/compiler_enums.h | 2 + compiler/dex/quick/arm/target_arm.cc | 2 + compiler/dex/quick/gen_invoke.cc | 101 +++++++++------------ compiler/dex/quick/mips/target_mips.cc | 2 + compiler/dex/quick/x86/target_x86.cc | 2 + compiler/driver/compiler_driver.cc | 28 +++--- compiler/driver/compiler_driver.h | 4 + compiler/image_writer.cc | 12 +++ compiler/image_writer.h | 5 +- compiler/oat_test.cc | 2 +- compiler/oat_writer.cc | 10 ++ compiler/oat_writer.h | 4 + dex2oat/dex2oat.cc | 4 - oatdump/oatdump.cc | 5 +- runtime/arch/arm/entrypoints_init_arm.cc | 4 +- runtime/arch/arm/quick_entrypoints_arm.S | 12 +++ runtime/arch/mips/entrypoints_init_mips.cc | 4 +- runtime/arch/mips/quick_entrypoints_mips.S | 15 +++ runtime/arch/x86/entrypoints_init_x86.cc | 4 +- runtime/arch/x86/quick_entrypoints_x86.S | 14 +++ runtime/asm_support.h | 3 +- runtime/class_linker.cc | 39 +++++++- runtime/class_linker.h | 19 ++++ runtime/class_linker_test.cc | 7 +- runtime/common_test.h | 3 - runtime/entrypoints/entrypoint_utils.h | 38 ++++++-- .../entrypoints/portable/portable_entrypoints.h | 1 + runtime/entrypoints/quick/quick_entrypoints.h | 2 +- runtime/gc/space/image_space.cc | 4 + runtime/image.h | 2 + runtime/mirror/art_method-inl.h | 7 ++ runtime/mirror/art_method.h | 2 + runtime/mirror/class-inl.h | 8 ++ runtime/mirror/class.h | 13 +++ runtime/mirror/object_test.cc | 1 + runtime/mirror/string.h | 2 +- runtime/oat.cc | 50 +++++++++- runtime/oat.h | 8 ++ runtime/object_utils.h | 2 + runtime/runtime.cc | 31 +++++++ runtime/runtime.h | 38 ++++++++ runtime/thread.cc | 3 +- test/100-reflect2/expected.txt | 2 +- test/Android.mk | 1 + test/InterfaceTest/InterfaceTest.java | 53 +++++++++++ 45 files changed, 468 insertions(+), 107 deletions(-) create mode 100644 test/InterfaceTest/InterfaceTest.java (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h index 6ea21fc586..56facfd889 100644 --- a/compiler/dex/compiler_enums.h +++ b/compiler/dex/compiler_enums.h @@ -44,6 +44,8 @@ enum SpecialTargetRegister { kRet0, kRet1, kInvokeTgt, + kHiddenArg, + kHiddenFpArg, kCount }; diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc index 3395ae7a44..52aba9b4df 100644 --- a/compiler/dex/quick/arm/target_arm.cc +++ b/compiler/dex/quick/arm/target_arm.cc @@ -74,6 +74,8 @@ int ArmMir2Lir::TargetReg(SpecialTargetRegister reg) { case kRet0: res = rARM_RET0; break; case kRet1: res = rARM_RET1; break; case kInvokeTgt: res = rARM_INVOKE_TGT; break; + case kHiddenArg: res = r12; break; + case kHiddenFpArg: res = INVALID_REG; break; case kCount: res = rARM_COUNT; break; } return res; diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 62feadedcc..0a5fbb1f17 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -491,69 +491,56 @@ static int NextVCallInsn(CompilationUnit* cu, CallInfo* info, } /* - * All invoke-interface calls bounce off of art_quick_invoke_interface_trampoline, - * which will locate the target and continue on via a tail call. + * Emit the next instruction in an invoke interface sequence. This will do a lookup in the + * class's IMT, calling either the actual method or art_quick_imt_conflict_trampoline if + * more than one interface method map to the same index. Note also that we'll load the first + * argument ("this") into kArg1 here rather than the standard LoadArgRegs. */ static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state, const MethodReference& target_method, - uint32_t unused, uintptr_t unused2, - uintptr_t direct_method, InvokeType unused4) { + uint32_t method_idx, uintptr_t unused, + uintptr_t direct_method, InvokeType unused2) { Mir2Lir* cg = static_cast(cu->cg.get()); - ThreadOffset trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline); - if (direct_method != 0) { - switch (state) { - case 0: // Load the trampoline target [sets kInvokeTgt]. - if (cu->instruction_set != kX86) { - cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline.Int32Value(), - cg->TargetReg(kInvokeTgt)); - } - // Get the interface Method* [sets kArg0] - if (direct_method != static_cast(-1)) { - cg->LoadConstant(cg->TargetReg(kArg0), direct_method); - } else { - CHECK_EQ(cu->dex_file, target_method.dex_file); - LIR* data_target = cg->ScanLiteralPool(cg->method_literal_list_, - target_method.dex_method_index, 0); - if (data_target == NULL) { - data_target = cg->AddWordData(&cg->method_literal_list_, - target_method.dex_method_index); - data_target->operands[1] = kInterface; - } - LIR* load_pc_rel = cg->OpPcRelLoad(cg->TargetReg(kArg0), data_target); - cg->AppendLIR(load_pc_rel); - DCHECK_EQ(cu->instruction_set, kThumb2) << reinterpret_cast(data_target); - } - break; - default: - return -1; + switch (state) { + case 0: // Set target method index in case of conflict [set kHiddenArg, kHiddenFpArg (x86)] + CHECK_EQ(cu->dex_file, target_method.dex_file); + CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds()); + cg->LoadConstant(cg->TargetReg(kHiddenArg), target_method.dex_method_index); + if (cu->instruction_set == kX86) { + cg->OpRegCopy(cg->TargetReg(kHiddenFpArg), cg->TargetReg(kHiddenArg)); + } + break; + case 1: { // Get "this" [set kArg1] + RegLocation rl_arg = info->args[0]; + cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1)); + break; } - } else { - switch (state) { - case 0: - // Get the current Method* [sets kArg0] - TUNING: remove copy of method if it is promoted. - cg->LoadCurrMethodDirect(cg->TargetReg(kArg0)); - // Load the trampoline target [sets kInvokeTgt]. - if (cu->instruction_set != kX86) { - cg->LoadWordDisp(cg->TargetReg(kSelf), trampoline.Int32Value(), - cg->TargetReg(kInvokeTgt)); - } - break; - case 1: // Get method->dex_cache_resolved_methods_ [set/use kArg0] - cg->LoadWordDisp(cg->TargetReg(kArg0), - mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(), - cg->TargetReg(kArg0)); + case 2: // Is "this" null? [use kArg1] + cg->GenNullCheck(info->args[0].s_reg_low, cg->TargetReg(kArg1), info->opt_flags); + // Get this->klass_ [use kArg1, set kInvokeTgt] + cg->LoadWordDisp(cg->TargetReg(kArg1), mirror::Object::ClassOffset().Int32Value(), + cg->TargetReg(kInvokeTgt)); break; - case 2: // Grab target method* [set/use kArg0] - CHECK_EQ(cu->dex_file, target_method.dex_file); - cg->LoadWordDisp(cg->TargetReg(kArg0), - mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + - (target_method.dex_method_index * 4), + case 3: // Get this->klass_->imtable [use kInvokeTgt, set kInvokeTgt] + cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), mirror::Class::ImTableOffset().Int32Value(), + cg->TargetReg(kInvokeTgt)); + break; + case 4: // Get target method [use kInvokeTgt, set kArg0] + cg->LoadWordDisp(cg->TargetReg(kInvokeTgt), ((method_idx % ClassLinker::kImtSize) * 4) + + mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value(), cg->TargetReg(kArg0)); break; + case 5: // Get the compiled code address [use kArg0, set kInvokeTgt] + if (cu->instruction_set != kX86) { + cg->LoadWordDisp(cg->TargetReg(kArg0), + mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value(), + cg->TargetReg(kInvokeTgt)); + break; + } + // Intentional fallthrough for X86 default: return -1; - } } return state + 1; } @@ -1390,11 +1377,8 @@ void Mir2Lir::GenInvoke(CallInfo* info) { &vtable_idx, &direct_code, &direct_method) && !SLOW_INVOKE_PATH; if (info->type == kInterface) { - if (fast_path) { - p_null_ck = &null_ck; - } next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck; - skip_this = false; + skip_this = fast_path; } else if (info->type == kDirect) { if (fast_path) { p_null_ck = &null_ck; @@ -1434,15 +1418,14 @@ void Mir2Lir::GenInvoke(CallInfo* info) { if (cu_->instruction_set != kX86) { call_inst = OpReg(kOpBlx, TargetReg(kInvokeTgt)); } else { - if (fast_path && info->type != kInterface) { + if (fast_path) { call_inst = OpMem(kOpBlx, TargetReg(kArg0), mirror::ArtMethod::GetEntryPointFromCompiledCodeOffset().Int32Value()); } else { ThreadOffset trampoline(-1); switch (info->type) { case kInterface: - trampoline = fast_path ? QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline) - : QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck); + trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeInterfaceTrampolineWithAccessCheck); break; case kDirect: trampoline = QUICK_ENTRYPOINT_OFFSET(pInvokeDirectTrampolineWithAccessCheck); diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc index 0ee32d4d21..9c598e6bee 100644 --- a/compiler/dex/quick/mips/target_mips.cc +++ b/compiler/dex/quick/mips/target_mips.cc @@ -76,6 +76,8 @@ int MipsMir2Lir::TargetReg(SpecialTargetRegister reg) { case kRet0: res = rMIPS_RET0; break; case kRet1: res = rMIPS_RET1; break; case kInvokeTgt: res = rMIPS_INVOKE_TGT; break; + case kHiddenArg: res = r_T0; break; + case kHiddenFpArg: res = INVALID_REG; break; case kCount: res = rMIPS_COUNT; break; } return res; diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index 901ac9e69d..878fa769b6 100644 --- a/compiler/dex/quick/x86/target_x86.cc +++ b/compiler/dex/quick/x86/target_x86.cc @@ -85,6 +85,8 @@ int X86Mir2Lir::TargetReg(SpecialTargetRegister reg) { case kRet0: res = rX86_RET0; break; case kRet1: res = rX86_RET1; break; case kInvokeTgt: res = rX86_INVOKE_TGT; break; + case kHiddenArg: res = rAX; break; + case kHiddenFpArg: res = fr0; break; case kCount: res = rX86_COUNT; break; } return res; diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 91b0188b7b..053ea16fe8 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -469,6 +469,11 @@ const std::vector* CompilerDriver::CreateJniDlsymLookup() const { return CreateTrampoline(instruction_set_, kJniAbi, JNI_ENTRYPOINT_OFFSET(pDlsymLookup)); } +const std::vector* CompilerDriver::CreatePortableImtConflictTrampoline() const { + return CreateTrampoline(instruction_set_, kPortableAbi, + PORTABLE_ENTRYPOINT_OFFSET(pPortableImtConflictTrampoline)); +} + const std::vector* CompilerDriver::CreatePortableResolutionTrampoline() const { return CreateTrampoline(instruction_set_, kPortableAbi, PORTABLE_ENTRYPOINT_OFFSET(pPortableResolutionTrampoline)); @@ -479,6 +484,11 @@ const std::vector* CompilerDriver::CreatePortableToInterpreterBridge() PORTABLE_ENTRYPOINT_OFFSET(pPortableToInterpreterBridge)); } +const std::vector* CompilerDriver::CreateQuickImtConflictTrampoline() const { + return CreateTrampoline(instruction_set_, kQuickAbi, + QUICK_ENTRYPOINT_OFFSET(pQuickImtConflictTrampoline)); +} + const std::vector* CompilerDriver::CreateQuickResolutionTrampoline() const { return CreateTrampoline(instruction_set_, kQuickAbi, QUICK_ENTRYPOINT_OFFSET(pQuickResolutionTrampoline)); @@ -1080,7 +1090,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType } use_dex_cache = true; } else { - if (sharp_type != kStatic && sharp_type != kDirect && sharp_type != kInterface) { + if (sharp_type != kStatic && sharp_type != kDirect) { return; } // TODO: support patching on all architectures. @@ -1101,9 +1111,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType } } if (update_stats && method_code_in_boot) { - if (sharp_type != kInterface) { // Interfaces always go via a trampoline until we get IMTs. - stats_->DirectCallsToBoot(*type); - } + stats_->DirectCallsToBoot(*type); stats_->DirectMethodsToBoot(*type); } if (!use_dex_cache && compiling_boot) { @@ -1145,19 +1153,15 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType if (compiling_boot) { *type = sharp_type; *direct_method = -1; - if (sharp_type != kInterface) { - *direct_code = -1; - } + *direct_code = -1; } else { bool method_in_image = Runtime::Current()->GetHeap()->FindSpaceFromObject(method, false)->IsImageSpace(); if (method_in_image) { - CHECK_EQ(method->IsAbstract(), sharp_type == kInterface); + CHECK(!method->IsAbstract()); *type = sharp_type; *direct_method = reinterpret_cast(method); - if (*type != kInterface) { - *direct_code = reinterpret_cast(method->GetEntryPointFromCompiledCode()); - } + *direct_code = reinterpret_cast(method->GetEntryPointFromCompiledCode()); target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile(); target_method->dex_method_index = method->GetDexMethodIndex(); } else if (!must_use_direct_pointers) { @@ -1187,6 +1191,8 @@ bool CompilerDriver::ComputeInvokeInfo(const DexCompilationUnit* mUnit, const ui if (resolved_method != NULL) { if (*invoke_type == kVirtual || *invoke_type == kSuper) { *vtable_idx = resolved_method->GetMethodIndex(); + } else if (*invoke_type == kInterface) { + *vtable_idx = resolved_method->GetDexMethodIndex(); } // Don't try to fast-path if we don't understand the caller's class or this appears to be an // Incompatible Class Change Error. diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 971021f903..c79175394a 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -130,10 +130,14 @@ class CompilerDriver { SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const std::vector* CreateJniDlsymLookup() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const std::vector* CreatePortableImtConflictTrampoline() const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const std::vector* CreatePortableResolutionTrampoline() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const std::vector* CreatePortableToInterpreterBridge() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const std::vector* CreateQuickImtConflictTrampoline() const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const std::vector* CreateQuickResolutionTrampoline() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); const std::vector* CreateQuickToInterpreterBridge() const diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 871cfd5c41..af61bcc79a 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -98,11 +98,15 @@ bool ImageWriter::Write(const std::string& image_filename, jni_dlsym_lookup_offset_ = oat_file_->GetOatHeader().GetJniDlsymLookupOffset(); + portable_imt_conflict_trampoline_offset_ = + oat_file_->GetOatHeader().GetPortableImtConflictTrampolineOffset(); portable_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetPortableResolutionTrampolineOffset(); portable_to_interpreter_bridge_offset_ = oat_file_->GetOatHeader().GetPortableToInterpreterBridgeOffset(); + quick_imt_conflict_trampoline_offset_ = + oat_file_->GetOatHeader().GetQuickImtConflictTrampolineOffset(); quick_resolution_trampoline_offset_ = oat_file_->GetOatHeader().GetQuickResolutionTrampolineOffset(); quick_to_interpreter_bridge_offset_ = @@ -390,6 +394,8 @@ ObjectArray* ImageWriter::CreateImageRoots() const { ObjectArray::Alloc(self, object_array_class, ImageHeader::kImageRootsMax)); image_roots->Set(ImageHeader::kResolutionMethod, runtime->GetResolutionMethod()); + image_roots->Set(ImageHeader::kImtConflictMethod, runtime->GetImtConflictMethod()); + image_roots->Set(ImageHeader::kDefaultImt, runtime->GetDefaultImt()); image_roots->Set(ImageHeader::kCalleeSaveMethod, runtime->GetCalleeSaveMethod(Runtime::kSaveAll)); image_roots->Set(ImageHeader::kRefsOnlySaveMethod, @@ -526,6 +532,12 @@ void ImageWriter::FixupMethod(const ArtMethod* orig, ArtMethod* copy) { copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_resolution_trampoline_offset_)); #else copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_resolution_trampoline_offset_)); +#endif + } else if (UNLIKELY(orig == Runtime::Current()->GetImtConflictMethod())) { +#if defined(ART_USE_PORTABLE_COMPILER) + copy->SetEntryPointFromCompiledCode(GetOatAddress(portable_imt_conflict_trampoline_offset_)); +#else + copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_imt_conflict_trampoline_offset_)); #endif } else { // We assume all methods have code. If they don't currently then we set them to the use the diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 0d85f36a5b..0b408e85cc 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -40,7 +40,8 @@ class ImageWriter { explicit ImageWriter(const CompilerDriver& compiler_driver) : compiler_driver_(compiler_driver), oat_file_(NULL), image_end_(0), image_begin_(NULL), oat_data_begin_(NULL), interpreter_to_interpreter_bridge_offset_(0), - interpreter_to_compiled_code_bridge_offset_(0), portable_resolution_trampoline_offset_(0), + interpreter_to_compiled_code_bridge_offset_(0), portable_imt_conflict_trampoline_offset_(0), + portable_resolution_trampoline_offset_(0), quick_imt_conflict_trampoline_offset_(0), quick_resolution_trampoline_offset_(0) {} ~ImageWriter() {} @@ -204,8 +205,10 @@ class ImageWriter { uint32_t interpreter_to_interpreter_bridge_offset_; uint32_t interpreter_to_compiled_code_bridge_offset_; uint32_t jni_dlsym_lookup_offset_; + uint32_t portable_imt_conflict_trampoline_offset_; uint32_t portable_resolution_trampoline_offset_; uint32_t portable_to_interpreter_bridge_offset_; + uint32_t quick_imt_conflict_trampoline_offset_; uint32_t quick_resolution_trampoline_offset_; uint32_t quick_to_interpreter_bridge_offset_; diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index af86743014..815bca5c5a 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -149,7 +149,7 @@ TEST_F(OatTest, WriteRead) { TEST_F(OatTest, OatHeaderSizeCheck) { // If this test is failing and you have to update these constants, // it is time to update OatHeader::kOatVersion - EXPECT_EQ(64U, sizeof(OatHeader)); + EXPECT_EQ(72U, sizeof(OatHeader)); EXPECT_EQ(28U, sizeof(OatMethodOffsets)); } diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index f681d7da6f..28355bfc74 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -55,8 +55,10 @@ OatWriter::OatWriter(const std::vector& dex_files, size_interpreter_to_interpreter_bridge_(0), size_interpreter_to_compiled_code_bridge_(0), size_jni_dlsym_lookup_(0), + size_portable_imt_conflict_trampoline_(0), size_portable_resolution_trampoline_(0), size_portable_to_interpreter_bridge_(0), + size_quick_imt_conflict_trampoline_(0), size_quick_resolution_trampoline_(0), size_quick_to_interpreter_bridge_(0), size_trampoline_alignment_(0), @@ -229,8 +231,10 @@ size_t OatWriter::InitOatCode(size_t offset) { DO_TRAMPOLINE(interpreter_to_interpreter_bridge_, InterpreterToInterpreterBridge); DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_, InterpreterToCompiledCodeBridge); DO_TRAMPOLINE(jni_dlsym_lookup_, JniDlsymLookup); + DO_TRAMPOLINE(portable_imt_conflict_trampoline_, PortableImtConflictTrampoline); DO_TRAMPOLINE(portable_resolution_trampoline_, PortableResolutionTrampoline); DO_TRAMPOLINE(portable_to_interpreter_bridge_, PortableToInterpreterBridge); + DO_TRAMPOLINE(quick_imt_conflict_trampoline_, QuickImtConflictTrampoline); DO_TRAMPOLINE(quick_resolution_trampoline_, QuickResolutionTrampoline); DO_TRAMPOLINE(quick_to_interpreter_bridge_, QuickToInterpreterBridge); @@ -239,8 +243,10 @@ size_t OatWriter::InitOatCode(size_t offset) { oat_header_->SetInterpreterToInterpreterBridgeOffset(0); oat_header_->SetInterpreterToCompiledCodeBridgeOffset(0); oat_header_->SetJniDlsymLookupOffset(0); + oat_header_->SetPortableImtConflictTrampolineOffset(0); oat_header_->SetPortableResolutionTrampolineOffset(0); oat_header_->SetPortableToInterpreterBridgeOffset(0); + oat_header_->SetQuickImtConflictTrampolineOffset(0); oat_header_->SetQuickResolutionTrampolineOffset(0); oat_header_->SetQuickToInterpreterBridgeOffset(0); } @@ -519,8 +525,10 @@ bool OatWriter::Write(OutputStream& out) { DO_STAT(size_interpreter_to_interpreter_bridge_); DO_STAT(size_interpreter_to_compiled_code_bridge_); DO_STAT(size_jni_dlsym_lookup_); + DO_STAT(size_portable_imt_conflict_trampoline_); DO_STAT(size_portable_resolution_trampoline_); DO_STAT(size_portable_to_interpreter_bridge_); + DO_STAT(size_quick_imt_conflict_trampoline_); DO_STAT(size_quick_resolution_trampoline_); DO_STAT(size_quick_to_interpreter_bridge_); DO_STAT(size_trampoline_alignment_); @@ -616,8 +624,10 @@ size_t OatWriter::WriteCode(OutputStream& out, const size_t file_offset) { DO_TRAMPOLINE(interpreter_to_interpreter_bridge_); DO_TRAMPOLINE(interpreter_to_compiled_code_bridge_); DO_TRAMPOLINE(jni_dlsym_lookup_); + DO_TRAMPOLINE(portable_imt_conflict_trampoline_); DO_TRAMPOLINE(portable_resolution_trampoline_); DO_TRAMPOLINE(portable_to_interpreter_bridge_); + DO_TRAMPOLINE(quick_imt_conflict_trampoline_); DO_TRAMPOLINE(quick_resolution_trampoline_); DO_TRAMPOLINE(quick_to_interpreter_bridge_); #undef DO_TRAMPOLINE diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index e3cb0a86ed..5d947cfaea 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -226,8 +226,10 @@ class OatWriter { UniquePtr > interpreter_to_interpreter_bridge_; UniquePtr > interpreter_to_compiled_code_bridge_; UniquePtr > jni_dlsym_lookup_; + UniquePtr > portable_imt_conflict_trampoline_; UniquePtr > portable_resolution_trampoline_; UniquePtr > portable_to_interpreter_bridge_; + UniquePtr > quick_imt_conflict_trampoline_; UniquePtr > quick_resolution_trampoline_; UniquePtr > quick_to_interpreter_bridge_; @@ -240,8 +242,10 @@ class OatWriter { uint32_t size_interpreter_to_interpreter_bridge_; uint32_t size_interpreter_to_compiled_code_bridge_; uint32_t size_jni_dlsym_lookup_; + uint32_t size_portable_imt_conflict_trampoline_; uint32_t size_portable_resolution_trampoline_; uint32_t size_portable_to_interpreter_bridge_; + uint32_t size_quick_imt_conflict_trampoline_; uint32_t size_quick_resolution_trampoline_; uint32_t size_quick_to_interpreter_bridge_; uint32_t size_trampoline_alignment_; diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index d8112ea708..1beb862267 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -345,10 +345,6 @@ class Dex2Oat { return false; } Runtime* runtime = Runtime::Current(); - // if we loaded an existing image, we will reuse values from the image roots. - if (!runtime->HasResolutionMethod()) { - runtime->SetResolutionMethod(runtime->CreateResolutionMethod()); - } for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i); if (!runtime->HasCalleeSaveMethod(type)) { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index fdeeaecd93..3a32ff14bd 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -86,6 +86,8 @@ static void usage() { const char* image_roots_descriptions_[] = { "kResolutionMethod", + "kImtConflictMethod", + "kDefaultImt", "kCalleeSaveMethod", "kRefsOnlySaveMethod", "kRefsAndArgsSaveMethod", @@ -1005,7 +1007,8 @@ class ImageDumper { indent_os << StringPrintf("OAT CODE: %p\n", oat_code); } } else if (method->IsAbstract() || method->IsCalleeSaveMethod() || - method->IsResolutionMethod() || MethodHelper(method).IsClassInitializer()) { + method->IsResolutionMethod() || method->IsImtConflictMethod() || + MethodHelper(method).IsClassInitializer()) { DCHECK(method->GetNativeGcMap() == NULL) << PrettyMethod(method); DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method); } else { diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc index 352982fc3a..3dac636df9 100644 --- a/runtime/arch/arm/entrypoints_init_arm.cc +++ b/runtime/arch/arm/entrypoints_init_arm.cc @@ -121,10 +121,10 @@ extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t); extern "C" int32_t art_quick_string_compareto(void*, void*); // Invoke entrypoints. +extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*); extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*); extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*); extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*); -extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*); extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*); @@ -253,10 +253,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, qpoints->pMemcpy = memcpy; // Invocation + qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S index 736ce2fb24..808ff5b34f 100644 --- a/runtime/arch/arm/quick_entrypoints_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -1040,6 +1040,18 @@ ENTRY art_quick_proxy_invoke_handler DELIVER_PENDING_EXCEPTION END art_quick_proxy_invoke_handler + /* + * Called to resolve an imt conflict. r12 is a hidden argument that holds the target method's + * dex method index. + */ +ENTRY art_quick_imt_conflict_trampoline + ldr r0, [sp, #0] @ load caller Method* + ldr r0, [r0, #METHOD_DEX_CACHE_METHODS_OFFSET] @ load dex_cache_resolved_methods + add r0, #OBJECT_ARRAY_DATA_OFFSET @ get starting address of data + ldr r0, [r0, r12, lsl 2] @ load the target method + b art_quick_invoke_interface_trampoline +END art_quick_imt_conflict_trampoline + .extern artQuickResolutionTrampoline ENTRY art_quick_resolution_trampoline SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc index cc975d75a3..331a461354 100644 --- a/runtime/arch/mips/entrypoints_init_mips.cc +++ b/runtime/arch/mips/entrypoints_init_mips.cc @@ -122,10 +122,10 @@ extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t); extern "C" int32_t art_quick_string_compareto(void*, void*); // Invoke entrypoints. +extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*); extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*); extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*); extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*); -extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*); extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*); @@ -253,10 +253,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, qpoints->pMemcpy = memcpy; // Invocation + qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S index 031d13a6b0..451b1bb30f 100644 --- a/runtime/arch/mips/quick_entrypoints_mips.S +++ b/runtime/arch/mips/quick_entrypoints_mips.S @@ -1060,6 +1060,21 @@ ENTRY art_quick_proxy_invoke_handler DELIVER_PENDING_EXCEPTION END art_quick_proxy_invoke_handler + /* + * Called to resolve an imt conflict. t0 is a hidden argument that holds the target method's + * dex method index. + */ +ENTRY art_quick_imt_conflict_trampoline + GENERATE_GLOBAL_POINTER + lw $a0, 0($sp) # load caller Method* + lw $a0, METHOD_DEX_CACHE_METHODS_OFFSET($a0) # load dex_cache_resolved_methods + sll $t0, 2 # convert target method offset to bytes + add $a0, $t0 # get address of target method + lw $a0, OBJECT_ARRAY_DATA_OFFSET($a0) # load the target method + la $t9, art_quick_invoke_interface_trampoline + jr $t9 +END art_quick_imt_conflict_trampoline + .extern artQuickResolutionTrampoline ENTRY art_quick_resolution_trampoline GENERATE_GLOBAL_POINTER diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc index 89dd1b8f8c..99b0dd548c 100644 --- a/runtime/arch/x86/entrypoints_init_x86.cc +++ b/runtime/arch/x86/entrypoints_init_x86.cc @@ -104,10 +104,10 @@ extern "C" int32_t art_quick_string_compareto(void*, void*); extern "C" void* art_quick_memcpy(void*, const void*, size_t); // Invoke entrypoints. +extern "C" void art_quick_imt_conflict_trampoline(mirror::ArtMethod*); extern "C" void art_quick_resolution_trampoline(mirror::ArtMethod*); extern "C" void art_quick_to_interpreter_bridge(mirror::ArtMethod*); extern "C" void art_quick_invoke_direct_trampoline_with_access_check(uint32_t, void*); -extern "C" void art_quick_invoke_interface_trampoline(uint32_t, void*); extern "C" void art_quick_invoke_interface_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_static_trampoline_with_access_check(uint32_t, void*); extern "C" void art_quick_invoke_super_trampoline_with_access_check(uint32_t, void*); @@ -235,10 +235,10 @@ void InitEntryPoints(InterpreterEntryPoints* ipoints, JniEntryPoints* jpoints, qpoints->pMemcpy = art_quick_memcpy; // Invocation + qpoints->pQuickImtConflictTrampoline = art_quick_imt_conflict_trampoline; qpoints->pQuickResolutionTrampoline = art_quick_resolution_trampoline; qpoints->pQuickToInterpreterBridge = art_quick_to_interpreter_bridge; qpoints->pInvokeDirectTrampolineWithAccessCheck = art_quick_invoke_direct_trampoline_with_access_check; - qpoints->pInvokeInterfaceTrampoline = art_quick_invoke_interface_trampoline; qpoints->pInvokeInterfaceTrampolineWithAccessCheck = art_quick_invoke_interface_trampoline_with_access_check; qpoints->pInvokeStaticTrampolineWithAccessCheck = art_quick_invoke_static_trampoline_with_access_check; qpoints->pInvokeSuperTrampolineWithAccessCheck = art_quick_invoke_super_trampoline_with_access_check; diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S index 805f6f4bd1..6a6891b331 100644 --- a/runtime/arch/x86/quick_entrypoints_x86.S +++ b/runtime/arch/x86/quick_entrypoints_x86.S @@ -997,6 +997,20 @@ DEFINE_FUNCTION art_quick_proxy_invoke_handler RETURN_OR_DELIVER_PENDING_EXCEPTION // return or deliver exception END_FUNCTION art_quick_proxy_invoke_handler + /* + * Called to resolve an imt conflict. xmm0 is a hidden argument that holds the target method's + * dex method index. + */ +DEFINE_FUNCTION art_quick_imt_conflict_trampoline + PUSH ecx + movl 8(%esp), %eax // load caller Method* + movl METHOD_DEX_CACHE_METHODS_OFFSET(%eax), %eax // load dex_cache_resolved_methods + movd %xmm0, %ecx // get target method index stored in xmm0 + movl OBJECT_ARRAY_DATA_OFFSET(%eax, %ecx, 4), %eax // load the target method + POP ecx + jmp art_quick_invoke_interface_trampoline +END_FUNCTION art_quick_imt_conflict_trampoline + DEFINE_FUNCTION art_quick_resolution_trampoline SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME PUSH esp // pass SP diff --git a/runtime/asm_support.h b/runtime/asm_support.h index a6700bc2e4..e9bbf91761 100644 --- a/runtime/asm_support.h +++ b/runtime/asm_support.h @@ -38,7 +38,8 @@ #define STRING_OFFSET_OFFSET 20 #define STRING_DATA_OFFSET 12 -// Offset of field Method::entry_point_from_compiled_code_ +// Offsets within java.lang.Method. +#define METHOD_DEX_CACHE_METHODS_OFFSET 16 #define METHOD_CODE_OFFSET 40 #endif // ART_RUNTIME_ASM_SUPPORT_H_ diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 03f2c9df42..2fc564fbd5 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -196,7 +196,9 @@ ClassLinker::ClassLinker(InternTable* intern_table) class_table_dirty_(false), intern_table_(intern_table), portable_resolution_trampoline_(NULL), - quick_resolution_trampoline_(NULL) { + quick_resolution_trampoline_(NULL), + portable_imt_conflict_trampoline_(NULL), + quick_imt_conflict_trampoline_(NULL) { CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax)); } @@ -336,6 +338,12 @@ void ClassLinker::InitFromCompiler(const std::vector& boot_class InitializePrimitiveClass(char_class.get(), Primitive::kPrimChar); SetClassRoot(kPrimitiveChar, char_class.get()); // needs descriptor + // Create runtime resolution and imt conflict methods. Also setup the default imt. + Runtime* runtime = Runtime::Current(); + runtime->SetResolutionMethod(runtime->CreateResolutionMethod()); + runtime->SetImtConflictMethod(runtime->CreateImtConflictMethod()); + runtime->SetDefaultImt(runtime->CreateDefaultImt(this)); + // Object, String and DexCache need to be rerun through FindSystemClass to finish init java_lang_Object->SetStatus(mirror::Class::kStatusNotReady, self); mirror::Class* Object_class = FindSystemClass("Ljava/lang/Object;"); @@ -1045,6 +1053,8 @@ void ClassLinker::InitFromImage() { CHECK(oat_file.GetOatHeader().GetImageFileLocation().empty()); portable_resolution_trampoline_ = oat_file.GetOatHeader().GetPortableResolutionTrampoline(); quick_resolution_trampoline_ = oat_file.GetOatHeader().GetQuickResolutionTrampoline(); + portable_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetPortableImtConflictTrampoline(); + quick_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetQuickImtConflictTrampoline(); mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches); mirror::ObjectArray* dex_caches = dex_caches_object->AsObjectArray(); @@ -3518,6 +3528,8 @@ bool ClassLinker::LinkVirtualMethods(SirtRef& klass) { bool ClassLinker::LinkInterfaceMethods(SirtRef& klass, mirror::ObjectArray* interfaces) { + // Set the imt table to be all conflicts by default. + klass->SetImTable(Runtime::Current()->GetDefaultImt()); size_t super_ifcount; if (klass->HasSuperClass()) { super_ifcount = klass->GetSuperClass()->GetIfTableCount(); @@ -3625,6 +3637,13 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef& klass, if (klass->IsInterface()) { return true; } + // Allocate imtable + bool imtable_changed = false; + SirtRef > imtable(self, AllocArtMethodArray(self, kImtSize)); + if (UNLIKELY(imtable.get() == NULL)) { + CHECK(self->IsExceptionPending()); // OOME. + return false; + } std::vector miranda_list; MethodHelper vtable_mh(NULL, this); MethodHelper interface_mh(NULL, this); @@ -3664,6 +3683,14 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef& klass, return false; } method_array->Set(j, vtable_method); + // Place method in imt if entry is empty, place conflict otherwise. + uint32_t imt_index = interface_method->GetDexMethodIndex() % kImtSize; + if (imtable->Get(imt_index) == NULL) { + imtable->Set(imt_index, vtable_method); + imtable_changed = true; + } else { + imtable->Set(imt_index, Runtime::Current()->GetImtConflictMethod()); + } break; } } @@ -3695,6 +3722,16 @@ bool ClassLinker::LinkInterfaceMethods(SirtRef& klass, } } } + if (imtable_changed) { + // Fill in empty entries in interface method table with conflict. + mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod(); + for (size_t i = 0; i < kImtSize; i++) { + if (imtable->Get(i) == NULL) { + imtable->Set(i, imt_conflict_method); + } + } + klass->SetImTable(imtable.get()); + } if (!miranda_list.empty()) { int old_method_count = klass->NumVirtualMethods(); int new_method_count = old_method_count + miranda_list.size(); diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 0bc1b5f444..473370d90f 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -51,6 +51,11 @@ typedef bool (ClassVisitor)(mirror::Class* c, void* arg); class ClassLinker { public: + // Interface method table size. Increasing this value reduces the chance of two interface methods + // colliding in the interface method table but increases the size of classes that implement + // (non-marker) interfaces. + static constexpr size_t kImtSize = 64; + // Creates the class linker by bootstrapping from dex files. static ClassLinker* CreateFromCompiler(const std::vector& boot_class_path, InternTable* intern_table) @@ -340,6 +345,18 @@ class ClassLinker { return quick_resolution_trampoline_; } + const void* GetPortableImtConflictTrampoline() const { + return portable_imt_conflict_trampoline_; + } + + const void* GetQuickImtConflictTrampoline() const { + return quick_imt_conflict_trampoline_; + } + + InternTable* GetInternTable() const { + return intern_table_; + } + // Attempts to insert a class into a class table. Returns NULL if // the class was inserted, otherwise returns an existing class with // the same descriptor and ClassLoader. @@ -608,6 +625,8 @@ class ClassLinker { const void* portable_resolution_trampoline_; const void* quick_resolution_trampoline_; + const void* portable_imt_conflict_trampoline_; + const void* quick_imt_conflict_trampoline_; friend class ImageWriter; // for GetClassRoots FRIEND_TEST(ClassLinkerTest, ClassRootDescriptors); diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 029b73e35f..a52b680260 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -497,6 +497,7 @@ struct ClassOffsets : public CheckOffsets { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, direct_methods_), "directMethods")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, ifields_), "iFields")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, iftable_), "ifTable")); + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, imtable_), "imTable")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, name_), "name")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, sfields_), "sFields")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, super_class_), "superClass")); @@ -582,11 +583,11 @@ struct StringClassOffsets : public CheckOffsets { offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, ASCII_), "ASCII")); offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, CASE_INSENSITIVE_ORDER_), "CASE_INSENSITIVE_ORDER")); - // alphabetical 64-bit - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, serialVersionUID_), "serialVersionUID")); - // alphabetical 32-bit offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, REPLACEMENT_CHAR_), "REPLACEMENT_CHAR")); + + // alphabetical 64-bit + offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StringClass, serialVersionUID_), "serialVersionUID")); }; }; diff --git a/runtime/common_test.h b/runtime/common_test.h index 899eab1f63..673a03b355 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -329,9 +329,6 @@ class CommonTest : public testing::Test { CompilerBackend compiler_backend = kQuick; #endif - if (!runtime_->HasResolutionMethod()) { - runtime_->SetResolutionMethod(runtime_->CreateResolutionMethod()); - } for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i); if (!runtime_->HasCalleeSaveMethod(type)) { diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index 200860470d..7ce50c5dfb 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -372,14 +372,21 @@ static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror: return vtable->GetWithoutChecks(vtable_index); } case kInterface: { - mirror::ArtMethod* interface_method = - this_object->GetClass()->FindVirtualMethodForInterface(resolved_method); - if (UNLIKELY(interface_method == nullptr)) { - ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, this_object, - referrer); - return nullptr; // Failure. + uint32_t imt_index = resolved_method->GetDexMethodIndex() % ClassLinker::kImtSize; + mirror::ObjectArray* imt_table = this_object->GetClass()->GetImTable(); + mirror::ArtMethod* imt_method = imt_table->Get(imt_index); + if (!imt_method->IsImtConflictMethod()) { + return imt_method; } else { - return interface_method; + mirror::ArtMethod* interface_method = + this_object->GetClass()->FindVirtualMethodForInterface(resolved_method); + if (UNLIKELY(interface_method == nullptr)) { + ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method, this_object, + referrer); + return nullptr; // Failure. + } else { + return interface_method; + } } } default: @@ -665,6 +672,23 @@ static inline const void* GetResolutionTrampoline(ClassLinker* class_linker) { #endif } +static inline const void* GetPortableImtConflictTrampoline(ClassLinker* class_linker) { + return class_linker->GetPortableImtConflictTrampoline(); +} + +static inline const void* GetQuickImtConflictTrampoline(ClassLinker* class_linker) { + return class_linker->GetQuickImtConflictTrampoline(); +} + +// Return address of imt conflict trampoline stub for defined compiler. +static inline const void* GetImtConflictTrampoline(ClassLinker* class_linker) { +#if defined(ART_USE_PORTABLE_COMPILER) + return GetPortableImtConflictTrampoline(class_linker); +#else + return GetQuickImtConflictTrampoline(class_linker); +#endif +} + extern "C" void art_portable_proxy_invoke_handler(); static inline const void* GetPortableProxyInvokeHandler() { return reinterpret_cast(art_portable_proxy_invoke_handler); diff --git a/runtime/entrypoints/portable/portable_entrypoints.h b/runtime/entrypoints/portable/portable_entrypoints.h index d4564471ac..dbea70735f 100644 --- a/runtime/entrypoints/portable/portable_entrypoints.h +++ b/runtime/entrypoints/portable/portable_entrypoints.h @@ -35,6 +35,7 @@ class Thread; // compiler ABI. struct PACKED(4) PortableEntryPoints { // Invocation + void (*pPortableImtConflictTrampoline)(mirror::ArtMethod*); void (*pPortableResolutionTrampoline)(mirror::ArtMethod*); void (*pPortableToInterpreterBridge)(mirror::ArtMethod*); }; diff --git a/runtime/entrypoints/quick/quick_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h index c8a85a0fe3..1ba206629e 100644 --- a/runtime/entrypoints/quick/quick_entrypoints.h +++ b/runtime/entrypoints/quick/quick_entrypoints.h @@ -118,10 +118,10 @@ struct PACKED(4) QuickEntryPoints { void* (*pMemcpy)(void*, const void*, size_t); // Invocation + void (*pQuickImtConflictTrampoline)(mirror::ArtMethod*); void (*pQuickResolutionTrampoline)(mirror::ArtMethod*); void (*pQuickToInterpreterBridge)(mirror::ArtMethod*); void (*pInvokeDirectTrampolineWithAccessCheck)(uint32_t, void*); - void (*pInvokeInterfaceTrampoline)(uint32_t, void*); void (*pInvokeInterfaceTrampolineWithAccessCheck)(uint32_t, void*); void (*pInvokeStaticTrampolineWithAccessCheck)(uint32_t, void*); void (*pInvokeSuperTrampolineWithAccessCheck)(uint32_t, void*); diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index fa28642c3e..e12ee063c0 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -241,6 +241,10 @@ ImageSpace* ImageSpace::Init(const char* image_file_name, bool validate_oat_file Runtime* runtime = Runtime::Current(); mirror::Object* resolution_method = image_header.GetImageRoot(ImageHeader::kResolutionMethod); runtime->SetResolutionMethod(down_cast(resolution_method)); + mirror::Object* imt_conflict_method = image_header.GetImageRoot(ImageHeader::kImtConflictMethod); + runtime->SetImtConflictMethod(down_cast(imt_conflict_method)); + mirror::Object* default_imt = image_header.GetImageRoot(ImageHeader::kDefaultImt); + runtime->SetDefaultImt(down_cast*>(default_imt)); mirror::Object* callee_save_method = image_header.GetImageRoot(ImageHeader::kCalleeSaveMethod); runtime->SetCalleeSaveMethod(down_cast(callee_save_method), Runtime::kSaveAll); diff --git a/runtime/image.h b/runtime/image.h index 2cb468fed1..246f106382 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -90,6 +90,8 @@ class PACKED(4) ImageHeader { enum ImageRoot { kResolutionMethod, + kImtConflictMethod, + kDefaultImt, kCalleeSaveMethod, kRefsOnlySaveMethod, kRefsAndArgsSaveMethod, diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h index ccf3e59f18..c9bf1609a0 100644 --- a/runtime/mirror/art_method-inl.h +++ b/runtime/mirror/art_method-inl.h @@ -202,6 +202,13 @@ inline bool ArtMethod::IsResolutionMethod() const { DCHECK(!result || IsRuntimeMethod()); return result; } + +inline bool ArtMethod::IsImtConflictMethod() const { + bool result = this == Runtime::Current()->GetImtConflictMethod(); + // Check that if we do think it is phony it looks like the imt conflict method. + DCHECK(!result || IsRuntimeMethod()); + return result; +} } // namespace mirror } // namespace art diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h index 052089373d..f396fbe436 100644 --- a/runtime/mirror/art_method.h +++ b/runtime/mirror/art_method.h @@ -357,6 +357,8 @@ class MANAGED ArtMethod : public Object { bool IsResolutionMethod() const; + bool IsImtConflictMethod() const; + uintptr_t NativePcOffset(const uintptr_t pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Converts a native PC to a dex PC. diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index cd5e865c7c..7f3a302768 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -139,6 +139,14 @@ inline void Class::SetVTable(ObjectArray* new_vtable) SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable, false); } +inline ObjectArray* Class::GetImTable() const { + return GetFieldObject*>(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), false); +} + +inline void Class::SetImTable(ObjectArray* new_imtable) { + SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), new_imtable, false); +} + inline bool Class::Implements(const Class* klass) const { DCHECK(klass != NULL); DCHECK(klass->IsInterface()) << PrettyClass(this); diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index d15f3375fd..ed1aad39d2 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -555,6 +555,15 @@ class MANAGED Class : public StaticStorageBase { return OFFSET_OF_OBJECT_MEMBER(Class, vtable_); } + ObjectArray* GetImTable() const; + + void SetImTable(ObjectArray* new_imtable) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static MemberOffset ImTableOffset() { + return OFFSET_OF_OBJECT_MEMBER(Class, imtable_); + } + // Given a method implemented by this class but potentially from a super class, return the // specific implementation method for this class. ArtMethod* FindVirtualMethodForVirtual(ArtMethod* method) const @@ -830,6 +839,9 @@ class MANAGED Class : public StaticStorageBase { // methods for the methods in the interface. IfTable* iftable_; + // Interface method table (imt), for quick "invoke-interface". + ObjectArray* imtable_; + // descriptor for the class such as "java.lang.Class" or "[C". Lazily initialized by ComputeName String* name_; @@ -912,6 +924,7 @@ std::ostream& operator<<(std::ostream& os, const Class::Status& rhs); class MANAGED ClassClass : public Class { private: + int32_t pad_; int64_t serialVersionUID_; friend struct art::ClassClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(ClassClass); diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index 6c6d488f4a..d0d1ee4a46 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -84,6 +84,7 @@ TEST_F(ObjectTest, AsmConstants) { EXPECT_EQ(STRING_OFFSET_OFFSET, String::OffsetOffset().Int32Value()); EXPECT_EQ(STRING_DATA_OFFSET, Array::DataOffset(sizeof(uint16_t)).Int32Value()); + EXPECT_EQ(METHOD_DEX_CACHE_METHODS_OFFSET, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()); EXPECT_EQ(METHOD_CODE_OFFSET, ArtMethod::EntryPointFromCompiledCodeOffset().Int32Value()); } diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h index 1879f04bef..01d8f318ff 100644 --- a/runtime/mirror/string.h +++ b/runtime/mirror/string.h @@ -156,8 +156,8 @@ class MANAGED StringClass : public Class { private: CharArray* ASCII_; Object* CASE_INSENSITIVE_ORDER_; - int64_t serialVersionUID_; uint32_t REPLACEMENT_CHAR_; + int64_t serialVersionUID_; friend struct art::StringClassOffsets; // for verifying offset information DISALLOW_IMPLICIT_CONSTRUCTORS(StringClass); }; diff --git a/runtime/oat.cc b/runtime/oat.cc index 6fe5d1097b..defda6bb1a 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -22,7 +22,7 @@ namespace art { const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' }; -const uint8_t OatHeader::kOatVersion[] = { '0', '0', '8', '\0' }; +const uint8_t OatHeader::kOatVersion[] = { '0', '0', '9', '\0' }; OatHeader::OatHeader() { memset(this, 0, sizeof(*this)); @@ -60,8 +60,10 @@ OatHeader::OatHeader(InstructionSet instruction_set, interpreter_to_interpreter_bridge_offset_ = 0; interpreter_to_compiled_code_bridge_offset_ = 0; jni_dlsym_lookup_offset_ = 0; + portable_imt_conflict_trampoline_offset_ = 0; portable_resolution_trampoline_offset_ = 0; portable_to_interpreter_bridge_offset_ = 0; + quick_imt_conflict_trampoline_offset_ = 0; quick_resolution_trampoline_offset_ = 0; quick_to_interpreter_bridge_offset_ = 0; } @@ -171,18 +173,37 @@ void OatHeader::SetJniDlsymLookupOffset(uint32_t offset) { UpdateChecksum(&jni_dlsym_lookup_offset_, sizeof(offset)); } +const void* OatHeader::GetPortableImtConflictTrampoline() const { + return reinterpret_cast(this) + GetPortableImtConflictTrampolineOffset(); +} + +uint32_t OatHeader::GetPortableImtConflictTrampolineOffset() const { + DCHECK(IsValid()); + CHECK_GE(portable_imt_conflict_trampoline_offset_, jni_dlsym_lookup_offset_); + return portable_imt_conflict_trampoline_offset_; +} + +void OatHeader::SetPortableImtConflictTrampolineOffset(uint32_t offset) { + CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_); + DCHECK(IsValid()); + DCHECK_EQ(portable_imt_conflict_trampoline_offset_, 0U) << offset; + + portable_imt_conflict_trampoline_offset_ = offset; + UpdateChecksum(&portable_imt_conflict_trampoline_offset_, sizeof(offset)); +} + const void* OatHeader::GetPortableResolutionTrampoline() const { return reinterpret_cast(this) + GetPortableResolutionTrampolineOffset(); } uint32_t OatHeader::GetPortableResolutionTrampolineOffset() const { DCHECK(IsValid()); - CHECK_GE(portable_resolution_trampoline_offset_, jni_dlsym_lookup_offset_); + CHECK_GE(portable_resolution_trampoline_offset_, portable_imt_conflict_trampoline_offset_); return portable_resolution_trampoline_offset_; } void OatHeader::SetPortableResolutionTrampolineOffset(uint32_t offset) { - CHECK(offset == 0 || offset >= jni_dlsym_lookup_offset_); + CHECK(offset == 0 || offset >= portable_imt_conflict_trampoline_offset_); DCHECK(IsValid()); DCHECK_EQ(portable_resolution_trampoline_offset_, 0U) << offset; @@ -209,18 +230,37 @@ void OatHeader::SetPortableToInterpreterBridgeOffset(uint32_t offset) { UpdateChecksum(&portable_to_interpreter_bridge_offset_, sizeof(offset)); } +const void* OatHeader::GetQuickImtConflictTrampoline() const { + return reinterpret_cast(this) + GetQuickImtConflictTrampolineOffset(); +} + +uint32_t OatHeader::GetQuickImtConflictTrampolineOffset() const { + DCHECK(IsValid()); + CHECK_GE(quick_imt_conflict_trampoline_offset_, portable_to_interpreter_bridge_offset_); + return quick_imt_conflict_trampoline_offset_; +} + +void OatHeader::SetQuickImtConflictTrampolineOffset(uint32_t offset) { + CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_); + DCHECK(IsValid()); + DCHECK_EQ(quick_imt_conflict_trampoline_offset_, 0U) << offset; + + quick_imt_conflict_trampoline_offset_ = offset; + UpdateChecksum(&quick_imt_conflict_trampoline_offset_, sizeof(offset)); +} + const void* OatHeader::GetQuickResolutionTrampoline() const { return reinterpret_cast(this) + GetQuickResolutionTrampolineOffset(); } uint32_t OatHeader::GetQuickResolutionTrampolineOffset() const { DCHECK(IsValid()); - CHECK_GE(quick_resolution_trampoline_offset_, portable_to_interpreter_bridge_offset_); + CHECK_GE(quick_resolution_trampoline_offset_, quick_imt_conflict_trampoline_offset_); return quick_resolution_trampoline_offset_; } void OatHeader::SetQuickResolutionTrampolineOffset(uint32_t offset) { - CHECK(offset == 0 || offset >= portable_to_interpreter_bridge_offset_); + CHECK(offset == 0 || offset >= quick_imt_conflict_trampoline_offset_); DCHECK(IsValid()); DCHECK_EQ(quick_resolution_trampoline_offset_, 0U) << offset; diff --git a/runtime/oat.h b/runtime/oat.h index a9dc540c03..c864c2cc52 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -62,6 +62,9 @@ class PACKED(4) OatHeader { const void* GetPortableResolutionTrampoline() const; uint32_t GetPortableResolutionTrampolineOffset() const; void SetPortableResolutionTrampolineOffset(uint32_t offset); + const void* GetPortableImtConflictTrampoline() const; + uint32_t GetPortableImtConflictTrampolineOffset() const; + void SetPortableImtConflictTrampolineOffset(uint32_t offset); const void* GetPortableToInterpreterBridge() const; uint32_t GetPortableToInterpreterBridgeOffset() const; void SetPortableToInterpreterBridgeOffset(uint32_t offset); @@ -69,6 +72,9 @@ class PACKED(4) OatHeader { const void* GetQuickResolutionTrampoline() const; uint32_t GetQuickResolutionTrampolineOffset() const; void SetQuickResolutionTrampolineOffset(uint32_t offset); + const void* GetQuickImtConflictTrampoline() const; + uint32_t GetQuickImtConflictTrampolineOffset() const; + void SetQuickImtConflictTrampolineOffset(uint32_t offset); const void* GetQuickToInterpreterBridge() const; uint32_t GetQuickToInterpreterBridgeOffset() const; void SetQuickToInterpreterBridgeOffset(uint32_t offset); @@ -91,8 +97,10 @@ class PACKED(4) OatHeader { uint32_t interpreter_to_interpreter_bridge_offset_; uint32_t interpreter_to_compiled_code_bridge_offset_; uint32_t jni_dlsym_lookup_offset_; + uint32_t portable_imt_conflict_trampoline_offset_; uint32_t portable_resolution_trampoline_offset_; uint32_t portable_to_interpreter_bridge_offset_; + uint32_t quick_imt_conflict_trampoline_offset_; uint32_t quick_resolution_trampoline_offset_; uint32_t quick_to_interpreter_bridge_offset_; diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 3ca3c0bcf3..bf25b810a9 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -458,6 +458,8 @@ class MethodHelper { Runtime* runtime = Runtime::Current(); if (method_ == runtime->GetResolutionMethod()) { return ""; + } else if (method_ == runtime->GetImtConflictMethod()) { + return ""; } else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kSaveAll)) { return ""; } else if (method_ == runtime->GetCalleeSaveMethod(Runtime::kRefsOnly)) { diff --git a/runtime/runtime.cc b/runtime/runtime.cc index f46b794387..34cf45b4c7 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -84,6 +84,8 @@ Runtime::Runtime() java_vm_(NULL), pre_allocated_OutOfMemoryError_(NULL), resolution_method_(NULL), + imt_conflict_method_(NULL), + default_imt_(NULL), threads_being_born_(0), shutdown_cond_(new ConditionVariable("Runtime shutdown", *Locks::runtime_shutdown_lock_)), shutting_down_(false), @@ -1175,6 +1177,10 @@ void Runtime::VisitNonThreadRoots(RootVisitor* visitor, void* arg) { } resolution_method_ = reinterpret_cast(visitor(resolution_method_, arg)); DCHECK(resolution_method_ != nullptr); + imt_conflict_method_ = reinterpret_cast(visitor(imt_conflict_method_, arg)); + DCHECK(imt_conflict_method_ != nullptr); + default_imt_ = reinterpret_cast*>(visitor(default_imt_, arg)); + DCHECK(default_imt_ != nullptr); for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) { callee_save_methods_[i] = reinterpret_cast( visitor(callee_save_methods_[i], arg)); @@ -1192,6 +1198,31 @@ void Runtime::VisitRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool VisitNonConcurrentRoots(visitor, arg); } +mirror::ObjectArray* Runtime::CreateDefaultImt(ClassLinker* cl) { + Thread* self = Thread::Current(); + SirtRef > imtable(self, cl->AllocArtMethodArray(self, 64)); + mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod(); + for (size_t i = 0; i < 64; i++) { + imtable->Set(i, imt_conflict_method); + } + return imtable.get(); +} + +mirror::ArtMethod* Runtime::CreateImtConflictMethod() { + mirror::Class* method_class = mirror::ArtMethod::GetJavaLangReflectArtMethod(); + Thread* self = Thread::Current(); + SirtRef + method(self, down_cast(method_class->AllocObject(self))); + method->SetDeclaringClass(method_class); + // TODO: use a special method for imt conflict method saves + method->SetDexMethodIndex(DexFile::kDexNoIndex); + // When compiling, the code pointer will get set later when the image is loaded. + Runtime* r = Runtime::Current(); + ClassLinker* cl = r->GetClassLinker(); + method->SetEntryPointFromCompiledCode(r->IsCompiler() ? NULL : GetImtConflictTrampoline(cl)); + return method.get(); +} + mirror::ArtMethod* Runtime::CreateResolutionMethod() { mirror::Class* method_class = mirror::ArtMethod::GetJavaLangReflectArtMethod(); Thread* self = Thread::Current(); diff --git a/runtime/runtime.h b/runtime/runtime.h index b6429b646d..51d9074d03 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -45,6 +45,7 @@ namespace gc { namespace mirror { class ArtMethod; class ClassLoader; + template class ObjectArray; template class PrimitiveArray; typedef PrimitiveArray ByteArray; class String; @@ -349,6 +350,39 @@ class Runtime { mirror::ArtMethod* CreateResolutionMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Returns a special method that calls into a trampoline for runtime imt conflicts + mirror::ArtMethod* GetImtConflictMethod() const { + CHECK(HasImtConflictMethod()); + return imt_conflict_method_; + } + + bool HasImtConflictMethod() const { + return imt_conflict_method_ != NULL; + } + + void SetImtConflictMethod(mirror::ArtMethod* method) { + imt_conflict_method_ = method; + } + + mirror::ArtMethod* CreateImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // Returns an imt with every entry set to conflict, used as default imt for all classes. + mirror::ObjectArray* GetDefaultImt() const { + CHECK(HasDefaultImt()); + return default_imt_; + } + + bool HasDefaultImt() const { + return default_imt_ != NULL; + } + + void SetDefaultImt(mirror::ObjectArray* imt) { + default_imt_ = imt; + } + + mirror::ObjectArray* CreateDefaultImt(ClassLinker* cl) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Returns a special method that describes all callee saves being spilled to the stack. enum CalleeSaveType { kSaveAll, @@ -485,6 +519,10 @@ class Runtime { mirror::ArtMethod* resolution_method_; + mirror::ArtMethod* imt_conflict_method_; + + mirror::ObjectArray* default_imt_; + // A non-zero value indicates that a thread has been created but not yet initialized. Guarded by // the shutdown lock so that threads aren't born while we're shutting down. size_t threads_being_born_ GUARDED_BY(Locks::runtime_shutdown_lock_); diff --git a/runtime/thread.cc b/runtime/thread.cc index 30636589cd..9751076235 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1555,6 +1555,7 @@ static const EntryPointInfo gThreadEntryPointInfo[] = { INTERPRETER_ENTRY_POINT_INFO(pInterpreterToInterpreterBridge), INTERPRETER_ENTRY_POINT_INFO(pInterpreterToCompiledCodeBridge), JNI_ENTRY_POINT_INFO(pDlsymLookup), + PORTABLE_ENTRY_POINT_INFO(pPortableImtConflictTrampoline), PORTABLE_ENTRY_POINT_INFO(pPortableResolutionTrampoline), PORTABLE_ENTRY_POINT_INFO(pPortableToInterpreterBridge), QUICK_ENTRY_POINT_INFO(pAllocArray), @@ -1617,10 +1618,10 @@ static const EntryPointInfo gThreadEntryPointInfo[] = { QUICK_ENTRY_POINT_INFO(pMemcmp16), QUICK_ENTRY_POINT_INFO(pStringCompareTo), QUICK_ENTRY_POINT_INFO(pMemcpy), + QUICK_ENTRY_POINT_INFO(pQuickImtConflictTrampoline), QUICK_ENTRY_POINT_INFO(pQuickResolutionTrampoline), QUICK_ENTRY_POINT_INFO(pQuickToInterpreterBridge), QUICK_ENTRY_POINT_INFO(pInvokeDirectTrampolineWithAccessCheck), - QUICK_ENTRY_POINT_INFO(pInvokeInterfaceTrampoline), QUICK_ENTRY_POINT_INFO(pInvokeInterfaceTrampolineWithAccessCheck), QUICK_ENTRY_POINT_INFO(pInvokeStaticTrampolineWithAccessCheck), QUICK_ENTRY_POINT_INFO(pInvokeSuperTrampolineWithAccessCheck), diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt index 967f167f37..3d87ebc559 100644 --- a/test/100-reflect2/expected.txt +++ b/test/100-reflect2/expected.txt @@ -35,7 +35,7 @@ z (class java.lang.Character) 62 (class java.lang.Long) 14 (class java.lang.Short) [public java.lang.String(), java.lang.String(int,int,char[]), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int)] -[private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final long java.lang.String.serialVersionUID, private static final char java.lang.String.REPLACEMENT_CHAR] +[private final char[] java.lang.String.value, private final int java.lang.String.count, private int java.lang.String.hashCode, private final int java.lang.String.offset, private static final char[] java.lang.String.ASCII, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER, private static final char java.lang.String.REPLACEMENT_CHAR, private static final long java.lang.String.serialVersionUID] [void java.lang.String._getChars(int,int,char[],int), public char java.lang.String.charAt(int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public volatile int java.lang.String.compareTo(java.lang.Object), public native int java.lang.String.compareTo(java.lang.String), public int java.lang.String.compareToIgnoreCase(java.lang.String), public java.lang.String java.lang.String.concat(java.lang.String), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public void java.lang.String.getBytes(int,int,byte[],int), public [B java.lang.String.getBytes(), public [B java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public [B java.lang.String.getBytes(java.nio.charset.Charset), public void java.lang.String.getChars(int,int,char[],int), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public native java.lang.String java.lang.String.intern(), public boolean java.lang.String.isEmpty(), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public boolean java.lang.String.matches(java.lang.String), public int java.lang.String.offsetByCodePoints(int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public [C java.lang.String.toCharArray(), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.failedBoundsCheck(int,int,int), private native int java.lang.String.fastIndexOf(int,int), private char java.lang.String.foldCase(char), public static transient java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static transient java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), private java.lang.StringIndexOutOfBoundsException java.lang.String.indexAndLength(int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int,int,char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.startEndAndLength(int,int), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(long), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int)] [] [interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence] diff --git a/test/Android.mk b/test/Android.mk index cdd61f0eef..6d3a84a25f 100644 --- a/test/Android.mk +++ b/test/Android.mk @@ -44,6 +44,7 @@ TEST_OAT_DIRECTORIES := \ Main \ HelloWorld \ \ + InterfaceTest \ JniTest \ NativeAllocations \ ParallelGC \ diff --git a/test/InterfaceTest/InterfaceTest.java b/test/InterfaceTest/InterfaceTest.java new file mode 100644 index 0000000000..ed18eb3dc7 --- /dev/null +++ b/test/InterfaceTest/InterfaceTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.util.Map; +import java.util.HashMap; + +class InterfaceTest { + + public static long test_virtual(HashMap map) { + Integer intobj = new Integer(0); + String s = "asdf"; + long start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + map.put(intobj, s); + } + long end = System.currentTimeMillis(); + return (end - start); + } + + public static long test_interface(Map map) { + Integer intobj = new Integer(0); + String s = "asdf"; + long start = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + map.put(intobj, s); + } + long end = System.currentTimeMillis(); + return (end - start); + } + + public static void main(String[] args) { + HashMap hashmap = new HashMap(); + long elapsed = test_virtual(hashmap); + System.logI("virtual map put: " + elapsed); + hashmap.clear(); + + elapsed = test_interface(hashmap); + System.logI("interface map put: " + elapsed); + } +} -- cgit v1.2.3-59-g8ed1b From dfb325e0ddd746cd8f7c2e3723b3a573eb7cc111 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 30 Oct 2013 01:00:44 -0700 Subject: Don't use UTF16 length as length for MUTF8. Bug 11367555. Change-Id: Ia0b07072a1a49d435c3b71ed9a668b316b7ff5d8 --- compiler/dex/quick/gen_invoke.cc | 2 +- compiler/driver/compiler_driver.cc | 20 ++++---- compiler/driver/compiler_driver.h | 2 +- compiler/image_writer.cc | 4 +- runtime/class_linker.cc | 67 ++++++++++++------------- runtime/debugger.cc | 6 +-- runtime/dex_file-inl.h | 83 +++++++++++++++++++++++++------ runtime/dex_file.cc | 4 +- runtime/dex_file.h | 72 ++++++--------------------- runtime/gc/heap-inl.h | 2 +- runtime/mirror/class.cc | 18 +++---- runtime/native/dalvik_system_VMRuntime.cc | 2 +- runtime/object_utils.h | 62 ++--------------------- runtime/reflection.cc | 2 +- runtime/verifier/method_verifier.cc | 4 +- 15 files changed, 152 insertions(+), 198 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 62feadedcc..5a1d3d1a52 100644 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -1232,7 +1232,7 @@ bool Mir2Lir::GenIntrinsic(CallInfo* info) { const DexFile::MethodId& target_mid = cu_->dex_file->GetMethodId(info->index); const DexFile::TypeId& declaring_type = cu_->dex_file->GetTypeId(target_mid.class_idx_); StringPiece tgt_methods_declaring_class( - cu_->dex_file->StringDataAsStringPieceByIdx(declaring_type.descriptor_idx_)); + cu_->dex_file->StringDataByIdx(declaring_type.descriptor_idx_)); if (tgt_methods_declaring_class.starts_with("Ljava/lang/Double;")) { std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file)); if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") { diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 91b0188b7b..7653d16352 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -600,11 +600,11 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vectorfind(descriptor.data()) != image_classes_->end(); + return image_classes_->find(descriptor) != image_classes_->end(); } } @@ -780,7 +780,7 @@ void CompilerDriver::UpdateImageClasses(base::TimingLogger& timings) { bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file, uint32_t type_idx) { if (IsImage() && - IsImageClass(dex_file.StringDataAsStringPieceByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_))) { + IsImageClass(dex_file.StringDataByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_))) { if (kIsDebugBuild) { ScopedObjectAccess soa(Thread::Current()); mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file); @@ -1108,7 +1108,7 @@ void CompilerDriver::GetCodeAndMethodForDirectCall(InvokeType* type, InvokeType } if (!use_dex_cache && compiling_boot) { MethodHelper mh(method); - if (!IsImageClass(mh.GetDeclaringClassDescriptorAsStringPiece())) { + if (!IsImageClass(mh.GetDeclaringClassDescriptor())) { // We can only branch directly to Methods that are resolved in the DexCache. // Otherwise we won't invoke the resolution trampoline. use_dex_cache = true; @@ -1573,8 +1573,8 @@ static void ResolveType(const ParallelCompilationManager* manager, size_t type_i CHECK(soa.Self()->IsExceptionPending()); mirror::Throwable* exception = soa.Self()->GetException(NULL); VLOG(compiler) << "Exception during type resolution: " << exception->Dump(); - if (ClassHelper(exception->GetClass()).GetDescriptorAsStringPiece() == - "Ljava/lang/OutOfMemoryError;") { + if (strcmp("Ljava/lang/OutOfMemoryError;", + ClassHelper(exception->GetClass()).GetDescriptor()) == 0) { // There's little point continuing compilation if the heap is exhausted. LOG(FATAL) << "Out of memory during type resolution for compilation"; } @@ -2089,11 +2089,11 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl const DexFile* dex_file = manager->GetDexFile(); const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index); const DexFile::TypeId& class_type_id = dex_file->GetTypeId(class_def.class_idx_); - StringPiece descriptor(dex_file->StringDataAsStringPieceByIdx(class_type_id.descriptor_idx_)); + const char* descriptor = dex_file->StringDataByIdx(class_type_id.descriptor_idx_); ScopedObjectAccess soa(Thread::Current()); mirror::ClassLoader* class_loader = soa.Decode(manager->GetClassLoader()); - mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor.data(), class_loader); + mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader); if (klass != NULL) { // Only try to initialize classes that were successfully verified. if (klass->IsVerified()) { @@ -2123,7 +2123,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl bool is_black_listed = StringPiece(descriptor).ends_with("$NoPreloadHolder;"); if (!is_black_listed) { for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) { - if (descriptor == class_initializer_black_list[i]) { + if (strcmp(descriptor, class_initializer_black_list[i]) == 0) { is_black_listed = true; break; } @@ -2131,7 +2131,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl } if (!is_black_listed) { VLOG(compiler) << "Initializing: " << descriptor; - if (descriptor == "Ljava/lang/Void;") { + if (strcmp("Ljava/lang/Void;", descriptor) == 0) { // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime. ObjectLock lock(soa.Self(), klass); mirror::ObjectArray* fields = klass->GetSFields(); diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 971021f903..fe21eff842 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -309,7 +309,7 @@ class CompilerDriver { } // Checks if class specified by type_idx is one of the image_classes_ - bool IsImageClass(const StringPiece& descriptor) const; + bool IsImageClass(const char* descriptor) const; void RecordClassStatus(ClassReference ref, mirror::Class::Status status) LOCKS_EXCLUDED(compiled_classes_lock_); diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc index 871cfd5c41..e66e214248 100644 --- a/compiler/image_writer.cc +++ b/compiler/image_writer.cc @@ -244,7 +244,7 @@ void ImageWriter::ComputeEagerResolvedStrings() } bool ImageWriter::IsImageClass(const Class* klass) { - return compiler_driver_.IsImageClass(ClassHelper(klass).GetDescriptorAsStringPiece()); + return compiler_driver_.IsImageClass(ClassHelper(klass).GetDescriptor()); } struct NonImageClasses { @@ -299,7 +299,7 @@ void ImageWriter::PruneNonImageClasses() { bool ImageWriter::NonImageClassesVisitor(Class* klass, void* arg) { NonImageClasses* context = reinterpret_cast(arg); if (!context->image_writer->IsImageClass(klass)) { - context->non_image_classes->insert(ClassHelper(klass).GetDescriptorAsStringPiece().as_string()); + context->non_image_classes->insert(ClassHelper(klass).GetDescriptor()); } return true; } diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 03f2c9df42..55bbf7cef1 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1878,7 +1878,7 @@ mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file SirtRef& klass) { uint32_t dex_method_idx = it.GetMemberIndex(); const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); - StringPiece method_name(dex_file.StringDataAsStringPieceByIdx(method_id.name_idx_)); + const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_); mirror::ArtMethod* dst = AllocArtMethod(self); if (UNLIKELY(dst == NULL)) { @@ -1899,34 +1899,30 @@ mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file uint32_t access_flags = it.GetMemberAccessFlags(); - if (UNLIKELY(method_name == "finalize")) { + if (UNLIKELY(strcmp("finalize", method_name) == 0)) { // Set finalizable flag on declaring class. - const DexFile::ProtoId& proto = dex_file.GetProtoId(method_id.proto_idx_); - if (dex_file.GetProtoParameters(proto) == NULL) { // No arguments - const DexFile::TypeId& return_type = dex_file.GetTypeId(proto.return_type_idx_); - if (dex_file.StringDataAsStringPieceByIdx(return_type.descriptor_idx_) == "V") { - // Void return type. - if (klass->GetClassLoader() != NULL) { // All non-boot finalizer methods are flagged + if (strcmp("V", dex_file.GetShorty(method_id.proto_idx_)) == 0) { + // Void return type. + if (klass->GetClassLoader() != NULL) { // All non-boot finalizer methods are flagged + klass->SetFinalizable(); + } else { + ClassHelper kh(klass.get()); + const char* klass_descriptor = kh.GetDescriptor(); + // The Enum class declares a "final" finalize() method to prevent subclasses from + // introducing a finalizer. We don't want to set the finalizable flag for Enum or its + // subclasses, so we exclude it here. + // We also want to avoid setting the flag on Object, where we know that finalize() is + // empty. + if ((strcmp("Ljava/lang/Object;", klass_descriptor) != 0) && + (strcmp("Ljava/lang/Enum;", klass_descriptor) != 0)) { klass->SetFinalizable(); - } else { - ClassHelper kh(klass.get()); - StringPiece klass_descriptor(kh.GetDescriptorAsStringPiece()); - // The Enum class declares a "final" finalize() method to prevent subclasses from - // introducing a finalizer. We don't want to set the finalizable flag for Enum or its - // subclasses, so we exclude it here. - // We also want to avoid setting the flag on Object, where we know that finalize() is - // empty. - if (klass_descriptor != "Ljava/lang/Object;" && - klass_descriptor != "Ljava/lang/Enum;") { - klass->SetFinalizable(); - } } } } } else if (method_name[0] == '<') { // Fix broken access flags for initializers. Bug 11157540. - bool is_init = (method_name == ""); - bool is_clinit = !is_init && (method_name == ""); + bool is_init = (strcmp("", method_name) == 0); + bool is_clinit = !is_init && (strcmp("", method_name) == 0); if (UNLIKELY(!is_init && !is_clinit)) { LOG(WARNING) << "Unexpected '<' at start of method name " << method_name; } else { @@ -2265,7 +2261,8 @@ bool ClassLinker::RemoveClass(const char* descriptor, const mirror::ClassLoader* ++it) { mirror::Class* klass = it->second; kh.ChangeClass(klass); - if (kh.GetDescriptorAsStringPiece() == descriptor && klass->GetClassLoader() == class_loader) { + if ((klass->GetClassLoader() == class_loader) && + (strcmp(descriptor, kh.GetDescriptor()) == 0)) { class_table_.erase(it); return true; } @@ -2311,14 +2308,15 @@ mirror::Class* ClassLinker::LookupClassFromTableLocked(const char* descriptor, for (auto it = class_table_.lower_bound(hash); it != end && it->first == hash; ++it) { mirror::Class* klass = it->second; kh.ChangeClass(klass); - if (klass->GetClassLoader() == class_loader && kh.GetDescriptorAsStringPiece() == descriptor) { + if ((klass->GetClassLoader() == class_loader) && + (strcmp(descriptor, kh.GetDescriptor()) == 0)) { if (kIsDebugBuild) { // Check for duplicates in the table. for (++it; it != end && it->first == hash; ++it) { mirror::Class* klass2 = it->second; kh.ChangeClass(klass2); - CHECK(!(kh.GetDescriptorAsStringPiece() == descriptor && - klass2->GetClassLoader() == class_loader)) + CHECK(!((klass2->GetClassLoader() == class_loader) && + (strcmp(descriptor, kh.GetDescriptor()) == 0))) << PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " " << PrettyClass(klass2) << " " << klass2 << " " << klass2->GetClassLoader(); } @@ -2426,7 +2424,7 @@ void ClassLinker::LookupClasses(const char* descriptor, std::vectorfirst == hash; ++it) { mirror::Class* klass = it->second; kh.ChangeClass(klass); - if (kh.GetDescriptorAsStringPiece() == descriptor) { + if (strcmp(descriptor, kh.GetDescriptor()) == 0) { result.push_back(klass); } } @@ -3885,7 +3883,7 @@ bool ClassLinker::LinkFields(SirtRef& klass, bool is_static) { // We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it. if (!is_static && - (ClassHelper(klass.get(), this).GetDescriptorAsStringPiece() == "Ljava/lang/ref/Reference;")) { + (strcmp("Ljava/lang/ref/Reference;", ClassHelper(klass.get(), this).GetDescriptor()) == 0)) { // We know there are no non-reference fields in the Reference classes, and we know // that 'referent' is alphabetically last, so this is easy... CHECK_EQ(num_reference_fields, num_fields); @@ -3910,8 +3908,8 @@ bool ClassLinker::LinkFields(SirtRef& klass, bool is_static) { fh.ChangeField(field); Primitive::Type type = fh.GetTypeAsPrimitiveType(); bool is_primitive = type != Primitive::kPrimNot; - if (ClassHelper(klass.get(), this).GetDescriptorAsStringPiece() == "Ljava/lang/ref/Reference;" && - fh.GetNameAsStringPiece() == "referent") { + if ((strcmp("Ljava/lang/ref/Reference;", ClassHelper(klass.get(), this).GetDescriptor()) == 0) + && (strcmp("referent", fh.GetName()) == 0)) { is_primitive = true; // We lied above, so we have to expect a lie here. } if (is_primitive) { @@ -4006,9 +4004,8 @@ mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, if (resolved != NULL) { return resolved; } - const DexFile::StringId& string_id = dex_file.GetStringId(string_idx); - int32_t utf16_length = dex_file.GetStringLength(string_id); - const char* utf8_data = dex_file.GetStringData(string_id); + uint32_t utf16_length; + const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length); mirror::String* string = intern_table_->InternStrong(utf16_length, utf8_data); dex_cache->SetResolvedString(string_idx, string); return string; @@ -4249,8 +4246,8 @@ mirror::ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file, return NULL; } - StringPiece name(dex_file.StringDataAsStringPieceByIdx(field_id.name_idx_)); - StringPiece type(dex_file.StringDataAsStringPieceByIdx( + StringPiece name(dex_file.StringDataByIdx(field_id.name_idx_)); + StringPiece type(dex_file.StringDataByIdx( dex_file.GetTypeId(field_id.type_idx_).descriptor_idx_)); resolved = klass->FindField(name, type); if (resolved != NULL) { diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 57bd57e61f..4b30a15dbf 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -891,7 +891,7 @@ JDWP::JdwpError Dbg::GetClassInfo(JDWP::RefTypeId class_id, JDWP::JdwpTypeTag* p } if (pDescriptor != NULL) { - *pDescriptor = ClassHelper(c).GetDescriptorAsStringPiece().as_string(); + *pDescriptor = ClassHelper(c).GetDescriptor(); } return JDWP::ERR_NONE; } @@ -934,7 +934,7 @@ JDWP::JdwpError Dbg::GetSignature(JDWP::RefTypeId class_id, std::string* signatu if (c == NULL) { return status; } - *signature = ClassHelper(c).GetDescriptorAsStringPiece().as_string(); + *signature = ClassHelper(c).GetDescriptor(); return JDWP::ERR_NONE; } @@ -2289,7 +2289,7 @@ void Dbg::PostClassPrepare(mirror::Class* c) { int state = JDWP::CS_VERIFIED | JDWP::CS_PREPARED; JDWP::JdwpTypeTag tag = c->IsInterface() ? JDWP::TT_INTERFACE : JDWP::TT_CLASS; gJdwpState->PostClassPrepare(tag, gRegistry->Add(c), - ClassHelper(c).GetDescriptorAsStringPiece().as_string(), state); + ClassHelper(c).GetDescriptor(), state); } void Dbg::UpdateDebugger(Thread* thread, mirror::Object* this_object, diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h index c57a1e7582..3b2135c2cd 100644 --- a/runtime/dex_file-inl.h +++ b/runtime/dex_file-inl.h @@ -18,7 +18,6 @@ #define ART_RUNTIME_DEX_FILE_INL_H_ #include "base/logging.h" -#include "base/stringpiece.h" #include "dex_file.h" #include "leb128.h" #include "utils.h" @@ -30,23 +29,14 @@ inline int32_t DexFile::GetStringLength(const StringId& string_id) const { return DecodeUnsignedLeb128(&ptr); } -inline const char* DexFile::GetStringDataAndLength(const StringId& string_id, uint32_t* length) const { - DCHECK(length != NULL) << GetLocation(); +inline const char* DexFile::GetStringDataAndUtf16Length(const StringId& string_id, + uint32_t* utf16_length) const { + DCHECK(utf16_length != NULL) << GetLocation(); const byte* ptr = begin_ + string_id.string_data_off_; - *length = DecodeUnsignedLeb128(&ptr); + *utf16_length = DecodeUnsignedLeb128(&ptr); return reinterpret_cast(ptr); } -inline StringPiece DexFile::StringDataAsStringPieceByIdx(uint32_t idx) const { - if (idx == kDexNoIndex) { - return StringPiece(); - } - const StringId& string_id = GetStringId(idx); - uint32_t length; - const char* data = GetStringDataAndLength(string_id, &length); - return StringPiece(data, static_cast(length)); -} - inline const Signature DexFile::GetMethodSignature(const MethodId& method_id) const { return Signature(this, GetProtoId(method_id.proto_idx_)); } @@ -57,6 +47,71 @@ inline const DexFile::TryItem* DexFile::GetTryItems(const CodeItem& code_item, u (RoundUp(reinterpret_cast(insns_end_), 4)) + offset; } +static inline bool DexFileStringEquals(const DexFile* df1, uint32_t sidx1, + const DexFile* df2, uint32_t sidx2) { + uint32_t s1_len; // Note: utf16 length != mutf8 length. + const char* s1_data = df1->StringDataAndUtf16LengthByIdx(sidx1, &s1_len); + uint32_t s2_len; + const char* s2_data = df2->StringDataAndUtf16LengthByIdx(sidx2, &s2_len); + return (s1_len == s2_len) && (strcmp(s1_data, s2_data) == 0); +} + +inline bool Signature::operator==(const Signature& rhs) const { + if (dex_file_ == nullptr) { + return rhs.dex_file_ == nullptr; + } + if (rhs.dex_file_ == nullptr) { + return false; + } + if (dex_file_ == rhs.dex_file_) { + return proto_id_ == rhs.proto_id_; + } + uint32_t lhs_shorty_len; // For a shorty utf16 length == mutf8 length. + const char* lhs_shorty_data = dex_file_->StringDataAndUtf16LengthByIdx(proto_id_->shorty_idx_, + &lhs_shorty_len); + StringPiece lhs_shorty(lhs_shorty_data, lhs_shorty_len); + { + uint32_t rhs_shorty_len; + const char* rhs_shorty_data = + rhs.dex_file_->StringDataAndUtf16LengthByIdx(rhs.proto_id_->shorty_idx_, + &rhs_shorty_len); + StringPiece rhs_shorty(rhs_shorty_data, rhs_shorty_len); + if (lhs_shorty != rhs_shorty) { + return false; // Shorty mismatch. + } + } + if (lhs_shorty[0] == 'L') { + const DexFile::TypeId& return_type_id = dex_file_->GetTypeId(proto_id_->return_type_idx_); + const DexFile::TypeId& rhs_return_type_id = + rhs.dex_file_->GetTypeId(rhs.proto_id_->return_type_idx_); + if (!DexFileStringEquals(dex_file_, return_type_id.descriptor_idx_, + rhs.dex_file_, rhs_return_type_id.descriptor_idx_)) { + return false; // Return type mismatch. + } + } + if (lhs_shorty.find('L', 1) != StringPiece::npos) { + const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_); + const DexFile::TypeList* rhs_params = rhs.dex_file_->GetProtoParameters(*rhs.proto_id_); + // Both lists are empty or have contents, or else shorty is broken. + DCHECK_EQ(params == nullptr, rhs_params == nullptr); + if (params != nullptr) { + uint32_t params_size = params->Size(); + DCHECK_EQ(params_size, rhs_params->Size()); // Parameter list size must match. + for (uint32_t i = 0; i < params_size; ++i) { + const DexFile::TypeId& param_id = dex_file_->GetTypeId(params->GetTypeItem(i).type_idx_); + const DexFile::TypeId& rhs_param_id = + rhs.dex_file_->GetTypeId(rhs_params->GetTypeItem(i).type_idx_); + if (!DexFileStringEquals(dex_file_, param_id.descriptor_idx_, + rhs.dex_file_, rhs_param_id.descriptor_idx_)) { + return false; // Parameter type mismatch. + } + } + } + } + return true; +} + + } // namespace art #endif // ART_RUNTIME_DEX_FILE_INL_H_ diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index a0f5601fff..d3bb483b74 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -459,7 +459,7 @@ const DexFile::StringId* DexFile::FindStringId(const char* string) const { int32_t mid = (hi + lo) / 2; uint32_t length; const DexFile::StringId& str_id = GetStringId(mid); - const char* str = GetStringDataAndLength(str_id, &length); + const char* str = GetStringDataAndUtf16Length(str_id, &length); int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string, str); if (compare > 0) { lo = mid + 1; @@ -479,7 +479,7 @@ const DexFile::StringId* DexFile::FindStringId(const uint16_t* string) const { int32_t mid = (hi + lo) / 2; uint32_t length; const DexFile::StringId& str_id = GetStringId(mid); - const char* str = GetStringDataAndLength(str_id, &length); + const char* str = GetStringDataAndUtf16Length(str_id, &length); int compare = CompareModifiedUtf8ToUtf16AsCodePointValues(str, string); if (compare > 0) { lo = mid + 1; diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 035a691025..7901ea7447 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -418,29 +418,29 @@ class DexFile { 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, uint32_t* length) const; + // Returns a pointer to the UTF-8 string data referred to by the given string_id as well as the + // length of the string when decoded as a UTF-16 string. Note the UTF-16 length is not the same + // as the string length of the string data. + const char* GetStringDataAndUtf16Length(const StringId& string_id, uint32_t* utf16_length) const; const char* GetStringData(const StringId& string_id) const { - uint32_t length; - return GetStringDataAndLength(string_id, &length); + uint32_t ignored; + return GetStringDataAndUtf16Length(string_id, &ignored); } - // return the UTF-8 encoded string with the specified string_id index - const char* StringDataAndLengthByIdx(uint32_t idx, uint32_t* unicode_length) const { + // Index version of GetStringDataAndUtf16Length. + const char* StringDataAndUtf16LengthByIdx(uint32_t idx, uint32_t* utf16_length) const { if (idx == kDexNoIndex) { - *unicode_length = 0; + *utf16_length = 0; return NULL; } const StringId& string_id = GetStringId(idx); - return GetStringDataAndLength(string_id, unicode_length); + return GetStringDataAndUtf16Length(string_id, utf16_length); } - StringPiece StringDataAsStringPieceByIdx(uint32_t idx) const; - const char* StringDataByIdx(uint32_t idx) const { uint32_t unicode_length; - return StringDataAndLengthByIdx(idx, &unicode_length); + return StringDataAndUtf16LengthByIdx(idx, &unicode_length); } // Looks up a string id for a given modified utf8 string. @@ -472,7 +472,7 @@ class DexFile { // Get the descriptor string associated with a given type index. const char* StringByTypeIdx(uint32_t idx, uint32_t* unicode_length) const { const TypeId& type_id = GetTypeId(idx); - return StringDataAndLengthByIdx(type_id.descriptor_idx_, unicode_length); + return StringDataAndUtf16LengthByIdx(type_id.descriptor_idx_, unicode_length); } const char* StringByTypeIdx(uint32_t idx) const { @@ -575,7 +575,7 @@ class DexFile { return StringDataByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_); } const char* GetMethodShorty(const MethodId& method_id, uint32_t* length) const { - return StringDataAndLengthByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_, length); + return StringDataAndUtf16LengthByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_, length); } // Returns the number of class definitions in the .dex file. size_t NumClassDefs() const { @@ -952,51 +952,7 @@ class Signature { return Signature(); } - bool operator==(const Signature& rhs) const { - if (dex_file_ == nullptr) { - return rhs.dex_file_ == nullptr; - } - if (rhs.dex_file_ == nullptr) { - return false; - } - if (dex_file_ == rhs.dex_file_) { - return proto_id_ == rhs.proto_id_; - } - StringPiece shorty(dex_file_->StringDataAsStringPieceByIdx(proto_id_->shorty_idx_)); - if (shorty != rhs.dex_file_->StringDataAsStringPieceByIdx(rhs.proto_id_->shorty_idx_)) { - return false; // Shorty mismatch. - } - if (shorty[0] == 'L') { - const DexFile::TypeId& return_type_id = dex_file_->GetTypeId(proto_id_->return_type_idx_); - const DexFile::TypeId& rhs_return_type_id = - rhs.dex_file_->GetTypeId(rhs.proto_id_->return_type_idx_); - if (dex_file_->StringDataAsStringPieceByIdx(return_type_id.descriptor_idx_) != - rhs.dex_file_->StringDataAsStringPieceByIdx(rhs_return_type_id.descriptor_idx_)) { - return false; // Return type mismatch. - } - } - if (shorty.find('L', 1) != StringPiece::npos) { - const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_); - const DexFile::TypeList* rhs_params = rhs.dex_file_->GetProtoParameters(*rhs.proto_id_); - // Both lists are empty or have contents, or else shorty is broken. - DCHECK_EQ(params == nullptr, rhs_params == nullptr); - if (params != nullptr) { - uint32_t params_size = params->Size(); - DCHECK_EQ(params_size, rhs_params->Size()); // Parameter list size must match. - for (uint32_t i = 0; i < params_size; ++i) { - const DexFile::TypeId& param_id = dex_file_->GetTypeId(params->GetTypeItem(i).type_idx_); - const DexFile::TypeId& rhs_param_id = - rhs.dex_file_->GetTypeId(rhs_params->GetTypeItem(i).type_idx_); - if (dex_file_->StringDataAsStringPieceByIdx(param_id.descriptor_idx_) != - rhs.dex_file_->StringDataAsStringPieceByIdx(rhs_param_id.descriptor_idx_)) { - return false; // Parameter type mismatch. - } - } - } - } - return true; - } - + bool operator==(const Signature& rhs) const; bool operator!=(const Signature& rhs) const { return !(*this == rhs); } diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h index b7ef77c35a..873eadc46a 100644 --- a/runtime/gc/heap-inl.h +++ b/runtime/gc/heap-inl.h @@ -127,7 +127,7 @@ inline bool Heap::TryAllocLargeObjectUninstrumented(Thread* self, mirror::Class* inline void Heap::DebugCheckPreconditionsForAllobObject(mirror::Class* c, size_t byte_count) { DCHECK(c == NULL || (c->IsClassClass() && byte_count >= sizeof(mirror::Class)) || (c->IsVariableSize() || c->GetObjectSize() == byte_count) || - ClassHelper(c).GetDescriptorAsStringPiece().length() == 0); + strlen(ClassHelper(c).GetDescriptor()) == 0); DCHECK_GE(byte_count, sizeof(mirror::Object)); } diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 319ca4a5f9..f3cb54aa15 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -135,7 +135,7 @@ String* Class::ComputeName() { if (name != NULL) { return name; } - std::string descriptor(ClassHelper(this).GetDescriptorAsStringPiece().as_string()); + std::string descriptor(ClassHelper(this).GetDescriptor()); if ((descriptor[0] != 'L') && (descriptor[0] != '[')) { // The descriptor indicates that this is the class for // a primitive type; special-case the return value. @@ -294,8 +294,8 @@ bool Class::IsInSamePackage(const Class* that) const { return true; } // Compare the package part of the descriptor string. - return IsInSamePackage(ClassHelper(klass1).GetDescriptorAsStringPiece(), - ClassHelper(klass2).GetDescriptorAsStringPiece()); + return IsInSamePackage(ClassHelper(klass1).GetDescriptor(), + ClassHelper(klass2).GetDescriptor()); } bool Class::IsClassClass() const { @@ -366,7 +366,7 @@ ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const String for (size_t i = 0; i < NumDirectMethods(); ++i) { ArtMethod* method = GetDirectMethod(i); mh.ChangeMethod(method); - if (name == mh.GetNameAsStringPiece() && mh.GetSignature() == signature) { + if (name == mh.GetName() && mh.GetSignature() == signature) { return method; } } @@ -378,7 +378,7 @@ ArtMethod* Class::FindDeclaredDirectMethod(const StringPiece& name, const Signat for (size_t i = 0; i < NumDirectMethods(); ++i) { ArtMethod* method = GetDirectMethod(i); mh.ChangeMethod(method); - if (name == mh.GetNameAsStringPiece() && signature == mh.GetSignature()) { + if (name == mh.GetName() && signature == mh.GetSignature()) { return method; } } @@ -432,7 +432,7 @@ ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, const Strin for (size_t i = 0; i < NumVirtualMethods(); ++i) { ArtMethod* method = GetVirtualMethod(i); mh.ChangeMethod(method); - if (name == mh.GetNameAsStringPiece() && mh.GetSignature() == signature) { + if (name == mh.GetName() && mh.GetSignature() == signature) { return method; } } @@ -445,7 +445,7 @@ ArtMethod* Class::FindDeclaredVirtualMethod(const StringPiece& name, for (size_t i = 0; i < NumVirtualMethods(); ++i) { ArtMethod* method = GetVirtualMethod(i); mh.ChangeMethod(method); - if (name == mh.GetNameAsStringPiece() && signature == mh.GetSignature()) { + if (name == mh.GetName() && signature == mh.GetSignature()) { return method; } } @@ -517,7 +517,7 @@ ArtField* Class::FindDeclaredInstanceField(const StringPiece& name, const String for (size_t i = 0; i < NumInstanceFields(); ++i) { ArtField* f = GetInstanceField(i); fh.ChangeField(f); - if (name == fh.GetNameAsStringPiece() && type == fh.GetTypeDescriptorAsStringPiece()) { + if (name == fh.GetName() && type == fh.GetTypeDescriptor()) { return f; } } @@ -566,7 +566,7 @@ ArtField* Class::FindDeclaredStaticField(const StringPiece& name, const StringPi for (size_t i = 0; i < NumStaticFields(); ++i) { ArtField* f = GetStaticField(i); fh.ChangeField(f); - if (name == fh.GetNameAsStringPiece() && type == fh.GetTypeDescriptorAsStringPiece()) { + if (name == fh.GetName() && type == fh.GetTypeDescriptor()) { return f; } } diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index 4629dbd0aa..71ed95c4e2 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -222,7 +222,7 @@ static void PreloadDexCachesResolveString(mirror::DexCache* dex_cache, } const DexFile* dex_file = dex_cache->GetDexFile(); uint32_t utf16Size; - const char* utf8 = dex_file->StringDataAndLengthByIdx(string_idx, &utf16Size); + const char* utf8 = dex_file->StringDataAndUtf16LengthByIdx(string_idx, &utf16Size); string = strings[utf8]; if (string == NULL) { return; diff --git a/runtime/object_utils.h b/runtime/object_utils.h index 3ca3c0bcf3..b0a4ce56fe 100644 --- a/runtime/object_utils.h +++ b/runtime/object_utils.h @@ -112,17 +112,6 @@ class ClassHelper { } } - StringPiece GetDescriptorAsStringPiece() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - CHECK(klass_ != NULL); - if (UNLIKELY(klass_->IsArrayClass() || klass_->IsPrimitive() || klass_->IsProxyClass())) { - return StringPiece(GetDescriptor()); - } else { - const DexFile& dex_file = GetDexFile(); - const DexFile::TypeId& type_id = dex_file.GetTypeId(GetClassDef()->class_idx_); - return dex_file.StringDataAsStringPieceByIdx(type_id.descriptor_idx_); - } - } - const char* GetArrayDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { std::string result("["); const mirror::Class* saved_klass = klass_; @@ -194,7 +183,7 @@ class ClassHelper { } const char* GetSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - std::string descriptor(GetDescriptorAsStringPiece().as_string()); + std::string descriptor(GetDescriptor()); const DexFile& dex_file = GetDexFile(); const DexFile::ClassDef* dex_class_def = GetClassDef(); CHECK(dex_class_def != NULL); @@ -291,16 +280,6 @@ class FieldHelper { return dex_file.GetFieldName(dex_file.GetFieldId(field_index)); } - StringPiece GetNameAsStringPiece() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - uint32_t field_index = field_->GetDexFieldIndex(); - if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { - return StringPiece(GetName()); - } - const DexFile& dex_file = GetDexFile(); - const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); - return dex_file.StringDataAsStringPieceByIdx(field_id.name_idx_); - } - mirror::Class* GetType(bool resolve = true) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { uint32_t field_index = field_->GetDexFieldIndex(); if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { @@ -329,17 +308,6 @@ class FieldHelper { return dex_file.GetFieldTypeDescriptor(field_id); } - StringPiece GetTypeDescriptorAsStringPiece() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - uint32_t field_index = field_->GetDexFieldIndex(); - if (UNLIKELY(field_->GetDeclaringClass()->IsProxyClass())) { - return StringPiece(GetTypeDescriptor()); - } - const DexFile& dex_file = GetDexFile(); - const DexFile::FieldId& field_id = dex_file.GetFieldId(field_index); - const DexFile::TypeId& type_id = dex_file.GetTypeId(field_id.type_idx_); - return dex_file.StringDataAsStringPieceByIdx(type_id.descriptor_idx_); - } - Primitive::Type GetTypeAsPrimitiveType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return Primitive::GetType(GetTypeDescriptor()[0]); @@ -365,7 +333,7 @@ class FieldHelper { DCHECK_LT(field_index, 2U); // 0 == Class[] interfaces; 1 == Class[][] throws; ClassHelper kh(field_->GetDeclaringClass()); - declaring_class_descriptor_ = kh.GetDescriptorAsStringPiece().as_string(); + declaring_class_descriptor_ = kh.GetDescriptor(); return declaring_class_descriptor_.c_str(); } const DexFile& dex_file = GetDexFile(); @@ -470,16 +438,6 @@ class MethodHelper { } } - StringPiece GetNameAsStringPiece() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const DexFile& dex_file = GetDexFile(); - uint32_t dex_method_idx = method_->GetDexMethodIndex(); - if (UNLIKELY(dex_method_idx == DexFile::kDexNoIndex)) { - return StringPiece(GetName()); - } - const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx); - return dex_file.StringDataAsStringPieceByIdx(method_id.name_idx_); - } - mirror::String* GetNameAsString() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { const DexFile& dex_file = GetDexFile(); uint32_t dex_method_idx = method_->GetDexMethodIndex(); @@ -559,18 +517,6 @@ class MethodHelper { return dex_file.GetMethodDeclaringClassDescriptor(dex_file.GetMethodId(dex_method_idx)); } - StringPiece GetDeclaringClassDescriptorAsStringPiece() - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - const DexFile& dex_file = GetDexFile(); - uint32_t dex_method_idx = method_->GetDexMethodIndex(); - if (UNLIKELY(dex_method_idx == DexFile::kDexNoIndex)) { - return StringPiece(""); - } - const DexFile::MethodId& mid = dex_file.GetMethodId(dex_method_idx); - const DexFile::TypeId& type_id = dex_file.GetTypeId(mid.class_idx_); - return dex_file.StringDataAsStringPieceByIdx(type_id.descriptor_idx_); - } - const char* GetDeclaringClassSourceFile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { return ClassHelper(method_->GetDeclaringClass()).GetSourceFile(); } @@ -635,8 +581,8 @@ class MethodHelper { const DexFile& other_dex_file = other->GetDexFile(); const DexFile::MethodId& other_mid = other_dex_file.GetMethodId(other->method_->GetDexMethodIndex()); - if (dex_file.StringDataAsStringPieceByIdx(mid.name_idx_) != - other_dex_file.StringDataAsStringPieceByIdx(other_mid.name_idx_)) { + if (!DexFileStringEquals(&dex_file, mid.name_idx_, + &other_dex_file, other_mid.name_idx_)) { return false; // Name mismatch. } return dex_file.GetMethodSignature(mid) == other_dex_file.GetMethodSignature(other_mid); diff --git a/runtime/reflection.cc b/runtime/reflection.cc index 4ff7349833..80e16aa6c0 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -323,7 +323,7 @@ static bool UnboxPrimitive(const ThrowLocation* throw_location, mirror::Object* } JValue boxed_value; - const StringPiece src_descriptor(ClassHelper(o->GetClass()).GetDescriptorAsStringPiece()); + const StringPiece src_descriptor(ClassHelper(o->GetClass()).GetDescriptor()); mirror::Class* src_class = NULL; ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); mirror::ArtField* primitive_field = o->GetClass()->GetIFields()->Get(0); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 7d2ee19572..563c8438e1 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -90,7 +90,7 @@ MethodVerifier::FailureKind MethodVerifier::VerifyClass(const mirror::Class* kla return kNoFailure; } mirror::Class* super = klass->GetSuperClass(); - if (super == NULL && ClassHelper(klass).GetDescriptorAsStringPiece() != "Ljava/lang/Object;") { + if (super == NULL && strcmp("Ljava/lang/Object;", ClassHelper(klass).GetDescriptor()) != 0) { *error = "Verifier rejected class "; *error += PrettyDescriptor(klass); *error += " that has no super class"; @@ -2188,7 +2188,7 @@ bool MethodVerifier::CodeFlowVerifyInstruction(uint32_t* start_guess) { if (called_method == NULL) { uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx); - is_constructor = dex_file_->StringDataAsStringPieceByIdx(method_id.name_idx_) == ""; + is_constructor = strcmp("", dex_file_->StringDataByIdx(method_id.name_idx_)) == 0; uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_; return_type_descriptor = dex_file_->StringByTypeIdx(return_type_idx); } else { -- cgit v1.2.3-59-g8ed1b From a52454455048d04d12e4da637a103412a55e579b Mon Sep 17 00:00:00 2001 From: Jeff Hao Date: Wed, 30 Oct 2013 14:12:12 -0700 Subject: Update compiler blacklist to include java.net.NetworkInterface. Change-Id: Ib93d2f75024b3def54eadc11547990150deccf4d --- compiler/driver/compiler_driver.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 9f06755307..783c3227a6 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1987,6 +1987,7 @@ static const char* class_initializer_black_list[] = { "Ljava/net/Inet4Address;", // Sub-class of InetAddress. "Ljava/net/Inet6Address;", // Sub-class of InetAddress. "Ljava/net/InetUnixAddress;", // Sub-class of InetAddress. + "Ljava/net/NetworkInterface;", // Calls to Random. -> System.currentTimeMillis -> OsConstants.initConstants. "Ljava/nio/charset/Charset;", // Calls Charset.getDefaultCharset -> System.getProperty -> OsConstants.initConstants. "Ljava/nio/charset/CharsetICU;", // Sub-class of Charset. "Ljava/nio/charset/Charsets;", // Calls Charset.forName. -- cgit v1.2.3-59-g8ed1b From 7020278bce98a0735dc6abcbd33bdf1ed2634f1d Mon Sep 17 00:00:00 2001 From: Dave Allison Date: Tue, 22 Oct 2013 17:52:19 -0700 Subject: Support hardware divide instruction Bug: 11299025 Uses sdiv for division and a combo of sdiv, mul and sub for modulus. Only does this on processors that are capable of the sdiv instruction, as determined by the build system. Also provides a command line arg --instruction-set-features= to allow cross compilation. Makefile adds the --instruction-set-features= arg to build-time dex2oat runs and defaults it to something obtained from the target architecture. Provides a GetInstructionSetFeatures() function on CompilerDriver that can be queried for various features. The only feature supported right now is hasDivideInstruction(). Also adds a few more instructions to the ARM disassembler b/11535253 is an addition to this CL to be done later. Change-Id: Ia8aaf801fd94bc71e476902749cf20f74eba9f68 --- Android.mk | 2 +- build/Android.executable.mk | 4 + build/Android.gtest.mk | 1 + build/Android.oat.mk | 22 +++- compiler/dex/compiler_ir.h | 3 + compiler/dex/quick/arm/arm_lir.h | 2 + compiler/dex/quick/arm/assemble_arm.cc | 8 ++ compiler/dex/quick/arm/int_arm.cc | 33 ++++- compiler/dex/quick/arm/utility_arm.cc | 4 + compiler/dex/quick/gen_common.cc | 40 +++++- compiler/driver/compiler_driver.cc | 2 + compiler/driver/compiler_driver.h | 10 +- compiler/oat_test.cc | 9 +- compiler/oat_writer.cc | 1 + dex2oat/dex2oat.cc | 57 +++++++- disassembler/disassembler_arm.cc | 232 +++++++++++++++++++++++++++++---- oatdump/oatdump.cc | 3 + runtime/Android.mk | 1 + runtime/arch/arm/arm_sdiv.S | 24 ++++ runtime/base/macros.h | 4 + runtime/common_test.h | 124 +++++++++++++++++- runtime/instruction_set.h | 50 +++++++ runtime/oat.cc | 11 +- runtime/oat.h | 3 + runtime/utils.cc | 29 +++++ runtime/utils.h | 9 +- 26 files changed, 636 insertions(+), 52 deletions(-) create mode 100644 runtime/arch/arm/arm_sdiv.S (limited to 'compiler/driver/compiler_driver.cc') diff --git a/Android.mk b/Android.mk index 0b4b2316fd..3112ab0288 100644 --- a/Android.mk +++ b/Android.mk @@ -270,7 +270,7 @@ oat-target-$(1): $$(OUT_OAT_FILE) $$(OUT_OAT_FILE): $(PRODUCT_OUT)/$(1) $(TARGET_BOOT_IMG_OUT) $(DEX2OAT_DEPENDENCY) @mkdir -p $$(dir $$@) - $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms64m --runtime-arg -Xmx64m --boot-image=$(TARGET_BOOT_IMG_OUT) --dex-file=$(PRODUCT_OUT)/$(1) --dex-location=/$(1) --oat-file=$$@ --host-prefix=$(PRODUCT_OUT) --instruction-set=$(TARGET_ARCH) --android-root=$(PRODUCT_OUT)/system + $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms64m --runtime-arg -Xmx64m --boot-image=$(TARGET_BOOT_IMG_OUT) --dex-file=$(PRODUCT_OUT)/$(1) --dex-location=/$(1) --oat-file=$$@ --host-prefix=$(PRODUCT_OUT) --instruction-set=$(TARGET_ARCH) --instruction-set-features=$(TARGET_INSTRUCTION_SET_FEATURES) --android-root=$(PRODUCT_OUT)/system endif diff --git a/build/Android.executable.mk b/build/Android.executable.mk index 5cf15be1c1..b317d92999 100644 --- a/build/Android.executable.mk +++ b/build/Android.executable.mk @@ -24,6 +24,10 @@ ifeq ($(ART_USE_PORTABLE_COMPILER),true) ART_EXECUTABLES_CFLAGS += -DART_USE_PORTABLE_COMPILER=1 endif +# add the default instruction set features +ART_EXECUTABLES_CFLAGS += \ + -DART_DEFAULT_INSTRUCTION_SET_FEATURES=$(DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES) + # $(1): executable ("d" will be appended for debug version) # $(2): source # $(3): extra shared libraries diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 655c7dd01f..0d759ce085 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -86,6 +86,7 @@ ART_TEST_CFLAGS := ifeq ($(ART_USE_PORTABLE_COMPILER),true) ART_TEST_CFLAGS += -DART_USE_PORTABLE_COMPILER=1 endif +ART_TEST_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=$(DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES) # $(1): target or host # $(2): file name diff --git a/build/Android.oat.mk b/build/Android.oat.mk index b680b820b7..5d355a6d86 100644 --- a/build/Android.oat.mk +++ b/build/Android.oat.mk @@ -26,7 +26,7 @@ LIBART_COMPILER := $(LIBARTD_COMPILER) # By default, do not run rerun dex2oat if the tool changes. # Comment out the | to force dex2oat to rerun on after all changes. -DEX2OAT_DEPENDENCY := | +DEX2OAT_DEPENDENCY := #| DEX2OAT_DEPENDENCY += $(DEX2OAT) DEX2OAT_DEPENDENCY += $(LIBART_COMPILER) @@ -57,15 +57,26 @@ TARGET_CORE_OAT_OUT := $(ART_TEST_OUT)/core.oat HOST_CORE_IMG_OUT := $(HOST_OUT_JAVA_LIBRARIES)/core.art TARGET_CORE_IMG_OUT := $(ART_TEST_OUT)/core.art +# DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES is set in ../build/core/dex_preopt.mk based on +# the TARGET_CPU_VARIANT + +TARGET_INSTRUCTION_SET_FEATURES := $(DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES) + $(HOST_CORE_IMG_OUT): $(HOST_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY) @echo "host dex2oat: $@ ($?)" @mkdir -p $(dir $@) - $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) --oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(IMG_HOST_BASE_ADDRESS) --instruction-set=$(HOST_ARCH) --host --android-root=$(HOST_OUT) + $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix \ + --dex-file=,$(HOST_CORE_DEX_FILES)) $(addprefix --dex-location=,$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$(HOST_CORE_OAT_OUT) \ + --oat-location=$(HOST_CORE_OAT) --image=$(HOST_CORE_IMG_OUT) --base=$(IMG_HOST_BASE_ADDRESS) \ + --instruction-set=$(HOST_ARCH) --host --android-root=$(HOST_OUT) $(TARGET_CORE_IMG_OUT): $(TARGET_CORE_DEX_FILES) $(DEX2OAT_DEPENDENCY) @echo "target dex2oat: $@ ($?)" @mkdir -p $(dir $@) - $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_CORE_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_CORE_DEX_LOCATIONS)) --oat-file=$(TARGET_CORE_OAT_OUT) --oat-location=$(TARGET_CORE_OAT) --image=$(TARGET_CORE_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) --instruction-set=$(TARGET_ARCH) --host-prefix=$(PRODUCT_OUT) --android-root=$(PRODUCT_OUT)/system + $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms16m --runtime-arg -Xmx16m --image-classes=$(PRELOADED_CLASSES) $(addprefix \ + --dex-file=,$(TARGET_CORE_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_CORE_DEX_LOCATIONS)) --oat-file=$(TARGET_CORE_OAT_OUT) \ + --oat-location=$(TARGET_CORE_OAT) --image=$(TARGET_CORE_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) \ + --instruction-set=$(TARGET_ARCH) --instruction-set-features=$(TARGET_INSTRUCTION_SET_FEATURES) --host-prefix=$(PRODUCT_OUT) --android-root=$(PRODUCT_OUT)/system $(HOST_CORE_OAT_OUT): $(HOST_CORE_IMG_OUT) @@ -110,7 +121,10 @@ $(TARGET_BOOT_IMG_OUT): $(TARGET_BOOT_DEX_FILES) $(DEX2OAT_DEPENDENCY) @echo "target dex2oat: $@ ($?)" @mkdir -p $(dir $@) @mkdir -p $(dir $(TARGET_BOOT_OAT_UNSTRIPPED_OUT)) - $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_BOOT_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_BOOT_DEX_LOCATIONS)) --oat-symbols=$(TARGET_BOOT_OAT_UNSTRIPPED_OUT) --oat-file=$(TARGET_BOOT_OAT_OUT) --oat-location=$(TARGET_BOOT_OAT) --image=$(TARGET_BOOT_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) --instruction-set=$(TARGET_ARCH) --host-prefix=$(PRODUCT_OUT) --android-root=$(PRODUCT_OUT)/system + $(hide) $(DEX2OAT) $(PARALLEL_ART_COMPILE_JOBS) --runtime-arg -Xms256m --runtime-arg -Xmx256m --image-classes=$(PRELOADED_CLASSES) $(addprefix --dex-file=,$(TARGET_BOOT_DEX_FILES)) $(addprefix --dex-location=,$(TARGET_BOOT_DEX_LOCATIONS)) \ + --oat-symbols=$(TARGET_BOOT_OAT_UNSTRIPPED_OUT) --oat-file=$(TARGET_BOOT_OAT_OUT) \ + --oat-location=$(TARGET_BOOT_OAT) --image=$(TARGET_BOOT_IMG_OUT) --base=$(IMG_TARGET_BASE_ADDRESS) \ + --instruction-set=$(TARGET_ARCH) --instruction-set-features=$(TARGET_INSTRUCTION_SET_FEATURES) --host-prefix=$(PRODUCT_OUT) --android-root=$(PRODUCT_OUT)/system $(TARGET_BOOT_OAT_UNSTRIPPED_OUT): $(TARGET_BOOT_IMG_OUT) diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h index 0d7209e438..fd46975b9a 100644 --- a/compiler/dex/compiler_ir.h +++ b/compiler/dex/compiler_ir.h @@ -97,6 +97,9 @@ struct CompilationUnit { CompilerBackend compiler_backend; InstructionSet instruction_set; + const InstructionSetFeatures& GetInstructionSetFeatures() { + return compiler_driver->GetInstructionSetFeatures(); + } // TODO: much of this info available elsewhere. Go to the original source? uint16_t num_dalvik_registers; // method->registers_size. const uint16_t* insns; diff --git a/compiler/dex/quick/arm/arm_lir.h b/compiler/dex/quick/arm/arm_lir.h index 2ff7f1ca6f..ffaaf84503 100644 --- a/compiler/dex/quick/arm/arm_lir.h +++ b/compiler/dex/quick/arm/arm_lir.h @@ -380,6 +380,8 @@ enum ArmOpcode { kThumb2CmnRR, // cmn [111010110001] rn[19..16] [0000] [1111] [0000] rm[3..0]. kThumb2EorRRR, // eor [111010101000] rn[19..16] [0000] rd[11..8] [0000] rm[3..0]. kThumb2MulRRR, // mul [111110110000] rn[19..16] [1111] rd[11..8] [0000] rm[3..0]. + kThumb2SdivRRR, // sdiv [111110111001] rn[19..16] [1111] rd[11..8] [1111] rm[3..0]. + kThumb2UdivRRR, // udiv [111110111011] rn[19..16] [1111] rd[11..8] [1111] rm[3..0]. kThumb2MnvRR, // mvn [11101010011011110] rd[11-8] [0000] rm[3..0]. kThumb2RsubRRI8, // rsub [111100011100] rn[19..16] [0000] rd[11..8] imm8[7..0]. kThumb2NegRR, // actually rsub rd, rn, #0. diff --git a/compiler/dex/quick/arm/assemble_arm.cc b/compiler/dex/quick/arm/assemble_arm.cc index e8c188c4c9..3d0f263fad 100644 --- a/compiler/dex/quick/arm/assemble_arm.cc +++ b/compiler/dex/quick/arm/assemble_arm.cc @@ -687,6 +687,14 @@ const ArmEncodingMap ArmMir2Lir::EncodingMap[kArmLast] = { kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, "mul", "!0C, !1C, !2C", 4, kFixupNone), + ENCODING_MAP(kThumb2SdivRRR, 0xfb90f0f0, + kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, + kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, + "sdiv", "!0C, !1C, !2C", 4, kFixupNone), + ENCODING_MAP(kThumb2UdivRRR, 0xfbb0f0f0, + kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0, + kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12, + "udiv", "!0C, !1C, !2C", 4, kFixupNone), ENCODING_MAP(kThumb2MnvRR, 0xea6f0000, kFmtBitBlt, 11, 8, kFmtBitBlt, 3, 0, kFmtShift, -1, -1, kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1, diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index 0a8cbf9cc0..42bf3d4d00 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -466,14 +466,39 @@ LIR* ArmMir2Lir::GenRegMemCheck(ConditionCode c_code, RegLocation ArmMir2Lir::GenDivRemLit(RegLocation rl_dest, int reg1, int lit, bool is_div) { - LOG(FATAL) << "Unexpected use of GenDivRemLit for Arm"; - return rl_dest; + RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); + + // Put the literal in a temp. + int lit_temp = AllocTemp(); + LoadConstant(lit_temp, lit); + // Use the generic case for div/rem with arg2 in a register. + // TODO: The literal temp can be freed earlier during a modulus to reduce reg pressure. + rl_result = GenDivRem(rl_result, reg1, lit_temp, is_div); + FreeTemp(lit_temp); + + return rl_result; } RegLocation ArmMir2Lir::GenDivRem(RegLocation rl_dest, int reg1, int reg2, bool is_div) { - LOG(FATAL) << "Unexpected use of GenDivRem for Arm"; - return rl_dest; + RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); + if (is_div) { + // Simple case, use sdiv instruction. + OpRegRegReg(kOpDiv, rl_result.low_reg, reg1, reg2); + } else { + // Remainder case, use the following code: + // temp = reg1 / reg2 - integer division + // temp = temp * reg2 + // dest = reg1 - temp + + int temp = AllocTemp(); + OpRegRegReg(kOpDiv, temp, reg1, reg2); + OpRegReg(kOpMul, temp, reg2); + OpRegRegReg(kOpSub, rl_result.low_reg, reg1, temp); + FreeTemp(temp); + } + + return rl_result; } bool ArmMir2Lir::GenInlinedMinMaxInt(CallInfo* info, bool is_min) { diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc index 3ceeacf5b1..d631cf7047 100644 --- a/compiler/dex/quick/arm/utility_arm.cc +++ b/compiler/dex/quick/arm/utility_arm.cc @@ -395,6 +395,10 @@ LIR* ArmMir2Lir::OpRegRegRegShift(OpKind op, int r_dest, int r_src1, DCHECK_EQ(shift, 0); opcode = kThumb2MulRRR; break; + case kOpDiv: + DCHECK_EQ(shift, 0); + opcode = kThumb2SdivRRR; + break; case kOpOr: opcode = kThumb2OrrRRR; break; diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 2b3404a9c7..df6493dc77 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -1307,6 +1307,7 @@ void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest, } StoreValue(rl_dest, rl_result); } else { + bool done = false; // Set to true if we happen to find a way to use a real instruction. if (cu_->instruction_set == kMips) { rl_src1 = LoadValue(rl_src1, kCoreReg); rl_src2 = LoadValue(rl_src2, kCoreReg); @@ -1314,7 +1315,23 @@ void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest, GenImmedCheck(kCondEq, rl_src2.low_reg, 0, kThrowDivZero); } rl_result = GenDivRem(rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv); - } else { + done = true; + } else if (cu_->instruction_set == kThumb2) { + if (cu_->GetInstructionSetFeatures().HasDivideInstruction()) { + // Use ARM SDIV instruction for division. For remainder we also need to + // calculate using a MUL and subtract. + rl_src1 = LoadValue(rl_src1, kCoreReg); + rl_src2 = LoadValue(rl_src2, kCoreReg); + if (check_zero) { + GenImmedCheck(kCondEq, rl_src2.low_reg, 0, kThrowDivZero); + } + rl_result = GenDivRem(rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv); + done = true; + } + } + + // If we haven't already generated the code use the callout function. + if (!done) { ThreadOffset func_offset = QUICK_ENTRYPOINT_OFFSET(pIdivmod); FlushAllRegs(); /* Send everything to home location */ LoadValueDirectFixed(rl_src2, TargetReg(kArg1)); @@ -1323,7 +1340,7 @@ void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest, if (check_zero) { GenImmedCheck(kCondEq, TargetReg(kArg1), 0, kThrowDivZero); } - // NOTE: callout here is not a safepoint + // NOTE: callout here is not a safepoint. CallHelper(r_tgt, func_offset, false /* not a safepoint */); if (op == kOpDiv) rl_result = GetReturn(false); @@ -1561,11 +1578,24 @@ void Mir2Lir::GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest, Re if (HandleEasyDivRem(opcode, is_div, rl_src, rl_dest, lit)) { return; } + + bool done = false; if (cu_->instruction_set == kMips) { rl_src = LoadValue(rl_src, kCoreReg); rl_result = GenDivRemLit(rl_dest, rl_src.low_reg, lit, is_div); - } else { - FlushAllRegs(); /* Everything to home location */ + done = true; + } else if (cu_->instruction_set == kThumb2) { + if (cu_->GetInstructionSetFeatures().HasDivideInstruction()) { + // Use ARM SDIV instruction for division. For remainder we also need to + // calculate using a MUL and subtract. + rl_src = LoadValue(rl_src, kCoreReg); + rl_result = GenDivRemLit(rl_dest, rl_src.low_reg, lit, is_div); + done = true; + } + } + + if (!done) { + FlushAllRegs(); /* Everything to home location. */ LoadValueDirectFixed(rl_src, TargetReg(kArg0)); Clobber(TargetReg(kArg0)); ThreadOffset func_offset = QUICK_ENTRYPOINT_OFFSET(pIdivmod); @@ -1583,7 +1613,7 @@ void Mir2Lir::GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest, Re } rl_src = LoadValue(rl_src, kCoreReg); rl_result = EvalLoc(rl_dest, kCoreReg, true); - // Avoid shifts by literal 0 - no support in Thumb. Change to copy + // Avoid shifts by literal 0 - no support in Thumb. Change to copy. if (shift_op && (lit == 0)) { OpRegCopy(rl_result.low_reg, rl_src.low_reg); } else { diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 783c3227a6..4871e162a3 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -336,10 +336,12 @@ extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver, std::string const& filename); CompilerDriver::CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set, + InstructionSetFeatures instruction_set_features, bool image, DescriptorSet* image_classes, size_t thread_count, bool dump_stats) : compiler_backend_(compiler_backend), instruction_set_(instruction_set), + instruction_set_features_(instruction_set_features), freezing_constructor_lock_("freezing constructor lock"), compiled_classes_lock_("compiled classes lock"), compiled_methods_lock_("compiled method lock"), diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 9b9a884339..9321f06526 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -91,6 +91,7 @@ class CompilerDriver { // can assume will be in the image, with NULL implying all available // classes. explicit CompilerDriver(CompilerBackend compiler_backend, InstructionSet instruction_set, + InstructionSetFeatures instruction_set_features, bool image, DescriptorSet* image_classes, size_t thread_count, bool dump_stats); @@ -104,10 +105,14 @@ class CompilerDriver { void CompileOne(const mirror::ArtMethod* method, base::TimingLogger& timings) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - InstructionSet GetInstructionSet() const { + const InstructionSet& GetInstructionSet() const { return instruction_set_; } + const InstructionSetFeatures& GetInstructionSetFeatures() const { + return instruction_set_features_; + } + CompilerBackend GetCompilerBackend() const { return compiler_backend_; } @@ -386,7 +391,8 @@ class CompilerDriver { CompilerBackend compiler_backend_; - InstructionSet instruction_set_; + const InstructionSet instruction_set_; + const InstructionSetFeatures instruction_set_features_; // All class references that require mutable ReaderWriterMutex freezing_constructor_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER; diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 815bca5c5a..6213b45c41 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -76,7 +76,10 @@ TEST_F(OatTest, WriteRead) { CompilerBackend compiler_backend = kQuick; #endif InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86; - compiler_driver_.reset(new CompilerDriver(compiler_backend, insn_set, false, NULL, 2, true)); + + InstructionSetFeatures insn_features; + compiler_driver_.reset(new CompilerDriver(compiler_backend, insn_set, + insn_features, false, NULL, 2, true)); jobject class_loader = NULL; if (kCompile) { base::TimingLogger timings("OatTest::WriteRead", false, false); @@ -149,17 +152,19 @@ TEST_F(OatTest, WriteRead) { TEST_F(OatTest, OatHeaderSizeCheck) { // If this test is failing and you have to update these constants, // it is time to update OatHeader::kOatVersion - EXPECT_EQ(72U, sizeof(OatHeader)); + EXPECT_EQ(76U, sizeof(OatHeader)); EXPECT_EQ(28U, sizeof(OatMethodOffsets)); } TEST_F(OatTest, OatHeaderIsValid) { InstructionSet instruction_set = kX86; + InstructionSetFeatures instruction_set_features; std::vector dex_files; uint32_t image_file_location_oat_checksum = 0; uint32_t image_file_location_oat_begin = 0; const std::string image_file_location; OatHeader oat_header(instruction_set, + instruction_set_features, &dex_files, image_file_location_oat_checksum, image_file_location_oat_begin, diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index 28355bfc74..f3bb11272e 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -98,6 +98,7 @@ OatWriter::~OatWriter() { size_t OatWriter::InitOatHeader() { // create the OatHeader oat_header_ = new OatHeader(compiler_driver_->GetInstructionSet(), + compiler_driver_->GetInstructionSetFeatures(), dex_files_, image_file_location_oat_checksum_, image_file_location_oat_begin_, diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 98c62cec66..1472337615 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -131,6 +131,10 @@ static void Usage(const char* fmt, ...) { UsageError(" Example: --instruction-set=x86"); UsageError(" Default: arm"); UsageError(""); + UsageError(" --instruction-set-features=...,: Specify instruction set features"); + UsageError(" Example: --instruction-set-features=div"); + UsageError(" Default: default"); + UsageError(""); UsageError(" --compiler-backend=(Quick|QuickGBC|Portable): select compiler backend"); UsageError(" set."); UsageError(" Example: --compiler-backend=Portable"); @@ -155,13 +159,15 @@ class Dex2Oat { Runtime::Options& options, CompilerBackend compiler_backend, InstructionSet instruction_set, + InstructionSetFeatures instruction_set_features, size_t thread_count) SHARED_TRYLOCK_FUNCTION(true, Locks::mutator_lock_) { if (!CreateRuntime(options, instruction_set)) { *p_dex2oat = NULL; return false; } - *p_dex2oat = new Dex2Oat(Runtime::Current(), compiler_backend, instruction_set, thread_count); + *p_dex2oat = new Dex2Oat(Runtime::Current(), compiler_backend, instruction_set, + instruction_set_features, thread_count); return true; } @@ -257,6 +263,7 @@ class Dex2Oat { UniquePtr driver(new CompilerDriver(compiler_backend_, instruction_set_, + instruction_set_features_, image, image_classes.release(), thread_count_, @@ -330,9 +337,11 @@ class Dex2Oat { explicit Dex2Oat(Runtime* runtime, CompilerBackend compiler_backend, InstructionSet instruction_set, + InstructionSetFeatures instruction_set_features, size_t thread_count) : compiler_backend_(compiler_backend), instruction_set_(instruction_set), + instruction_set_features_(instruction_set_features), runtime_(runtime), thread_count_(thread_count), start_ns_(NanoTime()) { @@ -391,6 +400,7 @@ class Dex2Oat { const CompilerBackend compiler_backend_; const InstructionSet instruction_set_; + const InstructionSetFeatures instruction_set_features_; Runtime* runtime_; size_t thread_count_; @@ -559,6 +569,32 @@ class WatchDog { const unsigned int WatchDog::kWatchDogWarningSeconds; const unsigned int WatchDog::kWatchDogTimeoutSeconds; +// Given a set of instruction features from the build, parse it. The +// input 'str' is a comma separated list of feature names. Parse it and +// return the InstructionSetFeatures object. +static InstructionSetFeatures ParseFeatureList(std::string str) { + InstructionSetFeatures result; + typedef std::vector FeatureList; + FeatureList features; + Split(str, ',', features); + for (FeatureList::iterator i = features.begin(); i != features.end(); i++) { + std::string feature = Trim(*i); + if (feature == "default") { + // Nothing to do. + } else if (feature == "div") { + // Supports divide instruction. + result.SetHasDivideInstruction(true); + } else if (feature == "nodiv") { + // Turn off support for divide instruction. + result.SetHasDivideInstruction(false); + } else { + Usage("Unknown instruction set feature: '%s'", feature.c_str()); + } + } + // others... + return result; +} + static int dex2oat(int argc, char** argv) { base::TimingLogger timings("compiler", false, false); @@ -595,6 +631,15 @@ static int dex2oat(int argc, char** argv) { #else CompilerBackend compiler_backend = kQuick; #endif + + // Take the default set of instruction features from the build if present. + InstructionSetFeatures instruction_set_features = +#ifdef ART_DEFAULT_INSTRUCTION_SET_FEATURES + ParseFeatureList(STRINGIFY(ART_DEFAULT_INSTRUCTION_SET_FEATURES)); +#else + ParseFeatureList("default"); +#endif + #if defined(__arm__) InstructionSet instruction_set = kThumb2; #elif defined(__i386__) @@ -604,6 +649,8 @@ static int dex2oat(int argc, char** argv) { #else #error "Unsupported architecture" #endif + + bool is_host = false; bool dump_stats = false; bool dump_timing = false; @@ -678,6 +725,9 @@ static int dex2oat(int argc, char** argv) { } else if (instruction_set_str == "x86") { instruction_set = kX86; } + } else if (option.starts_with("--instruction-set-features=")) { + StringPiece str = option.substr(strlen("--instruction-set-features=")).data(); + instruction_set_features = ParseFeatureList(str.as_string()); } else if (option.starts_with("--compiler-backend=")) { StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data(); if (backend_str == "Quick") { @@ -870,7 +920,8 @@ static int dex2oat(int argc, char** argv) { #endif Dex2Oat* p_dex2oat; - if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set, thread_count)) { + if (!Dex2Oat::Create(&p_dex2oat, options, compiler_backend, instruction_set, + instruction_set_features, thread_count)) { LOG(ERROR) << "Failed to create dex2oat"; return EXIT_FAILURE; } @@ -1093,8 +1144,6 @@ static int dex2oat(int argc, char** argv) { return EXIT_SUCCESS; } - - } // namespace art int main(int argc, char** argv) { diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc index 6239e9abb7..8d4f3ce263 100644 --- a/disassembler/disassembler_arm.cc +++ b/disassembler/disassembler_arm.cc @@ -374,7 +374,102 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) // uint32_t op5 = (instr >> 4) & 0xF; ArmRegister Rn(instr, 16); ArmRegister Rt(instr, 12); + ArmRegister Rd(instr, 8); uint32_t imm8 = instr & 0xFF; + if ((op3 & 2) == 2) { // 1x + int W = (instr >> 21) & 1; + int U = (instr >> 23) & 1; + int P = (instr >> 24) & 1; + + if ((op4 & 1) == 1) { + opcode << "ldrd"; + } else { + opcode << "strd"; + } + args << Rt << "," << Rd << ", [" << Rn; + const char *sign = U ? "+" : "-"; + if (P == 0 && W == 1) { + args << "], #" << sign << imm8; + } else { + args << ", #" << sign << imm8 << "]"; + if (W == 1) { + args << "!"; + } + } + } else { // 0x + switch (op4) { + case 0: + if (op3 == 0) { // op3 is 00, op4 is 00 + opcode << "strex"; + args << Rd << ", " << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]"; + } else { // op3 is 01, op4 is 00 + // this is one of strexb, strexh or strexd + int op5 = (instr >> 4) & 0xf; + switch (op5) { + case 4: + opcode << "strexb"; + break; + case 5: + opcode << "strexh"; + break; + case 7: + opcode << "strexd"; + break; + } + } + break; + case 1: + if (op3 == 0) { // op3 is 00, op4 is 01 + opcode << "ldrex"; + args << Rt << ", [" << Rn << ", #" << (imm8 << 2) << "]"; + } else { // op3 is 01, op4 is 01 + // this is one of strexb, strexh or strexd + int op5 = (instr >> 4) & 0xf; + switch (op5) { + case 0: + opcode << "tbb"; + break; + case 1: + opcode << "tbh"; + break; + case 4: + opcode << "ldrexb"; + break; + case 5: + opcode << "ldrexh"; + break; + case 7: + opcode << "ldrexd"; + break; + } + } + break; + case 2: // op3 is 0x, op4 is 10 + case 3: // op3 is 0x, op4 is 11 + if (op4 == 2) { + opcode << "strd"; + } else { + opcode << "ldrd"; + } + int W = (instr >> 21) & 1; + int U = (instr >> 23) & 1; + int P = (instr >> 24) & 1; + + args << Rt << "," << Rd << ", [" << Rn; + const char *sign = U ? "+" : "-"; + if (P == 0 && W == 1) { + args << "], #" << sign << imm8; + } else { + args << ", #" << sign << imm8 << "]"; + if (W == 1) { + args << "!"; + } + } + break; + } + } + + if (op3 == 0 && op4 == 0) { // STREX ArmRegister Rd(instr, 8); opcode << "strex"; @@ -519,19 +614,11 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) uint32_t op3 = (instr >> 20) & 0x3F; uint32_t coproc = (instr >> 8) & 0xF; uint32_t op4 = (instr >> 4) & 0x1; - if ((op3 == 2 || op3 == 2 || op3 == 6 || op3 == 7) || // 00x1x - (op3 >= 8 && op3 <= 15) || (op3 >= 16 && op3 <= 31)) { // 001xxx, 01xxxx - // Extension register load/store instructions - // |111|1|110|00000|0000|1111|110|000000000| - // |5 3|2|109|87654|3 0|54 2|10 |87 54 0| - // |---|-|---|-----|----|----|---|---------| - // |332|2|222|22222|1111|1111|110|000000000| - // |1 9|8|765|43210|9 6|54 2|10 |87 54 0| - // |---|-|---|-----|----|----|---|---------| - // |111|T|110| op3 | Rn | |101| | - // 111 0 110 01001 0011 0000 101 000000011 - ec930a03 - if (op3 == 9 || op3 == 0xD) { // VLDM - // 1110 110 PUDW1 nnnn dddd 101S iiii iiii + + if (coproc == 10 || coproc == 11) { // 101x + if (op3 < 0x20 && (op3 >> 1) != 2) { // 0xxxxx and not 00010x + // extension load/store instructions + int op = op3 & 0x1f; uint32_t P = (instr >> 24) & 1; uint32_t U = (instr >> 23) & 1; uint32_t D = (instr >> 22) & 1; @@ -541,20 +628,49 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) uint32_t Vd = (instr >> 12) & 0xF; uint32_t imm8 = instr & 0xFF; uint32_t d = (S == 0 ? ((Vd << 1) | D) : (Vd | (D << 4))); - if (P == 0 && U == 0 && W == 0) { - // TODO: 64bit transfers between ARM core and extension registers. - } else if (P == 0 && U == 1 && Rn.r == 13) { // VPOP - opcode << "vpop" << (S == 0 ? ".f64" : ".f32"); - args << d << " .. " << (d + imm8); - } else if (P == 1 && W == 0) { // VLDR - opcode << "vldr" << (S == 0 ? ".f64" : ".f32"); - args << d << ", [" << Rn << ", #" << imm8 << "]"; - } else { // VLDM - opcode << "vldm" << (S == 0 ? ".f64" : ".f32"); - args << Rn << ", " << d << " .. " << (d + imm8); + ArmRegister Rd(d, 0); + + if (op == 8 || op == 12 || op == 10 || op == 14 || + op == 18 || op == 22) { // 01x00 or 01x10 + // vector store multiple or vpush + if (P == 1 && U == 0 && W == 1 && Rn.r == 13) { + opcode << "vpush" << (S == 0 ? ".f64" : ".f32"); + args << Rd << " .. " << (Rd.r + imm8); + } else { + opcode << "vstm" << (S == 0 ? ".f64" : ".f32"); + args << Rn << ", " << Rd << " .. " << (Rd.r + imm8); + } + } else if (op == 16 || op == 20 || op == 24 || op == 28) { + // 1xx00 + // vector store register + opcode << "vstr" << (S == 0 ? ".f64" : ".f32"); + args << Rd << ", [" << Rn << ", #" << imm8 << "]"; + } else if (op == 17 || op == 21 || op == 25 || op == 29) { + // 1xx01 + // vector load register + opcode << "vldr" << (S == 0 ? ".f64" : ".f32"); + args << Rd << ", [" << Rn << ", #" << imm8 << "]"; + } else if (op == 9 || op == 13 || op == 11 || op == 15 || + op == 19 || op == 23 ) { // 01x11 10x11 + // vldm or vpop + if (P == 1 && U == 0 && W == 1 && Rn.r == 13) { + opcode << "vpop" << (S == 0 ? ".f64" : ".f32"); + args << Rd << " .. " << (Rd.r + imm8); + } else { + opcode << "vldm" << (S == 0 ? ".f64" : ".f32"); + args << Rn << ", " << Rd << " .. " << (Rd.r + imm8); + } } + } else if ((op3 >> 1) == 2) { // 00010x + // 64 bit transfers + } else if ((op3 >> 4) == 2 && op4 == 0) { // 10xxxx, op = 0 + // fp data processing + } else if ((op3 >> 4) == 2 && op4 == 1) { // 10xxxx, op = 1 + // 8,16,32 bit transfers } - } else if ((op3 & 0x30) == 0x20 && op4 == 0) { // 10 xxxx ... 0 + } + + if ((op3 & 0x30) == 0x20 && op4 == 0) { // 10 xxxx ... 0 if ((coproc & 0xE) == 0xA) { // VFP data-processing instructions // |111|1|1100|0000|0000|1111|110|0|00 |0|0|0000| @@ -1070,6 +1186,72 @@ size_t DisassemblerArm::DumpThumb32(std::ostream& os, const uint8_t* instr_ptr) } break; } + default: // more formats + if ((op2 >> 4) == 2) { // 010xxxx + // data processing (register) + } else if ((op2 >> 3) == 6) { // 0110xxx + // Multiply, multiply accumulate, and absolute difference + op1 = (instr >> 20) & 0x7; + op2 = (instr >> 4) & 0x2; + ArmRegister Ra(instr, 12); + ArmRegister Rn(instr, 16); + ArmRegister Rm(instr, 0); + ArmRegister Rd(instr, 8); + switch (op1) { + case 0: + if (op2 == 0) { + if (Ra.r == 0xf) { + opcode << "mul"; + args << Rd << ", " << Rn << ", " << Rm; + } else { + opcode << "mla"; + args << Rd << ", " << Rn << ", " << Rm << ", " << Ra; + } + } else { + opcode << "mls"; + args << Rd << ", " << Rn << ", " << Rm << ", " << Ra; + } + break; + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + break; // do these sometime + } + } else if ((op2 >> 3) == 7) { // 0111xxx + // Long multiply, long multiply accumulate, and divide + op1 = (instr >> 20) & 0x7; + op2 = (instr >> 4) & 0xf; + ArmRegister Rn(instr, 16); + ArmRegister Rm(instr, 0); + ArmRegister Rd(instr, 8); + ArmRegister RdHi(instr, 8); + ArmRegister RdLo(instr, 12); + switch (op1) { + case 0: + opcode << "smull"; + args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm; + break; + case 1: + opcode << "sdiv"; + args << Rd << ", " << Rn << ", " << Rm; + break; + case 2: + opcode << "umull"; + args << RdLo << ", " << RdHi << ", " << Rn << ", " << Rm; + break; + case 3: + opcode << "udiv"; + args << Rd << ", " << Rn << ", " << Rm; + break; + case 4: + case 5: + case 6: + break; // TODO: when we generate these... + } + } } default: break; diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 3a32ff14bd..b9716d556f 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -118,6 +118,9 @@ class OatDumper { os << "INSTRUCTION SET:\n"; os << oat_header.GetInstructionSet() << "\n\n"; + os << "INSTRUCTION SET FEATURES:\n"; + os << oat_header.GetInstructionSetFeatures().GetFeatureString() << "\n\n"; + os << "DEX FILE COUNT:\n"; os << oat_header.GetDexFileCount() << "\n\n"; diff --git a/runtime/Android.mk b/runtime/Android.mk index 3d275e63c0..bef4381c2b 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -187,6 +187,7 @@ LIBART_TARGET_SRC_FILES += \ arch/arm/jni_entrypoints_arm.S \ arch/arm/portable_entrypoints_arm.S \ arch/arm/quick_entrypoints_arm.S \ + arch/arm/arm_sdiv.S \ arch/arm/thread_arm.cc else # TARGET_ARCH != arm ifeq ($(TARGET_ARCH),x86) diff --git a/runtime/arch/arm/arm_sdiv.S b/runtime/arch/arm/arm_sdiv.S new file mode 100644 index 0000000000..925e428444 --- /dev/null +++ b/runtime/arch/arm/arm_sdiv.S @@ -0,0 +1,24 @@ +// This function is used to check for the CPU's support for the sdiv +// instruction at runtime. It will either return the value 1 or +// will cause an invalid instruction trap (SIGILL signal). The +// caller must arrange for the signal handler to set the r0 +// register to 0 and move the pc forward by 4 bytes (to skip +// the invalid instruction). + + +#include "asm_support_arm.S" + +.section .text +ENTRY CheckForARMSDIVInstruction + mov r1,#1 + // depending on the architecture, the assembler will not allow an + // sdiv instruction, so we will have to output the bytes directly. + + // sdiv r0,r1,r1 is two words: 0xfb91 0xf1f0. We need little endian. + .byte 0x91,0xfb,0xf1,0xf0 + + // if the divide worked, r0 will have the value #1 (result of sdiv). + // It will have 0 otherwise (set by the signal handler) + // the value is just returned from this function. + bx lr + END CheckForARMSDIVInstruction diff --git a/runtime/base/macros.h b/runtime/base/macros.h index d00c64a4ab..00a530a206 100644 --- a/runtime/base/macros.h +++ b/runtime/base/macros.h @@ -130,6 +130,10 @@ char (&ArraySizeHelper(T (&array)[N]))[N]; #define LIKELY(x) __builtin_expect((x), true) #define UNLIKELY(x) __builtin_expect((x), false) +// Stringify the argument. +#define QUOTE(x) #x +#define STRINGIFY(x) QUOTE(x) + #ifndef NDEBUG #define ALWAYS_INLINE #else diff --git a/runtime/common_test.h b/runtime/common_test.h index 673a03b355..79fa680392 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "../../external/icu4c/common/unicode/uvernum.h" #include "base/macros.h" @@ -152,6 +153,113 @@ class ScratchFile { UniquePtr file_; }; +#if defined(__arm__) + + +#include +#include +#include + + +// A signal handler called when have an illegal instruction. We record the fact in +// a global boolean and then increment the PC in the signal context to return to +// the next instruction. We know the instruction is an sdiv (4 bytes long). +static void baddivideinst(int signo, siginfo *si, void *data) { + (void)signo; + (void)si; + struct ucontext *uc = (struct ucontext *)data; + struct sigcontext *sc = &uc->uc_mcontext; + sc->arm_r0 = 0; // set R0 to #0 to signal error + sc->arm_pc += 4; // skip offending instruction +} + +// This is in arch/arm/arm_sdiv.S. It does the following: +// mov r1,#1 +// sdiv r0,r1,r1 +// bx lr +// +// the result will be the value 1 if sdiv is supported. If it is not supported +// a SIGILL signal will be raised and the signal handler (baddivideinst) called. +// The signal handler sets r0 to #0 and then increments pc beyond the failed instruction. +// Thus if the instruction is not supported, the result of this function will be #0 + +extern "C" bool CheckForARMSDIVInstruction(); + +static InstructionSetFeatures GuessInstructionFeatures() { + InstructionSetFeatures f; + + // Uncomment this for processing of /proc/cpuinfo. + if (false) { + // Look in /proc/cpuinfo for features we need. Only use this when we can guarantee that + // the kernel puts the appropriate feature flags in here. Sometimes it doesn't. + std::ifstream in("/proc/cpuinfo"); + if (in) { + while (!in.eof()) { + std::string line; + std::getline(in, line); + if (!in.eof()) { + if (line.find("Features") != std::string::npos) { + if (line.find("idivt") != std::string::npos) { + f.SetHasDivideInstruction(true); + } + } + } + in.close(); + } + } else { + LOG(INFO) << "Failed to open /proc/cpuinfo"; + } + } + + // See if have a sdiv instruction. Register a signal handler and try to execute + // an sdiv instruction. If we get a SIGILL then it's not supported. We can't use + // the /proc/cpuinfo method for this because Krait devices don't always put the idivt + // feature in the list. + struct sigaction sa, osa; + sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; + sa.sa_sigaction = baddivideinst; + sigaction(SIGILL, &sa, &osa); + + if (CheckForARMSDIVInstruction()) { + f.SetHasDivideInstruction(true); + } + + // Restore the signal handler. + sigaction(SIGILL, &osa, NULL); + + // Other feature guesses in here. + return f; +} + +#endif + +// Given a set of instruction features from the build, parse it. The +// input 'str' is a comma separated list of feature names. Parse it and +// return the InstructionSetFeatures object. +static InstructionSetFeatures ParseFeatureList(std::string str) { + LOG(INFO) << "Parsing features " << str; + InstructionSetFeatures result; + typedef std::vector FeatureList; + FeatureList features; + Split(str, ',', features); + for (FeatureList::iterator i = features.begin(); i != features.end(); i++) { + std::string feature = Trim(*i); + if (feature == "default") { + // Nothing to do. + } else if (feature == "div") { + // Supports divide instruction. + result.SetHasDivideInstruction(true); + } else if (feature == "nodiv") { + // Turn off support for divide instruction. + result.SetHasDivideInstruction(false); + } else { + LOG(FATAL) << "Unknown instruction set feature: '" << feature << "'"; + } + } + // Others... + return result; +} + class CommonTest : public testing::Test { public: static void MakeExecutable(const mirror::ByteArray* code_array) { @@ -314,8 +422,22 @@ class CommonTest : public testing::Test { class_linker_ = runtime_->GetClassLinker(); InstructionSet instruction_set = kNone; + + // take the default set of instruction features from the build if present + InstructionSetFeatures instruction_set_features = +#ifdef ART_DEFAULT_INSTRUCTION_SET_FEATURES + ParseFeatureList(STRINGIFY(ART_DEFAULT_INSTRUCTION_SET_FEATURES)); +#else + ParseFeatureList("default"); +#endif + #if defined(__arm__) instruction_set = kThumb2; + InstructionSetFeatures runtime_features = GuessInstructionFeatures(); + + // for ARM, do a runtime check to make sure that the features we are passed from + // the build match the features we actually determine at runtime. + ASSERT_EQ(instruction_set_features, runtime_features); #elif defined(__mips__) instruction_set = kMips; #elif defined(__i386__) @@ -338,6 +460,7 @@ class CommonTest : public testing::Test { } class_linker_->FixupDexCaches(runtime_->GetResolutionMethod()); compiler_driver_.reset(new CompilerDriver(compiler_backend, instruction_set, + instruction_set_features, true, new CompilerDriver::DescriptorSet, 2, true)); } @@ -568,7 +691,6 @@ class CheckJniAbortCatcher { #else #define TEST_DISABLED_FOR_PORTABLE() #endif - } // namespace art namespace std { diff --git a/runtime/instruction_set.h b/runtime/instruction_set.h index 2217f7f76e..aee7447faf 100644 --- a/runtime/instruction_set.h +++ b/runtime/instruction_set.h @@ -18,6 +18,9 @@ #define ART_RUNTIME_INSTRUCTION_SET_H_ #include +#include + +#include "base/macros.h" namespace art { @@ -29,6 +32,53 @@ enum InstructionSet { kMips }; +enum InstructionFeatures { + kHwDiv = 1 // Supports hardware divide. +}; + +// This is a bitmask of supported features per architecture. +class PACKED(4) InstructionSetFeatures { + public: + InstructionSetFeatures() : mask_(0) {} + explicit InstructionSetFeatures(uint32_t mask) : mask_(mask) {} + + bool HasDivideInstruction() const { + return (mask_ & kHwDiv) != 0; + } + + void SetHasDivideInstruction(bool v) { + mask_ = (mask_ & ~kHwDiv) | (v ? kHwDiv : 0); + } + + std::string GetFeatureString() const { + std::string result; + if ((mask_ & kHwDiv) != 0) { + result += "div"; + } + if (result.size() == 0) { + result = "none"; + } + return result; + } + + uint32_t get_mask() const { + return mask_; + } + + // Other features in here. + + bool operator==(const InstructionSetFeatures &peer) const { + return mask_ == peer.mask_; + } + + bool operator!=(const InstructionSetFeatures &peer) const { + return mask_ != peer.mask_; + } + + private: + uint32_t mask_; +}; + std::ostream& operator<<(std::ostream& os, const InstructionSet& rhs); } // namespace art diff --git a/runtime/oat.cc b/runtime/oat.cc index defda6bb1a..94897950e0 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -22,13 +22,14 @@ namespace art { const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' }; -const uint8_t OatHeader::kOatVersion[] = { '0', '0', '9', '\0' }; +const uint8_t OatHeader::kOatVersion[] = { '0', '1', '0', '\0' }; OatHeader::OatHeader() { memset(this, 0, sizeof(*this)); } OatHeader::OatHeader(InstructionSet instruction_set, + const InstructionSetFeatures& instruction_set_features, const std::vector* dex_files, uint32_t image_file_location_oat_checksum, uint32_t image_file_location_oat_data_begin, @@ -42,6 +43,9 @@ OatHeader::OatHeader(InstructionSet instruction_set, instruction_set_ = instruction_set; UpdateChecksum(&instruction_set_, sizeof(instruction_set_)); + instruction_set_features_ = instruction_set_features; + UpdateChecksum(&instruction_set_features_, sizeof(instruction_set_features_)); + dex_file_count_ = dex_files->size(); UpdateChecksum(&dex_file_count_, sizeof(dex_file_count_)); @@ -99,6 +103,11 @@ InstructionSet OatHeader::GetInstructionSet() const { return instruction_set_; } +const InstructionSetFeatures& OatHeader::GetInstructionSetFeatures() const { + CHECK(IsValid()); + return instruction_set_features_; +} + uint32_t OatHeader::GetExecutableOffset() const { DCHECK(IsValid()); DCHECK_ALIGNED(executable_offset_, kPageSize); diff --git a/runtime/oat.h b/runtime/oat.h index c864c2cc52..de840b5870 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,6 +32,7 @@ class PACKED(4) OatHeader { OatHeader(); OatHeader(InstructionSet instruction_set, + const InstructionSetFeatures& instruction_set_features, const std::vector* dex_files, uint32_t image_file_location_oat_checksum, uint32_t image_file_location_oat_data_begin, @@ -80,6 +81,7 @@ class PACKED(4) OatHeader { void SetQuickToInterpreterBridgeOffset(uint32_t offset); InstructionSet GetInstructionSet() const; + const InstructionSetFeatures& GetInstructionSetFeatures() const; uint32_t GetImageFileLocationOatChecksum() const; uint32_t GetImageFileLocationOatDataBegin() const; uint32_t GetImageFileLocationSize() const; @@ -92,6 +94,7 @@ class PACKED(4) OatHeader { uint32_t adler32_checksum_; InstructionSet instruction_set_; + InstructionSetFeatures instruction_set_features_; uint32_t dex_file_count_; uint32_t executable_offset_; uint32_t interpreter_to_interpreter_bridge_offset_; diff --git a/runtime/utils.cc b/runtime/utils.cc index 9796b99635..e039581b05 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -889,6 +889,35 @@ void Split(const std::string& s, char separator, std::vector& resul } } +std::string Trim(std::string s) { + std::string result; + unsigned int start_index = 0; + unsigned int end_index = s.size() - 1; + + // Skip initial whitespace. + while (start_index < s.size()) { + if (!isspace(s[start_index])) { + break; + } + start_index++; + } + + // Skip terminating whitespace. + while (end_index >= start_index) { + if (!isspace(s[end_index])) { + break; + } + end_index--; + } + + // All spaces, no beef. + if (end_index < start_index) { + return ""; + } + // Start_index is the first non-space, end_index is the last one. + return s.substr(start_index, end_index - start_index + 1); +} + template std::string Join(std::vector& strings, char separator) { if (strings.empty()) { diff --git a/runtime/utils.h b/runtime/utils.h index 51035b697f..6850e8b025 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -252,7 +252,7 @@ std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit); // Get the appropriate unit for a nanosecond duration. TimeUnit GetAppropriateTimeUnit(uint64_t nano_duration); -// Get the divisor to convert from a nanoseconds to a time unit +// Get the divisor to convert from a nanoseconds to a time unit. uint64_t GetNsToTimeUnitDivisor(TimeUnit time_unit); // Performs JNI name mangling as described in section 11.3 "Linking Native Methods" @@ -326,6 +326,9 @@ void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts // strings. Empty strings will be omitted. void Split(const std::string& s, char separator, std::vector& result); +// Trims whitespace off both ends of the given string. +std::string Trim(std::string s); + // Joins a vector of strings into a single string, using the given separator. template std::string Join(std::vector& strings, char separator); @@ -354,10 +357,10 @@ void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix = "", bool // Dumps the kernel stack for thread 'tid' to 'os'. Note that this is only available on linux-x86. void DumpKernelStack(std::ostream& os, pid_t tid, const char* prefix = "", bool include_count = true); -// Find $ANDROID_ROOT, /system, or abort +// Find $ANDROID_ROOT, /system, or abort. const char* GetAndroidRoot(); -// Find $ANDROID_DATA, /data, or abort +// Find $ANDROID_DATA, /data, or abort. const char* GetAndroidData(); // Returns the dalvik-cache location, or dies trying. -- cgit v1.2.3-59-g8ed1b From d3c20c1a46863841c866b64a4c21e8bf9396b54c Mon Sep 17 00:00:00 2001 From: Jeff Hao Date: Wed, 30 Oct 2013 14:12:12 -0700 Subject: Update compiler blacklist to include java.net.NetworkInterface. Bug: 11411129 Change-Id: Ib93d2f75024b3def54eadc11547990150deccf4d (cherry picked from commit a52454455048d04d12e4da637a103412a55e579b) --- compiler/driver/compiler_driver.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index bea94a74df..b876724f21 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1980,6 +1980,7 @@ static const char* class_initializer_black_list[] = { "Ljava/net/Inet4Address;", // Sub-class of InetAddress. "Ljava/net/Inet6Address;", // Sub-class of InetAddress. "Ljava/net/InetUnixAddress;", // Sub-class of InetAddress. + "Ljava/net/NetworkInterface;", // Calls to Random. -> System.currentTimeMillis -> OsConstants.initConstants. "Ljava/nio/charset/Charset;", // Calls Charset.getDefaultCharset -> System.getProperty -> OsConstants.initConstants. "Ljava/nio/charset/CharsetICU;", // Sub-class of Charset. "Ljava/nio/charset/Charsets;", // Calls Charset.forName. -- cgit v1.2.3-59-g8ed1b From 0e49b42e03af56521d8ce2c9c84ac5b79e6241c9 Mon Sep 17 00:00:00 2001 From: Jeff Hao Date: Fri, 8 Nov 2013 12:16:56 -0800 Subject: Fix handling of duplicate class definitions in boot classpath. The compiler driver would get the wrong class references if a class is defined multiple times in the boot classpath. It will now skip the extra definitions. Bug: 11598481 Samsung bug: 11539656 Change-Id: I4d9ae2b6d11190e6e6b89261d5f87c802def8810 --- compiler/driver/compiler_driver.cc | 86 +++++++++++++++++++++++++------------- 1 file changed, 56 insertions(+), 30 deletions(-) (limited to 'compiler/driver/compiler_driver.cc') diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index b876724f21..74fcbed9e7 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1432,22 +1432,47 @@ class ParallelCompilationManager { DISALLOW_COPY_AND_ASSIGN(ParallelCompilationManager); }; -// Return true if the class should be skipped during compilation. We -// never skip classes in the boot class loader. However, if we have a -// non-boot class loader and we can resolve the class in the boot -// class loader, we do skip the class. This happens if an app bundles -// classes found in the boot classpath. Since at runtime we will -// select the class from the boot classpath, do not attempt to resolve -// or compile it now. +// Return true if the class should be skipped during compilation. +// +// The first case where we skip is for redundant class definitions in +// the boot classpath. We skip all but the first definition in that case. +// +// The second case where we skip is when an app bundles classes found +// in the boot classpath. Since at runtime we will select the class from +// the boot classpath, we ignore the one from the app. static bool SkipClass(ClassLinker* class_linker, jobject class_loader, const DexFile& dex_file, const DexFile::ClassDef& class_def) { + const char* descriptor = dex_file.GetClassDescriptor(class_def); if (class_loader == NULL) { + DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, class_linker->GetBootClassPath()); + CHECK(pair.second != NULL); + if (pair.first != &dex_file) { + LOG(WARNING) << "Skipping class " << descriptor << " from " << dex_file.GetLocation() + << " previously found in " << pair.first->GetLocation(); + return true; + } return false; } - const char* descriptor = dex_file.GetClassDescriptor(class_def); return class_linker->IsInBootClassPath(descriptor); } +// A fast version of SkipClass above if the class pointer is available +// that avoids the expensive FindInClassPath search. +static bool SkipClass(jobject class_loader, const DexFile& dex_file, mirror::Class* klass) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(klass != NULL); + const DexFile& original_dex_file = *klass->GetDexCache()->GetDexFile(); + if (&dex_file != &original_dex_file) { + if (class_loader == NULL) { + LOG(WARNING) << "Skipping class " << PrettyDescriptor(klass) << " from " + << dex_file.GetLocation() << " previously found in " + << original_dex_file.GetLocation(); + } + return true; + } + return false; +} + static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manager, size_t class_def_index) LOCKS_EXCLUDED(Locks::mutator_lock_) { @@ -1612,11 +1637,13 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ LOCKS_EXCLUDED(Locks::mutator_lock_) { ATRACE_CALL(); ScopedObjectAccess soa(Thread::Current()); - const DexFile::ClassDef& class_def = manager->GetDexFile()->GetClassDef(class_def_index); - const char* descriptor = manager->GetDexFile()->GetClassDescriptor(class_def); - mirror::Class* klass = - manager->GetClassLinker()->FindClass(descriptor, - soa.Decode(manager->GetClassLoader())); + const DexFile& dex_file = *manager->GetDexFile(); + const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); + const char* descriptor = dex_file.GetClassDescriptor(class_def); + ClassLinker* class_linker = manager->GetClassLinker(); + jobject jclass_loader = manager->GetClassLoader(); + mirror::Class* klass = class_linker->FindClass(descriptor, + soa.Decode(jclass_loader)); if (klass == NULL) { CHECK(soa.Self()->IsExceptionPending()); soa.Self()->ClearException(); @@ -1626,23 +1653,18 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_ * This is to ensure the class is structurally sound for compilation. An unsound class * will be rejected by the verifier and later skipped during compilation in the compiler. */ - mirror::DexCache* dex_cache = manager->GetClassLinker()->FindDexCache(*manager->GetDexFile()); + mirror::DexCache* dex_cache = class_linker->FindDexCache(dex_file); std::string error_msg; - const DexFile* dex_file = manager->GetDexFile(); - const DexFile::ClassDef* class_def = &dex_file->GetClassDef(class_def_index); - if (verifier::MethodVerifier::VerifyClass(dex_file, - dex_cache, - soa.Decode(manager->GetClassLoader()), - class_def, true, &error_msg) == + if (verifier::MethodVerifier::VerifyClass(&dex_file, dex_cache, + soa.Decode(jclass_loader), + &class_def, true, &error_msg) == verifier::MethodVerifier::kHardFailure) { - const DexFile::ClassDef& class_def = manager->GetDexFile()->GetClassDef(class_def_index); - LOG(ERROR) << "Verification failed on class " - << PrettyDescriptor(manager->GetDexFile()->GetClassDescriptor(class_def)) + LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(descriptor) << " because: " << error_msg; } - } else { + } else if (!SkipClass(jclass_loader, dex_file, klass)) { CHECK(klass->IsResolved()) << PrettyClass(klass); - manager->GetClassLinker()->VerifyClass(klass); + class_linker->VerifyClass(klass); if (klass->IsErroneous()) { // ClassLinker::VerifyClass throws, which isn't useful in the compiler. @@ -2086,12 +2108,16 @@ static const char* class_initializer_black_list[] = { static void InitializeClass(const ParallelCompilationManager* manager, size_t class_def_index) LOCKS_EXCLUDED(Locks::mutator_lock_) { ATRACE_CALL(); - const DexFile::ClassDef& class_def = manager->GetDexFile()->GetClassDef(class_def_index); + jobject jclass_loader = manager->GetClassLoader(); + const DexFile& dex_file = *manager->GetDexFile(); + const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index); + const char* descriptor = dex_file.GetClassDescriptor(class_def); + ClassLinker* class_linker = manager->GetClassLinker(); ScopedObjectAccess soa(Thread::Current()); - mirror::ClassLoader* class_loader = soa.Decode(manager->GetClassLoader()); - const char* descriptor = manager->GetDexFile()->GetClassDescriptor(class_def); - mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader); - if (klass != NULL) { + mirror::ClassLoader* class_loader = soa.Decode(jclass_loader); + mirror::Class* klass = class_linker->FindClass(descriptor, class_loader); + + if (klass != NULL && !SkipClass(jclass_loader, dex_file, klass)) { // Only try to initialize classes that were successfully verified. if (klass->IsVerified()) { // Attempt to initialize the class but bail if we either need to initialize the super-class -- cgit v1.2.3-59-g8ed1b