More array types, bind to native. (#13)
More array types, bind to native implementations.
This commit is contained in:
@@ -64,15 +64,6 @@ inline void* AddressOfElementAt(ArrayHeader* obj, int32_t index) {
|
||||
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_;
|
||||
|
||||
@@ -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<uint32_t>(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<uint32_t>(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<uint32_t>(index) >= obj->count_) {
|
||||
ThrowArrayIndexOutOfBoundsException();
|
||||
}
|
||||
return *CharArrayAddressOfElementAt(obj, index);
|
||||
}
|
||||
|
||||
void Kotlin_CharArray_set(ArrayHeader* obj, KInt index, KChar value) {
|
||||
if (static_cast<uint32_t>(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<uint32_t>(index) >= obj->count_) {
|
||||
ThrowArrayIndexOutOfBoundsException();
|
||||
}
|
||||
return *IntArrayAddressOfElementAt(obj, index);
|
||||
}
|
||||
|
||||
void Kotlin_IntArray_set(ArrayHeader* obj, KInt index, KInt value) {
|
||||
if (static_cast<uint32_t>(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<uint32_t>(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<KByte*>(obj + 1) + index;
|
||||
}
|
||||
|
||||
inline const KByte* ByteArrayAddressOfElementAt(
|
||||
const ArrayHeader* obj, KInt index) {
|
||||
return reinterpret_cast<const KByte*>(obj + 1) + index;
|
||||
}
|
||||
|
||||
inline KChar* CharArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
|
||||
return reinterpret_cast<KChar*>(obj + 1) + index;
|
||||
}
|
||||
|
||||
inline const KChar* CharArrayAddressOfElementAt(
|
||||
const ArrayHeader* obj, KInt index) {
|
||||
return reinterpret_cast<const KChar*>(obj + 1) + index;
|
||||
}
|
||||
|
||||
inline KInt* IntArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
|
||||
return reinterpret_cast<KInt*>(obj + 1) + index;
|
||||
}
|
||||
|
||||
inline const KInt* IntArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
|
||||
return reinterpret_cast<const KInt*>(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
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
+105
-12
@@ -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<void*>(Kotlin_ByteArray_clone)
|
||||
};
|
||||
|
||||
const MethodTableRecord implByteArrayTypeInfoMethods[] = {
|
||||
// TODO: fill in hash.
|
||||
{ 0, reinterpret_cast<void*>(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<void*>(Kotlin_CharArray_clone)
|
||||
};
|
||||
|
||||
const MethodTableRecord implCharArrayTypeInfoMethods[] = {
|
||||
// TODO: fill in hash.
|
||||
{ 0, reinterpret_cast<void*>(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<void*>(Kotlin_IntArray_clone)
|
||||
};
|
||||
|
||||
const MethodTableRecord implIntArrayTypeInfoMethods[] = {
|
||||
// TODO: fill in hash.
|
||||
{ 0, reinterpret_cast<void*>(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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user