8067247: Crash: assert(method_holder->data() == 0 ...) failed: a) MT-unsafe modification of inline cache

Made invoker LambdaForm instance & its compiled form lifetime tightly coupled.

Reviewed-by: vlivanov
This commit is contained in:
Jamsheed Mohammed C M 2016-04-05 01:46:40 -07:00
parent fa667c5409
commit b26b78a4d4
8 changed files with 103 additions and 10 deletions

View File

@ -1042,6 +1042,14 @@ void CodeCache::clear_inline_caches() {
}
}
void CodeCache::cleanup_inline_caches() {
assert_locked_or_safepoint(CodeCache_lock);
NMethodIterator iter;
while(iter.next_alive()) {
iter.method()->cleanup_inline_caches(/*clean_all=*/true);
}
}
// Keeps track of time spent for checking dependencies
NOT_PRODUCT(static elapsedTimer dependentCheckTime;)

View File

@ -201,6 +201,7 @@ class CodeCache : AllStatic {
static bool needs_cache_clean() { return _needs_cache_clean; }
static void set_needs_cache_clean(bool v) { _needs_cache_clean = v; }
static void clear_inline_caches(); // clear all inline caches
static void cleanup_inline_caches();
// Returns true if an own CodeHeap for the given CodeBlobType is available
static bool heap_available(int code_blob_type);

View File

@ -1138,8 +1138,7 @@ void nmethod::clear_ic_stubs() {
}
}
void nmethod::cleanup_inline_caches() {
void nmethod::cleanup_inline_caches(bool clean_all/*=false*/) {
assert_locked_or_safepoint(CompiledIC_lock);
// If the method is not entrant or zombie then a JMP is plastered over the
@ -1169,7 +1168,7 @@ void nmethod::cleanup_inline_caches() {
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());
if (clean_all || !nm->is_in_use() || (nm->method()->code() != nm)) ic->set_to_clean(is_alive());
}
break;
}
@ -1179,7 +1178,7 @@ void nmethod::cleanup_inline_caches() {
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)) csc->set_to_clean();
if (clean_all || !nm->is_in_use() || (nm->method()->code() != nm)) csc->set_to_clean();
}
break;
}

View File

@ -599,7 +599,7 @@ public:
// Inline cache support
void clear_inline_caches();
void clear_ic_stubs();
void cleanup_inline_caches();
void cleanup_inline_caches(bool clean_all = false);
bool inlinecache_check_contains(address addr) const {
return (addr >= code_begin() && addr < verified_entry_point());
}

View File

@ -1376,8 +1376,8 @@ WB_ENTRY(jint, WB_ConstantPoolEncodeIndyIndex(JNIEnv* env, jobject wb, jint inde
return ConstantPool::encode_invokedynamic_index(index);
WB_END
WB_ENTRY(void, WB_ClearInlineCaches(JNIEnv* env, jobject wb))
VM_ClearICs clear_ics;
WB_ENTRY(void, WB_ClearInlineCaches(JNIEnv* env, jobject wb, jboolean preserve_static_stubs))
VM_ClearICs clear_ics(preserve_static_stubs == JNI_TRUE);
VMThread::execute(&clear_ics);
WB_END
@ -1757,7 +1757,7 @@ static JNINativeMethod methods[] = {
{CC"isShared", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsShared },
{CC"isSharedClass", CC"(Ljava/lang/Class;)Z", (void*)&WB_IsSharedClass },
{CC"areSharedStringsIgnored", CC"()Z", (void*)&WB_AreSharedStringsIgnored },
{CC"clearInlineCaches", CC"()V", (void*)&WB_ClearInlineCaches },
{CC"clearInlineCaches0", CC"(Z)V", (void*)&WB_ClearInlineCaches },
{CC"addCompilerDirective", CC"(Ljava/lang/String;)I",
(void*)&WB_AddCompilerDirective },
{CC"removeCompilerDirective", CC"(I)V", (void*)&WB_RemoveCompilerDirective },

View File

@ -105,6 +105,14 @@ void VM_ThreadStop::doit() {
}
}
void VM_ClearICs::doit() {
if (_preserve_static_stubs) {
CodeCache::cleanup_inline_caches();
} else {
CodeCache::clear_inline_caches();
}
}
void VM_Deoptimize::doit() {
// We do not want any GCs to happen while we are in the middle of this VM operation
ResourceMark rm;

View File

@ -231,9 +231,11 @@ class VM_ThreadStop: public VM_Operation {
};
class VM_ClearICs: public VM_Operation {
private:
bool _preserve_static_stubs;
public:
VM_ClearICs() {}
void doit() { CodeCache::clear_inline_caches(); }
VM_ClearICs(bool preserve_static_stubs) { _preserve_static_stubs = preserve_static_stubs; }
void doit();
VMOp_Type type() const { return VMOp_ClearICs; }
};

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8067247
* @library /test/lib /compiler/whitebox /
* @run main/bootclasspath -Xcomp -Xbatch
* -XX:CompileCommand=compileonly,InvokerGC::test
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* InvokerGC
*/
import java.lang.invoke.*;
import sun.hotspot.WhiteBox;
public class InvokerGC {
static final WhiteBox WB = WhiteBox.getWhiteBox();
static MethodHandle mh;
static {
try {
mh = MethodHandles.lookup().findStatic(InvokerGC.class, "dummy", MethodType.methodType(void.class));
} catch (Exception e) {
throw new Error(e);
}
}
static void dummy() {}
static void test() {
try {
mh.invoke();
} catch (Throwable e) {
throw new Error(e);
}
}
public static void main(String[] args) throws Throwable {
mh.invoke(); // Pre-generate an invoker for ()V signature
test(); // trigger method compilation
test();
WB.fullGC(); // WB.fullGC has always clear softref policy.
test();
WB.clearInlineCaches(true); // Preserve static stubs.
test(); // Trigger call site re-resolution. Invoker LambdaForm should stay the same.
System.out.println("TEST PASSED");
}
}