1 /* 2 * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2023, Institute of Software, Chinese Academy of Sciences. 4 * All rights reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 * 25 */ 26 27 /* 28 * @test 29 * @enablePreview 30 * @requires sun.arch.data.model == "64" 31 * @compile platform/PlatformLayouts.java 32 * @modules java.base/jdk.internal.foreign 33 * java.base/jdk.internal.foreign.abi 34 * java.base/jdk.internal.foreign.abi.riscv64 35 * java.base/jdk.internal.foreign.abi.riscv64.linux 36 * @build CallArrangerTestBase 37 * @run testng TestRISCV64CallArranger 38 */ 39 40 import java.lang.foreign.FunctionDescriptor; 41 import java.lang.foreign.MemoryLayout; 42 import java.lang.foreign.MemorySegment; 43 import jdk.internal.foreign.abi.Binding; 44 import jdk.internal.foreign.abi.CallingSequence; 45 import jdk.internal.foreign.abi.LinkerOptions; 46 import jdk.internal.foreign.abi.riscv64.linux.LinuxRISCV64CallArranger; 47 import jdk.internal.foreign.abi.StubLocations; 48 import jdk.internal.foreign.abi.VMStorage; 49 import org.testng.annotations.DataProvider; 50 import org.testng.annotations.Test; 51 52 import java.lang.foreign.ValueLayout; 53 import java.lang.invoke.MethodType; 54 55 import static java.lang.foreign.Linker.Option.firstVariadicArg; 56 import static java.lang.foreign.ValueLayout.ADDRESS; 57 import static jdk.internal.foreign.abi.Binding.*; 58 import static jdk.internal.foreign.abi.riscv64.RISCV64Architecture.*; 59 import static jdk.internal.foreign.abi.riscv64.RISCV64Architecture.Regs.*; 60 import static platform.PlatformLayouts.RISCV64.*; 61 62 import static org.testng.Assert.assertEquals; 63 import static org.testng.Assert.assertFalse; 64 import static org.testng.Assert.assertTrue; 65 66 public class TestRISCV64CallArranger extends CallArrangerTestBase { 67 68 private static final short STACK_SLOT_SIZE = 8; 69 private static final VMStorage TARGET_ADDRESS_STORAGE = StubLocations.TARGET_ADDRESS.storage(StorageType.PLACEHOLDER); 70 private static final VMStorage RETURN_BUFFER_STORAGE = StubLocations.RETURN_BUFFER.storage(StorageType.PLACEHOLDER); 71 72 @Test 73 public void testEmpty() { 74 MethodType mt = MethodType.methodType(void.class); 75 FunctionDescriptor fd = FunctionDescriptor.ofVoid(); 76 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false); 77 78 assertFalse(bindings.isInMemoryReturn()); 79 CallingSequence callingSequence = bindings.callingSequence(); 80 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 81 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 82 83 checkArgumentBindings(callingSequence, new Binding[][]{ 84 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) } 85 }); 86 87 checkReturnBindings(callingSequence, new Binding[]{}); 88 } 89 90 @Test 91 public void testInteger() { 92 MethodType mt = MethodType.methodType(void.class, 93 byte.class, short.class, int.class, int.class, 94 int.class, int.class, long.class, int.class, 95 int.class, byte.class); 96 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 97 C_CHAR, C_SHORT, C_INT, C_INT, 98 C_INT, C_INT, C_LONG, C_INT, 99 C_INT, C_CHAR); 100 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false); 101 102 assertFalse(bindings.isInMemoryReturn()); 103 CallingSequence callingSequence = bindings.callingSequence(); 104 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 105 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 106 107 checkArgumentBindings(callingSequence, new Binding[][]{ 108 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 109 { cast(byte.class, int.class), vmStore(x10, int.class) }, 110 { cast(short.class, int.class), vmStore(x11, int.class) }, 111 { vmStore(x12, int.class) }, 112 { vmStore(x13, int.class) }, 113 { vmStore(x14, int.class) }, 114 { vmStore(x15, int.class) }, 115 { vmStore(x16, long.class) }, 116 { vmStore(x17, int.class) }, 117 { vmStore(stackStorage(STACK_SLOT_SIZE, 0), int.class) }, 118 { cast(byte.class, int.class), vmStore(stackStorage(STACK_SLOT_SIZE, 8), int.class) } 119 }); 120 121 checkReturnBindings(callingSequence, new Binding[]{}); 122 } 123 124 @Test 125 public void testTwoIntTwoFloat() { 126 MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class, float.class); 127 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_FLOAT, C_FLOAT); 128 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false); 129 130 assertFalse(bindings.isInMemoryReturn()); 131 CallingSequence callingSequence = bindings.callingSequence(); 132 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 133 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 134 135 checkArgumentBindings(callingSequence, new Binding[][]{ 136 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 137 { vmStore(x10, int.class) }, 138 { vmStore(x11, int.class) }, 139 { vmStore(f10, float.class) }, 140 { vmStore(f11, float.class) } 141 }); 142 143 checkReturnBindings(callingSequence, new Binding[]{}); 144 } 145 146 @Test(dataProvider = "structs") 147 public void testStruct(MemoryLayout struct, Binding[] expectedBindings) { 148 MethodType mt = MethodType.methodType(void.class, MemorySegment.class); 149 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct); 150 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false); 151 152 assertFalse(bindings.isInMemoryReturn()); 153 CallingSequence callingSequence = bindings.callingSequence(); 154 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 155 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 156 157 checkArgumentBindings(callingSequence, new Binding[][]{ 158 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 159 expectedBindings 160 }); 161 162 checkReturnBindings(callingSequence, new Binding[]{}); 163 } 164 165 @DataProvider 166 public static Object[][] structs() { 167 MemoryLayout struct1 = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE, C_INT); 168 return new Object[][]{ 169 // struct s { void* a; double c; }; 170 { 171 MemoryLayout.structLayout(C_POINTER, C_DOUBLE), 172 new Binding[]{ 173 dup(), 174 bufferLoad(0, long.class), vmStore(x10, long.class), 175 bufferLoad(8, long.class), vmStore(x11, long.class) 176 } 177 }, 178 // struct s { int32_t a, b; double c; }; 179 { MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE), 180 new Binding[]{ 181 dup(), 182 // s.a & s.b 183 bufferLoad(0, long.class), vmStore(x10, long.class), 184 // s.c 185 bufferLoad(8, long.class), vmStore(x11, long.class) 186 } 187 }, 188 // struct s { int32_t a, b; double c; int32_t d; }; 189 { struct1, 190 new Binding[]{ 191 copy(struct1), 192 unboxAddress(), 193 vmStore(x10, long.class) 194 } 195 }, 196 // struct s { int32_t a[1]; float b[1]; }; 197 { MemoryLayout.structLayout(MemoryLayout.sequenceLayout(1, C_INT), 198 MemoryLayout.sequenceLayout(1, C_FLOAT)), 199 new Binding[]{ 200 dup(), 201 // s.a[0] 202 bufferLoad(0, int.class), vmStore(x10, int.class), 203 // s.b[0] 204 bufferLoad(4, float.class), vmStore(f10, float.class) 205 } 206 }, 207 // struct s { float a; /* padding */ double b }; 208 { MemoryLayout.structLayout(C_FLOAT, MemoryLayout.paddingLayout(4), C_DOUBLE), 209 new Binding[]{ 210 dup(), 211 // s.a 212 bufferLoad(0, float.class), vmStore(f10, float.class), 213 // s.b 214 bufferLoad(8, double.class), vmStore(f11, double.class), 215 } 216 } 217 }; 218 } 219 220 @Test 221 public void testStructFA1() { 222 MemoryLayout fa = MemoryLayout.structLayout(C_FLOAT, C_FLOAT); 223 224 MethodType mt = MethodType.methodType(MemorySegment.class, float.class, int.class, MemorySegment.class); 225 FunctionDescriptor fd = FunctionDescriptor.of(fa, C_FLOAT, C_INT, fa); 226 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false); 227 228 assertFalse(bindings.isInMemoryReturn()); 229 CallingSequence callingSequence = bindings.callingSequence(); 230 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class)); 231 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS, ADDRESS)); 232 233 checkArgumentBindings(callingSequence, new Binding[][]{ 234 { unboxAddress(), vmStore(RETURN_BUFFER_STORAGE, long.class) }, 235 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 236 { vmStore(f10, float.class) }, 237 { vmStore(x10, int.class) }, 238 { 239 dup(), 240 bufferLoad(0, float.class), 241 vmStore(f11, float.class), 242 bufferLoad(4, float.class), 243 vmStore(f12, float.class) 244 } 245 }); 246 247 checkReturnBindings(callingSequence, new Binding[]{ 248 allocate(fa), 249 dup(), 250 vmLoad(f10, float.class), 251 bufferStore(0, float.class), 252 dup(), 253 vmLoad(f11, float.class), 254 bufferStore(4, float.class) 255 }); 256 } 257 258 @Test 259 public void testStructFA2() { 260 MemoryLayout fa = MemoryLayout.structLayout(C_FLOAT, MemoryLayout.paddingLayout(4), C_DOUBLE); 261 262 MethodType mt = MethodType.methodType(MemorySegment.class, float.class, int.class, MemorySegment.class); 263 FunctionDescriptor fd = FunctionDescriptor.of(fa, C_FLOAT, C_INT, fa); 264 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false); 265 266 assertFalse(bindings.isInMemoryReturn()); 267 CallingSequence callingSequence = bindings.callingSequence(); 268 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class)); 269 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS, ADDRESS)); 270 271 checkArgumentBindings(callingSequence, new Binding[][]{ 272 { unboxAddress(), vmStore(RETURN_BUFFER_STORAGE, long.class) }, 273 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 274 { vmStore(f10, float.class) }, 275 { vmStore(x10, int.class) }, 276 { 277 dup(), 278 bufferLoad(0, float.class), 279 vmStore(f11, float.class), 280 bufferLoad(8, double.class), 281 vmStore(f12, double.class) 282 } 283 }); 284 285 checkReturnBindings(callingSequence, new Binding[]{ 286 allocate(fa), 287 dup(), 288 vmLoad(f10, float.class), 289 bufferStore(0, float.class), 290 dup(), 291 vmLoad(f11, double.class), 292 bufferStore(8, double.class) 293 }); 294 } 295 296 @Test 297 void spillFloatingPointStruct() { 298 MemoryLayout struct = MemoryLayout.structLayout(C_FLOAT, C_FLOAT); 299 // void f(float, float, float, float, float, float, float, struct) 300 MethodType mt = MethodType.methodType(void.class, float.class, float.class, 301 float.class, float.class, float.class, 302 float.class, float.class, MemorySegment.class); 303 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_FLOAT, C_FLOAT, C_FLOAT, C_FLOAT, 304 C_FLOAT, C_FLOAT, C_FLOAT, struct); 305 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false); 306 307 assertFalse(bindings.isInMemoryReturn()); 308 CallingSequence callingSequence = bindings.callingSequence(); 309 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 310 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 311 312 checkArgumentBindings(callingSequence, new Binding[][]{ 313 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 314 { vmStore(f10, float.class) }, 315 { vmStore(f11, float.class) }, 316 { vmStore(f12, float.class) }, 317 { vmStore(f13, float.class) }, 318 { vmStore(f14, float.class) }, 319 { vmStore(f15, float.class) }, 320 { vmStore(f16, float.class) }, 321 { 322 bufferLoad(0, long.class), 323 vmStore(x10, long.class) 324 } 325 }); 326 327 checkReturnBindings(callingSequence, new Binding[]{}); 328 } 329 330 @Test 331 public void testStructBoth() { 332 MemoryLayout struct = MemoryLayout.structLayout(C_INT, C_FLOAT); 333 334 MethodType mt = MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class, MemorySegment.class); 335 FunctionDescriptor fd = FunctionDescriptor.ofVoid(struct, struct, struct); 336 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false); 337 338 assertFalse(bindings.isInMemoryReturn()); 339 CallingSequence callingSequence = bindings.callingSequence(); 340 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 341 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 342 343 checkArgumentBindings(callingSequence, new Binding[][]{ 344 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 345 { 346 dup(), 347 bufferLoad(0, int.class), 348 vmStore(x10, int.class), 349 bufferLoad(4, float.class), 350 vmStore(f10, float.class) 351 }, 352 { 353 dup(), 354 bufferLoad(0, int.class), 355 vmStore(x11, int.class), 356 bufferLoad(4, float.class), 357 vmStore(f11, float.class) 358 }, 359 { 360 dup(), 361 bufferLoad(0, int.class), 362 vmStore(x12, int.class), 363 bufferLoad(4, float.class), 364 vmStore(f12, float.class) 365 } 366 }); 367 368 checkReturnBindings(callingSequence, new Binding[]{}); 369 } 370 371 @Test 372 public void testStructStackSpill() { 373 // A large (> 16 byte) struct argument that is spilled to the 374 // stack should be passed as a pointer to a copy and occupy one 375 // stack slot. 376 377 MemoryLayout struct = MemoryLayout.structLayout(C_INT, C_INT, C_DOUBLE, C_INT); 378 379 MethodType mt = MethodType.methodType( 380 void.class, MemorySegment.class, MemorySegment.class, int.class, int.class, 381 int.class, int.class, int.class, int.class, MemorySegment.class, int.class); 382 FunctionDescriptor fd = FunctionDescriptor.ofVoid( 383 struct, struct, C_INT, C_INT, C_INT, C_INT, C_INT, C_INT, struct, C_INT); 384 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false); 385 386 assertFalse(bindings.isInMemoryReturn()); 387 CallingSequence callingSequence = bindings.callingSequence(); 388 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 389 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS)); 390 391 checkArgumentBindings(callingSequence, new Binding[][]{ 392 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 393 { copy(struct), unboxAddress(), vmStore(x10, long.class) }, 394 { copy(struct), unboxAddress(), vmStore(x11, long.class) }, 395 { vmStore(x12, int.class) }, 396 { vmStore(x13, int.class) }, 397 { vmStore(x14, int.class) }, 398 { vmStore(x15, int.class) }, 399 { vmStore(x16, int.class) }, 400 { vmStore(x17, int.class) }, 401 { copy(struct), unboxAddress(), vmStore(stackStorage(STACK_SLOT_SIZE, 0), long.class) }, 402 { vmStore(stackStorage(STACK_SLOT_SIZE, 8), int.class) } 403 }); 404 405 checkReturnBindings(callingSequence, new Binding[]{}); 406 } 407 408 @Test 409 public void testVarArgsInRegs() { 410 MethodType mt = MethodType.methodType(void.class, int.class, int.class, float.class); 411 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_FLOAT); 412 FunctionDescriptor fdExpected = FunctionDescriptor.ofVoid(ADDRESS, C_INT, C_INT, C_FLOAT); 413 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(1))); 414 415 assertFalse(bindings.isInMemoryReturn()); 416 CallingSequence callingSequence = bindings.callingSequence(); 417 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 418 assertEquals(callingSequence.functionDesc(), fdExpected); 419 420 // This is identical to the non-variadic calling sequence 421 checkArgumentBindings(callingSequence, new Binding[][]{ 422 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 423 { vmStore(x10, int.class) }, 424 { vmStore(x11, int.class) }, 425 { vmStore(x12, float.class) } 426 }); 427 428 checkReturnBindings(callingSequence, new Binding[]{}); 429 } 430 431 @Test 432 public void testVarArgsLong() { 433 MethodType mt = MethodType.methodType(void.class, int.class, int.class, int.class, double.class, 434 double.class, long.class, long.class, int.class, 435 double.class, double.class, long.class); 436 FunctionDescriptor fd = FunctionDescriptor.ofVoid(C_INT, C_INT, C_INT, C_DOUBLE, C_DOUBLE, 437 C_LONG, C_LONG, C_INT, C_DOUBLE, 438 C_DOUBLE, C_LONG); 439 FunctionDescriptor fdExpected = FunctionDescriptor.ofVoid(ADDRESS, C_INT, C_INT, C_INT, C_DOUBLE, 440 C_DOUBLE, C_LONG, C_LONG, C_INT, 441 C_DOUBLE, C_DOUBLE, C_LONG); 442 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false, LinkerOptions.forDowncall(fd, firstVariadicArg(1))); 443 444 assertFalse(bindings.isInMemoryReturn()); 445 CallingSequence callingSequence = bindings.callingSequence(); 446 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class)); 447 assertEquals(callingSequence.functionDesc(), fdExpected); 448 449 // This is identical to the non-variadic calling sequence 450 checkArgumentBindings(callingSequence, new Binding[][]{ 451 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 452 { vmStore(x10, int.class) }, 453 { vmStore(x11, int.class) }, 454 { vmStore(x12, int.class) }, 455 { vmStore(x13, double.class) }, 456 { vmStore(x14, double.class) }, 457 { vmStore(x15, long.class) }, 458 { vmStore(x16, long.class) }, 459 { vmStore(x17, int.class) }, 460 { vmStore(stackStorage(STACK_SLOT_SIZE, 0), double.class) }, 461 { vmStore(stackStorage(STACK_SLOT_SIZE, 8), double.class) }, 462 { vmStore(stackStorage(STACK_SLOT_SIZE, 16), long.class) } 463 }); 464 465 checkReturnBindings(callingSequence, new Binding[]{}); 466 } 467 468 @Test 469 public void testReturnStruct1() { 470 MemoryLayout struct = MemoryLayout.structLayout(C_LONG, C_LONG, C_FLOAT); 471 472 MethodType mt = MethodType.methodType(MemorySegment.class, int.class, int.class, float.class); 473 FunctionDescriptor fd = FunctionDescriptor.of(struct, C_INT, C_INT, C_FLOAT); 474 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false); 475 476 assertTrue(bindings.isInMemoryReturn()); 477 CallingSequence callingSequence = bindings.callingSequence(); 478 assertEquals(callingSequence.callerMethodType(), 479 MethodType.methodType(void.class, MemorySegment.class, MemorySegment.class, 480 int.class, int.class, float.class)); 481 assertEquals(callingSequence.functionDesc(), 482 FunctionDescriptor.ofVoid(ADDRESS, C_POINTER, C_INT, C_INT, C_FLOAT)); 483 484 checkArgumentBindings(callingSequence, new Binding[][]{ 485 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) }, 486 { unboxAddress(), vmStore(x10, long.class) }, 487 { vmStore(x11, int.class) }, 488 { vmStore(x12, int.class) }, 489 { vmStore(f10, float.class) } 490 }); 491 492 checkReturnBindings(callingSequence, new Binding[]{}); 493 } 494 495 @Test 496 public void testReturnStruct2() { 497 MemoryLayout struct = MemoryLayout.structLayout(C_LONG, C_LONG); 498 499 MethodType mt = MethodType.methodType(MemorySegment.class); 500 FunctionDescriptor fd = FunctionDescriptor.of(struct); 501 LinuxRISCV64CallArranger.Bindings bindings = LinuxRISCV64CallArranger.getBindings(mt, fd, false); 502 503 assertFalse(bindings.isInMemoryReturn()); 504 CallingSequence callingSequence = bindings.callingSequence(); 505 assertEquals(callingSequence.callerMethodType(), mt.insertParameterTypes(0, MemorySegment.class, MemorySegment.class)); 506 assertEquals(callingSequence.functionDesc(), fd.insertArgumentLayouts(0, ADDRESS, ADDRESS)); 507 508 checkArgumentBindings(callingSequence, new Binding[][]{ 509 { unboxAddress(), vmStore(RETURN_BUFFER_STORAGE, long.class) }, 510 { unboxAddress(), vmStore(TARGET_ADDRESS_STORAGE, long.class) } 511 }); 512 513 checkReturnBindings(callingSequence, new Binding[]{ 514 allocate(struct), 515 dup(), 516 vmLoad(x10, long.class), 517 bufferStore(0, long.class), 518 dup(), 519 vmLoad(x11, long.class), 520 bufferStore(8, long.class) 521 }); 522 } 523 }