diff options
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. |