Improve code related to object layout (#2446)
This commit is contained in:
committed by
Nikolay Igotti
parent
ca9c4cde51
commit
328413337b
@@ -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 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 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 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) }
|
||||
|
||||
// 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 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 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) }
|
||||
|
||||
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")
|
||||
private external fun getAddressOfElement(array: Any, index: Int): COpaquePointer
|
||||
@SymbolName("Kotlin_Arrays_getByteArrayAddressOfElement")
|
||||
private external fun ByteArray.addressOfElement(index: Int): CPointer<ByteVar>
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
private inline fun <P : CVariable> Pinned<*>.addressOfElement(index: Int): CPointer<P> =
|
||||
getAddressOfElement(this.get(), index).reinterpret()
|
||||
@SymbolName("Kotlin_Arrays_getShortArrayAddressOfElement")
|
||||
private external fun ShortArray.addressOfElement(index: Int): CPointer<ShortVar>
|
||||
|
||||
@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>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getAddressOfElement")
|
||||
@SymbolName("Kotlin_Arrays_getShortArrayAddressOfElement")
|
||||
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>
|
||||
|
||||
@SymbolName("Kotlin_Arrays_getAddressOfElement")
|
||||
@SymbolName("Kotlin_Arrays_getLongArrayAddressOfElement")
|
||||
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>
|
||||
|
||||
+1
-1
@@ -1592,7 +1592,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
||||
|
||||
functionGenerationContext.gep(objCPtr, bodyOffset)
|
||||
} else {
|
||||
LLVMBuildGEP(functionGenerationContext.builder, objectPtr, cValuesOf(kImmOne), 1, "")!!
|
||||
objectPtr
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -133,7 +133,8 @@ private fun Context.getDeclaredFields(classDescriptor: ClassDescriptor): List<Ir
|
||||
}
|
||||
|
||||
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)!!
|
||||
|
||||
@@ -369,7 +370,7 @@ private class DeclarationsGeneratorVisitor(override val context: Context) :
|
||||
error(containingClass.descriptor.toString())
|
||||
val allFields = classDeclarations.fields
|
||||
this.fields[descriptor] = FieldLlvmDeclarations(
|
||||
allFields.indexOf(descriptor),
|
||||
allFields.indexOf(descriptor) + 1, // First field is ObjHeader.
|
||||
classDeclarations.bodyType
|
||||
)
|
||||
} else {
|
||||
|
||||
+3
-3
@@ -289,9 +289,9 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
NullPointer(int32Type), NullPointer(int8Type), NullPointer(kInt8Ptr))
|
||||
} else {
|
||||
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(
|
||||
LLVMOffsetOfElement(llvmTargetData, bodyType, index).toInt(),
|
||||
LLVMOffsetOfElement(llvmTargetData, bodyType, index + 1).toInt(),
|
||||
mapRuntimeType(type),
|
||||
llvmDeclarations.fields[index].name.asString())
|
||||
}
|
||||
@@ -316,7 +316,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
): ConstPointer {
|
||||
assert(descriptor.isInterface)
|
||||
|
||||
val size = 0
|
||||
val size = LLVMStoreSizeOfType(llvmTargetData, kObjHeader).toInt()
|
||||
|
||||
val superClass = context.ir.symbols.any.owner
|
||||
|
||||
|
||||
+8
-14
@@ -71,24 +71,20 @@ internal fun StaticData.createConstKotlinArray(arrayClass: IrClass, elements: Li
|
||||
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 compositeType = structType(runtime.objHeaderType, body.llvmType)
|
||||
|
||||
val global = this.createGlobal(compositeType, "")
|
||||
|
||||
val objHeaderPtr = global.pointer.getElementPtr(0)
|
||||
val objHeader = objHeader(typeInfo)
|
||||
|
||||
global.setInitializer(Struct(compositeType, objHeader, body))
|
||||
val global = this.placeGlobal("", Struct(objHeader, *fields))
|
||||
global.setConstant(true)
|
||||
|
||||
val objHeaderPtr = global.pointer.getElementPtr(0)
|
||||
|
||||
return createRef(objHeaderPtr)
|
||||
}
|
||||
|
||||
internal fun StaticData.createInitializer(type: IrClass, body: ConstValue): ConstValue =
|
||||
Struct(objHeader(type.typeInfoPtr), body)
|
||||
internal fun StaticData.createInitializer(type: IrClass, vararg fields: ConstValue): ConstValue =
|
||||
Struct(objHeader(type.typeInfoPtr), *fields)
|
||||
|
||||
private fun StaticData.getArrayListClass(): ClassDescriptor {
|
||||
val module = context.irModule!!.descriptor
|
||||
@@ -122,15 +118,13 @@ internal fun StaticData.createConstArrayList(array: ConstPointer, length: Int):
|
||||
val fqName = it.fqNameSafe.asString()
|
||||
sorted.put(fqName, arrayListFields[fqName]!!)
|
||||
}
|
||||
|
||||
val body = Struct(*(sorted.values.toTypedArray()))
|
||||
|
||||
return createConstKotlinObject(arrayListClass, body)
|
||||
return createConstKotlinObject(arrayListClass, *sorted.values.toTypedArray())
|
||||
}
|
||||
|
||||
internal fun StaticData.createUniqueInstance(
|
||||
kind: UniqueKind, bodyType: LLVMTypeRef, typeInfo: ConstPointer): ConstPointer {
|
||||
assert (getStructElements(bodyType).isEmpty())
|
||||
assert (getStructElements(bodyType).size == 1) // ObjHeader only.
|
||||
val objHeader = when (kind) {
|
||||
UniqueKind.UNIT -> objHeader(typeInfo)
|
||||
UniqueKind.EMPTY_ARRAY -> arrayHeader(typeInfo, 0)
|
||||
|
||||
@@ -489,13 +489,58 @@ KNativePtr Kotlin_ImmutableBlob_asCPointerImpl(KRef thiz, KInt 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();
|
||||
if (index < 0 || index >= array->count_) {
|
||||
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"
|
||||
|
||||
@@ -23,37 +23,48 @@
|
||||
namespace {
|
||||
|
||||
struct AtomicReferenceLayout {
|
||||
ObjHeader header;
|
||||
KRef value_;
|
||||
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) {
|
||||
volatile T* location = reinterpret_cast<volatile T*>(thiz + 1);
|
||||
volatile T* location = getValueLocation<T>(thiz);
|
||||
atomicSet(location, value);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
template <typename T> T compareAndSwapImpl(KRef thiz, T expectedValue, T newValue) {
|
||||
volatile T* location = reinterpret_cast<volatile T*>(thiz + 1);
|
||||
return compareAndSwap(location, expectedValue, newValue);
|
||||
volatile T* location = getValueLocation<T>(thiz);
|
||||
return compareAndSwap(location, expectedValue, 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);
|
||||
}
|
||||
|
||||
inline AtomicReferenceLayout* asAtomicReference(KRef thiz) {
|
||||
return reinterpret_cast<AtomicReferenceLayout*>(thiz + 1);
|
||||
return reinterpret_cast<AtomicReferenceLayout*>(thiz);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -93,7 +104,7 @@ KLong Kotlin_AtomicLong_compareAndSwap(KRef thiz, KLong expectedValue, KLong new
|
||||
// Potentially huge performance penalty, but correct.
|
||||
// TODO: reconsider, once target MIPS can do proper 64-bit CAS.
|
||||
while (compareAndSwap(&lock64, 0, 1) != 0);
|
||||
KLong* address = reinterpret_cast<KLong*>(thiz + 1);
|
||||
volatile KLong* address = getValueLocation<KLong>(thiz);
|
||||
KLong old = *address;
|
||||
if (old == expectedValue) {
|
||||
*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.
|
||||
KBoolean result = false;
|
||||
while (compareAndSwap(&lock64, 0, 1) != 0);
|
||||
KLong* address = reinterpret_cast<KLong*>(thiz + 1);
|
||||
volatile KLong* address = getValueLocation<KLong>(thiz);
|
||||
KLong old = *address;
|
||||
if (old == expectedValue) {
|
||||
result = true;
|
||||
@@ -129,7 +140,7 @@ void Kotlin_AtomicLong_set(KRef thiz, KLong newValue) {
|
||||
// Potentially huge performance penalty, but correct.
|
||||
// TODO: reconsider, once target MIPS can do proper 64-bit atomic store.
|
||||
while (compareAndSwap(&lock64, 0, 1) != 0);
|
||||
KLong* address = reinterpret_cast<KLong*>(thiz + 1);
|
||||
volatile KLong* address = getValueLocation<KLong>(thiz);
|
||||
*address = newValue;
|
||||
compareAndSwap(&lock64, 1, 0);
|
||||
#else
|
||||
@@ -142,7 +153,7 @@ KLong Kotlin_AtomicLong_get(KRef thiz) {
|
||||
// Potentially huge performance penalty, but correct.
|
||||
// TODO: reconsider, once target MIPS can do proper 64-bit atomic store.
|
||||
while (compareAndSwap(&lock64, 0, 1) != 0);
|
||||
KLong* address = reinterpret_cast<KLong*>(thiz + 1);
|
||||
volatile KLong* address = getValueLocation<KLong>(thiz);
|
||||
KLong value = *address;
|
||||
compareAndSwap(&lock64, 1, 0);
|
||||
return value;
|
||||
|
||||
@@ -45,6 +45,19 @@ constexpr int runtimeTypeSize[] = {
|
||||
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
|
||||
|
||||
extern "C" {
|
||||
@@ -130,13 +143,16 @@ RUNTIME_USED void* Konan_DebugGetFieldAddress(KRef obj, int index) {
|
||||
if (index > obj->array()->count_)
|
||||
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_)
|
||||
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.
|
||||
|
||||
@@ -47,6 +47,9 @@ constexpr container_size_t kContainerAlignment = 1024;
|
||||
// Single object alignment.
|
||||
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
|
||||
#define MEMORY_LOG(...) konan::consolePrintf(__VA_ARGS__);
|
||||
#else
|
||||
@@ -396,14 +399,25 @@ inline container_size_t alignUp(container_size_t size, int alignment) {
|
||||
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?
|
||||
inline container_size_t objectSize(const ObjHeader* obj) {
|
||||
const TypeInfo* type_info = obj->type_info();
|
||||
container_size_t size = (type_info->instanceSize_ < 0 ?
|
||||
// An array.
|
||||
ArrayDataSizeBytes(obj->array()) + sizeof(ArrayHeader)
|
||||
arrayObjectSize(obj->array())
|
||||
:
|
||||
type_info->instanceSize_ + sizeof(ObjHeader));
|
||||
type_info->instanceSize_);
|
||||
return alignUp(size, kObjectAlignment);
|
||||
}
|
||||
|
||||
@@ -494,7 +508,7 @@ inline void traverseContainerObjectFields(ContainerHeader* container, func proce
|
||||
if (typeInfo != theArrayTypeInfo) {
|
||||
for (int index = 0; index < typeInfo->objOffsetsCount_; index++) {
|
||||
ObjHeader** location = reinterpret_cast<ObjHeader**>(
|
||||
reinterpret_cast<uintptr_t>(obj + 1) + typeInfo->objOffsets_[index]);
|
||||
reinterpret_cast<uintptr_t>(obj) + typeInfo->objOffsets_[index]);
|
||||
process(location);
|
||||
}
|
||||
} else {
|
||||
@@ -1003,7 +1017,7 @@ void FreeContainer(ContainerHeader* container) {
|
||||
void ObjectContainer::Init(const TypeInfo* typeInfo) {
|
||||
RuntimeAssert(typeInfo->instanceSize_ >= 0, "Must be an object");
|
||||
uint32_t alloc_size =
|
||||
sizeof(ContainerHeader) + sizeof(ObjHeader) + typeInfo->instanceSize_;
|
||||
sizeof(ContainerHeader) + typeInfo->instanceSize_;
|
||||
header_ = AllocContainer(alloc_size);
|
||||
if (header_) {
|
||||
// One object in this container.
|
||||
@@ -1018,8 +1032,7 @@ void ObjectContainer::Init(const TypeInfo* typeInfo) {
|
||||
void ArrayContainer::Init(const TypeInfo* typeInfo, uint32_t elements) {
|
||||
RuntimeAssert(typeInfo->instanceSize_ < 0, "Must be an array");
|
||||
uint32_t alloc_size =
|
||||
sizeof(ContainerHeader) + sizeof(ArrayHeader) -
|
||||
typeInfo->instanceSize_ * elements;
|
||||
sizeof(ContainerHeader) + arrayObjectSize(typeInfo, elements);
|
||||
header_ = AllocContainer(alloc_size);
|
||||
RuntimeAssert(header_ != nullptr, "Cannot alloc memory");
|
||||
if (header_) {
|
||||
@@ -1030,7 +1043,7 @@ void ArrayContainer::Init(const TypeInfo* typeInfo, uint32_t elements) {
|
||||
SetHeader(GetPlace()->obj(), typeInfo);
|
||||
MEMORY_LOG("array at %p\n", GetPlace())
|
||||
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) {
|
||||
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));
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
@@ -1115,12 +1128,12 @@ ObjHeader* ArenaContainer::PlaceObject(const TypeInfo* type_info) {
|
||||
|
||||
ArrayHeader* ArenaContainer::PlaceArray(const TypeInfo* type_info, uint32_t count) {
|
||||
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));
|
||||
if (!result) {
|
||||
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();
|
||||
setHeader(result->obj(), type_info);
|
||||
result->count_ = count;
|
||||
@@ -1923,7 +1936,7 @@ KBoolean Konan_ensureAcyclicAndSet(ObjHeader* where, KInt index, ObjHeader* what
|
||||
if (!acyclic) return false;
|
||||
}
|
||||
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?
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -334,11 +334,6 @@ inline bool PermanentOrFrozen(ObjHeader* obj) {
|
||||
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 Container {
|
||||
protected:
|
||||
|
||||
@@ -20,60 +20,64 @@
|
||||
#include "Types.h"
|
||||
#include "Exceptions.h"
|
||||
|
||||
inline void* AddressOfElementAt(ArrayHeader* obj, int32_t index) {
|
||||
// Instance size is negative.
|
||||
return reinterpret_cast<uint8_t*>(obj + 1) -
|
||||
obj->type_info()->instanceSize_ * index;
|
||||
constexpr size_t alignUp(size_t size, size_t alignment) {
|
||||
return (size + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
inline const void* AddressOfElementAt(const ArrayHeader* obj, int32_t index) {
|
||||
// Instance size is negative.
|
||||
return reinterpret_cast<const uint8_t*>(obj + 1) -
|
||||
obj->type_info()->instanceSize_ * index;
|
||||
template <typename T>
|
||||
inline T* AddressOfElementAt(ArrayHeader* obj, KInt index) {
|
||||
int8_t* body = reinterpret_cast<int8_t*>(obj) + alignUp(sizeof(ArrayHeader), alignof(T));
|
||||
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.
|
||||
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) {
|
||||
return reinterpret_cast<const KByte*>(obj + 1) + index;
|
||||
return AddressOfElementAt<KByte>(obj, 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) {
|
||||
return reinterpret_cast<const KChar*>(obj + 1) + index;
|
||||
return AddressOfElementAt<KChar>(obj, 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) {
|
||||
return reinterpret_cast<const KInt*>(obj + 1) + index;
|
||||
return AddressOfElementAt<KInt>(obj, index);
|
||||
}
|
||||
|
||||
// Consider aligning of base to sizeof(T).
|
||||
template <typename T>
|
||||
inline T* PrimitiveArrayAddressOfElementAt(ArrayHeader* obj, KInt index) {
|
||||
return reinterpret_cast<T*>(obj + 1) + index;
|
||||
return AddressOfElementAt<T>(obj, index);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
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) {
|
||||
return reinterpret_cast<KRef*>(obj + 1) + index;
|
||||
return AddressOfElementAt<KRef>(obj, 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
|
||||
|
||||
@@ -18,7 +18,17 @@
|
||||
|
||||
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 lockOffset = sizeof(void*);
|
||||
|
||||
@@ -64,11 +74,11 @@ OBJ_GETTER(Konan_getWeakReferenceImpl, ObjHeader* referred) {
|
||||
|
||||
// Materialize a weak reference to either null or the real reference.
|
||||
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
|
||||
RETURN_OBJ(*referredAddress);
|
||||
#else
|
||||
int32_t* lockAddress = reinterpret_cast<int32_t*>(reinterpret_cast<char*>(counter + 1) + lockOffset);
|
||||
int32_t* lockAddress = &asWeakReferenceCounter(counter)->lock;
|
||||
// Spinlock.
|
||||
lock(lockAddress);
|
||||
ObjHolder holder(*referredAddress);
|
||||
@@ -78,12 +88,12 @@ OBJ_GETTER(Konan_WeakReferenceCounter_get, 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.
|
||||
#if KONAN_NO_THREADS
|
||||
*referredAddress = nullptr;
|
||||
#else
|
||||
int32_t* lockAddress = reinterpret_cast<int32_t*>(reinterpret_cast<char*>(counter + 1) + lockOffset);
|
||||
int32_t* lockAddress = &asWeakReferenceCounter(counter)->lock;
|
||||
// Spinlock.
|
||||
lock(lockAddress);
|
||||
*referredAddress = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user