diff options
author | Nicolas Geoffray <ngeoffray@google.com> | 2017-11-13 15:16:22 +0000 |
---|---|---|
committer | Nicolas Geoffray <ngeoffray@google.com> | 2018-03-19 09:25:09 +0000 |
commit | b041a406daf5213ac1d5c9bcdc197d34cba85bf3 (patch) | |
tree | f32c9f97143d2df79940e070f2862cc7a5f6e807 /runtime/verifier | |
parent | 51038fc5f8be887ff86fe062e6a5af840e37726d (diff) | |
download | art-b041a406daf5213ac1d5c9bcdc197d34cba85bf3.tar.gz art-b041a406daf5213ac1d5c9bcdc197d34cba85bf3.tar.bz2 art-b041a406daf5213ac1d5c9bcdc197d34cba85bf3.zip |
Use vdex's quickening info when decoding a quickened instruction.
bug: 74521989
Test: test.py, 678-quickening
Change-Id: I3a85cc6014afcf11889941dcd15b90d4296b8408
Diffstat (limited to 'runtime/verifier')
-rw-r--r-- | runtime/verifier/method_verifier-inl.h | 2 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.cc | 175 | ||||
-rw-r--r-- | runtime/verifier/method_verifier.h | 31 |
3 files changed, 32 insertions, 176 deletions
diff --git a/runtime/verifier/method_verifier-inl.h b/runtime/verifier/method_verifier-inl.h index 445a6ff7de..4b92c56b79 100644 --- a/runtime/verifier/method_verifier-inl.h +++ b/runtime/verifier/method_verifier-inl.h @@ -49,7 +49,7 @@ inline mirror::DexCache* MethodVerifier::GetDexCache() { } inline ArtMethod* MethodVerifier::GetMethod() const { - return mirror_method_; + return method_being_verified_; } inline MethodReference MethodVerifier::GetMethodReference() const { diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 2a2afc4a27..b07001e595 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -56,6 +56,7 @@ #include "runtime.h" #include "scoped_thread_state_change-inl.h" #include "stack.h" +#include "vdex_file.h" #include "verifier_compiler_binding.h" #include "verifier_deps.h" @@ -565,7 +566,7 @@ MethodVerifier::MethodVerifier(Thread* self, reg_table_(allocator_), work_insn_idx_(dex::kDexNoIndex), dex_method_idx_(dex_method_idx), - mirror_method_(method), + method_being_verified_(method), method_access_flags_(method_access_flags), return_type_(nullptr), dex_file_(dex_file), @@ -643,87 +644,6 @@ void MethodVerifier::FindLocksAtDexPc() { } } -ArtField* MethodVerifier::FindAccessedFieldAtDexPc(ArtMethod* m, uint32_t dex_pc) { - StackHandleScope<2> hs(Thread::Current()); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(m->GetDexCache())); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle(m->GetClassLoader())); - MethodVerifier verifier(hs.Self(), - m->GetDexFile(), - dex_cache, - class_loader, - m->GetClassDef(), - m->GetCodeItem(), - m->GetDexMethodIndex(), - m, - m->GetAccessFlags(), - true /* can_load_classes */, - true /* allow_soft_failures */, - false /* need_precise_constants */, - false /* verify_to_dump */, - true /* allow_thread_suspension */); - return verifier.FindAccessedFieldAtDexPc(dex_pc); -} - -ArtField* MethodVerifier::FindAccessedFieldAtDexPc(uint32_t dex_pc) { - CHECK(code_item_accessor_.HasCodeItem()); // This only makes sense for methods with code. - - // Strictly speaking, we ought to be able to get away with doing a subset of the full method - // verification. In practice, the phase we want relies on data structures set up by all the - // earlier passes, so we just run the full method verification and bail out early when we've - // got what we wanted. - bool success = Verify(); - if (!success) { - return nullptr; - } - RegisterLine* register_line = reg_table_.GetLine(dex_pc); - if (register_line == nullptr) { - return nullptr; - } - const Instruction* inst = &code_item_accessor_.InstructionAt(dex_pc); - return GetQuickFieldAccess(inst, register_line); -} - -ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(ArtMethod* m, uint32_t dex_pc) { - StackHandleScope<2> hs(Thread::Current()); - Handle<mirror::DexCache> dex_cache(hs.NewHandle(m->GetDexCache())); - Handle<mirror::ClassLoader> class_loader(hs.NewHandle(m->GetClassLoader())); - MethodVerifier verifier(hs.Self(), - m->GetDexFile(), - dex_cache, - class_loader, - m->GetClassDef(), - m->GetCodeItem(), - m->GetDexMethodIndex(), - m, - m->GetAccessFlags(), - true /* can_load_classes */, - true /* allow_soft_failures */, - false /* need_precise_constants */, - false /* verify_to_dump */, - true /* allow_thread_suspension */); - return verifier.FindInvokedMethodAtDexPc(dex_pc); -} - -ArtMethod* MethodVerifier::FindInvokedMethodAtDexPc(uint32_t dex_pc) { - CHECK(code_item_accessor_.HasCodeItem()); // This only makes sense for methods with code. - - // Strictly speaking, we ought to be able to get away with doing a subset of the full method - // verification. In practice, the phase we want relies on data structures set up by all the - // earlier passes, so we just run the full method verification and bail out early when we've - // got what we wanted. - bool success = Verify(); - if (!success) { - return nullptr; - } - RegisterLine* register_line = reg_table_.GetLine(dex_pc); - if (register_line == nullptr) { - return nullptr; - } - const Instruction* inst = &code_item_accessor_.InstructionAt(dex_pc); - const bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK); - return GetQuickInvokedMethod(inst, register_line, is_range, false); -} - bool MethodVerifier::Verify() { // Some older code doesn't correctly mark constructors as such. Test for this case by looking at // the name. @@ -4414,62 +4334,24 @@ bool MethodVerifier::CheckSignaturePolymorphicReceiver(const Instruction* inst) return true; } -ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst, RegisterLine* reg_line, - bool is_range, bool allow_failure) { +ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst, bool is_range) { if (is_range) { DCHECK_EQ(inst->Opcode(), Instruction::INVOKE_VIRTUAL_RANGE_QUICK); } else { DCHECK_EQ(inst->Opcode(), Instruction::INVOKE_VIRTUAL_QUICK); } - const RegType& actual_arg_type = reg_line->GetInvocationThis(this, inst, allow_failure); - if (!actual_arg_type.HasClass()) { - VLOG(verifier) << "Failed to get mirror::Class* from '" << actual_arg_type << "'"; - return nullptr; - } - mirror::Class* klass = actual_arg_type.GetClass(); - mirror::Class* dispatch_class; - if (klass->IsInterface()) { - // Derive Object.class from Class.class.getSuperclass(). - mirror::Class* object_klass = klass->GetClass()->GetSuperClass(); - if (FailOrAbort(object_klass->IsObjectClass(), - "Failed to find Object class in quickened invoke receiver", - work_insn_idx_)) { - return nullptr; - } - dispatch_class = object_klass; - } else { - dispatch_class = klass; - } - if (!dispatch_class->HasVTable()) { - FailOrAbort(allow_failure, - "Receiver class has no vtable for quickened invoke at ", - work_insn_idx_); - return nullptr; - } - uint16_t vtable_index = is_range ? inst->VRegB_3rc() : inst->VRegB_35c(); - auto* cl = Runtime::Current()->GetClassLinker(); - auto pointer_size = cl->GetImagePointerSize(); - if (static_cast<int32_t>(vtable_index) >= dispatch_class->GetVTableLength()) { - FailOrAbort(allow_failure, - "Receiver class has not enough vtable slots for quickened invoke at ", - work_insn_idx_); - return nullptr; - } - ArtMethod* res_method = dispatch_class->GetVTableEntry(vtable_index, pointer_size); - if (self_->IsExceptionPending()) { - FailOrAbort(allow_failure, - "Unexpected exception pending for quickened invoke at ", - work_insn_idx_); - return nullptr; - } - return res_method; + + DCHECK(method_being_verified_ != nullptr); + uint16_t method_idx = method_being_verified_->GetIndexFromQuickening(work_insn_idx_); + CHECK_NE(method_idx, DexFile::kDexNoIndex16); + return ResolveMethodAndCheckAccess(method_idx, METHOD_VIRTUAL); } ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instruction* inst, bool is_range) { DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_) << dex_file_->PrettyMethod(dex_method_idx_, true) << "@" << work_insn_idx_; - ArtMethod* res_method = GetQuickInvokedMethod(inst, work_line_.get(), is_range, false); + ArtMethod* res_method = GetQuickInvokedMethod(inst, is_range); if (res_method == nullptr) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer method from " << inst->Name(); return nullptr; @@ -5090,22 +4972,17 @@ void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, const RegType& } } -ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line) { - DCHECK(IsInstructionIGetQuickOrIPutQuick(inst->Opcode())) << inst->Opcode(); - const RegType& object_type = reg_line->GetRegisterType(this, inst->VRegB_22c()); - if (!object_type.HasClass()) { - VLOG(verifier) << "Failed to get mirror::Class* from '" << object_type << "'"; - return nullptr; - } - uint32_t field_offset = static_cast<uint32_t>(inst->VRegC_22c()); - ArtField* const f = ArtField::FindInstanceFieldWithOffset(object_type.GetClass(), field_offset); - if (f == nullptr) { - VLOG(verifier) << "Failed to find instance field at offset '" << field_offset - << "' from '" << mirror::Class::PrettyDescriptor(object_type.GetClass()) << "'"; - } else { - DCHECK_EQ(f->GetOffset().Uint32Value(), field_offset); +ArtField* MethodVerifier::GetQuickAccessedField() { + DCHECK(method_being_verified_ != nullptr); + uint16_t field_idx = method_being_verified_->GetIndexFromQuickening(work_insn_idx_); + CHECK_NE(field_idx, DexFile::kDexNoIndex16); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + ArtField* field = class_linker->ResolveFieldJLS(field_idx, dex_cache_, class_loader_); + if (field == nullptr) { + DCHECK(self_->IsExceptionPending()); + self_->ClearException(); } - return f; + return field; } template <MethodVerifier::FieldAccessType kAccType> @@ -5113,7 +4990,7 @@ void MethodVerifier::VerifyQuickFieldAccess(const Instruction* inst, const RegTy bool is_primitive) { DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_); - ArtField* field = GetQuickFieldAccess(inst, work_line_.get()); + ArtField* field = GetQuickAccessedField(); if (field == nullptr) { Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name(); return; @@ -5318,12 +5195,12 @@ InstructionFlags* MethodVerifier::CurrentInsnFlags() { const RegType& MethodVerifier::GetMethodReturnType() { if (return_type_ == nullptr) { - if (mirror_method_ != nullptr) { + if (method_being_verified_ != nullptr) { ObjPtr<mirror::Class> return_type_class = can_load_classes_ - ? mirror_method_->ResolveReturnType() - : mirror_method_->LookupResolvedReturnType(); + ? method_being_verified_->ResolveReturnType() + : method_being_verified_->LookupResolvedReturnType(); if (return_type_class != nullptr) { - return_type_ = &FromClass(mirror_method_->GetReturnTypeDescriptor(), + return_type_ = &FromClass(method_being_verified_->GetReturnTypeDescriptor(), return_type_class.Ptr(), return_type_class->CannotBeAssignedFromOtherTypes()); } else { @@ -5347,8 +5224,8 @@ const RegType& MethodVerifier::GetDeclaringClass() { const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_); const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_)); - if (mirror_method_ != nullptr) { - mirror::Class* klass = mirror_method_->GetDeclaringClass(); + if (method_being_verified_ != nullptr) { + mirror::Class* klass = method_being_verified_->GetDeclaringClass(); declaring_class_ = &FromClass(descriptor, klass, klass->CannotBeAssignedFromOtherTypes()); } else { declaring_class_ = ®_types_.FromDescriptor(GetClassLoader(), descriptor, false); diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 9a94297942..4c9518b0ec 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -162,20 +162,11 @@ class MethodVerifier { }; // Fills 'monitor_enter_dex_pcs' with the dex pcs of the monitor-enter instructions corresponding // to the locks held at 'dex_pc' in method 'm'. + // Note: this is the only situation where the verifier will visit quickened instructions. static void FindLocksAtDexPc(ArtMethod* m, uint32_t dex_pc, std::vector<DexLockInfo>* monitor_enter_dex_pcs) REQUIRES_SHARED(Locks::mutator_lock_); - // Returns the accessed field corresponding to the quick instruction's field - // offset at 'dex_pc' in method 'm'. - static ArtField* FindAccessedFieldAtDexPc(ArtMethod* m, uint32_t dex_pc) - REQUIRES_SHARED(Locks::mutator_lock_); - - // Returns the invoked method corresponding to the quick instruction's vtable - // index at 'dex_pc' in method 'm'. - static ArtMethod* FindInvokedMethodAtDexPc(ArtMethod* m, uint32_t dex_pc) - REQUIRES_SHARED(Locks::mutator_lock_); - static void Init() REQUIRES_SHARED(Locks::mutator_lock_); static void Shutdown(); @@ -206,7 +197,7 @@ class MethodVerifier { ALWAYS_INLINE InstructionFlags& GetInstructionFlags(size_t index); mirror::ClassLoader* GetClassLoader() REQUIRES_SHARED(Locks::mutator_lock_); mirror::DexCache* GetDexCache() REQUIRES_SHARED(Locks::mutator_lock_); - ArtMethod* GetMethod() const REQUIRES_SHARED(Locks::mutator_lock_); + ArtMethod* GetMethod() const; MethodReference GetMethodReference() const; uint32_t GetAccessFlags() const; bool HasCheckCasts() const; @@ -219,13 +210,11 @@ class MethodVerifier { const RegType& ResolveCheckedClass(dex::TypeIndex class_idx) REQUIRES_SHARED(Locks::mutator_lock_); // Returns the method of a quick invoke or null if it cannot be found. - ArtMethod* GetQuickInvokedMethod(const Instruction* inst, RegisterLine* reg_line, - bool is_range, bool allow_failure) + ArtMethod* GetQuickInvokedMethod(const Instruction* inst, bool is_range) REQUIRES_SHARED(Locks::mutator_lock_); // Returns the access field of a quick field access (iget/iput-quick) or null // if it cannot be found. - ArtField* GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line) - REQUIRES_SHARED(Locks::mutator_lock_); + ArtField* GetQuickAccessedField() REQUIRES_SHARED(Locks::mutator_lock_); uint32_t GetEncounteredFailureTypes() { return encountered_failure_types_; @@ -332,15 +321,6 @@ class MethodVerifier { void FindLocksAtDexPc() REQUIRES_SHARED(Locks::mutator_lock_); - ArtField* FindAccessedFieldAtDexPc(uint32_t dex_pc) - REQUIRES_SHARED(Locks::mutator_lock_); - - ArtMethod* FindInvokedMethodAtDexPc(uint32_t dex_pc) - REQUIRES_SHARED(Locks::mutator_lock_); - - SafeMap<uint32_t, std::set<uint32_t>>& FindStringInitMap() - REQUIRES_SHARED(Locks::mutator_lock_); - /* * Compute the width of the instruction at each address in the instruction stream, and store it in * insn_flags_. Addresses that are in the middle of an instruction, or that are part of switch @@ -745,8 +725,7 @@ class MethodVerifier { RegisterLineArenaUniquePtr saved_line_; const uint32_t dex_method_idx_; // The method we're working on. - // Its object representation if known. - ArtMethod* mirror_method_ GUARDED_BY(Locks::mutator_lock_); + ArtMethod* method_being_verified_; // Its ArtMethod representation if known. 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. |