diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt index 168a365903f..b755c2ee760 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/descriptors/DescriptorUtils.kt @@ -312,25 +312,13 @@ internal fun DeclarationDescriptor.getMemberScope(): MemberScope { // It is possible to declare "external inline fun", // but it doesn't have much sense for native, // since externals don't have IR bodies. - -// Enforce inlining of some constructors -private val mustInlineFunctions = setOf( - "kotlin.DoubleArray.", - "kotlin.FloatArray.", - "kotlin.ByteArray.", - "kotlin.ShortArray.", - "kotlin.IntArray.", - "kotlin.LongArray.", - "kotlin.CharArray.", - "kotlin.BooleanArray." -) +// Enforce inlining of some constructors. internal val FunctionDescriptor.needsInlining: Boolean get() { - val needs = this.isInline && !this.isExternal - if (valueParameters.size != 2) return needs // Constructor must have two parameters. - if (mustInlineFunctions.contains(fqNameSafe.toString())) return true - return needs + val inlineConstructor = annotations.hasAnnotation(FqName("konan.internal.InlineConstructor")) + if (inlineConstructor) return true + return (this.isInline && !this.isExternal) } internal val FunctionDescriptor.needsSerializedIr: Boolean diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt index ea1f38b752b..f21451fa3d7 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt @@ -40,11 +40,14 @@ import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.impl.* import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.resolve.descriptorUtil.hasDefaultValue import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.TypeSubstitutor +private val inlineConstructor = FqName("konan.internal.InlineConstructor") + //-----------------------------------------------------------------------------// internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() { @@ -99,12 +102,14 @@ private class Inliner(val currentScope: ScopeWithIr, val context: Context) { val copyIrElement = DeepCopyIrTreeWithDescriptors(currentScope.scope.scopeOwner, context) // Create DeepCopy for current scope. val substituteMap = mutableMapOf() + var isInlineConstructor = false //-------------------------------------------------------------------------// fun inline(irCall : IrCall, // Call to be substituted. functionDeclaration: IrFunction): IrReturnableBlockImpl { // Function to substitute. + isInlineConstructor = irCall.descriptor.annotations.hasAnnotation(inlineConstructor) val inlineFunctionBody = inlineFunction(irCall, functionDeclaration) val descriptorSubstitutor = copyIrElement.descriptorSubstitutorForExternalScope currentScope.irElement.transformChildrenVoid(descriptorSubstitutor) // Transform calls to object that might be returned from inline function call. @@ -365,15 +370,15 @@ private class Inliner(val currentScope: ScopeWithIr, val context: Context) { fun generateIrCall(expression: IrDelegatingConstructorCallImpl): IrStatement { - if (!expression.descriptor.fqNameSafe.toString().contains("kotlin.IntArray.")) return expression + if (!isInlineConstructor) return expression val newExpression = IrCallImpl( - startOffset = expression.startOffset, - endOffset = expression.endOffset, - type = expression.descriptor.returnType, - descriptor = expression.descriptor, - typeArguments = expression.typeArguments, - origin = expression.origin + expression.startOffset, + expression.endOffset, + expression.descriptor.returnType, + expression.descriptor, + expression.typeArguments, + expression.origin ).apply { expression.descriptor.valueParameters.forEach { val valueArgument = expression.getValueArgument(it) diff --git a/runtime/src/main/kotlin/konan/internal/Annotations.kt b/runtime/src/main/kotlin/konan/internal/Annotations.kt index 874ac4f2978..157d3768423 100644 --- a/runtime/src/main/kotlin/konan/internal/Annotations.kt +++ b/runtime/src/main/kotlin/konan/internal/Annotations.kt @@ -41,3 +41,11 @@ annotation class Intrinsic @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR, AnnotationTarget.CLASS) @Retention(AnnotationRetention.BINARY) annotation class ExportForCompiler + +/** + * Annotated constructor will be inlined. + */ +@Target(AnnotationTarget.CONSTRUCTOR) +@Retention(AnnotationRetention.BINARY) +annotation class InlineConstructor + diff --git a/runtime/src/main/kotlin/kotlin/Array.kt b/runtime/src/main/kotlin/kotlin/Array.kt index bc092ac20e5..64c967594d1 100644 --- a/runtime/src/main/kotlin/kotlin/Array.kt +++ b/runtime/src/main/kotlin/kotlin/Array.kt @@ -16,12 +16,14 @@ package kotlin import konan.internal.ExportForCompiler +import konan.internal.InlineConstructor // TODO: remove that, as RTTI shall be per instantiation. @ExportTypeInfo("theArrayTypeInfo") public final class Array { // Constructors are handled with compiler magic. - public constructor(size: Int, init: (Int) -> T) { + @InlineConstructor + public constructor(size: Int, init: (Int) -> T): this(size) { var index = 0 while (index < size) { this[index] = init(index) diff --git a/runtime/src/main/kotlin/kotlin/Arrays.kt b/runtime/src/main/kotlin/kotlin/Arrays.kt index 7875f4fc9b2..2b36fcbda61 100644 --- a/runtime/src/main/kotlin/kotlin/Arrays.kt +++ b/runtime/src/main/kotlin/kotlin/Arrays.kt @@ -25,6 +25,7 @@ import kotlin.internal.PureReifiable import kotlin.util.sortArrayComparable import kotlin.util.sortArrayWith import kotlin.util.sortArray +import konan.internal.InlineConstructor // TODO: make all iterator() methods inline. /** @@ -41,6 +42,7 @@ public final class ByteArray { * [init] function. The [init] function returns an array element given its index. */ // TODO: What about inline constructors? + @InlineConstructor public constructor(size: Int, init: (Int) -> Byte): this(size) { for (i in 0..size - 1) { this[i] = init(i) @@ -92,6 +94,7 @@ public final class CharArray { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ + @InlineConstructor public constructor(size: Int, init: (Int) -> Char): this(size) { for (i in 0..size - 1) { this[i] = init(i) @@ -142,6 +145,7 @@ public final class ShortArray { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ + @InlineConstructor public constructor(size: Int, init: (Int) -> Short): this(size) { for (i in 0..size - 1) { this[i] = init(i) @@ -192,6 +196,7 @@ public final class IntArray { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ + @InlineConstructor public constructor(size: Int, init: (Int) -> Int): this(size) { for (i in 0..size - 1) { this[i] = init(i) @@ -242,6 +247,7 @@ public final class LongArray { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ + @InlineConstructor public constructor(size: Int, init: (Int) -> Long): this(size) { for (i in 0..size - 1) { this[i] = init(i) @@ -292,6 +298,7 @@ public final class FloatArray { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ + @InlineConstructor public constructor(size: Int, init: (Int) -> Float): this(size) { for (i in 0..size - 1) { this[i] = init(i) @@ -338,6 +345,7 @@ public final class DoubleArray { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ + @InlineConstructor public constructor(size: Int, init: (Int) -> Double): this(size) { for (i in 0..size - 1) { this[i] = init(i) @@ -384,6 +392,7 @@ public final class BooleanArray { * Creates a new array of the specified [size], where each element is calculated by calling the specified * [init] function. The [init] function returns an array element given its index. */ + @InlineConstructor public constructor(size: Int, init: (Int) -> Boolean): this(size) { for (i in 0..size - 1) { this[i] = init(i)