Minorly rework CValuesRef to make it more universal when subclassing

Allow `getPointer` to register custom disposers with `defer`
This commit is contained in:
Svyatoslav Scherbina
2017-09-19 12:37:13 +03:00
committed by SvyatoslavScherbina
parent a3721f857c
commit 17ccd3ee02
8 changed files with 46 additions and 55 deletions
@@ -184,9 +184,9 @@ internal fun CValue<CXCursor>.isLeaf(): Boolean {
return !hasChildren return !hasChildren
} }
internal fun List<String>.toNativeStringArray(placement: NativePlacement): CArrayPointer<CPointerVar<ByteVar>> { internal fun List<String>.toNativeStringArray(scope: AutofreeScope): CArrayPointer<CPointerVar<ByteVar>> {
return placement.allocArray(this.size) { index -> return scope.allocArray(this.size) { index ->
this.value = this@toNativeStringArray[index].cstr.getPointer(placement) this.value = this@toNativeStringArray[index].cstr.getPointer(scope)
} }
} }
@@ -70,26 +70,7 @@ abstract class CValuesRef<T : CPointed> {
* If this reference is [CPointer], returns this pointer. * If this reference is [CPointer], returns this pointer.
* Otherwise copies the referenced values to [placement] and returns the pointer to the copy. * Otherwise copies the referenced values to [placement] and returns the pointer to the copy.
*/ */
abstract fun getPointer(placement: NativePlacement): CPointer<T> abstract fun getPointer(scope: AutofreeScope): CPointer<T>
}
inline fun <T : CPointed, R> CValuesRef<T>?.usePointer(block: (CPointer<T>?) -> R): R {
val allocated: Boolean
val pointer: CPointer<T>? = if (this is CPointer<T>?) {
allocated = false
this
} else {
allocated = true
this!!.getPointer(nativeHeap)
}
return try {
block(pointer)
} finally {
if (allocated) {
nativeHeap.free(pointer.rawValue)
}
}
} }
/** /**
@@ -100,7 +81,7 @@ abstract class CValues<T : CVariable> : CValuesRef<T>() {
/** /**
* Copies the values to [placement] and returns the pointer to the copy. * Copies the values to [placement] and returns the pointer to the copy.
*/ */
override abstract fun getPointer(placement: NativePlacement): CPointer<T> override abstract fun getPointer(scope: AutofreeScope): CPointer<T>
// TODO: optimize // TODO: optimize
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
@@ -134,7 +115,7 @@ abstract class CValues<T : CVariable> : CValuesRef<T>() {
abstract val size: Int abstract val size: Int
} }
fun <T : CVariable> CValues<T>.placeTo(placement: NativePlacement) = this.getPointer(placement) fun <T : CVariable> CValues<T>.placeTo(scope: AutofreeScope) = this.getPointer(scope)
/** /**
* The single immutable C value. * The single immutable C value.
@@ -163,7 +144,7 @@ class CPointer<T : CPointed> internal constructor(val rawValue: NativePtr) : CVa
override fun toString() = this.cPointerToString() override fun toString() = this.cPointerToString()
override fun getPointer(placement: NativePlacement) = this override fun getPointer(scope: AutofreeScope) = this
} }
/** /**
@@ -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 private var lastChunk: NativePointed? = null
@@ -209,8 +213,8 @@ fun NativePlacement.allocArrayOf(vararg elements: Float): CArrayPointer<FloatVar
fun <T : CPointed> NativePlacement.allocPointerTo() = alloc<CPointerVar<T>>() fun <T : CPointed> NativePlacement.allocPointerTo() = alloc<CPointerVar<T>>()
fun <T : CVariable> zeroValue(size: Int, align: Int): CValue<T> = object : CValue<T>() { fun <T : CVariable> zeroValue(size: Int, align: Int): CValue<T> = object : CValue<T>() {
override fun getPointer(placement: NativePlacement): CPointer<T> { override fun getPointer(scope: AutofreeScope): CPointer<T> {
val result = placement.alloc(size, align) val result = scope.alloc(size, align)
nativeMemUtils.zeroMemory(result, size) nativeMemUtils.zeroMemory(result, size)
return interpretCPointer(result.rawPtr)!! return interpretCPointer(result.rawPtr)!!
} }
@@ -232,7 +236,7 @@ fun <T : CVariable> CPointed.readValues(size: Int, align: Int): CValues<T> {
nativeMemUtils.getByteArray(this, bytes, size) nativeMemUtils.getByteArray(this, bytes, size)
return object : CValues<T>() { return object : CValues<T>() {
override fun getPointer(placement: NativePlacement): CPointer<T> = placement.placeBytes(bytes, align) override fun getPointer(scope: AutofreeScope): CPointer<T> = scope.placeBytes(bytes, align)
override val size get() = bytes.size override val size get() = bytes.size
} }
} }
@@ -244,7 +248,7 @@ fun <T : CVariable> CPointed.readValue(size: Long, align: Int): CValue<T> {
val bytes = ByteArray(size.toInt()) val bytes = ByteArray(size.toInt())
nativeMemUtils.getByteArray(this, bytes, size.toInt()) nativeMemUtils.getByteArray(this, bytes, size.toInt())
return object : CValue<T>() { return object : CValue<T>() {
override fun getPointer(placement: NativePlacement): CPointer<T> = placement.placeBytes(bytes, align) override fun getPointer(scope: AutofreeScope): CPointer<T> = scope.placeBytes(bytes, align)
override val size get() = bytes.size override val size get() = bytes.size
} }
} }
@@ -255,7 +259,7 @@ inline fun <reified T : CStructVar> T.readValue(): CValue<T> = this.readValue(si
fun CValue<*>.write(location: NativePtr) { fun CValue<*>.write(location: NativePtr) {
// TODO: probably CValue must be redesigned. // TODO: probably CValue must be redesigned.
val fakePlacement = object : NativePlacement { val fakeScope = object : AutofreeScope() {
var used = false var used = false
override fun alloc(size: Long, align: Int): NativePointed { override fun alloc(size: Long, align: Int): NativePointed {
assert(!used) assert(!used)
@@ -264,8 +268,8 @@ fun CValue<*>.write(location: NativePtr) {
} }
} }
this.getPointer(fakePlacement) this.getPointer(fakeScope)
assert(fakePlacement.used) assert(fakeScope.used)
} }
// TODO: optimize // TODO: optimize
@@ -302,7 +306,7 @@ inline fun <reified T : CVariable> createValues(count: Int, initializer: T.(inde
} }
fun cValuesOf(vararg elements: Byte): CValues<ByteVar> = object : CValues<ByteVar>() { fun cValuesOf(vararg elements: Byte): CValues<ByteVar> = object : CValues<ByteVar>() {
override fun getPointer(placement: NativePlacement) = placement.allocArrayOf(elements) override fun getPointer(scope: AutofreeScope) = scope.allocArrayOf(elements)
override val size get() = 1 * elements.size override val size get() = 1 * elements.size
} }
@@ -318,7 +322,7 @@ fun cValuesOf(vararg elements: Long): CValues<LongVar> =
createValues(elements.size) { index -> this.value = elements[index] } createValues(elements.size) { index -> this.value = elements[index] }
fun cValuesOf(vararg elements: Float): CValues<FloatVar> = object : CValues<FloatVar>() { fun cValuesOf(vararg elements: Float): CValues<FloatVar> = object : CValues<FloatVar>() {
override fun getPointer(placement: NativePlacement) = placement.allocArrayOf(*elements) override fun getPointer(scope: AutofreeScope) = scope.allocArrayOf(*elements)
override val size get() = 4 * elements.size override val size get() = 4 * elements.size
} }
@@ -348,8 +352,8 @@ val String.cstr: CValues<ByteVar>
return object : CValues<ByteVar>() { return object : CValues<ByteVar>() {
override val size get() = bytes.size + 1 override val size get() = bytes.size + 1
override fun getPointer(placement: NativePlacement): CPointer<ByteVar> { override fun getPointer(scope: AutofreeScope): CPointer<ByteVar> {
val result = placement.allocArray<ByteVar>(bytes.size + 1) val result = scope.allocArray<ByteVar>(bytes.size + 1)
nativeMemUtils.putByteArray(bytes, result.pointed, bytes.size) nativeMemUtils.putByteArray(bytes, result.pointed, bytes.size)
result[bytes.size] = 0.toByte() result[bytes.size] = 0.toByte()
return result return result
@@ -363,8 +367,8 @@ val String.wcstr: CValues<ShortVar>
return object : CValues<ShortVar>() { return object : CValues<ShortVar>() {
override val size get() = 2 * (chars.size + 1) override val size get() = 2 * (chars.size + 1)
override fun getPointer(placement: NativePlacement): CPointer<ShortVar> { override fun getPointer(scope: AutofreeScope): CPointer<ShortVar> {
val result = placement.allocArray<ShortVar>(chars.size + 1) val result = scope.allocArray<ShortVar>(chars.size + 1)
nativeMemUtils.putCharArray(chars, result.pointed, chars.size) nativeMemUtils.putCharArray(chars, result.pointed, chars.size)
result[chars.size] = 0.toShort() result[chars.size] = 0.toShort()
return result return result
@@ -16,7 +16,7 @@ const val FFI_TYPE_KIND_POINTER: FfiTypeKind = 7
private tailrec fun convertArgument( private tailrec fun convertArgument(
argument: Any?, isVariadic: Boolean, location: COpaquePointer, argument: Any?, isVariadic: Boolean, location: COpaquePointer,
additionalPlacement: NativePlacement additionalPlacement: AutofreeScope
): FfiTypeKind = when (argument) { ): FfiTypeKind = when (argument) {
is CValuesRef<*>? -> { is CValuesRef<*>? -> {
location.reinterpret<CPointerVar<*>>()[0] = argument?.getPointer(additionalPlacement) location.reinterpret<CPointerVar<*>>()[0] = argument?.getPointer(additionalPlacement)
@@ -96,7 +96,7 @@ inline fun <reified T : CVariable> NativePlacement.allocFfiReturnValueBuffer(ty
fun callWithVarargs(codePtr: NativePtr, returnValuePtr: NativePtr, returnTypeKind: FfiTypeKind, fun callWithVarargs(codePtr: NativePtr, returnValuePtr: NativePtr, returnTypeKind: FfiTypeKind,
fixedArguments: Array<out Any?>, variadicArguments: Array<out Any?>, fixedArguments: Array<out Any?>, variadicArguments: Array<out Any?>,
argumentsPlacement: NativePlacement) { argumentsPlacement: AutofreeScope) {
val totalArgumentsNumber = fixedArguments.size + variadicArguments.size val totalArgumentsNumber = fixedArguments.size + variadicArguments.size
@@ -40,6 +40,14 @@ class KotlinCodeBuilder {
lines.add(" ".repeat(nesting) + line) lines.add(" ".repeat(nesting) + line)
} }
private var memScoped = false
fun pushMemScoped() {
if (!memScoped) {
memScoped = true
pushBlock("memScoped {")
}
}
fun pushBlock(line: String, free: String = "") { fun pushBlock(line: String, free: String = "") {
out(line) out(line)
freeStack.add(free) freeStack.add(free)
@@ -41,9 +41,9 @@ class MappingBridgeGeneratorImpl(
kotlinValues.forEachIndexed { index, (type, value) -> kotlinValues.forEachIndexed { index, (type, value) ->
if (type.unwrapTypedefs() is RecordType) { if (type.unwrapTypedefs() is RecordType) {
val tmpVarName = "kni$index" builder.pushMemScoped()
builder.pushBlock("$value.usePointer { $tmpVarName ->") val bridgeArgument = "$value.getPointer(memScope).rawValue"
bridgeArguments.add(BridgeTypedKotlinValue(BridgedType.NATIVE_PTR, "$tmpVarName.rawValue")) bridgeArguments.add(BridgeTypedKotlinValue(BridgedType.NATIVE_PTR, bridgeArgument))
} else { } else {
val info = mirror(declarationMapper, type).info val info = mirror(declarationMapper, type).info
bridgeArguments.add(BridgeTypedKotlinValue(info.bridgedType, info.argToBridged(value))) bridgeArguments.add(BridgeTypedKotlinValue(info.bridgedType, info.argToBridged(value)))
@@ -599,24 +599,22 @@ class StubGenerator(
} }
} }
val tmpVarName = "kniTmp$index"
val representAsValuesRef = representCFunctionParameterAsValuesRef(parameter.type) val representAsValuesRef = representCFunctionParameterAsValuesRef(parameter.type)
val bridgeArgument = if (representCFunctionParameterAsString(parameter.type)) { val bridgeArgument = if (representCFunctionParameterAsString(parameter.type)) {
kotlinParameters.add(parameterName to KotlinTypes.string.makeNullable()) kotlinParameters.add(parameterName to KotlinTypes.string.makeNullable())
bodyGenerator.pushBlock("$parameterName?.cstr.usePointer { $tmpVarName ->") bodyGenerator.pushMemScoped()
tmpVarName "$parameterName?.cstr?.getPointer(memScope)"
} else if (representCFunctionParameterAsWString(parameter.type)) { } else if (representCFunctionParameterAsWString(parameter.type)) {
kotlinParameters.add(parameterName to KotlinTypes.string.makeNullable()) kotlinParameters.add(parameterName to KotlinTypes.string.makeNullable())
bodyGenerator.pushBlock("$parameterName?.wcstr.usePointer { $tmpVarName ->") bodyGenerator.pushMemScoped()
tmpVarName "$parameterName?.wcstr?.getPointer(memScope)"
} else if (representAsValuesRef != null) { } else if (representAsValuesRef != null) {
val pointedType = mirror(representAsValuesRef).pointedType val pointedType = mirror(representAsValuesRef).pointedType
val parameterType = KotlinTypes.cValuesRef.typeWith(pointedType).makeNullable() val parameterType = KotlinTypes.cValuesRef.typeWith(pointedType).makeNullable()
kotlinParameters.add(parameterName to parameterType) kotlinParameters.add(parameterName to parameterType)
bodyGenerator.pushBlock("$parameterName.usePointer { $tmpVarName ->") bodyGenerator.pushMemScoped()
tmpVarName "$parameterName?.getPointer(memScope)"
} else { } else {
val mirror = mirror(parameter.type) val mirror = mirror(parameter.type)
kotlinParameters.add(parameterName to mirror.argType) kotlinParameters.add(parameterName to mirror.argType)
@@ -640,7 +638,7 @@ class StubGenerator(
val returnTypeKind = getFfiTypeKind(func.returnType) val returnTypeKind = getFfiTypeKind(func.returnType)
kotlinParameters.add("vararg variadicArguments" to KotlinTypes.any.makeNullable()) kotlinParameters.add("vararg variadicArguments" to KotlinTypes.any.makeNullable())
bodyGenerator.pushBlock("memScoped {") bodyGenerator.pushMemScoped()
val resultVar = "kniResult" val resultVar = "kniResult"
@@ -67,7 +67,7 @@ class CPointerBox(val value: CPointer<CPointed>) : CValuesRef<CPointed>() {
override fun toString() = value.toString() 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<CPointed>?) = if (value != null) CPointerBox(value) else null fun boxCPointer(value: CPointer<CPointed>?) = if (value != null) CPointerBox(value) else null