Memory management design and implementation. (#148)
This commit is contained in:
+30
-3
@@ -103,20 +103,47 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
fun intToPtr(imm: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildIntToPtr(builder, imm, DestTy, Name)
|
||||
|
||||
fun alloca(type: KotlinType, name: String = ""): LLVMValueRef = alloca(getLLVMType(type), name)
|
||||
fun alloca(type: LLVMTypeRef?, name: String = ""): LLVMValueRef {
|
||||
appendingTo(prologueBb!!) {
|
||||
return LLVMBuildAlloca(builder, type, name)!!
|
||||
val result = 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 store(value: LLVMValueRef, ptr: LLVMValueRef): LLVMValueRef = LLVMBuildStore(builder, value, ptr)!!
|
||||
fun store(value: LLVMValueRef, ptr: LLVMValueRef) {
|
||||
// Use updateRef() or storeAny() API for that.
|
||||
assert(!isObjectRef(value))
|
||||
LLVMBuildStore(builder, value, ptr)
|
||||
}
|
||||
fun storeAnyLocal(value: LLVMValueRef, ptr: LLVMValueRef) {
|
||||
if (isObjectRef(value)) {
|
||||
updateLocalRef(value, ptr)
|
||||
} else {
|
||||
LLVMBuildStore(builder, value, ptr)
|
||||
}
|
||||
}
|
||||
fun storeAnyGlobal(value: LLVMValueRef, ptr: LLVMValueRef) {
|
||||
if (isObjectRef(value)) {
|
||||
updateGlobalRef(value, ptr)
|
||||
} else {
|
||||
LLVMBuildStore(builder, value, ptr)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Only use ignoreOld, when sure that memory is freshly inited and have no value.
|
||||
fun updateLocalRef(value: LLVMValueRef, address: LLVMValueRef, ignoreOld: Boolean = false) {
|
||||
call(if (ignoreOld) context.llvm.setLocalRefFunction else context.llvm.updateLocalRefFunction,
|
||||
listOf(address, value))
|
||||
}
|
||||
|
||||
fun updateGlobalRef(value: LLVMValueRef, address: LLVMValueRef, ignoreOld: Boolean = false) {
|
||||
call(if (ignoreOld) context.llvm.setGlobalRefFunction else context.llvm.updateGlobalRefFunction,
|
||||
listOf(address, value))
|
||||
}
|
||||
|
||||
fun isConst(value: LLVMValueRef): Boolean = (LLVMIsConstant(value) == 1)
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
+2
@@ -222,7 +222,9 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
val initInstanceFunction = importRtFunction("InitInstance")
|
||||
val allocArrayFunction = importRtFunction("AllocArrayInstance")
|
||||
val setLocalRefFunction = importRtFunction("SetLocalRef")
|
||||
val setGlobalRefFunction = importRtFunction("SetGlobalRef")
|
||||
val updateLocalRefFunction = importRtFunction("UpdateLocalRef")
|
||||
val updateGlobalRefFunction = importRtFunction("UpdateGlobalRef")
|
||||
val setArrayFunction = importRtFunction("Kotlin_Array_set")
|
||||
val copyImplArrayFunction = importRtFunction("Kotlin_Array_copyImpl")
|
||||
val lookupFieldOffset = importRtFunction("LookupFieldOffset")
|
||||
|
||||
+5
-5
@@ -204,7 +204,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
* Convenient [InnerScope] implementation that is bound to the [currentCodeContext].
|
||||
*/
|
||||
private abstract inner class InnerScopeImpl : InnerScope(currentCodeContext)
|
||||
|
||||
/**
|
||||
* Executes [block] with [codeContext] substituted as [currentCodeContext].
|
||||
*/
|
||||
@@ -250,7 +249,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val descriptor = irField.descriptor
|
||||
val initialization = evaluateExpression(irField.initializer)
|
||||
val globalPtr = LLVMGetNamedGlobal(context.llvmModule, descriptor.symbolName)
|
||||
codegen.store(initialization!!, globalPtr!!)
|
||||
codegen.storeAnyGlobal(initialization!!, globalPtr!!)
|
||||
}
|
||||
codegen.ret(null)
|
||||
}
|
||||
@@ -412,7 +411,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
fieldDeclaration.initializer?.let {
|
||||
val value = evaluateExpression(it)!!
|
||||
val fieldPtr = fieldPtrOfClass(thisPtr, fieldDescriptor)
|
||||
codegen.store(value, fieldPtr)
|
||||
codegen.storeAnyGlobal(value, fieldPtr)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1450,11 +1449,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val valueToAssign = evaluateExpression(value.value)!!
|
||||
if (value.descriptor.dispatchReceiverParameter != null) {
|
||||
val thisPtr = instanceFieldAccessReceiver(value)
|
||||
codegen.store(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor))
|
||||
codegen.storeAnyGlobal(valueToAssign, fieldPtrOfClass(thisPtr, value.descriptor))
|
||||
}
|
||||
else {
|
||||
val globalValue = LLVMGetNamedGlobal(context.llvmModule, value.descriptor.symbolName)
|
||||
codegen.store(valueToAssign, globalValue!!)
|
||||
codegen.storeAnyGlobal(valueToAssign, globalValue!!)
|
||||
}
|
||||
|
||||
return null
|
||||
@@ -1818,6 +1817,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
branch: IrBranch, bbNext: LLVMBasicBlockRef?, bbExit: LLVMBasicBlockRef?) {
|
||||
val neitherUnitNorNothing = !isNothing && !isUnit // If branches doesn't end with 'return' either result hasn't got 'unit' type.
|
||||
val branchResult = branch.result
|
||||
// TODO: use phis here!
|
||||
if (isUnconditional(branch)) { // It is the "else" clause.
|
||||
val brResult = evaluateExpression(branchResult) // Generate clause body.
|
||||
if (neitherUnitNorNothing) // If nor unit neither result ends with return
|
||||
|
||||
+9
-4
@@ -142,10 +142,6 @@ internal fun structType(types: List<LLVMTypeRef>): LLVMTypeRef = memScoped {
|
||||
LLVMStructType(allocArrayOf(types)[0].ptr, types.size, 0)!!
|
||||
}
|
||||
|
||||
internal fun ContextUtils.isObjectType(type: LLVMTypeRef) : Boolean {
|
||||
return type == kObjHeaderPtr || type == kArrayHeaderPtr
|
||||
}
|
||||
|
||||
internal fun ContextUtils.getLlvmFunctionType(function: FunctionDescriptor): LLVMTypeRef {
|
||||
val returnType = if (function is ConstructorDescriptor) voidType else getLLVMType(function.returnType!!)
|
||||
val paramTypes = ArrayList(function.allValueParameters.map { getLLVMType(it.type) })
|
||||
@@ -168,6 +164,14 @@ internal fun ContextUtils.isObjectReturn(functionType: LLVMTypeRef) : Boolean {
|
||||
return isObjectType(returnType)
|
||||
}
|
||||
|
||||
internal fun ContextUtils.isObjectRef(value: LLVMValueRef): Boolean {
|
||||
return isObjectType(value.type)
|
||||
}
|
||||
|
||||
internal fun ContextUtils.isObjectType(type: LLVMTypeRef): Boolean {
|
||||
return type == kObjHeaderPtr || type == kArrayHeaderPtr
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads [size] bytes contained in this array.
|
||||
*/
|
||||
@@ -208,6 +212,7 @@ internal fun functionType(returnType: LLVMTypeRef, isVarArg: Boolean = false, va
|
||||
LLVMFunctionType(returnType, paramTypesPtr, paramTypes.size, if (isVarArg) 1 else 0)!!
|
||||
}
|
||||
|
||||
|
||||
fun llvm2string(value: LLVMValueRef?): String {
|
||||
if (value == null) return "<null>"
|
||||
return LLVMPrintValueToString(value)!!.asCString().toString()
|
||||
|
||||
+1
-1
@@ -160,7 +160,7 @@ internal class RTTIGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
val refFieldIndices = classDesc.fields.mapIndexedNotNull { index, field ->
|
||||
val type = field.returnType!!
|
||||
if (!KotlinBuiltIns.isPrimitiveType(type)) {
|
||||
if (isObjectType(getLLVMType(type))) {
|
||||
index
|
||||
} else {
|
||||
null
|
||||
|
||||
+7
-4
@@ -18,7 +18,7 @@ internal class VariableManager(val codegen: CodeGenerator) {
|
||||
return codegen.load(address)
|
||||
}
|
||||
override fun store(value: LLVMValueRef) {
|
||||
codegen.store(value, address)
|
||||
codegen.storeAnyLocal(value, address)
|
||||
}
|
||||
override fun address() : LLVMValueRef {
|
||||
return this.address
|
||||
@@ -54,10 +54,13 @@ internal class VariableManager(val codegen: CodeGenerator) {
|
||||
|
||||
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 {
|
||||
// TODO: fix, due to the bug in frontend, we shall always create stack slot for variable now.
|
||||
// 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) {
|
||||
@@ -74,7 +77,7 @@ internal class VariableManager(val codegen: CodeGenerator) {
|
||||
val type = codegen.getLLVMType(descriptor.type)
|
||||
val slot = codegen.alloca(type, descriptor.name.asString())
|
||||
if (value != null)
|
||||
codegen.store(value, slot)
|
||||
codegen.storeAnyLocal(value, slot)
|
||||
variables.add(SlotRecord(slot, codegen.isObjectType(type)))
|
||||
descriptors[scoped] = index
|
||||
return index
|
||||
@@ -95,7 +98,7 @@ internal class VariableManager(val codegen: CodeGenerator) {
|
||||
val index = variables.size
|
||||
val slot = codegen.alloca(type)
|
||||
if (value != null)
|
||||
codegen.store(value, slot)
|
||||
codegen.storeAnyLocal(value, slot)
|
||||
variables.add(SlotRecord(slot, codegen.isObjectType(type)))
|
||||
return index
|
||||
}
|
||||
|
||||
@@ -10,12 +10,12 @@ fun assertFalse(cond: Boolean) {
|
||||
|
||||
fun assertEquals(value1: Any?, value2: Any?) {
|
||||
if (value1 != value2)
|
||||
println("FAIL")
|
||||
throw Error("FAIL " + value1 + " " + value2)
|
||||
}
|
||||
|
||||
fun assertEquals(value1: Int, value2: Int) {
|
||||
if (value1 != value2)
|
||||
println("FAIL")
|
||||
throw Error("FAIL " + value1 + " " + value2)
|
||||
}
|
||||
|
||||
fun testBasic() {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
class A {
|
||||
var field: B? = null
|
||||
}
|
||||
|
||||
class B(var field: Int)
|
||||
|
||||
fun main(args : Array<String>) {
|
||||
val a = A()
|
||||
a.field = B(2)
|
||||
}
|
||||
Reference in New Issue
Block a user