From 8ce0bddc17ef55d965b86e23d2c6beadb0228e05 Mon Sep 17 00:00:00 2001 From: Nikolay Igotti Date: Wed, 26 Oct 2016 18:37:02 +0300 Subject: [PATCH] More stdlib implementation. (#17) --- runtime/src/main/cpp/Memory.h | 41 +++++++++++++----- runtime/src/main/cpp/Natives.cpp | 34 +++++++++++++-- runtime/src/main/cpp/Natives.h | 43 +++++++++++-------- runtime/src/main/cpp/TypeInfo.h | 1 + runtime/src/main/kotlin/kotlin_native/Any.kt | 13 ++++++ .../src/main/kotlin/kotlin_native/String.kt | 3 ++ 6 files changed, 103 insertions(+), 32 deletions(-) create mode 100644 runtime/src/main/kotlin/kotlin_native/Any.kt diff --git a/runtime/src/main/cpp/Memory.h b/runtime/src/main/cpp/Memory.h index e58ac3e6354..93646898739 100644 --- a/runtime/src/main/cpp/Memory.h +++ b/runtime/src/main/cpp/Memory.h @@ -32,10 +32,37 @@ typedef enum { // Could be made 64-bit for large memory configs. typedef uint32_t container_offset_t; +// Header of all container objects. Contains reference counter. +struct ContainerHeader { + // Reference counter of container. Uses two lower bits of counter for + // container type (for polymorphism in ::Release()). + volatile uint32_t ref_count_; +}; + // Header of every object. struct ObjHeader { const TypeInfo* type_info_; container_offset_t container_offset_negative_; + + const TypeInfo* type_info() const { + // TODO: for moving collectors use meta-objects approach: + // - store tag in lower bit TypeInfo, which marks if meta-object is in place + // - when reading type_info_ check if it is unaligned + // - if it is, pointer points to the MetaObject + // - otherwise this is direct pointer to TypeInfo + // Meta-object allows storing additional data associated with some objects, + // such as stable hash code. + return type_info_; + } + + void set_type_info(const TypeInfo* type_info) { + type_info_ = type_info; + } + + ContainerHeader* container() const { + return reinterpret_cast( + reinterpret_cast(this) - container_offset_negative_); + } }; // Header of value type array objects. @@ -44,13 +71,6 @@ struct ArrayHeader : public ObjHeader { uint32_t count_; }; -// Header of all container objects. Contains reference counter. -struct ContainerHeader { - // Reference counter of container. Uses two lower bits of counter for - // container type (for polymorphism in ::Release()). - volatile uint32_t ref_count_; -}; - struct ArenaContainerHeader : public ContainerHeader { // Current allocation limit. uint8_t* current_; @@ -61,12 +81,13 @@ struct ArenaContainerHeader : public ContainerHeader { inline void* AddressOfElementAt(ArrayHeader* obj, int32_t index) { // Instance size is negative. - return reinterpret_cast(obj + 1) - obj->type_info_->instanceSize_ * index; + return reinterpret_cast(obj + 1) - + obj->type_info()->instanceSize_ * index; } inline uint32_t ArraySizeBytes(const ArrayHeader* obj) { // Instance size is negative. - return -obj->type_info_->instanceSize_ * obj->count_; + return -obj->type_info()->instanceSize_ * obj->count_; } @@ -135,7 +156,7 @@ class Container { void SetMeta(ObjHeader* obj, const TypeInfo* type_info) { obj->container_offset_negative_ = reinterpret_cast(obj) - reinterpret_cast(header_); - obj->type_info_ = type_info; + obj->set_type_info(type_info); } public: diff --git a/runtime/src/main/cpp/Natives.cpp b/runtime/src/main/cpp/Natives.cpp index f7dc623fadb..e187dc6ec75 100644 --- a/runtime/src/main/cpp/Natives.cpp +++ b/runtime/src/main/cpp/Natives.cpp @@ -9,6 +9,22 @@ extern "C" { +// Any.kt +KBool Kotlin_Any_equals(const ObjHeader* thiz, const ObjHeader* other) { + return thiz == other; +} + +KInt Kotlin_Any_hashCode(const ObjHeader* thiz) { + // Here we will use different mechanism for stable hashcode, using meta-objects + // if moving collector will be used. + return reinterpret_cast(thiz); +} + +ArrayHeader* Kotlin_Any_toString(const ObjHeader* thiz) { + + return nullptr; +} + // Arrays.kt // TODO: those must be compiler intrinsics afterwards. KByte Kotlin_ByteArray_get(const ArrayHeader* obj, KInt index) { @@ -97,7 +113,7 @@ KInt Kotlin_IntArray_getArrayLength(const ArrayHeader* array) { // io/Console.kt void Kotlin_io_Console_print(const ArrayHeader* array) { - RuntimeAssert(array->type_info_ == theStringTypeInfo, "Must use a string"); + RuntimeAssert(array->type_info() == theStringTypeInfo, "Must use a string"); // TODO: system stdout must be aware about UTF-8. write(STDOUT_FILENO, ByteArrayAddressOfElementAt(array, 0), array->count_); } @@ -122,7 +138,7 @@ KInt Kotlin_String_getStringLength(const ArrayHeader* array) { } ArrayHeader* Kotlin_String_fromUtf8Array(const ArrayHeader* array) { - RuntimeAssert(array->type_info_ == theByteArrayTypeInfo, "Must use 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(); @@ -136,8 +152,8 @@ ArrayHeader* Kotlin_String_fromUtf8Array(const ArrayHeader* array) { 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"); + 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(); @@ -152,4 +168,14 @@ ArrayHeader* Kotlin_String_plusImpl( return result; } +KBool Kotlin_String_equals( + const ArrayHeader* thiz, const ObjHeader* other) { + if (other == nullptr || other->type_info() != theStringTypeInfo) return 0; + const ArrayHeader* otherString = reinterpret_cast(other); + return thiz->count_ == otherString->count_ && + memcmp(ByteArrayAddressOfElementAt(thiz, 0), + ByteArrayAddressOfElementAt(otherString, 0), + thiz->count_) == 0; +} + } diff --git a/runtime/src/main/cpp/Natives.h b/runtime/src/main/cpp/Natives.h index 149aaf71835..061ead4bf77 100644 --- a/runtime/src/main/cpp/Natives.h +++ b/runtime/src/main/cpp/Natives.h @@ -4,6 +4,7 @@ #include "Memory.h" #include "Types.h" +typedef uint8_t KBool; typedef uint8_t KByte; typedef uint16_t KChar; // Note that it is signed. @@ -40,32 +41,38 @@ inline const KInt* IntArrayAddressOfElementAt(const ArrayHeader* obj, KInt index extern "C" { #endif +// Any.kt +KBool Kotlin_Any_equals(const ObjHeader* thiz, const ObjHeader* other); +KInt Kotlin_Any_hashCode(const ObjHeader* thiz); +ArrayHeader* Kotlin_Any_toString(const ObjHeader* thiz); + +// Arrays.kt // TODO: those must be compiler intrinsics afterwards. - // Arrays.kt -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_ByteArray_clone(const ArrayHeader* thiz); +KByte Kotlin_ByteArray_get(const ArrayHeader* thiz, KInt index); +void Kotlin_ByteArray_set(ArrayHeader* thiz, KInt index, KByte value); +KInt Kotlin_ByteArray_getArrayLength(const ArrayHeader* thiz); -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_CharArray_clone(const ArrayHeader* thiz); +KChar Kotlin_CharArray_get(const ArrayHeader* thiz, KInt index); +void Kotlin_CharArray_set(ArrayHeader* thiz, KInt index, KChar value); +KInt Kotlin_CharArray_getArrayLength(const ArrayHeader* thiz); -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); +ArrayHeader* Kotlin_IntArray_clone(const ArrayHeader* thiz); +KInt Kotlin_IntArray_get(const ArrayHeader* thiz, KInt index); +void Kotlin_IntArray_set(ArrayHeader* thiz, KInt index, KInt value); +KInt Kotlin_IntArray_getArrayLength(const ArrayHeader* thiz); // io/Console.kt -void Kotlin_io_Console_print(const ArrayHeader* obj); +void Kotlin_io_Console_print(const ArrayHeader* thiz); // String.kt -KInt Kotlin_String_compareTo(const ArrayHeader* obj, const ArrayHeader* other); -KChar Kotlin_String_get(const ArrayHeader* obj, KInt index); +KInt Kotlin_String_compareTo(const ArrayHeader* thiz, const ArrayHeader* other); +KChar Kotlin_String_get(const ArrayHeader* thiz, 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); +ArrayHeader* Kotlin_String_plusImpl(const ArrayHeader* thiz, const ArrayHeader* other); +KInt Kotlin_String_getStringLength(const ArrayHeader* thiz); +KBool Kotlin_String_equals(const ArrayHeader* thiz, const ObjHeader* other); #ifdef __cplusplus } diff --git a/runtime/src/main/cpp/TypeInfo.h b/runtime/src/main/cpp/TypeInfo.h index 157db7e5d49..ecfae72bb60 100644 --- a/runtime/src/main/cpp/TypeInfo.h +++ b/runtime/src/main/cpp/TypeInfo.h @@ -27,6 +27,7 @@ struct TypeInfo { int32_t instanceSize_; // Must be pointer to Any for array classes, and null for Any. const TypeInfo* superType_; + // All object references inside this object. const int* objOffsets_; int objOffsetsCount_; const TypeInfo* const* implementedInterfaces_; diff --git a/runtime/src/main/kotlin/kotlin_native/Any.kt b/runtime/src/main/kotlin/kotlin_native/Any.kt new file mode 100644 index 00000000000..52600fbda99 --- /dev/null +++ b/runtime/src/main/kotlin/kotlin_native/Any.kt @@ -0,0 +1,13 @@ +package kotlin_native + +public open class Any0 { + // @SymbolName("Kotlin_Any_equals") + // external public open operator fun equals0(other: Any0?): Boolean + + // TODO: do we need that in Any? + @SymbolName("Kotlin_Any_hashCode") + external public open fun hashCode0(): Int + + @SymbolName("Kotlin_Any_toString") + external public open fun toString0(): String +} diff --git a/runtime/src/main/kotlin/kotlin_native/String.kt b/runtime/src/main/kotlin/kotlin_native/String.kt index acb16b2da35..8220f7922eb 100644 --- a/runtime/src/main/kotlin/kotlin_native/String.kt +++ b/runtime/src/main/kotlin/kotlin_native/String.kt @@ -24,4 +24,7 @@ class String { @SymbolName("Kotlin_String_plusImpl") external private fun plusImpl(other:Any): String + + @SymbolName("Kotlin_String_equals") + external public override operator fun equals(other: Any?): Boolean } \ No newline at end of file