From 90577d440af4e17b19d83680377d4b460fd296bb Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Mon, 16 Jan 2017 12:22:27 +0300 Subject: [PATCH] Improve object arrays support. (#182) Also fix the way how symbol names are being generated. Before arrays2.kt was not linking. --- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 2 +- .../kotlin/backend/konan/llvm/NameUtils.kt | 2 +- backend.native/tests/build.gradle | 9 ++ .../tests/codegen/basics/array_to_any.kt | 2 +- .../tests/runtime/collections/array0.kt | 2 +- .../tests/runtime/collections/array2.kt | 7 ++ .../collections/moderately_large_array1.kt | 11 +++ runtime/src/main/kotlin/kotlin/Array.kt | 10 ++- runtime/src/main/kotlin/kotlin/Arrays.kt | 86 +++++++++++++++++++ .../kotlin/kotlin/collections/ArrayUtil.kt | 16 ++-- 10 files changed, 133 insertions(+), 14 deletions(-) create mode 100644 backend.native/tests/runtime/collections/array2.kt create mode 100644 backend.native/tests/runtime/collections/moderately_large_array1.kt 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 f199b2f30d4..dc57e601d18 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 @@ -1671,7 +1671,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid val typeInfo = codegen.typeInfoValue(containingClass) val allocHint = Int32(1).llvm val thisValue = if (containingClass.isArray) { - assert(args.size == 1 && args[0].type == int32Type) + assert(args.size >= 1 && args[0].type == int32Type) val allocArrayInstanceArgs = listOf(typeInfo, allocHint, args[0]) call(context.llvm.allocArrayFunction, allocArrayInstanceArgs) } else { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/NameUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/NameUtils.kt index d2418b967f6..700dc304de1 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/NameUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/NameUtils.kt @@ -21,7 +21,7 @@ private val exportForCppRuntimeAnnotation = FqName("konan.internal.ExportForCppR fun typeToHashString(type: KotlinType): String { if (TypeUtils.isTypeParameter(type)) return "GENERIC" - var hashString = type.constructor.toString() + var hashString = TypeUtils.getClassDescriptor(type)!!.fqNameSafe.asString() if (!type.arguments.isEmpty()) { hashString += "<${type.arguments.map { typeToHashString(it.type) diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index 668f9a0bf8c..b49212a7615 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -301,6 +301,11 @@ task array1(type: RunKonanTest) { source = "runtime/collections/array1.kt" } +task array2(type: RunKonanTest) { + goldValue = "0\n2\n4\n6\n8\n40\n" + source = "runtime/collections/array2.kt" +} + task if_else(type: RunKonanTest) { source = "codegen/branching/if_else.kt" } @@ -536,6 +541,10 @@ task moderately_large_array(type: RunKonanTest) { source = "runtime/collections/moderately_large_array.kt" } +task moderately_large_array1(type: RunKonanTest) { + goldValue = "-45392\n" + source = "runtime/collections/moderately_large_array1.kt" +} task string_builder0(type: RunKonanTest) { goldValue = "OK\n" diff --git a/backend.native/tests/codegen/basics/array_to_any.kt b/backend.native/tests/codegen/basics/array_to_any.kt index 43bf2de6cfc..e56ab313351 100644 --- a/backend.native/tests/codegen/basics/array_to_any.kt +++ b/backend.native/tests/codegen/basics/array_to_any.kt @@ -3,5 +3,5 @@ fun main(args: Array) { } fun foo(): Any { - return Array(0) + return Array(0, { i -> null }) } \ No newline at end of file diff --git a/backend.native/tests/runtime/collections/array0.kt b/backend.native/tests/runtime/collections/array0.kt index b555959cbcd..01fa4aeded9 100644 --- a/backend.native/tests/runtime/collections/array0.kt +++ b/backend.native/tests/runtime/collections/array0.kt @@ -24,6 +24,6 @@ fun main(args : Array) { val booleanArray = BooleanArray(12) println(booleanArray.size.toString()) - val stringArray = Array(13) + val stringArray = Array(13, { i -> ""}) println(stringArray.size.toString()) } \ No newline at end of file diff --git a/backend.native/tests/runtime/collections/array2.kt b/backend.native/tests/runtime/collections/array2.kt new file mode 100644 index 00000000000..edd2d3e1923 --- /dev/null +++ b/backend.native/tests/runtime/collections/array2.kt @@ -0,0 +1,7 @@ +fun main(args : Array) { + val byteArray = Array(5, { i -> (i * 2).toByte() }) + byteArray.map { println(it) } + + val intArray = Array(5, { i -> i * 4 }) + println(intArray.sum()) +} \ No newline at end of file diff --git a/backend.native/tests/runtime/collections/moderately_large_array1.kt b/backend.native/tests/runtime/collections/moderately_large_array1.kt new file mode 100644 index 00000000000..06db38faf13 --- /dev/null +++ b/backend.native/tests/runtime/collections/moderately_large_array1.kt @@ -0,0 +1,11 @@ +fun main(args: Array) { + val a = Array(100000, { i -> i.toByte()}) + + var sum = 0 + for (b in a) { + sum += b + } + + println(sum) +} + diff --git a/runtime/src/main/kotlin/kotlin/Array.kt b/runtime/src/main/kotlin/kotlin/Array.kt index 0e85653c63e..6bb2387e3fe 100644 --- a/runtime/src/main/kotlin/kotlin/Array.kt +++ b/runtime/src/main/kotlin/kotlin/Array.kt @@ -3,9 +3,15 @@ package kotlin // TODO: remove that, as RTTI shall be per instantiation. @ExportTypeInfo("theArrayTypeInfo") public final class Array : Cloneable { - // TODO: actual constructor has initializer parameter, implement it once lambdas are implemented. // Constructors are handled with compiler magic. - public constructor(@Suppress("UNUSED_PARAMETER") size: Int) {} + public constructor(size: Int, init: (Int) -> T) { + var index = 0 + while (index < size) { + this[index] = init(index) + index++ + } + } + internal constructor(@Suppress("UNUSED_PARAMETER") size: Int) {} public val size: Int get() = getArrayLength() diff --git a/runtime/src/main/kotlin/kotlin/Arrays.kt b/runtime/src/main/kotlin/kotlin/Arrays.kt index 5134c411f75..78e5f6c0bab 100644 --- a/runtime/src/main/kotlin/kotlin/Arrays.kt +++ b/runtime/src/main/kotlin/kotlin/Arrays.kt @@ -507,3 +507,89 @@ public val Array.indices: IntRange */ public val Array.lastIndex: Int get() = size - 1 + +/** + * Applies the given [transform] function to each element of the original array + * and appends the results to the given [destination]. + */ +public inline fun > Array.mapTo(destination: C, transform: (T) -> R): C { + for (item in this) + destination.add(transform(item)) + return destination +} + +/** + * Returns a list containing the results of applying the given [transform] function + * to each element in the original array. + */ +public inline fun Array.map(transform: (T) -> R): List { + return mapTo(ArrayList(size), transform) +} + +/** + * Returns the sum of all elements in the array. + */ +public fun Array.sum(): Int { + var sum: Int = 0 + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the array. + */ +public fun Array.sum(): Int { + var sum: Int = 0 + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the array. + */ +public fun Array.sum(): Int { + var sum: Int = 0 + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the array. + */ +public fun Array.sum(): Long { + var sum: Long = 0L + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the array. + */ +public fun Array.sum(): Float { + var sum: Float = 0.0f + for (element in this) { + sum += element + } + return sum +} + +/** + * Returns the sum of all elements in the array. + */ +public fun Array.sum(): Double { + var sum: Double = 0.0 + for (element in this) { + sum += element + } + return sum +} + + diff --git a/runtime/src/main/kotlin/kotlin/collections/ArrayUtil.kt b/runtime/src/main/kotlin/kotlin/collections/ArrayUtil.kt index 4ce36677c97..b2faaa21d2c 100644 --- a/runtime/src/main/kotlin/kotlin/collections/ArrayUtil.kt +++ b/runtime/src/main/kotlin/kotlin/collections/ArrayUtil.kt @@ -1,13 +1,13 @@ package kotlin.collections /** - * Returns an array of objects of the given type with the given [size], initialized with **lateinit** _uninitialized_ values. + * Returns an array of objects of the given type with the given [size], initialized with _uninitialized_ values. * Attempts to read _uninitialized_ values from this array work in implementation-dependent manner, * either throwing exception or returning some kind of implementation-specific default value. */ -fun arrayOfUninitializedElements(size: Int): Array { - // return (if (size == 0) emptyArray else Array(size)) as Array - return Array(size) +internal fun arrayOfUninitializedElements(size: Int): Array { + // TODO: special case for size == 0? + return Array(size) } /** @@ -16,7 +16,7 @@ fun arrayOfUninitializedElements(size: Int): Array { * either throwing exception or returning some kind of implementation-specific default value. */ fun Array.copyOfUninitializedElements(newSize: Int): Array { - val result = Array(newSize) + val result = arrayOfUninitializedElements(newSize) this.copyRangeTo(result, 0, if (newSize > this.size) this.size else newSize, 0) return result } @@ -33,7 +33,7 @@ fun IntArray.copyOfUninitializedElements(newSize: Int): IntArray { * Attempts to read _uninitialized_ value work in implementation-dependent manner, * either throwing exception or returning some kind of implementation-specific default value. */ -fun Array.resetAt(index: Int) { +internal fun Array.resetAt(index: Int) { (@Suppress("UNCHECKED_CAST")(this as Array))[index] = null } @@ -50,11 +50,11 @@ external private fun fillImpl(array: IntArray, fromIndex: Int, toIndex: Int, val * Attempts to read _uninitialized_ values work in implementation-dependent manner, * either throwing exception or returning some kind of implementation-specific default value. */ -fun Array.resetRange(fromIndex: Int, toIndex: Int) { +internal fun Array.resetRange(fromIndex: Int, toIndex: Int) { fillImpl(@Suppress("UNCHECKED_CAST") (this as Array), fromIndex, toIndex, null) } -fun IntArray.fill(fromIndex: Int, toIndex: Int, value: Int) { +internal fun IntArray.fill(fromIndex: Int, toIndex: Int, value: Int) { fillImpl(this, fromIndex, toIndex, value) }