8280152: AArch64: Reuse runtime call trampolines

Reviewed-by: aph, phh
This commit is contained in:
Yi-Fan Tsai 2022-08-17 17:35:02 +00:00 committed by Paul Hohensee
parent 8b4e6ba01f
commit 494d3873b1
5 changed files with 192 additions and 6 deletions

View File

@ -26,6 +26,56 @@
#include "asm/codeBuffer.inline.hpp"
#include "asm/macroAssembler.hpp"
bool CodeBuffer::pd_finalize_stubs() {
return emit_shared_stubs_to_interp<MacroAssembler>(this, _shared_stub_to_interp_requests);
void CodeBuffer::share_trampoline_for(address dest, int caller_offset) {
if (_shared_trampoline_requests == nullptr) {
constexpr unsigned init_size = 8;
constexpr unsigned max_size = 256;
_shared_trampoline_requests = new SharedTrampolineRequests(init_size, max_size);
}
bool created;
Offsets* offsets = _shared_trampoline_requests->put_if_absent(dest, &created);
if (created) {
_shared_trampoline_requests->maybe_grow();
}
offsets->add(caller_offset);
_finalize_stubs = true;
}
static bool emit_shared_trampolines(CodeBuffer* cb, CodeBuffer::SharedTrampolineRequests* requests) {
if (requests == nullptr) {
return true;
}
MacroAssembler masm(cb);
bool p_succeeded = true;
auto emit = [&](address dest, const CodeBuffer::Offsets &offsets) {
masm.set_code_section(cb->stubs());
masm.align(wordSize);
LinkedListIterator<int> it(offsets.head());
int offset = *it.next();
for (; !it.is_empty(); offset = *it.next()) {
masm.relocate(trampoline_stub_Relocation::spec(cb->insts()->start() + offset));
}
masm.set_code_section(cb->insts());
address stub = masm.emit_trampoline_stub(offset, dest);
if (stub == nullptr) {
ciEnv::current()->record_failure("CodeCache is full");
p_succeeded = false;
}
return p_succeeded;
};
requests->iterate(emit);
return p_succeeded;
}
bool CodeBuffer::pd_finalize_stubs() {
return emit_shared_stubs_to_interp<MacroAssembler>(this, _shared_stub_to_interp_requests)
&& emit_shared_trampolines(this, _shared_trampoline_requests);
}

View File

@ -34,4 +34,6 @@ public:
void flush_bundle(bool start_new_bundle) {}
static constexpr bool supports_shared_stubs() { return true; }
void share_trampoline_for(address dest, int caller_offset);
#endif // CPU_AARCH64_CODEBUFFER_AARCH64_HPP

View File

@ -878,10 +878,15 @@ address MacroAssembler::trampoline_call(Address entry, CodeBuffer* cbuf) {
if (!in_scratch_emit_size()) {
// We don't want to emit a trampoline if C2 is generating dummy
// code during its branch shortening phase.
address stub = emit_trampoline_stub(offset(), target);
if (stub == NULL) {
postcond(pc() == badAddress);
return NULL; // CodeCache is full
if (entry.rspec().type() == relocInfo::runtime_call_type) {
assert(CodeBuffer::supports_shared_stubs(), "must support shared stubs");
code()->share_trampoline_for(entry.target(), offset());
} else {
address stub = emit_trampoline_stub(offset(), target);
if (stub == NULL) {
postcond(pc() == badAddress);
return NULL; // CodeCache is full
}
}
}
target = pc();

View File

@ -31,6 +31,8 @@
#include "utilities/align.hpp"
#include "utilities/debug.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/linkedlist.hpp"
#include "utilities/resizeableResourceHash.hpp"
#include "utilities/macros.hpp"
class PhaseCFG;
@ -398,6 +400,9 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) {
SECT_LIMIT, SECT_NONE = -1
};
typedef LinkedListImpl<int> Offsets;
typedef ResizeableResourceHashtable<address, Offsets> SharedTrampolineRequests;
private:
enum {
sect_bits = 2, // assert (SECT_LIMIT <= (1<<sect_bits))
@ -424,6 +429,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) {
address _last_insn; // used to merge consecutive memory barriers, loads or stores.
SharedStubToInterpRequests* _shared_stub_to_interp_requests; // used to collect requests for shared iterpreter stubs
SharedTrampolineRequests* _shared_trampoline_requests; // used to collect requests for shared trampolines
bool _finalize_stubs; // Indicate if we need to finalize stubs to make CodeBuffer final.
#ifndef PRODUCT
@ -445,6 +451,7 @@ class CodeBuffer: public StackObj DEBUG_ONLY(COMMA private Scrubber) {
_last_insn = NULL;
_finalize_stubs = false;
_shared_stub_to_interp_requests = NULL;
_shared_trampoline_requests = NULL;
#ifndef PRODUCT
_decode_begin = NULL;

View File

@ -0,0 +1,122 @@
/*
* 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.
*
*/
/**
* @test SharedTrampolineTest
* @summary Checks that trampolines can be shared for static method.
* @bug 8280152
* @library /test/lib
*
* @requires os.arch=="aarch64"
*
* @run driver compiler.sharedstubs.SharedTrampolineTest
*/
package compiler.sharedstubs;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.regex.Pattern;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class SharedTrampolineTest {
private final static int ITERATIONS_TO_HEAT_LOOP = 20_000;
private static void runTest(String compiler, String test) throws Exception {
String testClassName = SharedTrampolineTest.class.getName() + "$" + test;
ArrayList<String> command = new ArrayList<String>();
command.add(compiler);
command.add("-XX:+UnlockDiagnosticVMOptions");
command.add("-Xbatch");
command.add("-XX:+PrintRelocations");
command.add("-XX:CompileCommand=compileonly," + testClassName + "::" + "test");
command.add("-XX:CompileCommand=dontinline," + testClassName + "::" + "test");
command.add("-XX:CompileCommand=dontinline," + testClassName + "::" + "log");
command.add(testClassName);
command.add("a");
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(command);
OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
analyzer.shouldHaveExitValue(0);
System.out.println(analyzer.getOutput());
checkOutput(analyzer);
}
public static void main(String[] args) throws Exception {
List<String> compilers = List.of("-XX:-TieredCompilation" /* C2 */);
List<String> tests = List.of("StaticMethodTest");
for (String compiler : compilers) {
for (String test : tests) {
runTest(compiler, test);
}
}
}
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) {
List<String> addrs = Pattern.compile("\\(trampoline_stub\\) addr=(\\w+) .*\\[trampoline owner")
.matcher(output.getStdout())
.results()
.map(m -> m.group(1))
.collect(Collectors.toList());
if (addrs.stream().distinct().count() >= addrs.size()) {
throw new RuntimeException("No stubs reused");
}
}
public static class StaticMethodTest {
private static void log(int i, String msg) {
}
static void test(int i, String[] args) {
if (i % args.length == 0) {
log(i, "args[0] = " + args[0]);
} else {
log(i, "No args");
}
}
public static void main(String[] args) {
for (int i = 1; i < ITERATIONS_TO_HEAT_LOOP; ++i) {
test(i, args);
}
}
}
}