Interop: rework String auto conversion

use memScoped
This commit is contained in:
Svyatoslav Scherbina
2016-10-19 15:59:55 +03:00
parent 53884f8da6
commit 8a66de216d
2 changed files with 25 additions and 24 deletions
@@ -32,13 +32,15 @@ fun Placement.allocNativeArrayOf(elements: ByteArray): NativeArray<Int8Box> {
} }
fun CString.Companion.fromString(str: String?): CString? { fun CString.Companion.fromString(str: String?): CString? {
if (str == null) { return str?.toCString(heap)
return null }
}
val bytes = str.toByteArray() // TODO: encoding 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 len = bytes.size
val nativeBytes = malloc(NativeArray of Int8Box length (len + 1)) val nativeBytes = retValPlacement.alloc(array[len + 1](Int8Box))
bytes.forEachIndexed { i, byte -> bytes.forEachIndexed { i, byte ->
nativeBytes[i].value = byte nativeBytes[i].value = byte
@@ -48,10 +50,6 @@ fun CString.Companion.fromString(str: String?): CString? {
return CString.fromArray(nativeBytes) return CString.fromArray(nativeBytes)
} }
fun NativeArray<Int8Box>.asCString() = CString.fromArray(this)
fun Int8Box.asCString() = CString.fromArray(NativeArray.byRefToFirstElem(this, Int8Box))
fun String.toCString() = CString.fromString(this)
class MemScope private constructor(private val arena: Arena) : Placement by arena { class MemScope private constructor(private val arena: Arena) : Placement by arena {
val memScope: Placement val memScope: Placement
get() = this get() = this
@@ -229,12 +229,12 @@ class StubGenerator(
* *
* @param kotlinType the name of Kotlin type to be used for this value in Kotlin. * @param kotlinType the name of Kotlin type to be used for this value in Kotlin.
* @param kotlinConv the function such that `kotlinConv(name)` converts variable `name` to pass it into JNI stub * @param kotlinConv the function such that `kotlinConv(name)` converts variable `name` to pass it into JNI stub
* @param convFree the function such that `convFree(name)` is the statement that frees the result of conversion * @param memScoped the conversion allocates memory and should be placed into `memScoped {}` block
* @param kotlinJniBridgeType the name of Kotlin type to be used for this value in JNI stub * @param kotlinJniBridgeType the name of Kotlin type to be used for this value in JNI stub
*/ */
class OutValueBinding(val kotlinType: String, class OutValueBinding(val kotlinType: String,
val kotlinConv: ((String) -> String)? = null, val kotlinConv: ((String) -> String)? = null,
val convFree: ((String) -> String)? = null, val memScoped: Boolean = false,
val kotlinJniBridgeType: String = kotlinType) val kotlinJniBridgeType: String = kotlinType)
/** /**
@@ -312,8 +312,8 @@ class StubGenerator(
) )
is Int8Type -> return OutValueBinding( is Int8Type -> return OutValueBinding(
kotlinType = "String?", kotlinType = "String?",
kotlinConv = { name -> "CString.fromString($name).getNativePtr().asLong()" }, kotlinConv = { name -> "$name?.toCString(memScope).getNativePtr().asLong()" },
convFree = { name -> "free(NativePtr.byValue($name))" }, memScoped = true,
kotlinJniBridgeType = "Long" kotlinJniBridgeType = "Long"
) )
} }
@@ -564,8 +564,9 @@ class StubGenerator(
"$name: " + paramBindings[i].kotlinType "$name: " + paramBindings[i].kotlinType
}.joinToString(", ") }.joinToString(", ")
out("fun ${func.name}($args): ${retValBinding.kotlinType} {") val header = "fun ${func.name}($args): ${retValBinding.kotlinType}"
indent {
fun generateBody() {
val externalParamNames = paramNames.mapIndexed { i: Int, name: String -> val externalParamNames = paramNames.mapIndexed { i: Int, name: String ->
val binding = paramBindings[i] val binding = paramBindings[i]
val externalParamName: String val externalParamName: String
@@ -581,13 +582,6 @@ class StubGenerator(
} }
out("val res = externals.${func.name}(" + externalParamNames.joinToString(", ") + ")") out("val res = externals.${func.name}(" + externalParamNames.joinToString(", ") + ")")
paramNames.forEachIndexed { i, name ->
val binding = paramBindings[i]
if (binding.convFree != null) {
assert(binding.kotlinConv != null)
out(binding.convFree.invoke(externalParamNames[i]))
}
}
if (dumpShims) { if (dumpShims) {
val returnValueRepresentation = retValBinding.conv("res") val returnValueRepresentation = retValBinding.conv("res")
@@ -599,9 +593,18 @@ class StubGenerator(
} }
out("return " + retValBinding.conv("res")) out("return " + retValBinding.conv("res"))
} }
out("}")
block(header) {
val memScoped = paramBindings.any { it.memScoped }
if (memScoped) {
block("memScoped") {
generateBody()
}
} else {
generateBody()
}
}
} }
private fun getFfiStructType(elementTypes: List<Type>) = private fun getFfiStructType(elementTypes: List<Type>) =