Merge pull request #8 from JetBrains/callbacks-strike-back

Fix bugs after supporting callbacks in Interop
This commit is contained in:
SvyatoslavScherbina
2016-10-14 17:40:02 +03:00
committed by GitHub
4 changed files with 64 additions and 22 deletions
@@ -3570,7 +3570,7 @@ enum class CXIndexOptFlags(val value: Int) {
} }
} }
object NativeFunctionType1 : NativeFunctionType<(CXCursor, CXCursor, NativePtr?) -> CXChildVisitResult>(UInt32, Struct(UInt32, SInt32, Pointer), Struct(UInt32, SInt32, Pointer), Pointer) { object NativeFunctionType1 : NativeFunctionType<(CXCursor, CXCursor, NativePtr?) -> CXChildVisitResult>(UInt32, Struct(UInt32, SInt32, Struct(Pointer, Pointer, Pointer)), Struct(UInt32, SInt32, Struct(Pointer, Pointer, Pointer)), Pointer) {
override fun invoke(function: (CXCursor, CXCursor, NativePtr?) -> CXChildVisitResult, args: NativeArray<NativePtrBox>, ret: NativePtr) { override fun invoke(function: (CXCursor, CXCursor, NativePtr?) -> CXChildVisitResult, args: NativeArray<NativePtrBox>, ret: NativePtr) {
val res = function(args[0].value.asRef(CXCursor)!!, args[1].value.asRef(CXCursor)!!, args[2].value.asRef(NativePtrBox)!!.value) val res = function(args[0].value.asRef(CXCursor)!!, args[1].value.asRef(CXCursor)!!, args[2].value.asRef(NativePtrBox)!!.value)
CXChildVisitResult.ref.byPtr(ret).value = res CXChildVisitResult.ref.byPtr(ret).value = res
@@ -3589,14 +3589,14 @@ object NativeFunctionType3 : NativeFunctionType<(NativePtr?, CXSourceLocation?,
} }
} }
object NativeFunctionType4 : NativeFunctionType<(CXCursor, NativePtr?) -> CXVisitorResult>(UInt32, Struct(UInt32, SInt32, Pointer), Pointer) { object NativeFunctionType4 : NativeFunctionType<(CXCursor, NativePtr?) -> CXVisitorResult>(UInt32, Struct(UInt32, SInt32, Struct(Pointer, Pointer, Pointer)), Pointer) {
override fun invoke(function: (CXCursor, NativePtr?) -> CXVisitorResult, args: NativeArray<NativePtrBox>, ret: NativePtr) { override fun invoke(function: (CXCursor, NativePtr?) -> CXVisitorResult, args: NativeArray<NativePtrBox>, ret: NativePtr) {
val res = function(args[0].value.asRef(CXCursor)!!, args[1].value.asRef(NativePtrBox)!!.value) val res = function(args[0].value.asRef(CXCursor)!!, args[1].value.asRef(NativePtrBox)!!.value)
CXVisitorResult.ref.byPtr(ret).value = res CXVisitorResult.ref.byPtr(ret).value = res
} }
} }
object NativeFunctionType5 : NativeFunctionType<(NativePtr?, CXCursor, CXSourceRange) -> CXVisitorResult>(UInt32, Pointer, Struct(UInt32, SInt32, Pointer), Struct(Pointer, UInt32, UInt32)) { object NativeFunctionType5 : NativeFunctionType<(NativePtr?, CXCursor, CXSourceRange) -> CXVisitorResult>(UInt32, Pointer, Struct(UInt32, SInt32, Struct(Pointer, Pointer, Pointer)), Struct(Struct(Pointer, Pointer), UInt32, UInt32)) {
override fun invoke(function: (NativePtr?, CXCursor, CXSourceRange) -> CXVisitorResult, args: NativeArray<NativePtrBox>, ret: NativePtr) { override fun invoke(function: (NativePtr?, CXCursor, CXSourceRange) -> CXVisitorResult, args: NativeArray<NativePtrBox>, ret: NativePtr) {
val res = function(args[0].value.asRef(NativePtrBox)!!.value, args[1].value.asRef(CXCursor)!!, args[2].value.asRef(CXSourceRange)!!) val res = function(args[0].value.asRef(NativePtrBox)!!.value, args[1].value.asRef(CXCursor)!!, args[2].value.asRef(CXSourceRange)!!)
CXVisitorResult.ref.byPtr(ret).value = res CXVisitorResult.ref.byPtr(ret).value = res
@@ -98,16 +98,27 @@ private class NativeIndexImpl : NativeIndex() {
* Computes [StructDef.hasNaturalLayout] property. * Computes [StructDef.hasNaturalLayout] property.
*/ */
fun structHasNaturalLayout(structDefCursor: CXCursor): Boolean { fun structHasNaturalLayout(structDefCursor: CXCursor): Boolean {
val hasAttributes = malloc(Int32Box) val defKind = structDefCursor.kind.value
hasAttributes.value = 0
clang_visitChildren(structDefCursor, { cursor, parent, clientData ->
if (clang_isAttribute(cursor.kind.value) != 0) {
clientData.asRef(Int32Box)!!.value = 1
}
CXChildVisitResult.CXChildVisit_Continue
}, hasAttributes.ptr)
return hasAttributes.value == 0 when (defKind) {
CXCursorKind.CXCursor_UnionDecl -> return false
CXCursorKind.CXCursor_StructDecl -> {
val hasAttributes = arena.alloc(Int32Box)
hasAttributes.value = 0
clang_visitChildren(structDefCursor, { cursor, parent, clientData ->
if (clang_isAttribute(cursor.kind.value) != 0) {
clientData.asRef(Int32Box)!!.value = 1
}
CXChildVisitResult.CXChildVisit_Continue
}, hasAttributes.ptr)
return hasAttributes.value == 0
}
else -> throw IllegalArgumentException(defKind.toString())
}
} }
fun convertType(type: CXType): Type { fun convertType(type: CXType): Type {
@@ -253,6 +264,7 @@ fun CXString.convertAndDispose(): String {
} }
fun buildNativeIndexImpl(headerFile: File, args: List<String>): NativeIndex { fun buildNativeIndexImpl(headerFile: File, args: List<String>): NativeIndex {
// TODO: dispose all allocated memory and resources
val args1 = args.map { CString.fromString(it)!!.asCharPtr() }.toTypedArray() val args1 = args.map { CString.fromString(it)!!.asCharPtr() }.toTypedArray()
val index = clang_createIndex(0, 0) val index = clang_createIndex(0, 0)
+7 -1
View File
@@ -101,6 +101,8 @@ JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypePointer(J
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypeStruct0(JNIEnv *env, jclass cls, jlong elements) { JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypeStruct0(JNIEnv *env, jclass cls, jlong elements) {
ffi_type* res = malloc(sizeof(ffi_type)); ffi_type* res = malloc(sizeof(ffi_type));
if (res != NULL) { if (res != NULL) {
res->size = 0;
res->alignment = 0;
res->elements = (ffi_type**) elements; res->elements = (ffi_type**) elements;
res->type = FFI_TYPE_STRUCT; res->type = FFI_TYPE_STRUCT;
} }
@@ -164,7 +166,11 @@ static void ffi_fun(ffi_cif *cif, void *ret, void **args, void *user_data) {
static jmethodID ffiFunImpl0 = NULL; static jmethodID ffiFunImpl0 = NULL;
static jclass cls = NULL; static jclass cls = NULL;
if (ffiFunImpl0 == NULL) { if (ffiFunImpl0 == NULL) {
cls = (*env)->FindClass(env, "kotlin_native/interop/CallbacksKt"); jclass clsLocal = (*env)->FindClass(env, "kotlin_native/interop/CallbacksKt");
checkException(env);
assert(clsLocal != NULL);
cls = (jclass) (*env)->NewGlobalRef(env, clsLocal);
checkException(env); checkException(env);
assert(cls != NULL); assert(cls != NULL);
@@ -374,7 +374,7 @@ class StubGenerator(
is RecordType -> { is RecordType -> {
val refType = getKotlinTypeForRefTo(type) val refType = getKotlinTypeForRefTo(type)
InValueBinding( return InValueBinding(
kotlinJniBridgeType = "Long", kotlinJniBridgeType = "Long",
conv = { "NativePtr.byValue($it).asRef(${refType.typeExpr})!!" }, conv = { "NativePtr.byValue($it).asRef(${refType.typeExpr})!!" },
kotlinType = refType.typeName kotlinType = refType.typeName
@@ -386,6 +386,16 @@ class StubGenerator(
} }
fun getCallbackParamBinding(type: Type): InValueBinding { fun getCallbackParamBinding(type: Type): InValueBinding {
when (type) {
is RecordType -> {
val refType = getKotlinTypeForRefTo(type)
return InValueBinding(
kotlinJniBridgeType = "Long",
conv = { throw UnsupportedOperationException() },
kotlinType = refType.typeName
)
}
}
return getInValueBinding(type) return getInValueBinding(type)
} }
@@ -578,6 +588,11 @@ class StubGenerator(
out("}") out("}")
} }
private fun getFfiStructType(elementTypes: List<Type>) =
"Struct(" +
elementTypes.map { getFfiType(it) }.joinToString(", ") +
")"
private fun getFfiType(type: Type): String { private fun getFfiType(type: Type): String {
return when(type) { return when(type) {
is VoidType -> "Void" is VoidType -> "Void"
@@ -588,29 +603,38 @@ class StubGenerator(
is Int32Type -> "SInt32" is Int32Type -> "SInt32"
is UInt32Type -> "UInt32" is UInt32Type -> "UInt32"
is IntPtrType, is UIntPtrType, // TODO is IntPtrType, is UIntPtrType, // TODO
is PointerType, is ArrayType -> "Pointer" is PointerType -> "Pointer"
is ConstArrayType -> getFfiStructType(
Array(type.length.toInt(), { type.elemType }).toList()
)
is EnumType -> getFfiType(type.def.baseType) is EnumType -> getFfiType(type.def.baseType)
is RecordType -> { is RecordType -> {
val def = type.decl.def!! val def = type.decl.def!!
if (!def.hasNaturalLayout) { if (!def.hasNaturalLayout) {
throw NotImplementedError() // TODO: represent pointer to function as NativePtr instead throw NotImplementedError() // TODO: represent pointer to function as NativePtr instead
} }
"Struct(" + def.fields.map { getFfiStructType(def.fields.map { it.type })
getFfiType(it.type)
}.joinToString(", ") + ")"
} }
else -> throw NotImplementedError(type.toString()) else -> throw NotImplementedError(type.toString())
} }
} }
private fun getArgFfiType(type: Type) = when (type) {
is ArrayType -> "Pointer"
else -> getFfiType(type)
}
private fun getRetValFfiType(type: Type) = getArgFfiType(type)
private fun generateFunctionType(type: FunctionType, name: String) { private fun generateFunctionType(type: FunctionType, name: String) {
val kotlinFunctionType = getKotlinFunctionType(type) val kotlinFunctionType = getKotlinFunctionType(type)
val constructorArgs = listOf(type.returnType, *type.parameterTypes.toTypedArray()).map { val constructorArgs = listOf(getRetValFfiType(type.returnType)) +
getFfiType(it) type.parameterTypes.map { getArgFfiType(it) }
}.joinToString(", ")
out("object $name : NativeFunctionType<$kotlinFunctionType>($constructorArgs) {") val constructorArgsStr = constructorArgs.joinToString(", ")
out("object $name : NativeFunctionType<$kotlinFunctionType>($constructorArgsStr) {")
indent { indent {
out("override fun invoke(function: $kotlinFunctionType, args: NativeArray<NativePtrBox>, ret: NativePtr) {") out("override fun invoke(function: $kotlinFunctionType, args: NativeArray<NativePtrBox>, ret: NativePtr) {")
indent { indent {