提交 b8343a24 编写于 作者: V vlivanov

8062280: C2: inlining failure due to access checks being too strict

Reviewed-by: kvn
上级 54cab266
...@@ -691,7 +691,8 @@ ciKlass* ciMethod::parameter_profiled_type(int i) { ...@@ -691,7 +691,8 @@ ciKlass* ciMethod::parameter_profiled_type(int i) {
// via assert_unique_concrete_method or assert_leaf_type. // via assert_unique_concrete_method or assert_leaf_type.
ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller, ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller,
ciInstanceKlass* callee_holder, ciInstanceKlass* callee_holder,
ciInstanceKlass* actual_recv) { ciInstanceKlass* actual_recv,
bool check_access) {
check_is_loaded(); check_is_loaded();
if (actual_recv->is_interface()) { if (actual_recv->is_interface()) {
...@@ -699,7 +700,7 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller, ...@@ -699,7 +700,7 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller,
return NULL; return NULL;
} }
ciMethod* root_m = resolve_invoke(caller, actual_recv); ciMethod* root_m = resolve_invoke(caller, actual_recv, check_access);
if (root_m == NULL) { if (root_m == NULL) {
// Something went wrong looking up the actual receiver method. // Something went wrong looking up the actual receiver method.
return NULL; return NULL;
...@@ -778,7 +779,7 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller, ...@@ -778,7 +779,7 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller,
// //
// Given a known receiver klass, find the target for the call. // Given a known receiver klass, find the target for the call.
// Return NULL if the call has no target or the target is abstract. // Return NULL if the call has no target or the target is abstract.
ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver) { ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, bool check_access) {
check_is_loaded(); check_is_loaded();
VM_ENTRY_MARK; VM_ENTRY_MARK;
...@@ -795,9 +796,9 @@ ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver) { ...@@ -795,9 +796,9 @@ ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver) {
|| ||
InstanceKlass::cast(h_recv())->is_linked() && !exact_receiver->is_interface()) { InstanceKlass::cast(h_recv())->is_linked() && !exact_receiver->is_interface()) {
if (holder()->is_interface()) { if (holder()->is_interface()) {
m = LinkResolver::resolve_interface_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass); m = LinkResolver::resolve_interface_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass, check_access);
} else { } else {
m = LinkResolver::resolve_virtual_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass); m = LinkResolver::resolve_virtual_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass, check_access);
} }
} }
......
...@@ -249,11 +249,12 @@ class ciMethod : public ciMetadata { ...@@ -249,11 +249,12 @@ class ciMethod : public ciMetadata {
// its calling environment. // its calling environment.
ciMethod* find_monomorphic_target(ciInstanceKlass* caller, ciMethod* find_monomorphic_target(ciInstanceKlass* caller,
ciInstanceKlass* callee_holder, ciInstanceKlass* callee_holder,
ciInstanceKlass* actual_receiver); ciInstanceKlass* actual_receiver,
bool check_access = true);
// Given a known receiver klass, find the target for the call. // Given a known receiver klass, find the target for the call.
// Return NULL if the call has no target or is abstract. // Return NULL if the call has no target or is abstract.
ciMethod* resolve_invoke(ciKlass* caller, ciKlass* exact_receiver); ciMethod* resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, bool check_access = true);
// Find the proper vtable index to invoke this method. // Find the proper vtable index to invoke this method.
int resolve_vtable_index(ciKlass* caller, ciKlass* receiver); int resolve_vtable_index(ciKlass* caller, ciKlass* receiver);
......
...@@ -1410,10 +1410,11 @@ methodHandle LinkResolver::resolve_virtual_call_or_null( ...@@ -1410,10 +1410,11 @@ methodHandle LinkResolver::resolve_virtual_call_or_null(
KlassHandle resolved_klass, KlassHandle resolved_klass,
Symbol* name, Symbol* name,
Symbol* signature, Symbol* signature,
KlassHandle current_klass) { KlassHandle current_klass,
bool check_access) {
EXCEPTION_MARK; EXCEPTION_MARK;
CallInfo info; CallInfo info;
resolve_virtual_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, true, false, THREAD); resolve_virtual_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, check_access, false, THREAD);
if (HAS_PENDING_EXCEPTION) { if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION;
return methodHandle(); return methodHandle();
...@@ -1426,10 +1427,11 @@ methodHandle LinkResolver::resolve_interface_call_or_null( ...@@ -1426,10 +1427,11 @@ methodHandle LinkResolver::resolve_interface_call_or_null(
KlassHandle resolved_klass, KlassHandle resolved_klass,
Symbol* name, Symbol* name,
Symbol* signature, Symbol* signature,
KlassHandle current_klass) { KlassHandle current_klass,
bool check_access) {
EXCEPTION_MARK; EXCEPTION_MARK;
CallInfo info; CallInfo info;
resolve_interface_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, true, false, THREAD); resolve_interface_call(info, Handle(), receiver_klass, resolved_klass, name, signature, current_klass, check_access, false, THREAD);
if (HAS_PENDING_EXCEPTION) { if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION;
return methodHandle(); return methodHandle();
...@@ -1457,10 +1459,11 @@ methodHandle LinkResolver::resolve_static_call_or_null( ...@@ -1457,10 +1459,11 @@ methodHandle LinkResolver::resolve_static_call_or_null(
KlassHandle resolved_klass, KlassHandle resolved_klass,
Symbol* name, Symbol* name,
Symbol* signature, Symbol* signature,
KlassHandle current_klass) { KlassHandle current_klass,
bool check_access) {
EXCEPTION_MARK; EXCEPTION_MARK;
CallInfo info; CallInfo info;
resolve_static_call(info, resolved_klass, name, signature, current_klass, true, false, THREAD); resolve_static_call(info, resolved_klass, name, signature, current_klass, check_access, false, THREAD);
if (HAS_PENDING_EXCEPTION) { if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION;
return methodHandle(); return methodHandle();
...@@ -1468,11 +1471,15 @@ methodHandle LinkResolver::resolve_static_call_or_null( ...@@ -1468,11 +1471,15 @@ methodHandle LinkResolver::resolve_static_call_or_null(
return info.selected_method(); return info.selected_method();
} }
methodHandle LinkResolver::resolve_special_call_or_null(KlassHandle resolved_klass, Symbol* name, Symbol* signature, methodHandle LinkResolver::resolve_special_call_or_null(
KlassHandle current_klass) { KlassHandle resolved_klass,
Symbol* name,
Symbol* signature,
KlassHandle current_klass,
bool check_access) {
EXCEPTION_MARK; EXCEPTION_MARK;
CallInfo info; CallInfo info;
resolve_special_call(info, resolved_klass, name, signature, current_klass, true, THREAD); resolve_special_call(info, resolved_klass, name, signature, current_klass, check_access, THREAD);
if (HAS_PENDING_EXCEPTION) { if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION;
return methodHandle(); return methodHandle();
......
...@@ -181,10 +181,10 @@ class LinkResolver: AllStatic { ...@@ -181,10 +181,10 @@ class LinkResolver: AllStatic {
// same as above for compile-time resolution; but returns null handle instead of throwing an exception on error // same as above for compile-time resolution; but returns null handle instead of throwing an exception on error
// also, does not initialize klass (i.e., no side effects) // also, does not initialize klass (i.e., no side effects)
static methodHandle resolve_virtual_call_or_null (KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); static methodHandle resolve_virtual_call_or_null (KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true);
static methodHandle resolve_interface_call_or_null(KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); static methodHandle resolve_interface_call_or_null(KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true);
static methodHandle resolve_static_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); static methodHandle resolve_static_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true);
static methodHandle resolve_special_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass); static methodHandle resolve_special_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass, bool check_access = true);
static int vtable_index_of_interface_method(KlassHandle klass, methodHandle resolved_method); static int vtable_index_of_interface_method(KlassHandle klass, methodHandle resolved_method);
// same as above for compile-time resolution; returns vtable_index if current_klass if linked // same as above for compile-time resolution; returns vtable_index if current_klass if linked
......
...@@ -859,7 +859,8 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod* ...@@ -859,7 +859,8 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
// Parse::do_call()) // Parse::do_call())
target = C->optimize_virtual_call(caller, jvms->bci(), klass, klass, target = C->optimize_virtual_call(caller, jvms->bci(), klass, klass,
target, receiver_type, is_virtual, target, receiver_type, is_virtual,
call_does_dispatch, vtable_index); // out-parameters call_does_dispatch, vtable_index, // out-parameters
/*check_access=*/false);
// We lack profiling at this call but type speculation may // We lack profiling at this call but type speculation may
// provide us with a type // provide us with a type
speculative_receiver_type = (receiver_type != NULL) ? receiver_type->speculative_type() : NULL; speculative_receiver_type = (receiver_type != NULL) ? receiver_type->speculative_type() : NULL;
......
...@@ -861,9 +861,11 @@ class Compile : public Phase { ...@@ -861,9 +861,11 @@ class Compile : public Phase {
ciMethod* optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass, ciMethod* optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciKlass* holder, ciMethod* callee, ciKlass* holder, ciMethod* callee,
const TypeOopPtr* receiver_type, bool is_virtual, const TypeOopPtr* receiver_type, bool is_virtual,
bool &call_does_dispatch, int &vtable_index); bool &call_does_dispatch, int &vtable_index,
bool check_access = true);
ciMethod* optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass, ciMethod* optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciMethod* callee, const TypeOopPtr* receiver_type); ciMethod* callee, const TypeOopPtr* receiver_type,
bool check_access = true);
// Report if there were too many traps at a current method and bci. // Report if there were too many traps at a current method and bci.
// Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded. // Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded.
......
...@@ -956,13 +956,15 @@ void Parse::count_compiled_calls(bool at_method_entry, bool is_inline) { ...@@ -956,13 +956,15 @@ void Parse::count_compiled_calls(bool at_method_entry, bool is_inline) {
ciMethod* Compile::optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass, ciMethod* Compile::optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciKlass* holder, ciMethod* callee, ciKlass* holder, ciMethod* callee,
const TypeOopPtr* receiver_type, bool is_virtual, const TypeOopPtr* receiver_type, bool is_virtual,
bool& call_does_dispatch, int& vtable_index) { bool& call_does_dispatch, int& vtable_index,
bool check_access) {
// Set default values for out-parameters. // Set default values for out-parameters.
call_does_dispatch = true; call_does_dispatch = true;
vtable_index = Method::invalid_vtable_index; vtable_index = Method::invalid_vtable_index;
// Choose call strategy. // Choose call strategy.
ciMethod* optimized_virtual_method = optimize_inlining(caller, bci, klass, callee, receiver_type); ciMethod* optimized_virtual_method = optimize_inlining(caller, bci, klass, callee,
receiver_type, check_access);
// Have the call been sufficiently improved such that it is no longer a virtual? // Have the call been sufficiently improved such that it is no longer a virtual?
if (optimized_virtual_method != NULL) { if (optimized_virtual_method != NULL) {
...@@ -977,7 +979,8 @@ ciMethod* Compile::optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKl ...@@ -977,7 +979,8 @@ ciMethod* Compile::optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKl
// Identify possible target method and inlining style // Identify possible target method and inlining style
ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass, ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciMethod* callee, const TypeOopPtr* receiver_type) { ciMethod* callee, const TypeOopPtr* receiver_type,
bool check_access) {
// only use for virtual or interface calls // only use for virtual or interface calls
// If it is obviously final, do not bother to call find_monomorphic_target, // If it is obviously final, do not bother to call find_monomorphic_target,
...@@ -1017,7 +1020,7 @@ ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass* ...@@ -1017,7 +1020,7 @@ ciMethod* Compile::optimize_inlining(ciMethod* caller, int bci, ciInstanceKlass*
} }
ciInstanceKlass* calling_klass = caller->holder(); ciInstanceKlass* calling_klass = caller->holder();
ciMethod* cha_monomorphic_target = callee->find_monomorphic_target(calling_klass, klass, actual_receiver); ciMethod* cha_monomorphic_target = callee->find_monomorphic_target(calling_klass, klass, actual_receiver, check_access);
if (cha_monomorphic_target != NULL) { if (cha_monomorphic_target != NULL) {
assert(!cha_monomorphic_target->is_abstract(), ""); assert(!cha_monomorphic_target->is_abstract(), "");
// Look at the method-receiver type. Does it add "too much information"? // Look at the method-receiver type. Does it add "too much information"?
......
/*
* 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 8062280
* @summary C2: inlining failure due to access checks being too strict
* @library /testlibrary
* @run main/othervm MHInlineTest
*/
import java.lang.invoke.*;
import com.oracle.java.testlibrary.*;
import static com.oracle.java.testlibrary.Asserts.*;
public class MHInlineTest {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
"-XX:+IgnoreUnrecognizedVMOptions", "-showversion",
"-server", "-XX:-TieredCompilation", "-Xbatch",
"-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining",
"-XX:CompileCommand=dontinline,MHInlineTest::test*",
"MHInlineTest$Launcher");
OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
analyzer.shouldHaveExitValue(0);
// The test is applicable only to C2 (present in Server VM).
if (analyzer.getStderr().contains("Server VM")) {
analyzer.shouldContain("MHInlineTest$B::public_x (3 bytes) inline (hot)");
analyzer.shouldContain( "MHInlineTest$B::protected_x (3 bytes) inline (hot)");
analyzer.shouldContain( "MHInlineTest$B::package_x (3 bytes) inline (hot)");
analyzer.shouldContain("MHInlineTest$A::package_final_x (3 bytes) inline (hot)");
analyzer.shouldContain("MHInlineTest$B::private_x (3 bytes) inline (hot)");
analyzer.shouldContain("MHInlineTest$B::private_static_x (3 bytes) inline (hot)");
analyzer.shouldContain("MHInlineTest$A::package_static_x (3 bytes) inline (hot)");
analyzer.shouldNotContain("MHInlineTest$A::protected_x (3 bytes) virtual call");
analyzer.shouldNotContain("MHInlineTest$A::package_x (3 bytes) virtual call");
}
}
static class A {
public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
public Class<?> public_x() { return A.class; }
protected Class<?> protected_x() { return A.class; }
Class<?> package_x() { return A.class; }
final Class<?> package_final_x() { return A.class; }
static Class<?> package_static_x() { return A.class; }
}
static class B extends A {
public static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
@Override public Class<?> public_x() { return B.class; }
@Override protected Class<?> protected_x() { return B.class; }
@Override Class<?> package_x() { return B.class; }
private Class<?> private_x() { return B.class; }
static Class<?> private_static_x() { return B.class; }
}
static final MethodHandle A_PUBLIC_X;
static final MethodHandle A_PROTECTED_X;
static final MethodHandle A_PACKAGE_X;
static final MethodHandle A_PACKAGE_STATIC_X;
static final MethodHandle A_PACKAGE_FINAL_X;
static final MethodHandle B_PRIVATE_X;
static final MethodHandle B_PRIVATE_STATIC_X;
static {
try {
MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
A_PUBLIC_X = LOOKUP.findVirtual(
A.class, "public_x", MethodType.methodType(Class.class));
A_PROTECTED_X = LOOKUP.findVirtual(
A.class, "protected_x", MethodType.methodType(Class.class));
A_PACKAGE_X = LOOKUP.findVirtual(
A.class, "package_x", MethodType.methodType(Class.class));
A_PACKAGE_FINAL_X = LOOKUP.findVirtual(
A.class, "package_final_x", MethodType.methodType(Class.class));
A_PACKAGE_STATIC_X = LOOKUP.findStatic(
A.class, "package_static_x", MethodType.methodType(Class.class));
B_PRIVATE_X = B.LOOKUP.findVirtual(
B.class, "private_x", MethodType.methodType(Class.class));
B_PRIVATE_STATIC_X = B.LOOKUP.findStatic(
B.class, "private_static_x", MethodType.methodType(Class.class));
} catch (Exception e) {
throw new Error(e);
}
}
static final A a = new B();
private static void testPublicMH() {
try {
Class<?> r = (Class<?>)A_PUBLIC_X.invokeExact(a);
assertEquals(r, B.class);
} catch (Throwable throwable) {
throw new Error(throwable);
}
}
private static void testProtectedMH() {
try {
Class<?> r = (Class<?>)A_PROTECTED_X.invokeExact(a);
assertEquals(r, B.class);
} catch (Throwable throwable) {
throw new Error(throwable);
}
}
private static void testPackageMH() {
try {
Class<?> r = (Class<?>)A_PACKAGE_X.invokeExact(a);
assertEquals(r, B.class);
} catch (Throwable throwable) {
throw new Error(throwable);
}
}
private static void testPackageFinalMH() {
try {
Class<?> r = (Class<?>)A_PACKAGE_FINAL_X.invokeExact(a);
assertEquals(r, A.class);
} catch (Throwable throwable) {
throw new Error(throwable);
}
}
private static void testPackageStaticMH() {
try {
Class<?> r = (Class<?>)A_PACKAGE_STATIC_X.invokeExact();
assertEquals(r, A.class);
} catch (Throwable throwable) {
throw new Error(throwable);
}
}
private static void testPrivateMH() {
try {
Class<?> r = (Class<?>)B_PRIVATE_X.invokeExact((B)a);
assertEquals(r, B.class);
} catch (Throwable throwable) {
throw new Error(throwable);
}
}
private static void testPrivateStaticMH() {
try {
Class<?> r = (Class<?>)B_PRIVATE_STATIC_X.invokeExact();
assertEquals(r, B.class);
} catch (Throwable throwable) {
throw new Error(throwable);
}
}
static class Launcher {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 20_000; i++) {
testPublicMH();
}
for (int i = 0; i < 20_000; i++) {
testProtectedMH();
}
for (int i = 0; i < 20_000; i++) {
testPackageMH();
}
for (int i = 0; i < 20_000; i++) {
testPackageFinalMH();
}
for (int i = 0; i < 20_000; i++) {
testPackageStaticMH();
}
for (int i = 0; i < 20_000; i++) {
testPrivateMH();
}
for (int i = 0; i < 20_000; i++) {
testPrivateStaticMH();
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册