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)!!
}
}
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) {
// Use updateRef() or storeAny() API for that.
assert(!isObjectRef(value))
@@ -670,7 +670,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val bbInit = codegen.basicBlock("label_init")
val bbExit = codegen.basicBlock("label_continue")
val onePtr = codegen.intToPtr(kImmInt64One, codegen.kObjHeaderPtr)
val objectVal = codegen.load(objectPtr)
val objectVal = codegen.loadSlot(objectPtr, false)
val condition = codegen.ucmpGt(objectVal, onePtr)
codegen.condBr(condition, bbExit, bbInit)
@@ -938,7 +938,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val exceptionPtrPtr = bitcast(codegen.kObjHeaderPtrPtr, exceptionRawPtr, "")
// 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.
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)}")
if (value.descriptor.dispatchReceiverParameter != null) {
val thisPtr = instanceFieldAccessReceiver(value)
return codegen.load(fieldPtrOfClass(thisPtr, value.descriptor))
return codegen.loadSlot(
fieldPtrOfClass(thisPtr, value.descriptor), value.descriptor.isVar())
}
else {
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 store(value: LLVMValueRef)
fun address() : LLVMValueRef
fun isRefSlot() : Boolean
}
inner class SlotRecord(val address: LLVMValueRef, val refSlot: Boolean) : Record {
override fun load() : LLVMValueRef {
return codegen.load(address)
}
override fun store(value: LLVMValueRef) {
codegen.storeAnyLocal(value, address)
}
override fun address() : LLVMValueRef {
return this.address
}
override fun isRefSlot() = this.refSlot
inner class SlotRecord(val address: LLVMValueRef, val refSlot: Boolean, val isVar: Boolean) : Record {
override fun load() : LLVMValueRef = codegen.loadSlot(address, isVar)
override fun store(value: LLVMValueRef) = codegen.storeAnyLocal(value, address)
override fun address() : LLVMValueRef = this.address
override fun toString() = (if (refSlot) "refslot" else "slot") + " for ${address}"
}
class ValueRecord(val value: LLVMValueRef, val descriptor: ValueDescriptor) : Record {
override fun load() : LLVMValueRef {
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 isRefSlot() : Boolean = false
override fun load() : LLVMValueRef = value
override fun store(value: LLVMValueRef) = throw Error("writing to immutable: ${descriptor}")
override fun address() : LLVMValueRef = throw Error("no address for: ${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 {
// Note that we always create slot for object references for memory management.
val descriptor = scoped.first
if (descriptor.isVar() || codegen.isObjectType(codegen.getLLVMType(descriptor.type)) || true) {
return createMutable(scoped, value)
} else {
return createImmutable(scoped, value!!)
}
if (!descriptor.isVar && value != null)
return createImmutable(scoped, value)
else
// 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
assert(descriptors.get(scoped) == null)
val index = variables.size
@@ -70,7 +57,7 @@ internal class VariableManager(val codegen: CodeGenerator) {
val slot = codegen.alloca(type, descriptor.name.asString())
if (value != null)
codegen.storeAnyLocal(value, slot)
variables.add(SlotRecord(slot, codegen.isObjectType(type)))
variables.add(SlotRecord(slot, codegen.isObjectType(type), isVar))
descriptors[scoped] = index
return index
}
@@ -91,7 +78,7 @@ internal class VariableManager(val codegen: CodeGenerator) {
val slot = codegen.alloca(type)
if (value != null)
codegen.storeAnyLocal(value, slot)
variables.add(SlotRecord(slot, codegen.isObjectType(type)))
variables.add(SlotRecord(slot, codegen.isObjectType(type), true))
return index
}
-4
View File
@@ -774,22 +774,18 @@ task expression_as_statement(type: RunKonanTest) {
}
task memory_var1(type: RunKonanTest) {
disabled = true
source = "runtime/memory/var1.kt"
}
task memory_var2(type: RunKonanTest) {
disabled = true
source = "runtime/memory/var2.kt"
}
task memory_var3(type: RunKonanTest) {
disabled = true
source = "runtime/memory/var3.kt"
}
task memory_var4(type: RunKonanTest) {
disabled = true
source = "runtime/memory/var4.kt"
}