From: Vladimir Marko Date: Mon, 15 Jun 2015 17:52:54 +0000 (+0100) Subject: ART: Fix reporting initialized classes by CompilerDriver. X-Git-Tag: android-x86-6.0-r1~124 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=a8b41003a717ecf399b890c18e9b0df49f55472f;p=android-x86%2Fart.git ART: Fix reporting initialized classes by CompilerDriver. Fix a bug where the CompilerDriver was erroneously reporting classes as initialized during AOT compilation when they were not guaranteed to be initialized at runtime. This fix prevents the Quick compiler from inlining calls to static methods in classes that are not guaranteed to be initialized, so that the runtime performs the initialization required for correctness. Bug: 21847756 (cherry picked from commit 07785bb98dc8bbe192970e0f4c2cafd338a8dc68) Change-Id: I60c7361cb6e8f51be20a3cbfcae19f3240bdfbed --- diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h index b25e96760..e0c56fcc8 100644 --- a/compiler/driver/compiler_driver-inl.h +++ b/compiler/driver/compiler_driver-inl.h @@ -233,11 +233,32 @@ inline bool CompilerDriver::IsStaticFieldInReferrerClass(mirror::Class* referrer return referrer_class == fields_class; } +inline bool CompilerDriver::CanAssumeClassIsInitialized(mirror::Class* klass) { + // Being loaded is a pre-requisite for being initialized but let's do the cheap check first. + // + // NOTE: When AOT compiling an app, we eagerly initialize app classes (and potentially their + // super classes in the boot image) but only those that have a trivial initialization, i.e. + // without () or static values in the dex file for that class or any of its super + // classes. So while we could see the klass as initialized during AOT compilation and have + // it only loaded at runtime, the needed initialization would have to be trivial and + // unobservable from Java, so we may as well treat it as initialized. + if (!klass->IsInitialized()) { + return false; + } + return CanAssumeClassIsLoaded(klass); +} + +inline bool CompilerDriver::CanReferrerAssumeClassIsInitialized(mirror::Class* referrer_class, + mirror::Class* klass) { + return (referrer_class != nullptr && referrer_class->IsSubClass(klass)) || + CanAssumeClassIsInitialized(klass); +} + inline bool CompilerDriver::IsStaticFieldsClassInitialized(mirror::Class* referrer_class, ArtField* resolved_field) { DCHECK(resolved_field->IsStatic()); mirror::Class* fields_class = resolved_field->GetDeclaringClass(); - return fields_class == referrer_class || fields_class->IsInitialized(); + return CanReferrerAssumeClassIsInitialized(referrer_class, fields_class); } inline ArtMethod* CompilerDriver::ResolveMethod( @@ -394,7 +415,7 @@ inline bool CompilerDriver::IsMethodsClassInitialized(mirror::Class* referrer_cl return true; } mirror::Class* methods_class = resolved_method->GetDeclaringClass(); - return methods_class == referrer_class || methods_class->IsInitialized(); + return CanReferrerAssumeClassIsInitialized(referrer_class, methods_class); } } // namespace art diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index e963c1240..55fabcc36 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -659,7 +659,8 @@ void CompilerDriver::PreCompile(jobject class_loader, const std::vectorfind(descriptor) != image_classes_->end(); } @@ -992,6 +993,24 @@ void CompilerDriver::UpdateImageClasses(TimingLogger* timings) { } } +bool CompilerDriver::CanAssumeClassIsLoaded(mirror::Class* klass) { + Runtime* runtime = Runtime::Current(); + if (!runtime->IsAotCompiler()) { + DCHECK(runtime->UseJit()); + // Having the klass reference here implies that the klass is already loaded. + return true; + } + if (!IsImage()) { + // Assume loaded only if klass is in the boot image. App classes cannot be assumed + // loaded because we don't even know what class loader will be used to load them. + bool class_in_image = runtime->GetHeap()->FindSpaceFromObject(klass, false)->IsImageSpace(); + return class_in_image; + } + std::string temp; + const char* descriptor = klass->GetDescriptor(&temp); + return IsImageClass(descriptor); +} + bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(const DexFile& dex_file, uint32_t type_idx) { if (IsImage() && IsImageClass(dex_file.StringDataByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_))) { diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 68c905eb2..f73700730 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -501,6 +501,16 @@ class CompilerDriver { uint32_t field_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Can we assume that the klass is initialized? + bool CanAssumeClassIsInitialized(mirror::Class* klass) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + bool CanReferrerAssumeClassIsInitialized(mirror::Class* referrer_class, mirror::Class* klass) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // Can we assume that the klass is loaded? + bool CanAssumeClassIsLoaded(mirror::Class* klass) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // These flags are internal to CompilerDriver for collecting INVOKE resolution statistics. // The only external contract is that unresolved method has flags 0 and resolved non-0. enum { diff --git a/runtime/oat.h b/runtime/oat.h index 604e16171..000ae8ed5 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,7 +32,7 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - static constexpr uint8_t kOatVersion[] = { '0', '6', '3', '\0' }; + static constexpr uint8_t kOatVersion[] = { '0', '6', '4', '\0' }; static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";