Very basic string support. (#10)
String, ByteArray support, type declarations.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "Assert.h"
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
|
|
||||||
void FreeObject(ContainerHeader* header) {
|
void FreeObject(ContainerHeader* header) {
|
||||||
@@ -16,16 +17,28 @@ ArenaContainer::ArenaContainer(uint32_t size) {
|
|||||||
header->end_ = header->current_ + 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*>(
|
header_ = reinterpret_cast<ContainerHeader*>(
|
||||||
calloc(sizeof(ContainerHeader) + sizeof(ObjHeader) +
|
calloc(sizeof(ContainerHeader) + sizeof(ObjHeader) +
|
||||||
type_info->size_ * elements, 1));
|
type_info->instanceSize_, 1));
|
||||||
header_->ref_count_ = CONTAINER_TAG_INCREMENT;
|
header_->ref_count_ = CONTAINER_TAG_INCREMENT;
|
||||||
SetMeta(GetPlace(), type_info);
|
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) {
|
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));
|
ObjHeader* result = reinterpret_cast<ObjHeader*>(Place(size));
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -35,7 +48,8 @@ ObjHeader* ArenaContainer::PlaceObject(const TypeInfo* type_info) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArrayHeader* ArenaContainer::PlaceArray(const TypeInfo* type_info, int count) {
|
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));
|
ArrayHeader* result = reinterpret_cast<ArrayHeader*>(Place(size));
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -55,11 +69,13 @@ void InitMemory() {
|
|||||||
|
|
||||||
// Now we ignore all placement hints and always allocate heap space for new object.
|
// Now we ignore all placement hints and always allocate heap space for new object.
|
||||||
void* AllocInstance(const TypeInfo* type_info, PlacementHint hint) {
|
void* AllocInstance(const TypeInfo* type_info, PlacementHint hint) {
|
||||||
|
RuntimeAssert(type_info->instanceSize_ >= 0, "must be an object");
|
||||||
return ObjectContainer(type_info).GetPlace();
|
return ObjectContainer(type_info).GetPlace();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* AllocArrayInstance(const TypeInfo* type_info, PlacementHint hint, uint32_t elements) {
|
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
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -5,8 +5,11 @@
|
|||||||
#include "TypeInfo.h"
|
#include "TypeInfo.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
// Allocation guaranteed to be frame local.
|
||||||
SCOPE_FRAME = 0,
|
SCOPE_FRAME = 0,
|
||||||
|
// Allocation is generic global allocation.
|
||||||
SCOPE_GLOBAL = 1,
|
SCOPE_GLOBAL = 1,
|
||||||
|
// Allocation shall take place in current arena.
|
||||||
SCOPE_ARENA = 2
|
SCOPE_ARENA = 2
|
||||||
} PlacementHint;
|
} PlacementHint;
|
||||||
|
|
||||||
@@ -22,7 +25,7 @@ typedef enum {
|
|||||||
CONTAINER_TAG_INVALID = 3,
|
CONTAINER_TAG_INVALID = 3,
|
||||||
// Actual value to increment/decrement conatiner by. Tag is in lower bits.
|
// Actual value to increment/decrement conatiner by. Tag is in lower bits.
|
||||||
CONTAINER_TAG_INCREMENT = 1 << 2,
|
CONTAINER_TAG_INCREMENT = 1 << 2,
|
||||||
//
|
// Mask for container type.
|
||||||
CONTAINER_TAG_MASK = (CONTAINER_TAG_INCREMENT - 1)
|
CONTAINER_TAG_MASK = (CONTAINER_TAG_INCREMENT - 1)
|
||||||
} ContainerTag;
|
} ContainerTag;
|
||||||
|
|
||||||
@@ -37,12 +40,13 @@ struct ObjHeader {
|
|||||||
|
|
||||||
// Header of value type array objects.
|
// Header of value type array objects.
|
||||||
struct ArrayHeader : public ObjHeader {
|
struct ArrayHeader : public ObjHeader {
|
||||||
|
// Elements count. Element size is stored in instanceSize_ field of TypeInfo, negated.
|
||||||
uint32_t count_;
|
uint32_t count_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Header of all container objects. Contains reference counter.
|
// Header of all container objects. Contains reference counter.
|
||||||
struct ContainerHeader {
|
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()).
|
// container type (for polymorphism in ::Release()).
|
||||||
volatile uint32_t ref_count_;
|
volatile uint32_t ref_count_;
|
||||||
};
|
};
|
||||||
@@ -55,7 +59,27 @@ struct ArenaContainerHeader : public ContainerHeader {
|
|||||||
uint8_t* end_;
|
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.
|
// to objects.
|
||||||
inline void AddRef(ContainerHeader* header) {
|
inline void AddRef(ContainerHeader* header) {
|
||||||
// Looking at container type we may want to skip AddRef() totally
|
// Looking at container type we may want to skip AddRef() totally
|
||||||
@@ -141,12 +165,9 @@ class Container {
|
|||||||
// Container for a single object.
|
// Container for a single object.
|
||||||
class ObjectContainer : public Container {
|
class ObjectContainer : public Container {
|
||||||
public:
|
public:
|
||||||
|
// Single instance.
|
||||||
explicit ObjectContainer(const TypeInfo* type_info) {
|
explicit ObjectContainer(const TypeInfo* type_info) {
|
||||||
Init(type_info, 1);
|
Init(type_info);
|
||||||
}
|
|
||||||
|
|
||||||
ObjectContainer(const TypeInfo* type_info, uint32_t elements) {
|
|
||||||
Init(type_info, elements);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Object container shalln't have any dtor, as it's being freed by ::Release().
|
// 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));
|
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:
|
private:
|
||||||
void Init(const TypeInfo* type_info, uint32_t elements);
|
void Init(const TypeInfo* type_info, uint32_t elements);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Class representing arena-style placement container.
|
// Class representing arena-style placement container.
|
||||||
// Container is used for reference counting,
|
// Container is used for reference counting,
|
||||||
// and it is assumed that objects with related placement will share container. Only
|
// and it is assumed that objects with related placement will share container. Only
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -6,6 +6,8 @@
|
|||||||
#include "Names.h"
|
#include "Names.h"
|
||||||
|
|
||||||
// An element of sorted by hash in-place array representing methods.
|
// 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 {
|
struct MethodTableRecord {
|
||||||
MethodNameHash nameSignature_;
|
MethodNameHash nameSignature_;
|
||||||
void* methodEntryPoint_;
|
void* methodEntryPoint_;
|
||||||
@@ -17,11 +19,13 @@ struct FieldTableRecord {
|
|||||||
int fieldOffset_;
|
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.
|
// constant.
|
||||||
struct TypeInfo {
|
struct TypeInfo {
|
||||||
ClassNameHash name_;
|
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 TypeInfo* superType_;
|
||||||
const int* objOffsets_;
|
const int* objOffsets_;
|
||||||
int objOffsetsCount_;
|
int objOffsetsCount_;
|
||||||
@@ -29,9 +33,9 @@ struct TypeInfo {
|
|||||||
int implementedInterfacesCount_;
|
int implementedInterfacesCount_;
|
||||||
void* const* vtable_; // TODO: place vtable at the end of TypeInfo to eliminate the indirection
|
void* const* vtable_; // TODO: place vtable at the end of TypeInfo to eliminate the indirection
|
||||||
const MethodTableRecord* openMethods_;
|
const MethodTableRecord* openMethods_;
|
||||||
int openMethodsCount_;
|
uint32_t openMethodsCount_;
|
||||||
const FieldTableRecord* fields_;
|
const FieldTableRecord* fields_;
|
||||||
int fieldsCount_;
|
uint32_t fieldsCount_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user