diff options
| author | 2016-10-04 21:45:24 +0000 | |
|---|---|---|
| committer | 2016-10-04 21:45:24 +0000 | |
| commit | 091f6754c353f5825129deff74d860caf28f78de (patch) | |
| tree | bc259b45bc292523e7a486569ac696e33204c10b /compiler | |
| parent | 26705cca4643385931f3b3568b6b82525400b52b (diff) | |
| parent | 38f250fd3cb36fac27bad7cac8eefacdf8a6e41e (diff) | |
Merge "Revert "Remove dead code from compiler driver.""
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/driver/compiler_driver-inl.h | 91 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.cc | 265 | ||||
| -rw-r--r-- | compiler/driver/compiler_driver.h | 123 |
3 files changed, 454 insertions, 25 deletions
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h index 9efd636d2f..b4730cc059 100644 --- a/compiler/driver/compiler_driver-inl.h +++ b/compiler/driver/compiler_driver-inl.h @@ -31,6 +31,10 @@ namespace art { +inline mirror::DexCache* CompilerDriver::GetDexCache(const DexCompilationUnit* mUnit) { + return mUnit->GetClassLinker()->FindDexCache(Thread::Current(), *mUnit->GetDexFile(), false); +} + inline mirror::ClassLoader* CompilerDriver::GetClassLoader(const ScopedObjectAccess& soa, const DexCompilationUnit* mUnit) { return soa.Decode<mirror::ClassLoader>(mUnit->GetClassLoader()).Decode(); @@ -83,6 +87,10 @@ inline ArtField* CompilerDriver::ResolveFieldWithDexFile( return resolved_field; } +inline mirror::DexCache* CompilerDriver::FindDexCache(const DexFile* dex_file) { + return Runtime::Current()->GetClassLinker()->FindDexCache(Thread::Current(), *dex_file, false); +} + inline ArtField* CompilerDriver::ResolveField( const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, @@ -92,6 +100,23 @@ inline ArtField* CompilerDriver::ResolveField( is_static); } +inline void CompilerDriver::GetResolvedFieldDexFileLocation( + ArtField* resolved_field, const DexFile** declaring_dex_file, + uint16_t* declaring_class_idx, uint16_t* declaring_field_idx) { + ObjPtr<mirror::Class> declaring_class = resolved_field->GetDeclaringClass(); + *declaring_dex_file = declaring_class->GetDexCache()->GetDexFile(); + *declaring_class_idx = declaring_class->GetDexTypeIndex(); + *declaring_field_idx = resolved_field->GetDexFieldIndex(); +} + +inline bool CompilerDriver::IsFieldVolatile(ArtField* field) { + return field->IsVolatile(); +} + +inline MemberOffset CompilerDriver::GetFieldOffset(ArtField* field) { + return field->GetOffset(); +} + inline std::pair<bool, bool> CompilerDriver::IsFastInstanceField( mirror::DexCache* dex_cache, mirror::Class* referrer_class, ArtField* resolved_field, uint16_t field_idx) { @@ -194,6 +219,43 @@ inline bool CompilerDriver::IsClassOfStaticMethodAvailableToReferrer( return result.first; } +inline bool CompilerDriver::IsStaticFieldInReferrerClass(mirror::Class* referrer_class, + ArtField* resolved_field) { + DCHECK(resolved_field->IsStatic()); + ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass(); + 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 <clinit>() 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->IsInterface() + && referrer_class->IsSubClass(klass)) + || CanAssumeClassIsInitialized(klass); +} + +inline bool CompilerDriver::IsStaticFieldsClassInitialized(mirror::Class* referrer_class, + ArtField* resolved_field) { + DCHECK(resolved_field->IsStatic()); + ObjPtr<mirror::Class> fields_class = resolved_field->GetDeclaringClass(); + return CanReferrerAssumeClassIsInitialized(referrer_class, fields_class.Decode()); +} + inline ArtMethod* CompilerDriver::ResolveMethod( ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit, @@ -213,6 +275,35 @@ inline ArtMethod* CompilerDriver::ResolveMethod( return resolved_method; } +inline void CompilerDriver::GetResolvedMethodDexFileLocation( + ArtMethod* resolved_method, const DexFile** declaring_dex_file, + uint16_t* declaring_class_idx, uint16_t* declaring_method_idx) { + mirror::Class* declaring_class = resolved_method->GetDeclaringClass(); + *declaring_dex_file = declaring_class->GetDexCache()->GetDexFile(); + *declaring_class_idx = declaring_class->GetDexTypeIndex(); + *declaring_method_idx = resolved_method->GetDexMethodIndex(); +} + +inline uint16_t CompilerDriver::GetResolvedMethodVTableIndex( + ArtMethod* resolved_method, InvokeType type) { + if (type == kVirtual || type == kSuper) { + return resolved_method->GetMethodIndex(); + } else if (type == kInterface) { + return resolved_method->GetDexMethodIndex(); + } else { + return DexFile::kDexNoIndex16; + } +} + +inline bool CompilerDriver::IsMethodsClassInitialized(mirror::Class* referrer_class, + ArtMethod* resolved_method) { + if (!resolved_method->IsStatic()) { + return true; + } + mirror::Class* methods_class = resolved_method->GetDeclaringClass(); + return CanReferrerAssumeClassIsInitialized(referrer_class, methods_class); +} + } // namespace art #endif // ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_ diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 6cca39722d..624287dd0d 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -95,6 +95,8 @@ class CompilerDriver::AOTCompilationStats { public: AOTCompilationStats() : stats_lock_("AOT compilation statistics lock"), + types_in_dex_cache_(0), types_not_in_dex_cache_(0), + strings_in_dex_cache_(0), strings_not_in_dex_cache_(0), resolved_types_(0), unresolved_types_(0), resolved_instance_fields_(0), unresolved_instance_fields_(0), resolved_local_static_fields_(0), resolved_static_fields_(0), unresolved_static_fields_(0), @@ -110,6 +112,8 @@ class CompilerDriver::AOTCompilationStats { } void Dump() { + DumpStat(types_in_dex_cache_, types_not_in_dex_cache_, "types known to be in dex cache"); + DumpStat(strings_in_dex_cache_, strings_not_in_dex_cache_, "strings known to be in dex cache"); DumpStat(resolved_types_, unresolved_types_, "types resolved"); DumpStat(resolved_instance_fields_, unresolved_instance_fields_, "instance fields resolved"); DumpStat(resolved_local_static_fields_ + resolved_static_fields_, unresolved_static_fields_, @@ -160,6 +164,26 @@ class CompilerDriver::AOTCompilationStats { #define STATS_LOCK() #endif + void TypeInDexCache() REQUIRES(!stats_lock_) { + STATS_LOCK(); + types_in_dex_cache_++; + } + + void TypeNotInDexCache() REQUIRES(!stats_lock_) { + STATS_LOCK(); + types_not_in_dex_cache_++; + } + + void StringInDexCache() REQUIRES(!stats_lock_) { + STATS_LOCK(); + strings_in_dex_cache_++; + } + + void StringNotInDexCache() REQUIRES(!stats_lock_) { + STATS_LOCK(); + strings_not_in_dex_cache_++; + } + void TypeDoesntNeedAccessCheck() REQUIRES(!stats_lock_) { STATS_LOCK(); resolved_types_++; @@ -201,6 +225,67 @@ class CompilerDriver::AOTCompilationStats { type_based_devirtualization_++; } + // Indicate that a method of the given type was resolved at compile time. + void ResolvedMethod(InvokeType type) REQUIRES(!stats_lock_) { + DCHECK_LE(type, kMaxInvokeType); + STATS_LOCK(); + resolved_methods_[type]++; + } + + // Indicate that a method of the given type was unresolved at compile time as it was in an + // unknown dex file. + void UnresolvedMethod(InvokeType type) REQUIRES(!stats_lock_) { + DCHECK_LE(type, kMaxInvokeType); + STATS_LOCK(); + unresolved_methods_[type]++; + } + + // Indicate that a type of virtual method dispatch has been converted into a direct method + // dispatch. + void VirtualMadeDirect(InvokeType type) REQUIRES(!stats_lock_) { + DCHECK(type == kVirtual || type == kInterface || type == kSuper); + STATS_LOCK(); + virtual_made_direct_[type]++; + } + + // Indicate that a method of the given type was able to call directly into boot. + void DirectCallsToBoot(InvokeType type) REQUIRES(!stats_lock_) { + DCHECK_LE(type, kMaxInvokeType); + STATS_LOCK(); + direct_calls_to_boot_[type]++; + } + + // Indicate that a method of the given type was able to be resolved directly from boot. + void DirectMethodsToBoot(InvokeType type) REQUIRES(!stats_lock_) { + DCHECK_LE(type, kMaxInvokeType); + STATS_LOCK(); + direct_methods_to_boot_[type]++; + } + + void ProcessedInvoke(InvokeType type, int flags) REQUIRES(!stats_lock_) { + STATS_LOCK(); + if (flags == 0) { + unresolved_methods_[type]++; + } else { + DCHECK_NE((flags & kFlagMethodResolved), 0); + resolved_methods_[type]++; + if ((flags & kFlagVirtualMadeDirect) != 0) { + virtual_made_direct_[type]++; + if ((flags & kFlagPreciseTypeDevirtualization) != 0) { + type_based_devirtualization_++; + } + } else { + DCHECK_EQ((flags & kFlagPreciseTypeDevirtualization), 0); + } + if ((flags & kFlagDirectCallToBoot) != 0) { + direct_calls_to_boot_[type]++; + } + if ((flags & kFlagDirectMethodToBoot) != 0) { + direct_methods_to_boot_[type]++; + } + } + } + // A check-cast could be eliminated due to verifier type analysis. void SafeCast() REQUIRES(!stats_lock_) { STATS_LOCK(); @@ -216,6 +301,12 @@ class CompilerDriver::AOTCompilationStats { private: Mutex stats_lock_; + size_t types_in_dex_cache_; + size_t types_not_in_dex_cache_; + + size_t strings_in_dex_cache_; + size_t strings_not_in_dex_cache_; + size_t resolved_types_; size_t unresolved_types_; @@ -754,10 +845,9 @@ void CompilerDriver::Resolve(jobject class_loader, // TODO: Collect the relevant string indices in parallel, then allocate them sequentially in a // stable order. -static void ResolveConstStrings(Handle<mirror::DexCache> dex_cache, +static void ResolveConstStrings(CompilerDriver* driver, const DexFile& dex_file, - const DexFile::CodeItem* code_item) - REQUIRES_SHARED(Locks::mutator_lock_) { + const DexFile::CodeItem* code_item) { if (code_item == nullptr) { // Abstract or native method. return; @@ -765,19 +855,18 @@ static void ResolveConstStrings(Handle<mirror::DexCache> dex_cache, const uint16_t* code_ptr = code_item->insns_; const uint16_t* code_end = code_item->insns_ + code_item->insns_size_in_code_units_; - ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); while (code_ptr < code_end) { const Instruction* inst = Instruction::At(code_ptr); switch (inst->Opcode()) { case Instruction::CONST_STRING: { uint32_t string_index = inst->VRegB_21c(); - class_linker->ResolveString(dex_file, string_index, dex_cache); + driver->CanAssumeStringIsPresentInDexCache(dex_file, string_index); break; } case Instruction::CONST_STRING_JUMBO: { uint32_t string_index = inst->VRegB_31c(); - class_linker->ResolveString(dex_file, string_index, dex_cache); + driver->CanAssumeStringIsPresentInDexCache(dex_file, string_index); break; } @@ -792,13 +881,7 @@ static void ResolveConstStrings(Handle<mirror::DexCache> dex_cache, static void ResolveConstStrings(CompilerDriver* driver, const std::vector<const DexFile*>& dex_files, TimingLogger* timings) { - ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<1> hs(soa.Self()); - ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); - MutableHandle<mirror::DexCache> dex_cache(hs.NewHandle<mirror::DexCache>(nullptr)); - for (const DexFile* dex_file : dex_files) { - dex_cache.Assign(class_linker->FindDexCache(soa.Self(), *dex_file, false)); TimingLogger::ScopedTiming t("Resolve const-string Strings", timings); size_t class_def_count = dex_file->NumClassDefs(); @@ -839,7 +922,7 @@ static void ResolveConstStrings(CompilerDriver* driver, continue; } previous_direct_method_idx = method_idx; - ResolveConstStrings(dex_cache, *dex_file, it.GetMethodCodeItem()); + ResolveConstStrings(driver, *dex_file, it.GetMethodCodeItem()); it.Next(); } // Virtual methods. @@ -853,7 +936,7 @@ static void ResolveConstStrings(CompilerDriver* driver, continue; } previous_virtual_method_idx = method_idx; - ResolveConstStrings(dex_cache, *dex_file, it.GetMethodCodeItem()); + ResolveConstStrings(driver, *dex_file, it.GetMethodCodeItem()); it.Next(); } DCHECK(!it.HasNext()); @@ -1324,6 +1407,54 @@ void CompilerDriver::MarkForDexToDexCompilation(Thread* self, const MethodRefere dex_to_dex_references_.back().GetMethodIndexes().SetBit(method_ref.dex_method_index); } +bool CompilerDriver::CanAssumeTypeIsPresentInDexCache(Handle<mirror::DexCache> dex_cache, + uint32_t type_idx) { + bool result = false; + if ((IsBootImage() && + IsImageClass(dex_cache->GetDexFile()->StringDataByIdx( + dex_cache->GetDexFile()->GetTypeId(type_idx).descriptor_idx_))) || + Runtime::Current()->UseJitCompilation()) { + mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); + result = (resolved_class != nullptr); + } + + if (result) { + stats_->TypeInDexCache(); + } else { + stats_->TypeNotInDexCache(); + } + return result; +} + +bool CompilerDriver::CanAssumeStringIsPresentInDexCache(const DexFile& dex_file, + uint32_t string_idx) { + // See also Compiler::ResolveDexFile + + bool result = false; + if (IsBootImage() || Runtime::Current()->UseJitCompilation()) { + ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<1> hs(soa.Self()); + ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); + Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache( + soa.Self(), dex_file, false))); + if (IsBootImage()) { + // We resolve all const-string strings when building for the image. + class_linker->ResolveString(dex_file, string_idx, dex_cache); + result = true; + } else { + // Just check whether the dex cache already has the string. + DCHECK(Runtime::Current()->UseJitCompilation()); + result = (dex_cache->GetResolvedString(string_idx) != nullptr); + } + } + if (result) { + stats_->StringInDexCache(); + } else { + stats_->StringNotInDexCache(); + } + return result; +} + bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx, Handle<mirror::DexCache> dex_cache, uint32_t type_idx) { @@ -1387,6 +1518,108 @@ bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_id return result; } +bool CompilerDriver::CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx, + bool* is_type_initialized, bool* use_direct_type_ptr, + uintptr_t* direct_type_ptr, bool* out_is_finalizable) { + ScopedObjectAccess soa(Thread::Current()); + Runtime* runtime = Runtime::Current(); + mirror::DexCache* dex_cache = runtime->GetClassLinker()->FindDexCache( + soa.Self(), dex_file, false); + mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx); + if (resolved_class == nullptr) { + return false; + } + if (GetCompilerOptions().GetCompilePic()) { + // Do not allow a direct class pointer to be used when compiling for position-independent + return false; + } + *out_is_finalizable = resolved_class->IsFinalizable(); + gc::Heap* heap = runtime->GetHeap(); + const bool compiling_boot = heap->IsCompilingBoot(); + const bool support_boot_image_fixup = GetSupportBootImageFixup(); + if (compiling_boot) { + // boot -> boot class pointers. + // True if the class is in the image at boot compiling time. + const bool is_image_class = IsBootImage() && IsImageClass( + dex_file.StringDataByIdx(dex_file.GetTypeId(type_idx).descriptor_idx_)); + // True if pc relative load works. + if (is_image_class && support_boot_image_fixup) { + *is_type_initialized = resolved_class->IsInitialized(); + *use_direct_type_ptr = false; + *direct_type_ptr = 0; + return true; + } else { + return false; + } + } else if (runtime->UseJitCompilation() && !heap->IsMovableObject(resolved_class)) { + *is_type_initialized = resolved_class->IsInitialized(); + // If the class may move around, then don't embed it as a direct pointer. + *use_direct_type_ptr = true; + *direct_type_ptr = reinterpret_cast<uintptr_t>(resolved_class); + return true; + } else { + // True if the class is in the image at app compiling time. + const bool class_in_image = heap->FindSpaceFromObject(resolved_class, false)->IsImageSpace(); + if (class_in_image && support_boot_image_fixup) { + // boot -> app class pointers. + *is_type_initialized = resolved_class->IsInitialized(); + // TODO This is somewhat hacky. We should refactor all of this invoke codepath. + *use_direct_type_ptr = !GetCompilerOptions().GetIncludePatchInformation(); + *direct_type_ptr = reinterpret_cast<uintptr_t>(resolved_class); + return true; + } else { + // app -> app class pointers. + // Give up because app does not have an image and class + // isn't created at compile time. TODO: implement this + // if/when each app gets an image. + return false; + } + } +} + +bool CompilerDriver::CanEmbedReferenceTypeInCode(ClassReference* ref, + bool* use_direct_ptr, + uintptr_t* direct_type_ptr) { + CHECK(ref != nullptr); + CHECK(use_direct_ptr != nullptr); + CHECK(direct_type_ptr != nullptr); + + ScopedObjectAccess soa(Thread::Current()); + mirror::Class* reference_class = mirror::Reference::GetJavaLangRefReference(); + bool is_initialized = false; + bool unused_finalizable; + // Make sure we have a finished Reference class object before attempting to use it. + if (!CanEmbedTypeInCode(*reference_class->GetDexCache()->GetDexFile(), + reference_class->GetDexTypeIndex(), &is_initialized, + use_direct_ptr, direct_type_ptr, &unused_finalizable) || + !is_initialized) { + return false; + } + ref->first = &reference_class->GetDexFile(); + ref->second = reference_class->GetDexClassDefIndex(); + return true; +} + +uint32_t CompilerDriver::GetReferenceSlowFlagOffset() const { + ScopedObjectAccess soa(Thread::Current()); + mirror::Class* klass = mirror::Reference::GetJavaLangRefReference(); + DCHECK(klass->IsInitialized()); + return klass->GetSlowPathFlagOffset().Uint32Value(); +} + +uint32_t CompilerDriver::GetReferenceDisableFlagOffset() const { + ScopedObjectAccess soa(Thread::Current()); + mirror::Class* klass = mirror::Reference::GetJavaLangRefReference(); + DCHECK(klass->IsInitialized()); + return klass->GetDisableIntrinsicFlagOffset().Uint32Value(); +} + +DexCacheArraysLayout CompilerDriver::GetDexCacheArraysLayout(const DexFile* dex_file) { + return ContainsElement(GetDexFilesForOatFile(), dex_file) + ? DexCacheArraysLayout(GetInstructionSetPointerSize(instruction_set_), dex_file) + : DexCacheArraysLayout(); +} + void CompilerDriver::ProcessedInstanceField(bool resolved) { if (!resolved) { stats_->UnresolvedInstanceField(); @@ -1405,6 +1638,10 @@ void CompilerDriver::ProcessedStaticField(bool resolved, bool local) { } } +void CompilerDriver::ProcessedInvoke(InvokeType invoke_type, int flags) { + stats_->ProcessedInvoke(invoke_type, flags); +} + ArtField* CompilerDriver::ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put, const ScopedObjectAccess& soa) { diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 9a4dd857fc..eb1222c315 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -182,6 +182,15 @@ class CompilerDriver { uint16_t class_def_index) REQUIRES(!requires_constructor_barrier_lock_); + // Callbacks from compiler to see what runtime checks must be generated. + + bool CanAssumeTypeIsPresentInDexCache(Handle<mirror::DexCache> dex_cache, + uint32_t type_idx) + REQUIRES_SHARED(Locks::mutator_lock_); + + bool CanAssumeStringIsPresentInDexCache(const DexFile& dex_file, uint32_t string_idx) + REQUIRES(!Locks::mutator_lock_); + // Are runtime access checks necessary in the compiled code? bool CanAccessTypeWithoutChecks(uint32_t referrer_idx, Handle<mirror::DexCache> dex_cache, @@ -196,6 +205,24 @@ class CompilerDriver { bool* out_is_finalizable) REQUIRES_SHARED(Locks::mutator_lock_); + bool CanEmbedTypeInCode(const DexFile& dex_file, uint32_t type_idx, + bool* is_type_initialized, bool* use_direct_type_ptr, + uintptr_t* direct_type_ptr, bool* out_is_finalizable); + + // Query methods for the java.lang.ref.Reference class. + bool CanEmbedReferenceTypeInCode(ClassReference* ref, + bool* use_direct_type_ptr, uintptr_t* direct_type_ptr); + uint32_t GetReferenceSlowFlagOffset() const; + uint32_t GetReferenceDisableFlagOffset() const; + + // Get the DexCache for the + mirror::DexCache* GetDexCache(const DexCompilationUnit* mUnit) + REQUIRES_SHARED(Locks::mutator_lock_); + + mirror::ClassLoader* GetClassLoader(const ScopedObjectAccess& soa, + const DexCompilationUnit* mUnit) + REQUIRES_SHARED(Locks::mutator_lock_); + // Resolve compiling method's class. Returns null on failure. mirror::Class* ResolveCompilingMethodsClass( const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, @@ -223,6 +250,19 @@ class CompilerDriver { uint32_t field_idx, bool is_static) REQUIRES_SHARED(Locks::mutator_lock_); + // Get declaration location of a resolved field. + void GetResolvedFieldDexFileLocation( + ArtField* resolved_field, const DexFile** declaring_dex_file, + uint16_t* declaring_class_idx, uint16_t* declaring_field_idx) + REQUIRES_SHARED(Locks::mutator_lock_); + + bool IsFieldVolatile(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); + MemberOffset GetFieldOffset(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); + + // Find a dex cache for a dex file. + inline mirror::DexCache* FindDexCache(const DexFile* dex_file) + REQUIRES_SHARED(Locks::mutator_lock_); + // Can we fast-path an IGET/IPUT access to an instance field? If yes, compute the field offset. std::pair<bool, bool> IsFastInstanceField( mirror::DexCache* dex_cache, mirror::Class* referrer_class, @@ -248,6 +288,15 @@ class CompilerDriver { uint32_t* storage_index) REQUIRES_SHARED(Locks::mutator_lock_); + // Is static field's in referrer's class? + bool IsStaticFieldInReferrerClass(mirror::Class* referrer_class, ArtField* resolved_field) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Is static field's class initialized? + bool IsStaticFieldsClassInitialized(mirror::Class* referrer_class, + ArtField* resolved_field) + REQUIRES_SHARED(Locks::mutator_lock_); + // Resolve a method. Returns null on failure, including incompatible class change. ArtMethod* ResolveMethod( ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache, @@ -255,8 +304,37 @@ class CompilerDriver { uint32_t method_idx, InvokeType invoke_type, bool check_incompatible_class_change = true) REQUIRES_SHARED(Locks::mutator_lock_); + // Get declaration location of a resolved field. + void GetResolvedMethodDexFileLocation( + ArtMethod* resolved_method, const DexFile** declaring_dex_file, + uint16_t* declaring_class_idx, uint16_t* declaring_method_idx) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Get the index in the vtable of the method. + uint16_t GetResolvedMethodVTableIndex( + ArtMethod* resolved_method, InvokeType type) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Is method's class initialized for an invoke? + // For static invokes to determine whether we need to consider potential call to <clinit>(). + // For non-static invokes, assuming a non-null reference, the class is always initialized. + bool IsMethodsClassInitialized(mirror::Class* referrer_class, ArtMethod* resolved_method) + REQUIRES_SHARED(Locks::mutator_lock_); + + // Get the layout of dex cache arrays for a dex file. Returns invalid layout if the + // dex cache arrays don't have a fixed layout. + DexCacheArraysLayout GetDexCacheArraysLayout(const DexFile* dex_file); + void ProcessedInstanceField(bool resolved); void ProcessedStaticField(bool resolved, bool local); + void ProcessedInvoke(InvokeType invoke_type, int flags); + + void ComputeFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, + const ScopedObjectAccess& soa, bool is_static, + ArtField** resolved_field, + mirror::Class** referrer_class, + mirror::DexCache** dex_cache) + REQUIRES_SHARED(Locks::mutator_lock_); // Can we fast path instance field access? Computes field's offset and volatility. bool ComputeInstanceFieldInfo(uint32_t field_idx, const DexCompilationUnit* mUnit, bool is_put, @@ -308,7 +386,6 @@ class CompilerDriver { void SetDedupeEnabled(bool dedupe_enabled) { compiled_method_storage_.SetDedupeEnabled(dedupe_enabled); } - bool DedupeEnabled() const { return compiled_method_storage_.DedupeEnabled(); } @@ -372,13 +449,6 @@ class CompilerDriver { return current_dex_to_dex_methods_; } - // Compute constant code and method pointers when possible. - void GetCodeAndMethodForDirectCall(const mirror::Class* referrer_class, - ArtMethod* method, - /* out */ uintptr_t* direct_code, - /* out */ uintptr_t* direct_method) - REQUIRES_SHARED(Locks::mutator_lock_); - private: // Return whether the declaring class of `resolved_member` is // available to `referrer_class` for read or write access using two @@ -407,9 +477,38 @@ class CompilerDriver { uint32_t field_idx) REQUIRES_SHARED(Locks::mutator_lock_); - mirror::ClassLoader* GetClassLoader(const ScopedObjectAccess& soa, - const DexCompilationUnit* mUnit) - REQUIRES_SHARED(Locks::mutator_lock_); + // Can we assume that the klass is initialized? + bool CanAssumeClassIsInitialized(mirror::Class* klass) + REQUIRES_SHARED(Locks::mutator_lock_); + bool CanReferrerAssumeClassIsInitialized(mirror::Class* referrer_class, mirror::Class* klass) + REQUIRES_SHARED(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 { + kBitMethodResolved = 0, + kBitVirtualMadeDirect, + kBitPreciseTypeDevirtualization, + kBitDirectCallToBoot, + kBitDirectMethodToBoot + }; + static constexpr int kFlagMethodResolved = 1 << kBitMethodResolved; + static constexpr int kFlagVirtualMadeDirect = 1 << kBitVirtualMadeDirect; + static constexpr int kFlagPreciseTypeDevirtualization = 1 << kBitPreciseTypeDevirtualization; + static constexpr int kFlagDirectCallToBoot = 1 << kBitDirectCallToBoot; + static constexpr int kFlagDirectMethodToBoot = 1 << kBitDirectMethodToBoot; + static constexpr int kFlagsMethodResolvedVirtualMadeDirect = + kFlagMethodResolved | kFlagVirtualMadeDirect; + static constexpr int kFlagsMethodResolvedPreciseTypeDevirtualization = + kFlagsMethodResolvedVirtualMadeDirect | kFlagPreciseTypeDevirtualization; + + public: // TODO make private or eliminate. + // Compute constant code and method pointers when possible. + void GetCodeAndMethodForDirectCall(const mirror::Class* referrer_class, + ArtMethod* method, + /* out */ uintptr_t* direct_code, + /* out */ uintptr_t* direct_method) + REQUIRES_SHARED(Locks::mutator_lock_); private: void PreCompile(jobject class_loader, @@ -467,6 +566,8 @@ class CompilerDriver { REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_); void UpdateImageClasses(TimingLogger* timings) REQUIRES(!Locks::mutator_lock_); + static void FindClinitImageClassesCallback(mirror::Object* object, void* arg) + REQUIRES_SHARED(Locks::mutator_lock_); void Compile(jobject class_loader, const std::vector<const DexFile*>& dex_files, |