Merge pull request #2 from JetBrains/interop-callbacks-1
Support callbacks in interop
This commit is contained in:
@@ -17,12 +17,6 @@ def compilerArgsForJniIncludes = ["", "linux", "darwin"].collect { "-I$javaHome/
|
|||||||
|
|
||||||
model {
|
model {
|
||||||
components {
|
components {
|
||||||
callback(NativeLibrarySpec) {
|
|
||||||
binaries.all {
|
|
||||||
cCompiler.args compilerArgsForJniIncludes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clangbridge(NativeLibrarySpec) {
|
clangbridge(NativeLibrarySpec) {
|
||||||
sources {
|
sources {
|
||||||
c.source.srcDir 'prebuilt/nativeInteropStubs/c'
|
c.source.srcDir 'prebuilt/nativeInteropStubs/c'
|
||||||
@@ -59,9 +53,8 @@ dependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
task nativelibs(type: Copy) {
|
task nativelibs(type: Copy) {
|
||||||
dependsOn 'callbackSharedLibrary', 'clangbridgeSharedLibrary'
|
dependsOn 'clangbridgeSharedLibrary'
|
||||||
|
|
||||||
from "$buildDir/libs/callback/shared/"
|
|
||||||
from "$buildDir/libs/clangbridge/shared/"
|
from "$buildDir/libs/clangbridge/shared/"
|
||||||
into "$buildDir/nativelibs/"
|
into "$buildDir/nativelibs/"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1256,9 +1256,9 @@ fun clang_getIBOutletCollectionType(arg0: CXCursor, retValPlacement: Placement):
|
|||||||
return NativePtr.byValue(res).asRef(CXType)!!
|
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 _parent = parent.getNativePtr().asLong()
|
||||||
val _visitor = visitor.asLong()
|
val _visitor = visitor?.staticAsNative(NativeFunctionType1).asLong()
|
||||||
val _client_data = client_data.asLong()
|
val _client_data = client_data.asLong()
|
||||||
val res = externals.clang_visitChildren(_parent, _visitor, _client_data)
|
val res = externals.clang_visitChildren(_parent, _visitor, _client_data)
|
||||||
return res
|
return res
|
||||||
@@ -1636,8 +1636,8 @@ fun clang_enableStackTraces(): Unit {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clang_executeOnThread(fn: NativePtr?, user_data: NativePtr?, stack_size: Int): Unit {
|
fun clang_executeOnThread(fn: ((NativePtr?) -> Unit)?, user_data: NativePtr?, stack_size: Int): Unit {
|
||||||
val _fn = fn.asLong()
|
val _fn = fn?.staticAsNative(NativeFunctionType2).asLong()
|
||||||
val _user_data = user_data.asLong()
|
val _user_data = user_data.asLong()
|
||||||
val res = externals.clang_executeOnThread(_fn, _user_data, stack_size)
|
val res = externals.clang_executeOnThread(_fn, _user_data, stack_size)
|
||||||
return res
|
return res
|
||||||
@@ -1790,9 +1790,9 @@ fun clang_toggleCrashRecovery(isEnabled: Int): Unit {
|
|||||||
return res
|
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 _tu = tu.getNativePtr().asLong()
|
||||||
val _visitor = visitor.asLong()
|
val _visitor = visitor?.staticAsNative(NativeFunctionType3).asLong()
|
||||||
val _client_data = client_data.asLong()
|
val _client_data = client_data.asLong()
|
||||||
val res = externals.clang_getInclusions(_tu, _visitor, _client_data)
|
val res = externals.clang_getInclusions(_tu, _visitor, _client_data)
|
||||||
return res
|
return res
|
||||||
@@ -1986,9 +1986,9 @@ fun clang_indexLoc_getCXSourceLocation(loc: CXIdxLoc, retValPlacement: Placement
|
|||||||
return NativePtr.byValue(res).asRef(CXSourceLocation)!!
|
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 _T = T.getNativePtr().asLong()
|
||||||
val _visitor = visitor.asLong()
|
val _visitor = visitor?.staticAsNative(NativeFunctionType4).asLong()
|
||||||
val _client_data = client_data.asLong()
|
val _client_data = client_data.asLong()
|
||||||
val res = externals.clang_Type_visitFields(_T, _visitor, _client_data)
|
val res = externals.clang_Type_visitFields(_T, _visitor, _client_data)
|
||||||
return res
|
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)
|
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 __arg by NativePtrBox at 8
|
||||||
val __next by __darwin_pthread_handler_rec.ref at 16
|
val __next by __darwin_pthread_handler_rec.ref at 16
|
||||||
}
|
}
|
||||||
@@ -2266,7 +2266,7 @@ class CXCursorAndRangeVisitor(ptr: NativePtr) : NativeStruct(ptr) {
|
|||||||
companion object : Type<CXCursorAndRangeVisitor>(16, ::CXCursorAndRangeVisitor)
|
companion object : Type<CXCursorAndRangeVisitor>(16, ::CXCursorAndRangeVisitor)
|
||||||
|
|
||||||
val context by NativePtrBox at 0
|
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) {
|
class CXIdxLoc(ptr: NativePtr) : NativeStruct(ptr) {
|
||||||
@@ -2446,14 +2446,14 @@ class IndexerCallbacks(ptr: NativePtr) : NativeStruct(ptr) {
|
|||||||
|
|
||||||
companion object : Type<IndexerCallbacks>(64, ::IndexerCallbacks)
|
companion object : Type<IndexerCallbacks>(64, ::IndexerCallbacks)
|
||||||
|
|
||||||
val abortQuery by NativePtrBox at 0
|
val abortQuery by NativeFunctionType6.ref at 0
|
||||||
val diagnostic by NativePtrBox at 8
|
val diagnostic by NativeFunctionType7.ref at 8
|
||||||
val enteredMainFile by NativePtrBox at 16
|
val enteredMainFile by NativeFunctionType8.ref at 16
|
||||||
val ppIncludedFile by NativePtrBox at 24
|
val ppIncludedFile by NativeFunctionType9.ref at 24
|
||||||
val importedASTFile by NativePtrBox at 32
|
val importedASTFile by NativeFunctionType10.ref at 32
|
||||||
val startedTranslationUnit by NativePtrBox at 40
|
val startedTranslationUnit by NativeFunctionType11.ref at 40
|
||||||
val indexDeclaration by NativePtrBox at 48
|
val indexDeclaration by NativeFunctionType12.ref at 48
|
||||||
val indexEntityReference by NativePtrBox at 56
|
val indexEntityReference by NativeFunctionType13.ref at 56
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class CXErrorCode(val value: Int) {
|
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<NativePtrBox>, 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<NativePtrBox>, 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<NativePtrBox>, 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<NativePtrBox>, 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<NativePtrBox>, 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<NativePtrBox>, 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<NativePtrBox>, 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<NativePtrBox>, 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<NativePtrBox>, 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<NativePtrBox>, 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<NativePtrBox>, 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<NativePtrBox>, 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<NativePtrBox>, ret: NativePtr) {
|
||||||
|
val res = function(args[0].value.asRef(NativePtrBox)!!.value, args[1].value.asRef(CXIdxEntityRefInfo.ref)!!.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object externals {
|
object externals {
|
||||||
init { System.loadLibrary("clangbridge") }
|
init { System.loadLibrary("clangbridge") }
|
||||||
external fun asctime(arg0: Long): Long
|
external fun asctime(arg0: Long): Long
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
#include <jni.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
-55
@@ -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
|
|
||||||
}
|
|
||||||
+37
-13
@@ -10,7 +10,9 @@ private class StructDeclImpl(spelling: String) : StructDecl(spelling) {
|
|||||||
override var def: StructDefImpl? = null
|
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<Field>()
|
override val fields = mutableListOf<Field>()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +94,22 @@ private class NativeIndexImpl : NativeIndex() {
|
|||||||
return res
|
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 {
|
fun convertType(type: CXType): Type {
|
||||||
val kind = type.kind.value
|
val kind = type.kind.value
|
||||||
return when (kind) {
|
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_Void -> VoidType
|
||||||
|
|
||||||
CXType_Char_U, CXType_UChar -> UInt8Type
|
CXType_Char_U, CXType_UChar -> UInt8Type
|
||||||
@@ -182,7 +201,8 @@ private class NativeIndexImpl : NativeIndex() {
|
|||||||
val structDecl = getStructDeclAt(cursor)
|
val structDecl = getStructDeclAt(cursor)
|
||||||
if (clang_isCursorDefinition(cursor) != 0) {
|
if (clang_isCursorDefinition(cursor) != 0) {
|
||||||
val size = clang_Type_getSizeOf(clang_getCursorType(cursor, arena))
|
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<String>): NativeIndex {
|
|||||||
|
|
||||||
val res = NativeIndexImpl()
|
val res = NativeIndexImpl()
|
||||||
try {
|
try {
|
||||||
val indexDeclarationNativeCallback = indexDeclarationCallback.setUp({ res.indexDeclaration(it) })
|
val nativeIndexPtr = StableObjPtr.create(res)
|
||||||
|
val clientData = nativeIndexPtr.value
|
||||||
|
|
||||||
try {
|
try {
|
||||||
with(callbacks) {
|
with(callbacks) {
|
||||||
abortQuery.value = null
|
abortQuery.setStatic(null)
|
||||||
diagnostic.value = null
|
diagnostic.setStatic(null)
|
||||||
enteredMainFile.value = null
|
enteredMainFile.setStatic(null)
|
||||||
ppIncludedFile.value = null
|
ppIncludedFile.setStatic(null)
|
||||||
importedASTFile.value = null
|
importedASTFile.setStatic(null)
|
||||||
startedTranslationUnit.value = null
|
startedTranslationUnit.setStatic(null)
|
||||||
indexDeclaration.value = indexDeclarationNativeCallback
|
indexDeclaration.setStatic { clientData, info ->
|
||||||
indexEntityReference.value = null
|
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)
|
mallocNativeArrayOf(Int8Box.Companion, *args1)[0], args1.size, null, 0, null, 0)
|
||||||
|
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
indexDeclarationCallback.reset()
|
nativeIndexPtr.dispose()
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
res.clearNativeMem()
|
res.clearNativeMem()
|
||||||
|
|||||||
+27
-22
@@ -31,8 +31,11 @@ abstract class StructDecl(val spelling: String) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* C struct definition.
|
* 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<Field>
|
abstract val fields: List<Field>
|
||||||
}
|
}
|
||||||
@@ -64,38 +67,40 @@ class FunctionDecl(val name: String, val parameters: List<Parameter>, val return
|
|||||||
/**
|
/**
|
||||||
* C type.
|
* C type.
|
||||||
*/
|
*/
|
||||||
open class Type
|
interface Type
|
||||||
|
|
||||||
open class PrimitiveType : Type()
|
interface PrimitiveType : Type
|
||||||
|
|
||||||
object VoidType : Type()
|
object VoidType : Type
|
||||||
|
|
||||||
object Int8Type : PrimitiveType()
|
object Int8Type : PrimitiveType
|
||||||
object UInt8Type : PrimitiveType()
|
object UInt8Type : PrimitiveType
|
||||||
|
|
||||||
object Int16Type : PrimitiveType()
|
object Int16Type : PrimitiveType
|
||||||
object UInt16Type : PrimitiveType()
|
object UInt16Type : PrimitiveType
|
||||||
|
|
||||||
object Int32Type : PrimitiveType()
|
object Int32Type : PrimitiveType
|
||||||
object UInt32Type : PrimitiveType()
|
object UInt32Type : PrimitiveType
|
||||||
|
|
||||||
object IntPtrType : PrimitiveType()
|
object IntPtrType : PrimitiveType
|
||||||
object UIntPtrType : PrimitiveType()
|
object UIntPtrType : PrimitiveType
|
||||||
|
|
||||||
object Int64Type : PrimitiveType()
|
object Int64Type : PrimitiveType
|
||||||
object UInt64Type : PrimitiveType()
|
object UInt64Type : PrimitiveType
|
||||||
|
|
||||||
class RecordType(val decl: StructDecl) : Type()
|
data class RecordType(val decl: StructDecl) : Type
|
||||||
|
|
||||||
class EnumType(val def: EnumDef) : Type()
|
data class EnumType(val def: EnumDef) : Type
|
||||||
|
|
||||||
class PointerType(val pointeeType : Type) : Type()
|
data class PointerType(val pointeeType : Type) : Type
|
||||||
|
|
||||||
class FunctionType(val parameterTypes: List<Type>, val returnType: Type) : Type()
|
data class FunctionType(val parameterTypes: List<Type>, val returnType: Type) : Type
|
||||||
|
|
||||||
open class ArrayType(val elemType: Type) : Type()
|
interface ArrayType : Type {
|
||||||
class ConstArrayType(elemType: Type, val length: Long) : ArrayType(elemType)
|
val elemType: Type
|
||||||
class IncompleteArrayType(elemType: Type) : ArrayType(elemType)
|
}
|
||||||
|
|
||||||
object UnsupportedType : Type()
|
data class ConstArrayType(override val elemType: Type, val length: Long) : ArrayType
|
||||||
|
data class IncompleteArrayType(override val elemType: Type) : ArrayType
|
||||||
|
|
||||||
|
object UnsupportedType : Type
|
||||||
@@ -9,6 +9,29 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply plugin: 'kotlin'
|
apply plugin: 'kotlin'
|
||||||
|
apply plugin: 'c'
|
||||||
|
|
||||||
|
def javaHome = System.getProperty('java.home')
|
||||||
|
def compilerArgsForJniIncludes = ["", "linux", "darwin"].collect { "-I$javaHome/../include/$it" } as String[]
|
||||||
|
|
||||||
|
model {
|
||||||
|
components {
|
||||||
|
callbacks(NativeLibrarySpec) {
|
||||||
|
sources.c.source {
|
||||||
|
srcDir 'src/callbacks/c'
|
||||||
|
include '**/*.c'
|
||||||
|
}
|
||||||
|
binaries.all {
|
||||||
|
cCompiler.args compilerArgsForJniIncludes
|
||||||
|
cCompiler.args "-I$ffiIncludePath"
|
||||||
|
|
||||||
|
String libffiPicPath = "$ffiLibPath/libffi_pic.a"
|
||||||
|
linker.args file(libffiPicPath).exists() ? libffiPicPath : "$ffiLibPath/libffi.a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@@ -17,3 +40,13 @@ repositories {
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
task nativelibs(type: Copy) {
|
||||||
|
dependsOn 'callbacksSharedLibrary'
|
||||||
|
|
||||||
|
from "$buildDir/libs/callbacks/shared/"
|
||||||
|
into "$buildDir/nativelibs/"
|
||||||
|
}
|
||||||
|
|
||||||
|
classes.dependsOn nativelibs
|
||||||
|
|||||||
@@ -0,0 +1,233 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <jni.h>
|
||||||
|
#include <ffi.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiTypeVoid
|
||||||
|
* Signature: ()J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypeVoid(JNIEnv *env, jclass cls) {
|
||||||
|
return (jlong) &ffi_type_void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiTypeUInt8
|
||||||
|
* Signature: ()J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypeUInt8(JNIEnv *env, jclass cls) {
|
||||||
|
return (jlong) &ffi_type_uint8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiTypeSInt8
|
||||||
|
* Signature: ()J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypeSInt8(JNIEnv *env, jclass cls) {
|
||||||
|
return (jlong) &ffi_type_sint8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiTypeUInt16
|
||||||
|
* Signature: ()J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypeUInt16(JNIEnv *env, jclass cls) {
|
||||||
|
return (jlong) &ffi_type_uint16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiTypeSInt16
|
||||||
|
* Signature: ()J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypeSInt16(JNIEnv *env, jclass cls) {
|
||||||
|
return (jlong) &ffi_type_sint16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiTypeUInt32
|
||||||
|
* Signature: ()J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypeUInt32(JNIEnv *env, jclass cls) {
|
||||||
|
return (jlong) &ffi_type_uint32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiTypeSInt32
|
||||||
|
* Signature: ()J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypeSInt32(JNIEnv *env, jclass cls) {
|
||||||
|
return (jlong) &ffi_type_sint32;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiTypeUInt64
|
||||||
|
* Signature: ()J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypeUInt64(JNIEnv *env, jclass cls) {
|
||||||
|
return (jlong) &ffi_type_uint64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiTypeSInt64
|
||||||
|
* Signature: ()J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypeSInt64(JNIEnv *env, jclass cls) {
|
||||||
|
return (jlong) &ffi_type_sint64;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiTypePointer
|
||||||
|
* Signature: ()J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypePointer(JNIEnv *env, jclass cls) {
|
||||||
|
return (jlong) &ffi_type_pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiTypeStruct0
|
||||||
|
* Signature: (J)J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiTypeStruct0(JNIEnv *env, jclass cls, jlong elements) {
|
||||||
|
ffi_type* res = malloc(sizeof(ffi_type));
|
||||||
|
if (res != NULL) {
|
||||||
|
res->elements = (ffi_type**) elements;
|
||||||
|
res->type = FFI_TYPE_STRUCT;
|
||||||
|
}
|
||||||
|
return (jlong) res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiCreateCif0
|
||||||
|
* Signature: (IJJ)J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiCreateCif0(JNIEnv *env, jclass cls, jint nArgs, jlong rType, jlong argTypes) {
|
||||||
|
ffi_cif* res = malloc(sizeof(ffi_cif));
|
||||||
|
if (res != NULL) {
|
||||||
|
ffi_status status = ffi_prep_cif(res, FFI_DEFAULT_ABI, nArgs, (ffi_type*)rType, (ffi_type**)argTypes);
|
||||||
|
if (status != FFI_OK) {
|
||||||
|
if (status == FFI_BAD_TYPEDEF) {
|
||||||
|
return -(jlong)1;
|
||||||
|
} else if (status == FFI_BAD_ABI) {
|
||||||
|
return -(jlong)2;
|
||||||
|
} else {
|
||||||
|
return -(jlong)3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (jlong) res;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checks for pending exception. If there is one, describes it and terminates the process.
|
||||||
|
static void checkException(JNIEnv *env) {
|
||||||
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
|
(*env)->ExceptionDescribe(env);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ffi_fun(ffi_cif *cif, void *ret, void **args, void *user_data) {
|
||||||
|
JNIEnv* env = getCurrentEnv();
|
||||||
|
|
||||||
|
static jmethodID ffiFunImpl0 = NULL;
|
||||||
|
static jclass cls = NULL;
|
||||||
|
if (ffiFunImpl0 == NULL) {
|
||||||
|
cls = (*env)->FindClass(env, "kotlin_native/interop/CallbacksKt");
|
||||||
|
checkException(env);
|
||||||
|
assert(cls != NULL);
|
||||||
|
|
||||||
|
ffiFunImpl0 = (*env)->GetStaticMethodID(env, cls, "ffiFunImpl0", "(JJJLjava/lang/Object;)V");
|
||||||
|
checkException(env);
|
||||||
|
assert(ffiFunImpl0 != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
(*env)->CallStaticVoidMethod(env, cls, ffiFunImpl0, (jlong) cif, (jlong) ret, (jlong) args, (jobject) user_data);
|
||||||
|
checkException(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: ffiCreateClosure0
|
||||||
|
* Signature: (JLjava/lang/Object;)J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_ffiCreateClosure0(JNIEnv *env, jclass cls, jlong ffiCif, jobject userData) {
|
||||||
|
jobject userDataGlobalRef = (*env)->NewGlobalRef(env, userData);
|
||||||
|
if (userDataGlobalRef == NULL) {
|
||||||
|
return (jlong)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(sizeof(jobject) == sizeof(void*)); // TODO: check statically
|
||||||
|
void* userDataPtr = (void*) userDataGlobalRef;
|
||||||
|
|
||||||
|
void* res;
|
||||||
|
ffi_closure *closure = ffi_closure_alloc(sizeof(ffi_closure), &res);
|
||||||
|
if (closure == NULL) {
|
||||||
|
return (jlong)0;
|
||||||
|
}
|
||||||
|
ffi_status status = ffi_prep_closure_loc(closure, (ffi_cif*)ffiCif, ffi_fun, userDataPtr, res);
|
||||||
|
if (status != FFI_OK) {
|
||||||
|
return -(jlong)1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (jlong) res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: newGlobalRef
|
||||||
|
* Signature: (Ljava/lang/Object;)J
|
||||||
|
*/
|
||||||
|
JNIEXPORT jlong JNICALL Java_kotlin_1native_interop_CallbacksKt_newGlobalRef(JNIEnv *env, jclass cls, jobject obj) {
|
||||||
|
jobject res = (*env)->NewGlobalRef(env, obj);
|
||||||
|
return (jlong) res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: derefGlobalRef
|
||||||
|
* Signature: (J)Ljava/lang/Object;
|
||||||
|
*/
|
||||||
|
JNIEXPORT jobject JNICALL Java_kotlin_1native_interop_CallbacksKt_derefGlobalRef(JNIEnv *env, jclass cls, jlong ref) {
|
||||||
|
return (jobject) ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Class: kotlin_native_interop_CallbacksKt
|
||||||
|
* Method: deleteGlobalRef
|
||||||
|
* Signature: (J)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_kotlin_1native_interop_CallbacksKt_deleteGlobalRef(JNIEnv *env, jclass cls, jlong ref) {
|
||||||
|
(*env)->DeleteGlobalRef(env, (jobject) ref);
|
||||||
|
}
|
||||||
@@ -0,0 +1,287 @@
|
|||||||
|
package kotlin_native.interop
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides a way to create a stable handle to any Kotlin object.
|
||||||
|
* Its [value] can be safely passed to native code e.g. to be received in a Kotlin callback.
|
||||||
|
*
|
||||||
|
* Any [StableObjPtr] should be manually [disposed][dispose]
|
||||||
|
*/
|
||||||
|
data class StableObjPtr private constructor(val value: NativePtr) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a handle for given object.
|
||||||
|
*/
|
||||||
|
fun create(any: Any) = StableObjPtr(NativePtr.byValue(newGlobalRef(any))!!)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates [StableObjPtr] from given raw value.
|
||||||
|
*
|
||||||
|
* @param value must be a [value] of some [StableObjPtr]
|
||||||
|
*/
|
||||||
|
fun fromValue(value: NativePtr) = StableObjPtr(value)
|
||||||
|
|
||||||
|
init {
|
||||||
|
loadCallbacksLibrary()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the handle. It must not be [used][get] after that.
|
||||||
|
*/
|
||||||
|
fun dispose() {
|
||||||
|
deleteGlobalRef(value.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the object this handle was [created][create] for.
|
||||||
|
*/
|
||||||
|
fun get(): Any = derefGlobalRef(value.value)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the type of native function.
|
||||||
|
*
|
||||||
|
* The instances of this class are supposed to be Kotlin objects (singletons),
|
||||||
|
* because creating the instance implies allocating some amount of non-freeable memory for the instance itself
|
||||||
|
* and for any unique Kotlin function "converted" to this type.
|
||||||
|
*
|
||||||
|
* Native function type definition consists in the following:
|
||||||
|
* - Definitions of native function's parameter and return types to be passed into the constructor
|
||||||
|
* - Implementation of [invoke] method which describes how to convert between these types and Kotlin types used in [F]
|
||||||
|
*
|
||||||
|
* @param F Kotlin function type corresponding to given native function type
|
||||||
|
*/
|
||||||
|
abstract class NativeFunctionType<F : Function<*>> protected constructor(returnType: CType, vararg paramTypes: CType) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a native function of this type, which calls given Kotlin *static* function.
|
||||||
|
*
|
||||||
|
* Given function must be *static*, i.e. an (unbound) reference to a Kotlin function or
|
||||||
|
* a closure which doesn't capture any variable
|
||||||
|
*/
|
||||||
|
fun fromStatic(function: F): NativePtr {
|
||||||
|
// TODO: optimize synchronization
|
||||||
|
synchronized(cache) {
|
||||||
|
return cache.getOrPut(function, { createFromStatic(function) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the C type of a function's parameter or return value.
|
||||||
|
* It is supposed to be constructed using the primitive types (such as [SInt32]) and the [Struct] combinator.
|
||||||
|
*
|
||||||
|
* This description omits the details that are irrelevant for the ABI.
|
||||||
|
*/
|
||||||
|
protected open class CType internal constructor(val ffiType: ffi_type) {
|
||||||
|
internal constructor(ffiTypePtr: Long) : this(NativePtr.byValue(ffiTypePtr).asRef(ffi_type)!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected object Void : CType(ffiTypeVoid())
|
||||||
|
protected object UInt8 : CType(ffiTypeUInt8())
|
||||||
|
protected object SInt8 : CType(ffiTypeSInt8())
|
||||||
|
protected object UInt16 : CType(ffiTypeUInt16())
|
||||||
|
protected object SInt16 : CType(ffiTypeSInt16())
|
||||||
|
protected object UInt32 : CType(ffiTypeUInt32())
|
||||||
|
protected object SInt32 : CType(ffiTypeSInt32())
|
||||||
|
protected object UInt64 : CType(ffiTypeUInt64())
|
||||||
|
protected object SInt64 : CType(ffiTypeSInt64())
|
||||||
|
protected object Pointer : CType(ffiTypePointer())
|
||||||
|
|
||||||
|
protected class Struct(vararg elementTypes: CType) : CType(
|
||||||
|
ffiTypeStruct(
|
||||||
|
elementTypes.map { it.ffiType }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method should invoke given Kotlin function.
|
||||||
|
*
|
||||||
|
* @param args array of pointers to arguments to be passed to [function]
|
||||||
|
* @param ret pointer to memory to be filled with return value of [function]
|
||||||
|
*/
|
||||||
|
protected abstract fun invoke(function: F, args: NativeArray<NativePtrBox>, ret: NativePtr)
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
init {
|
||||||
|
loadCallbacksLibrary()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val ffiCif = ffiCreateCif(returnType.ffiType, paramTypes.map { it.ffiType })
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates a native function of this type for given Kotlin function.
|
||||||
|
*/
|
||||||
|
private fun createFromStatic(function: F): NativePtr {
|
||||||
|
if (!isStatic(function)) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
|
||||||
|
val impl = { ret: NativePtr, args: NativeArray<NativePtrBox> ->
|
||||||
|
invoke(function, args, ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ffiCreateClosure(ffiCif, impl)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns `true` if given function is *static* as defined in [fromStatic].
|
||||||
|
*/
|
||||||
|
private fun isStatic(function: Function<*>): Boolean {
|
||||||
|
// TODO: revise
|
||||||
|
try {
|
||||||
|
with(function.javaClass.getDeclaredField("INSTANCE")) {
|
||||||
|
if (!java.lang.reflect.Modifier.isStatic(modifiers) || !java.lang.reflect.Modifier.isFinal(modifiers)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
isAccessible = true // TODO: undo
|
||||||
|
|
||||||
|
return get(null) == function
|
||||||
|
}
|
||||||
|
} catch (e: NoSuchFieldException) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val cache = mutableMapOf<F, NativePtr>()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see NativeFunctionType.fromStatic
|
||||||
|
*/
|
||||||
|
fun <F : Function<*>> F.staticAsNative(type: NativeFunctionType<F>) = type.fromStatic(this)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes a "struct" with native function pointer field.
|
||||||
|
*/
|
||||||
|
class NativeFunctionBox<F : Function<*>>(ptr: NativePtr, private val type: NativeFunctionType<F>) : NativeRef(ptr) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the function pointer field to null or native function calling given Kotlin function.
|
||||||
|
*/
|
||||||
|
fun setStatic(function: F?) {
|
||||||
|
val nativeFunPtr = function?.staticAsNative(type)
|
||||||
|
bridge.putPtr(ptr, nativeFunPtr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val <F : Function<*>> NativeFunctionType<F>.ref: NativeRef.TypeWithSize<NativeFunctionBox<F>>
|
||||||
|
get() = NativeRef.TypeWithSize(8, { NativeFunctionBox(it, this) }) // TODO: 64-bit specific
|
||||||
|
|
||||||
|
|
||||||
|
private fun loadCallbacksLibrary() {
|
||||||
|
System.loadLibrary("callbacks")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to `ffi_type` struct instance.
|
||||||
|
*/
|
||||||
|
internal class ffi_type (ptr: NativePtr) : NativeRef(ptr) {
|
||||||
|
companion object : Type<ffi_type>(::ffi_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to `ffi_cif` struct instance.
|
||||||
|
*/
|
||||||
|
internal class ffi_cif (ptr: NativePtr) : NativeRef(ptr) {
|
||||||
|
companion object : Type<ffi_cif>(::ffi_cif)
|
||||||
|
}
|
||||||
|
|
||||||
|
private external fun ffiTypeVoid(): Long
|
||||||
|
private external fun ffiTypeUInt8(): Long
|
||||||
|
private external fun ffiTypeSInt8(): Long
|
||||||
|
private external fun ffiTypeUInt16(): Long
|
||||||
|
private external fun ffiTypeSInt16(): Long
|
||||||
|
private external fun ffiTypeUInt32(): Long
|
||||||
|
private external fun ffiTypeSInt32(): Long
|
||||||
|
private external fun ffiTypeUInt64(): Long
|
||||||
|
private external fun ffiTypeSInt64(): Long
|
||||||
|
private external fun ffiTypePointer(): Long
|
||||||
|
|
||||||
|
private external fun ffiTypeStruct0(elements: Long): Long
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allocates and initializes `ffi_type` describing the struct.
|
||||||
|
*
|
||||||
|
* @param elements types of the struct elements
|
||||||
|
*/
|
||||||
|
private fun ffiTypeStruct(elementTypes: List<ffi_type>): ffi_type {
|
||||||
|
val elements = mallocNativeArrayOf(ffi_type, *elementTypes.toTypedArray(), null).ptr
|
||||||
|
val res = ffiTypeStruct0(elements.value)
|
||||||
|
if (res == 0L) {
|
||||||
|
throw OutOfMemoryError()
|
||||||
|
}
|
||||||
|
return NativePtr.byValue(res).asRef(ffi_type)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private external fun ffiCreateCif0(nArgs: Int, rType: Long, argTypes: Long): Long
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and prepares an `ffi_cif`.
|
||||||
|
*
|
||||||
|
* @param returnType native function return value type
|
||||||
|
* @param paramTypes native function parameter types
|
||||||
|
*
|
||||||
|
* @return the initialized `ffi_cif`
|
||||||
|
*/
|
||||||
|
private fun ffiCreateCif(returnType: ffi_type, paramTypes: List<ffi_type>): ffi_cif {
|
||||||
|
val nArgs = paramTypes.size
|
||||||
|
val rType = returnType.ptr
|
||||||
|
val argTypes = mallocNativeArrayOf(ffi_type, *paramTypes.toTypedArray(), null).ptr
|
||||||
|
val res = ffiCreateCif0(nArgs, rType.value, argTypes.value)
|
||||||
|
|
||||||
|
when (res) {
|
||||||
|
0L -> throw OutOfMemoryError()
|
||||||
|
-1L -> throw Error("FFI_BAD_TYPEDEF")
|
||||||
|
-2L -> throw Error("FFI_BAD_ABI")
|
||||||
|
-3L -> throw Error("libffi error occurred")
|
||||||
|
}
|
||||||
|
|
||||||
|
return NativePtr.byValue(res).asRef(ffi_cif)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ffiFunImpl0(ffiCif: Long, ret: Long, args: Long, userData: Any) {
|
||||||
|
ffiFunImpl(NativePtr.byValue(ffiCif).asRef(ffi_cif)!!,
|
||||||
|
NativePtr.byValue(ret)!!,
|
||||||
|
NativePtr.byValue(args).asRef(array(NativePtrBox))!!,
|
||||||
|
userData as (ret: NativePtr, args: NativeArray<NativePtrBox>) -> Unit)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called from native code when a native function created with [ffiCreateClosure] is invoked.
|
||||||
|
*
|
||||||
|
* @param ret pointer to memory to be filled with return value of the invoked native function
|
||||||
|
* @param args pointer to array of pointers to arguments passed to the invoked native function
|
||||||
|
*/
|
||||||
|
private fun ffiFunImpl(ffiCif: ffi_cif, ret: NativePtr, args: NativeArray<NativePtrBox>,
|
||||||
|
userData: (NativePtr, NativeArray<NativePtrBox>) -> Unit) {
|
||||||
|
|
||||||
|
userData.invoke(ret, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
private external fun ffiCreateClosure0(ffiCif: Long, userData: Any): Long
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses libffi to allocate a native function which will call [ffiFunImpl] when invoked.
|
||||||
|
*
|
||||||
|
* @param ffiCif describes the type of the function to create
|
||||||
|
*/
|
||||||
|
private fun ffiCreateClosure(ffiCif: ffi_cif, userData: (NativePtr, NativeArray<NativePtrBox>) -> Unit): NativePtr {
|
||||||
|
val res = ffiCreateClosure0(ffiCif.ptr.value, userData)
|
||||||
|
|
||||||
|
when (res) {
|
||||||
|
0L -> throw OutOfMemoryError()
|
||||||
|
-1L -> throw Error("libffi error occurred")
|
||||||
|
}
|
||||||
|
|
||||||
|
return NativePtr.byValue(res)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private external fun newGlobalRef(any: Any): Long
|
||||||
|
private external fun derefGlobalRef(ref: Long): Any
|
||||||
|
private external fun deleteGlobalRef(ref: Long)
|
||||||
+152
-30
@@ -66,6 +66,15 @@ class StubGenerator(
|
|||||||
|
|
||||||
val functionsToBind = nativeIndex.functions.filter { it.name !in excludedFunctions }
|
val functionsToBind = nativeIndex.functions.filter { it.name !in excludedFunctions }
|
||||||
|
|
||||||
|
private val usedFunctionTypes = mutableMapOf<FunctionType, String>()
|
||||||
|
|
||||||
|
val FunctionType.kotlinName: String
|
||||||
|
get() {
|
||||||
|
return usedFunctionTypes.getOrPut(this, {
|
||||||
|
"NativeFunctionType" + (usedFunctionTypes.size + 1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The output currently used by the generator.
|
* The output currently used by the generator.
|
||||||
* Should append line separator after any usage.
|
* Should append line separator after any usage.
|
||||||
@@ -181,10 +190,13 @@ class StubGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
is PointerType -> {
|
is PointerType -> {
|
||||||
if (type.pointeeType is VoidType || type.pointeeType is FunctionType) {
|
val pointeeType = type.pointeeType
|
||||||
|
if (pointeeType is VoidType) {
|
||||||
NativeRefType("NativePtrBox")
|
NativeRefType("NativePtrBox")
|
||||||
|
} else if (pointeeType is FunctionType) {
|
||||||
|
NativeRefType("NativeFunctionBox<${getKotlinFunctionType(pointeeType)}>", "${pointeeType.kotlinName}.ref")
|
||||||
} else {
|
} else {
|
||||||
val pointeeRefType = getKotlinTypeForRefTo(type.pointeeType)
|
val pointeeRefType = getKotlinTypeForRefTo(pointeeType)
|
||||||
NativeRefType("RefBox<${pointeeRefType.typeName}>", "${pointeeRefType.typeExpr}.ref")
|
NativeRefType("RefBox<${pointeeRefType.typeName}>", "${pointeeRefType.typeExpr}.ref")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,13 +270,6 @@ class StubGenerator(
|
|||||||
kotlinConv = { "$it.asLong()" },
|
kotlinConv = { "$it.asLong()" },
|
||||||
kotlinJniBridgeType = "Long"
|
kotlinJniBridgeType = "Long"
|
||||||
)
|
)
|
||||||
} else if (type.pointeeType is Int8Type) {
|
|
||||||
OutValueBinding(
|
|
||||||
kotlinType = "String?",
|
|
||||||
kotlinConv = { name -> "CString.fromString($name).getNativePtr().asLong()" },
|
|
||||||
convFree = { name -> "free(NativePtr.byValue($name))" },
|
|
||||||
kotlinJniBridgeType = "Long"
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
outValueRefBinding(getKotlinTypeForRefTo(type.pointeeType))
|
outValueRefBinding(getKotlinTypeForRefTo(type.pointeeType))
|
||||||
}
|
}
|
||||||
@@ -282,17 +287,51 @@ class StubGenerator(
|
|||||||
|
|
||||||
is ArrayType -> outValueRefBinding(getKotlinTypeForRefTo(type))
|
is ArrayType -> outValueRefBinding(getKotlinTypeForRefTo(type))
|
||||||
|
|
||||||
is RecordType -> {
|
else -> throw NotImplementedError()
|
||||||
val refType = getKotlinTypeForRefTo(type)
|
}
|
||||||
// pointer will be converted to value in C code
|
|
||||||
OutValueBinding(
|
fun getCFunctionParamBinding(type: Type): OutValueBinding {
|
||||||
kotlinType = refType.typeName,
|
when (type) {
|
||||||
kotlinConv = { "$it.getNativePtr().asLong()" },
|
is PointerType -> {
|
||||||
kotlinJniBridgeType = "Long"
|
val pointeeType = type.pointeeType
|
||||||
|
when (pointeeType) {
|
||||||
|
is FunctionType -> return OutValueBinding(
|
||||||
|
kotlinType = "(" + getKotlinFunctionType(pointeeType) + ")?",
|
||||||
|
kotlinConv = { "$it?.staticAsNative(${pointeeType.kotlinName}).asLong()" },
|
||||||
|
kotlinJniBridgeType = "Long"
|
||||||
|
)
|
||||||
|
is Int8Type -> return OutValueBinding(
|
||||||
|
kotlinType = "String?",
|
||||||
|
kotlinConv = { name -> "CString.fromString($name).getNativePtr().asLong()" },
|
||||||
|
convFree = { name -> "free(NativePtr.byValue($name))" },
|
||||||
|
kotlinJniBridgeType = "Long"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is RecordType -> {
|
||||||
|
val refType = getKotlinTypeForRefTo(type)
|
||||||
|
// pointer will be converted to value in C code
|
||||||
|
return OutValueBinding(
|
||||||
|
kotlinType = refType.typeName,
|
||||||
|
kotlinConv = { "$it.getNativePtr().asLong()" },
|
||||||
|
kotlinJniBridgeType = "Long"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return getOutValueBinding(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCallbackRetValBinding(type: Type): OutValueBinding {
|
||||||
|
if (type is VoidType) {
|
||||||
|
return OutValueBinding(
|
||||||
|
kotlinType = "Unit",
|
||||||
|
kotlinConv = { throw UnsupportedOperationException() },
|
||||||
|
kotlinJniBridgeType = "void"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> throw NotImplementedError()
|
return getOutValueBinding(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -302,8 +341,6 @@ class StubGenerator(
|
|||||||
|
|
||||||
is PrimitiveType -> InValueBinding(type.kotlinType)
|
is PrimitiveType -> InValueBinding(type.kotlinType)
|
||||||
|
|
||||||
is VoidType -> InValueBinding("Unit")
|
|
||||||
|
|
||||||
is PointerType -> {
|
is PointerType -> {
|
||||||
if (type.pointeeType is VoidType || type.pointeeType is FunctionType) {
|
if (type.pointeeType is VoidType || type.pointeeType is FunctionType) {
|
||||||
InValueBinding(
|
InValueBinding(
|
||||||
@@ -328,17 +365,35 @@ class StubGenerator(
|
|||||||
|
|
||||||
is ArrayType -> inValueRefBinding(getKotlinTypeForRefTo(type))
|
is ArrayType -> inValueRefBinding(getKotlinTypeForRefTo(type))
|
||||||
|
|
||||||
is RecordType -> {
|
else -> throw NotImplementedError()
|
||||||
// TODO: valid only for return values
|
}
|
||||||
val refType = getKotlinTypeForRefTo(type)
|
|
||||||
InValueBinding(
|
fun getCFunctionRetValBinding(type: Type): InValueBinding {
|
||||||
kotlinJniBridgeType = "Long",
|
when (type) {
|
||||||
conv = { "NativePtr.byValue($it).asRef(${refType.typeExpr})!!" },
|
is VoidType -> return InValueBinding("Unit")
|
||||||
kotlinType = refType.typeName
|
|
||||||
)
|
is RecordType -> {
|
||||||
|
val refType = getKotlinTypeForRefTo(type)
|
||||||
|
InValueBinding(
|
||||||
|
kotlinJniBridgeType = "Long",
|
||||||
|
conv = { "NativePtr.byValue($it).asRef(${refType.typeExpr})!!" },
|
||||||
|
kotlinType = refType.typeName
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> throw NotImplementedError()
|
return getInValueBinding(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCallbackParamBinding(type: Type): InValueBinding {
|
||||||
|
return getInValueBinding(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getKotlinFunctionType(type: FunctionType): String {
|
||||||
|
return "(" +
|
||||||
|
type.parameterTypes.map { getCallbackParamBinding(it).kotlinType }.joinToString(", ") +
|
||||||
|
") -> " +
|
||||||
|
getCallbackRetValBinding(type.returnType).kotlinType
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -437,14 +492,14 @@ class StubGenerator(
|
|||||||
/**
|
/**
|
||||||
* Constructs [InValueBinding] for return value of Kotlin binding for given C function.
|
* Constructs [InValueBinding] for return value of Kotlin binding for given C function.
|
||||||
*/
|
*/
|
||||||
private fun retValBinding(func: FunctionDecl) = getInValueBinding(func.returnType)
|
private fun retValBinding(func: FunctionDecl) = getCFunctionRetValBinding(func.returnType)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs [OutValueBinding]s for parameters of Kotlin binding for given C function.
|
* Constructs [OutValueBinding]s for parameters of Kotlin binding for given C function.
|
||||||
*/
|
*/
|
||||||
private fun paramBindings(func: FunctionDecl): Array<OutValueBinding> {
|
private fun paramBindings(func: FunctionDecl): Array<OutValueBinding> {
|
||||||
val paramBindings = func.parameters.map { param ->
|
val paramBindings = func.parameters.map { param ->
|
||||||
getOutValueBinding(param.type)
|
getCFunctionParamBinding(param.type)
|
||||||
}.toMutableList()
|
}.toMutableList()
|
||||||
|
|
||||||
val retValType = func.returnType
|
val retValType = func.returnType
|
||||||
@@ -523,6 +578,68 @@ class StubGenerator(
|
|||||||
out("}")
|
out("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getFfiType(type: Type): String {
|
||||||
|
return when(type) {
|
||||||
|
is VoidType -> "Void"
|
||||||
|
is Int8Type -> "SInt8"
|
||||||
|
is UInt8Type -> "UInt8"
|
||||||
|
is Int16Type -> "SInt16"
|
||||||
|
is UInt16Type -> "UInt16"
|
||||||
|
is Int32Type -> "SInt32"
|
||||||
|
is UInt32Type -> "UInt32"
|
||||||
|
is IntPtrType, is UIntPtrType, // TODO
|
||||||
|
is PointerType, is ArrayType -> "Pointer"
|
||||||
|
is EnumType -> getFfiType(type.def.baseType)
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun generateFunctionType(type: FunctionType, name: String) {
|
||||||
|
val kotlinFunctionType = getKotlinFunctionType(type)
|
||||||
|
|
||||||
|
val constructorArgs = listOf(type.returnType, *type.parameterTypes.toTypedArray()).map {
|
||||||
|
getFfiType(it)
|
||||||
|
}.joinToString(", ")
|
||||||
|
|
||||||
|
out("object $name : NativeFunctionType<$kotlinFunctionType>($constructorArgs) {")
|
||||||
|
indent {
|
||||||
|
out("override fun invoke(function: $kotlinFunctionType, args: NativeArray<NativePtrBox>, ret: NativePtr) {")
|
||||||
|
indent {
|
||||||
|
val args = type.parameterTypes.mapIndexed { i, paramType ->
|
||||||
|
val refType = getKotlinTypeForRefTo(paramType)
|
||||||
|
val ref = "args[$i].value.asRef(${refType.typeExpr})!!"
|
||||||
|
when (paramType) {
|
||||||
|
is RecordType -> "$ref"
|
||||||
|
else -> "$ref.value"
|
||||||
|
}
|
||||||
|
}.joinToString(", ")
|
||||||
|
|
||||||
|
out("val res = function($args)")
|
||||||
|
|
||||||
|
when (type.returnType) {
|
||||||
|
is RecordType -> throw NotImplementedError()
|
||||||
|
is VoidType -> {} // nothing to do
|
||||||
|
else -> {
|
||||||
|
val retRefType = getKotlinTypeForRefTo(type.returnType)
|
||||||
|
out("${retRefType.typeExpr}.byPtr(ret).value = res")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
out("}")
|
||||||
|
}
|
||||||
|
out("}")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Produces to [out] the definition of Kotlin JNI function used in binding for given C function.
|
* Produces to [out] the definition of Kotlin JNI function used in binding for given C function.
|
||||||
*/
|
*/
|
||||||
@@ -576,6 +693,11 @@ class StubGenerator(
|
|||||||
out("")
|
out("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
usedFunctionTypes.entries.forEach {
|
||||||
|
generateFunctionType(it.key, it.value)
|
||||||
|
out("")
|
||||||
|
}
|
||||||
|
|
||||||
out("object externals {")
|
out("object externals {")
|
||||||
indent {
|
indent {
|
||||||
out("init { System.loadLibrary(\"$libName\") }")
|
out("init { System.loadLibrary(\"$libName\") }")
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ class NativeInteropPlugin implements Plugin<Project> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
void apply(Project prj) {
|
void apply(Project prj) {
|
||||||
|
def runtimeNativeLibsDir = new File(prj.findProject(':Interop:Runtime').buildDir, 'nativelibs')
|
||||||
|
|
||||||
def nativeLibsDir = new File(prj.buildDir, "nativelibs")
|
def nativeLibsDir = new File(prj.buildDir, "nativelibs")
|
||||||
|
|
||||||
prj.configurations {
|
prj.configurations {
|
||||||
@@ -30,7 +32,11 @@ class NativeInteropPlugin implements Plugin<Project> {
|
|||||||
main = "org.jetbrains.kotlin.native.interop.gen.jvm.MainKt"
|
main = "org.jetbrains.kotlin.native.interop.gen.jvm.MainKt"
|
||||||
jvmArgs '-ea'
|
jvmArgs '-ea'
|
||||||
|
|
||||||
systemProperties "java.library.path" : new File(prj.findProject(":Interop:Indexer").buildDir, "nativelibs")
|
|
||||||
|
systemProperties "java.library.path" : prj.files(
|
||||||
|
new File(prj.findProject(":Interop:Indexer").buildDir, "nativelibs"),
|
||||||
|
runtimeNativeLibsDir
|
||||||
|
).asPath
|
||||||
systemProperties "llvmInstallPath" : prj.llvmInstallPath
|
systemProperties "llvmInstallPath" : prj.llvmInstallPath
|
||||||
environment "LIBCLANG_DISABLE_CRASH_RECOVERY": "1"
|
environment "LIBCLANG_DISABLE_CRASH_RECOVERY": "1"
|
||||||
environment "DYLD_LIBRARY_PATH": "${prj.llvmInstallPath}/lib"
|
environment "DYLD_LIBRARY_PATH": "${prj.llvmInstallPath}/lib"
|
||||||
@@ -60,7 +66,10 @@ class NativeInteropPlugin implements Plugin<Project> {
|
|||||||
// FIXME: choose tasks more wisely
|
// FIXME: choose tasks more wisely
|
||||||
prj.tasks.withType(JavaExec) {
|
prj.tasks.withType(JavaExec) {
|
||||||
if (!name.endsWith("InteropStubs")) {
|
if (!name.endsWith("InteropStubs")) {
|
||||||
systemProperties "java.library.path": nativeLibsDir
|
systemProperties "java.library.path": prj.files(
|
||||||
|
nativeLibsDir,
|
||||||
|
runtimeNativeLibsDir
|
||||||
|
).asPath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user