diff --git a/Interop/Indexer/build.gradle b/Interop/Indexer/build.gradle index 6b47cbb0029..e5f942750fd 100644 --- a/Interop/Indexer/build.gradle +++ b/Interop/Indexer/build.gradle @@ -17,12 +17,6 @@ def compilerArgsForJniIncludes = ["", "linux", "darwin"].collect { "-I$javaHome/ model { components { - callback(NativeLibrarySpec) { - binaries.all { - cCompiler.args compilerArgsForJniIncludes - } - } - clangbridge(NativeLibrarySpec) { sources { c.source.srcDir 'prebuilt/nativeInteropStubs/c' @@ -59,9 +53,8 @@ dependencies { } task nativelibs(type: Copy) { - dependsOn 'callbackSharedLibrary', 'clangbridgeSharedLibrary' + dependsOn 'clangbridgeSharedLibrary' - from "$buildDir/libs/callback/shared/" from "$buildDir/libs/clangbridge/shared/" into "$buildDir/nativelibs/" } diff --git a/Interop/Indexer/prebuilt/nativeInteropStubs/kotlin/clang/Clang.kt b/Interop/Indexer/prebuilt/nativeInteropStubs/kotlin/clang/Clang.kt index bf5a9d085bb..49cde2d3db9 100644 --- a/Interop/Indexer/prebuilt/nativeInteropStubs/kotlin/clang/Clang.kt +++ b/Interop/Indexer/prebuilt/nativeInteropStubs/kotlin/clang/Clang.kt @@ -1256,9 +1256,9 @@ fun clang_getIBOutletCollectionType(arg0: CXCursor, retValPlacement: Placement): return NativePtr.byValue(res).asRef(CXType)!! } -fun clang_visitChildren(parent: CXCursor, visitor: NativePtr?, client_data: NativePtr?): Int { +fun clang_visitChildren(parent: CXCursor, visitor: ((CXCursor, CXCursor, NativePtr?) -> CXChildVisitResult)?, client_data: NativePtr?): Int { val _parent = parent.getNativePtr().asLong() - val _visitor = visitor.asLong() + val _visitor = visitor?.staticAsNative(NativeFunctionType1).asLong() val _client_data = client_data.asLong() val res = externals.clang_visitChildren(_parent, _visitor, _client_data) return res @@ -1636,8 +1636,8 @@ fun clang_enableStackTraces(): Unit { return res } -fun clang_executeOnThread(fn: NativePtr?, user_data: NativePtr?, stack_size: Int): Unit { - val _fn = fn.asLong() +fun clang_executeOnThread(fn: ((NativePtr?) -> Unit)?, user_data: NativePtr?, stack_size: Int): Unit { + val _fn = fn?.staticAsNative(NativeFunctionType2).asLong() val _user_data = user_data.asLong() val res = externals.clang_executeOnThread(_fn, _user_data, stack_size) return res @@ -1790,9 +1790,9 @@ fun clang_toggleCrashRecovery(isEnabled: Int): Unit { return res } -fun clang_getInclusions(tu: CXTranslationUnitImpl?, visitor: NativePtr?, client_data: NativePtr?): Unit { +fun clang_getInclusions(tu: CXTranslationUnitImpl?, visitor: ((NativePtr?, CXSourceLocation?, Int, NativePtr?) -> Unit)?, client_data: NativePtr?): Unit { val _tu = tu.getNativePtr().asLong() - val _visitor = visitor.asLong() + val _visitor = visitor?.staticAsNative(NativeFunctionType3).asLong() val _client_data = client_data.asLong() val res = externals.clang_getInclusions(_tu, _visitor, _client_data) return res @@ -1986,9 +1986,9 @@ fun clang_indexLoc_getCXSourceLocation(loc: CXIdxLoc, retValPlacement: Placement return NativePtr.byValue(res).asRef(CXSourceLocation)!! } -fun clang_Type_visitFields(T: CXType, visitor: NativePtr?, client_data: NativePtr?): Int { +fun clang_Type_visitFields(T: CXType, visitor: ((CXCursor, NativePtr?) -> CXVisitorResult)?, client_data: NativePtr?): Int { val _T = T.getNativePtr().asLong() - val _visitor = visitor.asLong() + val _visitor = visitor?.staticAsNative(NativeFunctionType4).asLong() val _client_data = client_data.asLong() val res = externals.clang_Type_visitFields(_T, _visitor, _client_data) return res @@ -2006,7 +2006,7 @@ class __darwin_pthread_handler_rec(ptr: NativePtr) : NativeStruct(ptr) { companion object : Type<__darwin_pthread_handler_rec>(24, ::__darwin_pthread_handler_rec) - val __routine by NativePtrBox at 0 + val __routine by NativeFunctionType2.ref at 0 val __arg by NativePtrBox at 8 val __next by __darwin_pthread_handler_rec.ref at 16 } @@ -2266,7 +2266,7 @@ class CXCursorAndRangeVisitor(ptr: NativePtr) : NativeStruct(ptr) { companion object : Type(16, ::CXCursorAndRangeVisitor) val context by NativePtrBox at 0 - val visit by NativePtrBox at 8 + val visit by NativeFunctionType5.ref at 8 } class CXIdxLoc(ptr: NativePtr) : NativeStruct(ptr) { @@ -2446,14 +2446,14 @@ class IndexerCallbacks(ptr: NativePtr) : NativeStruct(ptr) { companion object : Type(64, ::IndexerCallbacks) - val abortQuery by NativePtrBox at 0 - val diagnostic by NativePtrBox at 8 - val enteredMainFile by NativePtrBox at 16 - val ppIncludedFile by NativePtrBox at 24 - val importedASTFile by NativePtrBox at 32 - val startedTranslationUnit by NativePtrBox at 40 - val indexDeclaration by NativePtrBox at 48 - val indexEntityReference by NativePtrBox at 56 + val abortQuery by NativeFunctionType6.ref at 0 + val diagnostic by NativeFunctionType7.ref at 8 + val enteredMainFile by NativeFunctionType8.ref at 16 + val ppIncludedFile by NativeFunctionType9.ref at 24 + val importedASTFile by NativeFunctionType10.ref at 32 + val startedTranslationUnit by NativeFunctionType11.ref at 40 + val indexDeclaration by NativeFunctionType12.ref at 48 + val indexEntityReference by NativeFunctionType13.ref at 56 } enum class CXErrorCode(val value: Int) { @@ -3570,6 +3570,92 @@ enum class CXIndexOptFlags(val value: Int) { } } +object NativeFunctionType1 : NativeFunctionType<(CXCursor, CXCursor, NativePtr?) -> CXChildVisitResult>(UInt32, Struct(UInt32, SInt32, Pointer), Struct(UInt32, SInt32, Pointer), Pointer) { + override fun invoke(function: (CXCursor, CXCursor, NativePtr?) -> CXChildVisitResult, args: NativeArray, ret: NativePtr) { + 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 + } +} + +object NativeFunctionType2 : NativeFunctionType<(NativePtr?) -> Unit>(Void, Pointer) { + override fun invoke(function: (NativePtr?) -> Unit, args: NativeArray, ret: NativePtr) { + val res = function(args[0].value.asRef(NativePtrBox)!!.value) + } +} + +object NativeFunctionType3 : NativeFunctionType<(NativePtr?, CXSourceLocation?, Int, NativePtr?) -> Unit>(Void, Pointer, Pointer, UInt32, Pointer) { + override fun invoke(function: (NativePtr?, CXSourceLocation?, Int, NativePtr?) -> Unit, args: NativeArray, ret: NativePtr) { + val res = function(args[0].value.asRef(NativePtrBox)!!.value, args[1].value.asRef(CXSourceLocation.ref)!!.value, args[2].value.asRef(Int32Box)!!.value, args[3].value.asRef(NativePtrBox)!!.value) + } +} + +object NativeFunctionType4 : NativeFunctionType<(CXCursor, NativePtr?) -> CXVisitorResult>(UInt32, Struct(UInt32, SInt32, Pointer), Pointer) { + override fun invoke(function: (CXCursor, NativePtr?) -> CXVisitorResult, args: NativeArray, ret: NativePtr) { + val res = function(args[0].value.asRef(CXCursor)!!, args[1].value.asRef(NativePtrBox)!!.value) + CXVisitorResult.ref.byPtr(ret).value = res + } +} + +object NativeFunctionType5 : NativeFunctionType<(NativePtr?, CXCursor, CXSourceRange) -> CXVisitorResult>(UInt32, Pointer, Struct(UInt32, SInt32, Pointer), Struct(Pointer, UInt32, UInt32)) { + override fun invoke(function: (NativePtr?, CXCursor, CXSourceRange) -> CXVisitorResult, args: NativeArray, ret: NativePtr) { + 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 + } +} + +object NativeFunctionType6 : NativeFunctionType<(NativePtr?, NativePtr?) -> Int>(SInt32, Pointer, Pointer) { + override fun invoke(function: (NativePtr?, NativePtr?) -> Int, args: NativeArray, ret: NativePtr) { + val res = function(args[0].value.asRef(NativePtrBox)!!.value, args[1].value.asRef(NativePtrBox)!!.value) + Int32Box.byPtr(ret).value = res + } +} + +object NativeFunctionType7 : NativeFunctionType<(NativePtr?, NativePtr?, NativePtr?) -> Unit>(Void, Pointer, Pointer, Pointer) { + override fun invoke(function: (NativePtr?, NativePtr?, NativePtr?) -> Unit, args: NativeArray, ret: NativePtr) { + val res = function(args[0].value.asRef(NativePtrBox)!!.value, args[1].value.asRef(NativePtrBox)!!.value, args[2].value.asRef(NativePtrBox)!!.value) + } +} + +object NativeFunctionType8 : NativeFunctionType<(NativePtr?, NativePtr?, NativePtr?) -> NativePtr?>(Pointer, Pointer, Pointer, Pointer) { + override fun invoke(function: (NativePtr?, NativePtr?, NativePtr?) -> NativePtr?, args: NativeArray, ret: NativePtr) { + val res = function(args[0].value.asRef(NativePtrBox)!!.value, args[1].value.asRef(NativePtrBox)!!.value, args[2].value.asRef(NativePtrBox)!!.value) + NativePtrBox.byPtr(ret).value = res + } +} + +object NativeFunctionType9 : NativeFunctionType<(NativePtr?, CXIdxIncludedFileInfo?) -> NativePtr?>(Pointer, Pointer, Pointer) { + override fun invoke(function: (NativePtr?, CXIdxIncludedFileInfo?) -> NativePtr?, args: NativeArray, ret: NativePtr) { + val res = function(args[0].value.asRef(NativePtrBox)!!.value, args[1].value.asRef(CXIdxIncludedFileInfo.ref)!!.value) + NativePtrBox.byPtr(ret).value = res + } +} + +object NativeFunctionType10 : NativeFunctionType<(NativePtr?, CXIdxImportedASTFileInfo?) -> NativePtr?>(Pointer, Pointer, Pointer) { + override fun invoke(function: (NativePtr?, CXIdxImportedASTFileInfo?) -> NativePtr?, args: NativeArray, ret: NativePtr) { + val res = function(args[0].value.asRef(NativePtrBox)!!.value, args[1].value.asRef(CXIdxImportedASTFileInfo.ref)!!.value) + NativePtrBox.byPtr(ret).value = res + } +} + +object NativeFunctionType11 : NativeFunctionType<(NativePtr?, NativePtr?) -> NativePtr?>(Pointer, Pointer, Pointer) { + override fun invoke(function: (NativePtr?, NativePtr?) -> NativePtr?, args: NativeArray, ret: NativePtr) { + val res = function(args[0].value.asRef(NativePtrBox)!!.value, args[1].value.asRef(NativePtrBox)!!.value) + NativePtrBox.byPtr(ret).value = res + } +} + +object NativeFunctionType12 : NativeFunctionType<(NativePtr?, CXIdxDeclInfo?) -> Unit>(Void, Pointer, Pointer) { + override fun invoke(function: (NativePtr?, CXIdxDeclInfo?) -> Unit, args: NativeArray, ret: NativePtr) { + val res = function(args[0].value.asRef(NativePtrBox)!!.value, args[1].value.asRef(CXIdxDeclInfo.ref)!!.value) + } +} + +object NativeFunctionType13 : NativeFunctionType<(NativePtr?, CXIdxEntityRefInfo?) -> Unit>(Void, Pointer, Pointer) { + override fun invoke(function: (NativePtr?, CXIdxEntityRefInfo?) -> Unit, args: NativeArray, ret: NativePtr) { + val res = function(args[0].value.asRef(NativePtrBox)!!.value, args[1].value.asRef(CXIdxEntityRefInfo.ref)!!.value) + } +} + object externals { init { System.loadLibrary("clangbridge") } external fun asctime(arg0: Long): Long diff --git a/Interop/Indexer/src/callback/c/callback.c b/Interop/Indexer/src/callback/c/callback.c deleted file mode 100644 index c9a521f96b0..00000000000 --- a/Interop/Indexer/src/callback/c/callback.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include - -static JavaVM *vm = NULL; - -// Returns the JNI env which can be used by the caller. -// If current thread is not attached to JVM, then it gets attached as daemon. -static JNIEnv* getCurrentEnv() { - JNIEnv* env; - assert (vm != NULL); - jint res = (*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_1); - if (res != JNI_OK) { - assert (res == JNI_EDETACHED); - res = (*vm)->AttachCurrentThreadAsDaemon(vm, (void**)&env, NULL); - assert (res == JNI_OK); - } - return env; -} - -jint JNI_OnLoad(JavaVM *vm_, void *reserved) { - vm = vm_; - return JNI_VERSION_1_1; -} - -// The implementation of native callback. -void indexDeclarationNativeCallback(void* arg1, void* arg2) { - JNIEnv* env = getCurrentEnv(); - - static jclass cls = NULL; - static jmethodID entryFromNative = NULL; - - if (cls == NULL) { - cls = (*env)->FindClass(env, "org/jetbrains/kotlin/native/interop/indexer/indexDeclarationCallback"); - assert(cls != NULL); - entryFromNative = (*env)->GetStaticMethodID(env, cls, "entryFromNative", "(J)V"); - assert(entryFromNative != NULL); - } - - (*env)->CallStaticVoidMethod(env, cls, entryFromNative, (jlong) arg2); - if ((*env)->ExceptionCheck(env)) { - (*env)->ExceptionDescribe(env); - assert(0); - } -} - -JNIEXPORT jlong JNICALL Java_org_jetbrains_kotlin_native_interop_indexer_indexDeclarationCallback_nativeCallbackPtr(JNIEnv *env, jobject obj) { - return (jlong) indexDeclarationNativeCallback; -} diff --git a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Callbacks.kt b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Callbacks.kt deleted file mode 100644 index 229ae4ef294..00000000000 --- a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Callbacks.kt +++ /dev/null @@ -1,55 +0,0 @@ -package org.jetbrains.kotlin.native.interop.indexer - -import clang.CXIdxDeclInfo -import kotlin_native.interop.NativePtr - -/** - * This object helps to create native callbacks with signature `void (CXClientData, const CXIdxDeclInfo *)`. - * At any time only one instance of native callback can exist. -*/ -internal object indexDeclarationCallback { - - /** - * The Kotlin function to be called when native callback is called. - */ - private var function: ((CXIdxDeclInfo)->Unit)? = null - - /** - * Creates instance of native callback with given Kotlin implementation. - * - * To create another one, this instance must be destroyed using [reset]. - */ - fun setUp(func: (CXIdxDeclInfo)->Unit): NativePtr { - assert (function == null) - function = func - return nativeCallbackPtr - } - - /** - * Destroys the (only) instance of native callback. - */ - fun reset() { - assert (function != null) - function = null - } - - /** - * This function is called from native callback implementation. - */ - @JvmStatic - private fun entryFromNative(info: Long) { - function!!(CXIdxDeclInfo(NativePtr.Companion.byValue(info)!!)) - } - - private val nativeCallbackPtr: NativePtr - - init { - System.loadLibrary("callback") - nativeCallbackPtr = NativePtr.byValue(nativeCallbackPtr())!! - } - - /** - * Returns the pointer to native callback. - */ - private external fun nativeCallbackPtr(): Long -} \ No newline at end of file diff --git a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt index 362a8841e81..a974f1b5c11 100644 --- a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt +++ b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Indexer.kt @@ -10,7 +10,9 @@ private class StructDeclImpl(spelling: String) : StructDecl(spelling) { override var def: StructDefImpl? = null } -private class StructDefImpl(size: Long, decl: StructDecl) : StructDef(size, decl) { +private class StructDefImpl(size: Long, decl: StructDecl, hasNaturalLayout: Boolean) : + StructDef(size, decl, hasNaturalLayout) { + override val fields = mutableListOf() } @@ -92,6 +94,22 @@ private class NativeIndexImpl : NativeIndex() { return res } + /** + * Computes [StructDef.hasNaturalLayout] property. + */ + fun structHasNaturalLayout(structDefCursor: CXCursor): Boolean { + val hasAttributes = malloc(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 + } + fun convertType(type: CXType): Type { val kind = type.kind.value return when (kind) { @@ -104,6 +122,7 @@ private class NativeIndexImpl : NativeIndex() { } } + // TODO: is e.g. CXType_Int guaranteed to be int32_t? CXType_Void -> VoidType CXType_Char_U, CXType_UChar -> UInt8Type @@ -182,7 +201,8 @@ private class NativeIndexImpl : NativeIndex() { val structDecl = getStructDeclAt(cursor) if (clang_isCursorDefinition(cursor) != 0) { val size = clang_Type_getSizeOf(clang_getCursorType(cursor, arena)) - structDecl.def = StructDefImpl(size, structDecl) + val hasNaturalLayout = structHasNaturalLayout(cursor) + structDecl.def = StructDefImpl(size, structDecl, hasNaturalLayout) } } @@ -241,28 +261,32 @@ fun buildNativeIndexImpl(headerFile: File, args: List): NativeIndex { val res = NativeIndexImpl() try { - val indexDeclarationNativeCallback = indexDeclarationCallback.setUp({ res.indexDeclaration(it) }) + val nativeIndexPtr = StableObjPtr.create(res) + val clientData = nativeIndexPtr.value try { with(callbacks) { - abortQuery.value = null - diagnostic.value = null - enteredMainFile.value = null - ppIncludedFile.value = null - importedASTFile.value = null - startedTranslationUnit.value = null - indexDeclaration.value = indexDeclarationNativeCallback - indexEntityReference.value = null + abortQuery.setStatic(null) + diagnostic.setStatic(null) + enteredMainFile.setStatic(null) + ppIncludedFile.setStatic(null) + importedASTFile.setStatic(null) + startedTranslationUnit.setStatic(null) + indexDeclaration.setStatic { clientData, info -> + val index = StableObjPtr.fromValue(clientData!!).get() as NativeIndexImpl + index.indexDeclaration(info!!) + } + indexEntityReference.setStatic(null) } - clang_indexSourceFile(indexAction, null, callbacks, IndexerCallbacks.Companion.size, 0, headerFile.path, + clang_indexSourceFile(indexAction, clientData, callbacks, IndexerCallbacks.size, 0, headerFile.path, mallocNativeArrayOf(Int8Box.Companion, *args1)[0], args1.size, null, 0, null, 0) return res } finally { - indexDeclarationCallback.reset() + nativeIndexPtr.dispose() } } finally { res.clearNativeMem() diff --git a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt index bda91fe2db7..6390ddd6d89 100644 --- a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt +++ b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/NativeIndex.kt @@ -31,8 +31,11 @@ abstract class StructDecl(val spelling: String) { /** * C struct definition. + * + * @param hasNaturalLayout must be `false` if the struct has unnatural layout, e.g. it is `packed`. + * May be `false` even if the struct has natural layout. */ -abstract class StructDef(val size: Long, val decl: StructDecl) { +abstract class StructDef(val size: Long, val decl: StructDecl, val hasNaturalLayout: Boolean) { abstract val fields: List } 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 dcd43323793..72bce02dbfb 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 @@ -590,10 +590,15 @@ class StubGenerator( is IntPtrType, is UIntPtrType, // TODO is PointerType, is ArrayType -> "Pointer" is EnumType -> getFfiType(type.def.baseType) - // FIXME: check that alignment is natural - is RecordType -> "Struct(" + type.decl.def!!.fields.map { - getFfiType(it.type) - }.joinToString(", ") + ")" + is RecordType -> { + val def = type.decl.def!! + if (!def.hasNaturalLayout) { + throw NotImplementedError() // TODO: represent pointer to function as NativePtr instead + } + "Struct(" + def.fields.map { + getFfiType(it.type) + }.joinToString(", ") + ")" + } else -> throw NotImplementedError(type.toString()) } }