Add "kind" argument to Get/SetVReg.
In order to determine where a register is promoted its necessary to know
the kind of use of the register.
Extend notion of precise-ness to numeric verifier register types.
Dump verifier output in oatdump.
Dump vregs with their location or constant value.
Introduce indenting ostream utility.
Change-Id: Ia3d29497877976bc24465484743bca08236e1768
diff --git a/src/verifier/method_verifier.cc b/src/verifier/method_verifier.cc
index 2149490..d6cd665 100644
--- a/src/verifier/method_verifier.cc
+++ b/src/verifier/method_verifier.cc
@@ -25,6 +25,7 @@
#include "dex_instruction.h"
#include "dex_instruction_visitor.h"
#include "verifier/dex_gc_map.h"
+#include "indenter.h"
#include "intern_table.h"
#include "leb128.h"
#include "logging.h"
@@ -324,22 +325,37 @@
return result;
}
-void MethodVerifier::VerifyMethodAndDump(AbstractMethod* method) {
- CHECK(method != NULL);
- MethodHelper mh(method);
- MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(),
- mh.GetClassDefIndex(), mh.GetCodeItem(), method->GetDexMethodIndex(),
- method, method->GetAccessFlags());
+void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_idx,
+ const DexFile* dex_file, DexCache* dex_cache,
+ ClassLoader* class_loader, uint32_t class_def_idx,
+ const DexFile::CodeItem* code_item, AbstractMethod* method,
+ uint32_t method_access_flags) {
+ MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item,
+ dex_method_idx, method, method_access_flags);
verifier.Verify();
- verifier.DumpFailures(LOG(INFO) << "Dump of method " << PrettyMethod(method) << "\n")
- << verifier.info_messages_.str() << MutatorLockedDumpable<MethodVerifier>(verifier);
+ verifier.DumpFailures(os);
+ os << verifier.info_messages_.str();
+ verifier.Dump(os);
+}
+
+std::vector<int32_t> MethodVerifier::DescribeVRegs(uint32_t dex_method_idx,
+ const DexFile* dex_file, DexCache* dex_cache,
+ ClassLoader* class_loader,
+ uint32_t class_def_idx,
+ const DexFile::CodeItem* code_item,
+ AbstractMethod* method,
+ uint32_t method_access_flags, uint32_t dex_pc) {
+ MethodVerifier verifier(dex_file, dex_cache, class_loader, class_def_idx, code_item,
+ dex_method_idx, method, method_access_flags);
+ verifier.Verify();
+ return verifier.DescribeVRegs(dex_pc);
}
MethodVerifier::MethodVerifier(const DexFile* dex_file, DexCache* dex_cache,
ClassLoader* class_loader, uint32_t class_def_idx, const DexFile::CodeItem* code_item,
- uint32_t method_idx, AbstractMethod* method, uint32_t method_access_flags)
+ uint32_t dex_method_idx, AbstractMethod* method, uint32_t method_access_flags)
: work_insn_idx_(-1),
- method_idx_(method_idx),
+ dex_method_idx_(dex_method_idx),
foo_method_(method),
method_access_flags_(method_access_flags),
dex_file_(dex_file),
@@ -355,7 +371,8 @@
monitor_enter_count_(0) {
}
-void MethodVerifier::FindLocksAtDexPc(AbstractMethod* m, uint32_t dex_pc, std::vector<uint32_t>& monitor_enter_dex_pcs) {
+void MethodVerifier::FindLocksAtDexPc(AbstractMethod* m, uint32_t dex_pc,
+ std::vector<uint32_t>& monitor_enter_dex_pcs) {
MethodHelper mh(m);
MethodVerifier verifier(&mh.GetDexFile(), mh.GetDexCache(), mh.GetClassLoader(),
mh.GetClassDefIndex(), mh.GetCodeItem(), m->GetDexMethodIndex(),
@@ -446,7 +463,7 @@
}
}
failures_.push_back(error);
- std::string location(StringPrintf("%s: [0x%X]", PrettyMethod(method_idx_, *dex_file_).c_str(),
+ std::string location(StringPrintf("%s: [0x%X]", PrettyMethod(dex_method_idx_, *dex_file_).c_str(),
work_insn_idx_));
std::ostringstream* failure_message = new std::ostringstream(location);
failure_messages_.push_back(failure_message);
@@ -1000,7 +1017,7 @@
if (!SetTypesFromSignature()) {
DCHECK_NE(failures_.size(), 0U);
std::string prepend("Bad signature in ");
- prepend += PrettyMethod(method_idx_, *dex_file_);
+ prepend += PrettyMethod(dex_method_idx_, *dex_file_);
PrependToLastFailMessage(prepend);
return false;
}
@@ -1010,7 +1027,7 @@
return false;
}
- Compiler::MethodReference ref(dex_file_, method_idx_);
+ Compiler::MethodReference ref(dex_file_, dex_method_idx_);
#if !defined(ART_USE_LLVM_COMPILER)
@@ -1054,17 +1071,28 @@
os << "Native method\n";
return;
}
- reg_types_.Dump(os);
+ {
+ os << "Register Types:\n";
+ Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
+ std::ostream indent_os(&indent_filter);
+ reg_types_.Dump(indent_os);
+ }
os << "Dumping instructions and register lines:\n";
+ Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
+ std::ostream indent_os(&indent_filter);
const Instruction* inst = Instruction::At(code_item_->insns_);
for (size_t dex_pc = 0; dex_pc < code_item_->insns_size_in_code_units_;
dex_pc += insn_flags_[dex_pc].GetLengthInCodeUnits()) {
- os << StringPrintf("0x%04zx", dex_pc) << ": " << insn_flags_[dex_pc].Dump()
- << " " << inst->DumpHex(5) << " " << inst->DumpString(dex_file_) << "\n";
RegisterLine* reg_line = reg_table_.GetLine(dex_pc);
if (reg_line != NULL) {
- os << reg_line->Dump() << "\n";
+ indent_os << reg_line->Dump() << "\n";
}
+ indent_os << StringPrintf("0x%04zx", dex_pc) << ": " << insn_flags_[dex_pc].Dump() << " ";
+ const bool kDumpHexOfInstruction = false;
+ if (kDumpHexOfInstruction) {
+ indent_os << inst->DumpHex(5) << " ";
+ }
+ indent_os << inst->DumpString(dex_file_) << "\n";
inst = inst->Next();
}
}
@@ -1108,7 +1136,7 @@
}
const DexFile::ProtoId& proto_id =
- dex_file_->GetMethodPrototype(dex_file_->GetMethodId(method_idx_));
+ dex_file_->GetMethodPrototype(dex_file_->GetMethodId(dex_method_idx_));
DexFileParameterIterator iterator(*dex_file_, proto_id);
for (; iterator.HasNext(); iterator.Next()) {
@@ -1153,8 +1181,9 @@
break;
case 'J':
case 'D': {
- const RegType& low_half = descriptor[0] == 'J' ? reg_types_.Long() : reg_types_.Double();
- reg_line->SetRegisterType(arg_start + cur_arg, low_half); // implicitly sets high-register
+ const RegType& lo_half = descriptor[0] == 'J' ? reg_types_.LongLo() : reg_types_.DoubleLo();
+ const RegType& hi_half = descriptor[0] == 'J' ? reg_types_.LongHi() : reg_types_.DoubleHi();
+ reg_line->SetRegisterTypeWide(arg_start + cur_arg, lo_half, hi_half);
cur_arg++;
break;
}
@@ -1250,7 +1279,7 @@
if (work_line_->CompareLine(register_line) != 0) {
Dump(std::cout);
std::cout << info_messages_.str();
- LOG(FATAL) << "work_line diverged in " << PrettyMethod(method_idx_, *dex_file_)
+ LOG(FATAL) << "work_line diverged in " << PrettyMethod(dex_method_idx_, *dex_file_)
<< "@" << reinterpret_cast<void*>(work_insn_idx_) << "\n"
<< " work_line=" << *work_line_ << "\n"
<< " expected=" << *register_line;
@@ -1259,7 +1288,7 @@
#endif
}
if (!CodeFlowVerifyInstruction(&start_guess)) {
- std::string prepend(PrettyMethod(method_idx_, *dex_file_));
+ std::string prepend(PrettyMethod(dex_method_idx_, *dex_file_));
prepend += " failed to verify: ";
PrependToLastFailMessage(prepend);
return false;
@@ -1500,32 +1529,51 @@
}
break;
- case Instruction::CONST_4:
/* could be boolean, int, float, or a null reference */
+ case Instruction::CONST_4:
work_line_->SetRegisterType(dec_insn.vA,
- reg_types_.FromCat1Const((dec_insn.vB << 28) >> 28));
+ reg_types_.FromCat1Const(static_cast<int32_t>(dec_insn.vB << 28) >> 28, true));
break;
case Instruction::CONST_16:
- /* could be boolean, int, float, or a null reference */
work_line_->SetRegisterType(dec_insn.vA,
- reg_types_.FromCat1Const(static_cast<int16_t>(dec_insn.vB)));
+ reg_types_.FromCat1Const(static_cast<int16_t>(dec_insn.vB), true));
break;
case Instruction::CONST:
- /* could be boolean, int, float, or a null reference */
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.FromCat1Const(dec_insn.vB));
+ work_line_->SetRegisterType(dec_insn.vA, reg_types_.FromCat1Const(dec_insn.vB, true));
break;
case Instruction::CONST_HIGH16:
- /* could be boolean, int, float, or a null reference */
work_line_->SetRegisterType(dec_insn.vA,
- reg_types_.FromCat1Const(dec_insn.vB << 16));
+ reg_types_.FromCat1Const(dec_insn.vB << 16, true));
break;
- case Instruction::CONST_WIDE_16:
- case Instruction::CONST_WIDE_32:
- case Instruction::CONST_WIDE:
- case Instruction::CONST_WIDE_HIGH16:
/* could be long or double; resolved upon use */
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.ConstLo());
+ case Instruction::CONST_WIDE_16: {
+ int64_t val = static_cast<int16_t>(dec_insn.vB);
+ const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
+ const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
+ work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
break;
+ }
+ case Instruction::CONST_WIDE_32: {
+ int64_t val = static_cast<int32_t>(dec_insn.vB);
+ const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
+ const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
+ work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+ break;
+ }
+ case Instruction::CONST_WIDE: {
+ int64_t val = dec_insn.vB_wide;
+ const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
+ const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
+ work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+ break;
+ }
+ case Instruction::CONST_WIDE_HIGH16: {
+ int64_t val = static_cast<uint64_t>(dec_insn.vB) << 48;
+ const RegType& lo = reg_types_.FromCat2ConstLo(static_cast<int32_t>(val), true);
+ const RegType& hi = reg_types_.FromCat2ConstHi(static_cast<int32_t>(val >> 32), true);
+ work_line_->SetRegisterTypeWide(dec_insn.vA, lo, hi);
+ break;
+ }
case Instruction::CONST_STRING:
case Instruction::CONST_STRING_JUMBO:
work_line_->SetRegisterType(dec_insn.vA, reg_types_.JavaLangString());
@@ -1658,19 +1706,23 @@
break;
case Instruction::CMPL_DOUBLE:
case Instruction::CMPG_DOUBLE:
- if (!work_line_->VerifyRegisterType(dec_insn.vB, reg_types_.Double())) {
+ if (!work_line_->VerifyRegisterTypeWide(dec_insn.vB, reg_types_.DoubleLo(),
+ reg_types_.DoubleHi())) {
break;
}
- if (!work_line_->VerifyRegisterType(dec_insn.vC, reg_types_.Double())) {
+ if (!work_line_->VerifyRegisterTypeWide(dec_insn.vC, reg_types_.DoubleLo(),
+ reg_types_.DoubleHi())) {
break;
}
work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
break;
case Instruction::CMP_LONG:
- if (!work_line_->VerifyRegisterType(dec_insn.vB, reg_types_.Long())) {
+ if (!work_line_->VerifyRegisterTypeWide(dec_insn.vB, reg_types_.LongLo(),
+ reg_types_.LongHi())) {
break;
}
- if (!work_line_->VerifyRegisterType(dec_insn.vC, reg_types_.Long())) {
+ if (!work_line_->VerifyRegisterTypeWide(dec_insn.vC, reg_types_.LongLo(),
+ reg_types_.LongHi())) {
break;
}
work_line_->SetRegisterType(dec_insn.vA, reg_types_.Integer());
@@ -1792,7 +1844,7 @@
VerifyAGet(dec_insn, reg_types_.Integer(), true);
break;
case Instruction::AGET_WIDE:
- VerifyAGet(dec_insn, reg_types_.Long(), true);
+ VerifyAGet(dec_insn, reg_types_.LongLo(), true);
break;
case Instruction::AGET_OBJECT:
VerifyAGet(dec_insn, reg_types_.JavaLangObject(false), false);
@@ -1814,7 +1866,7 @@
VerifyAPut(dec_insn, reg_types_.Integer(), true);
break;
case Instruction::APUT_WIDE:
- VerifyAPut(dec_insn, reg_types_.Long(), true);
+ VerifyAPut(dec_insn, reg_types_.LongLo(), true);
break;
case Instruction::APUT_OBJECT:
VerifyAPut(dec_insn, reg_types_.JavaLangObject(false), false);
@@ -1836,7 +1888,7 @@
VerifyISGet(dec_insn, reg_types_.Integer(), true, false);
break;
case Instruction::IGET_WIDE:
- VerifyISGet(dec_insn, reg_types_.Long(), true, false);
+ VerifyISGet(dec_insn, reg_types_.LongLo(), true, false);
break;
case Instruction::IGET_OBJECT:
VerifyISGet(dec_insn, reg_types_.JavaLangObject(false), false, false);
@@ -1858,7 +1910,7 @@
VerifyISPut(dec_insn, reg_types_.Integer(), true, false);
break;
case Instruction::IPUT_WIDE:
- VerifyISPut(dec_insn, reg_types_.Long(), true, false);
+ VerifyISPut(dec_insn, reg_types_.LongLo(), true, false);
break;
case Instruction::IPUT_OBJECT:
VerifyISPut(dec_insn, reg_types_.JavaLangObject(false), false, false);
@@ -1880,7 +1932,7 @@
VerifyISGet(dec_insn, reg_types_.Integer(), true, true);
break;
case Instruction::SGET_WIDE:
- VerifyISGet(dec_insn, reg_types_.Long(), true, true);
+ VerifyISGet(dec_insn, reg_types_.LongLo(), true, true);
break;
case Instruction::SGET_OBJECT:
VerifyISGet(dec_insn, reg_types_.JavaLangObject(false), false, true);
@@ -1902,7 +1954,7 @@
VerifyISPut(dec_insn, reg_types_.Integer(), true, true);
break;
case Instruction::SPUT_WIDE:
- VerifyISPut(dec_insn, reg_types_.Long(), true, true);
+ VerifyISPut(dec_insn, reg_types_.LongLo(), true, true);
break;
case Instruction::SPUT_OBJECT:
VerifyISPut(dec_insn, reg_types_.JavaLangObject(false), false, true);
@@ -1927,7 +1979,11 @@
descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
}
const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
- work_line_->SetResultRegisterType(return_type);
+ if (!return_type.IsLowHalf()) {
+ work_line_->SetResultRegisterType(return_type);
+ } else {
+ work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(®_types_));
+ }
just_set_result = true;
break;
}
@@ -1989,7 +2045,11 @@
}
const RegType& return_type = reg_types_.FromDescriptor(class_loader_, return_type_descriptor,
false);
- work_line_->SetResultRegisterType(return_type);
+ if (!return_type.IsLowHalf()) {
+ work_line_->SetResultRegisterType(return_type);
+ } else {
+ work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(®_types_));
+ }
just_set_result = true;
break;
}
@@ -2007,7 +2067,11 @@
descriptor = MethodHelper(called_method).GetReturnTypeDescriptor();
}
const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
- work_line_->SetResultRegisterType(return_type);
+ if (!return_type.IsLowHalf()) {
+ work_line_->SetResultRegisterType(return_type);
+ } else {
+ work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(®_types_));
+ }
just_set_result = true;
}
break;
@@ -2057,8 +2121,11 @@
descriptor = MethodHelper(abs_method).GetReturnTypeDescriptor();
}
const RegType& return_type = reg_types_.FromDescriptor(class_loader_, descriptor, false);
- work_line_->SetResultRegisterType(return_type);
- work_line_->SetResultRegisterType(return_type);
+ if (!return_type.IsLowHalf()) {
+ work_line_->SetResultRegisterType(return_type);
+ } else {
+ work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(®_types_));
+ }
just_set_result = true;
break;
}
@@ -2068,49 +2135,61 @@
break;
case Instruction::NEG_LONG:
case Instruction::NOT_LONG:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Long(), reg_types_.Long());
+ work_line_->CheckUnaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::NEG_FLOAT:
work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Float());
break;
case Instruction::NEG_DOUBLE:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Double(), reg_types_.Double());
+ work_line_->CheckUnaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::INT_TO_LONG:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Long(), reg_types_.Integer());
+ work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ reg_types_.Integer());
break;
case Instruction::INT_TO_FLOAT:
work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Integer());
break;
case Instruction::INT_TO_DOUBLE:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Double(), reg_types_.Integer());
+ work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ reg_types_.Integer());
break;
case Instruction::LONG_TO_INT:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Long());
+ work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Integer(),
+ reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::LONG_TO_FLOAT:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Long());
+ work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Float(),
+ reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::LONG_TO_DOUBLE:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Double(), reg_types_.Long());
+ work_line_->CheckUnaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::FLOAT_TO_INT:
work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Float());
break;
case Instruction::FLOAT_TO_LONG:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Long(), reg_types_.Float());
+ work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ reg_types_.Float());
break;
case Instruction::FLOAT_TO_DOUBLE:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Double(), reg_types_.Float());
+ work_line_->CheckUnaryOpToWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ reg_types_.Float());
break;
case Instruction::DOUBLE_TO_INT:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Integer(), reg_types_.Double());
+ work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Integer(),
+ reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::DOUBLE_TO_LONG:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Long(), reg_types_.Double());
+ work_line_->CheckUnaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::DOUBLE_TO_FLOAT:
- work_line_->CheckUnaryOp(dec_insn, reg_types_.Float(), reg_types_.Double());
+ work_line_->CheckUnaryOpFromWide(dec_insn, reg_types_.Float(),
+ reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::INT_TO_BYTE:
work_line_->CheckUnaryOp(dec_insn, reg_types_.Byte(), reg_types_.Integer());
@@ -2130,12 +2209,14 @@
case Instruction::SHL_INT:
case Instruction::SHR_INT:
case Instruction::USHR_INT:
- work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), false);
+ work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(),
+ reg_types_.Integer(), false);
break;
case Instruction::AND_INT:
case Instruction::OR_INT:
case Instruction::XOR_INT:
- work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(), reg_types_.Integer(), true);
+ work_line_->CheckBinaryOp(dec_insn, reg_types_.Integer(), reg_types_.Integer(),
+ reg_types_.Integer(), true);
break;
case Instruction::ADD_LONG:
case Instruction::SUB_LONG:
@@ -2145,13 +2226,16 @@
case Instruction::AND_LONG:
case Instruction::OR_LONG:
case Instruction::XOR_LONG:
- work_line_->CheckBinaryOp(dec_insn, reg_types_.Long(), reg_types_.Long(), reg_types_.Long(), false);
+ work_line_->CheckBinaryOpWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ reg_types_.LongLo(), reg_types_.LongHi(),
+ reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::SHL_LONG:
case Instruction::SHR_LONG:
case Instruction::USHR_LONG:
/* shift distance is Int, making these different from other binary operations */
- work_line_->CheckBinaryOp(dec_insn, reg_types_.Long(), reg_types_.Long(), reg_types_.Integer(), false);
+ work_line_->CheckBinaryOpWideShift(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ reg_types_.Integer());
break;
case Instruction::ADD_FLOAT:
case Instruction::SUB_FLOAT:
@@ -2165,7 +2249,9 @@
case Instruction::MUL_DOUBLE:
case Instruction::DIV_DOUBLE:
case Instruction::REM_DOUBLE:
- work_line_->CheckBinaryOp(dec_insn, reg_types_.Double(), reg_types_.Double(), reg_types_.Double(), false);
+ work_line_->CheckBinaryOpWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::ADD_INT_2ADDR:
case Instruction::SUB_INT_2ADDR:
@@ -2192,12 +2278,15 @@
case Instruction::AND_LONG_2ADDR:
case Instruction::OR_LONG_2ADDR:
case Instruction::XOR_LONG_2ADDR:
- work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Long(), reg_types_.Long(), reg_types_.Long(), false);
+ work_line_->CheckBinaryOp2addrWide(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ reg_types_.LongLo(), reg_types_.LongHi(),
+ reg_types_.LongLo(), reg_types_.LongHi());
break;
case Instruction::SHL_LONG_2ADDR:
case Instruction::SHR_LONG_2ADDR:
case Instruction::USHR_LONG_2ADDR:
- work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Long(), reg_types_.Long(), reg_types_.Integer(), false);
+ work_line_->CheckBinaryOp2addrWideShift(dec_insn, reg_types_.LongLo(), reg_types_.LongHi(),
+ reg_types_.Integer());
break;
case Instruction::ADD_FLOAT_2ADDR:
case Instruction::SUB_FLOAT_2ADDR:
@@ -2211,7 +2300,9 @@
case Instruction::MUL_DOUBLE_2ADDR:
case Instruction::DIV_DOUBLE_2ADDR:
case Instruction::REM_DOUBLE_2ADDR:
- work_line_->CheckBinaryOp2addr(dec_insn, reg_types_.Double(), reg_types_.Double(), reg_types_.Double(), false);
+ work_line_->CheckBinaryOp2addrWide(dec_insn, reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ reg_types_.DoubleLo(), reg_types_.DoubleHi(),
+ reg_types_.DoubleLo(), reg_types_.DoubleHi());
break;
case Instruction::ADD_INT_LIT16:
case Instruction::RSUB_INT:
@@ -2290,7 +2381,7 @@
} // end - switch (dec_insn.opcode)
if (have_pending_hard_failure_) {
- if (!Runtime::Current()->IsStarted()) {
+ if (Runtime::Current()->IsCompiler()) {
/* When compiling, check that the last failure is a hard failure */
CHECK_EQ(failures_[failures_.size() - 1], VERIFY_ERROR_BAD_CLASS_HARD);
}
@@ -2645,7 +2736,7 @@
const RegType& super = GetDeclaringClass().GetSuperClass(®_types_);
if (super.IsUnresolvedTypes()) {
Fail(VERIFY_ERROR_NO_METHOD) << "unknown super class in invoke-super from "
- << PrettyMethod(method_idx_, *dex_file_)
+ << PrettyMethod(dex_method_idx_, *dex_file_)
<< " to super " << PrettyMethod(res_method);
return NULL;
}
@@ -2653,7 +2744,7 @@
if (res_method->GetMethodIndex() >= super_klass->GetVTable()->GetLength()) {
MethodHelper mh(res_method);
Fail(VERIFY_ERROR_NO_METHOD) << "invalid invoke-super from "
- << PrettyMethod(method_idx_, *dex_file_)
+ << PrettyMethod(dex_method_idx_, *dex_file_)
<< " to super " << super
<< "." << mh.GetName()
<< mh.GetSignature();
@@ -2768,7 +2859,7 @@
}
void MethodVerifier::VerifyAGet(const DecodedInstruction& dec_insn,
- const RegType& insn_type, bool is_primitive) {
+ const RegType& insn_type, bool is_primitive) {
const RegType& index_type = work_line_->GetRegisterType(dec_insn.vC);
if (!index_type.IsArrayIndexTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Invalid reg type for array index (" << index_type << ")";
@@ -2782,7 +2873,8 @@
work_line_->SetRegisterType(dec_insn.vA, reg_types_.Zero());
} else {
// Category 2
- work_line_->SetRegisterType(dec_insn.vA, reg_types_.ConstLo());
+ work_line_->SetRegisterTypeWide(dec_insn.vA, reg_types_.FromCat2ConstLo(0, false),
+ reg_types_.FromCat2ConstHi(0, false));
}
} else if (!array_type.IsArrayTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "not array type " << array_type << " with aget";
@@ -2797,14 +2889,19 @@
<< " source for category 1 aget";
} else if (is_primitive && !insn_type.Equals(component_type) &&
!((insn_type.IsInteger() && component_type.IsFloat()) ||
- (insn_type.IsLong() && component_type.IsDouble()))) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array type " << array_type
- << " incompatible with aget of type " << insn_type;
+ (insn_type.IsLong() && component_type.IsDouble()))) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array type " << array_type
+ << " incompatible with aget of type " << insn_type;
} else {
- // Use knowledge of the field type which is stronger than the type inferred from the
- // instruction, which can't differentiate object types and ints from floats, longs from
- // doubles.
+ // Use knowledge of the field type which is stronger than the type inferred from the
+ // instruction, which can't differentiate object types and ints from floats, longs from
+ // doubles.
+ if (!component_type.IsLowHalf()) {
work_line_->SetRegisterType(dec_insn.vA, component_type);
+ } else {
+ work_line_->SetRegisterTypeWide(dec_insn.vA, component_type,
+ component_type.HighHalf(®_types_));
+ }
}
}
}
@@ -2925,7 +3022,7 @@
// the field is declared in this class
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "cannot access instance field " << PrettyField(field)
<< " of a not fully initialized object within the context of "
- << PrettyMethod(method_idx_, *dex_file_);
+ << PrettyMethod(dex_method_idx_, *dex_file_);
return NULL;
} else if (!field_klass.IsAssignableFrom(obj_type)) {
// Trying to access C1.field1 using reference of type C2, which is neither C1 or a sub-class
@@ -2986,7 +3083,11 @@
return;
}
}
- work_line_->SetRegisterType(dec_insn.vA, field_type);
+ if (!field_type.IsLowHalf()) {
+ work_line_->SetRegisterType(dec_insn.vA, field_type);
+ } else {
+ work_line_->SetRegisterTypeWide(dec_insn.vA, field_type, field_type.HighHalf(®_types_));
+ }
}
void MethodVerifier::VerifyISPut(const DecodedInstruction& dec_insn,
@@ -3113,7 +3214,7 @@
}
const RegType& MethodVerifier::GetMethodReturnType() {
- const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx_);
+ 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));
@@ -3125,7 +3226,7 @@
Class* klass = foo_method_->GetDeclaringClass();
return reg_types_.FromClass(klass, klass->IsFinal());
} else {
- const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx_);
+ const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(method_id.class_idx_));
return reg_types_.FromDescriptor(class_loader_, descriptor, false);
}
@@ -3265,6 +3366,50 @@
return it->second;
}
+std::vector<int32_t> MethodVerifier::DescribeVRegs(uint32_t dex_pc) {
+ RegisterLine* line = reg_table_.GetLine(dex_pc);
+ std::vector<int32_t> result;
+ for (size_t i = 0; i < line->NumRegs(); ++i) {
+ const RegType& type = line->GetRegisterType(i);
+ if (type.IsConstant()) {
+ result.push_back(type.IsPreciseConstant() ? kConstant : kImpreciseConstant);
+ result.push_back(type.ConstantValue());
+ } else if (type.IsConstantLo()) {
+ result.push_back(type.IsPreciseConstantLo() ? kConstant : kImpreciseConstant);
+ result.push_back(type.ConstantValueLo());
+ } else if (type.IsConstantHi()) {
+ result.push_back(type.IsPreciseConstantHi() ? kConstant : kImpreciseConstant);
+ result.push_back(type.ConstantValueHi());
+ } else if (type.IsIntegralTypes()) {
+ result.push_back(kIntVReg);
+ result.push_back(0);
+ } else if (type.IsFloat()) {
+ result.push_back(kFloatVReg);
+ result.push_back(0);
+ } else if (type.IsLong()) {
+ result.push_back(kLongLoVReg);
+ result.push_back(0);
+ result.push_back(kLongHiVReg);
+ result.push_back(0);
+ ++i;
+ } else if (type.IsDouble()) {
+ result.push_back(kDoubleLoVReg);
+ result.push_back(0);
+ result.push_back(kDoubleHiVReg);
+ result.push_back(0);
+ ++i;
+ } else if (type.IsUndefined() || type.IsConflict() || type.IsHighHalf()) {
+ result.push_back(kUndefined);
+ result.push_back(0);
+ } else {
+ CHECK(type.IsNonZeroReferenceTypes()) << type;
+ result.push_back(kReferenceVReg);
+ result.push_back(0);
+ }
+ }
+ return result;
+}
+
Mutex* MethodVerifier::dex_gc_maps_lock_ = NULL;
MethodVerifier::DexGcMapTable* MethodVerifier::dex_gc_maps_ = NULL;
diff --git a/src/verifier/method_verifier.h b/src/verifier/method_verifier.h
index 42283a2..95d7905 100644
--- a/src/verifier/method_verifier.h
+++ b/src/verifier/method_verifier.h
@@ -113,6 +113,8 @@
kTrackRegsAll,
};
+// A mapping from a dex pc to the register line statuses as they are immediately prior to the
+// execution of that instruction.
class PcToRegisterLineTable {
public:
PcToRegisterLineTable() {}
@@ -137,7 +139,6 @@
private:
typedef SafeMap<int32_t, RegisterLine*> Table;
- // Map from a dex pc to the register status associated with it
Table pc_to_register_line_;
};
@@ -162,7 +163,19 @@
std::string& error)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static void VerifyMethodAndDump(AbstractMethod* method)
+ static void VerifyMethodAndDump(std::ostream& os, uint32_t method_idx, const DexFile* dex_file,
+ DexCache* dex_cache, ClassLoader* class_loader,
+ uint32_t class_def_idx, const DexFile::CodeItem* code_item,
+ AbstractMethod* method, uint32_t method_access_flags)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ static std::vector<int32_t> DescribeVRegs(uint32_t dex_method_idx,
+ const DexFile* dex_file, DexCache* dex_cache,
+ ClassLoader* class_loader,
+ uint32_t class_def_idx,
+ const DexFile::CodeItem* code_item,
+ AbstractMethod* method,
+ uint32_t method_access_flags, uint32_t dex_pc)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
uint8_t EncodePcToReferenceMapData() const;
@@ -180,7 +193,7 @@
// Log for verification information.
std::ostream& LogVerifyInfo() {
- return info_messages_ << "VFY: " << PrettyMethod(method_idx_, *dex_file_)
+ return info_messages_ << "VFY: " << PrettyMethod(dex_method_idx_, *dex_file_)
<< '[' << reinterpret_cast<void*>(work_insn_idx_) << "] : ";
}
@@ -576,6 +589,9 @@
// Compute sizes for GC map data
void ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc);
+ // Describe VRegs at the given dex pc.
+ std::vector<int32_t> DescribeVRegs(uint32_t dex_pc);
+
InsnFlags* CurrentInsnFlags();
// All the GC maps that the verifier has created
@@ -617,7 +633,7 @@
// Storage for the register status we're saving for later.
UniquePtr<RegisterLine> saved_line_;
- uint32_t method_idx_; // The method we're working on.
+ uint32_t dex_method_idx_; // The method we're working on.
// Its object representation if known.
AbstractMethod* foo_method_ GUARDED_BY(Locks::mutator_lock_);
uint32_t method_access_flags_; // Method's access flags.
diff --git a/src/verifier/reg_type.cc b/src/verifier/reg_type.cc
index e02fbf4..dc41ceb 100644
--- a/src/verifier/reg_type.cc
+++ b/src/verifier/reg_type.cc
@@ -25,19 +25,22 @@
static const char* type_strings[] = {
"Undefined",
"Conflict",
- "Boolean",
- "Byte",
- "Short",
- "Char",
- "Integer",
- "Float",
- "Long (Low Half)",
- "Long (High Half)",
- "Double (Low Half)",
- "Double (High Half)",
- "64-bit Constant (Low Half)",
- "64-bit Constant (High Half)",
- "32-bit Constant",
+ "boolean",
+ "byte",
+ "short",
+ "char",
+ "int",
+ "float",
+ "long (Low Half)",
+ "long (High Half)",
+ "double (Low Half)",
+ "double (High Half)",
+ "Precise 32-bit Constant",
+ "Imprecise 32-bit Constant",
+ "Precise 64-bit Constant (Low Half)",
+ "Precise 64-bit Constant (High Half)",
+ "Imprecise 64-bit Constant (Low Half)",
+ "Imprecise 64-bit Constant (High Half)",
"Unresolved Reference",
"Uninitialized Reference",
"Uninitialized This Reference",
@@ -81,14 +84,34 @@
} else if (IsConstant()) {
uint32_t val = ConstantValue();
if (val == 0) {
- result = "Zero";
+ CHECK(IsPreciseConstant());
+ result = "Zero/null";
} else {
+ result = IsPreciseConstant() ? "Precise " : "Imprecise ";
if (IsConstantShort()) {
- result = StringPrintf("32-bit Constant: %d", val);
+ result += StringPrintf("Constant: %d", val);
} else {
- result = StringPrintf("32-bit Constant: 0x%x", val);
+ result += StringPrintf("Constant: 0x%x", val);
}
}
+ } else if (IsConstantLo()) {
+ int32_t val = ConstantValueLo();
+ result = IsPreciseConstantLo() ? "Precise " : "Imprecise ";
+ if (val >= std::numeric_limits<jshort>::min() &&
+ val <= std::numeric_limits<jshort>::max()) {
+ result += StringPrintf("Low-half Constant: %d", val);
+ } else {
+ result += StringPrintf("Low-half Constant: 0x%x", val);
+ }
+ } else if (IsConstantHi()) {
+ int32_t val = ConstantValueHi();
+ result = IsPreciseConstantHi() ? "Precise " : "Imprecise ";
+ if (val >= std::numeric_limits<jshort>::min() &&
+ val <= std::numeric_limits<jshort>::max()) {
+ result += StringPrintf("High-half Constant: %d", val);
+ } else {
+ result += StringPrintf("High-half Constant: 0x%x", val);
+ }
} else {
result = type_strings[type_];
if (IsReferenceTypes()) {
@@ -104,13 +127,14 @@
}
const RegType& RegType::HighHalf(RegTypeCache* cache) const {
- CHECK(IsLowHalf());
+ DCHECK(IsLowHalf());
if (type_ == kRegTypeLongLo) {
return cache->FromType(kRegTypeLongHi);
} else if (type_ == kRegTypeDoubleLo) {
return cache->FromType(kRegTypeDoubleHi);
} else {
- return cache->FromType(kRegTypeConstHi);
+ DCHECK_EQ(type_, kRegTypeImpreciseConstLo);
+ return cache->FromType(kRegTypeImpreciseConstHi);
}
}
@@ -244,16 +268,32 @@
if (val1 >= 0 && val2 >= 0) {
// +ve1 MERGE +ve2 => MAX(+ve1, +ve2)
if (val1 >= val2) {
- return *this;
+ if (!IsPreciseConstant()) {
+ return *this;
+ } else {
+ return reg_types->FromCat1Const(val1, false);
+ }
} else {
- return incoming_type;
+ if (!incoming_type.IsPreciseConstant()) {
+ return incoming_type;
+ } else {
+ return reg_types->FromCat1Const(val2, false);
+ }
}
} else if (val1 < 0 && val2 < 0) {
// -ve1 MERGE -ve2 => MIN(-ve1, -ve2)
if (val1 <= val2) {
- return *this;
+ if (!IsPreciseConstant()) {
+ return *this;
+ } else {
+ return reg_types->FromCat1Const(val1, false);
+ }
} else {
- return incoming_type;
+ if (!incoming_type.IsPreciseConstant()) {
+ return incoming_type;
+ } else {
+ return reg_types->FromCat1Const(val2, false);
+ }
}
} else {
// Values are +ve and -ve, choose smallest signed type in which they both fit
@@ -275,6 +315,14 @@
return reg_types->IntConstant();
}
}
+ } else if (IsConstantLo() && incoming_type.IsConstantLo()) {
+ int32_t val1 = ConstantValueLo();
+ int32_t val2 = incoming_type.ConstantValueLo();
+ return reg_types->FromCat2ConstLo(val1 | val2, false);
+ } else if (IsConstantHi() && incoming_type.IsConstantHi()) {
+ int32_t val1 = ConstantValueHi();
+ int32_t val2 = incoming_type.ConstantValueHi();
+ return reg_types->FromCat2ConstHi(val1 | val2, false);
} else if (IsIntegralTypes() && incoming_type.IsIntegralTypes()) {
if (IsBooleanTypes() && incoming_type.IsBooleanTypes()) {
return reg_types->Boolean(); // boolean MERGE boolean => boolean
diff --git a/src/verifier/reg_type.h b/src/verifier/reg_type.h
index 205867d..5daaf60 100644
--- a/src/verifier/reg_type.h
+++ b/src/verifier/reg_type.h
@@ -52,10 +52,13 @@
kRegTypeLongHi,
kRegTypeDoubleLo, // D.
kRegTypeDoubleHi,
- kRegTypeConstLo, // Const derived wide, lower half - could be long or double.
- kRegTypeConstHi, // Const derived wide, upper half - could be long or double.
- kRegTypeLastFixedLocation = kRegTypeConstHi,
- kRegTypeConst, // 32-bit constant derived value - could be float or int.
+ kRegTypeLastFixedLocation = kRegTypeDoubleHi,
+ kRegTypePreciseConst, // 32-bit constant - could be float or int.
+ kRegTypeImpreciseConst, // 32-bit constant derived value - could be float or int.
+ kRegTypePreciseConstLo, // Const wide, lower half - could be long or double.
+ kRegTypePreciseConstHi, // Const wide, upper half - could be long or double.
+ kRegTypeImpreciseConstLo, // Const derived wide, lower half - could be long or double.
+ kRegTypeImpreciseConstHi, // Const derived wide, upper half - could be long or double.
kRegTypeUnresolvedReference, // Reference type that couldn't be resolved.
kRegTypeUninitializedReference, // Freshly allocated reference type.
kRegTypeUninitializedThisReference, // Freshly allocated reference passed as "this".
@@ -105,38 +108,85 @@
IsUnresolvedAndUninitializedThisReference() || IsUnresolvedMergedReference() ||
IsUnresolvedSuperClass();
}
- bool IsLowHalf() const { return type_ == kRegTypeLongLo ||
- type_ == kRegTypeDoubleLo ||
- type_ == kRegTypeConstLo; }
- bool IsHighHalf() const { return type_ == kRegTypeLongHi ||
- type_ == kRegTypeDoubleHi ||
- type_ == kRegTypeConstHi; }
+ bool IsLowHalf() const {
+ return type_ == kRegTypeLongLo ||
+ type_ == kRegTypeDoubleLo ||
+ type_ == kRegTypePreciseConstLo ||
+ type_ == kRegTypeImpreciseConstLo;
+ }
+ bool IsHighHalf() const {
+ return type_ == kRegTypeLongHi ||
+ type_ == kRegTypeDoubleHi ||
+ type_ == kRegTypePreciseConstHi ||
+ type_ == kRegTypeImpreciseConstHi;
+ }
bool IsLongOrDoubleTypes() const { return IsLowHalf(); }
// Check this is the low half, and that type_h is its matching high-half
bool CheckWidePair(const RegType& type_h) const {
- return IsLowHalf() && (type_h.type_ == type_ + 1);
+ if (IsLowHalf()) {
+ return (type_h.type_ == type_ + 1) ||
+ (IsPreciseConstantLo() && !type_h.IsPreciseConstantHi()) ||
+ (!IsPreciseConstantLo() && type_h.IsPreciseConstantHi());
+ }
+ return false;
}
// The high half that corresponds to this low half
const RegType& HighHalf(RegTypeCache* cache) const
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool IsConstant() const { return type_ == kRegTypeConst; }
- bool IsLongConstant() const { return type_ == kRegTypeConstLo; }
- bool IsLongConstantHigh() const { return type_ == kRegTypeConstHi; }
+ bool IsPreciseConstant() const {
+ return type_ == kRegTypePreciseConst;
+ }
+ bool IsPreciseConstantLo() const {
+ bool result = (type_ == kRegTypePreciseConstLo);
+ DCHECK(result || (type_ == kRegTypeImpreciseConstLo));
+ return result;
+ }
+ bool IsPreciseConstantHi() const {
+ bool result = (type_ == kRegTypePreciseConstHi);
+ DCHECK(result || (type_ == kRegTypeImpreciseConstHi));
+ return result;
+ }
+ bool IsConstant() const {
+ return type_ == kRegTypePreciseConst || type_ == kRegTypeImpreciseConst;
+ }
- // If this is a 32-bit constant, what is the value? This value may just
- // approximate to the actual constant value by virtue of merging.
+ bool IsConstantLo() const {
+ return type_ == kRegTypePreciseConstLo || type_ == kRegTypeImpreciseConstLo;
+ }
+ bool IsLongConstant() const {
+ return IsConstantLo();
+ }
+ bool IsConstantHi() const {
+ return type_ == kRegTypePreciseConstHi || type_ == kRegTypeImpreciseConstHi;
+ }
+ bool IsLongConstantHigh() const {
+ return IsConstantHi();
+ }
+
+ // 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.
int32_t ConstantValue() const {
DCHECK(IsConstant());
return allocation_pc_or_constant_or_merged_types_;
}
+ int32_t ConstantValueLo() const {
+ DCHECK(IsConstantLo());
+ return allocation_pc_or_constant_or_merged_types_;
+ }
+ int32_t ConstantValueHi() const {
+ DCHECK(IsConstantHi());
+ return allocation_pc_or_constant_or_merged_types_;
+ }
- bool IsZero() const { return IsConstant() && ConstantValue() == 0; }
- bool IsOne() const { return IsConstant() && ConstantValue() == 1; }
- bool IsConstantBoolean() const { return IsZero() || IsOne(); }
+ bool IsZero() const { return IsPreciseConstant() && ConstantValue() == 0; }
+ bool IsOne() const { return IsPreciseConstant() && ConstantValue() == 1; }
+ bool IsConstantBoolean() const {
+ return IsConstant() && ConstantValue() >= 0 && ConstantValue() <= 1;
+ }
bool IsConstantByte() const {
return IsConstant() &&
ConstantValue() >= std::numeric_limits<jbyte>::min() &&
@@ -187,13 +237,17 @@
return IsLong() || IsLongConstant();
}
bool IsLongHighTypes() const {
- return type_ == kRegTypeLongHi || type_ == kRegTypeConstHi;
+ return type_ == kRegTypeLongHi ||
+ type_ == kRegTypePreciseConstHi ||
+ type_ == kRegTypeImpreciseConstHi;
}
bool IsDoubleTypes() const {
return IsDouble() || IsLongConstant();
}
bool IsDoubleHighTypes() const {
- return type_ == kRegTypeDoubleHi || type_ == kRegTypeConstHi;
+ return type_ == kRegTypeDoubleHi ||
+ type_ == kRegTypePreciseConstHi ||
+ type_ == kRegTypeImpreciseConstHi;
}
uint32_t GetAllocationPc() const {
@@ -351,8 +405,9 @@
: type_(type), klass_or_descriptor_(klass_or_descriptor),
allocation_pc_or_constant_or_merged_types_(allocation_pc_or_constant_or_merged_types),
cache_id_(cache_id) {
- DCHECK(IsConstant() || IsUninitializedTypes() || IsUnresolvedMergedReference() ||
- IsUnresolvedSuperClass() || allocation_pc_or_constant_or_merged_types == 0);
+ DCHECK(IsConstant() || IsConstantLo() || IsConstantHi() ||
+ IsUninitializedTypes() || IsUnresolvedMergedReference() || IsUnresolvedSuperClass() ||
+ allocation_pc_or_constant_or_merged_types == 0);
if (!IsConstant() && !IsLongConstant() && !IsLongConstantHigh() && !IsUndefined() &&
!IsConflict() && !IsUnresolvedMergedReference() && !IsUnresolvedSuperClass()) {
DCHECK(klass_or_descriptor != NULL);
diff --git a/src/verifier/reg_type_cache.cc b/src/verifier/reg_type_cache.cc
index 847cde9..1b91321 100644
--- a/src/verifier/reg_type_cache.cc
+++ b/src/verifier/reg_type_cache.cc
@@ -312,14 +312,41 @@
}
}
-const RegType& RegTypeCache::FromCat1Const(int32_t value) {
+const RegType& RegTypeCache::FromCat1Const(int32_t value, bool precise) {
+ RegType::Type wanted_type = precise ? RegType::kRegTypePreciseConst : RegType::kRegTypeImpreciseConst;
for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
- if (cur_entry->IsConstant() && cur_entry->ConstantValue() == value) {
+ if (cur_entry->GetType() == wanted_type && cur_entry->ConstantValue() == value) {
return *cur_entry;
}
}
- RegType* entry = new RegType(RegType::kRegTypeConst, NULL, value, entries_.size());
+ RegType* entry = new RegType(wanted_type, NULL, value, entries_.size());
+ entries_.push_back(entry);
+ return *entry;
+}
+
+const RegType& RegTypeCache::FromCat2ConstLo(int32_t value, bool precise) {
+ RegType::Type wanted_type = precise ? RegType::kRegTypePreciseConstLo : RegType::kRegTypeImpreciseConstLo;
+ for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
+ RegType* cur_entry = entries_[i];
+ if (cur_entry->GetType() == wanted_type && cur_entry->ConstantValueLo() == value) {
+ return *cur_entry;
+ }
+ }
+ RegType* entry = new RegType(wanted_type, NULL, value, entries_.size());
+ entries_.push_back(entry);
+ return *entry;
+}
+
+const RegType& RegTypeCache::FromCat2ConstHi(int32_t value, bool precise) {
+ RegType::Type wanted_type = precise ? RegType::kRegTypePreciseConstHi : RegType::kRegTypeImpreciseConstHi;
+ for (size_t i = RegType::kRegTypeLastFixedLocation + 1; i < entries_.size(); i++) {
+ RegType* cur_entry = entries_[i];
+ if (cur_entry->GetType() == wanted_type && cur_entry->ConstantValueHi() == value) {
+ return *cur_entry;
+ }
+ }
+ RegType* entry = new RegType(wanted_type, NULL, value, entries_.size());
entries_.push_back(entry);
return *entry;
}
@@ -337,11 +364,10 @@
}
void RegTypeCache::Dump(std::ostream& os) {
- os << "Register Types:\n";
for (size_t i = 0; i < entries_.size(); i++) {
RegType* cur_entry = entries_[i];
if (cur_entry != NULL) {
- os << "\t" << i << ": " << cur_entry->Dump() << "\n";
+ os << i << ": " << cur_entry->Dump() << "\n";
}
}
}
diff --git a/src/verifier/reg_type_cache.h b/src/verifier/reg_type_cache.h
index 36fd2c7..bf0c5b1 100644
--- a/src/verifier/reg_type_cache.h
+++ b/src/verifier/reg_type_cache.h
@@ -44,7 +44,10 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
const RegType& FromClass(Class* klass, bool precise)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- const RegType& FromCat1Const(int32_t value);
+ const RegType& FromCat1Const(int32_t value, bool precise)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ const RegType& FromCat2ConstLo(int32_t value, bool precise);
+ const RegType& FromCat2ConstHi(int32_t value, bool precise);
const RegType& FromDescriptor(ClassLoader* loader, const char* descriptor, bool precise)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
const RegType& FromType(RegType::Type)
@@ -70,12 +73,18 @@
const RegType& Float() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return FromType(RegType::kRegTypeFloat);
}
- const RegType& Long() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ const RegType& LongLo() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return FromType(RegType::kRegTypeLongLo);
}
- const RegType& Double() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ const RegType& LongHi() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return FromType(RegType::kRegTypeLongHi);
+ }
+ const RegType& DoubleLo() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return FromType(RegType::kRegTypeDoubleLo);
}
+ const RegType& DoubleHi() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return FromType(RegType::kRegTypeDoubleHi);
+ }
const RegType& JavaLangClass(bool precise) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return From(precise ? RegType::kRegTypeReference
@@ -103,11 +112,8 @@
const RegType& Conflict() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return FromType(RegType::kRegTypeConflict);
}
- const RegType& ConstLo() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return FromType(RegType::kRegTypeConstLo);
- }
const RegType& Zero() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- return FromCat1Const(0);
+ return FromCat1Const(0, true);
}
const RegType& Uninitialized(const RegType& type, uint32_t allocation_pc);
@@ -118,9 +124,15 @@
// Representatives of various constant types. When merging constants we can't infer a type,
// (an int may later be used as a float) so we select these representative values meaning future
// merges won't know the exact constant value but have some notion of its size.
- const RegType& ByteConstant() { return FromCat1Const(std::numeric_limits<jbyte>::min()); }
- const RegType& ShortConstant() { return FromCat1Const(std::numeric_limits<jshort>::min()); }
- const RegType& IntConstant() { return FromCat1Const(std::numeric_limits<jint>::max()); }
+ const RegType& ByteConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return FromCat1Const(std::numeric_limits<jbyte>::min(), false);
+ }
+ const RegType& ShortConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return FromCat1Const(std::numeric_limits<jshort>::min(), false);
+ }
+ const RegType& IntConstant() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return FromCat1Const(std::numeric_limits<jint>::max(), false);
+ }
const RegType& GetComponentType(const RegType& array, ClassLoader* loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/src/verifier/reg_type_test.cc b/src/verifier/reg_type_test.cc
index 6bdf886..18e9a65 100644
--- a/src/verifier/reg_type_test.cc
+++ b/src/verifier/reg_type_test.cc
@@ -184,7 +184,7 @@
EXPECT_FALSE(int_reg_type.IsDoubleTypes());
EXPECT_TRUE(int_reg_type.IsArrayIndexTypes());
- const RegType& long_reg_type = cache.Long();
+ const RegType& long_reg_type = cache.LongLo();
EXPECT_FALSE(long_reg_type.IsUndefined());
EXPECT_FALSE(long_reg_type.IsConflict());
EXPECT_FALSE(long_reg_type.IsZero());
@@ -246,7 +246,7 @@
EXPECT_FALSE(float_reg_type.IsDoubleTypes());
EXPECT_FALSE(float_reg_type.IsArrayIndexTypes());
- const RegType& double_reg_type = cache.Double();
+ const RegType& double_reg_type = cache.DoubleLo();
EXPECT_FALSE(double_reg_type.IsUndefined());
EXPECT_FALSE(double_reg_type.IsConflict());
EXPECT_FALSE(double_reg_type.IsZero());
diff --git a/src/verifier/register_line.cc b/src/verifier/register_line.cc
index 4882740..afd2eff 100644
--- a/src/verifier/register_line.cc
+++ b/src/verifier/register_line.cc
@@ -35,12 +35,9 @@
bool RegisterLine::SetRegisterType(uint32_t vdst, const RegType& new_type) {
DCHECK_LT(vdst, num_regs_);
- if (new_type.IsLowHalf()) {
- line_[vdst] = new_type.GetId();
- line_[vdst + 1] = new_type.HighHalf(verifier_->GetRegTypeCache()).GetId();
- } else if (new_type.IsHighHalf()) {
- /* should never set these explicitly */
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Explicit set of high register type";
+ if (new_type.IsLowHalf() || new_type.IsHighHalf()) {
+ verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Expected category1 register type not '"
+ << new_type << "'";
return false;
} else if (new_type.IsConflict()) { // should only be set during a merge
verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Set register to unknown type " << new_type;
@@ -58,13 +55,33 @@
return true;
}
+bool RegisterLine::SetRegisterTypeWide(uint32_t vdst, const RegType& new_type1,
+ const RegType& new_type2) {
+ DCHECK_LT(vdst, num_regs_);
+ if (!new_type1.CheckWidePair(new_type2)) {
+ verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Invalid wide pair '"
+ << new_type1 << "' '" << new_type2 << "'";
+ return false;
+ } else {
+ line_[vdst] = new_type1.GetId();
+ line_[vdst + 1] = new_type2.GetId();
+ }
+ // Clear the monitor entry bits for this register.
+ ClearAllRegToLockDepths(vdst);
+ ClearAllRegToLockDepths(vdst + 1);
+ return true;
+}
+
void RegisterLine::SetResultTypeToUnknown() {
result_[0] = RegType::kRegTypeUndefined;
result_[1] = RegType::kRegTypeUndefined;
}
void RegisterLine::SetResultRegisterType(const RegType& new_type) {
+ DCHECK(!new_type.IsLowHalf());
+ DCHECK(!new_type.IsHighHalf());
result_[0] = new_type.GetId();
+ result_[1] = RegType::kRegTypeUndefined;
if (new_type.IsLowHalf()) {
DCHECK_EQ(new_type.HighHalf(verifier_->GetRegTypeCache()).GetId(), new_type.GetId() + 1);
result_[1] = new_type.GetId() + 1;
@@ -73,6 +90,12 @@
}
}
+void RegisterLine::SetResultRegisterTypeWide(const RegType& new_type1, const RegType& new_type2) {
+ DCHECK(new_type1.CheckWidePair(new_type2));
+ result_[0] = new_type1.GetId();
+ result_[1] = new_type2.GetId();
+}
+
const RegType& RegisterLine::GetRegisterType(uint32_t vsrc) const {
// The register index was validated during the static pass, so we don't need to check it here.
DCHECK_LT(vsrc, num_regs_);
@@ -121,6 +144,29 @@
return true;
}
+bool RegisterLine::VerifyRegisterTypeWide(uint32_t vsrc, const RegType& check_type1,
+ const RegType& check_type2) {
+ DCHECK(check_type1.CheckWidePair(check_type2));
+ // Verify the src register type against the check type refining the type of the register
+ const RegType& src_type = GetRegisterType(vsrc);
+ if (!check_type1.IsAssignableFrom(src_type)) {
+ verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register v" << vsrc << " has type " << src_type
+ << " but expected " << check_type1;
+ return false;
+ }
+ const RegType& src_type_h = GetRegisterType(vsrc + 1);
+ if (!src_type.CheckWidePair(src_type_h)) {
+ verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register v" << vsrc << " has type "
+ << src_type << "/" << src_type_h;
+ return false;
+ }
+ // The register at vsrc has a defined type, we know the lower-upper-bound, but this is less
+ // precise than the subtype in vsrc so leave it for reference types. For primitive types
+ // if they are a defined type then they are as precise as we can get, however, for constant
+ // types we may wish to refine them. Unfortunately constant propagation has rendered this useless.
+ return true;
+}
+
void RegisterLine::MarkRefsAsInitialized(const RegType& uninit_type) {
DCHECK(uninit_type.IsUninitializedTypes());
const RegType& init_type = verifier_->GetRegTypeCache()->FromUninitialized(uninit_type);
@@ -180,7 +226,7 @@
verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "copy2 v" << vdst << "<-v" << vsrc
<< " type=" << type_l << "/" << type_h;
} else {
- SetRegisterType(vdst, type_l); // implicitly sets the second half
+ SetRegisterTypeWide(vdst, type_l, type_h);
}
}
@@ -209,7 +255,7 @@
<< "copyRes2 v" << vdst << "<- result0" << " type=" << type_l;
} else {
DCHECK(type_l.CheckWidePair(type_h)); // Set should never allow this case
- SetRegisterType(vdst, type_l); // also sets the high
+ SetRegisterTypeWide(vdst, type_l, type_h); // also sets the high
result_[0] = RegType::kRegTypeUndefined;
result_[1] = RegType::kRegTypeUndefined;
}
@@ -222,6 +268,30 @@
}
}
+void RegisterLine::CheckUnaryOpWide(const DecodedInstruction& dec_insn,
+ const RegType& dst_type1, const RegType& dst_type2,
+ const RegType& src_type1, const RegType& src_type2) {
+ if (VerifyRegisterTypeWide(dec_insn.vB, src_type1, src_type2)) {
+ SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+ }
+}
+
+void RegisterLine::CheckUnaryOpToWide(const DecodedInstruction& dec_insn,
+ const RegType& dst_type1, const RegType& dst_type2,
+ const RegType& src_type) {
+ if (VerifyRegisterType(dec_insn.vB, src_type)) {
+ SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+ }
+}
+
+void RegisterLine::CheckUnaryOpFromWide(const DecodedInstruction& dec_insn,
+ const RegType& dst_type,
+ const RegType& src_type1, const RegType& src_type2) {
+ if (VerifyRegisterTypeWide(dec_insn.vB, src_type1, src_type2)) {
+ SetRegisterType(dec_insn.vA, dst_type);
+ }
+}
+
void RegisterLine::CheckBinaryOp(const DecodedInstruction& dec_insn,
const RegType& dst_type,
const RegType& src_type1, const RegType& src_type2,
@@ -240,6 +310,25 @@
}
}
+void RegisterLine::CheckBinaryOpWide(const DecodedInstruction& dec_insn,
+ const RegType& dst_type1, const RegType& dst_type2,
+ const RegType& src_type1_1, const RegType& src_type1_2,
+ const RegType& src_type2_1, const RegType& src_type2_2) {
+ if (VerifyRegisterTypeWide(dec_insn.vB, src_type1_1, src_type1_2) &&
+ VerifyRegisterTypeWide(dec_insn.vC, src_type2_1, src_type2_2)) {
+ SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+ }
+}
+
+void RegisterLine::CheckBinaryOpWideShift(const DecodedInstruction& dec_insn,
+ const RegType& long_lo_type, const RegType& long_hi_type,
+ const RegType& int_type) {
+ if (VerifyRegisterTypeWide(dec_insn.vB, long_lo_type, long_hi_type) &&
+ VerifyRegisterType(dec_insn.vC, int_type)) {
+ SetRegisterTypeWide(dec_insn.vA, long_lo_type, long_hi_type);
+ }
+}
+
void RegisterLine::CheckBinaryOp2addr(const DecodedInstruction& dec_insn,
const RegType& dst_type, const RegType& src_type1,
const RegType& src_type2, bool check_boolean_op) {
@@ -257,6 +346,25 @@
}
}
+void RegisterLine::CheckBinaryOp2addrWide(const DecodedInstruction& dec_insn,
+ const RegType& dst_type1, const RegType& dst_type2,
+ const RegType& src_type1_1, const RegType& src_type1_2,
+ const RegType& src_type2_1, const RegType& src_type2_2) {
+ if (VerifyRegisterTypeWide(dec_insn.vA, src_type1_1, src_type1_2) &&
+ VerifyRegisterTypeWide(dec_insn.vB, src_type2_1, src_type2_2)) {
+ SetRegisterTypeWide(dec_insn.vA, dst_type1, dst_type2);
+ }
+}
+
+void RegisterLine::CheckBinaryOp2addrWideShift(const DecodedInstruction& dec_insn,
+ const RegType& long_lo_type, const RegType& long_hi_type,
+ const RegType& int_type) {
+ if (VerifyRegisterTypeWide(dec_insn.vA, long_lo_type, long_hi_type) &&
+ VerifyRegisterType(dec_insn.vB, int_type)) {
+ SetRegisterTypeWide(dec_insn.vA, long_lo_type, long_hi_type);
+ }
+}
+
void RegisterLine::CheckLiteralOp(const DecodedInstruction& dec_insn,
const RegType& dst_type, const RegType& src_type,
bool check_boolean_op) {
diff --git a/src/verifier/register_line.h b/src/verifier/register_line.h
index 9f0fcb0..c6c19f8 100644
--- a/src/verifier/register_line.h
+++ b/src/verifier/register_line.h
@@ -48,9 +48,6 @@
// During verification, we associate one of these with every "interesting" instruction. We track
// the status of all registers, and (if the method has any monitor-enter instructions) maintain a
// stack of entered monitors (identified by code unit offset).
-// If live-precise register maps are enabled, the "liveRegs" vector will be populated. Unlike the
-// other lists of registers here, we do not track the liveness of the method result register
-// (which is not visible to the GC).
class RegisterLine {
public:
RegisterLine(size_t num_regs, MethodVerifier* verifier)
@@ -88,16 +85,25 @@
bool SetRegisterType(uint32_t vdst, const RegType& new_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool SetRegisterTypeWide(uint32_t vdst, const RegType& new_type1, const RegType& new_type2)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
/* Set the type of the "result" register. */
void SetResultRegisterType(const RegType& new_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void SetResultRegisterTypeWide(const RegType& new_type1, const RegType& new_type2)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Get the type of register vsrc.
const RegType& GetRegisterType(uint32_t vsrc) const;
bool VerifyRegisterType(uint32_t vsrc, const RegType& check_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ bool VerifyRegisterTypeWide(uint32_t vsrc, const RegType& check_type1, const RegType& check_type2)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
void CopyFromLine(const RegisterLine* src) {
DCHECK_EQ(num_regs_, src->num_regs_);
memcpy(line_.get(), src->line_.get(), num_regs_ * sizeof(uint16_t));
@@ -171,6 +177,21 @@
const RegType& dst_type, const RegType& src_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void CheckUnaryOpWide(const DecodedInstruction& dec_insn,
+ const RegType& dst_type1, const RegType& dst_type2,
+ const RegType& src_type1, const RegType& src_type2)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ void CheckUnaryOpToWide(const DecodedInstruction& dec_insn,
+ const RegType& dst_type1, const RegType& dst_type2,
+ const RegType& src_type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ void CheckUnaryOpFromWide(const DecodedInstruction& dec_insn,
+ const RegType& dst_type,
+ const RegType& src_type1, const RegType& src_type2)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
/*
* Verify types for a simple three-register instruction (e.g. "add-int").
* "dst_type" is stored into vA, and "src_type1"/"src_type2" are verified
@@ -181,6 +202,17 @@
bool check_boolean_op)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void CheckBinaryOpWide(const DecodedInstruction& dec_insn,
+ const RegType& dst_type1, const RegType& dst_type2,
+ const RegType& src_type1_1, const RegType& src_type1_2,
+ const RegType& src_type2_1, const RegType& src_type2_2)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ void CheckBinaryOpWideShift(const DecodedInstruction& dec_insn,
+ const RegType& long_lo_type, const RegType& long_hi_type,
+ const RegType& int_type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
/*
* Verify types for a binary "2addr" operation. "src_type1"/"src_type2"
* are verified against vA/vB, then "dst_type" is stored into vA.
@@ -191,6 +223,17 @@
bool check_boolean_op)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void CheckBinaryOp2addrWide(const DecodedInstruction& dec_insn,
+ const RegType& dst_type1, const RegType& dst_type2,
+ const RegType& src_type1_1, const RegType& src_type1_2,
+ const RegType& src_type2_1, const RegType& src_type2_2)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ void CheckBinaryOp2addrWideShift(const DecodedInstruction& dec_insn,
+ const RegType& long_lo_type, const RegType& long_hi_type,
+ const RegType& int_type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
/*
* Verify types for A two-register instruction with a literal constant (e.g. "add-int/lit8").
* "dst_type" is stored into vA, and "src_type" is verified against vB.