< prev index next >

src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/abi/Binding.java

Print this page

   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  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 package jdk.internal.foreign.abi;
  26 

  27 import jdk.incubator.foreign.MemoryAddress;
  28 import jdk.incubator.foreign.MemoryHandles;
  29 import jdk.incubator.foreign.MemoryLayout;
  30 import jdk.incubator.foreign.MemorySegment;
  31 import jdk.incubator.foreign.ResourceScope;
  32 import jdk.incubator.foreign.SegmentAllocator;

  33 import jdk.internal.foreign.MemoryAddressImpl;
  34 import jdk.internal.foreign.ResourceScopeImpl;
  35 
  36 import java.lang.invoke.MethodHandle;
  37 import java.lang.invoke.MethodHandles;

  38 import java.util.ArrayList;
  39 import java.util.Deque;
  40 import java.util.List;
  41 import java.util.Objects;
  42 
  43 import java.lang.invoke.VarHandle;
  44 import java.nio.ByteOrder;
  45 
  46 import static java.lang.invoke.MethodHandles.collectArguments;
  47 import static java.lang.invoke.MethodHandles.filterArguments;
  48 import static java.lang.invoke.MethodHandles.insertArguments;
  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'.

 187  *
 188  * void f(int dummy, ...); // varargs
 189  *
 190  * f(0, 10f); // passing a float
 191  *
 192  * Argument bindings:
 193  * 0: VM_STORE(rcx, int.class) // moves the 'int dummy' into the RCX register
 194  *
 195  * 1: DUP // duplicates the '10f' argument
 196  *    VM_STORE(rdx, float.class) // move one copy into the RDX register
 197  *    VM_STORE(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     private static final MethodHandle MH_TO_SEGMENT;
 211 
 212     static {
 213         try {
 214             MethodHandles.Lookup lookup = MethodHandles.lookup();
 215             MH_UNBOX_ADDRESS = lookup.findVirtual(MemoryAddress.class, "toRawLongValue",
 216                     methodType(long.class));
 217             MH_BOX_ADDRESS = lookup.findStatic(MemoryAddress.class, "ofLong",
 218                     methodType(MemoryAddress.class, long.class));
 219             MH_BASE_ADDRESS = lookup.findVirtual(MemorySegment.class, "address",
 220                     methodType(MemoryAddress.class));
 221             MH_COPY_BUFFER = lookup.findStatic(Binding.Copy.class, "copyBuffer",
 222                     methodType(MemorySegment.class, MemorySegment.class, long.class, long.class, Context.class));
 223             MH_ALLOCATE_BUFFER = lookup.findStatic(Binding.Allocate.class, "allocateBuffer",
 224                     methodType(MemorySegment.class, long.class, long.class, Context.class));
 225             MH_TO_SEGMENT = lookup.findStatic(Binding.ToSegment.class, "toSegment",
 226                     methodType(MemorySegment.class, MemoryAddress.class, long.class, Context.class));
 227         } catch (ReflectiveOperationException e) {
 228             throw new RuntimeException(e);
 229         }
 230     }
 231 
 232     /**
 233      * A binding context is used as an helper to carry out evaluation of certain bindings; for instance,
 234      * it helps {@link Allocate} bindings, by providing the {@link SegmentAllocator} that should be used for
 235      * the allocation operation, or {@link ToSegment} bindings, by providing the {@link ResourceScope} that
 236      * should be used to create an unsafe struct from a memory address.
 237      */
 238     public static class Context implements AutoCloseable {
 239         private final SegmentAllocator allocator;
 240         private final ResourceScope scope;

 245         }
 246 
 247         public SegmentAllocator allocator() {
 248             return allocator;
 249         }
 250 
 251         public ResourceScope scope() {
 252             return scope;
 253         }
 254 
 255         @Override
 256         public void close() {
 257             scope().close();
 258         }
 259 
 260         /**
 261          * Create a binding context from given native scope.
 262          */
 263         public static Context ofBoundedAllocator(long size) {
 264             ResourceScope scope = ResourceScope.newConfinedScope();
 265             return new Context(SegmentAllocator.arenaAllocator(size, scope), scope);
 266         }
 267 
 268         /**
 269          * Create a binding context from given segment allocator. The resulting context will throw when
 270          * the context's scope is accessed.
 271          */
 272         public static Context ofAllocator(SegmentAllocator allocator) {
 273             return new Context(allocator, null) {
 274                 @Override
 275                 public ResourceScope scope() {
 276                     throw new UnsupportedOperationException();
 277                 }
 278             };
 279         }
 280 
 281         /**
 282          * Create a binding context from given scope. The resulting context will throw when
 283          * the context's allocator is accessed.
 284          */
 285         public static Context ofScope() {

 304             public ResourceScope scope() {
 305                 throw new UnsupportedOperationException();
 306             }
 307 
 308             @Override
 309             public void close() {
 310                 // do nothing
 311             }
 312         };
 313     }
 314 
 315     enum Tag {
 316         VM_STORE,
 317         VM_LOAD,
 318         BUFFER_STORE,
 319         BUFFER_LOAD,
 320         COPY_BUFFER,
 321         ALLOC_BUFFER,
 322         BOX_ADDRESS,
 323         UNBOX_ADDRESS,
 324         BASE_ADDRESS,
 325         TO_SEGMENT,
 326         DUP
 327     }
 328 
 329     private final Tag tag;
 330 
 331     private Binding(Tag tag) {
 332         this.tag = tag;
 333     }
 334 
 335     public Tag tag() {
 336         return tag;
 337     }
 338 
 339     public abstract void verify(Deque<Class<?>> stack);
 340 
 341     public abstract void interpret(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc,
 342                                    BindingInterpreter.LoadFunc loadFunc, Context context);
 343 
 344     public abstract MethodHandle specialize(MethodHandle specializedHandle, int insertPos, int allocatorPos);
 345 
 346     private static void checkType(Class<?> type) {
 347         if (!type.isPrimitive() || type == void.class || type == boolean.class)
 348             throw new IllegalArgumentException("Illegal type: " + type);
 349     }
 350 
 351     private static void checkOffset(long offset) {
 352         if (offset < 0)
 353             throw new IllegalArgumentException("Negative offset: " + offset);
 354     }
 355 
 356     public static VMStore vmStore(VMStorage storage, Class<?> type) {
 357         checkType(type);
 358         return new VMStore(storage, type);
 359     }
 360 
 361     public static VMLoad vmLoad(VMStorage storage, Class<?> type) {
 362         checkType(type);
 363         return new VMLoad(storage, type);
 364     }
 365 
 366     public static BufferStore bufferStore(long offset, Class<?> type) {
 367         checkType(type);

 371 
 372     public static BufferLoad bufferLoad(long offset, Class<?> type) {
 373         checkType(type);
 374         checkOffset(offset);
 375         return new BufferLoad(offset, type);
 376     }
 377 
 378     public static Copy copy(MemoryLayout layout) {
 379         return new Copy(layout.byteSize(), layout.byteAlignment());
 380     }
 381 
 382     public static Allocate allocate(MemoryLayout layout) {
 383         return new Allocate(layout.byteSize(), layout.byteAlignment());
 384     }
 385 
 386     public static BoxAddress boxAddress() {
 387         return BoxAddress.INSTANCE;
 388     }
 389 
 390     public static UnboxAddress unboxAddress() {
 391         return UnboxAddress.INSTANCE;
 392     }
 393 
 394     public static BaseAddress baseAddress() {
 395         return BaseAddress.INSTANCE;
 396     }
 397 
 398     public static ToSegment toSegment(MemoryLayout layout) {
 399         return new ToSegment(layout.byteSize());
 400     }
 401 
 402     public static Dup dup() {
 403         return Dup.INSTANCE;
 404     }
 405 
 406 
 407     public static Binding.Builder builder() {
 408         return new Binding.Builder();
 409     }
 410 
 411     @Override
 412     public boolean equals(Object o) {
 413         if (this == o) return true;
 414         if (o == null || getClass() != o.getClass()) return false;
 415         Binding binding = (Binding) o;

 450         public Binding.Builder copy(MemoryLayout layout) {
 451             bindings.add(Binding.copy(layout));
 452             return this;
 453         }
 454 
 455         public Binding.Builder allocate(MemoryLayout layout) {
 456             bindings.add(Binding.allocate(layout));
 457             return this;
 458         }
 459 
 460         public Binding.Builder boxAddress() {
 461             bindings.add(Binding.boxAddress());
 462             return this;
 463         }
 464 
 465         public Binding.Builder unboxAddress() {
 466             bindings.add(Binding.unboxAddress());
 467             return this;
 468         }
 469 
 470         public Binding.Builder baseAddress() {
 471             bindings.add(Binding.baseAddress());
 472             return this;
 473         }
 474 
 475         public Binding.Builder toSegment(MemoryLayout layout) {
 476             bindings.add(Binding.toSegment(layout));
 477             return this;
 478         }
 479 
 480         public Binding.Builder dup() {
 481             bindings.add(Binding.dup());
 482             return this;
 483         }
 484 
 485         public List<Binding> build() {
 486             return new ArrayList<>(bindings);
 487         }
 488     }
 489 
 490     static abstract class Move extends Binding {
 491         private final VMStorage storage;

 613 
 614         @Override
 615         public boolean equals(Object o) {
 616             if (this == o) return true;
 617             if (o == null || getClass() != o.getClass()) return false;
 618             if (!super.equals(o)) return false;
 619             Dereference that = (Dereference) o;
 620             return offset == that.offset &&
 621                     Objects.equals(type, that.type);
 622         }
 623 
 624         @Override
 625         public int hashCode() {
 626             return Objects.hash(super.hashCode(), offset, type);
 627         }
 628 
 629         public VarHandle varHandle() {
 630             // alignment is set to 1 byte here to avoid exceptions for cases where we do super word
 631             // copies of e.g. 2 int fields of a struct as a single long, while the struct is only
 632             // 4-byte-aligned (since it only contains ints)
 633             return MemoryHandles.insertCoordinates(MemoryHandles.varHandle(type, 1, ByteOrder.nativeOrder()), 1, offset);

 634         }
 635     }
 636 
 637     /**
 638      * BUFFER_STORE([offset into memory region], [type])
 639      * Pops a MemorySegment from the operand stack, loads a [type] from
 640      * [offset into memory region] from it, and pushes it onto the operand stack.
 641      * The [type] must be one of byte, short, char, int, long, float, or double
 642      */
 643     public static class BufferStore extends Dereference {
 644         private BufferStore(long offset, Class<?> type) {
 645             super(Tag.BUFFER_STORE, offset, type);
 646         }
 647 
 648         @Override
 649         public void verify(Deque<Class<?>> stack) {
 650             Class<?> storeType = stack.pop();
 651             SharedUtils.checkType(storeType, type());
 652             Class<?> segmentType = stack.pop();
 653             SharedUtils.checkType(segmentType, MemorySegment.class);

 723     }
 724 
 725     /**
 726      * COPY([size], [alignment])
 727      *   Creates a new MemorySegment with the given [size] and [alignment],
 728      *     and copies contents from a MemorySegment popped from the top of the operand stack into this new buffer,
 729      *     and pushes the new buffer onto the operand stack
 730      */
 731     public static class Copy extends Binding {
 732         private final long size;
 733         private final long alignment;
 734 
 735         private Copy(long size, long alignment) {
 736             super(Tag.COPY_BUFFER);
 737             this.size = size;
 738             this.alignment = alignment;
 739         }
 740 
 741         private static MemorySegment copyBuffer(MemorySegment operand, long size, long alignment,
 742                                                     Context context) {
 743             MemorySegment copy = context.allocator().allocate(size, alignment);
 744             copy.copyFrom(operand.asSlice(0, size));
 745             return copy;
 746         }
 747 
 748         public long size() {
 749             return size;
 750         }
 751 
 752         public long alignment() {
 753             return alignment;
 754         }
 755 
 756         @Override
 757         public String toString() {
 758             return "Copy{" +
 759                     "tag=" + tag() +
 760                     ", size=" + size +
 761                     ", alignment=" + alignment +
 762                     '}';
 763         }
 764 
 765         @Override

 858             if (this == o) return true;
 859             if (o == null || getClass() != o.getClass()) return false;
 860             if (!super.equals(o)) return false;
 861             Allocate allocate = (Allocate) o;
 862             return size == allocate.size &&
 863                     alignment == allocate.alignment;
 864         }
 865 
 866         @Override
 867         public int hashCode() {
 868             return Objects.hash(super.hashCode(), size, alignment);
 869         }
 870     }
 871 
 872     /**
 873      * UNBOX_ADDRESS()
 874      * Pops a 'MemoryAddress' from the operand stack, converts it to a 'long',
 875      *     and pushes that onto the operand stack.
 876      */
 877     public static class UnboxAddress extends Binding {
 878         private static final UnboxAddress INSTANCE = new UnboxAddress();
 879         private UnboxAddress() {










 880             super(Tag.UNBOX_ADDRESS);






 881         }
 882 
 883         @Override
 884         public void verify(Deque<Class<?>> stack) {
 885             Class<?> actualType = stack.pop();
 886             SharedUtils.checkType(actualType, MemoryAddress.class);
 887             stack.push(long.class);
 888         }
 889 
 890         @Override
 891         public void interpret(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc,
 892                               BindingInterpreter.LoadFunc loadFunc, Context context) {
 893             stack.push(((MemoryAddress)stack.pop()).toRawLongValue());
 894         }
 895 
 896         @Override
 897         public MethodHandle specialize(MethodHandle specializedHandle, int insertPos, int allocatorPos) {
 898             return filterArguments(specializedHandle, insertPos, MH_UNBOX_ADDRESS);

 899         }
 900 
 901         @Override
 902         public String toString() {
 903             return "UnboxAddress{}";
 904         }
 905     }
 906 
 907     /**
 908      * BOX_ADDRESS()
 909      * Pops a 'long' from the operand stack, converts it to a 'MemoryAddress',
 910      *     and pushes that onto the operand stack.
 911      */
 912     public static class BoxAddress extends Binding {
 913         private static final BoxAddress INSTANCE = new BoxAddress();
 914         private BoxAddress() {
 915             super(Tag.BOX_ADDRESS);
 916         }
 917 
 918         @Override

 922             stack.push(MemoryAddress.class);
 923         }
 924 
 925         @Override
 926         public void interpret(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc,
 927                               BindingInterpreter.LoadFunc loadFunc, Context context) {
 928             stack.push(MemoryAddress.ofLong((long) stack.pop()));
 929         }
 930 
 931         @Override
 932         public MethodHandle specialize(MethodHandle specializedHandle, int insertPos, int allocatorPos) {
 933             return filterArguments(specializedHandle, insertPos, MH_BOX_ADDRESS);
 934         }
 935 
 936         @Override
 937         public String toString() {
 938             return "BoxAddress{}";
 939         }
 940     }
 941 
 942     /**
 943      * BASE_ADDRESS()
 944      *   Pops a MemorySegment from the operand stack, and takes the base address of the segment
 945      *   (the MemoryAddress that points to the start), and pushes that onto the operand stack
 946      */
 947     public static class BaseAddress extends Binding {
 948         private static final BaseAddress INSTANCE = new BaseAddress();
 949         private BaseAddress() {
 950             super(Tag.BASE_ADDRESS);
 951         }
 952 
 953         @Override
 954         public void verify(Deque<Class<?>> stack) {
 955             Class<?> actualType = stack.pop();
 956             SharedUtils.checkType(actualType, MemorySegment.class);
 957             stack.push(MemoryAddress.class);
 958         }
 959 
 960         @Override
 961         public void interpret(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc,
 962                               BindingInterpreter.LoadFunc loadFunc, Context context) {
 963             stack.push(((MemorySegment) stack.pop()).address());
 964         }
 965 
 966         @Override
 967         public MethodHandle specialize(MethodHandle specializedHandle, int insertPos, int allocatorPos) {
 968             return filterArguments(specializedHandle, insertPos, MH_BASE_ADDRESS);
 969         }
 970 
 971         @Override
 972         public String toString() {
 973             return "BaseAddress{}";
 974         }
 975     }
 976 
 977     /**
 978      * TO_SEGMENT([size])
 979      *   Pops a MemoryAddress from the operand stack, and converts it to a MemorySegment
 980      *   with the given size, and pushes that onto the operand stack
 981      */
 982     public static class ToSegment extends Binding {
 983         private final long size;
 984         // FIXME alignment?
 985 
 986         public ToSegment(long size) {
 987             super(Tag.TO_SEGMENT);
 988             this.size = size;
 989         }
 990 
 991         private static MemorySegment toSegment(MemoryAddress operand, long size, Context context) {
 992             return MemoryAddressImpl.ofLongUnchecked(operand.toRawLongValue(), size, (ResourceScopeImpl) context.scope);
 993         }
 994 
 995         @Override
 996         public void verify(Deque<Class<?>> stack) {

   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  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 package jdk.internal.foreign.abi;
  26 
  27 import jdk.incubator.foreign.Addressable;
  28 import jdk.incubator.foreign.MemoryAddress;
  29 import jdk.incubator.foreign.MemoryHandles;
  30 import jdk.incubator.foreign.MemoryLayout;
  31 import jdk.incubator.foreign.MemorySegment;
  32 import jdk.incubator.foreign.ResourceScope;
  33 import jdk.incubator.foreign.SegmentAllocator;
  34 import jdk.incubator.foreign.ValueLayout;
  35 import jdk.internal.foreign.MemoryAddressImpl;
  36 import jdk.internal.foreign.ResourceScopeImpl;
  37 
  38 import java.lang.invoke.MethodHandle;
  39 import java.lang.invoke.MethodHandles;
  40 import java.lang.invoke.MethodType;
  41 import java.util.ArrayList;
  42 import java.util.Deque;
  43 import java.util.List;
  44 import java.util.Objects;
  45 
  46 import java.lang.invoke.VarHandle;
  47 import java.nio.ByteOrder;
  48 
  49 import static java.lang.invoke.MethodHandles.collectArguments;
  50 import static java.lang.invoke.MethodHandles.filterArguments;
  51 import static java.lang.invoke.MethodHandles.insertArguments;
  52 import static java.lang.invoke.MethodType.methodType;
  53 
  54 /**
  55  * The binding operators defined in the Binding class can be combined into argument and return value processing 'recipes'.
  56  *
  57  * The binding operators are interpreted using a stack-base interpreter. Operators can either consume operands from the
  58  * stack, or push them onto the stack.
  59  *
  60  * In the description of each binding we talk about 'boxing' and 'unboxing'.

 190  *
 191  * void f(int dummy, ...); // varargs
 192  *
 193  * f(0, 10f); // passing a float
 194  *
 195  * Argument bindings:
 196  * 0: VM_STORE(rcx, int.class) // moves the 'int dummy' into the RCX register
 197  *
 198  * 1: DUP // duplicates the '10f' argument
 199  *    VM_STORE(rdx, float.class) // move one copy into the RDX register
 200  *    VM_STORE(xmm1, float.class) // moves the other copy into the xmm2 register
 201  *
 202  * Return bindings:
 203  * none
 204  *
 205  * --------------------
 206  */
 207 public abstract class Binding {
 208     private static final MethodHandle MH_UNBOX_ADDRESS;
 209     private static final MethodHandle MH_BOX_ADDRESS;

 210     private static final MethodHandle MH_COPY_BUFFER;
 211     private static final MethodHandle MH_ALLOCATE_BUFFER;
 212     private static final MethodHandle MH_TO_SEGMENT;
 213 
 214     static {
 215         try {
 216             MethodHandles.Lookup lookup = MethodHandles.lookup();
 217             MH_UNBOX_ADDRESS = lookup.findVirtual(MemoryAddress.class, "toRawLongValue",
 218                     methodType(long.class));
 219             MH_BOX_ADDRESS = lookup.findStatic(MemoryAddress.class, "ofLong",
 220                     methodType(MemoryAddress.class, long.class));


 221             MH_COPY_BUFFER = lookup.findStatic(Binding.Copy.class, "copyBuffer",
 222                     methodType(MemorySegment.class, MemorySegment.class, long.class, long.class, Context.class));
 223             MH_ALLOCATE_BUFFER = lookup.findStatic(Binding.Allocate.class, "allocateBuffer",
 224                     methodType(MemorySegment.class, long.class, long.class, Context.class));
 225             MH_TO_SEGMENT = lookup.findStatic(Binding.ToSegment.class, "toSegment",
 226                     methodType(MemorySegment.class, MemoryAddress.class, long.class, Context.class));
 227         } catch (ReflectiveOperationException e) {
 228             throw new RuntimeException(e);
 229         }
 230     }
 231 
 232     /**
 233      * A binding context is used as an helper to carry out evaluation of certain bindings; for instance,
 234      * it helps {@link Allocate} bindings, by providing the {@link SegmentAllocator} that should be used for
 235      * the allocation operation, or {@link ToSegment} bindings, by providing the {@link ResourceScope} that
 236      * should be used to create an unsafe struct from a memory address.
 237      */
 238     public static class Context implements AutoCloseable {
 239         private final SegmentAllocator allocator;
 240         private final ResourceScope scope;

 245         }
 246 
 247         public SegmentAllocator allocator() {
 248             return allocator;
 249         }
 250 
 251         public ResourceScope scope() {
 252             return scope;
 253         }
 254 
 255         @Override
 256         public void close() {
 257             scope().close();
 258         }
 259 
 260         /**
 261          * Create a binding context from given native scope.
 262          */
 263         public static Context ofBoundedAllocator(long size) {
 264             ResourceScope scope = ResourceScope.newConfinedScope();
 265             return new Context(SegmentAllocator.newNativeArena(size, scope), scope);
 266         }
 267 
 268         /**
 269          * Create a binding context from given segment allocator. The resulting context will throw when
 270          * the context's scope is accessed.
 271          */
 272         public static Context ofAllocator(SegmentAllocator allocator) {
 273             return new Context(allocator, null) {
 274                 @Override
 275                 public ResourceScope scope() {
 276                     throw new UnsupportedOperationException();
 277                 }
 278             };
 279         }
 280 
 281         /**
 282          * Create a binding context from given scope. The resulting context will throw when
 283          * the context's allocator is accessed.
 284          */
 285         public static Context ofScope() {

 304             public ResourceScope scope() {
 305                 throw new UnsupportedOperationException();
 306             }
 307 
 308             @Override
 309             public void close() {
 310                 // do nothing
 311             }
 312         };
 313     }
 314 
 315     enum Tag {
 316         VM_STORE,
 317         VM_LOAD,
 318         BUFFER_STORE,
 319         BUFFER_LOAD,
 320         COPY_BUFFER,
 321         ALLOC_BUFFER,
 322         BOX_ADDRESS,
 323         UNBOX_ADDRESS,

 324         TO_SEGMENT,
 325         DUP
 326     }
 327 
 328     private final Tag tag;
 329 
 330     private Binding(Tag tag) {
 331         this.tag = tag;
 332     }
 333 
 334     public Tag tag() {
 335         return tag;
 336     }
 337 
 338     public abstract void verify(Deque<Class<?>> stack);
 339 
 340     public abstract void interpret(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc,
 341                                    BindingInterpreter.LoadFunc loadFunc, Context context);
 342 
 343     public abstract MethodHandle specialize(MethodHandle specializedHandle, int insertPos, int allocatorPos);
 344 
 345     private static void checkType(Class<?> type) {
 346         if (!type.isPrimitive() || type == void.class)
 347             throw new IllegalArgumentException("Illegal type: " + type);
 348     }
 349 
 350     private static void checkOffset(long offset) {
 351         if (offset < 0)
 352             throw new IllegalArgumentException("Negative offset: " + offset);
 353     }
 354 
 355     public static VMStore vmStore(VMStorage storage, Class<?> type) {
 356         checkType(type);
 357         return new VMStore(storage, type);
 358     }
 359 
 360     public static VMLoad vmLoad(VMStorage storage, Class<?> type) {
 361         checkType(type);
 362         return new VMLoad(storage, type);
 363     }
 364 
 365     public static BufferStore bufferStore(long offset, Class<?> type) {
 366         checkType(type);

 370 
 371     public static BufferLoad bufferLoad(long offset, Class<?> type) {
 372         checkType(type);
 373         checkOffset(offset);
 374         return new BufferLoad(offset, type);
 375     }
 376 
 377     public static Copy copy(MemoryLayout layout) {
 378         return new Copy(layout.byteSize(), layout.byteAlignment());
 379     }
 380 
 381     public static Allocate allocate(MemoryLayout layout) {
 382         return new Allocate(layout.byteSize(), layout.byteAlignment());
 383     }
 384 
 385     public static BoxAddress boxAddress() {
 386         return BoxAddress.INSTANCE;
 387     }
 388 
 389     public static UnboxAddress unboxAddress() {
 390         return UnboxAddress.INSTANCE.get(MemoryAddress.class);
 391     }
 392 
 393     public static UnboxAddress unboxAddress(Class<?> carrier) {
 394         return UnboxAddress.INSTANCE.get(carrier);
 395     }
 396 
 397     public static ToSegment toSegment(MemoryLayout layout) {
 398         return new ToSegment(layout.byteSize());
 399     }
 400 
 401     public static Dup dup() {
 402         return Dup.INSTANCE;
 403     }
 404 
 405 
 406     public static Binding.Builder builder() {
 407         return new Binding.Builder();
 408     }
 409 
 410     @Override
 411     public boolean equals(Object o) {
 412         if (this == o) return true;
 413         if (o == null || getClass() != o.getClass()) return false;
 414         Binding binding = (Binding) o;

 449         public Binding.Builder copy(MemoryLayout layout) {
 450             bindings.add(Binding.copy(layout));
 451             return this;
 452         }
 453 
 454         public Binding.Builder allocate(MemoryLayout layout) {
 455             bindings.add(Binding.allocate(layout));
 456             return this;
 457         }
 458 
 459         public Binding.Builder boxAddress() {
 460             bindings.add(Binding.boxAddress());
 461             return this;
 462         }
 463 
 464         public Binding.Builder unboxAddress() {
 465             bindings.add(Binding.unboxAddress());
 466             return this;
 467         }
 468 
 469         public Binding.Builder unboxAddress(Class<?> carrier) {
 470             bindings.add(Binding.unboxAddress(carrier));
 471             return this;
 472         }
 473 
 474         public Binding.Builder toSegment(MemoryLayout layout) {
 475             bindings.add(Binding.toSegment(layout));
 476             return this;
 477         }
 478 
 479         public Binding.Builder dup() {
 480             bindings.add(Binding.dup());
 481             return this;
 482         }
 483 
 484         public List<Binding> build() {
 485             return new ArrayList<>(bindings);
 486         }
 487     }
 488 
 489     static abstract class Move extends Binding {
 490         private final VMStorage storage;

 612 
 613         @Override
 614         public boolean equals(Object o) {
 615             if (this == o) return true;
 616             if (o == null || getClass() != o.getClass()) return false;
 617             if (!super.equals(o)) return false;
 618             Dereference that = (Dereference) o;
 619             return offset == that.offset &&
 620                     Objects.equals(type, that.type);
 621         }
 622 
 623         @Override
 624         public int hashCode() {
 625             return Objects.hash(super.hashCode(), offset, type);
 626         }
 627 
 628         public VarHandle varHandle() {
 629             // alignment is set to 1 byte here to avoid exceptions for cases where we do super word
 630             // copies of e.g. 2 int fields of a struct as a single long, while the struct is only
 631             // 4-byte-aligned (since it only contains ints)
 632             ValueLayout layout = MemoryLayout.valueLayout(type(), ByteOrder.nativeOrder()).withBitAlignment(8);
 633             return MemoryHandles.insertCoordinates(MemoryHandles.varHandle(layout), 1, offset);
 634         }
 635     }
 636 
 637     /**
 638      * BUFFER_STORE([offset into memory region], [type])
 639      * Pops a MemorySegment from the operand stack, loads a [type] from
 640      * [offset into memory region] from it, and pushes it onto the operand stack.
 641      * The [type] must be one of byte, short, char, int, long, float, or double
 642      */
 643     public static class BufferStore extends Dereference {
 644         private BufferStore(long offset, Class<?> type) {
 645             super(Tag.BUFFER_STORE, offset, type);
 646         }
 647 
 648         @Override
 649         public void verify(Deque<Class<?>> stack) {
 650             Class<?> storeType = stack.pop();
 651             SharedUtils.checkType(storeType, type());
 652             Class<?> segmentType = stack.pop();
 653             SharedUtils.checkType(segmentType, MemorySegment.class);

 723     }
 724 
 725     /**
 726      * COPY([size], [alignment])
 727      *   Creates a new MemorySegment with the given [size] and [alignment],
 728      *     and copies contents from a MemorySegment popped from the top of the operand stack into this new buffer,
 729      *     and pushes the new buffer onto the operand stack
 730      */
 731     public static class Copy extends Binding {
 732         private final long size;
 733         private final long alignment;
 734 
 735         private Copy(long size, long alignment) {
 736             super(Tag.COPY_BUFFER);
 737             this.size = size;
 738             this.alignment = alignment;
 739         }
 740 
 741         private static MemorySegment copyBuffer(MemorySegment operand, long size, long alignment,
 742                                                     Context context) {
 743             return context.allocator().allocate(size, alignment)
 744                             .copyFrom(operand.asSlice(0, size));

 745         }
 746 
 747         public long size() {
 748             return size;
 749         }
 750 
 751         public long alignment() {
 752             return alignment;
 753         }
 754 
 755         @Override
 756         public String toString() {
 757             return "Copy{" +
 758                     "tag=" + tag() +
 759                     ", size=" + size +
 760                     ", alignment=" + alignment +
 761                     '}';
 762         }
 763 
 764         @Override

 857             if (this == o) return true;
 858             if (o == null || getClass() != o.getClass()) return false;
 859             if (!super.equals(o)) return false;
 860             Allocate allocate = (Allocate) o;
 861             return size == allocate.size &&
 862                     alignment == allocate.alignment;
 863         }
 864 
 865         @Override
 866         public int hashCode() {
 867             return Objects.hash(super.hashCode(), size, alignment);
 868         }
 869     }
 870 
 871     /**
 872      * UNBOX_ADDRESS()
 873      * Pops a 'MemoryAddress' from the operand stack, converts it to a 'long',
 874      *     and pushes that onto the operand stack.
 875      */
 876     public static class UnboxAddress extends Binding {
 877 
 878         static final ClassValue<UnboxAddress> INSTANCE = new ClassValue<>() {
 879             @Override
 880             protected UnboxAddress computeValue(Class<?> type) {
 881                 return new UnboxAddress(type);
 882             }
 883         };
 884 
 885         final Class<?> carrier;
 886         final MethodHandle toAddress;
 887 
 888         private UnboxAddress(Class<?> carrier) {
 889             super(Tag.UNBOX_ADDRESS);
 890             this.carrier = carrier;
 891             try {
 892                 this.toAddress = MethodHandles.lookup().findVirtual(carrier, "address", MethodType.methodType(MemoryAddress.class));
 893             } catch (Throwable ex) {
 894                 throw new IllegalArgumentException(ex);
 895             }
 896         }
 897 
 898         @Override
 899         public void verify(Deque<Class<?>> stack) {
 900             Class<?> actualType = stack.pop();
 901             SharedUtils.checkType(actualType, carrier);
 902             stack.push(long.class);
 903         }
 904 
 905         @Override
 906         public void interpret(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc,
 907                               BindingInterpreter.LoadFunc loadFunc, Context context) {
 908             stack.push(((Addressable)stack.pop()).address().toRawLongValue());
 909         }
 910 
 911         @Override
 912         public MethodHandle specialize(MethodHandle specializedHandle, int insertPos, int allocatorPos) {
 913             return filterArguments(specializedHandle, insertPos,
 914                     MethodHandles.filterReturnValue(toAddress, MH_UNBOX_ADDRESS));
 915         }
 916 
 917         @Override
 918         public String toString() {
 919             return "UnboxAddress{}";
 920         }
 921     }
 922 
 923     /**
 924      * BOX_ADDRESS()
 925      * Pops a 'long' from the operand stack, converts it to a 'MemoryAddress',
 926      *     and pushes that onto the operand stack.
 927      */
 928     public static class BoxAddress extends Binding {
 929         private static final BoxAddress INSTANCE = new BoxAddress();
 930         private BoxAddress() {
 931             super(Tag.BOX_ADDRESS);
 932         }
 933 
 934         @Override

 938             stack.push(MemoryAddress.class);
 939         }
 940 
 941         @Override
 942         public void interpret(Deque<Object> stack, BindingInterpreter.StoreFunc storeFunc,
 943                               BindingInterpreter.LoadFunc loadFunc, Context context) {
 944             stack.push(MemoryAddress.ofLong((long) stack.pop()));
 945         }
 946 
 947         @Override
 948         public MethodHandle specialize(MethodHandle specializedHandle, int insertPos, int allocatorPos) {
 949             return filterArguments(specializedHandle, insertPos, MH_BOX_ADDRESS);
 950         }
 951 
 952         @Override
 953         public String toString() {
 954             return "BoxAddress{}";
 955         }
 956     }
 957 



































 958     /**
 959      * TO_SEGMENT([size])
 960      *   Pops a MemoryAddress from the operand stack, and converts it to a MemorySegment
 961      *   with the given size, and pushes that onto the operand stack
 962      */
 963     public static class ToSegment extends Binding {
 964         private final long size;
 965         // FIXME alignment?
 966 
 967         public ToSegment(long size) {
 968             super(Tag.TO_SEGMENT);
 969             this.size = size;
 970         }
 971 
 972         private static MemorySegment toSegment(MemoryAddress operand, long size, Context context) {
 973             return MemoryAddressImpl.ofLongUnchecked(operand.toRawLongValue(), size, (ResourceScopeImpl) context.scope);
 974         }
 975 
 976         @Override
 977         public void verify(Deque<Class<?>> stack) {
< prev index next >