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 llvm.LLVMWriteBitcodeToFile
import org.jetbrains.kotlin.backend.konan.library.impl.buildLibrary import org.jetbrains.kotlin.backend.konan.library.impl.buildLibrary
import org.jetbrains.kotlin.backend.konan.llvm.parseBitcodeFile import org.jetbrains.kotlin.backend.konan.llvm.parseBitcodeFile
import org.jetbrains.kotlin.backend.konan.util.getValueOrNull
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
internal fun produceOutput(context: Context) { internal fun produceOutput(context: Context) {
@@ -71,7 +72,8 @@ internal fun produceOutput(context: Context) {
llvmModule, llvmModule,
nopack, nopack,
manifest, manifest,
context.moduleEscapeAnalysisResult.build().toByteArray()) context.escapeAnalysisResult.getValueOrNull()?.build()?.toByteArray(),
context.dataFlowGraph)
context.library = library context.library = library
context.bitcodeFileName = library.mainBitcodeFileName 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, // But we have to wait until the code generation phase,
// to dump this information into generated file. // to dump this information into generated file.
var serializedLinkData: LinkData? = null var serializedLinkData: LinkData? = null
val moduleEscapeAnalysisResult: ModuleEscapeAnalysisResult.ModuleEAResult.Builder by lazy { val escapeAnalysisResult = lazy { ModuleEscapeAnalysisResult.ModuleEAResult.newBuilder() }
ModuleEscapeAnalysisResult.ModuleEAResult.newBuilder() var dataFlowGraph: ByteArray? = null
}
@Deprecated("") @Deprecated("")
lateinit var psi2IrGeneratorContext: GeneratorContext lateinit var psi2IrGeneratorContext: GeneratorContext
@@ -1334,7 +1334,7 @@ internal object EscapeAnalysis {
functionEAResultBuilder.addPointsTo(pointsToMask) functionEAResultBuilder.addPointsTo(pointsToMask)
} }
functionEAResultBuilder.escapes = escapes 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"), /* ... */ BITCODE("LLVM BitCode Generation"),
/* ... ... */ RTTI("RTTI Generation"), /* ... ... */ RTTI("RTTI Generation"),
/* ... ... */ BUILD_DFG("Data flow graph building"), /* ... ... */ 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"), /* ... ... */ CODEGEN("Code Generation"),
/* ... ... */ BITCODE_LINKER("Bitcode linking"), /* ... ... */ BITCODE_LINKER("Bitcode linking"),
/* */ LINK_STAGE("Link stage"), /* */ LINK_STAGE("Link stage"),
@@ -45,6 +45,8 @@ interface KonanLibraryLayout {
get() = File(linkdataDir, "module") get() = File(linkdataDir, "module")
val escapeAnalysisFile val escapeAnalysisFile
get() = File(linkdataDir, "module_escape_analysis") get() = File(linkdataDir, "module_escape_analysis")
val dataFlowGraphFile
get() = File(linkdataDir, "module_data_flow_graph")
fun packageFile(packageName: String) fun packageFile(packageName: String)
= File(linkdataDir, if (packageName == "") "root_package.knm" else "package_$packageName.knm") = File(linkdataDir, if (packageName == "") "root_package.knm" else "package_$packageName.knm")
} }
@@ -27,6 +27,7 @@ interface KonanLibraryReader {
val includedPaths: List<String> val includedPaths: List<String>
val linkerOpts: List<String> val linkerOpts: List<String>
val unresolvedDependencies: List<String> val unresolvedDependencies: List<String>
val dataFlowGraph: ByteArray?
val escapeAnalysis: ByteArray? val escapeAnalysis: ByteArray?
val isDefaultLibrary: Boolean get() = false val isDefaultLibrary: Boolean get() = false
val isNeededForLink: Boolean get() = true val isNeededForLink: Boolean get() = true
@@ -26,6 +26,7 @@ interface KonanLibraryWriter {
fun addLinkDependencies(libraries: List<KonanLibraryReader>) fun addLinkDependencies(libraries: List<KonanLibraryReader>)
fun addManifestAddend(path: String) fun addManifestAddend(path: String)
fun addEscapeAnalysis(escapeAnalysis: ByteArray) fun addEscapeAnalysis(escapeAnalysis: ByteArray)
fun addDataFlowGraph(dataFlowGraph: ByteArray)
val mainBitcodeFileName: String val mainBitcodeFileName: String
fun commit() 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.KonanConfig
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader 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.emptyPackages
import org.jetbrains.kotlin.backend.konan.serialization.deserializeModule import org.jetbrains.kotlin.backend.konan.serialization.deserializeModule
import org.jetbrains.kotlin.konan.file.File 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} 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 override val libraryName
get() = inPlace.libraryName get() = inPlace.libraryName
@@ -105,6 +105,10 @@ class LibraryWriterImpl(override val libDir: File, moduleName: String, currentAb
escapeAnalysisFile.writeBytes(escapeAnalysis) escapeAnalysisFile.writeBytes(escapeAnalysis)
} }
override fun addDataFlowGraph(dataFlowGraph: ByteArray) {
dataFlowGraphFile.writeBytes(dataFlowGraph)
}
override fun commit() { override fun commit() {
manifestProperties.saveToFile(manifestFile) manifestProperties.saveToFile(manifestFile)
if (!nopack) { if (!nopack) {
@@ -126,7 +130,8 @@ internal fun buildLibrary(
llvmModule: LLVMModuleRef, llvmModule: LLVMModuleRef,
nopack: Boolean, nopack: Boolean,
manifest: String?, manifest: String?,
escapeAnalysis: ByteArray?): KonanLibraryWriter { escapeAnalysis: ByteArray?,
dataFlowGraph: ByteArray?): KonanLibraryWriter {
val library = LibraryWriterImpl(output, moduleName, abiVersion, target, nopack) val library = LibraryWriterImpl(output, moduleName, abiVersion, target, nopack)
@@ -141,6 +146,7 @@ internal fun buildLibrary(
manifest ?.let { library.addManifestAddend(it) } manifest ?.let { library.addManifestAddend(it) }
library.addLinkDependencies(linkDependencies) library.addLinkDependencies(linkDependencies)
escapeAnalysis?.let { library.addEscapeAnalysis(it) } escapeAnalysis?.let { library.addEscapeAnalysis(it) }
dataFlowGraph?.let { library.addDataFlowGraph(it) }
library.commit() library.commit()
return library return library
@@ -81,6 +81,15 @@ internal fun emitLLVM(context: Context) {
moduleDFG = ModuleDFGBuilder(context, irModule).build() 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 lifetimes = mutableMapOf<IrElement, Lifetime>()
val codegenVisitor = CodeGeneratorVisitor(context, lifetimes) val codegenVisitor = CodeGeneratorVisitor(context, lifetimes)
phaser.phase(KonanPhase.ESCAPE_ANALYSIS) { phaser.phase(KonanPhase.ESCAPE_ANALYSIS) {
@@ -197,6 +197,10 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
if (DEBUG > severity) block() 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 module = DataFlowIR.Module(irModule.descriptor)
private val symbolTable = DataFlowIR.SymbolTable(context, irModule, module) private val symbolTable = DataFlowIR.SymbolTable(context, irModule, module)
@@ -542,11 +546,13 @@ internal class ModuleDFGBuilder(val context: Context, val irModule: IrModuleFrag
is IrGetField -> { is IrGetField -> {
val receiver = value.receiver?.let { expressionToEdge(it) } val receiver = value.receiver?.let { expressionToEdge(it) }
val receiverType = value.receiver?.let { symbolTable.mapType(it.type) } val receiverType = value.receiver?.let { symbolTable.mapType(it.type) }
val name = value.descriptor.name.asString()
DataFlowIR.Node.FieldRead( DataFlowIR.Node.FieldRead(
receiver, receiver,
DataFlowIR.Field( DataFlowIR.Field(
receiverType, 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 -> { is IrSetField -> {
val receiver = value.receiver?.let { expressionToEdge(it) } val receiver = value.receiver?.let { expressionToEdge(it) }
val receiverType = value.receiver?.let { symbolTable.mapType(it.type) } val receiverType = value.receiver?.let { symbolTable.mapType(it.type) }
val name = value.descriptor.name.asString()
DataFlowIR.Node.FieldWrite( DataFlowIR.Node.FieldWrite(
receiver, receiver,
DataFlowIR.Field( DataFlowIR.Field(
receiverType, receiverType,
value.descriptor.name.asString() name.localHash.value,
takeName { name }
), ),
expressionToEdge(value.value) expressionToEdge(value.value)
) )
@@ -31,20 +31,20 @@ internal object DataFlowIR {
// Special marker type forbidding devirtualization on its instances. // Special marker type forbidding devirtualization on its instances.
object Virtual : Declared(false, true) 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 { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is External) return false if (other !is External) return false
return name == other.name return hash == other.hash
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return name.hashCode() return hash.hashCode()
} }
override fun toString(): String { 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>() 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 { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is Public) return false if (other !is Public) return false
return name == other.name return hash == other.hash
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return name.hashCode() return hash.hashCode()
} }
override fun toString(): String { 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 { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is Private) return false if (other !is Private) return false
@@ -94,43 +94,43 @@ internal object DataFlowIR {
} }
abstract class FunctionSymbol { 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 { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is External) return false if (other !is External) return false
return name == other.name return hash == other.hash
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return name.hashCode() return hash.hashCode()
} }
override fun toString(): String { override fun toString(): String {
return "ExternalFunction(name='$name')" return "ExternalFunction(hash='$hash', name='$name')"
} }
} }
abstract class Declared(val module: Module, val symbolTableIndex: Int) : FunctionSymbol() 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 { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is Public) return false if (other !is Public) return false
return name == other.name return hash == other.hash
} }
override fun hashCode(): Int { override fun hashCode(): Int {
return name.hashCode() return hash.hashCode()
} }
override fun toString(): String { 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 { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
if (other !is Private) return false 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?) { class Edge(val castToType: Type?) {
@@ -316,6 +316,11 @@ internal object DataFlowIR {
} }
class SymbolTable(val context: Context, val irModule: IrModuleFragment, val module: Module) { 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 classMap = mutableMapOf<ClassDescriptor, Type>()
val functionMap = mutableMapOf<CallableDescriptor, FunctionSymbol>() val functionMap = mutableMapOf<CallableDescriptor, FunctionSymbol>()
@@ -354,16 +359,16 @@ internal object DataFlowIR {
val name = descriptor.fqNameSafe.asString() val name = descriptor.fqNameSafe.asString()
if (descriptor.module != irModule.descriptor) 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 } classMap[descriptor]?.let { return it }
val isFinal = descriptor.isFinal() val isFinal = descriptor.isFinal()
val isAbstract = descriptor.isAbstract() val isAbstract = descriptor.isAbstract()
val type = if (descriptor.isExported()) val type = if (descriptor.isExported())
Type.Public(name, isFinal, isAbstract) Type.Public(name.localHash.value, isFinal, isAbstract, takeName { name })
else else
Type.Private(name, privateTypeIndex++, isFinal, isAbstract) Type.Private(privateTypeIndex++, isFinal, isAbstract, takeName { name })
if (!descriptor.isInterface) { if (!descriptor.isInterface) {
val vtableBuilder = context.getVtableBuilder(descriptor) val vtableBuilder = context.getVtableBuilder(descriptor)
type.vtable += vtableBuilder.vtableEntries.map { mapFunction(it.getImplementation(context)) } type.vtable += vtableBuilder.vtableEntries.map { mapFunction(it.getImplementation(context)) }
@@ -405,11 +410,11 @@ internal object DataFlowIR {
functionMap.getOrPut(it) { functionMap.getOrPut(it) {
when (it) { when (it) {
is PropertyDescriptor -> is PropertyDescriptor ->
FunctionSymbol.Private("${it.symbolName}_init", privateFunIndex++, module, -1) FunctionSymbol.Private(privateFunIndex++, module, -1, takeName { "${it.symbolName}_init" })
is FunctionDescriptor -> { is FunctionDescriptor -> {
if (it.module != irModule.descriptor || it.externalOrIntrinsic()) if (it.module != irModule.descriptor || it.externalOrIntrinsic())
FunctionSymbol.External(it.symbolName) FunctionSymbol.External(it.symbolName.localHash.value, takeName { it.symbolName })
else { else {
val isAbstract = it.modality == Modality.ABSTRACT val isAbstract = it.modality == Modality.ABSTRACT
val classDescriptor = it.containingDeclaration as? ClassDescriptor val classDescriptor = it.containingDeclaration as? ClassDescriptor
@@ -420,9 +425,9 @@ internal object DataFlowIR {
++module.numberOfFunctions ++module.numberOfFunctions
val symbolTableIndex = if (!placeToFunctionsTable) -1 else couldBeCalledVirtuallyIndex++ val symbolTableIndex = if (!placeToFunctionsTable) -1 else couldBeCalledVirtuallyIndex++
if (it.isExported()) if (it.isExported())
FunctionSymbol.Public(it.symbolName, module, symbolTableIndex) FunctionSymbol.Public(it.symbolName.localHash.value, module, symbolTableIndex, takeName { it.symbolName })
else else
FunctionSymbol.Private(getFqName(it).asString() + "#internal", privateFunIndex++, module, symbolTableIndex) FunctionSymbol.Private(privateFunIndex++, module, symbolTableIndex, takeName { getFqName(it).asString() + "#internal" })
} }
} }