On Fri, 11 Apr 2025 09:09:05 GMT, Kim Barrett <kbarr...@openjdk.org> wrote:
>> On a second thought, I think we should do this shift before this PR, so that >> it is cleanly backportable. This bug messes with concurrent GC invariants, >> so it would be nice to fix it in current LTSes. > > As far as I can tell, intrinsic selection only applies when the call target is > exactly the intrinsically attributed method. (Possibly after optimizations > that lead to a call to that specific method.) And that's obviously necessary > for correctness of applying intrinsics. > > The documentation for `@IntrinsicCandidate` suggests it is "better to make > intrinsics be static methods", but non-static methods are certainly permitted, > and I've found several. In particular, the method in question, > `Reference::get`, has been a virtual intrinsic with at least three > (non-intrinsic) overrides (SoftReference, PhantomReference, and > FinalReference) for a long time. > > I did a bit of experimenting, and as far as I can tell, everything works as > expected. Reference::get is already registered as having > vmIntrinsics::_Reference_get as it's intrinsic_id, and that intrinsic id is > handled by the various code processors, such as being in the dispatch table > that @vnkozlov refreenced. > > All of Reference::get, Reference::refersTo, and Reference::clear are subtly > different in the details of how they are implemented and intrinsified, because > there are differences among them. > > refersTo is final, but needs different implementations for Reference and > PhantomReference. That distinction is handled via nonpublic virtual > refersToImpl. And those are implemented in terms of separate intrinsified > private native methods because we found that C2 handling of intrinsified > virtual native methods had problems. If not for that issue, the refersToImpl > methods would be intrinsified virtual native methods. > > Reference::clear also needs clearImpl, but for a different reason. There are > places where we want to directly call the implementation of Reference::clear, > ignoring any overrides by derived application classes. That is accomplished by > calling the virtual clearImpl, which has implementations in Reference and > PhantomReference. And the clearImpls are implemented in terms of separate > intrinsified private native methods because of the above mentioned C2 issue. > > The native implementations for clear call the same JVM_ReferenceClear helper > function, which uses unknown_referent_no_keepalive to handle the distinction > between weak and phantom strengths. If we just had the native implementation > we could drop the PhantomReference override. But this operation also has > intrinsic support, and the intrinsic makes use of the known strength. > > Reference::get already has long-standing intrinsic support. The only thing > being ch... I think I understand the intrinsic matchers machinery better now: it indeed binds intrinsics to concrete methods. So virtual overrides are supposed to have no difference. Also, I tried a few examples where I thought it should fail, and it does not. I added some diagnostic checks around interpreter, and they do not fail: diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index bdc2ca908bd..255fa6443af 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -652,6 +652,21 @@ address TemplateInterpreterGenerator::generate_Reference_get_entry(void) { // rdx: scratch // rdi: scratch + if (UseNewCode) { + Label L_good; + __ push(rscratch1); + __ push(rscratch2); + + __ load_klass(rscratch1, rax, rscratch2); + __ cmpb(Address(rscratch1, in_bytes(InstanceKlass::reference_type_offset())), REF_PHANTOM); + __ jccb(Assembler::notEqual, L_good); + __ stop("PHANTOM REFERENCE CALLED WITH INTERPRETER REFERENCE.GET INTRINSIC"); + __ bind(L_good); + + __ pop(rscratch2); + __ pop(rscratch1); + } + // Load the value of the referent field. const Address field_address(rax, referent_offset); __ load_heap_oop(rax, field_address, /*tmp1*/ rbx, ON_WEAK_OOP_REF); I tried C2 IR test, and it works fine: we return constant `0` for `PhantomReferences`, like we would expect. I am going to RFR that test separately. ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/24315#discussion_r2039300718