Implement StableObjPtr for Kotlin N
This commit is contained in:
committed by
SvyatoslavScherbina
parent
d07295d732
commit
a50b38da5a
+37
@@ -261,6 +261,43 @@ Note that some function types are not supported currently. For example,
|
|||||||
it is not possible to get pointer to function that receives or returns structs
|
it is not possible to get pointer to function that receives or returns structs
|
||||||
by value.
|
by value.
|
||||||
|
|
||||||
|
#### Passing user data to callbacks ####
|
||||||
|
|
||||||
|
Often C APIs allow passing some user data to callbacks. Such data is usually
|
||||||
|
provided by user when configuring the callback. It is passed to some C function
|
||||||
|
(or written to the struct) as e.g. `void*`.
|
||||||
|
However references to Kotlin objects can't be directly passed to C.
|
||||||
|
So they require wrapping before configuring callback and then unwrapping in
|
||||||
|
the callback itself, to safely swim from Kotlin to Kotlin through the C world.
|
||||||
|
Such wrapping is possible with `StableObjPtr` class.
|
||||||
|
|
||||||
|
To wrap the reference:
|
||||||
|
```
|
||||||
|
val stablePtr = StableObjPtr.create(kotlinReference)
|
||||||
|
val voidPtr = stablePtr.value
|
||||||
|
```
|
||||||
|
where the `voidPtr` is `COpaquePointer` and can be passed to the C function.
|
||||||
|
|
||||||
|
To unwrap the reference:
|
||||||
|
|
||||||
|
```
|
||||||
|
val stablePtr = StableObjPtr.fromValue(voidPtr)
|
||||||
|
val kotlinReference = stablePtr.get()
|
||||||
|
```
|
||||||
|
where `kotlinReference` is the original wrapped reference (however it's type is
|
||||||
|
`Any` so it may require casting).
|
||||||
|
|
||||||
|
The created `StableObjPtr` should eventually be manually disposed using
|
||||||
|
`.dispose()` method to prevent memory leaks:
|
||||||
|
|
||||||
|
```
|
||||||
|
stablePtr.dispose()
|
||||||
|
```
|
||||||
|
|
||||||
|
After that it becomes invalid, so `voidPtr` can't be unwrapped anymore.
|
||||||
|
|
||||||
|
See `samples/libcurl` for more details.
|
||||||
|
|
||||||
### Definition file hints ###
|
### Definition file hints ###
|
||||||
|
|
||||||
The `.def` file supports several options for adjusting generated bindings.
|
The `.def` file supports several options for adjusting generated bindings.
|
||||||
|
|||||||
@@ -1,5 +1,51 @@
|
|||||||
package kotlinx.cinterop
|
package kotlinx.cinterop
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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: COpaquePointer) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a handle for given object.
|
||||||
|
*/
|
||||||
|
fun create(any: Any) = fromValue(createStablePointer(any))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates [StableObjPtr] from given raw value.
|
||||||
|
*
|
||||||
|
* @param value must be a [value] of some [StableObjPtr]
|
||||||
|
*/
|
||||||
|
fun fromValue(value: COpaquePointer) = StableObjPtr(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disposes the handle. It must not be [used][get] after that.
|
||||||
|
*/
|
||||||
|
fun dispose() {
|
||||||
|
disposeStablePointer(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the object this handle was [created][create] for.
|
||||||
|
*/
|
||||||
|
fun get(): Any = derefStablePointer(value)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@SymbolName("Kotlin_Interop_createStablePointer")
|
||||||
|
private external fun createStablePointer(any: Any): COpaquePointer
|
||||||
|
|
||||||
|
@SymbolName("Kotlin_Interop_disposeStablePointer")
|
||||||
|
private external fun disposeStablePointer(pointer: COpaquePointer)
|
||||||
|
|
||||||
|
@SymbolName("Kotlin_Interop_derefStablePointer")
|
||||||
|
private external fun derefStablePointer(pointer: COpaquePointer): Any
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of C function which can be constructed from the appropriate Kotlin function without using any adapter.
|
* The type of C function which can be constructed from the appropriate Kotlin function without using any adapter.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ fun callWithVarargs(codePtr: NativePtr, returnValuePtr: NativePtr, returnTypeKin
|
|||||||
fixedArguments.size, totalArgumentsNumber)
|
fixedArguments.size, totalArgumentsNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
@SymbolName("callWithVarargs")
|
@SymbolName("Kotlin_Interop_callWithVarargs")
|
||||||
private external fun callWithVarargs(codePtr: NativePtr, returnValuePtr: NativePtr, returnTypeKind: FfiTypeKind,
|
private external fun callWithVarargs(codePtr: NativePtr, returnValuePtr: NativePtr, returnTypeKind: FfiTypeKind,
|
||||||
arguments: NativePtr, argumentTypeKinds: NativePtr,
|
arguments: NativePtr, argumentTypeKinds: NativePtr,
|
||||||
fixedArgumentsNumber: Int, totalArgumentsNumber: Int)
|
fixedArgumentsNumber: Int, totalArgumentsNumber: Int)
|
||||||
@@ -19,6 +19,9 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <ffi.h>
|
#include <ffi.h>
|
||||||
|
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "Types.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
typedef int FfiTypeKind;
|
typedef int FfiTypeKind;
|
||||||
@@ -51,7 +54,7 @@ ffi_type* convertFfiTypeKindToType(FfiTypeKind typeKind) {
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
void callWithVarargs(void* codePtr, void* returnValuePtr, FfiTypeKind returnTypeKind,
|
void Kotlin_Interop_callWithVarargs(void* codePtr, void* returnValuePtr, FfiTypeKind returnTypeKind,
|
||||||
void** arguments, intptr_t* argumentTypeKinds,
|
void** arguments, intptr_t* argumentTypeKinds,
|
||||||
int fixedArgumentsNumber, int totalArgumentsNumber) {
|
int fixedArgumentsNumber, int totalArgumentsNumber) {
|
||||||
|
|
||||||
@@ -70,4 +73,19 @@ void callWithVarargs(void* codePtr, void* returnValuePtr, FfiTypeKind returnType
|
|||||||
ffi_call(&cif, (void (*)())codePtr, returnValuePtr, arguments);
|
ffi_call(&cif, (void (*)())codePtr, returnValuePtr, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* Kotlin_Interop_createStablePointer(KRef any) {
|
||||||
|
::AddRef(any->container());
|
||||||
|
return reinterpret_cast<void*>(any);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Kotlin_Interop_disposeStablePointer(void* pointer) {
|
||||||
|
KRef ref = reinterpret_cast<KRef>(pointer);
|
||||||
|
::Release(ref->container());
|
||||||
|
}
|
||||||
|
|
||||||
|
OBJ_GETTER(Kotlin_Interop_derefStablePointer, void* pointer) {
|
||||||
|
KRef ref = reinterpret_cast<KRef>(pointer);
|
||||||
|
RETURN_OBJ(ref);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user