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.x64 32 * java.base/jdk.internal.foreign.abi.x64.windows 33 * @build CallArrangerTestBase 34 * @run testng TestWindowsCallArranger 35 */ 36 37 import java.lang.foreign.FunctionDescriptor; 38 import java.lang.foreign.MemoryLayout; 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.x64.windows.CallArranger; 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.Binding.copy; 54 import static jdk.internal.foreign.abi.x64.X86_64Architecture.*; 55 import static jdk.internal.foreign.abi.x64.X86_64Architecture.Regs.*; 56 import static platform.PlatformLayouts.Win64.*; 57 58 import static org.testng.Assert.*; 59 60 public class TestWindowsCallArranger extends CallArrangerTestBase { 61 62 private static final short STACK_SLOT_SIZE = 8; 63 private static final VMStorage TARGET_ADDRESS_STORAGE = StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER); 64 65 @Test 66 public void testEmpty() { 67 MethodType mt = MethodType.methodType(void.class); 68 FunctionDescriptor fd = FunctionDescriptor.ofVoid(); 69 CallArranger.Bindings bindings = CallArranger.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 }); 79 checkReturnBindings(callingSequence, new Binding[]{}); 80 } 81 82 @Test 83 public void testIntegerRegs() { 84 MethodType mt = MethodType.methodType(void.class, int.class, int.class, int.class, int.class); 85 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_INT, C_INT); 86 CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); 87 88 assertFalse(bindings.isInMemoryReturn()); 89 CallingSequence callingSequence = bindings.callingSequence(); 90 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 91 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 92 93 checkArgumentBindings(callingSequence, new Binding[][]{ 94 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 95 { vmStore(rcx, int.class) }, 96 { vmStore(rdx, int.class) }, 97 { vmStore(r8, int.class) }, 98 { vmStore(r9, int.class) } 99 }); 100 101 checkReturnBindings(callingSequence, new Binding[]{}); 102 } 103 104 @Test 105 public void testDoubleRegs() { 106 MethodType mt = MethodType.methodType(void.class, double.class, double.class, double.class, double.class); 107 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_DOUBLE, C_DOUBLE, C_DOUBLE, C_DOUBLE); 108 CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); 109 110 assertFalse(bindings.isInMemoryReturn()); 111 CallingSequence callingSequence = bindings.callingSequence(); 112 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 113 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 114 115 checkArgumentBindings(callingSequence, new Binding[][]{ 116 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 117 { vmStore(xmm0, double.class) }, 118 { vmStore(xmm1, double.class) }, 119 { vmStore(xmm2, double.class) }, 120 { vmStore(xmm3, double.class) } 121 }); 122 123 checkReturnBindings(callingSequence, new Binding[]{}); 124 } 125 126 @Test 127 public void testMixed() { 128 MethodType mt = MethodType.methodType(void.class, 129 long.class, long.class, float.class, float.class, long.class, long.class, float.class, float.class); 130 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 131 C_LONG_LONG, C_LONG_LONG, C_FLOAT, C_FLOAT, C_LONG_LONG, C_LONG_LONG, C_FLOAT, C_FLOAT); 132 CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); 133 134 assertFalse(bindings.isInMemoryReturn()); 135 CallingSequence callingSequence = bindings.callingSequence(); 136 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 137 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 138 139 checkArgumentBindings(callingSequence, new Binding[][]{ 140 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 141 { vmStore(rcx, long.class) }, 142 { vmStore(rdx, long.class) }, 143 { vmStore(xmm2, float.class) }, 144 { vmStore(xmm3, float.class) }, 145 { vmStore(stackStorage(STACK_SLOT_SIZE, 0), long.class) }, 146 { vmStore(stackStorage(STACK_SLOT_SIZE, 8), long.class) }, 147 { vmStore(stackStorage(STACK_SLOT_SIZE, 16), float.class) }, 148 { vmStore(stackStorage(STACK_SLOT_SIZE, 24), float.class) } 149 }); 150 151 checkReturnBindings(callingSequence, new Binding[]{}); 152 } 153 154 @Test 155 public void testAbiExample() { 156 MemoryLayout structLayout = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE); 157 MethodType mt = MethodType.methodType(void.class, 158 int.class, int.class, MemorySegment.class, int.class, int.class, 159 double.class, double.class, double.class, int.class, int.class, int.class); 160 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 161 C_INT, C_INT, structLayout, C_INT, C_INT, 162 C_DOUBLE, C_DOUBLE, C_DOUBLE, C_INT, C_INT, C_INT); 163 CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); 164 165 assertFalse(bindings.isInMemoryReturn()); 166 CallingSequence callingSequence = bindings.callingSequence(); 167 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 168 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 169 170 checkArgumentBindings(callingSequence, new Binding[][]{ 171 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 172 { vmStore(rcx, int.class) }, 173 { vmStore(rdx, int.class) }, 174 { 175 copy(structLayout), 176 unboxAddress(), 177 vmStore(r8, long.class) 178 }, 179 { vmStore(r9, int.class) }, 180 { vmStore(stackStorage(STACK_SLOT_SIZE, 0), int.class) }, 181 { vmStore(stackStorage(STACK_SLOT_SIZE, 8), double.class) }, 182 { vmStore(stackStorage(STACK_SLOT_SIZE, 16), double.class) }, 183 { vmStore(stackStorage(STACK_SLOT_SIZE, 24), double.class) }, 184 { vmStore(stackStorage(STACK_SLOT_SIZE, 32), int.class) }, 185 { vmStore(stackStorage(STACK_SLOT_SIZE, 40), int.class) }, 186 { vmStore(stackStorage(STACK_SLOT_SIZE, 48), int.class) } 187 }); 188 189 checkReturnBindings(callingSequence, new Binding[]{}); 190 } 191 192 @Test 193 public void testAbiExampleVarargs() { 194 MethodType mt = MethodType.methodType(void.class, 195 int.class, double.class, int.class, double.class, double.class); 196 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 197 C_INT, C_DOUBLE, C_INT, C_DOUBLE, C_DOUBLE); 198 FunctionDescriptor fdExpected = FunctionDescriptor.ofVoid( 199 ADDRESS, C_INT, C_DOUBLE, C_INT, C_DOUBLE, C_DOUBLE); 200 CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(2))); 201 202 assertFalse(bindings.isInMemoryReturn()); 203 CallingSequence callingSequence = bindings.callingSequence(); 204 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 205 assertEquals(callingSequence.functionDesc(), fdExpected); 206 207 checkArgumentBindings(callingSequence, new Binding[][]{ 208 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 209 { vmStore(rcx, int.class) }, 210 { vmStore(xmm1, double.class) }, 211 { vmStore(r8, int.class) }, 212 { dup(), vmStore(r9, double.class), vmStore(xmm3, double.class) }, 213 { vmStore(stackStorage(STACK_SLOT_SIZE, 0), double.class) }, 214 }); 215 216 checkReturnBindings(callingSequence, new Binding[]{}); 217 } 218 219 /** 220 * struct s { 221 * uint64_t u0; 222 * } s; 223 * 224 * void m(struct s s); 225 * 226 * m(s); 227 */ 228 @Test 229 public void testStructRegister() { 230 MemoryLayout struct = MemoryLayout.structLayout(C_LONG_LONG); 231 232 MethodType mt = MethodType.methodType(void.class, MemorySegment.class); 233 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct); 234 CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); 235 236 assertFalse(bindings.isInMemoryReturn()); 237 CallingSequence callingSequence = bindings.callingSequence(); 238 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 239 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 240 241 checkArgumentBindings(callingSequence, new Binding[][]{ 242 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 243 { bufferLoad(0, long.class), vmStore(rcx, long.class) } 244 }); 245 246 checkReturnBindings(callingSequence, new Binding[]{}); 247 } 248 249 /** 250 * struct s { 251 * uint64_t u0, u1; 252 * } s; 253 * 254 * void m(struct s s); 255 * 256 * m(s); 257 */ 258 @Test 259 public void testStructReference() { 260 MemoryLayout struct = MemoryLayout.structLayout(C_LONG_LONG, C_LONG_LONG); 261 262 MethodType mt = MethodType.methodType(void.class, MemorySegment.class); 263 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct); 264 CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); 265 266 assertFalse(bindings.isInMemoryReturn()); 267 CallingSequence callingSequence = bindings.callingSequence(); 268 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 269 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 270 271 checkArgumentBindings(callingSequence, new Binding[][]{ 272 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 273 { 274 copy(struct), 275 unboxAddress(), 276 vmStore(rcx, long.class) 277 } 278 }); 279 280 checkReturnBindings(callingSequence, new Binding[]{}); 281 } 282 283 /** 284 * typedef void (*f)(void); 285 * 286 * void m(f f); 287 * void f_impl(void); 288 * 289 * m(f_impl); 290 */ 291 @Test 292 public void testMemoryAddress() { 293 MethodType mt = MethodType.methodType(void.class, MemorySegment.class); 294 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_POINTER); 295 CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); 296 297 assertFalse(bindings.isInMemoryReturn()); 298 CallingSequence callingSequence = bindings.callingSequence(); 299 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 300 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 301 302 checkArgumentBindings(callingSequence, new Binding[][]{ 303 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 304 { unboxAddress(), vmStore(rcx, long.class) } 305 }); 306 307 checkReturnBindings(callingSequence, new Binding[]{}); 308 } 309 310 @Test 311 public void testReturnRegisterStruct() { 312 MemoryLayout struct = MemoryLayout.structLayout(C_LONG_LONG); 313 314 MethodType mt = MethodType.methodType(MemorySegment.class); 315 FunctionDescriptor fd = FunctionDescriptor.of(struct); 316 CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); 317 318 assertFalse(bindings.isInMemoryReturn()); 319 CallingSequence callingSequence = bindings.callingSequence(); 320 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 321 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 322 323 checkArgumentBindings(callingSequence, new Binding[][]{ 324 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 325 }); 326 327 checkReturnBindings(callingSequence, 328 new Binding[]{ allocate(struct), 329 dup(), 330 vmLoad(rax, long.class), 331 bufferStore(0, long.class) }); 332 } 333 334 @Test 335 public void testIMR() { 336 MemoryLayout struct = MemoryLayout.structLayout(C_LONG_LONG, C_LONG_LONG); 337 338 MethodType mt = MethodType.methodType(MemorySegment.class); 339 FunctionDescriptor fd = FunctionDescriptor.of(struct); 340 CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); 341 342 assertTrue(bindings.isInMemoryReturn()); 343 CallingSequence callingSequence = bindings.callingSequence(); 344 assertEquals(callingSequence.callerMethodType(), MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class)); 345 assertEquals(callingSequence.functionDesc(), FunctionDescriptor.ofVoid(ADDRESS, C_POINTER)); 346 347 checkArgumentBindings(callingSequence, new Binding[][]{ 348 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 349 { unboxAddress(), vmStore(rcx, long.class) } 350 }); 351 352 checkReturnBindings(callingSequence, new Binding[]{}); 353 } 354 355 @Test 356 public void testStackStruct() { 357 MemoryLayout struct = MemoryLayout.structLayout(C_POINTER, C_DOUBLE, C_INT); 358 359 MethodType mt = MethodType.methodType(void.class, 360 MemorySegment.class, int.class, double.class, MemorySegment.class, 361 MemorySegment.class, int.class, double.class, MemorySegment.class, 362 MemorySegment.class, int.class, double.class, MemorySegment.class, 363 MemorySegment.class, int.class, double.class, MemorySegment.class); 364 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 365 struct, C_INT, C_DOUBLE, C_POINTER, 366 struct, C_INT, C_DOUBLE, C_POINTER, 367 struct, C_INT, C_DOUBLE, C_POINTER, 368 struct, C_INT, C_DOUBLE, C_POINTER); 369 CallArranger.Bindings bindings = CallArranger.getBindings(mt, fd, false); 370 371 assertFalse(bindings.isInMemoryReturn()); 372 CallingSequence callingSequence = bindings.callingSequence(); 373 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 374 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 375 376 checkArgumentBindings(callingSequence, new Binding[][]{ 377 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 378 { copy(struct), unboxAddress(), vmStore(rcx, long.class) }, 379 { vmStore(rdx, int.class) }, 380 { vmStore(xmm2, double.class) }, 381 { unboxAddress(), vmStore(r9, long.class) }, 382 { copy(struct), unboxAddress(), vmStore(stackStorage(STACK_SLOT_SIZE, 0), long.class) }, 383 { vmStore(stackStorage(STACK_SLOT_SIZE, 8), int.class) }, 384 { vmStore(stackStorage(STACK_SLOT_SIZE, 16), double.class) }, 385 { unboxAddress(), vmStore(stackStorage(STACK_SLOT_SIZE, 24), long.class) }, 386 { copy(struct), unboxAddress(), vmStore(stackStorage(STACK_SLOT_SIZE, 32), long.class) }, 387 { vmStore(stackStorage(STACK_SLOT_SIZE, 40), int.class) }, 388 { vmStore(stackStorage(STACK_SLOT_SIZE, 48), double.class) }, 389 { unboxAddress(), vmStore(stackStorage(STACK_SLOT_SIZE, 56), long.class) }, 390 { copy(struct), unboxAddress(), vmStore(stackStorage(STACK_SLOT_SIZE, 64), long.class) }, 391 { vmStore(stackStorage(STACK_SLOT_SIZE, 72), int.class) }, 392 { vmStore(stackStorage(STACK_SLOT_SIZE, 80), double.class) }, 393 { unboxAddress(), vmStore(stackStorage(STACK_SLOT_SIZE, 88), long.class) }, 394 }); 395 396 checkReturnBindings(callingSequence, new Binding[]{}); 397 } 398 }