ART: Add verifier support for invoke-polymorphic.
Change-Id: I1e1860cad80db46320c3ef5a9eaceb7529ea68d7
Bug: 30550796,33099829,33191712
Test: make test-art-host
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 0e1d7e7..daef35d 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -245,6 +245,10 @@
return (GetAccessFlags() & kAccSynthetic) != 0;
}
+ bool IsVarargs() {
+ return (GetAccessFlags() & kAccVarargs) != 0;
+ }
+
template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
bool IsProxyMethod() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index 99b9f9d..578550c 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -189,6 +189,7 @@
kVerifyVarArgRangeNonZero = 0x100000,
kVerifyRuntimeOnly = 0x200000,
kVerifyError = 0x400000,
+ kVerifyRegHPrototype = 0x800000
};
static constexpr uint32_t kMaxVarArgRegs = 5;
@@ -579,6 +580,10 @@
kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide));
}
+ int GetVerifyTypeArgumentH() const {
+ return (kInstructionVerifyFlags[Opcode()] & kVerifyRegHPrototype);
+ }
+
int GetVerifyExtraFlags() const {
return (kInstructionVerifyFlags[Opcode()] & (kVerifyArrayData | kVerifyBranchTarget |
kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgNonZero | kVerifyVarArgRange |
diff --git a/runtime/dex_instruction_list.h b/runtime/dex_instruction_list.h
index e537afe..ca2ce1d 100644
--- a/runtime/dex_instruction_list.h
+++ b/runtime/dex_instruction_list.h
@@ -269,8 +269,8 @@
V(0xF7, UNUSED_F7, "unused-f7", k10x, kIndexUnknown, 0, kVerifyError) \
V(0xF8, UNUSED_F8, "unused-f8", k10x, kIndexUnknown, 0, kVerifyError) \
V(0xF9, UNUSED_F9, "unused-f9", k10x, kIndexUnknown, 0, kVerifyError) \
- V(0xFA, INVOKE_POLYMORPHIC, "invoke-polymorphic", k45cc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero | kExperimental) \
- V(0xFB, INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range", k4rcc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero | kExperimental) \
+ V(0xFA, INVOKE_POLYMORPHIC, "invoke-polymorphic", k45cc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero | kVerifyRegHPrototype) \
+ V(0xFB, INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range", k4rcc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero | kVerifyRegHPrototype) \
V(0xFC, UNUSED_FC, "unused-fc", k10x, kIndexUnknown, 0, kVerifyError) \
V(0xFD, UNUSED_FD, "unused-fd", k10x, kIndexUnknown, 0, kVerifyError) \
V(0xFE, UNUSED_FE, "unused-fe", k10x, kIndexUnknown, 0, kVerifyError) \
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 72dbe6a..22da07d 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -865,11 +865,6 @@
// The invoke_method_idx here is the name of the signature polymorphic method that
// was symbolically invoked in bytecode (say MethodHandle.invoke or MethodHandle.invokeExact)
// and not the method that we'll dispatch to in the end.
- //
- // TODO(narayan) We'll have to check in the verifier that this is in fact a
- // signature polymorphic method so that we disallow calls via invoke-polymorphic
- // to non sig-poly methods. This would also have the side effect of verifying
- // that vRegC really is a reference type.
StackHandleScope<6> hs(self);
Handle<mirror::MethodHandleImpl> method_handle(hs.NewHandle(
ObjPtr<mirror::MethodHandleImpl>::DownCast(
diff --git a/runtime/mirror/method_handle_impl.cc b/runtime/mirror/method_handle_impl.cc
index fdfaaa8..4f1c448 100644
--- a/runtime/mirror/method_handle_impl.cc
+++ b/runtime/mirror/method_handle_impl.cc
@@ -22,6 +22,12 @@
namespace art {
namespace mirror {
+mirror::Class* MethodHandle::StaticClass() {
+ mirror::Class* klass = MethodHandleImpl::StaticClass()->GetSuperClass();
+ DCHECK(klass->DescriptorEquals("Ljava/lang/invoke/MethodHandle;"));
+ return klass;
+}
+
GcRoot<mirror::Class> MethodHandleImpl::static_class_;
void MethodHandleImpl::SetClass(Class* klass) {
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
index 9054216..5ea82b5 100644
--- a/runtime/mirror/method_handle_impl.h
+++ b/runtime/mirror/method_handle_impl.h
@@ -57,6 +57,8 @@
return static_cast<MethodHandleKind>(handle_kind);
}
+ static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
HeapReference<mirror::MethodType> nominal_type_;
HeapReference<mirror::MethodType> method_type_;
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 7137db8..38cc35c 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -41,6 +41,7 @@
#include "mirror/class.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
+#include "mirror/method_handle_impl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "reg_type-inl.h"
@@ -1184,6 +1185,11 @@
result = result && CheckWideRegisterIndex(inst->VRegC());
break;
}
+ switch (inst->GetVerifyTypeArgumentH()) {
+ case Instruction::kVerifyRegHPrototype:
+ result = result && CheckPrototypeIndex(inst->VRegH());
+ break;
+ }
switch (inst->GetVerifyExtraFlags()) {
case Instruction::kVerifyArrayData:
result = result && CheckArrayData(code_offset);
@@ -1289,6 +1295,15 @@
return true;
}
+inline bool MethodVerifier::CheckPrototypeIndex(uint32_t idx) {
+ if (idx >= dex_file_->GetHeader().proto_ids_size_) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad prototype index " << idx << " (max "
+ << dex_file_->GetHeader().proto_ids_size_ << ")";
+ return false;
+ }
+ return true;
+}
+
inline bool MethodVerifier::CheckStringIndex(uint32_t idx) {
if (idx >= dex_file_->GetHeader().string_ids_size_) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad string index " << idx << " (max "
@@ -2934,7 +2949,7 @@
* allowing the latter only if the "this" argument is the same as the "this" argument to
* this method (which implies that we're in a constructor ourselves).
*/
- const RegType& this_type = work_line_->GetInvocationThis(this, inst, is_range);
+ const RegType& this_type = work_line_->GetInvocationThis(this, inst);
if (this_type.IsConflict()) // failure.
break;
@@ -3015,7 +3030,7 @@
/* Get the type of the "this" arg, which should either be a sub-interface of called
* interface or Object (see comments in RegType::JoinClass).
*/
- const RegType& this_type = work_line_->GetInvocationThis(this, inst, is_range);
+ const RegType& this_type = work_line_->GetInvocationThis(this, inst);
if (this_type.IsZero()) {
/* null pointer always passes (and always fails at runtime) */
} else {
@@ -3057,10 +3072,37 @@
}
case Instruction::INVOKE_POLYMORPHIC:
case Instruction::INVOKE_POLYMORPHIC_RANGE: {
+ bool is_range = (inst->Opcode() == Instruction::INVOKE_POLYMORPHIC_RANGE);
+ ArtMethod* called_method = VerifyInvocationArgs(inst, METHOD_POLYMORPHIC, is_range);
+ if (called_method == nullptr) {
+ // Convert potential soft failures in VerifyInvocationArgs() to hard errors.
+ if (failure_messages_.size() > 0) {
+ std::string message = failure_messages_.back()->str();
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << message;
+ } else {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke-polymorphic verification failure.";
+ }
+ break;
+ }
+ if (!CheckSignaturePolymorphicMethod(called_method) ||
+ !CheckSignaturePolymorphicReceiver(inst)) {
+ break;
+ }
+ const uint32_t proto_idx = (is_range) ? inst->VRegH_4rcc() : inst->VRegH_45cc();
+ const char* descriptor =
+ dex_file_->GetReturnTypeDescriptor(dex_file_->GetProtoId(proto_idx));
+ const RegType& return_type =
+ reg_types_.FromDescriptor(GetClassLoader(), descriptor, false);
+ if (!return_type.IsLowHalf()) {
+ work_line_->SetResultRegisterType(this, return_type);
+ } else {
+ work_line_->SetResultRegisterTypeWide(return_type, return_type.HighHalf(®_types_));
+ }
+ // TODO(oth): remove when compiler support is available.
Fail(VERIFY_ERROR_FORCE_INTERPRETER)
- << "instruction is not supported by verifier; skipping verification";
+ << "invoke-polymorphic is not supported by compiler";
have_pending_experimental_failure_ = true;
- return false;
+ break;
}
case Instruction::NEG_INT:
case Instruction::NOT_INT:
@@ -3416,8 +3458,6 @@
work_line_->SetResultTypeToUnknown(this);
}
-
-
/*
* Handle "branch". Tag the branch target.
*
@@ -3740,7 +3780,8 @@
} else if (method_type == METHOD_SUPER && is_interface) {
return kInterfaceMethodResolution;
} else {
- DCHECK(method_type == METHOD_VIRTUAL || method_type == METHOD_SUPER);
+ DCHECK(method_type == METHOD_VIRTUAL || method_type == METHOD_SUPER
+ || method_type == METHOD_POLYMORPHIC);
return kVirtualMethodResolution;
}
}
@@ -3868,15 +3909,18 @@
return nullptr;
}
// See if the method type implied by the invoke instruction matches the access flags for the
- // target method.
+ // target method. The flags for METHOD_POLYMORPHIC are based on there being precisely two
+ // signature polymorphic methods supported by the run-time which are native methods with variable
+ // arguments.
if ((method_type == METHOD_DIRECT && (!res_method->IsDirect() || res_method->IsStatic())) ||
(method_type == METHOD_STATIC && !res_method->IsStatic()) ||
((method_type == METHOD_SUPER ||
method_type == METHOD_VIRTUAL ||
- method_type == METHOD_INTERFACE) && res_method->IsDirect())
- ) {
+ method_type == METHOD_INTERFACE) && res_method->IsDirect()) ||
+ ((method_type == METHOD_POLYMORPHIC) &&
+ (!res_method->IsNative() || !res_method->IsVarargs()))) {
Fail(VERIFY_ERROR_CLASS_CHANGE) << "invoke type (" << method_type << ") does not match method "
- " type of " << res_method->PrettyMethod();
+ "type of " << res_method->PrettyMethod();
return nullptr;
}
return res_method;
@@ -3888,20 +3932,18 @@
// We use vAA as our expected arg count, rather than res_method->insSize, because we need to
// match the call to the signature. Also, we might be calling through an abstract method
// definition (which doesn't have register count values).
- const size_t expected_args = (is_range) ? inst->VRegA_3rc() : inst->VRegA_35c();
+ const size_t expected_args = inst->VRegA();
/* caught by static verifier */
DCHECK(is_range || expected_args <= 5);
- if (expected_args > code_item_->outs_size_) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args
- << ") exceeds outsSize (" << code_item_->outs_size_ << ")";
- return nullptr;
- }
- uint32_t arg[5];
- if (!is_range) {
- inst->GetVarArgs(arg);
+ // TODO(oth): Enable this path for invoke-polymorphic when b/33099829 is resolved.
+ if (method_type != METHOD_POLYMORPHIC) {
+ if (expected_args > code_item_->outs_size_) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid argument count (" << expected_args
+ << ") exceeds outsSize (" << code_item_->outs_size_ << ")";
+ return nullptr;
+ }
}
- uint32_t sig_registers = 0;
/*
* Check the "this" argument, which must be an instance of the class that declared the method.
@@ -3909,7 +3951,7 @@
* rigorous check here (which is okay since we have to do it at runtime).
*/
if (method_type != METHOD_STATIC) {
- const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst, is_range);
+ const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst);
if (actual_arg_type.IsConflict()) { // GetInvocationThis failed.
CHECK(have_pending_hard_failure_);
return nullptr;
@@ -3945,7 +3987,7 @@
res_method_class = &FromClass(klass->GetDescriptor(&temp), klass,
klass->CannotBeAssignedFromOtherTypes());
} else {
- const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+ const uint32_t method_idx = inst->VRegB();
const dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
res_method_class = ®_types_.FromDescriptor(
GetClassLoader(),
@@ -3965,13 +4007,17 @@
}
}
}
- sig_registers = 1;
}
+ uint32_t arg[5];
+ if (!is_range) {
+ inst->GetVarArgs(arg);
+ }
+ uint32_t sig_registers = (method_type == METHOD_STATIC) ? 0 : 1;
for ( ; it->HasNext(); it->Next()) {
if (sig_registers >= expected_args) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation, expected " << inst->VRegA() <<
- " arguments, found " << sig_registers << " or more.";
+ " argument registers, method signature has " << sig_registers + 1 << " or more";
return nullptr;
}
@@ -3984,7 +4030,7 @@
}
const RegType& reg_type = reg_types_.FromDescriptor(GetClassLoader(), param_descriptor, false);
- uint32_t get_reg = is_range ? inst->VRegC_3rc() + static_cast<uint32_t>(sig_registers) :
+ uint32_t get_reg = is_range ? inst->VRegC() + static_cast<uint32_t>(sig_registers) :
arg[sig_registers];
if (reg_type.IsIntegralTypes()) {
const RegType& src_type = work_line_->GetRegisterType(this, get_reg);
@@ -4020,7 +4066,7 @@
}
if (expected_args != sig_registers) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Rejecting invocation, expected " << expected_args <<
- " arguments, found " << sig_registers;
+ " argument registers, method signature has " << sig_registers;
return nullptr;
}
return res_method;
@@ -4032,11 +4078,10 @@
// As the method may not have been resolved, make this static check against what we expect.
// The main reason for this code block is to fail hard when we find an illegal use, e.g.,
// wrong number of arguments or wrong primitive types, even if the method could not be resolved.
- const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+ const uint32_t method_idx = inst->VRegB();
DexFileParameterIterator it(*dex_file_,
dex_file_->GetProtoId(dex_file_->GetMethodId(method_idx).proto_idx_));
- VerifyInvocationArgsFromIterator<DexFileParameterIterator>(&it, inst, method_type, is_range,
- nullptr);
+ VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, nullptr);
}
class MethodParamListDescriptorIterator {
@@ -4069,8 +4114,7 @@
const Instruction* inst, MethodType method_type, bool is_range) {
// Resolve the method. This could be an abstract or concrete method depending on what sort of call
// we're making.
- const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
-
+ const uint32_t method_idx = inst->VRegB();
ArtMethod* res_method = ResolveMethodAndCheckAccess(method_idx, method_type);
if (res_method == nullptr) { // error or class is unresolved
// Check what we can statically.
@@ -4133,10 +4177,84 @@
}
}
- // Process the target method's signature. This signature may or may not
- MethodParamListDescriptorIterator it(res_method);
- return VerifyInvocationArgsFromIterator<MethodParamListDescriptorIterator>(&it, inst, method_type,
- is_range, res_method);
+ if (method_type == METHOD_POLYMORPHIC) {
+ // Process the signature of the calling site that is invoking the method handle.
+ DexFileParameterIterator it(*dex_file_, dex_file_->GetProtoId(inst->VRegH()));
+ return VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method);
+ } else {
+ // Process the target method's signature.
+ MethodParamListDescriptorIterator it(res_method);
+ return VerifyInvocationArgsFromIterator(&it, inst, method_type, is_range, res_method);
+ }
+}
+
+bool MethodVerifier::CheckSignaturePolymorphicMethod(ArtMethod* method) {
+ mirror::Class* klass = method->GetDeclaringClass();
+ if (klass != mirror::MethodHandle::StaticClass()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+ << "Signature polymorphic method must be declared in java.lang.invoke.MethodClass";
+ return false;
+ }
+
+ const char* method_name = method->GetName();
+ if (strcmp(method_name, "invoke") != 0 && strcmp(method_name, "invokeExact") != 0) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+ << "Signature polymorphic method name invalid: " << method_name;
+ return false;
+ }
+
+ const DexFile::TypeList* types = method->GetParameterTypeList();
+ if (types->Size() != 1) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+ << "Signature polymorphic method has too many arguments " << types->Size() << " != 1";
+ return false;
+ }
+
+ const dex::TypeIndex argument_type_index = types->GetTypeItem(0).type_idx_;
+ const char* argument_descriptor = method->GetTypeDescriptorFromTypeIdx(argument_type_index);
+ if (strcmp(argument_descriptor, "[Ljava/lang/Object;") != 0) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+ << "Signature polymorphic method has unexpected argument type: " << argument_descriptor;
+ return false;
+ }
+
+ const char* return_descriptor = method->GetReturnTypeDescriptor();
+ if (strcmp(return_descriptor, "Ljava/lang/Object;") != 0) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+ << "Signature polymorphic method has unexpected return type: " << return_descriptor;
+ return false;
+ }
+
+ return true;
+}
+
+bool MethodVerifier::CheckSignaturePolymorphicReceiver(const Instruction* inst) {
+ const RegType& this_type = work_line_->GetInvocationThis(this, inst);
+ if (this_type.IsZero()) {
+ /* null pointer always passes (and always fails at run time) */
+ return true;
+ } else if (!this_type.IsNonZeroReferenceTypes()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+ << "invoke-polymorphic receiver is not a reference: "
+ << this_type;
+ return false;
+ } else if (this_type.IsUninitializedReference()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+ << "invoke-polymorphic receiver is uninitialized: "
+ << this_type;
+ return false;
+ } else if (!this_type.HasClass()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+ << "invoke-polymorphic receiver has no class: "
+ << this_type;
+ return false;
+ } else if (!this_type.GetClass()->IsSubClass(mirror::MethodHandle::StaticClass())) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD)
+ << "invoke-polymorphic receiver is not a subclass of MethodHandle: "
+ << this_type;
+ return false;
+ }
+ return true;
}
ArtMethod* MethodVerifier::GetQuickInvokedMethod(const Instruction* inst, RegisterLine* reg_line,
@@ -4146,7 +4264,7 @@
} else {
DCHECK_EQ(inst->Opcode(), Instruction::INVOKE_VIRTUAL_QUICK);
}
- const RegType& actual_arg_type = reg_line->GetInvocationThis(this, inst, is_range, allow_failure);
+ 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;
@@ -4208,7 +4326,7 @@
// We use vAA as our expected arg count, rather than res_method->insSize, because we need to
// match the call to the signature. Also, we might be calling through an abstract method
// definition (which doesn't have register count values).
- const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst, is_range);
+ const RegType& actual_arg_type = work_line_->GetInvocationThis(this, inst);
if (actual_arg_type.IsConflict()) { // GetInvocationThis failed.
return nullptr;
}
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index f3faecd..fa5a698 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -63,7 +63,8 @@
METHOD_STATIC, // static
METHOD_VIRTUAL, // virtual
METHOD_SUPER, // super
- METHOD_INTERFACE // interface
+ METHOD_INTERFACE, // interface
+ METHOD_POLYMORPHIC // polymorphic
};
std::ostream& operator<<(std::ostream& os, const MethodType& rhs);
@@ -474,6 +475,10 @@
// reference isn't for an array class.
bool CheckNewInstance(dex::TypeIndex idx);
+ // Perform static checks on a prototype indexing instruction. All we do here is ensure that the
+ // prototype index is in the valid range.
+ bool CheckPrototypeIndex(uint32_t idx);
+
/* Ensure that the string index is in the valid range. */
bool CheckStringIndex(uint32_t idx);
@@ -512,6 +517,12 @@
// - vA holds word count, vC holds index of first reg.
bool CheckVarArgRangeRegs(uint32_t vA, uint32_t vC);
+ // Checks the method matches the expectations required to be signature polymorphic.
+ bool CheckSignaturePolymorphicMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Checks the invoked receiver matches the expectations for signature polymorphic methods.
+ bool CheckSignaturePolymorphicReceiver(const Instruction* inst) REQUIRES_SHARED(Locks::mutator_lock_);
+
// Extract the relative offset from a branch instruction.
// Returns "false" on failure (e.g. this isn't a branch instruction).
bool GetBranchOffset(uint32_t cur_offset, int32_t* pOffset, bool* pConditional,
diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc
index da3d946..a6088aa 100644
--- a/runtime/verifier/register_line.cc
+++ b/runtime/verifier/register_line.cc
@@ -44,8 +44,9 @@
}
const RegType& RegisterLine::GetInvocationThis(MethodVerifier* verifier, const Instruction* inst,
- bool is_range, bool allow_failure) {
- const size_t args_count = is_range ? inst->VRegA_3rc() : inst->VRegA_35c();
+ bool allow_failure) {
+ DCHECK(inst->IsInvoke());
+ const size_t args_count = inst->VRegA();
if (args_count < 1) {
if (!allow_failure) {
verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invoke lacks 'this'";
@@ -53,7 +54,7 @@
return verifier->GetRegTypeCache()->Conflict();
}
/* Get the element type of the array held in vsrc */
- const uint32_t this_reg = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
+ const uint32_t this_reg = inst->VRegC();
const RegType& this_type = GetRegisterType(verifier, this_reg);
if (!this_type.IsReferenceTypes()) {
if (!allow_failure) {
diff --git a/runtime/verifier/register_line.h b/runtime/verifier/register_line.h
index 7603a79..221aa80 100644
--- a/runtime/verifier/register_line.h
+++ b/runtime/verifier/register_line.h
@@ -217,7 +217,6 @@
*/
const RegType& GetInvocationThis(MethodVerifier* verifier,
const Instruction* inst,
- bool is_range,
bool allow_failure = false)
REQUIRES_SHARED(Locks::mutator_lock_);