More preparations for escape analysis. (#201)

This commit is contained in:
Nikolay Igotti
2017-01-30 11:10:32 +03:00
committed by GitHub
parent 01cb9d4cac
commit b06f5d0d5b
10 changed files with 254 additions and 155 deletions
@@ -17,6 +17,8 @@ import java.lang.System.out
internal final class Context(val config: KonanConfig) : KonanBackendContext() {
val debug = true
var moduleDescriptor: ModuleDescriptor? = null
// TODO: make lateinit?
@@ -17,10 +17,14 @@ 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
var slotsPhi: LLVMValueRef? = null
var slotCount = 0
var localAllocs = 0
private var returnSlot: LLVMValueRef? = null
private var slotsPhi: LLVMValueRef? = null
private var slotCount = 0
private var localAllocs = 0
private var arenaSlot: LLVMValueRef? = null
private val intPtrType = LLVMIntPtrType(llvmTargetData)!!
private val immOneIntPtrType = LLVMConstInt(intPtrType, 1, 1)!!
fun prologue(descriptor: FunctionDescriptor) {
val llvmFunction = llvmFunction(descriptor)
@@ -28,7 +32,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
prologue(llvmFunction,
LLVMGetReturnType(getLlvmFunctionType(descriptor))!!)
if (!descriptor.isExported()) {
if (!descriptor.isExported() && !context.debug) {
LLVMSetLinkage(llvmFunction, LLVMLinkage.LLVMPrivateLinkage)
// (Cannot do this before the function body is created).
}
@@ -57,6 +61,9 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
// First slot can be assigned to keep pointer to frame local arena.
slotCount = 1
localAllocs = 0
// Is removed by DCE trivially, if not needed.
arenaSlot = intToPtr(
or(ptrToInt(slotsPhi, intPtrType), immOneIntPtrType), kObjHeaderPtrPtr)
}
fun epilogue() {
@@ -90,7 +97,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
val returnPhi = phi(returnType!!)
addPhiIncoming(returnPhi, *returns.toList().toTypedArray())
if (returnSlot != null) {
updateLocalRef(returnPhi, returnSlot!!)
updateReturnRef(returnPhi, returnSlot!!)
}
releaseVars()
LLVMBuildRet(builder, returnPhi)
@@ -139,6 +146,8 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
fun div (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildSDiv(builder, arg0, arg1, name)!!
fun srem (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildSRem(builder, arg0, arg1, name)!!
fun or (arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildOr (builder, arg0, arg1, name)!!
/* integers comparisons */
fun icmpEq(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntEQ, arg0, arg1, name)!!
fun icmpGt(arg0: LLVMValueRef, arg1: LLVMValueRef, name: String = ""): LLVMValueRef = LLVMBuildICmp(builder, LLVMIntPredicate.LLVMIntSGT, arg0, arg1, name)!!
@@ -154,7 +163,8 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
fun bitcast(type: LLVMTypeRef?, value: LLVMValueRef, name: String = "") = LLVMBuildBitCast(builder, value, type, name)!!
fun intToPtr(imm: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildIntToPtr(builder, imm, DestTy, Name)!!
fun intToPtr(value: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildIntToPtr(builder, value, DestTy, Name)!!
fun ptrToInt(value: LLVMValueRef?, DestTy: LLVMTypeRef, Name: String = "") = LLVMBuildPtrToInt(builder, value, DestTy, Name)!!
fun alloca(type: LLVMTypeRef?, name: String = ""): LLVMValueRef {
if (isObjectType(type!!)) {
@@ -165,33 +175,13 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
}
}
// Return object slot (ab)used for arena matching given allocation.
private fun arenaSlot() : LLVMValueRef {
return gep(slotsPhi!!, Int32(0).llvm)
}
fun allocInstance(typeInfo: LLVMValueRef, hint: Int) : LLVMValueRef {
if (hint == SCOPE_FRAME) {
val aux = arenaSlot()
localAllocs++
return call(context.llvm.arenaAllocInstanceFunction, listOf(typeInfo, aux))
} else {
val slot = vars.createAnonymousSlot()
return call(context.llvm.allocInstanceFunction, listOf(typeInfo, slot))
}
fun allocInstance(typeInfo: LLVMValueRef, lifetime: Lifetime) : LLVMValueRef {
return call(context.llvm.allocInstanceFunction, listOf(typeInfo), lifetime)
}
fun allocArray(
typeInfo: LLVMValueRef, hint: Int, count: LLVMValueRef) : LLVMValueRef {
if (hint == SCOPE_FRAME) {
val aux = arenaSlot()
localAllocs++
return call(context.llvm.arenaAllocArrayFunction, listOf(typeInfo, count, aux))
} else {
val slot = vars.createAnonymousSlot()
return call(context.llvm.allocArrayFunction, listOf(typeInfo, count, slot))
}
typeInfo: LLVMValueRef, count: LLVMValueRef, lifetime: Lifetime) : LLVMValueRef {
return call(context.llvm.allocArrayFunction, listOf(typeInfo, count), lifetime)
}
fun load(value: LLVMValueRef, name: String = ""): LLVMValueRef {
@@ -235,6 +225,10 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
}
}
fun updateReturnRef(value: LLVMValueRef, address: LLVMValueRef) {
call(context.llvm.updateReturnRefFunction, listOf(address, value))
}
// 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,
@@ -250,19 +244,44 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
//-------------------------------------------------------------------------//
fun callAtFunctionScope(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>, name: String = "") =
call(llvmFunction, args, this::cleanupLandingpad, name)
fun callAtFunctionScope(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
lifetime: Lifetime) =
call(llvmFunction, args, lifetime, this::cleanupLandingpad)
fun call(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
lazyLandingpad: () -> LLVMBasicBlockRef? = { null }, name: String = ""): LLVMValueRef {
resultLifetime: Lifetime = Lifetime.IRRELEVANT,
lazyLandingpad: () -> LLVMBasicBlockRef? = { null }): LLVMValueRef {
var callArgs = if (isObjectReturn(llvmFunction.type)) {
// If function returns an object - create slot for the returned value or give local arena.
// This allows appropriate rootset accounting by just looking at the stack slots,
// along with ability to allocate in appropriate arena.
val resultSlot = when (resultLifetime.slotType) {
SlotType.ARENA -> {
localAllocs++
arenaSlot!!
}
SlotType.RETURN -> returnSlot!!
// TODO: for RETURN_IF_ARENA choose between created slot and arenaSlot
// dynamically.
SlotType.ANONYMOUS, SlotType.RETURN_IF_ARENA -> vars.createAnonymousSlot()
else -> throw Error("Incorrect slot type")
}
args + resultSlot
} else {
args
}
return callRaw(llvmFunction, callArgs, lazyLandingpad)
}
private fun callRaw(llvmFunction: LLVMValueRef, args: List<LLVMValueRef>,
lazyLandingpad: () -> LLVMBasicBlockRef?): LLVMValueRef {
memScoped {
val rargs = allocArrayOf(args)[0].ptr
if (LLVMIsAFunction(llvmFunction) != null /* the function declaration */ &&
LLVMAttribute.LLVMNoUnwindAttribute in LLVMGetFunctionAttrSet(llvmFunction)) {
return LLVMBuildCall(builder, llvmFunction, rargs, args.size, name)!!
return LLVMBuildCall(builder, llvmFunction, rargs, args.size, "")!!
} else {
val landingpad = lazyLandingpad()
@@ -276,7 +295,7 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
}
val success = basicBlock()
val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, landingpad, name)!!
val result = LLVMBuildInvoke(builder, llvmFunction, rargs, args.size, success, landingpad, "")!!
positionAtEnd(success)
return result
}
@@ -15,11 +15,41 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.module
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
// Different scopes/lifetimes of an object, computed by escape analysis.
const val SCOPE_FRAME = 0
const val SCOPE_GLOBAL = 1
const val SCOPE_ARENA = 2
const val SCOPE_PERMANENT = 3
internal enum class SlotType {
// Frame local arena slot can be used.
ARENA,
// Return slot can be used.
RETURN,
// Return slot, if it is an arena, can be used.
RETURN_IF_ARENA,
// Anonymous slot.
ANONYMOUS,
// Unknown slot type.
UNKNOWN
}
// Lifetimes class of reference, computed by escape analysis.
internal enum class Lifetime(val slotType: SlotType) {
// If reference is frame-local (only obtained from some call and never leaves).
LOCAL(SlotType.ARENA),
// If reference is only returned.
RETURN_VALUE(SlotType.RETURN),
// If reference is set as field of references of class RETURN_VALUE or INDIRECT_RETURN_VALUE.
INDIRECT_RETURN_VALUE(SlotType.RETURN_IF_ARENA),
// If reference is stored to the field of an incoming parameters.
PARAMETER_FIELD(SlotType.ANONYMOUS),
// If reference refers to the global (either global object or global variable).
GLOBAL(SlotType.ANONYMOUS),
// If reference used to throw.
THROW(SlotType.ANONYMOUS),
// If reference used as an argument of outgoing function. Class can be improved by escape analysis
// of called function.
ARGUMENT(SlotType.ANONYMOUS),
// If reference class is unknown.
UNKNOWN(SlotType.UNKNOWN),
// If reference class is irrelevant.
IRRELEVANT(SlotType.UNKNOWN)
}
/**
* Provides utility methods to the implementer.
@@ -207,10 +237,9 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
var globalInitIndex:Int = 0
val allocInstanceFunction = importRtFunction("AllocInstance")
val arenaAllocInstanceFunction = importRtFunction("ArenaAllocInstance")
val allocArrayFunction = importRtFunction("AllocArrayInstance")
val arenaAllocArrayFunction = importRtFunction("ArenaAllocArrayInstance")
val initInstanceFunction = importRtFunction("InitInstance")
val updateReturnRefFunction = importRtFunction("UpdateReturnRef")
val setLocalRefFunction = importRtFunction("SetLocalRef")
val setGlobalRefFunction = importRtFunction("SetGlobalRef")
val updateLocalRefFunction = importRtFunction("UpdateLocalRef")
@@ -2,7 +2,7 @@ package org.jetbrains.kotlin.backend.konan.llvm
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid
@@ -11,14 +11,15 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
// We build graph with the following nodes:
// * allocation set, keeping tuple of [local, ctor call, owner function], AS
// * local store set, keeping pair [local, stored], LSS
// * field store set, keeping tuple [local, stored], FSS
// * global store set, [local, stored], GSS
// * field store set, keeping tuple [local, object to store, stored field id], FSS
// * global store set, [local, stored global address], GSS
// Function we're trying to compute is the following:
// for each element of AS, could it be referred by someone, whose value is
// alive on return from function, where element was allocated.
// Each element in RS is associated with few elements in AS, which it could refer to.
// TODO: exact algorithm TBD.
internal class EscapeAnalyzerVisitor(val allocHints: MutableMap<IrCall, Int>) : IrElementVisitorVoid {
//
internal class EscapeAnalyzerVisitor(
val lifetimes: MutableMap<IrMemberAccessExpression, Lifetime>) : IrElementVisitorVoid {
override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this)
@@ -29,8 +30,9 @@ internal class EscapeAnalyzerVisitor(val allocHints: MutableMap<IrCall, Int>) :
}
}
fun prepareAllocHints(irModule: IrModuleFragment, allocHints: MutableMap<IrCall, Int>) {
assert(allocHints.size == 0)
internal fun computeLifetimes(irModule: IrModuleFragment,
lifetimes: MutableMap<IrMemberAccessExpression, Lifetime>) {
assert(lifetimes.size == 0)
irModule.acceptVoid(EscapeAnalyzerVisitor(allocHints))
irModule.acceptVoid(EscapeAnalyzerVisitor(lifetimes))
}
@@ -119,7 +119,7 @@ internal class MetadatorVisitor(val context: Context) : IrElementVisitorVoid {
/**
* Defines how to generate context-dependent operations.
*/
interface CodeContext {
internal interface CodeContext {
/**
* Generates `return` [value] operation.
@@ -132,7 +132,7 @@ interface CodeContext {
fun genContinue(destination: IrContinue)
fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>): LLVMValueRef
fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef
fun genThrow(exception: LLVMValueRef)
@@ -168,7 +168,7 @@ interface CodeContext {
internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid {
val codegen = CodeGenerator(context)
val allocHints = mutableMapOf<IrCall, Int>()
val resultLifetimes = mutableMapOf<IrMemberAccessExpression, Lifetime>()
//-------------------------------------------------------------------------//
@@ -190,7 +190,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
override fun genContinue(destination: IrContinue) = unsupported()
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>) = unsupported(function)
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, resultLifetime: Lifetime) = unsupported(function)
override fun genThrow(exception: LLVMValueRef) = unsupported()
@@ -237,7 +237,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
override fun visitModuleFragment(module: IrModuleFragment) {
context.log("visitModule : ${ir2string(module)}")
prepareAllocHints(module, allocHints)
computeLifetimes(module, resultLifetimes)
module.acceptChildrenVoid(this)
appendLlvmUsed(context.llvm.usedFunctions)
@@ -529,14 +529,14 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
}
}
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>) =
codegen.callAtFunctionScope(function, args)
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, resultLifetime: Lifetime) =
codegen.callAtFunctionScope(function, args, resultLifetime)
override fun genThrow(exception: LLVMValueRef) {
val objHeaderPtr = codegen.bitcast(codegen.kObjHeaderPtr, exception)
val args = listOf(objHeaderPtr)
this.genCall(context.llvm.throwExceptionFunction, args)
this.genCall(context.llvm.throwExceptionFunction, args, Lifetime.IRRELEVANT)
codegen.unreachable()
}
@@ -695,7 +695,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, ctor)
val newValue = call(context.llvm.initInstanceFunction, args)
val newValue = call(context.llvm.initInstanceFunction, args, Lifetime.GLOBAL)
val bbInitResult = codegen.currentBlock
codegen.br(bbExit)
@@ -802,7 +802,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
codegen.plus(sum, size!!)
}
val array = codegen.allocArray(codegen.typeInfoValue(value.type)!!, SCOPE_GLOBAL, finalLength)
val array = codegen.allocArray(codegen.typeInfoValue(value.type)!!, finalLength, Lifetime.GLOBAL)
elements.fold(kImmZero) { sum, (exp, size, isArray) ->
if (!isArray) {
call(context.llvm.setArrayFunction, listOf(array, sum, exp))
@@ -841,8 +841,10 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
return@map Element(codegen.staticData.kotlinStringLiteral(it as IrConst<String>).llvm, null, string.length)
} else {
val toStringDescriptor = getToString(it.type)
val string = if (KotlinBuiltIns.isString(it.type)) evaluationResult
else evaluateSimpleFunctionCall(toStringDescriptor, listOf(evaluationResult))
val string =
if (KotlinBuiltIns.isString(it.type)) evaluationResult
else evaluateSimpleFunctionCall(
toStringDescriptor, listOf(evaluationResult), Lifetime.LOCAL)
val length = call(codegen.llvmFunction(kStringLength!!), listOf(string))
return@map Element(string, length, -1)
}
@@ -856,7 +858,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val constructor = kStringBuilder!!.constructors
.firstOrNull { it -> it.valueParameters.size == 1 && KotlinBuiltIns.isInt(it.valueParameters[0].type) }!!
val stringBuilderObj = codegen.allocInstance(codegen.typeInfoValue(kStringBuilder), SCOPE_FRAME)
val stringBuilderObj = codegen.allocInstance(codegen.typeInfoValue(kStringBuilder), Lifetime.LOCAL)
call(codegen.llvmFunction(constructor), listOf(stringBuilderObj, totalLength))
@@ -865,7 +867,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
return@fold sum
}
return evaluateSimpleFunctionCall(kStringBuilderToString!!, listOf(stringBuilderObj))
return evaluateSimpleFunctionCall(kStringBuilderToString!!, listOf(stringBuilderObj),
Lifetime.GLOBAL /* TODO: fix */)
}
//-------------------------------------------------------------------------//
@@ -957,8 +960,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
}
// The call inside [CatchingScope] must be configured to dispatch exception to the scope's handler.
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>): LLVMValueRef {
val res = codegen.call(function, args, this::landingpad)
override fun genCall(function: LLVMValueRef, args: List<LLVMValueRef>, lifetime: Lifetime): LLVMValueRef {
val res = codegen.call(function, args, lifetime, this::landingpad)
return res
}
@@ -1295,7 +1298,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.
call(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
}
@@ -1632,7 +1635,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
value is IrDelegatingConstructorCall ->
return delegatingConstructorCall(value.descriptor, args)
value.descriptor is FunctionDescriptor -> return evaluateFunctionCall(value as IrCall, args)
value.descriptor is FunctionDescriptor -> return evaluateFunctionCall(
value as IrCall, args, resultLifetime(value))
else -> {
TODO("${ir2string(value)}")
}
@@ -1667,11 +1671,12 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
private fun evaluateFunctionCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
private fun evaluateFunctionCall(callee: IrCall, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef {
val descriptor:FunctionDescriptor = callee.descriptor as FunctionDescriptor
if (descriptor.isFunctionInvoke) {
return evaluateFunctionInvoke(descriptor, args)
return evaluateFunctionInvoke(descriptor, args, resultLifetime)
}
if (descriptor.isIntrinsic) {
@@ -1681,7 +1686,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
when (descriptor) {
is IrBuiltinOperatorDescriptorBase -> return evaluateOperatorCall (callee, args)
is ConstructorDescriptor -> return evaluateConstructorCall (callee, args)
else -> return evaluateSimpleFunctionCall(descriptor, args, callee.superQualifier)
else -> return evaluateSimpleFunctionCall(
descriptor, args, resultLifetime, callee.superQualifier)
}
}
@@ -1696,7 +1702,7 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
}
private fun evaluateFunctionInvoke(descriptor: FunctionDescriptor,
args: List<LLVMValueRef>): LLVMValueRef {
args: List<LLVMValueRef>, resultLifetime: Lifetime): LLVMValueRef {
// Note: the whole function code below is written in the assumption that
// `invoke` method receiver is passed as first argument.
@@ -1711,22 +1717,24 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
// Get `functionImpl.unboundRef`:
val unboundRef = evaluateSimpleFunctionCall(functionImplUnboundRefGetter,
listOf(functionImpl))
listOf(functionImpl), Lifetime.IRRELEVANT /* unboundRef isn't managed reference */)
// Cast `functionImpl.unboundRef` to pointer to function:
val entryPtr = codegen.bitcast(pointerType(unboundRefType), unboundRef, "entry")
return call(descriptor, entryPtr, args)
return call(descriptor, entryPtr, args, resultLifetime)
}
//-------------------------------------------------------------------------//
private fun evaluateSimpleFunctionCall(descriptor: FunctionDescriptor, args: List<LLVMValueRef>, superClass: ClassDescriptor? = null): LLVMValueRef {
private fun evaluateSimpleFunctionCall(
descriptor: FunctionDescriptor, args: List<LLVMValueRef>,
resultLifetime: Lifetime, superClass: ClassDescriptor? = null): LLVMValueRef {
//context.log("evaluateSimpleFunctionCall : $tmpVariableName = ${ir2string(value)}")
if (descriptor.isOverridable && superClass == null)
return callVirtual(descriptor, args)
return callVirtual(descriptor, args, resultLifetime)
else
return callDirect(descriptor, args)
return callDirect(descriptor, args, resultLifetime)
}
//-------------------------------------------------------------------------//
@@ -1737,12 +1745,13 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
if (descriptor.dispatchReceiverParameter != null)
args.add(evaluateExpression(value.dispatchReceiver!!)) //add this ptr
args.add(evaluateExpression(value.getValueArgument(0)!!))
return evaluateSimpleFunctionCall(descriptor, args, value.superQualifier)
return evaluateSimpleFunctionCall(
descriptor, args, Lifetime.IRRELEVANT, value.superQualifier)
}
//-------------------------------------------------------------------------//
private fun hintForCall(callee: IrCall): Int {
return allocHints.getOrElse(callee) { SCOPE_GLOBAL }
private fun resultLifetime(callee: IrMemberAccessExpression): Lifetime {
return resultLifetimes.getOrElse(callee) { Lifetime.GLOBAL }
}
private fun evaluateConstructorCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
@@ -1751,12 +1760,13 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
val constructedClass = (callee.descriptor as ConstructorDescriptor).constructedClass
val thisValue = if (constructedClass.isArray) {
assert(args.size >= 1 && args[0].type == int32Type)
codegen.allocArray(codegen.typeInfoValue(constructedClass), hintForCall(callee), args[0])
codegen.allocArray(codegen.typeInfoValue(constructedClass), args[0],
resultLifetime(callee))
} else {
codegen.allocInstance(codegen.typeInfoValue(constructedClass), hintForCall(callee))
codegen.allocInstance(codegen.typeInfoValue(constructedClass), resultLifetime(callee))
}
evaluateSimpleFunctionCall(callee.descriptor as FunctionDescriptor,
listOf(thisValue) + args)
listOf(thisValue) + args, Lifetime.IRRELEVANT /* constructor doesn't return anything */)
return thisValue
}
}
@@ -1851,15 +1861,17 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
//-------------------------------------------------------------------------//
fun callDirect(descriptor: FunctionDescriptor, args: List<LLVMValueRef>): LLVMValueRef {
fun callDirect(descriptor: FunctionDescriptor, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef {
val realDescriptor = descriptor.resolveFakeOverride().original
val llvmFunction = codegen.functionLlvmValue(realDescriptor)
return call(descriptor, llvmFunction, args)
return call(descriptor, llvmFunction, args, resultLifetime)
}
//-------------------------------------------------------------------------//
fun callVirtual(descriptor: FunctionDescriptor, args: List<LLVMValueRef>): LLVMValueRef {
fun callVirtual(descriptor: FunctionDescriptor, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef {
val typeInfoPtrPtr = LLVMBuildStructGEP(codegen.builder, args[0], 0 /* type_info */, "")!!
val typeInfoPtr = codegen.load(typeInfoPtrPtr)
assert (typeInfoPtr.type == codegen.kTypeInfoPtr)
@@ -1881,12 +1893,11 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
// for an additional per-interface vtable.
val methodHash = codegen.functionHash(descriptor) // Calculate hash of the method to be invoked
val lookupArgs = listOf(typeInfoPtr, methodHash) // Prepare args for lookup
call(context.llvm.lookupOpenMethodFunction,
lookupArgs)
call(context.llvm.lookupOpenMethodFunction, lookupArgs)
}
val functionPtrType = pointerType(codegen.getLlvmFunctionType(descriptor)) // Construct type of the method to be invoked
val function = codegen.bitcast(functionPtrType, llvmMethod) // Cast method address to the type
return call(descriptor, function, args) // Invoke the method
return call(descriptor, function, args, resultLifetime) // Invoke the method
}
//-------------------------------------------------------------------------//
@@ -1895,8 +1906,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
// instead of a plain list.
// 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 = call(function, args)
private fun call(descriptor: FunctionDescriptor, function: LLVMValueRef, args: List<LLVMValueRef>,
resultLifetime: Lifetime): LLVMValueRef {
val result = call(function, args, resultLifetime)
if (descriptor.returnType?.isNothing() == true) {
codegen.unreachable()
}
@@ -1908,15 +1920,9 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
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 at the stack slots.
val resultSlot = codegen.vars.createAnonymousSlot()
return currentCodeContext.genCall(function, args + resultSlot)
} else {
return currentCodeContext.genCall(function, args)
}
private fun call(function: LLVMValueRef, args: List<LLVMValueRef>,
resultLifetime: Lifetime = Lifetime.IRRELEVANT): LLVMValueRef {
return currentCodeContext.genCall(function, args, resultLifetime)
}
//-------------------------------------------------------------------------//
@@ -1934,7 +1940,8 @@ internal class CodeGeneratorVisitor(val context: Context) : IrElementVisitorVoid
codegen.bitcast(thisPtrArgType, thisPtr)
}
return callDirect(descriptor, listOf(thisPtrArg) + args)
return callDirect(descriptor, listOf(thisPtrArg) + args,
Lifetime.IRRELEVANT /* no value returned */)
}
//-------------------------------------------------------------------------//