Return objects to slot. (#161)
This commit is contained in:
+15
-1
@@ -17,6 +17,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
// TODO: remove, to make CodeGenerator descriptor-agnostic.
|
||||
var constructedClass: ClassDescriptor? = null
|
||||
val vars = VariableManager(this)
|
||||
var returnSlot: LLVMValueRef? = null
|
||||
|
||||
fun prologue(descriptor: FunctionDescriptor) {
|
||||
prologue(llvmFunction(descriptor),
|
||||
@@ -28,8 +29,11 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
fun prologue(function:LLVMValueRef, returnType:LLVMTypeRef) {
|
||||
assert(returns.size == 0)
|
||||
|
||||
assert(this.function != function)
|
||||
|
||||
if (isObjectType(returnType)) {
|
||||
this.returnSlot = LLVMGetParam(function, numParameters(function.type) - 1)
|
||||
}
|
||||
this.function = function
|
||||
this.returnType = returnType
|
||||
this.constructedClass = null
|
||||
@@ -48,11 +52,15 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
when {
|
||||
returnType == voidType -> {
|
||||
vars.releaseVars()
|
||||
assert(returnSlot == null)
|
||||
LLVMBuildRetVoid(builder)
|
||||
}
|
||||
returns.size > 0 -> {
|
||||
val returnPhi = phi(returnType!!)
|
||||
addPhiIncoming(returnPhi, *returns.toList().toTypedArray())
|
||||
if (returnSlot != null) {
|
||||
updateLocalRef(returnPhi, returnSlot!!)
|
||||
}
|
||||
vars.releaseVars()
|
||||
LLVMBuildRet(builder, returnPhi)
|
||||
}
|
||||
@@ -63,6 +71,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
|
||||
returns.clear()
|
||||
vars.clear()
|
||||
returnSlot = null
|
||||
}
|
||||
|
||||
private var prologueBb: LLVMBasicBlockRef? = null
|
||||
@@ -103,6 +112,11 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
|
||||
fun load(value: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildLoad(builder, value, name)!!
|
||||
fun store(value: LLVMValueRef, ptr: LLVMValueRef): LLVMValueRef = LLVMBuildStore(builder, value, ptr)!!
|
||||
|
||||
fun updateLocalRef(value: LLVMValueRef, address: LLVMValueRef, ignoreOld: Boolean = false) {
|
||||
call(if (ignoreOld) context.llvm.setLocalRefFunction else context.llvm.updateLocalRefFunction,
|
||||
listOf(address, value))
|
||||
}
|
||||
|
||||
fun isConst(value: LLVMValueRef): Boolean = (LLVMIsConstant(value) == 1)
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
+2
@@ -221,6 +221,8 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
|
||||
val allocInstanceFunction = importRtFunction("AllocInstance")
|
||||
val initInstanceFunction = importRtFunction("InitInstance")
|
||||
val allocArrayFunction = importRtFunction("AllocArrayInstance")
|
||||
val setLocalRefFunction = importRtFunction("SetLocalRef")
|
||||
val updateLocalRefFunction = importRtFunction("UpdateLocalRef")
|
||||
val setArrayFunction = importRtFunction("Kotlin_Array_set")
|
||||
val copyImplArrayFunction = importRtFunction("Kotlin_Array_copyImpl")
|
||||
val lookupFieldOffset = importRtFunction("LookupFieldOffset")
|
||||
|
||||
+29
-30
@@ -429,10 +429,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
codegen.ret(thisPtr)
|
||||
}
|
||||
|
||||
codegen.ret(null)
|
||||
codegen.epilogue()
|
||||
context.log("visitConstructor : ${ir2string(constructorDeclaration)}")
|
||||
}
|
||||
@@ -553,11 +552,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
|
||||
override fun genReturn(target: CallableDescriptor, value: LLVMValueRef?) {
|
||||
if (declaration == null) {
|
||||
codegen.ret(value)
|
||||
return
|
||||
}
|
||||
if (target == declaration.descriptor) {
|
||||
if (declaration == null || target == declaration.descriptor) {
|
||||
codegen.ret(value)
|
||||
} else {
|
||||
super.genReturn(target, value)
|
||||
@@ -582,9 +577,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
private fun bindParameters(descriptor: FunctionDescriptor?): Map<ParameterDescriptor, LLVMValueRef> {
|
||||
if (descriptor == null) return emptyMap()
|
||||
val paramDescriptors = descriptor.allValueParameters
|
||||
|
||||
assert(paramDescriptors.size == codegen.countParams(descriptor))
|
||||
|
||||
return paramDescriptors.mapIndexed { i, paramDescriptor ->
|
||||
val param = codegen.param(descriptor, i)
|
||||
assert(codegen.getLLVMType(paramDescriptor.type) == param.type)
|
||||
@@ -757,7 +749,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val initFunction = value.descriptor.constructors.first { it.valueParameters.size == 0 }
|
||||
val ctor = codegen.llvmFunction(initFunction)
|
||||
val args = listOf(objectPtr, typeInfo, allocHint, ctor)
|
||||
val newValue = currentCodeContext.genCall(context.llvm.initInstanceFunction, args)
|
||||
val newValue = call(context.llvm.initInstanceFunction, args)
|
||||
codegen.br(bbExit)
|
||||
|
||||
codegen.positionAtEnd(bbExit)
|
||||
@@ -846,7 +838,6 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
private fun evaluateVararg(value: IrVararg): LLVMValueRef? {
|
||||
@@ -879,14 +870,13 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
val typeInfo = codegen.typeInfoValue(value.type)!!
|
||||
val arrayCreationArgs = listOf(typeInfo, kImmInt32One, finalLength)
|
||||
val array = currentCodeContext.genCall(context.llvm.allocArrayFunction, arrayCreationArgs)
|
||||
|
||||
val array = call(context.llvm.allocArrayFunction, arrayCreationArgs)
|
||||
elements.fold(kImmZero) { sum, (exp, size, isArray) ->
|
||||
if (!isArray) {
|
||||
currentCodeContext.genCall(context.llvm.setArrayFunction, listOf(array, sum, exp))
|
||||
call(context.llvm.setArrayFunction, listOf(array, sum, exp))
|
||||
return@fold codegen.plus(sum, kImmOne)
|
||||
} else {
|
||||
currentCodeContext.genCall(context.llvm.copyImplArrayFunction, listOf(exp, kImmZero, array, sum, size!!))
|
||||
call(context.llvm.copyImplArrayFunction, listOf(exp, kImmZero, array, sum, size!!))
|
||||
return@fold codegen.plus(sum, size)
|
||||
}
|
||||
}
|
||||
@@ -920,7 +910,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val toStringDescriptor = getToString(it.type)
|
||||
val string = if (KotlinBuiltIns.isString(it.type)) evaluationResult
|
||||
else evaluateSimpleFunctionCall(toStringDescriptor, listOf(evaluationResult))
|
||||
val length = currentCodeContext.genCall(codegen.llvmFunction(kStringLength!!), listOf(string))
|
||||
val length = call(codegen.llvmFunction(kStringLength!!), listOf(string))
|
||||
return@map Element(string, length, -1)
|
||||
}
|
||||
}
|
||||
@@ -933,12 +923,12 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
|
||||
val constructor = kStringBuilder!!.constructors
|
||||
.firstOrNull { it -> it.valueParameters.size == 1 && KotlinBuiltIns.isInt(it.valueParameters[0].type) }!!
|
||||
val stringBuilderObjPtr = currentCodeContext.genCall(context.llvm.allocInstanceFunction,
|
||||
val stringBuilderObj = call(context.llvm.allocInstanceFunction,
|
||||
listOf(codegen.typeInfoValue(kStringBuilder.defaultType)!!, kImmOne))
|
||||
val stringBuilderObj = currentCodeContext.genCall(codegen.llvmFunction(constructor), listOf(stringBuilderObjPtr, totalLength))
|
||||
call(codegen.llvmFunction(constructor), listOf(stringBuilderObj, totalLength))
|
||||
|
||||
stringsWithLengths.fold(stringBuilderObj) { sum, (string, _, _) ->
|
||||
currentCodeContext.genCall(codegen.llvmFunction(kStringBuilderAppendStringFn!!), listOf(sum, string))
|
||||
call(codegen.llvmFunction(kStringBuilderAppendStringFn!!), listOf(sum, string))
|
||||
return@fold sum
|
||||
}
|
||||
|
||||
@@ -1390,7 +1380,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val srcArg = evaluateExpression(value.argument)!! // Evaluate src expression.
|
||||
val srcObjInfoPtr = codegen.bitcast(codegen.kObjHeaderPtr, srcArg) // Cast src to ObjInfoPtr.
|
||||
val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list.
|
||||
currentCodeContext.genCall(context.llvm.checkInstanceFunction, args) // Check if dst is subclass of src.
|
||||
call(context.llvm.checkInstanceFunction, args) // Check if dst is subclass of src.
|
||||
return srcArg
|
||||
}
|
||||
|
||||
@@ -1431,9 +1421,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val srcObjInfoPtr = codegen.bitcast(codegen.kObjHeaderPtr, obj) // Cast src to ObjInfoPtr.
|
||||
val args = listOf(srcObjInfoPtr, dstTypeInfo) // Create arg list.
|
||||
|
||||
val result = currentCodeContext.genCall( // Check if dst is subclass of src.
|
||||
context.llvm.isInstanceFunction, args)
|
||||
|
||||
val result = call(context.llvm.isInstanceFunction, args) // Check if dst is subclass of src.
|
||||
return LLVMBuildTrunc(codegen.builder, result, kInt1, "")!! // Truncate result to boolean
|
||||
}
|
||||
|
||||
@@ -1783,14 +1771,15 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val thisValue = if (containingClass.isArray) {
|
||||
assert(args.size == 1 && args[0].type == int32Type)
|
||||
val allocArrayInstanceArgs = listOf(typeInfo, allocHint, args[0])
|
||||
currentCodeContext.genCall(context.llvm.allocArrayFunction, allocArrayInstanceArgs)
|
||||
call(context.llvm.allocArrayFunction, allocArrayInstanceArgs)
|
||||
} else {
|
||||
currentCodeContext.genCall(context.llvm.allocInstanceFunction, listOf(typeInfo, allocHint))
|
||||
call(context.llvm.allocInstanceFunction, listOf(typeInfo, allocHint))
|
||||
}
|
||||
val constructorParams: MutableList<LLVMValueRef> = mutableListOf()
|
||||
constructorParams += thisValue
|
||||
constructorParams += args
|
||||
return evaluateSimpleFunctionCall(callee.descriptor as FunctionDescriptor, constructorParams)
|
||||
evaluateSimpleFunctionCall(callee.descriptor as FunctionDescriptor, constructorParams)
|
||||
return thisValue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1900,8 +1889,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
val typeInfoPtr = codegen.bitcast(codegen.kTypeInfoPtr, typeInfoI8Ptr) // Cast TypeInfo (i8*) to TypeInfo*.
|
||||
val methodHash = codegen.functionHash(descriptor) // Calculate hash of the method to be invoked
|
||||
val lookupArgs = listOf(typeInfoPtr, methodHash) // Prepare args for lookup
|
||||
val llvmMethod = currentCodeContext.genCall(
|
||||
context.llvm.lookupOpenMethodFunction,
|
||||
val llvmMethod = call(context.llvm.lookupOpenMethodFunction,
|
||||
lookupArgs) // Get method ptr to be invoked
|
||||
|
||||
val functionPtrType = pointerType(codegen.getLlvmFunctionType(descriptor)) // Construct type of the method to be invoked
|
||||
@@ -1916,13 +1904,24 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
|
||||
// In such case it would be possible to check that all args are available and in the correct order.
|
||||
// However, it currently requires some refactoring to be performed.
|
||||
private fun call(descriptor: FunctionDescriptor, function: LLVMValueRef, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
val result = currentCodeContext.genCall(function, args)
|
||||
val result = call(function, args)
|
||||
if (descriptor.returnType?.isNothing() == true) {
|
||||
codegen.unreachable()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun call(function: LLVMValueRef, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
if (codegen.isObjectReturn(function.type)) {
|
||||
// If function returns an object - create slot for the returned value.
|
||||
// This allows appropriate rootset accounting by just looking on stack slots.
|
||||
val resultSlot = codegen.vars.createAnonymousSlot()
|
||||
return currentCodeContext.genCall(function, args + resultSlot)
|
||||
} else {
|
||||
return currentCodeContext.genCall(function, args)
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------//
|
||||
|
||||
fun delegatingConstructorCall(descriptor: ClassConstructorDescriptor, args: List<LLVMValueRef>): LLVMValueRef {
|
||||
|
||||
+24
-3
@@ -4,6 +4,7 @@ import kotlinx.cinterop.*
|
||||
import llvm.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.allValueParameters
|
||||
import org.jetbrains.kotlin.backend.konan.KonanPlatform
|
||||
import org.jetbrains.kotlin.descriptors.ConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
|
||||
internal val LLVMValueRef.type: LLVMTypeRef
|
||||
@@ -141,10 +142,14 @@ 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 = getLLVMType(function.returnType!!)
|
||||
val params = function.allValueParameters
|
||||
val paramTypes = params.map { getLLVMType(it.type) }
|
||||
val returnType = if (function is ConstructorDescriptor) voidType else getLLVMType(function.returnType!!)
|
||||
val paramTypes = ArrayList(function.allValueParameters.map { getLLVMType(it.type) })
|
||||
if (isObjectType(returnType)) paramTypes.add(kObjHeaderPtrPtr)
|
||||
|
||||
memScoped {
|
||||
val paramTypesPtr = allocArrayOf(paramTypes)[0].ptr
|
||||
@@ -152,6 +157,17 @@ internal fun ContextUtils.getLlvmFunctionType(function: FunctionDescriptor): LLV
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ContextUtils.numParameters(functionType: LLVMTypeRef) : Int {
|
||||
// Note that type is usually function pointer, so we have to dereference it.
|
||||
return LLVMCountParamTypes(LLVMGetElementType(functionType))!!
|
||||
}
|
||||
|
||||
internal fun ContextUtils.isObjectReturn(functionType: LLVMTypeRef) : Boolean {
|
||||
// Note that type is usually function pointer, so we have to dereference it.
|
||||
val returnType = LLVMGetReturnType(LLVMGetElementType(functionType))!!
|
||||
return isObjectType(returnType)
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads [size] bytes contained in this array.
|
||||
*/
|
||||
@@ -197,3 +213,8 @@ fun llvm2string(value: LLVMValueRef?): String {
|
||||
return LLVMPrintValueToString(value)!!.asCString().toString()
|
||||
}
|
||||
|
||||
fun llvmtype2string(type: LLVMTypeRef?): String {
|
||||
if (type == null) return "<null type>"
|
||||
return LLVMPrintTypeToString(type)!!.asCString().toString()
|
||||
}
|
||||
|
||||
|
||||
+9
-7
@@ -60,7 +60,7 @@ internal class VariableManager(val codegen: CodeGenerator) {
|
||||
// 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() || isObjectType(codegen.getLLVMType(descriptor.type)) || true) {
|
||||
if (descriptor.isVar() || codegen.isObjectType(codegen.getLLVMType(descriptor.type)) || true) {
|
||||
return createMutable(scoped, value)
|
||||
} else {
|
||||
return createImmutable(scoped, value!!)
|
||||
@@ -75,7 +75,7 @@ internal class VariableManager(val codegen: CodeGenerator) {
|
||||
val slot = codegen.alloca(type, descriptor.name.asString())
|
||||
if (value != null)
|
||||
codegen.store(value, slot)
|
||||
variables.add(SlotRecord(slot, isObjectType(type)))
|
||||
variables.add(SlotRecord(slot, codegen.isObjectType(type)))
|
||||
descriptors[scoped] = index
|
||||
return index
|
||||
}
|
||||
@@ -85,12 +85,18 @@ internal class VariableManager(val codegen: CodeGenerator) {
|
||||
return createAnonymousMutable(codegen.getLLVMType(type), value)
|
||||
}
|
||||
|
||||
// Think of slot reuse.
|
||||
fun createAnonymousSlot(value: LLVMValueRef? = null) : LLVMValueRef {
|
||||
val index = createAnonymousMutable(codegen.kObjHeaderPtr, value)
|
||||
return addressOf(index)
|
||||
}
|
||||
|
||||
fun createAnonymousMutable(type: LLVMTypeRef, value: LLVMValueRef? = null) : Int {
|
||||
val index = variables.size
|
||||
val slot = codegen.alloca(type)
|
||||
if (value != null)
|
||||
codegen.store(value, slot)
|
||||
variables.add(SlotRecord(slot, isObjectType(type)))
|
||||
variables.add(SlotRecord(slot, codegen.isObjectType(type)))
|
||||
return index
|
||||
}
|
||||
|
||||
@@ -118,8 +124,4 @@ internal class VariableManager(val codegen: CodeGenerator) {
|
||||
fun store(value: LLVMValueRef, index: Int) {
|
||||
variables[index].store(value)
|
||||
}
|
||||
|
||||
private fun isObjectType(type: LLVMTypeRef) : Boolean {
|
||||
return type == codegen.kObjHeaderPtr || type == codegen.kArrayHeaderPtr
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,6 +108,7 @@ abstract class KonanTest extends DefaultTask {
|
||||
}
|
||||
}
|
||||
|
||||
// Please do not use this framework anymore!
|
||||
class UnitKonanTest extends KonanTest {
|
||||
void compileTest(File sourceS, File runtimeS, File stdlibKtBc, File exe) {
|
||||
def testC = sourceS.absolutePath.replace(".kt.S", "-test.c")
|
||||
@@ -120,6 +121,11 @@ class UnitKonanTest extends KonanTest {
|
||||
args argList
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
void executeTest() {
|
||||
// Do nothing, unit tests go away.
|
||||
}
|
||||
}
|
||||
|
||||
class RunKonanTest extends KonanTest {
|
||||
|
||||
Reference in New Issue
Block a user