1 /* 2 * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 /* 26 * @test 27 * @compile platform/PlatformLayouts.java 28 * @modules java.base/jdk.internal.foreign 29 * java.base/jdk.internal.foreign.abi 30 * java.base/jdk.internal.foreign.abi.aarch64 31 * @build CallArrangerTestBase 32 * @run testng TestWindowsAArch64CallArranger 33 */ 34 35 import java.lang.foreign.FunctionDescriptor; 36 import java.lang.foreign.MemoryLayout; 37 import java.lang.foreign.MemorySegment; 38 import jdk.internal.foreign.abi.Binding; 39 import jdk.internal.foreign.abi.CallingSequence; 40 import jdk.internal.foreign.abi.LinkerOptions; 41 import jdk.internal.foreign.abi.StubLocations; 42 import jdk.internal.foreign.abi.VMStorage; 43 import jdk.internal.foreign.abi.aarch64.CallArranger; 44 import org.testng.annotations.DataProvider; 45 import org.testng.annotations.Test; 46 47 import java.lang.invoke.MethodType; 48 49 import static java.lang.foreign.Linker.Option.firstVariadicArg; 50 import static java.lang.foreign.ValueLayout.ADDRESS; 51 import static jdk.internal.foreign.abi.Binding.*; 52 import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.*; 53 import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.Regs.*; 54 import static platform.PlatformLayouts.AArch64.*; 55 import static org.testng.Assert.assertEquals; 56 import static org.testng.Assert.assertFalse; 57 import static org.testng.Assert.assertTrue; 58 59 public class TestWindowsAArch64CallArranger extends CallArrangerTestBase { 60 61 private static final VMStorage TARGET_ADDRESS_STORAGE = StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER); 62 private static final VMStorage RETURN_BUFFER_STORAGE = StubLocations.RETURN_BUFFER.storage(StorageType.PLACEHOLDER); 63 64 @Test 65 public void testWindowsArgsInRegs() { 66 MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class, double.class); 67 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_FLOAT, C_DOUBLE); 68 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false); 69 70 assertFalse(bindings.isInMemoryReturn()); 71 CallingSequence callingSequence = bindings.callingSequence(); 72 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 73 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 74 75 checkArgumentBindings(callingSequence, new Binding[][]{ 76 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 77 { vmStore(r0, int.class) }, 78 { vmStore(r1, int.class) }, 79 { vmStore(v0, float.class) }, 80 { vmStore(v1, double.class) }, 81 }); 82 83 checkReturnBindings(callingSequence, new Binding[]{}); 84 } 85 86 @Test 87 public void testWindowsVarArgsInRegs() { 88 MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class, double.class); 89 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_FLOAT, C_DOUBLE); 90 FunctionDescriptor fdExpected = FunctionDescriptor.ofVoid(ADDRESS, C_INT, C_INT, C_FLOAT, C_DOUBLE); 91 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(1))); 92 93 assertFalse(bindings.isInMemoryReturn()); 94 CallingSequence callingSequence = bindings.callingSequence(); 95 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 96 assertEquals(callingSequence.functionDesc(), fdExpected); 97 98 checkArgumentBindings(callingSequence, new Binding[][]{ 99 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 100 { vmStore(r0, int.class) }, 101 { vmStore(r1, int.class) }, 102 { vmStore(r2, float.class) }, 103 { vmStore(r3, double.class) }, 104 }); 105 106 checkReturnBindings(callingSequence, new Binding[]{}); 107 } 108 109 @Test 110 public void testWindowsArgsInRegsAndOnStack() { 111 MethodType mt = MethodType.methodType(void.class, double.class, int.class, float.class, 112 double.class, float.class, float.class, double.class, 113 float.class, float.class, float.class, int.class); 114 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_DOUBLE, C_INT, C_FLOAT, 115 C_DOUBLE, C_FLOAT, C_FLOAT, C_DOUBLE, 116 C_FLOAT, C_FLOAT, C_FLOAT, C_INT); 117 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false); 118 119 assertFalse(bindings.isInMemoryReturn()); 120 CallingSequence callingSequence = bindings.callingSequence(); 121 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 122 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 123 124 checkArgumentBindings(callingSequence, new Binding[][]{ 125 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 126 { vmStore(v0, double.class) }, 127 { vmStore(r0, int.class) }, 128 { vmStore(v1, float.class) }, 129 { vmStore(v2, double.class) }, 130 { vmStore(v3, float.class) }, 131 { vmStore(v4, float.class) }, 132 { vmStore(v5, double.class) }, 133 { vmStore(v6, float.class) }, 134 { vmStore(v7, float.class) }, 135 { vmStore(stackStorage((short) 4, 0), float.class) }, 136 { vmStore(r1, int.class) }, 137 }); 138 139 checkReturnBindings(callingSequence, new Binding[]{}); 140 } 141 142 @Test 143 public void testWindowsVarArgsInRegsAndOnStack() { 144 MethodType mt = MethodType.methodType(void.class, double.class, int.class, float.class, 145 double.class, float.class, float.class, double.class, 146 float.class, float.class, float.class); 147 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_DOUBLE, C_INT, C_FLOAT, 148 C_DOUBLE, C_FLOAT, C_FLOAT, C_DOUBLE, 149 C_FLOAT, C_FLOAT, C_FLOAT); 150 FunctionDescriptor fdExpected = FunctionDescriptor.ofVoid(ADDRESS, C_DOUBLE, C_INT, C_FLOAT, C_DOUBLE, C_FLOAT, C_FLOAT, C_DOUBLE, C_FLOAT, C_FLOAT, C_FLOAT); 151 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(1))); 152 153 assertFalse(bindings.isInMemoryReturn()); 154 CallingSequence callingSequence = bindings.callingSequence(); 155 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 156 assertEquals(callingSequence.functionDesc(), fdExpected); 157 158 checkArgumentBindings(callingSequence, new Binding[][]{ 159 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 160 { vmStore(r0, double.class) }, 161 { vmStore(r1, int.class) }, 162 { vmStore(r2, float.class) }, 163 { vmStore(r3, double.class) }, 164 { vmStore(r4, float.class) }, 165 { vmStore(r5, float.class) }, 166 { vmStore(r6, double.class) }, 167 { vmStore(r7, float.class) }, 168 { vmStore(stackStorage((short) 4, 0), float.class) }, 169 { vmStore(stackStorage((short) 4, 8), float.class) }, 170 }); 171 172 checkReturnBindings(callingSequence, new Binding[]{}); 173 } 174 175 @Test 176 public void testWindowsHfa4FloatsInFloatRegs() { 177 MemoryLayout struct = MemoryLayout.structLayout(C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT); 178 179 MethodType mt = MethodType.methodType(void.class, MemorySegment.class, int.class); 180 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT); 181 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false); 182 183 assertFalse(bindings.isInMemoryReturn()); 184 CallingSequence callingSequence = bindings.callingSequence(); 185 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 186 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 187 188 checkArgumentBindings(callingSequence, new Binding[][]{ 189 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 190 { 191 dup(), 192 bufferLoad(0, float.class), 193 vmStore(v0, float.class), 194 dup(), 195 bufferLoad(4, float.class), 196 vmStore(v1, float.class), 197 dup(), 198 bufferLoad(8, float.class), 199 vmStore(v2, float.class), 200 bufferLoad(12, float.class), 201 vmStore(v3, float.class), 202 }, 203 { vmStore(r0, int.class) }, 204 }); 205 206 checkReturnBindings(callingSequence, new Binding[]{}); 207 } 208 209 @Test 210 public void testWindowsVariadicHfa4FloatsInIntRegs() { 211 MemoryLayout struct = MemoryLayout.structLayout(C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT); 212 213 MethodType mt = MethodType.methodType(void.class, MemorySegment.class, int.class); 214 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT); 215 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(0))); 216 217 assertFalse(bindings.isInMemoryReturn()); 218 CallingSequence callingSequence = bindings.callingSequence(); 219 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 220 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 221 222 checkArgumentBindings(callingSequence, new Binding[][]{ 223 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 224 { 225 dup(), 226 bufferLoad(0, long.class), 227 vmStore(r0, long.class), 228 bufferLoad(8, long.class), 229 vmStore(r1, long.class), 230 }, 231 { vmStore(r2, int.class) }, 232 }); 233 234 checkReturnBindings(callingSequence, new Binding[]{}); 235 } 236 237 @Test 238 public void testWindowsHfa2DoublesInFloatRegs() { 239 MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE); 240 241 MethodType mt = MethodType.methodType( 242 void.class, MemorySegment.class, int.class); 243 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT); 244 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false); 245 246 assertFalse(bindings.isInMemoryReturn()); 247 CallingSequence callingSequence = bindings.callingSequence(); 248 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 249 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 250 251 checkArgumentBindings(callingSequence, new Binding[][]{ 252 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 253 { 254 dup(), 255 bufferLoad(0, double.class), 256 vmStore(v0, double.class), 257 bufferLoad(8, double.class), 258 vmStore(v1, double.class), 259 }, 260 { vmStore(r0, int.class) }, 261 }); 262 263 checkReturnBindings(callingSequence, new Binding[]{}); 264 } 265 266 @Test 267 public void testWindowsVariadicHfa2DoublesInIntRegs() { 268 MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE); 269 270 MethodType mt = MethodType.methodType( 271 void.class, MemorySegment.class, int.class); 272 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT); 273 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(0))); 274 275 assertFalse(bindings.isInMemoryReturn()); 276 CallingSequence callingSequence = bindings.callingSequence(); 277 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 278 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 279 280 checkArgumentBindings(callingSequence, new Binding[][]{ 281 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 282 { 283 dup(), 284 bufferLoad(0, long.class), 285 vmStore(r0, long.class), 286 bufferLoad(8, long.class), 287 vmStore(r1, long.class), 288 }, 289 { vmStore(r2, int.class) }, 290 }); 291 292 checkReturnBindings(callingSequence, new Binding[]{}); 293 } 294 295 @Test 296 public void testWindowsHfa3DoublesInFloatRegs() { 297 MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE, C_DOUBLE); 298 299 MethodType mt = MethodType.methodType( 300 void.class, MemorySegment.class, int.class); 301 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT); 302 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false); 303 304 assertFalse(bindings.isInMemoryReturn()); 305 CallingSequence callingSequence = bindings.callingSequence(); 306 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 307 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 308 309 checkArgumentBindings(callingSequence, new Binding[][]{ 310 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 311 { 312 dup(), 313 bufferLoad(0, double.class), 314 vmStore(v0, double.class), 315 dup(), 316 bufferLoad(8, double.class), 317 vmStore(v1, double.class), 318 bufferLoad(16, double.class), 319 vmStore(v2, double.class), 320 }, 321 { vmStore(r0, int.class) }, 322 }); 323 324 checkReturnBindings(callingSequence, new Binding[]{}); 325 } 326 327 @Test 328 public void testWindowsVariadicHfa3DoublesAsReferenceStruct() { 329 MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE, C_DOUBLE); 330 331 MethodType mt = MethodType.methodType( 332 void.class, MemorySegment.class, int.class); 333 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT); 334 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(0))); 335 336 assertFalse(bindings.isInMemoryReturn()); 337 CallingSequence callingSequence = bindings.callingSequence(); 338 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 339 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 340 341 checkArgumentBindings(callingSequence, new Binding[][]{ 342 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 343 { copy(struct), unboxAddress(), vmStore(r0, long.class) }, 344 { vmStore(r1, int.class) }, 345 }); 346 347 checkReturnBindings(callingSequence, new Binding[]{}); 348 } 349 }