8285487: AArch64: Do not generate unneeded trampolines for runtime calls

Reviewed-by: xliu, aph
This commit is contained in:
Evgeny Astigeevich 2022-09-07 14:39:48 +00:00 committed by Andrew Haley
parent d696104535
commit 6ff4775b71
2 changed files with 136 additions and 16 deletions

View File

@ -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.

View 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());
}
}
}
}