From 9c2c76e6ebba68a220d0b8d613ce64830bf69d25 Mon Sep 17 00:00:00 2001 From: Iaroslav Date: Tue, 9 Jun 2020 14:26:21 +0700 Subject: [PATCH] Implement foreign Memory implementation with JDK Incubator Foreign API (requires JDK 14) --- .../memory/foreign/ForeignMemory.kt | 51 +++++++++++++++++++ .../memory/foreign/ForeignReader.kt | 35 +++++++++++++ .../memory/foreign/ForeignWriter.kt | 35 +++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignMemory.kt create mode 100644 kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignReader.kt create mode 100644 kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignWriter.kt diff --git a/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignMemory.kt b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignMemory.kt new file mode 100644 index 000000000..fc5b518d2 --- /dev/null +++ b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignMemory.kt @@ -0,0 +1,51 @@ +package scientifik.memory.foreign + +import jdk.incubator.foreign.MemoryHandles +import jdk.incubator.foreign.MemorySegment +import scientifik.memory.Memory +import scientifik.memory.MemoryReader +import scientifik.memory.MemoryWriter +import java.lang.invoke.VarHandle +import java.nio.ByteOrder + +fun Memory.Companion.allocateForeign(length: Int): Memory { + return ForeignMemory(MemorySegment.allocateNative(length.toLong())) +} + +internal class ForeignMemory(val scope: MemorySegment) : Memory, AutoCloseable { + override val size: Int + get() = scope.byteSize().toInt() + + private val writer: MemoryWriter = ForeignWriter(this) + private val reader: MemoryReader = ForeignReader(this) + + override fun view(offset: Int, length: Int): ForeignMemory = + ForeignMemory(scope.asSlice(offset.toLong(), length.toLong())) + + override fun copy(): Memory { + val bytes = scope.toByteArray() + val newScope = MemorySegment.allocateNative(scope.byteSize())!! + + var point = newScope.baseAddress() + + bytes.forEach { + byteHandle.set(point, it) + point = point.addOffset(1) + } + + return ForeignMemory(newScope) + } + + override fun reader(): MemoryReader = reader + override fun writer(): MemoryWriter = writer + override fun close(): Unit = scope.close() + + internal companion object { + internal val doubleHandle: VarHandle = MemoryHandles.varHandle(java.lang.Double.TYPE, ByteOrder.nativeOrder())!! + internal val floatHandle: VarHandle = MemoryHandles.varHandle(java.lang.Float.TYPE, ByteOrder.nativeOrder())!! + internal val byteHandle: VarHandle = MemoryHandles.varHandle(java.lang.Byte.TYPE, ByteOrder.nativeOrder())!! + internal val shortHandle: VarHandle = MemoryHandles.varHandle(java.lang.Short.TYPE, ByteOrder.nativeOrder())!! + internal val intHandle: VarHandle = MemoryHandles.varHandle(Integer.TYPE, ByteOrder.nativeOrder())!! + internal val longHandle: VarHandle = MemoryHandles.varHandle(java.lang.Long.TYPE, ByteOrder.nativeOrder())!! + } +} diff --git a/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignReader.kt b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignReader.kt new file mode 100644 index 000000000..3de1f3f20 --- /dev/null +++ b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignReader.kt @@ -0,0 +1,35 @@ +package scientifik.memory.foreign + +import jdk.incubator.foreign.MemorySegment +import scientifik.memory.MemoryReader + +internal class ForeignReader(override val memory: ForeignMemory) : MemoryReader { + private val scope: MemorySegment + get() = memory.scope.asReadOnly() + + override fun readDouble(offset: Int): Double = with(scope) { + ForeignMemory.doubleHandle.get(baseAddress().addOffset(offset.toLong())) as Double + } + + override fun readFloat(offset: Int): Float = with(scope) { + ForeignMemory.floatHandle.get(baseAddress().addOffset(offset.toLong())) as Float + } + + override fun readByte(offset: Int): Byte = with(scope) { + ForeignMemory.byteHandle.get(baseAddress().addOffset(offset.toLong())) as Byte + } + + override fun readShort(offset: Int): Short = with(scope) { + ForeignMemory.shortHandle.get(baseAddress().addOffset(offset.toLong())) as Short + } + + override fun readInt(offset: Int): Int = with(scope) { + ForeignMemory.intHandle.get(baseAddress().addOffset(offset.toLong())) as Int + } + + override fun readLong(offset: Int): Long = with(scope) { + ForeignMemory.longHandle.get(baseAddress().addOffset(offset.toLong())) as Long + } + + override fun release(): Unit = memory.close() +} diff --git a/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignWriter.kt b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignWriter.kt new file mode 100644 index 000000000..8787e2384 --- /dev/null +++ b/kmath-memory/src/jvmMain/kotlin/scientifik/memory/foreign/ForeignWriter.kt @@ -0,0 +1,35 @@ +package scientifik.memory.foreign + +import jdk.incubator.foreign.MemorySegment +import scientifik.memory.MemoryWriter + +internal class ForeignWriter(override val memory: ForeignMemory) : MemoryWriter { + private val scope: MemorySegment + get() = memory.scope + + override fun writeDouble(offset: Int, value: Double): Unit = with(scope) { + ForeignMemory.doubleHandle.set(baseAddress().addOffset(offset.toLong()), value) + } + + override fun writeFloat(offset: Int, value: Float): Unit = with(scope) { + ForeignMemory.floatHandle.set(baseAddress().addOffset(offset.toLong()), value) + } + + override fun writeByte(offset: Int, value: Byte): Unit = with(scope) { + ForeignMemory.byteHandle.set(baseAddress().addOffset(offset.toLong()), value) + } + + override fun writeShort(offset: Int, value: Short): Unit = with(scope) { + ForeignMemory.shortHandle.set(baseAddress().addOffset(offset.toLong()), value) + } + + override fun writeInt(offset: Int, value: Int): Unit = with(scope) { + ForeignMemory.intHandle.set(baseAddress().addOffset(offset.toLong()), value) + } + + override fun writeLong(offset: Int, value: Long): Unit = with(scope) { + ForeignMemory.longHandle.set(baseAddress().addOffset(offset.toLong()), value) + } + + override fun release(): Unit = memory.close() +}