< prev index next >

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

Print this page

  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.MemoryLayout;



 26 



 27 import java.util.ArrayList;

 28 import java.util.List;

 29 import java.util.Objects;
 30 










 31 /**
 32  * The binding operators defined in the Binding class can be combined into argument and return value processing 'recipes'.
 33  *
 34  * The binding operators are interpreted using a stack-base interpreter. Operators can either consume operands from the
 35  * stack, or push them onto the stack.
 36  *
 37  * In the description of each binding we talk about 'boxing' and 'unboxing'.
 38  *  - Unboxing is the process of taking a Java value and decomposing it, and storing components into machine
 39  *    storage locations. As such, the binding interpreter stack starts with the Java value on it, and should end empty.
 40  *  - Boxing is the process of re-composing a Java value by pulling components from machine storage locations.
 41  *    If a MemorySegment is needed to store the result, one should be allocated using the ALLOCATE_BUFFER operator.
 42  *    The binding interpreter stack starts off empty, and ends with the value to be returned as the only value on it.
 43  * A binding operator can be interpreted differently based on whether we are boxing or unboxing a value. For example,
 44  * the CONVERT_ADDRESS operator 'unboxes' a MemoryAddress to a long, but 'boxes' a long to a MemoryAddress.
 45  *
 46  * Here are some examples of binding recipes derived from C declarations, and according to the Windows ABI (recipes are
 47  * ABI-specific). Note that each argument has it's own recipe, which is indicated by '[number]:' (though, the only
 48  * example that has multiple arguments is the one using varargs).
 49  *
 50  * --------------------

165  *
166  * --------------------
167  *
168  * void f(int dummy, ...); // varargs
169  *
170  * f(0, 10f); // passing a float
171  *
172  * Argument bindings:
173  * 0: MOVE(rcx, int.class) // moves the 'int dummy' into the RCX register
174  *
175  * 1: DUP // duplicates the '10f' argument
176  *    MOVE(rdx, float.class) // move one copy into the RDX register
177  *    MOVE(xmm1, float.class) // moves the other copy into the xmm2 register
178  *
179  * Return bindings:
180  * none
181  *
182  * --------------------
183  */
184 public abstract class Binding {
























185     enum Tag {
186         MOVE,
187         DEREFERENCE,
188         COPY_BUFFER,
189         ALLOC_BUFFER,
190         CONVERT_ADDRESS,
191         BASE_ADDRESS,
192         DUP
193     }
194 
195     private final Tag tag;
196 
197     private Binding(Tag tag) {
198         this.tag = tag;
199     }
200 
201     public Tag tag() {
202         return tag;
203     }
204 






























205     private static void checkType(Class<?> type) {
206         if (!type.isPrimitive() || type == void.class || type == boolean.class)
207             throw new IllegalArgumentException("Illegal type: " + type);
208     }
209 






210     public static Move move(VMStorage storage, Class<?> type) {
211         checkType(type);
212         return new Move(storage, type);
213     }
214 
215     public static Dereference dereference(long offset, Class<?> type) {
216         checkType(type);
217         if (offset < 0)
218             throw new IllegalArgumentException("Negative offset: " + offset);
219         return new Dereference(offset, type);
220     }
221 
222     public static Copy copy(MemoryLayout layout) {
223         return new Copy(layout.byteSize(), layout.byteAlignment());
224     }
225 
226     public static Allocate allocate(MemoryLayout layout) {
227         return new Allocate(layout.byteSize(), layout.byteAlignment());
228     }
229 

319             return "Move{" +
320                     "tag=" + tag() +
321                     ", storage=" + storage +
322                     ", type=" + type +
323                     '}';
324         }
325 
326         @Override
327         public boolean equals(Object o) {
328             if (this == o) return true;
329             if (o == null || getClass() != o.getClass()) return false;
330             Move move = (Move) o;
331             return storage.equals(move.storage) &&
332                     type.equals(move.type);
333         }
334 
335         @Override
336         public int hashCode() {
337             return Objects.hash(tag(), storage, type);
338         }
































339     }
340 
341     /**
342      * DEREFERENCE([offset into memory region], [type])
343      *   When unboxing: pops a MemorySegment from the operand stack,
344      *     loads a [type] from [offset into memory region] from it, and pushes it onto the operand stack
345      *   When boxing: pops a [type], and then a MemorySegment from the operand stack,
346      *     and then stores [type] to [offset into memory region] of the MemorySegment
347      * The [type] must be one of byte, short, char, int, long, float, or double
348      */
349     public static class Dereference extends Binding {
350         private final long offset;
351         private final Class<?> type;
352 
353         private Dereference(long offset, Class<?> type) {
354             super(Tag.DEREFERENCE);
355             this.offset = offset;
356             this.type = type;
357         }
358 

369             return "Dereference{" +
370                     "tag=" + tag() +
371                     ", offset=" + offset +
372                     ", type=" + type +
373                     '}';
374         }
375 
376         @Override
377         public boolean equals(Object o) {
378             if (this == o) return true;
379             if (o == null || getClass() != o.getClass()) return false;
380             Dereference that = (Dereference) o;
381             return offset == that.offset &&
382                     type.equals(that.type);
383         }
384 
385         @Override
386         public int hashCode() {
387             return Objects.hash(tag(), offset, type);
388         }























































389     }
390 
391     /**
392      * COPY([size], [alignment])
393      *   Creates a new MemorySegment with the given [size] and [alignment],
394      *     and copies contents from a MemorySegment popped from the top of the operand stack into this new buffer,
395      *     and pushes the new buffer onto the operand stack
396      */
397     public static class Copy extends Binding {
398         private final long size;
399         private final long alignment;
400 
401         private Copy(long size, long alignment) {
402             super(Tag.COPY_BUFFER);
403             this.size = size;
404             this.alignment = alignment;
405         }
406 
407         public long size() {
408             return size;

417             return "Copy{" +
418                     "tag=" + tag() +
419                     ", size=" + size +
420                     ", alignment=" + alignment +
421                     '}';
422         }
423 
424         @Override
425         public boolean equals(Object o) {
426             if (this == o) return true;
427             if (o == null || getClass() != o.getClass()) return false;
428             Copy copy = (Copy) o;
429             return size == copy.size &&
430                     alignment == copy.alignment;
431         }
432 
433         @Override
434         public int hashCode() {
435             return Objects.hash(tag(), size, alignment);
436         }











































437     }
438 
439     /**
440      * ALLOCATE([size], [alignment])
441      *   Creates a new MemorySegment with the give [size] and [alignment], and pushes it onto the operand stack.
442      */
443     public static class Allocate extends Binding {
444         private final long size;
445         private final long alignment;
446 
447         private Allocate(long size, long alignment) {
448             super(Tag.ALLOC_BUFFER);
449             this.size = size;
450             this.alignment = alignment;
451         }
452 
453         public long size() {
454             return size;
455         }
456 

463             return "AllocateBuffer{" +
464                     "tag=" + tag() +
465                     "size=" + size +
466                     ", alignment=" + alignment +
467                     '}';
468         }
469 
470         @Override
471         public boolean equals(Object o) {
472             if (this == o) return true;
473             if (o == null || getClass() != o.getClass()) return false;
474             Allocate that = (Allocate) o;
475             return size == that.size &&
476                     alignment == that.alignment;
477         }
478 
479         @Override
480         public int hashCode() {
481             return Objects.hash(tag(), size, alignment);
482         }






























483     }
484 
485     /**
486      * CONVERT_ADDRESS()
487      *   When unboxing: pops a 'MemoryAddress' from the operand stack, converts it to a 'long',
488      *     and pushes that onto the operand stack
489      *   When boxing: pops a 'long' from the operand stack, converts it to a 'MemoryAddress',
490      *     and pushes that onto the operand stack
491      */
492     public static class ConvertAddress extends Binding {
493         private static final ConvertAddress INSTANCE = new ConvertAddress();
494         private ConvertAddress() {
495             super(Tag.CONVERT_ADDRESS);
496         }
497 
498         @Override
499         public String toString() {
500             return "BoxAddress{" +
501                     "tag=" + tag() +
502                     "}";
503         }
504 
505         @Override
506         public int hashCode() {
507             return tag().hashCode();
508         }
509 
510         @Override
511         public boolean equals(Object o) {
512             if (this == o) return true;
513             return o != null && getClass() == o.getClass();
514         }


































515     }
516 
517     /**
518      * BASE_ADDRESS()
519      *   Pops a MemorySegment from the operand stack, and takes the base address of the segment
520      *   (the MemoryAddress that points to the start), and pushes that onto the operand stack
521      */
522     public static class BaseAddress extends Binding {
523         private static final BaseAddress INSTANCE = new BaseAddress();
524         private BaseAddress() {
525             super(Tag.BASE_ADDRESS);
526         }
527 
528         @Override
529         public String toString() {
530             return "BaseAddress{" +
531                     "tag=" + tag() +
532                     "}";
533         }
534 
535         @Override
536         public int hashCode() {
537             return tag().hashCode();
538         }
539 
540         @Override
541         public boolean equals(Object o) {
542             if (this == o) return true;
543             return o != null && getClass() == o.getClass();
544         }


































545     }
546 
547     /**
548      * DUP()
549      *   Duplicates the value on the top of the operand stack (without popping it!),
550      *   and pushes the duplicate onto the operand stack
551      */
552     public static class Dup extends Binding {
553         private static final Dup INSTANCE = new Dup();
554         private Dup() {
555             super(Tag.DUP);
556         }
557 
558         @Override
559         public String toString() {
560             return "Dup{" +
561                     "tag=" + tag() +
562                     "}";
563         }
564 
565         @Override
566         public int hashCode() {
567             return tag().hashCode();
568         }
569 
570         @Override
571         public boolean equals(Object o) {
572             if (this == o) return true;
573             return o != null && getClass() == o.getClass();
574         }


































































575     }
576 }

  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  * --------------------

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 

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 

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;

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 

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 }
< prev index next >