summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Nicolas Geoffray <ngeoffray@google.com> 2022-08-05 12:32:31 +0000
committer Nicolas Geoffray <ngeoffray@google.com> 2022-08-09 15:02:24 +0000
commite22aa32240589cf31d341e0f59bf0bf522b4a239 (patch)
tree38d19747a3c0957546d38036eca59ccfceaaac79
parente9142f27e405580e76c077ac7d249373487d7753 (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.bp1
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h241
-rw-r--r--runtime/entrypoints/entrypoint_utils.h11
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc12
-rw-r--r--runtime/interpreter/interpreter.cc2
-rw-r--r--runtime/interpreter/interpreter_common.cc40
-rw-r--r--runtime/interpreter/interpreter_common.h105
-rw-r--r--runtime/interpreter/interpreter_intrinsics.cc678
-rw-r--r--runtime/interpreter/interpreter_intrinsics.h41
-rw-r--r--runtime/interpreter/interpreter_switch_impl-inl.h2
-rw-r--r--runtime/interpreter/mterp/nterp.cc8
-rw-r--r--runtime/interpreter/unstarted_runtime_test.cc6
-rw-r--r--test/841-defaults/expected-stderr.txt0
-rw-r--r--test/841-defaults/expected-stdout.txt0
-rw-r--r--test/841-defaults/info.txt2
-rw-r--r--test/841-defaults/src/Main.java132
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);
+ }
+}