diff --git a/backend.native/tests/build.gradle b/backend.native/tests/build.gradle index f0f4d511cdd..8bed9c0be3f 100644 --- a/backend.native/tests/build.gradle +++ b/backend.native/tests/build.gradle @@ -198,6 +198,11 @@ task tostring0(type: RunKonanTest) { source = "runtime/basic/tostring0.kt" } +task tostring1(type: RunKonanTest) { + goldValue = "ello\n" + source = "runtime/basic/tostring1.kt" +} + task array0(type: RunKonanTest) { goldValue = "5\n6\n7\n8\n9\n10\n11\n12\n13\n" source = "runtime/basic/array0.kt" diff --git a/backend.native/tests/runtime/basic/tostring1.kt b/backend.native/tests/runtime/basic/tostring1.kt new file mode 100644 index 00000000000..ac114d515ab --- /dev/null +++ b/backend.native/tests/runtime/basic/tostring1.kt @@ -0,0 +1,4 @@ +fun main(args : Array) { + val hello = "Hello world" + println(hello.subSequence(1, 5).toString()) +} \ No newline at end of file diff --git a/runtime/src/main/cpp/Natives.cpp b/runtime/src/main/cpp/Natives.cpp index 12ab466bb95..5962aeaea0c 100644 --- a/runtime/src/main/cpp/Natives.cpp +++ b/runtime/src/main/cpp/Natives.cpp @@ -11,6 +11,9 @@ extern "C" { +// TODO: remove, once can generate empty string constant in compile time. +KString theEmptyString = nullptr; + // Any.kt KBoolean Kotlin_Any_equals(KConstRef thiz, KConstRef other) { return thiz == other; @@ -123,9 +126,21 @@ KInt Kotlin_String_hashCode(KString thiz) { return CityHash64(ByteArrayAddressOfElementAt(thiz, 0), thiz->count_); } -KRef Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex) { - RuntimeAssert(false, "Unsupported operation"); - return nullptr; +KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex) { + if (startIndex < 0 || endIndex >= thiz->count_ || startIndex > endIndex) { + // TODO: is it correct exception? + ThrowArrayIndexOutOfBoundsException(); + } + if (startIndex == endIndex) { + return theEmptyString; + } + // TODO: support UTF-8. + KInt length = endIndex - startIndex; + ArrayHeader* result = ArrayContainer(theStringTypeInfo, length).GetPlace(); + memcpy(ByteArrayAddressOfElementAt(result, 0), + ByteArrayAddressOfElementAt(thiz, startIndex), + length); + return result; } } // extern "C" diff --git a/runtime/src/main/cpp/Natives.h b/runtime/src/main/cpp/Natives.h index a84b8bc4215..3bb0d652757 100644 --- a/runtime/src/main/cpp/Natives.h +++ b/runtime/src/main/cpp/Natives.h @@ -51,6 +51,8 @@ inline const KRef* ArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) { extern "C" { #endif +extern KString theEmptyString; + // Any.kt KBoolean Kotlin_Any_equals(KConstRef thiz, KConstRef other); KInt Kotlin_Any_hashCode(KConstRef thiz); @@ -95,7 +97,7 @@ KChar Kotlin_String_get(KString thiz, KInt index); KString Kotlin_String_fromUtf8Array(const ArrayHeader* array); KString Kotlin_String_plusImpl(KString thiz, KString other); KInt Kotlin_String_getStringLength(KString thiz); -KRef Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex); +KString Kotlin_String_subSequence(KString thiz, KInt startIndex, KInt endIndex); #ifdef __cplusplus } diff --git a/runtime/src/main/kotlin/kotlin/String.kt b/runtime/src/main/kotlin/kotlin/String.kt index 7ac864ab547..058500e61c2 100644 --- a/runtime/src/main/kotlin/kotlin/String.kt +++ b/runtime/src/main/kotlin/kotlin/String.kt @@ -3,6 +3,10 @@ package kotlin @SymbolName("Kotlin_String_fromUtf8Array") external fun fromUtf8Array(array: ByteArray) : String +// TODO: enable, once global variables implemented. +// @SymbolName("theEmptyString") +// val theEmptyString = "" + @ExportTypeInfo("theStringTypeInfo") public final class String : Comparable, CharSequence { @SymbolName("Kotlin_String_hashCode")