From a58d682d405f219b481961d9d55ba8ec076211f4 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Tue, 22 Nov 2016 12:10:49 +0700 Subject: [PATCH] Interop: remove old version --- .../kotlin/kotlin_native/interop/Bridge.kt | 46 --- .../kotlin/kotlin_native/interop/Callbacks.kt | 287 ------------------ .../kotlin/kotlin_native/interop/Types.kt | 202 ------------ .../kotlin/kotlin_native/interop/Utils.kt | 76 ----- 4 files changed, 611 deletions(-) delete mode 100644 Interop/Runtime/src/main/kotlin/kotlin_native/interop/Bridge.kt delete mode 100644 Interop/Runtime/src/main/kotlin/kotlin_native/interop/Callbacks.kt delete mode 100644 Interop/Runtime/src/main/kotlin/kotlin_native/interop/Types.kt delete mode 100644 Interop/Runtime/src/main/kotlin/kotlin_native/interop/Utils.kt diff --git a/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Bridge.kt b/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Bridge.kt deleted file mode 100644 index 611202f6cdc..00000000000 --- a/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Bridge.kt +++ /dev/null @@ -1,46 +0,0 @@ -package kotlin_native.interop - -import sun.misc.Unsafe - -data class NativePtr private constructor(internal val value: Long) { - - fun displacedBy(offset: Int) = NativePtr(value + offset) - - companion object { - fun byValue(value: Long): NativePtr? { - return if (value == 0L) { - null - } else { - NativePtr(value) - } - } - } -} - -fun NativePtr?.asLong() = if (this == null) 0L else value - -internal object bridge { - - fun malloc(size: Int): NativePtr = NativePtr.byValue(unsafe.allocateMemory(size.toLong()))!! - fun free(ptr: NativePtr) = unsafe.freeMemory(ptr.asLong()) - - fun getInt64(ptr: NativePtr): Long = unsafe.getLong(ptr.asLong()) - fun putInt64(ptr: NativePtr, value: Long) = unsafe.putLong(ptr.asLong(), value) - - fun getPtr(ptr: NativePtr): NativePtr? = NativePtr.byValue(unsafe.getLong(ptr.asLong())) - fun putPtr(ptr: NativePtr, value: NativePtr?) = unsafe.putLong(ptr.asLong(), value.asLong()) - - fun getInt32(ptr: NativePtr): Int = unsafe.getInt(ptr.asLong()) - fun putInt32(ptr: NativePtr, value: Int) = unsafe.putInt(ptr.asLong(), value) - - fun getInt16(ptr: NativePtr): Short = unsafe.getShort(ptr.asLong()) - fun putInt16(ptr: NativePtr, value: Short) = unsafe.putShort(ptr.asLong(), value) - - fun getInt8(ptr: NativePtr): Byte = unsafe.getByte(ptr.asLong()) - fun putInt8(ptr: NativePtr, value: Byte) = unsafe.putByte(ptr.asLong(), value) - - private val unsafe = with(Unsafe::class.java.getDeclaredField("theUnsafe")) { - isAccessible = true - return@with this.get(null) as Unsafe - } -} \ No newline at end of file diff --git a/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Callbacks.kt b/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Callbacks.kt deleted file mode 100644 index 15389fae432..00000000000 --- a/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Callbacks.kt +++ /dev/null @@ -1,287 +0,0 @@ -package kotlin_native.interop - -/** - * This class provides a way to create a stable handle to any Kotlin object. - * Its [value] can be safely passed to native code e.g. to be received in a Kotlin callback. - * - * Any [StableObjPtr] should be manually [disposed][dispose] - */ -data class StableObjPtr private constructor(val value: NativePtr) { - - companion object { - - /** - * Creates a handle for given object. - */ - fun create(any: Any) = StableObjPtr(NativePtr.byValue(newGlobalRef(any))!!) - - /** - * Creates [StableObjPtr] from given raw value. - * - * @param value must be a [value] of some [StableObjPtr] - */ - fun fromValue(value: NativePtr) = StableObjPtr(value) - - init { - loadCallbacksLibrary() - } - } - - /** - * Disposes the handle. It must not be [used][get] after that. - */ - fun dispose() { - deleteGlobalRef(value.value) - } - - /** - * Returns the object this handle was [created][create] for. - */ - fun get(): Any = derefGlobalRef(value.value) - -} - -/** - * Describes the type of native function. - * - * The instances of this class are supposed to be Kotlin objects (singletons), - * because creating the instance implies allocating some amount of non-freeable memory for the instance itself - * and for any unique Kotlin function "converted" to this type. - * - * Native function type definition consists in the following: - * - Definitions of native function's parameter and return types to be passed into the constructor - * - Implementation of [invoke] method which describes how to convert between these types and Kotlin types used in [F] - * - * @param F Kotlin function type corresponding to given native function type -*/ -abstract class NativeFunctionType> protected constructor(returnType: CType, vararg paramTypes: CType) { - - /** - * Returns a native function of this type, which calls given Kotlin *static* function. - * - * Given function must be *static*, i.e. an (unbound) reference to a Kotlin function or - * a closure which doesn't capture any variable - */ - fun fromStatic(function: F): NativePtr { - // TODO: optimize synchronization - synchronized(cache) { - return cache.getOrPut(function, { createFromStatic(function) }) - } - } - - /** - * Describes the C type of a function's parameter or return value. - * It is supposed to be constructed using the primitive types (such as [SInt32]) and the [Struct] combinator. - * - * This description omits the details that are irrelevant for the ABI. - */ - protected open class CType internal constructor(val ffiType: ffi_type) { - internal constructor(ffiTypePtr: Long) : this(NativePtr.byValue(ffiTypePtr).asRef(ffi_type)!!) - } - - protected object Void : CType(ffiTypeVoid()) - protected object UInt8 : CType(ffiTypeUInt8()) - protected object SInt8 : CType(ffiTypeSInt8()) - protected object UInt16 : CType(ffiTypeUInt16()) - protected object SInt16 : CType(ffiTypeSInt16()) - protected object UInt32 : CType(ffiTypeUInt32()) - protected object SInt32 : CType(ffiTypeSInt32()) - protected object UInt64 : CType(ffiTypeUInt64()) - protected object SInt64 : CType(ffiTypeSInt64()) - protected object Pointer : CType(ffiTypePointer()) - - protected class Struct(vararg elementTypes: CType) : CType( - ffiTypeStruct( - elementTypes.map { it.ffiType } - ) - ) - - /** - * This method should invoke given Kotlin function. - * - * @param args array of pointers to arguments to be passed to [function] - * @param ret pointer to memory to be filled with return value of [function] - */ - protected abstract fun invoke(function: F, args: NativeArray, ret: NativePtr) - - companion object { - init { - loadCallbacksLibrary() - } - } - - private val ffiCif = ffiCreateCif(returnType.ffiType, paramTypes.map { it.ffiType }) - - /** - * Allocates a native function of this type for given Kotlin function. - */ - private fun createFromStatic(function: F): NativePtr { - if (!isStatic(function)) { - throw IllegalArgumentException() - } - - val impl = { ret: NativePtr, args: NativeArray -> - invoke(function, args, ret) - } - - return ffiCreateClosure(ffiCif, impl) - } - - /** - * Returns `true` if given function is *static* as defined in [fromStatic]. - */ - private fun isStatic(function: Function<*>): Boolean { - // TODO: revise - try { - with(function.javaClass.getDeclaredField("INSTANCE")) { - if (!java.lang.reflect.Modifier.isStatic(modifiers) || !java.lang.reflect.Modifier.isFinal(modifiers)) { - return false - } - - isAccessible = true // TODO: undo - - return get(null) == function - } - } catch (e: NoSuchFieldException) { - return false - } - } - - private val cache = mutableMapOf() -} - -/** - * @see NativeFunctionType.fromStatic - */ -fun > F.staticAsNative(type: NativeFunctionType) = type.fromStatic(this) - -/** - * Describes a "struct" with native function pointer field. - */ -class NativeFunctionBox>(ptr: NativePtr, private val type: NativeFunctionType) : NativeRef(ptr) { - - /** - * Sets the function pointer field to null or native function calling given Kotlin function. - */ - fun setStatic(function: F?) { - val nativeFunPtr = function?.staticAsNative(type) - bridge.putPtr(ptr, nativeFunPtr) - } -} - -val > NativeFunctionType.ref: NativeRef.TypeWithSize> - get() = NativeRef.TypeWithSize(8, { NativeFunctionBox(it, this) }) // TODO: 64-bit specific - - -private fun loadCallbacksLibrary() { - System.loadLibrary("callbacks") -} - - -/** - * Reference to `ffi_type` struct instance. - */ -internal class ffi_type (ptr: NativePtr) : NativeRef(ptr) { - companion object : Type(::ffi_type) -} - -/** - * Reference to `ffi_cif` struct instance. - */ -internal class ffi_cif (ptr: NativePtr) : NativeRef(ptr) { - companion object : Type(::ffi_cif) -} - -private external fun ffiTypeVoid(): Long -private external fun ffiTypeUInt8(): Long -private external fun ffiTypeSInt8(): Long -private external fun ffiTypeUInt16(): Long -private external fun ffiTypeSInt16(): Long -private external fun ffiTypeUInt32(): Long -private external fun ffiTypeSInt32(): Long -private external fun ffiTypeUInt64(): Long -private external fun ffiTypeSInt64(): Long -private external fun ffiTypePointer(): Long - -private external fun ffiTypeStruct0(elements: Long): Long - -/** - * Allocates and initializes `ffi_type` describing the struct. - * - * @param elements types of the struct elements - */ -private fun ffiTypeStruct(elementTypes: List): ffi_type { - val elements = mallocNativeArrayOf(ffi_type, *elementTypes.toTypedArray(), null).ptr - val res = ffiTypeStruct0(elements.value) - if (res == 0L) { - throw OutOfMemoryError() - } - return NativePtr.byValue(res).asRef(ffi_type)!! -} - -private external fun ffiCreateCif0(nArgs: Int, rType: Long, argTypes: Long): Long - -/** - * Creates and prepares an `ffi_cif`. - * - * @param returnType native function return value type - * @param paramTypes native function parameter types - * - * @return the initialized `ffi_cif` - */ -private fun ffiCreateCif(returnType: ffi_type, paramTypes: List): ffi_cif { - val nArgs = paramTypes.size - val rType = returnType.ptr - val argTypes = mallocNativeArrayOf(ffi_type, *paramTypes.toTypedArray(), null).ptr - val res = ffiCreateCif0(nArgs, rType.value, argTypes.value) - - when (res) { - 0L -> throw OutOfMemoryError() - -1L -> throw Error("FFI_BAD_TYPEDEF") - -2L -> throw Error("FFI_BAD_ABI") - -3L -> throw Error("libffi error occurred") - } - - return NativePtr.byValue(res).asRef(ffi_cif)!! -} - -private fun ffiFunImpl0(ffiCif: Long, ret: Long, args: Long, userData: Any) { - ffiFunImpl(NativePtr.byValue(ffiCif).asRef(ffi_cif)!!, - NativePtr.byValue(ret)!!, - NativePtr.byValue(args).asRef(array(NativePtrBox))!!, - userData as (ret: NativePtr, args: NativeArray) -> Unit) -} - -/** - * This function is called from native code when a native function created with [ffiCreateClosure] is invoked. - * - * @param ret pointer to memory to be filled with return value of the invoked native function - * @param args pointer to array of pointers to arguments passed to the invoked native function - */ -private fun ffiFunImpl(ffiCif: ffi_cif, ret: NativePtr, args: NativeArray, - userData: (NativePtr, NativeArray) -> Unit) { - - userData.invoke(ret, args) -} - -private external fun ffiCreateClosure0(ffiCif: Long, userData: Any): Long - -/** - * Uses libffi to allocate a native function which will call [ffiFunImpl] when invoked. - * - * @param ffiCif describes the type of the function to create - */ -private fun ffiCreateClosure(ffiCif: ffi_cif, userData: (NativePtr, NativeArray) -> Unit): NativePtr { - val res = ffiCreateClosure0(ffiCif.ptr.value, userData) - - when (res) { - 0L -> throw OutOfMemoryError() - -1L -> throw Error("libffi error occurred") - } - - return NativePtr.byValue(res)!! -} - -private external fun newGlobalRef(any: Any): Long -private external fun derefGlobalRef(ref: Long): Any -private external fun deleteGlobalRef(ref: Long) \ No newline at end of file diff --git a/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Types.kt b/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Types.kt deleted file mode 100644 index d51d41770c7..00000000000 --- a/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Types.kt +++ /dev/null @@ -1,202 +0,0 @@ -package kotlin_native.interop - -import java.io.Closeable - -// TODO: what about equals/hashCode? - -open class NativeRef(val ptr: NativePtr) { - open class Type(val byPtr: (NativePtr) -> T) - open class TypeWithSize(val size: Int, byPtr: (NativePtr) -> T) : NativeRef.Type(byPtr) - - final override fun equals(other: Any?): Boolean{ - if (this === other) return true - if (other !is NativeRef) return false - - return ptr == other.ptr - } - - final override fun hashCode(): Int{ - return ptr.hashCode() - } -} - -fun NativePtr?.asRef(type: NativeRef.Type) = this?.let { type.byPtr(this) } -fun NativeRef?.getNativePtr() = this?.ptr - -class Int8Box(ptr: NativePtr) : NativeRef(ptr) { - companion object : NativeRef.TypeWithSize(1, ::Int8Box) - var value: Byte - get() = bridge.getInt8(ptr) - set(value) = bridge.putInt8(ptr, value) -} - -class Int16Box(ptr: NativePtr) : NativeRef(ptr) { - companion object : NativeRef.TypeWithSize(2, ::Int16Box) - var value: Short - get() = bridge.getInt16(ptr) - set(value) = bridge.putInt16(ptr, value) -} - -class Int32Box(ptr: NativePtr) : NativeRef(ptr) { - companion object : NativeRef.TypeWithSize(4, ::Int32Box) - var value: Int - get() = bridge.getInt32(ptr) - set(value) = bridge.putInt32(ptr, value) -} - -class NativePtrBox(ptr: NativePtr) : NativeRef(ptr) { - companion object : NativeRef.TypeWithSize(8, ::NativePtrBox) // TODO: 64-bit specific - var value: NativePtr? - get() = bridge.getPtr(ptr) - set(value) = bridge.putPtr(ptr, value) -} - -class Int64Box(ptr: NativePtr) : NativeRef(ptr) { - companion object : NativeRef.TypeWithSize(8, ::Int64Box) - var value: Long - get() = bridge.getInt64(ptr) - set(value) = bridge.putInt64(ptr, value) -} - -class RefBox(ptr: NativePtr, val referentType: NativeRef.Type) : NativeRef(ptr) { - companion object { - infix fun of(type: NativeRef.Type) = NativeRef.TypeWithSize>(8, { RefBox(it, type) }) // TODO: 64-bit specific - } - - var value: T? - get() = bridge.getPtr(ptr).asRef(referentType) - set(value) = bridge.putPtr(ptr, value.getNativePtr()) -} - -val NativeRef.Type.ref: NativeRef.TypeWithSize> - get() = Ref to this - -object Ref { - infix fun to(type: NativeRef.Type) = RefBox.Companion of type - infix fun to(type: Byte.Companion) = Int8Box.Companion - infix fun to(type: Short.Companion) = Int16Box.Companion - infix fun to(type: Int.Companion) = Int32Box.Companion - infix fun to(type: Long.Companion) = Int64Box.Companion -} - -open class NativeStruct(ptr: NativePtr) : NativeRef(ptr) { - open class Type(size: Int, byPtr: (NativePtr) -> T) : NativeRef.TypeWithSize(size, byPtr) - - companion object { - class FieldAt(val type: NativeRef.Type, val offset: Int) { - operator fun getValue(thisRef: NativeStruct, property: kotlin.reflect.KProperty<*>): T { - return type.byPtr(thisRef.ptr.displacedBy(offset)) - } - } - - infix fun NativeRef.Type.at(offset: Int) = NativeStruct.Companion.FieldAt(this, offset) - } -} - -class NativeArray(ptr: NativePtr, val elemType: NativeRef.TypeWithSize) : NativeRef(ptr) { - operator fun get(index: Int): T { - return elemType.byPtr(ptr.displacedBy(index * elemType.size)) - } - - companion object { - - class Type (val elemType: NativeRef.TypeWithSize) : - NativeRef.Type>({ ptr -> NativeArray(ptr, elemType) }) { - - infix fun length(length: Int) = - NativeRef.TypeWithSize(elemType.size * length, { ptr -> NativeArray(ptr, elemType) }) - } - - infix fun of(elemType: NativeRef.TypeWithSize) = NativeArray.Companion.Type(elemType) - - fun byRefToFirstElem(ref: T, refType: NativeRef.TypeWithSize) = NativeArray(ref.ptr, refType) - } -} - -operator fun NativeRef.TypeWithSize.get(length: Int) = NativeArray.Companion of this length length -object array { - - // array(type) - operator fun invoke(type: NativeRef.TypeWithSize) = NativeArray.Companion of type - - // array[length](type) - operator fun get(length: Int) = array.ArrayWithLength(length) - - class ArrayWithLength(val length: Int) { - infix fun of(type: NativeRef.TypeWithSize) = NativeArray.Companion of type length length - - operator fun invoke(type: NativeRef.TypeWithSize) = this of type - } - -} - - -class CString private constructor(internal val array: NativeArray) : NativeRef(array.ptr) { - companion object { - fun fromArray(array: NativeArray) = CString(array) - } - - fun length(): Int { - var res = 0 - while (array[res].value != 0.toByte()) { - ++res - } - return res - } - - override fun toString(): String { - val bytes = ByteArray(this.length()) - bytes.forEachIndexed { i, byte -> - bytes[i] = this.array[i].value - } - return String(bytes) // TODO: encoding - } - - fun asCharPtr() = array[0] -} - -class __va_list_tag(ptr: NativePtr) : NativeRef(ptr) // FIXME - -interface Placement { - fun alloc(size: Int): NativePtr -} - -object heap : Placement { - override fun alloc(size: Int) = bridge.malloc(size) - - fun free(ptr: NativePtr) = bridge.free(ptr) - - fun free(ref: NativeRef) = free(ref.ptr) -} - -// TODO: implement optimally -class Arena : Placement, Closeable { - - private val allocatedChunks = mutableListOf() - - override fun alloc(size: Int): NativePtr { - val res = heap.alloc(size) - try { - allocatedChunks.add(res) - return res - } catch (e: Throwable) { - heap.free(res) - throw e - } - } - - fun clear() { - allocatedChunks.forEach { - heap.free(it) - } - - allocatedChunks.clear() - } - - override fun close() = clear() - -} - -fun Placement.alloc(type: NativeRef.TypeWithSize): T { - return type.byPtr(this.alloc(type.size)) -} \ No newline at end of file diff --git a/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Utils.kt b/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Utils.kt deleted file mode 100644 index b5c9c5bc373..00000000000 --- a/Interop/Runtime/src/main/kotlin/kotlin_native/interop/Utils.kt +++ /dev/null @@ -1,76 +0,0 @@ -package kotlin_native.interop - -fun malloc(type: NativeRef.TypeWithSize) = type.byPtr(bridge.malloc(type.size)) - -fun free(ptr: NativePtr?) { - if (ptr != null) { - bridge.free(ptr) - } -} - -fun free(ref: NativeRef?) = free(ref.getNativePtr()) - -fun Placement.allocNativeArrayOf(elemType: NativeRef.Type, elements: List): NativeArray> { - val res = this.alloc(array[elements.size](elemType.ref)) - elements.forEachIndexed { i, element -> - res[i].value = element - } - return res -} - -fun Placement.allocNativeArrayOf(elemType: NativeRef.Type, vararg elements: T?) = - allocNativeArrayOf(elemType, elements.toList()) - -fun mallocNativeArrayOf(elemType: NativeRef.Type, vararg elements: T?) = heap.allocNativeArrayOf(elemType, *elements) - -fun Placement.allocNativeArrayOf(elements: ByteArray): NativeArray { - val res = this.alloc(array[elements.size](Int8Box)) - elements.forEachIndexed { i, element -> - res[i].value = element - } - return res -} - -fun CString.Companion.fromString(str: String?): CString? { - return str?.toCString(heap) -} - -fun Int8Box.asCString() = CString.fromArray(NativeArray.byRefToFirstElem(this, Int8Box)) - -fun String.toCString(retValPlacement: Placement): CString { - val bytes = this.toByteArray() // TODO: encoding - val len = bytes.size - val nativeBytes = retValPlacement.alloc(array[len + 1](Int8Box)) - - bytes.forEachIndexed { i, byte -> - nativeBytes[i].value = byte - } - nativeBytes[len].value = 0 - - return CString.fromArray(nativeBytes) -} - -class MemScope private constructor(private val arena: Arena) : Placement by arena { - val memScope: Placement - get() = this - - companion object { - internal inline fun use(block: MemScope.()->R): R { - val memScope = MemScope(Arena()) - try { - return memScope.block() - } finally { - memScope.arena.clear() - } - } - } -} - -/** - * Runs given [block] providing allocation of memory - * which will be automatically disposed at the end of this scope. - */ -inline fun memScoped(block: MemScope.()->R): R { - @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") // TODO: it is a hack - return MemScope.use(block) -} \ No newline at end of file