diff options
Diffstat (limited to 'runtime/art_method-inl.h')
| -rw-r--r-- | runtime/art_method-inl.h | 248 |
1 files changed, 245 insertions, 3 deletions
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index 6499baccf8..3ea5130162 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -48,6 +48,201 @@ namespace art { +namespace detail { + +template <> struct ShortyTraits<'V'> { + using Type = void; + static Type Get(const JValue& value ATTRIBUTE_UNUSED) {} + // `kVRegCount` and `Set()` are not defined. +}; + +template <> struct ShortyTraits<'Z'> { + // Despite using `uint8_t` for `boolean` in `JValue`, we shall use `bool` here. + using Type = bool; + static Type Get(const JValue& value) { return value.GetZ() != 0u; } + static constexpr size_t kVRegCount = 1u; + static void Set(uint32_t* args, Type value) { args[0] = static_cast<uint32_t>(value ? 1u : 0u); } +}; + +template <> struct ShortyTraits<'B'> { + using Type = int8_t; + static Type Get(const JValue& value) { return value.GetB(); } + static constexpr size_t kVRegCount = 1u; + static void Set(uint32_t* args, Type value) { args[0] = static_cast<uint32_t>(value); } +}; + +template <> struct ShortyTraits<'C'> { + using Type = uint16_t; + static Type Get(const JValue& value) { return value.GetC(); } + static constexpr size_t kVRegCount = 1u; + static void Set(uint32_t* args, Type value) { args[0] = static_cast<uint32_t>(value); } +}; + +template <> struct ShortyTraits<'S'> { + using Type = int16_t; + static Type Get(const JValue& value) { return value.GetS(); } + static constexpr size_t kVRegCount = 1u; + static void Set(uint32_t* args, Type value) { args[0] = static_cast<uint32_t>(value); } +}; + +template <> struct ShortyTraits<'I'> { + using Type = int32_t; + static Type Get(const JValue& value) { return value.GetI(); } + static constexpr size_t kVRegCount = 1u; + static void Set(uint32_t* args, Type value) { args[0] = static_cast<uint32_t>(value); } +}; + +template <> struct ShortyTraits<'J'> { + using Type = int64_t; + static Type Get(const JValue& value) { return value.GetJ(); } + static constexpr size_t kVRegCount = 2u; + static void Set(uint32_t* args, Type value) { + // Little-endian representation. + args[0] = static_cast<uint32_t>(value); + args[1] = static_cast<uint32_t>(static_cast<uint64_t>(value) >> 32); + } +}; + +template <> struct ShortyTraits<'F'> { + using Type = float; + static Type Get(const JValue& value) { return value.GetF(); } + static constexpr size_t kVRegCount = 1u; + static void Set(uint32_t* args, Type value) { args[0] = bit_cast<uint32_t>(value); } +}; + +template <> struct ShortyTraits<'D'> { + using Type = double; + static Type Get(const JValue& value) { return value.GetD(); } + static constexpr size_t kVRegCount = 2u; + static void Set(uint32_t* args, Type value) { + // Little-endian representation. + uint64_t v = bit_cast<uint64_t>(value); + args[0] = static_cast<uint32_t>(v); + args[1] = static_cast<uint32_t>(v >> 32); + } +}; + +template <> struct ShortyTraits<'L'> { + using Type = ObjPtr<mirror::Object>; + static Type Get(const JValue& value) REQUIRES_SHARED(Locks::mutator_lock_) { + return value.GetL(); + } + static constexpr size_t kVRegCount = 1u; + static void Set(uint32_t* args, Type value) REQUIRES_SHARED(Locks::mutator_lock_) { + args[0] = StackReference<mirror::Object>::FromMirrorPtr(value.Ptr()).AsVRegValue(); + } +}; + +template <char... Shorty> +constexpr auto MaterializeShorty() { + constexpr size_t kSize = std::size({Shorty...}) + 1u; + return std::array<char, kSize>{Shorty..., '\0'}; +} + +template <char... ArgType> +constexpr size_t NumberOfVRegs() { + constexpr size_t kArgVRegCount[] = { + ShortyTraits<ArgType>::kVRegCount... + }; + size_t sum = 0u; + for (size_t count : kArgVRegCount) { + sum += count; + } + return sum; +} + +template <char... ArgType> +inline ALWAYS_INLINE void FillVRegs(uint32_t* vregs ATTRIBUTE_UNUSED, + typename ShortyTraits<ArgType>::Type... args ATTRIBUTE_UNUSED) + REQUIRES_SHARED(Locks::mutator_lock_) {} + +template <char FirstArgType, char... ArgType> +inline ALWAYS_INLINE void FillVRegs(uint32_t* vregs, + typename ShortyTraits<FirstArgType>::Type first_arg, + typename ShortyTraits<ArgType>::Type... args) + REQUIRES_SHARED(Locks::mutator_lock_) { + ShortyTraits<FirstArgType>::Set(vregs, first_arg); + FillVRegs<ArgType...>(vregs + ShortyTraits<FirstArgType>::kVRegCount, args...); +} + +template <char... ArgType> +inline ALWAYS_INLINE auto MaterializeVRegs(typename ShortyTraits<ArgType>::Type... args) + REQUIRES_SHARED(Locks::mutator_lock_) { + constexpr size_t kNumVRegs = NumberOfVRegs<ArgType...>(); + std::array<uint32_t, kNumVRegs> vregs; + FillVRegs<ArgType...>(vregs.data(), args...); + return vregs; +} + +} // namespace detail + +template <char ReturnType, char... ArgType> +inline typename detail::ShortyTraits<ReturnType>::Type +ArtMethod::InvokeStatic(Thread* self, typename detail::ShortyTraits<ArgType>::Type... args) { + DCHECK(IsStatic()); + DCHECK(GetDeclaringClass()->IsInitialized()); // Used only for initialized well-known classes. + JValue result; + constexpr auto shorty = detail::MaterializeShorty<ReturnType, ArgType...>(); + auto vregs = detail::MaterializeVRegs<ArgType...>(args...); + Invoke(self, vregs.data(), sizeof(vregs), &result, shorty.data()); + return detail::ShortyTraits<ReturnType>::Get(result); +} + +template <char ReturnType, char... ArgType> +typename detail::ShortyTraits<ReturnType>::Type +ArtMethod::InvokeInstance(Thread* self, + ObjPtr<mirror::Object> receiver, + typename detail::ShortyTraits<ArgType>::Type... args) { + DCHECK(!GetDeclaringClass()->IsInterface()); + DCHECK(!IsStatic()); + JValue result; + constexpr auto shorty = detail::MaterializeShorty<ReturnType, ArgType...>(); + auto vregs = detail::MaterializeVRegs<'L', ArgType...>(receiver, args...); + Invoke(self, vregs.data(), sizeof(vregs), &result, shorty.data()); + return detail::ShortyTraits<ReturnType>::Get(result); +} + +template <char ReturnType, char... ArgType> +typename detail::ShortyTraits<ReturnType>::Type +ArtMethod::InvokeFinal(Thread* self, + ObjPtr<mirror::Object> receiver, + typename detail::ShortyTraits<ArgType>::Type... args) { + DCHECK(!GetDeclaringClass()->IsInterface()); + DCHECK(!IsStatic()); + DCHECK(IsFinal() || GetDeclaringClass()->IsFinal()); + DCHECK(receiver != nullptr); + return InvokeInstance<ReturnType, ArgType...>(self, receiver, args...); +} + +template <char ReturnType, char... ArgType> +typename detail::ShortyTraits<ReturnType>::Type +ArtMethod::InvokeVirtual(Thread* self, + ObjPtr<mirror::Object> receiver, + typename detail::ShortyTraits<ArgType>::Type... args) { + DCHECK(!GetDeclaringClass()->IsInterface()); + DCHECK(!IsStatic()); + DCHECK(!IsFinal()); + DCHECK(receiver != nullptr); + ArtMethod* target_method = + receiver->GetClass()->FindVirtualMethodForVirtual(this, kRuntimePointerSize); + DCHECK(target_method != nullptr); + return target_method->InvokeInstance<ReturnType, ArgType...>(self, receiver, args...); +} + +template <char ReturnType, char... ArgType> +typename detail::ShortyTraits<ReturnType>::Type +ArtMethod::InvokeInterface(Thread* self, + ObjPtr<mirror::Object> receiver, + typename detail::ShortyTraits<ArgType>::Type... args) { + DCHECK(GetDeclaringClass()->IsInterface()); + DCHECK(!IsStatic()); + DCHECK(receiver != nullptr); + ArtMethod* target_method = + receiver->GetClass()->FindVirtualMethodForInterface(this, kRuntimePointerSize); + DCHECK(target_method != nullptr); + return target_method->InvokeInstance<ReturnType, ArgType...>(self, receiver, args...); +} + template <ReadBarrierOption kReadBarrierOption> inline ObjPtr<mirror::Class> ArtMethod::GetDeclaringClassUnchecked() { GcRootSource gc_root_source(this); @@ -102,6 +297,15 @@ inline ObjPtr<mirror::Class> ArtMethod::ResolveClassFromTypeIndex(dex::TypeIndex return type; } +inline bool ArtMethod::IsStringConstructor() { + uint32_t access_flags = GetAccessFlags(); + DCHECK(!IsClassInitializer(access_flags)); + return IsConstructor(access_flags) && + // No read barrier needed for reading a constant reference only to read + // a constant string class flag. See `ReadBarrierOption`. + GetDeclaringClass<kWithoutReadBarrier>()->IsStringClass(); +} + inline bool ArtMethod::IsOverridableByDefaultMethod() { // It is safe to avoid the read barrier here since the constant interface flag // in the `Class` object is stored before creating the `ArtMethod` and storing @@ -332,7 +536,7 @@ inline ObjPtr<mirror::DexCache> ArtMethod::GetDexCache() { return klass->GetDexCache<kDefaultVerifyFlags, kReadBarrierOption>(); } else { DCHECK(!IsProxyMethod()); - return GetObsoleteDexCache(); + return GetObsoleteDexCache<kReadBarrierOption>(); } } @@ -378,9 +582,10 @@ inline ObjPtr<mirror::Class> ArtMethod::ResolveReturnType() { return ResolveClassFromTypeIndex(GetReturnTypeIndex()); } -template <ReadBarrierOption kReadBarrierOption> inline bool ArtMethod::HasSingleImplementation() { - if (IsFinal() || GetDeclaringClass<kReadBarrierOption>()->IsFinal()) { + // No read barrier needed for reading a constant reference only to read + // a constant final class flag. See `ReadBarrierOption`. + if (IsFinal() || GetDeclaringClass<kWithoutReadBarrier>()->IsFinal()) { // We don't set kAccSingleImplementation for these cases since intrinsic // can use the flag also. return true; @@ -464,6 +669,43 @@ inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor, PointerSize poi } } +template <ReadBarrierOption kReadBarrierOption> +inline bool ArtMethod::StillNeedsClinitCheck() { + if (!NeedsClinitCheckBeforeCall()) { + return false; + } + ObjPtr<mirror::Class> klass = GetDeclaringClass<kReadBarrierOption>(); + return !klass->IsVisiblyInitialized(); +} + +inline bool ArtMethod::StillNeedsClinitCheckMayBeDead() { + if (!NeedsClinitCheckBeforeCall()) { + return false; + } + ObjPtr<mirror::Class> klass = GetDeclaringClassMayBeDead(); + return !klass->IsVisiblyInitialized(); +} + +inline bool ArtMethod::IsDeclaringClassVerifiedMayBeDead() { + ObjPtr<mirror::Class> klass = GetDeclaringClassMayBeDead(); + return klass->IsVerified(); +} + +inline ObjPtr<mirror::Class> ArtMethod::GetDeclaringClassMayBeDead() { + // Helper method for checking the status of the declaring class which may be dead. + // + // To avoid resurrecting an unreachable object, or crashing the GC in some GC phases, + // we must not use a full read barrier. Therefore we read the declaring class without + // a read barrier and check if it's already marked. If yes, we check the status of the + // to-space class object as intended. Otherwise, there is no to-space object and the + // from-space class object contains the most recent value of the status field; even if + // this races with another thread doing a read barrier and updating the status, that's + // no different from a race with a thread that just updates the status. + ObjPtr<mirror::Class> klass = GetDeclaringClass<kWithoutReadBarrier>(); + ObjPtr<mirror::Class> marked = ReadBarrier::IsMarked(klass.Ptr()); + return (marked != nullptr) ? marked : klass; +} + inline CodeItemInstructionAccessor ArtMethod::DexInstructions() { return CodeItemInstructionAccessor(*GetDexFile(), GetCodeItem()); } |