提交 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) {
// via assert_unique_concrete_method or assert_leaf_type.
ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller,
ciInstanceKlass* callee_holder,
ciInstanceKlass* actual_recv) {
ciInstanceKlass* actual_recv,
bool check_access) {
check_is_loaded();
if (actual_recv->is_interface()) {
......@@ -699,7 +700,7 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller,
return NULL;
}
ciMethod* root_m = resolve_invoke(caller, actual_recv);
ciMethod* root_m = resolve_invoke(caller, actual_recv, check_access);
if (root_m == NULL) {
// Something went wrong looking up the actual receiver method.
return NULL;
......@@ -778,7 +779,7 @@ ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller,
//
// Given a known receiver klass, find the target for the call.
// 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();
VM_ENTRY_MARK;
......@@ -795,9 +796,9 @@ ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver) {
||
InstanceKlass::cast(h_recv())->is_linked() && !exact_receiver->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 {
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 {
// its calling environment.
ciMethod* find_monomorphic_target(ciInstanceKlass* caller,
ciInstanceKlass* callee_holder,
ciInstanceKlass* actual_receiver);
ciInstanceKlass* actual_receiver,
bool check_access = true);
// Given a known receiver klass, find the target for the call.
// 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.
int resolve_vtable_index(ciKlass* caller, ciKlass* receiver);
......
......@@ -1410,10 +1410,11 @@ methodHandle LinkResolver::resolve_virtual_call_or_null(
KlassHandle resolved_klass,
Symbol* name,
Symbol* signature,
KlassHandle current_klass) {
KlassHandle current_klass,
bool check_access) {
EXCEPTION_MARK;
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) {
CLEAR_PENDING_EXCEPTION;
return methodHandle();
......@@ -1426,10 +1427,11 @@ methodHandle LinkResolver::resolve_interface_call_or_null(
KlassHandle resolved_klass,
Symbol* name,
Symbol* signature,
KlassHandle current_klass) {
KlassHandle current_klass,
bool check_access) {
EXCEPTION_MARK;
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) {
CLEAR_PENDING_EXCEPTION;
return methodHandle();
......@@ -1457,10 +1459,11 @@ methodHandle LinkResolver::resolve_static_call_or_null(
KlassHandle resolved_klass,
Symbol* name,
Symbol* signature,
KlassHandle current_klass) {
KlassHandle current_klass,
bool check_access) {
EXCEPTION_MARK;
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) {
CLEAR_PENDING_EXCEPTION;
return methodHandle();
......@@ -1468,11 +1471,15 @@ methodHandle LinkResolver::resolve_static_call_or_null(
return info.selected_method();
}
methodHandle LinkResolver::resolve_special_call_or_null(KlassHandle resolved_klass, Symbol* name, Symbol* signature,
KlassHandle current_klass) {
methodHandle LinkResolver::resolve_special_call_or_null(
KlassHandle resolved_klass,
Symbol* name,
Symbol* signature,
KlassHandle current_klass,
bool check_access) {
EXCEPTION_MARK;
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) {
CLEAR_PENDING_EXCEPTION;
return methodHandle();
......
......@@ -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
// 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_interface_call_or_null(KlassHandle receiver_klass, 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);
static methodHandle resolve_special_call_or_null (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, bool check_access = true);
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, bool check_access = true);
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
......
......@@ -859,7 +859,8 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
// Parse::do_call())
target = C->optimize_virtual_call(caller, jvms->bci(), klass, klass,
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
// provide us with a type
speculative_receiver_type = (receiver_type != NULL) ? receiver_type->speculative_type() : NULL;
......
......@@ -861,9 +861,11 @@ class Compile : public Phase {
ciMethod* optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciKlass* holder, ciMethod* callee,
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* 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 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) {
ciMethod* Compile::optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKlass* klass,
ciKlass* holder, ciMethod* callee,
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.
call_does_dispatch = true;
vtable_index = Method::invalid_vtable_index;
// 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?
if (optimized_virtual_method != NULL) {
......@@ -977,7 +979,8 @@ ciMethod* Compile::optimize_virtual_call(ciMethod* caller, int bci, ciInstanceKl
// Identify possible target method and inlining style
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
// 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*
}
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) {
assert(!cha_monomorphic_target->is_abstract(), "");
// 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.
先完成此消息的编辑!
想要评论请 注册