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
|
||||
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 ###
|
||||
|
||||
The `.def` file supports several options for adjusting generated bindings.
|
||||
|
||||
@@ -1,5 +1,51 @@
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -107,7 +107,7 @@ fun callWithVarargs(codePtr: NativePtr, returnValuePtr: NativePtr, returnTypeKin
|
||||
fixedArguments.size, totalArgumentsNumber)
|
||||
}
|
||||
|
||||
@SymbolName("callWithVarargs")
|
||||
@SymbolName("Kotlin_Interop_callWithVarargs")
|
||||
private external fun callWithVarargs(codePtr: NativePtr, returnValuePtr: NativePtr, returnTypeKind: FfiTypeKind,
|
||||
arguments: NativePtr, argumentTypeKinds: NativePtr,
|
||||
fixedArgumentsNumber: Int, totalArgumentsNumber: Int)
|
||||
@@ -19,6 +19,9 @@
|
||||
#include <stdint.h>
|
||||
#include <ffi.h>
|
||||
|
||||
#include "Memory.h"
|
||||
#include "Types.h"
|
||||
|
||||
namespace {
|
||||
|
||||
typedef int FfiTypeKind;
|
||||
@@ -51,7 +54,7 @@ ffi_type* convertFfiTypeKindToType(FfiTypeKind typeKind) {
|
||||
|
||||
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,
|
||||
int fixedArgumentsNumber, int totalArgumentsNumber) {
|
||||
|
||||
@@ -70,4 +73,19 @@ void callWithVarargs(void* codePtr, void* returnValuePtr, FfiTypeKind returnType
|
||||
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