Merge "Fix FOUR_ARG_DOWNCALL assembly stubs on arm and x86." into nyc-dev
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index b65e98a..f0c4eaf 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -1154,7 +1154,11 @@
loop->IsDefinedOutOfTheLoop(array_get->InputAt(1))) {
SideEffects loop_effects = side_effects_.GetLoopEffects(loop->GetHeader());
if (!array_get->GetSideEffects().MayDependOn(loop_effects)) {
- HoistToPreHeaderOrDeoptBlock(loop, array_get);
+ // We can hoist ArrayGet only if its execution is guaranteed on every iteration.
+ // In other words only if array_get_bb dominates all back branches.
+ if (loop->DominatesAllBackEdges(array_get->GetBlock())) {
+ HoistToPreHeaderOrDeoptBlock(loop, array_get);
+ }
}
}
}
@@ -1379,13 +1383,7 @@
}
// Does the current basic block dominate all back edges? If not,
// don't apply dynamic bce to something that may not be executed.
- for (HBasicBlock* back_edge : loop->GetBackEdges()) {
- if (!block->Dominates(back_edge)) {
- return false;
- }
- }
- // Success!
- return true;
+ return loop->DominatesAllBackEdges(block);
}
return false;
}
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 60329cc..f4d3842 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -734,6 +734,15 @@
return false;
}
+bool HLoopInformation::DominatesAllBackEdges(HBasicBlock* block) {
+ for (HBasicBlock* back_edge : GetBackEdges()) {
+ if (!block->Dominates(back_edge)) {
+ return false;
+ }
+ }
+ return true;
+}
+
bool HBasicBlock::Dominates(HBasicBlock* other) const {
// Walk up the dominator tree from `other`, to find out if `this`
// is an ancestor.
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 6960ceb..f3915a2 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -733,6 +733,8 @@
return blocks_.GetHighestBitSet() != -1;
}
+ bool DominatesAllBackEdges(HBasicBlock* block);
+
private:
// Internal recursive implementation of `Populate`.
void PopulateRecursive(HBasicBlock* block);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 0e0a30b..c9a4bfe 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -696,6 +696,16 @@
graph->SetArtMethod(method);
ScopedObjectAccess soa(Thread::Current());
interpreter_metadata = method->GetQuickenedInfo();
+ uint16_t type_index = method->GetDeclaringClass()->GetDexTypeIndex();
+
+ // Update the dex cache if the type is not in it yet. Note that under AOT,
+ // the verifier must have set it, but under JIT, there's no guarantee, as we
+ // don't necessarily run the verifier.
+ // The compiler and the compiler driver assume the compiling class is
+ // in the dex cache.
+ if (dex_cache->GetResolvedType(type_index) == nullptr) {
+ dex_cache->SetResolvedType(type_index, method->GetDeclaringClass());
+ }
}
std::unique_ptr<CodeGenerator> codegen(
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 5d4bca1..86fef28 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -641,6 +641,12 @@
REQUIRES(!Locks::classlinker_classes_lock_)
SHARED_REQUIRES(Locks::mutator_lock_);
+ // Throw the class initialization failure recorded when first trying to initialize the given
+ // class.
+ void ThrowEarlierClassFailure(mirror::Class* c, bool wrap_in_no_class_def = false)
+ SHARED_REQUIRES(Locks::mutator_lock_)
+ REQUIRES(!dex_lock_);
+
struct DexCacheData {
// Weak root to the DexCache. Note: Do not decode this unnecessarily or else class unloading may
// not work properly.
@@ -1057,12 +1063,6 @@
// Return the quick generic JNI stub for testing.
const void* GetRuntimeQuickGenericJniStub() const;
- // Throw the class initialization failure recorded when first trying to initialize the given
- // class.
- void ThrowEarlierClassFailure(mirror::Class* c, bool wrap_in_no_class_def = false)
- SHARED_REQUIRES(Locks::mutator_lock_)
- REQUIRES(!dex_lock_);
-
bool CanWeInitializeClass(mirror::Class* klass, bool can_init_statics, bool can_init_parents)
SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 1515630..6f735aa 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -41,6 +41,23 @@
if (c != nullptr && c->IsResolved()) {
return soa.AddLocalReference<jclass>(c);
}
+ // If class is erroneous, throw the earlier failure, wrapped in certain cases. See b/28787733.
+ if (c != nullptr && c->IsErroneous()) {
+ cl->ThrowEarlierClassFailure(c);
+ Thread* self = soa.Self();
+ mirror::Class* eiie_class =
+ self->DecodeJObject(WellKnownClasses::java_lang_ExceptionInInitializerError)->AsClass();
+ mirror::Class* iae_class =
+ self->DecodeJObject(WellKnownClasses::java_lang_IllegalAccessError)->AsClass();
+ mirror::Class* ncdfe_class =
+ self->DecodeJObject(WellKnownClasses::java_lang_NoClassDefFoundError)->AsClass();
+ mirror::Class* exception = self->GetException()->GetClass();
+ if (exception == eiie_class || exception == iae_class || exception == ncdfe_class) {
+ self->ThrowNewWrappedException("Ljava/lang/ClassNotFoundException;",
+ PrettyDescriptor(c).c_str());
+ }
+ return nullptr;
+ }
if (loader != nullptr) {
// Try the common case.
StackHandleScope<1> hs(soa.Self());
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index d288943..355d552 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -41,6 +41,9 @@
jclass WellKnownClasses::java_lang_ClassNotFoundException;
jclass WellKnownClasses::java_lang_Daemons;
jclass WellKnownClasses::java_lang_Error;
+jclass WellKnownClasses::java_lang_ExceptionInInitializerError;
+jclass WellKnownClasses::java_lang_IllegalAccessError;
+jclass WellKnownClasses::java_lang_NoClassDefFoundError;
jclass WellKnownClasses::java_lang_Object;
jclass WellKnownClasses::java_lang_OutOfMemoryError;
jclass WellKnownClasses::java_lang_reflect_AbstractMethod;
@@ -228,6 +231,9 @@
java_lang_Object = CacheClass(env, "java/lang/Object");
java_lang_OutOfMemoryError = CacheClass(env, "java/lang/OutOfMemoryError");
java_lang_Error = CacheClass(env, "java/lang/Error");
+ java_lang_ExceptionInInitializerError = CacheClass(env, "java/lang/ExceptionInInitializerError");
+ java_lang_IllegalAccessError = CacheClass(env, "java/lang/IllegalAccessError");
+ java_lang_NoClassDefFoundError = CacheClass(env, "java/lang/NoClassDefFoundError");
java_lang_reflect_AbstractMethod = CacheClass(env, "java/lang/reflect/AbstractMethod");
java_lang_reflect_Constructor = CacheClass(env, "java/lang/reflect/Constructor");
java_lang_reflect_Field = CacheClass(env, "java/lang/reflect/Field");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 482ff0a..cc60b4d 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -52,6 +52,9 @@
static jclass java_lang_ClassNotFoundException;
static jclass java_lang_Daemons;
static jclass java_lang_Error;
+ static jclass java_lang_ExceptionInInitializerError;
+ static jclass java_lang_IllegalAccessError;
+ static jclass java_lang_NoClassDefFoundError;
static jclass java_lang_Object;
static jclass java_lang_OutOfMemoryError;
static jclass java_lang_reflect_AbstractMethod;
diff --git a/test/142-classloader2/smali/B.smali b/test/142-classloader2/smali/B.smali
new file mode 100644
index 0000000..01bd593
--- /dev/null
+++ b/test/142-classloader2/smali/B.smali
@@ -0,0 +1,10 @@
+.class public LB;
+
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+ .registers 1
+ invoke-direct {p1}, Ljava/lang/Object;-><init>()V
+ return-void
+.end method
+
diff --git a/test/142-classloader2/src/Main.java b/test/142-classloader2/src/Main.java
index 86c61eb..89dadce 100644
--- a/test/142-classloader2/src/Main.java
+++ b/test/142-classloader2/src/Main.java
@@ -71,6 +71,21 @@
throw new IllegalStateException("Expected Ex-A, found " + exValue);
}
+ // Try to load a dex file with bad dex code. Use new instance to force verification.
+ try {
+ Class<?> badClass = Main.class.getClassLoader().loadClass("B");
+ badClass.newInstance();
+ System.out.println("Should not be able to load class from bad dex file.");
+ } catch (VerifyError e) {
+ }
+
+ // Make sure the same error is rethrown when reloading the bad class.
+ try {
+ Class<?> badClass = Main.class.getClassLoader().loadClass("B");
+ System.out.println("Should not be able to load class from bad dex file.");
+ } catch (VerifyError e) {
+ }
+
System.out.println("Everything OK.");
}
}
diff --git a/test/562-bce-preheader/src/Main.java b/test/562-bce-preheader/src/Main.java
index 8b527b4..4397f67 100644
--- a/test/562-bce-preheader/src/Main.java
+++ b/test/562-bce-preheader/src/Main.java
@@ -90,6 +90,25 @@
return a;
}
+ /**
+ * Example shows that we can hoist ArrayGet to pre-header only if
+ * its execution is guaranteed.
+ */
+ public static int hoistcheck(int[] c) {
+ int i = 0, i2 = 0, i3 = 0, k = 0;
+ int n = c.length;
+ for (i = -100000000; i < 20; i += 10000000) {
+ i3 = i;
+ i2 = 0;
+ while (i2++ < 1) {
+ if (i3 >= 0 && i3 < n) {
+ k += c[i3];
+ }
+ }
+ }
+ return k;
+ }
+
public static void main(String args[]) {
int[][] x = new int[2][2];
int y;
@@ -119,6 +138,9 @@
int[] z = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
expectEquals(10, doit(z));
+ int c[] = { 1, 2, 3, 5 };
+ expectEquals(1, hoistcheck(c));
+
System.out.println("passed");
}