8280152: AArch64: Reuse runtime call trampolines
Reviewed-by: aph, phh
This commit is contained in:
parent
8b4e6ba01f
commit
494d3873b1
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user