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 * @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 TestWindowsAArch64CallArranger 34 */ 35 36 import java.lang.foreign.FunctionDescriptor; 37 import java.lang.foreign.MemoryLayout; 38 import java.lang.foreign.MemorySegment; 39 import jdk.internal.foreign.abi.Binding; 40 import jdk.internal.foreign.abi.CallingSequence; 41 import jdk.internal.foreign.abi.LinkerOptions; 42 import jdk.internal.foreign.abi.StubLocations; 43 import jdk.internal.foreign.abi.VMStorage; 44 import jdk.internal.foreign.abi.aarch64.CallArranger; 45 import org.testng.annotations.DataProvider; 46 import org.testng.annotations.Test; 47 48 import java.lang.invoke.MethodType; 49 50 import static java.lang.foreign.Linker.Option.firstVariadicArg; 51 import static java.lang.foreign.ValueLayout.ADDRESS; 52 import static jdk.internal.foreign.abi.Binding.*; 53 import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.*; 54 import static jdk.internal.foreign.abi.aarch64.AArch64Architecture.Regs.*; 55 import static platform.PlatformLayouts.AArch64.*; 56 import static org.testng.Assert.assertEquals; 57 import static org.testng.Assert.assertFalse; 58 import static org.testng.Assert.assertTrue; 59 60 public class TestWindowsAArch64CallArranger extends CallArrangerTestBase { 61 62 private static final VMStorage TARGET_ADDRESS_STORAGE = StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER); 63 private static final VMStorage RETURN_BUFFER_STORAGE = StubLocations.RETURN_BUFFER.storage(StorageType.PLACEHOLDER); 64 65 @Test 66 public void testWindowsArgsInRegs() { 67 MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class, double.class); 68 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_FLOAT, C_DOUBLE); 69 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false); 70 71 assertFalse(bindings.isInMemoryReturn()); 72 CallingSequence callingSequence = bindings.callingSequence(); 73 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 74 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 75 76 checkArgumentBindings(callingSequence, new Binding[][]{ 77 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 78 { vmStore(r0, int.class) }, 79 { vmStore(r1, int.class) }, 80 { vmStore(v0, float.class) }, 81 { vmStore(v1, double.class) }, 82 }); 83 84 checkReturnBindings(callingSequence, new Binding[]{}); 85 } 86 87 @Test 88 public void testWindowsVarArgsInRegs() { 89 MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class, double.class); 90 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_FLOAT, C_DOUBLE); 91 FunctionDescriptor fdExpected = FunctionDescriptor.ofVoid(ADDRESS, C_INT, C_INT, C_FLOAT, C_DOUBLE); 92 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(1))); 93 94 assertFalse(bindings.isInMemoryReturn()); 95 CallingSequence callingSequence = bindings.callingSequence(); 96 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 97 assertEquals(callingSequence.functionDesc(), fdExpected); 98 99 checkArgumentBindings(callingSequence, new Binding[][]{ 100 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 101 { vmStore(r0, int.class) }, 102 { vmStore(r1, int.class) }, 103 { vmStore(r2, float.class) }, 104 { vmStore(r3, double.class) }, 105 }); 106 107 checkReturnBindings(callingSequence, new Binding[]{}); 108 } 109 110 @Test 111 public void testWindowsArgsInRegsAndOnStack() { 112 MethodType mt = MethodType.methodType(void.class, double.class, int.class, float.class, 113 double.class, float.class, float.class, double.class, 114 float.class, float.class, float.class, int.class); 115 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_DOUBLE, C_INT, C_FLOAT, 116 C_DOUBLE, C_FLOAT, C_FLOAT, C_DOUBLE, 117 C_FLOAT, C_FLOAT, C_FLOAT, C_INT); 118 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false); 119 120 assertFalse(bindings.isInMemoryReturn()); 121 CallingSequence callingSequence = bindings.callingSequence(); 122 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 123 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 124 125 checkArgumentBindings(callingSequence, new Binding[][]{ 126 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 127 { vmStore(v0, double.class) }, 128 { vmStore(r0, int.class) }, 129 { vmStore(v1, float.class) }, 130 { vmStore(v2, double.class) }, 131 { vmStore(v3, float.class) }, 132 { vmStore(v4, float.class) }, 133 { vmStore(v5, double.class) }, 134 { vmStore(v6, float.class) }, 135 { vmStore(v7, float.class) }, 136 { vmStore(stackStorage((short) 4, 0), float.class) }, 137 { vmStore(r1, int.class) }, 138 }); 139 140 checkReturnBindings(callingSequence, new Binding[]{}); 141 } 142 143 @Test 144 public void testWindowsVarArgsInRegsAndOnStack() { 145 MethodType mt = MethodType.methodType(void.class, double.class, int.class, float.class, 146 double.class, float.class, float.class, double.class, 147 float.class, float.class, float.class); 148 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_DOUBLE, C_INT, C_FLOAT, 149 C_DOUBLE, C_FLOAT, C_FLOAT, C_DOUBLE, 150 C_FLOAT, C_FLOAT, C_FLOAT); 151 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); 152 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(1))); 153 154 assertFalse(bindings.isInMemoryReturn()); 155 CallingSequence callingSequence = bindings.callingSequence(); 156 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 157 assertEquals(callingSequence.functionDesc(), fdExpected); 158 159 checkArgumentBindings(callingSequence, new Binding[][]{ 160 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 161 { vmStore(r0, double.class) }, 162 { vmStore(r1, int.class) }, 163 { vmStore(r2, float.class) }, 164 { vmStore(r3, double.class) }, 165 { vmStore(r4, float.class) }, 166 { vmStore(r5, float.class) }, 167 { vmStore(r6, double.class) }, 168 { vmStore(r7, float.class) }, 169 { vmStore(stackStorage((short) 4, 0), float.class) }, 170 { vmStore(stackStorage((short) 4, 8), float.class) }, 171 }); 172 173 checkReturnBindings(callingSequence, new Binding[]{}); 174 } 175 176 @Test 177 public void testWindowsHfa4FloatsInFloatRegs() { 178 MemoryLayout struct = MemoryLayout.structLayout(C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT); 179 180 MethodType mt = MethodType.methodType(void.class, MemorySegment.class, int.class); 181 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT); 182 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false); 183 184 assertFalse(bindings.isInMemoryReturn()); 185 CallingSequence callingSequence = bindings.callingSequence(); 186 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 187 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 188 189 checkArgumentBindings(callingSequence, new Binding[][]{ 190 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 191 { 192 dup(), 193 bufferLoad(0, float.class), 194 vmStore(v0, float.class), 195 dup(), 196 bufferLoad(4, float.class), 197 vmStore(v1, float.class), 198 dup(), 199 bufferLoad(8, float.class), 200 vmStore(v2, float.class), 201 bufferLoad(12, float.class), 202 vmStore(v3, float.class), 203 }, 204 { vmStore(r0, int.class) }, 205 }); 206 207 checkReturnBindings(callingSequence, new Binding[]{}); 208 } 209 210 @Test 211 public void testWindowsVariadicHfa4FloatsInIntRegs() { 212 MemoryLayout struct = MemoryLayout.structLayout(C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT); 213 214 MethodType mt = MethodType.methodType(void.class, MemorySegment.class, int.class); 215 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT); 216 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(0))); 217 218 assertFalse(bindings.isInMemoryReturn()); 219 CallingSequence callingSequence = bindings.callingSequence(); 220 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 221 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 222 223 checkArgumentBindings(callingSequence, new Binding[][]{ 224 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 225 { 226 dup(), 227 bufferLoad(0, long.class), 228 vmStore(r0, long.class), 229 bufferLoad(8, long.class), 230 vmStore(r1, long.class), 231 }, 232 { vmStore(r2, int.class) }, 233 }); 234 235 checkReturnBindings(callingSequence, new Binding[]{}); 236 } 237 238 @Test 239 public void testWindowsHfa2DoublesInFloatRegs() { 240 MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE); 241 242 MethodType mt = MethodType.methodType( 243 void.class, MemorySegment.class, int.class); 244 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT); 245 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false); 246 247 assertFalse(bindings.isInMemoryReturn()); 248 CallingSequence callingSequence = bindings.callingSequence(); 249 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 250 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 251 252 checkArgumentBindings(callingSequence, new Binding[][]{ 253 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 254 { 255 dup(), 256 bufferLoad(0, double.class), 257 vmStore(v0, double.class), 258 bufferLoad(8, double.class), 259 vmStore(v1, double.class), 260 }, 261 { vmStore(r0, int.class) }, 262 }); 263 264 checkReturnBindings(callingSequence, new Binding[]{}); 265 } 266 267 @Test 268 public void testWindowsVariadicHfa2DoublesInIntRegs() { 269 MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE); 270 271 MethodType mt = MethodType.methodType( 272 void.class, MemorySegment.class, int.class); 273 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT); 274 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(0))); 275 276 assertFalse(bindings.isInMemoryReturn()); 277 CallingSequence callingSequence = bindings.callingSequence(); 278 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 279 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 280 281 checkArgumentBindings(callingSequence, new Binding[][]{ 282 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 283 { 284 dup(), 285 bufferLoad(0, long.class), 286 vmStore(r0, long.class), 287 bufferLoad(8, long.class), 288 vmStore(r1, long.class), 289 }, 290 { vmStore(r2, int.class) }, 291 }); 292 293 checkReturnBindings(callingSequence, new Binding[]{}); 294 } 295 296 @Test 297 public void testWindowsHfa3DoublesInFloatRegs() { 298 MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE, C_DOUBLE); 299 300 MethodType mt = MethodType.methodType( 301 void.class, MemorySegment.class, int.class); 302 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT); 303 CallArranger.Bindings bindings = CallArranger.WINDOWS.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 { 313 dup(), 314 bufferLoad(0, double.class), 315 vmStore(v0, double.class), 316 dup(), 317 bufferLoad(8, double.class), 318 vmStore(v1, double.class), 319 bufferLoad(16, double.class), 320 vmStore(v2, double.class), 321 }, 322 { vmStore(r0, int.class) }, 323 }); 324 325 checkReturnBindings(callingSequence, new Binding[]{}); 326 } 327 328 @Test 329 public void testWindowsVariadicHfa3DoublesAsReferenceStruct() { 330 MemoryLayout struct = MemoryLayout.structLayout(C_DOUBLE, C_DOUBLE, C_DOUBLE); 331 332 MethodType mt = MethodType.methodType( 333 void.class, MemorySegment.class, int.class); 334 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, C_INT); 335 CallArranger.Bindings bindings = CallArranger.WINDOWS.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(0))); 336 337 assertFalse(bindings.isInMemoryReturn()); 338 CallingSequence callingSequence = bindings.callingSequence(); 339 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 340 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 341 342 checkArgumentBindings(callingSequence, new Binding[][]{ 343 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 344 { copy(struct), unboxAddress(), vmStore(r0, long.class) }, 345 { vmStore(r1, int.class) }, 346 }); 347 348 checkReturnBindings(callingSequence, new Binding[]{}); 349 } 350 }