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());
}
}
}