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