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)!!
|
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))
|
||||||
|
|||||||
+6
-4
@@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
-32
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user