# HG changeset patch # User iignatyev # Date 1418066358 -10800 # Mon Dec 08 22:19:18 2014 +0300 # Node ID 4e4b33e9ee7047ac09de5d55f33cb084837a7d73 # Parent 3c858304c7e199feaaf703d2eef6b07d1643c549 8028595: WhiteBox API for stress testing of TieredCompilation Reviewed-by: diff --git a/src/share/vm/c1/c1_GraphBuilder.cpp b/src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp +++ b/src/share/vm/c1/c1_GraphBuilder.cpp @@ -3574,6 +3574,9 @@ case vmIntrinsics::_fullFence : break; + case vmIntrinsics::_getCompiler: + break; + default : return false; // do not inline } // create intrinsic node diff --git a/src/share/vm/c1/c1_LIRGenerator.cpp b/src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp +++ b/src/share/vm/c1/c1_LIRGenerator.cpp @@ -1209,6 +1209,11 @@ set_no_result(x); } +void LIRGenerator::do_getCompiler(Intrinsic* x) { + LIR_Opr value = load_constant(new Constant(new IntConstant(1))); + set_result(x, value); +} + // Examble: ref.get() // Combination of LoadField and g1 pre-write barrier void LIRGenerator::do_Reference_get(Intrinsic* x) { @@ -3171,6 +3176,10 @@ if (os::is_MP()) __ membar(); break; + case vmIntrinsics::_getCompiler: + do_getCompiler(x); + break; + case vmIntrinsics::_Reference_get: do_Reference_get(x); break; diff --git a/src/share/vm/c1/c1_LIRGenerator.hpp b/src/share/vm/c1/c1_LIRGenerator.hpp --- a/src/share/vm/c1/c1_LIRGenerator.hpp +++ b/src/share/vm/c1/c1_LIRGenerator.hpp @@ -250,6 +250,7 @@ void do_FPIntrinsics(Intrinsic* x); void do_Reference_get(Intrinsic* x); void do_update_CRC32(Intrinsic* x); + void do_getCompiler(Intrinsic* x); void do_UnsafePrefetch(UnsafePrefetch* x, bool is_store); diff --git a/src/share/vm/classfile/vmSymbols.hpp b/src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp +++ b/src/share/vm/classfile/vmSymbols.hpp @@ -866,6 +866,9 @@ do_intrinsic(_fullFence, sun_misc_Unsafe, fullFence_name, fullFence_signature, F_RN) \ do_name( fullFence_name, "fullFence") \ do_alias( fullFence_signature, void_method_signature) \ + do_intrinsic(_getCompiler, sun_misc_Unsafe, getCompiler_name, getCompiler_signature, F_S) \ + do_name( getCompiler_name, "getCompiler") \ + do_alias( getCompiler_signature, void_int_signature) \ \ /* unsafe memory references (there are a lot of them...) */ \ do_signature(getObject_signature, "(Ljava/lang/Object;J)Ljava/lang/Object;") \ diff --git a/src/share/vm/opto/library_call.cpp b/src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp +++ b/src/share/vm/opto/library_call.cpp @@ -287,6 +287,8 @@ bool inline_updateBytesCRC32(); bool inline_updateByteBufferCRC32(); bool inline_multiplyToLen(); + + bool inline_getCompiler(); }; @@ -819,6 +821,8 @@ case vmIntrinsics::_storeFence: case vmIntrinsics::_fullFence: return inline_unsafe_fence(intrinsic_id()); + case vmIntrinsics::_getCompiler: return inline_getCompiler(); + case vmIntrinsics::_currentThread: return inline_native_currentThread(); case vmIntrinsics::_isInterrupted: return inline_native_isInterrupted(); @@ -3199,6 +3203,11 @@ return true; } +bool LibraryCallKit::inline_getCompiler() { + set_result(_gvn.transform(intcon(2))); + return true; +} + //------------------------inline_native_currentThread------------------ bool LibraryCallKit::inline_native_currentThread() { Node* junk = NULL; diff --git a/src/share/vm/prims/whitebox.cpp b/src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp +++ b/src/share/vm/prims/whitebox.cpp @@ -69,6 +69,14 @@ bool WhiteBox::_used = false; volatile bool WhiteBox::compilation_locked = false; +class VM_WhiteBoxOperation : public VM_Operation { + public: + VM_WhiteBoxOperation() { } + VMOp_Type type() const { return VMOp_WhiteBoxOperation; } + bool allow_nested_vm_operations() const { return true; } +}; + + WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj)) return (jlong)(void*)JNIHandles::resolve(obj); WB_END @@ -404,6 +412,43 @@ return env->FromReflectedMethod(method); } +// Deoptimizes all compiled frames and makes nmethods not entrant if it's requested +class VM_WhiteBoxDeoptimizeFrames : public VM_WhiteBoxOperation { + private: + int _result; + const bool _make_not_entrant; + public: + VM_WhiteBoxDeoptimizeFrames(bool make_not_entrant) : + _result(0), _make_not_entrant(make_not_entrant) { } + int result() const { return _result; } + + void doit() { + for (JavaThread* t = Threads::first(); t != NULL; t = t->next()) { + if (t->has_last_Java_frame()) { + for (StackFrameStream fst(t, UseBiasedLocking); !fst.is_done(); fst.next()) { + frame* f = fst.current(); + if (f->can_be_deoptimized() && !f->is_deoptimized_frame()) { + RegisterMap* reg_map = fst.register_map(); + Deoptimization::deoptimize(t, *f, reg_map); + if (_make_not_entrant) { + nmethod* nm = CodeCache::find_nmethod(f->pc()); + assert(nm != NULL, "sanity check"); + nm->make_not_entrant(); + } + ++_result; + } + } + } + } + } +}; + +WB_ENTRY(jint, WB_DeoptimizeFrames(JNIEnv* env, jobject o, jboolean make_not_entrant)) + VM_WhiteBoxDeoptimizeFrames op(make_not_entrant); + VMThread::execute(&op); + return op.result(); +WB_END + WB_ENTRY(void, WB_DeoptimizeAll(JNIEnv* env, jobject o)) MutexLockerEx mu(Compile_lock); CodeCache::mark_all_nmethods_for_deoptimization(); @@ -526,13 +571,6 @@ return (mh->queued_for_compilation() || nm != NULL); WB_END -class VM_WhiteBoxOperation : public VM_Operation { - public: - VM_WhiteBoxOperation() { } - VMOp_Type type() const { return VMOp_WhiteBoxOperation; } - bool allow_nested_vm_operations() const { return true; } -}; - class AlwaysFalseClosure : public BoolObjectClosure { public: bool do_object_b(oop p) { return false; } @@ -761,7 +799,6 @@ } WB_END - WB_ENTRY(void, WB_LockCompilation(JNIEnv* env, jobject o, jlong timeout)) WhiteBox::compilation_locked = true; WB_END @@ -1201,6 +1238,7 @@ {CC"NMTChangeTrackingLevel", CC"()Z", (void*)&WB_NMTChangeTrackingLevel}, {CC"NMTGetHashSize", CC"()I", (void*)&WB_NMTGetHashSize }, #endif // INCLUDE_NMT + {CC"deoptimizeFrames", CC"(Z)I", (void*)&WB_DeoptimizeFrames }, {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;Z)I", (void*)&WB_DeoptimizeMethod }, diff --git a/test/compiler/whitebox/DeoptimizeFramesTest.java b/test/compiler/whitebox/DeoptimizeFramesTest.java new file mode 100644 --- /dev/null +++ b/test/compiler/whitebox/DeoptimizeFramesTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 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. + */ + +/* + * @test DeoptimizeFramesTest + * @bug 8028595 + * @library /testlibrary /testlibrary/whitebox + * @build DeoptimizeFramesTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -Xmixed + * -XX:CompileCommand=compileonly,DeoptimizeFramesTest$TestCaseImpl::method + * -XX:-DeoptimizeRandom DeoptimizeFramesTest true + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -Xmixed + * -XX:CompileCommand=compileonly,DeoptimizeFramesTest$TestCaseImpl::method + * -XX:-DeoptimizeRandom DeoptimizeFramesTest false + * @summary testing of WB::deoptimizeFrames() + */ +import java.lang.reflect.Executable; +import java.util.concurrent.Callable; + +import sun.hotspot.code.NMethod; +import com.oracle.java.testlibrary.Asserts; + +public class DeoptimizeFramesTest extends CompilerWhiteBoxTest { + private final boolean makeNotEntrant; + + private DeoptimizeFramesTest(boolean makeNotEntrant) { + super(new TestCaseImpl()); + // to prevent inlining of #method + WHITE_BOX.testSetDontInlineMethod(method, true); + this.makeNotEntrant = makeNotEntrant; + System.out.printf("DeoptimizeFramesTest(makeNotEntrant = %b)%n", + makeNotEntrant); + } + + public static void main(String[] args) throws Exception { + Asserts.assertEQ(args.length, 1, + "[TESTBUG] args should contain 1 element"); + new DeoptimizeFramesTest(Boolean.valueOf(args[0])).runTest(); + } + + @Override + protected void test() throws Exception { + compile(); + checkCompiled(); + WHITE_BOX.deoptimizeFrames(makeNotEntrant); + checkCompiled(); + NMethod nm = NMethod.get(method, testCase.isOsr()); + Thread t = new Thread(() -> {while(true) { WHITE_BOX.deoptimizeFrames(makeNotEntrant); }}); + t.setDaemon(true); + t.start(); + for (int i = 0, result = compile(1); result != 0; result = compile(1), ++i) { + if (CompilerWhiteBoxTest.IS_VERBOSE && i % 100 == 0) { + System.out.printf("[%d] compiler is %d%n", i, result); + printInfo(); + } + } + // invoke one more time to recompile not entrant if any + compile(1); + + NMethod nm2 = NMethod.get(method, testCase.isOsr()); + if (makeNotEntrant) { + if (nm2 != null) { + Asserts.assertNE(nm.compile_id, nm2.compile_id, + String.format("compilation %d can't be available", nm.compile_id)); + } + } else { + Asserts.assertEQ(nm.compile_id, nm2.compile_id, "should be the same nmethod"); + } + } + + private static class TestCaseImpl implements TestCase { + private static final Executable EXECUTABLE; + private static final int RECURSION_DEPTH = 100; + static { + try { + EXECUTABLE = TestCaseImpl.class.getDeclaredMethod("method"); + } catch (NoSuchMethodException e) { + throw new Error("[TESTBUG] method not found", e); + } + } + + private volatile int i; + + @Override + public String name() { + return "recursiveMethod"; + } + + @Override + public Executable getExecutable() { + return EXECUTABLE; + } + + @Override + public Callable getCallable() { + return () -> { + i = 0; + return method(); + }; + } + + @Override + public boolean isOsr() { + return false; + } + + private int method() { + ++i; + int compiler = sun.misc.Unsafe.getCompiler(); + if (i < RECURSION_DEPTH) { + return compiler * method(); + } + return compiler; + } + } +} diff --git a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java --- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java @@ -109,6 +109,7 @@ public native int NMTGetHashSize(); // Compiler + public native int deoptimizeFrames(boolean makeNotEntrant); public native void deoptimizeAll(); public boolean isMethodCompiled(Executable method) { return isMethodCompiled(method, false /*not osr*/);