Merge "Remove legacy notion of GetClassFromRegister" into dalvik-dev
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index c03b724..c422066 100644
--- a/src/dex_verifier.cc
+++ b/src/dex_verifier.cc
@@ -210,7 +210,7 @@
} else if (!IsUnresolvedTypes() && GetClass()->IsInterface()) {
return true; // We allow assignment to any interface, see comment in ClassJoin
} else if (IsJavaLangObjectArray()) {
- return src.IsObjectArray(); // All reference arrays may be assigned to Object[]
+ return src.IsObjectArrayTypes(); // All reference arrays may be assigned to Object[]
} else if (!IsUnresolvedTypes() && !src.IsUnresolvedTypes() &&
GetClass()->IsAssignableFrom(src.GetClass())) {
// We're assignable from the Class point-of-view
@@ -553,7 +553,7 @@
}
const RegType& RegTypeCache::GetComponentType(const RegType& array, const ClassLoader* loader) {
- CHECK(array.IsArrayClass());
+ CHECK(array.IsArrayTypes());
if (array.IsUnresolvedTypes()) {
std::string descriptor(array.GetDescriptor()->ToModifiedUtf8());
std::string component(descriptor.substr(1, descriptor.size() - 1));
@@ -629,24 +629,6 @@
return this_type;
}
-Class* RegisterLine::GetClassFromRegister(uint32_t vsrc) const {
- /* get the element type of the array held in vsrc */
- const RegType& type = GetRegisterType(vsrc);
- /* if "always zero", we allow it to fail at runtime */
- if (type.IsZero()) {
- return NULL;
- } else if (!type.IsReferenceTypes()) {
- verifier_->Fail(VERIFY_ERROR_GENERIC) << "tried to get class from non-ref register v" << vsrc
- << " (type=" << type << ")";
- return NULL;
- } else if (type.IsUninitializedReference()) {
- verifier_->Fail(VERIFY_ERROR_GENERIC) << "register " << vsrc << " holds uninitialized reference";
- return NULL;
- } else {
- return type.GetClass();
- }
-}
-
bool RegisterLine::VerifyRegisterType(uint32_t vsrc, const RegType& check_type) {
// Verify the src register type against the check type refining the type of the register
const RegType& src_type = GetRegisterType(vsrc);
@@ -2119,7 +2101,7 @@
case Instruction::ARRAY_LENGTH: {
const RegType& res_type = work_line_->GetRegisterType(dec_insn.vB_);
if (res_type.IsReferenceTypes()) {
- if (!res_type.IsArrayClass() && !res_type.IsZero()) { // ie not an array or null
+ if (!res_type.IsArrayTypes() && !res_type.IsZero()) { // ie not an array or null
Fail(VERIFY_ERROR_GENERIC) << "array-length on non-array " << res_type;
} else {
work_line_->SetRegisterType(dec_insn.vA_, reg_types_.Integer());
@@ -2147,7 +2129,7 @@
case Instruction::NEW_ARRAY: {
const RegType& res_type = ResolveClassAndCheckAccess(dec_insn.vC_);
// TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
- if (!res_type.IsArrayClass()) {
+ if (!res_type.IsArrayTypes()) {
Fail(VERIFY_ERROR_GENERIC) << "new-array on non-array class " << res_type;
} else {
/* make sure "size" register is valid type */
@@ -2161,7 +2143,7 @@
case Instruction::FILLED_NEW_ARRAY_RANGE: {
const RegType& res_type = ResolveClassAndCheckAccess(dec_insn.vB_);
// TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
- if (!res_type.IsArrayClass()) {
+ if (!res_type.IsArrayTypes()) {
Fail(VERIFY_ERROR_GENERIC) << "filled-new-array on non-array class";
} else {
bool is_range = (dec_insn.opcode_ == Instruction::FILLED_NEW_ARRAY_RANGE);
@@ -2211,31 +2193,27 @@
case Instruction::FILL_ARRAY_DATA: {
/* Similar to the verification done for APUT */
- Class* res_class = work_line_->GetClassFromRegister(dec_insn.vA_);
- if (failure_ == VERIFY_ERROR_NONE) {
- /* res_class can be null if the reg type is Zero */
- if (res_class != NULL) {
- Class* component_type = res_class->GetComponentType();
- if (!res_class->IsArrayClass() || !component_type->IsPrimitive() ||
- component_type->IsPrimitiveVoid()) {
- Fail(VERIFY_ERROR_GENERIC) << "invalid fill-array-data on "
- << PrettyDescriptor(res_class);
+ const RegType& array_type = work_line_->GetRegisterType(dec_insn.vA_);
+ /* array_type can be null if the reg type is Zero */
+ if (!array_type.IsZero()) {
+ const RegType& component_type = reg_types_.GetComponentType(array_type,
+ method_->GetDeclaringClass()->GetClassLoader());
+ DCHECK(!component_type.IsUnknown());
+ if (!array_type.IsArrayTypes() || component_type.IsNonZeroReferenceTypes()) {
+ Fail(VERIFY_ERROR_GENERIC) << "invalid fill-array-data on " << array_type;
+ } else {
+ // Now verify if the element width in the table matches the element width declared in
+ // the array
+ const uint16_t* array_data = insns + (insns[1] | (((int32_t) insns[2]) << 16));
+ if (array_data[0] != Instruction::kArrayDataSignature) {
+ Fail(VERIFY_ERROR_GENERIC) << "invalid magic for array-data";
} else {
- const RegType& value_type = reg_types_.FromClass(component_type);
- DCHECK(!value_type.IsUnknown());
- // Now verify if the element width in the table matches the element width declared in
- // the array
- const uint16_t* array_data = insns + (insns[1] | (((int32_t) insns[2]) << 16));
- if (array_data[0] != Instruction::kArrayDataSignature) {
- Fail(VERIFY_ERROR_GENERIC) << "invalid magic for array-data";
- } else {
- size_t elem_width = Primitive::ComponentSize(component_type->GetPrimitiveType());
- // Since we don't compress the data in Dex, expect to see equal width of data stored
- // in the table and expected from the array class.
- if (array_data[1] != elem_width) {
- Fail(VERIFY_ERROR_GENERIC) << "array-data size mismatch (" << array_data[1]
- << " vs " << elem_width << ")";
- }
+ size_t elem_width = Primitive::ComponentSize(component_type.GetPrimitiveType());
+ // Since we don't compress the data in Dex, expect to see equal width of data stored
+ // in the table and expected from the array class.
+ if (array_data[1] != elem_width) {
+ Fail(VERIFY_ERROR_GENERIC) << "array-data size mismatch (" << array_data[1]
+ << " vs " << elem_width << ")";
}
}
}
@@ -3284,45 +3262,39 @@
if (!index_type.IsArrayIndexTypes()) {
Fail(VERIFY_ERROR_GENERIC) << "Invalid reg type for array index (" << index_type << ")";
} else {
- Class* array_class = work_line_->GetClassFromRegister(dec_insn.vB_);
- if (failure_ == VERIFY_ERROR_NONE) {
- if (array_class == NULL) {
- // Null array class; this code path will fail at runtime. Infer a merge-able type from the
- // instruction type. TODO: have a proper notion of bottom here.
- if (!is_primitive || insn_type.IsCategory1Types()) {
- // Reference or category 1
- work_line_->SetRegisterType(dec_insn.vA_, reg_types_.Zero());
- } else {
- // Category 2
- work_line_->SetRegisterType(dec_insn.vA_, reg_types_.ConstLo());
- }
+ const RegType& array_type = work_line_->GetRegisterType(dec_insn.vB_);
+ if (array_type.IsZero()) {
+ // Null array class; this code path will fail at runtime. Infer a merge-able type from the
+ // instruction type. TODO: have a proper notion of bottom here.
+ if (!is_primitive || insn_type.IsCategory1Types()) {
+ // Reference or category 1
+ work_line_->SetRegisterType(dec_insn.vA_, reg_types_.Zero());
} else {
- /* verify the class */
- Class* component_class = array_class->GetComponentType();
- const RegType& component_type = reg_types_.FromClass(component_class);
- if (!array_class->IsArrayClass()) {
- Fail(VERIFY_ERROR_GENERIC) << "not array type "
- << PrettyDescriptor(array_class) << " with aget";
- } else if (component_class->IsPrimitive() && !is_primitive) {
- Fail(VERIFY_ERROR_GENERIC) << "primitive array type "
- << PrettyDescriptor(array_class)
- << " source for aget-object";
- } else if (!component_class->IsPrimitive() && is_primitive) {
- Fail(VERIFY_ERROR_GENERIC) << "reference array type "
- << PrettyDescriptor(array_class)
- << " 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_GENERIC) << "array type "
- << PrettyDescriptor(array_class)
+ // Category 2
+ work_line_->SetRegisterType(dec_insn.vA_, reg_types_.ConstLo());
+ }
+ } else {
+ /* verify the class */
+ const RegType& component_type = reg_types_.GetComponentType(array_type,
+ method_->GetDeclaringClass()->GetClassLoader());
+ if (!array_type.IsArrayTypes()) {
+ Fail(VERIFY_ERROR_GENERIC) << "not array type " << array_type << " with aget";
+ } else if (!component_type.IsReferenceTypes() && !is_primitive) {
+ Fail(VERIFY_ERROR_GENERIC) << "primitive array type " << array_type
+ << " source for aget-object";
+ } else if (component_type.IsNonZeroReferenceTypes() && is_primitive) {
+ Fail(VERIFY_ERROR_GENERIC) << "reference array type " << array_type
+ << " 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_GENERIC) << "array type " << array_type
<< " incompatible with aget of type " << insn_type;
- } else {
+ } 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.
work_line_->SetRegisterType(dec_insn.vA_, component_type);
- }
}
}
}
@@ -3334,38 +3306,32 @@
if (!index_type.IsArrayIndexTypes()) {
Fail(VERIFY_ERROR_GENERIC) << "Invalid reg type for array index (" << index_type << ")";
} else {
- Class* array_class = work_line_->GetClassFromRegister(dec_insn.vB_);
- if (failure_ == VERIFY_ERROR_NONE) {
- if (array_class == NULL) {
- // Null array class; this code path will fail at runtime. Infer a merge-able type from the
- // instruction type.
+ const RegType& array_type = work_line_->GetRegisterType(dec_insn.vB_);
+ if (array_type.IsZero()) {
+ // Null array type; this code path will fail at runtime. Infer a merge-able type from the
+ // instruction type.
+ } else {
+ /* verify the class */
+ const RegType& component_type = reg_types_.GetComponentType(array_type,
+ method_->GetDeclaringClass()->GetClassLoader());
+ if (!array_type.IsArrayTypes()) {
+ Fail(VERIFY_ERROR_GENERIC) << "not array type " << array_type << " with aput";
+ } else if (!component_type.IsReferenceTypes() && !is_primitive) {
+ Fail(VERIFY_ERROR_GENERIC) << "primitive array type " << array_type
+ << " source for aput-object";
+ } else if (component_type.IsNonZeroReferenceTypes() && is_primitive) {
+ Fail(VERIFY_ERROR_GENERIC) << "reference array type " << array_type
+ << " source for category 1 aput";
+ } else if (is_primitive && !insn_type.Equals(component_type) &&
+ !((insn_type.IsInteger() && component_type.IsFloat()) ||
+ (insn_type.IsLong() && component_type.IsDouble()))) {
+ Fail(VERIFY_ERROR_GENERIC) << "array type " << array_type
+ << " incompatible with aput of type " << insn_type;
} else {
- /* verify the class */
- Class* component_class = array_class->GetComponentType();
- const RegType& component_type = reg_types_.FromClass(component_class);
- if (!array_class->IsArrayClass()) {
- Fail(VERIFY_ERROR_GENERIC) << "not array type "
- << PrettyDescriptor(array_class) << " with aput";
- } else if (component_class->IsPrimitive() && !is_primitive) {
- Fail(VERIFY_ERROR_GENERIC) << "primitive array type "
- << PrettyDescriptor(array_class)
- << " source for aput-object";
- } else if (!component_class->IsPrimitive() && is_primitive) {
- Fail(VERIFY_ERROR_GENERIC) << "reference array type "
- << PrettyDescriptor(array_class)
- << " source for category 1 aput";
- } else if (is_primitive && !insn_type.Equals(component_type) &&
- !((insn_type.IsInteger() && component_type.IsFloat()) ||
- (insn_type.IsLong() && component_type.IsDouble()))) {
- Fail(VERIFY_ERROR_GENERIC) << "array type "
- << PrettyDescriptor(array_class)
- << " incompatible with aput of type " << insn_type;
- } else {
- // The instruction agrees with the type of array, confirm the value to be stored does too
- // Note: we use the instruction type (rather than the component type) for aput-object as
- // incompatible classes will be caught at runtime as an array store exception
- work_line_->VerifyRegisterType(dec_insn.vA_, is_primitive ? component_type : insn_type);
- }
+ // The instruction agrees with the type of array, confirm the value to be stored does too
+ // Note: we use the instruction type (rather than the component type) for aput-object as
+ // incompatible classes will be caught at runtime as an array store exception
+ work_line_->VerifyRegisterType(dec_insn.vA_, is_primitive ? component_type : insn_type);
}
}
}
@@ -3603,7 +3569,7 @@
void DexVerifier::VerifyFilledNewArrayRegs(const Instruction::DecodedInstruction& dec_insn,
const RegType& res_type, bool is_range) {
- DCHECK(res_type.IsArrayClass()) << res_type; // Checked before calling.
+ DCHECK(res_type.IsArrayTypes()) << res_type; // Checked before calling.
/*
* Verify each register. If "arg_count" is bad, VerifyRegisterType() will run off the end of the
* list and fail. It's legal, if silly, for arg_count to be zero.
diff --git a/src/dex_verifier.h b/src/dex_verifier.h
index 032e777..1537cbf 100644
--- a/src/dex_verifier.h
+++ b/src/dex_verifier.h
@@ -212,34 +212,8 @@
bool IsJavaLangObject() const {
return IsReference() && GetClass()->IsObjectClass();
}
- bool IsObjectArray() const {
- if (IsReference()) {
- Class* type = GetClass();
- return type->IsArrayClass() && !type->GetComponentType()->IsPrimitive();
- } else if (IsUnresolvedTypes()) {
- // Primitive arrays will always resolve
- DCHECK(GetDescriptor()->CharAt(1) == 'L' || GetDescriptor()->CharAt(1) == '[');
- return GetDescriptor()->CharAt(0) == '[';
- }
- return false;
- }
- bool IsJavaLangObjectArray() const {
- if (IsReference()) {
- Class* type = GetClass();
- return type->IsArrayClass() && type->GetComponentType()->IsObjectClass();
- }
- return false;
- }
- bool IsInstantiableTypes() const {
- return IsUnresolvedTypes() || (IsNonZeroReferenceTypes() && GetClass()->IsInstantiable());
- }
- String* GetDescriptor() const {
- DCHECK(IsUnresolvedTypes());
- DCHECK(klass_or_descriptor_ != NULL);
- DCHECK(klass_or_descriptor_->GetClass()->IsStringClass());
- return down_cast<String*>(klass_or_descriptor_);
- }
- bool IsArrayClass() const {
+
+ bool IsArrayTypes() const {
if (IsUnresolvedTypes()) {
return GetDescriptor()->CharAt(0) == '[';
} else if (!IsConstant()) {
@@ -249,6 +223,61 @@
}
}
+ bool IsObjectArrayTypes() const {
+ if (IsUnresolvedTypes()) {
+ // Primitive arrays will always resolve
+ DCHECK(GetDescriptor()->CharAt(1) == 'L' || GetDescriptor()->CharAt(1) == '[');
+ return GetDescriptor()->CharAt(0) == '[';
+ } else if (!IsConstant()) {
+ Class* type = GetClass();
+ return type->IsArrayClass() && !type->GetComponentType()->IsPrimitive();
+ } else {
+ return false;
+ }
+ }
+
+ Primitive::Type GetPrimitiveType() const {
+ if (IsNonZeroReferenceTypes()) {
+ return Primitive::kPrimNot;
+ } else if (IsBooleanTypes()) {
+ return Primitive::kPrimBoolean;
+ } else if (IsByteTypes()) {
+ return Primitive::kPrimByte;
+ } else if (IsShortTypes()) {
+ return Primitive::kPrimShort;
+ } else if (IsCharTypes()) {
+ return Primitive::kPrimChar;
+ } else if (IsFloat()) {
+ return Primitive::kPrimFloat;
+ } else if (IsIntegralTypes()) {
+ return Primitive::kPrimInt;
+ } else if (IsDouble()) {
+ return Primitive::kPrimDouble;
+ } else {
+ DCHECK(IsLongTypes());
+ return Primitive::kPrimLong;
+ }
+ }
+
+ bool IsJavaLangObjectArray() const {
+ if (IsReference()) {
+ Class* type = GetClass();
+ return type->IsArrayClass() && type->GetComponentType()->IsObjectClass();
+ }
+ return false;
+ }
+
+ bool IsInstantiableTypes() const {
+ return IsUnresolvedTypes() || (IsNonZeroReferenceTypes() && GetClass()->IsInstantiable());
+ }
+
+ String* GetDescriptor() const {
+ DCHECK(IsUnresolvedTypes());
+ DCHECK(klass_or_descriptor_ != NULL);
+ DCHECK(klass_or_descriptor_->GetClass()->IsStringClass());
+ return down_cast<String*>(klass_or_descriptor_);
+ }
+
uint16_t GetId() const {
return cache_id_;
}
@@ -668,13 +697,6 @@
const RegType& GetInvocationThis(const Instruction::DecodedInstruction& dec_insn);
/*
- * Get the value from a register, and cast it to a Class. Sets "*failure" if something fails.
- * This fails if the register holds an uninitialized class.
- * If the register holds kRegTypeZero, this returns a NULL pointer.
- */
- Class* GetClassFromRegister(uint32_t vsrc) const;
-
- /*
* Verify types for a simple two-register instruction (e.g. "neg-int").
* "dst_type" is stored into vA, and "src_type" is verified against vB.
*/