< 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.MemoryHandles;
 26 import jdk.incubator.foreign.MemoryLayout;



 27 



 28 import java.util.ArrayList;

 29 import java.util.List;

 30 import java.util.Objects;
 31 
 32 import java.lang.invoke.VarHandle;
 33 import java.nio.ByteOrder;







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

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
























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






























209     private static void checkType(Class<?> type) {
210         if (!type.isPrimitive() || type == void.class || type == boolean.class)
211             throw new IllegalArgumentException("Illegal type: " + type);
212     }
213 






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

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
































343     }
344 
345     /**
346      * DEREFERENCE([offset into memory region], [type])
347      *   When unboxing: pops a MemorySegment from the operand stack,
348      *     loads a [type] from [offset into memory region] from it, and pushes it onto the operand stack
349      *   When boxing: pops a [type], and then a MemorySegment from the operand stack,
350      *     and then stores [type] to [offset into memory region] of the MemorySegment
351      * The [type] must be one of byte, short, char, int, long, float, or double
352      */
353     public static class Dereference extends Binding {
354         private final long offset;
355         private final Class<?> type;
356 
357         private Dereference(long offset, Class<?> type) {
358             super(Tag.DEREFERENCE);
359             this.offset = offset;
360             this.type = type;
361         }
362 
363         public long offset() {
364             return offset;
365         }
366 
367         public Class<?> type() {
368             return type;
369         }
370 
371         public VarHandle varHandle() {
372             return MemoryHandles.withOffset(MemoryHandles.varHandle(type, ByteOrder.nativeOrder()), offset);
373         }
374 
375         @Override
376         public String toString() {
377             return "Dereference{" +
378                     "tag=" + tag() +
379                     ", offset=" + offset +
380                     ", type=" + type +
381                     '}';
382         }
383 
384         @Override
385         public boolean equals(Object o) {
386             if (this == o) return true;
387             if (o == null || getClass() != o.getClass()) return false;
388             Dereference that = (Dereference) o;
389             return offset == that.offset &&
390                     type.equals(that.type);
391         }
392 
393         @Override
394         public int hashCode() {
395             return Objects.hash(tag(), offset, type);
396         }























































397     }
398 
399     /**
400      * COPY([size], [alignment])
401      *   Creates a new MemorySegment with the given [size] and [alignment],
402      *     and copies contents from a MemorySegment popped from the top of the operand stack into this new buffer,
403      *     and pushes the new buffer onto the operand stack
404      */
405     public static class Copy extends Binding {
406         private final long size;
407         private final long alignment;
408 
409         private Copy(long size, long alignment) {
410             super(Tag.COPY_BUFFER);
411             this.size = size;
412             this.alignment = alignment;
413         }
414 
415         public long size() {
416             return size;

425             return "Copy{" +
426                     "tag=" + tag() +
427                     ", size=" + size +
428                     ", alignment=" + alignment +
429                     '}';
430         }
431 
432         @Override
433         public boolean equals(Object o) {
434             if (this == o) return true;
435             if (o == null || getClass() != o.getClass()) return false;
436             Copy copy = (Copy) o;
437             return size == copy.size &&
438                     alignment == copy.alignment;
439         }
440 
441         @Override
442         public int hashCode() {
443             return Objects.hash(tag(), size, alignment);
444         }











































445     }
446 
447     /**
448      * ALLOCATE([size], [alignment])
449      *   Creates a new MemorySegment with the give [size] and [alignment], and pushes it onto the operand stack.
450      */
451     public static class Allocate extends Binding {
452         private final long size;
453         private final long alignment;
454 
455         private Allocate(long size, long alignment) {
456             super(Tag.ALLOC_BUFFER);
457             this.size = size;
458             this.alignment = alignment;
459         }
460 
461         public long size() {
462             return size;
463         }
464 

471             return "AllocateBuffer{" +
472                     "tag=" + tag() +
473                     "size=" + size +
474                     ", alignment=" + alignment +
475                     '}';
476         }
477 
478         @Override
479         public boolean equals(Object o) {
480             if (this == o) return true;
481             if (o == null || getClass() != o.getClass()) return false;
482             Allocate that = (Allocate) o;
483             return size == that.size &&
484                     alignment == that.alignment;
485         }
486 
487         @Override
488         public int hashCode() {
489             return Objects.hash(tag(), size, alignment);
490         }






























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


































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


































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


































































583     }
584 }

  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  *

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

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 >