RFR: 8267807: C2: Downcast receiver to target holder during inlining
Vladimir Ivanov
vlivanov at openjdk.java.net
Wed Jun 2 23:34:40 UTC 2021
On Wed, 2 Jun 2021 23:24:06 GMT, Vladimir Ivanov <vlivanov at openjdk.org> wrote:
>> I closely looked at the relevant logic and couldn't find any possibility to bypass receiver subtype check.
>>
>> There are 2 call site shapes possible:
>>
>> 1. `invokevirtual C.m RECV => J.m DEFAULT` (`J.m` - resolved and selected method)
>>
>> Verifier guarantees that RECV <: C (REFC) and method resolution ensures that C <: J (REFC <: DECC).
>>
>>
>> 2. `invokeinterface I.m RECV => J.m DEFAULT` (`J.m` - resolved and selected method)
>>
>> `I` (REFC) is required to be an interface (structural constraint of `invokeinterface` instruction).
>>
>> Then, here's the relevant code:
>>
>> ciInstanceKlass* actual_receiver = resolved_iklass;
>> ...
>> ciInstanceKlass *ikl = receiver_type->klass()->as_instance_klass();
>> if (ikl->is_loaded() && ikl->is_initialized() && !ikl->is_interface() &&
>> (ikl == actual_receiver || ikl->is_subtype_of(actual_receiver))) {
>> // ikl is a same or better type than the original actual_receiver,
>> // e.g. static receiver from bytecodes.
>> actual_receiver = ikl;
>> // Is the actual_receiver exact?
>> actual_receiver_is_exact = receiver_type->klass_is_exact();
>> }
>>
>> ciInstanceKlass* calling_klass = caller->holder();
>> ciMethod* cha_monomorphic_target = resolved_method->find_monomorphic_target(calling_klass, resolved_iklass, actual_receiver, check_access);
>>
>> ...
>>
>> ciMethod* ciMethod::find_monomorphic_target(...) {
>> ...
>> if (actual_recv->is_interface()) {
>> // %%% We cannot trust interface types, yet. See bug 6312651.
>> return NULL;
>> }
>>
>>
>>
>> `receiver_type` can represent either an interface (1a) or a class (1b `ikl`).
>>
>> 1a. But if `ikl->is_interface()`, then `actual_receiver` stays as an interface (`I`, REFC) and `find_monomorphic_target()` returns NULL.
>>
>> 1b. If `ikl` is a class, then `ikl != actual_receiver` and depending on whether `ikl->is_subtype_of(actual_receiver))`, `actual_receiver` is either REFC (interface) or `receiver_type`.
>>
>> `find_monomorphic_target()` can succeed only in the latter case (`actual_receiver` is a class and not an interface), but previous static subtype check guarantees that the receiver type (a class) implements the interface.
>>
>> Q.E.D
>
> So, CHA is still kept conservative when interface types on receiver are encountered.
> Currently, only single implementor case is optimised, but there are proper receiver subtype checks in place.
>
> It should be quite straightforward to relax aforementioned constraints on receiver types (only classes, no interfaces), but then we would require additional receiver subtype check accompanying `Compile::optimize_virtual_call()` calls.
Anyway, as a defense in depth measure, we could still insert receiver subtype check when CHA returns a default method and hope that the check will go away once the type system better tracks interface types. Though the subtype check against an interface can be quite expensive, I don't expect any performance regressions considering CHA hasn't optimized default methods before.
-------------
PR: https://git.openjdk.java.net/jdk/pull/4212
More information about the hotspot-compiler-dev
mailing list