Why does call_site_target keep changing for a Nashorn method?

Liu, Xin xxinliu at amazon.com
Sat Jan 19 00:39:47 UTC 2019


Hi, Vladimir, 

Thank you for the response. After reading your email and associated RFEs,  now I got the background story. 
I understand the design decision in hotspot. 

In my case, compiler thread crowds out the app thread because we run application in docker with 1 CPU. 
Is it good idea that we decay the invocation counts of the methods if they fail due to 'call_site_target value change?'

Thanks, 
--lx


On 1/17/19, 2:36 PM, "Vladimir Ivanov" <vladimir.x.ivanov at oracle.com> wrote:

    C1/C2 optimistically inline through CallSite instances even if those are 
    mutable (MutableCallSite/VolatileCallSite). It requires a nmethod 
    dependency and once CallSite target changes, all dependent nmethods 
    should be invalidated. If such change happens during compilation, 
    nmethod installation fails.
    
    That's exactly what you observe: the dependency is recorded during 
    inlining, but failed verification during installation.
    
    Regarding the observed behavior, it is well-known [1] [2] and was a 
    deliberate choice. As JDK-7087838 [1] states:
    
    "The consensus among language runtime implementors is that they want 
    control over switch points (and thus call sites) and so it's their 
    responsibility to handle extensive invalidation of such."
    
    So, such pathological behavior is treated as a bug in user code (Nashorn 
    in this particular case).
    
    There's an RFE filed [3] to consider alternative options for unstable 
    calls.
    
    Best regards,
    Vladimir Ivanov
    
    [1] https://bugs.openjdk.java.net/browse/JDK-7087838
    [2] https://bugs.openjdk.java.net/browse/JDK-7177745
    [3] https://bugs.openjdk.java.net/browse/JDK-8147550
    
    On 16/01/2019 14:04, Liu, Xin wrote:
    > 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 22^th 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
    > 
    



More information about the hotspot-compiler-dev mailing list