Skip to content

Commit 0abcd62

Browse files
authored
Meta-object support. (JetBrains#1451)
1 parent 0bfa68c commit 0abcd62

7 files changed

Lines changed: 128 additions & 86 deletions

File tree

backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/CodeGenerator.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,9 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
616616
val typeInfoPtr: LLVMValueRef = if (owner.isObjCClass()) {
617617
call(context.llvm.getObjCKotlinTypeInfo, listOf(receiver))
618618
} else {
619-
val typeInfoPtrPtr = LLVMBuildStructGEP(builder, receiver, 0 /* type_info */, "")!!
619+
val typeInfoOrMetaPtr = structGep(receiver, 0 /* typeInfoOrMeta_ */)
620+
val typeInfoOrMeta = load(typeInfoOrMetaPtr)
621+
val typeInfoPtrPtr = structGep(typeInfoOrMeta, 0 /* typeInfo */)
620622
load(typeInfoPtrPtr)
621623
}
622624

@@ -655,10 +657,10 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
655657

656658
val objectPtr = codegen.getObjectInstanceStorage(descriptor, shared)
657659
val bbCurrent = currentBlock
658-
val bbInit = basicBlock("label_init", locationInfo)
659-
val bbExit = basicBlock("label_continue", locationInfo)
660+
val bbInit= basicBlock("label_init", locationInfo)
661+
val bbExit= basicBlock("label_continue", locationInfo)
660662
val objectVal = loadSlot(objectPtr, false)
661-
val objectInitialized = icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType)
663+
val objectInitialized= icmpUGt(ptrToInt(objectVal, codegen.intPtrType), codegen.immOneIntPtrType)
662664
condBr(objectInitialized, bbExit, bbInit)
663665

664666
positionAtEnd(bbInit)

backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ internal val LLVMValueRef.type: LLVMTypeRef
2727
* Represents the value which can be emitted as bitcode const value
2828
*/
2929
internal interface ConstValue {
30-
3130
val llvm: LLVMValueRef
3231
}
3332

@@ -54,9 +53,8 @@ private class ConstGetElementPtr(val pointer: ConstPointer, val index: Int) : Co
5453

5554
internal fun ConstPointer.bitcast(toType: LLVMTypeRef) = constPointer(LLVMConstBitCast(this.llvm, toType)!!)
5655

57-
internal class ConstArray(val elemType: LLVMTypeRef?, val elements: List<ConstValue>) : ConstValue {
58-
59-
override val llvm = LLVMConstArray(elemType, elements.map { it.llvm }.toCValues(), elements.size)!!
56+
internal class ConstArray(elementType: LLVMTypeRef?, val elements: List<ConstValue>) : ConstValue {
57+
override val llvm = LLVMConstArray(elementType, elements.map { it.llvm }.toCValues(), elements.size)!!
6058
}
6159

6260
internal open class Struct(val type: LLVMTypeRef?, val elements: List<ConstValue?>) : ConstValue {
@@ -108,7 +106,7 @@ internal class Zero(val type: LLVMTypeRef) : ConstValue {
108106
override val llvm = LLVMConstNull(type)!!
109107
}
110108

111-
internal class NullPointer(val pointeeType: LLVMTypeRef): ConstPointer {
109+
internal class NullPointer(pointeeType: LLVMTypeRef): ConstPointer {
112110
override val llvm = LLVMConstNull(pointerType(pointeeType))!!
113111
}
114112

@@ -149,7 +147,6 @@ internal val kInt8Ptr = pointerType(int8Type)
149147
internal val kInt8PtrPtr = pointerType(kInt8Ptr)
150148
internal val kNullInt8Ptr = LLVMConstNull(kInt8Ptr)!!
151149
internal val kImmInt32One = Int32(1).llvm
152-
internal val kImmInt64One = Int64(1).llvm
153150
internal val ContextUtils.kNullObjHeaderPtr: LLVMValueRef
154151
get() = LLVMConstNull(this.kObjHeaderPtr)!!
155152
internal val ContextUtils.kNullObjHeaderPtrPtr: LLVMValueRef

backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/RTTIGenerator.kt

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,28 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
3535
inner class MethodTableRecord(val nameSignature: LocalHash, val methodEntryPoint: ConstPointer?) :
3636
Struct(runtime.methodTableRecordType, nameSignature, methodEntryPoint)
3737

38-
private inner class TypeInfo(val name: ConstValue, val size: Int,
39-
val superType: ConstValue,
40-
val objOffsets: ConstValue,
41-
val objOffsetsCount: Int,
42-
val interfaces: ConstValue,
43-
val interfacesCount: Int,
44-
val methods: ConstValue,
45-
val methodsCount: Int,
46-
val fields: ConstValue,
47-
val fieldsCount: Int,
48-
val packageName: String?,
49-
val relativeName: String?,
50-
val writableTypeInfo: ConstPointer?) :
38+
private inner class TypeInfo(
39+
selfPtr: ConstPointer,
40+
name: ConstValue,
41+
size: Int,
42+
superType: ConstValue,
43+
objOffsets: ConstValue,
44+
objOffsetsCount: Int,
45+
interfaces: ConstValue,
46+
interfacesCount: Int,
47+
methods: ConstValue,
48+
methodsCount: Int,
49+
fields: ConstValue,
50+
fieldsCount: Int,
51+
packageName: String?,
52+
relativeName: String?,
53+
writableTypeInfo: ConstPointer?) :
54+
5155
Struct(
5256
runtime.typeInfoType,
5357

58+
selfPtr,
59+
5460
name,
5561
Int32(size),
5662

@@ -162,8 +168,11 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
162168
runtime.methodTableRecordType, methods)
163169

164170
val reflectionInfo = getReflectionInfo(classDesc)
165-
166-
val typeInfo = TypeInfo(name, size,
171+
val typeInfoGlobal = llvmDeclarations.typeInfoGlobal
172+
val typeInfo = TypeInfo(
173+
classDesc.typeInfoPtr,
174+
name,
175+
size,
167176
superType,
168177
objOffsetsPtr, objOffsets.size,
169178
interfacesPtr, interfaces.size,
@@ -174,8 +183,6 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
174183
llvmDeclarations.writableTypeInfoGlobal?.pointer
175184
)
176185

177-
val typeInfoGlobal = llvmDeclarations.typeInfoGlobal
178-
179186
val typeInfoGlobalValue = if (!classDesc.typeInfoHasVtableAttached) {
180187
typeInfo
181188
} else {
@@ -265,8 +272,12 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
265272
.also { it.setZeroInitializer() }
266273
.pointer
267274
}
268-
269-
val typeInfo = TypeInfo(
275+
val vtable = vtable(superClass)
276+
val typeInfoWithVtableType = structType(runtime.typeInfoType, vtable.llvmType)
277+
val typeInfoWithVtableGlobal = staticData.createGlobal(typeInfoWithVtableType, "", isExported = false)
278+
val result = typeInfoWithVtableGlobal.pointer.getElementPtr(0)
279+
val typeInfoWithVtable = Struct(TypeInfo(
280+
selfPtr = result,
270281
name = name,
271282
size = size,
272283
superType = superClass.typeInfoPtr,
@@ -277,12 +288,12 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
277288
packageName = reflectionInfo.packageName,
278289
relativeName = reflectionInfo.relativeName,
279290
writableTypeInfo = writableTypeInfo
280-
)
291+
), vtable)
281292

282-
val vtable = vtable(superClass)
293+
typeInfoWithVtableGlobal.setInitializer(typeInfoWithVtable)
294+
typeInfoWithVtableGlobal.setConstant(true)
283295

284-
return staticData.placeGlobal("", Struct(typeInfo, vtable))
285-
.pointer.getElementPtr(0)
296+
return result
286297
}
287298

288299
private val OverriddenFunctionDescriptor.implementation get() = getImplementation(context)

runtime/src/main/cpp/Arrays.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ static inline void copyImpl(KConstRef thiz, KInt fromIndex,
4242
namespace {
4343

4444
const ArrayHeader anEmptyArray = {
45-
theArrayTypeInfo, /* permanent object */ 0, /* element count */ 0
45+
const_cast<TypeInfo*>(theArrayTypeInfo), /* permanent object */ 0, /* element count */ 0
4646
};
4747

4848
} // namespace

runtime/src/main/cpp/Memory.cpp

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@
3939
// Auto-adjust GC thresholds.
4040
#define GC_ERGONOMICS 1
4141

42-
// TODO: ensure it it read-only.
42+
// TODO: ensure it is read-only.
4343
ContainerHeader ObjHeader::theStaticObjectsContainer = {
44-
CONTAINER_TAG_PERMANENT | CONTAINER_TAG_INCREMENT
44+
CONTAINER_TAG_PERMANENT | CONTAINER_TAG_INCREMENT,
45+
0 /* Object count */
4546
};
4647

4748
namespace {
@@ -416,7 +417,11 @@ RUNTIME_NORETURN void ThrowInvalidMutabilityException();
416417
} // extern "C"
417418

418419
inline void runDeallocationHooks(ObjHeader* obj) {
420+
if (obj->has_meta_object()) {
421+
ObjHeader::destroyMetaObject(&obj->typeInfoOrMeta_);
422+
}
419423
#if KONAN_OBJC_INTEROP
424+
// TODO: rewrite using meta-object.
420425
if (obj->type_info() == theObjCPointerHolderTypeInfo) {
421426
void* objcPtr = *reinterpret_cast<void**>(obj + 1); // TODO: use more reliable layout description
422427
objc_release(objcPtr);
@@ -806,6 +811,29 @@ inline size_t containerSize(const ContainerHeader* container) {
806811

807812
} // namespace
808813

814+
MetaObjHeader* ObjHeader::createMetaObject(TypeInfo** location) {
815+
MetaObjHeader* meta = konanConstructInstance<MetaObjHeader>();
816+
TypeInfo* typeInfo = *location;
817+
meta->typeInfo_ = typeInfo;
818+
#if KONAN_NO_THREADS
819+
*location = reinterpret_cast<TypeInfo*>(meta);
820+
#else
821+
TypeInfo* old = __sync_val_compare_and_swap(location, typeInfo, reinterpret_cast<TypeInfo*>(meta));
822+
if (old->typeInfo_ != old) {
823+
// Someone installed a new meta-object since the check.
824+
konanFreeMemory(meta);
825+
meta = reinterpret_cast<MetaObjHeader*>(old);
826+
}
827+
#endif
828+
return meta;
829+
}
830+
831+
void ObjHeader::destroyMetaObject(TypeInfo** location) {
832+
TypeInfo* meta = *location;
833+
*location = nullptr;
834+
konanFreeMemory(meta);
835+
}
836+
809837
ContainerHeader* AllocContainer(size_t size) {
810838
auto state = memoryState;
811839
#if USE_GC
@@ -842,37 +870,37 @@ void FreeContainer(ContainerHeader* header) {
842870
}
843871
}
844872

845-
void ObjectContainer::Init(const TypeInfo* type_info) {
846-
RuntimeAssert(type_info->instanceSize_ >= 0, "Must be an object");
873+
void ObjectContainer::Init(const TypeInfo* typeInfo) {
874+
RuntimeAssert(typeInfo->instanceSize_ >= 0, "Must be an object");
847875
uint32_t alloc_size =
848-
sizeof(ContainerHeader) + sizeof(ObjHeader) + type_info->instanceSize_ + kObjectReservedTailSize;
876+
sizeof(ContainerHeader) + sizeof(ObjHeader) + typeInfo->instanceSize_ + kObjectReservedTailSize;
849877
header_ = AllocContainer(alloc_size);
850878
if (header_) {
851879
// One object in this container.
852880
header_->setObjectCount(1);
853881
// header->refCount_ is zero initialized by AllocContainer().
854-
SetMeta(GetPlace(), type_info);
882+
SetHeader(GetPlace(), typeInfo);
855883
MEMORY_LOG("object at %p\n", GetPlace())
856884
OBJECT_ALLOC_EVENT(memoryState, type_info->instanceSize_, GetPlace())
857885
}
858886
}
859887

860-
void ArrayContainer::Init(const TypeInfo* type_info, uint32_t elements) {
861-
RuntimeAssert(type_info->instanceSize_ < 0, "Must be an array");
888+
void ArrayContainer::Init(const TypeInfo* typeInfo, uint32_t elements) {
889+
RuntimeAssert(typeInfo->instanceSize_ < 0, "Must be an array");
862890
uint32_t alloc_size =
863891
sizeof(ContainerHeader) + sizeof(ArrayHeader) -
864-
type_info->instanceSize_ * elements + kObjectReservedTailSize;
892+
typeInfo->instanceSize_ * elements + kObjectReservedTailSize;
865893
header_ = AllocContainer(alloc_size);
866894
RuntimeAssert(header_ != nullptr, "Cannot alloc memory");
867895
if (header_) {
868896
// One object in this container.
869897
header_->setObjectCount(1);
870898
// header->refCount_ is zero initialized by AllocContainer().
871899
GetPlace()->count_ = elements;
872-
SetMeta(GetPlace()->obj(), type_info);
900+
SetHeader(GetPlace()->obj(), typeInfo);
873901
MEMORY_LOG("array at %p\n", GetPlace())
874902
OBJECT_ALLOC_EVENT(
875-
memoryState, -type_info->instanceSize_ * elements, GetPlace()->obj())
903+
memoryState, -typeInfo->instanceSize_ * elements, GetPlace()->obj())
876904
}
877905
}
878906

@@ -951,7 +979,7 @@ ObjHeader* ArenaContainer::PlaceObject(const TypeInfo* type_info) {
951979
}
952980
OBJECT_ALLOC_EVENT(memoryState, type_info->instanceSize_, result)
953981
currentChunk_->asHeader()->incObjectCount();
954-
setMeta(result, type_info);
982+
setHeader(result, type_info);
955983
return result;
956984
}
957985

@@ -964,7 +992,7 @@ ArrayHeader* ArenaContainer::PlaceArray(const TypeInfo* type_info, uint32_t coun
964992
}
965993
OBJECT_ALLOC_EVENT(memoryState, -type_info->instanceSize_ * count, result->obj())
966994
currentChunk_->asHeader()->incObjectCount();
967-
setMeta(result->obj(), type_info);
995+
setHeader(result->obj(), type_info);
968996
result->count_ = count;
969997
return result;
970998
}
@@ -992,13 +1020,17 @@ void ReleaseRefFromAssociatedObject(const ObjHeader* object) {
9921020
extern "C" {
9931021

9941022
MemoryState* InitMemory() {
995-
RuntimeAssert(offsetof(ArrayHeader, type_info_)
1023+
RuntimeAssert(offsetof(ArrayHeader, typeInfoOrMeta_)
1024+
==
1025+
offsetof(ObjHeader, typeInfoOrMeta_),
1026+
"Layout mismatch");
1027+
RuntimeAssert(offsetof(ArrayHeader, containerOffsetNegative_)
9961028
==
997-
offsetof(ObjHeader, type_info_),
1029+
offsetof(ObjHeader , containerOffsetNegative_),
9981030
"Layout mismatch");
999-
RuntimeAssert(offsetof(ArrayHeader, container_offset_negative_)
1031+
RuntimeAssert(offsetof(TypeInfo, typeInfo_)
10001032
==
1001-
offsetof(ObjHeader , container_offset_negative_),
1033+
offsetof(MetaObjHeader, typeInfo_),
10021034
"Layout mismatch");
10031035
RuntimeAssert(sizeof(FrameOverlay) % sizeof(ObjHeader**) == 0, "Frame overlay should contain only pointers")
10041036
RuntimeAssert(memoryState == nullptr, "memory state must be clear");

0 commit comments

Comments
 (0)