Merge "Tests should include exception stack traces on failure." into dalvik-dev
diff --git a/Android.mk b/Android.mk
index eda1e33..df2b843 100644
--- a/Android.mk
+++ b/Android.mk
@@ -155,7 +155,6 @@
$(eval $(call build-art-cache-oat,system/app/ContactsProvider.apk))
$(eval $(call build-art-cache-oat,system/app/DefaultContainerService.apk))
$(eval $(call build-art-cache-oat,system/app/DeskClockGoogle.apk))
-$(eval $(call build-art-cache-oat,system/app/Development.apk))
$(eval $(call build-art-cache-oat,system/app/DownloadProvider.apk))
$(eval $(call build-art-cache-oat,system/app/DownloadProviderUi.apk))
$(eval $(call build-art-cache-oat,system/app/DrmProvider.apk))
@@ -193,7 +192,6 @@
$(eval $(call build-art-cache-oat,system/app/Music2.apk))
$(eval $(call build-art-cache-oat,system/app/MusicFX.apk))
$(eval $(call build-art-cache-oat,system/app/MyVerizon.apk))
-$(eval $(call build-art-cache-oat,system/app/NetSpeed.apk))
$(eval $(call build-art-cache-oat,system/app/NetworkLocation.apk))
$(eval $(call build-art-cache-oat,system/app/Nfc.apk))
$(eval $(call build-art-cache-oat,system/app/OneTimeInitializer.apk))
@@ -208,10 +206,7 @@
$(eval $(call build-art-cache-oat,system/app/SetupWizard.apk))
$(eval $(call build-art-cache-oat,system/app/SharedStorageBackup.apk))
$(eval $(call build-art-cache-oat,system/app/SoundRecorder.apk))
-$(eval $(call build-art-cache-oat,system/app/SpeechRecorder.apk))
$(eval $(call build-art-cache-oat,system/app/SPG.apk))
-$(eval $(call build-art-cache-oat,system/app/StingrayProgramMenu.apk))
-$(eval $(call build-art-cache-oat,system/app/StingrayProgramMenuSystem.apk))
$(eval $(call build-art-cache-oat,system/app/Stk.apk))
$(eval $(call build-art-cache-oat,system/app/Street.apk))
$(eval $(call build-art-cache-oat,system/app/SyncMLSvc.apk))
@@ -250,6 +245,10 @@
$(eval $(call build-art-cache-oat,system/framework/send_bug.jar))
$(eval $(call build-art-cache-oat,system/framework/svc.jar))
+ifeq ($(TARGET_BUILD_VARIANT),eng)
+ $(eval $(call build-art-cache-oat,system/app/Development.apk))
+endif
+
else
ifeq ($(TARGET_PRODUCT),$(filter $(TARGET_PRODUCT),soju sojus))
@@ -270,7 +269,6 @@
$(eval $(call build-art-cache-oat,system/app/ContactsProvider.apk))
$(eval $(call build-art-cache-oat,system/app/DefaultContainerService.apk))
$(eval $(call build-art-cache-oat,system/app/DeskClockGoogle.apk))
-$(eval $(call build-art-cache-oat,system/app/Development.apk))
$(eval $(call build-art-cache-oat,system/app/DownloadProvider.apk))
$(eval $(call build-art-cache-oat,system/app/DownloadProviderUi.apk))
$(eval $(call build-art-cache-oat,system/app/DrmProvider.apk))
@@ -306,7 +304,6 @@
$(eval $(call build-art-cache-oat,system/app/Mms.apk))
$(eval $(call build-art-cache-oat,system/app/Music2.apk))
$(eval $(call build-art-cache-oat,system/app/MusicFX.apk))
-$(eval $(call build-art-cache-oat,system/app/NetSpeed.apk))
$(eval $(call build-art-cache-oat,system/app/NetworkLocation.apk))
$(eval $(call build-art-cache-oat,system/app/Nfc.apk))
$(eval $(call build-art-cache-oat,system/app/OneTimeInitializer.apk))
@@ -319,9 +316,6 @@
$(eval $(call build-art-cache-oat,system/app/SetupWizard.apk))
$(eval $(call build-art-cache-oat,system/app/SharedStorageBackup.apk))
$(eval $(call build-art-cache-oat,system/app/SoundRecorder.apk))
-$(eval $(call build-art-cache-oat,system/app/SpeechRecorder.apk))
-$(eval $(call build-art-cache-oat,system/app/StingrayProgramMenu.apk))
-$(eval $(call build-art-cache-oat,system/app/StingrayProgramMenuSystem.apk))
$(eval $(call build-art-cache-oat,system/app/Street.apk))
$(eval $(call build-art-cache-oat,system/app/SystemUI.apk))
$(eval $(call build-art-cache-oat,system/app/TagGoogle.apk))
@@ -355,6 +349,10 @@
$(eval $(call build-art-cache-oat,system/framework/send_bug.jar))
$(eval $(call build-art-cache-oat,system/framework/svc.jar))
+ifeq ($(TARGET_BUILD_VARIANT),eng)
+ $(eval $(call build-art-cache-oat,system/app/Development.apk))
+endif
+
else
ifeq ($(TARGET_PRODUCT),$(filter $(TARGET_PRODUCT),stingray))
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 51e5f3c..f343ed4 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1924,6 +1924,7 @@
const DexFile& dex_file = FindDexFile(klass->GetDexCache());
if (VerifyClassUsingOatFile(dex_file, klass) ||
verifier::DexVerifier::VerifyClass(klass, error_msg)) {
+ DCHECK(!Thread::Current()->IsExceptionPending());
// Make sure all classes referenced by catch blocks are resolved
ResolveClassExceptionHandlerTypes(dex_file, klass);
klass->SetStatus(Class::kStatusVerified);
@@ -1934,7 +1935,7 @@
<< " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8()
<< " because: " << error_msg;
Thread* self = Thread::Current();
- CHECK(!self->IsExceptionPending()) << self->GetException()->Dump();
+ CHECK(!self->IsExceptionPending());
self->ThrowNewException("Ljava/lang/VerifyError;", error_msg.c_str());
CHECK_EQ(klass->GetStatus(), Class::kStatusVerifying) << PrettyDescriptor(klass);
klass->SetStatus(Class::kStatusError);
@@ -1961,17 +1962,34 @@
UniquePtr<const OatFile::OatClass> oat_class(oat_dex_file->GetOatClass(class_def_index));
CHECK(oat_class.get() != NULL) << descriptor;
Class::Status status = oat_class->GetStatus();
- if (status == Class::kStatusError) {
- Thread* self = Thread::Current();
- self->ThrowNewExceptionF("Ljava/lang/VerifyError;", "Compile-time verification of %s failed",
- PrettyDescriptor(klass).c_str());
- klass->SetStatus(Class::kStatusError);
- return true;
- }
if (status == Class::kStatusVerified || status == Class::kStatusInitialized) {
return true;
}
+ if (status == Class::kStatusError) {
+ // Compile time verification failed. Compile time verification can fail because we have
+ // incomplete type information. Consider the following:
+ // class ... {
+ // Foo x;
+ // .... () {
+ // if (...) {
+ // v1 gets assigned a type of resolved class Foo
+ // } else {
+ // v1 gets assigned a type of unresolved class Bar
+ // }
+ // iput x = v1
+ // } }
+ // when we merge v1 following the if-the-else it results in Conflict
+ // (see verifier::RegType::Merge) as we can't know the type of Bar and we could possibly be
+ // allowing an unsafe assignment to the field x in the iput (javac may have compiled this as
+ // it knew Bar was a sub-class of Foo, but for us this may have been moved into a separate apk
+ // at compile time).
+ return false;
+ }
if (status == Class::kStatusNotReady) {
+ // Status is uninitialized if we couldn't determine the status at compile time, for example,
+ // not loading the class.
+ // TODO: when the verifier doesn't rely on Class-es failing to resolve/load the type hierarchy
+ // isn't a problem and this case shouldn't occur
return false;
}
LOG(FATAL) << "Unexpected class status: " << status;
diff --git a/src/dalvik_system_VMRuntime.cc b/src/dalvik_system_VMRuntime.cc
index 5dcbb41..76da622 100644
--- a/src/dalvik_system_VMRuntime.cc
+++ b/src/dalvik_system_VMRuntime.cc
@@ -98,12 +98,21 @@
return toStringArray(env, Runtime::Current()->GetProperties());
}
+// This is for backward compatibility with dalvik which returned the
+// meaningless "." when no boot classpath or classpath was
+// specified. Unfortunately, some tests were using java.class.path to
+// lookup relative file locations, so they are counting on this to be
+// ".", presumably some applications or libraries could have as well.
+const char* DefaultToDot(const std::string& class_path) {
+ return class_path.empty() ? "." : class_path.c_str();
+}
+
jstring VMRuntime_bootClassPath(JNIEnv* env, jobject) {
- return env->NewStringUTF(Runtime::Current()->GetBootClassPath().c_str());
+ return env->NewStringUTF(DefaultToDot(Runtime::Current()->GetBootClassPath()));
}
jstring VMRuntime_classPath(JNIEnv* env, jobject) {
- return env->NewStringUTF(Runtime::Current()->GetClassPath().c_str());
+ return env->NewStringUTF(DefaultToDot(Runtime::Current()->GetClassPath()));
}
jstring VMRuntime_vmVersion(JNIEnv* env, jobject) {
diff --git a/src/dex_instruction.h b/src/dex_instruction.h
index 26e5653..975ec86 100644
--- a/src/dex_instruction.h
+++ b/src/dex_instruction.h
@@ -195,7 +195,7 @@
int GetVerifyTypeArgumentC() const {
return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegC | kVerifyRegCField |
- kVerifyRegCNewArray | kVerifyRegBType | kVerifyRegBWide));
+ kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide));
}
int GetVerifyExtraFlags() const {
diff --git a/src/dex_verifier.cc b/src/dex_verifier.cc
index c03b724..584bddd 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 << ")";
}
}
}
@@ -3060,17 +3038,17 @@
common_super = ®_types_.JavaLangThrowable();
} else {
const RegType& exception = ResolveClassAndCheckAccess(iterator.GetHandlerTypeIndex());
- /* TODO: on error do we want to keep going? If we don't fail this we run the risk of
- * having a non-Throwable introduced at runtime. However, that won't pass an instanceof
- * test, so is essentially harmless.
- */
- if(!reg_types_.JavaLangThrowable().IsAssignableFrom(exception)) {
+ if (common_super == NULL) {
+ // Unconditionally assign for the first handler. We don't assert this is a Throwable
+ // as that is caught at runtime
+ common_super = &exception;
+ } else if(!reg_types_.JavaLangThrowable().IsAssignableFrom(exception)) {
+ // We don't know enough about the type and the common path merge will result in
+ // Conflict. Fail here knowing the correct thing can be done at runtime.
Fail(VERIFY_ERROR_GENERIC) << "unexpected non-exception class " << exception;
return reg_types_.Unknown();
- } else if (common_super == NULL) {
- common_super = &exception;
} else if (common_super->Equals(exception)) {
- // nothing to do
+ // odd case, but nothing to do
} else {
common_super = &common_super->Merge(exception, ®_types_);
CHECK(reg_types_.JavaLangThrowable().IsAssignableFrom(*common_super));
@@ -3084,6 +3062,7 @@
if (common_super == NULL) {
/* no catch blocks, or no catches with classes we can find */
Fail(VERIFY_ERROR_GENERIC) << "unable to find exception handler";
+ return reg_types_.Unknown();
}
return *common_super;
}
@@ -3284,45 +3263,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 if (!array_type.IsArrayTypes()) {
+ Fail(VERIFY_ERROR_GENERIC) << "not array type " << array_type << " with aget";
+ } else {
+ /* verify the class */
+ const RegType& component_type = reg_types_.GetComponentType(array_type,
+ method_->GetDeclaringClass()->GetClassLoader());
+ 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 +3307,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 if (!array_type.IsArrayTypes()) {
+ Fail(VERIFY_ERROR_GENERIC) << "not array type " << array_type << " with aput";
+ } else {
+ /* verify the class */
+ const RegType& component_type = reg_types_.GetComponentType(array_type,
+ method_->GetDeclaringClass()->GetClassLoader());
+ 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 +3570,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..b5325ff 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.
*/
@@ -1139,9 +1161,8 @@
/*
* For the "move-exception" instruction at "work_insn_idx_", which must be at an exception handler
- * address, determine the first common superclass of all exceptions that can land here.
- * Returns NULL if no matching exception handler can be found, or if the exception is not a
- * subclass of Throwable.
+ * address, determine the Join of all exceptions that can land here. Fails if no matching
+ * exception handler can be found or if the Join of exception types fails.
*/
const RegType& GetCaughtExceptionType();
diff --git a/src/runtime.cc b/src/runtime.cc
index 726b30c..306bb87 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -109,6 +109,10 @@
}
gAborting = true;
os << "Runtime aborting...\n";
+ if (Runtime::Current() == NULL) {
+ os << "(Runtime does not yet exist!)\n";
+ return;
+ }
Thread* self = Thread::Current();
if (self == NULL) {
os << "(Aborting thread was not attached to runtime!)\n";
@@ -259,14 +263,10 @@
const char* boot_class_path = getenv("BOOTCLASSPATH");
if (boot_class_path != NULL) {
parsed->boot_class_path_ = boot_class_path;
- } else {
- parsed->boot_class_path_ = ".";
}
const char* class_path = getenv("CLASSPATH");
if (class_path != NULL) {
parsed->class_path_ = class_path;
- } else {
- parsed->class_path_ = ".";
}
#ifdef NDEBUG
// -Xcheck:jni is off by default for regular builds...