diff --git a/src/share/vm/oops/instanceKlass.cpp b/src/share/vm/oops/instanceKlass.cpp index ff0b09ee7c4a7e28a6e36d4d51aaa8dfd00c08af..6805f62a69c748e9c3233d3e2aa473202dffd7ed 100644 --- a/src/share/vm/oops/instanceKlass.cpp +++ b/src/share/vm/oops/instanceKlass.cpp @@ -2890,6 +2890,22 @@ void InstanceKlass::remove_osr_nmethod(nmethod* n) { OsrList_lock->unlock(); } +int InstanceKlass::mark_osr_nmethods(const Method* m) { + // This is a short non-blocking critical region, so the no safepoint check is ok. + MutexLockerEx ml(OsrList_lock, Mutex::_no_safepoint_check_flag); + nmethod* osr = osr_nmethods_head(); + int found = 0; + while (osr != NULL) { + assert(osr->is_osr_method(), "wrong kind of nmethod found in chain"); + if (osr->method() == m) { + osr->mark_for_deoptimization(); + found++; + } + osr = osr->osr_link(); + } + return found; +} + nmethod* InstanceKlass::lookup_osr_nmethod(const Method* m, int bci, int comp_level, bool match_level) const { // This is a short non-blocking critical region, so the no safepoint check is ok. OsrList_lock->lock_without_safepoint_check(); diff --git a/src/share/vm/oops/instanceKlass.hpp b/src/share/vm/oops/instanceKlass.hpp index c0e9bf3f7f7caee2f2c324332a97cca48a75b0d6..96e7fe3c378b056bb6050d327d46069b003e9aca 100644 --- a/src/share/vm/oops/instanceKlass.hpp +++ b/src/share/vm/oops/instanceKlass.hpp @@ -783,6 +783,7 @@ class InstanceKlass: public Klass { void set_osr_nmethods_head(nmethod* h) { _osr_nmethods_head = h; }; void add_osr_nmethod(nmethod* n); void remove_osr_nmethod(nmethod* n); + int mark_osr_nmethods(const Method* m); nmethod* lookup_osr_nmethod(const Method* m, int bci, int level, bool match_level) const; // Breakpoint support (see methods on Method* for details) diff --git a/src/share/vm/oops/method.hpp b/src/share/vm/oops/method.hpp index 8d92437e2911a448eb2ea5cb424b2c6ee858cae9..3bbff0b210bfc4aeebc068985230cab89eb34644 100644 --- a/src/share/vm/oops/method.hpp +++ b/src/share/vm/oops/method.hpp @@ -793,6 +793,10 @@ class Method : public Metadata { return method_holder()->lookup_osr_nmethod(this, InvocationEntryBci, level, match_level) != NULL; } + int mark_osr_nmethods() { + return method_holder()->mark_osr_nmethods(this); + } + nmethod* lookup_osr_nmethod_for(int bci, int level, bool match_level) { return method_holder()->lookup_osr_nmethod(this, bci, level, match_level); } diff --git a/src/share/vm/prims/whitebox.cpp b/src/share/vm/prims/whitebox.cpp index f0024396ebc5e703ef8824a4ce7cd9d1d355dc1a..7d36d7882dd2bc56664f5332a250f5add45f9963 100644 --- a/src/share/vm/prims/whitebox.cpp +++ b/src/share/vm/prims/whitebox.cpp @@ -404,19 +404,10 @@ WB_ENTRY(jint, WB_DeoptimizeMethod(JNIEnv* env, jobject o, jobject method, jbool CHECK_JNI_EXCEPTION_(env, result); MutexLockerEx mu(Compile_lock); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - nmethod* code; if (is_osr) { - int bci = InvocationEntryBci; - while ((code = mh->lookup_osr_nmethod_for(bci, CompLevel_none, false)) != NULL) { - code->mark_for_deoptimization(); - ++result; - bci = code->osr_entry_bci() + 1; - } - } else { - code = mh->code(); - } - if (code != NULL) { - code->mark_for_deoptimization(); + result += mh->mark_osr_nmethods(); + } else if (mh->code() != NULL) { + mh->code()->mark_for_deoptimization(); ++result; } result += CodeCache::mark_for_deoptimization(mh()); diff --git a/test/compiler/whitebox/DeoptimizeMultipleOSRTest.java b/test/compiler/whitebox/DeoptimizeMultipleOSRTest.java new file mode 100644 index 0000000000000000000000000000000000000000..f81d199a8d0f0fb7ff2e2c9e05ffc541142626d3 --- /dev/null +++ b/test/compiler/whitebox/DeoptimizeMultipleOSRTest.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2013, 2014, 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. + */ + +import sun.hotspot.WhiteBox; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; + +/* + * @test DeoptimizeMultipleOSRTest + * @bug 8061817 + * @library /testlibrary /testlibrary/whitebox + * @build DeoptimizeMultipleOSRTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,DeoptimizeMultipleOSRTest::triggerOSR DeoptimizeMultipleOSRTest + * @summary testing of WB::deoptimizeMethod() + */ +public class DeoptimizeMultipleOSRTest { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final long BACKEDGE_THRESHOLD = 150000; + private Method method; + private int counter = 0; + + public static void main(String[] args) throws Exception { + DeoptimizeMultipleOSRTest test = new DeoptimizeMultipleOSRTest(); + test.test(); + } + + /** + * Triggers two different OSR compilations for the same method and + * checks if WhiteBox.deoptimizeMethod() deoptimizes both. + * + * @throws Exception + */ + public void test() throws Exception { + method = DeoptimizeMultipleOSRTest.class.getDeclaredMethod("triggerOSR", boolean.class, long.class); + // Trigger two OSR compiled versions + triggerOSR(true, BACKEDGE_THRESHOLD); + triggerOSR(false, BACKEDGE_THRESHOLD); + // Wait for compilation + CompilerWhiteBoxTest.waitBackgroundCompilation(method); + // Deoptimize + WHITE_BOX.deoptimizeMethod(method, true); + if (WHITE_BOX.isMethodCompiled(method, true)) { + throw new AssertionError("Not all OSR compiled versions were deoptimized"); + } + } + + /** + * Triggers OSR compilations by executing loops. + * + * @param first Determines which loop to execute + * @param limit The number of loop iterations + */ + public void triggerOSR(boolean first, long limit) { + if (limit != 1) { + // Warmup method to avoid uncommon traps + for (int i = 0; i < limit; ++i) { + triggerOSR(first, 1); + } + CompilerWhiteBoxTest.waitBackgroundCompilation(method); + } + if (first) { + // Trigger OSR compilation 1 + for (int i = 0; i < limit; ++i) { + counter++; + } + } else { + // Trigger OSR compilation 2 + for (int i = 0; i < limit; ++i) { + counter++; + } + } + } +}