Very basic string support. (#10)

String, ByteArray support, type declarations.
This commit is contained in:
Nikolay Igotti
2016-10-20 16:04:28 +03:00
committed by GitHub
parent badcccac58
commit 09cb649c32
8 changed files with 261 additions and 17 deletions
+21 -5
View File
@@ -1,5 +1,6 @@
#include <stdlib.h>
#include "Assert.h"
#include "Memory.h"
void FreeObject(ContainerHeader* header) {
@@ -16,16 +17,28 @@ ArenaContainer::ArenaContainer(uint32_t size) {
header->end_ = header->current_ + size;
}
void ObjectContainer::Init(const TypeInfo* type_info, uint32_t elements) {
void ObjectContainer::Init(const TypeInfo* type_info) {
RuntimeAssert(type_info->instanceSize_ >= 0, "Must be an object");
header_ = reinterpret_cast<ContainerHeader*>(
calloc(sizeof(ContainerHeader) + sizeof(ObjHeader) +
type_info->size_ * elements, 1));
type_info->instanceSize_, 1));
header_->ref_count_ = CONTAINER_TAG_INCREMENT;
SetMeta(GetPlace(), type_info);
}
void ArrayContainer::Init(const TypeInfo* type_info, uint32_t elements) {
RuntimeAssert(type_info->instanceSize_ < 0, "Must be an array");
header_ = reinterpret_cast<ContainerHeader*>(
calloc(sizeof(ContainerHeader) + sizeof(ArrayHeader) -
type_info->instanceSize_ * elements, 1));
header_->ref_count_ = CONTAINER_TAG_INCREMENT;
GetPlace()->count_ = elements;
SetMeta(GetPlace(), type_info);
}
ObjHeader* ArenaContainer::PlaceObject(const TypeInfo* type_info) {
int size = type_info->size_ + sizeof(ObjHeader);
RuntimeAssert(type_info->instanceSize_ >= 0, "must be an object");
uint32_t size = type_info->instanceSize_ + sizeof(ObjHeader);
ObjHeader* result = reinterpret_cast<ObjHeader*>(Place(size));
if (!result) {
return nullptr;
@@ -35,7 +48,8 @@ ObjHeader* ArenaContainer::PlaceObject(const TypeInfo* type_info) {
}
ArrayHeader* ArenaContainer::PlaceArray(const TypeInfo* type_info, int count) {
int size = sizeof(ArrayHeader) + type_info->size_ * count;
RuntimeAssert(type_info->instanceSize_ < 0, "must be an array");
uint32_t size = sizeof(ArrayHeader) - type_info->instanceSize_ * count;
ArrayHeader* result = reinterpret_cast<ArrayHeader*>(Place(size));
if (!result) {
return nullptr;
@@ -55,11 +69,13 @@ void InitMemory() {
// Now we ignore all placement hints and always allocate heap space for new object.
void* AllocInstance(const TypeInfo* type_info, PlacementHint hint) {
RuntimeAssert(type_info->instanceSize_ >= 0, "must be an object");
return ObjectContainer(type_info).GetPlace();
}
void* AllocArrayInstance(const TypeInfo* type_info, PlacementHint hint, uint32_t elements) {
return ObjectContainer(type_info, elements).GetPlace();
RuntimeAssert(type_info->instanceSize_ < 0, "must be an array");
return ArrayContainer(type_info, elements).GetPlace();
}
#ifdef __cplusplus
+47 -8
View File
@@ -5,8 +5,11 @@
#include "TypeInfo.h"
typedef enum {
// Allocation guaranteed to be frame local.
SCOPE_FRAME = 0,
// Allocation is generic global allocation.
SCOPE_GLOBAL = 1,
// Allocation shall take place in current arena.
SCOPE_ARENA = 2
} PlacementHint;
@@ -22,7 +25,7 @@ typedef enum {
CONTAINER_TAG_INVALID = 3,
// Actual value to increment/decrement conatiner by. Tag is in lower bits.
CONTAINER_TAG_INCREMENT = 1 << 2,
//
// Mask for container type.
CONTAINER_TAG_MASK = (CONTAINER_TAG_INCREMENT - 1)
} ContainerTag;
@@ -37,12 +40,13 @@ struct ObjHeader {
// Header of value type array objects.
struct ArrayHeader : public ObjHeader {
// Elements count. Element size is stored in instanceSize_ field of TypeInfo, negated.
uint32_t count_;
};
// Header of all container objects. Contains reference counter.
struct ContainerHeader {
// Reference counter of container. Maybe use some upper bit of counter for
// Reference counter of container. Uses two lower bits of counter for
// container type (for polymorphism in ::Release()).
volatile uint32_t ref_count_;
};
@@ -55,7 +59,27 @@ struct ArenaContainerHeader : public ContainerHeader {
uint8_t* end_;
};
// Thos two operations are implemented by translator when storing references
inline void* AddressOfElementAt(ArrayHeader* obj, int32_t index) {
// Instance size is negative.
return reinterpret_cast<uint8_t*>(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<uint8_t*>(obj + 1) + index;
}
inline const uint8_t* ByteArrayAddressOfElementAt(const ArrayHeader* obj, int32_t index) {
return reinterpret_cast<const uint8_t*>(obj + 1) + index;
}
inline uint32_t ArraySizeBytes(const ArrayHeader* obj) {
// Instance size is negative.
return -obj->type_info_->instanceSize_ * obj->count_;
}
// Those two operations are implemented by translator when storing references
// to objects.
inline void AddRef(ContainerHeader* header) {
// Looking at container type we may want to skip AddRef() totally
@@ -141,12 +165,9 @@ class Container {
// Container for a single object.
class ObjectContainer : public Container {
public:
// Single instance.
explicit ObjectContainer(const TypeInfo* type_info) {
Init(type_info, 1);
}
ObjectContainer(const TypeInfo* type_info, uint32_t elements) {
Init(type_info, elements);
Init(type_info);
}
// Object container shalln't have any dtor, as it's being freed by ::Release().
@@ -155,10 +176,28 @@ class ObjectContainer : public Container {
reinterpret_cast<uint8_t*>(header_) + sizeof(ContainerHeader));
}
private:
void Init(const TypeInfo* type_info);
};
class ArrayContainer : public Container {
public:
ArrayContainer(const TypeInfo* type_info, uint32_t elements) {
Init(type_info, elements);
}
// Array container shalln't have any dtor, as it's being freed by ::Release().
ArrayHeader* GetPlace() const {
return reinterpret_cast<ArrayHeader*>(
reinterpret_cast<uint8_t*>(header_) + sizeof(ContainerHeader));
}
private:
void Init(const TypeInfo* type_info, uint32_t elements);
};
// Class representing arena-style placement container.
// Container is used for reference counting,
// and it is assumed that objects with related placement will share container. Only
+46
View File
@@ -0,0 +1,46 @@
#include <string.h>
#include "Assert.h"
#include "Exceptions.h"
#include "Memory.h"
#include "Natives.h"
#include "Types.h"
extern "C" {
// TODO: those must be compiler intrinsics afterwards.
KByte Kotlin_ByteArray_get(const ArrayHeader* obj, int32_t index) {
if (static_cast<uint32_t>(index) >= obj->count_) {
ThrowArrayIndexOutOfBoundsException();
}
return *ByteArrayAddressOfElementAt(obj, index);
}
void Kotlin_ByteArray_set(ArrayHeader* obj, int32_t index, KByte value) {
if (static_cast<uint32_t>(index) >= obj->count_) {
ThrowArrayIndexOutOfBoundsException();
}
*ByteArrayAddressOfElementAt(obj, index) = value;
}
KChar Kotlin_String_get(const ArrayHeader* obj, int32_t index) {
// TODO: support full UTF-8.
if (static_cast<uint32_t>(index) >= obj->count_) {
ThrowArrayIndexOutOfBoundsException();
}
return *ByteArrayAddressOfElementAt(obj, index);
}
ArrayHeader* Kotlin_String_fromUtf8Array(const ArrayHeader* array) {
RuntimeAssert(array->type_info_ == theByteArrayTypeInfo, "Must get a byte array");
uint32_t length = ArraySizeBytes(array);
// TODO: support full UTF-8.
ArrayHeader* result = ArrayContainer(theStringTypeInfo, length).GetPlace();
memcpy(
ByteArrayAddressOfElementAt(result, 0),
ByteArrayAddressOfElementAt(array, 0),
length);
return result;
}
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef RUNTIME_NATIVES_H
#define RUNTIME_NATIVES_H
#include "Memory.h"
#include "Types.h"
typedef uint16_t KChar;
typedef uint8_t KByte;
#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_String_fromUtf8Array(const ArrayHeader* array);
#ifdef __cplusplus
}
#endif
#endif // RUNTIME_NATIVES_H
+8 -4
View File
@@ -6,6 +6,8 @@
#include "Names.h"
// An element of sorted by hash in-place array representing methods.
// For systems where introspection is not needed - only open methods are in
// this table.
struct MethodTableRecord {
MethodNameHash nameSignature_;
void* methodEntryPoint_;
@@ -17,11 +19,13 @@ struct FieldTableRecord {
int fieldOffset_;
};
// This struct represents runtime type information and by itself is compile time
// This struct represents runtime type information and by itself is the compile time
// constant.
struct TypeInfo {
ClassNameHash name_;
int size_;
// Negative value marks array class/string, and it is negated element size.
int32_t instanceSize_;
// Must be pointer to Any for array classes, and null for Any.
const TypeInfo* superType_;
const int* objOffsets_;
int objOffsetsCount_;
@@ -29,9 +33,9 @@ struct TypeInfo {
int implementedInterfacesCount_;
void* const* vtable_; // TODO: place vtable at the end of TypeInfo to eliminate the indirection
const MethodTableRecord* openMethods_;
int openMethodsCount_;
uint32_t openMethodsCount_;
const FieldTableRecord* fields_;
int fieldsCount_;
uint32_t fieldsCount_;
};
#ifdef __cplusplus
+69
View File
@@ -0,0 +1,69 @@
#include "Types.h"
namespace {
// Use 'echo -n "kotlin.ByteArray" | shasum -| xargs ~/bin/as_array' to generate hash.
const TypeInfo implAnyTypeInfo = {
// kotlin.Any
{ 0x6a, 0x97, 0xc2, 0x61, 0x64, 0x3a, 0xc6, 0x5e, 0x2a, 0x03,
0xf9, 0xc1, 0x4c, 0x1f, 0x66, 0x9a, 0x44, 0xb2, 0x6b, 0x11 },
0, // instanceSize_
nullptr, // superType_
nullptr, // objOffsets
0, // objOffsetsCount_
nullptr, // implementedInterfaces_
0, // implementedInterfacesCount_
nullptr, // vtable_
nullptr, // openMethods_
0, // openMethodsCount_
nullptr, // fields_
0 // fieldsCount_
};
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_
};
const TypeInfo implStringTypeInfo = {
{ 0x5b, 0xac, 0x68, 0xed, 0x43, 0xd4, 0x81, 0x4a, 0x14, 0x18,
0x10, 0xfa, 0x65, 0x09, 0xb9, 0xef, 0x20, 0x0a, 0xba, 0x78 }, // kotlin.String
-1, // instanceSize_, Strings are treated as array of 1 byte elements
&implAnyTypeInfo, // superType_
nullptr, // objOffsets
0, // objOffsetsCount_
nullptr, // implementedInterfaces_
0, // implementedInterfacesCount_
nullptr, // vtable_
nullptr, // openMethods_
0, // openMethodsCount_
nullptr, // fields_
0 // fieldsCount_
};
} // namespace
#ifdef __cplusplus
extern "C" {
#endif
const TypeInfo* theAnyTypeInfo = &implAnyTypeInfo;
const TypeInfo* theByteArrayTypeInfo = &implByteArrayTypeInfo;
const TypeInfo* theStringTypeInfo = &implStringTypeInfo;
#ifdef __cplusplus
}
#endif
+18
View File
@@ -0,0 +1,18 @@
#ifndef RUNTIME_TYPES_H
#define RUNTIME_TYPES_H
#include "TypeInfo.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const TypeInfo* theAnyTypeInfo;
extern const TypeInfo* theByteArrayTypeInfo;
extern const TypeInfo* theStringTypeInfo;
#ifdef __cplusplus
}
#endif
#endif // RUNTIME_TYPES_H
@@ -0,0 +1,28 @@
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
}
class String {
companion object {
external fun fromUtf8Array(ByteArray: array) : String
}
external public operator fun plus(other: Any?): String
public val length: Int
get() = getStringLength()
// Can be O(N).
external public fun get(index: Int): Char
// external public fun subSequence(startIndex: Int, endIndex: Int): CharSequence
external public fun compareTo(other: String): Int
external private fun getStringLength(): Int
}