diff --git a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt index 18be14343e1..cf50ed81ca3 100644 --- a/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt +++ b/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Utils.kt @@ -203,9 +203,9 @@ fun CPointed.readValues(size: Int, align: Int): CValues { inline fun T.readValues(count: Int): CValues = this.readValues(size = count * sizeOf().toInt(), align = alignOf()) -fun CPointed.readValue(size: Int, align: Int): CValue { - val bytes = ByteArray(size) - nativeMemUtils.getByteArray(this, bytes, size) +fun CPointed.readValue(size: Long, align: Int): CValue { + val bytes = ByteArray(size.toInt()) + nativeMemUtils.getByteArray(this, bytes, size.toInt()) return object : CValue() { override fun getPointer(placement: NativePlacement): CPointer = placement.placeBytes(bytes, align) override val size get() = bytes.size @@ -214,7 +214,7 @@ fun CPointed.readValue(size: Int, align: Int): CValue { // Note: can't be declared as property due to possible clash with a struct field. // TODO: find better name. -inline fun T.readValue(): CValue = this.readValue(sizeOf().toInt(), alignOf()) +inline fun T.readValue(): CValue = this.readValue(sizeOf(), alignOf()) // TODO: optimize fun CValues.getBytes(): ByteArray = memScoped { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt index 51d0b04da98..0afc57d28a1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/InteropUtils.kt @@ -103,6 +103,14 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns) { it.valueParameters.size == 0 } + val readValue = packageScope.getContributedFunctions("readValue").single { + it.valueParameters.size == 0 + } + + val readValueBySizeAndAlign = packageScope.getContributedFunctions("readValue").single { + it.valueParameters.size == 2 + } + val typeOf = packageScope.getContributedFunctions("typeOf").single() val variableTypeClass = diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt index b2ab3fe9837..30710e7e517 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/InteropLowering.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.ir.builders.irCall import org.jetbrains.kotlin.ir.builders.irGet import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrCallableReferenceImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl import org.jetbrains.kotlin.ir.expressions.impl.IrGetObjectValueImpl @@ -179,6 +180,21 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB return alloc(placement, size, align) } + private fun IrBuilderWithScope.readValue(receiver: IrExpression, typeArgument: KotlinType): IrCallImpl? { + val size = sizeOf(typeArgument) ?: return null + val align = alignOf(typeArgument) ?: return null + + val callee = interop.readValueBySizeAndAlign + val typeParameter = callee.typeParameters.single() + val typeArguments = mapOf(typeParameter to typeArgument) + + return irCall(callee, typeArguments).apply { + extensionReceiver = receiver + putValueArgument(0, size) + putValueArgument(1, align) + } + } + override fun visitCall(expression: IrCall): IrExpression { expression.transformChildrenVoid(this) @@ -252,6 +268,13 @@ private class InteropTransformer(val context: Context, val irFile: IrFile) : IrB } } + interop.readValue -> { + val typeArgument = expression.getSingleTypeArgument() + val receiver = expression.extensionReceiver!! + + builder.readValue(receiver, typeArgument) ?: expression + } + interop.staticCFunction -> { val argument = expression.getValueArgument(0)!! if (argument !is IrCallableReference || argument.getArguments().isNotEmpty()) { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/builders/IrBuilders.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/builders/IrBuilders.kt index dd251ada63e..f4c1966bc1c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/builders/IrBuilders.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/ir/builders/IrBuilders.kt @@ -16,6 +16,8 @@ package org.jetbrains.kotlin.ir.builders +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueDescriptor import org.jetbrains.kotlin.descriptors.VariableDescriptor import org.jetbrains.kotlin.ir.expressions.IrExpression @@ -23,6 +25,8 @@ import org.jetbrains.kotlin.ir.expressions.IrLoop import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.types.KotlinType +import org.jetbrains.kotlin.types.TypeProjectionImpl +import org.jetbrains.kotlin.types.TypeSubstitutor inline fun IrBuilderWithScope.irLetSequence( value: IrExpression, @@ -50,3 +54,17 @@ fun IrBuilderWithScope.irTrue() = IrConstImpl.boolean(startOffset, endOffset, co fun IrBuilderWithScope.irGet(value: ValueDescriptor) = IrGetValueImpl(startOffset, endOffset, value) + +fun IrBuilderWithScope.irCall( + callee: CallableDescriptor, + typeArguments: Map +): IrCallImpl { + val substitutionContext = typeArguments.map { (typeParameter, typeArgument) -> + typeParameter.typeConstructor to TypeProjectionImpl(typeArgument) + }.toMap() + + val substitutor = TypeSubstitutor.create(substitutionContext) + val substitutedCallee = callee.substitute(substitutor)!! + + return IrCallImpl(this.startOffset, this.endOffset, substitutedCallee, typeArguments) +} \ No newline at end of file