summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2012-03-31 21:08:41 -0700
committerIan Rogers <irogers@google.com>2012-03-31 22:38:22 -0700
commit0045a290e6b79a274250e3112880c04bde437d4a (patch)
treea125d556b6c817218b14f6f3f72079b83d0032c4
parentd23f5206cf72ca3fb53ac3049649bb7d018232bf (diff)
downloadart-0045a290e6b79a274250e3112880c04bde437d4a.zip
art-0045a290e6b79a274250e3112880c04bde437d4a.tar.gz
art-0045a290e6b79a274250e3112880c04bde437d4a.tar.bz2
Avoid a case of eager initialization.
Don't mark as initialized classes that contain static field initialization. Change-Id: Iedcabbdf355e8861eb7731650eee1467f68ae0cd
-rw-r--r--src/class_linker.cc33
-rw-r--r--src/class_linker.h9
-rw-r--r--src/class_linker_test.cc2
-rw-r--r--src/compiler.cc5
-rw-r--r--src/java_lang_Class.cc4
-rw-r--r--src/java_lang_reflect_Constructor.cc2
-rw-r--r--src/java_lang_reflect_Field.cc4
-rw-r--r--src/jni_internal.cc12
-rw-r--r--src/oat/runtime/support_stubs.cc2
-rw-r--r--src/reflection.cc2
-rw-r--r--src/runtime_support.cc4
-rw-r--r--src/runtime_support.h2
-rw-r--r--src/thread.cc4
13 files changed, 49 insertions, 36 deletions
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 80dd7eb..c94347d 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -546,7 +546,7 @@ void ClassLinker::RunRootClinits() {
for (size_t i = 0; i < ClassLinker::kClassRootsMax; ++i) {
Class* c = GetClassRoot(ClassRoot(i));
if (!c->IsArrayClass() && !c->IsPrimitive()) {
- EnsureInitialized(GetClassRoot(ClassRoot(i)), true);
+ EnsureInitialized(GetClassRoot(ClassRoot(i)), true, true);
CHECK(!self->IsExceptionPending()) << PrettyTypeOf(self->GetException());
}
}
@@ -2338,7 +2338,7 @@ static void CheckProxyMethod(Method* method, SirtRef<Method>& prototype) {
CHECK_EQ(mh.GetReturnType(), mh2.GetReturnType());
}
-bool ClassLinker::InitializeClass(Class* klass, bool can_run_clinit) {
+bool ClassLinker::InitializeClass(Class* klass, bool can_run_clinit, bool can_init_statics) {
CHECK(klass->IsResolved() || klass->IsErroneous())
<< PrettyClass(klass) << " is " << klass->GetStatus();
@@ -2404,7 +2404,7 @@ bool ClassLinker::InitializeClass(Class* klass, bool can_run_clinit) {
uint64_t t0 = NanoTime();
- if (!InitializeSuperClass(klass, can_run_clinit)) {
+ if (!InitializeSuperClass(klass, can_run_clinit, can_init_statics)) {
// Super class initialization failed, this can be because we can't run
// super-class class initializers in which case we'll be verified.
// Otherwise this class is erroneous.
@@ -2416,7 +2416,7 @@ bool ClassLinker::InitializeClass(Class* klass, bool can_run_clinit) {
return false;
}
- InitializeStaticFields(klass);
+ bool has_static_field_initializers = InitializeStaticFields(klass);
if (clinit != NULL) {
clinit->Invoke(self, NULL, NULL, NULL);
@@ -2441,7 +2441,14 @@ bool ClassLinker::InitializeClass(Class* klass, bool can_run_clinit) {
++thread_stats->class_init_count;
global_stats->class_init_time_ns += (t1 - t0);
thread_stats->class_init_time_ns += (t1 - t0);
- klass->SetStatus(Class::kStatusInitialized);
+ // Set the class as initialized except if we can't initialize static fields and static field
+ // initialization is necessary.
+ if (!can_init_statics && has_static_field_initializers) {
+ klass->SetStatus(Class::kStatusVerified); // Don't leave class in initializing state.
+ success = false;
+ } else {
+ klass->SetStatus(Class::kStatusInitialized);
+ }
if (VLOG_IS_ON(class_linker)) {
ClassHelper kh(klass);
LOG(INFO) << "Initialized class " << kh.GetDescriptor() << " from " << kh.GetLocation();
@@ -2577,7 +2584,7 @@ bool ClassLinker::IsSameDescriptorInDifferentClassContexts(const char* descripto
return found1 == found2;
}
-bool ClassLinker::InitializeSuperClass(Class* klass, bool can_run_clinit) {
+bool ClassLinker::InitializeSuperClass(Class* klass, bool can_run_clinit, bool can_init_fields) {
CHECK(klass != NULL);
if (!klass->IsInterface() && klass->HasSuperClass()) {
Class* super_class = klass->GetSuperClass();
@@ -2585,7 +2592,7 @@ bool ClassLinker::InitializeSuperClass(Class* klass, bool can_run_clinit) {
CHECK(!super_class->IsInterface());
Thread* self = Thread::Current();
klass->MonitorEnter(self);
- bool super_initialized = InitializeClass(super_class, can_run_clinit);
+ bool super_initialized = InitializeClass(super_class, can_run_clinit, can_init_fields);
klass->MonitorExit(self);
// TODO: check for a pending exception
if (!super_initialized) {
@@ -2604,7 +2611,7 @@ bool ClassLinker::InitializeSuperClass(Class* klass, bool can_run_clinit) {
return true;
}
-bool ClassLinker::EnsureInitialized(Class* c, bool can_run_clinit) {
+bool ClassLinker::EnsureInitialized(Class* c, bool can_run_clinit, bool can_init_fields) {
CHECK(c != NULL);
if (c->IsInitialized()) {
return true;
@@ -2612,7 +2619,7 @@ bool ClassLinker::EnsureInitialized(Class* c, bool can_run_clinit) {
Thread* self = Thread::Current();
ScopedThreadStateChange tsc(self, Thread::kRunnable);
- bool success = InitializeClass(c, can_run_clinit);
+ bool success = InitializeClass(c, can_run_clinit, can_init_fields);
if (!success) {
CHECK(self->IsExceptionPending() || !can_run_clinit) << PrettyClass(c);
}
@@ -2629,15 +2636,15 @@ void ClassLinker::ConstructFieldMap(const DexFile& dex_file, const DexFile::Clas
}
}
-void ClassLinker::InitializeStaticFields(Class* klass) {
+bool ClassLinker::InitializeStaticFields(Class* klass) {
size_t num_static_fields = klass->NumStaticFields();
if (num_static_fields == 0) {
- return;
+ return false;
}
DexCache* dex_cache = klass->GetDexCache();
// TODO: this seems like the wrong check. do we really want !IsPrimitive && !IsArray?
if (dex_cache == NULL) {
- return;
+ return false;
}
ClassHelper kh(klass);
const DexFile::ClassDef* dex_class_def = kh.GetClassDef();
@@ -2652,7 +2659,9 @@ void ClassLinker::InitializeStaticFields(Class* klass) {
for (size_t i = 0; it.HasNext(); i++, it.Next()) {
it.ReadValueToField(field_map[i]);
}
+ return true;
}
+ return false;
}
bool ClassLinker::LinkClass(SirtRef<Class>& klass, ObjectArray<Class>* interfaces) {
diff --git a/src/class_linker.h b/src/class_linker.h
index eb76738..3226a6f 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -222,7 +222,7 @@ class ClassLinker {
// Returns true on success, false if there's an exception pending.
// can_run_clinit=false allows the compiler to attempt to init a class,
// given the restriction that no <clinit> execution is possible.
- bool EnsureInitialized(Class* c, bool can_run_clinit);
+ bool EnsureInitialized(Class* c, bool can_run_clinit, bool can_init_fields);
// Initializes classes that have instances in the image but that have
// <clinit> methods so they could not be initialized by the compiler.
@@ -365,11 +365,12 @@ class ClassLinker {
bool IsDexFileRegisteredLocked(const DexFile& dex_file) const;
void RegisterOatFileLocked(const OatFile& oat_file);
- bool InitializeClass(Class* klass, bool can_run_clinit);
+ bool InitializeClass(Class* klass, bool can_run_clinit, bool can_init_statics);
bool WaitForInitializeClass(Class* klass, Thread* self, ObjectLock& lock);
bool ValidateSuperClassDescriptors(const Class* klass);
- bool InitializeSuperClass(Class* klass, bool can_run_clinit);
- void InitializeStaticFields(Class* klass);
+ bool InitializeSuperClass(Class* klass, bool can_run_clinit, bool can_init_fields);
+ // Initialize static fields, returns true if fields were initialized.
+ bool InitializeStaticFields(Class* klass);
bool IsSameDescriptorInDifferentClassContexts(const char* descriptor,
const Class* klass1,
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index f505d58..6fac6f8 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -835,7 +835,7 @@ TEST_F(ClassLinkerTest, TwoClassLoadersOneClass) {
TEST_F(ClassLinkerTest, StaticFields) {
SirtRef<ClassLoader> class_loader(LoadDex("Statics"));
Class* statics = class_linker_->FindClass("LStatics;", class_loader.get());
- class_linker_->EnsureInitialized(statics, true);
+ class_linker_->EnsureInitialized(statics, true, true);
// Static final primitives that are initialized by a compile-time constant
// expression resolve to a copy of a constant value from the constant pool.
diff --git a/src/compiler.cc b/src/compiler.cc
index 5507c36..bac39ef 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -1173,7 +1173,10 @@ void Compiler::InitializeClassesWithoutClinit(const ClassLoader* class_loader, c
if (klass != NULL) {
if (klass->IsVerified()) {
// Only try to initialize classes that were successfully verified.
- class_linker->EnsureInitialized(klass, false);
+ bool compiling_boot = Runtime::Current()->GetHeap()->GetSpaces().size() == 1;
+ bool can_init_static_fields = compiling_boot &&
+ IsImageClass(descriptor);
+ class_linker->EnsureInitialized(klass, false, can_init_static_fields);
}
// record the final class status if necessary
Class::Status status = klass->GetStatus();
diff --git a/src/java_lang_Class.cc b/src/java_lang_Class.cc
index 20af47a..fcd1689 100644
--- a/src/java_lang_Class.cc
+++ b/src/java_lang_Class.cc
@@ -68,7 +68,7 @@ static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean
return NULL;
}
if (initialize) {
- class_linker->EnsureInitialized(c, true);
+ class_linker->EnsureInitialized(c, true, true);
}
return AddLocalReference<jclass>(env, c);
}
@@ -403,7 +403,7 @@ static jobject Class_newInstanceImpl(JNIEnv* env, jobject javaThis) {
return NULL;
}
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
return NULL;
}
diff --git a/src/java_lang_reflect_Constructor.cc b/src/java_lang_reflect_Constructor.cc
index c908bb7..9a498f4 100644
--- a/src/java_lang_reflect_Constructor.cc
+++ b/src/java_lang_reflect_Constructor.cc
@@ -41,7 +41,7 @@ static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectA
return NULL;
}
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
DCHECK(Thread::Current()->IsExceptionPending());
return NULL;
}
diff --git a/src/java_lang_reflect_Field.cc b/src/java_lang_reflect_Field.cc
index 70636d6..a7785e7 100644
--- a/src/java_lang_reflect_Field.cc
+++ b/src/java_lang_reflect_Field.cc
@@ -26,7 +26,7 @@ namespace art {
static bool GetFieldValue(Object* o, Field* f, JValue& value, bool allow_references) {
ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(), true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(), true, true)) {
return false;
}
switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
@@ -157,7 +157,7 @@ static jshort Field_getShort(JNIEnv* env, jobject javaField, jobject javaObj) {
}
static void SetFieldValue(Object* o, Field* f, const JValue& new_value, bool allow_references) {
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(), true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(), true, true)) {
return;
}
switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 949217b..c5ffec1 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -331,7 +331,7 @@ static void ThrowNoSuchMethodError(ScopedJniThreadState& ts, Class* c, const cha
static jmethodID FindMethodID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) {
Class* c = Decode<Class*>(ts, jni_class);
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
return NULL;
}
@@ -366,7 +366,7 @@ static const ClassLoader* GetClassLoader(Thread* self) {
static jfieldID FindFieldID(ScopedJniThreadState& ts, jclass jni_class, const char* name, const char* sig, bool is_static) {
Class* c = Decode<Class*>(ts, jni_class);
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
return NULL;
}
@@ -966,7 +966,7 @@ class JNI {
static jobject AllocObject(JNIEnv* env, jclass java_class) {
ScopedJniThreadState ts(env);
Class* c = Decode<Class*>(ts, java_class);
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
return NULL;
}
return AddLocalReference<jobject>(env, c->AllocObject());
@@ -984,7 +984,7 @@ class JNI {
static jobject NewObjectV(JNIEnv* env, jclass java_class, jmethodID mid, va_list args) {
ScopedJniThreadState ts(env);
Class* c = Decode<Class*>(ts, java_class);
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
return NULL;
}
Object* result = c->AllocObject();
@@ -1003,7 +1003,7 @@ class JNI {
static jobject NewObjectA(JNIEnv* env, jclass java_class, jmethodID mid, jvalue* args) {
ScopedJniThreadState ts(env);
Class* c = Decode<Class*>(ts, java_class);
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
return NULL;
}
Object* result = c->AllocObject();
@@ -2898,7 +2898,7 @@ void* JavaVMExt::FindCodeForNativeMethod(Method* m) {
// If this is a static method, it could be called before the class
// has been initialized.
if (m->IsStatic()) {
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
return NULL;
}
} else {
diff --git a/src/oat/runtime/support_stubs.cc b/src/oat/runtime/support_stubs.cc
index 8727a5d..5f7d635 100644
--- a/src/oat/runtime/support_stubs.cc
+++ b/src/oat/runtime/support_stubs.cc
@@ -141,7 +141,7 @@ const void* UnresolvedDirectMethodTrampolineFromCode(Method* called, Method** sp
if (LIKELY(called->IsDirect() == !is_virtual)) {
// Ensure that the called method's class is initialized.
Class* called_class = called->GetDeclaringClass();
- linker->EnsureInitialized(called_class, true);
+ linker->EnsureInitialized(called_class, true, true);
if (LIKELY(called_class->IsInitialized())) {
code = called->GetCode();
} else if (called_class->IsInitializing()) {
diff --git a/src/reflection.cc b/src/reflection.cc
index ffc1e1f..008c1cd 100644
--- a/src/reflection.cc
+++ b/src/reflection.cc
@@ -54,7 +54,7 @@ jobject InvokeMethod(JNIEnv* env, jobject javaMethod, jobject javaReceiver, jobj
Method* m = reinterpret_cast<Method*>(mid);
Class* declaring_class = m->GetDeclaringClass();
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaring_class, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaring_class, true, true)) {
return NULL;
}
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 0ee9990..7b907ae 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -229,7 +229,7 @@ Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* sel
// we'd still be waiting for the lock.
if (fields_class->IsInitializing()) {
return resolved_field;
- } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true)) {
+ } else if (Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true, true)) {
return resolved_field;
} else {
DCHECK(self->IsExceptionPending()); // Throw exception and unwind
@@ -367,7 +367,7 @@ Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread*
if (klass == referring_class && MethodHelper(referrer).IsClassInitializer()) {
return klass;
}
- if (!class_linker->EnsureInitialized(klass, true)) {
+ if (!class_linker->EnsureInitialized(klass, true, true)) {
CHECK(self->IsExceptionPending());
return NULL; // Failure - Indicate to caller to deliver exception
}
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 2f5ba5b..0229bc1 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -87,7 +87,7 @@ static inline Object* AllocObjectFromCode(uint32_t type_idx, Method* method, Thr
return NULL; // Failure
}
}
- if (!runtime->GetClassLinker()->EnsureInitialized(klass, true)) {
+ if (!runtime->GetClassLinker()->EnsureInitialized(klass, true, true)) {
DCHECK(self->IsExceptionPending());
return NULL; // Failure
}
diff --git a/src/thread.cc b/src/thread.cc
index c4934b0..5233dd1 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -244,14 +244,14 @@ Thread* Thread::Attach(const char* thread_name, bool as_daemon, Object* thread_g
}
Object* Thread::GetMainThreadGroup() {
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(gThreadGroup, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(gThreadGroup, true, true)) {
return NULL;
}
return gThreadGroup_mMain->GetObject(NULL);
}
Object* Thread::GetSystemThreadGroup() {
- if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(gThreadGroup, true)) {
+ if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(gThreadGroup, true, true)) {
return NULL;
}
return gThreadGroup_mSystem->GetObject(NULL);