Why does call_site_target keep changing for a Nashorn method?

Liu, Xin xxinliu at amazon.com
Wed Jan 16 22:04:27 UTC 2019


In one of our applications, C1/C2 keeps compiling a Javascript method generated by Nashorn but the code fails a dependency check right before installing in the code cache. This is with JDK tip.

It can’t pass ‘Dependencies::check_call_site_target_value’.
[C2 Parsing]
<bc code='182' bci='1'/>
<dependency type='unique_concrete_method' ctxk='1131' x='1141'/>
<call method='1141' count='878838' prof_factor='0.024122' inline='1'/>
<inline_success reason='accessor'/>
<parse method='1141' uses='21249.000000' stamp='1112.538'>
<bc code='180' bci='1'/>
<unknown id='1556'/>
<unknown id='1866'/>
<dependency type='call_site_target_value' x0='1556' x='1866'/>
<parse_done nodes='41636' live='12226' memory='12130984' stamp='1112.538'/>
</parse>

[Validating compilation dependencies]
<dependency type='call_site_target_value' x0='1132' x='1143'/>
<dependency type='call_site_target_value' x0='1334' x='1337'/>
<dependency type='call_site_target_value' x0='1424' x='1425'/>
<dependency type='call_site_target_value' x0='1437' x='1438'/>
<dependency type='call_site_target_value' x0='1454' x='1455'/>
<dependency type='call_site_target_value' x0='1465' x='1466'/>
<dependency type='call_site_target_value' x0='1482' x='1483'/>
<dependency type='call_site_target_value' x0='1498' x='1499'/>
<dependency type='call_site_target_value' x0='1509' x='1510'/>
<dependency type='call_site_target_value' x0='1526' x='1576'/>
<dependency type='call_site_target_value' x0='1528' x='1667'/>
<dependency type='call_site_target_value' x0='1536' x='1692'/>
<dependency type='call_site_target_value' x0='1537' x='1707'/>
<dependency type='call_site_target_value' x0='1538' x='1730'/>
<dependency type='call_site_target_value' x0='1539' x='1746'/>
<dependency type='call_site_target_value' x0='1540' x='1787'/>
<dependency type='call_site_target_value' x0='1550' x='1804'/>
<dependency type='call_site_target_value' x0='1553' x='1820'/>
<dependency type='call_site_target_value' x0='1554' x='1836'/>
<dependency type='call_site_target_value' x0='1555' x='1849'/>
<dependency type='call_site_target_value' x0='1556' x='1866'/>
<dependency_failed type='call_site_target_value' x0='1556' x='1866' witness='jdk/nashorn/internal/runtime/linker/LinkerCallSite' stamp='1113.578'/>

It’s related to the GWT methodHandle.  The 2 mismatched methodhandles are very similar except for argL3, which is an int[2].
Even though arg0-2 are not identical objects, their contents are same.

(gdb) call java_lang_invoke_CallSite::target(call_site)->print()
java.lang.invoke.BoundMethodHandle$Species_LLLL
{0x00000000f586ca98} - klass: 'java/lang/invoke/BoundMethodHandle$Species_LLLL'
- ---- fields (total size 6 words):
- 'customizationCount' 'B' @12  0
- private final 'type' 'Ljava/lang/invoke/MethodType;' @16  a 'java/lang/invoke/MethodType'{0x00000000e21e2878} = (Ljava/lang/Object;Ljdk/nashorn/internal/runtime/Undefined;Ljava/lang/Object;)Ljava/lang/Object; (e21e2878)
- final 'form' 'Ljava/lang/invoke/LambdaForm;' @20  a 'java/lang/invoke/LambdaForm'{0x00000000e1e4a670} => a 'java/lang/invoke/MemberName'{0x00000000e1e4a938} = {method} {0x00007fffa512cb68} 'guard''(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;' in 'java/lang/invoke/LambdaForm$MH' (e1e4a670)
- 'asTypeCache' 'Ljava/lang/invoke/MethodHandle;' @24  NULL (0)
- final 'argL0' 'Ljava/lang/Object;' @28  a 'java/lang/invoke/BoundMethodHandle$Species_LL'{0x00000000f586c9e8} (f586c9e8)
- final 'argL1' 'Ljava/lang/Object;' @32  a 'java/lang/invoke/MethodHandleImpl$CountingWrapper'{0x00000000f586ca28} (f586ca28)
- final 'argL2' 'Ljava/lang/Object;' @36  a 'java/lang/invoke/MethodHandleImpl$CountingWrapper'{0x00000000f586ca60} (f586ca60)
- final 'argL3' 'Ljava/lang/Object;' @40  [I{0x00000000f586ca10} (f586ca10)

(gdb) call method_handle->print()
java.lang.invoke.BoundMethodHandle$Species_LLLL
{0x00000000f6b18500} - klass: 'java/lang/invoke/BoundMethodHandle$Species_LLLL'
- ---- fields (total size 6 words):
- 'customizationCount' 'B' @12  0
- private final 'type' 'Ljava/lang/invoke/MethodType;' @16  a 'java/lang/invoke/MethodType'{0x00000000e21e2878} = (Ljava/lang/Object;Ljdk/nashorn/internal/runtime/Undefined;Ljava/lang/Object;)Ljava/lang/Object; (e21e2878)
- final 'form' 'Ljava/lang/invoke/LambdaForm;' @20  a 'java/lang/invoke/LambdaForm'{0x00000000e1e4a670} => a 'java/lang/invoke/MemberName'{0x00000000e1e4a938} = {method} {0x00007fffa512cb68} 'guard''(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;' in 'java/lang/invoke/LambdaForm$MH' (e1e4a670)
- 'asTypeCache' 'Ljava/lang/invoke/MethodHandle;' @24  NULL (0)
- final 'argL0' 'Ljava/lang/Object;' @28  a 'java/lang/invoke/BoundMethodHandle$Species_LL'{0x00000000f6b18450} (f6b18450)
- final 'argL1' 'Ljava/lang/Object;' @32  a 'java/lang/invoke/MethodHandleImpl$CountingWrapper'{0x00000000f6b18490} (f6b18490)
- final 'argL2' 'Ljava/lang/Object;' @36  a 'java/lang/invoke/MethodHandleImpl$CountingWrapper'{0x00000000f6b184c8} (f6b184c8)
- final 'argL3' 'Ljava/lang/Object;' @40  [I{0x00000000f6b18478} (f6b18478)

My guess is argL3 is counters in Java.lang.invoke.MethodHandleImpl.


// Intrinsified by C2. Counters are used during parsing to calculate branch frequencies.
@LambdaForm.Hidden
@jdk.internal.HotSpotIntrinsicCandidate
static
boolean profileBoolean(boolean result, int[] counters) {
    // Profile is int[2] where [0] and [1] correspond to false and true occurrences respectively.
    int idx = result ? 1 : 0;
    try {
        counters[idx] = Math.addExact(counters[idx], 1);
    } catch (ArithmeticException e) {
        // Avoid continuous overflow by halving the problematic count.
        counters[idx] = counters[idx] / 2;
    }
    return result;
}


I am still struggling to understand the source code in java.lang.invoke.*.  Could anybody enlighten me why the target of the callsite changes every time here?  it is relative to this profiling thing?
In validation log, it has validated the dep “dependency type='call_site_target_value' x0='1556' x='1866'” above. Why it can’t pass it after then? My guess is one MH object has been changed by another Java thread.
One interesting fact that compiler thread can’t pass 22th dep.  My tuition is it goes over an unknown threshold.

The 2nd question is about ciEnv:: validate_compile_task_dependencies.  Why does failure of call_site_target_value_changed not count as a deopt?
The flag  _inc_decompile_count_on_failure =false stops MDO to mark this method ‘not_compileable’.  C2 doesn’t set the flag, so C2 ends up compiling it over and over, which makes C2 a cpu hog. Here’s the code in validate_compile_task_dependencies

  bool counter_changed = system_dictionary_modification_counter_changed();
  Dependencies::DepType result = dependencies()->validate_dependencies(_task, counter_changed);
  if (result != Dependencies::end_marker) {
    if (result == Dependencies::call_site_target_value) {
      _inc_decompile_count_on_failure = false;
      record_failure("call site target change");

Maybe the right thing to do is to count this as a deopt and change the deopt limit computation to take into account the size of the method in nodes, just as done for abandoning compilation if the graph is too big.

Thanks,
--lx

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/hotspot-compiler-dev/attachments/20190116/328346a5/attachment-0001.html>


More information about the hotspot-compiler-dev mailing list