summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/interpreter/mterp/mterp.cc101
1 files changed, 62 insertions, 39 deletions
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 4c06e12af9..abbc50936d 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -681,57 +681,80 @@ extern "C" size_t MterpSuspendCheck(Thread* self)
return MterpShouldSwitchInterpreters();
}
-// Helper function to do a null check after trying to resolve the field. Not for statics since obj
-// does not exist there. There is a suspend check, object is a double pointer to update the value
-// in the caller in case it moves.
-template<FindFieldType type, bool kAccessCheck>
-ALWAYS_INLINE static inline ArtField* FindInstanceField(uint32_t field_idx,
- ArtMethod* referrer,
- Thread* self,
- size_t size,
- mirror::Object** obj)
- REQUIRES(!Roles::uninterruptible_)
- REQUIRES_SHARED(Locks::mutator_lock_) {
+template<typename PrimType, typename RetType, typename Getter, FindFieldType kType>
+NO_INLINE RetType artGetInstanceFromMterp(uint32_t field_idx,
+ mirror::Object* obj,
+ ArtMethod* referrer,
+ Thread* self)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<1> hs(self);
- HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(obj));
- ArtField* field = FindFieldFromCode<type, kAccessCheck>(field_idx, referrer, self, size);
- if (LIKELY(field != nullptr) && UNLIKELY(h == nullptr)) {
- ThrowNullPointerExceptionForFieldAccess(field, /*is_read*/true);
- return nullptr;
+ HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(&obj)); // GC might move the object.
+ ArtField* field = FindFieldFromCode<kType, /* access_checks */ false>(
+ field_idx, referrer, self, sizeof(PrimType));
+ if (UNLIKELY(field == nullptr)) {
+ return 0; // Will throw exception by checking with Thread::Current.
}
- return field;
+ if (UNLIKELY(h == nullptr)) {
+ ThrowNullPointerExceptionForFieldAccess(field, /*is_read*/ true);
+ return 0; // Will throw exception by checking with Thread::Current.
+ }
+ return Getter::Get(obj, field);
+}
+
+template<typename PrimType, typename RetType, typename Getter>
+ALWAYS_INLINE RetType artGetInstanceFromMterpFast(uint32_t field_idx,
+ mirror::Object* obj,
+ ArtMethod* referrer,
+ Thread* self)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ constexpr bool kIsObject = std::is_same<RetType, mirror::Object*>::value;
+ constexpr FindFieldType kType = kIsObject ? InstanceObjectRead : InstancePrimitiveRead;
+
+ // This effectively inlines the fast path from ArtMethod::GetDexCache.
+ // It avoids non-inlined call which in turn allows elimination of the prologue and epilogue.
+ if (LIKELY(!referrer->IsObsolete())) {
+ // Avoid read barriers, since we need only the pointer to the native (non-movable)
+ // DexCache field array which we can get even through from-space objects.
+ ObjPtr<mirror::Class> klass = referrer->GetDeclaringClass<kWithoutReadBarrier>();
+ mirror::DexCache* dex_cache = klass->GetDexCache<kDefaultVerifyFlags, kWithoutReadBarrier>();
+ // Try to find the desired field in DexCache.
+ ArtField* field = dex_cache->GetResolvedField(field_idx, kRuntimePointerSize);
+ if (LIKELY(field != nullptr & obj != nullptr)) {
+ if (kIsDebugBuild) {
+ // Compare the fast path and slow path.
+ StackHandleScope<1> hs(self);
+ HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(&obj)); // GC might move the object.
+ DCHECK_EQ(field, (FindFieldFromCode<kType, /* access_checks */ false>(
+ field_idx, referrer, self, sizeof(PrimType))));
+ }
+ return Getter::Get(obj, field);
+ }
+ }
+ // Slow path. Last and with identical arguments so that it becomes single instruction tail call.
+ return artGetInstanceFromMterp<PrimType, RetType, Getter, kType>(field_idx, obj, referrer, self);
}
-#define ART_GET_FIELD_FROM_MTERP(Kind, PrimitiveType, RetType, SetType, \
- PrimitiveOrObject, IsObject, Ptr) \
+#define ART_GET_FIELD_FROM_MTERP(Kind, PrimType, RetType, Ptr) \
extern "C" RetType artGet ## Kind ## InstanceFromMterp(uint32_t field_idx, \
mirror::Object* obj, \
ArtMethod* referrer, \
Thread* self) \
REQUIRES_SHARED(Locks::mutator_lock_) { \
- constexpr FindFieldType kType = Instance ## PrimitiveOrObject ## Read; \
- constexpr size_t kSize = sizeof(PrimitiveType); \
- mirror::DexCache* dex_cache = referrer->GetDexCache(); \
- ArtField* field = dex_cache->GetResolvedField(field_idx, kRuntimePointerSize); \
- if (LIKELY(field != nullptr && obj != nullptr)) { \
- return field->Get ## Kind (obj)Ptr; /* NOLINT */ \
- } \
- field = FindInstanceField<kType, true>(field_idx, referrer, self, kSize, &obj); \
- if (LIKELY(field != nullptr)) { \
- return field->Get ## Kind (obj)Ptr; /* NOLINT */ \
+ struct Getter { /* Specialize the field load depending on the field type */ \
+ static RetType Get(mirror::Object* o, ArtField* f) REQUIRES_SHARED(Locks::mutator_lock_) { \
+ return f->Get##Kind(o)Ptr; \
} \
- /* Will throw exception by checking with Thread::Current. */ \
- return 0; \
+ }; \
+ return artGetInstanceFromMterpFast<PrimType, RetType, Getter>(field_idx, obj, referrer, self); \
} \
-ART_GET_FIELD_FROM_MTERP(Byte, int8_t, ssize_t, uint32_t, Primitive, false, )
-ART_GET_FIELD_FROM_MTERP(Boolean, int8_t, size_t, uint32_t, Primitive, false, )
-ART_GET_FIELD_FROM_MTERP(Short, int16_t, ssize_t, uint16_t, Primitive, false, )
-ART_GET_FIELD_FROM_MTERP(Char, int16_t, size_t, uint16_t, Primitive, false, )
-ART_GET_FIELD_FROM_MTERP(32, int32_t, size_t, uint32_t, Primitive, false, )
-ART_GET_FIELD_FROM_MTERP(64, int64_t, uint64_t, uint64_t, Primitive, false, )
-ART_GET_FIELD_FROM_MTERP(Obj, mirror::HeapReference<mirror::Object>, mirror::Object*,
- mirror::Object*, Object, true, .Ptr())
+ART_GET_FIELD_FROM_MTERP(Byte, int8_t, ssize_t, )
+ART_GET_FIELD_FROM_MTERP(Boolean, uint8_t, size_t, )
+ART_GET_FIELD_FROM_MTERP(Short, int16_t, ssize_t, )
+ART_GET_FIELD_FROM_MTERP(Char, uint16_t, size_t, )
+ART_GET_FIELD_FROM_MTERP(32, uint32_t, size_t, )
+ART_GET_FIELD_FROM_MTERP(64, uint64_t, uint64_t, )
+ART_GET_FIELD_FROM_MTERP(Obj, mirror::HeapReference<mirror::Object>, mirror::Object*, .Ptr())
#undef ART_GET_FIELD_FROM_MTERP