[14] RFR(S): 8230019: [REDO] compiler/types/correctness/* tests fail with "assert(recv == __null || recv->is_klass()) failed: wrong type"
Christian Hagedorn
christian.hagedorn at oracle.com
Mon Oct 28 10:38:30 UTC 2019
Hi Vladimir
I don't think that the String class is unloaded. In the previous fix [6]
I called clear_row() if either the klass 'k' was NULL or it was
unloaded. This means that in my test case the MDO contains the String
klass at row index 0 but the index 1 is empty, i.e. the klass is NULL.
As a result, I cleared that counter with clear_row() by mistake when
processing the row index 1 (since 'k' is NULL). My new fix will only set
the klass to NULL with set_receiver(row, NULL) and will not clear the
counter anymore. In my evaluation below I compared the previous fix [6]
with my new fix.
Best regards,
Christian
[6] http://cr.openjdk.java.net/~thartmann/8225670/webrev.00/
On 26.10.19 00:12, Vladimir Kozlov wrote:
> Yes, that is what I suspected. MDO had only one receiver and if we clean
> counter it will look like it is never called.
> clear_row() assumes that at least one receiver is valid.
>
> Hmm, but if the class is unloaded when we construct copy of MDO then
> this compilation is invalid anyway. Right? You need to get new profiling
> information after unloading to get correct MDO.
>
> If one klass in MDO call site is still valid we can still compile and
> have uncommon trap for second case. But if no valid klass is recorded in
> MDO call site (all were nulled) we can't compile it based on counter. We
> should bailout and re-collect profiling info or generate uncommon trap
> instead of call. For later we have to separate cases when the site is
> never called or it was called but classes later were unloaded. hmm, C2
> actually should generate uncommon trap if class is unloaded. Why classes
> are unloaded in a first place?
>
> Can you tell why class is unloaded in your test case? It is String!!! Or
> more accurate why clear_row() was called?
>
> Thanks,
> Vladimir
>
> On 10/25/19 10:18 AM, Christian Hagedorn wrote:
>> Hi Vladimir
>>
>> Thank you for your review!
>>
>> On 24.10.19 18:55, Vladimir Kozlov wrote:
>>> I would like to see what happens with MDO data with Tobias fix which
>>> caused regression. If it is simple. May be from LogCompilation.
>>
>>> The only explanation I can think of if we had only one receiver in
>>> MDO which we cleaned up and it confuse C2 to treat call site as never
>>> executed [3] so that it can't use speculative_receiver_type which
>>> come from other data
>> It was actually my fix. I've tried to come up with a test case where
>> the regression can easily be seen. I found the following example which
>> shows the benefit of not clearing the counter with clear_row():
>>
>> public void test() {
>> String s = "test";
>> for (int i = 0; i < 1_000_000; i++ ) {
>> s.replace("e", "t"); // Just a big enough method that
>> does not get inlined by default
>> }
>> }
>>
>> If we use clear_row(), then String::replace is not inlined:
>>
>> org.sample.ClearRow::test @ 5 (27 bytes) made not entrant
>> @ 16 java.lang.String::replace (255 bytes) too big
>>
>> The MDO counter for String::replace is reset to zero. This profile
>> information is passed to ok_to_inline [1] and the zeroed counter is
>> eventually read at [2]. The following frequency check [3] fails and
>> thus InlineTree::should_inline returns false because the method is too
>> big (and wrongly assumed to be never called).
>>
>> However, if we just use set_receiver(row, NULL) instead of
>> clear_row(), which does not reset the counter, then call_site_count is
>> big number greater than zero at [2] and the check at [3] succeeds. The
>> maximum inline size is increased to FreqInlineSize (325 by default).
>> Therefore String::replace is inlined:
>>
>> org.sample.ClearRow::test @ 5 (27 bytes) made not entrant
>> @ 16 java.lang.String::replace (255 bytes) inline (hot)
>>
>>
>> I also quickly put it into a local JMH benchmark. It can clearly be
>> seen that not clearing the counter is beneficial:
>>
>> set_receiver(row, NULL):
>> Benchmark Mode Cnt Score Error Units
>> ClearRow.test thrpt 5 42.810 ± 1.572 ops/s
>>
>> clear_row():
>> Benchmark Mode Cnt Score Error Units
>> ClearRow.test thrpt 5 32.658 ± 1.267 ops/s
>>
>>
>> There are other cases, for example by using HashMap::put instead, in
>> which call_does_dispatch is true [4]. It then skips directly to your
>> mentioned check at [5]. The check succeeds having a non reset counter
>> and the speculative_receiver_type can be used to inline the method.
>>
>>
>> So I guess we've seen large performance regressions due to many such
>> missed inline opportunities due to lost/wrong profiling information.
>>
>> Best regards,
>> Christian
>>
>>
>> [1]
>> http://hg.openjdk.java.net/jdk/jdk/file/18c246ad2ff9/src/hotspot/share/opto/doCall.cpp#l171
>>
>> [2]
>> http://hg.openjdk.java.net/jdk/jdk/file/18c246ad2ff9/src/hotspot/share/opto/bytecodeInfo.cpp#l163
>>
>> [3]
>> http://hg.openjdk.java.net/jdk/jdk/file/18c246ad2ff9/src/hotspot/share/opto/bytecodeInfo.cpp#l170
>>
>> [4]
>> http://hg.openjdk.java.net/jdk/jdk/file/18c246ad2ff9/src/hotspot/share/opto/doCall.cpp#l167
>>
>> [5]
>> http://hg.openjdk.java.net/jdk/jdk/file/18c246ad2ff9/src/hotspot/share/opto/doCall.cpp#l205
>>
More information about the hotspot-compiler-dev
mailing list