summaryrefslogtreecommitdiffstats
path: root/runtime/verifier
diff options
context:
space:
mode:
authorNicolas Geoffray <ngeoffray@google.com>2017-11-13 15:16:22 +0000
committerNicolas Geoffray <ngeoffray@google.com>2018-03-19 09:25:09 +0000
commitb041a406daf5213ac1d5c9bcdc197d34cba85bf3 (patch)
treef32c9f97143d2df79940e070f2862cc7a5f6e807 /runtime/verifier
parent51038fc5f8be887ff86fe062e6a5af840e37726d (diff)
downloadart-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.h2
-rw-r--r--runtime/verifier/method_verifier.cc175
-rw-r--r--runtime/verifier/method_verifier.h31
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_ = &reg_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.