1 /* 2 * Copyright (c) 2019, 2020, 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 package jdk.internal.foreign.abi; 24 25 import jdk.incubator.foreign.MemoryAddress; 26 import jdk.incubator.foreign.MemoryHandles; 27 import jdk.incubator.foreign.MemoryLayout; 28 import jdk.incubator.foreign.MemorySegment; 29 import jdk.incubator.foreign.NativeScope; 30 import jdk.internal.foreign.MemoryAddressImpl; 31 32 import java.lang.invoke.MethodHandle; 33 import java.lang.invoke.MethodHandles; 34 import java.lang.invoke.MethodType; 35 import java.util.ArrayList; 36 import java.util.Deque; 37 import java.util.List; 38 import java.util.Map; 39 import java.util.Objects; 40 41 import java.lang.invoke.VarHandle; 42 import java.nio.ByteOrder; 43 import java.util.concurrent.ConcurrentHashMap; 44 45 import static java.lang.invoke.MethodHandles.collectArguments; 46 import static java.lang.invoke.MethodHandles.filterArguments; 47 import static java.lang.invoke.MethodHandles.insertArguments; 48 import static java.lang.invoke.MethodHandles.permuteArguments; 49 import static java.lang.invoke.MethodType.methodType; 50 51 /** 52 * The binding operators defined in the Binding class can be combined into argument and return value processing 'recipes'. 53 * 54 * The binding operators are interpreted using a stack-base interpreter. Operators can either consume operands from the 55 * stack, or push them onto the stack. 56 * 57 * In the description of each binding we talk about 'boxing' and 'unboxing'. 58 * - Unboxing is the process of taking a Java value and decomposing it, and storing components into machine 59 * storage locations. As such, the binding interpreter stack starts with the Java value on it, and should end empty. 60 * - Boxing is the process of re-composing a Java value by pulling components from machine storage locations. 61 * If a MemorySegment is needed to store the result, one should be allocated using the ALLOCATE_BUFFER operator. 62 * The binding interpreter stack starts off empty, and ends with the value to be returned as the only value on it. 63 * A binding operator can be interpreted differently based on whether we are boxing or unboxing a value. For example, 64 * the CONVERT_ADDRESS operator 'unboxes' a MemoryAddress to a long, but 'boxes' a long to a MemoryAddress. 65 * 66 * Here are some examples of binding recipes derived from C declarations, and according to the Windows ABI (recipes are 67 * ABI-specific). Note that each argument has it's own recipe, which is indicated by '[number]:' (though, the only 68 * example that has multiple arguments is the one using varargs). 69 * 70 * -------------------- 71 * 72 * void f(int i); 73 * 74 * Argument bindings: 75 * 0: MOVE(rcx, int.class) // move an 'int' into the RCX register 76 * 77 * Return bindings: 78 * none 79 * 80 * -------------------- 81 * 82 * void f(int* i); 83 * 84 * Argument bindings: 85 * 0: CONVERT_ADDRESS // the 'MemoryAddress' is converted into a 'long' 86 * MOVE(rcx, long.class) // the 'long' is moved into the RCX register 87 * 88 * Return bindings: 89 * none 90 * 91 * -------------------- 92 * 93 * int* f(); 94 * 95 * Argument bindings: 96 * none 97 * 98 * Return bindings: 99 * 0: MOVE(rax, long) // load a 'long' from the RAX register 100 * CONVERT_ADDRESS // convert the 'long' into a 'MemoryAddress' 101 * 102 * -------------------- 103 * 104 * typedef struct { // fits into single register 105 * int x; 106 * int y; 107 * } MyStruct; 108 * 109 * void f(MyStruct ms); 110 * 111 * Argument bindings: 112 * 0: DEREFERENCE(0, long.class) // From the struct's memory region, load a 'long' from offset '0' 113 * MOVE(rcx, long.class) // and copy that into the RCX register 114 * 115 * Return bindings: 116 * none 117 * 118 * -------------------- 119 * 120 * typedef struct { // does not fit into single register 121 * long long x; 122 * long long y; 123 * } MyStruct; 124 * 125 * void f(MyStruct ms); 126 * 127 * For the Windows ABI: 128 * 129 * Argument bindings: 130 * 0: COPY(16, 8) // copy the memory region containing the struct 131 * BASE_ADDRESS // take the base address of the copy 132 * CONVERT_ADDRESS // converts the base address to a 'long' 133 * MOVE(rcx, long.class) // moves the 'long' into the RCX register 134 * 135 * Return bindings: 136 * none 137 * 138 * For the SysV ABI: 139 * 140 * Argument bindings: 141 * 0: DUP // duplicates the MemoryRegion operand 142 * DEREFERENCE(0, long.class) // loads a 'long' from offset '0' 143 * MOVE(rdx, long.class) // moves the long into the RDX register 144 * DEREFERENCE(8, long.class) // loads a 'long' from offset '8' 145 * MOVE(rcx, long.class) // moves the long into the RCX register 146 * 147 * Return bindings: 148 * none 149 * 150 * -------------------- 151 * 152 * typedef struct { // fits into single register 153 * int x; 154 * int y; 155 * } MyStruct; 156 * 157 * MyStruct f(); 158 * 159 * Argument bindings: 160 * none 161 * 162 * Return bindings: 163 * 0: ALLOCATE(GroupLayout(C_INT, C_INT)) // allocate a buffer with the memory layout of the struct 164 * DUP // duplicate the allocated buffer 165 * MOVE(rax, long.class) // loads a 'long' from rax 166 * DEREFERENCE(0, long.class) // stores a 'long' at offset 0 167 * 168 * -------------------- 169 * 170 * typedef struct { // does not fit into single register 171 * long long x; 172 * long long y; 173 * } MyStruct; 174 * 175 * MyStruct f(); 176 * 177 * !! uses synthetic argument, which is a pointer to a pre-allocated buffer 178 * 179 * Argument bindings: 180 * 0: CONVERT_ADDRESS // unbox the MemoryAddress synthetic argument 181 * MOVE(rcx, long.class) // moves the 'long' into the RCX register 182 * 183 * Return bindings: 184 * none 185 * 186 * -------------------- 187 * 188 * void f(int dummy, ...); // varargs 189 * 190 * f(0, 10f); // passing a float 191 * 192 * Argument bindings: 193 * 0: MOVE(rcx, int.class) // moves the 'int dummy' into the RCX register 194 * 195 * 1: DUP // duplicates the '10f' argument 196 * MOVE(rdx, float.class) // move one copy into the RDX register 197 * MOVE(xmm1, float.class) // moves the other copy into the xmm2 register 198 * 199 * Return bindings: 200 * none 201 * 202 * -------------------- 203 */ 204 public abstract class Binding { 205 private static final MethodHandle MH_UNBOX_ADDRESS; 206 private static final MethodHandle MH_BOX_ADDRESS; 207 private static final MethodHandle MH_BASE_ADDRESS; 208 private static final MethodHandle MH_COPY_BUFFER; 209 private static final MethodHandle MH_ALLOCATE_BUFFER; 210 211 static { 212 try { 213 MethodHandles.Lookup lookup = MethodHandles.lookup(); 214 MH_UNBOX_ADDRESS = lookup.findVirtual(MemoryAddress.class, "toRawLongValue", 215 methodType(long.class)); 216 MH_BOX_ADDRESS = lookup.findStatic(MemoryAddress.class, "ofLong", 217 methodType(MemoryAddress.class, long.class)); 218 MH_BASE_ADDRESS = lookup.findVirtual(MemorySegment.class, "baseAddress", 219 methodType(MemoryAddress.class)); 220 MH_COPY_BUFFER = lookup.findStatic(Binding.class, "copyBuffer", 221 methodType(MemorySegment.class, MemorySegment.class, long.class, long.class, NativeScope.class)); 222 MH_ALLOCATE_BUFFER = lookup.findStatic(MemorySegment.class, "allocateNative", 223 methodType(MemorySegment.class, long.class, long.class)); 224 } catch (ReflectiveOperationException e) { 225 throw new RuntimeException(e); 226 } 227 } 228 229 enum Tag { 230 MOVE, 231 DEREFERENCE, 232 COPY_BUFFER, 233 ALLOC_BUFFER, 234 CONVERT_ADDRESS, 235 BASE_ADDRESS, 236 DUP 237 } 238 239 private final Tag tag; 240 241 private Binding(Tag tag) { 242 this.tag = tag; 243 } 244 245 public Tag tag() { 246 return tag; 247 } 248 249 public abstract void verifyUnbox(Deque<Class<?>> stack); 250 public abstract void verifyBox(Deque<Class<?>> stack); 251 252 public abstract void unbox(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc, NativeScope scope); 253 public abstract void box(Deque<Object> stack, BindingInterpreter.LoadFunc loadFunc); 254 255 public abstract MethodHandle specializeUnbox(MethodHandle specializedHandle, int insertPos); 256 public abstract MethodHandle specializeBox(MethodHandle returnFilter); 257 258 private static MethodHandle mergeArguments(MethodHandle mh, int sourceIndex, int destIndex) { 259 MethodType oldType = mh.type(); 260 Class<?> sourceType = oldType.parameterType(sourceIndex); 261 Class<?> destType = oldType.parameterType(destIndex); 262 if (sourceType != destType) { 263 // TODO meet? 264 throw new IllegalArgumentException("Parameter types differ: " + sourceType + " != " + destType); 265 } 266 MethodType newType = oldType.dropParameterTypes(destIndex, destIndex + 1); 267 int[] reorder = new int[oldType.parameterCount()]; 268 assert destIndex > sourceIndex; 269 for (int i = 0, index = 0; i < reorder.length; i++) { 270 if (i != destIndex) { 271 reorder[i] = index++; 272 } else { 273 reorder[i] = sourceIndex; 274 } 275 } 276 return permuteArguments(mh, newType, reorder); 277 } 278 279 private static void checkType(Class<?> type) { 280 if (!type.isPrimitive() || type == void.class || type == boolean.class) 281 throw new IllegalArgumentException("Illegal type: " + type); 282 } 283 284 private static MemorySegment copyBuffer(MemorySegment operand, long size, long alignment, NativeScope allocator) { 285 MemorySegment copy = allocator.allocate(size, alignment).segment(); 286 copy.copyFrom(operand.asSlice(0, size)); 287 return copy; 288 } 289 290 public static Move move(VMStorage storage, Class<?> type) { 291 checkType(type); 292 return new Move(storage, type); 293 } 294 295 public static Dereference dereference(long offset, Class<?> type) { 296 checkType(type); 297 if (offset < 0) 298 throw new IllegalArgumentException("Negative offset: " + offset); 299 return new Dereference(offset, type); 300 } 301 302 public static Copy copy(MemoryLayout layout) { 303 return new Copy(layout.byteSize(), layout.byteAlignment()); 304 } 305 306 public static Allocate allocate(MemoryLayout layout) { 307 return new Allocate(layout.byteSize(), layout.byteAlignment()); 308 } 309 310 public static ConvertAddress convertAddress() { 311 return ConvertAddress.INSTANCE; 312 } 313 314 public static BaseAddress baseAddress() { 315 return BaseAddress.INSTANCE; 316 } 317 318 public static Dup dup() { 319 return Dup.INSTANCE; 320 } 321 322 323 public static Binding.Builder builder() { 324 return new Binding.Builder(); 325 } 326 327 /** 328 * A builder helper class for generating lists of Bindings 329 */ 330 public static class Builder { 331 private final List<Binding> bindings = new ArrayList<>(); 332 333 public Binding.Builder move(VMStorage storage, Class<?> type) { 334 bindings.add(Binding.move(storage, type)); 335 return this; 336 } 337 338 public Binding.Builder dereference(long offset, Class<?> type) { 339 bindings.add(Binding.dereference(offset, type)); 340 return this; 341 } 342 343 public Binding.Builder copy(MemoryLayout layout) { 344 bindings.add(Binding.copy(layout)); 345 return this; 346 } 347 348 public Binding.Builder allocate(MemoryLayout layout) { 349 bindings.add(Binding.allocate(layout)); 350 return this; 351 } 352 353 public Binding.Builder convertAddress() { 354 bindings.add(Binding.convertAddress()); 355 return this; 356 } 357 358 public Binding.Builder baseAddress() { 359 bindings.add(Binding.baseAddress()); 360 return this; 361 } 362 363 public Binding.Builder dup() { 364 bindings.add(Binding.dup()); 365 return this; 366 } 367 368 public List<Binding> build() { 369 return new ArrayList<>(bindings); 370 } 371 } 372 373 /** 374 * MOVE([storage location], [type]) 375 * When unboxing: pops a [type] from the operand stack, and moves it to [storage location] 376 * When boxing: loads a [type] from [storage location], and pushes it onto the operand stack 377 * The [type] must be one of byte, short, char, int, long, float, or double 378 */ 379 public static class Move extends Binding { 380 private final VMStorage storage; 381 private final Class<?> type; 382 383 private Move(VMStorage storage, Class<?> type) { 384 super(Tag.MOVE); 385 this.storage = storage; 386 this.type = type; 387 } 388 389 public VMStorage storage() { 390 return storage; 391 } 392 393 public Class<?> type() { 394 return type; 395 } 396 397 @Override 398 public String toString() { 399 return "Move{" + 400 "tag=" + tag() + 401 ", storage=" + storage + 402 ", type=" + type + 403 '}'; 404 } 405 406 @Override 407 public boolean equals(Object o) { 408 if (this == o) return true; 409 if (o == null || getClass() != o.getClass()) return false; 410 Move move = (Move) o; 411 return storage.equals(move.storage) && 412 type.equals(move.type); 413 } 414 415 @Override 416 public int hashCode() { 417 return Objects.hash(tag(), storage, type); 418 } 419 420 @Override 421 public void verifyUnbox(Deque<Class<?>> stack) { 422 Class<?> actualType = stack.pop(); 423 Class<?> expectedType = type; 424 SharedUtils.checkType(actualType, expectedType); 425 } 426 427 @Override 428 public void verifyBox(Deque<Class<?>> stack) { 429 stack.push(type); 430 } 431 432 @Override 433 public void unbox(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc, NativeScope scope) { 434 storeFunc.store(storage, type, stack.pop()); 435 } 436 437 @Override 438 public void box(Deque<Object> stack, BindingInterpreter.LoadFunc loadFunc) { 439 stack.push(loadFunc.load(storage, type)); 440 } 441 442 @Override 443 public MethodHandle specializeUnbox(MethodHandle specializedHandle, int insertPos) { 444 return specializedHandle; // no-op 445 } 446 447 @Override 448 public MethodHandle specializeBox(MethodHandle returnFilter) { 449 return returnFilter; // no-op 450 } 451 } 452 453 /** 454 * DEREFERENCE([offset into memory region], [type]) 455 * When unboxing: pops a MemorySegment from the operand stack, 456 * loads a [type] from [offset into memory region] from it, and pushes it onto the operand stack 457 * When boxing: pops a [type], and then a MemorySegment from the operand stack, 458 * and then stores [type] to [offset into memory region] of the MemorySegment 459 * The [type] must be one of byte, short, char, int, long, float, or double 460 */ 461 public static class Dereference extends Binding { 462 private final long offset; 463 private final Class<?> type; 464 465 private Dereference(long offset, Class<?> type) { 466 super(Tag.DEREFERENCE); 467 this.offset = offset; 468 this.type = type; 469 } 470 471 public long offset() { 472 return offset; 473 } 474 475 public Class<?> type() { 476 return type; 477 } 478 479 @Override 480 public String toString() { 481 return "Dereference{" + 482 "tag=" + tag() + 483 ", offset=" + offset + 484 ", type=" + type + 485 '}'; 486 } 487 488 @Override 489 public boolean equals(Object o) { 490 if (this == o) return true; 491 if (o == null || getClass() != o.getClass()) return false; 492 Dereference that = (Dereference) o; 493 return offset == that.offset && 494 type.equals(that.type); 495 } 496 497 @Override 498 public int hashCode() { 499 return Objects.hash(tag(), offset, type); 500 } 501 502 @Override 503 public void verifyUnbox(Deque<Class<?>> stack) { 504 Class<?> actualType = stack.pop(); 505 SharedUtils.checkType(actualType, MemorySegment.class); 506 Class<?> newType = type; 507 stack.push(newType); 508 } 509 510 @Override 511 public void verifyBox(Deque<Class<?>> stack) { 512 Class<?> storeType = stack.pop(); 513 SharedUtils.checkType(storeType, type); 514 Class<?> segmentType = stack.pop(); 515 SharedUtils.checkType(segmentType, MemorySegment.class); 516 } 517 518 @Override 519 public void unbox(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc, NativeScope scope) { 520 MemorySegment operand = (MemorySegment) stack.pop(); 521 MemoryAddress baseAddress = operand.baseAddress(); 522 MemoryAddress readAddress = baseAddress.addOffset(offset); 523 stack.push(SharedUtils.read(readAddress, type)); 524 } 525 526 @Override 527 public void box(Deque<Object> stack, BindingInterpreter.LoadFunc loadFunc) { 528 Object value = stack.pop(); 529 MemorySegment operand = (MemorySegment) stack.pop(); 530 MemoryAddress baseAddress = operand.baseAddress(); 531 MemoryAddress writeAddress = baseAddress.addOffset(offset); 532 SharedUtils.write(writeAddress, type, value); 533 } 534 535 private VarHandle varHandle() { 536 return MemoryHandles.withOffset(MemoryHandles.varHandle(type, ByteOrder.nativeOrder()), offset); 537 } 538 539 @Override 540 public MethodHandle specializeUnbox(MethodHandle specializedHandle, int insertPos) { 541 MethodHandle filter = filterArguments( 542 varHandle() 543 .toMethodHandle(VarHandle.AccessMode.GET) 544 .asType(methodType(type, MemoryAddress.class)), 0, MH_BASE_ADDRESS); 545 return filterArguments(specializedHandle, insertPos, filter); 546 } 547 548 @Override 549 public MethodHandle specializeBox(MethodHandle returnFilter) { 550 MethodHandle setter = varHandle().toMethodHandle(VarHandle.AccessMode.SET); 551 setter = filterArguments( 552 setter.asType(methodType(void.class, MemoryAddress.class, type)), 553 0, MH_BASE_ADDRESS); 554 return collectArguments(returnFilter, returnFilter.type().parameterCount(), setter); 555 } 556 } 557 558 /** 559 * COPY([size], [alignment]) 560 * Creates a new MemorySegment with the given [size] and [alignment], 561 * and copies contents from a MemorySegment popped from the top of the operand stack into this new buffer, 562 * and pushes the new buffer onto the operand stack 563 */ 564 public static class Copy extends Binding { 565 private final long size; 566 private final long alignment; 567 568 private Copy(long size, long alignment) { 569 super(Tag.COPY_BUFFER); 570 this.size = size; 571 this.alignment = alignment; 572 } 573 574 public long size() { 575 return size; 576 } 577 578 public long alignment() { 579 return alignment; 580 } 581 582 @Override 583 public String toString() { 584 return "Copy{" + 585 "tag=" + tag() + 586 ", size=" + size + 587 ", alignment=" + alignment + 588 '}'; 589 } 590 591 @Override 592 public boolean equals(Object o) { 593 if (this == o) return true; 594 if (o == null || getClass() != o.getClass()) return false; 595 Copy copy = (Copy) o; 596 return size == copy.size && 597 alignment == copy.alignment; 598 } 599 600 @Override 601 public int hashCode() { 602 return Objects.hash(tag(), size, alignment); 603 } 604 605 @Override 606 public void verifyUnbox(Deque<Class<?>> stack) { 607 Class<?> actualType = stack.pop(); 608 SharedUtils.checkType(actualType, MemorySegment.class); 609 stack.push(MemorySegment.class); 610 } 611 612 @Override 613 public void verifyBox(Deque<Class<?>> stack) { 614 Class<?> actualType = stack.pop(); 615 SharedUtils.checkType(actualType, MemoryAddress.class); 616 stack.push(MemorySegment.class); 617 } 618 619 @Override 620 public void unbox(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc, NativeScope scope) { 621 MemorySegment operand = (MemorySegment) stack.pop(); 622 MemorySegment copy = scope.allocate(size, alignment).segment(); 623 copy.copyFrom(operand.asSlice(0, size)); 624 stack.push(copy); 625 } 626 627 @Override 628 public void box(Deque<Object> stack, BindingInterpreter.LoadFunc loadFunc) { 629 MemoryAddress operand = (MemoryAddress) stack.pop(); 630 operand = MemoryAddressImpl.ofLongUnchecked(operand.toRawLongValue(), size); 631 MemorySegment copy = MemorySegment.allocateNative(size, alignment); 632 copy.copyFrom(operand.segment().asSlice(0, size)); 633 stack.push(copy); // leaked 634 } 635 636 @Override 637 public MethodHandle specializeUnbox(MethodHandle specializedHandle, int insertPos) { 638 MethodHandle filter = insertArguments(MH_COPY_BUFFER, 1, size, alignment); 639 specializedHandle = collectArguments(specializedHandle, insertPos, filter); 640 return mergeArguments(specializedHandle, 0, insertPos + 1); 641 } 642 643 @Override 644 public MethodHandle specializeBox(MethodHandle returnFilter) { 645 throw new UnsupportedOperationException(); 646 } 647 } 648 649 /** 650 * ALLOCATE([size], [alignment]) 651 * Creates a new MemorySegment with the give [size] and [alignment], and pushes it onto the operand stack. 652 */ 653 public static class Allocate extends Binding { 654 private final long size; 655 private final long alignment; 656 657 private Allocate(long size, long alignment) { 658 super(Tag.ALLOC_BUFFER); 659 this.size = size; 660 this.alignment = alignment; 661 } 662 663 public long size() { 664 return size; 665 } 666 667 public long alignment() { 668 return alignment; 669 } 670 671 @Override 672 public String toString() { 673 return "AllocateBuffer{" + 674 "tag=" + tag() + 675 "size=" + size + 676 ", alignment=" + alignment + 677 '}'; 678 } 679 680 @Override 681 public boolean equals(Object o) { 682 if (this == o) return true; 683 if (o == null || getClass() != o.getClass()) return false; 684 Allocate that = (Allocate) o; 685 return size == that.size && 686 alignment == that.alignment; 687 } 688 689 @Override 690 public int hashCode() { 691 return Objects.hash(tag(), size, alignment); 692 } 693 694 @Override 695 public void verifyUnbox(Deque<Class<?>> stack) { 696 throw new UnsupportedOperationException(); 697 } 698 699 @Override 700 public void verifyBox(Deque<Class<?>> stack) { 701 stack.push(MemorySegment.class); 702 } 703 704 @Override 705 public void unbox(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc, NativeScope scope) { 706 throw new UnsupportedOperationException(); 707 } 708 709 @Override 710 public void box(Deque<Object> stack, BindingInterpreter.LoadFunc loadFunc) { 711 stack.push(MemorySegment.allocateNative(size, alignment)); 712 } 713 714 @Override 715 public MethodHandle specializeUnbox(MethodHandle specializedHandle, int insertPos) { 716 throw new UnsupportedOperationException(); 717 } 718 719 @Override 720 public MethodHandle specializeBox(MethodHandle returnFilter) { 721 return collectArguments(returnFilter, 0, insertArguments(MH_ALLOCATE_BUFFER, 0, size, alignment)); 722 } 723 } 724 725 /** 726 * CONVERT_ADDRESS() 727 * When unboxing: pops a 'MemoryAddress' from the operand stack, converts it to a 'long', 728 * and pushes that onto the operand stack 729 * When boxing: pops a 'long' from the operand stack, converts it to a 'MemoryAddress', 730 * and pushes that onto the operand stack 731 */ 732 public static class ConvertAddress extends Binding { 733 private static final ConvertAddress INSTANCE = new ConvertAddress(); 734 private ConvertAddress() { 735 super(Tag.CONVERT_ADDRESS); 736 } 737 738 @Override 739 public String toString() { 740 return "BoxAddress{" + 741 "tag=" + tag() + 742 "}"; 743 } 744 745 @Override 746 public int hashCode() { 747 return tag().hashCode(); 748 } 749 750 @Override 751 public boolean equals(Object o) { 752 if (this == o) return true; 753 return o != null && getClass() == o.getClass(); 754 } 755 756 @Override 757 public void verifyUnbox(Deque<Class<?>> stack) { 758 Class<?> actualType = stack.pop(); 759 SharedUtils.checkType(actualType, MemoryAddress.class); 760 stack.push(long.class); 761 } 762 763 @Override 764 public void verifyBox(Deque<Class<?>> stack) { 765 Class<?> actualType = stack.pop(); 766 SharedUtils.checkType(actualType, long.class); 767 stack.push(MemoryAddress.class); 768 } 769 770 @Override 771 public void unbox(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc, NativeScope scope) { 772 stack.push(((MemoryAddress) stack.pop()).toRawLongValue()); 773 } 774 775 @Override 776 public void box(Deque<Object> stack, BindingInterpreter.LoadFunc loadFunc) { 777 stack.push(MemoryAddress.ofLong((long) stack.pop())); 778 } 779 780 @Override 781 public MethodHandle specializeUnbox(MethodHandle specializedHandle, int insertPos) { 782 return filterArguments(specializedHandle, insertPos, MH_UNBOX_ADDRESS); 783 } 784 785 @Override 786 public MethodHandle specializeBox(MethodHandle returnFilter) { 787 return filterArguments(returnFilter, 0, MH_BOX_ADDRESS); 788 } 789 } 790 791 /** 792 * BASE_ADDRESS() 793 * Pops a MemorySegment from the operand stack, and takes the base address of the segment 794 * (the MemoryAddress that points to the start), and pushes that onto the operand stack 795 */ 796 public static class BaseAddress extends Binding { 797 private static final BaseAddress INSTANCE = new BaseAddress(); 798 private BaseAddress() { 799 super(Tag.BASE_ADDRESS); 800 } 801 802 @Override 803 public String toString() { 804 return "BaseAddress{" + 805 "tag=" + tag() + 806 "}"; 807 } 808 809 @Override 810 public int hashCode() { 811 return tag().hashCode(); 812 } 813 814 @Override 815 public boolean equals(Object o) { 816 if (this == o) return true; 817 return o != null && getClass() == o.getClass(); 818 } 819 820 @Override 821 public void verifyUnbox(Deque<Class<?>> stack) { 822 Class<?> actualType = stack.pop(); 823 SharedUtils.checkType(actualType, MemorySegment.class); 824 stack.push(MemoryAddress.class); 825 } 826 827 @Override 828 public void verifyBox(Deque<Class<?>> stack) { 829 Class<?> actualType = stack.pop(); 830 SharedUtils.checkType(actualType, MemorySegment.class); 831 stack.push(MemoryAddress.class); 832 } 833 834 @Override 835 public void unbox(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc, NativeScope scope) { 836 stack.push(((MemorySegment) stack.pop()).baseAddress()); 837 } 838 839 @Override 840 public void box(Deque<Object> stack, BindingInterpreter.LoadFunc loadFunc) { 841 stack.push(((MemorySegment) stack.pop()).baseAddress()); 842 } 843 844 @Override 845 public MethodHandle specializeUnbox(MethodHandle specializedHandle, int insertPos) { 846 return filterArguments(specializedHandle, insertPos, MH_BASE_ADDRESS); 847 } 848 849 @Override 850 public MethodHandle specializeBox(MethodHandle returnFilter) { 851 throw new UnsupportedOperationException(); 852 } 853 } 854 855 /** 856 * DUP() 857 * Duplicates the value on the top of the operand stack (without popping it!), 858 * and pushes the duplicate onto the operand stack 859 */ 860 public static class Dup extends Binding { 861 private static final Dup INSTANCE = new Dup(); 862 private Dup() { 863 super(Tag.DUP); 864 } 865 866 @Override 867 public String toString() { 868 return "Dup{" + 869 "tag=" + tag() + 870 "}"; 871 } 872 873 @Override 874 public int hashCode() { 875 return tag().hashCode(); 876 } 877 878 @Override 879 public boolean equals(Object o) { 880 if (this == o) return true; 881 return o != null && getClass() == o.getClass(); 882 } 883 884 @Override 885 public void verifyUnbox(Deque<Class<?>> stack) { 886 stack.push(stack.peekLast()); 887 } 888 889 @Override 890 public void verifyBox(Deque<Class<?>> stack) { 891 stack.push(stack.peekLast()); 892 } 893 894 @Override 895 public void unbox(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc, NativeScope scope) { 896 stack.push(stack.peekLast()); 897 } 898 899 @Override 900 public void box(Deque<Object> stack, BindingInterpreter.LoadFunc loadFunc) { 901 stack.push(stack.peekLast()); 902 } 903 904 /* 905 * Fixes up Y-shaped data graphs (produced by DEREFERENCE): 906 * 907 * 1. DUP() 908 * 2. DEREFERENCE(0, int.class) 909 * 3. MOVE (ignored) 910 * 4. DEREFERENCE(4, int.class) 911 * 5. MOVE (ignored) 912 * 913 * (specialized in reverse!) 914 * 915 * 5. (int, int) -> void insertPos = 1 916 * 4. (MemorySegment, int) -> void insertPos = 1 917 * 3. (MemorySegment, int) -> void insertPos = 0 918 * 2. (MemorySegment, MemorySegment) -> void insertPos = 0 919 * 1. (MemorySegment) -> void insertPos = 0 920 * 921 */ 922 @Override 923 public MethodHandle specializeUnbox(MethodHandle specializedHandle, int insertPos) { 924 return mergeArguments(specializedHandle, insertPos, insertPos + 1); 925 } 926 927 /* 928 * Fixes up Y-shaped data graphs (produced by DEREFERENCE): 929 * 930 * 1. ALLOCATE_BUFFER(4, 4) 931 * 2. DUP 932 * 3. MOVE (ignored) 933 * 4. DEREFERNCE(0, int.class) 934 * 935 * (specialized in reverse!) 936 * 937 * input: (MemorySegment) -> MemorySegment (identity function of high-level return) 938 * 4. (MemorySegment, MemorySegment, int) -> MemorySegment 939 * 3. (MemorySegment, MemorySegment, int) -> MemorySegment 940 * 2. (MemorySegment, int) -> MemorySegment 941 * 1. (int) -> MemorySegment 942 * 943 */ 944 @Override 945 public MethodHandle specializeBox(MethodHandle returnFilter) { 946 // assumes shape like: (MS, ..., MS, T) R 947 return mergeArguments(returnFilter, 0, returnFilter.type().parameterCount() - 2); 948 } 949 } 950 }