diff options
author | 2022-08-05 12:32:31 +0000 | |
---|---|---|
committer | 2022-08-09 15:02:24 +0000 | |
commit | e22aa32240589cf31d341e0f59bf0bf522b4a239 (patch) | |
tree | 38d19747a3c0957546d38036eca59ccfceaaac79 | |
parent | e9142f27e405580e76c077ac7d249373487d7753 (diff) |
Reland^2 "Use the thread local cache in interpreter / unresolved entrypoints"
This reverts commit 93d6dcb6972185c82db5b87d1648380968736f1a.
Bug: b/240233684
Reason for revert: Fixed invokeinterface
Change-Id: I135d35de43a9a7ba2e4f2d636c1b24ea88375172
-rw-r--r-- | runtime/Android.bp | 1 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils-inl.h | 241 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils.h | 11 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 12 | ||||
-rw-r--r-- | runtime/interpreter/interpreter.cc | 2 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_common.cc | 40 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_common.h | 105 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_intrinsics.cc | 678 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_intrinsics.h | 41 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_switch_impl-inl.h | 2 | ||||
-rw-r--r-- | runtime/interpreter/mterp/nterp.cc | 8 | ||||
-rw-r--r-- | runtime/interpreter/unstarted_runtime_test.cc | 6 | ||||
-rw-r--r-- | test/841-defaults/expected-stderr.txt | 0 | ||||
-rw-r--r-- | test/841-defaults/expected-stdout.txt | 0 | ||||
-rw-r--r-- | test/841-defaults/info.txt | 2 | ||||
-rw-r--r-- | test/841-defaults/src/Main.java | 132 |
16 files changed, 316 insertions, 965 deletions
diff --git a/runtime/Android.bp b/runtime/Android.bp index d58c37ae77..a2af30cfe5 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -173,7 +173,6 @@ libart_cc_defaults { "interpreter/interpreter.cc", "interpreter/interpreter_cache.cc", "interpreter/interpreter_common.cc", - "interpreter/interpreter_intrinsics.cc", "interpreter/interpreter_switch_impl0.cc", "interpreter/interpreter_switch_impl1.cc", "interpreter/interpreter_switch_impl2.cc", diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index 4ee1013816..91c266392c 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -486,6 +486,123 @@ 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 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); + 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, @@ -546,130 +663,6 @@ 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, diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index 8b6fc69bea..ae5687506a 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -143,11 +143,12 @@ inline ArtField* FindFieldFromCode(uint32_t field_idx, REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); -template<InvokeType type, bool access_check> -inline ArtMethod* FindMethodFromCode(uint32_t method_idx, - ObjPtr<mirror::Object>* this_object, - ArtMethod* referrer, - Thread* self) +template<InvokeType type> +inline ArtMethod* FindMethodToCall(Thread* self, + ArtMethod* referrer, + ObjPtr<mirror::Object>* this_object, + const Instruction& inst, + /*out*/ bool* string_init) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_); diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 60bbde4e02..91d252dc02 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -2279,12 +2279,18 @@ static TwoWordReturn artInvokeCommon(uint32_t method_idx, uint32_t shorty_len; const char* shorty = dex_file->GetMethodShorty(dex_file->GetMethodId(method_idx), &shorty_len); { - // Remember the args in case a GC happens in FindMethodFromCode. + // Remember the args in case a GC happens in FindMethodToCall. ScopedObjectAccessUnchecked soa(self->GetJniEnv()); RememberForGcArgumentVisitor visitor(sp, type == kStatic, shorty, shorty_len, &soa); visitor.VisitArguments(); - method = FindMethodFromCode<type, /*access_check=*/true>( - method_idx, &this_object, caller_method, self); + + uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp); + CodeItemInstructionAccessor accessor(caller_method->DexInstructions()); + CHECK_LT(dex_pc, accessor.InsnsSizeInCodeUnits()); + const Instruction& instr = accessor.InstructionAt(dex_pc); + bool string_init = false; + method = FindMethodToCall<type>(self, caller_method, &this_object, instr, &string_init); + visitor.FixupReferences(); } diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index 5aa2fb6eed..e6fb221b10 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -523,7 +523,7 @@ void EnterInterpreterFromDeoptimize(Thread* self, new_dex_pc = dex_pc + instr->SizeInCodeUnits(); } else if (instr->IsInvoke()) { DCHECK(deopt_method_type == DeoptimizationMethodType::kDefault); - if (IsStringInit(instr, shadow_frame->GetMethod())) { + if (IsStringInit(*instr, shadow_frame->GetMethod())) { uint16_t this_obj_vreg = GetReceiverRegisterForStringInit(instr); // Move the StringFactory.newStringFromChars() result into the register representing // "this object" when invoking the string constructor in the original dex instruction. diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 4ee4cb5a9f..a9d473b3ba 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -242,7 +242,8 @@ static ALWAYS_INLINE bool DoCallCommon(ArtMethod* called_method, JValue* result, uint16_t number_of_inputs, uint32_t (&arg)[Instruction::kMaxVarArgRegs], - uint32_t vregC) REQUIRES_SHARED(Locks::mutator_lock_); + uint32_t vregC, + bool string_init) REQUIRES_SHARED(Locks::mutator_lock_); template <bool is_range> ALWAYS_INLINE void CopyRegisters(ShadowFrame& caller_frame, @@ -1213,15 +1214,8 @@ static inline bool DoCallCommon(ArtMethod* called_method, JValue* result, uint16_t number_of_inputs, uint32_t (&arg)[Instruction::kMaxVarArgRegs], - uint32_t vregC) { - bool string_init = false; - // Replace calls to String.<init> with equivalent StringFactory call. - if (UNLIKELY(called_method->GetDeclaringClass()->IsStringClass() - && called_method->IsConstructor())) { - called_method = WellKnownClasses::StringInitToStringFactory(called_method); - string_init = true; - } - + uint32_t vregC, + bool string_init) { // Compute method information. CodeItemDataAccessor accessor(called_method->DexInstructionData()); // Number of registers for the callee's call frame. @@ -1412,8 +1406,13 @@ static inline bool DoCallCommon(ArtMethod* called_method, template<bool is_range, bool do_assignability_check> NO_STACK_PROTECTOR -bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame, - const Instruction* inst, uint16_t inst_data, JValue* result) { +bool DoCall(ArtMethod* called_method, + Thread* self, + ShadowFrame& shadow_frame, + const Instruction* inst, + uint16_t inst_data, + bool is_string_init, + JValue* result) { // Argument word count. const uint16_t number_of_inputs = (is_range) ? inst->VRegA_3rc(inst_data) : inst->VRegA_35c(inst_data); @@ -1430,8 +1429,14 @@ bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame, } return DoCallCommon<is_range, do_assignability_check>( - called_method, self, shadow_frame, - result, number_of_inputs, arg, vregC); + called_method, + self, + shadow_frame, + result, + number_of_inputs, + arg, + vregC, + is_string_init); } template <bool is_range, bool do_access_check, bool transaction_active> @@ -1558,9 +1563,12 @@ void RecordArrayElementsInTransaction(ObjPtr<mirror::Array> array, int32_t count // Explicit DoCall template function declarations. #define EXPLICIT_DO_CALL_TEMPLATE_DECL(_is_range, _do_assignability_check) \ template REQUIRES_SHARED(Locks::mutator_lock_) \ - bool DoCall<_is_range, _do_assignability_check>(ArtMethod* method, Thread* self, \ + bool DoCall<_is_range, _do_assignability_check>(ArtMethod* method, \ + Thread* self, \ ShadowFrame& shadow_frame, \ - const Instruction* inst, uint16_t inst_data, \ + const Instruction* inst, \ + uint16_t inst_data, \ + bool string_init, \ JValue* result) EXPLICIT_DO_CALL_TEMPLATE_DECL(false, false); EXPLICIT_DO_CALL_TEMPLATE_DECL(false, true); diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index fe9cf57ec5..49d7e649ea 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -20,7 +20,6 @@ #include "android-base/macros.h" #include "instrumentation.h" #include "interpreter.h" -#include "interpreter_intrinsics.h" #include "transaction.h" #include <math.h> @@ -126,8 +125,13 @@ void RecordArrayElementsInTransaction(ObjPtr<mirror::Array> array, int32_t count // DoFastInvoke and DoInvokeVirtualQuick functions. // Returns true on success, otherwise throws an exception and returns false. template<bool is_range, bool do_assignability_check> -bool DoCall(ArtMethod* called_method, Thread* self, ShadowFrame& shadow_frame, - const Instruction* inst, uint16_t inst_data, JValue* result); +bool DoCall(ArtMethod* called_method, + Thread* self, + ShadowFrame& shadow_frame, + const Instruction* inst, + uint16_t inst_data, + bool string_init, + JValue* result); // Called by the switch interpreter to know if we can stay in it. bool ShouldStayInSwitchInterpreter(ArtMethod* method) @@ -220,7 +224,7 @@ static inline ALWAYS_INLINE void PerformNonStandardReturn( // Handles all invoke-XXX/range instructions except for invoke-polymorphic[/range]. // Returns true on success, otherwise throws an exception and returns false. -template<InvokeType type, bool is_range, bool do_access_check, bool is_mterp> +template<InvokeType type, bool is_range, bool do_access_check> static ALWAYS_INLINE bool DoInvoke(Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, @@ -231,68 +235,19 @@ static ALWAYS_INLINE bool DoInvoke(Thread* self, if (UNLIKELY(self->ObserveAsyncException())) { return false; } - const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c(); - const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c(); + const uint32_t vregC = is_range ? inst->VRegC_3rc() : inst->VRegC_35c(); + ObjPtr<mirror::Object> obj = type == kStatic ? nullptr : shadow_frame.GetVRegReference(vregC); ArtMethod* sf_method = shadow_frame.GetMethod(); - - // Try to find the method in small thread-local cache first (only used when - // nterp is not used as mterp and nterp use the cache in an incompatible way). - InterpreterCache* tls_cache = self->GetInterpreterCache(); - size_t tls_value; - ArtMethod* resolved_method; - if (!IsNterpSupported() && LIKELY(tls_cache->Get(self, inst, &tls_value))) { - resolved_method = reinterpret_cast<ArtMethod*>(tls_value); - } else { - ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); - constexpr ClassLinker::ResolveMode resolve_mode = - do_access_check ? ClassLinker::ResolveMode::kCheckICCEAndIAE - : ClassLinker::ResolveMode::kNoChecks; - resolved_method = class_linker->ResolveMethod<resolve_mode>(self, method_idx, sf_method, type); - if (UNLIKELY(resolved_method == nullptr)) { - CHECK(self->IsExceptionPending()); - result->SetJ(0); - return false; - } - if (!IsNterpSupported()) { - tls_cache->Set(self, inst, reinterpret_cast<size_t>(resolved_method)); - } - } - - // Null pointer check and virtual method resolution. - ArtMethod* called_method = nullptr; - { - // `FindMethodToCall` might suspend, so don't keep `receiver` as a local - // variable after the call. - ObjPtr<mirror::Object> receiver = - (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC); - called_method = FindMethodToCall<type, do_access_check>( - method_idx, resolved_method, &receiver, sf_method, self); - if (UNLIKELY(called_method == nullptr)) { - CHECK(self->IsExceptionPending()); - result->SetJ(0); - return false; - } - } - if (UNLIKELY(!called_method->IsInvokable())) { - called_method->ThrowInvocationTimeError( - (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC)); + bool string_init = false; + ArtMethod* called_method = FindMethodToCall<type>(self, sf_method, &obj, *inst, &string_init); + if (called_method == nullptr) { + DCHECK(self->IsExceptionPending()); result->SetJ(0); return false; } - jit::Jit* jit = Runtime::Current()->GetJit(); - if (is_mterp && !is_range && called_method->IsIntrinsic()) { - if (MterpHandleIntrinsic(&shadow_frame, called_method, inst, inst_data, - shadow_frame.GetResultRegister())) { - if (jit != nullptr && sf_method != nullptr) { - jit->NotifyInterpreterToCompiledCodeTransition(self, sf_method); - } - return !self->IsExceptionPending(); - } - } - - return DoCall<is_range, do_access_check>(called_method, self, shadow_frame, inst, inst_data, - result); + return DoCall<is_range, do_access_check>( + called_method, self, shadow_frame, inst, inst_data, string_init, result); } static inline ObjPtr<mirror::MethodHandle> ResolveMethodHandle(Thread* self, @@ -760,34 +715,6 @@ void ArtInterpreterToCompiledCodeBridge(Thread* self, uint16_t arg_offset, JValue* result); -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; -} - // Set string value created from StringFactory.newStringFromXXX() into all aliases of // StringFactory.newEmptyString(). void SetStringInitValueToAllAliases(ShadowFrame* shadow_frame, diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc deleted file mode 100644 index c8344bc760..0000000000 --- a/runtime/interpreter/interpreter_intrinsics.cc +++ /dev/null @@ -1,678 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "interpreter/interpreter_intrinsics.h" - -#include "dex/dex_instruction.h" -#include "intrinsics_enum.h" -#include "interpreter/interpreter_common.h" - -namespace art { -namespace interpreter { - - -#define BINARY_INTRINSIC(name, op, get1, get2, set) \ -static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame, \ - const Instruction* inst, \ - uint16_t inst_data, \ - JValue* result_register) \ - REQUIRES_SHARED(Locks::mutator_lock_) { \ - uint32_t arg[Instruction::kMaxVarArgRegs] = {}; \ - inst->GetVarArgs(arg, inst_data); \ - result_register->set(op(shadow_frame->get1, shadow_frame->get2)); \ - return true; \ -} - -#define BINARY_II_INTRINSIC(name, op, set) \ - BINARY_INTRINSIC(name, op, GetVReg(arg[0]), GetVReg(arg[1]), set) - -#define BINARY_JJ_INTRINSIC(name, op, set) \ - BINARY_INTRINSIC(name, op, GetVRegLong(arg[0]), GetVRegLong(arg[2]), set) - -#define BINARY_JI_INTRINSIC(name, op, set) \ - BINARY_INTRINSIC(name, op, GetVRegLong(arg[0]), GetVReg(arg[2]), set) - -#define UNARY_INTRINSIC(name, op, get, set) \ -static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame, \ - const Instruction* inst, \ - uint16_t inst_data, \ - JValue* result_register) \ - REQUIRES_SHARED(Locks::mutator_lock_) { \ - uint32_t arg[Instruction::kMaxVarArgRegs] = {}; \ - inst->GetVarArgs(arg, inst_data); \ - result_register->set(op(shadow_frame->get(arg[0]))); \ - return true; \ -} - - -// java.lang.Integer.reverse(I)I -UNARY_INTRINSIC(MterpIntegerReverse, ReverseBits32, GetVReg, SetI); - -// java.lang.Integer.reverseBytes(I)I -UNARY_INTRINSIC(MterpIntegerReverseBytes, BSWAP, GetVReg, SetI); - -// java.lang.Integer.bitCount(I)I -UNARY_INTRINSIC(MterpIntegerBitCount, POPCOUNT, GetVReg, SetI); - -// java.lang.Integer.compare(II)I -BINARY_II_INTRINSIC(MterpIntegerCompare, Compare, SetI); - -// java.lang.Integer.highestOneBit(I)I -UNARY_INTRINSIC(MterpIntegerHighestOneBit, HighestOneBitValue, GetVReg, SetI); - -// java.lang.Integer.LowestOneBit(I)I -UNARY_INTRINSIC(MterpIntegerLowestOneBit, LowestOneBitValue, GetVReg, SetI); - -// java.lang.Integer.numberOfLeadingZeros(I)I -UNARY_INTRINSIC(MterpIntegerNumberOfLeadingZeros, JAVASTYLE_CLZ, GetVReg, SetI); - -// java.lang.Integer.numberOfTrailingZeros(I)I -UNARY_INTRINSIC(MterpIntegerNumberOfTrailingZeros, JAVASTYLE_CTZ, GetVReg, SetI); - -// java.lang.Integer.rotateRight(II)I -BINARY_II_INTRINSIC(MterpIntegerRotateRight, (Rot<int32_t, false>), SetI); - -// java.lang.Integer.rotateLeft(II)I -BINARY_II_INTRINSIC(MterpIntegerRotateLeft, (Rot<int32_t, true>), SetI); - -// java.lang.Integer.signum(I)I -UNARY_INTRINSIC(MterpIntegerSignum, Signum, GetVReg, SetI); - -// java.lang.Long.reverse(J)J -UNARY_INTRINSIC(MterpLongReverse, ReverseBits64, GetVRegLong, SetJ); - -// java.lang.Long.reverseBytes(J)J -UNARY_INTRINSIC(MterpLongReverseBytes, BSWAP, GetVRegLong, SetJ); - -// java.lang.Long.bitCount(J)I -UNARY_INTRINSIC(MterpLongBitCount, POPCOUNT, GetVRegLong, SetI); - -// java.lang.Long.compare(JJ)I -BINARY_JJ_INTRINSIC(MterpLongCompare, Compare, SetI); - -// java.lang.Long.highestOneBit(J)J -UNARY_INTRINSIC(MterpLongHighestOneBit, HighestOneBitValue, GetVRegLong, SetJ); - -// java.lang.Long.lowestOneBit(J)J -UNARY_INTRINSIC(MterpLongLowestOneBit, LowestOneBitValue, GetVRegLong, SetJ); - -// java.lang.Long.numberOfLeadingZeros(J)I -UNARY_INTRINSIC(MterpLongNumberOfLeadingZeros, JAVASTYLE_CLZ, GetVRegLong, SetJ); - -// java.lang.Long.numberOfTrailingZeros(J)I -UNARY_INTRINSIC(MterpLongNumberOfTrailingZeros, JAVASTYLE_CTZ, GetVRegLong, SetJ); - -// java.lang.Long.rotateRight(JI)J -BINARY_JI_INTRINSIC(MterpLongRotateRight, (Rot<int64_t, false>), SetJ); - -// java.lang.Long.rotateLeft(JI)J -BINARY_JI_INTRINSIC(MterpLongRotateLeft, (Rot<int64_t, true>), SetJ); - -// java.lang.Long.signum(J)I -UNARY_INTRINSIC(MterpLongSignum, Signum, GetVRegLong, SetI); - -// java.lang.Short.reverseBytes(S)S -UNARY_INTRINSIC(MterpShortReverseBytes, BSWAP, GetVRegShort, SetS); - -// java.lang.Math.min(II)I -BINARY_II_INTRINSIC(MterpMathMinIntInt, std::min, SetI); - -// java.lang.Math.min(JJ)J -BINARY_JJ_INTRINSIC(MterpMathMinLongLong, std::min, SetJ); - -// java.lang.Math.max(II)I -BINARY_II_INTRINSIC(MterpMathMaxIntInt, std::max, SetI); - -// java.lang.Math.max(JJ)J -BINARY_JJ_INTRINSIC(MterpMathMaxLongLong, std::max, SetJ); - -// java.lang.Math.abs(I)I -UNARY_INTRINSIC(MterpMathAbsInt, std::abs, GetVReg, SetI); - -// java.lang.Math.abs(J)J -UNARY_INTRINSIC(MterpMathAbsLong, std::abs, GetVRegLong, SetJ); - -// java.lang.Math.abs(F)F -UNARY_INTRINSIC(MterpMathAbsFloat, 0x7fffffff&, GetVReg, SetI); - -// java.lang.Math.abs(D)D -UNARY_INTRINSIC(MterpMathAbsDouble, INT64_C(0x7fffffffffffffff)&, GetVRegLong, SetJ); - -// java.lang.Math.sqrt(D)D -UNARY_INTRINSIC(MterpMathSqrt, std::sqrt, GetVRegDouble, SetD); - -// java.lang.Math.ceil(D)D -UNARY_INTRINSIC(MterpMathCeil, std::ceil, GetVRegDouble, SetD); - -// java.lang.Math.floor(D)D -UNARY_INTRINSIC(MterpMathFloor, std::floor, GetVRegDouble, SetD); - -// java.lang.Math.sin(D)D -UNARY_INTRINSIC(MterpMathSin, std::sin, GetVRegDouble, SetD); - -// java.lang.Math.cos(D)D -UNARY_INTRINSIC(MterpMathCos, std::cos, GetVRegDouble, SetD); - -// java.lang.Math.tan(D)D -UNARY_INTRINSIC(MterpMathTan, std::tan, GetVRegDouble, SetD); - -// java.lang.Math.asin(D)D -UNARY_INTRINSIC(MterpMathAsin, std::asin, GetVRegDouble, SetD); - -// java.lang.Math.acos(D)D -UNARY_INTRINSIC(MterpMathAcos, std::acos, GetVRegDouble, SetD); - -// java.lang.Math.atan(D)D -UNARY_INTRINSIC(MterpMathAtan, std::atan, GetVRegDouble, SetD); - -// java.lang.String.charAt(I)C -static ALWAYS_INLINE bool MterpStringCharAt(ShadowFrame* shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result_register) - REQUIRES_SHARED(Locks::mutator_lock_) { - uint32_t arg[Instruction::kMaxVarArgRegs] = {}; - inst->GetVarArgs(arg, inst_data); - ObjPtr<mirror::String> str = shadow_frame->GetVRegReference(arg[0])->AsString(); - int length = str->GetLength(); - int index = shadow_frame->GetVReg(arg[1]); - uint16_t res; - if (UNLIKELY(index < 0) || (index >= length)) { - return false; // Punt and let non-intrinsic version deal with the throw. - } - if (str->IsCompressed()) { - res = str->GetValueCompressed()[index]; - } else { - res = str->GetValue()[index]; - } - result_register->SetC(res); - return true; -} - -// java.lang.String.compareTo(Ljava/lang/string)I -static ALWAYS_INLINE bool MterpStringCompareTo(ShadowFrame* shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result_register) - REQUIRES_SHARED(Locks::mutator_lock_) { - uint32_t arg[Instruction::kMaxVarArgRegs] = {}; - inst->GetVarArgs(arg, inst_data); - ObjPtr<mirror::String> str = shadow_frame->GetVRegReference(arg[0])->AsString(); - ObjPtr<mirror::Object> arg1 = shadow_frame->GetVRegReference(arg[1]); - if (arg1 == nullptr) { - return false; - } - result_register->SetI(str->CompareTo(arg1->AsString())); - return true; -} - -#define STRING_INDEXOF_INTRINSIC(name, starting_pos) \ -static ALWAYS_INLINE bool Mterp##name(ShadowFrame* shadow_frame, \ - const Instruction* inst, \ - uint16_t inst_data, \ - JValue* result_register) \ - REQUIRES_SHARED(Locks::mutator_lock_) { \ - uint32_t arg[Instruction::kMaxVarArgRegs] = {}; \ - inst->GetVarArgs(arg, inst_data); \ - ObjPtr<mirror::String> str = shadow_frame->GetVRegReference(arg[0])->AsString(); \ - int ch = shadow_frame->GetVReg(arg[1]); \ - if (ch >= 0x10000) { \ - /* Punt if supplementary char. */ \ - return false; \ - } \ - result_register->SetI(str->FastIndexOf(ch, starting_pos)); \ - return true; \ -} - -// java.lang.String.indexOf(I)I -STRING_INDEXOF_INTRINSIC(StringIndexOf, 0); - -// java.lang.String.indexOf(II)I -STRING_INDEXOF_INTRINSIC(StringIndexOfAfter, shadow_frame->GetVReg(arg[2])); - -#define SIMPLE_STRING_INTRINSIC(name, operation) \ -static ALWAYS_INLINE bool Mterp##name(ShadowFrame* shadow_frame, \ - const Instruction* inst, \ - uint16_t inst_data, \ - JValue* result_register) \ - REQUIRES_SHARED(Locks::mutator_lock_) { \ - uint32_t arg[Instruction::kMaxVarArgRegs] = {}; \ - inst->GetVarArgs(arg, inst_data); \ - ObjPtr<mirror::String> str = shadow_frame->GetVRegReference(arg[0])->AsString(); \ - result_register->operation; \ - return true; \ -} - -// java.lang.String.isEmpty()Z -SIMPLE_STRING_INTRINSIC(StringIsEmpty, SetZ(str->GetLength() == 0)) - -// java.lang.String.length()I -SIMPLE_STRING_INTRINSIC(StringLength, SetI(str->GetLength())) - -// java.lang.String.getCharsNoCheck(II[CI)V -static ALWAYS_INLINE bool MterpStringGetCharsNoCheck(ShadowFrame* shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result_register ATTRIBUTE_UNUSED) - REQUIRES_SHARED(Locks::mutator_lock_) { - // Start, end & index already checked by caller - won't throw. Destination is uncompressed. - uint32_t arg[Instruction::kMaxVarArgRegs] = {}; - inst->GetVarArgs(arg, inst_data); - ObjPtr<mirror::String> str = shadow_frame->GetVRegReference(arg[0])->AsString(); - int32_t start = shadow_frame->GetVReg(arg[1]); - int32_t end = shadow_frame->GetVReg(arg[2]); - int32_t index = shadow_frame->GetVReg(arg[4]); - ObjPtr<mirror::CharArray> array = shadow_frame->GetVRegReference(arg[3])->AsCharArray(); - uint16_t* dst = array->GetData() + index; - int32_t len = (end - start); - if (str->IsCompressed()) { - const uint8_t* src_8 = str->GetValueCompressed() + start; - for (int i = 0; i < len; i++) { - dst[i] = src_8[i]; - } - } else { - uint16_t* src_16 = str->GetValue() + start; - memcpy(dst, src_16, len * sizeof(uint16_t)); - } - return true; -} - -// java.lang.String.equalsLjava/lang/Object;)Z -static ALWAYS_INLINE bool MterpStringEquals(ShadowFrame* shadow_frame, - const Instruction* inst, - uint16_t inst_data, - JValue* result_register) - REQUIRES_SHARED(Locks::mutator_lock_) { - uint32_t arg[Instruction::kMaxVarArgRegs] = {}; - inst->GetVarArgs(arg, inst_data); - ObjPtr<mirror::String> str = shadow_frame->GetVRegReference(arg[0])->AsString(); - ObjPtr<mirror::Object> obj = shadow_frame->GetVRegReference(arg[1]); - bool res = false; // Assume not equal. - if ((obj != nullptr) && obj->IsString()) { - ObjPtr<mirror::String> str2 = obj->AsString(); - if (str->GetCount() == str2->GetCount()) { - // Length & compression status are same. Can use block compare. - void* bytes1; - void* bytes2; - int len = str->GetLength(); - if (str->IsCompressed()) { - bytes1 = str->GetValueCompressed(); - bytes2 = str2->GetValueCompressed(); - } else { - len *= sizeof(uint16_t); - bytes1 = str->GetValue(); - bytes2 = str2->GetValue(); - } - res = (memcmp(bytes1, bytes2, len) == 0); - } - } - result_register->SetZ(res); - return true; -} - -#define VARHANDLE_FENCE_INTRINSIC(name, std_memory_operation) \ -static ALWAYS_INLINE bool name(ShadowFrame* shadow_frame ATTRIBUTE_UNUSED, \ - const Instruction* inst ATTRIBUTE_UNUSED, \ - uint16_t inst_data ATTRIBUTE_UNUSED, \ - JValue* result_register ATTRIBUTE_UNUSED) \ - REQUIRES_SHARED(Locks::mutator_lock_) { \ - std::atomic_thread_fence(std_memory_operation); \ - return true; \ -} - -// The VarHandle fence methods are static (unlike jdk.internal.misc.Unsafe versions). -// The fences for the LoadLoadFence and StoreStoreFence are stronger -// than strictly required, but the impact should be marginal. -VARHANDLE_FENCE_INTRINSIC(MterpVarHandleFullFence, std::memory_order_seq_cst) -VARHANDLE_FENCE_INTRINSIC(MterpVarHandleAcquireFence, std::memory_order_acquire) -VARHANDLE_FENCE_INTRINSIC(MterpVarHandleReleaseFence, std::memory_order_release) -VARHANDLE_FENCE_INTRINSIC(MterpVarHandleLoadLoadFence, std::memory_order_acquire) -VARHANDLE_FENCE_INTRINSIC(MterpVarHandleStoreStoreFence, std::memory_order_release) - -#define METHOD_HANDLE_INVOKE_INTRINSIC(name) \ -static ALWAYS_INLINE bool Mterp##name(ShadowFrame* shadow_frame, \ - const Instruction* inst, \ - uint16_t inst_data, \ - JValue* result) \ - REQUIRES_SHARED(Locks::mutator_lock_) { \ - if (inst->Opcode() == Instruction::INVOKE_POLYMORPHIC) { \ - return DoInvokePolymorphic<false>(Thread::Current(), *shadow_frame, inst, inst_data, result); \ - } else { \ - return DoInvokePolymorphic<true>(Thread::Current(), *shadow_frame, inst, inst_data, result); \ - } \ -} - -METHOD_HANDLE_INVOKE_INTRINSIC(MethodHandleInvokeExact) -METHOD_HANDLE_INVOKE_INTRINSIC(MethodHandleInvoke) - -#define VAR_HANDLE_ACCESSOR_INTRINSIC(name) \ -static ALWAYS_INLINE bool Mterp##name(ShadowFrame* shadow_frame, \ - const Instruction* inst, \ - uint16_t inst_data, \ - JValue* result) \ - REQUIRES_SHARED(Locks::mutator_lock_) { \ - return Do##name(Thread::Current(), *shadow_frame, inst, inst_data, result); \ -} - -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleCompareAndExchange) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleCompareAndExchangeAcquire) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleCompareAndExchangeRelease) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleCompareAndSet) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGet); -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAcquire) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndAdd) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndAddAcquire) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndAddRelease) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseAnd) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseAndAcquire) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseAndRelease) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseOr) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseOrAcquire) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseOrRelease) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseXor) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseXorAcquire) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndBitwiseXorRelease) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndSet) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndSetAcquire) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetAndSetRelease) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetOpaque) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleGetVolatile) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleSet) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleSetOpaque) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleSetRelease) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleSetVolatile) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleWeakCompareAndSet) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleWeakCompareAndSetAcquire) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleWeakCompareAndSetPlain) -VAR_HANDLE_ACCESSOR_INTRINSIC(VarHandleWeakCompareAndSetRelease) - -static ALWAYS_INLINE bool MterpReachabilityFence(ShadowFrame* shadow_frame ATTRIBUTE_UNUSED, - const Instruction* inst ATTRIBUTE_UNUSED, - uint16_t inst_data ATTRIBUTE_UNUSED, - JValue* result_register ATTRIBUTE_UNUSED) - REQUIRES_SHARED(Locks::mutator_lock_) { - // Do nothing; Its only purpose is to keep the argument reference live - // at preceding suspend points. That's automatic in the interpreter. - return true; -} - -// Macro to help keep track of what's left to implement. -#define UNIMPLEMENTED_CASE(name) \ - case Intrinsics::k##name: \ - res = false; \ - break; - -#define INTRINSIC_CASE(name) \ - case Intrinsics::k##name: \ - res = Mterp##name(shadow_frame, inst, inst_data, result_register); \ - break; - -bool MterpHandleIntrinsic(ShadowFrame* shadow_frame, - ArtMethod* const called_method, - const Instruction* inst, - uint16_t inst_data, - JValue* result_register) - REQUIRES_SHARED(Locks::mutator_lock_) { - Intrinsics intrinsic = static_cast<Intrinsics>(called_method->GetIntrinsic()); - bool res = false; // Assume failure - switch (intrinsic) { - UNIMPLEMENTED_CASE(DoubleDoubleToRawLongBits /* (D)J */) - UNIMPLEMENTED_CASE(DoubleDoubleToLongBits /* (D)J */) - UNIMPLEMENTED_CASE(DoubleIsInfinite /* (D)Z */) - UNIMPLEMENTED_CASE(DoubleIsNaN /* (D)Z */) - UNIMPLEMENTED_CASE(DoubleLongBitsToDouble /* (J)D */) - UNIMPLEMENTED_CASE(FloatFloatToRawIntBits /* (F)I */) - UNIMPLEMENTED_CASE(FloatFloatToIntBits /* (F)I */) - UNIMPLEMENTED_CASE(FloatIsInfinite /* (F)Z */) - UNIMPLEMENTED_CASE(FloatIsNaN /* (F)Z */) - UNIMPLEMENTED_CASE(FloatIntBitsToFloat /* (I)F */) - UNIMPLEMENTED_CASE(IntegerDivideUnsigned /* (II)I */) - UNIMPLEMENTED_CASE(LongDivideUnsigned /* (JJ)J */) - INTRINSIC_CASE(IntegerReverse) - INTRINSIC_CASE(IntegerReverseBytes) - INTRINSIC_CASE(IntegerBitCount) - INTRINSIC_CASE(IntegerCompare) - INTRINSIC_CASE(IntegerHighestOneBit) - INTRINSIC_CASE(IntegerLowestOneBit) - INTRINSIC_CASE(IntegerNumberOfLeadingZeros) - INTRINSIC_CASE(IntegerNumberOfTrailingZeros) - INTRINSIC_CASE(IntegerRotateRight) - INTRINSIC_CASE(IntegerRotateLeft) - INTRINSIC_CASE(IntegerSignum) - INTRINSIC_CASE(LongReverse) - INTRINSIC_CASE(LongReverseBytes) - INTRINSIC_CASE(LongBitCount) - INTRINSIC_CASE(LongCompare) - INTRINSIC_CASE(LongHighestOneBit) - INTRINSIC_CASE(LongLowestOneBit) - INTRINSIC_CASE(LongNumberOfLeadingZeros) - INTRINSIC_CASE(LongNumberOfTrailingZeros) - INTRINSIC_CASE(LongRotateRight) - INTRINSIC_CASE(LongRotateLeft) - INTRINSIC_CASE(LongSignum) - INTRINSIC_CASE(ShortReverseBytes) - INTRINSIC_CASE(MathAbsDouble) - INTRINSIC_CASE(MathAbsFloat) - INTRINSIC_CASE(MathAbsLong) - INTRINSIC_CASE(MathAbsInt) - UNIMPLEMENTED_CASE(MathFmaDouble /* (DDD)D */) - UNIMPLEMENTED_CASE(MathFmaFloat /* (FFF)F */) - UNIMPLEMENTED_CASE(MathMinDoubleDouble /* (DD)D */) - UNIMPLEMENTED_CASE(MathMinFloatFloat /* (FF)F */) - INTRINSIC_CASE(MathMinLongLong) - INTRINSIC_CASE(MathMinIntInt) - UNIMPLEMENTED_CASE(MathMaxDoubleDouble /* (DD)D */) - UNIMPLEMENTED_CASE(MathMaxFloatFloat /* (FF)F */) - INTRINSIC_CASE(MathMaxLongLong) - INTRINSIC_CASE(MathMaxIntInt) - INTRINSIC_CASE(MathCos) - INTRINSIC_CASE(MathSin) - INTRINSIC_CASE(MathAcos) - INTRINSIC_CASE(MathAsin) - INTRINSIC_CASE(MathAtan) - UNIMPLEMENTED_CASE(MathAtan2 /* (DD)D */) - UNIMPLEMENTED_CASE(MathCbrt /* (D)D */) - UNIMPLEMENTED_CASE(MathCosh /* (D)D */) - UNIMPLEMENTED_CASE(MathExp /* (D)D */) - UNIMPLEMENTED_CASE(MathExpm1 /* (D)D */) - UNIMPLEMENTED_CASE(MathHypot /* (DD)D */) - UNIMPLEMENTED_CASE(MathLog /* (D)D */) - UNIMPLEMENTED_CASE(MathLog10 /* (D)D */) - UNIMPLEMENTED_CASE(MathNextAfter /* (DD)D */) - UNIMPLEMENTED_CASE(MathPow /* (DD)D */) - UNIMPLEMENTED_CASE(MathSinh /* (D)D */) - INTRINSIC_CASE(MathTan) - UNIMPLEMENTED_CASE(MathTanh /* (D)D */) - INTRINSIC_CASE(MathSqrt) - INTRINSIC_CASE(MathCeil) - INTRINSIC_CASE(MathFloor) - UNIMPLEMENTED_CASE(MathRint /* (D)D */) - UNIMPLEMENTED_CASE(MathRoundDouble /* (D)J */) - UNIMPLEMENTED_CASE(MathRoundFloat /* (F)I */) - UNIMPLEMENTED_CASE(MathMultiplyHigh /* (JJ)J */) - UNIMPLEMENTED_CASE(SystemArrayCopyByte /* ([BI[BII)V */) - UNIMPLEMENTED_CASE(SystemArrayCopyChar /* ([CI[CII)V */) - UNIMPLEMENTED_CASE(SystemArrayCopyInt /* ([II[III)V */) - UNIMPLEMENTED_CASE(SystemArrayCopy /* (Ljava/lang/Object;ILjava/lang/Object;II)V */) - UNIMPLEMENTED_CASE(ThreadCurrentThread /* ()Ljava/lang/Thread; */) - UNIMPLEMENTED_CASE(MemoryPeekByte /* (J)B */) - UNIMPLEMENTED_CASE(MemoryPeekIntNative /* (J)I */) - UNIMPLEMENTED_CASE(MemoryPeekLongNative /* (J)J */) - UNIMPLEMENTED_CASE(MemoryPeekShortNative /* (J)S */) - UNIMPLEMENTED_CASE(MemoryPokeByte /* (JB)V */) - UNIMPLEMENTED_CASE(MemoryPokeIntNative /* (JI)V */) - UNIMPLEMENTED_CASE(MemoryPokeLongNative /* (JJ)V */) - UNIMPLEMENTED_CASE(MemoryPokeShortNative /* (JS)V */) - INTRINSIC_CASE(ReachabilityFence /* (Ljava/lang/Object;)V */) - INTRINSIC_CASE(StringCharAt) - INTRINSIC_CASE(StringCompareTo) - INTRINSIC_CASE(StringEquals) - INTRINSIC_CASE(StringGetCharsNoCheck) - INTRINSIC_CASE(StringIndexOf) - INTRINSIC_CASE(StringIndexOfAfter) - UNIMPLEMENTED_CASE(StringStringIndexOf /* (Ljava/lang/String;)I */) - UNIMPLEMENTED_CASE(StringStringIndexOfAfter /* (Ljava/lang/String;I)I */) - INTRINSIC_CASE(StringIsEmpty) - INTRINSIC_CASE(StringLength) - UNIMPLEMENTED_CASE(StringNewStringFromBytes /* ([BIII)Ljava/lang/String; */) - UNIMPLEMENTED_CASE(StringNewStringFromChars /* (II[C)Ljava/lang/String; */) - UNIMPLEMENTED_CASE(StringNewStringFromString /* (Ljava/lang/String;)Ljava/lang/String; */) - UNIMPLEMENTED_CASE(StringBufferAppend /* (Ljava/lang/String;)Ljava/lang/StringBuffer; */) - UNIMPLEMENTED_CASE(StringBufferLength /* ()I */) - UNIMPLEMENTED_CASE(StringBufferToString /* ()Ljava/lang/String; */) - UNIMPLEMENTED_CASE( - StringBuilderAppendObject /* (Ljava/lang/Object;)Ljava/lang/StringBuilder; */) - UNIMPLEMENTED_CASE( - StringBuilderAppendString /* (Ljava/lang/String;)Ljava/lang/StringBuilder; */) - UNIMPLEMENTED_CASE( - StringBuilderAppendCharSequence /* (Ljava/lang/CharSequence;)Ljava/lang/StringBuilder; */) - UNIMPLEMENTED_CASE(StringBuilderAppendCharArray /* ([C)Ljava/lang/StringBuilder; */) - UNIMPLEMENTED_CASE(StringBuilderAppendBoolean /* (Z)Ljava/lang/StringBuilder; */) - UNIMPLEMENTED_CASE(StringBuilderAppendChar /* (C)Ljava/lang/StringBuilder; */) - UNIMPLEMENTED_CASE(StringBuilderAppendInt /* (I)Ljava/lang/StringBuilder; */) - UNIMPLEMENTED_CASE(StringBuilderAppendLong /* (J)Ljava/lang/StringBuilder; */) - UNIMPLEMENTED_CASE(StringBuilderAppendFloat /* (F)Ljava/lang/StringBuilder; */) - UNIMPLEMENTED_CASE(StringBuilderAppendDouble /* (D)Ljava/lang/StringBuilder; */) - UNIMPLEMENTED_CASE(StringBuilderLength /* ()I */) - UNIMPLEMENTED_CASE(StringBuilderToString /* ()Ljava/lang/String; */) - UNIMPLEMENTED_CASE(UnsafeCASInt /* (Ljava/lang/Object;JII)Z */) - UNIMPLEMENTED_CASE(UnsafeCASLong /* (Ljava/lang/Object;JJJ)Z */) - UNIMPLEMENTED_CASE(UnsafeCASObject /* (Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z */) - UNIMPLEMENTED_CASE(UnsafeGet /* (Ljava/lang/Object;J)I */) - UNIMPLEMENTED_CASE(UnsafeGetVolatile /* (Ljava/lang/Object;J)I */) - UNIMPLEMENTED_CASE(UnsafeGetObject /* (Ljava/lang/Object;J)Ljava/lang/Object; */) - UNIMPLEMENTED_CASE(UnsafeGetObjectVolatile /* (Ljava/lang/Object;J)Ljava/lang/Object; */) - UNIMPLEMENTED_CASE(UnsafeGetLong /* (Ljava/lang/Object;J)J */) - UNIMPLEMENTED_CASE(UnsafeGetLongVolatile /* (Ljava/lang/Object;J)J */) - UNIMPLEMENTED_CASE(UnsafePut /* (Ljava/lang/Object;JI)V */) - UNIMPLEMENTED_CASE(UnsafePutOrdered /* (Ljava/lang/Object;JI)V */) - UNIMPLEMENTED_CASE(UnsafePutVolatile /* (Ljava/lang/Object;JI)V */) - UNIMPLEMENTED_CASE(UnsafePutObject /* (Ljava/lang/Object;JLjava/lang/Object;)V */) - UNIMPLEMENTED_CASE(UnsafePutObjectOrdered /* (Ljava/lang/Object;JLjava/lang/Object;)V */) - UNIMPLEMENTED_CASE(UnsafePutObjectVolatile /* (Ljava/lang/Object;JLjava/lang/Object;)V */) - UNIMPLEMENTED_CASE(UnsafePutLong /* (Ljava/lang/Object;JJ)V */) - UNIMPLEMENTED_CASE(UnsafePutLongOrdered /* (Ljava/lang/Object;JJ)V */) - UNIMPLEMENTED_CASE(UnsafePutLongVolatile /* (Ljava/lang/Object;JJ)V */) - UNIMPLEMENTED_CASE(UnsafeGetAndAddInt /* (Ljava/lang/Object;JI)I */) - UNIMPLEMENTED_CASE(UnsafeGetAndAddLong /* (Ljava/lang/Object;JJ)J */) - UNIMPLEMENTED_CASE(UnsafeGetAndSetInt /* (Ljava/lang/Object;JI)I */) - UNIMPLEMENTED_CASE(UnsafeGetAndSetLong /* (Ljava/lang/Object;JJ)J */) - UNIMPLEMENTED_CASE(UnsafeGetAndSetObject /* (Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object; */) - UNIMPLEMENTED_CASE(UnsafeLoadFence /* ()V */) - UNIMPLEMENTED_CASE(UnsafeStoreFence /* ()V */) - UNIMPLEMENTED_CASE(UnsafeFullFence /* ()V */) - UNIMPLEMENTED_CASE(JdkUnsafeCASInt /* (Ljava/lang/Object;JII)Z */) - UNIMPLEMENTED_CASE(JdkUnsafeCASLong /* (Ljava/lang/Object;JJJ)Z */) - UNIMPLEMENTED_CASE(JdkUnsafeCASObject /* (Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z */) - UNIMPLEMENTED_CASE(JdkUnsafeCompareAndSetInt /* (Ljava/lang/Object;JII)Z */) - UNIMPLEMENTED_CASE(JdkUnsafeCompareAndSetLong /* (Ljava/lang/Object;JJJ)Z */) - UNIMPLEMENTED_CASE(JdkUnsafeCompareAndSetObject /* (Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z */) - UNIMPLEMENTED_CASE(JdkUnsafeGet /* (Ljava/lang/Object;J)I */) - UNIMPLEMENTED_CASE(JdkUnsafeGetVolatile /* (Ljava/lang/Object;J)I */) - UNIMPLEMENTED_CASE(JdkUnsafeGetAcquire /* (Ljava/lang/Object;J)I */) - UNIMPLEMENTED_CASE(JdkUnsafeGetObject /* (Ljava/lang/Object;J)Ljava/lang/Object; */) - UNIMPLEMENTED_CASE(JdkUnsafeGetObjectVolatile /* (Ljava/lang/Object;J)Ljava/lang/Object; */) - UNIMPLEMENTED_CASE(JdkUnsafeGetObjectAcquire /* (Ljava/lang/Object;J)Ljava/lang/Object; */) - UNIMPLEMENTED_CASE(JdkUnsafeGetLong /* (Ljava/lang/Object;J)J */) - UNIMPLEMENTED_CASE(JdkUnsafeGetLongVolatile /* (Ljava/lang/Object;J)J */) - UNIMPLEMENTED_CASE(JdkUnsafeGetLongAcquire /* (Ljava/lang/Object;J)J */) - UNIMPLEMENTED_CASE(JdkUnsafePut /* (Ljava/lang/Object;JI)V */) - UNIMPLEMENTED_CASE(JdkUnsafePutOrdered /* (Ljava/lang/Object;JI)V */) - UNIMPLEMENTED_CASE(JdkUnsafePutVolatile /* (Ljava/lang/Object;JI)V */) - UNIMPLEMENTED_CASE(JdkUnsafePutRelease /* (Ljava/lang/Object;JI)V */) - UNIMPLEMENTED_CASE(JdkUnsafePutObject /* (Ljava/lang/Object;JLjava/lang/Object;)V */) - UNIMPLEMENTED_CASE(JdkUnsafePutObjectOrdered /* (Ljava/lang/Object;JLjava/lang/Object;)V */) - UNIMPLEMENTED_CASE(JdkUnsafePutObjectVolatile /* (Ljava/lang/Object;JLjava/lang/Object;)V */) - UNIMPLEMENTED_CASE(JdkUnsafePutObjectRelease /* (Ljava/lang/Object;JLjava/lang/Object;)V */) - UNIMPLEMENTED_CASE(JdkUnsafePutLong /* (Ljava/lang/Object;JJ)V */) - UNIMPLEMENTED_CASE(JdkUnsafePutLongOrdered /* (Ljava/lang/Object;JJ)V */) - UNIMPLEMENTED_CASE(JdkUnsafePutLongVolatile /* (Ljava/lang/Object;JJ)V */) - UNIMPLEMENTED_CASE(JdkUnsafePutLongRelease /* (Ljava/lang/Object;JJ)V */) - UNIMPLEMENTED_CASE(JdkUnsafeGetAndAddInt /* (Ljava/lang/Object;JI)I */) - UNIMPLEMENTED_CASE(JdkUnsafeGetAndAddLong /* (Ljava/lang/Object;JJ)J */) - UNIMPLEMENTED_CASE(JdkUnsafeGetAndSetInt /* (Ljava/lang/Object;JI)I */) - UNIMPLEMENTED_CASE(JdkUnsafeGetAndSetLong /* (Ljava/lang/Object;JJ)J */) - UNIMPLEMENTED_CASE(JdkUnsafeGetAndSetObject /* (Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object; */) - UNIMPLEMENTED_CASE(JdkUnsafeLoadFence /* ()V */) - UNIMPLEMENTED_CASE(JdkUnsafeStoreFence /* ()V */) - UNIMPLEMENTED_CASE(JdkUnsafeFullFence /* ()V */) - UNIMPLEMENTED_CASE(ReferenceGetReferent /* ()Ljava/lang/Object; */) - UNIMPLEMENTED_CASE(ReferenceRefersTo /* (Ljava/lang/Object;)Z */) - UNIMPLEMENTED_CASE(IntegerValueOf /* (I)Ljava/lang/Integer; */) - UNIMPLEMENTED_CASE(ThreadInterrupted /* ()Z */) - UNIMPLEMENTED_CASE(CRC32Update /* (II)I */) - UNIMPLEMENTED_CASE(CRC32UpdateBytes /* (I[BII)I */) - UNIMPLEMENTED_CASE(CRC32UpdateByteBuffer /* (IJII)I */) - UNIMPLEMENTED_CASE(FP16Compare /* (SS)I */) - UNIMPLEMENTED_CASE(FP16ToFloat /* (S)F */) - UNIMPLEMENTED_CASE(FP16ToHalf /* (F)S */) - UNIMPLEMENTED_CASE(FP16Floor /* (S)S */) - UNIMPLEMENTED_CASE(FP16Ceil /* (S)S */) - UNIMPLEMENTED_CASE(FP16Rint /* (S)S */) - UNIMPLEMENTED_CASE(FP16Greater /* (SS)Z */) - UNIMPLEMENTED_CASE(FP16GreaterEquals /* (SS)Z */) - UNIMPLEMENTED_CASE(FP16Less /* (SS)Z */) - UNIMPLEMENTED_CASE(FP16LessEquals /* (SS)Z */) - UNIMPLEMENTED_CASE(FP16Min /* (SS)S */) - UNIMPLEMENTED_CASE(FP16Max /* (SS)S */) - INTRINSIC_CASE(VarHandleFullFence) - INTRINSIC_CASE(VarHandleAcquireFence) - INTRINSIC_CASE(VarHandleReleaseFence) - INTRINSIC_CASE(VarHandleLoadLoadFence) - INTRINSIC_CASE(VarHandleStoreStoreFence) - INTRINSIC_CASE(MethodHandleInvokeExact) - INTRINSIC_CASE(MethodHandleInvoke) - INTRINSIC_CASE(VarHandleCompareAndExchange) - INTRINSIC_CASE(VarHandleCompareAndExchangeAcquire) - INTRINSIC_CASE(VarHandleCompareAndExchangeRelease) - INTRINSIC_CASE(VarHandleCompareAndSet) - INTRINSIC_CASE(VarHandleGet) - INTRINSIC_CASE(VarHandleGetAcquire) - INTRINSIC_CASE(VarHandleGetAndAdd) - INTRINSIC_CASE(VarHandleGetAndAddAcquire) - INTRINSIC_CASE(VarHandleGetAndAddRelease) - INTRINSIC_CASE(VarHandleGetAndBitwiseAnd) - INTRINSIC_CASE(VarHandleGetAndBitwiseAndAcquire) - INTRINSIC_CASE(VarHandleGetAndBitwiseAndRelease) - INTRINSIC_CASE(VarHandleGetAndBitwiseOr) - INTRINSIC_CASE(VarHandleGetAndBitwiseOrAcquire) - INTRINSIC_CASE(VarHandleGetAndBitwiseOrRelease) - INTRINSIC_CASE(VarHandleGetAndBitwiseXor) - INTRINSIC_CASE(VarHandleGetAndBitwiseXorAcquire) - INTRINSIC_CASE(VarHandleGetAndBitwiseXorRelease) - INTRINSIC_CASE(VarHandleGetAndSet) - INTRINSIC_CASE(VarHandleGetAndSetAcquire) - INTRINSIC_CASE(VarHandleGetAndSetRelease) - INTRINSIC_CASE(VarHandleGetOpaque) - INTRINSIC_CASE(VarHandleGetVolatile) - INTRINSIC_CASE(VarHandleSet) - INTRINSIC_CASE(VarHandleSetOpaque) - INTRINSIC_CASE(VarHandleSetRelease) - INTRINSIC_CASE(VarHandleSetVolatile) - INTRINSIC_CASE(VarHandleWeakCompareAndSet) - INTRINSIC_CASE(VarHandleWeakCompareAndSetAcquire) - INTRINSIC_CASE(VarHandleWeakCompareAndSetPlain) - INTRINSIC_CASE(VarHandleWeakCompareAndSetRelease) - case Intrinsics::kNone: - res = false; - break; - // Note: no default case to ensure we catch any newly added intrinsics. - } - return res; -} - -} // namespace interpreter -} // namespace art diff --git a/runtime/interpreter/interpreter_intrinsics.h b/runtime/interpreter/interpreter_intrinsics.h deleted file mode 100644 index 2a23002d05..0000000000 --- a/runtime/interpreter/interpreter_intrinsics.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_RUNTIME_INTERPRETER_INTERPRETER_INTRINSICS_H_ -#define ART_RUNTIME_INTERPRETER_INTERPRETER_INTRINSICS_H_ - -#include "jvalue.h" - -namespace art { - -class ArtMethod; -class Instruction; -class ShadowFrame; - -namespace interpreter { - -// Invokes to methods identified as intrinics are routed here. If there is -// no interpreter implementation, return false and a normal invoke will proceed. -bool MterpHandleIntrinsic(ShadowFrame* shadow_frame, - ArtMethod* const called_method, - const Instruction* inst, - uint16_t inst_data, - JValue* result_register); - -} // namespace interpreter -} // namespace art - -#endif // ART_RUNTIME_INTERPRETER_INTERPRETER_INTRINSICS_H_ diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h index c09050e221..215194ed21 100644 --- a/runtime/interpreter/interpreter_switch_impl-inl.h +++ b/runtime/interpreter/interpreter_switch_impl-inl.h @@ -353,7 +353,7 @@ class InstructionHandler { template<InvokeType type, bool is_range> HANDLER_ATTRIBUTES bool HandleInvoke() { - bool success = DoInvoke<type, is_range, do_access_check, /*is_mterp=*/ false>( + bool success = DoInvoke<type, is_range, do_access_check>( Self(), shadow_frame_, inst_, inst_data_, ResultRegister()); return PossiblyHandlePendingExceptionOnInvoke(!success); } diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc index be1d229845..5922efd5b8 100644 --- a/runtime/interpreter/mterp/nterp.cc +++ b/runtime/interpreter/mterp/nterp.cc @@ -26,7 +26,6 @@ #include "entrypoints/entrypoint_utils-inl.h" #include "interpreter/interpreter_cache-inl.h" #include "interpreter/interpreter_common.h" -#include "interpreter/interpreter_intrinsics.h" #include "interpreter/shadow_frame-inl.h" #include "mirror/string-alloc-inl.h" #include "nterp_helpers.h" @@ -96,13 +95,12 @@ inline void UpdateHotness(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock } template<typename T> -inline void UpdateCache(Thread* self, uint16_t* dex_pc_ptr, T value) { - DCHECK(kUseReadBarrier) << "Nterp only works with read barriers"; +inline void UpdateCache(Thread* self, const uint16_t* dex_pc_ptr, T value) { self->GetInterpreterCache()->Set(self, dex_pc_ptr, value); } template<typename T> -inline void UpdateCache(Thread* self, uint16_t* dex_pc_ptr, T* value) { +inline void UpdateCache(Thread* self, const uint16_t* dex_pc_ptr, T* value) { UpdateCache(self, dex_pc_ptr, reinterpret_cast<size_t>(value)); } @@ -252,7 +250,7 @@ extern "C" const char* NterpGetShortyFromInvokeCustom(ArtMethod* caller, uint16_ } FLATTEN -extern "C" size_t NterpGetMethod(Thread* self, ArtMethod* caller, uint16_t* dex_pc_ptr) +extern "C" size_t NterpGetMethod(Thread* self, ArtMethod* caller, const uint16_t* dex_pc_ptr) REQUIRES_SHARED(Locks::mutator_lock_) { UpdateHotness(caller); const Instruction* inst = Instruction::At(dex_pc_ptr); diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc index 75a692e48d..70948b8565 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -420,11 +420,13 @@ TEST_F(UnstartedRuntimeTest, StringInit) { shadow_frame->SetVRegReference(0, reference_empty_string.Get()); shadow_frame->SetVRegReference(1, string_arg.Get()); - interpreter::DoCall<false, false>(method, + ArtMethod* factory = WellKnownClasses::StringInitToStringFactory(method); + interpreter::DoCall<false, false>(factory, self, *shadow_frame, Instruction::At(inst_data), inst_data[0], + /* string_init= */ true, &result); ObjPtr<mirror::String> string_result = down_cast<mirror::String*>(result.GetL()); EXPECT_EQ(string_arg->GetLength(), string_result->GetLength()); @@ -1024,6 +1026,7 @@ TEST_F(UnstartedRuntimeTest, FloatConversion) { *shadow_frame, Instruction::At(inst_data), inst_data[0], + /* string_init= */ false, &result); ObjPtr<mirror::String> string_result = down_cast<mirror::String*>(result.GetL()); ASSERT_TRUE(string_result != nullptr); @@ -1179,6 +1182,7 @@ class UnstartedClassForNameTest : public UnstartedRuntimeTest { *shadow_frame, Instruction::At(inst_data), inst_data[0], + /* string_init= */ false, &result); CHECK(!self->IsExceptionPending()); } diff --git a/test/841-defaults/expected-stderr.txt b/test/841-defaults/expected-stderr.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/841-defaults/expected-stderr.txt diff --git a/test/841-defaults/expected-stdout.txt b/test/841-defaults/expected-stdout.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/841-defaults/expected-stdout.txt diff --git a/test/841-defaults/info.txt b/test/841-defaults/info.txt new file mode 100644 index 0000000000..85e265fa7e --- /dev/null +++ b/test/841-defaults/info.txt @@ -0,0 +1,2 @@ +Regression test for doing an invokeinterface on a default method whose +dex method index is greater than the imt size. diff --git a/test/841-defaults/src/Main.java b/test/841-defaults/src/Main.java new file mode 100644 index 0000000000..c07b516c2e --- /dev/null +++ b/test/841-defaults/src/Main.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +interface Itf { + default int defaultMethod1() { return 1; } + default int defaultMethod2() { return 2; } + default int defaultMethod3() { return 3; } + default int defaultMethod4() { return 4; } + default int defaultMethod5() { return 5; } + default int defaultMethod6() { return 6; } + default int defaultMethod7() { return 7; } + default int defaultMethod8() { return 8; } + default int defaultMethod9() { return 9; } + default int defaultMethod10() { return 10; } + default int defaultMethod11() { return 11; } + default int defaultMethod12() { return 12; } + default int defaultMethod13() { return 13; } + default int defaultMethod14() { return 14; } + default int defaultMethod15() { return 15; } + default int defaultMethod16() { return 16; } + default int defaultMethod17() { return 17; } + default int defaultMethod18() { return 18; } + default int defaultMethod19() { return 19; } + default int defaultMethod20() { return 20; } + default int defaultMethod21() { return 21; } + default int defaultMethod22() { return 22; } + default int defaultMethod23() { return 23; } + default int defaultMethod24() { return 24; } + default int defaultMethod25() { return 25; } + default int defaultMethod26() { return 26; } + default int defaultMethod27() { return 27; } + default int defaultMethod28() { return 28; } + default int defaultMethod29() { return 29; } + default int defaultMethod30() { return 30; } + default int defaultMethod31() { return 31; } + default int defaultMethod32() { return 32; } + default int defaultMethod33() { return 33; } + default int defaultMethod34() { return 34; } + default int defaultMethod35() { return 35; } + default int defaultMethod36() { return 36; } + default int defaultMethod37() { return 37; } + default int defaultMethod38() { return 38; } + default int defaultMethod39() { return 39; } + default int defaultMethod40() { return 40; } + default int defaultMethod41() { return 41; } + default int defaultMethod42() { return 42; } + default int defaultMethod43() { return 43; } + default int defaultMethod44() { return 44; } + default int defaultMethod45() { return 45; } + default int defaultMethod46() { return 46; } + default int defaultMethod47() { return 47; } + default int defaultMethod48() { return 48; } + default int defaultMethod49() { return 49; } + default int defaultMethod50() { return 50; } + default int defaultMethod51() { return 51; } +} + +public class Main implements Itf { + static Itf itf = new Main(); + public static void assertEquals(int value, int expected) { + if (value != expected) { + throw new Error("Expected " + expected + ", got " + value); + } + } + + public static void main(String[] args) throws Exception { + assertEquals(itf.defaultMethod1(), 1); + assertEquals(itf.defaultMethod2(), 2); + assertEquals(itf.defaultMethod3(), 3); + assertEquals(itf.defaultMethod4(), 4); + assertEquals(itf.defaultMethod5(), 5); + assertEquals(itf.defaultMethod6(), 6); + assertEquals(itf.defaultMethod7(), 7); + assertEquals(itf.defaultMethod8(), 8); + assertEquals(itf.defaultMethod9(), 9); + assertEquals(itf.defaultMethod10(), 10); + assertEquals(itf.defaultMethod11(), 11); + assertEquals(itf.defaultMethod12(), 12); + assertEquals(itf.defaultMethod13(), 13); + assertEquals(itf.defaultMethod14(), 14); + assertEquals(itf.defaultMethod15(), 15); + assertEquals(itf.defaultMethod16(), 16); + assertEquals(itf.defaultMethod17(), 17); + assertEquals(itf.defaultMethod18(), 18); + assertEquals(itf.defaultMethod19(), 19); + assertEquals(itf.defaultMethod20(), 20); + assertEquals(itf.defaultMethod21(), 21); + assertEquals(itf.defaultMethod22(), 22); + assertEquals(itf.defaultMethod23(), 23); + assertEquals(itf.defaultMethod24(), 24); + assertEquals(itf.defaultMethod25(), 25); + assertEquals(itf.defaultMethod26(), 26); + assertEquals(itf.defaultMethod27(), 27); + assertEquals(itf.defaultMethod28(), 28); + assertEquals(itf.defaultMethod29(), 29); + assertEquals(itf.defaultMethod30(), 30); + assertEquals(itf.defaultMethod31(), 31); + assertEquals(itf.defaultMethod32(), 32); + assertEquals(itf.defaultMethod33(), 33); + assertEquals(itf.defaultMethod34(), 34); + assertEquals(itf.defaultMethod35(), 35); + assertEquals(itf.defaultMethod36(), 36); + assertEquals(itf.defaultMethod37(), 37); + assertEquals(itf.defaultMethod38(), 38); + assertEquals(itf.defaultMethod39(), 39); + assertEquals(itf.defaultMethod40(), 40); + assertEquals(itf.defaultMethod41(), 41); + assertEquals(itf.defaultMethod42(), 42); + assertEquals(itf.defaultMethod43(), 43); + assertEquals(itf.defaultMethod44(), 44); + assertEquals(itf.defaultMethod45(), 45); + assertEquals(itf.defaultMethod46(), 46); + assertEquals(itf.defaultMethod47(), 47); + assertEquals(itf.defaultMethod48(), 48); + assertEquals(itf.defaultMethod49(), 49); + assertEquals(itf.defaultMethod50(), 50); + assertEquals(itf.defaultMethod51(), 51); + } +} |