JDK-8144856 : fix assert in CompiledStaticCall::set_to_interpreted
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 9
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2015-12-07
  • Updated: 2017-08-11
  • Resolved: 2016-05-10
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9 b122Fixed
Related Reports
Relates :  
Relates :  
Description
[~never] pointed out that a fix for an assert on x86 that came in via JDK-8062493:

http://hg.openjdk.java.net/jdk9/hs-comp/hotspot/diff/a41fe5ffa839/src/cpu/x86/vm/compiledIC_x86.cpp#l1.34

should also be done on all other architectures.  The failure manifests as:

#  assert(method_loader->data() == 0 || method_loader->data() == (intptr_t)callee()) failed: a) MT-unsafe modification of inline cache

It depends on whether in an optimized debug build it managed to fold those reads into one.
Comments
[~dlong] analysis was done using JDK-8067247. fix is for the same bug. i will assign the bug to myself.
14-03-2016

[~jcm], can you verify if this is the same bug as 8067247?
13-03-2016

lform instance not having strong ref forced new LF Compilation at re-resolution link time after GC. this issue can be fixed by keeping a strong ref to lform instance. solution: keep a strong ref to lform instance in LF class diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -655,6 +655,8 @@ mv.visitAnnotation(DONTINLINE_SIG, true); } + constantPlaceholder(lambdaForm); // keep LambdaForm instance & its compiled form lifetimes tightly coupled + if (lambdaForm.customized != null) { // Since LambdaForm is customized for a particular MethodHandle, it's safe to substitute // receiver MethodHandle (at slot #0) with an embedded constant and use it instead.
10-03-2016

thanks for guiding me [~vlivanov]
10-03-2016

trace after applying the fix linkMethod java.lang.invoke.MethodHandle.invoke()void/5 linkMethod => java.lang.invoke.LambdaForm$MH/9314459.invoke_003_MT(Object,Object)void/invokeStatic + ()void CompiledStaticCall@0xf4815c3b: set_to_interpreted java.lang.invoke.LambdaForm$MH/9314459.invoke_003_MT(Ljava/lang/Object;Ljava/lang/Object;)V IC@0xf4815c3b: monomorphic to interpreter: {method} {0xe2d17168} 'invoke_003_MT' '(Ljava/lang/Object;Ljava/lang/Object;)V' in 'java/lang/invok IC@0xf4815c3b: set to clean Inline cache at 0xf4815c3b, calling interpreted 0xf481647a cached_value 0x00000000 linkMethod java.lang.invoke.MethodHandle.invoke()void/5 linkMethod => java.lang.invoke.LambdaForm$MH/9314459.invoke_003_MT(Object,Object)void/invokeStatic + ()void CompiledStaticCall@0xf4815c3b: set_to_interpreted java.lang.invoke.LambdaForm$MH/9314459.invoke_003_MT(Ljava/lang/Object;Ljava/lang/Object;)V IC@0xf4815c3b: monomorphic to interpreter: {method} {0xe2d17168} 'invoke_003_MT' '(Ljava/lang/Object;Ljava/lang/Object;)V' in 'java/lang/invok
10-03-2016

It can be a GC bug: soft references are allowed to be cleared only when the object becomes softly reachable (no strong refs left): * <p> Suppose that the garbage collector determines at a certain point in time * that an object is <a href="package-summary.html#reachability">softly * reachable</a>. At that time it may choose to clear atomically all soft * references to that object and all soft references to any other * softly-reachable objects from which that object is reachable through a chain * of strong references. ... * <p> All soft references to softly-reachable objects are guaranteed to have * been cleared before the virtual machine throws an * {@code OutOfMemoryError}. If GC doesn't obey that, it can clear the cache while the cached LF is alive. It triggers new invoker LF creation on the next lookup and 2 different Method* will be observed in the call site, triggering the assertion.
10-03-2016

The following code in unpack_method_and_appendix() produces a strong reference from the caller to the compiled LF class: (*appendix_result) = Handle(THREAD, appendix); // the target is stored in the cpCache and if a reference to this // MethodName is dropped we need a way to make sure the // class_loader containing this method is kept alive. // FIXME: the appendix might also preserve this dependency. ClassLoaderData* this_key = InstanceKlass::cast(accessing_klass())->class_loader_data(); this_key->record_dependency(m->method_holder(), CHECK_NULL); // Can throw OOM return methodHandle(THREAD, m);
10-03-2016

we have hard ref to methodname, lform has just softref and can be collected ? analyzing further.
10-03-2016

is lambdaforms are kept as soft reference(cached) and when there is constrain in memory its collected. creating new method after full gc collection?
09-03-2016

ICs that point to stubs in OSR method are set to clean in gc epilog forcing re-resolution. void nmethod::cleanup_inline_caches() { assert_locked_or_safepoint(CompiledIC_lock); // If the method is not entrant or zombie then a JMP is plastered over the // first few bytes. If an oop in the old code was there, that oop // should not get GC'd. Skip the first few bytes of oops on // not-entrant methods. address low_boundary = verified_entry_point(); if (!is_in_use()) { low_boundary += NativeJump::instruction_size; // %%% Note: On SPARC we patch only a 4-byte trap, not a full NativeJump. // This means that the low_boundary is going to be a little too high. // This shouldn't matter, since oops of non-entrant methods are never used. // In fact, why are we bothering to look at oops in a non-entrant method?? } // Find all calls in an nmethod and clear the ones that point to non-entrant, // zombie and unloaded nmethods. ResourceMark rm; RelocIterator iter(this, low_boundary); while(iter.next()) { switch(iter.type()) { case relocInfo::virtual_call_type: case relocInfo::opt_virtual_call_type: { CompiledIC *ic = CompiledIC_at(&iter); // Ok, to lookup references to zombies here CodeBlob *cb = CodeCache::find_blob_unsafe(ic->ic_destination()); if( cb != NULL && cb->is_nmethod() ) { nmethod* nm = (nmethod*)cb; // Clean inline caches pointing to zombie, non-entrant and unloaded methods if (!nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean(is_alive()); } break; }
08-03-2016

previously i had a feeling that this is very intermittent race condition, and no core files in hand to analyze(from bug history). As i had looked at the linked case with this in mind, never cared to reproduce it. yesterday out of curiosity i tried reproducing it. and found that its always reproducible! my miss! Analysis: this MH invocation happens in *Test::run( osr compiled). First invocation CompiledStaticCall@0xf49174fb: set_to_interpreted java.lang.invoke.LambdaForm$MH/8126749.invoke_MT(Ljava/lang/Object;Ljava/lang/Object;)V IC@0xf49174fb: monomorphic to interpreter: {method} {0xe2e0c958} 'invoke_MT' '(Ljava/lang/Object;Ljava/lang/Object;)V' in 'java/lang/invoke/La this invocation is itself a gc call ic is set to clean in gc second time resolution to same gc( with new Method* ) CompiledStaticCall@0xf49174fb: set_to_interpreted java.lang.invoke.LambdaForm$MH/3886634.invoke_MT(Ljava/lang/Object;Ljava/lang/Object;)V and fail
08-03-2016

checking why new Method* is created in lookup ( for same method)
08-03-2016

We shouldn't use this bug to investigate the assert firing. The assert is clearly wrong as it is now so let's fix that first.
17-12-2015

made changes for all the platforms
11-12-2015

We could. I don't really care. All I want is to get the assert fixed on all architectures.
09-12-2015

It looks like 8067247 is the same issue. Should we close one as a duplicate?
09-12-2015

yes
08-12-2015

[~jcm], can you take care of this one?
07-12-2015