class CodeItemDataAccessor; class CodeItemDebugInfoAccessor; class CodeItemInstructionAccessor; class DexFile; template<class T> class Handle; class ImtConflictTable; enum InvokeType : uint32_t; union JValue; template<typename T> class LengthPrefixedArray; class OatQuickMethodHeader; class ProfilingInfo; class ScopedObjectAccessAlreadyRunnable; class ShadowFrame; class Signature;
namespace mirror { class Array; classClass; class ClassLoader; class DexCache; class IfTable; class Object; template <typename MirrorType> class ObjectArray; class PointerArray; class String;
} // namespace mirror
class EXPORT ArtMethod final { public: // Should the class state be checked on sensitive operations?
DECLARE_RUNTIME_DEBUG_FLAG(kCheckDeclaringClassState);
// The runtime dex_method_index is kDexNoIndex. To lower dependencies, we use this // constexpr, and ensure that the value is correct in art_method.cc. static constexpr uint32_t kRuntimeMethodDexMethodIndex = 0xFFFFFFFF;
// Visit the declaring class in 'method' if it is within [start_boundary, end_boundary). template<typename RootVisitorType> staticvoid VisitRoots(RootVisitorType& visitor,
uint8_t* start_boundary,
uint8_t* end_boundary,
ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_);
// Visit declaring classes of all the art-methods in 'array' that reside // in [start_boundary, end_boundary). template<PointerSize kPointerSize, typename RootVisitorType> staticvoid VisitArrayRoots(RootVisitorType& visitor,
uint8_t* start_boundary,
uint8_t* end_boundary,
LengthPrefixedArray<ArtMethod>* array)
REQUIRES_SHARED(Locks::mutator_lock_);
// This version should only be called when it's certain there is no // concurrency so there is no need to guarantee atomicity. For example, // before the method is linked. void SetAccessFlags(uint32_t new_access_flags) REQUIRES_SHARED(Locks::mutator_lock_) { // The following check ensures that we do not set `Intrinsics::kNone` (see b/228049006).
DCHECK_IMPLIES((new_access_flags & kAccIntrinsic) != 0,
(new_access_flags & kAccIntrinsicBits) != 0);
access_flags_.store(new_access_flags, std::memory_order_relaxed);
}
// Returns true if the method is a class initializer according to access flags. bool IsClassInitializer() const { return IsClassInitializer(GetAccessFlags());
}
// Returns true if the method is a copied method. bool IsCopied() const { return IsCopied(GetAccessFlags());
}
staticbool IsCopied(uint32_t access_flags) { // We do not have intrinsics for any default methods and therefore intrinsics are never copied. // So we are using a flag from the intrinsic flags range and need to check `kAccIntrinsic` too.
static_assert((kAccCopied & kAccIntrinsicBits) != 0, "kAccCopied deliberately overlaps intrinsic bits"); constbool copied = (access_flags & (kAccIntrinsic | kAccCopied)) == kAccCopied;
DCHECK_IMPLIES(IsMiranda(access_flags) || IsDefaultConflicting(access_flags), copied)
<< "Miranda or default-conflict methods must always be copied."; return copied;
}
staticbool IsMiranda(uint32_t access_flags) { // Miranda methods are marked as copied and abstract but not default. // We need to check the kAccIntrinsic too, see `IsCopied()`. static constexpr uint32_t kMask = kAccIntrinsic | kAccCopied | kAccAbstract | kAccDefault; static constexpr uint32_t kValue = kAccCopied | kAccAbstract; return (access_flags & kMask) == kValue;
}
// A default conflict method is a special sentinel method that stands for a conflict between // multiple default methods. It cannot be invoked, throwing an IncompatibleClassChangeError // if one attempts to do so. bool IsDefaultConflicting() const { return IsDefaultConflicting(GetAccessFlags());
}
staticbool IsDefaultConflicting(uint32_t access_flags) { // Default conflct methods are marked as copied, abstract and default. // We need to check the kAccIntrinsic too, see `IsCopied()`. static constexpr uint32_t kMask = kAccIntrinsic | kAccCopied | kAccAbstract | kAccDefault; static constexpr uint32_t kValue = kAccCopied | kAccAbstract | kAccDefault; return (access_flags & kMask) == kValue;
}
// Returns true if invoking this method will not throw an AbstractMethodError or // IncompatibleClassChangeError. bool IsInvokable() const { return IsInvokable(GetAccessFlags());
}
staticbool IsInvokable(uint32_t access_flags) { // Default conflicting methods are marked with `kAccAbstract` (as well as `kAccCopied` // and `kAccDefault`) but they are not considered abstract, see `IsAbstract()`.
DCHECK_EQ((access_flags & kAccAbstract) == 0,
!IsDefaultConflicting(access_flags) && !IsAbstract(access_flags)); return (access_flags & kAccAbstract) == 0;
}
// Returns true if the method is marked as pre-compiled. bool IsPreCompiled() const { return IsPreCompiled(GetAccessFlags());
}
void SetPreCompiled() REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(IsInvokable());
DCHECK(IsCompilable()); // kAccPreCompiled and kAccCompileDontBother overlaps with kAccIntrinsicBits. // We don't mark the intrinsics as precompiled, which means in JIT zygote // mode, compiled code for intrinsics will not be shared, and apps will // compile intrinsics themselves if needed. if (IsIntrinsic()) { return;
}
AddAccessFlags(kAccPreCompiled | kAccCompileDontBother);
}
// Returns true if the method resides in shared memory. bool IsMemorySharedMethod() { return IsMemorySharedMethod(GetAccessFlags());
}
staticbool IsMemorySharedMethod(uint32_t access_flags) { // There's an overlap with `kAccMemorySharedMethod` and `kAccIntrinsicBits` but that's OK as // intrinsics are always in the boot image and therefore memory shared.
static_assert((kAccMemorySharedMethod & kAccIntrinsicBits) != 0, "kAccMemorySharedMethod deliberately overlaps intrinsic bits"); if (IsIntrinsic(access_flags)) { returntrue;
}
// Checks to see if the method was annotated with @dalvik.annotation.optimization.FastNative. bool IsFastNative() const { return IsFastNative(GetAccessFlags());
}
staticbool IsFastNative(uint32_t access_flags) { // The presence of the annotation is checked by ClassLinker and recorded in access flags. // The kAccFastNative flag value is used with a different meaning for non-native methods, // so we need to check the kAccNative flag as well.
constexpr uint32_t mask = kAccFastNative | kAccNative; return (access_flags & mask) == mask;
}
// Checks to see if the method was annotated with @dalvik.annotation.optimization.CriticalNative. bool IsCriticalNative() const { return IsCriticalNative(GetAccessFlags());
}
staticbool IsCriticalNative([[maybe_unused]] uint32_t access_flags) { #ifdef ART_USE_RESTRICTED_MODE // Return false to treat all critical native methods as normal native methods instead, i.e.: // will use the generic JNI trampoline instead. // TODO(Simulator): support critical native methods returnfalse; #else // The presence of the annotation is checked by ClassLinker and recorded in access flags. // The kAccCriticalNative flag value is used with a different meaning for non-native methods, // so we need to check the kAccNative flag as well.
constexpr uint32_t mask = kAccCriticalNative | kAccNative; return (access_flags & mask) == mask; #endif
}
// Returns true if the method is managed (not native). bool IsManaged() const { return IsManaged(GetAccessFlags());
}
// Returns true if the method is managed (not native) and invokable. bool IsManagedAndInvokable() const { return IsManagedAndInvokable(GetAccessFlags());
}
// Returns true if the method is abstract. bool IsAbstract() const { return IsAbstract(GetAccessFlags());
}
staticbool IsAbstract(uint32_t access_flags) { // Default confliciting methods have `kAccAbstract` set but they are not actually abstract. return (access_flags & kAccAbstract) != 0 && !IsDefaultConflicting(access_flags);
}
// Returns true if the method is declared synthetic. bool IsSynthetic() const { return IsSynthetic(GetAccessFlags());
}
bool SkipAccessChecks() const { // The kAccSkipAccessChecks flag value is used with a different meaning for native methods, // so we need to check the kAccNative flag as well. return (GetAccessFlags() & (kAccSkipAccessChecks | kAccNative)) == kAccSkipAccessChecks;
}
void SetSkipAccessChecks() REQUIRES_SHARED(Locks::mutator_lock_) { // SkipAccessChecks() is applicable only to non-native methods.
DCHECK(!IsNative());
AddAccessFlags(kAccSkipAccessChecks);
} void ClearSkipAccessChecks() REQUIRES_SHARED(Locks::mutator_lock_) { // SkipAccessChecks() is applicable only to non-native methods.
DCHECK(!IsNative());
ClearAccessFlags(kAccSkipAccessChecks);
}
// Returns true if the method has previously been warm. bool PreviouslyWarm() const { return PreviouslyWarm(GetAccessFlags());
}
void SetPreviouslyWarm() REQUIRES_SHARED(Locks::mutator_lock_) { if (IsIntrinsic()) { // kAccPreviouslyWarm overlaps with kAccIntrinsicBits. return;
}
AddAccessFlags(kAccPreviouslyWarm);
}
// Should this method be run in the interpreter and count locks (e.g., failed structured- // locking verification)? bool MustCountLocks() const { return MustCountLocks(GetAccessFlags());
}
// Returns true if the method is using the nterp entrypoint fast path. bool HasNterpEntryPointFastPathFlag() const { return HasNterpEntryPointFastPathFlag(GetAccessFlags());
}
static uint32_t ClearNterpFastPathFlags(uint32_t access_flags) { // `kAccNterpEntryPointFastPathFlag` has a different use for native methods. if (!IsNative(access_flags)) {
access_flags &= ~kAccNterpEntryPointFastPathFlag;
}
access_flags &= ~kAccNterpInvokeFastPathFlag; return access_flags;
}
// Returns whether the method is a string constructor. The method must not // be a class initializer. (Class initializers are called from a different // context where we do not need to check for string constructors.) bool IsStringConstructor() REQUIRES_SHARED(Locks::mutator_lock_);
// Returns true if this method could be overridden by a default method. bool IsOverridableByDefaultMethod() REQUIRES_SHARED(Locks::mutator_lock_);
// Throws the error that would result from trying to invoke this method (i.e. // IncompatibleClassChangeError, AbstractMethodError, or IllegalAccessError). // Only call if !IsInvokable(); void ThrowInvocationTimeError(ObjPtr<mirror::Object> receiver)
REQUIRES_SHARED(Locks::mutator_lock_);
void SetMethodIndex(uint16_t new_method_index) REQUIRES_SHARED(Locks::mutator_lock_) { // Not called within a transaction.
method_index_ = new_method_index;
}
void SetDexMethodIndex(uint32_t new_idx) REQUIRES_SHARED(Locks::mutator_lock_) { // Not called within a transaction.
dex_method_index_ = new_idx;
}
// Lookup the Class from the type index into this method's dex cache.
ObjPtr<mirror::Class> LookupResolvedClassFromTypeIndex(dex::TypeIndex type_idx)
REQUIRES_SHARED(Locks::mutator_lock_); // Resolve the Class from the type index into this method's dex cache.
ObjPtr<mirror::Class> ResolveClassFromTypeIndex(dex::TypeIndex type_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns true if this method has the same name and signature of the other method. bool HasSameNameAndSignature(ArtMethod* other) REQUIRES_SHARED(Locks::mutator_lock_);
// Find the method that this method overrides.
ArtMethod* FindOverriddenMethod(PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
// Find the method index for this method within other_dexfile. If this method isn't present then // return dex::kDexNoIndex. The name_and_signature_idx MUST refer to a MethodId with the same // name and signature in the other_dexfile, such as the method index used to resolve this method // in the other_dexfile.
uint32_t FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
uint32_t name_and_signature_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns true if the method needs a class initialization check according to access flags. // Only static methods other than the class initializer need this check. // The caller is responsible for performing the actual check. bool NeedsClinitCheckBeforeCall() const { return NeedsClinitCheckBeforeCall(GetAccessFlags());
}
staticbool NeedsClinitCheckBeforeCall(uint32_t access_flags) { // The class initializer is special as it is invoked during initialization // and does not need the check. return IsStatic(access_flags) && !IsConstructor(access_flags);
}
// Check if the method needs a class initialization check before call // and its declaring class is not yet visibly initialized. // (The class needs to be visibly initialized before we can use entrypoints // to compiled code for static methods. See b/18161648 .) template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> bool StillNeedsClinitCheck() REQUIRES_SHARED(Locks::mutator_lock_);
// Similar to `StillNeedsClinitCheck()` but the method's declaring class may // be dead but not yet reclaimed by the GC, so we cannot do a full read barrier // but we still want to check the class status in the to-space class if any. // Note: JIT can hold and use such methods during managed heap GC. bool StillNeedsClinitCheckMayBeDead() REQUIRES_SHARED(Locks::mutator_lock_);
// Check if the declaring class has been verified and look at the to-space // class object, if any, as in `StillNeedsClinitCheckMayBeDead()`. bool IsDeclaringClassVerifiedMayBeDead() REQUIRES_SHARED(Locks::mutator_lock_);
// Takes a method and returns a 'canonical' one if the method is default (and therefore // potentially copied from some other class). For example, this ensures that the debugger does not // get confused as to which method we are in.
ArtMethod* GetCanonicalMethod(PointerSize pointer_size = kRuntimePointerSize)
REQUIRES_SHARED(Locks::mutator_lock_);
void SetEntryPointFromJni(constvoid* entrypoint)
REQUIRES_SHARED(Locks::mutator_lock_) { // The resolution method also has a JNI entrypoint for direct calls from // compiled code to the JNI dlsym lookup stub for @CriticalNative.
DCHECK(IsNative() || IsRuntimeMethod());
SetEntryPointFromJniPtrSize(entrypoint, kRuntimePointerSize);
}
// Is this a CalleSaveMethod or ResolutionMethod and therefore doesn't adhere to normal // conventions for a method of managed code. Returns false for Proxy methods.
ALWAYS_INLINE bool IsRuntimeMethod() const { return dex_method_index_ == kRuntimeMethodDexMethodIndex;
}
// Find the catch block for the given exception type and dex_pc. When a catch block is found, // indicates whether the found catch block is responsible for clearing the exception or whether // a move-exception instruction is present.
uint32_t FindCatchBlock(Handle<mirror::Class> exception_type, uint32_t dex_pc, bool* has_no_move_exception)
REQUIRES_SHARED(Locks::mutator_lock_);
// NO_THREAD_SAFETY_ANALYSIS since we don't know what the callback requires. template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, bool kVisitProxyMethod = true, typename RootVisitorType> void VisitRoots(RootVisitorType& visitor, PointerSize pointer_size) NO_THREAD_SAFETY_ANALYSIS;
// Lookup return type.
ObjPtr<mirror::Class> LookupResolvedReturnType() REQUIRES_SHARED(Locks::mutator_lock_); // Resolve return type. May cause thread suspension due to GetClassFromTypeIdx // calling ResolveType this caused a large number of bugs at call sites.
ObjPtr<mirror::Class> ResolveReturnType() REQUIRES_SHARED(Locks::mutator_lock_);
// May cause thread suspension due to class resolution. bool EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> params)
REQUIRES_SHARED(Locks::mutator_lock_);
// Size of an instance of this native class. static constexpr size_t Size(PointerSize pointer_size) { return PtrSizedFieldsOffset(pointer_size) +
(sizeof(PtrSizedFields) / sizeof(void*)) * static_cast<size_t>(pointer_size);
}
// Alignment of an instance of this native class. static constexpr size_t Alignment(PointerSize pointer_size) { // The ArtMethod alignment is the same as image pointer size. This differs from // alignof(ArtMethod) if cross-compiling with pointer_size != sizeof(void*). returnstatic_cast<size_t>(pointer_size);
}
// Returns the method header for the compiled code containing 'pc'. Note that runtime // methods will return null for this method, as they are not oat based. const OatQuickMethodHeader* GetOatQuickMethodHeader(uintptr_t pc)
REQUIRES_SHARED(Locks::mutator_lock_);
// Get compiled code for the method, return null if no code exists. constvoid* GetOatMethodQuickCode(PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns a human-readable signature for 'm'. Something like "a.b.C.m" or // "a.b.C.m(II)V" (depending on the value of 'with_signature'). static std::string PrettyMethod(ArtMethod* m, bool with_signature = true)
REQUIRES_SHARED(Locks::mutator_lock_);
std::string PrettyMethod(bool with_signature = true)
REQUIRES_SHARED(Locks::mutator_lock_); // Returns the JNI native function name for the non-overloaded method 'm'.
std::string JniShortName()
REQUIRES_SHARED(Locks::mutator_lock_); // Returns the JNI native function name for the overloaded method 'm'.
std::string JniLongName()
REQUIRES_SHARED(Locks::mutator_lock_);
// Visit the individual members of an ArtMethod. Used by imgdiag. // As imgdiag does not support mixing instruction sets or pointer sizes (e.g., using imgdiag32 // to inspect 64-bit images, etc.), we can go beneath the accessors directly to the class members. template <typename VisitorFunc> void VisitMembers(VisitorFunc& visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(IsImagePointerSize(kRuntimePointerSize));
visitor(this, &declaring_class_, "declaring_class_");
visitor(this, &access_flags_, "access_flags_");
visitor(this, &dex_method_index_, "dex_method_index_");
visitor(this, &method_index_, "method_index_");
visitor(this, &hotness_count_, "hotness_count_");
visitor(this, &ptr_sized_fields_.data_, "ptr_sized_fields_.data_");
visitor(this,
&ptr_sized_fields_.entry_point_from_quick_compiled_code_, "ptr_sized_fields_.entry_point_from_quick_compiled_code_");
}
// Returns the dex instructions of the code item for the art method. Returns an empty array for // the null code item case.
ALWAYS_INLINE CodeItemInstructionAccessor DexInstructions()
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns the dex code item data section of the DexFile for the art method.
ALWAYS_INLINE CodeItemDataAccessor DexInstructionData()
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns the dex code item debug info section of the DexFile for the art method.
ALWAYS_INLINE CodeItemDebugInfoAccessor DexInstructionDebugInfo()
REQUIRES_SHARED(Locks::mutator_lock_);
protected: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". // The class we are a part of.
GcRoot<mirror::Class> declaring_class_;
// Access flags; low 16 bits are defined by spec. // Getting and setting this flag needs to be atomic when concurrency is // possible, e.g. after this method's class is linked. Such as when setting // verifier flags and single-implementation flag.
std::atomic<std::uint32_t> access_flags_;
/* Dex file fields. The defining dex file is available via declaring_class_->dex_cache_ */
// Index into method_ids of the dex file associated with this method.
uint32_t dex_method_index_;
/* End of dex file fields. */
// Entry within a dispatch table for this method. For static/direct methods the index is into // the declaringClass.directMethods, for virtual methods the vtable and for interface methods the // interface's method array in `IfTable`s of implementing classes.
uint16_t method_index_;
union { // Non-abstract methods: The hotness we measure for this method. Not atomic, // as we allow missing increments: if the method is hot, we will see it eventually.
uint16_t hotness_count_; // Abstract interface methods: IMT index. // Abstract class (non-interface) methods: Unused (zero-initialized).
uint16_t imt_index_;
};
// Fake padding field gets inserted here.
// Must be the last fields in the method. struct PtrSizedFields { // Depending on the method type, the data is // - native method: pointer to the JNI function registered to this method // or a function to resolve the JNI function, // - resolution method: pointer to a function to resolve the method and // the JNI function for @CriticalNative. // - conflict method: ImtConflictTable, // - abstract/interface method: the single-implementation if any, // - proxy method: the original interface method or constructor, // - default conflict method: null // - other methods: during AOT the code item offset, at runtime a pointer // to the code item. void* data_;
// Method dispatch from quick compiled code invokes this pointer which may cause bridging into // the interpreter. void* entry_point_from_quick_compiled_code_;
} ptr_sized_fields_;
// Helper method for checking the class status of a possibly dead declaring class. // See `StillNeedsClinitCheckMayBeDead()` and `IsDeclaringClassVerifierMayBeDead()`.
ObjPtr<mirror::Class> GetDeclaringClassMayBeDead() REQUIRES_SHARED(Locks::mutator_lock_);
// Used by GetName and GetNameView to share common code. constchar* GetRuntimeMethodName() REQUIRES_SHARED(Locks::mutator_lock_);
DISALLOW_COPY_AND_ASSIGN(ArtMethod); // Need to use CopyFrom to deal with 32 vs 64 bits.
};
class MethodCallback { public: virtual ~MethodCallback() {}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.