diff --git a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/NativeAllocationScope.java b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/NativeScope.java similarity index 64% rename from src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/NativeAllocationScope.java rename to src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/NativeScope.java index 0a69eabb61d..e29dd4f3cd0 100644 --- a/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/NativeAllocationScope.java +++ b/src/jdk.incubator.foreign/share/classes/jdk/incubator/foreign/NativeScope.java @@ -26,42 +26,55 @@ package jdk.incubator.foreign; -import jdk.internal.foreign.BoundedAllocationScope; -import jdk.internal.foreign.UnboundedAllocationScope; +import jdk.internal.foreign.AbstractNativeScope; import java.lang.invoke.VarHandle; import java.util.OptionalLong; /** - * This class provides a scope of given size, within which several allocations can be performed. An allocation scope is backed - * by off-heap memory. Allocation scopes can be either <em>bounded</em> or <em>unbounded</em>, depending on whether the size - * of the allocation scope is known statically. If an application knows before-hand how much memory it needs to allocate the values it needs, - * using a <em>bounded</em> allocation scope will typically provide better performances than independently allocating the memory - * for each value (e.g. using {@link MemorySegment#allocateNative(long)}), or using an <em>unbounded</em> allocation scope. - * For this reason, using a bounded allocation scope is recommended in cases where programs might need to emulate native stack allocation. + * This class provides a scope of given size, within which several allocations can be performed. An native scope is backed + * by off-heap memory. Native scopes can be either <em>bounded</em> or <em>unbounded</em>, depending on whether the size + * of the native scope is known statically. If an application knows before-hand how much memory it needs to allocate the values it needs, + * using a <em>bounded</em> native scope will typically provide better performances than independently allocating the memory + * for each value (e.g. using {@link MemorySegment#allocateNative(long)}), or using an <em>unbounded</em> native scope. + * For this reason, using a bounded native scope is recommended in cases where programs might need to emulate native stack allocation. + * <p> + * Allocation scopes are thread-confined (see {@link #ownerThread()}; as such, the resulting {@code MemoryAddress} instances + * returned by the native scope will be backed by memory segments confined by the same owner thread as the native scope. + * <p> + * To allow for more usability, it is possible for an native scope to reclaim ownership of an existing memory segments + * (see {@link #register(MemorySegment)}). This might be useful to allow one or more segments which were independently + * created to share the same life-cycle as a given native scope - which in turns enables client to group all memory + * allocation and usage under a single <em>try-with-resources block</em>. */ -public abstract class NativeAllocationScope implements AutoCloseable { +public abstract class NativeScope implements AutoCloseable { /** - * If this allocation scope is bounded, returns the size, in bytes, of this allocation scope. - * @return the size, in bytes, of this allocation scope (if available). + * If this native scope is bounded, returns the size, in bytes, of this native scope. + * @return the size, in bytes, of this native scope (if available). */ public abstract OptionalLong byteSize(); /** - * Returns the number of allocated bytes in this allocation scope. - * @return the number of allocated bytes in this allocation scope. + * The thread owning this native scope. + * @return the thread owning this native scope. + */ + public abstract Thread ownerThread(); + + /** + * Returns the number of allocated bytes in this native scope. + * @return the number of allocated bytes in this native scope. */ public abstract long allocatedBytes(); /** - * Allocate a block of memory in this allocation scope with given layout and initialize it with given byte value. + * Allocate a block of memory in this native scope with given layout and initialize it with given byte value. * The address returned by this method is associated with a segment which cannot be closed. Moreover, the returned * address must conform to the layout alignment constraints. * @param layout the layout of the block of memory to be allocated. * @param value the value to be set on the newly allocated memory block. * @return an address which points to the newly allocated memory block. - * @throws OutOfMemoryError if there is not enough space left in this allocation scope, that is, if + * @throws OutOfMemoryError if there is not enough space left in this native scope, that is, if * {@code limit() - size() < layout.byteSize()}. * @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a byte value. */ @@ -73,13 +86,13 @@ public MemoryAddress allocate(MemoryLayout layout, byte value) { } /** - * Allocate a block of memory in this allocation scope with given layout and initialize it with given short value. + * Allocate a block of memory in this native scope with given layout and initialize it with given short value. * The address returned by this method is associated with a segment which cannot be closed. Moreover, the returned * address must conform to the layout alignment constraints. * @param layout the layout of the block of memory to be allocated. * @param value the value to be set on the newly allocated memory block. * @return an address which points to the newly allocated memory block. - * @throws OutOfMemoryError if there is not enough space left in this allocation scope, that is, if + * @throws OutOfMemoryError if there is not enough space left in this native scope, that is, if * {@code limit() - size() < layout.byteSize()}. * @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a short value. */ @@ -91,13 +104,13 @@ public MemoryAddress allocate(MemoryLayout layout, short value) { } /** - * Allocate a block of memory in this allocation scope with given layout and initialize it with given int value. + * Allocate a block of memory in this native scope with given layout and initialize it with given int value. * The address returned by this method is associated with a segment which cannot be closed. Moreover, the returned * address must conform to the layout alignment constraints. * @param layout the layout of the block of memory to be allocated. * @param value the value to be set on the newly allocated memory block. * @return an address which points to the newly allocated memory block. - * @throws OutOfMemoryError if there is not enough space left in this allocation scope, that is, if + * @throws OutOfMemoryError if there is not enough space left in this native scope, that is, if * {@code limit() - size() < layout.byteSize()}. * @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a int value. */ @@ -109,13 +122,13 @@ public MemoryAddress allocate(MemoryLayout layout, int value) { } /** - * Allocate a block of memory in this allocation scope with given layout and initialize it with given float value. + * Allocate a block of memory in this native scope with given layout and initialize it with given float value. * The address returned by this method is associated with a segment which cannot be closed. Moreover, the returned * address must conform to the layout alignment constraints. * @param layout the layout of the block of memory to be allocated. * @param value the value to be set on the newly allocated memory block. * @return an address which points to the newly allocated memory block. - * @throws OutOfMemoryError if there is not enough space left in this allocation scope, that is, if + * @throws OutOfMemoryError if there is not enough space left in this native scope, that is, if * {@code limit() - size() < layout.byteSize()}. * @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a float value. */ @@ -127,13 +140,13 @@ public MemoryAddress allocate(MemoryLayout layout, float value) { } /** - * Allocate a block of memory in this allocation scope with given layout and initialize it with given long value. + * Allocate a block of memory in this native scope with given layout and initialize it with given long value. * The address returned by this method is associated with a segment which cannot be closed. Moreover, the returned * address must conform to the layout alignment constraints. * @param layout the layout of the block of memory to be allocated. * @param value the value to be set on the newly allocated memory block. * @return an address which points to the newly allocated memory block. - * @throws OutOfMemoryError if there is not enough space left in this allocation scope, that is, if + * @throws OutOfMemoryError if there is not enough space left in this native scope, that is, if * {@code limit() - size() < layout.byteSize()}. * @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a long value. */ @@ -145,13 +158,13 @@ public MemoryAddress allocate(MemoryLayout layout, long value) { } /** - * Allocate a block of memory in this allocation scope with given layout and initialize it with given double value. + * Allocate a block of memory in this native scope with given layout and initialize it with given double value. * The address returned by this method is associated with a segment which cannot be closed. Moreover, the returned * address must conform to the layout alignment constraints. * @param layout the layout of the block of memory to be allocated. * @param value the value to be set on the newly allocated memory block. * @return an address which points to the newly allocated memory block. - * @throws OutOfMemoryError if there is not enough space left in this allocation scope, that is, if + * @throws OutOfMemoryError if there is not enough space left in this native scope, that is, if * {@code limit() - size() < layout.byteSize()}. * @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of a double value. */ @@ -163,13 +176,13 @@ public MemoryAddress allocate(MemoryLayout layout, double value) { } /** - * Allocate a block of memory in this allocation scope with given layout and initialize it with given address value. + * Allocate a block of memory in this native scope with given layout and initialize it with given address value. * The address returned by this method is associated with a segment which cannot be closed. Moreover, the returned * address must conform to the layout alignment constraints. * @param layout the layout of the block of memory to be allocated. * @param value the value to be set on the newly allocated memory block. * @return an address which points to the newly allocated memory block. - * @throws OutOfMemoryError if there is not enough space left in this allocation scope, that is, if + * @throws OutOfMemoryError if there is not enough space left in this native scope, that is, if * {@code limit() - size() < layout.byteSize()}. * @throws IllegalArgumentException if {@code layout.byteSize()} does not conform to the size of an address value. */ @@ -191,11 +204,11 @@ private static Class<?> carrierForSize(long size) { } /** - * Allocate a block of memory in this allocation scope with given layout. The address returned by this method is + * Allocate a block of memory in this native scope with given layout. The address returned by this method is * associated with a segment which cannot be closed. Moreover, the returned address must conform to the layout alignment constraints. * @param layout the layout of the block of memory to be allocated. * @return an address which points to the newly allocated memory block. - * @throws OutOfMemoryError if there is not enough space left in this allocation scope, that is, if + * @throws OutOfMemoryError if there is not enough space left in this native scope, that is, if * {@code limit() - size() < layout.byteSize()}. */ public MemoryAddress allocate(MemoryLayout layout) { @@ -203,11 +216,11 @@ public MemoryAddress allocate(MemoryLayout layout) { } /** - * Allocate a block of memory in this allocation scope with given size. The address returned by this method is + * Allocate a block of memory in this native scope with given size. The address returned by this method is * associated with a segment which cannot be closed. Moreover, the returned address must be aligned to {@code size}. * @param bytesSize the size (in bytes) of the block of memory to be allocated. * @return an address which points to the newly allocated memory block. - * @throws OutOfMemoryError if there is not enough space left in this allocation scope, that is, if + * @throws OutOfMemoryError if there is not enough space left in this native scope, that is, if * {@code limit() - size() < bytesSize}. */ public MemoryAddress allocate(long bytesSize) { @@ -215,38 +228,57 @@ public MemoryAddress allocate(long bytesSize) { } /** - * Allocate a block of memory in this allocation scope with given size and alignment constraint. + * Allocate a block of memory in this native scope with given size and alignment constraint. * The address returned by this method is associated with a segment which cannot be closed. Moreover, * the returned address must be aligned to {@code alignment}. * @param bytesSize the size (in bytes) of the block of memory to be allocated. * @param bytesAlignment the alignment (in bytes) of the block of memory to be allocated. * @return an address which points to the newly allocated memory block. - * @throws OutOfMemoryError if there is not enough space left in this allocation scope, that is, if + * @throws OutOfMemoryError if there is not enough space left in this native scope, that is, if * {@code limit() - size() < bytesSize}. */ public abstract MemoryAddress allocate(long bytesSize, long bytesAlignment); /** - * Close this allocation scope; calling this method will render any address obtained through this allocation scope - * unusable and might release any backing memory resources associated with this allocation scope. + * Register a segment on this scope, which will then reclaim ownership of said segment. + * The input segment must be closeable - that is, it must feature the {@link MemorySegment#CLOSE} access mode. + * As a side-effect, the input segment will be marked as <em>not alive</em>, and a new segment will be returned. + * <p> + * The returned segment will feature only {@link MemorySegment#READ} and + * {@link MemorySegment#WRITE} access modes (assuming these were available in the original segment). As such + * the resulting segment cannot be closed directly using {@link MemorySegment#close()} - but it will be closed + * indirectly when this native scope is closed. + * @param segment the segment which will be registered on this native scope. + * @return a new, non closeable memory segment, backed by the same underlying region as {@code segment}, + * but whose life-cycle is tied to that of this native scope. + * @throws IllegalStateException if {@code segment} is not <em>alive</em> (see {@link MemorySegment#isAlive()}). + * @throws NullPointerException if {@code segment == null} + * @throws IllegalArgumentException if {@code segment.ownerThread() != this.ownerThread()}, or if {@code segment} + * does not feature the {@link MemorySegment#CLOSE} access mode. + */ + public abstract MemorySegment register(MemorySegment segment); + + /** + * Close this native scope; calling this method will render any address obtained through this native scope + * unusable and might release any backing memory resources associated with this native scope. */ @Override public abstract void close(); /** - * Creates a new bounded allocation scope, backed by off-heap memory. - * @param size the size of the allocation scope. - * @return a new bounded allocation scope, with given size (in bytes). + * Creates a new bounded native scope, backed by off-heap memory. + * @param size the size of the native scope. + * @return a new bounded native scope, with given size (in bytes). */ - public static NativeAllocationScope boundedScope(long size) { - return new BoundedAllocationScope(size); + public static NativeScope boundedScope(long size) { + return new AbstractNativeScope.BoundedNativeScope(size); } /** - * Creates a new unbounded allocation scope, backed by off-heap memory. - * @return a new unbounded allocation scope. + * Creates a new unbounded native scope, backed by off-heap memory. + * @return a new unbounded native scope. */ - public static NativeAllocationScope unboundedScope() { - return new UnboundedAllocationScope(); + public static NativeScope unboundedScope() { + return new AbstractNativeScope.UnboundedNativeScope(); } } diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index 2bfe7926e8d..8ca639cc99a 100644 --- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -238,12 +238,16 @@ public MemorySegment withOwnerThread(Thread newOwner) { if (scope.ownerThread() == newOwner) { throw new IllegalArgumentException("Segment already owned by thread: " + newOwner); } else { - try { - return dup(0L, length, mask, scope.dup(newOwner)); - } finally { - //flush read/writes to segment memory before returning the new segment - VarHandle.fullFence(); - } + return dupAndClose(newOwner); + } + } + + public MemorySegment dupAndClose(Thread newOwner) { + try { + return dup(0L, length, mask, scope.dup(newOwner)); + } finally { + //flush read/writes to segment memory before returning the new segment + VarHandle.fullFence(); } } diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/AbstractNativeScope.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/AbstractNativeScope.java new file mode 100644 index 00000000000..8b0dcf238a8 --- /dev/null +++ b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/AbstractNativeScope.java @@ -0,0 +1,154 @@ +package jdk.internal.foreign; + +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.NativeScope; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.OptionalLong; + +public abstract class AbstractNativeScope extends NativeScope { + + private final List<MemorySegment> segments = new ArrayList<>(); + private final Thread ownerThread; + + private static final int SCOPE_MASK = MemorySegment.READ | MemorySegment.WRITE; // no terminal operations allowed + + AbstractNativeScope(Thread ownerThread) { + this.ownerThread = ownerThread; + } + + @Override + public Thread ownerThread() { + return ownerThread; + } + + @Override + public void close() { + for (MemorySegment segment : segments) { + try { + segment.close(); + } catch (IllegalStateException ex) { + //already closed - skip + } + } + } + + void checkOwnerThread() { + if (Thread.currentThread() != ownerThread()) { + throw new IllegalStateException("Attempt to access scope from different thread"); + } + } + + MemorySegment newSegment(long size, long align) { + MemorySegment segment = MemorySegment.allocateNative(size, align); + segments.add(segment); + return segment; + } + + MemorySegment newSegment(long size) { + return newSegment(size, size); + } + + @Override + public MemorySegment register(MemorySegment segment) { + Objects.requireNonNull(segment); + if (segment.ownerThread() != ownerThread()) { + throw new IllegalArgumentException("Cannot register segment owned by a different thread"); + } else if (!segment.hasAccessModes(MemorySegment.CLOSE)) { + throw new IllegalArgumentException("Cannot register a non-closeable segment"); + } + MemorySegment attachedSegment = ((AbstractMemorySegmentImpl)segment) + .dupAndClose(ownerThread()); + segments.add(attachedSegment); + return attachedSegment + .withAccessModes(segment.accessModes() & SCOPE_MASK); + } + + public static class UnboundedNativeScope extends AbstractNativeScope { + + private static final long BLOCK_SIZE = 4 * 1024; + private static final long MAX_ALLOC_SIZE = BLOCK_SIZE / 2; + + private MemorySegment segment; + private long sp = 0L; + private long size = 0L; + + @Override + public OptionalLong byteSize() { + return OptionalLong.empty(); + } + + @Override + public long allocatedBytes() { + return size; + } + + public UnboundedNativeScope() { + super(Thread.currentThread()); + this.segment = newSegment(BLOCK_SIZE); + } + + @Override + public MemoryAddress allocate(long bytesSize, long bytesAlignment) { + checkOwnerThread(); + if (bytesSize > MAX_ALLOC_SIZE) { + MemorySegment segment = newSegment(bytesSize, bytesAlignment); + return segment.withAccessModes(SCOPE_MASK) + .baseAddress(); + } + for (int i = 0; i < 2; i++) { + long min = ((MemoryAddressImpl) segment.baseAddress()).unsafeGetOffset(); + long start = Utils.alignUp(min + sp, bytesAlignment) - min; + try { + MemorySegment slice = segment.asSlice(start, bytesSize) + .withAccessModes(SCOPE_MASK); + sp = start + bytesSize; + size += Utils.alignUp(bytesSize, bytesAlignment); + return slice.baseAddress(); + } catch (IndexOutOfBoundsException ex) { + sp = 0L; + segment = newSegment(BLOCK_SIZE, 1L); + } + } + throw new AssertionError("Cannot get here!"); + } + } + + public static class BoundedNativeScope extends AbstractNativeScope { + private final MemorySegment segment; + private long sp = 0L; + + @Override + public OptionalLong byteSize() { + return OptionalLong.of(segment.byteSize()); + } + + @Override + public long allocatedBytes() { + return sp; + } + + public BoundedNativeScope(long size) { + super(Thread.currentThread()); + this.segment = newSegment(size, 1); + } + + @Override + public MemoryAddress allocate(long bytesSize, long bytesAlignment) { + checkOwnerThread(); + long min = ((MemoryAddressImpl)segment.baseAddress()).unsafeGetOffset(); + long start = Utils.alignUp(min + sp, bytesAlignment) - min; + try { + MemorySegment slice = segment.asSlice(start, bytesSize) + .withAccessModes(SCOPE_MASK); + sp = start + bytesSize; + return slice.baseAddress(); + } catch (IndexOutOfBoundsException ex) { + throw new OutOfMemoryError("Not enough space left to allocate"); + } + } + } +} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/BoundedAllocationScope.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/BoundedAllocationScope.java deleted file mode 100644 index 86bee37d84d..00000000000 --- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/BoundedAllocationScope.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.foreign; - -import jdk.incubator.foreign.NativeAllocationScope; -import jdk.incubator.foreign.MemoryAddress; -import jdk.incubator.foreign.MemorySegment; - -import java.util.OptionalLong; - -public class BoundedAllocationScope extends NativeAllocationScope { - private final MemorySegment segment; - private long sp = 0L; - - @Override - public OptionalLong byteSize() { - return OptionalLong.of(segment.byteSize()); - } - - @Override - public long allocatedBytes() { - return sp; - } - - public BoundedAllocationScope(long size) { - this.segment = MemorySegment.allocateNative(size); - } - - @Override - public MemoryAddress allocate(long bytesSize, long bytesAlignment) { - long min = ((MemoryAddressImpl)segment.baseAddress()).unsafeGetOffset(); - long start = Utils.alignUp(min + sp, bytesAlignment) - min; - try { - MemorySegment slice = segment.asSlice(start, bytesSize) - .withAccessModes(MemorySegment.READ | MemorySegment.WRITE | MemorySegment.ACQUIRE); - sp = start + bytesSize; - return slice.baseAddress(); - } catch (IndexOutOfBoundsException ex) { - throw new OutOfMemoryError("Not enough space left to allocate"); - } - } - - @Override - public void close() { - segment.close(); - } -} diff --git a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/UnboundedAllocationScope.java b/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/UnboundedAllocationScope.java deleted file mode 100644 index cc38f75f5f2..00000000000 --- a/src/jdk.incubator.foreign/share/classes/jdk/internal/foreign/UnboundedAllocationScope.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.internal.foreign; - -import jdk.incubator.foreign.NativeAllocationScope; -import jdk.incubator.foreign.MemoryAddress; -import jdk.incubator.foreign.MemorySegment; - -import java.util.ArrayList; -import java.util.List; -import java.util.OptionalLong; -import java.util.function.LongFunction; - -public class UnboundedAllocationScope extends NativeAllocationScope { - - private static final long BLOCK_SIZE = 4 * 1024; - private static final long MAX_ALLOC_SIZE = BLOCK_SIZE / 2; - - private final List<MemorySegment> usedSegments = new ArrayList<>(); - private MemorySegment segment; - private long sp = 0L; - private long size = 0L; - - @Override - public OptionalLong byteSize() { - return OptionalLong.empty(); - } - - @Override - public long allocatedBytes() { - return size; - } - - public UnboundedAllocationScope() { - this.segment = MemorySegment.allocateNative(BLOCK_SIZE); - } - - @Override - public MemoryAddress allocate(long bytesSize, long bytesAlignment) { - if (bytesSize > MAX_ALLOC_SIZE) { - MemorySegment segment = MemorySegment.allocateNative(bytesSize, bytesAlignment); - usedSegments.add(segment); - return segment.withAccessModes(MemorySegment.READ | MemorySegment.WRITE | MemorySegment.ACQUIRE) - .baseAddress(); - } - for (int i = 0; i < 2; i++) { - long min = ((MemoryAddressImpl) segment.baseAddress()).unsafeGetOffset(); - long start = Utils.alignUp(min + sp, bytesAlignment) - min; - try { - MemorySegment slice = segment.asSlice(start, bytesSize) - .withAccessModes(MemorySegment.READ | MemorySegment.WRITE | MemorySegment.ACQUIRE); - sp = start + bytesSize; - size += Utils.alignUp(bytesSize, bytesAlignment); - return slice.baseAddress(); - } catch (IndexOutOfBoundsException ex) { - sp = 0L; - usedSegments.add(segment); - segment = MemorySegment.allocateNative(BLOCK_SIZE); - } - } - throw new AssertionError("Cannot get here!"); - } - - @Override - public void close() { - segment.close(); - usedSegments.forEach(MemorySegment::close); - } -} diff --git a/test/jdk/java/foreign/Cstring.java b/test/jdk/java/foreign/Cstring.java index fc83c846c8a..8228464e15f 100644 --- a/test/jdk/java/foreign/Cstring.java +++ b/test/jdk/java/foreign/Cstring.java @@ -23,7 +23,7 @@ import java.lang.invoke.VarHandle; import java.nio.charset.Charset; -import jdk.incubator.foreign.NativeAllocationScope; +import jdk.incubator.foreign.NativeScope; import jdk.incubator.foreign.MemoryAddress; import jdk.incubator.foreign.MemoryLayout; import jdk.incubator.foreign.MemorySegment; @@ -54,7 +54,7 @@ private static MemorySegment toCString(byte[] bytes) { return segment; } - private static MemoryAddress toCString(byte[] bytes, NativeAllocationScope scope) { + private static MemoryAddress toCString(byte[] bytes, NativeScope scope) { MemoryLayout strLayout = MemoryLayout.ofSequence(bytes.length + 1, C_CHAR); MemoryAddress addr = scope.allocate(strLayout); copy(addr, bytes); @@ -77,11 +77,11 @@ public static MemorySegment toCString(String str, Charset charset) { return toCString(str.getBytes(charset)); } - public static MemoryAddress toCString(String str, NativeAllocationScope scope) { + public static MemoryAddress toCString(String str, NativeScope scope) { return toCString(str.getBytes(), scope); } - public static MemoryAddress toCString(String str, Charset charset, NativeAllocationScope scope) { + public static MemoryAddress toCString(String str, Charset charset, NativeScope scope) { return toCString(str.getBytes(charset), scope); } diff --git a/test/jdk/java/foreign/TestAllocationScope.java b/test/jdk/java/foreign/TestAllocationScope.java deleted file mode 100644 index 9eaaaa1b616..00000000000 --- a/test/jdk/java/foreign/TestAllocationScope.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -/* - * @test - * @run testng TestAllocationScope - */ - -import jdk.incubator.foreign.NativeAllocationScope; -import jdk.incubator.foreign.MemoryHandles; -import jdk.incubator.foreign.MemoryLayouts; -import jdk.incubator.foreign.MemoryLayout; -import jdk.incubator.foreign.MemoryAddress; - -import org.testng.annotations.*; - -import java.lang.invoke.VarHandle; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Function; - -import static org.testng.Assert.*; - -public class TestAllocationScope { - - final static int ELEMS = 128; - - @Test(dataProvider = "allocationScopes") - public <Z> void testAllocation(Z value, ScopeFactory scopeFactory, MemoryLayout layout, Class<?> carrier, AllocationFunction<Z> allocationFunction, Function<MemoryLayout, VarHandle> handleFactory) { - MemoryLayout[] layouts = { - layout, - layout.withBitAlignment(layout.bitAlignment() * 2), - layout.withBitAlignment(layout.bitAlignment() * 4), - layout.withBitAlignment(layout.bitAlignment() * 8) - }; - for (MemoryLayout alignedLayout : layouts) { - List<MemoryAddress> addressList = new ArrayList<>(); - int elems = ELEMS / ((int)alignedLayout.byteAlignment() / (int)layout.byteAlignment()); - try (NativeAllocationScope scope = scopeFactory.make((int)alignedLayout.byteSize() * ELEMS)) { - for (int i = 0 ; i < elems ; i++) { - MemoryAddress address = allocationFunction.allocate(scope, alignedLayout, value); - assertEquals(address.segment().byteSize(), alignedLayout.byteSize()); - addressList.add(address); - VarHandle handle = handleFactory.apply(alignedLayout); - assertEquals(value, handle.get(address)); - try { - address.segment().close(); - fail(); - } catch (UnsupportedOperationException uoe) { - //failure is expected - assertTrue(true); - } - } - boolean isBound = scope.byteSize().isPresent(); - try { - allocationFunction.allocate(scope, alignedLayout, value); //too much, should fail if bound - assertFalse(isBound); - } catch (OutOfMemoryError ex) { - //failure is expected if bound - assertTrue(isBound); - } - } - // addresses should be invalid now - for (MemoryAddress address : addressList) { - assertFalse(address.segment().isAlive()); - } - } - } - - static final int SIZE_256M = 1024 * 1024 * 256; - - @Test - public void testBigAllocationInUnboundedScope() { - try (NativeAllocationScope scope = NativeAllocationScope.unboundedScope()) { - for (int i = 8 ; i < SIZE_256M ; i *= 8) { - MemoryAddress address = scope.allocate(i); - //check size - assertEquals(address.segment().byteSize(), i); - //check alignment - assertTrue(address.segment().baseAddress().toRawLongValue() % i == 0); - } - } - } - - @DataProvider(name = "allocationScopes") - static Object[][] allocationScopes() { - return new Object[][] { - { (byte)42, (ScopeFactory) NativeAllocationScope::boundedScope, MemoryLayouts.BITS_8_BE, byte.class, - (AllocationFunction<Byte>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(byte.class) }, - { (short)42, (ScopeFactory) NativeAllocationScope::boundedScope, MemoryLayouts.BITS_16_BE, short.class, - (AllocationFunction<Short>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(short.class) }, - { 42, (ScopeFactory) NativeAllocationScope::boundedScope, - MemoryLayouts.BITS_32_BE, int.class, - (AllocationFunction<Integer>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(int.class) }, - { 42f, (ScopeFactory) NativeAllocationScope::boundedScope, MemoryLayouts.BITS_32_BE, float.class, - (AllocationFunction<Float>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(float.class) }, - { 42L, (ScopeFactory) NativeAllocationScope::boundedScope, MemoryLayouts.BITS_64_BE, long.class, - (AllocationFunction<Long>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(long.class) }, - { 42d, (ScopeFactory) NativeAllocationScope::boundedScope, MemoryLayouts.BITS_64_BE, double.class, - (AllocationFunction<Double>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(double.class) }, - { MemoryAddress.ofLong(42), (ScopeFactory) NativeAllocationScope::boundedScope, MemoryLayouts.BITS_64_BE, MemoryAddress.class, - (AllocationFunction<MemoryAddress>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> MemoryHandles.asAddressVarHandle(l.varHandle(long.class)) }, - - { (byte)42, (ScopeFactory) NativeAllocationScope::boundedScope, MemoryLayouts.BITS_8_LE, byte.class, - (AllocationFunction<Byte>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(byte.class) }, - { (short)42, (ScopeFactory) NativeAllocationScope::boundedScope, MemoryLayouts.BITS_16_LE, short.class, - (AllocationFunction<Short>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(short.class) }, - { 42, (ScopeFactory) NativeAllocationScope::boundedScope, - MemoryLayouts.BITS_32_LE, int.class, - (AllocationFunction<Integer>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(int.class) }, - { 42f, (ScopeFactory) NativeAllocationScope::boundedScope, MemoryLayouts.BITS_32_LE, float.class, - (AllocationFunction<Float>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(float.class) }, - { 42L, (ScopeFactory) NativeAllocationScope::boundedScope, MemoryLayouts.BITS_64_LE, long.class, - (AllocationFunction<Long>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(long.class) }, - { 42d, (ScopeFactory) NativeAllocationScope::boundedScope, MemoryLayouts.BITS_64_LE, double.class, - (AllocationFunction<Double>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(double.class) }, - { MemoryAddress.ofLong(42), (ScopeFactory) NativeAllocationScope::boundedScope, MemoryLayouts.BITS_64_LE, MemoryAddress.class, - (AllocationFunction<MemoryAddress>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> MemoryHandles.asAddressVarHandle(l.varHandle(long.class)) }, - - { (byte)42, (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), MemoryLayouts.BITS_8_BE, byte.class, - (AllocationFunction<Byte>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(byte.class) }, - { (short)42, (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), MemoryLayouts.BITS_16_BE, short.class, - (AllocationFunction<Short>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(short.class) }, - { 42, (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), - MemoryLayouts.BITS_32_BE, int.class, - (AllocationFunction<Integer>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(int.class) }, - { 42f, (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), MemoryLayouts.BITS_32_BE, float.class, - (AllocationFunction<Float>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(float.class) }, - { 42L, (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), MemoryLayouts.BITS_64_BE, long.class, - (AllocationFunction<Long>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(long.class) }, - { 42d, (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), MemoryLayouts.BITS_64_BE, double.class, - (AllocationFunction<Double>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(double.class) }, - { MemoryAddress.ofLong(42), (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), MemoryLayouts.BITS_64_BE, MemoryAddress.class, - (AllocationFunction<MemoryAddress>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> MemoryHandles.asAddressVarHandle(l.varHandle(long.class)) }, - - { (byte)42, (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), MemoryLayouts.BITS_8_LE, byte.class, - (AllocationFunction<Byte>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(byte.class) }, - { (short)42, (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), MemoryLayouts.BITS_16_LE, short.class, - (AllocationFunction<Short>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(short.class) }, - { 42, (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), - MemoryLayouts.BITS_32_LE, int.class, - (AllocationFunction<Integer>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(int.class) }, - { 42f, (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), MemoryLayouts.BITS_32_LE, float.class, - (AllocationFunction<Float>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(float.class) }, - { 42L, (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), MemoryLayouts.BITS_64_LE, long.class, - (AllocationFunction<Long>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(long.class) }, - { 42d, (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), MemoryLayouts.BITS_64_LE, double.class, - (AllocationFunction<Double>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> l.varHandle(double.class) }, - { MemoryAddress.ofLong(42), (ScopeFactory)size -> NativeAllocationScope.unboundedScope(), MemoryLayouts.BITS_64_LE, MemoryAddress.class, - (AllocationFunction<MemoryAddress>) NativeAllocationScope::allocate, - (Function<MemoryLayout, VarHandle>)l -> MemoryHandles.asAddressVarHandle(l.varHandle(long.class)) }, - }; - } - - interface AllocationFunction<X> { - MemoryAddress allocate(NativeAllocationScope scope, MemoryLayout layout, X value); - } - - interface ScopeFactory { - NativeAllocationScope make(int size); - } -} diff --git a/test/jdk/java/foreign/TestNativeScope.java b/test/jdk/java/foreign/TestNativeScope.java new file mode 100644 index 00000000000..10b82dc4814 --- /dev/null +++ b/test/jdk/java/foreign/TestNativeScope.java @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @run testng TestNativeScope + */ + +import jdk.incubator.foreign.MemorySegment; +import jdk.incubator.foreign.NativeScope; +import jdk.incubator.foreign.MemoryHandles; +import jdk.incubator.foreign.MemoryLayouts; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.MemoryAddress; + +import org.testng.annotations.*; + +import java.lang.invoke.VarHandle; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; + +import static jdk.incubator.foreign.MemorySegment.CLOSE; +import static jdk.incubator.foreign.MemorySegment.HANDOFF; +import static org.testng.Assert.*; + +public class TestNativeScope { + + final static int ELEMS = 128; + + @Test(dataProvider = "nativeScopes") + public <Z> void testAllocation(Z value, ScopeFactory scopeFactory, MemoryLayout layout, Class<?> carrier, AllocationFunction<Z> allocationFunction, Function<MemoryLayout, VarHandle> handleFactory) { + MemoryLayout[] layouts = { + layout, + layout.withBitAlignment(layout.bitAlignment() * 2), + layout.withBitAlignment(layout.bitAlignment() * 4), + layout.withBitAlignment(layout.bitAlignment() * 8) + }; + for (MemoryLayout alignedLayout : layouts) { + List<MemoryAddress> addressList = new ArrayList<>(); + int elems = ELEMS / ((int)alignedLayout.byteAlignment() / (int)layout.byteAlignment()); + try (NativeScope scope = scopeFactory.make((int)alignedLayout.byteSize() * ELEMS)) { + for (int i = 0 ; i < elems ; i++) { + MemoryAddress address = allocationFunction.allocate(scope, alignedLayout, value); + assertEquals(address.segment().byteSize(), alignedLayout.byteSize()); + addressList.add(address); + VarHandle handle = handleFactory.apply(alignedLayout); + assertEquals(value, handle.get(address)); + try { + address.segment().close(); + fail(); + } catch (UnsupportedOperationException uoe) { + //failure is expected + assertTrue(true); + } + } + boolean isBound = scope.byteSize().isPresent(); + try { + allocationFunction.allocate(scope, alignedLayout, value); //too much, should fail if bound + assertFalse(isBound); + } catch (OutOfMemoryError ex) { + //failure is expected if bound + assertTrue(isBound); + } + } + // addresses should be invalid now + for (MemoryAddress address : addressList) { + assertFalse(address.segment().isAlive()); + } + } + } + + static final int SIZE_256M = 1024 * 1024 * 256; + + @Test + public void testBigAllocationInUnboundedScope() { + try (NativeScope scope = NativeScope.unboundedScope()) { + for (int i = 8 ; i < SIZE_256M ; i *= 8) { + MemoryAddress address = scope.allocate(i); + //check size + assertEquals(address.segment().byteSize(), i); + //check alignment + assertTrue(address.segment().baseAddress().toRawLongValue() % i == 0); + } + } + } + + @Test + public void testAttachClose() { + MemorySegment s1 = MemorySegment.ofArray(new byte[1]); + MemorySegment s2 = MemorySegment.ofArray(new byte[1]); + MemorySegment s3 = MemorySegment.ofArray(new byte[1]); + assertTrue(s1.isAlive()); + assertTrue(s2.isAlive()); + assertTrue(s3.isAlive()); + try (NativeScope scope = NativeScope.boundedScope(10)) { + MemorySegment ss1 = scope.register(s1); + assertFalse(s1.isAlive()); + assertTrue(ss1.isAlive()); + s1 = ss1; + MemorySegment ss2 = scope.register(s2); + assertFalse(s2.isAlive()); + assertTrue(ss2.isAlive()); + s2 = ss2; + MemorySegment ss3 = scope.register(s3); + assertFalse(s3.isAlive()); + assertTrue(ss3.isAlive()); + s3 = ss3; + } + assertFalse(s1.isAlive()); + assertFalse(s2.isAlive()); + assertFalse(s3.isAlive()); + } + + @Test + public void testNoTerminalOps() { + try (NativeScope scope = NativeScope.boundedScope(10)) { + MemorySegment s1 = MemorySegment.ofArray(new byte[1]); + MemorySegment attached = scope.register(s1); + int[] terminalOps = {CLOSE, HANDOFF}; + for (int mode : terminalOps) { + if (attached.hasAccessModes(mode)) { + fail(); + } + } + } + } + + @Test(expectedExceptions = IllegalArgumentException.class) + public void testNoReattach() { + MemorySegment s1 = MemorySegment.ofArray(new byte[1]); + NativeScope scope1 = NativeScope.boundedScope(10); + NativeScope scope2 = NativeScope.boundedScope(10); + scope2.register(scope1.register(s1)); + } + + @Test(expectedExceptions = NullPointerException.class) + public void testNullClaim() { + NativeScope.boundedScope(10).register(null); + } + + @Test(expectedExceptions = IllegalStateException.class) + public void testNotAliveClaim() { + MemorySegment segment = MemorySegment.ofArray(new byte[1]); + segment.close(); + NativeScope.boundedScope(10).register(segment); + } + + @Test + public void testNoClaimFromWrongThread() throws InterruptedException { + MemorySegment s = MemorySegment.ofArray(new byte[1]); + AtomicBoolean failed = new AtomicBoolean(false); + Thread t = new Thread(() -> { + try { + NativeScope.boundedScope(10).register(s); + } catch (IllegalArgumentException ex) { + failed.set(true); + } + }); + t.start(); + t.join(); + assertTrue(failed.get()); + } + + @DataProvider(name = "nativeScopes") + static Object[][] nativeScopes() { + return new Object[][] { + { (byte)42, (ScopeFactory) NativeScope::boundedScope, MemoryLayouts.BITS_8_BE, byte.class, + (AllocationFunction<Byte>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(byte.class) }, + { (short)42, (ScopeFactory) NativeScope::boundedScope, MemoryLayouts.BITS_16_BE, short.class, + (AllocationFunction<Short>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(short.class) }, + { 42, (ScopeFactory) NativeScope::boundedScope, + MemoryLayouts.BITS_32_BE, int.class, + (AllocationFunction<Integer>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(int.class) }, + { 42f, (ScopeFactory) NativeScope::boundedScope, MemoryLayouts.BITS_32_BE, float.class, + (AllocationFunction<Float>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(float.class) }, + { 42L, (ScopeFactory) NativeScope::boundedScope, MemoryLayouts.BITS_64_BE, long.class, + (AllocationFunction<Long>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(long.class) }, + { 42d, (ScopeFactory) NativeScope::boundedScope, MemoryLayouts.BITS_64_BE, double.class, + (AllocationFunction<Double>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(double.class) }, + { MemoryAddress.ofLong(42), (ScopeFactory) NativeScope::boundedScope, MemoryLayouts.BITS_64_BE, MemoryAddress.class, + (AllocationFunction<MemoryAddress>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> MemoryHandles.asAddressVarHandle(l.varHandle(long.class)) }, + + { (byte)42, (ScopeFactory) NativeScope::boundedScope, MemoryLayouts.BITS_8_LE, byte.class, + (AllocationFunction<Byte>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(byte.class) }, + { (short)42, (ScopeFactory) NativeScope::boundedScope, MemoryLayouts.BITS_16_LE, short.class, + (AllocationFunction<Short>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(short.class) }, + { 42, (ScopeFactory) NativeScope::boundedScope, + MemoryLayouts.BITS_32_LE, int.class, + (AllocationFunction<Integer>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(int.class) }, + { 42f, (ScopeFactory) NativeScope::boundedScope, MemoryLayouts.BITS_32_LE, float.class, + (AllocationFunction<Float>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(float.class) }, + { 42L, (ScopeFactory) NativeScope::boundedScope, MemoryLayouts.BITS_64_LE, long.class, + (AllocationFunction<Long>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(long.class) }, + { 42d, (ScopeFactory) NativeScope::boundedScope, MemoryLayouts.BITS_64_LE, double.class, + (AllocationFunction<Double>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(double.class) }, + { MemoryAddress.ofLong(42), (ScopeFactory) NativeScope::boundedScope, MemoryLayouts.BITS_64_LE, MemoryAddress.class, + (AllocationFunction<MemoryAddress>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> MemoryHandles.asAddressVarHandle(l.varHandle(long.class)) }, + + { (byte)42, (ScopeFactory)size -> NativeScope.unboundedScope(), MemoryLayouts.BITS_8_BE, byte.class, + (AllocationFunction<Byte>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(byte.class) }, + { (short)42, (ScopeFactory)size -> NativeScope.unboundedScope(), MemoryLayouts.BITS_16_BE, short.class, + (AllocationFunction<Short>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(short.class) }, + { 42, (ScopeFactory)size -> NativeScope.unboundedScope(), + MemoryLayouts.BITS_32_BE, int.class, + (AllocationFunction<Integer>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(int.class) }, + { 42f, (ScopeFactory)size -> NativeScope.unboundedScope(), MemoryLayouts.BITS_32_BE, float.class, + (AllocationFunction<Float>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(float.class) }, + { 42L, (ScopeFactory)size -> NativeScope.unboundedScope(), MemoryLayouts.BITS_64_BE, long.class, + (AllocationFunction<Long>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(long.class) }, + { 42d, (ScopeFactory)size -> NativeScope.unboundedScope(), MemoryLayouts.BITS_64_BE, double.class, + (AllocationFunction<Double>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(double.class) }, + { MemoryAddress.ofLong(42), (ScopeFactory)size -> NativeScope.unboundedScope(), MemoryLayouts.BITS_64_BE, MemoryAddress.class, + (AllocationFunction<MemoryAddress>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> MemoryHandles.asAddressVarHandle(l.varHandle(long.class)) }, + + { (byte)42, (ScopeFactory)size -> NativeScope.unboundedScope(), MemoryLayouts.BITS_8_LE, byte.class, + (AllocationFunction<Byte>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(byte.class) }, + { (short)42, (ScopeFactory)size -> NativeScope.unboundedScope(), MemoryLayouts.BITS_16_LE, short.class, + (AllocationFunction<Short>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(short.class) }, + { 42, (ScopeFactory)size -> NativeScope.unboundedScope(), + MemoryLayouts.BITS_32_LE, int.class, + (AllocationFunction<Integer>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(int.class) }, + { 42f, (ScopeFactory)size -> NativeScope.unboundedScope(), MemoryLayouts.BITS_32_LE, float.class, + (AllocationFunction<Float>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(float.class) }, + { 42L, (ScopeFactory)size -> NativeScope.unboundedScope(), MemoryLayouts.BITS_64_LE, long.class, + (AllocationFunction<Long>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(long.class) }, + { 42d, (ScopeFactory)size -> NativeScope.unboundedScope(), MemoryLayouts.BITS_64_LE, double.class, + (AllocationFunction<Double>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> l.varHandle(double.class) }, + { MemoryAddress.ofLong(42), (ScopeFactory)size -> NativeScope.unboundedScope(), MemoryLayouts.BITS_64_LE, MemoryAddress.class, + (AllocationFunction<MemoryAddress>) NativeScope::allocate, + (Function<MemoryLayout, VarHandle>)l -> MemoryHandles.asAddressVarHandle(l.varHandle(long.class)) }, + }; + } + + interface AllocationFunction<X> { + MemoryAddress allocate(NativeScope scope, MemoryLayout layout, X value); + } + + interface ScopeFactory { + NativeScope make(int size); + } +}