Move singleton support from IR visitor to code generator

This commit is contained in:
Svyatoslav Scherbina
2018-01-09 14:21:38 +03:00
committed by SvyatoslavScherbina
parent d4f39f8142
commit f986a0cb10
3 changed files with 77 additions and 65 deletions
@@ -21,6 +21,7 @@ import kotlinx.cinterop.*
import llvm.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.isInterface
import org.jetbrains.kotlin.backend.konan.descriptors.isUnit
import org.jetbrains.kotlin.backend.konan.descriptors.stdlibModule
import org.jetbrains.kotlin.backend.konan.isObjCClass
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
@@ -49,6 +50,32 @@ internal class CodeGenerator(override val context: Context) : ContextUtils {
fun functionLlvmValue(descriptor: FunctionDescriptor) = descriptor.llvmFunction
fun functionEntryPointAddress(descriptor: FunctionDescriptor) = descriptor.entryPointAddress.llvm
fun functionHash(descriptor: FunctionDescriptor): LLVMValueRef = descriptor.functionName.localHash.llvm
fun getObjectInstanceStorage(descriptor: ClassDescriptor): LLVMValueRef {
assert (!descriptor.isUnit())
val llvmGlobal = if (!isExternal(descriptor)) {
context.llvmDeclarations.forSingleton(descriptor).instanceFieldRef
} else {
val llvmType = getLLVMType(descriptor.defaultType)
importGlobal(
descriptor.objectInstanceFieldSymbolName,
llvmType,
origin = descriptor.llvmSymbolOrigin,
threadLocal = true
)
}
context.llvm.objects += llvmGlobal
return llvmGlobal
}
fun typeInfoForAllocation(constructedClass: ClassDescriptor): LLVMValueRef {
val descriptorForTypeInfo = if (constructedClass.isObjCClass()) {
context.interopBuiltIns.objCPointerHolder
} else {
constructedClass
}
return typeInfoValue(descriptorForTypeInfo)
}
}
internal sealed class ExceptionHandler {
@@ -352,6 +379,9 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
return call(context.llvm.allocInstanceFunction, listOf(typeInfo), lifetime)
}
fun allocInstance(descriptor: ClassDescriptor, lifetime: Lifetime): LLVMValueRef =
allocInstance(codegen.typeInfoForAllocation(descriptor), lifetime)
fun allocArray(
typeInfo: LLVMValueRef, count: LLVMValueRef, lifetime: Lifetime): LLVMValueRef {
return call(context.llvm.allocArrayFunction, listOf(typeInfo, count), lifetime)
@@ -532,6 +562,40 @@ internal class FunctionGenerationContext(val function: LLVMValueRef,
return bitcast(functionPtrType, llvmMethod) // Cast method address to the type
}
fun getObjectValue(
descriptor: ClassDescriptor,
exceptionHandler: ExceptionHandler,
locationInfo: LocationInfo?
): LLVMValueRef {
if (descriptor.isUnit()) {
return codegen.theUnitInstanceRef.llvm
}
val objectPtr = codegen.getObjectInstanceStorage(descriptor)
val bbCurrent = currentBlock
val bbInit = basicBlock("label_init", locationInfo)
val bbExit = basicBlock("label_continue", locationInfo)
val objectVal = loadSlot(objectPtr, false)
val condition = icmpNe(objectVal, codegen.kNullObjHeaderPtr)
condBr(condition, bbExit, bbInit)
positionAtEnd(bbInit)
val typeInfo = codegen.typeInfoForAllocation(descriptor)
val initFunction = 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, Lifetime.GLOBAL, exceptionHandler)
val bbInitResult = currentBlock
br(bbExit)
positionAtEnd(bbExit)
val valuePhi = phi(codegen.getLLVMType(descriptor.defaultType))
addPhiIncoming(valuePhi,
bbCurrent to objectVal, bbInitResult to newValue)
return valuePhi
}
fun resetDebugLocation() {
if (!context.shouldContainDebugInfo()) return
if (!currentPositionHolder.isAfterTerminator)
@@ -439,6 +439,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
val compilerUsedGlobals = mutableListOf<LLVMValueRef>()
val staticInitializers = mutableListOf<LLVMValueRef>()
val fileInitializers = mutableListOf<IrField>()
val objects = mutableSetOf<LLVMValueRef>()
private object lazyRtFunction {
operator fun provideDelegate(
@@ -332,7 +332,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val address = context.llvmDeclarations.forStaticField(descriptor).storage
storeAny(codegen.kNullObjHeaderPtr, address)
}
objects.forEach { storeAny(codegen.kNullObjHeaderPtr, it) }
context.llvm.objects.forEach { storeAny(codegen.kNullObjHeaderPtr, it) }
ret(null)
}
@@ -378,12 +378,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
override fun visitFile(declaration: IrFile) {
// TODO: collect those two in one place.
context.llvm.fileInitializers.clear()
objects.clear()
context.llvm.objects.clear()
using(FileScope(declaration)) {
declaration.acceptChildrenVoid(this)
if (context.llvm.fileInitializers.isEmpty() && objects.isEmpty())
if (context.llvm.fileInitializers.isEmpty() && context.llvm.objects.isEmpty())
return
// Create global initialization records.
@@ -449,7 +449,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
if (constructorDescriptor.isPrimary) {
if (DescriptorUtils.isObject(classDescriptor)) {
if (!classDescriptor.isUnit()) {
val objectPtr = getObjectInstanceStorage(classDescriptor)
val objectPtr = codegen.getObjectInstanceStorage(classDescriptor)
LLVMSetInitializer(objectPtr, codegen.kNullObjHeaderPtr)
}
@@ -730,35 +730,12 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private fun evaluateGetObjectValue(value: IrGetObjectValue): LLVMValueRef {
if (value.descriptor.isUnit()) {
return codegen.theUnitInstanceRef.llvm
}
val objectPtr = getObjectInstanceStorage(value.descriptor)
val bbCurrent = functionGenerationContext.currentBlock
val bbInit = functionGenerationContext.basicBlock("label_init", value.startLocation)
val bbExit = functionGenerationContext.basicBlock("label_continue", value.startLocation)
val objectVal = functionGenerationContext.loadSlot(objectPtr, false)
val condition = functionGenerationContext.icmpNe(objectVal, codegen.kNullObjHeaderPtr)
functionGenerationContext.condBr(condition, bbExit, bbInit)
functionGenerationContext.positionAtEnd(bbInit)
val typeInfo = typeInfoForAllocation(value.descriptor)
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, Lifetime.GLOBAL)
val bbInitResult = functionGenerationContext.currentBlock
functionGenerationContext.br(bbExit)
functionGenerationContext.positionAtEnd(bbExit)
val valuePhi = functionGenerationContext.phi(codegen.getLLVMType(value.type))
functionGenerationContext.addPhiIncoming(valuePhi,
bbCurrent to objectVal, bbInitResult to newValue)
return valuePhi
}
private fun evaluateGetObjectValue(value: IrGetObjectValue): LLVMValueRef =
functionGenerationContext.getObjectValue(
value.descriptor,
currentCodeContext.exceptionHandler,
value.startLocation
)
//-------------------------------------------------------------------------//
@@ -1300,27 +1277,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
//-------------------------------------------------------------------------//
private val objects = mutableSetOf<LLVMValueRef>()
private fun getObjectInstanceStorage(descriptor: ClassDescriptor): LLVMValueRef {
assert (!descriptor.isUnit())
val llvmGlobal = if (!codegen.isExternal(descriptor)) {
context.llvmDeclarations.forSingleton(descriptor).instanceFieldRef
} else {
val llvmType = codegen.getLLVMType(descriptor.defaultType)
codegen.importGlobal(
descriptor.objectInstanceFieldSymbolName,
llvmType,
origin = descriptor.llvmSymbolOrigin,
threadLocal = true
)
}
objects += llvmGlobal
return llvmGlobal
}
//-------------------------------------------------------------------------//
private fun evaluateSetField(value: IrSetField): LLVMValueRef {
context.log{"evaluateSetField : ${ir2string(value)}"}
val valueToAssign = evaluateExpression(value.value)
@@ -1947,7 +1903,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
callDirect(context.interopBuiltIns.allocObjCObject, listOf(genGetObjCClass(constructedClass)),
resultLifetime(callee))
} else {
functionGenerationContext.allocInstance(typeInfoForAllocation(constructedClass), resultLifetime(callee))
functionGenerationContext.allocInstance(constructedClass, resultLifetime(callee))
}
evaluateSimpleFunctionCall(callee.descriptor,
listOf(thisValue) + args, Lifetime.IRRELEVANT /* constructor doesn't return anything */)
@@ -1955,15 +1911,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
}
}
private fun typeInfoForAllocation(constructedClass: ClassDescriptor): LLVMValueRef {
val descriptorForTypeInfo = if (constructedClass.isObjCClass()) {
context.interopBuiltIns.objCPointerHolder
} else {
constructedClass
}
return codegen.typeInfoValue(descriptorForTypeInfo)
}
//-------------------------------------------------------------------------//
private fun evaluateIntrinsicCall(callee: IrCall, args: List<LLVMValueRef>): LLVMValueRef {
@@ -2064,7 +2011,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
val typeParameterT = context.ir.symbols.createUninitializedInstance.descriptor.typeParameters[0]
val enumClass = callee.getTypeArgument(typeParameterT)!!
val enumClassDescriptor = enumClass.constructor.declarationDescriptor as ClassDescriptor
functionGenerationContext.allocInstance(typeInfoForAllocation(enumClassDescriptor), resultLifetime(callee))
functionGenerationContext.allocInstance(enumClassDescriptor, resultLifetime(callee))
}
else -> TODO(callee.descriptor.original.toString())