--- old/src/share/vm/ci/ciMethod.cpp 2015-06-10 14:57:19.000000000 +0300 +++ new/src/share/vm/ci/ciMethod.cpp 2015-06-10 14:57:19.000000000 +0300 @@ -71,8 +71,7 @@ // Loaded method. ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) : ciMetadata(h_m()), - _holder(holder), - _has_injected_profile(false) + _holder(holder) { assert(h_m() != NULL, "no null method"); @@ -170,8 +169,7 @@ _liveness( NULL), _can_be_statically_bound(false), _method_blocks( NULL), - _method_data( NULL), - _has_injected_profile( false) + _method_data( NULL) #if defined(COMPILER2) || defined(SHARK) , _flow( NULL), --- old/src/share/vm/ci/ciMethod.hpp 2015-06-10 14:57:20.000000000 +0300 +++ new/src/share/vm/ci/ciMethod.hpp 2015-06-10 14:57:20.000000000 +0300 @@ -81,7 +81,6 @@ bool _is_c1_compilable; bool _is_c2_compilable; bool _can_be_statically_bound; - bool _has_injected_profile; // Lazy fields, filled in on demand address _code; @@ -179,9 +178,9 @@ // Code size for inlining decisions. int code_size_for_inlining(); - bool caller_sensitive() { return get_Method()->caller_sensitive(); } - bool force_inline() { return get_Method()->force_inline(); } - bool dont_inline() { return get_Method()->dont_inline(); } + bool caller_sensitive() const { return get_Method()->caller_sensitive(); } + bool force_inline() const { return get_Method()->force_inline(); } + bool dont_inline() const { return get_Method()->dont_inline(); } int comp_level(); int highest_osr_comp_level(); @@ -289,9 +288,6 @@ int instructions_size(); int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC - bool has_injected_profile() const { return _has_injected_profile; } - void set_injected_profile(bool x) { _has_injected_profile = x; } - // Stack walking support bool is_ignored_by_security_stack_walk() const; --- old/src/share/vm/classfile/classFileParser.cpp 2015-06-10 14:57:20.000000000 +0300 +++ new/src/share/vm/classfile/classFileParser.cpp 2015-06-10 14:57:20.000000000 +0300 @@ -1742,6 +1742,10 @@ if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code return _method_DontInline; + case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_InjectedProfile_signature): + if (_location != _in_method) break; // only allow for methods + if (!privileged) break; // only allow in privileged code + return _method_InjectedProfile; case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature): if (_location != _in_method) break; // only allow for methods if (!privileged) break; // only allow in privileged code @@ -1783,6 +1787,8 @@ m->set_force_inline(true); if (has_annotation(_method_DontInline)) m->set_dont_inline(true); + if (has_annotation(_method_InjectedProfile)) + m->set_has_injected_profile(true); if (has_annotation(_method_LambdaForm_Compiled) && m->intrinsic_id() == vmIntrinsics::_none) m->set_intrinsic_id(vmIntrinsics::_compiledLambdaForm); if (has_annotation(_method_LambdaForm_Hidden)) --- old/src/share/vm/classfile/classFileParser.hpp 2015-06-10 14:57:22.000000000 +0300 +++ new/src/share/vm/classfile/classFileParser.hpp 2015-06-10 14:57:21.000000000 +0300 @@ -127,6 +127,7 @@ _method_CallerSensitive, _method_ForceInline, _method_DontInline, + _method_InjectedProfile, _method_LambdaForm_Compiled, _method_LambdaForm_Hidden, _sun_misc_Contended, --- old/src/share/vm/classfile/vmSymbols.hpp 2015-06-10 14:57:23.000000000 +0300 +++ new/src/share/vm/classfile/vmSymbols.hpp 2015-06-10 14:57:22.000000000 +0300 @@ -281,6 +281,7 @@ template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \ template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \ template(java_lang_invoke_DontInline_signature, "Ljava/lang/invoke/DontInline;") \ + template(java_lang_invoke_InjectedProfile_signature, "Ljava/lang/invoke/InjectedProfile;") \ template(java_lang_invoke_Stable_signature, "Ljava/lang/invoke/Stable;") \ template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \ template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \ --- old/src/share/vm/oops/method.cpp 2015-06-10 14:57:23.000000000 +0300 +++ new/src/share/vm/oops/method.cpp 2015-06-10 14:57:23.000000000 +0300 @@ -93,6 +93,7 @@ set_force_inline(false); set_hidden(false); set_dont_inline(false); + set_has_injected_profile(false); set_method_data(NULL); clear_method_counters(); set_vtable_index(Method::garbage_vtable_index); --- old/src/share/vm/oops/method.hpp 2015-06-10 14:57:24.000000000 +0300 +++ new/src/share/vm/oops/method.hpp 2015-06-10 14:57:24.000000000 +0300 @@ -76,12 +76,13 @@ // Flags enum Flags { - _jfr_towrite = 1 << 0, - _caller_sensitive = 1 << 1, - _force_inline = 1 << 2, - _dont_inline = 1 << 3, - _hidden = 1 << 4, - _running_emcp = 1 << 5 + _jfr_towrite = 1 << 0, + _caller_sensitive = 1 << 1, + _force_inline = 1 << 2, + _dont_inline = 1 << 3, + _hidden = 1 << 4, + _has_injected_profile = 1 << 5, + _running_emcp = 1 << 6 }; u1 _flags; @@ -814,6 +815,13 @@ _flags = x ? (_flags | _hidden) : (_flags & ~_hidden); } + bool has_injected_profile() { + return (_flags & _has_injected_profile) != 0; + } + void set_has_injected_profile(bool x) { + _flags = x ? (_flags | _has_injected_profile) : (_flags & ~_has_injected_profile); + } + ConstMethod::MethodType method_type() const { return _constMethod->method_type(); } --- old/src/share/vm/opto/compile.cpp 2015-06-10 14:57:25.000000000 +0300 +++ new/src/share/vm/opto/compile.cpp 2015-06-10 14:57:25.000000000 +0300 @@ -3390,9 +3390,6 @@ bool Compile::too_many_traps(ciMethod* method, int bci, Deoptimization::DeoptReason reason) { - if (method->has_injected_profile()) { - return false; - } ciMethodData* md = method->method_data(); if (md->is_empty()) { // Assume the trap has not occurred, or that it occurred only @@ -3442,9 +3439,6 @@ bool Compile::too_many_recompiles(ciMethod* method, int bci, Deoptimization::DeoptReason reason) { - if (method->has_injected_profile()) { - return false; - } ciMethodData* md = method->method_data(); if (md->is_empty()) { // Assume the trap has not occurred, or that it occurred only --- old/src/share/vm/opto/library_call.cpp 2015-06-10 14:57:27.000000000 +0300 +++ new/src/share/vm/opto/library_call.cpp 2015-06-10 14:57:27.000000000 +0300 @@ -6015,8 +6015,6 @@ jint false_cnt = aobj->element_value(0).as_int(); jint true_cnt = aobj->element_value(1).as_int(); - method()->set_injected_profile(true); - if (C->log() != NULL) { C->log()->elem("observe source='profileBoolean' false='%d' true='%d'", false_cnt, true_cnt); --- old/src/share/vm/runtime/deoptimization.cpp 2015-06-10 14:57:29.000000000 +0300 +++ new/src/share/vm/runtime/deoptimization.cpp 2015-06-10 14:57:29.000000000 +0300 @@ -1460,7 +1460,11 @@ // // The other actions cause immediate removal of the present code. - bool update_trap_state = (reason != Reason_tenured); + // Traps caused by injected profile shouldn't pollute trap counts. + bool injected_profile_trap = trap_method->has_injected_profile() && + (reason == Reason_intrinsic || reason == Reason_unreached); + + bool update_trap_state = (reason != Reason_tenured) && !injected_profile_trap; bool make_not_entrant = false; bool make_not_compilable = false; bool reprofile = false; --- /dev/null 2015-06-10 14:57:30.000000000 +0300 +++ new/test/compiler/jsr292/PollutedTrapCounts.java 2015-06-10 14:57:30.000000000 +0300 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2015, 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 8074551 + * @library /testlibrary + * @run main/othervm -Xbatch -XX:-TieredCompilation PollutedTrapCounts + */ +import java.lang.invoke.*; +import jdk.test.lib.*; + +public class PollutedTrapCounts { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+IgnoreUnrecognizedVMOptions", + "-XX:-TieredCompilation", "-Xbatch", + "-XX:PerBytecodeRecompilationCutoff=10", "-XX:PerMethodRecompilationCutoff=10", + "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining", + "PollutedTrapCounts$Test"); + + OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); + + analyzer.shouldHaveExitValue(0); + + analyzer.shouldNotContain("not compilable (disabled)"); + } + + static class Test { + public static final MethodHandle test1; + public static final MethodHandle test2; + public static final MethodHandle empty; + + static { + try { + Class THIS_CLASS = Test.class; + MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + test1 = LOOKUP.findStatic(THIS_CLASS, "test1", MethodType.methodType(boolean.class, boolean.class)); + test2 = LOOKUP.findStatic(THIS_CLASS, "test2", MethodType.methodType(boolean.class, boolean.class)); + empty = LOOKUP.findStatic(THIS_CLASS, "empty", MethodType.methodType(void.class, boolean.class)); + } catch(Throwable e) { + throw new Error(e); + } + } + + static boolean test1(boolean b) { + return b; + } + static boolean test2(boolean b) { + return true; + } + static void empty(boolean b) {} + + static void test(boolean freqValue, boolean removeInlineBlocker) throws Throwable { + MethodHandle innerGWT = MethodHandles.guardWithTest(test1, empty, empty); + MethodHandle outerGWT = MethodHandles.guardWithTest(test2, innerGWT, innerGWT); + + // Trigger compilation + for (int i = 0; i < 20_000; i++) { + outerGWT.invokeExact(freqValue); + } + + // Trigger deopt & nmethod invalidation + outerGWT.invokeExact(!freqValue); + + // Force inline blocker removal on rare-taken path + if (removeInlineBlocker) { + for (int i = 0; i < 100; i++) { + outerGWT.invokeExact(!freqValue); + } + } + + // Trigger recompilation + for (int i = 0; i < 20_000; i++) { + outerGWT.invokeExact(freqValue); + } + } + + public static void main(String[] args) throws Throwable { + boolean freqValue = true; + boolean removeInlineBlocker = false; + for (int i = 0; i < 20; i++) { + test(freqValue, removeInlineBlocker); + freqValue = !freqValue; + removeInlineBlocker = !removeInlineBlocker; + } + } + } +}