diff --git a/runtime/src/main/cpp/Memory.h b/runtime/src/main/cpp/Memory.h index 60f6a638a61..e58ac3e6354 100644 --- a/runtime/src/main/cpp/Memory.h +++ b/runtime/src/main/cpp/Memory.h @@ -64,15 +64,6 @@ inline void* AddressOfElementAt(ArrayHeader* obj, int32_t index) { return reinterpret_cast(obj + 1) - obj->type_info_->instanceSize_ * index; } -// Optimized version not accessing type info. -inline uint8_t* ByteArrayAddressOfElementAt(ArrayHeader* obj, int32_t index) { - return reinterpret_cast(obj + 1) + index; -} - -inline const uint8_t* ByteArrayAddressOfElementAt(const ArrayHeader* obj, int32_t index) { - return reinterpret_cast(obj + 1) + index; -} - inline uint32_t ArraySizeBytes(const ArrayHeader* obj) { // Instance size is negative. return -obj->type_info_->instanceSize_ * obj->count_; diff --git a/runtime/src/main/cpp/Natives.cpp b/runtime/src/main/cpp/Natives.cpp index be9f220610e..27ba22acb0b 100644 --- a/runtime/src/main/cpp/Natives.cpp +++ b/runtime/src/main/cpp/Natives.cpp @@ -9,21 +9,97 @@ extern "C" { // TODO: those must be compiler intrinsics afterwards. -KByte Kotlin_ByteArray_get(const ArrayHeader* obj, int32_t index) { +KByte Kotlin_ByteArray_get(const ArrayHeader* obj, KInt index) { if (static_cast(index) >= obj->count_) { ThrowArrayIndexOutOfBoundsException(); } return *ByteArrayAddressOfElementAt(obj, index); } -void Kotlin_ByteArray_set(ArrayHeader* obj, int32_t index, KByte value) { +void Kotlin_ByteArray_set(ArrayHeader* obj, KInt index, KByte value) { if (static_cast(index) >= obj->count_) { ThrowArrayIndexOutOfBoundsException(); } *ByteArrayAddressOfElementAt(obj, index) = value; } -KChar Kotlin_String_get(const ArrayHeader* obj, int32_t index) { +ArrayHeader* Kotlin_ByteArray_clone(const ArrayHeader* array) { + uint32_t length = ArraySizeBytes(array); + ArrayHeader* result = ArrayContainer(theByteArrayTypeInfo, length).GetPlace(); + memcpy( + ByteArrayAddressOfElementAt(result, 0), + ByteArrayAddressOfElementAt(array, 0), + length); + return result; +} + +KInt Kotlin_ByteArray_getArrayLength(const ArrayHeader* array) { + return array->count_; +} + +KChar Kotlin_CharArray_get(const ArrayHeader* obj, KInt index) { + if (static_cast(index) >= obj->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + return *CharArrayAddressOfElementAt(obj, index); +} + +void Kotlin_CharArray_set(ArrayHeader* obj, KInt index, KChar value) { + if (static_cast(index) >= obj->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + *CharArrayAddressOfElementAt(obj, index) = value; +} + +ArrayHeader* Kotlin_CharArray_clone(const ArrayHeader* array) { + uint32_t length = ArraySizeBytes(array); + ArrayHeader* result = ArrayContainer(theCharArrayTypeInfo, length).GetPlace(); + memcpy( + CharArrayAddressOfElementAt(result, 0), + CharArrayAddressOfElementAt(array, 0), + length); + return result; +} + +KInt Kotlin_CharArray_getArrayLength(const ArrayHeader* array) { + return array->count_; +} + +KInt Kotlin_IntArray_get(const ArrayHeader* obj, KInt index) { + if (static_cast(index) >= obj->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + return *IntArrayAddressOfElementAt(obj, index); +} + +void Kotlin_IntArray_set(ArrayHeader* obj, KInt index, KInt value) { + if (static_cast(index) >= obj->count_) { + ThrowArrayIndexOutOfBoundsException(); + } + *IntArrayAddressOfElementAt(obj, index) = value; +} + +ArrayHeader* Kotlin_IntArray_clone(const ArrayHeader* array) { + uint32_t length = ArraySizeBytes(array); + ArrayHeader* result = ArrayContainer(theIntArrayTypeInfo, length).GetPlace(); + memcpy( + IntArrayAddressOfElementAt(result, 0), + IntArrayAddressOfElementAt(array, 0), + length); + return result; +} + +KInt Kotlin_IntArray_getArrayLength(const ArrayHeader* array) { + return array->count_; +} + +KInt Kotlin_String_compareTo(const ArrayHeader* obj, const ArrayHeader* other) { + return memcmp(ByteArrayAddressOfElementAt(obj, 0), + ByteArrayAddressOfElementAt(other, 0), + obj->count_ < other->count_ ? obj->count_ : other->count_); +} + +KChar Kotlin_String_get(const ArrayHeader* obj, KInt index) { // TODO: support full UTF-8. if (static_cast(index) >= obj->count_) { ThrowArrayIndexOutOfBoundsException(); @@ -31,8 +107,12 @@ KChar Kotlin_String_get(const ArrayHeader* obj, int32_t index) { return *ByteArrayAddressOfElementAt(obj, index); } +KInt Kotlin_String_getStringLength(const ArrayHeader* array) { + return array->count_; +} + ArrayHeader* Kotlin_String_fromUtf8Array(const ArrayHeader* array) { - RuntimeAssert(array->type_info_ == theByteArrayTypeInfo, "Must get a byte array"); + RuntimeAssert(array->type_info_ == theByteArrayTypeInfo, "Must use a byte array"); uint32_t length = ArraySizeBytes(array); // TODO: support full UTF-8. ArrayHeader* result = ArrayContainer(theStringTypeInfo, length).GetPlace(); @@ -43,4 +123,23 @@ ArrayHeader* Kotlin_String_fromUtf8Array(const ArrayHeader* array) { return result; } +ArrayHeader* Kotlin_String_plusImpl( + const ArrayHeader* obj, const ArrayHeader* other) { + // TODO: support UTF-8 + RuntimeAssert(obj->type_info_ == theStringTypeInfo, "Must be a string"); + RuntimeAssert(other->type_info_ == theStringTypeInfo, "Must be a string"); + uint32_t result_length = obj->count_ + other->count_; + ArrayHeader* result = ArrayContainer( + theStringTypeInfo, result_length).GetPlace(); + memcpy( + ByteArrayAddressOfElementAt(result, 0), + ByteArrayAddressOfElementAt(obj, 0), + obj->count_); + memcpy( + ByteArrayAddressOfElementAt(result, obj->count_), + ByteArrayAddressOfElementAt(other, 0), + other->count_); + return result; +} + } diff --git a/runtime/src/main/cpp/Natives.h b/runtime/src/main/cpp/Natives.h index 4c405a827a2..89c122b440f 100644 --- a/runtime/src/main/cpp/Natives.h +++ b/runtime/src/main/cpp/Natives.h @@ -4,18 +4,63 @@ #include "Memory.h" #include "Types.h" -typedef uint16_t KChar; typedef uint8_t KByte; +typedef uint16_t KChar; +// Note that it is signed. +typedef int32_t KInt; + +// Optimized versions not accessing type info. +inline KByte* ByteArrayAddressOfElementAt(ArrayHeader* obj, KInt index) { + return reinterpret_cast(obj + 1) + index; +} + +inline const KByte* ByteArrayAddressOfElementAt( + const ArrayHeader* obj, KInt index) { + return reinterpret_cast(obj + 1) + index; +} + +inline KChar* CharArrayAddressOfElementAt(ArrayHeader* obj, KInt index) { + return reinterpret_cast(obj + 1) + index; +} + +inline const KChar* CharArrayAddressOfElementAt( + const ArrayHeader* obj, KInt index) { + return reinterpret_cast(obj + 1) + index; +} + +inline KInt* IntArrayAddressOfElementAt(ArrayHeader* obj, KInt index) { + return reinterpret_cast(obj + 1) + index; +} + +inline const KInt* IntArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) { + return reinterpret_cast(obj + 1) + index; +} #ifdef __cplusplus extern "C" { #endif // TODO: those must be compiler intrinsics afterwards. -KByte Kotlin_ByteArray_get(const ArrayHeader* obj, int32_t index); -void Kotlin_ByteArray_set(ArrayHeader* obj, int32_t index, KByte value); -KChar Kotlin_String_get(const ArrayHeader* obj, int32_t index); +ArrayHeader* Kotlin_ByteArray_clone(const ArrayHeader* obj); +KByte Kotlin_ByteArray_get(const ArrayHeader* obj, KInt index); +void Kotlin_ByteArray_set(ArrayHeader* obj, KInt index, KByte value); +KInt Kotlin_ByteArray_getArrayLength(const ArrayHeader* obj); + +ArrayHeader* Kotlin_CharArray_clone(const ArrayHeader* obj); +KChar Kotlin_CharArray_get(const ArrayHeader* obj, KInt index); +void Kotlin_CharArray_set(ArrayHeader* obj, KInt index, KChar value); +KInt Kotlin_CharArray_getArrayLength(const ArrayHeader* obj); + +ArrayHeader* Kotlin_IntArray_clone(const ArrayHeader* obj); +KInt Kotlin_IntArray_get(const ArrayHeader* obj, KInt index); +void Kotlin_IntArray_set(ArrayHeader* obj, KInt index, KInt value); +KInt Kotlin_IntArray_getArrayLength(const ArrayHeader* obj); + +KInt Kotlin_String_compareTo(const ArrayHeader* obj, const ArrayHeader* other); +KChar Kotlin_String_get(const ArrayHeader* obj, KInt index); ArrayHeader* Kotlin_String_fromUtf8Array(const ArrayHeader* array); +ArrayHeader* Kotlin_String_plusImpl(const ArrayHeader* obj, const ArrayHeader* other); +KInt Kotlin_String_getStringLength(const ArrayHeader* obj); #ifdef __cplusplus } diff --git a/runtime/src/main/cpp/TypeInfo.h b/runtime/src/main/cpp/TypeInfo.h index 52f1ad9076d..157db7e5d49 100644 --- a/runtime/src/main/cpp/TypeInfo.h +++ b/runtime/src/main/cpp/TypeInfo.h @@ -29,7 +29,7 @@ struct TypeInfo { const TypeInfo* superType_; const int* objOffsets_; int objOffsetsCount_; - TypeInfo* const* implementedInterfaces_; + const TypeInfo* const* implementedInterfaces_; int implementedInterfacesCount_; void* const* vtable_; // TODO: place vtable at the end of TypeInfo to eliminate the indirection const MethodTableRecord* openMethods_; diff --git a/runtime/src/main/cpp/Types.cpp b/runtime/src/main/cpp/Types.cpp index 9f0b8898183..646c5706848 100644 --- a/runtime/src/main/cpp/Types.cpp +++ b/runtime/src/main/cpp/Types.cpp @@ -1,3 +1,4 @@ +#include "Natives.h" #include "Types.h" namespace { @@ -20,22 +21,111 @@ const TypeInfo implAnyTypeInfo = { 0 // fieldsCount_ }; +const TypeInfo implCloneableTypeInfo = { + // kotlin.Cloneable + { 0x2d, 0x4b, 0x3d, 0x2f, 0x69, 0x0d, 0x1c, 0xb5, 0x6e, 0xc6, + 0x67, 0xa7, 0x24, 0x57, 0x35, 0x98, 0xa4, 0x23, 0x0b, 0xc5 }, + 0, // instanceSize_ + nullptr, // superType_ + nullptr, // objOffsets + 0, // objOffsetsCount_ + nullptr, // implementedInterfaces_ + 0, // implementedInterfacesCount_ + nullptr, // vtable_ + nullptr, // openMethods_ + 0, // openMethodsCount_ + nullptr, // fields_ + 0 // fieldsCount_ +}; + +void* const implByteArrayTypeInfoVTbl[] = { + reinterpret_cast(Kotlin_ByteArray_clone) +}; + +const MethodTableRecord implByteArrayTypeInfoMethods[] = { + // TODO: fill in hash. + { 0, reinterpret_cast(Kotlin_ByteArray_clone) } +}; + +const TypeInfo* implByteArrayTypeInfoIfaces[] = { + &implCloneableTypeInfo +}; + const TypeInfo implByteArrayTypeInfo = { // kotlin.ByteArray { 0x9e, 0x23, 0xa6, 0xa6, 0x91, 0x9b, 0x6b, 0x0a, 0x00, 0xc5, 0x35, 0xe8, 0xd9, 0xd1, 0xa3, 0xb6, 0xc5, 0xc6, 0xd7, 0x65 }, - -1, // instanceSize_, array of 1 byte elements - &implAnyTypeInfo, // superType_ - nullptr, // objOffsets - 0, // objOffsetsCount_ - // TODO: actually, shall implement cloneable, it seems. - nullptr, // implementedInterfaces_ - 0, // implementedInterfacesCount_ - nullptr, // vtable_ - nullptr, // openMethods_ - 0, // openMethodsCount_ - nullptr, // fields_ - 0 // fieldsCount_ + -1, // instanceSize_, array of 1 byte elements + &implAnyTypeInfo, // superType_ + nullptr, // objOffsets + 0, // objOffsetsCount_ + implByteArrayTypeInfoIfaces, // implementedInterfaces_ + 1, // implementedInterfacesCount_ + implByteArrayTypeInfoVTbl, // vtable_ + implByteArrayTypeInfoMethods, // openMethods_ + 1, // openMethodsCount_ + nullptr, // fields_ + 0 // fieldsCount_ +}; + +void* const implCharArrayTypeInfoVTbl[] = { + reinterpret_cast(Kotlin_CharArray_clone) +}; + +const MethodTableRecord implCharArrayTypeInfoMethods[] = { + // TODO: fill in hash. + { 0, reinterpret_cast(Kotlin_CharArray_clone) } +}; + +const TypeInfo* implCharArrayTypeInfoIfaces[] = { + &implCloneableTypeInfo +}; + +const TypeInfo implCharArrayTypeInfo = { + // kotlin.CharArray + { 0x70, 0x88, 0xd4, 0x20, 0x91, 0x6e, 0x25, 0x80, 0x33, 0x64, + 0x5a, 0x8d, 0x56, 0xaf, 0x99, 0x19, 0x14, 0xde, 0x5b, 0x71 }, + -2, // instanceSize_, array of 2 byte elements + &implAnyTypeInfo, // superType_ + nullptr, // objOffsets + 0, // objOffsetsCount_ + implCharArrayTypeInfoIfaces, // implementedInterfaces_ + 1, // implementedInterfacesCount_ + implCharArrayTypeInfoVTbl, // vtable_ + implCharArrayTypeInfoMethods, // openMethods_ + 1, // openMethodsCount_ + nullptr, // fields_ + 0 // fieldsCount_ +}; + +void* const implIntArrayTypeInfoVTbl[] = { + reinterpret_cast(Kotlin_IntArray_clone) +}; + +const MethodTableRecord implIntArrayTypeInfoMethods[] = { + // TODO: fill in hash. + { 0, reinterpret_cast(Kotlin_IntArray_clone) } +}; + +const TypeInfo* implIntArrayTypeInfoIfaces[] = { + &implCloneableTypeInfo +}; + +const TypeInfo implIntArrayTypeInfo = { + // kotlin.IntArray + { 0xdd, 0x69, 0x38, 0x31, 0x3e, 0x03, 0xc6, 0xfd, 0x88, 0x8f, + 0x1c, 0x83, 0x18, 0x06, 0xcc, 0xcb, 0x8d, 0x71, 0xd1, 0x4c }, + -4, // instanceSize_, array of 4 byte elements + &implAnyTypeInfo, // superType_ + nullptr, // objOffsets + 0, // objOffsetsCount_ + implIntArrayTypeInfoIfaces, // implementedInterfaces_ + 1, // implementedInterfacesCount_ + implIntArrayTypeInfoVTbl, // vtable_ + implIntArrayTypeInfoMethods, // openMethods_ + 1, // openMethodsCount_ + nullptr, // fields_ + 0 // fieldsCount_ }; const TypeInfo implStringTypeInfo = { @@ -61,7 +151,10 @@ extern "C" { #endif const TypeInfo* theAnyTypeInfo = &implAnyTypeInfo; +const TypeInfo* theCloneableTypeInfo = &implCloneableTypeInfo; const TypeInfo* theByteArrayTypeInfo = &implByteArrayTypeInfo; +const TypeInfo* theCharArrayTypeInfo = &implCharArrayTypeInfo; +const TypeInfo* theIntArrayTypeInfo = &implIntArrayTypeInfo; const TypeInfo* theStringTypeInfo = &implStringTypeInfo; #ifdef __cplusplus diff --git a/runtime/src/main/cpp/Types.h b/runtime/src/main/cpp/Types.h index d0226a505c5..c4143d02292 100644 --- a/runtime/src/main/cpp/Types.h +++ b/runtime/src/main/cpp/Types.h @@ -8,7 +8,10 @@ extern "C" { #endif extern const TypeInfo* theAnyTypeInfo; +extern const TypeInfo* theCloneableTypeInfo; extern const TypeInfo* theByteArrayTypeInfo; +extern const TypeInfo* theCharArrayTypeInfo; +extern const TypeInfo* theIntArrayTypeInfo; extern const TypeInfo* theStringTypeInfo; #ifdef __cplusplus diff --git a/runtime/src/main/kotlin/kotlin_native/String.kt b/runtime/src/main/kotlin/kotlin_native/String.kt index 9f0c08b885e..488bbd8bbde 100644 --- a/runtime/src/main/kotlin/kotlin_native/String.kt +++ b/runtime/src/main/kotlin/kotlin_native/String.kt @@ -1,28 +1,82 @@ package kotlin_native -class ByteArray(size: Int) { - public val size: Int - - external public operator fun get(index: Int): Byte - - external public operator fun set(index: Int, value: Byte): Unit +public interface Cloneable { + public fun clone(): Any } +class ByteArray(size: Int) : Cloneable { + public val size: Int + get() = getArrayLength() + + @SymbolName("Kotlin_ByteArray_get") + external public operator fun get(index: Int): Byte + + @SymbolName("Kotlin_ByteArray_set") + external public operator fun set(index: Int, value: Byte): Unit + + @SymbolName("Kotlin_ByteArray_clone") + external public override fun clone(): Any + + @SymbolName("Kotlin_ByteArray_getArrayLength") + external private fun getArrayLength(): Int +} + +class CharArray(size: Int) : Cloneable { + public val size: Int + get() = getArrayLength() + + @SymbolName("Kotlin_CharArray_get") + external public operator fun get(index: Int): Char + + @SymbolName("Kotlin_CharArray_set") + external public operator fun set(index: Int, value: Char): Unit + + @SymbolName("Kotlin_CharArray_clone") + external public override fun clone(): Any + + @SymbolName("Kotlin_CharArray_getArrayLength") + external private fun getArrayLength(): Int +} + +class IntArray(size: Int) : Cloneable { + public val size: Int + get() = getArrayLength() + + @SymbolName("Kotlin_IntArray_get") + external public operator fun get(index: Int): Char + + @SymbolName("Kotlin_IntArray_set") + external public operator fun set(index: Int, value: Char): Unit + + @SymbolName("Kotlin_IntArray_clone") + external public override fun clone(): Any + + @SymbolName("Kotlin_IntArray_getArrayLength") + external private fun getArrayLength(): Int +} + +@SymbolName("Kotlin_String_fromUtf8Array") +external fun fromUtf8Array(array: ByteArray) : String + class String { - companion object { - external fun fromUtf8Array(ByteArray: array) : String + public operator fun plus(other: Any?): String { + return plusImpl(other.toString()) } - external public operator fun plus(other: Any?): String public val length: Int get() = getStringLength() // Can be O(N). + @SymbolName("Kotlin_String_get") external public fun get(index: Int): Char // external public fun subSequence(startIndex: Int, endIndex: Int): CharSequence - + @SymbolName("Kotlin_String_compareTo") external public fun compareTo(other: String): Int + @SymbolName("Kotlin_String_getStringLength") external private fun getStringLength(): Int + + @SymbolName("Kotlin_String_plusImpl") + external private fun plusImpl(other:Any): String } \ No newline at end of file diff --git a/runtime/src/main/kotlin/kotlin_native/annotations.kt b/runtime/src/main/kotlin/kotlin_native/annotations.kt index de835209772..28bc223294a 100644 --- a/runtime/src/main/kotlin/kotlin_native/annotations.kt +++ b/runtime/src/main/kotlin/kotlin_native/annotations.kt @@ -8,4 +8,4 @@ package kotlin_native */ @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.BINARY) -annotation class SymbolName(val name: String) +annotation class SymbolName(val name: kotlin.String)