Rewrote escape analysis to use DFG
This commit is contained in:
-1
@@ -89,7 +89,6 @@ internal fun produceOutput(context: Context) {
|
||||
llvmModule,
|
||||
nopack,
|
||||
manifest,
|
||||
context.escapeAnalysisResult.getValueOrNull()?.build()?.toByteArray(),
|
||||
context.dataFlowGraph)
|
||||
|
||||
context.library = library
|
||||
|
||||
-1
@@ -176,7 +176,6 @@ 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 escapeAnalysisResult = lazy { ModuleEscapeAnalysisResult.ModuleEAResult.newBuilder() }
|
||||
var dataFlowGraph: ByteArray? = null
|
||||
|
||||
@Deprecated("")
|
||||
|
||||
+205
-876
File diff suppressed because it is too large
Load Diff
-15
@@ -1,15 +0,0 @@
|
||||
syntax = "proto2";
|
||||
package org.jetbrains.kotlin.backend.konan;
|
||||
|
||||
option java_outer_classname = "ModuleEscapeAnalysisResult";
|
||||
option optimize_for = LITE_RUNTIME;
|
||||
|
||||
message FunctionEAResult {
|
||||
required string fqName = 1;
|
||||
required int32 escapes = 2;
|
||||
repeated int32 pointsTo = 3;
|
||||
}
|
||||
|
||||
message ModuleEAResult {
|
||||
repeated FunctionEAResult functionEAResults = 1;
|
||||
}
|
||||
+1
-1
@@ -31,7 +31,7 @@ internal class DirectedGraphMultiNode<out K>(val nodes: Set<K>)
|
||||
|
||||
internal class DirectedGraphCondensation<out K>(val topologicalOrder: List<DirectedGraphMultiNode<K>>)
|
||||
|
||||
internal class DirectedGraphCondensationBuilder<K, out N: DirectedGraphNode<K>>(val graph: DirectedGraph<K, N>) {
|
||||
internal class DirectedGraphCondensationBuilder<K, out N: DirectedGraphNode<K>>(private val graph: DirectedGraph<K, N>) {
|
||||
private val visited = mutableSetOf<K>()
|
||||
private val order = mutableListOf<N>()
|
||||
private val nodeToMultiNodeMap = mutableMapOf<N, DirectedGraphMultiNode<K>>()
|
||||
|
||||
-2
@@ -44,8 +44,6 @@ interface KonanLibraryLayout {
|
||||
get() = File(libDir, "linkdata")
|
||||
val moduleHeaderFile
|
||||
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)
|
||||
|
||||
-1
@@ -28,7 +28,6 @@ interface KonanLibraryReader {
|
||||
val linkerOpts: List<String>
|
||||
val unresolvedDependencies: List<String>
|
||||
val dataFlowGraph: ByteArray?
|
||||
val escapeAnalysis: ByteArray?
|
||||
val isDefaultLibrary: Boolean get() = false
|
||||
val isNeededForLink: Boolean get() = true
|
||||
val manifestProperties: Properties
|
||||
|
||||
-1
@@ -25,7 +25,6 @@ interface KonanLibraryWriter {
|
||||
fun addKotlinBitcode(llvmModule: LLVMModuleRef)
|
||||
fun addLinkDependencies(libraries: List<KonanLibraryReader>)
|
||||
fun addManifestAddend(path: String)
|
||||
fun addEscapeAnalysis(escapeAnalysis: ByteArray)
|
||||
fun addDataFlowGraph(dataFlowGraph: ByteArray)
|
||||
val mainBitcodeFileName: String
|
||||
fun commit()
|
||||
|
||||
-1
@@ -51,7 +51,6 @@ class LibraryReaderImpl(var libraryFile: File, val currentAbiVersion: Int,
|
||||
}
|
||||
|
||||
val targetList = inPlace.targetsDir.listFiles.map{it.name}
|
||||
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
|
||||
|
||||
-6
@@ -101,10 +101,6 @@ class LibraryWriterImpl(override val libDir: File, moduleName: String, currentAb
|
||||
manifestProperties.putAll(properties)
|
||||
}
|
||||
|
||||
override fun addEscapeAnalysis(escapeAnalysis: ByteArray) {
|
||||
escapeAnalysisFile.writeBytes(escapeAnalysis)
|
||||
}
|
||||
|
||||
override fun addDataFlowGraph(dataFlowGraph: ByteArray) {
|
||||
dataFlowGraphFile.writeBytes(dataFlowGraph)
|
||||
}
|
||||
@@ -130,7 +126,6 @@ internal fun buildLibrary(
|
||||
llvmModule: LLVMModuleRef,
|
||||
nopack: Boolean,
|
||||
manifest: String?,
|
||||
escapeAnalysis: ByteArray?,
|
||||
dataFlowGraph: ByteArray?): KonanLibraryWriter {
|
||||
|
||||
val library = LibraryWriterImpl(output, moduleName, abiVersion, target, nopack)
|
||||
@@ -145,7 +140,6 @@ internal fun buildLibrary(
|
||||
}
|
||||
manifest ?.let { library.addManifestAddend(it) }
|
||||
library.addLinkDependencies(linkDependencies)
|
||||
escapeAnalysis?.let { library.addEscapeAnalysis(it) }
|
||||
dataFlowGraph?.let { library.addDataFlowGraph(it) }
|
||||
|
||||
library.commit()
|
||||
|
||||
+2
-3
@@ -24,10 +24,8 @@ import org.jetbrains.kotlin.backend.common.ir.ir2string
|
||||
import org.jetbrains.kotlin.backend.konan.*
|
||||
import org.jetbrains.kotlin.backend.konan.descriptors.*
|
||||
import org.jetbrains.kotlin.backend.konan.ir.*
|
||||
import org.jetbrains.kotlin.backend.konan.library.impl.buildLibrary
|
||||
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
|
||||
import org.jetbrains.kotlin.backend.konan.optimizations.*
|
||||
import org.jetbrains.kotlin.backend.konan.util.getValueOrNull
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
@@ -94,7 +92,8 @@ internal fun emitLLVM(context: Context) {
|
||||
val lifetimes = mutableMapOf<IrElement, Lifetime>()
|
||||
val codegenVisitor = CodeGeneratorVisitor(context, lifetimes)
|
||||
phaser.phase(KonanPhase.ESCAPE_ANALYSIS) {
|
||||
EscapeAnalysis.computeLifetimes(irModule, context, codegenVisitor.codegen, lifetimes)
|
||||
val callGraph = CallGraphBuilder(context, moduleDFG!!, externalModulesDFG!!).build()
|
||||
EscapeAnalysis.computeLifetimes(moduleDFG!!, externalModulesDFG!!, callGraph, lifetimes)
|
||||
}
|
||||
|
||||
phaser.phase(KonanPhase.CODEGEN) {
|
||||
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
package org.jetbrains.kotlin.backend.konan.optimizations
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.DirectedGraph
|
||||
import org.jetbrains.kotlin.backend.konan.DirectedGraphNode
|
||||
import org.jetbrains.kotlin.backend.konan.Context
|
||||
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.findMainEntryPoint
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
|
||||
internal class CallGraphNode(val graph: CallGraph, val symbol: DataFlowIR.FunctionSymbol)
|
||||
: DirectedGraphNode<DataFlowIR.FunctionSymbol> {
|
||||
|
||||
override val key get() = symbol
|
||||
|
||||
override val directEdges: List<DataFlowIR.FunctionSymbol> by lazy {
|
||||
graph.directEdges[symbol]!!.callSites
|
||||
.map { it.actualCallee }
|
||||
.filter { graph.reversedEdges.containsKey(it) }
|
||||
}
|
||||
|
||||
override val reversedEdges: List<DataFlowIR.FunctionSymbol> by lazy {
|
||||
graph.reversedEdges[symbol]!!
|
||||
}
|
||||
|
||||
class CallSite(val call: DataFlowIR.Node.Call, val actualCallee: DataFlowIR.FunctionSymbol)
|
||||
|
||||
val callSites = mutableListOf<CallSite>()
|
||||
}
|
||||
|
||||
internal class CallGraph(val directEdges: Map<DataFlowIR.FunctionSymbol, CallGraphNode>,
|
||||
val reversedEdges: Map<DataFlowIR.FunctionSymbol, MutableList<DataFlowIR.FunctionSymbol>>)
|
||||
: DirectedGraph<DataFlowIR.FunctionSymbol, CallGraphNode> {
|
||||
|
||||
override val nodes get() = directEdges.values
|
||||
|
||||
override fun get(key: DataFlowIR.FunctionSymbol) = directEdges[key]!!
|
||||
|
||||
fun addEdge(caller: DataFlowIR.FunctionSymbol, callSite: CallGraphNode.CallSite) {
|
||||
directEdges[caller]!!.callSites += callSite
|
||||
reversedEdges[callSite.actualCallee]?.add(caller)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal class CallGraphBuilder(val context: Context,
|
||||
val moduleDFG: ModuleDFG,
|
||||
val externalModulesDFG: ExternalModulesDFG) {
|
||||
|
||||
private val DEBUG = 0
|
||||
|
||||
private inline fun DEBUG_OUTPUT(severity: Int, block: () -> Unit) {
|
||||
if (DEBUG > severity) block()
|
||||
}
|
||||
|
||||
private val hasMain = context.config.configuration.get(KonanConfigKeys.PRODUCE) == CompilerOutputKind.PROGRAM
|
||||
|
||||
private val symbolTable = moduleDFG.symbolTable
|
||||
|
||||
private fun DataFlowIR.Type.resolved(): DataFlowIR.Type.Declared {
|
||||
if (this is DataFlowIR.Type.Declared) return this
|
||||
val hash = (this as DataFlowIR.Type.External).hash
|
||||
return externalModulesDFG.publicTypes[hash] ?: error("Unable to resolve exported type $hash")
|
||||
}
|
||||
|
||||
private fun DataFlowIR.FunctionSymbol.resolved(): DataFlowIR.FunctionSymbol {
|
||||
if (this is DataFlowIR.FunctionSymbol.External)
|
||||
return externalModulesDFG.publicFunctions[this.hash] ?: this
|
||||
return this
|
||||
}
|
||||
|
||||
private fun DataFlowIR.Type.Declared.isSubtypeOf(other: DataFlowIR.Type.Declared): Boolean {
|
||||
return this == other || this.superTypes.any { it.resolved().isSubtypeOf(other) }
|
||||
}
|
||||
|
||||
private val directEdges = mutableMapOf<DataFlowIR.FunctionSymbol, CallGraphNode>()
|
||||
private val reversedEdges = mutableMapOf<DataFlowIR.FunctionSymbol, MutableList<DataFlowIR.FunctionSymbol>>()
|
||||
private val callGraph = CallGraph(directEdges, reversedEdges)
|
||||
|
||||
fun build(): CallGraph {
|
||||
val rootSet = if (hasMain) {
|
||||
listOf(symbolTable.mapFunction(findMainEntryPoint(context)!!).resolved()) +
|
||||
moduleDFG.functions
|
||||
.filter { it.value.isGlobalInitializer }
|
||||
.map { it.key }
|
||||
} else {
|
||||
moduleDFG.functions.keys.filterIsInstance<DataFlowIR.FunctionSymbol.Public>()
|
||||
}
|
||||
@Suppress("LoopToCallChain")
|
||||
for (symbol in rootSet) {
|
||||
if (!directEdges.containsKey(symbol))
|
||||
dfs(symbol)
|
||||
}
|
||||
return callGraph
|
||||
}
|
||||
|
||||
private fun dfs(symbol: DataFlowIR.FunctionSymbol) {
|
||||
val node = CallGraphNode(callGraph, symbol)
|
||||
directEdges.put(symbol, node)
|
||||
val list = mutableListOf<DataFlowIR.FunctionSymbol>()
|
||||
reversedEdges.put(symbol, list)
|
||||
val function = moduleDFG.functions[symbol] ?: externalModulesDFG.functionDFGs[symbol]
|
||||
val body = function!!.body
|
||||
body.nodes.filterIsInstance<DataFlowIR.Node.Call>()
|
||||
.forEach {
|
||||
val callee = it.callee.resolved()
|
||||
callGraph.addEdge(symbol, CallGraphNode.CallSite(it, callee))
|
||||
if (callee is DataFlowIR.FunctionSymbol.Declared
|
||||
&& it !is DataFlowIR.Node.VirtualCall
|
||||
&& !directEdges.containsKey(callee))
|
||||
dfs(callee)
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-6
@@ -262,13 +262,16 @@ internal object DFGSerializer {
|
||||
}
|
||||
}
|
||||
|
||||
class ExternalFunctionSymbol(val hash: Long, val numberOfParameters: Int, val name: String?) {
|
||||
class ExternalFunctionSymbol(val hash: Long, val numberOfParameters: Int, val escapes: Int?, val pointsTo: IntArray?, val name: String?) {
|
||||
|
||||
constructor(data: ArraySlice) : this(data.readLong(), data.readInt(), data.readNullableString())
|
||||
constructor(data: ArraySlice) : this(data.readLong(), data.readInt(), data.readNullableInt(),
|
||||
data.readNullable { readIntArray() }, data.readNullableString())
|
||||
|
||||
fun write(result: ArraySlice) {
|
||||
result.writeLong(hash)
|
||||
result.writeInt(numberOfParameters)
|
||||
result.writeNullableInt(escapes)
|
||||
result.writeNullable(pointsTo) { writeIntArray(it) }
|
||||
result.writeNullableString(name)
|
||||
}
|
||||
}
|
||||
@@ -313,8 +316,8 @@ internal object DFGSerializer {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun external(hash: Long, numberOfParameters: Int, name: String?) =
|
||||
FunctionSymbol(ExternalFunctionSymbol(hash, numberOfParameters, name), null, null)
|
||||
fun external(hash: Long, numberOfParameters: Int, escapes: Int?, pointsTo: IntArray?, name: String?) =
|
||||
FunctionSymbol(ExternalFunctionSymbol(hash, numberOfParameters, escapes, pointsTo, name), null, null)
|
||||
|
||||
fun public(hash: Long, numberOfParameters: Int, index: Int, name: String?) =
|
||||
FunctionSymbol(null, PublicFunctionSymbol(hash, numberOfParameters, index, name), null)
|
||||
@@ -675,7 +678,7 @@ internal object DFGSerializer {
|
||||
val name = functionSymbol.name
|
||||
when (functionSymbol) {
|
||||
is DataFlowIR.FunctionSymbol.External ->
|
||||
FunctionSymbol.external(functionSymbol.hash, numberOfParameters, name)
|
||||
FunctionSymbol.external(functionSymbol.hash, numberOfParameters, functionSymbol.escapes, functionSymbol.pointsTo, name)
|
||||
|
||||
is DataFlowIR.FunctionSymbol.Public ->
|
||||
FunctionSymbol.public(functionSymbol.hash, numberOfParameters, functionSymbol.symbolTableIndex, name)
|
||||
@@ -817,7 +820,7 @@ internal object DFGSerializer {
|
||||
val private = it.private
|
||||
when {
|
||||
external != null ->
|
||||
DataFlowIR.FunctionSymbol.External(external.hash, external.numberOfParameters, external.name)
|
||||
DataFlowIR.FunctionSymbol.External(external.hash, external.numberOfParameters, external.escapes, external.pointsTo, external.name)
|
||||
|
||||
public != null -> {
|
||||
val symbolTableIndex = public.index
|
||||
|
||||
+147
-107
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.konan.llvm.isExported
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.localHash
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.symbolName
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
@@ -22,6 +23,8 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
import org.jetbrains.kotlin.resolve.constants.IntValue
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -96,7 +99,7 @@ internal object DataFlowIR {
|
||||
}
|
||||
|
||||
abstract class FunctionSymbol(val numberOfParameters: Int, val name: String?) {
|
||||
class External(val hash: Long, numberOfParameters: Int, name: String? = null)
|
||||
class External(val hash: Long, numberOfParameters: Int, val escapes: Int?, val pointsTo: IntArray?, name: String? = null)
|
||||
: FunctionSymbol(numberOfParameters, name) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
@@ -110,7 +113,7 @@ internal object DataFlowIR {
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "ExternalFunction(hash='$hash', name='$name')"
|
||||
return "ExternalFunction(hash='$hash', name='$name', escapes='$escapes', pointsTo='${pointsTo?.contentToString()}')"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,109 +214,8 @@ internal object DataFlowIR {
|
||||
val body: FunctionBody) {
|
||||
|
||||
|
||||
fun printNode(node: Node, ids: Map<Node, Int>) {
|
||||
when (node) {
|
||||
is Node.Const ->
|
||||
println(" CONST ${node.type}")
|
||||
|
||||
is Node.Parameter ->
|
||||
println(" PARAM ${node.index}")
|
||||
|
||||
is Node.Singleton ->
|
||||
println(" SINGLETON ${node.type}")
|
||||
|
||||
is Node.StaticCall -> {
|
||||
println(" STATIC CALL ${node.callee}")
|
||||
node.arguments.forEach {
|
||||
print(" ARG #${ids[it.node]!!}")
|
||||
if (it.castToType == null)
|
||||
println()
|
||||
else
|
||||
println(" CASTED TO ${it.castToType}")
|
||||
}
|
||||
}
|
||||
|
||||
is Node.VtableCall -> {
|
||||
println(" VIRTUAL CALL ${node.callee}")
|
||||
println(" RECEIVER: ${node.receiverType}")
|
||||
println(" VTABLE INDEX: ${node.calleeVtableIndex}")
|
||||
node.arguments.forEach {
|
||||
print(" ARG #${ids[it.node]!!}")
|
||||
if (it.castToType == null)
|
||||
println()
|
||||
else
|
||||
println(" CASTED TO ${it.castToType}")
|
||||
}
|
||||
}
|
||||
|
||||
is Node.ItableCall -> {
|
||||
println(" INTERFACE CALL ${node.callee}")
|
||||
println(" RECEIVER: ${node.receiverType}")
|
||||
println(" METHOD HASH: ${node.calleeHash}")
|
||||
node.arguments.forEach {
|
||||
print(" ARG #${ids[it.node]!!}")
|
||||
if (it.castToType == null)
|
||||
println()
|
||||
else
|
||||
println(" CASTED TO ${it.castToType}")
|
||||
}
|
||||
}
|
||||
|
||||
is Node.NewObject -> {
|
||||
println(" NEW OBJECT ${node.callee}")
|
||||
println(" TYPE ${node.returnType}")
|
||||
node.arguments.forEach {
|
||||
print(" ARG #${ids[it.node]!!}")
|
||||
if (it.castToType == null)
|
||||
println()
|
||||
else
|
||||
println(" CASTED TO ${it.castToType}")
|
||||
}
|
||||
}
|
||||
|
||||
is Node.FieldRead -> {
|
||||
println(" FIELD READ ${node.field}")
|
||||
print(" RECEIVER #${node.receiver?.node?.let { ids[it]!! } ?: "null"}")
|
||||
if (node.receiver?.castToType == null)
|
||||
println()
|
||||
else
|
||||
println(" CASTED TO ${node.receiver.castToType}")
|
||||
}
|
||||
|
||||
is Node.FieldWrite -> {
|
||||
println(" FIELD WRITE ${node.field}")
|
||||
print(" RECEIVER #${node.receiver?.node?.let { ids[it]!! } ?: "null"}")
|
||||
if (node.receiver?.castToType == null)
|
||||
println()
|
||||
else
|
||||
println(" CASTED TO ${node.receiver.castToType}")
|
||||
print(" VALUE #${ids[node.value.node]!!}")
|
||||
if (node.value.castToType == null)
|
||||
println()
|
||||
else
|
||||
println(" CASTED TO ${node.value.castToType}")
|
||||
}
|
||||
|
||||
is Node.Variable -> {
|
||||
println(" ${if (node.temp) "TEMP VAR" else "VARIABLE"} ")
|
||||
node.values.forEach {
|
||||
print(" VAL #${ids[it.node]!!}")
|
||||
if (it.castToType == null)
|
||||
println()
|
||||
else
|
||||
println(" CASTED TO ${it.castToType}")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
else -> {
|
||||
println(" UNKNOWN: ${node::class.java}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun debugOutput() {
|
||||
println("FUNCTION TEMPLATE $symbol")
|
||||
println("FUNCTION $symbol")
|
||||
println("Params: $numberOfParameters")
|
||||
val ids = body.nodes.withIndex().associateBy({ it.value }, { it.index })
|
||||
body.nodes.forEach {
|
||||
@@ -323,6 +225,122 @@ internal object DataFlowIR {
|
||||
println(" RETURNS")
|
||||
printNode(body.returns, ids)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun printNode(node: Node, ids: Map<Node, Int>) = print(nodeToString(node, ids))
|
||||
|
||||
fun nodeToString(node: Node, ids: Map<Node, Int>) = when (node) {
|
||||
is Node.Const ->
|
||||
" CONST ${node.type}\n"
|
||||
|
||||
is Node.Parameter ->
|
||||
" PARAM ${node.index}\n"
|
||||
|
||||
is Node.Singleton ->
|
||||
" SINGLETON ${node.type}\n"
|
||||
|
||||
is Node.StaticCall -> {
|
||||
val result = StringBuilder()
|
||||
result.appendln(" STATIC CALL ${node.callee}")
|
||||
node.arguments.forEach {
|
||||
result.append(" ARG #${ids[it.node]!!}")
|
||||
if (it.castToType == null)
|
||||
result.appendln()
|
||||
else
|
||||
result.appendln(" CASTED TO ${it.castToType}")
|
||||
}
|
||||
result.toString()
|
||||
}
|
||||
|
||||
is Node.VtableCall -> {
|
||||
val result = StringBuilder()
|
||||
result.appendln(" VIRTUAL CALL ${node.callee}")
|
||||
result.appendln(" RECEIVER: ${node.receiverType}")
|
||||
result.appendln(" VTABLE INDEX: ${node.calleeVtableIndex}")
|
||||
node.arguments.forEach {
|
||||
result.append(" ARG #${ids[it.node]!!}")
|
||||
if (it.castToType == null)
|
||||
result.appendln()
|
||||
else
|
||||
result.appendln(" CASTED TO ${it.castToType}")
|
||||
}
|
||||
result.toString()
|
||||
}
|
||||
|
||||
is Node.ItableCall -> {
|
||||
val result = StringBuilder()
|
||||
result.appendln(" INTERFACE CALL ${node.callee}")
|
||||
result.appendln(" RECEIVER: ${node.receiverType}")
|
||||
result.appendln(" METHOD HASH: ${node.calleeHash}")
|
||||
node.arguments.forEach {
|
||||
result.append(" ARG #${ids[it.node]!!}")
|
||||
if (it.castToType == null)
|
||||
result.appendln()
|
||||
else
|
||||
result.appendln(" CASTED TO ${it.castToType}")
|
||||
}
|
||||
result.toString()
|
||||
}
|
||||
|
||||
is Node.NewObject -> {
|
||||
val result = StringBuilder()
|
||||
result.appendln(" NEW OBJECT ${node.callee}")
|
||||
result.appendln(" TYPE ${node.returnType}")
|
||||
node.arguments.forEach {
|
||||
result.append(" ARG #${ids[it.node]!!}")
|
||||
if (it.castToType == null)
|
||||
result.appendln()
|
||||
else
|
||||
result.appendln(" CASTED TO ${it.castToType}")
|
||||
}
|
||||
result.toString()
|
||||
}
|
||||
|
||||
is Node.FieldRead -> {
|
||||
val result = StringBuilder()
|
||||
result.appendln(" FIELD READ ${node.field}")
|
||||
result.append(" RECEIVER #${node.receiver?.node?.let { ids[it]!! } ?: "null"}")
|
||||
if (node.receiver?.castToType == null)
|
||||
result.appendln()
|
||||
else
|
||||
result.appendln(" CASTED TO ${node.receiver.castToType}")
|
||||
result.toString()
|
||||
}
|
||||
|
||||
is Node.FieldWrite -> {
|
||||
val result = StringBuilder()
|
||||
result.appendln(" FIELD WRITE ${node.field}")
|
||||
result.append(" RECEIVER #${node.receiver?.node?.let { ids[it]!! } ?: "null"}")
|
||||
if (node.receiver?.castToType == null)
|
||||
result.appendln()
|
||||
else
|
||||
result.appendln(" CASTED TO ${node.receiver.castToType}")
|
||||
print(" VALUE #${ids[node.value.node]!!}")
|
||||
if (node.value.castToType == null)
|
||||
result.appendln()
|
||||
else
|
||||
result.appendln(" CASTED TO ${node.value.castToType}")
|
||||
result.toString()
|
||||
}
|
||||
|
||||
is Node.Variable -> {
|
||||
val result = StringBuilder()
|
||||
result.appendln(" ${if (node.temp) "TEMP VAR" else "VARIABLE"} ")
|
||||
node.values.forEach {
|
||||
result.append(" VAL #${ids[it.node]!!}")
|
||||
if (it.castToType == null)
|
||||
result.appendln()
|
||||
else
|
||||
result.appendln(" CASTED TO ${it.castToType}")
|
||||
}
|
||||
result.toString()
|
||||
}
|
||||
|
||||
else -> {
|
||||
" UNKNOWN: ${node::class.java}\n"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SymbolTable(val context: Context, val irModule: IrModuleFragment, val module: Module) {
|
||||
@@ -334,6 +352,21 @@ internal object DataFlowIR {
|
||||
val classMap = mutableMapOf<ClassDescriptor, Type>()
|
||||
val functionMap = mutableMapOf<CallableDescriptor, FunctionSymbol>()
|
||||
|
||||
private val NAME_ESCAPES = Name.identifier("Escapes")
|
||||
private val NAME_POINTS_TO = Name.identifier("PointsTo")
|
||||
private val FQ_NAME_KONAN = FqName.fromSegments(listOf("konan"))
|
||||
|
||||
private val FQ_NAME_ESCAPES = FQ_NAME_KONAN.child(NAME_ESCAPES)
|
||||
private val FQ_NAME_POINTS_TO = FQ_NAME_KONAN.child(NAME_POINTS_TO)
|
||||
|
||||
private val konanPackage = context.builtIns.builtInsModule.getPackage(FQ_NAME_KONAN).memberScope
|
||||
private val escapesAnnotationDescriptor = konanPackage.getContributedClassifier(
|
||||
NAME_ESCAPES, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||
private val escapesWhoDescriptor = escapesAnnotationDescriptor.unsubstitutedPrimaryConstructor!!.valueParameters.single()
|
||||
private val pointsToAnnotationDescriptor = konanPackage.getContributedClassifier(
|
||||
NAME_POINTS_TO, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||
private val pointsToOnWhomDescriptor = pointsToAnnotationDescriptor.unsubstitutedPrimaryConstructor!!.valueParameters.single()
|
||||
|
||||
var privateTypeIndex = 0
|
||||
var privateFunIndex = 0
|
||||
var couldBeCalledVirtuallyIndex = 0
|
||||
@@ -427,9 +460,16 @@ internal object DataFlowIR {
|
||||
is FunctionDescriptor -> {
|
||||
val name = if (it.isExported()) it.symbolName else it.internalName
|
||||
val numberOfParameters = it.allParameters.size + if (it.isSuspend) 1 else 0
|
||||
if (it.module != irModule.descriptor || it.externalOrIntrinsic())
|
||||
FunctionSymbol.External(name.localHash.value, numberOfParameters, takeName { name })
|
||||
else {
|
||||
if (it.module != irModule.descriptor || it.externalOrIntrinsic()) {
|
||||
val escapesAnnotation = it.annotations.findAnnotation(FQ_NAME_ESCAPES)
|
||||
val pointsToAnnotation = it.annotations.findAnnotation(FQ_NAME_POINTS_TO)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val escapesBitMask = (escapesAnnotation?.allValueArguments?.get(escapesWhoDescriptor.name) as? ConstantValue<Int>)?.value
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val pointsToBitMask = (pointsToAnnotation?.allValueArguments?.get(pointsToOnWhomDescriptor.name) as? ConstantValue<List<IntValue>>)?.value
|
||||
FunctionSymbol.External(name.localHash.value, numberOfParameters, escapesBitMask,
|
||||
pointsToBitMask?.let { it.map { it.value }.toIntArray() }, takeName { name })
|
||||
} else {
|
||||
val isAbstract = it.modality == Modality.ABSTRACT
|
||||
val classDescriptor = it.containingDeclaration as? ClassDescriptor
|
||||
val placeToFunctionsTable = !isAbstract && it !is ConstructorDescriptor && classDescriptor != null
|
||||
|
||||
Reference in New Issue
Block a user