Improve code related to object layout (#2446)

This commit is contained in:
SvyatoslavScherbina
2018-12-09 10:38:23 +03:00
committed by Nikolay Igotti
parent ca9c4cde51
commit 328413337b
12 changed files with 189 additions and 89 deletions
@@ -44,16 +44,16 @@ inline fun <T : Any, R> T.usePinned(block: (Pinned<T>) -> R): R {
} }
} }
fun Pinned<ByteArray>.addressOf(index: Int): CPointer<ByteVar> = this.addressOfElement(index) fun Pinned<ByteArray>.addressOf(index: Int): CPointer<ByteVar> = this.get().addressOfElement(index)
fun ByteArray.refTo(index: Int): CValuesRef<ByteVar> = this.usingPinned { addressOf(index) } fun ByteArray.refTo(index: Int): CValuesRef<ByteVar> = this.usingPinned { addressOf(index) }
fun Pinned<ShortArray>.addressOf(index: Int): CPointer<ShortVar> = this.addressOfElement(index) fun Pinned<ShortArray>.addressOf(index: Int): CPointer<ShortVar> = this.get().addressOfElement(index)
fun ShortArray.refTo(index: Int): CValuesRef<ShortVar> = this.usingPinned { addressOf(index) } fun ShortArray.refTo(index: Int): CValuesRef<ShortVar> = this.usingPinned { addressOf(index) }
fun Pinned<IntArray>.addressOf(index: Int): CPointer<IntVar> = this.addressOfElement(index) fun Pinned<IntArray>.addressOf(index: Int): CPointer<IntVar> = this.get().addressOfElement(index)
fun IntArray.refTo(index: Int): CValuesRef<IntVar> = this.usingPinned { addressOf(index) } fun IntArray.refTo(index: Int): CValuesRef<IntVar> = this.usingPinned { addressOf(index) }
fun Pinned<LongArray>.addressOf(index: Int): CPointer<LongVar> = this.addressOfElement(index) fun Pinned<LongArray>.addressOf(index: Int): CPointer<LongVar> = this.get().addressOfElement(index)
fun LongArray.refTo(index: Int): CValuesRef<LongVar> = this.usingPinned { addressOf(index) } fun LongArray.refTo(index: Int): CValuesRef<LongVar> = this.usingPinned { addressOf(index) }
// TODO: pinning of unsigned arrays involves boxing as they are inline classes wrapping signed arrays. // TODO: pinning of unsigned arrays involves boxing as they are inline classes wrapping signed arrays.
@@ -69,10 +69,10 @@ fun UIntArray.refTo(index: Int): CValuesRef<UIntVar> = this.usingPinned { addres
fun Pinned<ULongArray>.addressOf(index: Int): CPointer<ULongVar> = this.get().addressOfElement(index) fun Pinned<ULongArray>.addressOf(index: Int): CPointer<ULongVar> = this.get().addressOfElement(index)
fun ULongArray.refTo(index: Int): CValuesRef<ULongVar> = this.usingPinned { addressOf(index) } fun ULongArray.refTo(index: Int): CValuesRef<ULongVar> = this.usingPinned { addressOf(index) }
fun Pinned<FloatArray>.addressOf(index: Int): CPointer<FloatVar> = this.addressOfElement(index) fun Pinned<FloatArray>.addressOf(index: Int): CPointer<FloatVar> = this.get().addressOfElement(index)
fun FloatArray.refTo(index: Int): CValuesRef<FloatVar> = this.usingPinned { addressOf(index) } fun FloatArray.refTo(index: Int): CValuesRef<FloatVar> = this.usingPinned { addressOf(index) }
fun Pinned<DoubleArray>.addressOf(index: Int): CPointer<DoubleVar> = this.addressOfElement(index) fun Pinned<DoubleArray>.addressOf(index: Int): CPointer<DoubleVar> = this.get().addressOfElement(index)
fun DoubleArray.refTo(index: Int): CValuesRef<DoubleVar> = this.usingPinned { addressOf(index) } fun DoubleArray.refTo(index: Int): CValuesRef<DoubleVar> = this.usingPinned { addressOf(index) }
private inline fun <T : Any, P : CPointed> T.usingPinned( private inline fun <T : Any, P : CPointed> T.usingPinned(
@@ -86,21 +86,32 @@ private inline fun <T : Any, P : CPointed> T.usingPinned(
} }
} }
@SymbolName("Kotlin_Arrays_getAddressOfElement") @SymbolName("Kotlin_Arrays_getByteArrayAddressOfElement")
private external fun getAddressOfElement(array: Any, index: Int): COpaquePointer private external fun ByteArray.addressOfElement(index: Int): CPointer<ByteVar>
@Suppress("NOTHING_TO_INLINE") @SymbolName("Kotlin_Arrays_getShortArrayAddressOfElement")
private inline fun <P : CVariable> Pinned<*>.addressOfElement(index: Int): CPointer<P> = private external fun ShortArray.addressOfElement(index: Int): CPointer<ShortVar>
getAddressOfElement(this.get(), index).reinterpret()
@SymbolName("Kotlin_Arrays_getAddressOfElement") @SymbolName("Kotlin_Arrays_getIntArrayAddressOfElement")
private external fun IntArray.addressOfElement(index: Int): CPointer<IntVar>
@SymbolName("Kotlin_Arrays_getLongArrayAddressOfElement")
private external fun LongArray.addressOfElement(index: Int): CPointer<LongVar>
@SymbolName("Kotlin_Arrays_getByteArrayAddressOfElement")
private external fun UByteArray.addressOfElement(index: Int): CPointer<UByteVar> private external fun UByteArray.addressOfElement(index: Int): CPointer<UByteVar>
@SymbolName("Kotlin_Arrays_getAddressOfElement") @SymbolName("Kotlin_Arrays_getShortArrayAddressOfElement")
private external fun UShortArray.addressOfElement(index: Int): CPointer<UShortVar> private external fun UShortArray.addressOfElement(index: Int): CPointer<UShortVar>
@SymbolName("Kotlin_Arrays_getAddressOfElement") @SymbolName("Kotlin_Arrays_getIntArrayAddressOfElement")
private external fun UIntArray.addressOfElement(index: Int): CPointer<UIntVar> private external fun UIntArray.addressOfElement(index: Int): CPointer<UIntVar>
@SymbolName("Kotlin_Arrays_getAddressOfElement") @SymbolName("Kotlin_Arrays_getLongArrayAddressOfElement")
private external fun ULongArray.addressOfElement(index: Int): CPointer<ULongVar> private external fun ULongArray.addressOfElement(index: Int): CPointer<ULongVar>
@SymbolName("Kotlin_Arrays_getFloatArrayAddressOfElement")
private external fun FloatArray.addressOfElement(index: Int): CPointer<FloatVar>
@SymbolName("Kotlin_Arrays_getDoubleArrayAddressOfElement")
private external fun DoubleArray.addressOfElement(index: Int): CPointer<DoubleVar>
@@ -1592,7 +1592,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
functionGenerationContext.gep(objCPtr, bodyOffset) functionGenerationContext.gep(objCPtr, bodyOffset)
} else { } else {
LLVMBuildGEP(functionGenerationContext.builder, objectPtr, cValuesOf(kImmOne), 1, "")!! objectPtr
} }
} }
@@ -133,7 +133,8 @@ private fun Context.getDeclaredFields(classDescriptor: ClassDescriptor): List<Ir
} }
private fun ContextUtils.createClassBodyType(name: String, fields: List<IrField>): LLVMTypeRef { private fun ContextUtils.createClassBodyType(name: String, fields: List<IrField>): LLVMTypeRef {
val fieldTypes = fields.map { getLLVMType(it.type) } val fieldTypes = listOf(runtime.objHeaderType) + fields.map { getLLVMType(it.type) }
// TODO: consider adding synthetic ObjHeader field to Any.
val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!! val classType = LLVMStructCreateNamed(LLVMGetModuleContext(context.llvmModule), name)!!
@@ -369,7 +370,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
error(containingClass.descriptor.toString()) error(containingClass.descriptor.toString())
val allFields = classDeclarations.fields val allFields = classDeclarations.fields
this.fields[descriptor] = FieldLlvmDeclarations( this.fields[descriptor] = FieldLlvmDeclarations(
allFields.indexOf(descriptor), allFields.indexOf(descriptor) + 1, // First field is ObjHeader.
classDeclarations.bodyType classDeclarations.bodyType
) )
} else { } else {
@@ -289,9 +289,9 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
NullPointer(int32Type), NullPointer(int8Type), NullPointer(kInt8Ptr)) NullPointer(int32Type), NullPointer(int8Type), NullPointer(kInt8Ptr))
} else { } else {
data class FieldRecord(val offset: Int, val type: Int, val name: String) data class FieldRecord(val offset: Int, val type: Int, val name: String)
val fields = getStructElements(bodyType).mapIndexedNotNull { index, type -> val fields = getStructElements(bodyType).drop(1).mapIndexedNotNull { index, type ->
FieldRecord( FieldRecord(
LLVMOffsetOfElement(llvmTargetData, bodyType, index).toInt(), LLVMOffsetOfElement(llvmTargetData, bodyType, index + 1).toInt(),
mapRuntimeType(type), mapRuntimeType(type),
llvmDeclarations.fields[index].name.asString()) llvmDeclarations.fields[index].name.asString())
} }
@@ -316,7 +316,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
): ConstPointer { ): ConstPointer {
assert(descriptor.isInterface) assert(descriptor.isInterface)
val size = 0 val size = LLVMStoreSizeOfType(llvmTargetData, kObjHeader).toInt()
val superClass = context.ir.symbols.any.owner val superClass = context.ir.symbols.any.owner
@@ -71,24 +71,20 @@ internal fun StaticData.createConstKotlinArray(arrayClass: IrClass, elements: Li
return createRef(objHeaderPtr) return createRef(objHeaderPtr)
} }
internal fun StaticData.createConstKotlinObject(type: IrClass, body: ConstValue): ConstPointer { internal fun StaticData.createConstKotlinObject(type: IrClass, vararg fields: ConstValue): ConstPointer {
val typeInfo = type.typeInfoPtr val typeInfo = type.typeInfoPtr
val compositeType = structType(runtime.objHeaderType, body.llvmType)
val global = this.createGlobal(compositeType, "")
val objHeaderPtr = global.pointer.getElementPtr(0)
val objHeader = objHeader(typeInfo) val objHeader = objHeader(typeInfo)
global.setInitializer(Struct(compositeType, objHeader, body)) val global = this.placeGlobal("", Struct(objHeader, *fields))
global.setConstant(true) global.setConstant(true)
val objHeaderPtr = global.pointer.getElementPtr(0)
return createRef(objHeaderPtr) return createRef(objHeaderPtr)
} }
internal fun StaticData.createInitializer(type: IrClass, body: ConstValue): ConstValue = internal fun StaticData.createInitializer(type: IrClass, vararg fields: ConstValue): ConstValue =
Struct(objHeader(type.typeInfoPtr), body) Struct(objHeader(type.typeInfoPtr), *fields)
private fun StaticData.getArrayListClass(): ClassDescriptor { private fun StaticData.getArrayListClass(): ClassDescriptor {
val module = context.irModule!!.descriptor val module = context.irModule!!.descriptor
@@ -123,14 +119,12 @@ internal fun StaticData.createConstArrayList(array: ConstPointer, length: Int):
sorted.put(fqName, arrayListFields[fqName]!!) sorted.put(fqName, arrayListFields[fqName]!!)
} }
val body = Struct(*(sorted.values.toTypedArray())) return createConstKotlinObject(arrayListClass, *sorted.values.toTypedArray())
return createConstKotlinObject(arrayListClass, body)
} }
internal fun StaticData.createUniqueInstance( internal fun StaticData.createUniqueInstance(
kind: UniqueKind, bodyType: LLVMTypeRef, typeInfo: ConstPointer): ConstPointer { kind: UniqueKind, bodyType: LLVMTypeRef, typeInfo: ConstPointer): ConstPointer {
assert (getStructElements(bodyType).isEmpty()) assert (getStructElements(bodyType).size == 1) // ObjHeader only.
val objHeader = when (kind) { val objHeader = when (kind) {
UniqueKind.UNIT -> objHeader(typeInfo) UniqueKind.UNIT -> objHeader(typeInfo)
UniqueKind.EMPTY_ARRAY -> arrayHeader(typeInfo, 0) UniqueKind.EMPTY_ARRAY -> arrayHeader(typeInfo, 0)
+47 -2
View File
@@ -489,13 +489,58 @@ KNativePtr Kotlin_ImmutableBlob_asCPointerImpl(KRef thiz, KInt offset) {
return PrimitiveArrayAddressOfElementAt<KByte>(array, offset); return PrimitiveArrayAddressOfElementAt<KByte>(array, offset);
} }
KNativePtr Kotlin_Arrays_getAddressOfElement(KRef thiz, KInt index) { KNativePtr Kotlin_Arrays_getByteArrayAddressOfElement(KRef thiz, KInt index) {
ArrayHeader* array = thiz->array(); ArrayHeader* array = thiz->array();
if (index < 0 || index >= array->count_) { if (index < 0 || index >= array->count_) {
ThrowArrayIndexOutOfBoundsException(); ThrowArrayIndexOutOfBoundsException();
} }
return AddressOfElementAt(array, index); return AddressOfElementAt<KByte>(array, index);
}
KNativePtr Kotlin_Arrays_getShortArrayAddressOfElement(KRef thiz, KInt index) {
ArrayHeader* array = thiz->array();
if (index < 0 || index >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
return AddressOfElementAt<KShort>(array, index);
}
KNativePtr Kotlin_Arrays_getIntArrayAddressOfElement(KRef thiz, KInt index) {
ArrayHeader* array = thiz->array();
if (index < 0 || index >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
return AddressOfElementAt<KInt>(array, index);
}
KNativePtr Kotlin_Arrays_getLongArrayAddressOfElement(KRef thiz, KInt index) {
ArrayHeader* array = thiz->array();
if (index < 0 || index >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
return AddressOfElementAt<KLong>(array, index);
}
KNativePtr Kotlin_Arrays_getFloatArrayAddressOfElement(KRef thiz, KInt index) {
ArrayHeader* array = thiz->array();
if (index < 0 || index >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
return AddressOfElementAt<KFloat>(array, index);
}
KNativePtr Kotlin_Arrays_getDoubleArrayAddressOfElement(KRef thiz, KInt index) {
ArrayHeader* array = thiz->array();
if (index < 0 || index >= array->count_) {
ThrowArrayIndexOutOfBoundsException();
}
return AddressOfElementAt<KDouble>(array, index);
} }
} // extern "C" } // extern "C"
+22 -11
View File
@@ -23,37 +23,48 @@
namespace { namespace {
struct AtomicReferenceLayout { struct AtomicReferenceLayout {
ObjHeader header;
KRef value_; KRef value_;
KInt lock_; KInt lock_;
}; };
template<typename T> struct AtomicPrimitive {
ObjHeader header;
volatile T value_;
};
template <typename T> inline volatile T* getValueLocation(KRef thiz) {
AtomicPrimitive<T>* atomic = reinterpret_cast<AtomicPrimitive<T>*>(thiz);
return &atomic->value_;
}
template <typename T> void setImpl(KRef thiz, T value) { template <typename T> void setImpl(KRef thiz, T value) {
volatile T* location = reinterpret_cast<volatile T*>(thiz + 1); volatile T* location = getValueLocation<T>(thiz);
atomicSet(location, value); atomicSet(location, value);
} }
template <typename T> T getImpl(KRef thiz) { template <typename T> T getImpl(KRef thiz) {
volatile T* location = reinterpret_cast<volatile T*>(thiz + 1); volatile T* location = getValueLocation<T>(thiz);
return atomicGet(location); return atomicGet(location);
} }
template <typename T> T addAndGetImpl(KRef thiz, T delta) { template <typename T> T addAndGetImpl(KRef thiz, T delta) {
volatile T* location = reinterpret_cast<volatile T*>(thiz + 1); volatile T* location = getValueLocation<T>(thiz);
return atomicAdd(location, delta); return atomicAdd(location, delta);
} }
template <typename T> T compareAndSwapImpl(KRef thiz, T expectedValue, T newValue) { template <typename T> T compareAndSwapImpl(KRef thiz, T expectedValue, T newValue) {
volatile T* location = reinterpret_cast<volatile T*>(thiz + 1); volatile T* location = getValueLocation<T>(thiz);
return compareAndSwap(location, expectedValue, newValue); return compareAndSwap(location, expectedValue, newValue);
} }
template <typename T> KBoolean compareAndSetImpl(KRef thiz, T expectedValue, T newValue) { template <typename T> KBoolean compareAndSetImpl(KRef thiz, T expectedValue, T newValue) {
volatile T* location = reinterpret_cast<volatile T*>(thiz + 1); volatile T* location = getValueLocation<T>(thiz);
return compareAndSet(location, expectedValue, newValue); return compareAndSet(location, expectedValue, newValue);
} }
inline AtomicReferenceLayout* asAtomicReference(KRef thiz) { inline AtomicReferenceLayout* asAtomicReference(KRef thiz) {
return reinterpret_cast<AtomicReferenceLayout*>(thiz + 1); return reinterpret_cast<AtomicReferenceLayout*>(thiz);
} }
} // namespace } // namespace
@@ -93,7 +104,7 @@ KLong Kotlin_AtomicLong_compareAndSwap(KRef thiz, KLong expectedValue, KLong new
// Potentially huge performance penalty, but correct. // Potentially huge performance penalty, but correct.
// TODO: reconsider, once target MIPS can do proper 64-bit CAS. // TODO: reconsider, once target MIPS can do proper 64-bit CAS.
while (compareAndSwap(&lock64, 0, 1) != 0); while (compareAndSwap(&lock64, 0, 1) != 0);
KLong* address = reinterpret_cast<KLong*>(thiz + 1); volatile KLong* address = getValueLocation<KLong>(thiz);
KLong old = *address; KLong old = *address;
if (old == expectedValue) { if (old == expectedValue) {
*address = newValue; *address = newValue;
@@ -111,7 +122,7 @@ KBoolean Kotlin_AtomicLong_compareAndSet(KRef thiz, KLong expectedValue, KLong n
// TODO: reconsider, once target MIPS can do proper 64-bit CAS. // TODO: reconsider, once target MIPS can do proper 64-bit CAS.
KBoolean result = false; KBoolean result = false;
while (compareAndSwap(&lock64, 0, 1) != 0); while (compareAndSwap(&lock64, 0, 1) != 0);
KLong* address = reinterpret_cast<KLong*>(thiz + 1); volatile KLong* address = getValueLocation<KLong>(thiz);
KLong old = *address; KLong old = *address;
if (old == expectedValue) { if (old == expectedValue) {
result = true; result = true;
@@ -129,7 +140,7 @@ void Kotlin_AtomicLong_set(KRef thiz, KLong newValue) {
// Potentially huge performance penalty, but correct. // Potentially huge performance penalty, but correct.
// TODO: reconsider, once target MIPS can do proper 64-bit atomic store. // TODO: reconsider, once target MIPS can do proper 64-bit atomic store.
while (compareAndSwap(&lock64, 0, 1) != 0); while (compareAndSwap(&lock64, 0, 1) != 0);
KLong* address = reinterpret_cast<KLong*>(thiz + 1); volatile KLong* address = getValueLocation<KLong>(thiz);
*address = newValue; *address = newValue;
compareAndSwap(&lock64, 1, 0); compareAndSwap(&lock64, 1, 0);
#else #else
@@ -142,7 +153,7 @@ KLong Kotlin_AtomicLong_get(KRef thiz) {
// Potentially huge performance penalty, but correct. // Potentially huge performance penalty, but correct.
// TODO: reconsider, once target MIPS can do proper 64-bit atomic store. // TODO: reconsider, once target MIPS can do proper 64-bit atomic store.
while (compareAndSwap(&lock64, 0, 1) != 0); while (compareAndSwap(&lock64, 0, 1) != 0);
KLong* address = reinterpret_cast<KLong*>(thiz + 1); volatile KLong* address = getValueLocation<KLong>(thiz);
KLong value = *address; KLong value = *address;
compareAndSwap(&lock64, 1, 0); compareAndSwap(&lock64, 1, 0);
return value; return value;
+18 -2
View File
@@ -45,6 +45,19 @@ constexpr int runtimeTypeSize[] = {
1 // BOOLEAN 1 // BOOLEAN
}; };
constexpr int runtimeTypeAlignment[] = {
-1, // INVALID
alignof(ObjHeader*), // OBJECT
alignof(int8_t), // INT8
alignof(int16_t), // INT16
alignof(int32_t), // INT32
alignof(int64_t), // INT64
alignof(float), // FLOAT32
alignof(double), // FLOAT64
alignof(void*), // NATIVE_PTR
1 // BOOLEAN
};
} // namespace } // namespace
extern "C" { extern "C" {
@@ -130,13 +143,16 @@ RUNTIME_USED void* Konan_DebugGetFieldAddress(KRef obj, int index) {
if (index > obj->array()->count_) if (index > obj->array()->count_)
return nullptr; return nullptr;
return reinterpret_cast<uint8_t*>(obj->array() + 1) + index * runtimeTypeSize[-extendedTypeInfo->fieldsCount_]; int32_t typeIndex = -extendedTypeInfo->fieldsCount_;
return reinterpret_cast<uint8_t*>(obj->array())
+ alignUp(sizeof(struct ArrayHeader), runtimeTypeAlignment[typeIndex])
+ index * runtimeTypeSize[typeIndex];
} }
if (index >= extendedTypeInfo->fieldsCount_) if (index >= extendedTypeInfo->fieldsCount_)
return nullptr; return nullptr;
return reinterpret_cast<uint8_t*>(obj + 1) + extendedTypeInfo->fieldOffsets_[index]; return reinterpret_cast<uint8_t*>(obj) + extendedTypeInfo->fieldOffsets_[index];
} }
// Compute address of field or an array element at the index, or null, if incorrect. // Compute address of field or an array element at the index, or null, if incorrect.
+24 -11
View File
@@ -47,6 +47,9 @@ constexpr container_size_t kContainerAlignment = 1024;
// Single object alignment. // Single object alignment.
constexpr container_size_t kObjectAlignment = 8; constexpr container_size_t kObjectAlignment = 8;
// Required e.g. for object size computations to be correct.
static_assert(sizeof(ContainerHeader) % kObjectAlignment == 0, "sizeof(ContainerHeader) is not aligned");
#if TRACE_MEMORY #if TRACE_MEMORY
#define MEMORY_LOG(...) konan::consolePrintf(__VA_ARGS__); #define MEMORY_LOG(...) konan::consolePrintf(__VA_ARGS__);
#else #else
@@ -396,14 +399,25 @@ inline container_size_t alignUp(container_size_t size, int alignment) {
return (size + alignment - 1) & ~(alignment - 1); return (size + alignment - 1) & ~(alignment - 1);
} }
inline uint32_t arrayObjectSize(const TypeInfo* typeInfo, uint32_t count) {
// Note: array body is aligned, but for size computation it is enough to align the sum.
static_assert(kObjectAlignment % alignof(KLong) == 0, "");
static_assert(kObjectAlignment % alignof(KDouble) == 0, "");
return alignUp(sizeof(ArrayHeader) - typeInfo->instanceSize_ * count, kObjectAlignment);
}
inline uint32_t arrayObjectSize(const ArrayHeader* obj) {
return arrayObjectSize(obj->type_info(), obj->count_);
}
// TODO: shall we do padding for alignment? // TODO: shall we do padding for alignment?
inline container_size_t objectSize(const ObjHeader* obj) { inline container_size_t objectSize(const ObjHeader* obj) {
const TypeInfo* type_info = obj->type_info(); const TypeInfo* type_info = obj->type_info();
container_size_t size = (type_info->instanceSize_ < 0 ? container_size_t size = (type_info->instanceSize_ < 0 ?
// An array. // An array.
ArrayDataSizeBytes(obj->array()) + sizeof(ArrayHeader) arrayObjectSize(obj->array())
: :
type_info->instanceSize_ + sizeof(ObjHeader)); type_info->instanceSize_);
return alignUp(size, kObjectAlignment); return alignUp(size, kObjectAlignment);
} }
@@ -494,7 +508,7 @@ inline void traverseContainerObjectFields(ContainerHeader* container, func proce
if (typeInfo != theArrayTypeInfo) { if (typeInfo != theArrayTypeInfo) {
for (int index = 0; index < typeInfo->objOffsetsCount_; index++) { for (int index = 0; index < typeInfo->objOffsetsCount_; index++) {
ObjHeader** location = reinterpret_cast<ObjHeader**>( ObjHeader** location = reinterpret_cast<ObjHeader**>(
reinterpret_cast<uintptr_t>(obj + 1) + typeInfo->objOffsets_[index]); reinterpret_cast<uintptr_t>(obj) + typeInfo->objOffsets_[index]);
process(location); process(location);
} }
} else { } else {
@@ -1003,7 +1017,7 @@ void FreeContainer(ContainerHeader* container) {
void ObjectContainer::Init(const TypeInfo* typeInfo) { void ObjectContainer::Init(const TypeInfo* typeInfo) {
RuntimeAssert(typeInfo->instanceSize_ >= 0, "Must be an object"); RuntimeAssert(typeInfo->instanceSize_ >= 0, "Must be an object");
uint32_t alloc_size = uint32_t alloc_size =
sizeof(ContainerHeader) + sizeof(ObjHeader) + typeInfo->instanceSize_; sizeof(ContainerHeader) + typeInfo->instanceSize_;
header_ = AllocContainer(alloc_size); header_ = AllocContainer(alloc_size);
if (header_) { if (header_) {
// One object in this container. // One object in this container.
@@ -1018,8 +1032,7 @@ void ObjectContainer::Init(const TypeInfo* typeInfo) {
void ArrayContainer::Init(const TypeInfo* typeInfo, uint32_t elements) { void ArrayContainer::Init(const TypeInfo* typeInfo, uint32_t elements) {
RuntimeAssert(typeInfo->instanceSize_ < 0, "Must be an array"); RuntimeAssert(typeInfo->instanceSize_ < 0, "Must be an array");
uint32_t alloc_size = uint32_t alloc_size =
sizeof(ContainerHeader) + sizeof(ArrayHeader) - sizeof(ContainerHeader) + arrayObjectSize(typeInfo, elements);
typeInfo->instanceSize_ * elements;
header_ = AllocContainer(alloc_size); header_ = AllocContainer(alloc_size);
RuntimeAssert(header_ != nullptr, "Cannot alloc memory"); RuntimeAssert(header_ != nullptr, "Cannot alloc memory");
if (header_) { if (header_) {
@@ -1030,7 +1043,7 @@ void ArrayContainer::Init(const TypeInfo* typeInfo, uint32_t elements) {
SetHeader(GetPlace()->obj(), typeInfo); SetHeader(GetPlace()->obj(), typeInfo);
MEMORY_LOG("array at %p\n", GetPlace()) MEMORY_LOG("array at %p\n", GetPlace())
OBJECT_ALLOC_EVENT( OBJECT_ALLOC_EVENT(
memoryState, -typeInfo->instanceSize_ * elements, GetPlace()->obj()) memoryState, arrayObjectSize(typeInfo, elements), GetPlace()->obj())
} }
} }
@@ -1102,7 +1115,7 @@ ObjHeader** ArenaContainer::getSlot() {
ObjHeader* ArenaContainer::PlaceObject(const TypeInfo* type_info) { ObjHeader* ArenaContainer::PlaceObject(const TypeInfo* type_info) {
RuntimeAssert(type_info->instanceSize_ >= 0, "must be an object"); RuntimeAssert(type_info->instanceSize_ >= 0, "must be an object");
uint32_t size = type_info->instanceSize_ + sizeof(ObjHeader); uint32_t size = type_info->instanceSize_;
ObjHeader* result = reinterpret_cast<ObjHeader*>(place(size)); ObjHeader* result = reinterpret_cast<ObjHeader*>(place(size));
if (!result) { if (!result) {
return nullptr; return nullptr;
@@ -1115,12 +1128,12 @@ ObjHeader* ArenaContainer::PlaceObject(const TypeInfo* type_info) {
ArrayHeader* ArenaContainer::PlaceArray(const TypeInfo* type_info, uint32_t count) { ArrayHeader* ArenaContainer::PlaceArray(const TypeInfo* type_info, uint32_t count) {
RuntimeAssert(type_info->instanceSize_ < 0, "must be an array"); RuntimeAssert(type_info->instanceSize_ < 0, "must be an array");
container_size_t size = sizeof(ArrayHeader) - type_info->instanceSize_ * count; container_size_t size = arrayObjectSize(type_info, count);
ArrayHeader* result = reinterpret_cast<ArrayHeader*>(place(size)); ArrayHeader* result = reinterpret_cast<ArrayHeader*>(place(size));
if (!result) { if (!result) {
return nullptr; return nullptr;
} }
OBJECT_ALLOC_EVENT(memoryState, -type_info->instanceSize_ * count, result->obj()) OBJECT_ALLOC_EVENT(memoryState, arrayObjectSize(type_info, count), result->obj())
currentChunk_->asHeader()->incObjectCount(); currentChunk_->asHeader()->incObjectCount();
setHeader(result->obj(), type_info); setHeader(result->obj(), type_info);
result->count_ = count; result->count_ = count;
@@ -1923,7 +1936,7 @@ KBoolean Konan_ensureAcyclicAndSet(ObjHeader* where, KInt index, ObjHeader* what
if (!acyclic) return false; if (!acyclic) return false;
} }
UpdateRef(reinterpret_cast<ObjHeader**>( UpdateRef(reinterpret_cast<ObjHeader**>(
reinterpret_cast<uintptr_t>(where + 1) + where->type_info()->objOffsets_[index]), what); reinterpret_cast<uintptr_t>(where) + where->type_info()->objOffsets_[index]), what);
// Fence on updated location? // Fence on updated location?
return true; return true;
} }
-5
View File
@@ -334,11 +334,6 @@ inline bool PermanentOrFrozen(ObjHeader* obj) {
return container == nullptr || container->frozen(); return container == nullptr || container->frozen();
} }
inline uint32_t ArrayDataSizeBytes(const ArrayHeader* obj) {
// Instance size is negative.
return -obj->type_info()->instanceSize_ * obj->count_;
}
// Class representing arbitrary placement container. // Class representing arbitrary placement container.
class Container { class Container {
protected: protected:
+22 -18
View File
@@ -20,60 +20,64 @@
#include "Types.h" #include "Types.h"
#include "Exceptions.h" #include "Exceptions.h"
inline void* AddressOfElementAt(ArrayHeader* obj, int32_t index) { constexpr size_t alignUp(size_t size, size_t alignment) {
// Instance size is negative. return (size + alignment - 1) & ~(alignment - 1);
return reinterpret_cast<uint8_t*>(obj + 1) -
obj->type_info()->instanceSize_ * index;
} }
inline const void* AddressOfElementAt(const ArrayHeader* obj, int32_t index) { template <typename T>
// Instance size is negative. inline T* AddressOfElementAt(ArrayHeader* obj, KInt index) {
return reinterpret_cast<const uint8_t*>(obj + 1) - int8_t* body = reinterpret_cast<int8_t*>(obj) + alignUp(sizeof(ArrayHeader), alignof(T));
obj->type_info()->instanceSize_ * index; return reinterpret_cast<T*>(body) + index;
}
template <typename T>
inline const T* AddressOfElementAt(const ArrayHeader* obj, KInt index) {
const int8_t* body = reinterpret_cast<const int8_t*>(obj) + alignUp(sizeof(ArrayHeader), alignof(T));
return reinterpret_cast<const T*>(body) + index;
} }
// Optimized versions not accessing type info. // Optimized versions not accessing type info.
inline KByte* ByteArrayAddressOfElementAt(ArrayHeader* obj, KInt index) { inline KByte* ByteArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
return reinterpret_cast<KByte*>(obj + 1) + index; return AddressOfElementAt<KByte>(obj, index);
} }
inline const KByte* ByteArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) { inline const KByte* ByteArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
return reinterpret_cast<const KByte*>(obj + 1) + index; return AddressOfElementAt<KByte>(obj, index);
} }
inline KChar* CharArrayAddressOfElementAt(ArrayHeader* obj, KInt index) { inline KChar* CharArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
return reinterpret_cast<KChar*>(obj + 1) + index; return AddressOfElementAt<KChar>(obj, index);
} }
inline const KChar* CharArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) { inline const KChar* CharArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
return reinterpret_cast<const KChar*>(obj + 1) + index; return AddressOfElementAt<KChar>(obj, index);
} }
inline KInt* IntArrayAddressOfElementAt(ArrayHeader* obj, KInt index) { inline KInt* IntArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
return reinterpret_cast<KInt*>(obj + 1) + index; return AddressOfElementAt<KInt>(obj, index);
} }
inline const KInt* IntArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) { inline const KInt* IntArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
return reinterpret_cast<const KInt*>(obj + 1) + index; return AddressOfElementAt<KInt>(obj, index);
} }
// Consider aligning of base to sizeof(T). // Consider aligning of base to sizeof(T).
template <typename T> template <typename T>
inline T* PrimitiveArrayAddressOfElementAt(ArrayHeader* obj, KInt index) { inline T* PrimitiveArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
return reinterpret_cast<T*>(obj + 1) + index; return AddressOfElementAt<T>(obj, index);
} }
template <typename T> template <typename T>
inline const T* PrimitiveArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) { inline const T* PrimitiveArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
return reinterpret_cast<const T*>(obj + 1) + index; return AddressOfElementAt<T>(obj, index);
} }
inline KRef* ArrayAddressOfElementAt(ArrayHeader* obj, KInt index) { inline KRef* ArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
return reinterpret_cast<KRef*>(obj + 1) + index; return AddressOfElementAt<KRef>(obj, index);
} }
inline const KRef* ArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) { inline const KRef* ArrayAddressOfElementAt(const ArrayHeader* obj, KInt index) {
return reinterpret_cast<const KRef*>(obj + 1) + index; return AddressOfElementAt<KRef>(obj, index);
} }
#ifdef __cplusplus #ifdef __cplusplus
+15 -5
View File
@@ -18,7 +18,17 @@
namespace { namespace {
// TODO: an ugly hack with fixed offsets. // TODO: an ugly hack with fixed layout.
struct WeakReferenceCounter {
ObjHeader header;
KRef referred;
KInt lock;
};
inline WeakReferenceCounter* asWeakReferenceCounter(ObjHeader* obj) {
return reinterpret_cast<WeakReferenceCounter*>(obj);
}
constexpr int referredOffset = 0; constexpr int referredOffset = 0;
constexpr int lockOffset = sizeof(void*); constexpr int lockOffset = sizeof(void*);
@@ -64,11 +74,11 @@ OBJ_GETTER(Konan_getWeakReferenceImpl, ObjHeader* referred) {
// Materialize a weak reference to either null or the real reference. // Materialize a weak reference to either null or the real reference.
OBJ_GETTER(Konan_WeakReferenceCounter_get, ObjHeader* counter) { OBJ_GETTER(Konan_WeakReferenceCounter_get, ObjHeader* counter) {
ObjHeader** referredAddress = reinterpret_cast<ObjHeader**>(reinterpret_cast<char*>(counter + 1) + referredOffset); ObjHeader** referredAddress = &asWeakReferenceCounter(counter)->referred;
#if KONAN_NO_THREADS #if KONAN_NO_THREADS
RETURN_OBJ(*referredAddress); RETURN_OBJ(*referredAddress);
#else #else
int32_t* lockAddress = reinterpret_cast<int32_t*>(reinterpret_cast<char*>(counter + 1) + lockOffset); int32_t* lockAddress = &asWeakReferenceCounter(counter)->lock;
// Spinlock. // Spinlock.
lock(lockAddress); lock(lockAddress);
ObjHolder holder(*referredAddress); ObjHolder holder(*referredAddress);
@@ -78,12 +88,12 @@ OBJ_GETTER(Konan_WeakReferenceCounter_get, ObjHeader* counter) {
} }
void WeakReferenceCounterClear(ObjHeader* counter) { void WeakReferenceCounterClear(ObjHeader* counter) {
ObjHeader** referredAddress = reinterpret_cast<ObjHeader**>(reinterpret_cast<char*>(counter + 1) + referredOffset); ObjHeader** referredAddress = &asWeakReferenceCounter(counter)->referred;
// Note, that we don't do UpdateRef here, as reference is weak. // Note, that we don't do UpdateRef here, as reference is weak.
#if KONAN_NO_THREADS #if KONAN_NO_THREADS
*referredAddress = nullptr; *referredAddress = nullptr;
#else #else
int32_t* lockAddress = reinterpret_cast<int32_t*>(reinterpret_cast<char*>(counter + 1) + lockOffset); int32_t* lockAddress = &asWeakReferenceCounter(counter)->lock;
// Spinlock. // Spinlock.
lock(lockAddress); lock(lockAddress);
*referredAddress = nullptr; *referredAddress = nullptr;