Implement StableObjPtr for Kotlin N

This commit is contained in:
Svyatoslav Scherbina
2017-03-30 14:03:05 +03:00
committed by SvyatoslavScherbina
parent d07295d732
commit a50b38da5a
4 changed files with 103 additions and 2 deletions
+37
View File
@@ -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 -1
View File
@@ -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);
}
}