#include"array.h" #include"base/array_ref.h" #include"base/atomic_pair.h" #include"base/bit_utils.h" #include"base/locks.h" #include"base/macros.h" #include"com_android_art_flags.h" #include"dex/dex_file.h" #include"dex/dex_file_types.h" #include"gc_root.h"// Note: must not use -inl here to avoid circular dependency. #include"linear_alloc.h" #include"object.h" #include"object_array.h"
namespace art HIDDEN {
namespace linker { class ImageWriter;
} // namespace linker
class ArtField; class ArtMethod; struct DexCacheOffsets; class DexFile; union JValue; class ReflectiveValueVisitor; class Thread;
namespace mirror {
class CallSite; classClass; class ClassLoader; class DexCache; class MethodType; class String;
template <typename T> struct alignas(8) DexCachePair {
GcRoot<T> object;
uint32_t index; // The array is initially [ {0,0}, {0,0}, {0,0} ... ] // We maintain the invariant that once a dex cache entry is populated, // the pointer is always non-0 // Any given entry would thus be: // {non-0, non-0} OR {0,0} // // It's generally sufficiently enough then to check if the // lookup index matches the stored index (for a >0 lookup index) // because if it's true the pointer is also non-null. // // For the 0th entry which is a special case, the value is either // {0,0} (initial state) or {non-0, 0} which indicates // that a valid object is stored at that index for a dex section id of 0. // // As an optimization, we want to avoid branching on the object pointer since // it's always non-null if the id branch succeeds (except for the 0th id). // Set the initial state for the 0th entry to be {0,1} which is guaranteed to fail // the lookup id == stored id branch.
DexCachePair(ObjPtr<T> object, uint32_t index);
DexCachePair() : index(0) {}
DexCachePair(const DexCachePair<T>&) = default;
DexCachePair& operator=(const DexCachePair<T>&) = default;
static uint32_t InvalidIndexForSlot(uint32_t slot) { // Since the cache size is a power of two, 0 will always map to slot 0. // Use 1 for slot 0 and 0 for all other slots. return (slot == 0) ? 1u : 0u;
}
static uint32_t InvalidIndexForSlot(uint32_t slot) { // Since the cache size is a power of two, 0 will always map to slot 0. // Use 1 for slot 0 and 0 for all other slots. return (slot == 0) ? 1u : 0u;
}
void Clear(uint32_t index) {
uint32_t slot = SlotIndex(index); // The index comparison is racy but should only be called from the transactional interpreter. // For the weak `const-string` interns feature, we clear the entry unconditionally. // Evicted entries can be re-resolved if needed, even though this can result in OOME // for a weakly interned `String` that's been collected in the meantime. if (com::android::art::flags::weak_const_string() ||
entries_[slot].load(std::memory_order_relaxed).index == index) {
DexCachePair<T> cleared(nullptr, DexCachePair<T>::InvalidIndexForSlot(slot));
entries_[slot].store(cleared, std::memory_order_relaxed);
}
}
private:
uint32_t SlotIndex(uint32_t index) { return index % size;
}
// Only to be used in locations that don't need the atomic or will later load // and read atomically.
GcRoot<T>* GetGcRootAddress(uint32_t index) REQUIRES_SHARED(Locks::mutator_lock_) {
static_assert(sizeof(GcRoot<T>) == sizeof(Atomic<GcRoot<T>>)); returnreinterpret_cast<GcRoot<T>*>(&entries_[index]);
}
// C++ mirror of java.lang.DexCache. class MANAGED DexCache final : public Object { public:
MIRROR_CLASS("Ljava/lang/DexCache;");
// Size of java.lang.DexCache.class. static uint32_t ClassSize(PointerSize pointer_size);
// Note: update the image version in image.cc if changing any of these cache sizes.
// Size of type dex cache. Needs to be a power of 2 for entrypoint assumptions to hold. static constexpr size_t kDexCacheTypeCacheSize = 1024;
static_assert(IsPowerOfTwo(kDexCacheTypeCacheSize), "Type dex cache size is not a power of 2.");
// Size of string dex cache. Needs to be a power of 2 for entrypoint assumptions to hold. static constexpr size_t kDexCacheStringCacheSize = 1024;
static_assert(IsPowerOfTwo(kDexCacheStringCacheSize), "String dex cache size is not a power of 2.");
// Size of field dex cache. Needs to be a power of 2 for entrypoint assumptions to hold. static constexpr size_t kDexCacheFieldCacheSize = 1024;
static_assert(IsPowerOfTwo(kDexCacheFieldCacheSize), "Field dex cache size is not a power of 2.");
// Size of method dex cache. Needs to be a power of 2 for entrypoint assumptions to hold. static constexpr size_t kDexCacheMethodCacheSize = 1024;
static_assert(IsPowerOfTwo(kDexCacheMethodCacheSize), "Method dex cache size is not a power of 2.");
// Size of method type dex cache. Needs to be a power of 2 for entrypoint assumptions // to hold. static constexpr size_t kDexCacheMethodTypeCacheSize = 1024;
static_assert(IsPowerOfTwo(kDexCacheMethodTypeCacheSize), "MethodType dex cache size is not a power of 2.");
// Size of an instance of java.lang.DexCache not including referenced values. static constexpr uint32_t InstanceSize() { returnsizeof(DexCache);
}
// Zero all array references. // WARNING: This does not free the memory since it is in LinearAlloc.
EXPORT void ResetNativeArrays() REQUIRES_SHARED(Locks::mutator_lock_);
// Clear a string for a string_idx, used to undo string intern transactions to make sure // the string isn't kept live. void ClearString(dex::StringIndex string_idx) REQUIRES_SHARED(Locks::mutator_lock_);
// Clear a method type for proto_idx, used to undo method type resolution // in aborted transactions to make sure the method type isn't kept live. void ClearMethodType(dex::ProtoIndex proto_idx) REQUIRES_SHARED(Locks::mutator_lock_);
// Attempts to bind |call_site_idx| to the call site |resolved|. The // caller must use the return value in place of |resolved|. This is // because multiple threads can invoke the bootstrap method each // producing a call site, but the method handle invocation on the // call site must be on a common agreed value.
ObjPtr<CallSite> SetResolvedCallSite(uint32_t call_site_idx, ObjPtr<CallSite> resolved)
REQUIRES_SHARED(Locks::mutator_lock_) WARN_UNUSED;
// Visit native gc-roots in the arrays for which 'should_visit' returns true template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor, typename ShouldVisitVisitor> void VisitNativeRoots(const Visitor& visitor, const ShouldVisitVisitor& should_visit)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_);
// Sets null to dex cache array fields which were allocated with the startup // allocator. void UnlinkStartupCaches() REQUIRES_SHARED(Locks::mutator_lock_);
// Returns whether we should allocate a full array given the number of elements. // Note: update the image version in image.cc if changing this method. staticbool ShouldAllocateFullArray(size_t number_of_elements, size_t dex_cache_size) { return number_of_elements <= dex_cache_size;
}
private: // Allocate new array in linear alloc and save it in the given fields. template<typename T>
T* AllocArray(MemberOffset obj_offset, size_t num, LinearAllocKind kind, bool startup = false)
REQUIRES_SHARED(Locks::mutator_lock_);
// Visit instance fields of the dex cache as well as its associated arrays. template <bool kVisitNativeRoots,
VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor> void VisitReferences(ObjPtr<Class> klass, const Visitor& visitor)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_);
// Returns whether we should allocate a full array given the current state of // the runtime and oat files. bool ShouldAllocateFullArrayAtStartup() REQUIRES_SHARED(Locks::mutator_lock_);
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.