8329258: TailCall should not use frame pointer register for jump target

Co-authored-by: Fei Yang <fyang@openjdk.org>
Reviewed-by: rcastanedalo, aph
This commit is contained in:
Tobias Hartmann 2024-05-02 11:38:00 +00:00
parent 4a78906db1
commit cccc95358d
5 changed files with 117 additions and 4 deletions

View File

@ -694,6 +694,11 @@ reg_class no_special_ptr_reg %{
return _NO_SPECIAL_PTR_REG_mask;
%}
// Class for all non_special pointer registers (excluding rfp)
reg_class no_special_no_rfp_ptr_reg %{
return _NO_SPECIAL_NO_RFP_PTR_REG_mask;
%}
// Class for all float registers
reg_class float_reg(
V0,
@ -1125,6 +1130,7 @@ extern RegMask _PTR_REG_mask;
extern RegMask _NO_SPECIAL_REG32_mask;
extern RegMask _NO_SPECIAL_REG_mask;
extern RegMask _NO_SPECIAL_PTR_REG_mask;
extern RegMask _NO_SPECIAL_NO_RFP_PTR_REG_mask;
class CallStubImpl {
@ -1213,6 +1219,7 @@ source %{
RegMask _NO_SPECIAL_REG32_mask;
RegMask _NO_SPECIAL_REG_mask;
RegMask _NO_SPECIAL_PTR_REG_mask;
RegMask _NO_SPECIAL_NO_RFP_PTR_REG_mask;
void reg_mask_init() {
// We derive below RegMask(s) from the ones which are auto-generated from
@ -1249,6 +1256,9 @@ source %{
_NO_SPECIAL_REG_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg()));
_NO_SPECIAL_PTR_REG_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg()));
}
_NO_SPECIAL_NO_RFP_PTR_REG_mask = _NO_SPECIAL_PTR_REG_mask;
_NO_SPECIAL_NO_RFP_PTR_REG_mask.Remove(OptoReg::as_OptoReg(r29->as_VMReg()));
}
// Optimizaton of volatile gets and puts
@ -4690,6 +4700,18 @@ operand iRegPNoSp()
interface(REG_INTER);
%}
// This operand is not allowed to use rfp even if
// rfp is not used to hold the frame pointer.
operand iRegPNoSpNoRfp()
%{
constraint(ALLOC_IN_RC(no_special_no_rfp_ptr_reg));
match(RegP);
match(iRegPNoSp);
op_cost(0);
format %{ %}
interface(REG_INTER);
%}
// Pointer 64 bit Register R0 only
operand iRegP_R0()
%{
@ -16087,7 +16109,9 @@ instruct CallLeafNoFPDirect(method meth)
// Also known as an 'interprocedural jump'.
// Target of jump will eventually return to caller.
// TailJump below removes the return address.
instruct TailCalljmpInd(iRegPNoSp jump_target, inline_cache_RegP method_ptr)
// Don't use rfp for 'jump_target' because a MachEpilogNode has already been
// emitted just above the TailCall which has reset rfp to the caller state.
instruct TailCalljmpInd(iRegPNoSpNoRfp jump_target, inline_cache_RegP method_ptr)
%{
match(TailCall jump_target method_ptr);
@ -16100,7 +16124,7 @@ instruct TailCalljmpInd(iRegPNoSp jump_target, inline_cache_RegP method_ptr)
ins_pipe(pipe_class_call);
%}
instruct TailjmpInd(iRegPNoSp jump_target, iRegP_R0 ex_oop)
instruct TailjmpInd(iRegPNoSpNoRfp jump_target, iRegP_R0 ex_oop)
%{
match(TailJump jump_target ex_oop);

View File

@ -649,10 +649,12 @@ reg_class non_allocatable_reg(
R23, R23_H // java thread
);
// Class for all non-special integer registers
reg_class no_special_reg32 %{
return _NO_SPECIAL_REG32_mask;
%}
// Class for all non-special long integer registers
reg_class no_special_reg %{
return _NO_SPECIAL_REG_mask;
%}
@ -661,10 +663,16 @@ reg_class ptr_reg %{
return _PTR_REG_mask;
%}
// Class for all non_special pointer registers
reg_class no_special_ptr_reg %{
return _NO_SPECIAL_PTR_REG_mask;
%}
// Class for all non_special pointer registers (excluding fp)
reg_class no_special_no_fp_ptr_reg %{
return _NO_SPECIAL_NO_FP_PTR_REG_mask;
%}
// Class for 64 bit register r10
reg_class r10_reg(
R10, R10_H
@ -1037,6 +1045,7 @@ extern RegMask _PTR_REG_mask;
extern RegMask _NO_SPECIAL_REG32_mask;
extern RegMask _NO_SPECIAL_REG_mask;
extern RegMask _NO_SPECIAL_PTR_REG_mask;
extern RegMask _NO_SPECIAL_NO_FP_PTR_REG_mask;
class CallStubImpl {
@ -1099,6 +1108,7 @@ RegMask _PTR_REG_mask;
RegMask _NO_SPECIAL_REG32_mask;
RegMask _NO_SPECIAL_REG_mask;
RegMask _NO_SPECIAL_PTR_REG_mask;
RegMask _NO_SPECIAL_NO_FP_PTR_REG_mask;
void reg_mask_init() {
@ -1133,6 +1143,9 @@ void reg_mask_init() {
_NO_SPECIAL_REG_mask.Remove(OptoReg::as_OptoReg(x8->as_VMReg()));
_NO_SPECIAL_PTR_REG_mask.Remove(OptoReg::as_OptoReg(x8->as_VMReg()));
}
_NO_SPECIAL_NO_FP_PTR_REG_mask = _NO_SPECIAL_PTR_REG_mask;
_NO_SPECIAL_NO_FP_PTR_REG_mask.Remove(OptoReg::as_OptoReg(x8->as_VMReg()));
}
void PhaseOutput::pd_perform_mach_node_analysis() {
@ -3175,6 +3188,18 @@ operand iRegPNoSp()
interface(REG_INTER);
%}
// This operand is not allowed to use fp even if
// fp is not used to hold the frame pointer.
operand iRegPNoSpNoFp()
%{
constraint(ALLOC_IN_RC(no_special_no_fp_ptr_reg));
match(RegP);
match(iRegPNoSp);
op_cost(0);
format %{ %}
interface(REG_INTER);
%}
operand iRegP_R10()
%{
constraint(ALLOC_IN_RC(r10_reg));
@ -10506,7 +10531,9 @@ instruct cmpFastUnlockLightweight(rFlagsReg cr, iRegP object, iRegP_R10 box, iRe
// Also known as an 'interprocedural jump'.
// Target of jump will eventually return to caller.
// TailJump below removes the return address.
instruct TailCalljmpInd(iRegPNoSp jump_target, inline_cache_RegP method_oop)
// Don't use fp for 'jump_target' because a MachEpilogNode has already been
// emitted just above the TailCall which has reset fp to the caller state.
instruct TailCalljmpInd(iRegPNoSpNoFp jump_target, inline_cache_RegP method_oop)
%{
match(TailCall jump_target method_oop);
@ -10519,7 +10546,7 @@ instruct TailCalljmpInd(iRegPNoSp jump_target, inline_cache_RegP method_oop)
ins_pipe(pipe_class_call);
%}
instruct TailjmpInd(iRegPNoSp jump_target, iRegP_R10 ex_oop)
instruct TailjmpInd(iRegPNoSpNoFp jump_target, iRegP_R10 ex_oop)
%{
match(TailJump jump_target ex_oop);

View File

@ -13558,6 +13558,8 @@ instruct Ret() %{
// Also known as an 'interprocedural jump'.
// Target of jump will eventually return to caller.
// TailJump below removes the return address.
// Don't use ebp for 'jump_target' because a MachEpilogNode has already been
// emitted just above the TailCall which has reset ebp to the caller state.
instruct TailCalljmpInd(eRegP_no_EBP jump_target, eBXRegP method_ptr) %{
match(TailCall jump_target method_ptr);
ins_cost(300);

View File

@ -12469,6 +12469,8 @@ instruct Ret()
// Also known as an 'interprocedural jump'.
// Target of jump will eventually return to caller.
// TailJump below removes the return address.
// Don't use rbp for 'jump_target' because a MachEpilogNode has already been
// emitted just above the TailCall which has reset rbp to the caller state.
instruct TailCalljmpInd(no_rbp_RegP jump_target, rbx_RegP method_ptr)
%{
match(TailCall jump_target method_ptr);

View File

@ -0,0 +1,58 @@
/*
* Copyright (c) 2024, Oracle and/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
* @key stress randomness
* @bug 8329258
* @summary Test correct execution of the tail call at the end of the arraycopy stub.
* @requires vm.compiler2.enabled
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -Xbatch -XX:-TieredCompilation
* -XX:+StressGCM -XX:+StressLCM
* -XX:CompileCommand=quiet -XX:CompileCommand=compileonly,*::test
* compiler.arraycopy.TestTailCallInArrayCopyStub
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -Xbatch -XX:-TieredCompilation
* -XX:+StressGCM -XX:+StressLCM -XX:StressSeed=75451718
* -XX:CompileCommand=quiet -XX:CompileCommand=compileonly,*::test
* compiler.arraycopy.TestTailCallInArrayCopyStub
*/
package compiler.arraycopy;
public class TestTailCallInArrayCopyStub {
public static void test(byte[] src, byte[] dst) {
try {
System.arraycopy(src, -1, dst, 0, src.length);
} catch (Exception e) {
// Expected
}
}
public static void main(String[] args) {
byte[] array = new byte[5];
for (int i = 0; i < 10_000; ++i) {
test(array, array);
}
}
}