Fix 084-class-init
Don't update the code and direct methods table for classes that are
still initializing as a 2nd thread may need to wait for class
initialization.
Fix the return value of EnsureInitialized when the class initializer
throws an exception.
Change-Id: I571d983f1a4025b5bcdd51b817d252ef131a6e97
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 14f4b7e..045974f 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -2067,12 +2067,14 @@
uint64_t t1 = NanoTime();
+ bool success = true;
{
ObjectLock lock(klass);
if (self->IsExceptionPending()) {
WrapExceptionInInitializer();
klass->SetStatus(Class::kStatusError);
+ success = false;
} else {
RuntimeStats* global_stats = Runtime::Current()->GetStats();
RuntimeStats* thread_stats = self->GetStats();
@@ -2088,8 +2090,7 @@
}
lock.NotifyAll();
}
-
- return true;
+ return success;
}
bool ClassLinker::WaitForInitializeClass(Class* klass, Thread* self, ObjectLock& lock) {
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 1a6d2e6..696ef70 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -408,12 +408,18 @@
Method* called = linker->ResolveMethod(method_idx, *caller_sp, true);
if (LIKELY(!thread->IsExceptionPending())) {
if (LIKELY(called->IsDirect())) {
- // Update CodeAndDirectMethod table
- Method* caller = *caller_sp;
- DexCache* dex_cache = caller->GetDeclaringClass()->GetDexCache();
- dex_cache->GetCodeAndDirectMethods()->SetResolvedDirectMethod(method_idx, called);
- // We got this far, ensure that the declaring class is initialized
- linker->EnsureInitialized(called->GetDeclaringClass(), true);
+ // Ensure that the called method's class is initialized
+ Class* called_class = called->GetDeclaringClass();
+ linker->EnsureInitialized(called_class, true);
+ if (LIKELY(called_class->IsInitialized())) {
+ // Update CodeAndDirectMethod table and avoid the trampoline when we know the called class
+ // is initialized (see test 084-class-init SlowInit)
+ Method* caller = *caller_sp;
+ DexCache* dex_cache = caller->GetDeclaringClass()->GetDexCache();
+ dex_cache->GetCodeAndDirectMethods()->SetResolvedDirectMethod(method_idx, called);
+ // We got this far, ensure that the declaring class is initialized
+ linker->EnsureInitialized(called->GetDeclaringClass(), true);
+ }
} else {
// Direct method has been made virtual
thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
@@ -430,7 +436,7 @@
thread->ClearException();
} else {
// Expect class to at least be initializing
- CHECK(called->GetDeclaringClass()->IsInitializing());
+ DCHECK(called->GetDeclaringClass()->IsInitializing());
// Set up entry into main method
regs[0] = reinterpret_cast<uintptr_t>(called);
code = const_cast<void*>(called->GetCode());