summaryrefslogtreecommitdiff
path: root/runtime/art_method-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/art_method-inl.h')
-rw-r--r--runtime/art_method-inl.h309
1 files changed, 298 insertions, 11 deletions
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 844a0ffa9b..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;
@@ -388,19 +593,64 @@ inline bool ArtMethod::HasSingleImplementation() {
return (GetAccessFlags() & kAccSingleImplementation) != 0;
}
-template<ReadBarrierOption kReadBarrierOption, typename RootVisitorType>
+template<ReadBarrierOption kReadBarrierOption, bool kVisitProxyMethod, typename RootVisitorType>
void ArtMethod::VisitRoots(RootVisitorType& visitor, PointerSize pointer_size) {
if (LIKELY(!declaring_class_.IsNull())) {
visitor.VisitRoot(declaring_class_.AddressWithoutBarrier());
- ObjPtr<mirror::Class> klass = declaring_class_.Read<kReadBarrierOption>();
- if (UNLIKELY(klass->IsProxyClass())) {
- // For normal methods, dex cache shortcuts will be visited through the declaring class.
- // However, for proxies we need to keep the interface method alive, so we visit its roots.
- ArtMethod* interface_method = GetInterfaceMethodForProxyUnchecked(pointer_size);
- DCHECK(interface_method != nullptr);
- interface_method->VisitRoots<kReadBarrierOption>(visitor, pointer_size);
+ if (kVisitProxyMethod) {
+ ObjPtr<mirror::Class> klass = declaring_class_.Read<kReadBarrierOption>();
+ if (UNLIKELY(klass->IsProxyClass())) {
+ // For normal methods, dex cache shortcuts will be visited through the declaring class.
+ // However, for proxies we need to keep the interface method alive, so we visit its roots.
+ ArtMethod* interface_method = GetInterfaceMethodForProxyUnchecked(pointer_size);
+ DCHECK(interface_method != nullptr);
+ interface_method->VisitRoots<kReadBarrierOption, kVisitProxyMethod>(visitor, pointer_size);
+ }
+ }
+ }
+}
+
+template<typename RootVisitorType>
+void ArtMethod::VisitRoots(RootVisitorType& visitor,
+ uint8_t* start_boundary,
+ uint8_t* end_boundary,
+ ArtMethod* method) {
+ mirror::CompressedReference<mirror::Object>* cls_ptr =
+ reinterpret_cast<mirror::CompressedReference<mirror::Object>*>(
+ reinterpret_cast<uint8_t*>(method) + DeclaringClassOffset().Int32Value());
+ if (reinterpret_cast<uint8_t*>(cls_ptr) >= start_boundary
+ && reinterpret_cast<uint8_t*>(cls_ptr) < end_boundary) {
+ visitor.VisitRootIfNonNull(cls_ptr);
+ }
+}
+
+template<PointerSize kPointerSize, typename RootVisitorType>
+void ArtMethod::VisitArrayRoots(RootVisitorType& visitor,
+ uint8_t* start_boundary,
+ uint8_t* end_boundary,
+ LengthPrefixedArray<ArtMethod>* array) {
+ DCHECK_LE(start_boundary, end_boundary);
+ DCHECK_NE(array->size(), 0u);
+ static constexpr size_t kMethodSize = ArtMethod::Size(kPointerSize);
+ ArtMethod* first_method = &array->At(0, kMethodSize, ArtMethod::Alignment(kPointerSize));
+ DCHECK_LE(static_cast<void*>(end_boundary),
+ static_cast<void*>(reinterpret_cast<uint8_t*>(first_method)
+ + array->size() * kMethodSize));
+ uint8_t* declaring_class =
+ reinterpret_cast<uint8_t*>(first_method) + DeclaringClassOffset().Int32Value();
+ // Jump to the first class to visit.
+ if (declaring_class < start_boundary) {
+ size_t remainder = (start_boundary - declaring_class) % kMethodSize;
+ declaring_class = start_boundary;
+ if (remainder > 0) {
+ declaring_class += kMethodSize - remainder;
}
}
+ while (declaring_class < end_boundary) {
+ visitor.VisitRootIfNonNull(
+ reinterpret_cast<mirror::CompressedReference<mirror::Object>*>(declaring_class));
+ declaring_class += kMethodSize;
+ }
}
template <typename Visitor>
@@ -419,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());
}