Why does call_site_target keep changing for a Nashorn method?

Vladimir Ivanov vladimir.x.ivanov at oracle.com
Sat Jan 19 01:05:44 UTC 2019


> 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?'

Yes, sounds reasonable. I believe compilation bailed out due to 
invalidated call_site_target dependency should be treated as if it were 
a deoptimization with Action_reinterpret, but resetting invocation 
counts may be too much. So, decaying counters instead sounds reasonable.

Also, it's hard to tell what method to act on: problematic CallSite may 
be located somewhere deep in inline tree, but only root method is known.

Best regards,
Vladimir Ivanov

> 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