From ba32b78bfaf83f69003f83333ab6975b35343fde Mon Sep 17 00:00:00 2001 From: Mikhail Ablakatov Date: Wed, 18 Jun 2025 11:48:45 +0000 Subject: [PATCH] 8358329: AArch64: emit direct branches in static stubs for small code caches Reviewed-by: aph, eastigeevich --- .../cpu/aarch64/compiledIC_aarch64.cpp | 6 +- .../cpu/aarch64/macroAssembler_aarch64.cpp | 12 +- .../cpu/aarch64/nativeInst_aarch64.cpp | 12 -- .../cpu/aarch64/nativeInst_aarch64.hpp | 5 +- .../c2/aarch64/TestStaticCallStub.java | 144 ++++++++++++++++++ 5 files changed, 160 insertions(+), 19 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/aarch64/TestStaticCallStub.java diff --git a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp index 24a7a78b800..6fe3315014b 100644 --- a/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp @@ -90,13 +90,15 @@ void CompiledDirectCall::set_to_interpreted(const methodHandle& callee, address = nativeMovConstReg_at(stub + NativeInstruction::instruction_size); #ifdef ASSERT - NativeGeneralJump* jump = nativeGeneralJump_at(method_holder->next_instruction_address()); + NativeJump* jump = MacroAssembler::codestub_branch_needs_far_jump() + ? nativeGeneralJump_at(method_holder->next_instruction_address()) + : nativeJump_at(method_holder->next_instruction_address()); verify_mt_safe(callee, entry, method_holder, jump); #endif // Update stub. method_holder->set_data((intptr_t)callee()); - NativeGeneralJump::insert_unconditional(method_holder->next_instruction_address(), entry); + MacroAssembler::pd_patch_instruction(method_holder->next_instruction_address(), entry); ICache::invalidate_range(stub, to_interp_stub_size()); // Update jump to call. set_destination_mt_safe(stub); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 93b303e51c9..cbd941397f3 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -984,11 +984,19 @@ void MacroAssembler::emit_static_call_stub() { mov_metadata(rmethod, nullptr); // Jump to the entry point of the c2i stub. - movptr(rscratch1, 0); - br(rscratch1); + if (codestub_branch_needs_far_jump()) { + movptr(rscratch1, 0); + br(rscratch1); + } else { + b(pc()); + } } int MacroAssembler::static_call_stub_size() { + if (!codestub_branch_needs_far_jump()) { + // isb; movk; movz; movz; b + return 5 * NativeInstruction::instruction_size; + } // isb; movk; movz; movz; movk; movz; movz; br return 8 * NativeInstruction::instruction_size; } diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp index 33158d6b97a..0b05b4ac3e5 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp @@ -386,18 +386,6 @@ void NativeJump::patch_verified_entry(address entry, address verified_entry, add void NativeGeneralJump::verify() { } -void NativeGeneralJump::insert_unconditional(address code_pos, address entry) { - NativeGeneralJump* n_jump = (NativeGeneralJump*)code_pos; - - CodeBuffer cb(code_pos, instruction_size); - MacroAssembler a(&cb); - - a.movptr(rscratch1, (uintptr_t)entry); - a.br(rscratch1); - - ICache::invalidate_range(code_pos, instruction_size); -} - // MT-safe patching of a long jump instruction. void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer) { ShouldNotCallThis(); diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp index 0eb5ff815be..9b9b83e38b8 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2014, 2108, Red Hat Inc. All rights reserved. + * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2025, Red Hat Inc. 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 @@ -383,7 +383,6 @@ public: address jump_destination() const; void set_jump_destination(address dest); - static void insert_unconditional(address code_pos, address entry); static void replace_mt_safe(address instr_addr, address code_buffer); static void verify(); }; diff --git a/test/hotspot/jtreg/compiler/c2/aarch64/TestStaticCallStub.java b/test/hotspot/jtreg/compiler/c2/aarch64/TestStaticCallStub.java new file mode 100644 index 00000000000..0c6535ff856 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/aarch64/TestStaticCallStub.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2025, Arm Limited. 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 jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.*; + +/* + * @test + * @summary Calls to c2i interface stubs should be generated with near branches + * for segmented code cache up to 250MB + * @library /test/lib / + * + * @requires vm.flagless + * @requires os.arch=="aarch64" + * @requires vm.debug == false + * @requires vm.compiler2.enabled + * + * @run driver compiler.c2.aarch64.TestStaticCallStub + */ +public class TestStaticCallStub { + + static String[] nearStaticCallOpcodeSeq = {"isb", "mov", "movk", "movk", "b"}; + static String[] farStaticCallOpcodeSeq = {"isb", "mov", "movk", "movk", "mov", "movk", "movk", "br"}; + + static String extractOpcode(String line) { + line = line.trim(); + int semicolonIndex = line.indexOf(';'); + if (semicolonIndex != -1) { + line = line.substring(0, semicolonIndex).trim(); + } + + String[] words = line.split("\\s+"); + if (words.length > 1) { + return words[1]; + } + + return ""; + } + + static List extractOpcodesN(ListIterator itr, int n) { + List extractedOpcodes = new ArrayList<>(); + + while (itr.hasNext() && extractedOpcodes.size() < n) { + String opcode = extractOpcode(itr.next()); + if (!opcode.isEmpty()) { + extractedOpcodes.add(opcode); + } + } + + return extractedOpcodes; + } + + static void verifyNearStaticCall(ListIterator itr) { + List extractedOpcodes = extractOpcodesN(itr, nearStaticCallOpcodeSeq.length); + + if (!Arrays.asList(nearStaticCallOpcodeSeq).equals(extractedOpcodes)) { + throw new RuntimeException("for code cache < 250MB the static call stub is expected to be implemented using near branch"); + } + + return; + } + + static void verifyFarStaticCall(ListIterator itr) { + List extractedOpcodes = extractOpcodesN(itr, farStaticCallOpcodeSeq.length); + + if (!Arrays.asList(farStaticCallOpcodeSeq).equals(extractedOpcodes)) { + throw new RuntimeException("for code cache > 250MB the static call stub is expected to be implemented using far branch"); + } + + return; + } + + static void runVM(boolean bigCodeCache) throws Exception { + String className = TestStaticCallStub.class.getName(); + String[] procArgs = { + "-XX:-Inline", + "-Xcomp", + "-Xbatch", + "-XX:+TieredCompilation", + "-XX:+SegmentedCodeCache", + "-XX:ReservedCodeCacheSize=" + (bigCodeCache ? "256M" : "200M"), + "-XX:+UnlockDiagnosticVMOptions", + "-XX:CompileCommand=option," + className + "::main,bool,PrintAssembly,true", + className}; + + + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(procArgs); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + List lines = output.asLines(); + + ListIterator itr = lines.listIterator(); + while (itr.hasNext()) { + String line = itr.next(); + if (line.contains("{static_stub}")) { + itr.previous(); + if (bigCodeCache) { + verifyFarStaticCall(itr); + } else { + verifyNearStaticCall(itr); + } + return; + } + } + throw new RuntimeException("Assembly output: static call stub is not found"); + } + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + // Main VM: fork VM with options + runVM(true); + runVM(false); + return; + } + if (args.length > 0) { + // We are in a forked VM. Just exit + System.out.println("Ok"); + } + } +} +