# HG changeset patch # User xliu # Date 1557213423 -7200 # Node ID 1dc9bf9d016b7b113441fb3f5da432b3143e6dae # Parent a9f729b641a36017091095ba3131f475812e53f3 8222670: pathological case of JIT recompilation and code cache bloat Summary: Prevent downgraded compilation tasks from recompiling. Reviewed-by: sgehwolf, thartmann diff -r a9f729b641a3 -r 1dc9bf9d016b src/hotspot/share/compiler/compileBroker.hpp --- a/src/hotspot/share/compiler/compileBroker.hpp Tue May 07 07:44:15 2019 +0200 +++ b/src/hotspot/share/compiler/compileBroker.hpp Tue May 07 09:17:03 2019 +0200 @@ -229,7 +229,6 @@ static JavaThread* make_thread(jobject thread_oop, CompileQueue* queue, AbstractCompiler* comp, TRAPS); static void init_compiler_sweeper_threads(); static void possibly_add_compiler_threads(); - static bool compilation_is_complete (const methodHandle& method, int osr_bci, int comp_level); static bool compilation_is_prohibited(const methodHandle& method, int osr_bci, int comp_level, bool excluded); static void preload_classes (const methodHandle& method, TRAPS); @@ -285,6 +284,7 @@ return NULL; } + static bool compilation_is_complete(const methodHandle& method, int osr_bci, int comp_level); static bool compilation_is_in_queue(const methodHandle& method); static void print_compile_queues(outputStream* st); static void print_directives(outputStream* st); diff -r a9f729b641a3 -r 1dc9bf9d016b src/hotspot/share/oops/instanceKlass.cpp --- a/src/hotspot/share/oops/instanceKlass.cpp Tue May 07 07:44:15 2019 +0200 +++ b/src/hotspot/share/oops/instanceKlass.cpp Tue May 07 09:17:03 2019 +0200 @@ -2965,6 +2965,13 @@ // On-stack replacement stuff void InstanceKlass::add_osr_nmethod(nmethod* n) { +#ifndef PRODUCT + if (TieredCompilation) { + nmethod * prev = lookup_osr_nmethod(n->method(), n->osr_entry_bci(), n->comp_level(), true); + assert(prev == NULL || !prev->is_in_use(), + "redundunt OSR recompilation detected. memory leak in CodeCache!"); + } +#endif // only one compilation can be active { // This is a short non-blocking critical region, so the no safepoint check is ok. @@ -3083,7 +3090,9 @@ } osr = osr->osr_link(); } - if (best != NULL && best->comp_level() >= comp_level && match_level == false) { + + assert(match_level == false || best == NULL, "shouldn't pick up anything if match_level is set"); + if (best != NULL && best->comp_level() >= comp_level) { return best; } return NULL; diff -r a9f729b641a3 -r 1dc9bf9d016b src/hotspot/share/prims/whitebox.cpp --- a/src/hotspot/share/prims/whitebox.cpp Tue May 07 07:44:15 2019 +0200 +++ b/src/hotspot/share/prims/whitebox.cpp Tue May 07 09:17:03 2019 +0200 @@ -1080,6 +1080,24 @@ return result; WB_END +WB_ENTRY(void, WB_MarkMethodProfiled(JNIEnv* env, jobject o, jobject method)) + jmethodID jmid = reflected_method_to_jmid(thread, env, method); + CHECK_JNI_EXCEPTION(env); + methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); + + MethodData* mdo = mh->method_data(); + if (mdo == NULL) { + Method::build_interpreter_method_data(mh, CHECK_AND_CLEAR); + mdo = mh->method_data(); + } + mdo->init(); + InvocationCounter* icnt = mdo->invocation_counter(); + InvocationCounter* bcnt = mdo->backedge_counter(); + // set i-counter according to TieredThresholdPolicy::is_method_profiled + icnt->set(InvocationCounter::wait_for_compile, Tier4MinInvocationThreshold); + bcnt->set(InvocationCounter::wait_for_compile, Tier4CompileThreshold); +WB_END + WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION(env); @@ -2209,6 +2227,8 @@ CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation}, {CC"enqueueInitializerForCompilation0", CC"(Ljava/lang/Class;I)Z", (void*)&WB_EnqueueInitializerForCompilation}, + {CC"markMethodProfiled", + CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_MarkMethodProfiled}, {CC"clearMethodState0", CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState}, {CC"lockCompilation", CC"()V", (void*)&WB_LockCompilation}, diff -r a9f729b641a3 -r 1dc9bf9d016b src/hotspot/share/runtime/tieredThresholdPolicy.cpp --- a/src/hotspot/share/runtime/tieredThresholdPolicy.cpp Tue May 07 07:44:15 2019 +0200 +++ b/src/hotspot/share/runtime/tieredThresholdPolicy.cpp Tue May 07 09:17:03 2019 +0200 @@ -353,6 +353,16 @@ TieredStopAtLevel > CompLevel_full_profile && max_method != NULL && is_method_profiled(max_method)) { max_task->set_comp_level(CompLevel_limited_profile); + + if (CompileBroker::compilation_is_complete(max_method, max_task->osr_bci(), CompLevel_limited_profile)) { + if (PrintTieredEvents) { + print_event(REMOVE_FROM_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level()); + } + compile_queue->remove_and_mark_stale(max_task); + max_method->clear_queued_for_compilation(); + return NULL; + } + if (PrintTieredEvents) { print_event(UPDATE_IN_QUEUE, max_method, max_method, max_task->osr_bci(), (CompLevel)max_task->comp_level()); } diff -r a9f729b641a3 -r 1dc9bf9d016b test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/jtreg/compiler/tiered/Level2RecompilationTest.java Tue May 07 09:17:03 2019 +0200 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2019, 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 Level2RecompilationTest + * @summary Test downgrading mechanism from level 3 to level 2 for those profiled methods. + * @library /test/lib / + * @modules java.base/jdk.internal.misc + * java.management + * + * @build sun.hotspot.WhiteBox + * @run driver ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+TieredCompilation + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-UseCounterDecay + * -XX:CompileCommand=compileonly,compiler.whitebox.SimpleTestCaseHelper::* + * -XX:CompileCommand=print,compiler.whitebox.SimpleTestCaseHelper::* + * compiler.tiered.Level2RecompilationTest + */ + +package compiler.tiered; + +import compiler.whitebox.CompilerWhiteBoxTest; +import jtreg.SkippedException; + +public class Level2RecompilationTest extends CompLevelsTest { + public static void main(String[] args) throws Throwable { + if (CompilerWhiteBoxTest.skipOnTieredCompilation(false)) { + throw new SkippedException("Test isn't applicable for non-tiered mode"); + } + String[] testcases = {"METHOD_TEST", "OSR_STATIC_TEST"}; + CompilerWhiteBoxTest.main(Level2RecompilationTest::new, testcases); + } + + protected Level2RecompilationTest(TestCase testCase) { + super(testCase); + // to prevent inlining of #method + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + @Override + protected void test() throws Exception { + if (skipXcompOSR()) { + return; + } + + checkNotCompiled(); + int bci = WHITE_BOX.getMethodEntryBci(method); + WHITE_BOX.markMethodProfiled(method); + if (testCase.isOsr()) { + // for OSR compilation, it must be the begin of a BB. + // c1_GraphBulider.cpp:153 assert(method()->bci_block_start().at(cur_bci), ... + bci = 0; + } + + WHITE_BOX.enqueueMethodForCompilation(method, COMP_LEVEL_FULL_PROFILE, bci); + checkCompiled(); + checkLevel(COMP_LEVEL_LIMITED_PROFILE, getCompLevel()); + + for (int i=0; i<1_000; ++i) { + WHITE_BOX.enqueueMethodForCompilation(method, COMP_LEVEL_FULL_PROFILE, bci); + waitBackgroundCompilation(); + checkLevel(COMP_LEVEL_LIMITED_PROFILE, getCompLevel()); + } + } + + @Override + protected void checkLevel(int expected, int actual) { + if (expected == COMP_LEVEL_FULL_PROFILE + && actual == COMP_LEVEL_LIMITED_PROFILE) { + // for simple method full_profile may be replaced by limited_profile + if (IS_VERBOSE) { + System.out.printf("Level check: full profiling was replaced " + + "by limited profiling. Expected: %d, actual:%d\n", + expected, actual); + } + return; + } + super.checkLevel(expected, actual); + } +} + diff -r a9f729b641a3 -r 1dc9bf9d016b test/lib/sun/hotspot/WhiteBox.java --- a/test/lib/sun/hotspot/WhiteBox.java Tue May 07 07:44:15 2019 +0200 +++ b/test/lib/sun/hotspot/WhiteBox.java Tue May 07 09:17:03 2019 +0200 @@ -330,6 +330,7 @@ return enqueueInitializerForCompilation0(aClass, compLevel); } private native void clearMethodState0(Executable method); + public native void markMethodProfiled(Executable method); public void clearMethodState(Executable method) { Objects.requireNonNull(method); clearMethodState0(method);