Add verifier support for dequickening
Also some cleanup.
Bug: 17950037
Change-Id: I1f50fe07f1558e9c4f78953b7afa639d7f310b3c
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index 17328c4..d684bc9 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -82,13 +82,13 @@
size_t num_entries, ref_bitmap_bits, pc_bits;
ComputeGcMapSizes(method_verifier, &num_entries, &ref_bitmap_bits, &pc_bits);
// There's a single byte to encode the size of each bitmap.
- if (ref_bitmap_bits >= (8 /* bits per byte */ * 8192 /* 13-bit size */ )) {
+ if (ref_bitmap_bits >= kBitsPerByte * 8192 /* 13-bit size */) {
// TODO: either a better GC map format or per method failures
method_verifier->Fail(verifier::VERIFY_ERROR_BAD_CLASS_HARD)
<< "Cannot encode GC map for method with " << ref_bitmap_bits << " registers";
return false;
}
- size_t ref_bitmap_bytes = (ref_bitmap_bits + 7) / 8;
+ size_t ref_bitmap_bytes = RoundUp(ref_bitmap_bits, kBitsPerByte) / kBitsPerByte;
// There are 2 bytes to encode the number of entries.
if (num_entries >= 65536) {
// TODO: Either a better GC map format or per method failures.
@@ -98,10 +98,10 @@
}
size_t pc_bytes;
verifier::RegisterMapFormat format;
- if (pc_bits <= 8) {
+ if (pc_bits <= kBitsPerByte) {
format = verifier::kRegMapFormatCompact8;
pc_bytes = 1;
- } else if (pc_bits <= 16) {
+ } else if (pc_bits <= kBitsPerByte * 2) {
format = verifier::kRegMapFormatCompact16;
pc_bytes = 2;
} else {
@@ -152,10 +152,10 @@
verifier::RegisterLine* line = method_verifier->GetRegLine(i);
for (size_t j = 0; j < code_item->registers_size_; j++) {
if (line->GetRegisterType(method_verifier, j).IsNonZeroReferenceTypes()) {
- DCHECK_LT(j / 8, map.RegWidth());
- DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 1);
- } else if ((j / 8) < map.RegWidth()) {
- DCHECK_EQ((reg_bitmap[j / 8] >> (j % 8)) & 1, 0);
+ DCHECK_LT(j / kBitsPerByte, map.RegWidth());
+ DCHECK_EQ((reg_bitmap[j / kBitsPerByte] >> (j % kBitsPerByte)) & 1, 1);
+ } else if ((j / kBitsPerByte) < map.RegWidth()) {
+ DCHECK_EQ((reg_bitmap[j / kBitsPerByte] >> (j % kBitsPerByte)) & 1, 0);
} else {
// If a register doesn't contain a reference then the bitmap may be shorter than the line.
}
@@ -190,6 +190,31 @@
*log2_max_gc_pc = i;
}
+void VerifiedMethod::GenerateDeQuickenMap(verifier::MethodVerifier* method_verifier) {
+ if (method_verifier->HasFailures()) {
+ return;
+ }
+ const DexFile::CodeItem* code_item = method_verifier->CodeItem();
+ const uint16_t* insns = code_item->insns_;
+ const Instruction* inst = Instruction::At(insns);
+ const Instruction* end = Instruction::At(insns + code_item->insns_size_in_code_units_);
+ for (; inst < end; inst = inst->Next()) {
+ const bool is_virtual_quick = inst->Opcode() == Instruction::INVOKE_VIRTUAL_QUICK;
+ const bool is_range_quick = inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE_QUICK;
+ if (is_virtual_quick || is_range_quick) {
+ uint32_t dex_pc = inst->GetDexPc(insns);
+ verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
+ mirror::ArtMethod* method = method_verifier->GetQuickInvokedMethod(inst, line,
+ is_range_quick);
+ CHECK(method != nullptr);
+ // The verifier must know what the type of the object was or else we would have gotten a
+ // failure. Put the dex method index in the dequicken map since we need this to get number of
+ // arguments in the compiler.
+ dequicken_map_.Put(dex_pc, method->ToMethodReference());
+ }
+ }
+}
+
void VerifiedMethod::GenerateDevirtMap(verifier::MethodVerifier* method_verifier) {
// It is risky to rely on reg_types for sharpening in cases of soft
// verification, we might end up sharpening to a wrong implementation. Just abort.
@@ -203,10 +228,10 @@
const Instruction* end = Instruction::At(insns + code_item->insns_size_in_code_units_);
for (; inst < end; inst = inst->Next()) {
- bool is_virtual = (inst->Opcode() == Instruction::INVOKE_VIRTUAL) ||
- (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE);
- bool is_interface = (inst->Opcode() == Instruction::INVOKE_INTERFACE) ||
- (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
+ const bool is_virtual = inst->Opcode() == Instruction::INVOKE_VIRTUAL ||
+ inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE;
+ const bool is_interface = inst->Opcode() == Instruction::INVOKE_INTERFACE ||
+ inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE;
if (!is_interface && !is_virtual) {
continue;
@@ -214,8 +239,8 @@
// Get reg type for register holding the reference to the object that will be dispatched upon.
uint32_t dex_pc = inst->GetDexPc(insns);
verifier::RegisterLine* line = method_verifier->GetRegLine(dex_pc);
- bool is_range = (inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE) ||
- (inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE);
+ const bool is_range = inst->Opcode() == Instruction::INVOKE_VIRTUAL_RANGE ||
+ inst->Opcode() == Instruction::INVOKE_INTERFACE_RANGE;
const verifier::RegType&
reg_type(line->GetRegisterType(method_verifier,
is_range ? inst->VRegC_3rc() : inst->VRegC_35c()));
@@ -241,14 +266,14 @@
continue;
}
// Find the concrete method.
- mirror::ArtMethod* concrete_method = NULL;
+ mirror::ArtMethod* concrete_method = nullptr;
if (is_interface) {
concrete_method = reg_type.GetClass()->FindVirtualMethodForInterface(abstract_method);
}
if (is_virtual) {
concrete_method = reg_type.GetClass()->FindVirtualMethodForVirtual(abstract_method);
}
- if (concrete_method == NULL || concrete_method->IsAbstract()) {
+ if (concrete_method == nullptr || concrete_method->IsAbstract()) {
// In cases where concrete_method is not found, or is abstract, continue to the next invoke.
continue;
}
@@ -256,10 +281,7 @@
concrete_method->GetDeclaringClass()->IsFinal()) {
// If we knew exactly the class being dispatched upon, or if the target method cannot be
// overridden record the target to be used in the compiler driver.
- MethodReference concrete_ref(
- concrete_method->GetDeclaringClass()->GetDexCache()->GetDexFile(),
- concrete_method->GetDexMethodIndex());
- devirt_map_.Put(dex_pc, concrete_ref);
+ devirt_map_.Put(dex_pc, concrete_method->ToMethodReference());
}
}
}
diff --git a/compiler/dex/verified_method.h b/compiler/dex/verified_method.h
index 257e70c..fe9dfd1 100644
--- a/compiler/dex/verified_method.h
+++ b/compiler/dex/verified_method.h
@@ -85,12 +85,19 @@
void GenerateDevirtMap(verifier::MethodVerifier* method_verifier)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Generate dequickening map into dequicken_map_.
+ void GenerateDeQuickenMap(verifier::MethodVerifier* method_verifier)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Generate safe case set into safe_cast_set_.
void GenerateSafeCastSet(verifier::MethodVerifier* method_verifier)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
std::vector<uint8_t> dex_gc_map_;
DevirtualizationMap devirt_map_;
+ // Dequicken map is required for having the compiler compiled quickened invokes. The quicken map
+ // enables us to get the dex method index so that we can get the required argument count.
+ DevirtualizationMap dequicken_map_;
SafeCastSet safe_cast_set_;
};
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 64663ed..9b982b7 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -20,6 +20,7 @@
#include "dex_file.h"
#include "gc_root.h"
#include "invoke_type.h"
+#include "method_reference.h"
#include "modifiers.h"
#include "object.h"
#include "object_callbacks.h"
@@ -522,6 +523,10 @@
uintptr_t ToNativeQuickPc(const uint32_t dex_pc, bool abort_on_failure = true)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ MethodReference ToMethodReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return MethodReference(GetDexFile(), GetDexMethodIndex());
+ }
+
// Find the catch block for the given exception type and dex_pc. When a catch block is found,
// indicates whether the found catch block is responsible for clearing the exception or whether
// a move-exception instruction is present.
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 59efebf..65c5c21 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -3408,7 +3408,7 @@
return nullptr;
}
mirror::ArtMethod* res_method = dispatch_class->GetVTableEntry(vtable_index);
- if (FailOrAbort(this, !Thread::Current()->IsExceptionPending(),
+ if (FailOrAbort(this, !self_->IsExceptionPending(),
"Unexpected exception pending for quickened invoke at ",
work_insn_idx_)) {
return nullptr;
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 0c4bf3c..c3bd4af 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -238,6 +238,10 @@
bool HasFailures() const;
const RegType& ResolveCheckedClass(uint32_t class_idx)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::ArtMethod* GetQuickInvokedMethod(const Instruction* inst,
+ RegisterLine* reg_line,
+ bool is_range)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
private:
// Private constructor for dumping.
@@ -586,11 +590,6 @@
mirror::ArtMethod* res_method)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- mirror::ArtMethod* GetQuickInvokedMethod(const Instruction* inst,
- RegisterLine* reg_line,
- bool is_range)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
mirror::ArtMethod* VerifyInvokeVirtualQuickArgs(const Instruction* inst, bool is_range)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);