From 17ccd3ee020ad7dcde4cf66ecfbf469ee7fa0c51 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Tue, 19 Sep 2017 12:37:13 +0300 Subject: [PATCH] Minorly rework `CValuesRef` to make it more universal when subclassing Allow `getPointer` to register custom disposers with `defer` --- .../kotlin/native/interop/indexer/Utils.kt | 6 ++-- .../src/main/kotlin/kotlinx/cinterop/Types.kt | 27 +++------------- .../src/main/kotlin/kotlinx/cinterop/Utils.kt | 32 +++++++++++-------- .../native/kotlin/kotlinx/cinterop/Varargs.kt | 4 +-- .../kotlin/native/interop/gen/CodeBuilders.kt | 8 +++++ .../interop/gen/MappingBridgeGeneratorImpl.kt | 6 ++-- .../native/interop/gen/jvm/StubGenerator.kt | 16 ++++------ .../kotlin/konan/internal/InteropBoxing.kt | 2 +- 8 files changed, 46 insertions(+), 55 deletions(-) diff --git a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Utils.kt b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Utils.kt index 07eeaaf2926..c159cc12eb3 100644 --- a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Utils.kt +++ b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Utils.kt @@ -184,9 +184,9 @@ internal fun CValue.isLeaf(): Boolean { return !hasChildren } -internal fun List.toNativeStringArray(placement: NativePlacement): CArrayPointer> { - return placement.allocArray(this.size) { index -> - this.value = this@toNativeStringArray[index].cstr.getPointer(placement) +internal fun List.toNativeStringArray(scope: AutofreeScope): CArrayPointer> { + return scope.allocArray(this.size) { index -> + this.value = this@toNativeStringArray[index].cstr.getPointer(scope) } } diff --git a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt index 9ac50e2bd04..b2d762d8bc1 100644 --- a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt +++ b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt @@ -70,26 +70,7 @@ 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. */ - abstract fun getPointer(placement: NativePlacement): CPointer -} - -inline fun CValuesRef?.usePointer(block: (CPointer?) -> R): R { - val allocated: Boolean - val pointer: CPointer? = if (this is CPointer?) { - allocated = false - this - } else { - allocated = true - this!!.getPointer(nativeHeap) - } - - return try { - block(pointer) - } finally { - if (allocated) { - nativeHeap.free(pointer.rawValue) - } - } + abstract fun getPointer(scope: AutofreeScope): CPointer } /** @@ -100,7 +81,7 @@ abstract class CValues : CValuesRef() { /** * Copies the values to [placement] and returns the pointer to the copy. */ - override abstract fun getPointer(placement: NativePlacement): CPointer + override abstract fun getPointer(scope: AutofreeScope): CPointer // TODO: optimize override fun equals(other: Any?): Boolean { @@ -134,7 +115,7 @@ abstract class CValues : CValuesRef() { abstract val size: Int } -fun CValues.placeTo(placement: NativePlacement) = this.getPointer(placement) +fun CValues.placeTo(scope: AutofreeScope) = this.getPointer(scope) /** * The single immutable C value. @@ -163,7 +144,7 @@ class CPointer internal constructor(val rawValue: NativePtr) : CVa override fun toString() = this.cPointerToString() - override fun getPointer(placement: NativePlacement) = this + override fun getPointer(scope: AutofreeScope) = this } /** diff --git a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt index c4d3ddd1985..ecb5aa053bc 100644 --- a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt +++ b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt @@ -65,7 +65,11 @@ open class DeferScope { } } -open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : NativePlacement, DeferScope() { +abstract class AutofreeScope : DeferScope(), NativePlacement { + override abstract fun alloc(size: Long, align: Int): NativePointed +} + +open class ArenaBase(private val parent: NativeFreeablePlacement = nativeHeap) : AutofreeScope() { private var lastChunk: NativePointed? = null @@ -209,8 +213,8 @@ fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer NativePlacement.allocPointerTo() = alloc>() fun zeroValue(size: Int, align: Int): CValue = object : CValue() { - override fun getPointer(placement: NativePlacement): CPointer { - val result = placement.alloc(size, align) + override fun getPointer(scope: AutofreeScope): CPointer { + val result = scope.alloc(size, align) nativeMemUtils.zeroMemory(result, size) return interpretCPointer(result.rawPtr)!! } @@ -232,7 +236,7 @@ fun CPointed.readValues(size: Int, align: Int): CValues { nativeMemUtils.getByteArray(this, bytes, size) return object : CValues() { - override fun getPointer(placement: NativePlacement): CPointer = placement.placeBytes(bytes, align) + override fun getPointer(scope: AutofreeScope): CPointer = scope.placeBytes(bytes, align) override val size get() = bytes.size } } @@ -244,7 +248,7 @@ 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(placement: NativePlacement): CPointer = placement.placeBytes(bytes, align) + override fun getPointer(scope: AutofreeScope): CPointer = scope.placeBytes(bytes, align) override val size get() = bytes.size } } @@ -255,7 +259,7 @@ inline fun T.readValue(): CValue = this.readValue(si fun CValue<*>.write(location: NativePtr) { // TODO: probably CValue must be redesigned. - val fakePlacement = object : NativePlacement { + val fakeScope = object : AutofreeScope() { var used = false override fun alloc(size: Long, align: Int): NativePointed { assert(!used) @@ -264,8 +268,8 @@ fun CValue<*>.write(location: NativePtr) { } } - this.getPointer(fakePlacement) - assert(fakePlacement.used) + this.getPointer(fakeScope) + assert(fakeScope.used) } // TODO: optimize @@ -302,7 +306,7 @@ inline fun createValues(count: Int, initializer: T.(inde } fun cValuesOf(vararg elements: Byte): CValues = object : CValues() { - override fun getPointer(placement: NativePlacement) = placement.allocArrayOf(elements) + override fun getPointer(scope: AutofreeScope) = scope.allocArrayOf(elements) override val size get() = 1 * elements.size } @@ -318,7 +322,7 @@ 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(placement: NativePlacement) = placement.allocArrayOf(*elements) + override fun getPointer(scope: AutofreeScope) = scope.allocArrayOf(*elements) override val size get() = 4 * elements.size } @@ -348,8 +352,8 @@ val String.cstr: CValues return object : CValues() { override val size get() = bytes.size + 1 - override fun getPointer(placement: NativePlacement): CPointer { - val result = placement.allocArray(bytes.size + 1) + 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 @@ -363,8 +367,8 @@ val String.wcstr: CValues return object : CValues() { override val size get() = 2 * (chars.size + 1) - override fun getPointer(placement: NativePlacement): CPointer { - val result = placement.allocArray(chars.size + 1) + override fun getPointer(scope: AutofreeScope): CPointer { + val result = scope.allocArray(chars.size + 1) nativeMemUtils.putCharArray(chars, result.pointed, chars.size) result[chars.size] = 0.toShort() return result diff --git a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/Varargs.kt b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/Varargs.kt index bb59a59a48c..645de66c00d 100644 --- a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/Varargs.kt +++ b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/Varargs.kt @@ -16,7 +16,7 @@ const val FFI_TYPE_KIND_POINTER: FfiTypeKind = 7 private tailrec fun convertArgument( argument: Any?, isVariadic: Boolean, location: COpaquePointer, - additionalPlacement: NativePlacement + additionalPlacement: AutofreeScope ): FfiTypeKind = when (argument) { is CValuesRef<*>? -> { location.reinterpret>()[0] = argument?.getPointer(additionalPlacement) @@ -96,7 +96,7 @@ inline fun NativePlacement.allocFfiReturnValueBuffer(ty fun callWithVarargs(codePtr: NativePtr, returnValuePtr: NativePtr, returnTypeKind: FfiTypeKind, fixedArguments: Array, variadicArguments: Array, - argumentsPlacement: NativePlacement) { + argumentsPlacement: AutofreeScope) { val totalArgumentsNumber = fixedArguments.size + variadicArguments.size 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 27535c63f75..45f93d25896 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 @@ -40,6 +40,14 @@ class KotlinCodeBuilder { lines.add(" ".repeat(nesting) + line) } + private var memScoped = false + fun pushMemScoped() { + if (!memScoped) { + memScoped = true + pushBlock("memScoped {") + } + } + fun pushBlock(line: String, free: String = "") { out(line) freeStack.add(free) 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 4ffbd288c88..96419ba8e5c 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 @@ -41,9 +41,9 @@ class MappingBridgeGeneratorImpl( kotlinValues.forEachIndexed { index, (type, value) -> if (type.unwrapTypedefs() is RecordType) { - val tmpVarName = "kni$index" - builder.pushBlock("$value.usePointer { $tmpVarName ->") - bridgeArguments.add(BridgeTypedKotlinValue(BridgedType.NATIVE_PTR, "$tmpVarName.rawValue")) + builder.pushMemScoped() + val bridgeArgument = "$value.getPointer(memScope).rawValue" + bridgeArguments.add(BridgeTypedKotlinValue(BridgedType.NATIVE_PTR, bridgeArgument)) } else { val info = mirror(declarationMapper, type).info bridgeArguments.add(BridgeTypedKotlinValue(info.bridgedType, info.argToBridged(value))) 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 07a96273fb0..d2cf4366d6d 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 @@ -599,24 +599,22 @@ class StubGenerator( } } - val tmpVarName = "kniTmp$index" - val representAsValuesRef = representCFunctionParameterAsValuesRef(parameter.type) val bridgeArgument = if (representCFunctionParameterAsString(parameter.type)) { kotlinParameters.add(parameterName to KotlinTypes.string.makeNullable()) - bodyGenerator.pushBlock("$parameterName?.cstr.usePointer { $tmpVarName ->") - tmpVarName + bodyGenerator.pushMemScoped() + "$parameterName?.cstr?.getPointer(memScope)" } else if (representCFunctionParameterAsWString(parameter.type)) { kotlinParameters.add(parameterName to KotlinTypes.string.makeNullable()) - bodyGenerator.pushBlock("$parameterName?.wcstr.usePointer { $tmpVarName ->") - tmpVarName + bodyGenerator.pushMemScoped() + "$parameterName?.wcstr?.getPointer(memScope)" } else if (representAsValuesRef != null) { val pointedType = mirror(representAsValuesRef).pointedType val parameterType = KotlinTypes.cValuesRef.typeWith(pointedType).makeNullable() kotlinParameters.add(parameterName to parameterType) - bodyGenerator.pushBlock("$parameterName.usePointer { $tmpVarName ->") - tmpVarName + bodyGenerator.pushMemScoped() + "$parameterName?.getPointer(memScope)" } else { val mirror = mirror(parameter.type) kotlinParameters.add(parameterName to mirror.argType) @@ -640,7 +638,7 @@ class StubGenerator( val returnTypeKind = getFfiTypeKind(func.returnType) kotlinParameters.add("vararg variadicArguments" to KotlinTypes.any.makeNullable()) - bodyGenerator.pushBlock("memScoped {") + bodyGenerator.pushMemScoped() val resultVar = "kniResult" diff --git a/runtime/src/main/kotlin/konan/internal/InteropBoxing.kt b/runtime/src/main/kotlin/konan/internal/InteropBoxing.kt index 593a2c60d1d..4c8c43e2567 100644 --- a/runtime/src/main/kotlin/konan/internal/InteropBoxing.kt +++ b/runtime/src/main/kotlin/konan/internal/InteropBoxing.kt @@ -67,7 +67,7 @@ class CPointerBox(val value: CPointer) : CValuesRef() { override fun toString() = value.toString() - override fun getPointer(placement: NativePlacement) = value.getPointer(placement) + override fun getPointer(scope: AutofreeScope) = value.getPointer(scope) } fun boxCPointer(value: CPointer?) = if (value != null) CPointerBox(value) else null