committed by
SvyatoslavScherbina
parent
c848ee519d
commit
5586d29764
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlinx.cinterop
|
||||
|
||||
import konan.internal.Intrinsic
|
||||
import konan.internal.ExportForCompiler
|
||||
|
||||
@Intrinsic external operator fun <R> CPointer<CFunction<() -> R>>.invoke(): R
|
||||
|
||||
@Intrinsic external operator fun <P1, R> CPointer<CFunction<(P1) -> R>>.invoke(p1: P1): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, R> CPointer<CFunction<(P1, P2) -> R>>.invoke(p1: P1, p2: P2): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, R> CPointer<CFunction<(P1, P2, P3) -> R>>.invoke(p1: P1, p2: P2, p3: P3): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, R> CPointer<CFunction<(P1, P2, P3, P4) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, R> CPointer<CFunction<(P1, P2, P3, P4, P5) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20, p21: P21): R
|
||||
|
||||
@Intrinsic external operator fun <P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22, R> CPointer<CFunction<(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, P22) -> R>>.invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20, p21: P21, p22: P22): R
|
||||
|
||||
@ExportForCompiler
|
||||
private fun invokeImplUnitRet(ptr: COpaquePointer, vararg args: Any?): Unit = memScoped {
|
||||
callWithVarargs(ptr.rawValue, nativeNullPtr, FFI_TYPE_KIND_VOID, args, emptyArray(), memScope)
|
||||
}
|
||||
|
||||
@ExportForCompiler
|
||||
private fun invokeImplByteRet(ptr: COpaquePointer, vararg args: Any?): Byte = memScoped {
|
||||
val resultBuffer = allocFfiReturnValueBuffer<ByteVar>(ByteVar)
|
||||
callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_SINT8, args, emptyArray(), memScope)
|
||||
resultBuffer.value
|
||||
}
|
||||
|
||||
@ExportForCompiler
|
||||
private fun invokeImplShortRet(ptr: COpaquePointer, vararg args: Any?): Short = memScoped {
|
||||
val resultBuffer = allocFfiReturnValueBuffer<ShortVar>(ShortVar)
|
||||
callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_SINT16, args, emptyArray(), memScope)
|
||||
resultBuffer.value
|
||||
}
|
||||
|
||||
@ExportForCompiler
|
||||
private fun invokeImplIntRet(ptr: COpaquePointer, vararg args: Any?): Int = memScoped {
|
||||
val resultBuffer = allocFfiReturnValueBuffer<IntVar>(IntVar)
|
||||
callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_SINT32, args, emptyArray(), memScope)
|
||||
resultBuffer.value
|
||||
}
|
||||
|
||||
@ExportForCompiler
|
||||
private fun invokeImplLongRet(ptr: COpaquePointer, vararg args: Any?): Long = memScoped {
|
||||
val resultBuffer = allocFfiReturnValueBuffer<LongVar>(LongVar)
|
||||
callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_SINT64, args, emptyArray(), memScope)
|
||||
resultBuffer.value
|
||||
}
|
||||
|
||||
@ExportForCompiler
|
||||
private fun invokeImplFloatRet(ptr: COpaquePointer, vararg args: Any?): Float = memScoped {
|
||||
val resultBuffer = allocFfiReturnValueBuffer<FloatVar>(FloatVar)
|
||||
callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_FLOAT, args, emptyArray(), memScope)
|
||||
resultBuffer.value
|
||||
}
|
||||
|
||||
@ExportForCompiler
|
||||
private fun invokeImplDoubleRet(ptr: COpaquePointer, vararg args: Any?): Double = memScoped {
|
||||
val resultBuffer = allocFfiReturnValueBuffer<DoubleVar>(DoubleVar)
|
||||
callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_DOUBLE, args, emptyArray(), memScope)
|
||||
resultBuffer.value
|
||||
}
|
||||
|
||||
@ExportForCompiler
|
||||
private fun invokeImplPointerRet(ptr: COpaquePointer, vararg args: Any?): COpaquePointer? = memScoped {
|
||||
val resultBuffer = allocFfiReturnValueBuffer<COpaquePointerVar>(COpaquePointerVar)
|
||||
callWithVarargs(ptr.rawValue, resultBuffer.rawPtr, FFI_TYPE_KIND_POINTER, args, emptyArray(), memScope)
|
||||
resultBuffer.value
|
||||
}
|
||||
+22
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
private val cPointerName = "CPointer"
|
||||
private val nativePointedName = "NativePointed"
|
||||
@@ -105,6 +106,27 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns) {
|
||||
val readBits = packageScope.getContributedFunctions("readBits").single()
|
||||
val writeBits = packageScope.getContributedFunctions("writeBits").single()
|
||||
|
||||
val cFunctionPointerInvokes = packageScope.getContributedFunctions(OperatorNameConventions.INVOKE.asString())
|
||||
.filter {
|
||||
val extensionReceiverParameter = it.extensionReceiverParameter
|
||||
it.isOperator &&
|
||||
extensionReceiverParameter != null &&
|
||||
TypeUtils.getClassDescriptor(extensionReceiverParameter.type) == cPointer
|
||||
}.toSet()
|
||||
|
||||
val invokeImpls = mapOf(
|
||||
builtIns.unit to "invokeImplUnitRet",
|
||||
builtIns.byte to "invokeImplByteRet",
|
||||
builtIns.short to "invokeImplShortRet",
|
||||
builtIns.int to "invokeImplIntRet",
|
||||
builtIns.long to "invokeImplLongRet",
|
||||
builtIns.float to "invokeImplFloatRet",
|
||||
builtIns.double to "invokeImplDoubleRet",
|
||||
cPointer to "invokeImplPointerRet"
|
||||
).mapValues { (_, name) ->
|
||||
packageScope.getContributedFunctions(name).single()
|
||||
}.toMap()
|
||||
|
||||
val objCObject = packageScope.getContributedClassifier("ObjCObject") as ClassDescriptor
|
||||
val objCPointerHolder = packageScope.getContributedClassifier("ObjCPointerHolder") as ClassDescriptor
|
||||
|
||||
|
||||
+4
@@ -61,6 +61,10 @@ internal class KonanSymbols(context: Context, val symbolTable: SymbolTable): Sym
|
||||
val interopObjCObjectRawValueGetter =
|
||||
symbolTable.referenceSimpleFunction(context.interopBuiltIns.objCObjectRawPtr.getter!!)
|
||||
|
||||
val interopInvokeImpls = context.interopBuiltIns.invokeImpls.mapValues { (_, function) ->
|
||||
symbolTable.referenceSimpleFunction(function)
|
||||
}
|
||||
|
||||
val getNativeNullPtr = symbolTable.referenceSimpleFunction(context.builtIns.getNativeNullPtr)
|
||||
|
||||
val boxFunctions = ValueType.values().associate {
|
||||
|
||||
+47
-11
@@ -354,6 +354,8 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
|
||||
}
|
||||
}
|
||||
|
||||
fun reportError(message: String): Nothing = context.reportCompilationError(message, irFile, expression)
|
||||
|
||||
return when (descriptor) {
|
||||
interop.cPointerRawValue.getter ->
|
||||
// Replace by the intrinsic call to be handled by code generator:
|
||||
@@ -399,7 +401,7 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
|
||||
signatureTypes.forEachIndexed { index, type ->
|
||||
type.ensureSupportedInCallbacks(
|
||||
isReturnType = (index == signatureTypes.lastIndex),
|
||||
reportError = { context.reportCompilationError(it, irFile, expression) }
|
||||
reportError = ::reportError
|
||||
)
|
||||
}
|
||||
|
||||
@@ -495,33 +497,67 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB
|
||||
}
|
||||
}
|
||||
|
||||
in interop.cFunctionPointerInvokes -> {
|
||||
// Replace by `invokeImpl${type}Ret`:
|
||||
|
||||
val returnType =
|
||||
expression.getTypeArgument(descriptor.typeParameters.single { it.name.asString() == "R" })!!
|
||||
|
||||
returnType.checkCTypeNullability(::reportError)
|
||||
|
||||
val invokeImpl = symbols.interopInvokeImpls[TypeUtils.getClassDescriptor(returnType)] ?:
|
||||
context.reportCompilationError(
|
||||
"Invocation of C function pointer with return type '$returnType' is not supported yet",
|
||||
irFile, expression
|
||||
)
|
||||
|
||||
builder.irCall(invokeImpl).apply {
|
||||
putValueArgument(0, expression.extensionReceiver)
|
||||
|
||||
val varargParameter = invokeImpl.descriptor.valueParameters[1]
|
||||
val varargArgument = IrVarargImpl(
|
||||
startOffset, endOffset, varargParameter.type, varargParameter.varargElementType!!
|
||||
).apply {
|
||||
descriptor.valueParameters.forEach {
|
||||
this.addElement(expression.getValueArgument(it)!!)
|
||||
}
|
||||
}
|
||||
putValueArgument(varargParameter, varargArgument)
|
||||
}
|
||||
}
|
||||
|
||||
else -> expression
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinType.ensureSupportedInCallbacks(isReturnType: Boolean, reportError: (String) -> Nothing) {
|
||||
this.checkCTypeNullability(reportError)
|
||||
|
||||
if (isReturnType && KotlinBuiltIns.isUnit(this)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(this)) {
|
||||
if (!this.isMarkedNullable) {
|
||||
return
|
||||
}
|
||||
reportError("Type $this must not be nullable when used in callback signature")
|
||||
if (KotlinBuiltIns.isPrimitiveType(this)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (TypeUtils.getClassDescriptor(this) == interop.cPointer) {
|
||||
if (this.isMarkedNullable) {
|
||||
return
|
||||
}
|
||||
|
||||
reportError("Type $this must be nullable when used in callback signature")
|
||||
return
|
||||
}
|
||||
|
||||
reportError("Type $this is not supported in callback signature")
|
||||
}
|
||||
|
||||
private fun KotlinType.checkCTypeNullability(reportError: (String) -> Nothing) {
|
||||
if (KotlinBuiltIns.isPrimitiveTypeOrNullablePrimitiveType(this) && this.isMarkedNullable) {
|
||||
reportError("Type $this must not be nullable when used in C function signature")
|
||||
}
|
||||
|
||||
if (TypeUtils.getClassDescriptor(this) == interop.cPointer && !this.isMarkedNullable) {
|
||||
reportError("Type $this must be nullable when used in C function signature")
|
||||
}
|
||||
}
|
||||
|
||||
private fun unwrapStaticFunctionArgument(argument: IrExpression): IrFunctionReference? {
|
||||
if (argument is IrFunctionReference) {
|
||||
return argument
|
||||
|
||||
@@ -1994,6 +1994,11 @@ kotlinNativeInterop {
|
||||
flavor 'native'
|
||||
}
|
||||
|
||||
cfunptr {
|
||||
defFile 'interop/basics/cfunptr.def'
|
||||
flavor 'native'
|
||||
}
|
||||
|
||||
if (isMac()) {
|
||||
opengl {
|
||||
defFile '../../samples/opengl/src/main/c_interop/opengl.def'
|
||||
@@ -2057,6 +2062,13 @@ task interop_bitfields(type: RunInteropKonanTest) {
|
||||
interop = 'bitfields'
|
||||
}
|
||||
|
||||
task interop_funptr(type: RunInteropKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||
goldValue = "42\n17\n"
|
||||
source = "interop/basics/funptr.kt"
|
||||
interop = 'cfunptr'
|
||||
}
|
||||
|
||||
task interop_echo_server(type: RunInteropKonanTest) {
|
||||
disabled = (project.testTarget == 'wasm32') // No interop for wasm yet.
|
||||
if (!isMac()) {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
headerFilter = NOTHING
|
||||
---
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef int (*atoiPtrType)(const char*);
|
||||
|
||||
static atoiPtrType getAtoiPtr() {
|
||||
return &atoi;
|
||||
}
|
||||
|
||||
static void __printInt(int x) {
|
||||
printf("%d\n", x);
|
||||
}
|
||||
|
||||
static void* __getPrintIntPtr() {
|
||||
return &__printInt;
|
||||
}
|
||||
|
||||
typedef void* (*getPrintIntPtrPtrType)(void);
|
||||
|
||||
static getPrintIntPtrPtrType getGetPrintIntPtrPtr() {
|
||||
return &__getPrintIntPtr;
|
||||
}
|
||||
|
||||
static double __add(double x, double y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
typedef double (*addPtrType)(double, double);
|
||||
|
||||
static addPtrType getAddPtr() {
|
||||
return &__add;
|
||||
}
|
||||
|
||||
static int __doubleToInt(double x) {
|
||||
return (int) x;
|
||||
}
|
||||
|
||||
typedef int (*doubleToIntPtrType)(double);
|
||||
|
||||
static doubleToIntPtrType getDoubleToIntPtr() {
|
||||
return &__doubleToInt;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import kotlinx.cinterop.*
|
||||
import cfunptr.*
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val atoiPtr = getAtoiPtr()!!
|
||||
|
||||
val getPrintIntPtrPtr = getGetPrintIntPtrPtr()!!
|
||||
val printIntPtr = getPrintIntPtrPtr()!!.reinterpret<CFunction<(Int) -> Unit>>()
|
||||
|
||||
val fortyTwo = memScoped {
|
||||
atoiPtr("42".cstr.getPointer(memScope))
|
||||
}
|
||||
|
||||
printIntPtr(fortyTwo)
|
||||
|
||||
printIntPtr(
|
||||
getDoubleToIntPtr()!!(
|
||||
getAddPtr()!!(5.1, 12.2)
|
||||
)
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user