Properly keep track of references. (#169)

This commit is contained in:
Nikolay Igotti
2016-12-29 14:11:17 +03:00
committed by GitHub
parent b25225ba5e
commit 174cdc321c
4 changed files with 39 additions and 41 deletions
@@ -138,7 +138,20 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
return LLVMBuildAlloca(builder, type, name)!! return LLVMBuildAlloca(builder, type, name)!!
} }
} }
fun load(value: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildLoad(builder, value, name)!! fun load(value: LLVMValueRef, name: String = ""): LLVMValueRef {
val result = LLVMBuildLoad(builder, value, name)!!
// Use loadSlot() API for that.
assert(!isObjectRef(value))
return result
}
fun loadSlot(address: LLVMValueRef, isVar: Boolean, name: String = "") : LLVMValueRef {
val value = LLVMBuildLoad(builder, address, name)!!
if (isObjectRef(value) && isVar) {
val slot = alloca(LLVMTypeOf(value))
storeAnyLocal(value, slot)
}
return value
}
fun store(value: LLVMValueRef, ptr: LLVMValueRef) { fun store(value: LLVMValueRef, ptr: LLVMValueRef) {
// Use updateRef() or storeAny() API for that. // Use updateRef() or storeAny() API for that.
assert(!isObjectRef(value)) assert(!isObjectRef(value))
@@ -670,7 +670,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val bbInit = codegen.basicBlock("label_init") val bbInit = codegen.basicBlock("label_init")
val bbExit = codegen.basicBlock("label_continue") val bbExit = codegen.basicBlock("label_continue")
val onePtr = codegen.intToPtr(kImmInt64One, codegen.kObjHeaderPtr) val onePtr = codegen.intToPtr(kImmInt64One, codegen.kObjHeaderPtr)
val objectVal = codegen.load(objectPtr) val objectVal = codegen.loadSlot(objectPtr, false)
val condition = codegen.ucmpGt(objectVal, onePtr) val condition = codegen.ucmpGt(objectVal, onePtr)
codegen.condBr(condition, bbExit, bbInit) codegen.condBr(condition, bbExit, bbInit)
@@ -938,7 +938,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val exceptionPtrPtr = bitcast(codegen.kObjHeaderPtrPtr, exceptionRawPtr, "") val exceptionPtrPtr = bitcast(codegen.kObjHeaderPtrPtr, exceptionRawPtr, "")
// Pointer to Kotlin exception object: // Pointer to Kotlin exception object:
val exceptionPtr = load(exceptionPtrPtr, "exception") // We do need a slot here, as otherwise exception instance could be freed by _cxa_end_catch.
val exceptionPtr = loadSlot(exceptionPtrPtr, true, "exception")
// __cxa_end_catch performs some C++ cleanup, including calling `KotlinException` class destructor. // __cxa_end_catch performs some C++ cleanup, including calling `KotlinException` class destructor.
val endCatch = externalFunction("__cxa_end_catch", functionType(voidType, false)) val endCatch = externalFunction("__cxa_end_catch", functionType(voidType, false))
@@ -1343,11 +1344,12 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
context.log("evaluateGetField : ${ir2string(value)}") context.log("evaluateGetField : ${ir2string(value)}")
if (value.descriptor.dispatchReceiverParameter != null) { if (value.descriptor.dispatchReceiverParameter != null) {
val thisPtr = instanceFieldAccessReceiver(value) val thisPtr = instanceFieldAccessReceiver(value)
return codegen.load(fieldPtrOfClass(thisPtr, value.descriptor)) return codegen.loadSlot(
fieldPtrOfClass(thisPtr, value.descriptor), value.descriptor.isVar())
} }
else { else {
val ptr = LLVMGetNamedGlobal(context.llvmModule, value.descriptor.symbolName)!! val ptr = LLVMGetNamedGlobal(context.llvmModule, value.descriptor.symbolName)!!
return codegen.load(ptr) return codegen.loadSlot(ptr, value.descriptor.isVar())
} }
} }
@@ -10,36 +10,19 @@ internal class VariableManager(val codegen: CodeGenerator) {
fun load() : LLVMValueRef fun load() : LLVMValueRef
fun store(value: LLVMValueRef) fun store(value: LLVMValueRef)
fun address() : LLVMValueRef fun address() : LLVMValueRef
fun isRefSlot() : Boolean
} }
inner class SlotRecord(val address: LLVMValueRef, val refSlot: Boolean) : Record { inner class SlotRecord(val address: LLVMValueRef, val refSlot: Boolean, val isVar: Boolean) : Record {
override fun load() : LLVMValueRef { override fun load() : LLVMValueRef = codegen.loadSlot(address, isVar)
return codegen.load(address) override fun store(value: LLVMValueRef) = codegen.storeAnyLocal(value, address)
} override fun address() : LLVMValueRef = this.address
override fun store(value: LLVMValueRef) {
codegen.storeAnyLocal(value, address)
}
override fun address() : LLVMValueRef {
return this.address
}
override fun isRefSlot() = this.refSlot
override fun toString() = (if (refSlot) "refslot" else "slot") + " for ${address}" override fun toString() = (if (refSlot) "refslot" else "slot") + " for ${address}"
} }
class ValueRecord(val value: LLVMValueRef, val descriptor: ValueDescriptor) : Record { class ValueRecord(val value: LLVMValueRef, val descriptor: ValueDescriptor) : Record {
override fun load() : LLVMValueRef { override fun load() : LLVMValueRef = value
return value override fun store(value: LLVMValueRef) = throw Error("writing to immutable: ${descriptor}")
} override fun address() : LLVMValueRef = throw Error("no address for: ${descriptor}")
override fun store(value: LLVMValueRef) {
throw Error("writing to immutable: ${descriptor}")
}
override fun address() : LLVMValueRef {
throw Error("no address for: ${descriptor}")
}
override fun isRefSlot() : Boolean = false
override fun toString() = "value of ${value} from ${descriptor}" override fun toString() = "value of ${value} from ${descriptor}"
} }
@@ -55,14 +38,18 @@ internal class VariableManager(val codegen: CodeGenerator) {
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
if (descriptor.isVar() || codegen.isObjectType(codegen.getLLVMType(descriptor.type)) || true) { if (!descriptor.isVar && value != null)
return createMutable(scoped, value) return createImmutable(scoped, value)
} else { else
return createImmutable(scoped, value!!) // Unfortunately, we have to create mutable slots here,
} // as even vals can be assigned on multiple paths. However, we use varness
// knowledge, as anonymous slots are created only for true vars (for vals
// their single assigner already have slot).
return createMutable(scoped, descriptor.isVar, value)
} }
fun createMutable(scoped: Pair<VariableDescriptor, CodeContext>, value: LLVMValueRef? = null) : Int { fun createMutable(scoped: Pair<VariableDescriptor, CodeContext>,
isVar: Boolean, value: LLVMValueRef? = null) : Int {
val descriptor = scoped.first val descriptor = scoped.first
assert(descriptors.get(scoped) == null) assert(descriptors.get(scoped) == null)
val index = variables.size val index = variables.size
@@ -70,7 +57,7 @@ internal class VariableManager(val codegen: CodeGenerator) {
val slot = codegen.alloca(type, descriptor.name.asString()) val slot = codegen.alloca(type, descriptor.name.asString())
if (value != null) if (value != null)
codegen.storeAnyLocal(value, slot) codegen.storeAnyLocal(value, slot)
variables.add(SlotRecord(slot, codegen.isObjectType(type))) variables.add(SlotRecord(slot, codegen.isObjectType(type), isVar))
descriptors[scoped] = index descriptors[scoped] = index
return index return index
} }
@@ -91,7 +78,7 @@ internal class VariableManager(val codegen: CodeGenerator) {
val slot = codegen.alloca(type) val slot = codegen.alloca(type)
if (value != null) if (value != null)
codegen.storeAnyLocal(value, slot) codegen.storeAnyLocal(value, slot)
variables.add(SlotRecord(slot, codegen.isObjectType(type))) variables.add(SlotRecord(slot, codegen.isObjectType(type), true))
return index return index
} }
-4
View File
@@ -774,22 +774,18 @@ task expression_as_statement(type: RunKonanTest) {
} }
task memory_var1(type: RunKonanTest) { task memory_var1(type: RunKonanTest) {
disabled = true
source = "runtime/memory/var1.kt" source = "runtime/memory/var1.kt"
} }
task memory_var2(type: RunKonanTest) { task memory_var2(type: RunKonanTest) {
disabled = true
source = "runtime/memory/var2.kt" source = "runtime/memory/var2.kt"
} }
task memory_var3(type: RunKonanTest) { task memory_var3(type: RunKonanTest) {
disabled = true
source = "runtime/memory/var3.kt" source = "runtime/memory/var3.kt"
} }
task memory_var4(type: RunKonanTest) { task memory_var4(type: RunKonanTest) {
disabled = true
source = "runtime/memory/var4.kt" source = "runtime/memory/var4.kt"
} }