Extract generated <obinit> method, and calls to it

This commit is contained in:
Tamas Vajk
2021-09-24 15:31:14 +02:00
committed by Ian Lynagh
parent e31c573fb5
commit b87c8e2529
5 changed files with 58 additions and 17 deletions

View File

@@ -43,7 +43,7 @@ class KotlinExtractorExtension(private val invocationTrapFile: String, private v
moduleFragment.files.mapIndexed { index: Int, file: IrFile ->
val fileTrapWriter = FileTrapWriter(lm, invocationTrapFileBW, file)
fileTrapWriter.writeCompilation_compiling_files(compilation, index, fileTrapWriter.fileId)
doFile(invocationTrapFile, fileTrapWriter, checkTrapIdentical, logCounter, trapDir, srcDir, file)
doFile(invocationTrapFile, fileTrapWriter, checkTrapIdentical, logCounter, trapDir, srcDir, file, pluginContext)
}
logger.printLimitedWarningCounts()
// We don't want the compiler to continue and generate class
@@ -94,7 +94,14 @@ private fun equivalentTrap(f1: File, f2: File): Boolean {
}
}
fun doFile(invocationTrapFile: String, fileTrapWriter: FileTrapWriter, checkTrapIdentical: Boolean, logCounter: LogCounter, trapDir: File, srcDir: File, file: IrFile) {
fun doFile(invocationTrapFile: String,
fileTrapWriter: FileTrapWriter,
checkTrapIdentical: Boolean,
logCounter: LogCounter,
trapDir: File,
srcDir: File,
file: IrFile,
pluginContext: IrPluginContext) {
val filePath = file.path
val logger = FileLogger(logCounter, fileTrapWriter)
logger.info("Extracting file $filePath")
@@ -116,7 +123,7 @@ fun doFile(invocationTrapFile: String, fileTrapWriter: FileTrapWriter, checkTrap
trapTmpFile.bufferedWriter().use { trapFileBW ->
trapFileBW.write("// Generated by invocation ${invocationTrapFile.replace("\n", "\n// ")}\n")
val tw = FileTrapWriter(TrapLabelManager(), trapFileBW, file)
val fileExtractor = KotlinFileExtractor(logger, tw, file)
val fileExtractor = KotlinFileExtractor(logger, tw, file, pluginContext)
fileExtractor.extractFileContents(tw.fileId)
}
if (checkTrapIdentical && trapFile.exists()) {
@@ -151,7 +158,7 @@ fun <T> fakeLabel(): Label<T> {
return IntLabel(0)
}
class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val file: IrFile) {
class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val file: IrFile, val pluginContext: IrPluginContext) {
val fileClass by lazy {
extractFileClass(file)
}
@@ -213,11 +220,7 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
is IrClass -> extractClass(declaration)
is IrFunction -> extractFunction(declaration, if (optParentid.isPresent()) optParentid.get() else fileClass)
is IrAnonymousInitializer -> {
// todo: how do we want to represent this?
// there could be multiple 'init' blocks inside a declaration.
// We could add a generated 'init' method, with all the statements inside the blocks.
// In Kotlin/JVM, the statements inside 'init' blocks get copied to the default constructor, or if there's no default then to all of them.
logger.warnElement(Severity.ErrorSevere, "Todo: handle IrAnonymousInitializer", declaration)
// Leaving this intentionally empty. init blocks are extracted during class extraction.
}
is IrProperty -> extractProperty(declaration, if (optParentid.isPresent()) optParentid.get() else fileClass)
else -> logger.warnElement(Severity.ErrorSevere, "Unrecognised IrDeclaration: " + declaration.javaClass, declaration)
@@ -363,6 +366,9 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
}
}
c.declarations.map { extractDeclaration(it, Optional.of(id)) }
extractObjectInitializerFunction(c, id)
return id
}
@@ -399,10 +405,14 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
}
private fun getFunctionLabel(f: IrFunction) : String {
val paramTypeIds = f.valueParameters.joinToString() { "{${useType(erase(it.type)).toString()}}" }
val returnTypeId = useType(erase(f.returnType))
val parentId = useDeclarationParent(f.parent)
val label = "@\"callable;{$parentId}.${f.name.asString()}($paramTypeIds){$returnTypeId}\""
return getFunctionLabel(f.parent, f.name.asString(), f.valueParameters, f.returnType)
}
private fun getFunctionLabel(parent: IrDeclarationParent, name: String, parameters: List<IrValueParameter>, returnType: IrType) : String {
val paramTypeIds = parameters.joinToString() { "{${useType(erase(it.type)).toString()}}" }
val returnTypeId = useType(erase(returnType))
val parentId = useDeclarationParent(parent)
val label = "@\"callable;{$parentId}.$name($paramTypeIds){$returnTypeId}\""
return label
}
@@ -459,6 +469,19 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
tw.writeParamName(id, vp.name.asString())
}
private fun extractObjectInitializerFunction(c: IrClass, parentid: Label<out DbReftype>) {
var methodLabel = getFunctionLabel(c, "<obinit>", listOf(), pluginContext.irBuiltIns.unitType)
val methodId = tw.getLabelFor<DbMethod>(methodLabel)
val signature = "TODO"
val returnTypeId = useType(pluginContext.irBuiltIns.unitType)
tw.writeMethods(methodId, "<obinit>", signature, returnTypeId, parentid, methodId)
val locId = tw.getLocation(c)
tw.writeHasLocation(methodId, locId)
// todo add body with non-static field initializers, and init blocks
}
fun extractFunction(f: IrFunction, parentid: Label<out DbReftype>) {
val id = useFunction(f)
val locId = tw.getLocation(f)
@@ -702,11 +725,19 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
val callableLabel = useFunction(irCallable)
when(e) {
is IrInstanceInitializerCall -> {
// todo: how do we want to handle this?
// In Kotlin/JVM, this seems like a no-op.
if (e.classSymbol.owner.declarations.any { it is IrAnonymousInitializer }) {
// we could add a call to a generated 'init' function.
if (irCallable is IrConstructor && irCallable.isPrimary) {
// Todo add parameter to field assignments
}
// Add call to <obinit>:
val id = tw.getFreshIdLabel<DbMethodaccess>()
val typeId = useType(e.type)
val locId = tw.getLocation(e)
var methodLabel = getFunctionLabel(irCallable.parent, "<obinit>", listOf(), e.type)
val methodId = tw.getLabelFor<DbMethod>(methodLabel)
tw.writeExprs_methodaccess(id, typeId, parent, idx)
tw.writeHasLocation(id, locId)
tw.writeCallableBinding(id, methodId)
}
is IrDelegatingConstructorCall -> {
val delegatingClass = e.symbol.owner.parent as IrClass