in runtime/verifier/method_verifier.cc [1099:1211]
bool MethodVerifier::VerifyInstruction(const Instruction* inst, uint32_t code_offset) {
if (UNLIKELY(inst->IsExperimental())) {
// Experimental instructions don't yet have verifier support implementation.
// While it is possible to use them by themselves, when we try to use stable instructions
// with a virtual register that was created by an experimental instruction,
// the data flow analysis will fail.
Fail(VERIFY_ERROR_FORCE_INTERPRETER)
<< "experimental instruction is not supported by verifier; skipping verification";
have_pending_experimental_failure_ = true;
return false;
}
bool result = true;
switch (inst->GetVerifyTypeArgumentA()) {
case Instruction::kVerifyRegA:
result = result && CheckRegisterIndex(inst->VRegA());
break;
case Instruction::kVerifyRegAWide:
result = result && CheckWideRegisterIndex(inst->VRegA());
break;
}
switch (inst->GetVerifyTypeArgumentB()) {
case Instruction::kVerifyRegB:
result = result && CheckRegisterIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBField:
result = result && CheckFieldIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBMethod:
result = result && CheckMethodIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBNewInstance:
result = result && CheckNewInstance(inst->VRegB());
break;
case Instruction::kVerifyRegBString:
result = result && CheckStringIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBType:
result = result && CheckTypeIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBWide:
result = result && CheckWideRegisterIndex(inst->VRegB());
break;
}
switch (inst->GetVerifyTypeArgumentC()) {
case Instruction::kVerifyRegC:
result = result && CheckRegisterIndex(inst->VRegC());
break;
case Instruction::kVerifyRegCField:
result = result && CheckFieldIndex(inst->VRegC());
break;
case Instruction::kVerifyRegCNewArray:
result = result && CheckNewArray(inst->VRegC());
break;
case Instruction::kVerifyRegCType:
result = result && CheckTypeIndex(inst->VRegC());
break;
case Instruction::kVerifyRegCWide:
result = result && CheckWideRegisterIndex(inst->VRegC());
break;
case Instruction::kVerifyRegCString:
result = result && CheckStringIndex(inst->VRegC());
break;
}
switch (inst->GetVerifyExtraFlags()) {
case Instruction::kVerifyArrayData:
result = result && CheckArrayData(code_offset);
break;
case Instruction::kVerifyBranchTarget:
result = result && CheckBranchTarget(code_offset);
break;
case Instruction::kVerifySwitchTargets:
result = result && CheckSwitchTargets(code_offset);
break;
case Instruction::kVerifyVarArgNonZero:
// Fall-through.
case Instruction::kVerifyVarArg: {
// Instructions that can actually return a negative value shouldn't have this flag.
uint32_t v_a = dchecked_integral_cast<uint32_t>(inst->VRegA());
if ((inst->GetVerifyExtraFlags() == Instruction::kVerifyVarArgNonZero && v_a == 0) ||
v_a > Instruction::kMaxVarArgRegs) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid arg count (" << v_a << ") in "
"non-range invoke";
return false;
}
uint32_t args[Instruction::kMaxVarArgRegs];
inst->GetVarArgs(args);
result = result && CheckVarArgRegs(v_a, args);
break;
}
case Instruction::kVerifyVarArgRangeNonZero:
// Fall-through.
case Instruction::kVerifyVarArgRange:
if (inst->GetVerifyExtraFlags() == Instruction::kVerifyVarArgRangeNonZero &&
inst->VRegA() <= 0) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid arg count (" << inst->VRegA() << ") in "
"range invoke";
return false;
}
result = result && CheckVarArgRangeRegs(inst->VRegA(), inst->VRegC());
break;
case Instruction::kVerifyError:
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected opcode " << inst->Name();
result = false;
break;
}
if (inst->GetVerifyIsRuntimeOnly() && Runtime::Current()->IsAotCompiler() && !verify_to_dump_) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "opcode only expected at runtime " << inst->Name();
result = false;
}
return result;
}