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 * @enablePreview 28 * @requires sun.arch.data.model == "64" 29 * @compile platform/PlatformLayouts.java 30 * @modules java.base/jdk.internal.foreign 31 * java.base/jdk.internal.foreign.abi 32 * java.base/jdk.internal.foreign.abi.aarch64 33 * @build CallArrangerTestBase 34 * @run testng TestMacOsAArch64CallArranger 35 */ 36 37 import java.lang.foreign.FunctionDescriptor; 38 import java.lang.foreign.MemoryLayout; 39 import java.lang.foreign.StructLayout; 40 import java.lang.foreign.MemorySegment; 41 import jdk.internal.foreign.abi.Binding; 42 import jdk.internal.foreign.abi.CallingSequence; 43 import jdk.internal.foreign.abi.LinkerOptions; 44 import jdk.internal.foreign.abi.StubLocations; 45 import jdk.internal.foreign.abi.VMStorage; 46 import jdk.internal.foreign.abi.aarch64.CallArranger; 47 import org.testng.annotations.DataProvider; 48 import org.testng.annotations.Test; 49 50 import java.lang.invoke.MethodType; 51 52 import static java.lang.foreign.Linker.Option.firstVariadicArg; 53 import static java.lang.foreign.ValueLayout.ADDRESS; 54 import static jdk.internal.foreign.abi.Binding.*; 55 import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.*; 56 import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.Regs.*; 57 import static platform.PlatformLayouts.AArch64.*; 58 import static org.testng.Assert.assertEquals; 59 import static org.testng.Assert.assertFalse; 60 import static org.testng.Assert.assertTrue; 61 62 public class TestMacOsAArch64CallArranger extends CallArrangerTestBase { 63 64 private static final VMStorage TARGET_ADDRESS_STORAGE = StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER); 65 66 @Test 67 public void testVarArgsOnStack() { 68 MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class); 69 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_FLOAT); 70 FunctionDescriptor fdExpected = FunctionDescriptor.ofVoid(ADDRESS, C_INT, C_INT, C_FLOAT); 71 CallArranger.Bindings bindings = CallArranger.MACOS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(1))); 72 73 assertFalse(bindings.isInMemoryReturn()); 74 CallingSequence callingSequence = bindings.callingSequence(); 75 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 76 assertEquals(callingSequence.functionDesc(), fdExpected); 77 78 // The two variadic arguments should be allocated on the stack 79 checkArgumentBindings(callingSequence, new Binding[][]{ 80 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 81 { vmStore(r0, int.class) }, 82 { vmStore(stackStorage((short) 4, 0), int.class) }, 83 { vmStore(stackStorage((short) 4, 8), float.class) }, 84 }); 85 86 checkReturnBindings(callingSequence, new Binding[]{}); 87 } 88 89 @Test 90 public void testMacArgsOnStack() { 91 MethodType mt = MethodType.methodType(void.class, 92 int.class, int.class, int.class, int.class, 93 int.class, int.class, int.class, int.class, 94 int.class, int.class, short.class, byte.class); 95 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 96 C_INT, C_INT, C_INT, C_INT, 97 C_INT, C_INT, C_INT, C_INT, 98 C_INT, C_INT, C_SHORT, C_CHAR); 99 CallArranger.Bindings bindings = CallArranger.MACOS.getBindings(mt, fd, false); 100 101 assertFalse(bindings.isInMemoryReturn()); 102 CallingSequence callingSequence = bindings.callingSequence(); 103 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 104 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 105 106 checkArgumentBindings(callingSequence, new Binding[][]{ 107 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 108 { vmStore(r0, int.class) }, 109 { vmStore(r1, int.class) }, 110 { vmStore(r2, int.class) }, 111 { vmStore(r3, int.class) }, 112 { vmStore(r4, int.class) }, 113 { vmStore(r5, int.class) }, 114 { vmStore(r6, int.class) }, 115 { vmStore(r7, int.class) }, 116 { vmStore(stackStorage((short) 4, 0), int.class) }, 117 { vmStore(stackStorage((short) 4, 4), int.class) }, 118 { cast(short.class, int.class), vmStore(stackStorage((short) 2, 8), int.class) }, 119 { cast(byte.class, int.class), vmStore(stackStorage((short) 1, 10), int.class) }, 120 }); 121 122 checkReturnBindings(callingSequence, new Binding[]{}); 123 } 124 125 @Test 126 public void testMacArgsOnStack2() { 127 StructLayout struct = MemoryLayout.structLayout( 128 C_FLOAT, 129 C_FLOAT 130 ); 131 MethodType mt = MethodType.methodType(void.class, 132 long.class, long.class, long.class, long.class, 133 long.class, long.class, long.class, long.class, 134 double.class, double.class, double.class, double.class, 135 double.class, double.class, double.class, double.class, 136 int.class, MemorySegment.class); 137 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 138 C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, 139 C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, 140 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, 141 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, 142 C_INT, struct); 143 CallArranger.Bindings bindings = CallArranger.MACOS.getBindings(mt, fd, false); 144 145 assertFalse(bindings.isInMemoryReturn()); 146 CallingSequence callingSequence = bindings.callingSequence(); 147 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 148 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 149 150 checkArgumentBindings(callingSequence, new Binding[][]{ 151 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 152 { vmStore(r0, long.class) }, 153 { vmStore(r1, long.class) }, 154 { vmStore(r2, long.class) }, 155 { vmStore(r3, long.class) }, 156 { vmStore(r4, long.class) }, 157 { vmStore(r5, long.class) }, 158 { vmStore(r6, long.class) }, 159 { vmStore(r7, long.class) }, 160 { vmStore(v0, double.class) }, 161 { vmStore(v1, double.class) }, 162 { vmStore(v2, double.class) }, 163 { vmStore(v3, double.class) }, 164 { vmStore(v4, double.class) }, 165 { vmStore(v5, double.class) }, 166 { vmStore(v6, double.class) }, 167 { vmStore(v7, double.class) }, 168 { vmStore(stackStorage((short) 4, 0), int.class) }, 169 { 170 dup(), 171 bufferLoad(0, int.class), 172 vmStore(stackStorage((short) 4, 4), int.class), 173 bufferLoad(4, int.class), 174 vmStore(stackStorage((short) 4, 8), int.class), 175 } 176 }); 177 178 checkReturnBindings(callingSequence, new Binding[]{}); 179 } 180 181 @Test 182 public void testMacArgsOnStack3() { 183 StructLayout struct = MemoryLayout.structLayout( 184 C_POINTER, 185 C_POINTER 186 ); 187 MethodType mt = MethodType.methodType(void.class, 188 long.class, long.class, long.class, long.class, 189 long.class, long.class, long.class, long.class, 190 double.class, double.class, double.class, double.class, 191 double.class, double.class, double.class, double.class, 192 MemorySegment.class, float.class); 193 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 194 C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, 195 C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, 196 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, 197 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, 198 struct, C_FLOAT); 199 CallArranger.Bindings bindings = CallArranger.MACOS.getBindings(mt, fd, false); 200 201 assertFalse(bindings.isInMemoryReturn()); 202 CallingSequence callingSequence = bindings.callingSequence(); 203 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 204 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 205 206 checkArgumentBindings(callingSequence, new Binding[][]{ 207 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 208 { vmStore(r0, long.class) }, 209 { vmStore(r1, long.class) }, 210 { vmStore(r2, long.class) }, 211 { vmStore(r3, long.class) }, 212 { vmStore(r4, long.class) }, 213 { vmStore(r5, long.class) }, 214 { vmStore(r6, long.class) }, 215 { vmStore(r7, long.class) }, 216 { vmStore(v0, double.class) }, 217 { vmStore(v1, double.class) }, 218 { vmStore(v2, double.class) }, 219 { vmStore(v3, double.class) }, 220 { vmStore(v4, double.class) }, 221 { vmStore(v5, double.class) }, 222 { vmStore(v6, double.class) }, 223 { vmStore(v7, double.class) }, 224 { dup(), 225 bufferLoad(0, long.class), vmStore(stackStorage((short) 8, 0), long.class), 226 bufferLoad(8, long.class), vmStore(stackStorage((short) 8, 8), long.class) }, 227 { vmStore(stackStorage((short) 4, 16), float.class) }, 228 }); 229 230 checkReturnBindings(callingSequence, new Binding[]{}); 231 } 232 233 @Test 234 public void testMacArgsOnStack4() { 235 StructLayout struct = MemoryLayout.structLayout( 236 C_INT, 237 C_INT, 238 C_POINTER 239 ); 240 MethodType mt = MethodType.methodType(void.class, 241 long.class, long.class, long.class, long.class, 242 long.class, long.class, long.class, long.class, 243 double.class, double.class, double.class, double.class, 244 double.class, double.class, double.class, double.class, 245 float.class, MemorySegment.class); 246 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 247 C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, 248 C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, 249 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, 250 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, 251 C_FLOAT, struct); 252 CallArranger.Bindings bindings = CallArranger.MACOS.getBindings(mt, fd, false); 253 254 assertFalse(bindings.isInMemoryReturn()); 255 CallingSequence callingSequence = bindings.callingSequence(); 256 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 257 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 258 259 checkArgumentBindings(callingSequence, new Binding[][]{ 260 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 261 { vmStore(r0, long.class) }, 262 { vmStore(r1, long.class) }, 263 { vmStore(r2, long.class) }, 264 { vmStore(r3, long.class) }, 265 { vmStore(r4, long.class) }, 266 { vmStore(r5, long.class) }, 267 { vmStore(r6, long.class) }, 268 { vmStore(r7, long.class) }, 269 { vmStore(v0, double.class) }, 270 { vmStore(v1, double.class) }, 271 { vmStore(v2, double.class) }, 272 { vmStore(v3, double.class) }, 273 { vmStore(v4, double.class) }, 274 { vmStore(v5, double.class) }, 275 { vmStore(v6, double.class) }, 276 { vmStore(v7, double.class) }, 277 { vmStore(stackStorage((short) 4, 0), float.class) }, 278 { dup(), 279 bufferLoad(0, long.class), vmStore(stackStorage((short) 8, 8), long.class), 280 bufferLoad(8, long.class), vmStore(stackStorage((short) 8, 16), long.class) }, 281 }); 282 283 checkReturnBindings(callingSequence, new Binding[]{}); 284 } 285 286 // structs that are passed field-wise should not have padding after them 287 @Test 288 public void testMacArgsOnStack5() { 289 StructLayout struct = MemoryLayout.structLayout( 290 C_FLOAT 291 ); 292 MethodType mt = MethodType.methodType(void.class, 293 long.class, long.class, long.class, long.class, 294 long.class, long.class, long.class, long.class, 295 double.class, double.class, double.class, double.class, 296 double.class, double.class, double.class, double.class, 297 MemorySegment.class, int.class, MemorySegment.class); 298 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 299 C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, 300 C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, 301 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, 302 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, 303 struct, C_INT, C_POINTER); 304 CallArranger.Bindings bindings = CallArranger.MACOS.getBindings(mt, fd, false); 305 306 assertFalse(bindings.isInMemoryReturn()); 307 CallingSequence callingSequence = bindings.callingSequence(); 308 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 309 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 310 311 checkArgumentBindings(callingSequence, new Binding[][]{ 312 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 313 { vmStore(r0, long.class) }, 314 { vmStore(r1, long.class) }, 315 { vmStore(r2, long.class) }, 316 { vmStore(r3, long.class) }, 317 { vmStore(r4, long.class) }, 318 { vmStore(r5, long.class) }, 319 { vmStore(r6, long.class) }, 320 { vmStore(r7, long.class) }, 321 { vmStore(v0, double.class) }, 322 { vmStore(v1, double.class) }, 323 { vmStore(v2, double.class) }, 324 { vmStore(v3, double.class) }, 325 { vmStore(v4, double.class) }, 326 { vmStore(v5, double.class) }, 327 { vmStore(v6, double.class) }, 328 { vmStore(v7, double.class) }, 329 { 330 bufferLoad(0, int.class), 331 vmStore(stackStorage((short) 4, 0), int.class), 332 }, 333 { vmStore(stackStorage((short) 4, 4), int.class) }, 334 { unboxAddress(), vmStore(stackStorage((short) 8, 8), long.class) }, 335 }); 336 337 checkReturnBindings(callingSequence, new Binding[]{}); 338 } 339 340 // structs that are passed chunk-wise should have padding before them, as well as after 341 @Test 342 public void testMacArgsOnStack6() { 343 StructLayout struct = MemoryLayout.structLayout( 344 C_INT 345 ); 346 MethodType mt = MethodType.methodType(void.class, 347 long.class, long.class, long.class, long.class, 348 long.class, long.class, long.class, long.class, 349 double.class, double.class, double.class, double.class, 350 double.class, double.class, double.class, double.class, 351 int.class, MemorySegment.class, double.class, MemorySegment.class); 352 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 353 C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, 354 C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, C_LONG_LONG, 355 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, 356 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE, 357 C_INT, struct, C_DOUBLE, C_POINTER); 358 CallArranger.Bindings bindings = CallArranger.MACOS.getBindings(mt, fd, false); 359 360 assertFalse(bindings.isInMemoryReturn()); 361 CallingSequence callingSequence = bindings.callingSequence(); 362 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 363 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 364 365 checkArgumentBindings(callingSequence, new Binding[][]{ 366 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 367 { vmStore(r0, long.class) }, 368 { vmStore(r1, long.class) }, 369 { vmStore(r2, long.class) }, 370 { vmStore(r3, long.class) }, 371 { vmStore(r4, long.class) }, 372 { vmStore(r5, long.class) }, 373 { vmStore(r6, long.class) }, 374 { vmStore(r7, long.class) }, 375 { vmStore(v0, double.class) }, 376 { vmStore(v1, double.class) }, 377 { vmStore(v2, double.class) }, 378 { vmStore(v3, double.class) }, 379 { vmStore(v4, double.class) }, 380 { vmStore(v5, double.class) }, 381 { vmStore(v6, double.class) }, 382 { vmStore(v7, double.class) }, 383 { vmStore(stackStorage((short) 4, 0), int.class) }, 384 { 385 bufferLoad(0, int.class), 386 vmStore(stackStorage((short) 4, 8), int.class), 387 }, 388 { vmStore(stackStorage((short) 8, 16), double.class) }, 389 { unboxAddress(), vmStore(stackStorage((short) 8, 24), long.class) }, 390 }); 391 392 checkReturnBindings(callingSequence, new Binding[]{}); 393 } 394 }