Aligning ReceiverTypeData for JVMCI, C1 and C2
Vladimir Kozlov
vladimir.kozlov at oracle.com
Wed Aug 17 19:24:43 UTC 2016
The only place C2 uses type check profiling data is in GraphKit::maybe_cast_profiled_receiver() which calls profile_has_unique_klass() method:
if (profile.count() >= 0 && // no cast failures here
profile.has_receiver(0) &&
profile.morphism() == 1) {
As you see it only check for one concrete case - only one successful (type check always succeed during bytecode execution) klass recorded. If C2 find such case it will generate klass compare code
using this profiled klass (instead of klass from bytecode) with uncommon trap on false branch. It is called type narrowing in C2.
If profiling data does not have concrete klass C2 still try to find narrowed type from type speculation (code added by Roland which record additional profiling information for calls). See
maybe_cast_profiled_receiver().
And if C2 does not have any of this narrow type klasses it will generate standard subtype check with klass from bytecode which have throw (or uncommon trap) on failed path. But this code is more
complex as expected.
Regards,
Vladimir
On 8/17/16 2:03 AM, Doug Simon wrote:
> Thanks for the reply Vladimir. So, my understanding now is that for typechecks, C2 only has/uses this information:
>
> 1. Total number of failed typechecks (from `count` field)
> 2. Total number of failed profiled typechecks (from negative types in the profile)
> 3. Total number of successful profile typechecks (from positive types in the profile)
>
> What’s interesting is that C2 does not know the total number of successful non-profiled typechecks which in turn means it doesn’t know what percentage of checked types are represented by the profiled types. I assume this means C2 never emits an uncommon trap on the code path for missed profiled types.
>
> Based on my new understanding, I’ll submit a bug to correct the comment. This is highly complex code and so comment accuracy is imperative.
>
> -Doug
>
>> On 17 Aug 2016, at 02:44, Vladimir Kozlov <vladimir.kozlov at oracle.com> wrote:
>>
>> First, C1 does not use profile data.
>>
>> Second, CounterData::count field is incremented on overflow only for virtual calls (it is used only for virtual call in such case):
>>
>> int non_profiled_offset = -1;
>> if (is_virtual_call) {
>> non_profiled_offset = in_bytes(CounterData::count_offset());
>> }
>>
>> And it is decremented only for type casts (aastore, checkcast, instanceof) because profile_typecheck_failed() is called only from gen_subtype_check().
>>
>> So the comment is wrong, should be:
>>
>> // ReceiverTypeData for instanceof/checkcast/aastore:
>> // C1/C2: count is decremented for failed type checks
>>
>> I think it is answering you 1. question.
>>
>> Based on that your 2 statement is wrong in the sense that 'count' should not be incremented for type checks. Actually JVMCI comments are correct.
>>
>> Regards,
>> Vladimir
>>
>> On 8/11/16 6:03 AM, Doug Simon wrote:
>>> While investigating comments on https://bugs.openjdk.java.net/browse/JDK-8156137, I was reacquainted with this comment in methodData.hpp:
>>>
>>> class ReceiverTypeData : public CounterData {
>>> friend class VMStructs;
>>> friend class JVMCIVMStructs;
>>> protected:
>>> enum {
>>> #if INCLUDE_JVMCI
>>> // Description of the different counters
>>> // ReceiverTypeData for instanceof/checkcast/aastore:
>>> // C1/C2: count is incremented on type overflow and decremented for failed type checks
>>> // JVMCI: count decremented for failed type checks and nonprofiled_count is incremented on type overflow
>>> // TODO (chaeubl): in fact, JVMCI should also increment the count for failed type checks to mimic the C1/C2 behavior
>>> // VirtualCallData for invokevirtual/invokeinterface:
>>> // C1/C2: count is incremented on type overflow
>>> // JVMCI: count is incremented on type overflow, nonprofiled_count is incremented on method overflow
>>>
>>> // JVMCI is interested in knowing the percentage of type checks involving a type not explicitly in the profile
>>> nonprofiled_count_off_set = counter_cell_count,
>>> receiver0_offset,
>>> #else
>>>
>>> A number of questions arose and Roland and I refreshed our understanding of this code:
>>>
>>> 1. How does C2 use the `count` field? It seems to have dubious value as it is both *incremented* on type overflow and *decremented* on failed type checks (we’ve confirmed the implementation matches this, at least on x86). If overflow types always cause failed type checks, the `count` field will be 0. Isn’t there a risk C2 interprets that to mean that only types in the profile were seen? I believe that it’s for this reason, the original author of the JVMCI code added the `non_profiled_count` field so we can tell if the profile provides full coverage of the seen types. If a profile is “complete”, Graal places a guard that deoptimizes if any other type is seen.
>>>
>>> 2. When EnableJVMCI is true, the current implementation never updates the `count` field for type overflow, only the `non_profiled_count` (the TODO comment should read “... should also increment the count for failed type checks... “). Depending on how C1 and C2 use the `count` field, this may have adverse effects.
>>>
>>> To clear this up, I propose that the `non_profiled_count` field be made unconditional. However, before doing so we need to better understand how C1 and C2 use the `count` field and what changes would be needed to have them use `non_profiled_count`. Failing that, we should make the interpreter update `count` (in addition to `non_profiled_count`) for type overflows when JVMCI is enabled to avoid adverse consequences for C1 and C2.
>>>
>>> -Doug
>>>
>
More information about the hotspot-compiler-dev
mailing list