Added serialization/deserialization of DFG

This commit is contained in:
Igor Chevdar
2017-11-21 12:52:22 +03:00
parent 4c4ab1f226
commit efbc8fd3e6
13 changed files with 1072 additions and 37 deletions
@@ -19,6 +19,7 @@ import llvm.LLVMLinkModules2
import llvm.LLVMWriteBitcodeToFile
import org.jetbrains.kotlin.backend.konan.library.impl.buildLibrary
import org.jetbrains.kotlin.backend.konan.llvm.parseBitcodeFile
import org.jetbrains.kotlin.backend.konan.util.getValueOrNull
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
internal fun produceOutput(context: Context) {
@@ -71,7 +72,8 @@ internal fun produceOutput(context: Context) {
llvmModule,
nopack,
manifest,
context.moduleEscapeAnalysisResult.build().toByteArray())
context.escapeAnalysisResult.getValueOrNull()?.build()?.toByteArray(),
context.dataFlowGraph)
context.library = library
context.bitcodeFileName = library.mainBitcodeFileName
@@ -175,9 +175,8 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
// But we have to wait until the code generation phase,
// to dump this information into generated file.
var serializedLinkData: LinkData? = null
val moduleEscapeAnalysisResult: ModuleEscapeAnalysisResult.ModuleEAResult.Builder by lazy {
ModuleEscapeAnalysisResult.ModuleEAResult.newBuilder()
}
val escapeAnalysisResult = lazy { ModuleEscapeAnalysisResult.ModuleEAResult.newBuilder() }
var dataFlowGraph: ByteArray? = null
@Deprecated("")
lateinit var psi2IrGeneratorContext: GeneratorContext
@@ -1334,7 +1334,7 @@ internal object EscapeAnalysis {
functionEAResultBuilder.addPointsTo(pointsToMask)
}
functionEAResultBuilder.escapes = escapes
context.moduleEscapeAnalysisResult.addFunctionEAResults(functionEAResultBuilder)
context.escapeAnalysisResult.value.addFunctionEAResults(functionEAResultBuilder)
}
}
}
@@ -60,7 +60,9 @@ enum class KonanPhase(val description: String,
/* ... */ BITCODE("LLVM BitCode Generation"),
/* ... ... */ RTTI("RTTI Generation"),
/* ... ... */ BUILD_DFG("Data flow graph building"),
/* ... ... */ ESCAPE_ANALYSIS("Escape analysis", BUILD_DFG),
/* ... ... */ SERIALIZE_DFG("Data flow graph serializing", BUILD_DFG),
/* ... ... */ DESERIALIZE_DFG("Data flow graph deserializing"),
/* ... ... */ ESCAPE_ANALYSIS("Escape analysis", BUILD_DFG, DESERIALIZE_DFG),
/* ... ... */ CODEGEN("Code Generation"),
/* ... ... */ BITCODE_LINKER("Bitcode linking"),
/* */ LINK_STAGE("Link stage"),
@@ -45,6 +45,8 @@ interface KonanLibraryLayout {
get() = File(linkdataDir, "module")
val escapeAnalysisFile
get() = File(linkdataDir, "module_escape_analysis")
val dataFlowGraphFile
get() = File(linkdataDir, "module_data_flow_graph")
fun packageFile(packageName: String)
= File(linkdataDir, if (packageName == "") "root_package.knm" else "package_$packageName.knm")
}
@@ -27,6 +27,7 @@ interface KonanLibraryReader {
val includedPaths: List<String>
val linkerOpts: List<String>
val unresolvedDependencies: List<String>
val dataFlowGraph: ByteArray?
val escapeAnalysis: ByteArray?
val isDefaultLibrary: Boolean get() = false
val isNeededForLink: Boolean get() = true
@@ -26,6 +26,7 @@ interface KonanLibraryWriter {
fun addLinkDependencies(libraries: List<KonanLibraryReader>)
fun addManifestAddend(path: String)
fun addEscapeAnalysis(escapeAnalysis: ByteArray)
fun addDataFlowGraph(dataFlowGraph: ByteArray)
val mainBitcodeFileName: String
fun commit()
}
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.backend.konan.library.impl
import org.jetbrains.kotlin.backend.konan.KonanConfig
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader
import org.jetbrains.kotlin.backend.konan.createInteropLibrary
import org.jetbrains.kotlin.backend.konan.serialization.emptyPackages
import org.jetbrains.kotlin.backend.konan.serialization.deserializeModule
import org.jetbrains.kotlin.konan.file.File
@@ -52,7 +51,8 @@ class LibraryReaderImpl(var libraryFile: File, val currentAbiVersion: Int,
}
val targetList = inPlace.targetsDir.listFiles.map{it.name}
override val escapeAnalysis: ByteArray? by lazy { inPlace.escapeAnalysisFile.let { if (it.exists) it.readBytes() else null } }
override val escapeAnalysis by lazy { inPlace.escapeAnalysisFile.let { if (it.exists) it.readBytes() else null } }
override val dataFlowGraph by lazy { inPlace.dataFlowGraphFile.let { if (it.exists) it.readBytes() else null } }
override val libraryName
get() = inPlace.libraryName
@@ -105,6 +105,10 @@ class LibraryWriterImpl(override val libDir: File, moduleName: String, currentAb
escapeAnalysisFile.writeBytes(escapeAnalysis)
}
override fun addDataFlowGraph(dataFlowGraph: ByteArray) {
dataFlowGraphFile.writeBytes(dataFlowGraph)
}
override fun commit() {
manifestProperties.saveToFile(manifestFile)
if (!nopack) {
@@ -126,7 +130,8 @@ internal fun buildLibrary(
llvmModule: LLVMModuleRef,
nopack: Boolean,
manifest: String?,
escapeAnalysis: ByteArray?): KonanLibraryWriter {
escapeAnalysis: ByteArray?,
dataFlowGraph: ByteArray?): KonanLibraryWriter {
val library = LibraryWriterImpl(output, moduleName, abiVersion, target, nopack)
@@ -141,6 +146,7 @@ internal fun buildLibrary(
manifest ?.let { library.addManifestAddend(it) }
library.addLinkDependencies(linkDependencies)
escapeAnalysis?.let { library.addEscapeAnalysis(it) }
dataFlowGraph?.let { library.addDataFlowGraph(it) }
library.commit()
return library
@@ -81,6 +81,15 @@ internal fun emitLLVM(context: Context) {
moduleDFG = ModuleDFGBuilder(context, irModule).build()
}
phaser.phase(KonanPhase.SERIALIZE_DFG) {
DFGSerializer.serialize(context, moduleDFG!!)
}
var externalModulesDFG: ExternalModulesDFG? = null
phaser.phase(KonanPhase.DESERIALIZE_DFG) {
externalModulesDFG = DFGSerializer.deserialize(context, moduleDFG!!.symbolTable.privateTypeIndex, moduleDFG!!.symbolTable.privateFunIndex)
}
val lifetimes = mutableMapOf<IrElement, Lifetime>()
val codegenVisitor = CodeGeneratorVisitor(context, lifetimes)
phaser.phase(KonanPhase.ESCAPE_ANALYSIS) {
@@ -197,6 +197,10 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
if (DEBUG > severity) block()
}
private val TAKE_NAMES = false // Take fqNames for all functions and types (for debug purposes).
private inline fun takeName(block: () -> String) = if (TAKE_NAMES) block() else null
private val module = DataFlowIR.Module(irModule.descriptor)
private val symbolTable = DataFlowIR.SymbolTable(context, irModule, module)
@@ -542,11 +546,13 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
is IrGetField -> {
val receiver = value.receiver?.let { expressionToEdge(it) }
val receiverType = value.receiver?.let { symbolTable.mapType(it.type) }
val name = value.descriptor.name.asString()
DataFlowIR.Node.FieldRead(
receiver,
DataFlowIR.Field(
receiverType,
value.descriptor.name.asString()
name.localHash.value,
takeName { name }
)
)
}
@@ -554,11 +560,13 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
is IrSetField -> {
val receiver = value.receiver?.let { expressionToEdge(it) }
val receiverType = value.receiver?.let { symbolTable.mapType(it.type) }
val name = value.descriptor.name.asString()
DataFlowIR.Node.FieldWrite(
receiver,
DataFlowIR.Field(
receiverType,
value.descriptor.name.asString()
name.localHash.value,
takeName { name }
),
expressionToEdge(value.value)
)
@@ -31,20 +31,20 @@ internal object DataFlowIR {
// Special marker type forbidding devirtualization on its instances.
object Virtual : Declared(false, true)
class External(val name: String) : Type() {
class External(val hash: Long, val name: String? = null) : Type() {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is External) return false
return name == other.name
return hash == other.hash
}
override fun hashCode(): Int {
return name.hashCode()
return hash.hashCode()
}
override fun toString(): String {
return "ExternalType(name='$name')"
return "ExternalType(hash='$hash', name='$name')"
}
}
@@ -54,24 +54,24 @@ internal object DataFlowIR {
val itable = mutableMapOf<Long, FunctionSymbol>()
}
class Public(val name: String, isFinal: Boolean, isAbstract: Boolean) : Declared(isFinal, isAbstract) {
class Public(val hash: Long, isFinal: Boolean, isAbstract: Boolean, val name: String? = null) : Declared(isFinal, isAbstract) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Public) return false
return name == other.name
return hash == other.hash
}
override fun hashCode(): Int {
return name.hashCode()
return hash.hashCode()
}
override fun toString(): String {
return "PublicType(name='$name')"
return "PublicType(hash='$hash', name='$name')"
}
}
class Private(val name: String, val index: Int, isFinal: Boolean, isAbstract: Boolean) : Declared(isFinal, isAbstract) {
class Private(val index: Int, isFinal: Boolean, isAbstract: Boolean, val name: String? = null) : Declared(isFinal, isAbstract) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Private) return false
@@ -94,43 +94,43 @@ internal object DataFlowIR {
}
abstract class FunctionSymbol {
class External(val name: String) : FunctionSymbol() {
class External(val hash: Long, val name: String? = null) : FunctionSymbol() {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is External) return false
return name == other.name
return hash == other.hash
}
override fun hashCode(): Int {
return name.hashCode()
return hash.hashCode()
}
override fun toString(): String {
return "ExternalFunction(name='$name')"
return "ExternalFunction(hash='$hash', name='$name')"
}
}
abstract class Declared(val module: Module, val symbolTableIndex: Int) : FunctionSymbol()
class Public(val name: String, module: Module, symbolTableIndex: Int) : Declared(module, symbolTableIndex) {
class Public(val hash: Long, module: Module, symbolTableIndex: Int, val name: String? = null) : Declared(module, symbolTableIndex) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Public) return false
return name == other.name
return hash == other.hash
}
override fun hashCode(): Int {
return name.hashCode()
return hash.hashCode()
}
override fun toString(): String {
return "PublicFunction(name='$name')"
return "PublicFunction(hash='$hash', name='$name')"
}
}
class Private(val name: String, val index: Int, module: Module, symbolTableIndex: Int) : Declared(module, symbolTableIndex) {
class Private(val index: Int, module: Module, symbolTableIndex: Int, val name: String? = null) : Declared(module, symbolTableIndex) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Private) return false
@@ -148,7 +148,7 @@ internal object DataFlowIR {
}
}
data class Field(val type: Type?, val name: String)
data class Field(val type: Type?, val hash: Long, val name: String? = null)
class Edge(val castToType: Type?) {
@@ -316,6 +316,11 @@ internal object DataFlowIR {
}
class SymbolTable(val context: Context, val irModule: IrModuleFragment, val module: Module) {
private val TAKE_NAMES = false // Take fqNames for all functions and types (for debug purposes).
private inline fun takeName(block: () -> String) = if (TAKE_NAMES) block() else null
val classMap = mutableMapOf<ClassDescriptor, Type>()
val functionMap = mutableMapOf<CallableDescriptor, FunctionSymbol>()
@@ -354,16 +359,16 @@ internal object DataFlowIR {
val name = descriptor.fqNameSafe.asString()
if (descriptor.module != irModule.descriptor)
return classMap.getOrPut(descriptor) { Type.External(name) }
return classMap.getOrPut(descriptor) { Type.External(name.localHash.value, takeName { name }) }
classMap[descriptor]?.let { return it }
val isFinal = descriptor.isFinal()
val isAbstract = descriptor.isAbstract()
val type = if (descriptor.isExported())
Type.Public(name, isFinal, isAbstract)
Type.Public(name.localHash.value, isFinal, isAbstract, takeName { name })
else
Type.Private(name, privateTypeIndex++, isFinal, isAbstract)
Type.Private(privateTypeIndex++, isFinal, isAbstract, takeName { name })
if (!descriptor.isInterface) {
val vtableBuilder = context.getVtableBuilder(descriptor)
type.vtable += vtableBuilder.vtableEntries.map { mapFunction(it.getImplementation(context)) }
@@ -405,11 +410,11 @@ internal object DataFlowIR {
functionMap.getOrPut(it) {
when (it) {
is PropertyDescriptor ->
FunctionSymbol.Private("${it.symbolName}_init", privateFunIndex++, module, -1)
FunctionSymbol.Private(privateFunIndex++, module, -1, takeName { "${it.symbolName}_init" })
is FunctionDescriptor -> {
if (it.module != irModule.descriptor || it.externalOrIntrinsic())
FunctionSymbol.External(it.symbolName)
FunctionSymbol.External(it.symbolName.localHash.value, takeName { it.symbolName })
else {
val isAbstract = it.modality == Modality.ABSTRACT
val classDescriptor = it.containingDeclaration as? ClassDescriptor
@@ -420,9 +425,9 @@ internal object DataFlowIR {
++module.numberOfFunctions
val symbolTableIndex = if (!placeToFunctionsTable) -1 else couldBeCalledVirtuallyIndex++
if (it.isExported())
FunctionSymbol.Public(it.symbolName, module, symbolTableIndex)
FunctionSymbol.Public(it.symbolName.localHash.value, module, symbolTableIndex, takeName { it.symbolName })
else
FunctionSymbol.Private(getFqName(it).asString() + "#internal", privateFunIndex++, module, symbolTableIndex)
FunctionSymbol.Private(privateFunIndex++, module, symbolTableIndex, takeName { getFqName(it).asString() + "#internal" })
}
}