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