summaryrefslogtreecommitdiff
path: root/runtime/entrypoints/entrypoint_utils-inl.h
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/entrypoints/entrypoint_utils-inl.h')
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h249
1 files changed, 124 insertions, 125 deletions
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index b454d49119..4ee1013816 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -486,131 +486,6 @@ EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(StaticPrimitiveWrite);
#undef EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL
#undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL
-static inline bool IsStringInit(const DexFile* dex_file, uint32_t method_idx)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- const dex::MethodId& method_id = dex_file->GetMethodId(method_idx);
- const char* class_name = dex_file->StringByTypeIdx(method_id.class_idx_);
- const char* method_name = dex_file->GetMethodName(method_id);
- // Instead of calling ResolveMethod() which has suspend point and can trigger
- // GC, look up the method symbolically.
- // Compare method's class name and method name against string init.
- // It's ok since it's not allowed to create your own java/lang/String.
- // TODO: verify that assumption.
- if ((strcmp(class_name, "Ljava/lang/String;") == 0) &&
- (strcmp(method_name, "<init>") == 0)) {
- return true;
- }
- return false;
-}
-
-static inline bool IsStringInit(const Instruction& instr, ArtMethod* caller)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (instr.Opcode() == Instruction::INVOKE_DIRECT ||
- instr.Opcode() == Instruction::INVOKE_DIRECT_RANGE) {
- uint16_t callee_method_idx = (instr.Opcode() == Instruction::INVOKE_DIRECT_RANGE) ?
- instr.VRegB_3rc() : instr.VRegB_35c();
- return IsStringInit(caller->GetDexFile(), callee_method_idx);
- }
- return false;
-}
-
-extern "C" size_t NterpGetMethod(Thread* self, ArtMethod* caller, const uint16_t* dex_pc_ptr);
-
-template <InvokeType type>
-ArtMethod* FindMethodToCall(Thread* self,
- ArtMethod* caller,
- ObjPtr<mirror::Object>* this_object,
- const Instruction& inst,
- /*out*/ bool* string_init)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
-
- // Try to find the method in thread-local cache.
- size_t tls_value = 0u;
- if (!self->GetInterpreterCache()->Get(self, &inst, &tls_value)) {
- DCHECK(!self->IsExceptionPending());
- // NterpGetMethod can suspend, so save this_object.
- StackHandleScope<1> hs(self);
- HandleWrapperObjPtr<mirror::Object> h_this(hs.NewHandleWrapper(this_object));
- tls_value = NterpGetMethod(self, caller, reinterpret_cast<const uint16_t*>(&inst));
- if (self->IsExceptionPending()) {
- return nullptr;
- }
- }
-
- if (type != kStatic && UNLIKELY((*this_object) == nullptr)) {
- if (UNLIKELY(IsStringInit(inst, caller))) {
- // Hack for String init:
- //
- // We assume that the input of String.<init> in verified code is always
- // an uninitialized reference. If it is a null constant, it must have been
- // optimized out by the compiler and we arrive here after deoptimization.
- // Do not throw NullPointerException.
- } else {
- // Maintain interpreter-like semantics where NullPointerException is thrown
- // after potential NoSuchMethodError from class linker.
- const uint32_t method_idx = inst.VRegB();
- ThrowNullPointerExceptionForMethodAccess(method_idx, type);
- return nullptr;
- }
- }
-
- static constexpr size_t kStringInitMethodFlag = 0b1;
- static constexpr size_t kInvokeInterfaceOnObjectMethodFlag = 0b1;
- static constexpr size_t kDefaultMethodFlag = 0b10;
- static constexpr size_t kMethodMask = ~0b11;
-
- ArtMethod* called_method = nullptr;
- switch (type) {
- case kDirect:
- case kSuper:
- case kStatic:
- // Note: for the interpreter, the String.<init> special casing for invocation is handled
- // in DoCallCommon.
- *string_init = ((tls_value & kStringInitMethodFlag) != 0);
- DCHECK_EQ(*string_init, IsStringInit(inst, caller));
- called_method = reinterpret_cast<ArtMethod*>(tls_value & kMethodMask);
- break;
- case kInterface:
- if ((tls_value & kInvokeInterfaceOnObjectMethodFlag) != 0) {
- // invokeinterface on a j.l.Object method.
- uint16_t method_index = tls_value >> 16;
- called_method = (*this_object)->GetClass()->GetVTableEntry(method_index, pointer_size);
- } else {
- ArtMethod* interface_method = reinterpret_cast<ArtMethod*>(tls_value & kMethodMask);
- if ((tls_value & kDefaultMethodFlag) != 0) {
- // Default non-abstract method.
- called_method = (*this_object)->GetClass()->GetImt(pointer_size)->Get(
- interface_method->GetMethodIndex(), pointer_size);
- } else {
- // Regular abstract interface method.
- called_method = (*this_object)->GetClass()->GetImt(pointer_size)->Get(
- interface_method->GetImtIndex(), pointer_size);
- }
- if (called_method->IsRuntimeMethod()) {
- called_method = (*this_object)->GetClass()->FindVirtualMethodForInterface(
- interface_method, pointer_size);
- if (UNLIKELY(called_method == nullptr)) {
- ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(
- interface_method, *this_object, caller);
- return nullptr;
- }
- }
- }
- break;
- case kVirtual:
- called_method = (*this_object)->GetClass()->GetVTableEntry(tls_value, pointer_size);
- break;
- }
-
- if (UNLIKELY(!called_method->IsInvokable())) {
- called_method->ThrowInvocationTimeError((type == kStatic) ? nullptr : *this_object);
- return nullptr;
- }
- DCHECK(!called_method->IsRuntimeMethod()) << called_method->PrettyMethod();
- return called_method;
-}
-
template<bool access_check>
ALWAYS_INLINE ArtMethod* FindSuperMethodToCall(uint32_t method_idx,
ArtMethod* resolved_method,
@@ -671,6 +546,130 @@ ALWAYS_INLINE ArtMethod* FindSuperMethodToCall(uint32_t method_idx,
return super_class->GetVTableEntry(vtable_index, linker->GetImagePointerSize());
}
+// Follow virtual/interface indirections if applicable.
+// Will throw null-pointer exception the if the object is null.
+template<InvokeType type, bool access_check>
+ALWAYS_INLINE ArtMethod* FindMethodToCall(uint32_t method_idx,
+ ArtMethod* resolved_method,
+ ObjPtr<mirror::Object>* this_object,
+ ArtMethod* referrer,
+ Thread* self)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+ // Null pointer check.
+ if (UNLIKELY(*this_object == nullptr && type != kStatic)) {
+ if (UNLIKELY(resolved_method->GetDeclaringClass()->IsStringClass() &&
+ resolved_method->IsConstructor())) {
+ // Hack for String init:
+ //
+ // We assume that the input of String.<init> in verified code is always
+ // an unitialized reference. If it is a null constant, it must have been
+ // optimized out by the compiler. Do not throw NullPointerException.
+ } else {
+ // Maintain interpreter-like semantics where NullPointerException is thrown
+ // after potential NoSuchMethodError from class linker.
+ ThrowNullPointerExceptionForMethodAccess(method_idx, type);
+ return nullptr; // Failure.
+ }
+ }
+ switch (type) {
+ case kStatic:
+ case kDirect:
+ return resolved_method;
+ case kVirtual: {
+ ObjPtr<mirror::Class> klass = (*this_object)->GetClass();
+ uint16_t vtable_index = resolved_method->GetMethodIndex();
+ if (access_check &&
+ (!klass->HasVTable() ||
+ vtable_index >= static_cast<uint32_t>(klass->GetVTableLength()))) {
+ // Behavior to agree with that of the verifier.
+ ThrowNoSuchMethodError(type, resolved_method->GetDeclaringClass(),
+ resolved_method->GetName(), resolved_method->GetSignature());
+ return nullptr; // Failure.
+ }
+ DCHECK(klass->HasVTable()) << klass->PrettyClass();
+ return klass->GetVTableEntry(vtable_index, class_linker->GetImagePointerSize());
+ }
+ case kSuper: {
+ return FindSuperMethodToCall<access_check>(method_idx, resolved_method, referrer, self);
+ }
+ case kInterface: {
+ size_t imt_index = resolved_method->GetImtIndex();
+ PointerSize pointer_size = class_linker->GetImagePointerSize();
+ ObjPtr<mirror::Class> klass = (*this_object)->GetClass();
+ ArtMethod* imt_method = klass->GetImt(pointer_size)->Get(imt_index, pointer_size);
+ if (!imt_method->IsRuntimeMethod()) {
+ if (kIsDebugBuild) {
+ ArtMethod* method = klass->FindVirtualMethodForInterface(
+ resolved_method, class_linker->GetImagePointerSize());
+ CHECK_EQ(imt_method, method) << ArtMethod::PrettyMethod(resolved_method) << " / "
+ << imt_method->PrettyMethod() << " / "
+ << ArtMethod::PrettyMethod(method) << " / "
+ << klass->PrettyClass();
+ }
+ return imt_method;
+ } else {
+ ArtMethod* interface_method = klass->FindVirtualMethodForInterface(
+ resolved_method, class_linker->GetImagePointerSize());
+ if (UNLIKELY(interface_method == nullptr)) {
+ ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method,
+ *this_object, referrer);
+ return nullptr; // Failure.
+ }
+ return interface_method;
+ }
+ }
+ default:
+ LOG(FATAL) << "Unknown invoke type " << type;
+ return nullptr; // Failure.
+ }
+}
+
+template<InvokeType type, bool access_check>
+inline ArtMethod* FindMethodFromCode(uint32_t method_idx,
+ ObjPtr<mirror::Object>* this_object,
+ ArtMethod* referrer,
+ Thread* self) {
+ ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+ constexpr ClassLinker::ResolveMode resolve_mode =
+ access_check ? ClassLinker::ResolveMode::kCheckICCEAndIAE
+ : ClassLinker::ResolveMode::kNoChecks;
+ ArtMethod* resolved_method;
+ if (type == kStatic) {
+ resolved_method = class_linker->ResolveMethod<resolve_mode>(self, method_idx, referrer, type);
+ } else {
+ StackHandleScope<1> hs(self);
+ HandleWrapperObjPtr<mirror::Object> h_this(hs.NewHandleWrapper(this_object));
+ resolved_method = class_linker->ResolveMethod<resolve_mode>(self, method_idx, referrer, type);
+ }
+ if (UNLIKELY(resolved_method == nullptr)) {
+ DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
+ return nullptr; // Failure.
+ }
+ return FindMethodToCall<type, access_check>(
+ method_idx, resolved_method, this_object, referrer, self);
+}
+
+// Explicit template declarations of FindMethodFromCode for all invoke types.
+#define EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, _access_check) \
+ template REQUIRES_SHARED(Locks::mutator_lock_) ALWAYS_INLINE \
+ ArtMethod* FindMethodFromCode<_type, _access_check>(uint32_t method_idx, \
+ ObjPtr<mirror::Object>* this_object, \
+ ArtMethod* referrer, \
+ Thread* self)
+#define EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \
+ EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, false); \
+ EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, true)
+
+EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kStatic);
+EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kDirect);
+EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kVirtual);
+EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kSuper);
+EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(kInterface);
+
+#undef EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL
+#undef EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL
+
inline ObjPtr<mirror::Class> ResolveVerifyAndClinit(dex::TypeIndex type_idx,
ArtMethod* referrer,
Thread* self,