mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-29 00:02:34 +00:00
8285487: AArch64: Do not generate unneeded trampolines for runtime calls
Reviewed-by: xliu, aph
This commit is contained in:
parent
d696104535
commit
6ff4775b71
@ -849,6 +849,37 @@ void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, in
|
||||
call_VM_base(oop_result, noreg, noreg, entry_point, number_of_arguments, check_exceptions);
|
||||
}
|
||||
|
||||
// Check the entry target is always reachable from any branch.
|
||||
static bool is_always_within_branch_range(Address entry) {
|
||||
const address target = entry.target();
|
||||
|
||||
if (!CodeCache::contains(target)) {
|
||||
// We always use trampolines for callees outside CodeCache.
|
||||
assert(entry.rspec().type() == relocInfo::runtime_call_type, "non-runtime call of an external target");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!MacroAssembler::far_branches()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (entry.rspec().type() == relocInfo::runtime_call_type) {
|
||||
// Runtime calls are calls of a non-compiled method (stubs, adapters).
|
||||
// Non-compiled methods stay forever in CodeCache.
|
||||
// We check whether the longest possible branch is within the branch range.
|
||||
assert(CodeCache::find_blob(target) != NULL &&
|
||||
!CodeCache::find_blob(target)->is_compiled(),
|
||||
"runtime call of compiled method");
|
||||
const address right_longest_branch_start = CodeCache::high_bound() - NativeInstruction::instruction_size;
|
||||
const address left_longest_branch_start = CodeCache::low_bound();
|
||||
const bool is_reachable = Assembler::reachable_from_branch_at(left_longest_branch_start, target) &&
|
||||
Assembler::reachable_from_branch_at(right_longest_branch_start, target);
|
||||
return is_reachable;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Maybe emit a call via a trampoline. If the code cache is small
|
||||
// trampolines won't be emitted.
|
||||
address MacroAssembler::trampoline_call(Address entry, CodeBuffer* cbuf) {
|
||||
@ -859,22 +890,7 @@ address MacroAssembler::trampoline_call(Address entry, CodeBuffer* cbuf) {
|
||||
|
||||
address target = entry.target();
|
||||
|
||||
// We might need a trampoline if branches are far.
|
||||
bool need_trampoline = far_branches();
|
||||
if (!need_trampoline && entry.rspec().type() == relocInfo::runtime_call_type && !CodeCache::contains(target)) {
|
||||
// If it is a runtime call of an address outside small CodeCache,
|
||||
// we need to check whether it is in range.
|
||||
assert(target < CodeCache::low_bound() || target >= CodeCache::high_bound(), "target is inside CodeCache");
|
||||
// Case 1: -------T-------L====CodeCache====H-------
|
||||
// ^-------longest branch---|
|
||||
// Case 2: -------L====CodeCache====H-------T-------
|
||||
// |-------longest branch ---^
|
||||
address longest_branch_start = (target < CodeCache::low_bound()) ? CodeCache::high_bound() - NativeInstruction::instruction_size
|
||||
: CodeCache::low_bound();
|
||||
need_trampoline = !reachable_from_branch_at(longest_branch_start, target);
|
||||
}
|
||||
|
||||
if (need_trampoline) {
|
||||
if (!is_always_within_branch_range(entry)) {
|
||||
if (!in_scratch_emit_size()) {
|
||||
// We don't want to emit a trampoline if C2 is generating dummy
|
||||
// code during its branch shortening phase.
|
||||
|
||||
104
test/hotspot/jtreg/compiler/c2/aarch64/TestTrampoline.java
Normal file
104
test/hotspot/jtreg/compiler/c2/aarch64/TestTrampoline.java
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright Amazon.com Inc. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package compiler.c2.aarch64;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
/**
|
||||
* @test TestTrampoline
|
||||
* @summary Checks that trampolines to runtime code are not generated if they are not needed.
|
||||
* @bug 8285487
|
||||
* @library /test/lib
|
||||
*
|
||||
* @requires vm.flagless & os.arch=="aarch64" &
|
||||
* vm.debug == false & vm.compiler2.enabled
|
||||
*
|
||||
* @run driver compiler.c2.aarch64.TestTrampoline
|
||||
*/
|
||||
|
||||
public class TestTrampoline {
|
||||
private final static int ITERATIONS_TO_HEAT_LOOP = 20_000;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
String testClassName = TestTrampoline.Test.class.getName();
|
||||
ArrayList<String> command = new ArrayList<String>();
|
||||
command.add("-XX:+UnlockDiagnosticVMOptions");
|
||||
command.add("-Xbatch");
|
||||
command.add("-XX:CompileCommand=print," + testClassName + "::" + "test");
|
||||
// ReservedCodeCacheSize=130M causes generation of trampolines.
|
||||
// As the non-nmethod segment is put between other two segments,
|
||||
// runtime calls will be within 128M range.
|
||||
// So there is no need for trampolines for runtime calls.
|
||||
command.add("-XX:ReservedCodeCacheSize=130M");
|
||||
command.add("-XX:+SegmentedCodeCache");
|
||||
command.add(testClassName);
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(command);
|
||||
OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
|
||||
analyzer.shouldHaveExitValue(0);
|
||||
System.out.println(analyzer.getOutput());
|
||||
checkOutput(analyzer);
|
||||
}
|
||||
|
||||
private static String skipTo(Iterator<String> iter, String substring) {
|
||||
while (iter.hasNext()) {
|
||||
String nextLine = iter.next();
|
||||
if (nextLine.contains(substring)) {
|
||||
return nextLine;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void checkOutput(OutputAnalyzer output) {
|
||||
Iterator<String> iter = output.asLines().listIterator();
|
||||
|
||||
String match = skipTo(iter, "Compiled method (c2)");
|
||||
if (match == null || !match.contains("Test::test")) {
|
||||
throw new RuntimeException("Missing compiler output for the method 'test'");
|
||||
}
|
||||
|
||||
match = skipTo(iter, "[Stub Code]");
|
||||
if (match != null && skipTo(iter, "{trampoline_stub}") != null) {
|
||||
throw new RuntimeException("Found unexpected {trampoline_stub}");
|
||||
}
|
||||
}
|
||||
|
||||
static class Test {
|
||||
private static void test(String s, int i) {
|
||||
if (s.charAt(i) > 128)
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String s = "Returns the char value at the specified index.";
|
||||
for (int i = 0; i < ITERATIONS_TO_HEAT_LOOP; ++i) {
|
||||
test(s, i % s.length());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user