diff options
author | Ian Rogers <irogers@google.com> | 2012-03-31 21:08:41 -0700 |
---|---|---|
committer | Ian Rogers <irogers@google.com> | 2012-03-31 22:38:22 -0700 |
commit | 0045a290e6b79a274250e3112880c04bde437d4a (patch) | |
tree | a125d556b6c817218b14f6f3f72079b83d0032c4 | |
parent | d23f5206cf72ca3fb53ac3049649bb7d018232bf (diff) | |
download | art-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.cc | 33 | ||||
-rw-r--r-- | src/class_linker.h | 9 | ||||
-rw-r--r-- | src/class_linker_test.cc | 2 | ||||
-rw-r--r-- | src/compiler.cc | 5 | ||||
-rw-r--r-- | src/java_lang_Class.cc | 4 | ||||
-rw-r--r-- | src/java_lang_reflect_Constructor.cc | 2 | ||||
-rw-r--r-- | src/java_lang_reflect_Field.cc | 4 | ||||
-rw-r--r-- | src/jni_internal.cc | 12 | ||||
-rw-r--r-- | src/oat/runtime/support_stubs.cc | 2 | ||||
-rw-r--r-- | src/reflection.cc | 2 | ||||
-rw-r--r-- | src/runtime_support.cc | 4 | ||||
-rw-r--r-- | src/runtime_support.h | 2 | ||||
-rw-r--r-- | src/thread.cc | 4 |
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); |