summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2013-08-19 21:51:45 -0700
committerIan Rogers <irogers@google.com>2013-08-19 22:52:23 -0700
commite6bb3b2ce5a69c31c2adfc7eb2705633b7f966eb (patch)
tree2c562e3de0fcd0cdd4528c4d2f40aa7fc75eea2e
parentcf3de6209f056aa8d6005e4610d49855da581eb4 (diff)
downloadart-e6bb3b2ce5a69c31c2adfc7eb2705633b7f966eb.zip
art-e6bb3b2ce5a69c31c2adfc7eb2705633b7f966eb.tar.gz
art-e6bb3b2ce5a69c31c2adfc7eb2705633b7f966eb.tar.bz2
Reduce AOT initialization.
When compiling apps there is no need to resolve all types in the dex file, just those declared in the dex file. There's also no need to initialize static fields if we can only leave the class in a verified state. Increase use of CompilerDriver::IsImage. Move timing of dex2oat setup to before Runtime::Create. On run-test 056 the performance improvement is an order of magnitude, for ThinkFree dex2oat time is dominated by compilation and this change has no effect. Bug 10316099. Change-Id: Ibdd7caa43284e7448e6a56d810967100ae4a7898
-rw-r--r--compiler/driver/compiler_driver.cc253
-rw-r--r--compiler/driver/compiler_driver.h1
-rw-r--r--dex2oat/dex2oat.cc2
-rw-r--r--runtime/class_linker.cc57
-rw-r--r--runtime/class_linker.h2
5 files changed, 173 insertions, 142 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 120f232..38ffa10 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -582,10 +582,11 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vector<const De
bool CompilerDriver::IsImageClass(const char* descriptor) const {
DCHECK(descriptor != NULL);
- if (image_classes_.get() == NULL) {
+ if (!IsImage()) {
return true;
+ } else {
+ return image_classes_->find(descriptor) != image_classes_->end();
}
- return image_classes_->find(descriptor) != image_classes_->end();
}
static void ResolveExceptionsForMethod(MethodHelper* mh,
@@ -655,7 +656,7 @@ static bool RecordImageClassesVisitor(mirror::Class* klass, void* arg)
// Make a list of descriptors for classes to include in the image
void CompilerDriver::LoadImageClasses(base::TimingLogger& timings)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
- if (image_classes_.get() == NULL) {
+ if (!IsImage()) {
return;
}
@@ -669,7 +670,7 @@ void CompilerDriver::LoadImageClasses(base::TimingLogger& timings)
SirtRef<mirror::Class> klass(self, class_linker->FindSystemClass(descriptor.c_str()));
if (klass.get() == NULL) {
image_classes_->erase(it++);
- LOG(WARNING) << "Failed to find class " << descriptor;
+ VLOG(compiler) << "Failed to find class " << descriptor;
Thread::Current()->ClearException();
} else {
++it;
@@ -742,21 +743,19 @@ void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void
}
void CompilerDriver::UpdateImageClasses(base::TimingLogger& timings) {
- if (image_classes_.get() == NULL) {
- return;
- }
-
- timings.NewSplit("UpdateImageClasses");
+ if (IsImage()) {
+ timings.NewSplit("UpdateImageClasses");
- // Update image_classes_ with classes for objects created by <clinit> methods.
- Thread* self = Thread::Current();
- const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
- gc::Heap* heap = Runtime::Current()->GetHeap();
- // TODO: Image spaces only?
- WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
- heap->FlushAllocStack();
- heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this);
- self->EndAssertNoThreadSuspension(old_cause);
+ // Update image_classes_ with classes for objects created by <clinit> methods.
+ Thread* self = Thread::Current();
+ const char* old_cause = self->StartAssertNoThreadSuspension("ImageWriter");
+ gc::Heap* heap = Runtime::Current()->GetHeap();
+ // TODO: Image spaces only?
+ WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
+ heap->FlushAllocStack();
+ heap->GetLiveBitmap()->Walk(FindClinitImageClassesCallback, this);
+ self->EndAssertNoThreadSuspension(old_cause);
+ }
}
void CompilerDriver::RecordClassStatus(ClassReference ref, CompiledClass* compiled_class) {
@@ -1436,12 +1435,18 @@ static bool SkipClass(mirror::ClassLoader* class_loader,
return true;
}
-static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manager, size_t class_def_index)
+static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manager,
+ size_t class_def_index)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
ScopedObjectAccess soa(Thread::Current());
mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader());
const DexFile& dex_file = *manager->GetDexFile();
+ // If an instance field is final then we need to have a barrier on the return, static final
+ // fields are assigned within the lock held for class initialization. Conservatively assume
+ // constructor barriers are always required.
+ bool requires_constructor_barrier = true;
+
// Method and Field are the worst. We can't resolve without either
// context from the code use (to disambiguate virtual vs direct
// method and instance vs static field) or from class
@@ -1450,72 +1455,89 @@ static void ResolveClassFieldsAndMethods(const ParallelCompilationManager* manag
// definitions, since many of them many never be referenced by
// generated code.
const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
- if (SkipClass(class_loader, dex_file, class_def)) {
- return;
- }
-
- // Note the class_data pointer advances through the headers,
- // static fields, instance fields, direct methods, and virtual
- // methods.
- const byte* class_data = dex_file.GetClassData(class_def);
- if (class_data == NULL) {
- // empty class such as a marker interface
- return;
- }
- Thread* self = Thread::Current();
- ClassLinker* class_linker = manager->GetClassLinker();
- mirror::DexCache* dex_cache = class_linker->FindDexCache(dex_file);
- ClassDataItemIterator it(dex_file, class_data);
- while (it.HasNextStaticField()) {
- mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache,
- class_loader, true);
- if (field == NULL) {
- CHECK(self->IsExceptionPending());
- self->ClearException();
- }
- it.Next();
- }
- // If an instance field is final then we need to have a barrier on the return, static final
- // fields are assigned within the lock held for class initialization.
- bool requires_constructor_barrier = false;
- while (it.HasNextInstanceField()) {
- if ((it.GetMemberAccessFlags() & kAccFinal) != 0) {
- requires_constructor_barrier = true;
- }
-
- mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(), dex_cache,
- class_loader, false);
- if (field == NULL) {
- CHECK(self->IsExceptionPending());
- self->ClearException();
+ if (!SkipClass(class_loader, dex_file, class_def)) {
+ // Note the class_data pointer advances through the headers,
+ // static fields, instance fields, direct methods, and virtual
+ // methods.
+ const byte* class_data = dex_file.GetClassData(class_def);
+ if (class_data == NULL) {
+ // Empty class such as a marker interface.
+ requires_constructor_barrier = false;
+ } else {
+ ClassLinker* class_linker = manager->GetClassLinker();
+ mirror::DexCache* dex_cache = class_linker->FindDexCache(dex_file);
+
+ // Resolve the class.
+ mirror::Class* klass = class_linker->ResolveType(dex_file, class_def.class_idx_, dex_cache,
+ class_loader);
+
+ bool resolve_fields_and_methods;
+ if (klass == NULL) {
+ // Class couldn't be resolved, for example, super-class is in a different dex file. Don't
+ // attempt to resolve methods and fields when there is no declaring class.
+ CHECK(soa.Self()->IsExceptionPending());
+ Thread::Current()->ClearException();
+ resolve_fields_and_methods = false;
+ } else {
+ resolve_fields_and_methods = manager->GetCompiler()->IsImage();
+ }
+ ClassDataItemIterator it(dex_file, class_data);
+ while (it.HasNextStaticField()) {
+ if (resolve_fields_and_methods) {
+ mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
+ dex_cache, class_loader, true);
+ if (field == NULL) {
+ CHECK(soa.Self()->IsExceptionPending());
+ soa.Self()->ClearException();
+ }
+ }
+ it.Next();
+ }
+ // We require a constructor barrier if there are final instance fields.
+ requires_constructor_barrier = false;
+ while (it.HasNextInstanceField()) {
+ if ((it.GetMemberAccessFlags() & kAccFinal) != 0) {
+ requires_constructor_barrier = true;
+ }
+ if (resolve_fields_and_methods) {
+ mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
+ dex_cache, class_loader, false);
+ if (field == NULL) {
+ CHECK(soa.Self()->IsExceptionPending());
+ soa.Self()->ClearException();
+ }
+ }
+ it.Next();
+ }
+ if (resolve_fields_and_methods) {
+ while (it.HasNextDirectMethod()) {
+ mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(),
+ dex_cache, class_loader, NULL,
+ it.GetMethodInvokeType(class_def));
+ if (method == NULL) {
+ CHECK(soa.Self()->IsExceptionPending());
+ soa.Self()->ClearException();
+ }
+ it.Next();
+ }
+ while (it.HasNextVirtualMethod()) {
+ mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(),
+ dex_cache, class_loader, NULL,
+ it.GetMethodInvokeType(class_def));
+ if (method == NULL) {
+ CHECK(soa.Self()->IsExceptionPending());
+ soa.Self()->ClearException();
+ }
+ it.Next();
+ }
+ DCHECK(!it.HasNext());
+ }
}
- it.Next();
}
if (requires_constructor_barrier) {
manager->GetCompiler()->AddRequiresConstructorBarrier(soa.Self(), manager->GetDexFile(),
class_def_index);
}
- while (it.HasNextDirectMethod()) {
- mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(),
- dex_cache, class_loader, NULL,
- it.GetMethodInvokeType(class_def));
- if (method == NULL) {
- CHECK(self->IsExceptionPending());
- self->ClearException();
- }
- it.Next();
- }
- while (it.HasNextVirtualMethod()) {
- mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(),
- dex_cache, class_loader, NULL,
- it.GetMethodInvokeType(class_def));
- if (method == NULL) {
- CHECK(self->IsExceptionPending());
- self->ClearException();
- }
- it.Next();
- }
- DCHECK(!it.HasNext());
}
static void ResolveType(const ParallelCompilationManager* manager, size_t type_idx)
@@ -1541,10 +1563,16 @@ void CompilerDriver::ResolveDexFile(jobject class_loader, const DexFile& dex_fil
// TODO: we could resolve strings here, although the string table is largely filled with class
// and method names.
- timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " Types").c_str()));
ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool);
- context.ForAll(0, dex_file.NumTypeIds(), ResolveType, thread_count_);
+ if (IsImage()) {
+ // For images we resolve all types, such as array, whereas for applications just those with
+ // classdefs are resolved by ResolveClassFieldsAndMethods.
+ // TODO: strdup memory leak.
+ timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " Types").c_str()));
+ context.ForAll(0, dex_file.NumTypeIds(), ResolveType, thread_count_);
+ }
+ // TODO: strdup memory leak.
timings.NewSplit(strdup(("Resolve " + dex_file.GetLocation() + " MethodsAndFields").c_str()));
context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_);
}
@@ -1567,7 +1595,8 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_
mirror::Class* klass =
manager->GetClassLinker()->FindClass(descriptor,
soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader()));
- if (klass == NULL) { CHECK(soa.Self()->IsExceptionPending());
+ if (klass == NULL) {
+ CHECK(soa.Self()->IsExceptionPending());
soa.Self()->ClearException();
/*
@@ -1587,25 +1616,25 @@ static void VerifyClass(const ParallelCompilationManager* manager, size_t class_
<< PrettyDescriptor(manager->GetDexFile()->GetClassDescriptor(class_def))
<< " because: " << error_msg;
}
- return;
- }
- CHECK(klass->IsResolved()) << PrettyClass(klass);
- manager->GetClassLinker()->VerifyClass(klass);
-
- if (klass->IsErroneous()) {
- // ClassLinker::VerifyClass throws, which isn't useful in the compiler.
- CHECK(soa.Self()->IsExceptionPending());
- soa.Self()->ClearException();
- }
+ } else {
+ CHECK(klass->IsResolved()) << PrettyClass(klass);
+ manager->GetClassLinker()->VerifyClass(klass);
+ if (klass->IsErroneous()) {
+ // ClassLinker::VerifyClass throws, which isn't useful in the compiler.
+ CHECK(soa.Self()->IsExceptionPending());
+ soa.Self()->ClearException();
+ }
- CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous())
- << PrettyDescriptor(klass) << ": state=" << klass->GetStatus();
+ CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous())
+ << PrettyDescriptor(klass) << ": state=" << klass->GetStatus();
+ }
soa.Self()->AssertNoPendingException();
}
void CompilerDriver::VerifyDexFile(jobject class_loader, const DexFile& dex_file,
ThreadPool& thread_pool, base::TimingLogger& timings) {
+ // TODO: strdup memory leak.
timings.NewSplit(strdup(("Verify " + dex_file.GetLocation()).c_str()));
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, thread_pool);
@@ -2032,23 +2061,20 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
mirror::ClassLoader* class_loader = soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader());
const char* descriptor = manager->GetDexFile()->GetClassDescriptor(class_def);
mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader);
- bool compiling_boot = Runtime::Current()->GetHeap()->GetContinuousSpaces().size() == 1;
- bool can_init_static_fields = compiling_boot &&
- manager->GetCompiler()->IsImageClass(descriptor);
if (klass != NULL) {
- // We don't want class initialization occurring on multiple threads due to deadlock problems.
- // For example, a parent class is initialized (holding its lock) that refers to a sub-class
- // in its static/class initializer causing it to try to acquire the sub-class' lock. While
- // on a second thread the sub-class is initialized (holding its lock) after first initializing
- // its parents, whose locks are acquired. This leads to a parent-to-child and a child-to-parent
- // lock ordering and consequent potential deadlock.
- // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
- // than use a special Object for the purpose we use the Class of java.lang.Class.
- ObjectLock lock1(soa.Self(), klass->GetClass());
- // The lock required to initialize the class.
- ObjectLock lock2(soa.Self(), klass);
// Only try to initialize classes that were successfully verified.
if (klass->IsVerified()) {
+ // We don't want class initialization occurring on multiple threads due to deadlock problems.
+ // For example, a parent class is initialized (holding its lock) that refers to a sub-class
+ // in its static/class initializer causing it to try to acquire the sub-class' lock. While
+ // on a second thread the sub-class is initialized (holding its lock) after first initializing
+ // its parents, whose locks are acquired. This leads to a parent-to-child and a child-to-parent
+ // lock ordering and consequent potential deadlock.
+ // We need to use an ObjectLock due to potential suspension in the interpreting code. Rather
+ // than use a special Object for the purpose we use the Class of java.lang.Class.
+ ObjectLock lock(soa.Self(), klass->GetClass());
+ bool can_init_static_fields = manager->GetCompiler()->IsImage() &&
+ manager->GetCompiler()->IsImageClass(descriptor);
manager->GetClassLinker()->EnsureInitialized(klass, false, can_init_static_fields);
if (soa.Self()->IsExceptionPending()) {
soa.Self()->GetException(NULL)->Dump();
@@ -2069,6 +2095,7 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
VLOG(compiler) << "Initializing: " << descriptor;
if (StringPiece(descriptor) == "Ljava/lang/Void;") {
// Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
+ ObjectLock lock(soa.Self(), klass);
mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
CHECK_EQ(fields->GetLength(), 1);
fields->Get(0)->SetObj(klass, manager->GetClassLinker()->FindPrimitiveClass('V'));
@@ -2102,11 +2129,15 @@ static void InitializeClass(const ParallelCompilationManager* manager, size_t cl
void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file,
ThreadPool& thread_pool, base::TimingLogger& timings) {
+ // TODO: strdup memory leak.
timings.NewSplit(strdup(("InitializeNoClinit " + dex_file.GetLocation()).c_str()));
#ifndef NDEBUG
- for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
- const char* descriptor = class_initializer_black_list[i];
- CHECK(IsValidDescriptor(descriptor)) << descriptor;
+ // Sanity check blacklist descriptors.
+ if (IsImage()) {
+ for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
+ const char* descriptor = class_initializer_black_list[i];
+ CHECK(IsValidDescriptor(descriptor)) << descriptor;
+ }
}
#endif
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 21a44ea..bcde178 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -110,6 +110,7 @@ class CompilerDriver {
return compiler_backend_;
}
+ // Are we compiling and creating an image file?
bool IsImage() const {
return image_;
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index ceb6bf6..89552a3 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -825,6 +825,7 @@ static int dex2oat(int argc, char** argv) {
return EXIT_FAILURE;
}
+ timings.StartSplit("dex2oat Setup");
LOG(INFO) << "dex2oat: " << oat_location;
Runtime::Options options;
@@ -926,7 +927,6 @@ static int dex2oat(int argc, char** argv) {
}
}
- timings.StartSplit("dex2oat Setup");
UniquePtr<const CompilerDriver> compiler(dex2oat->CreateOatFile(boot_image_option,
host_prefix.get(),
android_root,
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d0b8bbd..b4c767d 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2311,8 +2311,9 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
mirror::Class::Status oat_file_class_status(mirror::Class::kStatusNotReady);
bool preverified = VerifyClassUsingOatFile(dex_file, klass, oat_file_class_status);
if (oat_file_class_status == mirror::Class::kStatusError) {
- LOG(WARNING) << "Skipping runtime verification of erroneous class " << PrettyDescriptor(klass)
- << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
+ VLOG(class_linker) << "Skipping runtime verification of erroneous class "
+ << PrettyDescriptor(klass) << " in "
+ << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
ThrowVerifyError(klass, "Rejecting class %s because it failed compile-time verification",
PrettyDescriptor(klass).c_str());
klass->SetStatus(mirror::Class::kStatusError);
@@ -2326,7 +2327,7 @@ void ClassLinker::VerifyClass(mirror::Class* klass) {
}
if (preverified || verifier_failure != verifier::MethodVerifier::kHardFailure) {
if (!preverified && verifier_failure != verifier::MethodVerifier::kNoFailure) {
- LOG(WARNING) << "Soft verification failure in class " << PrettyDescriptor(klass)
+ VLOG(class_linker) << "Soft verification failure in class " << PrettyDescriptor(klass)
<< " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8()
<< " because: " << error_msg;
}
@@ -2722,14 +2723,6 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_run_clinit, boo
}
clinit = klass->FindDeclaredDirectMethod("<clinit>", "()V");
- if (clinit != NULL && !can_run_clinit) {
- // if the class has a <clinit> but we can't run it during compilation,
- // don't bother going to kStatusInitializing. We return false so that
- // sub-classes don't believe this class is initialized.
- // Opportunistically link non-static methods, TODO: don't initialize and dirty pages
- // in second pass.
- return false;
- }
// If the class is kStatusInitializing, either this thread is
// initializing higher up the stack or another thread has beat us
@@ -2775,9 +2768,9 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_run_clinit, boo
return false;
}
- bool has_static_field_initializers = InitializeStaticFields(klass);
+ bool has_static_field_initializers = InitializeStaticFields(klass, can_init_statics);
- if (clinit != NULL) {
+ if (clinit != NULL && can_run_clinit) {
if (Runtime::Current()->IsStarted()) {
JValue result;
clinit->Invoke(self, NULL, 0, &result, 'V');
@@ -2786,7 +2779,11 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_run_clinit, boo
}
}
- FixupStaticTrampolines(klass);
+ // Opportunistically set static method trampolines to their destiniation. Unless initialization
+ // is being hindered at compile time.
+ if (can_init_statics || can_run_clinit || (!has_static_field_initializers && clinit == NULL)) {
+ FixupStaticTrampolines(klass);
+ }
uint64_t t1 = NanoTime();
@@ -2805,15 +2802,15 @@ bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_run_clinit, boo
++thread_stats->class_init_count;
global_stats->class_init_time_ns += (t1 - t0);
thread_stats->class_init_time_ns += (t1 - t0);
- // 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(mirror::Class::kStatusVerified); // Don't leave class in initializing state.
+ // Set the class as initialized except if failed to initialize static fields.
+ if ((!can_init_statics && has_static_field_initializers) ||
+ (!can_run_clinit && clinit != NULL)) {
+ klass->SetStatus(mirror::Class::kStatusVerified);
success = false;
} else {
klass->SetStatus(mirror::Class::kStatusInitialized);
}
- if (VLOG_IS_ON(class_linker)) {
+ if (success && VLOG_IS_ON(class_linker)) {
ClassHelper kh(klass);
LOG(INFO) << "Initialized class " << kh.GetDescriptor() << " from " << kh.GetLocation();
}
@@ -2986,10 +2983,9 @@ bool ClassLinker::EnsureInitialized(mirror::Class* c, bool can_run_clinit, bool
return true;
}
- Thread* self = Thread::Current();
- ScopedThreadStateChange tsc(self, kRunnable);
bool success = InitializeClass(c, can_run_clinit, can_init_fields);
if (!success) {
+ Thread* self = Thread::Current();
CHECK(self->IsExceptionPending() || !can_run_clinit) << PrettyClass(c);
}
return success;
@@ -3005,7 +3001,7 @@ void ClassLinker::ConstructFieldMap(const DexFile& dex_file, const DexFile::Clas
}
}
-bool ClassLinker::InitializeStaticFields(mirror::Class* klass) {
+bool ClassLinker::InitializeStaticFields(mirror::Class* klass, bool can_init_statics) {
size_t num_static_fields = klass->NumStaticFields();
if (num_static_fields == 0) {
return false;
@@ -3022,16 +3018,19 @@ bool ClassLinker::InitializeStaticFields(mirror::Class* klass) {
EncodedStaticFieldValueIterator it(dex_file, dex_cache, klass->GetClassLoader(),
this, *dex_class_def);
- if (it.HasNext()) {
- // We reordered the fields, so we need to be able to map the field indexes to the right fields.
- SafeMap<uint32_t, mirror::ArtField*> field_map;
- ConstructFieldMap(dex_file, *dex_class_def, klass, field_map);
- for (size_t i = 0; it.HasNext(); i++, it.Next()) {
- it.ReadValueToField(field_map.Get(i));
+ if (!it.HasNext()) {
+ return false;
+ } else {
+ if (can_init_statics) {
+ // We reordered the fields, so we need to be able to map the field indexes to the right fields.
+ SafeMap<uint32_t, mirror::ArtField*> field_map;
+ ConstructFieldMap(dex_file, *dex_class_def, klass, field_map);
+ for (size_t i = 0; it.HasNext(); i++, it.Next()) {
+ it.ReadValueToField(field_map.Get(i));
+ }
}
return true;
}
- return false;
}
bool ClassLinker::LinkClass(SirtRef<mirror::Class>& klass,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index d0cc562..fdf17a2 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -443,7 +443,7 @@ class ClassLinker {
bool InitializeSuperClass(mirror::Class* klass, bool can_run_clinit, bool can_init_fields)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Initialize static fields, returns true if fields were initialized.
- bool InitializeStaticFields(mirror::Class* klass)
+ bool InitializeStaticFields(mirror::Class* klass, bool can_init_statics)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsSameDescriptorInDifferentClassContexts(const char* descriptor,