mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 23:04:50 +02:00
8074551: GWT can be marked non-compilable due to deopt count pollution
Reviewed-by: kvn
This commit is contained in:
parent
513d9a5ede
commit
90a42c2491
11 changed files with 142 additions and 26 deletions
|
@ -71,8 +71,7 @@
|
||||||
// Loaded method.
|
// Loaded method.
|
||||||
ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) :
|
ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) :
|
||||||
ciMetadata(h_m()),
|
ciMetadata(h_m()),
|
||||||
_holder(holder),
|
_holder(holder)
|
||||||
_has_injected_profile(false)
|
|
||||||
{
|
{
|
||||||
assert(h_m() != NULL, "no null method");
|
assert(h_m() != NULL, "no null method");
|
||||||
|
|
||||||
|
@ -170,8 +169,7 @@ ciMethod::ciMethod(ciInstanceKlass* holder,
|
||||||
_liveness( NULL),
|
_liveness( NULL),
|
||||||
_can_be_statically_bound(false),
|
_can_be_statically_bound(false),
|
||||||
_method_blocks( NULL),
|
_method_blocks( NULL),
|
||||||
_method_data( NULL),
|
_method_data( NULL)
|
||||||
_has_injected_profile( false)
|
|
||||||
#if defined(COMPILER2) || defined(SHARK)
|
#if defined(COMPILER2) || defined(SHARK)
|
||||||
,
|
,
|
||||||
_flow( NULL),
|
_flow( NULL),
|
||||||
|
|
|
@ -81,7 +81,6 @@ class ciMethod : public ciMetadata {
|
||||||
bool _is_c1_compilable;
|
bool _is_c1_compilable;
|
||||||
bool _is_c2_compilable;
|
bool _is_c2_compilable;
|
||||||
bool _can_be_statically_bound;
|
bool _can_be_statically_bound;
|
||||||
bool _has_injected_profile;
|
|
||||||
|
|
||||||
// Lazy fields, filled in on demand
|
// Lazy fields, filled in on demand
|
||||||
address _code;
|
address _code;
|
||||||
|
@ -179,9 +178,9 @@ class ciMethod : public ciMetadata {
|
||||||
// Code size for inlining decisions.
|
// Code size for inlining decisions.
|
||||||
int code_size_for_inlining();
|
int code_size_for_inlining();
|
||||||
|
|
||||||
bool caller_sensitive() { return get_Method()->caller_sensitive(); }
|
bool caller_sensitive() const { return get_Method()->caller_sensitive(); }
|
||||||
bool force_inline() { return get_Method()->force_inline(); }
|
bool force_inline() const { return get_Method()->force_inline(); }
|
||||||
bool dont_inline() { return get_Method()->dont_inline(); }
|
bool dont_inline() const { return get_Method()->dont_inline(); }
|
||||||
|
|
||||||
int comp_level();
|
int comp_level();
|
||||||
int highest_osr_comp_level();
|
int highest_osr_comp_level();
|
||||||
|
@ -289,9 +288,6 @@ class ciMethod : public ciMetadata {
|
||||||
int instructions_size();
|
int instructions_size();
|
||||||
int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC
|
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
|
// Stack walking support
|
||||||
bool is_ignored_by_security_stack_walk() const;
|
bool is_ignored_by_security_stack_walk() const;
|
||||||
|
|
||||||
|
|
|
@ -1742,6 +1742,10 @@ ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_d
|
||||||
if (_location != _in_method) break; // only allow for methods
|
if (_location != _in_method) break; // only allow for methods
|
||||||
if (!privileged) break; // only allow in privileged code
|
if (!privileged) break; // only allow in privileged code
|
||||||
return _method_DontInline;
|
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):
|
case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature):
|
||||||
if (_location != _in_method) break; // only allow for methods
|
if (_location != _in_method) break; // only allow for methods
|
||||||
if (!privileged) break; // only allow in privileged code
|
if (!privileged) break; // only allow in privileged code
|
||||||
|
@ -1783,6 +1787,8 @@ void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) {
|
||||||
m->set_force_inline(true);
|
m->set_force_inline(true);
|
||||||
if (has_annotation(_method_DontInline))
|
if (has_annotation(_method_DontInline))
|
||||||
m->set_dont_inline(true);
|
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)
|
if (has_annotation(_method_LambdaForm_Compiled) && m->intrinsic_id() == vmIntrinsics::_none)
|
||||||
m->set_intrinsic_id(vmIntrinsics::_compiledLambdaForm);
|
m->set_intrinsic_id(vmIntrinsics::_compiledLambdaForm);
|
||||||
if (has_annotation(_method_LambdaForm_Hidden))
|
if (has_annotation(_method_LambdaForm_Hidden))
|
||||||
|
|
|
@ -127,6 +127,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||||
_method_CallerSensitive,
|
_method_CallerSensitive,
|
||||||
_method_ForceInline,
|
_method_ForceInline,
|
||||||
_method_DontInline,
|
_method_DontInline,
|
||||||
|
_method_InjectedProfile,
|
||||||
_method_LambdaForm_Compiled,
|
_method_LambdaForm_Compiled,
|
||||||
_method_LambdaForm_Hidden,
|
_method_LambdaForm_Hidden,
|
||||||
_sun_misc_Contended,
|
_sun_misc_Contended,
|
||||||
|
|
|
@ -278,6 +278,7 @@
|
||||||
template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \
|
template(java_lang_invoke_LambdaForm, "java/lang/invoke/LambdaForm") \
|
||||||
template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \
|
template(java_lang_invoke_ForceInline_signature, "Ljava/lang/invoke/ForceInline;") \
|
||||||
template(java_lang_invoke_DontInline_signature, "Ljava/lang/invoke/DontInline;") \
|
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_Stable_signature, "Ljava/lang/invoke/Stable;") \
|
||||||
template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \
|
template(java_lang_invoke_LambdaForm_Compiled_signature, "Ljava/lang/invoke/LambdaForm$Compiled;") \
|
||||||
template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \
|
template(java_lang_invoke_LambdaForm_Hidden_signature, "Ljava/lang/invoke/LambdaForm$Hidden;") \
|
||||||
|
|
|
@ -93,6 +93,7 @@ Method::Method(ConstMethod* xconst, AccessFlags access_flags, int size) {
|
||||||
set_force_inline(false);
|
set_force_inline(false);
|
||||||
set_hidden(false);
|
set_hidden(false);
|
||||||
set_dont_inline(false);
|
set_dont_inline(false);
|
||||||
|
set_has_injected_profile(false);
|
||||||
set_method_data(NULL);
|
set_method_data(NULL);
|
||||||
clear_method_counters();
|
clear_method_counters();
|
||||||
set_vtable_index(Method::garbage_vtable_index);
|
set_vtable_index(Method::garbage_vtable_index);
|
||||||
|
|
|
@ -76,12 +76,13 @@ class Method : public Metadata {
|
||||||
|
|
||||||
// Flags
|
// Flags
|
||||||
enum Flags {
|
enum Flags {
|
||||||
_jfr_towrite = 1 << 0,
|
_jfr_towrite = 1 << 0,
|
||||||
_caller_sensitive = 1 << 1,
|
_caller_sensitive = 1 << 1,
|
||||||
_force_inline = 1 << 2,
|
_force_inline = 1 << 2,
|
||||||
_dont_inline = 1 << 3,
|
_dont_inline = 1 << 3,
|
||||||
_hidden = 1 << 4,
|
_hidden = 1 << 4,
|
||||||
_running_emcp = 1 << 5
|
_has_injected_profile = 1 << 5,
|
||||||
|
_running_emcp = 1 << 6
|
||||||
};
|
};
|
||||||
u1 _flags;
|
u1 _flags;
|
||||||
|
|
||||||
|
@ -814,6 +815,13 @@ class Method : public Metadata {
|
||||||
_flags = x ? (_flags | _hidden) : (_flags & ~_hidden);
|
_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 {
|
ConstMethod::MethodType method_type() const {
|
||||||
return _constMethod->method_type();
|
return _constMethod->method_type();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3390,9 +3390,6 @@ bool Compile::final_graph_reshaping() {
|
||||||
bool Compile::too_many_traps(ciMethod* method,
|
bool Compile::too_many_traps(ciMethod* method,
|
||||||
int bci,
|
int bci,
|
||||||
Deoptimization::DeoptReason reason) {
|
Deoptimization::DeoptReason reason) {
|
||||||
if (method->has_injected_profile()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ciMethodData* md = method->method_data();
|
ciMethodData* md = method->method_data();
|
||||||
if (md->is_empty()) {
|
if (md->is_empty()) {
|
||||||
// Assume the trap has not occurred, or that it occurred only
|
// Assume the trap has not occurred, or that it occurred only
|
||||||
|
@ -3442,9 +3439,6 @@ bool Compile::too_many_traps(Deoptimization::DeoptReason reason,
|
||||||
bool Compile::too_many_recompiles(ciMethod* method,
|
bool Compile::too_many_recompiles(ciMethod* method,
|
||||||
int bci,
|
int bci,
|
||||||
Deoptimization::DeoptReason reason) {
|
Deoptimization::DeoptReason reason) {
|
||||||
if (method->has_injected_profile()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
ciMethodData* md = method->method_data();
|
ciMethodData* md = method->method_data();
|
||||||
if (md->is_empty()) {
|
if (md->is_empty()) {
|
||||||
// Assume the trap has not occurred, or that it occurred only
|
// Assume the trap has not occurred, or that it occurred only
|
||||||
|
|
|
@ -6125,8 +6125,6 @@ bool LibraryCallKit::inline_profileBoolean() {
|
||||||
jint false_cnt = aobj->element_value(0).as_int();
|
jint false_cnt = aobj->element_value(0).as_int();
|
||||||
jint true_cnt = aobj->element_value(1).as_int();
|
jint true_cnt = aobj->element_value(1).as_int();
|
||||||
|
|
||||||
method()->set_injected_profile(true);
|
|
||||||
|
|
||||||
if (C->log() != NULL) {
|
if (C->log() != NULL) {
|
||||||
C->log()->elem("observe source='profileBoolean' false='%d' true='%d'",
|
C->log()->elem("observe source='profileBoolean' false='%d' true='%d'",
|
||||||
false_cnt, true_cnt);
|
false_cnt, true_cnt);
|
||||||
|
|
|
@ -1460,7 +1460,11 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
|
||||||
//
|
//
|
||||||
// The other actions cause immediate removal of the present code.
|
// 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_entrant = false;
|
||||||
bool make_not_compilable = false;
|
bool make_not_compilable = false;
|
||||||
bool reprofile = false;
|
bool reprofile = false;
|
||||||
|
|
109
hotspot/test/compiler/jsr292/PollutedTrapCounts.java
Normal file
109
hotspot/test/compiler/jsr292/PollutedTrapCounts.java
Normal file
|
@ -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 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue