Group slots together. (#166)
This commit is contained in:
+39
-6
@@ -18,6 +18,8 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
var constructedClass: ClassDescriptor? = null
|
var constructedClass: ClassDescriptor? = null
|
||||||
val vars = VariableManager(this)
|
val vars = VariableManager(this)
|
||||||
var returnSlot: LLVMValueRef? = null
|
var returnSlot: LLVMValueRef? = null
|
||||||
|
var slotsPhi: LLVMValueRef? = null
|
||||||
|
var slotCount = 0
|
||||||
|
|
||||||
fun prologue(descriptor: FunctionDescriptor) {
|
fun prologue(descriptor: FunctionDescriptor) {
|
||||||
prologue(llvmFunction(descriptor),
|
prologue(llvmFunction(descriptor),
|
||||||
@@ -41,17 +43,34 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
entryBb = LLVMAppendBasicBlock(function, "entry")
|
entryBb = LLVMAppendBasicBlock(function, "entry")
|
||||||
epilogueBb = LLVMAppendBasicBlock(function, "epilogue")
|
epilogueBb = LLVMAppendBasicBlock(function, "epilogue")
|
||||||
positionAtEnd(entryBb!!)
|
positionAtEnd(entryBb!!)
|
||||||
|
slotsPhi = phi(kObjHeaderPtrPtr)
|
||||||
|
slotCount = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
fun epilogue() {
|
fun epilogue() {
|
||||||
appendingTo(prologueBb!!) {
|
appendingTo(prologueBb!!) {
|
||||||
|
val slots = if (slotCount > 0)
|
||||||
|
LLVMBuildArrayAlloca(builder, kObjHeaderPtr, Int32(slotCount).llvm, "")!!
|
||||||
|
else
|
||||||
|
kNullObjHeaderPtrPtr
|
||||||
|
if (slotCount > 0) {
|
||||||
|
// Zero-init slots.
|
||||||
|
val slotsMem = bitcast(kInt8Ptr, slots)
|
||||||
|
val pointerSize = LLVMABISizeOfType(llvmTargetData, kObjHeaderPtr).toInt()
|
||||||
|
val alignment = LLVMABIAlignmentOfType(llvmTargetData, kObjHeaderPtr)
|
||||||
|
call(context.llvm.memsetFunction,
|
||||||
|
listOf(slotsMem, Int8(0).llvm,
|
||||||
|
Int32(slotCount * pointerSize).llvm, Int32(alignment).llvm,
|
||||||
|
Int1(0).llvm))
|
||||||
|
}
|
||||||
|
addPhiIncoming(slotsPhi!!, prologueBb!! to slots)
|
||||||
br(entryBb!!)
|
br(entryBb!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
appendingTo(epilogueBb!!) {
|
appendingTo(epilogueBb!!) {
|
||||||
when {
|
when {
|
||||||
returnType == voidType -> {
|
returnType == voidType -> {
|
||||||
vars.releaseVars()
|
releaseVars()
|
||||||
assert(returnSlot == null)
|
assert(returnSlot == null)
|
||||||
LLVMBuildRetVoid(builder)
|
LLVMBuildRetVoid(builder)
|
||||||
}
|
}
|
||||||
@@ -61,7 +80,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
if (returnSlot != null) {
|
if (returnSlot != null) {
|
||||||
updateLocalRef(returnPhi, returnSlot!!)
|
updateLocalRef(returnPhi, returnSlot!!)
|
||||||
}
|
}
|
||||||
vars.releaseVars()
|
releaseVars()
|
||||||
LLVMBuildRet(builder, returnPhi)
|
LLVMBuildRet(builder, returnPhi)
|
||||||
}
|
}
|
||||||
// Do nothing, all paths throw.
|
// Do nothing, all paths throw.
|
||||||
@@ -72,6 +91,14 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
returns.clear()
|
returns.clear()
|
||||||
vars.clear()
|
vars.clear()
|
||||||
returnSlot = null
|
returnSlot = null
|
||||||
|
slotsPhi = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun releaseVars() {
|
||||||
|
if (slotCount > 0) {
|
||||||
|
call(context.llvm.releaseLocalRefsFunction,
|
||||||
|
listOf(slotsPhi, Int32(slotCount).llvm))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var prologueBb: LLVMBasicBlockRef? = null
|
private var prologueBb: LLVMBasicBlockRef? = null
|
||||||
@@ -104,11 +131,11 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
fun intToPtr(imm: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildIntToPtr(builder, imm, DestTy, Name)!!
|
fun intToPtr(imm: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildIntToPtr(builder, imm, DestTy, Name)!!
|
||||||
|
|
||||||
fun alloca(type: LLVMTypeRef?, name: String = ""): LLVMValueRef {
|
fun alloca(type: LLVMTypeRef?, name: String = ""): LLVMValueRef {
|
||||||
|
if (isObjectType(type!!)) {
|
||||||
|
return gep(slotsPhi!!, Int32(slotCount++).llvm)
|
||||||
|
}
|
||||||
appendingTo(prologueBb!!) {
|
appendingTo(prologueBb!!) {
|
||||||
val result = LLVMBuildAlloca(builder, type, name)!!
|
return LLVMBuildAlloca(builder, type, name)!!
|
||||||
if (isObjectType(type!!))
|
|
||||||
LLVMBuildStore(builder, kNullObjHeaderPtr, result)
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun load(value: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildLoad(builder, value, name)!!
|
fun load(value: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildLoad(builder, value, name)!!
|
||||||
@@ -132,6 +159,12 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun gep(base: LLVMValueRef, index: LLVMValueRef): LLVMValueRef {
|
||||||
|
memScoped {
|
||||||
|
val args = allocArrayOf(index)
|
||||||
|
return LLVMBuildGEP(builder, base, args[0].ptr, 1, "")!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Only use ignoreOld, when sure that memory is freshly inited and have no value.
|
// Only use ignoreOld, when sure that memory is freshly inited and have no value.
|
||||||
fun updateLocalRef(value: LLVMValueRef, address: LLVMValueRef, ignoreOld: Boolean = false) {
|
fun updateLocalRef(value: LLVMValueRef, address: LLVMValueRef, ignoreOld: Boolean = false) {
|
||||||
|
|||||||
+10
@@ -205,6 +205,14 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
|||||||
return LLVMAddFunction(llvmModule, name, functionType)!!
|
return LLVMAddFunction(llvmModule, name, functionType)!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun importMemset() : LLVMValueRef {
|
||||||
|
memScoped {
|
||||||
|
val parameterTypes = allocArrayOf(int8TypePtr, int8Type, int32Type, int32Type, int1Type)
|
||||||
|
val functionType = LLVMFunctionType(LLVMVoidType(), parameterTypes[0].ptr, 5, 0)
|
||||||
|
return LLVMAddFunction(llvmModule, "llvm.memset.p0i8.i32", functionType)!!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val staticData = StaticData(context)
|
val staticData = StaticData(context)
|
||||||
|
|
||||||
val runtimeFile = context.config.configuration.get(KonanConfigKeys.RUNTIME_FILE)!!
|
val runtimeFile = context.config.configuration.get(KonanConfigKeys.RUNTIME_FILE)!!
|
||||||
@@ -226,6 +234,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
|||||||
val setGlobalRefFunction = importRtFunction("SetGlobalRef")
|
val setGlobalRefFunction = importRtFunction("SetGlobalRef")
|
||||||
val updateLocalRefFunction = importRtFunction("UpdateLocalRef")
|
val updateLocalRefFunction = importRtFunction("UpdateLocalRef")
|
||||||
val updateGlobalRefFunction = importRtFunction("UpdateGlobalRef")
|
val updateGlobalRefFunction = importRtFunction("UpdateGlobalRef")
|
||||||
|
val releaseLocalRefsFunction = importRtFunction("ReleaseLocalRefs")
|
||||||
val setArrayFunction = importRtFunction("Kotlin_Array_set")
|
val setArrayFunction = importRtFunction("Kotlin_Array_set")
|
||||||
val copyImplArrayFunction = importRtFunction("Kotlin_Array_copyImpl")
|
val copyImplArrayFunction = importRtFunction("Kotlin_Array_copyImpl")
|
||||||
val lookupFieldOffset = importRtFunction("LookupFieldOffset")
|
val lookupFieldOffset = importRtFunction("LookupFieldOffset")
|
||||||
@@ -234,6 +243,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
|||||||
val checkInstanceFunction = importRtFunction("CheckInstance")
|
val checkInstanceFunction = importRtFunction("CheckInstance")
|
||||||
val throwExceptionFunction = importRtFunction("ThrowException")
|
val throwExceptionFunction = importRtFunction("ThrowException")
|
||||||
val appendToInitalizersTail = importRtFunction("AppendToInitializersTail")
|
val appendToInitalizersTail = importRtFunction("AppendToInitializersTail")
|
||||||
|
val memsetFunction = importMemset()
|
||||||
val usedFunctions = mutableListOf<LLVMValueRef>()
|
val usedFunctions = mutableListOf<LLVMValueRef>()
|
||||||
val staticInitializers = mutableListOf<LLVMValueRef>()
|
val staticInitializers = mutableListOf<LLVMValueRef>()
|
||||||
val fileInitializers = mutableListOf<IrElement>()
|
val fileInitializers = mutableListOf<IrElement>()
|
||||||
|
|||||||
+7
@@ -68,6 +68,10 @@ internal open class Struct(val type: LLVMTypeRef?, val elements: List<ConstValue
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class Int1(val value: Byte) : ConstValue {
|
||||||
|
override val llvm = LLVMConstInt(LLVMInt1Type(), value.toLong(), 1)!!
|
||||||
|
}
|
||||||
|
|
||||||
internal class Int8(val value: Byte) : ConstValue {
|
internal class Int8(val value: Byte) : ConstValue {
|
||||||
override val llvm = LLVMConstInt(LLVMInt8Type(), value.toLong(), 1)!!
|
override val llvm = LLVMConstInt(LLVMInt8Type(), value.toLong(), 1)!!
|
||||||
}
|
}
|
||||||
@@ -96,6 +100,7 @@ internal fun constValue(value: LLVMValueRef) = object : ConstValue {
|
|||||||
override val llvm = value
|
override val llvm = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val int1Type = LLVMInt1Type()!!
|
||||||
internal val int8Type = LLVMInt8Type()!!
|
internal val int8Type = LLVMInt8Type()!!
|
||||||
internal val int32Type = LLVMInt32Type()!!
|
internal val int32Type = LLVMInt32Type()!!
|
||||||
internal val int8TypePtr = pointerType(int8Type)
|
internal val int8TypePtr = pointerType(int8Type)
|
||||||
@@ -129,6 +134,8 @@ internal val kImmInt32One = Int32(1).llvm
|
|||||||
internal val kImmInt64One = Int64(1).llvm
|
internal val kImmInt64One = Int64(1).llvm
|
||||||
internal val ContextUtils.kNullObjHeaderPtr: LLVMValueRef
|
internal val ContextUtils.kNullObjHeaderPtr: LLVMValueRef
|
||||||
get() = LLVMConstNull(this.kObjHeaderPtr)!!
|
get() = LLVMConstNull(this.kObjHeaderPtr)!!
|
||||||
|
internal val ContextUtils.kNullObjHeaderPtrPtr: LLVMValueRef
|
||||||
|
get() = LLVMConstNull(this.kObjHeaderPtrPtr)!!
|
||||||
|
|
||||||
// Nothing type has no values, but we do generate unreachable code and thus need some fake value:
|
// Nothing type has no values, but we do generate unreachable code and thus need some fake value:
|
||||||
internal val ContextUtils.kNothingFakeValue: LLVMValueRef
|
internal val ContextUtils.kNothingFakeValue: LLVMValueRef
|
||||||
|
|||||||
-8
@@ -52,14 +52,6 @@ internal class VariableManager(val codegen: CodeGenerator) {
|
|||||||
descriptors.clear()
|
descriptors.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun releaseVars() {
|
|
||||||
// This function is called by codegen to cleanup local references when leaving frame.
|
|
||||||
for (variable in variables) {
|
|
||||||
if (variable.isRefSlot())
|
|
||||||
codegen.updateLocalRef(codegen.kNullObjHeaderPtr, variable.address())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createVariable(scoped: Pair<VariableDescriptor, CodeContext>, value: LLVMValueRef? = null) : Int {
|
fun createVariable(scoped: Pair<VariableDescriptor, CodeContext>, value: LLVMValueRef? = null) : Int {
|
||||||
// Note that we always create slot for object references for memory management.
|
// Note that we always create slot for object references for memory management.
|
||||||
val descriptor = scoped.first
|
val descriptor = scoped.first
|
||||||
|
|||||||
@@ -55,17 +55,16 @@ void FreeContainer(ContainerHeader* header) {
|
|||||||
ObjHeader* obj = reinterpret_cast<ObjHeader*>(header + 1);
|
ObjHeader* obj = reinterpret_cast<ObjHeader*>(header + 1);
|
||||||
const TypeInfo* typeInfo = obj->type_info();
|
const TypeInfo* typeInfo = obj->type_info();
|
||||||
|
|
||||||
|
// We use *local* versions as no other threads could see dead objects.
|
||||||
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 + 1) + typeInfo->objOffsets_[index]);
|
||||||
UpdateGlobalRef(location, nullptr);
|
UpdateLocalRef(location, nullptr);
|
||||||
}
|
}
|
||||||
// Object arrays are *special*.
|
// Object arrays are *special*.
|
||||||
if (typeInfo == theArrayTypeInfo) {
|
if (typeInfo == theArrayTypeInfo) {
|
||||||
ArrayHeader* array = obj->array();
|
ArrayHeader* array = obj->array();
|
||||||
for (int index = 0; index < array->count_; index++) {
|
ReleaseLocalRefs(ArrayAddressOfElementAt(array, 0), array->count_);
|
||||||
UpdateGlobalRef(ArrayAddressOfElementAt(array, index), nullptr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// And release underlying memory.
|
// And release underlying memory.
|
||||||
@@ -152,9 +151,7 @@ inline void ReleaseRef(const ObjHeader* object) {
|
|||||||
Release(object->container());
|
Release(object->container());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
|
||||||
|
|
||||||
void InitMemory() {
|
void InitMemory() {
|
||||||
RuntimeAssert(offsetof(ArrayHeader, type_info_)
|
RuntimeAssert(offsetof(ArrayHeader, type_info_)
|
||||||
@@ -321,6 +318,50 @@ void UpdateGlobalRef(ObjHeader** location, const ObjHeader* object) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
void ReleaseLocalRefs(ObjHeader** start, int count) {
|
||||||
}
|
#if TRACE_MEMORY
|
||||||
|
printf("ReleaseLocalRefs %p .. %p\n", start, start + count);
|
||||||
#endif
|
#endif
|
||||||
|
ObjHeader** current = start;
|
||||||
|
while (count-- > 0) {
|
||||||
|
ObjHeader* object = *current;
|
||||||
|
if (object != nullptr) {
|
||||||
|
ReleaseRef(object);
|
||||||
|
// Just for sanity, optional.
|
||||||
|
*current = nullptr;
|
||||||
|
}
|
||||||
|
current++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ReleaseGlobalRefs(ObjHeader** start, int count) {
|
||||||
|
#if TRACE_MEMORY
|
||||||
|
printf("ReleaseGlobalRefs %p .. %p\n", start, start + count);
|
||||||
|
#endif
|
||||||
|
#if CONCURRENT
|
||||||
|
ObjHeader** current = start;
|
||||||
|
while (count-- > 0) {
|
||||||
|
ObjHeader* object = *current;
|
||||||
|
if (object != nullptr) {
|
||||||
|
bool written = __sync_bool_compare_and_swap(
|
||||||
|
current, object, nullptr);
|
||||||
|
if (written)
|
||||||
|
ReleaseRef(object);
|
||||||
|
}
|
||||||
|
current++;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ObjHeader** current = start;
|
||||||
|
while (count-- > 0) {
|
||||||
|
ObjHeader* object = *current;
|
||||||
|
if (object != nullptr) {
|
||||||
|
ReleaseRef(object);
|
||||||
|
// Usually required.
|
||||||
|
*current = nullptr;
|
||||||
|
}
|
||||||
|
current++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|||||||
@@ -351,6 +351,9 @@ void SetGlobalRef(ObjHeader** location, const ObjHeader* object);
|
|||||||
void UpdateLocalRef(ObjHeader** location, const ObjHeader* object);
|
void UpdateLocalRef(ObjHeader** location, const ObjHeader* object);
|
||||||
// Update potentially globally visible location.
|
// Update potentially globally visible location.
|
||||||
void UpdateGlobalRef(ObjHeader** location, const ObjHeader* object);
|
void UpdateGlobalRef(ObjHeader** location, const ObjHeader* object);
|
||||||
|
// Optimization: release all references in range.
|
||||||
|
void ReleaseLocalRefs(ObjHeader** start, int count);
|
||||||
|
void ReleaseGlobalRefs(ObjHeader** start, int count);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user