Properly keep track of references. (#169)
This commit is contained in:
+14
-1
@@ -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))
|
||||
|
||||
+6
-4
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-32
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user