diff --git a/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmNativeMem.kt b/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmNativeMem.kt index 3b34cfa4073..ceae51a34c4 100644 --- a/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmNativeMem.kt +++ b/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmNativeMem.kt @@ -68,33 +68,30 @@ internal object nativeMemUtils { } fun getByteArray(source: NativePointed, dest: ByteArray, length: Int) { - val clazz = ByteArray::class.java - val baseOffset = unsafe.arrayBaseOffset(clazz).toLong(); - unsafe.copyMemory(null, source.address, dest, baseOffset, length.toLong()) + unsafe.copyMemory(null, source.address, dest, byteArrayBaseOffset, length.toLong()) } fun putByteArray(source: ByteArray, dest: NativePointed, length: Int) { - val clazz = ByteArray::class.java - val baseOffset = unsafe.arrayBaseOffset(clazz).toLong(); - unsafe.copyMemory(source, baseOffset, null, dest.address, length.toLong()) + unsafe.copyMemory(source, byteArrayBaseOffset, null, dest.address, length.toLong()) } fun getCharArray(source: NativePointed, dest: CharArray, length: Int) { - val clazz = CharArray::class.java - val baseOffset = unsafe.arrayBaseOffset(clazz).toLong(); - unsafe.copyMemory(null, source.address, dest, baseOffset, length.toLong() * 2) + unsafe.copyMemory(null, source.address, dest, charArrayBaseOffset, length.toLong() * 2) } fun putCharArray(source: CharArray, dest: NativePointed, length: Int) { - val clazz = CharArray::class.java - val baseOffset = unsafe.arrayBaseOffset(clazz).toLong(); - unsafe.copyMemory(source, baseOffset, null, dest.address, length.toLong() * 2) + unsafe.copyMemory(source, charArrayBaseOffset, null, dest.address, length.toLong() * 2) } - fun zeroMemory(dest: NativePointed, length: Int): Unit = unsafe.setMemory(dest.address, length.toLong(), 0) + fun zeroMemory(dest: NativePointed, length: Int): Unit = + unsafe.setMemory(dest.address, length.toLong(), 0) + + fun copyMemory(dest: NativePointed, length: Int, src: NativePointed) = + unsafe.copyMemory(src.address, dest.address, length.toLong()) + @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") - inline fun allocateInstance(): T { + inline fun allocateInstance(): T { return unsafe.allocateInstance(T::class.java) as T } @@ -115,4 +112,7 @@ internal object nativeMemUtils { isAccessible = true return@with this.get(null) as Unsafe } + + private val byteArrayBaseOffset = unsafe.arrayBaseOffset(ByteArray::class.java).toLong() + private val charArrayBaseOffset = unsafe.arrayBaseOffset(CharArray::class.java).toLong() } diff --git a/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt b/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt index 412e01d2c40..f59ad3fe2a3 100644 --- a/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt +++ b/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt @@ -23,7 +23,8 @@ typealias NativePtr = Long internal typealias NonNullNativePtr = NativePtr @PublishedApi internal fun NonNullNativePtr.toNativePtr() = this internal fun NativePtr.toNonNull(): NonNullNativePtr = this -val nativeNullPtr: NativePtr = 0L + +public val nativeNullPtr: NativePtr = 0L // TODO: the functions below should eventually be intrinsified diff --git a/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmUtils.kt b/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmUtils.kt index 3a7a8ebf0a9..6bbdc788180 100644 --- a/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmUtils.kt +++ b/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmUtils.kt @@ -82,4 +82,4 @@ inline fun Long.narrow(): R = when (R::class.java) { inline fun Number.invalidNarrowing(): R { throw Error("unable to narrow ${this.javaClass.simpleName} \"${this}\" to ${R::class.java.simpleName}") -} +} \ No newline at end of file diff --git a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt index f65fea9389f..25f359715fa 100644 --- a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt +++ b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2017 JetBrains s.r.o. + * Copyright 2010-2019 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,13 +24,13 @@ package kotlinx.cinterop * * TODO: the behavior of [equals], [hashCode] and [toString] differs on Native and JVM backends. */ -open class NativePointed internal constructor(rawPtr: NonNullNativePtr) { +public open class NativePointed internal constructor(rawPtr: NonNullNativePtr) { var rawPtr = rawPtr.toNativePtr() internal set } // `null` value of `NativePointed?` is mapped to `nativeNullPtr`. -val NativePointed?.rawPtr: NativePtr +public val NativePointed?.rawPtr: NativePtr get() = if (this != null) this.rawPtr else nativeNullPtr /** @@ -38,22 +38,22 @@ val NativePointed?.rawPtr: NativePtr * * @param T must not be abstract */ -inline fun interpretPointed(ptr: NativePtr): T = interpretNullablePointed(ptr)!! +public inline fun interpretPointed(ptr: NativePtr): T = interpretNullablePointed(ptr)!! private class OpaqueNativePointed(rawPtr: NativePtr) : NativePointed(rawPtr.toNonNull()) -fun interpretOpaquePointed(ptr: NativePtr): NativePointed = interpretPointed(ptr) -fun interpretNullableOpaquePointed(ptr: NativePtr): NativePointed? = interpretNullablePointed(ptr) +public fun interpretOpaquePointed(ptr: NativePtr): NativePointed = interpretPointed(ptr) +public fun interpretNullableOpaquePointed(ptr: NativePtr): NativePointed? = interpretNullablePointed(ptr) /** * Changes the interpretation of the pointed data or code. */ -inline fun NativePointed.reinterpret(): T = interpretPointed(this.rawPtr) +public inline fun NativePointed.reinterpret(): T = interpretPointed(this.rawPtr) /** * C data or code. */ -abstract class CPointed(rawPtr: NativePtr) : NativePointed(rawPtr.toNonNull()) +public abstract class CPointed(rawPtr: NativePtr) : NativePointed(rawPtr.toNonNull()) /** * Represents a reference to (possibly empty) sequence of C values. @@ -67,26 +67,28 @@ abstract class CPointed(rawPtr: NativePtr) : NativePointed(rawPtr.toNonNull()) * There are also other implementations of [CValuesRef] that provide temporary pointer, * e.g. Kotlin Native specific [refTo] functions to pass primitive arrays directly to native. */ -abstract class CValuesRef { +public abstract class CValuesRef { /** - * If this reference is [CPointer], returns this pointer. - * Otherwise copies the referenced values to [placement] and returns the pointer to the copy. + * If this reference is [CPointer], returns this pointer, otherwise + * allocate storage value in the scope and return it. */ - abstract fun getPointer(scope: AutofreeScope): CPointer + public abstract fun getPointer(scope: AutofreeScope): CPointer } /** * The (possibly empty) sequence of immutable C values. * It is self-contained and doesn't depend on native memory. */ -abstract class CValues : CValuesRef() { +public abstract class CValues : CValuesRef() { /** * Copies the values to [placement] and returns the pointer to the copy. */ - abstract override fun getPointer(scope: AutofreeScope): CPointer + public override fun getPointer(scope: AutofreeScope): CPointer { + return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!) + } // TODO: optimize - override fun equals(other: Any?): Boolean { + public override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is CValues<*>) return false @@ -106,7 +108,7 @@ abstract class CValues : CValuesRef() { return true } - override fun hashCode(): Int { + public override fun hashCode(): Int { var result = 0 for (byte in this.getBytes()) { result = result * 31 + byte @@ -114,10 +116,17 @@ abstract class CValues : CValuesRef() { return result } - abstract val size: Int + public abstract val size: Int + + public abstract val align: Int + + /** + * Copy the referenced values to [placement] and return placement pointer. + */ + public abstract fun place(placement: CPointer): CPointer } -fun CValues.placeTo(scope: AutofreeScope) = this.getPointer(scope) +public fun CValues.placeTo(scope: AutofreeScope) = this.getPointer(scope) /** * The single immutable C value. @@ -125,18 +134,18 @@ fun CValues.placeTo(scope: AutofreeScope) = this.getPointer(s * * TODO: consider providing an adapter instead of subtyping [CValues]. */ -abstract class CValue : CValues() +public abstract class CValue : CValues() /** * C pointer. */ -class CPointer internal constructor(@PublishedApi internal val value: NonNullNativePtr) : CValuesRef() { +public class CPointer internal constructor(@PublishedApi internal val value: NonNullNativePtr) : CValuesRef() { // TODO: replace by [value]. @Suppress("NOTHING_TO_INLINE") - inline val rawValue: NativePtr get() = value.toNativePtr() + public inline val rawValue: NativePtr get() = value.toNativePtr() - override fun equals(other: Any?): Boolean { + public override fun equals(other: Any?): Boolean { if (this === other) { return true // fast path } @@ -144,19 +153,19 @@ class CPointer internal constructor(@PublishedApi internal val val return (other is CPointer<*>) && (rawValue == other.rawValue) } - override fun hashCode(): Int { + public override fun hashCode(): Int { return rawValue.hashCode() } - override fun toString() = this.cPointerToString() + public override fun toString() = this.cPointerToString() - override fun getPointer(scope: AutofreeScope) = this + public override fun getPointer(scope: AutofreeScope) = this } /** * Returns the pointer to this data or code. */ -val T.ptr: CPointer +public val T.ptr: CPointer get() = interpretCPointer(this.rawPtr)!! /** @@ -164,33 +173,33 @@ val T.ptr: CPointer * * @param T must not be abstract */ -inline val CPointer.pointed: T +public inline val CPointer.pointed: T get() = interpretPointed(this.rawValue) // `null` value of `CPointer?` is mapped to `nativeNullPtr` -val CPointer<*>?.rawValue: NativePtr +public val CPointer<*>?.rawValue: NativePtr get() = if (this != null) this.rawValue else nativeNullPtr -fun CPointer<*>.reinterpret(): CPointer = interpretCPointer(this.rawValue)!! +public fun CPointer<*>.reinterpret(): CPointer = interpretCPointer(this.rawValue)!! -fun CPointer?.toLong() = this.rawValue.toLong() +public fun CPointer?.toLong() = this.rawValue.toLong() -fun Long.toCPointer(): CPointer? = interpretCPointer(nativeNullPtr + this) +public fun Long.toCPointer(): CPointer? = interpretCPointer(nativeNullPtr + this) /** * The [CPointed] without any specified interpretation. */ -abstract class COpaque(rawPtr: NativePtr) : CPointed(rawPtr) // TODO: should it correspond to COpaquePointer? +public abstract class COpaque(rawPtr: NativePtr) : CPointed(rawPtr) // TODO: should it correspond to COpaquePointer? /** * The pointer with an opaque type. */ -typealias COpaquePointer = CPointer // FIXME +public typealias COpaquePointer = CPointer // FIXME /** * The variable containing a [COpaquePointer]. */ -typealias COpaquePointerVar = CPointerVarOf +public typealias COpaquePointerVar = CPointerVarOf /** * The C data variable located in memory. @@ -198,7 +207,7 @@ typealias COpaquePointerVar = CPointerVarOf * The non-abstract subclasses should represent the (complete) C data type and thus specify size and alignment. * Each such subclass must have a companion object which is a [Type]. */ -abstract class CVariable(rawPtr: NativePtr) : CPointed(rawPtr) { +public abstract class CVariable(rawPtr: NativePtr) : CPointed(rawPtr) { /** * The (complete) C data type. @@ -207,7 +216,7 @@ abstract class CVariable(rawPtr: NativePtr) : CPointed(rawPtr) { * @param align the alignments in bytes that is enough for this data type. * It may be greater than actually required for simplicity. */ - open class Type(val size: Long, val align: Int) { + public open class Type(val size: Long, val align: Int) { init { require(size % align == 0L) @@ -216,24 +225,24 @@ abstract class CVariable(rawPtr: NativePtr) : CPointed(rawPtr) { } } -inline fun sizeOf() = typeOf().size -inline fun alignOf() = typeOf().align +public inline fun sizeOf() = typeOf().size +public inline fun alignOf() = typeOf().align /** * Returns the member of this [CStructVar] which is located by given offset in bytes. */ -inline fun CStructVar.memberAt(offset: Long): T { +public inline fun CStructVar.memberAt(offset: Long): T { return interpretPointed(this.rawPtr + offset) } -inline fun CStructVar.arrayMemberAt(offset: Long): CArrayPointer { +public inline fun CStructVar.arrayMemberAt(offset: Long): CArrayPointer { return interpretCPointer(this.rawPtr + offset)!! } /** * The C struct-typed variable located in memory. */ -abstract class CStructVar(rawPtr: NativePtr) : CVariable(rawPtr) { +public abstract class CStructVar(rawPtr: NativePtr) : CVariable(rawPtr) { open class Type(size: Long, align: Int) : CVariable.Type(size, align) } @@ -245,83 +254,84 @@ sealed class CPrimitiveVar(rawPtr: NativePtr) : CVariable(rawPtr) { open class Type(size: Int) : CVariable.Type(size.toLong(), align = size) } -interface CEnum { - val value: Any +public interface CEnum { + public val value: Any } -abstract class CEnumVar(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) + +public abstract class CEnumVar(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) // generics below are used for typedef support // these classes are not supposed to be used directly, instead the typealiases are provided. @Suppress("FINAL_UPPER_BOUND") -class BooleanVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { +public class BooleanVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { companion object : Type(1) } @Suppress("FINAL_UPPER_BOUND") -class ByteVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { +public class ByteVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { companion object : Type(1) } @Suppress("FINAL_UPPER_BOUND") -class ShortVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { +public class ShortVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { companion object : Type(2) } @Suppress("FINAL_UPPER_BOUND") -class IntVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { +public class IntVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { companion object : Type(4) } @Suppress("FINAL_UPPER_BOUND") -class LongVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { +public class LongVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { companion object : Type(8) } @Suppress("FINAL_UPPER_BOUND") -class UByteVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { +public class UByteVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { companion object : Type(1) } @Suppress("FINAL_UPPER_BOUND") -class UShortVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { +public class UShortVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { companion object : Type(2) } @Suppress("FINAL_UPPER_BOUND") -class UIntVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { +public class UIntVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { companion object : Type(4) } @Suppress("FINAL_UPPER_BOUND") -class ULongVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { +public class ULongVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { companion object : Type(8) } @Suppress("FINAL_UPPER_BOUND") -class FloatVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { +public class FloatVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { companion object : Type(4) } @Suppress("FINAL_UPPER_BOUND") -class DoubleVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { +public class DoubleVarOf(rawPtr: NativePtr) : CPrimitiveVar(rawPtr) { companion object : Type(8) } -typealias BooleanVar = BooleanVarOf -typealias ByteVar = ByteVarOf -typealias ShortVar = ShortVarOf -typealias IntVar = IntVarOf -typealias LongVar = LongVarOf -typealias UByteVar = UByteVarOf -typealias UShortVar = UShortVarOf -typealias UIntVar = UIntVarOf -typealias ULongVar = ULongVarOf -typealias FloatVar = FloatVarOf -typealias DoubleVar = DoubleVarOf +public typealias BooleanVar = BooleanVarOf +public typealias ByteVar = ByteVarOf +public typealias ShortVar = ShortVarOf +public typealias IntVar = IntVarOf +public typealias LongVar = LongVarOf +public typealias UByteVar = UByteVarOf +public typealias UShortVar = UShortVarOf +public typealias UIntVar = UIntVarOf +public typealias ULongVar = ULongVarOf +public typealias FloatVar = FloatVarOf +public typealias DoubleVar = DoubleVarOf @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") -var BooleanVarOf.value: T +public var BooleanVarOf.value: T get() { val byte = nativeMemUtils.getByte(this) return byte.toBoolean() as T @@ -329,78 +339,78 @@ var BooleanVarOf.value: T set(value) = nativeMemUtils.putByte(this, value.toByte()) @Suppress("NOTHING_TO_INLINE") -inline fun Boolean.toByte(): Byte = if (this) 1 else 0 +public inline fun Boolean.toByte(): Byte = if (this) 1 else 0 @Suppress("NOTHING_TO_INLINE") -inline fun Byte.toBoolean() = (this - 0 != 0) +public inline fun Byte.toBoolean() = (this.toInt() != 0) @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") -var ByteVarOf.value: T +public var ByteVarOf.value: T get() = nativeMemUtils.getByte(this) as T set(value) = nativeMemUtils.putByte(this, value) @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") -var ShortVarOf.value: T +public var ShortVarOf.value: T get() = nativeMemUtils.getShort(this) as T set(value) = nativeMemUtils.putShort(this, value) @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") -var IntVarOf.value: T +public var IntVarOf.value: T get() = nativeMemUtils.getInt(this) as T set(value) = nativeMemUtils.putInt(this, value) @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") -var LongVarOf.value: T +public var LongVarOf.value: T get() = nativeMemUtils.getLong(this) as T set(value) = nativeMemUtils.putLong(this, value) @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") -var UByteVarOf.value: T +public var UByteVarOf.value: T get() = nativeMemUtils.getByte(this).toUByte() as T set(value) = nativeMemUtils.putByte(this, value.toByte()) @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") -var UShortVarOf.value: T +public var UShortVarOf.value: T get() = nativeMemUtils.getShort(this).toUShort() as T set(value) = nativeMemUtils.putShort(this, value.toShort()) @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") -var UIntVarOf.value: T +public var UIntVarOf.value: T get() = nativeMemUtils.getInt(this).toUInt() as T set(value) = nativeMemUtils.putInt(this, value.toInt()) @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") -var ULongVarOf.value: T +public var ULongVarOf.value: T get() = nativeMemUtils.getLong(this).toULong() as T set(value) = nativeMemUtils.putLong(this, value.toLong()) // TODO: ensure native floats have the appropriate binary representation @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") -var FloatVarOf.value: T +public var FloatVarOf.value: T get() = nativeMemUtils.getFloat(this) as T set(value) = nativeMemUtils.putFloat(this, value) @Suppress("FINAL_UPPER_BOUND", "UNCHECKED_CAST") -var DoubleVarOf.value: T +public var DoubleVarOf.value: T get() = nativeMemUtils.getDouble(this) as T set(value) = nativeMemUtils.putDouble(this, value) -class CPointerVarOf>(rawPtr: NativePtr) : CVariable(rawPtr) { +public class CPointerVarOf>(rawPtr: NativePtr) : CVariable(rawPtr) { companion object : CVariable.Type(pointerSize.toLong(), pointerSize) } /** * The C data variable containing the pointer to `T`. */ -typealias CPointerVar = CPointerVarOf> +public typealias CPointerVar = CPointerVarOf> /** * The value of this variable. */ @Suppress("UNCHECKED_CAST") -inline var

> CPointerVarOf

.value: P? +public inline var

> CPointerVarOf

.value: P? get() = interpretCPointer(nativeMemUtils.getNativePtr(this)) as P? set(value) = nativeMemUtils.putNativePtr(this, value.rawValue) @@ -409,13 +419,13 @@ inline var

> CPointerVarOf

.value: P? * * @param T must not be abstract */ -inline var > CPointerVarOf

.pointed: T? +public inline var > CPointerVarOf

.pointed: T? get() = this.value?.pointed set(value) { this.value = value?.ptr as P? } -inline operator fun CPointer.get(index: Long): T { +public inline operator fun CPointer.get(index: Long): T { val offset = if (index == 0L) { 0L // optimization for JVM impl which uses reflection for now. } else { @@ -424,40 +434,40 @@ inline operator fun CPointer.get(index: Long): T { return interpretPointed(this.rawValue + offset) } -inline operator fun CPointer.get(index: Int): T = this.get(index.toLong()) +public inline operator fun CPointer.get(index: Int): T = this.get(index.toLong()) @Suppress("NOTHING_TO_INLINE") @JvmName("plus\$CPointer") -inline operator fun > CPointer?.plus(index: Long): CPointer? = +public inline operator fun > CPointer?.plus(index: Long): CPointer? = interpretCPointer(this.rawValue + index * pointerSize) @Suppress("NOTHING_TO_INLINE") @JvmName("plus\$CPointer") -inline operator fun > CPointer?.plus(index: Int): CPointer? = +public inline operator fun > CPointer?.plus(index: Int): CPointer? = this + index.toLong() @Suppress("NOTHING_TO_INLINE") -inline operator fun > CPointer>.get(index: Int): T? = +public inline operator fun > CPointer>.get(index: Int): T? = (this + index)!!.pointed.value @Suppress("NOTHING_TO_INLINE") -inline operator fun > CPointer>.set(index: Int, value: T?) { +public inline operator fun > CPointer>.set(index: Int, value: T?) { (this + index)!!.pointed.value = value } @Suppress("NOTHING_TO_INLINE") -inline operator fun > CPointer>.get(index: Long): T? = +public inline operator fun > CPointer>.get(index: Long): T? = (this + index)!!.pointed.value @Suppress("NOTHING_TO_INLINE") -inline operator fun > CPointer>.set(index: Long, value: T?) { +public inline operator fun > CPointer>.set(index: Long, value: T?) { (this + index)!!.pointed.value = value } -typealias CArrayPointer = CPointer -typealias CArrayPointerVar = CPointerVar +public typealias CArrayPointer = CPointer +public typealias CArrayPointerVar = CPointerVar /** * The C function. */ -class CFunction>(rawPtr: NativePtr) : CPointed(rawPtr) \ No newline at end of file +public class CFunction>(rawPtr: NativePtr) : CPointed(rawPtr) \ No newline at end of file diff --git a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt index 264638aef3c..33a95aa0f0d 100644 --- a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt +++ b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt @@ -16,21 +16,21 @@ package kotlinx.cinterop -interface NativePlacement { +public interface NativePlacement { - fun alloc(size: Long, align: Int): NativePointed + public fun alloc(size: Long, align: Int): NativePointed - fun alloc(size: Int, align: Int) = alloc(size.toLong(), align) + public fun alloc(size: Int, align: Int): NativePointed = alloc(size.toLong(), align) } -interface NativeFreeablePlacement : NativePlacement { - fun free(mem: NativePtr) +public interface NativeFreeablePlacement : NativePlacement { + public fun free(mem: NativePtr) } -fun NativeFreeablePlacement.free(pointer: CPointer<*>) = this.free(pointer.rawValue) -fun NativeFreeablePlacement.free(pointed: NativePointed) = this.free(pointed.rawPtr) +public fun NativeFreeablePlacement.free(pointer: CPointer<*>) = this.free(pointer.rawValue) +public fun NativeFreeablePlacement.free(pointed: NativePointed) = this.free(pointed.rawPtr) -object nativeHeap : NativeFreeablePlacement { +public object nativeHeap : NativeFreeablePlacement { override fun alloc(size: Long, align: Int) = nativeMemUtils.alloc(size, align) override fun free(mem: NativePtr) = nativeMemUtils.free(mem) @@ -38,7 +38,7 @@ object nativeHeap : NativeFreeablePlacement { private typealias Deferred = () -> Unit -open class DeferScope { +public open class DeferScope { @PublishedApi internal var topDeferred: Deferred? = null @@ -65,11 +65,11 @@ open class DeferScope { } } -abstract class AutofreeScope : DeferScope(), NativePlacement { +public abstract class AutofreeScope : DeferScope(), NativePlacement { abstract override fun alloc(size: Long, align: Int): NativePointed } -open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : AutofreeScope() { +public open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : AutofreeScope() { private var lastChunk: NativePointed? = null @@ -97,7 +97,7 @@ open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : } -class Arena(parent: NativeFreeablePlacement = nativeHeap) : ArenaBase(parent) { +public class Arena(parent: NativeFreeablePlacement = nativeHeap) : ArenaBase(parent) { fun clear() = this.clearImpl() } @@ -106,7 +106,7 @@ class Arena(parent: NativeFreeablePlacement = nativeHeap) : ArenaBase(parent) { * * @param T must not be abstract */ -inline fun NativePlacement.alloc(): T = +public inline fun NativePlacement.alloc(): T = alloc(typeOf()).reinterpret() @PublishedApi @@ -118,7 +118,7 @@ internal fun NativePlacement.alloc(type: CVariable.Type): NativePointed = * * @param T must not be abstract */ -inline fun NativePlacement.alloc(initialize: T.() -> Unit): T = +public inline fun NativePlacement.alloc(initialize: T.() -> Unit): T = alloc().also { it.initialize() } /** @@ -126,7 +126,7 @@ inline fun NativePlacement.alloc(initialize: T.() -> Uni * * @param T must not be abstract */ -inline fun NativePlacement.allocArray(length: Long): CArrayPointer = +public inline fun NativePlacement.allocArray(length: Long): CArrayPointer = alloc(sizeOf() * length, alignOf()).reinterpret().ptr /** @@ -134,7 +134,7 @@ inline fun NativePlacement.allocArray(length: Long): CAr * * @param T must not be abstract */ -inline fun NativePlacement.allocArray(length: Int): CArrayPointer = +public inline fun NativePlacement.allocArray(length: Int): CArrayPointer = allocArray(length.toLong()) /** @@ -142,7 +142,7 @@ inline fun NativePlacement.allocArray(length: Int): CArr * * @param T must not be abstract */ -inline fun NativePlacement.allocArray(length: Long, +public inline fun NativePlacement.allocArray(length: Long, initializer: T.(index: Long)->Unit): CArrayPointer { val res = allocArray(length) @@ -158,9 +158,8 @@ inline fun NativePlacement.allocArray(length: Long, * * @param T must not be abstract */ -inline fun NativePlacement.allocArray(length: Int, - initializer: T.(index: Int)->Unit): CArrayPointer = - allocArray(length.toLong()) { index -> +public inline fun NativePlacement.allocArray( + length: Int, initializer: T.(index: Int)->Unit): CArrayPointer = allocArray(length.toLong()) { index -> this.initializer(index.toInt()) } @@ -168,7 +167,7 @@ inline fun NativePlacement.allocArray(length: Int, /** * Allocates C array of pointers to given elements. */ -fun NativePlacement.allocArrayOfPointersTo(elements: List): CArrayPointer> { +public fun NativePlacement.allocArrayOfPointersTo(elements: List): CArrayPointer> { val res = allocArray>(elements.size) elements.forEachIndexed { index, value -> res[index] = value?.ptr @@ -179,22 +178,21 @@ fun NativePlacement.allocArrayOfPointersTo(elements: List): C /** * Allocates C array of pointers to given elements. */ -fun NativePlacement.allocArrayOfPointersTo(vararg elements: T?) = +public fun NativePlacement.allocArrayOfPointersTo(vararg elements: T?) = allocArrayOfPointersTo(listOf(*elements)) /** * Allocates C array of given values. */ -inline fun > +public inline fun > NativePlacement.allocArrayOf(vararg elements: T?): CArrayPointer> { - return allocArrayOf(listOf(*elements)) } /** * Allocates C array of given values. */ -inline fun > +public inline fun > NativePlacement.allocArrayOf(elements: List): CArrayPointer> { val res = allocArray>(elements.size) @@ -206,13 +204,13 @@ inline fun > return res } -fun NativePlacement.allocArrayOf(elements: ByteArray): CArrayPointer { +public fun NativePlacement.allocArrayOf(elements: ByteArray): CArrayPointer { val result = allocArray(elements.size) nativeMemUtils.putByteArray(elements, result.pointed, elements.size) return result } -fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer { +public fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer { val res = allocArray(elements.size) var index = 0 while (index < elements.size) { @@ -222,48 +220,67 @@ fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer NativePlacement.allocPointerTo() = alloc>() +public fun NativePlacement.allocPointerTo() = alloc>() -fun zeroValue(size: Int, align: Int): CValue = object : CValue() { +@PublishedApi +internal class ZeroValue(private val sizeBytes: Int, private val alignBytes: Int): CValue() { + // Optimization to avoid unneeded virtual calls in base class implementation. override fun getPointer(scope: AutofreeScope): CPointer { - val result = scope.alloc(size, align) - nativeMemUtils.zeroMemory(result, size) - return interpretCPointer(result.rawPtr)!! + return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!) } - override val size get() = size + override fun place(placement: CPointer): CPointer { + nativeMemUtils.zeroMemory(interpretPointed(placement.rawValue), sizeBytes) + return placement + } + override val size get() = sizeBytes + + override val align get() = alignBytes + } +@Suppress("NOTHING_TO_INLINE") +public inline fun zeroValue(size: Int, align: Int): CValue = ZeroValue(size, align) -inline fun zeroValue(): CValue = - zeroValue(sizeOf().toInt(), alignOf()) +public inline fun zeroValue(): CValue = zeroValue(sizeOf().toInt(), alignOf()) -inline fun cValue(): CValue = zeroValue() +public inline fun cValue(): CValue = zeroValue() -private fun NativePlacement.placeBytes(bytes: ByteArray, align: Int): CPointer { - val result = this.alloc(size = bytes.size, align = align) - nativeMemUtils.putByteArray(bytes, result, bytes.size) - return interpretCPointer(result.rawPtr)!! -} - -fun CPointed.readValues(size: Int, align: Int): CValues { +public fun CPointed.readValues(size: Int, align: Int): CValues { val bytes = ByteArray(size) nativeMemUtils.getByteArray(this, bytes, size) - return object : CValues() { - override fun getPointer(scope: AutofreeScope): CPointer = scope.placeBytes(bytes, align) - override val size get() = bytes.size + return object : CValue() { + // Optimization to avoid unneeded virtual calls in base class implementation. + override fun getPointer(scope: AutofreeScope): CPointer { + return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!) + } + override fun place(placement: CPointer): CPointer { + nativeMemUtils.putByteArray(bytes, interpretPointed(placement.rawValue), bytes.size) + return placement + } + override val size get() = size + override val align get() = align } } -inline fun T.readValues(count: Int): CValues = +public inline fun T.readValues(count: Int): CValues = this.readValues(size = count * sizeOf().toInt(), align = alignOf()) -fun CPointed.readValue(size: Long, align: Int): CValue { +public fun CPointed.readValue(size: Long, align: Int): CValue { val bytes = ByteArray(size.toInt()) nativeMemUtils.getByteArray(this, bytes, size.toInt()) + return object : CValue() { - override fun getPointer(scope: AutofreeScope): CPointer = scope.placeBytes(bytes, align) - override val size get() = bytes.size + override fun place(placement: CPointer): CPointer { + nativeMemUtils.putByteArray(bytes, interpretPointed(placement.rawValue), bytes.size) + return placement + } + // Optimization to avoid unneeded virtual calls in base class implementation. + public override fun getPointer(scope: AutofreeScope): CPointer { + return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!) + } + override val size get() = size.toInt() + override val align get() = align } } @@ -272,138 +289,140 @@ fun CPointed.readValue(size: Long, align: Int): CValue { // Note: can't be declared as property due to possible clash with a struct field. // TODO: find better name. -inline fun T.readValue(): CValue = this.readValue(typeOf()) +public inline fun T.readValue(): CValue = this.readValue(typeOf()) -fun CValue<*>.write(location: NativePtr) { - // TODO: probably CValue must be redesigned. - val fakeScope = object : AutofreeScope() { - var used = false - override fun alloc(size: Long, align: Int): NativePointed { - assert(!used) - used = true - return interpretPointed(location) - } - } - - this.getPointer(fakeScope) - assert(fakeScope.used) +public fun CValue.write(location: NativePtr) { + this.place(interpretCPointer(location)!!) } // TODO: optimize -fun CValues.getBytes(): ByteArray = memScoped { +public fun CValues.getBytes(): ByteArray = memScoped { val result = ByteArray(size) - nativeMemUtils.getByteArray( source = this@getBytes.placeTo(memScope).reinterpret().pointed, dest = result, length = result.size ) - result } /** * Calls the [block] with temporary copy if this value as receiver. */ -inline fun CValue.useContents(block: T.() -> R): R = memScoped { +public inline fun CValue.useContents(block: T.() -> R): R = memScoped { this@useContents.placeTo(memScope).pointed.block() } -inline fun CValue.copy(modify: T.() -> Unit): CValue = useContents { +public inline fun CValue.copy(modify: T.() -> Unit): CValue = useContents { this.modify() this.readValue() } -inline fun cValue(initialize: T.() -> Unit): CValue = +public inline fun cValue(initialize: T.() -> Unit): CValue = zeroValue().copy(modify = initialize) -inline fun createValues(count: Int, initializer: T.(index: Int) -> Unit) = memScoped { +public inline fun createValues(count: Int, initializer: T.(index: Int) -> Unit) = memScoped { val array = allocArray(count, initializer) array[0].readValues(count) } -fun cValuesOf(vararg elements: Byte): CValues = object : CValues() { - override fun getPointer(scope: AutofreeScope) = scope.allocArrayOf(elements) - override val size get() = 1 * elements.size -} - // TODO: optimize other [cValuesOf] methods: +fun cValuesOf(vararg elements: Byte): CValues = object : CValues() { + // Optimization to avoid unneeded virtual calls in base class implementation. + override fun getPointer(scope: AutofreeScope): CPointer { + return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!) + } + override fun place(placement: CPointer): CPointer { + nativeMemUtils.putByteArray(elements, interpretPointed(placement.rawValue), elements.size) + return placement + } -fun cValuesOf(vararg elements: Short): CValues = - createValues(elements.size) { index -> this.value = elements[index] } - -fun cValuesOf(vararg elements: Int): CValues = - createValues(elements.size) { index -> this.value = elements[index] } - -fun cValuesOf(vararg elements: Long): CValues = - createValues(elements.size) { index -> this.value = elements[index] } - -fun cValuesOf(vararg elements: Float): CValues = object : CValues() { - override fun getPointer(scope: AutofreeScope) = scope.allocArrayOf(*elements) - override val size get() = 4 * elements.size + override val size get() = 1 * elements.size + override val align get() = 1 } -fun cValuesOf(vararg elements: Double): CValues = +public fun cValuesOf(vararg elements: Short): CValues = createValues(elements.size) { index -> this.value = elements[index] } -fun cValuesOf(vararg elements: CPointer?): CValues> = +public fun cValuesOf(vararg elements: Int): CValues = createValues(elements.size) { index -> this.value = elements[index] } -fun ByteArray.toCValues() = cValuesOf(*this) -fun ShortArray.toCValues() = cValuesOf(*this) -fun IntArray.toCValues() = cValuesOf(*this) -fun LongArray.toCValues() = cValuesOf(*this) -fun FloatArray.toCValues() = cValuesOf(*this) -fun DoubleArray.toCValues() = cValuesOf(*this) -fun Array?>.toCValues() = cValuesOf(*this) +public fun cValuesOf(vararg elements: Long): CValues = + createValues(elements.size) { index -> this.value = elements[index] } -fun List?>.toCValues() = this.toTypedArray().toCValues() +public fun cValuesOf(vararg elements: Float): CValues = + createValues(elements.size) { index -> this.value = elements[index] } + +public fun cValuesOf(vararg elements: Double): CValues = + createValues(elements.size) { index -> this.value = elements[index] } + +public fun cValuesOf(vararg elements: CPointer?): CValues> = + createValues(elements.size) { index -> this.value = elements[index] } + +public fun ByteArray.toCValues() = cValuesOf(*this) +public fun ShortArray.toCValues() = cValuesOf(*this) +public fun IntArray.toCValues() = cValuesOf(*this) +public fun LongArray.toCValues() = cValuesOf(*this) +public fun FloatArray.toCValues() = cValuesOf(*this) +public fun DoubleArray.toCValues() = cValuesOf(*this) +public fun Array?>.toCValues() = cValuesOf(*this) +public fun List?>.toCValues() = this.toTypedArray().toCValues() private class CString(val bytes: ByteArray): CValues() { override val size get() = bytes.size + 1 + override val align get() = 1 + // Optimization to avoid unneeded virtual calls in base class implementation. override fun getPointer(scope: AutofreeScope): CPointer { - val result = scope.allocArray(bytes.size + 1) - nativeMemUtils.putByteArray(bytes, result.pointed, bytes.size) - result[bytes.size] = 0.toByte() - return result + return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!) + } + override fun place(placement: CPointer): CPointer { + nativeMemUtils.putByteArray(bytes, placement.pointed, bytes.size) + placement[bytes.size] = 0.toByte() + return placement } } /** * @return the value of zero-terminated UTF-8-encoded C string constructed from given [kotlin.String]. */ -val String.cstr: CValues +public val String.cstr: CValues get() = CString(encodeToUtf8(this)) /** * Convert this list of Kotlin strings to C array of C strings, * allocating memory for the array and C strings with given [AutofreeScope]. */ -fun List.toCStringArray(autofreeScope: AutofreeScope): CPointer> = +public fun List.toCStringArray(autofreeScope: AutofreeScope): CPointer> = autofreeScope.allocArrayOf(this.map { it.cstr.getPointer(autofreeScope) }) /** * Convert this array of Kotlin strings to C array of C strings, * allocating memory for the array and C strings with given [AutofreeScope]. */ -fun Array.toCStringArray(autofreeScope: AutofreeScope): CPointer> = +public fun Array.toCStringArray(autofreeScope: AutofreeScope): CPointer> = autofreeScope.allocArrayOf(this.map { it.cstr.getPointer(autofreeScope) }) private class WCString(val chars: CharArray): CValues() { override val size get() = 2 * (chars.size + 1) + override val align get() = 2 + + // Optimization to avoid unneeded virtual calls in base class implementation. override fun getPointer(scope: AutofreeScope): CPointer { - val result = scope.allocArray(chars.size + 1) - nativeMemUtils.putCharArray(chars, result.pointed, chars.size) + return place(interpretCPointer(scope.alloc(size, align).rawPtr)!!) + } + + override fun place(placement: CPointer): CPointer { + nativeMemUtils.putCharArray(chars, placement.pointed, chars.size) // TODO: fix, after KT-29627 is fixed. - nativeMemUtils.putShort((result + chars.size)!!.pointed, 0) - return result + nativeMemUtils.putShort((placement + chars.size)!!.pointed, 0) + return placement } } -val String.wcstr: CValues +public val String.wcstr: CValues get() = WCString(this.toCharArray()) /** @@ -412,7 +431,7 @@ val String.wcstr: CValues * @return the [kotlin.String] decoded from given zero-terminated UTF-8-encoded C string. */ // TODO: optimize -fun CPointer.toKString(): String { +public fun CPointer.toKString(): String { val nativeBytes = this var length = 0 @@ -425,7 +444,7 @@ fun CPointer.toKString(): String { return decodeFromUtf8(bytes) } -class MemScope : ArenaBase() { +public class MemScope : ArenaBase() { val memScope: MemScope get() = this @@ -440,7 +459,7 @@ class MemScope : ArenaBase() { * 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 { +public inline fun memScoped(block: MemScope.()->R): R { val memScope = MemScope() try { return memScope.block() @@ -449,7 +468,7 @@ inline fun memScoped(block: MemScope.()->R): R { } } -fun COpaquePointer.readBytes(count: Int): ByteArray { +public fun COpaquePointer.readBytes(count: Int): ByteArray { val result = ByteArray(count) nativeMemUtils.getByteArray(this.reinterpret().pointed, result, count) return result diff --git a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeMem.kt b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeMem.kt index b87593f0cd9..f9d73548f35 100644 --- a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeMem.kt +++ b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeMem.kt @@ -103,6 +103,17 @@ internal object nativeMemUtils { } } + // TODO: optimize + fun copyMemory(dest: NativePointed, length: Int, src: NativePointed): Unit { + val destArray = dest.reinterpret().ptr + val srcArray = src.reinterpret().ptr + var index = 0 + while (index < length) { + destArray[index] = srcArray[index] + ++index + } + } + fun alloc(size: Long, align: Int): NativePointed { val ptr = malloc(size, align) if (ptr == nativeNullPtr) { @@ -157,4 +168,4 @@ private external fun cfree(ptr: NativePtr) @TypedIntrinsic(IntrinsicType.INTEROP_READ_BITS) external fun readBits(ptr: NativePtr, offset: Long, size: Int, signed: Boolean): Long @TypedIntrinsic(IntrinsicType.INTEROP_WRITE_BITS) -external fun writeBits(ptr: NativePtr, offset: Long, size: Int, value: Long) \ No newline at end of file +external fun writeBits(ptr: NativePtr, offset: Long, size: Int, value: Long) diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/CodeBuilders.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/CodeBuilders.kt index 99ed8c918ac..0f1563333c0 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/CodeBuilders.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/CodeBuilders.kt @@ -34,14 +34,25 @@ inline fun buildNativeCodeLines(scope: NativeScope, block: NativeCodeBuilder.() return builder.lines } -class KotlinCodeBuilder(val scope: KotlinScope) { - private val lines = mutableListOf() +private class Block(val nesting: Int, val start: String, val end: String) { + val prologue = mutableListOf() + val body = mutableListOf() + val epilogue = mutableListOf() - private val freeStack = mutableListOf() - private val nesting get() = freeStack.size + fun indent(line: String) = " ".repeat(nesting) + line + fun indentBraces(line: String) = " ".repeat(nesting - 1) + line +} + +class KotlinCodeBuilder(val scope: KotlinScope) { + + private val blocks = mutableListOf() + + init { + pushBlock("", "") + } fun out(line: String) { - lines.add(" ".repeat(nesting) + line) + currentBlock().body += line } private var memScoped = false @@ -52,24 +63,36 @@ class KotlinCodeBuilder(val scope: KotlinScope) { } } - fun pushBlock(line: String, free: String = "") { - out(line) - freeStack.add(free) + fun getNativePointer(name: String): String { + return "$name?.getPointer(memScope)" } - private fun popBlocks() { - while (freeStack.isNotEmpty()) { - val free = freeStack.last() - freeStack.removeAt(freeStack.lastIndex) - out("} $free".trim()) - } + fun returnResult(result: String) { + currentBlock().body += "return $result" + } + + private fun currentBlock() = blocks.last() + + fun pushBlock(start: String, end: String = "}") { + val block = Block(blocks.size, start = start, end = end) + blocks += block + } + + private fun emitBlockAndNested(position: Int, lines: MutableList) { + if (position >= blocks.size) return + val block = blocks[position] + if (block.start.isNotEmpty()) lines += block.indentBraces(block.start) + lines += block.prologue.map { block.indent(it) } + lines += block.body.map { block.indent(it) } + emitBlockAndNested(position + 1, lines) + lines += block.epilogue.map { block.indent(it) } + if (block.end.isNotEmpty()) lines += block.indentBraces(block.end) } fun build(): List { - this.popBlocks() - val result = this.lines.toList() - this.lines.clear() - return result + val lines = mutableListOf() + emitBlockAndNested(0, lines) + return lines.toList() } } diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/MappingBridgeGeneratorImpl.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/MappingBridgeGeneratorImpl.kt index 2e50dc69bad..07c8273840c 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/MappingBridgeGeneratorImpl.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/MappingBridgeGeneratorImpl.kt @@ -57,8 +57,9 @@ class MappingBridgeGeneratorImpl( is RecordType -> { val mirror = mirror(declarationMapper, returnType) val tmpVarName = kniRetVal + // We clear in the finally block. builder.out("val $tmpVarName = nativeHeap.alloc<${mirror.pointedType.render(builder.scope)}>()") - builder.pushBlock("try {", free = "finally { nativeHeap.free($tmpVarName) }") + builder.pushBlock(start = "try {", end = "} finally { nativeHeap.free($tmpVarName) }") bridgeArguments.add(BridgeTypedKotlinValue(BridgedType.NATIVE_PTR, "$tmpVarName.rawPtr")) BridgedType.VOID } diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt index b9210dffa60..80b550bbeed 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/Mappings.kt @@ -315,7 +315,7 @@ sealed class TypeInfo { val objCBlock = "((__bridge $blockType)${nativeValues.last()})" "$objCBlock(${nativeValues.dropLast(1).joinToString()})" }.let { - codeBuilder.out("return $it") + codeBuilder.returnResult(it) } codeBuilder.build().joinTo(this, separator = "\n") @@ -341,7 +341,7 @@ sealed class TypeInfo { error(pointed) override fun cToBridged(expr: String) = error(pointed) - // TODO: this method must not exist + // TODO: this method must not exist. override fun constructPointedType(valueType: KotlinType): KotlinClassifierType = error(pointed) } } diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt index 4ddfa9f87a0..d2fd65697ae 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/ObjCStubs.kt @@ -231,7 +231,7 @@ class ObjCMethodStub(private val stubGenerator: StubGenerator, "$messenger(${messengerArguments.joinToString()})" } - bodyGenerator.out("return $result") + bodyGenerator.returnResult(result) this.implementationTemplate = genImplementationTemplate(stubGenerator) this.bodyLines = bodyGenerator.build() diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/SimpleBridgeGeneratorImpl.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/SimpleBridgeGeneratorImpl.kt index d1d676f7644..916534b9441 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/SimpleBridgeGeneratorImpl.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/SimpleBridgeGeneratorImpl.kt @@ -191,7 +191,7 @@ class SimpleBridgeGeneratorImpl( kotlinExpr = "objc_retainAutoreleaseReturnValue($kotlinExpr)" // (Objective-C does the same for returned pointers). } - out("return $kotlinExpr") + returnResult(kotlinExpr) }.forEach { kotlinLines.add(" $it") } diff --git a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt index f42761ad1c5..dc9279f294e 100644 --- a/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt +++ b/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/StubGenerator.kt @@ -613,7 +613,6 @@ class StubGenerator( private val cCallSymbolName: String? init { - // TODO: support dumpShims val kotlinParameters = mutableListOf>() val bodyGenerator = KotlinCodeBuilder(scope = kotlinFile) val bridgeArguments = mutableListOf() @@ -648,13 +647,12 @@ class StubGenerator( } else if (representAsValuesRef != null) { kotlinParameters.add(parameterName to representAsValuesRef) bodyGenerator.pushMemScoped() - "$parameterName?.getPointer(memScope)" + bodyGenerator.getNativePointer(parameterName) } else { val mirror = mirror(parameter.type) kotlinParameters.add(parameterName to mirror.argType) parameterName } - bridgeArguments.add(TypedKotlinValue(parameter.type, bridgeArgument)) } @@ -667,7 +665,7 @@ class StubGenerator( ) { nativeValues -> "${func.name}(${nativeValues.joinToString()})" } - bodyGenerator.out("return $result") + bodyGenerator.returnResult(result) isCCall = false cCallSymbolName = null } else { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt index 43eeadadcc8..c1c3cd80d8a 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/ContextUtils.kt @@ -295,6 +295,12 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { return LLVMAddFunction(llvmModule, "llvm.memset.p0i8.i32", functionType)!! } + private fun importMemcpy(): LLVMValueRef { + val parameterTypes = cValuesOf(int8TypePtr, int8TypePtr, int32Type, int1Type) + val functionType = LLVMFunctionType(LLVMVoidType(), parameterTypes, 4, 0) + return LLVMAddFunction(llvmModule, "llvm.memcpy.p0i8.p0i8.i32", functionType)!! + } + internal fun externalFunction(name: String, type: LLVMTypeRef, origin: CompiledKonanModuleOrigin): LLVMValueRef { this.imports.add(origin) @@ -463,6 +469,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) { ) val memsetFunction = importMemset() + val memcpyFunction = importMemcpy() val usedFunctions = mutableListOf() val usedGlobals = mutableListOf() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt index c8715c866ea..a45dcfef116 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt @@ -77,6 +77,7 @@ internal enum class IntrinsicType { INTEROP_NARROW, INTEROP_STATIC_C_FUNCTION, INTEROP_FUNPTR_INVOKE, + INTEROP_MEMORY_COPY, // Worker WORKER_EXECUTE } @@ -216,6 +217,7 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv IntrinsicType.LIST_OF_INTERNAL -> emitListOfInternal(callSite, args) IntrinsicType.IDENTITY -> emitIdentity(args) IntrinsicType.GET_CONTINUATION -> emitGetContinuation() + IntrinsicType.INTEROP_MEMORY_COPY -> emitMemoryCopy(callSite, args) IntrinsicType.RETURN_IF_SUSPEND, IntrinsicType.INTEROP_BITS_TO_FLOAT, IntrinsicType.INTEROP_BITS_TO_DOUBLE, @@ -377,6 +379,12 @@ internal class IntrinsicGenerator(private val environment: IntrinsicGeneratorEnv return codegen.theUnitInstanceRef.llvm } + private fun FunctionGenerationContext.emitMemoryCopy(callSite: IrCall, args: List): LLVMValueRef { + println("memcpy at ${callSite}") + args.map { println(llvm2string(it)) } + TODO("Implement me") + } + private fun extractConstUnsignedInt(value: LLVMValueRef): Long { assert(LLVMIsConstant(value) != 0) return LLVMConstIntGetZExtValue(value) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt index 0438ab6610a..af2cc409181 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt @@ -27,9 +27,8 @@ internal interface ConstPointer : ConstValue { } internal fun constPointer(value: LLVMValueRef) = object : ConstPointer { - init { - assert (LLVMIsConstant(value) == 1) + assert(LLVMIsConstant(value) == 1) } override val llvm = value diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt index 7f146933062..1b1b2084305 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt @@ -209,7 +209,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { } else { methodTableRecords(irClass) } - val methodsPtr = staticData.placeGlobalConstArray("kmethods:$className", runtime.methodTableRecordType, methods) @@ -243,7 +242,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { } fun vtable(irClass: IrClass): ConstArray { - // TODO: compile-time resolution limits binary compatibility + // TODO: compile-time resolution limits binary compatibility. val vtableEntries = context.getVtableBuilder(irClass).vtableEntries.map { val implementation = it.implementation if (implementation == null || implementation.isExternalObjCClassMethod()) { @@ -264,7 +263,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils { if (previous != null) throw AssertionError("Duplicate method table entry: functionName = '$functionName', hash = '${nameSignature.value}', entry1 = $previous, entry2 = $it") - // TODO: compile-time resolution limits binary compatibility + // TODO: compile-time resolution limits binary compatibility. val implementation = it.implementation val methodEntryPoint = implementation?.entryPointAddress MethodTableRecord(nameSignature, methodEntryPoint) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt index 3f51b966726..9011af3ffb9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt @@ -961,6 +961,9 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB ) } } + IntrinsicType.INTEROP_MEMORY_COPY -> { + TODO("So far unsupported") + } IntrinsicType.OBJC_INIT_BY -> { val intrinsic = interop.objCObjectInitBy.name