From 8faf375c1bdbaa22660efc4f635824e1e2afdd70 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Tue, 6 Sep 2016 15:18:38 +0300 Subject: [PATCH] experiments/MemLayout: add one more prototype --- experiments/MemLayout/src/_2/main.kt | 242 +++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 experiments/MemLayout/src/_2/main.kt diff --git a/experiments/MemLayout/src/_2/main.kt b/experiments/MemLayout/src/_2/main.kt new file mode 100644 index 00000000000..55cfecab65e --- /dev/null +++ b/experiments/MemLayout/src/_2/main.kt @@ -0,0 +1,242 @@ +package _2 + +import bridge +import kotlin.reflect.KProperty +import java.io.Closeable +import NativeFunction + + +operator fun NativeFunction.invoke(vararg args: Any?): Long { + val convertedArgs = LongArray(args.size) + + val allocatedArgs = mutableListOf>() + args.forEachIndexed { i, arg -> + val convertedArg = when (arg) { + null -> 0L + is Long -> arg + is Ptr<*> -> arg.ptr + is String -> { + val cString = CString.fromString(arg) + allocatedArgs.add(cString) + cString.ptr + } + is Byte -> arg.toLong() + is Char -> arg.toLong() + is Short -> arg.toLong() + is Int -> arg.toLong() + else -> throw NotImplementedError() + } + convertedArgs[i] = convertedArg + } + try { + return bridge.call(this.ptr, *convertedArgs) + } finally { + allocatedArgs.forEach { bridge.free(it.ptr) } + } +} + +open class StructLayout(val size: Int) + +open class Ptr(val ptr: Long) + + +fun alloc(layout: T): HeapPtr { + return HeapPtr(bridge.malloc(layout.size)) +} + +class HeapPtr(ptr: Long) : Ptr(ptr), Closeable { + override fun close() { + free() + } + + fun free() { + bridge.free(ptr) + } + +} + +class ByteField(val offset: Int) { + operator fun getValue(thisRef: Ptr<*>, property: KProperty<*>): Byte { + return bridge.getByte(thisRef.ptr + offset) + } + + operator fun setValue(thisRef: Ptr<*>, property: KProperty<*>, value: Byte) { + bridge.putByte(thisRef.ptr + offset, value) + } +} + +class ShortField(val offset: Int) { + operator fun getValue(thisRef: Ptr<*>, property: KProperty<*>): Short { + return bridge.getShort(thisRef.ptr + offset) + } + + operator fun setValue(thisRef: Ptr<*>, property: KProperty<*>, value: Short) { + bridge.putShort(thisRef.ptr + offset, value) + } +} + + +class IntField(val offset: Int) { + operator fun getValue(thisRef: Ptr<*>, property: KProperty<*>): Int { + return bridge.getInt(thisRef.ptr + offset) + } + + operator fun setValue(thisRef: Ptr<*>, property: KProperty<*>, value: Int) { + bridge.putInt(thisRef.ptr + offset, value) + } +} + + +class LongField(val offset: Int) { + operator fun getValue(thisRef: Ptr<*>, property: KProperty<*>): Long { + return bridge.getLong(thisRef.ptr + offset) + } + + operator fun setValue(thisRef: Ptr<*>, property: KProperty<*>, value: Long) { + bridge.putLong(thisRef.ptr + offset, value) + } +} + +class PtrField(val offset: Int) { + operator fun getValue(thisRef: Ptr<*>, property: KProperty<*>): Ptr { + return Ptr(bridge.getLong(thisRef.ptr + offset)) + } + + operator fun setValue(thisRef: Ptr<*>, property: KProperty<*>, value: Ptr) { + bridge.putLong(thisRef.ptr + offset, value.ptr) + } +} + +class StructField(val offset: Int) { + operator fun getValue(thisRef: Ptr<*>, property: KProperty<*>) = Ptr(thisRef.ptr + offset) +} + +fun byteAt(offset: Int) = ByteField(offset) +fun shortAt(offset: Int) = ShortField(offset) +fun intAt(offset: Int) = IntField(offset) +fun longAt(offset: Int) = LongField(offset) +fun ptrAt(offset: Int) = PtrField(offset) +fun structAt(offset: Int) = StructField(offset) + +class StructArray(val elemLayout: T, length: Int) : StructLayout(elemLayout.size * length) + +class PtrToStructArray(ptr: Long, val elemLayout: StructLayout) : Ptr>(ptr) { + operator fun get(index: Int) = Ptr(ptr + elemLayout.size * index) +} + +fun allocArray(layout: StructArray) = PtrToStructArray(alloc(layout).ptr, layout.elemLayout) +fun allocArray(elemLayout: T, length: Int) = allocArray(StructArray(elemLayout, length)) + +object IntBox : StructLayout(4) +var Ptr.value by intAt(0) + +class PtrBox : StructLayout(8) +var Ptr>.value by ptrAt(0) + +class CString(length: Int) : StructLayout(length + 1) { + + companion object { + + fun fromString(str: String): Ptr { + val bytes = str.toByteArray(); // FIXME: encoding + val result = alloc(CString(bytes.size)) + + bytes.forEachIndexed { i, byte -> + result[i] = byte + } + result[bytes.size] = 0.toByte() + return result + } + } +} + +operator fun Ptr.get(index: Int) = bridge.getByte(ptr + index) +operator fun Ptr.set(index: Int, value: Byte) = bridge.putByte(ptr + index, value) + +fun Ptr.toKotlinString(): String { + + var length = 0 + while (this[length] != 0.toByte()) { + ++length + } + + val bytes = ByteArray(length) + for (i in 0 .. length-1) { + bytes.set(i, this[i]) + } + + return String(bytes) // FIXME: encoding +} + +object timespec : StructLayout(16); + +val Ptr.tv_sec by longAt(0) +val Ptr.tv_usec by longAt(8) + +object stat64 : StructLayout(144); + +val Ptr.st_dev by intAt(0) +val Ptr.st_mode by shortAt(4) +val Ptr.st_nlink by shortAt(6) +val Ptr.st_ino by longAt(8) +val Ptr.st_atimespec by structAt(32) +val Ptr.st_mtimespec by structAt(48) +val Ptr.st_ctimespec by structAt(64) +val Ptr.st_birthtimespec by structAt(80) +val Ptr.st_size by longAt(96) + +val stat64Fun = NativeFunction.lookup("stat\$INODE64")!! + +object dirent64 : StructLayout(1048); +val Ptr.d_ino by longAt(0) +val Ptr.d_seekoff by longAt(8) +val Ptr.d_reclen by shortAt(16) +val Ptr.d_namelen by shortAt(18) +val Ptr.d_type by byteAt(20) +val Ptr.d_name by structAt(21) + +val opendir = NativeFunction.lookup("opendir")!! +val readdir_r64 = NativeFunction.lookup("readdir_r\$INODE64")!! +val closedir = NativeFunction.lookup("closedir")!! + +fun main(args: Array) { + + val array = allocArray(IntBox, 5) + array[0].value = 5 + array[1].value = 6 + + println(array[0].value) + println(array[1].value) + + alloc(stat64).use { s -> + val res = stat64Fun("/etc/passwd", s) + println(res) + with(s) { + println("st_dev=$st_dev") + println("st_mode=$st_mode") + println("st_nlink=$st_nlink") + println("st_ino=$st_ino") + println("st_mtimespec.tv_sec=${st_mtimespec.tv_sec}") + println("st_size=$st_size") + } + } + + val dirp = opendir("/tmp") + try { + alloc(dirent64).use { entry -> + alloc(PtrBox()).use { result -> + + while (true) { + val errno = readdir_r64(dirp, entry, result) + if (result.value.ptr == 0L) { + break + } + println(entry.d_name.toKotlinString()) + } + + } + } + } finally { + closedir(dirp) + } +}; \ No newline at end of file