Interop: add support for passing structs by value
also improve support for enums
This commit is contained in:
+72
-10
@@ -17,6 +17,9 @@ class StubGenerator(
|
|||||||
|
|
||||||
val enums = translationUnit.enumList.map { it.name to it }.toMap()
|
val enums = translationUnit.enumList.map { it.name to it }.toMap()
|
||||||
|
|
||||||
|
val structs = translationUnit.structList.map { it.name to it }.toMap()
|
||||||
|
|
||||||
|
|
||||||
val functionsToBind = translationUnit.functionList.uniqueBy { it.name }.filter { it.name !in excludedFunctions }
|
val functionsToBind = translationUnit.functionList.uniqueBy { it.name }.filter { it.name !in excludedFunctions }
|
||||||
|
|
||||||
private fun mangleStructName(name: String) = if (name !in forbiddenStructNames) name else (name + "Struct")
|
private fun mangleStructName(name: String) = if (name !in forbiddenStructNames) name else (name + "Struct")
|
||||||
@@ -28,6 +31,9 @@ class StubGenerator(
|
|||||||
val NativeIndex.CForwardStruct.mangledName: String
|
val NativeIndex.CForwardStruct.mangledName: String
|
||||||
get() = mangleStructName(name)
|
get() = mangleStructName(name)
|
||||||
|
|
||||||
|
val EnumType.baseType: DirectlyMappedType
|
||||||
|
get() = (parseType(enums[name]!!.type) as DirectlyMappedType)
|
||||||
|
|
||||||
private var out: (String) -> Unit = {
|
private var out: (String) -> Unit = {
|
||||||
throw IllegalStateException()
|
throw IllegalStateException()
|
||||||
}
|
}
|
||||||
@@ -67,7 +73,7 @@ class StubGenerator(
|
|||||||
is Int64Type -> "int64_t"
|
is Int64Type -> "int64_t"
|
||||||
is UInt64Type -> "uint64_t"
|
is UInt64Type -> "uint64_t"
|
||||||
is PointerType -> pointeeType.getStringRepresentation() + "*"
|
is PointerType -> pointeeType.getStringRepresentation() + "*"
|
||||||
is RecordType -> "struct $name"
|
is RecordType -> structs[name]?.spelling ?: "void" // FIXME
|
||||||
is FunctionPointerType -> this.returnType.getStringRepresentation() + " (*)(" +
|
is FunctionPointerType -> this.returnType.getStringRepresentation() + " (*)(" +
|
||||||
this.parameterTypes.map { it.getStringRepresentation() }.joinToString(", ") + ")"
|
this.parameterTypes.map { it.getStringRepresentation() }.joinToString(", ") + ")"
|
||||||
is ArrayType -> "void*" // TODO
|
is ArrayType -> "void*" // TODO
|
||||||
@@ -84,6 +90,7 @@ class StubGenerator(
|
|||||||
is Int32Type, is UInt32Type -> NativeRefType("Int32Box")
|
is Int32Type, is UInt32Type -> NativeRefType("Int32Box")
|
||||||
is Int64Type, is UInt64Type -> NativeRefType("Int64Box")
|
is Int64Type, is UInt64Type -> NativeRefType("Int64Box")
|
||||||
is RecordType -> NativeRefType("${mangleStructName(type.name)}")
|
is RecordType -> NativeRefType("${mangleStructName(type.name)}")
|
||||||
|
is EnumType -> NativeRefType("${type.name}.ref")
|
||||||
is PointerType -> {
|
is PointerType -> {
|
||||||
if (type.pointeeType is VoidType) {
|
if (type.pointeeType is VoidType) {
|
||||||
NativeRefType("NativePtrBox")
|
NativeRefType("NativePtrBox")
|
||||||
@@ -148,10 +155,19 @@ class StubGenerator(
|
|||||||
is EnumType -> OutValueBinding(
|
is EnumType -> OutValueBinding(
|
||||||
kotlinType = type.name,
|
kotlinType = type.name,
|
||||||
kotlinConv = { "$it.value" },
|
kotlinConv = { "$it.value" },
|
||||||
kotlinJniBridgeType = "Long"
|
kotlinJniBridgeType = type.baseType.kotlinType
|
||||||
)
|
)
|
||||||
is ArrayType -> outValueRefBinding(getKotlinNativeRefType(type))
|
is ArrayType -> outValueRefBinding(getKotlinNativeRefType(type))
|
||||||
is FunctionPointerType -> getOutValueBinding(PointerType(VoidType))
|
is FunctionPointerType -> getOutValueBinding(PointerType(VoidType))
|
||||||
|
is RecordType -> {
|
||||||
|
val refType = getKotlinNativeRefType(type)
|
||||||
|
// pointer will be converted to value in C code
|
||||||
|
OutValueBinding(
|
||||||
|
kotlinType = refType.typeName,
|
||||||
|
kotlinConv = { "$it.getNativePtr().asLong()" },
|
||||||
|
kotlinJniBridgeType = "Long"
|
||||||
|
)
|
||||||
|
}
|
||||||
else -> throw NotImplementedError()
|
else -> throw NotImplementedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,11 +186,20 @@ class StubGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
is EnumType -> InValueBinding(
|
is EnumType -> InValueBinding(
|
||||||
kotlinJniBridgeType = "Long",
|
kotlinJniBridgeType = type.baseType.kotlinType,
|
||||||
conv = { "${type.name}.byValue($it)" },
|
conv = { "${type.name}.byValue($it)" },
|
||||||
kotlinType = type.name
|
kotlinType = type.name
|
||||||
)
|
)
|
||||||
is ArrayType -> inValueRefBinding(getKotlinNativeRefType(type))
|
is ArrayType -> inValueRefBinding(getKotlinNativeRefType(type))
|
||||||
|
is RecordType -> {
|
||||||
|
// FIXME
|
||||||
|
val refType = getKotlinNativeRefType(type)
|
||||||
|
InValueBinding(
|
||||||
|
kotlinJniBridgeType = "Long",
|
||||||
|
conv = { "NativePtr.byValue($it).asRef(${refType.typeExpr})!!" },
|
||||||
|
kotlinType = refType.typeName
|
||||||
|
)
|
||||||
|
}
|
||||||
else -> throw NotImplementedError()
|
else -> throw NotImplementedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,7 +240,10 @@ class StubGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateKotlinEnum(e: NativeIndex.CEnum) {
|
private fun generateKotlinEnum(e: NativeIndex.CEnum) {
|
||||||
out("enum class ${e.name}(val value: Long) {")
|
val baseType = (parseType(e.type) as DirectlyMappedType)
|
||||||
|
val baseRefType = getKotlinNativeRefType(baseType)
|
||||||
|
|
||||||
|
out("enum class ${e.name}(val value: ${baseType.kotlinType}) {")
|
||||||
indent {
|
indent {
|
||||||
e.valueList.forEach {
|
e.valueList.forEach {
|
||||||
out("${it.name}(${it.value}),")
|
out("${it.name}(${it.value}),")
|
||||||
@@ -223,8 +251,16 @@ class StubGenerator(
|
|||||||
out(";")
|
out(";")
|
||||||
out("")
|
out("")
|
||||||
out("companion object {")
|
out("companion object {")
|
||||||
out(" fun byValue(value: Long) = ${e.name}.values().find { it.value == value }!!")
|
out(" fun byValue(value: ${baseType.kotlinType}) = ${e.name}.values().find { it.value == value }!!")
|
||||||
out("}")
|
out("}")
|
||||||
|
out("")
|
||||||
|
out("class ref(ptr: NativePtr) : NativeRef(ptr) {")
|
||||||
|
out(" companion object : TypeWithSize<ref>(${baseRefType.typeExpr}.size, ::ref)")
|
||||||
|
out(" var value: ${e.name}")
|
||||||
|
out(" get() = byValue(${baseRefType.typeExpr}.byPtr(ptr).value)")
|
||||||
|
out(" set(value) { ${baseRefType.typeExpr}.byPtr(ptr).value = value.value }")
|
||||||
|
out("}")
|
||||||
|
|
||||||
}
|
}
|
||||||
out("}")
|
out("}")
|
||||||
}
|
}
|
||||||
@@ -234,15 +270,33 @@ class StubGenerator(
|
|||||||
private fun paramBindings(func: NativeIndex.Function): Array<OutValueBinding> {
|
private fun paramBindings(func: NativeIndex.Function): Array<OutValueBinding> {
|
||||||
val paramBindings = func.parameterList.map { param ->
|
val paramBindings = func.parameterList.map { param ->
|
||||||
getOutValueBinding(parseType(param.type))
|
getOutValueBinding(parseType(param.type))
|
||||||
}.toTypedArray()
|
}.toMutableList()
|
||||||
return paramBindings
|
|
||||||
|
val retValType = parseType(func.returnType)
|
||||||
|
if (retValType is RecordType) {
|
||||||
|
val retValRefType = getKotlinNativeRefType(retValType)
|
||||||
|
val typeExpr = retValRefType.typeExpr
|
||||||
|
|
||||||
|
paramBindings.add(OutValueBinding(
|
||||||
|
kotlinType = "Placement",
|
||||||
|
kotlinConv = { name -> "$name.alloc($typeExpr.size).asLong()" },
|
||||||
|
kotlinJniBridgeType = "Long"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
return paramBindings.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun paramNames(func: NativeIndex.Function): Array<String> {
|
private fun paramNames(func: NativeIndex.Function): Array<String> {
|
||||||
val paramNames = func.parameterList.mapIndexed { i: Int, parameter: NativeIndex.Function.Parameter ->
|
val paramNames = func.parameterList.mapIndexed { i: Int, parameter: NativeIndex.Function.Parameter ->
|
||||||
if (parameter.name != "") parameter.name else "arg$i"
|
if (parameter.name != "") parameter.name else "arg$i"
|
||||||
}.toTypedArray()
|
}.toMutableList()
|
||||||
return paramNames
|
|
||||||
|
if (parseType(func.returnType) is RecordType) {
|
||||||
|
paramNames.add("retValPlacement")
|
||||||
|
}
|
||||||
|
|
||||||
|
return paramNames.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateKotlinBindingMethod(func: NativeIndex.Function) {
|
private fun generateKotlinBindingMethod(func: NativeIndex.Function) {
|
||||||
@@ -394,7 +448,11 @@ class StubGenerator(
|
|||||||
|
|
||||||
val params = func.parameterList.mapIndexed { i, parameter ->
|
val params = func.parameterList.mapIndexed { i, parameter ->
|
||||||
val cType = parseType(parameter.type).getStringRepresentation()
|
val cType = parseType(parameter.type).getStringRepresentation()
|
||||||
"($cType)${paramNames[i]}"
|
if (parseType(parameter.type) is RecordType) {
|
||||||
|
"*($cType*)${paramNames[i]}" // FIXME
|
||||||
|
} else {
|
||||||
|
"($cType)${paramNames[i]}"
|
||||||
|
}
|
||||||
}.joinToString(", ")
|
}.joinToString(", ")
|
||||||
|
|
||||||
val callExpr = "${func.name}($params)"
|
val callExpr = "${func.name}($params)"
|
||||||
@@ -406,8 +464,12 @@ class StubGenerator(
|
|||||||
val jniFuncName = "Java_" + funcFullName.replace("_", "_1").replace('.', '_').replace("$", "_00024")
|
val jniFuncName = "Java_" + funcFullName.replace("_", "_1").replace('.', '_').replace("$", "_00024")
|
||||||
|
|
||||||
out("JNIEXPORT $cReturnType JNICALL $jniFuncName (JNIEnv *env, jobject obj$args) {")
|
out("JNIEXPORT $cReturnType JNICALL $jniFuncName (JNIEnv *env, jobject obj$args) {")
|
||||||
|
|
||||||
if (cReturnType == "void") {
|
if (cReturnType == "void") {
|
||||||
out(" $callExpr;")
|
out(" $callExpr;")
|
||||||
|
} else if (retValBinding.kotlinType in structs) { // FIXME
|
||||||
|
out(" *(${structs[retValBinding.kotlinType]!!.spelling}*)retValPlacement = $callExpr;")
|
||||||
|
out(" return ($cReturnType) retValPlacement;")
|
||||||
} else {
|
} else {
|
||||||
out(" return ($cReturnType) ($callExpr);")
|
out(" return ($cReturnType) ($callExpr);")
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
Submodule experiments/kni updated: 43de50dc75...147829a017
Reference in New Issue
Block a user