From baaf6edba74780af20f36a2e9f44abf9b8c676ab Mon Sep 17 00:00:00 2001 From: Sergey Bogolepov <1580082+sbogolepov@users.noreply.github.com> Date: Wed, 19 Dec 2018 18:40:30 +0300 Subject: [PATCH] Move more intrinsics under TypedIntrinsic annotation (#2474) --- .../kotlin/kotlinx/cinterop/NativeMem.kt | 39 +- .../kotlin/kotlinx/cinterop/NativeTypes.kt | 14 +- .../kotlin/kotlinx/cinterop/ObjectiveCImpl.kt | 13 +- .../jetbrains/kotlin/backend/konan/Context.kt | 2 - .../kotlin/backend/konan/InteropUtils.kt | 28 -- .../backend/konan/llvm/IntrinsicGenerator.kt | 380 +++++++++++++++--- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 294 +------------- runtime/src/main/kotlin/kotlin/Numbers.kt | 4 +- runtime/src/main/kotlin/kotlin/Primitives.kt | 4 +- .../kotlin/native/internal/Coroutines.kt | 2 +- .../kotlin/native/internal/IntrinsicType.kt | 28 +- .../kotlin/native/internal/Intrinsics.kt | 25 +- .../kotlin/native/internal/KClassImpl.kt | 2 +- .../kotlin/native/internal/NativePtr.kt | 9 +- .../kotlin/native/internal/RuntimeUtils.kt | 4 +- .../konan/library/SearchPathResolver.kt | 2 +- 16 files changed, 432 insertions(+), 418 deletions(-) diff --git a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeMem.kt b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeMem.kt index 5c2211239a1..71a5cc4efac 100644 --- a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeMem.kt +++ b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeMem.kt @@ -18,37 +18,40 @@ package kotlinx.cinterop import kotlin.native.* import kotlin.native.internal.Intrinsic +import kotlin.native.internal.TypedIntrinsic +import kotlin.native.internal.IntrinsicType @PublishedApi internal inline val pointerSize: Int get() = getPointerSize() @PublishedApi -@Intrinsic internal external fun getPointerSize(): Int +@TypedIntrinsic(IntrinsicType.GET_POINTER_SIZE) +internal external fun getPointerSize(): Int // TODO: do not use singleton because it leads to init-check on any access. @PublishedApi internal object nativeMemUtils { - @Intrinsic external fun getByte(mem: NativePointed): Byte - @Intrinsic external fun putByte(mem: NativePointed, value: Byte) + @TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getByte(mem: NativePointed): Byte + @TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putByte(mem: NativePointed, value: Byte) - @Intrinsic external fun getShort(mem: NativePointed): Short - @Intrinsic external fun putShort(mem: NativePointed, value: Short) + @TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getShort(mem: NativePointed): Short + @TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putShort(mem: NativePointed, value: Short) - @Intrinsic external fun getInt(mem: NativePointed): Int - @Intrinsic external fun putInt(mem: NativePointed, value: Int) + @TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getInt(mem: NativePointed): Int + @TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putInt(mem: NativePointed, value: Int) - @Intrinsic external fun getLong(mem: NativePointed): Long - @Intrinsic external fun putLong(mem: NativePointed, value: Long) + @TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getLong(mem: NativePointed): Long + @TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putLong(mem: NativePointed, value: Long) - @Intrinsic external fun getFloat(mem: NativePointed): Float - @Intrinsic external fun putFloat(mem: NativePointed, value: Float) + @TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getFloat(mem: NativePointed): Float + @TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putFloat(mem: NativePointed, value: Float) - @Intrinsic external fun getDouble(mem: NativePointed): Double - @Intrinsic external fun putDouble(mem: NativePointed, value: Double) + @TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getDouble(mem: NativePointed): Double + @TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putDouble(mem: NativePointed, value: Double) - @Intrinsic external fun getNativePtr(mem: NativePointed): NativePtr - @Intrinsic external fun putNativePtr(mem: NativePointed, value: NativePtr) + @TypedIntrinsic(IntrinsicType.READ_PRIMITIVE) external fun getNativePtr(mem: NativePointed): NativePtr + @TypedIntrinsic(IntrinsicType.WRITE_PRIMITIVE) external fun putNativePtr(mem: NativePointed, value: NativePtr) // TODO: optimize fun getByteArray(source: NativePointed, dest: ByteArray, length: Int) { @@ -151,5 +154,7 @@ private external fun malloc(size: Long, align: Int): NativePtr @SymbolName("Kotlin_interop_free") private external fun cfree(ptr: NativePtr) -@Intrinsic external fun readBits(ptr: NativePtr, offset: Long, size: Int, signed: Boolean): Long -@Intrinsic external fun writeBits(ptr: NativePtr, offset: Long, size: Int, value: Long) \ No newline at end of file +@TypedIntrinsic(IntrinsicType.READ_BITS) +external fun readBits(ptr: NativePtr, offset: Long, size: Int, signed: Boolean): Long +@TypedIntrinsic(IntrinsicType.WRITE_BITS) +external fun writeBits(ptr: NativePtr, offset: Long, size: Int, value: Long) \ No newline at end of file diff --git a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeTypes.kt b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeTypes.kt index 2e60d91412a..feafdefea42 100644 --- a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeTypes.kt +++ b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/NativeTypes.kt @@ -20,6 +20,8 @@ import kotlin.native.internal.getNativeNullPtr import kotlin.native.internal.reinterpret import kotlin.native.internal.Intrinsic import kotlin.native.internal.VolatileLambda +import kotlin.native.internal.TypedIntrinsic +import kotlin.native.internal.IntrinsicType typealias NativePtr = kotlin.native.internal.NativePtr internal typealias NonNullNativePtr = kotlin.native.internal.NonNullNativePtr @@ -37,16 +39,20 @@ fun typeOf(): CVariable.Type = throw Error("typeOf() is called w * * @param T must not be abstract */ -@Intrinsic external fun interpretNullablePointed(ptr: NativePtr): T? +@TypedIntrinsic(IntrinsicType.IDENTITY) +external fun interpretNullablePointed(ptr: NativePtr): T? /** * Performs type cast of the [CPointer] from the given raw pointer. */ -@Intrinsic external fun interpretCPointer(rawValue: NativePtr): CPointer? +@TypedIntrinsic(IntrinsicType.IDENTITY) +external fun interpretCPointer(rawValue: NativePtr): CPointer? -@Intrinsic external fun NativePointed.getRawPointer(): NativePtr +@TypedIntrinsic(IntrinsicType.IDENTITY) +external fun NativePointed.getRawPointer(): NativePtr -@Intrinsic external fun CPointer<*>.getRawValue(): NativePtr +@TypedIntrinsic(IntrinsicType.IDENTITY) +external fun CPointer<*>.getRawValue(): NativePtr internal fun CPointer<*>.cPointerToString() = "CPointer(raw=$rawValue)" diff --git a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/ObjectiveCImpl.kt b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/ObjectiveCImpl.kt index 57afe9c726b..79015a7a519 100644 --- a/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/ObjectiveCImpl.kt +++ b/Interop/Runtime/src/native/kotlin/kotlinx/cinterop/ObjectiveCImpl.kt @@ -19,6 +19,8 @@ package kotlinx.cinterop import kotlin.native.* import kotlin.native.internal.ExportTypeInfo +import kotlin.native.internal.TypedIntrinsic +import kotlin.native.internal.IntrinsicType interface ObjCObject interface ObjCClass : ObjCObject @@ -91,7 +93,8 @@ var ObjCNotImplementedVar.value: T typealias ObjCStringVarOf = ObjCNotImplementedVar typealias ObjCBlockVar = ObjCNotImplementedVar -@kotlin.native.internal.Intrinsic external fun getReceiverOrSuper(receiver: NativePtr, superClass: NativePtr): COpaquePointer? +@TypedIntrinsic(IntrinsicType.OBJC_GET_RECEIVER_OR_SUPER) +external fun getReceiverOrSuper(receiver: NativePtr, superClass: NativePtr): COpaquePointer? @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.BINARY) @@ -146,12 +149,14 @@ private fun allocObjCObject(clazz: NativePtr): NativePtr { return rawResult } -@kotlin.native.internal.Intrinsic +@TypedIntrinsic(IntrinsicType.OBJC_GET_OBJC_CLASS) @kotlin.native.internal.ExportForCompiler private external fun getObjCClass(): NativePtr -@kotlin.native.internal.Intrinsic external fun getMessenger(superClass: NativePtr): COpaquePointer? -@kotlin.native.internal.Intrinsic external fun getMessengerStret(superClass: NativePtr): COpaquePointer? +@TypedIntrinsic(IntrinsicType.OBJC_GET_MESSENGER) +external fun getMessenger(superClass: NativePtr): COpaquePointer? +@TypedIntrinsic(IntrinsicType.OBJC_GET_MESSENGER_STRET) +external fun getMessengerStret(superClass: NativePtr): COpaquePointer? internal class ObjCWeakReferenceImpl : kotlin.native.ref.WeakReferenceImpl() { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt index bc71ccf9fa0..2b39c317e65 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Context.kt @@ -277,8 +277,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) { private val packageScope by lazy { builtIns.builtInsModule.getPackage(KonanFqNames.internalPackageName).memberScope } val nativePtr by lazy { packageScope.getContributedClassifier(NATIVE_PTR_NAME) as ClassDescriptor } - val nativePtrPlusLong by lazy { nativePtr.unsubstitutedMemberScope.getContributedFunctions("plus").single() } - val nativePtrToLong by lazy { nativePtr.unsubstitutedMemberScope.getContributedFunctions("toLong").single() } val getNativeNullPtr by lazy { packageScope.getContributedFunctions("getNativeNullPtr").single() } val immutableBlobOf by lazy { builtIns.builtInsModule.getPackage(KonanFqNames.packageName).memberScope.getContributedFunctions("immutableBlobOf").single() 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 bfbae3e1115..222efce93ab 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 @@ -31,8 +31,6 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns, vararg konanPrimitives: val packageScope = builtIns.builtInsModule.getPackage(InteropFqNames.packageName).memberScope - val getPointerSize = packageScope.getContributedFunctions("getPointerSize").single() - val nativePointed = packageScope.getContributedClass(InteropFqNames.nativePointedName) val cPointer = this.packageScope.getContributedClass(InteropFqNames.cPointerName) @@ -54,26 +52,8 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns, vararg konanPrimitives: TypeUtils.getClassDescriptor(extensionReceiverParameter.type) == nativePointed } - val interpretNullablePointed = packageScope.getContributedFunctions("interpretNullablePointed").single() - - val interpretCPointer = packageScope.getContributedFunctions("interpretCPointer").single() - val typeOf = packageScope.getContributedFunctions("typeOf").single() - val nativeMemUtils = packageScope.getContributedClass("nativeMemUtils") - - private val primitives = arrayOf( - arrayOf(builtIns.byte, builtIns.short, builtIns.int, builtIns.long, builtIns.float, builtIns.double), - konanPrimitives).flatten() - - val readPrimitive = primitives.map { - nativeMemUtils.unsubstitutedMemberScope.getContributedFunctions("get" + it.name).single() - }.toSet() - - val writePrimitive = primitives.map { - nativeMemUtils.unsubstitutedMemberScope.getContributedFunctions("put" + it.name).single() - }.toSet() - val bitsToFloat = packageScope.getContributedFunctions("bitsToFloat").single() val bitsToDouble = packageScope.getContributedFunctions("bitsToDouble").single() @@ -93,9 +73,6 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns, vararg konanPrimitives: val convert = packageScope.getContributedFunctions("convert").toSet() - val readBits = packageScope.getContributedFunctions("readBits").single() - val writeBits = packageScope.getContributedFunctions("writeBits").single() - val cFunctionPointerInvokes = packageScope.getContributedFunctions(OperatorNameConventions.INVOKE.asString()) .filter { val extensionReceiverParameter = it.extensionReceiverParameter @@ -135,11 +112,6 @@ internal class InteropBuiltIns(builtIns: KonanBuiltIns, vararg konanPrimitives: val objCObjectRawPtr = packageScope.getContributedFunctions("objcPtr").single() - val getObjCReceiverOrSuper = packageScope.getContributedFunctions("getReceiverOrSuper").single() - - val getObjCMessenger = packageScope.getContributedFunctions("getMessenger").single() - val getObjCMessengerStret = packageScope.getContributedFunctions("getMessengerStret").single() - val interpretObjCPointerOrNull = packageScope.getContributedFunctions("interpretObjCPointerOrNull").single() val interpretObjCPointer = packageScope.getContributedFunctions("interpretObjCPointer").single() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt index aa689d1f3e4..bde38762e5b 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IntrinsicGenerator.kt @@ -1,9 +1,14 @@ package org.jetbrains.kotlin.backend.konan.llvm +import kotlinx.cinterop.cValuesOf import llvm.* import org.jetbrains.kotlin.backend.konan.descriptors.TypedIntrinsic import org.jetbrains.kotlin.backend.konan.reportCompilationError +import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.expressions.IrCall +import org.jetbrains.kotlin.ir.expressions.IrVararg +import org.jetbrains.kotlin.ir.expressions.getTypeArgument +import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.name.Name private enum class IntrinsicType { @@ -36,11 +41,35 @@ private enum class IntrinsicType { SIGNED_COMPARE_TO, UNSIGNED_COMPARE_TO, NOT, - TO_BITS, - FROM_BITS + REINTERPRET, + ARE_EQUAL_BY_VALUE, + IEEE_754_EQUALS, + // OBJC + OBJC_GET_MESSENGER, + OBJC_GET_MESSENGER_STRET, + OBJC_GET_OBJC_CLASS, + OBJC_GET_RECEIVER_OR_SUPER, + // Other + GET_CLASS_TYPE_INFO, + READ_BITS, + WRITE_BITS, + CREATE_UNINITIALIZED_INSTANCE, + LIST_OF_INTERNAL, + IDENTITY, + GET_CONTINUATION, + // Interop + READ_PRIMITIVE, + WRITE_PRIMITIVE, + GET_POINTER_SIZE, + NATIVE_PTR_TO_LONG, + NATIVE_PTR_PLUS_LONG, + GET_NATIVE_NULL_PTR } -internal class IntrinsicGenerator(val codegen: CodeGenerator) { +internal class IntrinsicGenerator(private val codegen: CodeGenerator, + private val lifetimeCalculator: (IrElement) -> Lifetime, + private val continuationProvider: () -> LLVMValueRef, + private val exceptionHandlerProvider: () -> ExceptionHandler) { private val context = codegen.context @@ -54,48 +83,297 @@ internal class IntrinsicGenerator(val codegen: CodeGenerator) { return IntrinsicType.valueOf(value) } - fun evaluateCall(callSite: IrCall, args: List, generationContext: FunctionGenerationContext, exceptionHandler: ExceptionHandler): LLVMValueRef = - generationContext.evaluateCall(callSite, args, exceptionHandler) + fun evaluateCall(callSite: IrCall, args: List, generationContext: FunctionGenerationContext): LLVMValueRef = + generationContext.evaluateCall(callSite, args) // Assuming that we checked for `TypedIntrinsic` annotation presence. - private fun FunctionGenerationContext.evaluateCall(callSite: IrCall, args: List, exceptionHandler: ExceptionHandler): LLVMValueRef { - val result = when (getIntrinsicType(callSite)) { - IntrinsicType.PLUS -> emitPlus(args) - IntrinsicType.MINUS -> emitMinus(args) - IntrinsicType.TIMES -> emitTimes(args) - IntrinsicType.SIGNED_DIV -> emitSignedDiv(args, exceptionHandler) - IntrinsicType.SIGNED_REM -> emitSignedRem(args, exceptionHandler) - IntrinsicType.UNSIGNED_DIV -> emitUnsignedDiv(args, exceptionHandler) - IntrinsicType.UNSIGNED_REM -> emitUnsignedRem(args, exceptionHandler) - IntrinsicType.INC -> emitInc(args) - IntrinsicType.DEC -> emitDec(args) - IntrinsicType.UNARY_PLUS -> emitUnaryPlus(args) - IntrinsicType.UNARY_MINUS -> emitUnaryMinus(args) - IntrinsicType.SHL -> emitShl(args) - IntrinsicType.SHR -> emitShr(args) - IntrinsicType.USHR -> emitUshr(args) - IntrinsicType.AND -> emitAnd(args) - IntrinsicType.OR -> emitOr(args) - IntrinsicType.XOR -> emitXor(args) - IntrinsicType.INV -> emitInv(args) - IntrinsicType.SIGNED_COMPARE_TO -> emitSignedCompareTo(args) - IntrinsicType.UNSIGNED_COMPARE_TO -> emitUnsignedCompareTo(args) - IntrinsicType.NOT -> emitNot(args) - IntrinsicType.FROM_BITS -> emitReinterpret(callSite, args) - IntrinsicType.TO_BITS -> emitReinterpret(callSite, args) - IntrinsicType.SIGN_EXTEND -> emitSignExtend(callSite, args) - IntrinsicType.ZERO_EXTEND -> emitZeroExtend(callSite, args) - IntrinsicType.INT_TRUNCATE -> emitIntTruncate(callSite, args) - IntrinsicType.SIGNED_TO_FLOAT -> emitSignedToFloat(callSite, args) - IntrinsicType.UNSIGNED_TO_FLOAT -> emitUnsignedToFloat(callSite, args) - IntrinsicType.FLOAT_TO_SIGNED -> emitFloatToSigned(callSite, args) - IntrinsicType.FLOAT_EXTEND -> emitFloatExtend(callSite, args) - IntrinsicType.FLOAT_TRUNCATE -> emitFloatTruncate(callSite, args) + private fun FunctionGenerationContext.evaluateCall(callSite: IrCall, args: List): LLVMValueRef = + when (getIntrinsicType(callSite)) { + IntrinsicType.PLUS -> emitPlus(args) + IntrinsicType.MINUS -> emitMinus(args) + IntrinsicType.TIMES -> emitTimes(args) + IntrinsicType.SIGNED_DIV -> emitSignedDiv(args) + IntrinsicType.SIGNED_REM -> emitSignedRem(args) + IntrinsicType.UNSIGNED_DIV -> emitUnsignedDiv(args) + IntrinsicType.UNSIGNED_REM -> emitUnsignedRem(args) + IntrinsicType.INC -> emitInc(args) + IntrinsicType.DEC -> emitDec(args) + IntrinsicType.UNARY_PLUS -> emitUnaryPlus(args) + IntrinsicType.UNARY_MINUS -> emitUnaryMinus(args) + IntrinsicType.SHL -> emitShl(args) + IntrinsicType.SHR -> emitShr(args) + IntrinsicType.USHR -> emitUshr(args) + IntrinsicType.AND -> emitAnd(args) + IntrinsicType.OR -> emitOr(args) + IntrinsicType.XOR -> emitXor(args) + IntrinsicType.INV -> emitInv(args) + IntrinsicType.SIGNED_COMPARE_TO -> emitSignedCompareTo(args) + IntrinsicType.UNSIGNED_COMPARE_TO -> emitUnsignedCompareTo(args) + IntrinsicType.NOT -> emitNot(args) + IntrinsicType.REINTERPRET -> emitReinterpret(callSite, args) + IntrinsicType.SIGN_EXTEND -> emitSignExtend(callSite, args) + IntrinsicType.ZERO_EXTEND -> emitZeroExtend(callSite, args) + IntrinsicType.INT_TRUNCATE -> emitIntTruncate(callSite, args) + IntrinsicType.SIGNED_TO_FLOAT -> emitSignedToFloat(callSite, args) + IntrinsicType.UNSIGNED_TO_FLOAT -> emitUnsignedToFloat(callSite, args) + IntrinsicType.FLOAT_TO_SIGNED -> emitFloatToSigned(callSite, args) + IntrinsicType.FLOAT_EXTEND -> emitFloatExtend(callSite, args) + IntrinsicType.FLOAT_TRUNCATE -> emitFloatTruncate(callSite, args) + IntrinsicType.ARE_EQUAL_BY_VALUE -> emitAreEqualByValue(args) + IntrinsicType.IEEE_754_EQUALS -> emitIeee754Equals(args) + IntrinsicType.OBJC_GET_MESSENGER -> emitObjCGetMessenger(args, isStret = false) + IntrinsicType.OBJC_GET_MESSENGER_STRET -> emitObjCGetMessenger(args, isStret = true) + IntrinsicType.OBJC_GET_OBJC_CLASS -> emitGetObjCClass(callSite) + IntrinsicType.OBJC_GET_RECEIVER_OR_SUPER -> emitGetReceiverOrSuper(args) + IntrinsicType.GET_CLASS_TYPE_INFO -> emitGetClassTypeInfo(callSite) + IntrinsicType.READ_BITS -> emitReadBits(args) + IntrinsicType.WRITE_BITS -> emitWriteBits(args) + IntrinsicType.READ_PRIMITIVE -> emitReadPrimitive(callSite, args) + IntrinsicType.WRITE_PRIMITIVE -> emitWritePrimitive(callSite, args) + IntrinsicType.GET_POINTER_SIZE -> emitGetPointerSize() + IntrinsicType.CREATE_UNINITIALIZED_INSTANCE -> emitCreateUninitializedInstance(callSite) + IntrinsicType.NATIVE_PTR_TO_LONG -> emitNativePtrToLong(callSite, args) + IntrinsicType.NATIVE_PTR_PLUS_LONG -> emitNativePtrPlusLong(args) + IntrinsicType.GET_NATIVE_NULL_PTR -> emitGetNativeNullPtr() + IntrinsicType.LIST_OF_INTERNAL -> emitListOfInternal(callSite, args) + IntrinsicType.IDENTITY -> emitIdentity(args) + IntrinsicType.GET_CONTINUATION -> emitGetContinuation() + } + + private fun FunctionGenerationContext.emitGetContinuation(): LLVMValueRef = + continuationProvider() + + private fun FunctionGenerationContext.emitIdentity(args: List): LLVMValueRef = + args.single() + + private fun FunctionGenerationContext.emitListOfInternal(callSite: IrCall, args: List): LLVMValueRef { + val varargExpression = callSite.getValueArgument(0) as IrVararg + val vararg = args.single() + + val length = varargExpression.elements.size + // TODO: store length in `vararg` itself when more abstract types will be used for values. + + val array = constPointer(vararg) + // Note: dirty hack here: `vararg` has type `Array`, but `createConstArrayList` expects `Array`; + // however `vararg` is immutable, and in current implementation it has type `Array`, + // so let's ignore this mismatch currently for simplicity. + + return context.llvm.staticData.createConstArrayList(array, length).llvm + } + + private fun FunctionGenerationContext.emitGetNativeNullPtr(): LLVMValueRef = + kNullInt8Ptr + + private fun FunctionGenerationContext.emitNativePtrPlusLong(args: List): LLVMValueRef = + gep(args[0], args[1]) + + private fun FunctionGenerationContext.emitNativePtrToLong(callSite: IrCall, args: List): LLVMValueRef { + val intPtrValue = ptrToInt(args.single(), codegen.intPtrType) + val resultType = callSite.llvmReturnType + return if (resultType == intPtrValue.type) { + intPtrValue + } else { + LLVMBuildSExt(builder, intPtrValue, resultType, "")!! } - assert(result.type == callSite.llvmReturnType) { - "Substitution of ${callSite.symbol.owner.functionName} has wrong result type" + } + + private fun FunctionGenerationContext.emitCreateUninitializedInstance(callSite: IrCall): LLVMValueRef { + val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0] + val enumClass = callSite.getTypeArgument(typeParameterT)!! + val enumIrClass = enumClass.getClass()!! + return allocInstance(enumIrClass, lifetimeCalculator(callSite)) + } + + private fun FunctionGenerationContext.emitGetPointerSize(): LLVMValueRef = + Int32(LLVMPointerSize(codegen.llvmTargetData)).llvm + + private fun FunctionGenerationContext.emitReadPrimitive(callSite: IrCall, args: List): LLVMValueRef { + val pointerType = pointerType(callSite.llvmReturnType) + val rawPointer = args.last() + val pointer = bitcast(pointerType, rawPointer) + return load(pointer) + } + + private fun FunctionGenerationContext.emitWritePrimitive(callSite: IrCall, args: List): LLVMValueRef { + val function = callSite.symbol.owner + val pointerType = pointerType(codegen.getLLVMType(function.valueParameters.last().type)) + val rawPointer = args[1] + val pointer = bitcast(pointerType, rawPointer) + store(args[2], pointer) + return codegen.theUnitInstanceRef.llvm + } + + private fun FunctionGenerationContext.emitReadBits(args: List): LLVMValueRef { + val ptr = args[0] + assert(ptr.type == int8TypePtr) + + val offset = extractConstUnsignedInt(args[1]) + val size = extractConstUnsignedInt(args[2]).toInt() + val signed = extractConstUnsignedInt(args[3]) != 0L + + val prefixBitsNum = (offset % 8).toInt() + val suffixBitsNum = (8 - ((size + offset) % 8).toInt()) % 8 + + // Note: LLVM allows to read without padding tail up to byte boundary, but the result seems to be incorrect. + + val bitsWithPaddingNum = prefixBitsNum + size + suffixBitsNum + val bitsWithPaddingType = LLVMIntType(bitsWithPaddingNum)!! + + val bitsWithPaddingPtr = bitcast(org.jetbrains.kotlin.backend.konan.llvm.pointerType(bitsWithPaddingType), gep(ptr, org.jetbrains.kotlin.backend.konan.llvm.Int64(offset / 8).llvm)) + val bitsWithPadding = load(bitsWithPaddingPtr).setUnaligned() + + val bits = shr( + shl(bitsWithPadding, suffixBitsNum), + prefixBitsNum + suffixBitsNum, signed + ) + return when { + bitsWithPaddingNum == 64 -> bits + bitsWithPaddingNum > 64 -> trunc(bits, org.jetbrains.kotlin.backend.konan.llvm.int64Type) + else -> ext(bits, org.jetbrains.kotlin.backend.konan.llvm.int64Type, signed) } - return result + } + + private fun FunctionGenerationContext.emitWriteBits(args: List): LLVMValueRef { + val ptr = args[0] + assert(ptr.type == int8TypePtr) + + val offset = extractConstUnsignedInt(args[1]) + val size = extractConstUnsignedInt(args[2]).toInt() + + val value = args[3] + assert(value.type == int64Type) + + val bitsType = LLVMIntType(size)!! + + val prefixBitsNum = (offset % 8).toInt() + val suffixBitsNum = (8 - ((size + offset) % 8).toInt()) % 8 + + val bitsWithPaddingNum = prefixBitsNum + size + suffixBitsNum + val bitsWithPaddingType = LLVMIntType(bitsWithPaddingNum)!! + + // 0011111000: + val discardBitsMask = LLVMConstShl( + LLVMConstZExt( + LLVMConstAllOnes(bitsType), // 11111 + bitsWithPaddingType + ), // 1111100000 + LLVMConstInt(bitsWithPaddingType, prefixBitsNum.toLong(), 0) + ) + + val preservedBitsMask = LLVMConstNot(discardBitsMask)!! + + val bitsWithPaddingPtr = bitcast(pointerType(bitsWithPaddingType), gep(ptr, Int64(offset / 8).llvm)) + + val bits = trunc(value, bitsType) + + val bitsToStore = if (prefixBitsNum == 0 && suffixBitsNum == 0) { + bits + } else { + val previousValue = load(bitsWithPaddingPtr).setUnaligned() + val preservedBits = and(previousValue, preservedBitsMask) + val bitsWithPadding = shl(zext(bits, bitsWithPaddingType), prefixBitsNum) + + or(bitsWithPadding, preservedBits) + } + llvm.LLVMBuildStore(builder, bitsToStore, bitsWithPaddingPtr)!!.setUnaligned() + return codegen.theUnitInstanceRef.llvm + } + + private fun extractConstUnsignedInt(value: LLVMValueRef): Long { + assert(LLVMIsConstant(value) != 0) + return LLVMConstIntGetZExtValue(value) + } + + private fun FunctionGenerationContext.emitGetClassTypeInfo(callSite: IrCall): LLVMValueRef { + val typeArgument = callSite.getTypeArgument(0)!! + val typeArgumentClass = typeArgument.getClass() + return if (typeArgumentClass == null) { + // Should not happen anymore, but it is safer to handle this case. + unreachable() + kNullInt8Ptr + } else { + val typeInfo = codegen.typeInfoValue(typeArgumentClass) + LLVMConstBitCast(typeInfo, kInt8Ptr)!! + } + } + + private fun FunctionGenerationContext.emitGetReceiverOrSuper(args: List): LLVMValueRef { + assert(args.size == 2) + val receiver = args[0] + val superClass = args[1] + + val superClassIsNull = icmpEq(superClass, kNullInt8Ptr) + + return ifThenElse(superClassIsNull, receiver) { + val structType = structType(kInt8Ptr, kInt8Ptr) + val ptr = alloca(structType) + store(receiver, LLVMBuildGEP(builder, ptr, cValuesOf(kImmZero, kImmZero), 2, "")!!) + store(superClass, LLVMBuildGEP(builder, ptr, cValuesOf(kImmZero, kImmOne), 2, "")!!) + bitcast(int8TypePtr, ptr) + } + } + + // TODO: Find better place for these guys. + private val kImmZero = LLVMConstInt(LLVMInt32Type(), 0, 1)!! + private val kImmOne = LLVMConstInt(LLVMInt32Type(), 1, 1)!! + + private fun FunctionGenerationContext.emitGetObjCClass(callSite: IrCall): LLVMValueRef { + val descriptor = callSite.descriptor.original + val typeArgument = callSite.getTypeArgument(descriptor.typeParameters.single()) + return getObjCClass(typeArgument!!.getClass()!!, exceptionHandlerProvider()) + } + + private fun FunctionGenerationContext.emitObjCGetMessenger(args: List, isStret: Boolean): LLVMValueRef { + val messengerNameSuffix = if (isStret) "_stret" else "" + + val functionType = functionType(int8TypePtr, true, int8TypePtr, int8TypePtr) + + val libobjc = context.standardLlvmSymbolsOrigin + val normalMessenger = context.llvm.externalFunction( + "objc_msgSend$messengerNameSuffix", + functionType, + origin = libobjc + ) + val superMessenger = context.llvm.externalFunction( + "objc_msgSendSuper$messengerNameSuffix", + functionType, + origin = libobjc + ) + + val superClass = args.single() + val messenger = LLVMBuildSelect(builder, + If = icmpEq(superClass, kNullInt8Ptr), + Then = normalMessenger, + Else = superMessenger, + Name = "" + )!! + + return bitcast(int8TypePtr, messenger) + } + + private fun FunctionGenerationContext.emitAreEqualByValue(args: List): LLVMValueRef { + val (first, second) = args + assert (first.type == second.type) { "Types are different: '${llvmtype2string(first.type)}' and '${llvmtype2string(second.type)}'" } + + return when (val typeKind = LLVMGetTypeKind(first.type)) { + llvm.LLVMTypeKind.LLVMFloatTypeKind, llvm.LLVMTypeKind.LLVMDoubleTypeKind -> { + val numBits = llvm.LLVMSizeOfTypeInBits(codegen.llvmTargetData, first.type).toInt() + val integerType = llvm.LLVMIntType(numBits)!! + icmpEq(bitcast(integerType, first), bitcast(integerType, second)) + } + llvm.LLVMTypeKind.LLVMIntegerTypeKind, llvm.LLVMTypeKind.LLVMPointerTypeKind -> icmpEq(first, second) + else -> error(typeKind) + } + } + + private fun FunctionGenerationContext.emitIeee754Equals(args: List): LLVMValueRef { + val (first, second) = args + assert (first.type == second.type) + { "Types are different: '${llvmtype2string(first.type)}' and '${llvmtype2string(second.type)}'" } + val type = LLVMGetTypeKind(first.type) + assert (type == LLVMTypeKind.LLVMFloatTypeKind || type == LLVMTypeKind.LLVMDoubleTypeKind) + { "Should be of floating point kind, not: '${llvmtype2string(first.type)}'"} + return fcmpEq(first, second) } private fun FunctionGenerationContext.emitReinterpret(callSite: IrCall, args: List) = @@ -196,18 +474,18 @@ internal class IntrinsicGenerator(val codegen: CodeGenerator) { }!! } - private fun FunctionGenerationContext.emitThrowIfZero(divider: LLVMValueRef, exceptionHandler: ExceptionHandler) { + private fun FunctionGenerationContext.emitThrowIfZero(divider: LLVMValueRef) { ifThen(icmpEq(divider, Zero(divider.type).llvm)) { val throwArithExc = codegen.llvmFunction(context.ir.symbols.throwArithmeticException.owner) - call(throwArithExc, emptyList(), Lifetime.GLOBAL, exceptionHandler) + call(throwArithExc, emptyList(), Lifetime.GLOBAL, exceptionHandlerProvider()) unreachable() } } - private fun FunctionGenerationContext.emitSignedDiv(args: List, exceptionHandler: ExceptionHandler): LLVMValueRef { + private fun FunctionGenerationContext.emitSignedDiv(args: List): LLVMValueRef { val (first, second) = args if (!second.type.isFloatingPoint()) { - emitThrowIfZero(second, exceptionHandler) + emitThrowIfZero(second) } return if (first.type.isFloatingPoint()) { LLVMBuildFDiv(builder, first, second, "") @@ -216,10 +494,10 @@ internal class IntrinsicGenerator(val codegen: CodeGenerator) { }!! } - private fun FunctionGenerationContext.emitSignedRem(args: List, exceptionHandler: ExceptionHandler): LLVMValueRef { + private fun FunctionGenerationContext.emitSignedRem(args: List): LLVMValueRef { val (first, second) = args if (!second.type.isFloatingPoint()) { - emitThrowIfZero(second, exceptionHandler) + emitThrowIfZero(second) } return if (first.type.isFloatingPoint()) { LLVMBuildFRem(builder, first, second, "") @@ -228,15 +506,15 @@ internal class IntrinsicGenerator(val codegen: CodeGenerator) { }!! } - private fun FunctionGenerationContext.emitUnsignedDiv(args: List, exceptionHandler: ExceptionHandler): LLVMValueRef { + private fun FunctionGenerationContext.emitUnsignedDiv(args: List): LLVMValueRef { val (first, second) = args - emitThrowIfZero(second, exceptionHandler) + emitThrowIfZero(second) return LLVMBuildUDiv(builder, first, second, "")!! } - private fun FunctionGenerationContext.emitUnsignedRem(args: List, exceptionHandler: ExceptionHandler): LLVMValueRef { + private fun FunctionGenerationContext.emitUnsignedRem(args: List): LLVMValueRef { val (first, second) = args - emitThrowIfZero(second, exceptionHandler) + emitThrowIfZero(second) return LLVMBuildURem(builder, first, second, "")!! } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index c04a4c3f366..b597b07281a 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -291,13 +291,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map intrinsicGenerator.evaluateCall(callee, args, functionGenerationContext, currentCodeContext.exceptionHandler) - function.isIntrinsic -> evaluateIntrinsicCall(callee, argsWithContinuationIfNeeded) + function.isTypedIntrinsic -> intrinsicGenerator.evaluateCall(callee, args, functionGenerationContext) + function.isIntrinsic -> context.reportCompilationError("Unexpected @Intrinsic function: ${function.name.asString()}") function.origin == IrDeclarationOrigin.IR_BUILTINS_STUB -> evaluateOperatorCall(callee, argsWithContinuationIfNeeded) function is ConstructorDescriptor -> evaluateConstructorCall(callee, argsWithContinuationIfNeeded) else -> evaluateSimpleFunctionCall(function, argsWithContinuationIfNeeded, resultLifetime, callee.superQualifierSymbol?.owner) @@ -2198,233 +2196,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map): LLVMValueRef { - val descriptor = callee.descriptor.original - val function = callee.symbol.owner - val name = descriptor.fqNameUnsafe.asString() - - when (name) { - "kotlin.native.internal.areEqualByValue" -> { - val arg0 = args[0] - val arg1 = args[1] - assert (arg0.type == arg1.type, - { "Types are different: '${llvmtype2string(arg0.type)}' and '${llvmtype2string(arg1.type)}'" }) - - val typeKind = LLVMGetTypeKind(arg0.type) - with (functionGenerationContext) { - return when (typeKind) { - LLVMTypeKind.LLVMFloatTypeKind, LLVMTypeKind.LLVMDoubleTypeKind -> { - val numBits = LLVMSizeOfTypeInBits(codegen.llvmTargetData, arg0.type).toInt() - val integerType = LLVMIntType(numBits)!! - icmpEq(bitcast(integerType, arg0), bitcast(integerType, arg1)) - } - - LLVMTypeKind.LLVMIntegerTypeKind, LLVMTypeKind.LLVMPointerTypeKind -> icmpEq(arg0, arg1) - - else -> error(typeKind) - } - } - } - "kotlin.native.internal.ieee754Equals" -> { - val arg0 = args[0] - val arg1 = args[1] - assert (arg0.type == arg1.type, - { "Types are different: '${llvmtype2string(arg0.type)}' and '${llvmtype2string(arg1.type)}'" }) - val type = LLVMGetTypeKind(arg0.type) - assert (type == LLVMTypeKind.LLVMFloatTypeKind || type == LLVMTypeKind.LLVMDoubleTypeKind, - { "Should be of floating point kind, not: '${llvmtype2string(arg0.type)}'"}) - return functionGenerationContext.fcmpEq(arg0, arg1) - - } - "kotlin.native.internal.getContinuation" -> return getContinuation() - } - - val interop = context.interopBuiltIns - - return when (descriptor) { - interop.interpretNullablePointed, interop.interpretCPointer, - interop.nativePointedGetRawPointer, interop.cPointerGetRawValue, // TODO: implement through `reinterpret` - context.ir.symbols.reinterpret.descriptor -> args.single() - - in interop.readPrimitive -> { - val pointerType = pointerType(codegen.getLLVMType(function.returnType)) - val rawPointer = args.last() - val pointer = functionGenerationContext.bitcast(pointerType, rawPointer) - functionGenerationContext.load(pointer) - } - in interop.writePrimitive -> { - val pointerType = pointerType(codegen.getLLVMType(function.valueParameters.last().type)) - val rawPointer = args[1] - val pointer = functionGenerationContext.bitcast(pointerType, rawPointer) - functionGenerationContext.store(args[2], pointer) - codegen.theUnitInstanceRef.llvm - } - context.nativePtrPlusLong -> functionGenerationContext.gep(args[0], args[1]) - context.getNativeNullPtr -> kNullInt8Ptr - interop.getPointerSize -> Int32(LLVMPointerSize(codegen.llvmTargetData)).llvm - context.nativePtrToLong -> { - val intPtrValue = functionGenerationContext.ptrToInt(args.single(), codegen.intPtrType) - val resultType = functionGenerationContext.getLLVMType(function.returnType) - - if (resultType == intPtrValue.type) { - intPtrValue - } else { - LLVMBuildSExt(functionGenerationContext.builder, intPtrValue, resultType, "")!! - } - } - - interop.getObjCReceiverOrSuper -> { - genGetObjCReceiverOrSuper(args) - } - - interop.getObjCClass -> { - val typeArgument = callee.getTypeArgument(descriptor.typeParameters.single()) - val irClass = typeArgument!!.getClass()!! - genGetObjCClass(irClass) - } - - interop.getObjCMessenger -> { - genGetObjCMessenger(args, isStret = false) - } - interop.getObjCMessengerStret -> { - genGetObjCMessenger(args, isStret = true) - } - - interop.readBits -> genReadBits(args) - interop.writeBits -> genWriteBits(args) - - context.ir.symbols.getClassTypeInfo.descriptor -> { - val typeArgument = callee.getTypeArgument(0)!! - val typeArgumentClass = typeArgument.getClass() - if (typeArgumentClass == null) { - // Should not happen anymore, but it is safer to handle this case. - functionGenerationContext.unreachable() - kNullInt8Ptr - } else { - val typeInfo = codegen.typeInfoValue(typeArgumentClass) - LLVMConstBitCast(typeInfo, kInt8Ptr)!! - } - } - - context.ir.symbols.createUninitializedInstance.descriptor -> { - val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0] - val enumClass = callee.getTypeArgument(typeParameterT)!! - val enumIrClass = enumClass.getClass()!! - functionGenerationContext.allocInstance(enumIrClass, resultLifetime(callee)) - } - - context.ir.symbols.listOfInternal.descriptor -> { - val varargExpression = callee.getValueArgument(0) as IrVararg - val vararg = args.single() - - val length = varargExpression.elements.size - // TODO: store length in `vararg` itself when more abstract types will be used for values. - - val array = constPointer(vararg) - // Note: dirty hack here: `vararg` has type `Array`, but `createConstArrayList` expects `Array`; - // however `vararg` is immutable, and in current implementation it has type `Array`, - // so let's ignore this mismatch currently for simplicity. - - return context.llvm.staticData.createConstArrayList(array, length).llvm - } - - else -> TODO(callee.descriptor.original.toString()) - } - } - - private fun genReadBits(args: List): LLVMValueRef { - val ptr = args[0] - assert(ptr.type == int8TypePtr) - - val offset = extractConstUnsignedInt(args[1]) - val size = extractConstUnsignedInt(args[2]).toInt() - val signed = extractConstUnsignedInt(args[3]) != 0L - - val prefixBitsNum = (offset % 8).toInt() - val suffixBitsNum = (8 - ((size + offset) % 8).toInt()) % 8 - - // Note: LLVM allows to read without padding tail up to byte boundary, but the result seems to be incorrect. - - val bitsWithPaddingNum = prefixBitsNum + size + suffixBitsNum - val bitsWithPaddingType = LLVMIntType(bitsWithPaddingNum)!! - - with (functionGenerationContext) { - val bitsWithPaddingPtr = bitcast(pointerType(bitsWithPaddingType), gep(ptr, Int64(offset / 8).llvm)) - val bitsWithPadding = load(bitsWithPaddingPtr).setUnaligned() - - val bits = shr( - shl(bitsWithPadding, suffixBitsNum), - prefixBitsNum + suffixBitsNum, signed - ) - - return if (bitsWithPaddingNum == 64) { - bits - } else if (bitsWithPaddingNum > 64) { - trunc(bits, int64Type) - } else { - ext(bits, int64Type, signed) - } - } - } - - private fun genWriteBits(args: List): LLVMValueRef { - val ptr = args[0] - assert(ptr.type == int8TypePtr) - - val offset = extractConstUnsignedInt(args[1]) - val size = extractConstUnsignedInt(args[2]).toInt() - - val value = args[3] - assert(value.type == int64Type) - - val bitsType = LLVMIntType(size)!! - - val prefixBitsNum = (offset % 8).toInt() - val suffixBitsNum = (8 - ((size + offset) % 8).toInt()) % 8 - - val bitsWithPaddingNum = prefixBitsNum + size + suffixBitsNum - val bitsWithPaddingType = LLVMIntType(bitsWithPaddingNum)!! - - // 0011111000: - val discardBitsMask = LLVMConstShl( - LLVMConstZExt( - LLVMConstAllOnes(bitsType), // 11111 - bitsWithPaddingType - ), // 1111100000 - LLVMConstInt(bitsWithPaddingType, prefixBitsNum.toLong(), 0) - ) - - val preservedBitsMask = LLVMConstNot(discardBitsMask)!! - - with (functionGenerationContext) { - val bitsWithPaddingPtr = bitcast(pointerType(bitsWithPaddingType), gep(ptr, Int64(offset / 8).llvm)) - - val bits = trunc(value, bitsType) - - val bitsToStore = if (prefixBitsNum == 0 && suffixBitsNum == 0) { - bits - } else { - val previousValue = load(bitsWithPaddingPtr).setUnaligned() - val preservedBits = and(previousValue, preservedBitsMask) - val bitsWithPadding = shl(zext(bits, bitsWithPaddingType), prefixBitsNum) - - or(bitsWithPadding, preservedBits) - } - - LLVMBuildStore(builder, bitsToStore, bitsWithPaddingPtr)!!.setUnaligned() - } - - return codegen.theUnitInstanceRef.llvm - } - - private fun extractConstUnsignedInt(value: LLVMValueRef): Long { - assert(LLVMIsConstant(value) != 0) - return LLVMConstIntGetZExtValue(value) - } - private fun genGetObjCClass(classDescriptor: ClassDescriptor): LLVMValueRef { return functionGenerationContext.getObjCClass(classDescriptor, currentCodeContext.exceptionHandler) } @@ -2446,64 +2217,13 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map, isStret: Boolean): LLVMValueRef { - val gen = functionGenerationContext - - val messengerNameSuffix = if (isStret) "_stret" else "" - - val functionType = functionType(int8TypePtr, true, int8TypePtr, int8TypePtr) - - val libobjc = context.standardLlvmSymbolsOrigin - val normalMessenger = context.llvm.externalFunction( - "objc_msgSend$messengerNameSuffix", - functionType, - origin = libobjc - ) - val superMessenger = context.llvm.externalFunction( - "objc_msgSendSuper$messengerNameSuffix", - functionType, - origin = libobjc - ) - - val superClass = args.single() - val messenger = LLVMBuildSelect(gen.builder, - If = gen.icmpEq(superClass, kNullInt8Ptr), - Then = normalMessenger, - Else = superMessenger, - Name = "" - )!! - - return gen.bitcast(int8TypePtr, messenger) - } - - private fun genGetObjCReceiverOrSuper(args: List): LLVMValueRef { - val gen = functionGenerationContext - - assert(args.size == 2) - val receiver = args[0] - val superClass = args[1] - - val superClassIsNull = gen.icmpEq(superClass, kNullInt8Ptr) - - return gen.ifThenElse(superClassIsNull, receiver) { - val structType = structType(kInt8Ptr, kInt8Ptr) - val ptr = gen.alloca(structType) - gen.store(receiver, - LLVMBuildGEP(gen.builder, ptr, cValuesOf(kImmZero, kImmZero), 2, "")!!) - - gen.store(superClass, - LLVMBuildGEP(gen.builder, ptr, cValuesOf(kImmZero, kImmOne), 2, "")!!) - - gen.bitcast(int8TypePtr, ptr) - } - } - //-------------------------------------------------------------------------// private val kImmZero = LLVMConstInt(LLVMInt32Type(), 0, 1)!! private val kImmOne = LLVMConstInt(LLVMInt32Type(), 1, 1)!! private val kTrue = LLVMConstInt(LLVMInt1Type(), 1, 1)!! private val kFalse = LLVMConstInt(LLVMInt1Type(), 0, 1)!! + // TODO: Intrinsify? private fun evaluateOperatorCall(callee: IrCall, args: List): LLVMValueRef { context.log{"evaluateOperatorCall : origin:${ir2string(callee)}"} val descriptor = callee.symbol.owner diff --git a/runtime/src/main/kotlin/kotlin/Numbers.kt b/runtime/src/main/kotlin/kotlin/Numbers.kt index b9e4285568d..579f716d845 100644 --- a/runtime/src/main/kotlin/kotlin/Numbers.kt +++ b/runtime/src/main/kotlin/kotlin/Numbers.kt @@ -71,7 +71,7 @@ public actual inline fun Double.toRawBits(): Long = bits() public actual inline fun Double.Companion.fromBits(bits: Long): Double = kotlin.fromBits(bits) @PublishedApi -@TypedIntrinsic(IntrinsicType.FROM_BITS) +@TypedIntrinsic(IntrinsicType.REINTERPRET) external internal fun fromBits(bits: Long): Double /** @@ -99,5 +99,5 @@ public actual inline fun Float.toRawBits(): Int = bits() public actual inline fun Float.Companion.fromBits(bits: Int): Float = kotlin.fromBits(bits) @PublishedApi -@TypedIntrinsic(IntrinsicType.FROM_BITS) +@TypedIntrinsic(IntrinsicType.REINTERPRET) external internal fun fromBits(bits: Int): Float diff --git a/runtime/src/main/kotlin/kotlin/Primitives.kt b/runtime/src/main/kotlin/kotlin/Primitives.kt index da35a70d519..925e4fb0956 100644 --- a/runtime/src/main/kotlin/kotlin/Primitives.kt +++ b/runtime/src/main/kotlin/kotlin/Primitives.kt @@ -1174,7 +1174,7 @@ public final class Float private constructor(private val value: kotlin.native.in return bits() } - @TypedIntrinsic(IntrinsicType.TO_BITS) + @TypedIntrinsic(IntrinsicType.REINTERPRET) @PublishedApi external internal fun bits(): Int } @@ -1396,7 +1396,7 @@ public final class Double private constructor(private val value: kotlin.native.i public override fun hashCode(): Int = bits().hashCode() - @TypedIntrinsic(IntrinsicType.TO_BITS) + @TypedIntrinsic(IntrinsicType.REINTERPRET) @PublishedApi external internal fun bits(): Long } diff --git a/runtime/src/main/kotlin/kotlin/native/internal/Coroutines.kt b/runtime/src/main/kotlin/kotlin/native/internal/Coroutines.kt index 87bc8e05983..a8ad27dff86 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/Coroutines.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/Coroutines.kt @@ -13,7 +13,7 @@ import kotlin.coroutines.intrinsics.* internal inline suspend fun suspendCoroutineUninterceptedOrReturn(crossinline block: (Continuation) -> Any?): T = returnIfSuspended(block(getContinuation())) -@Intrinsic +@TypedIntrinsic(IntrinsicType.GET_CONTINUATION) @PublishedApi internal external fun getContinuation(): Continuation diff --git a/runtime/src/main/kotlin/kotlin/native/internal/IntrinsicType.kt b/runtime/src/main/kotlin/kotlin/native/internal/IntrinsicType.kt index 247d77aa9c4..f0bccce317b 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/IntrinsicType.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/IntrinsicType.kt @@ -2,6 +2,7 @@ package kotlin.native.internal class IntrinsicType { companion object { + // Arithmetic const val PLUS = "PLUS" const val MINUS = "MINUS" const val TIMES = "TIMES" @@ -31,7 +32,30 @@ class IntrinsicType { const val SIGNED_COMPARE_TO = "SIGNED_COMPARE_TO" const val UNSIGNED_COMPARE_TO = "UNSIGNED_COMPARE_TO" const val NOT = "NOT" - const val TO_BITS = "TO_BITS" - const val FROM_BITS = "FROM_BITS" + const val REINTERPRET = "REINTERPRET" + const val ARE_EQUAL_BY_VALUE = "ARE_EQUAL_BY_VALUE" + const val IEEE_754_EQUALS = "IEEE_754_EQUALS" + // ObjC related stuff + const val OBJC_GET_MESSENGER = "OBJC_GET_MESSENGER" + const val OBJC_GET_MESSENGER_STRET = "OBJC_GET_MESSENGER_STRET" + const val OBJC_GET_OBJC_CLASS = "OBJC_GET_OBJC_CLASS" + const val OBJC_GET_RECEIVER_OR_SUPER = "OBJC_GET_RECEIVER_OR_SUPER" + + // Other + const val GET_CLASS_TYPE_INFO = "GET_CLASS_TYPE_INFO" + const val READ_BITS = "READ_BITS" + const val WRITE_BITS = "WRITE_BITS" + const val CREATE_UNINITIALIZED_INSTANCE = "CREATE_UNINITIALIZED_INSTANCE" + const val LIST_OF_INTERNAL = "LIST_OF_INTERNAL" + const val IDENTITY = "IDENTITY" + const val GET_CONTINUATION = "GET_CONTINUATION" + + // Interop + const val READ_PRIMITIVE = "READ_PRIMITIVE" + const val WRITE_PRIMITIVE = "WRITE_PRIMITIVE" + const val GET_POINTER_SIZE = "GET_POINTER_SIZE" + const val NATIVE_PTR_TO_LONG = "NATIVE_PTR_TO_LONG" + const val NATIVE_PTR_PLUS_LONG = "NATIVE_PTR_PLUS_LONG" + const val GET_NATIVE_NULL_PTR = "GET_NATIVE_NULL_PTR" } } \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin/native/internal/Intrinsics.kt b/runtime/src/main/kotlin/kotlin/native/internal/Intrinsics.kt index 5e966a569bd..1a16c13473a 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/Intrinsics.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/Intrinsics.kt @@ -9,20 +9,23 @@ import kotlinx.cinterop.CPointer import kotlinx.cinterop.NativePointed import kotlinx.cinterop.NativePtr -@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Boolean, second: Boolean): Boolean -@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Byte, second: Byte): Boolean -@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Short, second: Short): Boolean -@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Int, second: Int): Boolean -@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Long, second: Long): Boolean -@Intrinsic @PublishedApi external internal fun areEqualByValue(first: NativePtr, second: NativePtr): Boolean +import kotlin.native.internal.TypedIntrinsic +import kotlin.native.internal.IntrinsicType + +@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Boolean, second: Boolean): Boolean +@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Byte, second: Byte): Boolean +@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Short, second: Short): Boolean +@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Int, second: Int): Boolean +@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Long, second: Long): Boolean +@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: NativePtr, second: NativePtr): Boolean // Bitwise equality: -@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Float, second: Float): Boolean -@Intrinsic @PublishedApi external internal fun areEqualByValue(first: Double, second: Double): Boolean +@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Float, second: Float): Boolean +@TypedIntrinsic(IntrinsicType.ARE_EQUAL_BY_VALUE) @PublishedApi external internal fun areEqualByValue(first: Double, second: Double): Boolean // IEEE754 equality: -@Intrinsic @PublishedApi external internal fun ieee754Equals(first: Float, second: Float): Boolean -@Intrinsic @PublishedApi external internal fun ieee754Equals(first: Double, second: Double): Boolean +@TypedIntrinsic(IntrinsicType.IEEE_754_EQUALS) @PublishedApi external internal fun ieee754Equals(first: Float, second: Float): Boolean +@TypedIntrinsic(IntrinsicType.IEEE_754_EQUALS) @PublishedApi external internal fun ieee754Equals(first: Double, second: Double): Boolean // Reinterprets this value from T to R having the same binary representation (e.g. to unwrap inline class). -@Intrinsic @PublishedApi external internal fun T.reinterpret(): R +@TypedIntrinsic(IntrinsicType.IDENTITY) @PublishedApi external internal fun T.reinterpret(): R diff --git a/runtime/src/main/kotlin/kotlin/native/internal/KClassImpl.kt b/runtime/src/main/kotlin/kotlin/native/internal/KClassImpl.kt index cb9a4f12a3a..d35166d0906 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/KClassImpl.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/KClassImpl.kt @@ -62,7 +62,7 @@ internal class KClassUnsupportedImpl(private val message: String) : KClass internal external fun getObjectTypeInfo(obj: Any): NativePtr @ExportForCompiler -@Intrinsic +@TypedIntrinsic(IntrinsicType.GET_CLASS_TYPE_INFO) internal external inline fun getClassTypeInfo(): NativePtr @SymbolName("Kotlin_TypeInfo_getPackageName") diff --git a/runtime/src/main/kotlin/kotlin/native/internal/NativePtr.kt b/runtime/src/main/kotlin/kotlin/native/internal/NativePtr.kt index 72234661e67..5bc5c975d88 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/NativePtr.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/NativePtr.kt @@ -7,16 +7,19 @@ package kotlin.native.internal -@Intrinsic external fun getNativeNullPtr(): NativePtr +@TypedIntrinsic(IntrinsicType.GET_NATIVE_NULL_PTR) +external fun getNativeNullPtr(): NativePtr class NativePtr @PublishedApi internal constructor(private val value: NonNullNativePtr?) { companion object { val NULL = getNativeNullPtr() } - @Intrinsic external operator fun plus(offset: Long): NativePtr + @TypedIntrinsic(IntrinsicType.NATIVE_PTR_PLUS_LONG) + external operator fun plus(offset: Long): NativePtr - @Intrinsic external fun toLong(): Long + @TypedIntrinsic(IntrinsicType.NATIVE_PTR_TO_LONG) + external fun toLong(): Long override fun equals(other: Any?) = (other is NativePtr) && kotlin.native.internal.areEqualByValue(this, other) diff --git a/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt b/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt index 7515fce620e..e905f6a7597 100644 --- a/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt +++ b/runtime/src/main/kotlin/kotlin/native/internal/RuntimeUtils.kt @@ -117,7 +117,7 @@ fun > valuesForEnum(values: Array): Array { return result as Array } -@Intrinsic +@TypedIntrinsic(IntrinsicType.CREATE_UNINITIALIZED_INSTANCE) internal external fun createUninitializedInstance(): T @Intrinsic @@ -150,7 +150,7 @@ fun KonanObjectToUtf8Array(value: Any?): ByteArray { return string.toUtf8() } -@Intrinsic +@TypedIntrinsic(IntrinsicType.LIST_OF_INTERNAL) @PublishedApi internal fun listOfInternal(vararg elements: T): List { val result = ArrayList(elements.size) diff --git a/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/SearchPathResolver.kt b/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/SearchPathResolver.kt index 1b528db16bf..0581220ff72 100644 --- a/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/SearchPathResolver.kt +++ b/shared/src/library/kotlin/org/jetbrains/kotlin/konan/library/SearchPathResolver.kt @@ -203,7 +203,7 @@ internal fun SearchPathResolverWithTarget.libraryMatch(candidate: KonanLibraryIm val candidateAbiVersion = candidate.versions.abiVersion val candidateLibraryVersion = candidate.versions.libraryVersion - if (resolverTarget != null && !candidate.targetList.contains(resolverTarget.visibleName)) { + if (!candidate.targetList.contains(resolverTarget.visibleName)) { logger("skipping $candidatePath. The target doesn't match. Expected '$resolverTarget', found ${candidate.targetList}") return false }