2 * Copyright (C) 2020 Michael Zucchi
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 import java.lang.invoke.*;
21 import java.lang.ref.Cleaner;
22 import jdk.incubator.foreign.*;
23 import static jdk.incubator.foreign.ValueLayout.*;
25 import java.util.AbstractList;
26 import java.util.function.Function;
27 import java.util.function.BiFunction;
28 import java.util.List;
31 * A utility for memory operations including a stack allocator.
33 * The stack allocator works like this
35 * try (Frame f = Memory.createFrame()) {
36 * MemorySegment a = f.allocate(size);
39 * Any memory allocated is freed when the frame is closed.
41 * This is MUCH faster than using MemorySegment.allocateNative().
45 // probably should be INT8 INT16, etc
46 public static final OfByte BYTE = JAVA_BYTE;
47 public static final OfShort SHORT = JAVA_SHORT.withBitAlignment(16);
48 public static final OfInt INT = JAVA_INT.withBitAlignment(32);
49 public static final OfLong LONG = JAVA_LONG.withBitAlignment(64);
50 public static final OfFloat FLOAT = JAVA_FLOAT.withBitAlignment(32);
51 public static final OfDouble DOUBLE = JAVA_DOUBLE.withBitAlignment(64);
52 public static final OfAddress POINTER = ADDRESS.withBitAlignment(64);
54 static final ResourceScope sharedScope = ResourceScope.newSharedScope(); // cleaner?
55 static final MemorySegment NULL = MemorySegment.ofAddress(MemoryAddress.NULL, 1, ResourceScope.globalScope());
57 public static ResourceScope sharedScope() {
61 public static MethodHandle downcall(String name, FunctionDescriptor desc) {
62 return SymbolLookup.loaderLookup().lookup(name)
63 .map(sym -> CLinker.systemCLinker().downcallHandle(sym, desc))
67 public static MethodHandle downcall(NativeSymbol sym, FunctionDescriptor desc) {
68 return CLinker.systemCLinker().downcallHandle(sym, desc);
71 public static MethodHandle downcall(String name, MemoryAddress sym, FunctionDescriptor desc, ResourceScope scope) {
72 return sym != MemoryAddress.NULL
73 ? CLinker.systemCLinker().downcallHandle(NativeSymbol.ofAddress(name, sym, scope), desc)
77 static final MethodHandles.Lookup lookup = MethodHandles.lookup();
79 public static NativeSymbol upcall(Object instance, FunctionDescriptor desc, ResourceScope scope) {
81 java.lang.reflect.Method m = instance.getClass().getMethods()[0];
82 MethodHandle handle = lookup.findVirtual(instance.getClass(), "call", MethodType.methodType(m.getReturnType(), m.getParameterTypes()))
84 return CLinker.systemCLinker().upcallStub(handle, desc, scope);
85 } catch (Throwable t) {
86 throw new AssertionError(t);
91 public static NativeSymbol upcall(Object instance, String method, String signature, FunctionDescriptor desc, ResourceScope scope) {
93 MethodHandle handle = lookup.findVirtual(instance.getClass(), method, MethodType.fromMethodDescriptorString(signature, Memory.class.getClassLoader()))
95 return CLinker.systemCLinker().upcallStub(handle, desc, scope);
96 } catch (Throwable t) {
97 throw new AssertionError(t);
101 static final ResourceScope scope = ResourceScope.newSharedScope(Cleaner.create());
102 private static final ThreadLocal<Stack> stacks = ThreadLocal.withInitial(() -> new Stack(scope));
104 public static Frame createFrame() {
105 return stacks.get().createFrame();
110 private final MemorySegment stack;
112 private Thread thread = Thread.currentThread();
114 Stack(ResourceScope scope) {
115 stack = MemorySegment.allocateNative(4096, 4096, scope);
119 Frame createFrame() {
122 private final long tos = sp;
123 private Thread self = thread;
124 private ResourceScope scope;
127 public MemorySegment allocate(long size, long alignment) {
128 if (self != Thread.currentThread())
129 throw new IllegalStateException();
130 if (alignment != Long.highestOneBit(alignment))
131 throw new IllegalArgumentException();
133 sp = (sp - size) & ~(alignment - 1);
134 return stack.asSlice(sp, size).fill((byte)0);
137 scope = ResourceScope.newConfinedScope();
138 return MemorySegment.allocateNative(size, alignment, scope);
143 public void close() {
155 public interface Addressable {
156 MemoryAddress address();
157 ResourceScope scope();
160 public interface Array<T> {
162 T getAtIndex(long i);
165 public record FunctionPointer<T>(NativeSymbol symbol, T function) {
168 public static MemoryAddress address(jdk.incubator.foreign.Addressable v) {
169 return v != null ? v.address() : MemoryAddress.NULL;
172 public static MemoryAddress address(Memory.Addressable v) {
173 return v != null ? v.address() : MemoryAddress.NULL;
176 public static <T> MemoryAddress address(FunctionPointer<T> v) {
177 return v != null ? v.symbol().address() : MemoryAddress.NULL;
180 public static long length(List<?> list) {
181 return list != null ? list.size() : 0;
184 public static long length(Array<?> list) {
185 return list != null ? list.length() : 0;
188 public static long size(MemorySegment s) {
189 return s != null ? s.byteSize() : 0;
192 // hmm do i want this or not?
193 // -> added 'type safety'
194 // -> load of crap to be written
195 public static class ByteArray extends AbstractList<Byte> implements Memory.Addressable {
196 final MemorySegment segment;
198 private ByteArray(MemorySegment segment) {
199 this.segment = segment;
202 public static ByteArray create(MemorySegment segment) {
203 return new ByteArray(segment);
206 public static ByteArray createArray(MemoryAddress address, long length, ResourceScope scope) {
207 return create(MemorySegment.ofAddress(address, length, scope));
210 public static ByteArray createArray(MemoryAddress address, ResourceScope scope) {
211 return create(MemorySegment.ofAddress(address, Long.MAX_VALUE, scope));
214 public static ByteArray createArray(long length, SegmentAllocator alloc) {
215 return create(alloc.allocateArray(Memory.BYTE, length));
218 public static ByteArray create(String value, SegmentAllocator alloc) {
219 return create(alloc.allocateUtf8String(value));
222 public static ByteArray create(String value, ResourceScope scope) {
223 return create(SegmentAllocator.nativeAllocator(scope).allocateUtf8String(value));
226 public final MemoryAddress address() {
227 return segment.address();
230 public final ResourceScope scope() {
231 return segment.scope();
236 return (int)length();
240 public Byte get(int index) {
241 return getAtIndex(index);
245 public Byte set(int index, Byte value) {
246 byte old = getAtIndex(index);
247 setAtIndex(index, value);
251 public long length() {
252 return segment.byteSize() / Memory.BYTE.byteSize();
255 public byte getAtIndex(long index) {
256 return (byte)segment.get(Memory.BYTE, index);
259 public void setAtIndex(long index, byte value) {
260 segment.set(Memory.BYTE, index, value);
264 public static class ShortArray extends AbstractList<Short> implements Memory.Addressable {
265 final MemorySegment segment;
267 private ShortArray(MemorySegment segment) {
268 this.segment = segment;
271 public static ShortArray create(MemorySegment segment) {
272 return new ShortArray(segment);
275 public static ShortArray createArray(MemoryAddress address, long length, ResourceScope scope) {
276 return create(MemorySegment.ofAddress(address, length * Memory.SHORT.byteSize(), scope));
279 public static ShortArray createArray(MemoryAddress address, ResourceScope scope) {
280 return create(MemorySegment.ofAddress(address, Long.MAX_VALUE, scope));
283 public static ShortArray createArray(long length, SegmentAllocator alloc) {
284 return create(alloc.allocateArray(Memory.SHORT, length));
287 public static ShortArray create(SegmentAllocator alloc, short... values) {
288 return create(alloc.allocateArray(Memory.SHORT, values));
291 public final MemoryAddress address() {
292 return segment.address();
295 public final ResourceScope scope() {
296 return segment.scope();
301 return (int)length();
305 public Short get(int index) {
306 return getAtIndex(index);
310 public Short set(int index, Short value) {
311 short old = getAtIndex(index);
312 setAtIndex(index, value);
316 public long length() {
317 return segment.byteSize() / Memory.SHORT.byteSize();
320 public short getAtIndex(long index) {
321 return segment.getAtIndex(Memory.SHORT, index);
324 public void setAtIndex(long index, short value) {
325 segment.setAtIndex(Memory.SHORT, index, value);
329 public static class IntArray extends AbstractList<Integer> implements Memory.Addressable {
330 final MemorySegment segment;
332 private IntArray(MemorySegment segment) {
333 this.segment = segment;
336 public static IntArray create(MemorySegment segment) {
337 return new IntArray(segment);
340 public static IntArray createArray(MemoryAddress address, long length, ResourceScope scope) {
341 return create(MemorySegment.ofAddress(address, length * Memory.INT.byteSize(), scope));
344 public static IntArray createArray(MemoryAddress address, ResourceScope scope) {
345 return create(MemorySegment.ofAddress(address, Long.MAX_VALUE, scope));
348 public static IntArray createArray(long length, SegmentAllocator alloc) {
349 return create(alloc.allocateArray(Memory.INT, length));
352 public static IntArray create(SegmentAllocator alloc, int... values) {
353 return create(alloc.allocateArray(Memory.INT, values));
356 public final MemoryAddress address() {
357 return segment.address();
360 public final ResourceScope scope() {
361 return segment.scope();
366 return (int)length();
370 public Integer get(int index) {
371 return getAtIndex(index);
375 public Integer set(int index, Integer value) {
376 int old = getAtIndex(index);
377 setAtIndex(index, value);
381 public long length() {
382 return segment.byteSize() / Memory.INT.byteSize();
385 public int getAtIndex(long index) {
386 return segment.getAtIndex(Memory.INT, index);
389 public void setAtIndex(long index, int value) {
390 segment.setAtIndex(Memory.INT, index, value);
394 public static class LongArray extends AbstractList<Long> implements Memory.Addressable {
395 final MemorySegment segment;
397 public LongArray(MemorySegment segment) {
398 this.segment = segment;
401 public static LongArray create(MemorySegment segment) {
402 return new LongArray(segment);
405 public static LongArray createArray(MemoryAddress address, long length, ResourceScope scope) {
406 return create(MemorySegment.ofAddress(address, length * Memory.LONG.byteSize(), scope));
409 public static LongArray createArray(long length, SegmentAllocator alloc) {
410 return create(alloc.allocateArray(Memory.LONG, length));
413 public static LongArray create(SegmentAllocator alloc, long... values) {
414 return create(alloc.allocateArray(Memory.LONG, values));
417 public final MemoryAddress address() {
418 return segment.address();
421 public final ResourceScope scope() {
422 return segment.scope();
427 return (int)length();
431 public Long get(int index) {
432 return getAtIndex(index);
436 public Long set(int index, Long value) {
437 long old = getAtIndex(index);
438 setAtIndex(index, value);
442 public long length() {
443 return segment.byteSize() / Memory.LONG.byteSize();
446 public long getAtIndex(long index) {
447 return segment.getAtIndex(Memory.LONG, index);
450 public void setAtIndex(long index, long value) {
451 segment.setAtIndex(Memory.LONG, index, value);
455 public static class FloatArray extends AbstractList<Float> implements Memory.Addressable {
456 final MemorySegment segment;
458 private FloatArray(MemorySegment segment) {
459 this.segment = segment;
462 public static FloatArray create(MemorySegment segment) {
463 return new FloatArray(segment);
466 public static FloatArray createArray(MemoryAddress address, long length, ResourceScope scope) {
467 return create(MemorySegment.ofAddress(address, length * FLOAT.byteSize(), scope));
470 public static FloatArray createArray(MemoryAddress address, ResourceScope scope) {
471 return create(MemorySegment.ofAddress(address, Long.MAX_VALUE, scope));
474 public static FloatArray createArray(long length, SegmentAllocator alloc) {
475 return create(alloc.allocateArray(Memory.FLOAT, length));
478 public static FloatArray create(SegmentAllocator alloc, float... values) {
479 return create(alloc.allocateArray(Memory.FLOAT, values));
482 public final MemoryAddress address() {
483 return segment.address();
486 public final ResourceScope scope() {
487 return segment.scope();
492 return (int)length();
496 public Float get(int index) {
497 return getAtIndex(index);
501 public Float set(int index, Float value) {
502 float old = getAtIndex(index);
503 setAtIndex(index, value);
507 public long length() {
508 return segment.byteSize() / Memory.FLOAT.byteSize();
511 public float getAtIndex(long index) {
512 return segment.getAtIndex(Memory.FLOAT, index);
515 public void setAtIndex(long index, float value) {
516 segment.setAtIndex(Memory.FLOAT, index, value);
520 public static class DoubleArray extends AbstractList<Double> implements Memory.Addressable {
521 final MemorySegment segment;
523 private DoubleArray(MemorySegment segment) {
524 this.segment = segment;
527 public static DoubleArray create(MemorySegment segment) {
528 return new DoubleArray(segment);
531 public static DoubleArray createArray(MemoryAddress address, long length, ResourceScope scope) {
532 return create(MemorySegment.ofAddress(address, length * Memory.DOUBLE.byteSize(), scope));
535 public static DoubleArray createArray(MemoryAddress address, ResourceScope scope) {
536 return create(MemorySegment.ofAddress(address, Long.MAX_VALUE, scope));
539 public static DoubleArray createArray(long length, SegmentAllocator alloc) {
540 return create(alloc.allocateArray(Memory.DOUBLE, length));
543 public static DoubleArray create(SegmentAllocator alloc, double... values) {
544 return create(alloc.allocateArray(Memory.DOUBLE, values));
547 public final MemoryAddress address() {
548 return segment.address();
551 public final ResourceScope scope() {
552 return segment.scope();
557 return (int)length();
561 public Double get(int index) {
562 return getAtIndex(index);
566 public Double set(int index, Double value) {
567 double old = getAtIndex(index);
568 setAtIndex(index, value);
572 public long length() {
573 return segment.byteSize() / Memory.DOUBLE.byteSize();
576 public double getAtIndex(long index) {
577 return segment.getAtIndex(Memory.DOUBLE, index);
580 public void setAtIndex(long index, double value) {
581 segment.setAtIndex(Memory.DOUBLE, index, value);
585 public static class PointerArray extends AbstractList<MemoryAddress> implements Memory.Addressable {
586 final MemorySegment segment;
588 private PointerArray(MemorySegment segment) {
589 this.segment = segment;
592 public static PointerArray create(MemorySegment segment) {
593 return new PointerArray(segment);
596 public static PointerArray createArray(MemoryAddress address, long length, ResourceScope scope) {
597 return create(MemorySegment.ofAddress(address, length, scope));
600 public static PointerArray createArray(long length, SegmentAllocator alloc) {
601 return create(alloc.allocateArray(Memory.POINTER, length));
604 public static PointerArray create(Frame alloc, MemoryAddress... values) {
605 return create(alloc.allocateArray(Memory.POINTER, values));
608 public final MemoryAddress address() {
609 return segment.address();
612 public final ResourceScope scope() {
613 return segment.scope();
618 return (int)length();
622 public MemoryAddress get(int index) {
623 return getAtIndex(index);
627 public MemoryAddress set(int index, MemoryAddress value) {
628 MemoryAddress old = getAtIndex(index);
629 setAtIndex(index, value);
633 public long length() {
634 return segment.byteSize() / Memory.POINTER.byteSize();
637 public MemoryAddress getAtIndex(long index) {
638 return segment.getAtIndex(Memory.POINTER, index);
641 public void setAtIndex(long index, MemoryAddress value) {
642 segment.setAtIndex(Memory.POINTER, index, value);
646 // This needs a separate scope from the array itself
647 public static class HandleArray<T extends Memory.Addressable> extends AbstractList<T> implements Memory.Addressable {
648 public final MemorySegment segment;
649 final ResourceScope scope;
650 BiFunction<MemoryAddress,ResourceScope,T> create;
652 private HandleArray(MemorySegment segment, BiFunction<MemoryAddress,ResourceScope,T> create, ResourceScope scope) {
653 this.segment = segment;
654 this.create = create;
658 public static <T extends Memory.Addressable> HandleArray<T> create(MemorySegment segment, BiFunction<MemoryAddress,ResourceScope,T> create) {
659 return new HandleArray<>(segment, create, segment.scope());
662 public static <T extends Memory.Addressable> HandleArray<T> create(MemorySegment segment, BiFunction<MemoryAddress,ResourceScope,T> create, ResourceScope scope) {
663 return new HandleArray<>(segment, create, scope);
666 public static <T extends Memory.Addressable> HandleArray<T> createArray(long size, SegmentAllocator alloc, BiFunction<MemoryAddress,ResourceScope,T> create) {
667 return create(alloc.allocateArray(Memory.POINTER, size), create);
670 public static <T extends Memory.Addressable> HandleArray<T> createArray(long size, SegmentAllocator alloc, BiFunction<MemoryAddress,ResourceScope,T> create, ResourceScope scope) {
671 return create(alloc.allocateArray(Memory.POINTER, size), create, scope);
674 public static <T extends Memory.Addressable> HandleArray<T> createArray(MemoryAddress address, long size, BiFunction<MemoryAddress,ResourceScope,T> create, ResourceScope scope) {
675 return create(MemorySegment.ofAddress(address, size * Memory.POINTER.byteSize(), scope), create);
679 public final MemoryAddress address() {
680 return segment.address();
683 public final ResourceScope scope() {
684 return segment.scope();
689 return (int)length();
693 public T get(int index) {
694 return getAtIndex(index);
698 public T set(int index, T value) {
699 T old = getAtIndex(index);
700 setAtIndex(index, value);
704 public long length() {
705 return segment.byteSize() / Memory.POINTER.byteSize();
708 public T getAtIndex(long index) {
709 MemoryAddress ptr = segment.getAtIndex(Memory.POINTER, index);
710 return ptr != null ? create.apply(ptr, scope) : null;
713 public void setAtIndex(long index, T value) {
714 segment.setAtIndex(Memory.POINTER, index, value != null ? value.address() : MemoryAddress.NULL);