# HG changeset patch # User jcm # Date 1459846000 25200 # Node ID 9989add27bf4fcb8a761687997e12b888af161bb # Parent 67b04a68b881fa51a5cb9ed9476f30fe5b3b4d22 8067247: Crash: assert(method_holder->data() == 0 ...) failed: a) MT-unsafe modification of inline cache Summary: Made invoker LambdaForm instance & its compiled form lifetime tightly coupled. Reviewed-by: vlivanov diff -r 67b04a68b881 -r 9989add27bf4 hotspot/src/share/vm/code/codeCache.cpp --- a/hotspot/src/share/vm/code/codeCache.cpp Sun Apr 03 21:44:54 2016 -0700 +++ b/hotspot/src/share/vm/code/codeCache.cpp Tue Apr 05 01:46:40 2016 -0700 @@ -1042,6 +1042,14 @@ } } +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;) diff -r 67b04a68b881 -r 9989add27bf4 hotspot/src/share/vm/code/codeCache.hpp --- a/hotspot/src/share/vm/code/codeCache.hpp Sun Apr 03 21:44:54 2016 -0700 +++ b/hotspot/src/share/vm/code/codeCache.hpp Tue Apr 05 01:46:40 2016 -0700 @@ -201,6 +201,7 @@ 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); diff -r 67b04a68b881 -r 9989add27bf4 hotspot/src/share/vm/code/nmethod.cpp --- a/hotspot/src/share/vm/code/nmethod.cpp Sun Apr 03 21:44:54 2016 -0700 +++ b/hotspot/src/share/vm/code/nmethod.cpp Tue Apr 05 01:46:40 2016 -0700 @@ -1138,8 +1138,7 @@ } } - -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 @@ 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 @@ 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; } diff -r 67b04a68b881 -r 9989add27bf4 hotspot/src/share/vm/code/nmethod.hpp --- a/hotspot/src/share/vm/code/nmethod.hpp Sun Apr 03 21:44:54 2016 -0700 +++ b/hotspot/src/share/vm/code/nmethod.hpp Tue Apr 05 01:46:40 2016 -0700 @@ -599,7 +599,7 @@ // 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()); } diff -r 67b04a68b881 -r 9989add27bf4 hotspot/src/share/vm/prims/whitebox.cpp --- a/hotspot/src/share/vm/prims/whitebox.cpp Sun Apr 03 21:44:54 2016 -0700 +++ b/hotspot/src/share/vm/prims/whitebox.cpp Tue Apr 05 01:46:40 2016 -0700 @@ -1376,8 +1376,8 @@ 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 @@ {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 }, diff -r 67b04a68b881 -r 9989add27bf4 hotspot/src/share/vm/runtime/vm_operations.cpp --- a/hotspot/src/share/vm/runtime/vm_operations.cpp Sun Apr 03 21:44:54 2016 -0700 +++ b/hotspot/src/share/vm/runtime/vm_operations.cpp Tue Apr 05 01:46:40 2016 -0700 @@ -105,6 +105,14 @@ } } +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; diff -r 67b04a68b881 -r 9989add27bf4 hotspot/src/share/vm/runtime/vm_operations.hpp --- a/hotspot/src/share/vm/runtime/vm_operations.hpp Sun Apr 03 21:44:54 2016 -0700 +++ b/hotspot/src/share/vm/runtime/vm_operations.hpp Tue Apr 05 01:46:40 2016 -0700 @@ -231,9 +231,11 @@ }; 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; } }; diff -r 67b04a68b881 -r 9989add27bf4 hotspot/test/compiler/jsr292/InvokerGC.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/jsr292/InvokerGC.java Tue Apr 05 01:46:40 2016 -0700 @@ -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"); + } +}