Refactor CAdapterGenerator to avoid using SymbolTable during codegen

This commit is contained in:
Svyatoslav Scherbina
2019-04-11 14:15:47 +03:00
committed by SvyatoslavScherbina
parent 1ec5a188f7
commit 50c4fcb3db
4 changed files with 66 additions and 12 deletions
@@ -18,6 +18,11 @@ import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.builtins.UnsignedType import org.jetbrains.kotlin.builtins.UnsignedType
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.IrClass
import org.jetbrains.kotlin.ir.declarations.IrEnumEntry
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.referenceFunction
import org.jetbrains.kotlin.konan.target.* import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.name.isChildOf import org.jetbrains.kotlin.name.isChildOf
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -204,8 +209,9 @@ private class ExportedElement(val kind: ElementKind,
when { when {
isFunction -> { isFunction -> {
val function = declaration as FunctionDescriptor val function = declaration as FunctionDescriptor
val irFunction = irSymbol.owner as IrFunction
cname = "_konan_function_${owner.nextFunctionIndex()}" cname = "_konan_function_${owner.nextFunctionIndex()}"
val llvmFunction = owner.codegen.llvmFunction(context.ir.getFromCurrentModule(function)) val llvmFunction = owner.codegen.llvmFunction(irFunction)
// If function is virtual, we need to resolve receiver properly. // If function is virtual, we need to resolve receiver properly.
val bridge = if (!DescriptorUtils.isTopLevelDeclaration(function) && !function.isExtension && val bridge = if (!DescriptorUtils.isTopLevelDeclaration(function) && !function.isExtension &&
function.isOverridable) { function.isOverridable) {
@@ -214,7 +220,7 @@ private class ExportedElement(val kind: ElementKind,
val receiver = param(0) val receiver = param(0)
val numParams = LLVMCountParams(llvmFunction) val numParams = LLVMCountParams(llvmFunction)
val args = (0..numParams - 1).map { index -> param(index) } val args = (0..numParams - 1).map { index -> param(index) }
val callee = lookupVirtualImpl(receiver, context.ir.getFromCurrentModule(function)) val callee = lookupVirtualImpl(receiver, irFunction)
val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true) val result = call(callee, args, exceptionHandler = ExceptionHandler.Caller, verbatim = true)
ret(result) ret(result)
} }
@@ -224,19 +230,19 @@ private class ExportedElement(val kind: ElementKind,
LLVMSetLinkage(bridge, LLVMLinkage.LLVMExternalLinkage) LLVMSetLinkage(bridge, LLVMLinkage.LLVMExternalLinkage)
} }
isClass -> { isClass -> {
val classDescriptor = declaration as ClassDescriptor val irClass = irSymbol.owner as IrClass
cname = "_konan_function_${owner.nextFunctionIndex()}" cname = "_konan_function_${owner.nextFunctionIndex()}"
// Produce type getter. // Produce type getter.
val getTypeFunction = LLVMAddFunction(context.llvmModule, "${cname}_type", owner.kGetTypeFuncType)!! val getTypeFunction = LLVMAddFunction(context.llvmModule, "${cname}_type", owner.kGetTypeFuncType)!!
val builder = LLVMCreateBuilder()!! val builder = LLVMCreateBuilder()!!
val bb = LLVMAppendBasicBlock(getTypeFunction, "")!! val bb = LLVMAppendBasicBlock(getTypeFunction, "")!!
LLVMPositionBuilderAtEnd(builder, bb) LLVMPositionBuilderAtEnd(builder, bb)
LLVMBuildRet(builder, context.ir.getFromCurrentModule(classDescriptor).typeInfoPtr.llvm) LLVMBuildRet(builder, irClass.typeInfoPtr.llvm)
LLVMDisposeBuilder(builder) LLVMDisposeBuilder(builder)
// Produce instance getter if needed. // Produce instance getter if needed.
if (isSingletonObject) { if (isSingletonObject) {
generateFunction(owner.codegen, owner.kGetObjectFuncType, "${cname}_instance") { generateFunction(owner.codegen, owner.kGetObjectFuncType, "${cname}_instance") {
val value = getObjectValue(context.ir.get(classDescriptor), ExceptionHandler.Caller, null) val value = getObjectValue(irClass, ExceptionHandler.Caller, null)
ret(value) ret(value)
} }
} }
@@ -245,7 +251,7 @@ private class ExportedElement(val kind: ElementKind,
// Produce entry getter. // Produce entry getter.
cname = "_konan_function_${owner.nextFunctionIndex()}" cname = "_konan_function_${owner.nextFunctionIndex()}"
generateFunction(owner.codegen, owner.kGetObjectFuncType, cname) { generateFunction(owner.codegen, owner.kGetObjectFuncType, cname) {
val irEnumEntry = context.ir.getEnumEntryFromCurrentModule(declaration as ClassDescriptor) val irEnumEntry = irSymbol.owner as IrEnumEntry
val value = getEnumEntry(irEnumEntry, ExceptionHandler.Caller) val value = getEnumEntry(irEnumEntry, ExceptionHandler.Caller)
ret(value) ret(value)
} }
@@ -269,6 +275,13 @@ private class ExportedElement(val kind: ElementKind,
val isEnumEntry = declaration is ClassDescriptor && declaration.kind == ClassKind.ENUM_ENTRY val isEnumEntry = declaration is ClassDescriptor && declaration.kind == ClassKind.ENUM_ENTRY
val isSingletonObject = declaration is ClassDescriptor && DescriptorUtils.isObject(declaration) val isSingletonObject = declaration is ClassDescriptor && DescriptorUtils.isObject(declaration)
private val irSymbol = when {
isFunction -> owner.symbolTable.referenceFunction(declaration as FunctionDescriptor)
isClass -> owner.symbolTable.referenceClass(declaration as ClassDescriptor)
isEnumEntry -> owner.symbolTable.referenceEnumEntry(declaration as ClassDescriptor)
else -> error("unexpected $kind element: $declaration")
}
fun KotlinType.includeToSignature() = !this.isUnit() fun KotlinType.includeToSignature() = !this.isUnit()
fun makeCFunctionSignature(shortName: Boolean): List<Pair<String, ClassDescriptor>> { fun makeCFunctionSignature(shortName: Boolean): List<Pair<String, ClassDescriptor>> {
@@ -493,14 +506,19 @@ private fun ModuleDescriptor.getPackageFragments(): List<PackageFragmentDescript
getPackage(it).fragments.filter { it.module == this } getPackage(it).fragments.filter { it.module == this }
} }
internal class CAdapterGenerator( internal class CAdapterGenerator(val context: Context) : DeclarationDescriptorVisitor<Boolean, Void?> {
val context: Context, internal val codegen: CodeGenerator) : DeclarationDescriptorVisitor<Boolean, Void?> {
private val scopes = mutableListOf<ExportedElementScope>() private val scopes = mutableListOf<ExportedElementScope>()
internal val prefix = context.config.moduleId internal val prefix = context.config.moduleId
private lateinit var outputStreamWriter: PrintWriter private lateinit var outputStreamWriter: PrintWriter
private val paramNamesRecorded = mutableMapOf<String, Int>() private val paramNamesRecorded = mutableMapOf<String, Int>()
private var codegenOrNull: CodeGenerator? = null
internal val codegen get() = codegenOrNull!!
private var symbolTableOrNull: SymbolTable? = null
internal val symbolTable get() = symbolTableOrNull!!
internal fun paramsToUniqueNames(params: List<ParameterDescriptor>): Map<ParameterDescriptor, String> { internal fun paramsToUniqueNames(params: List<ParameterDescriptor>): Map<ParameterDescriptor, String> {
paramNamesRecorded.clear() paramNamesRecorded.clear()
return params.associate { return params.associate {
@@ -641,7 +659,25 @@ internal class CAdapterGenerator(
private val moduleDescriptors = mutableSetOf<ModuleDescriptor>() private val moduleDescriptors = mutableSetOf<ModuleDescriptor>()
fun generateBindings() { fun buildExports(symbolTable: SymbolTable) {
this.symbolTableOrNull = symbolTable
try {
buildExports()
} finally {
this.symbolTableOrNull = null
}
}
fun generateBindings(codegen: CodeGenerator) {
this.codegenOrNull = codegen
try {
generateBindings()
} finally {
this.codegenOrNull = null
}
}
private fun buildExports() {
scopes.push(ExportedElementScope(ScopeKind.TOP, "kotlin")) scopes.push(ExportedElementScope(ScopeKind.TOP, "kotlin"))
moduleDescriptors += context.moduleDescriptor moduleDescriptors += context.moduleDescriptor
moduleDescriptors += context.getExportedDependencies() moduleDescriptors += context.getExportedDependencies()
@@ -660,7 +696,9 @@ internal class CAdapterGenerator(
).forEach { ).forEach {
TypeUtils.getClassDescriptor(it)!!.accept(this@CAdapterGenerator, null) TypeUtils.getClassDescriptor(it)!!.accept(this@CAdapterGenerator, null)
} }
}
private fun generateBindings() {
val top = scopes.pop() val top = scopes.pop()
assert(scopes.isEmpty() && top.kind == ScopeKind.TOP) assert(scopes.isEmpty() && top.kind == ScopeKind.TOP)
@@ -1012,9 +1050,9 @@ internal class CAdapterGenerator(
private var functionIndex = 0 private var functionIndex = 0
fun nextFunctionIndex() = functionIndex++ fun nextFunctionIndex() = functionIndex++
internal val kGetTypeFuncType = internal val kGetTypeFuncType get() =
LLVMFunctionType(codegen.kTypeInfoPtr, null, 0, 0)!! LLVMFunctionType(codegen.kTypeInfoPtr, null, 0, 0)!!
// Abstraction leak for slot :(. // Abstraction leak for slot :(.
internal val kGetObjectFuncType = internal val kGetObjectFuncType get() =
LLVMFunctionType(codegen.kObjHeaderPtr, cValuesOf(codegen.kObjHeaderPtrPtr), 1, 0)!! LLVMFunctionType(codegen.kObjHeaderPtr, cValuesOf(codegen.kObjHeaderPtrPtr), 1, 0)!!
} }
@@ -203,6 +203,8 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
lateinit var objCExport: ObjCExport lateinit var objCExport: ObjCExport
lateinit var cAdapterGenerator: CAdapterGenerator
override val builtIns: KonanBuiltIns by lazy(PUBLICATION) { override val builtIns: KonanBuiltIns by lazy(PUBLICATION) {
moduleDescriptor.builtIns as KonanBuiltIns moduleDescriptor.builtIns as KonanBuiltIns
} }
@@ -72,6 +72,19 @@ internal val objCExportPhase = konanUnitPhase(
description = "Objective-C header generation" description = "Objective-C header generation"
) )
internal val buildCExportsPhase = konanUnitPhase(
op = {
if (this.isNativeLibrary) {
this.cAdapterGenerator = CAdapterGenerator(this).also {
it.buildExports(this.symbolTable!!)
}
}
},
name = "BuildCExports",
description = "Build C exports",
prerequisite = setOf(createSymbolTablePhase)
)
internal val psiToIrPhase = konanUnitPhase( internal val psiToIrPhase = konanUnitPhase(
op = { op = {
// Translate AST to high level IR. // Translate AST to high level IR.
@@ -303,6 +316,7 @@ val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase(
lower = frontendPhase then lower = frontendPhase then
createSymbolTablePhase then createSymbolTablePhase then
objCExportPhase then objCExportPhase then
buildCExportsPhase then
psiToIrPhase then psiToIrPhase then
destroySymbolTablePhase then destroySymbolTablePhase then
irGeneratorPluginsPhase then irGeneratorPluginsPhase then
@@ -295,7 +295,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
} }
private fun appendCAdapters() { private fun appendCAdapters() {
CAdapterGenerator(context, codegen).generateBindings() context.cAdapterGenerator.generateBindings(codegen)
} }
//-------------------------------------------------------------------------// //-------------------------------------------------------------------------//