From 4c0eb42259d790fddcd9978b66328dbb3ab65615 Mon Sep 17 00:00:00 2001 From: Roland Levillain Date: Fri, 24 Apr 2015 16:43:49 +0100 Subject: Ensure inlined static calls perform clinit checks in Optimizing. Calls to static methods have implicit class initialization (clinit) checks of the method's declaring class in Optimizing. However, when such a static call is inlined, the implicit clinit check vanishes, possibly leading to an incorrect behavior. To ensure that inlining static methods does not change the behavior of a program, add explicit class initialization checks (art::HClinitCheck) as well as load class instructions (art::HLoadClass) as last input of static calls (art::HInvokeStaticOrDirect) in Optimizing' control flow graphs, when the declaring class is reachable and not known to be already initialized. Then when considering the inlining of a static method call, proceed only if the method has no implicit clinit check requirement. The added explicit clinit checks are already removed by the art::PrepareForRegisterAllocation visitor. This CL also extends this visitor to turn explicit clinit checks from static invokes into implicit ones after the inlining step, by removing the added art::HLoadClass nodes mentioned hereinbefore. Change-Id: I9ba452b8bd09ae1fdd9a3797ef556e3e7e19c651 --- compiler/driver/compiler_driver.h | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'compiler/driver/compiler_driver.h') diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index ce13a17792..742e2e5857 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -280,6 +280,18 @@ class CompilerDriver { ArtField* resolved_field, uint16_t field_idx, uint32_t* storage_index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Return whether the declaring class of `resolved_method` is + // available to `referrer_class`. If this is true, compute the type + // index of the declaring class in the referrer's dex file and + // return it through the out argument `storage_index`; otherwise + // return DexFile::kDexNoIndex through `storage_index`. + bool IsClassOfStaticMethodAvailableToReferrer(mirror::DexCache* dex_cache, + mirror::Class* referrer_class, + mirror::ArtMethod* resolved_method, + uint16_t method_idx, + uint32_t* storage_index) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Is static field's in referrer's class? bool IsStaticFieldInReferrerClass(mirror::Class* referrer_class, ArtField* resolved_field) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -455,6 +467,33 @@ class CompilerDriver { } private: + // Return whether the declaring class of `resolved_member` is + // available to `referrer_class` for read or write access using two + // Boolean values returned as a pair. If is true at least for read + // access, compute the type index of the declaring class in the + // referrer's dex file and return it through the out argument + // `storage_index`; otherwise return DexFile::kDexNoIndex through + // `storage_index`. + template + std::pair IsClassOfStaticMemberAvailableToReferrer(mirror::DexCache* dex_cache, + mirror::Class* referrer_class, + ArtMember* resolved_member, + uint16_t member_idx, + uint32_t* storage_index) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // Can `referrer_class` access the resolved `member`? + // Dispatch call to mirror::Class::CanAccessResolvedField or + // mirror::Class::CanAccessResolvedMember depending on the value of + // ArtMember. + template + static bool CanAccessResolvedMember(mirror::Class* referrer_class, + mirror::Class* access_to, + ArtMember* member, + mirror::DexCache* dex_cache, + uint32_t field_idx) + 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 { -- cgit v1.2.3-59-g8ed1b