summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/code_generator.cc4
-rw-r--r--compiler/optimizing/intrinsics.h81
-rw-r--r--runtime/arch/arm64/quick_entrypoints_arm64.S2
-rw-r--r--runtime/arch/mips/quick_entrypoints_mips.S2
-rw-r--r--runtime/arch/mips64/quick_entrypoints_mips64.S2
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S2
-rw-r--r--runtime/art_method.cc8
-rw-r--r--runtime/art_method.h10
-rw-r--r--runtime/entrypoints/quick/quick_trampoline_entrypoints.cc59
-rw-r--r--runtime/interpreter/interpreter_common.cc450
-rw-r--r--runtime/interpreter/interpreter_common.h13
-rw-r--r--runtime/interpreter/interpreter_intrinsics.cc106
-rw-r--r--runtime/interpreter/unstarted_runtime.cc12
-rw-r--r--runtime/interpreter/unstarted_runtime_list.h1
-rw-r--r--runtime/intrinsics_list.h40
-rw-r--r--runtime/invoke_type.h13
-rw-r--r--runtime/method_handles.cc293
-rw-r--r--runtime/method_handles.h25
-rw-r--r--runtime/mirror/emulated_stack_frame.cc2
-rw-r--r--runtime/well_known_classes.cc4
-rw-r--r--runtime/well_known_classes.h1
-rwxr-xr-xtest/988-method-trace/gen_srcs.py3
22 files changed, 850 insertions, 283 deletions
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 9d0b5c865d..b8d1f52995 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -536,6 +536,7 @@ void CodeGenerator::GenerateInvokeStaticOrDirectRuntimeCall(
break;
case kVirtual:
case kInterface:
+ case kPolymorphic:
LOG(FATAL) << "Unexpected invoke type: " << invoke->GetInvokeType();
UNREACHABLE();
}
@@ -563,6 +564,9 @@ void CodeGenerator::GenerateInvokeUnresolvedRuntimeCall(HInvokeUnresolved* invok
case kInterface:
entrypoint = kQuickInvokeInterfaceTrampolineWithAccessCheck;
break;
+ case kPolymorphic:
+ LOG(FATAL) << "Unexpected invoke type: " << invoke->GetInvokeType();
+ UNREACHABLE();
}
InvokeRuntime(entrypoint, invoke, invoke->GetDexPc(), nullptr);
}
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index 4429e6e5b7..bdeb261dbe 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -256,30 +256,63 @@ void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke) { \
LOG(FATAL) << "Unreachable: intrinsic " << invoke->GetIntrinsic() \
<< " should have been converted to HIR"; \
}
-#define UNREACHABLE_INTRINSICS(Arch) \
-UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits) \
-UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits) \
-UNREACHABLE_INTRINSIC(Arch, FloatIsNaN) \
-UNREACHABLE_INTRINSIC(Arch, DoubleIsNaN) \
-UNREACHABLE_INTRINSIC(Arch, IntegerRotateLeft) \
-UNREACHABLE_INTRINSIC(Arch, LongRotateLeft) \
-UNREACHABLE_INTRINSIC(Arch, IntegerRotateRight) \
-UNREACHABLE_INTRINSIC(Arch, LongRotateRight) \
-UNREACHABLE_INTRINSIC(Arch, IntegerCompare) \
-UNREACHABLE_INTRINSIC(Arch, LongCompare) \
-UNREACHABLE_INTRINSIC(Arch, IntegerSignum) \
-UNREACHABLE_INTRINSIC(Arch, LongSignum) \
-UNREACHABLE_INTRINSIC(Arch, StringCharAt) \
-UNREACHABLE_INTRINSIC(Arch, StringIsEmpty) \
-UNREACHABLE_INTRINSIC(Arch, StringLength) \
-UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence) \
-UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence) \
-UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence) \
-UNREACHABLE_INTRINSIC(Arch, VarHandleFullFence) \
-UNREACHABLE_INTRINSIC(Arch, VarHandleAcquireFence) \
-UNREACHABLE_INTRINSIC(Arch, VarHandleReleaseFence) \
-UNREACHABLE_INTRINSIC(Arch, VarHandleLoadLoadFence) \
-UNREACHABLE_INTRINSIC(Arch, VarHandleStoreStoreFence)
+#define UNREACHABLE_INTRINSICS(Arch) \
+UNREACHABLE_INTRINSIC(Arch, FloatFloatToIntBits) \
+UNREACHABLE_INTRINSIC(Arch, DoubleDoubleToLongBits) \
+UNREACHABLE_INTRINSIC(Arch, FloatIsNaN) \
+UNREACHABLE_INTRINSIC(Arch, DoubleIsNaN) \
+UNREACHABLE_INTRINSIC(Arch, IntegerRotateLeft) \
+UNREACHABLE_INTRINSIC(Arch, LongRotateLeft) \
+UNREACHABLE_INTRINSIC(Arch, IntegerRotateRight) \
+UNREACHABLE_INTRINSIC(Arch, LongRotateRight) \
+UNREACHABLE_INTRINSIC(Arch, IntegerCompare) \
+UNREACHABLE_INTRINSIC(Arch, LongCompare) \
+UNREACHABLE_INTRINSIC(Arch, IntegerSignum) \
+UNREACHABLE_INTRINSIC(Arch, LongSignum) \
+UNREACHABLE_INTRINSIC(Arch, StringCharAt) \
+UNREACHABLE_INTRINSIC(Arch, StringIsEmpty) \
+UNREACHABLE_INTRINSIC(Arch, StringLength) \
+UNREACHABLE_INTRINSIC(Arch, UnsafeLoadFence) \
+UNREACHABLE_INTRINSIC(Arch, UnsafeStoreFence) \
+UNREACHABLE_INTRINSIC(Arch, UnsafeFullFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleFullFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleAcquireFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleReleaseFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleLoadLoadFence) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleStoreStoreFence) \
+UNREACHABLE_INTRINSIC(Arch, MethodHandleInvokeExact) \
+UNREACHABLE_INTRINSIC(Arch, MethodHandleInvoke) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleCompareAndExchange) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleCompareAndExchangeAcquire) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleCompareAndExchangeRelease) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleCompareAndSet) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGet) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAcquire) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndAdd) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndAddAcquire) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndAddRelease) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseAnd) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseAndAcquire) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseAndRelease) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseOr) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseOrAcquire) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseOrRelease) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseXor) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseXorAcquire) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndBitwiseXorRelease) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndSet) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndSetAcquire) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetAndSetRelease) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetOpaque) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleGetVolatile) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleSet) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleSetOpaque) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleSetRelease) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleSetVolatile) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleWeakCompareAndSet) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleWeakCompareAndSetAcquire) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleWeakCompareAndSetPlain) \
+UNREACHABLE_INTRINSIC(Arch, VarHandleWeakCompareAndSetRelease)
template <typename IntrinsicLocationsBuilder, typename Codegenerator>
bool IsCallFreeIntrinsic(HInvoke* invoke, Codegenerator* codegen) {
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index adfc88fd35..280e5937c6 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -2921,7 +2921,7 @@ ENTRY art_quick_invoke_polymorphic
INCREASE_FRAME 16 // Reserve space for JValue result.
str xzr, [sp, #0] // Initialize result to zero.
mov x0, sp // Set r0 to point to result.
- bl artInvokePolymorphic // ArtInvokePolymorphic(result, receiver, thread, save_area)
+ bl artInvokePolymorphic // artInvokePolymorphic(result, receiver, thread, save_area)
uxtb w0, w0 // Result is the return type descriptor as a char.
sub w0, w0, 'A' // Convert to zero based index.
cmp w0, 'Z' - 'A'
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index ee3f17d06a..489c52c0d2 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -3228,7 +3228,7 @@ ENTRY art_quick_invoke_polymorphic
sw $zero, 20($sp) # Initialize JValue result.
sw $zero, 16($sp)
la $t9, artInvokePolymorphic
- jalr $t9 # (result, receiver, Thread*, context)
+ jalr $t9 # artInvokePolymorphic(result, receiver, Thread*, context)
addiu $a0, $sp, 16 # Make $a0 a pointer to the JValue result
.macro MATCH_RETURN_TYPE c, handler
li $t0, \c
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index d4ad275f35..98ffe6504a 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -3028,7 +3028,7 @@ ENTRY art_quick_invoke_polymorphic
daddiu $sp, $sp, -8 # Reserve space for JValue result.
.cfi_adjust_cfa_offset 8
sd $zero, 0($sp) # Initialize JValue result.
- jal artInvokePolymorphic # (result, receiver, Thread*, context)
+ jal artInvokePolymorphic # artInvokePolymorphic(result, receiver, Thread*, context)
move $a0, $sp # Make $a0 a pointer to the JValue result
.macro MATCH_RETURN_TYPE c, handler
li $t0, \c
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index eecca58a41..25716dc1bb 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -2419,7 +2419,7 @@ DEFINE_FUNCTION art_quick_invoke_polymorphic
CFI_ADJUST_CFA_OFFSET(4)
PUSH ecx // pass receiver (method handle)
PUSH eax // pass JResult
- call SYMBOL(artInvokePolymorphic) // (result, receiver, Thread*, SP)
+ call SYMBOL(artInvokePolymorphic) // artInvokePolymorphic(result, receiver, Thread*, SP)
subl LITERAL('A'), %eax // Eliminate out of bounds options
cmpb LITERAL('Z' - 'A'), %al
ja .Lcleanup_and_return
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index d4297df76f..80f5c348ee 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -166,6 +166,8 @@ InvokeType ArtMethod::GetInvokeType() {
return kInterface;
} else if (IsDirect()) {
return kDirect;
+ } else if (IsPolymorphicSignature()) {
+ return kPolymorphic;
} else {
return kVirtual;
}
@@ -427,6 +429,12 @@ bool ArtMethod::IsAnnotatedWithCriticalNative() {
/* lookup_in_resolved_boot_classes */ true);
}
+bool ArtMethod::IsAnnotatedWithPolymorphicSignature() {
+ return IsAnnotatedWith(WellKnownClasses::java_lang_invoke_MethodHandle_PolymorphicSignature,
+ DexFile::kDexVisibilityRuntime,
+ /* lookup_in_resolved_boot_classes */ true);
+}
+
bool ArtMethod::IsAnnotatedWith(jclass klass,
uint32_t visibility,
bool lookup_in_resolved_boot_classes) {
diff --git a/runtime/art_method.h b/runtime/art_method.h
index caef81c601..fe85cb4afa 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -271,6 +271,12 @@ class ArtMethod FINAL {
bool IsProxyMethod() REQUIRES_SHARED(Locks::mutator_lock_);
+ bool IsPolymorphicSignature() REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Methods with a polymorphic signature have constraints that they
+ // are native and varargs. Check these first before possibly expensive call.
+ return IsNative() && IsVarargs() && IsAnnotatedWithPolymorphicSignature();
+ }
+
bool SkipAccessChecks() {
return (GetAccessFlags() & kAccSkipAccessChecks) != 0;
}
@@ -316,6 +322,10 @@ class ArtMethod FINAL {
// -- Unrelated to the GC notion of "critical".
bool IsAnnotatedWithCriticalNative();
+ // Checks to see if the method was annotated with
+ // @java.lang.invoke.MethodHandle.PolymorphicSignature.
+ bool IsAnnotatedWithPolymorphicSignature();
+
// Returns true if this method could be overridden by a default method.
bool IsOverridableByDefaultMethod() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index cf5cc111b7..4d7c2a1acb 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2574,7 +2574,7 @@ extern "C" TwoWordReturn artInvokeInterfaceTrampoline(ArtMethod* interface_metho
// each type.
extern "C" uintptr_t artInvokePolymorphic(
JValue* result,
- mirror::Object* raw_method_handle,
+ mirror::Object* raw_receiver,
Thread* self,
ArtMethod** sp)
REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -2602,26 +2602,29 @@ extern "C" uintptr_t artInvokePolymorphic(
RememberForGcArgumentVisitor gc_visitor(sp, kMethodIsStatic, shorty, shorty_length, &soa);
gc_visitor.VisitArguments();
- // Wrap raw_method_handle in a Handle for safety.
- StackHandleScope<2> hs(self);
- Handle<mirror::MethodHandle> method_handle(
- hs.NewHandle(ObjPtr<mirror::MethodHandle>::DownCast(MakeObjPtr(raw_method_handle))));
- raw_method_handle = nullptr;
+ // Wrap raw_receiver in a Handle for safety.
+ StackHandleScope<3> hs(self);
+ Handle<mirror::Object> receiver_handle(hs.NewHandle(raw_receiver));
+ raw_receiver = nullptr;
self->EndAssertNoThreadSuspension(old_cause);
- // Resolve method - it's either MethodHandle.invoke() or MethodHandle.invokeExact().
+ // Resolve method.
ClassLinker* linker = Runtime::Current()->GetClassLinker();
ArtMethod* resolved_method = linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
self, inst.VRegB(), caller_method, kVirtual);
- DCHECK((resolved_method ==
- jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact)) ||
- (resolved_method ==
- jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_invoke)));
- if (UNLIKELY(method_handle.IsNull())) {
+
+ if (UNLIKELY(receiver_handle.IsNull())) {
ThrowNullPointerExceptionForMethodAccess(resolved_method, InvokeType::kVirtual);
return static_cast<uintptr_t>('V');
}
+ // TODO(oth): Ensure this path isn't taken for VarHandle accessors (b/65872996).
+ DCHECK_EQ(resolved_method->GetDeclaringClass(),
+ WellKnownClasses::ToClass(WellKnownClasses::java_lang_invoke_MethodHandle));
+
+ Handle<mirror::MethodHandle> method_handle(hs.NewHandle(
+ ObjPtr<mirror::MethodHandle>::DownCast(MakeObjPtr(receiver_handle.Get()))));
+
Handle<mirror::MethodType> method_type(
hs.NewHandle(linker->ResolveMethodType(self, proto_idx, caller_method)));
@@ -2662,16 +2665,28 @@ extern "C" uintptr_t artInvokePolymorphic(
// consecutive order.
uint32_t unused_args[Instruction::kMaxVarArgRegs] = {};
uint32_t first_callee_arg = first_arg + 1;
- if (!DoInvokePolymorphic<true /* is_range */>(self,
- resolved_method,
- *shadow_frame,
- method_handle,
- method_type,
- unused_args,
- first_callee_arg,
- result)) {
- DCHECK(self->IsExceptionPending());
- }
+
+ bool isExact = (jni::EncodeArtMethod(resolved_method) ==
+ WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact);
+ bool success = false;
+ if (isExact) {
+ success = MethodHandleInvokeExact<true/*is_range*/>(self,
+ *shadow_frame,
+ method_handle,
+ method_type,
+ unused_args,
+ first_callee_arg,
+ result);
+ } else {
+ success = MethodHandleInvoke<true/*is_range*/>(self,
+ *shadow_frame,
+ method_handle,
+ method_type,
+ unused_args,
+ first_callee_arg,
+ result);
+ }
+ DCHECK(success || self->IsExceptionPending());
// Pop transition record.
self->PopManagedStackFragment(fragment);
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 9fb9fe7274..0a1ae36167 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -22,6 +22,7 @@
#include "debugger.h"
#include "dex_file_types.h"
#include "entrypoints/runtime_asm_entrypoints.h"
+#include "intrinsics_enum.h"
#include "jit/jit.h"
#include "jvalue.h"
#include "method_handles-inl.h"
@@ -588,11 +589,12 @@ void SetStringInitValueToAllAliases(ShadowFrame* shadow_frame,
}
template<bool is_range>
-bool DoInvokePolymorphic(Thread* self,
- ShadowFrame& shadow_frame,
- const Instruction* inst,
- uint16_t inst_data,
- JValue* result)
+static bool DoMethodHandleInvokeCommon(Thread* self,
+ ShadowFrame& shadow_frame,
+ bool invoke_exact,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Make sure to check for async exceptions
if (UNLIKELY(self->ObserveAsyncException())) {
@@ -638,41 +640,381 @@ bool DoInvokePolymorphic(Thread* self,
return false;
}
- ArtMethod* invoke_method =
- class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
- self, invoke_method_idx, shadow_frame.GetMethod(), kVirtual);
-
// There is a common dispatch method for method handles that takes
// arguments either from a range or an array of arguments depending
// on whether the DEX instruction is invoke-polymorphic/range or
// invoke-polymorphic. The array here is for the latter.
uint32_t args[Instruction::kMaxVarArgRegs] = {};
- if (is_range) {
+ if (UNLIKELY(is_range)) {
// VRegC is the register holding the method handle. Arguments passed
// to the method handle's target do not include the method handle.
uint32_t first_arg = inst->VRegC_4rcc() + 1;
- return DoInvokePolymorphic<is_range>(self,
- invoke_method,
- shadow_frame,
- method_handle,
- callsite_type,
- args /* unused */,
- first_arg,
- result);
+ static const bool kIsRange = true;
+ if (invoke_exact) {
+ return art::MethodHandleInvokeExact<kIsRange>(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ args /* unused */,
+ first_arg,
+ result);
+ } else {
+ return art::MethodHandleInvoke<kIsRange>(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ args /* unused */,
+ first_arg,
+ result);
+ }
} else {
// Get the register arguments for the invoke.
inst->GetVarArgs(args, inst_data);
// Drop the first register which is the method handle performing the invoke.
memmove(args, args + 1, sizeof(args[0]) * (Instruction::kMaxVarArgRegs - 1));
args[Instruction::kMaxVarArgRegs - 1] = 0;
- return DoInvokePolymorphic<is_range>(self,
- invoke_method,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- args[0],
- result);
+ static const bool kIsRange = false;
+ if (invoke_exact) {
+ return art::MethodHandleInvokeExact<kIsRange>(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ args,
+ args[0],
+ result);
+ } else {
+ return art::MethodHandleInvoke<kIsRange>(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ args,
+ args[0],
+ result);
+ }
+ }
+}
+
+bool DoMethodHandleInvokeExact(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (inst->Opcode() == Instruction::INVOKE_POLYMORPHIC) {
+ static const bool kIsRange = false;
+ return DoMethodHandleInvokeCommon<kIsRange>(
+ self, shadow_frame, true /* is_exact */, inst, inst_data, result);
+ } else {
+ DCHECK_EQ(inst->Opcode(), Instruction::INVOKE_POLYMORPHIC_RANGE);
+ static const bool kIsRange = true;
+ return DoMethodHandleInvokeCommon<kIsRange>(
+ self, shadow_frame, true /* is_exact */, inst, inst_data, result);
+ }
+}
+
+bool DoMethodHandleInvoke(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (inst->Opcode() == Instruction::INVOKE_POLYMORPHIC) {
+ static const bool kIsRange = false;
+ return DoMethodHandleInvokeCommon<kIsRange>(
+ self, shadow_frame, false /* is_exact */, inst, inst_data, result);
+ } else {
+ DCHECK_EQ(inst->Opcode(), Instruction::INVOKE_POLYMORPHIC_RANGE);
+ static const bool kIsRange = true;
+ return DoMethodHandleInvokeCommon<kIsRange>(
+ self, shadow_frame, false /* is_exact */, inst, inst_data, result);
+ }
+}
+
+static bool UnimplementedSignaturePolymorphicMethod(Thread* self ATTRIBUTE_UNUSED,
+ ShadowFrame& shadow_frame ATTRIBUTE_UNUSED,
+ const Instruction* inst ATTRIBUTE_UNUSED,
+ uint16_t inst_data ATTRIBUTE_UNUSED,
+ JValue* result ATTRIBUTE_UNUSED)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ UNIMPLEMENTED(FATAL) << "TODO(oth): b/65872996";
+ return false;
+}
+
+bool DoVarHandleCompareAndExchange(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleCompareAndExchangeAcquire(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleCompareAndExchangeRelease(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleCompareAndSet(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGet(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAcquire(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndAdd(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndAddAcquire(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndAddRelease(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndBitwiseAnd(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndBitwiseAndAcquire(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndBitwiseAndRelease(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndBitwiseOr(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndBitwiseOrAcquire(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndBitwiseOrRelease(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndBitwiseXor(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndBitwiseXorAcquire(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndBitwiseXorRelease(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndSet(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndSetAcquire(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetAndSetRelease(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetOpaque(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleGetVolatile(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleSet(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleSetOpaque(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleSetRelease(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleSetVolatile(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleWeakCompareAndSet(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleWeakCompareAndSetAcquire(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleWeakCompareAndSetPlain(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+bool DoVarHandleWeakCompareAndSetRelease(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return UnimplementedSignaturePolymorphicMethod(self, shadow_frame, inst, inst_data, result);
+}
+
+template<bool is_range>
+bool DoInvokePolymorphic(Thread* self,
+ ShadowFrame& shadow_frame,
+ const Instruction* inst,
+ uint16_t inst_data,
+ JValue* result) {
+ const int invoke_method_idx = inst->VRegB();
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ ArtMethod* invoke_method =
+ class_linker->ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
+ self, invoke_method_idx, shadow_frame.GetMethod(), kVirtual);
+
+ // Ensure intrinsic identifiers are initialized.
+ DCHECK(invoke_method->IsIntrinsic());
+
+ // Dispatch based on intrinsic identifier associated with method.
+ switch (static_cast<art::Intrinsics>(invoke_method->GetIntrinsic())) {
+#define CASE_SIGNATURE_POLYMORPHIC_INTRINSIC(Name, ...) \
+ case Intrinsics::k##Name: \
+ return Do ## Name(self, shadow_frame, inst, inst_data, result);
+#include "intrinsics_list.h"
+ SIGNATURE_POLYMORPHIC_INTRINSICS_LIST(CASE_SIGNATURE_POLYMORPHIC_INTRINSIC)
+#undef INTRINSICS_LIST
+#undef SIGNATURE_POLYMORPHIC_INTRINSICS_LIST
+#undef CASE_SIGNATURE_POLYMORPHIC_INTRINSIC
+ default:
+ LOG(FATAL) << "Unreachable: " << invoke_method->GetIntrinsic();
+ UNREACHABLE();
+ return false;
}
}
@@ -839,19 +1181,16 @@ static ObjPtr<mirror::CallSite> InvokeBootstrapMethod(Thread* self,
// Invoke the bootstrap method handle.
JValue result;
- // This array of arguments is unused. DoInvokePolymorphic() operates on either a
+ // This array of arguments is unused. DoMethodHandleInvokeExact() operates on either a
// an argument array or a range, but always takes an array argument.
uint32_t args_unused[Instruction::kMaxVarArgRegs];
- ArtMethod* invoke_exact =
- jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact);
- bool invoke_success = DoInvokePolymorphic<true /* is_range */>(self,
- invoke_exact,
- *bootstrap_frame,
- bootstrap,
- bootstrap_method_type,
- args_unused,
- 0,
- &result);
+ bool invoke_success = art::MethodHandleInvokeExact<true /* is_range */>(self,
+ *bootstrap_frame,
+ bootstrap,
+ bootstrap_method_type,
+ args_unused,
+ 0,
+ &result);
if (!invoke_success) {
DCHECK(self->IsExceptionPending());
return nullptr;
@@ -942,16 +1281,13 @@ bool DoInvokeCustom(Thread* self,
inst->GetVarArgs(args, inst_data);
}
- ArtMethod* invoke_exact =
- jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact);
- return DoInvokePolymorphic<is_range>(self,
- invoke_exact,
- shadow_frame,
- target,
- target_method_type,
- args,
- args[0],
- result);
+ return art::MethodHandleInvokeExact<is_range>(self,
+ shadow_frame,
+ target,
+ target_method_type,
+ args,
+ args[0],
+ result);
}
template <bool is_range>
@@ -1344,16 +1680,6 @@ EXPLICIT_DO_CALL_TEMPLATE_DECL(true, false);
EXPLICIT_DO_CALL_TEMPLATE_DECL(true, true);
#undef EXPLICIT_DO_CALL_TEMPLATE_DECL
-// Explicit DoInvokeCustom template function declarations.
-#define EXPLICIT_DO_INVOKE_CUSTOM_TEMPLATE_DECL(_is_range) \
- template REQUIRES_SHARED(Locks::mutator_lock_) \
- bool DoInvokeCustom<_is_range>( \
- Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, \
- uint16_t inst_data, JValue* result)
-EXPLICIT_DO_INVOKE_CUSTOM_TEMPLATE_DECL(false);
-EXPLICIT_DO_INVOKE_CUSTOM_TEMPLATE_DECL(true);
-#undef EXPLICIT_DO_INVOKE_CUSTOM_TEMPLATE_DECL
-
// Explicit DoInvokePolymorphic template function declarations.
#define EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(_is_range) \
template REQUIRES_SHARED(Locks::mutator_lock_) \
@@ -1364,6 +1690,16 @@ EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(false);
EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(true);
#undef EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL
+// Explicit DoInvokeCustom template function declarations.
+#define EXPLICIT_DO_INVOKE_CUSTOM_TEMPLATE_DECL(_is_range) \
+ template REQUIRES_SHARED(Locks::mutator_lock_) \
+ bool DoInvokeCustom<_is_range>( \
+ Thread* self, ShadowFrame& shadow_frame, const Instruction* inst, \
+ uint16_t inst_data, JValue* result)
+EXPLICIT_DO_INVOKE_CUSTOM_TEMPLATE_DECL(false);
+EXPLICIT_DO_INVOKE_CUSTOM_TEMPLATE_DECL(true);
+#undef EXPLICIT_DO_INVOKE_CUSTOM_TEMPLATE_DECL
+
// Explicit DoFilledNewArray template function declarations.
#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check, _transaction_active) \
template REQUIRES_SHARED(Locks::mutator_lock_) \
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index e7f67ebb0d..f097bc71b9 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -222,7 +222,18 @@ static inline mirror::MethodType* ResolveMethodType(Thread* self,
return class_linker->ResolveMethodType(self, method_type_index, referrer);
}
-// Performs a signature polymorphic invoke (invoke-polymorphic/invoke-polymorphic-range).
+#define DECLARE_SIGNATURE_POLYMORPHIC_HANDLER(Name, ...) \
+bool Do ## Name(Thread* self, \
+ ShadowFrame& shadow_frame, \
+ const Instruction* inst, \
+ uint16_t inst_data, \
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_);
+#include "intrinsics_list.h"
+INTRINSICS_LIST(DECLARE_SIGNATURE_POLYMORPHIC_HANDLER)
+#undef INTRINSICS_LIST
+#undef DECLARE_SIGNATURE_POLYMORPHIC_HANDLER
+
+// Performs a invoke-polymorphic or invoke-polymorphic-range.
template<bool is_range>
bool DoInvokePolymorphic(Thread* self,
ShadowFrame& shadow_frame,
diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc
index bb827883b5..37593bc728 100644
--- a/runtime/interpreter/interpreter_intrinsics.cc
+++ b/runtime/interpreter/interpreter_intrinsics.cc
@@ -323,14 +323,14 @@ static ALWAYS_INLINE bool MterpStringEquals(ShadowFrame* shadow_frame,
return true;
}
-#define VARHANDLE_FENCE_INTRINSIC(name, std_memory_operation) \
-static ALWAYS_INLINE bool name(ShadowFrame* /* shadow_frame */, \
- const Instruction* /* inst */, \
- uint16_t /* inst_data */, \
- JValue* /* result_register */) \
- REQUIRES_SHARED(Locks::mutator_lock_) { \
- std::atomic_thread_fence(std_memory_operation); \
- 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 sun.misc.Unsafe versions).
@@ -342,6 +342,63 @@ 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)
+
// Macro to help keep track of what's left to implement.
#define UNIMPLEMENTED_CASE(name) \
case Intrinsics::k##name: \
@@ -494,6 +551,39 @@ bool MterpHandleIntrinsic(ShadowFrame* shadow_frame,
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;
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 7a8ae9a9db..31e7986770 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1636,6 +1636,18 @@ void UnstartedRuntime::UnstartedSystemIdentityHashCode(
result->SetI((obj != nullptr) ? obj->IdentityHashCode() : 0);
}
+// Checks whether the runtime is s64-bit. This is needed for the clinit of
+// java.lang.invoke.VarHandle clinit. The clinit determines sets of
+// available VarHandle accessors and these differ based on machine
+// word size.
+void UnstartedRuntime::UnstartedJNIVMRuntimeIs64Bit(
+ Thread* self ATTRIBUTE_UNUSED, ArtMethod* method ATTRIBUTE_UNUSED,
+ mirror::Object* receiver ATTRIBUTE_UNUSED, uint32_t* args ATTRIBUTE_UNUSED, JValue* result) {
+ PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+ jboolean is64bit = (pointer_size == PointerSize::k64) ? JNI_TRUE : JNI_FALSE;
+ result->SetZ(is64bit);
+}
+
void UnstartedRuntime::UnstartedJNIVMRuntimeNewUnpaddedArray(
Thread* self, ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver ATTRIBUTE_UNUSED,
uint32_t* args, JValue* result) {
diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h
index e7047c7372..c029e07432 100644
--- a/runtime/interpreter/unstarted_runtime_list.h
+++ b/runtime/interpreter/unstarted_runtime_list.h
@@ -80,6 +80,7 @@
// Methods that are native.
#define UNSTARTED_RUNTIME_JNI_LIST(V) \
+ V(VMRuntimeIs64Bit, "boolean dalvik.system.VMRuntime.is64Bit()") \
V(VMRuntimeNewUnpaddedArray, "java.lang.Object dalvik.system.VMRuntime.newUnpaddedArray(java.lang.Class, int)") \
V(VMStackGetCallingClassLoader, "java.lang.ClassLoader dalvik.system.VMStack.getCallingClassLoader()") \
V(VMStackGetStackClass2, "java.lang.Class dalvik.system.VMStack.getStackClass2()") \
diff --git a/runtime/intrinsics_list.h b/runtime/intrinsics_list.h
index 3b9b521d24..d007728750 100644
--- a/runtime/intrinsics_list.h
+++ b/runtime/intrinsics_list.h
@@ -47,6 +47,43 @@
// Note: Thread.interrupted is marked with kAllSideEffects due to the lack
// of finer grain side effects representation.
+// Intrinsics for methods with signature polymorphic behaviours.
+#define SIGNATURE_POLYMORPHIC_INTRINSICS_LIST(V) \
+ V(MethodHandleInvokeExact, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/MethodHandle;", "invokeExact", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(MethodHandleInvoke, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/MethodHandle;", "invoke", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleCompareAndExchange, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "compareAndExchange", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleCompareAndExchangeAcquire, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "compareAndExchangeAcquire", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleCompareAndExchangeRelease, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "compareAndExchangeRelease", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleCompareAndSet, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "compareAndSet", "([Ljava/lang/Object;)Z") \
+ V(VarHandleGet, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "get", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAcquire, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAcquire", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndAdd, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndAdd", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndAddAcquire, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndAddAcquire", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndAddRelease, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndAddRelease", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndBitwiseAnd, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndBitwiseAnd", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndBitwiseAndAcquire, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndBitwiseAndAcquire", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndBitwiseAndRelease, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndBitwiseAndRelease", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndBitwiseOr, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndBitwiseOr", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndBitwiseOrAcquire, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndBitwiseOrAcquire", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndBitwiseOrRelease, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndBitwiseOrRelease", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndBitwiseXor, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndBitwiseXor", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndBitwiseXorAcquire, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndBitwiseXorAcquire", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndBitwiseXorRelease, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndBitwiseXorRelease", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndSet, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndSet", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndSetAcquire, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndSetAcquire", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetAndSetRelease, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getAndSetRelease", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetOpaque, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getOpaque", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleGetVolatile, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "getVolatile", "([Ljava/lang/Object;)Ljava/lang/Object;") \
+ V(VarHandleSet, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "set", "([Ljava/lang/Object;)V") \
+ V(VarHandleSetOpaque, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "setOpaque", "([Ljava/lang/Object;)V") \
+ V(VarHandleSetRelease, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "setRelease", "([Ljava/lang/Object;)V") \
+ V(VarHandleSetVolatile, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "setVolatile", "([Ljava/lang/Object;)V") \
+ V(VarHandleWeakCompareAndSet, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "weakCompareAndSet", "([Ljava/lang/Object;)Z") \
+ V(VarHandleWeakCompareAndSetAcquire, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "weakCompareAndSetAcquire", "([Ljava/lang/Object;)Z") \
+ V(VarHandleWeakCompareAndSetPlain, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "weakCompareAndSetPlain", "([Ljava/lang/Object;)Z") \
+ V(VarHandleWeakCompareAndSetRelease, kPolymorphic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/invoke/VarHandle;", "weakCompareAndSetRelease", "([Ljava/lang/Object;)Z")
+
+// The complete list of intrinsics.
#define INTRINSICS_LIST(V) \
V(DoubleDoubleToRawLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "doubleToRawLongBits", "(D)J") \
V(DoubleDoubleToLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "doubleToLongBits", "(D)J") \
@@ -179,7 +216,8 @@
V(VarHandleAcquireFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "acquireFence", "()V") \
V(VarHandleReleaseFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "releaseFence", "()V") \
V(VarHandleLoadLoadFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "loadLoadFence", "()V") \
- V(VarHandleStoreStoreFence, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "storeStoreFence", "()V")
+ V(VarHandleStoreStoreFence, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "storeStoreFence", "()V") \
+ SIGNATURE_POLYMORPHIC_INTRINSICS_LIST(V)
#endif // ART_RUNTIME_INTRINSICS_LIST_H_
#undef ART_RUNTIME_INTRINSICS_LIST_H_ // #define is only for lint.
diff --git a/runtime/invoke_type.h b/runtime/invoke_type.h
index a003f7fe9e..2b877e6f51 100644
--- a/runtime/invoke_type.h
+++ b/runtime/invoke_type.h
@@ -22,12 +22,13 @@
namespace art {
enum InvokeType : uint32_t {
- kStatic, // <<static>>
- kDirect, // <<direct>>
- kVirtual, // <<virtual>>
- kSuper, // <<super>>
- kInterface, // <<interface>>
- kMaxInvokeType = kInterface
+ kStatic, // <<static>>
+ kDirect, // <<direct>>
+ kVirtual, // <<virtual>>
+ kSuper, // <<super>>
+ kInterface, // <<interface>>
+ kPolymorphic, // <<polymorphic>>
+ kMaxInvokeType = kPolymorphic
};
std::ostream& operator<<(std::ostream& os, const InvokeType& rhs);
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 65f39e4468..5a5d5713a8 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -355,15 +355,6 @@ inline bool ConvertAndCopyArgumentsFromCallerFrame(
num_method_params);
}
-inline bool IsMethodHandleInvokeExact(const ArtMethod* const method) {
- if (method == jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact)) {
- return true;
- } else {
- DCHECK_EQ(method, jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandle_invoke));
- return false;
- }
-}
-
inline bool IsInvoke(const mirror::MethodHandle::Kind handle_kind) {
return handle_kind <= mirror::MethodHandle::Kind::kLastInvokeKind;
}
@@ -416,15 +407,14 @@ static inline bool IsCallerTransformer(Handle<mirror::MethodType> callsite_type)
}
template <bool is_range>
-static inline bool DoCallPolymorphic(ArtMethod* called_method,
- Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> target_type,
- Thread* self,
- ShadowFrame& shadow_frame,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- JValue* result)
- REQUIRES_SHARED(Locks::mutator_lock_) {
+static inline bool MethodHandleInvokeMethod(ArtMethod* called_method,
+ Handle<mirror::MethodType> callsite_type,
+ Handle<mirror::MethodType> target_type,
+ Thread* self,
+ ShadowFrame& shadow_frame,
+ const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+ uint32_t first_arg,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
// Compute method information.
const DexFile::CodeItem* code_item = called_method->GetCodeItem();
@@ -552,15 +542,15 @@ static inline bool DoCallPolymorphic(ArtMethod* called_method,
}
template <bool is_range>
-static inline bool DoCallTransform(ArtMethod* called_method,
- Handle<mirror::MethodType> callsite_type,
- Handle<mirror::MethodType> callee_type,
- Thread* self,
- ShadowFrame& shadow_frame,
- Handle<mirror::MethodHandle> receiver,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- JValue* result)
+static inline bool MethodHandleInvokeTransform(ArtMethod* called_method,
+ Handle<mirror::MethodType> callsite_type,
+ Handle<mirror::MethodType> callee_type,
+ Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> receiver,
+ const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+ uint32_t first_arg,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
// This can be fixed to two, because the method we're calling here
// (MethodHandle.transformInternal) doesn't have any locals and the signature
@@ -753,34 +743,34 @@ bool DoInvokePolymorphicMethod(Thread* self,
Handle<mirror::MethodType> callee_type =
(handle_kind == mirror::MethodHandle::Kind::kInvokeCallSiteTransform) ? callsite_type
: handle_type;
- return DoCallTransform<is_range>(called_method,
- callsite_type,
- callee_type,
- self,
- shadow_frame,
- method_handle /* receiver */,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeTransform<is_range>(called_method,
+ callsite_type,
+ callee_type,
+ self,
+ shadow_frame,
+ method_handle /* receiver */,
+ args,
+ first_arg,
+ result);
} else {
- return DoCallPolymorphic<is_range>(called_method,
- callsite_type,
- handle_type,
- self,
- shadow_frame,
- args,
- first_arg,
- result);
+ return MethodHandleInvokeMethod<is_range>(called_method,
+ callsite_type,
+ handle_type,
+ self,
+ shadow_frame,
+ args,
+ first_arg,
+ result);
}
}
// Helper for getters in invoke-polymorphic.
-inline static void DoFieldGetForInvokePolymorphic(Thread* self,
- const ShadowFrame& shadow_frame,
- ObjPtr<mirror::Object>& obj,
- ArtField* field,
- Primitive::Type field_type,
- JValue* result)
+inline static void MethodHandleFieldGet(Thread* self,
+ const ShadowFrame& shadow_frame,
+ ObjPtr<mirror::Object>& obj,
+ ArtField* field,
+ Primitive::Type field_type,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
switch (field_type) {
case Primitive::kPrimBoolean:
@@ -817,12 +807,12 @@ inline static void DoFieldGetForInvokePolymorphic(Thread* self,
}
// Helper for setters in invoke-polymorphic.
-inline bool DoFieldPutForInvokePolymorphic(Thread* self,
- ShadowFrame& shadow_frame,
- ObjPtr<mirror::Object>& obj,
- ArtField* field,
- Primitive::Type field_type,
- JValue& value)
+inline bool MethodHandleFieldPut(Thread* self,
+ ShadowFrame& shadow_frame,
+ ObjPtr<mirror::Object>& obj,
+ ArtField* field,
+ Primitive::Type field_type,
+ JValue& value)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(!Runtime::Current()->IsActiveTransaction());
static const bool kTransaction = false; // Not in a transaction.
@@ -895,14 +885,13 @@ static JValue GetValueFromShadowFrame(const ShadowFrame& shadow_frame,
}
template <bool is_range, bool do_conversions>
-bool DoInvokePolymorphicFieldAccess(Thread* self,
- ShadowFrame& shadow_frame,
- Handle<mirror::MethodHandle> method_handle,
- Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- JValue* result)
- REQUIRES_SHARED(Locks::mutator_lock_) {
+bool MethodHandleFieldAccess(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+ uint32_t first_arg,
+ JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<1> hs(self);
Handle<mirror::MethodType> handle_type(hs.NewHandle(method_handle->GetMethodType()));
const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
@@ -913,7 +902,7 @@ bool DoInvokePolymorphicFieldAccess(Thread* self,
case mirror::MethodHandle::kInstanceGet: {
size_t obj_reg = is_range ? first_arg : args[0];
ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(obj_reg);
- DoFieldGetForInvokePolymorphic(self, shadow_frame, obj, field, field_type, result);
+ MethodHandleFieldGet(self, shadow_frame, obj, field, field_type, result);
if (do_conversions && !ConvertReturnValue(callsite_type, handle_type, result)) {
DCHECK(self->IsExceptionPending());
return false;
@@ -926,7 +915,7 @@ bool DoInvokePolymorphicFieldAccess(Thread* self,
DCHECK(self->IsExceptionPending());
return false;
}
- DoFieldGetForInvokePolymorphic(self, shadow_frame, obj, field, field_type, result);
+ MethodHandleFieldGet(self, shadow_frame, obj, field, field_type, result);
if (do_conversions && !ConvertReturnValue(callsite_type, handle_type, result)) {
DCHECK(self->IsExceptionPending());
return false;
@@ -951,7 +940,7 @@ bool DoInvokePolymorphicFieldAccess(Thread* self,
return false;
}
ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(obj_reg);
- return DoFieldPutForInvokePolymorphic(self, shadow_frame, obj, field, field_type, value);
+ return MethodHandleFieldPut(self, shadow_frame, obj, field, field_type, value);
}
case mirror::MethodHandle::kStaticPut: {
ObjPtr<mirror::Object> obj = GetAndInitializeDeclaringClass(self, field);
@@ -974,7 +963,7 @@ bool DoInvokePolymorphicFieldAccess(Thread* self,
DCHECK(self->IsExceptionPending());
return false;
}
- return DoFieldPutForInvokePolymorphic(self, shadow_frame, obj, field, field_type, value);
+ return MethodHandleFieldPut(self, shadow_frame, obj, field, field_type, value);
}
default:
LOG(FATAL) << "Unreachable: " << handle_kind;
@@ -983,26 +972,24 @@ bool DoInvokePolymorphicFieldAccess(Thread* self,
}
template <bool is_range>
-static inline bool DoInvokePolymorphicNonExact(Thread* self,
- ShadowFrame& shadow_frame,
- Handle<mirror::MethodHandle> method_handle,
- Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- JValue* result)
+static inline bool MethodHandleInvokeInternal(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+ uint32_t first_arg,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
- ObjPtr<mirror::MethodType> handle_type(method_handle->GetMethodType());
- CHECK(handle_type != nullptr);
-
if (IsFieldAccess(handle_kind)) {
+ ObjPtr<mirror::MethodType> handle_type(method_handle->GetMethodType());
DCHECK(!callsite_type->IsExactMatch(handle_type.Ptr()));
if (!callsite_type->IsConvertible(handle_type.Ptr())) {
ThrowWrongMethodTypeException(handle_type.Ptr(), callsite_type.Get());
return false;
}
const bool do_convert = true;
- return DoInvokePolymorphicFieldAccess<is_range, do_convert>(
+ return MethodHandleFieldAccess<is_range, do_convert>(
self,
shadow_frame,
method_handle,
@@ -1011,7 +998,6 @@ static inline bool DoInvokePolymorphicNonExact(Thread* self,
first_arg,
result);
}
-
return DoInvokePolymorphicMethod<is_range>(self,
shadow_frame,
method_handle,
@@ -1022,27 +1008,32 @@ static inline bool DoInvokePolymorphicNonExact(Thread* self,
}
template <bool is_range>
-bool DoInvokePolymorphicExact(Thread* self,
- ShadowFrame& shadow_frame,
- Handle<mirror::MethodHandle> method_handle,
- Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- JValue* result)
+static inline bool MethodHandleInvokeExactInternal(
+ Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+ uint32_t first_arg,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<1> hs(self);
- const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
Handle<mirror::MethodType> method_handle_type(hs.NewHandle(method_handle->GetMethodType()));
+ if (!callsite_type->IsExactMatch(method_handle_type.Get())) {
+ ThrowWrongMethodTypeException(method_handle_type.Get(), callsite_type.Get());
+ return false;
+ }
+
+ const mirror::MethodHandle::Kind handle_kind = method_handle->GetHandleKind();
if (IsFieldAccess(handle_kind)) {
const bool do_convert = false;
- return DoInvokePolymorphicFieldAccess<is_range, do_convert>(
- self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
+ return MethodHandleFieldAccess<is_range, do_convert>(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ args,
+ first_arg,
+ result);
}
// Slow-path check.
@@ -1120,77 +1111,77 @@ bool DoInvokePolymorphicExact(Thread* self,
} // namespace
template <bool is_range>
-bool DoInvokePolymorphic(Thread* self,
- ArtMethod* invoke_method,
- ShadowFrame& shadow_frame,
- Handle<mirror::MethodHandle> method_handle,
- Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- JValue* result)
+inline bool MethodHandleInvoke(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+ uint32_t first_arg,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_) {
- ObjPtr<mirror::MethodType> method_handle_type = method_handle->GetMethodType();
- if (IsMethodHandleInvokeExact(invoke_method)) {
- // We need to check the nominal type of the handle in addition to the
- // real type. The "nominal" type is present when MethodHandle.asType is
- // called any handle, and results in the declared type of the handle
- // changing.
- ObjPtr<mirror::MethodType> nominal_type(method_handle->GetNominalType());
- if (UNLIKELY(nominal_type != nullptr)) {
- if (UNLIKELY(!callsite_type->IsExactMatch(nominal_type.Ptr()))) {
- ThrowWrongMethodTypeException(nominal_type.Ptr(), callsite_type.Get());
- return false;
- }
-
- if (LIKELY(!nominal_type->IsExactMatch(method_handle_type.Ptr()))) {
- // Different nominal type means we have to treat as non-exact.
- return DoInvokePolymorphicNonExact<is_range>(self,
+ if (UNLIKELY(callsite_type->IsExactMatch(method_handle->GetMethodType()))) {
+ // A non-exact invoke that can be invoked exactly.
+ return MethodHandleInvokeExactInternal<is_range>(self,
shadow_frame,
method_handle,
callsite_type,
args,
first_arg,
result);
- }
- }
-
- if (!callsite_type->IsExactMatch(method_handle_type.Ptr())) {
- ThrowWrongMethodTypeException(method_handle_type.Ptr(), callsite_type.Get());
- return false;
- }
- return DoInvokePolymorphicExact<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
} else {
- if (UNLIKELY(callsite_type->IsExactMatch(method_handle_type.Ptr()))) {
- // A non-exact invoke that can be invoked exactly.
- return DoInvokePolymorphicExact<is_range>(self,
+ return MethodHandleInvokeInternal<is_range>(self,
shadow_frame,
method_handle,
callsite_type,
args,
first_arg,
result);
+ }
+}
+
+template <bool is_range>
+bool MethodHandleInvokeExact(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+ uint32_t first_arg,
+ JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ // We need to check the nominal type of the handle in addition to the
+ // real type. The "nominal" type is present when MethodHandle.asType is
+ // called any handle, and results in the declared type of the handle
+ // changing.
+ ObjPtr<mirror::MethodType> nominal_type(method_handle->GetNominalType());
+ if (UNLIKELY(nominal_type != nullptr)) {
+ if (UNLIKELY(!callsite_type->IsExactMatch(nominal_type.Ptr()))) {
+ ThrowWrongMethodTypeException(nominal_type.Ptr(), callsite_type.Get());
+ return false;
+ }
+ if (LIKELY(!nominal_type->IsExactMatch(method_handle->GetMethodType()))) {
+ // Different nominal type means we have to treat as non-exact.
+ return MethodHandleInvokeInternal<is_range>(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ args,
+ first_arg,
+ result);
}
- return DoInvokePolymorphicNonExact<is_range>(self,
- shadow_frame,
- method_handle,
- callsite_type,
- args,
- first_arg,
- result);
}
+ return MethodHandleInvokeExactInternal<is_range>(self,
+ shadow_frame,
+ method_handle,
+ callsite_type,
+ args,
+ first_arg,
+ result);
}
-#define EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(_is_range) \
+#define EXPLICIT_DO_METHOD_HANDLE_METHOD(_name, _is_range) \
template REQUIRES_SHARED(Locks::mutator_lock_) \
- bool DoInvokePolymorphic<_is_range>( \
+ bool MethodHandle##_name<_is_range>( \
Thread* self, \
- ArtMethod* invoke_method, \
ShadowFrame& shadow_frame, \
Handle<mirror::MethodHandle> method_handle, \
Handle<mirror::MethodType> callsite_type, \
@@ -1198,8 +1189,10 @@ bool DoInvokePolymorphic(Thread* self,
uint32_t first_arg, \
JValue* result)
-EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(true);
-EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL(false);
-#undef EXPLICIT_DO_INVOKE_POLYMORPHIC_TEMPLATE_DECL
+EXPLICIT_DO_METHOD_HANDLE_METHOD(Invoke, true);
+EXPLICIT_DO_METHOD_HANDLE_METHOD(Invoke, false);
+EXPLICIT_DO_METHOD_HANDLE_METHOD(InvokeExact, true);
+EXPLICIT_DO_METHOD_HANDLE_METHOD(InvokeExact, false);
+#undef EXPLICIT_DO_METHOD_HANDLE_METHOD
} // namespace art
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index 55680f09e7..8641918f1b 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -202,14 +202,23 @@ class ShadowFrameSetter {
};
template <bool is_range>
-bool DoInvokePolymorphic(Thread* self,
- ArtMethod* invoke_method,
- ShadowFrame& shadow_frame,
- Handle<mirror::MethodHandle> method_handle,
- Handle<mirror::MethodType> callsite_type,
- const uint32_t (&args)[Instruction::kMaxVarArgRegs],
- uint32_t first_arg,
- JValue* result)
+bool MethodHandleInvoke(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+ uint32_t first_arg,
+ JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+template <bool is_range>
+bool MethodHandleInvokeExact(Thread* self,
+ ShadowFrame& shadow_frame,
+ Handle<mirror::MethodHandle> method_handle,
+ Handle<mirror::MethodType> callsite_type,
+ const uint32_t (&args)[Instruction::kMaxVarArgRegs],
+ uint32_t first_arg,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
} // namespace art
diff --git a/runtime/mirror/emulated_stack_frame.cc b/runtime/mirror/emulated_stack_frame.cc
index a6129ccc5f..f82bfbfaef 100644
--- a/runtime/mirror/emulated_stack_frame.cc
+++ b/runtime/mirror/emulated_stack_frame.cc
@@ -289,7 +289,7 @@ void EmulatedStackFrame::VisitRoots(RootVisitor* visitor) {
static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
}
-// Explicit DoInvokePolymorphic template function declarations.
+// Explicit CreateFromShadowFrameAndArgs template function declarations.
#define EXPLICIT_CREATE_FROM_SHADOW_FRAME_AND_ARGS_DECL(_is_range) \
template REQUIRES_SHARED(Locks::mutator_lock_) \
mirror::EmulatedStackFrame* EmulatedStackFrame::CreateFromShadowFrameAndArgs<_is_range>( \
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index bfcd95c846..829dea9107 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -52,6 +52,7 @@ jclass WellKnownClasses::java_lang_ClassNotFoundException;
jclass WellKnownClasses::java_lang_Daemons;
jclass WellKnownClasses::java_lang_Error;
jclass WellKnownClasses::java_lang_invoke_MethodHandle;
+jclass WellKnownClasses::java_lang_invoke_MethodHandle_PolymorphicSignature;
jclass WellKnownClasses::java_lang_IllegalAccessError;
jclass WellKnownClasses::java_lang_NoClassDefFoundError;
jclass WellKnownClasses::java_lang_Object;
@@ -298,6 +299,7 @@ void WellKnownClasses::Init(JNIEnv* env) {
java_lang_Error = CacheClass(env, "java/lang/Error");
java_lang_IllegalAccessError = CacheClass(env, "java/lang/IllegalAccessError");
java_lang_invoke_MethodHandle = CacheClass(env, "java/lang/invoke/MethodHandle");
+ java_lang_invoke_MethodHandle_PolymorphicSignature = CacheClass(env, "java/lang/invoke/MethodHandle$PolymorphicSignature");
java_lang_NoClassDefFoundError = CacheClass(env, "java/lang/NoClassDefFoundError");
java_lang_reflect_Constructor = CacheClass(env, "java/lang/reflect/Constructor");
java_lang_reflect_Executable = CacheClass(env, "java/lang/reflect/Executable");
@@ -334,6 +336,7 @@ void WellKnownClasses::Init(JNIEnv* env) {
java_lang_invoke_MethodHandle_invokeExact = CacheMethod(env, java_lang_invoke_MethodHandle, false, "invokeExact", "([Ljava/lang/Object;)Ljava/lang/Object;");
java_lang_invoke_MethodHandles_lookup = CacheMethod(env, "java/lang/invoke/MethodHandles", true, "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;");
java_lang_invoke_MethodHandles_Lookup_findConstructor = CacheMethod(env, "java/lang/invoke/MethodHandles$Lookup", false, "findConstructor", "(Ljava/lang/Class;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;");
+
java_lang_ref_FinalizerReference_add = CacheMethod(env, "java/lang/ref/FinalizerReference", true, "add", "(Ljava/lang/Object;)V");
java_lang_ref_ReferenceQueue_add = CacheMethod(env, "java/lang/ref/ReferenceQueue", true, "add", "(Ljava/lang/ref/Reference;)V");
@@ -434,6 +437,7 @@ void WellKnownClasses::Clear() {
java_lang_Error = nullptr;
java_lang_IllegalAccessError = nullptr;
java_lang_invoke_MethodHandle = nullptr;
+ java_lang_invoke_MethodHandle_PolymorphicSignature = nullptr;
java_lang_NoClassDefFoundError = nullptr;
java_lang_Object = nullptr;
java_lang_OutOfMemoryError = nullptr;
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 7deef636b1..b2fd4d6e4c 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -64,6 +64,7 @@ struct WellKnownClasses {
static jclass java_lang_Error;
static jclass java_lang_IllegalAccessError;
static jclass java_lang_invoke_MethodHandle;
+ static jclass java_lang_invoke_MethodHandle_PolymorphicSignature;
static jclass java_lang_NoClassDefFoundError;
static jclass java_lang_Object;
static jclass java_lang_OutOfMemoryError;
diff --git a/test/988-method-trace/gen_srcs.py b/test/988-method-trace/gen_srcs.py
index 9d26032edc..225f41b5b6 100755
--- a/test/988-method-trace/gen_srcs.py
+++ b/test/988-method-trace/gen_srcs.py
@@ -39,7 +39,8 @@ IDX_CLASS_NAME = -3
# Exclude all hidden API.
KLASS_BLACK_LIST = ['sun.misc.Unsafe', 'libcore.io.Memory', 'java.lang.StringFactory',
- 'java.lang.invoke.VarHandle' ] # TODO(b/65872996): Enable when VarHandle is visible.
+ 'java.lang.invoke.MethodHandle', # invokes are tested by 956-method-handles
+ 'java.lang.invoke.VarHandle' ] # TODO(b/65872996): will tested separately
METHOD_BLACK_LIST = [('java.lang.ref.Reference', 'getReferent'),
('java.lang.String', 'getCharsNoCheck'),
('java.lang.System', 'arraycopy')] # arraycopy has a manual test.