Made escape analysis a bit more conservative for now

This commit is contained in:
Igor Chevdar
2017-08-07 16:45:07 +03:00
parent 72ca603d71
commit 31d2618b9c
3 changed files with 25 additions and 15 deletions
@@ -100,8 +100,8 @@ internal object EscapeAnalysis {
open fun add(entry: RoleInfoEntry) = entries.add(entry) open fun add(entry: RoleInfoEntry) = entries.add(entry)
} }
private fun isInteresting(type: KotlinType?): Boolean = private fun RuntimeAware.isInteresting(type: KotlinType?): Boolean =
type != null && !type.isUnit() && !type.isNothing() type != null && !type.isUnit() && !type.isNothing() && isObjectType(type)
private class Roles { private class Roles {
val data = HashMap<Role, RoleInfo>() val data = HashMap<Role, RoleInfo>()
@@ -265,7 +265,7 @@ internal object EscapeAnalysis {
private class IntraproceduralAnalysisResult(val functionAnalysisResults: Map<FunctionDescriptor, FunctionAnalysisResult>, private class IntraproceduralAnalysisResult(val functionAnalysisResults: Map<FunctionDescriptor, FunctionAnalysisResult>,
val expressionValuesExtractor: ExpressionValuesExtractor) val expressionValuesExtractor: ExpressionValuesExtractor)
private class IntraproceduralAnalysis { private class IntraproceduralAnalysis(val context: RuntimeAware) {
// Possible values of a returnable block. // Possible values of a returnable block.
private val returnableBlockValues = mutableMapOf<IrReturnableBlock, MutableList<IrExpression>>() private val returnableBlockValues = mutableMapOf<IrReturnableBlock, MutableList<IrExpression>>()
@@ -276,12 +276,12 @@ internal object EscapeAnalysis {
private val expressionValuesExtractor = ExpressionValuesExtractor(returnableBlockValues, suspendableExpressionValues) private val expressionValuesExtractor = ExpressionValuesExtractor(returnableBlockValues, suspendableExpressionValues)
private fun isInteresting(expression: IrExpression) = private fun isInteresting(expression: IrExpression) =
(expression is IrMemberAccessExpression && isInteresting(expression.type)) (expression is IrMemberAccessExpression && context.isInteresting(expression.type))
|| (expression is IrGetValue && isInteresting(expression.type)) || (expression is IrGetValue && context.isInteresting(expression.type))
|| (expression is IrGetField && isInteresting(expression.type)) || (expression is IrGetField && context.isInteresting(expression.type))
|| expression is IrGetObjectValue || expression is IrGetObjectValue
private fun isInteresting(variable: ValueDescriptor) = isInteresting(variable.type) private fun isInteresting(variable: ValueDescriptor) = context.isInteresting(variable.type)
fun analyze(irModule: IrModuleFragment): IntraproceduralAnalysisResult { fun analyze(irModule: IrModuleFragment): IntraproceduralAnalysisResult {
val result = mutableMapOf<FunctionDescriptor, FunctionAnalysisResult>() val result = mutableMapOf<FunctionDescriptor, FunctionAnalysisResult>()
@@ -465,6 +465,14 @@ internal object EscapeAnalysis {
variableValues = if (useVarValues) variableValues else null variableValues = if (useVarValues) variableValues else null
) )
nodes.forEach { assignRole(receiver, Role.FIELD_WRITTEN, RoleInfoEntry(it)) } nodes.forEach { assignRole(receiver, Role.FIELD_WRITTEN, RoleInfoEntry(it)) }
// TODO: make more precise analysis and differentiate fields from receivers.
// See test escape2.kt, why we need these edges.
val receiverNodes = expressionValuesExtractor.extractNodesUsingVariableValues(
expression = receiver,
variableValues = if (useVarValues) variableValues else null
)
receiverNodes.forEach { assignRole(expression.value, Role.FIELD_WRITTEN, RoleInfoEntry(it)) }
} }
super.visitSetField(expression) super.visitSetField(expression)
} }
@@ -624,6 +632,7 @@ internal object EscapeAnalysis {
private class InterproceduralAnalysisResult(val functionEscapeAnalysisResults: Map<FunctionDescriptor, FunctionEscapeAnalysisResult>) private class InterproceduralAnalysisResult(val functionEscapeAnalysisResults: Map<FunctionDescriptor, FunctionEscapeAnalysisResult>)
private class InterproceduralAnalysis(context: Context, private class InterproceduralAnalysis(context: Context,
val runtimeAware: RuntimeAware,
val externalFunctionEscapeAnalysisResults: Map<String, FunctionEscapeAnalysisResult>, val externalFunctionEscapeAnalysisResults: Map<String, FunctionEscapeAnalysisResult>,
val intraproceduralAnalysisResult: IntraproceduralAnalysisResult, val intraproceduralAnalysisResult: IntraproceduralAnalysisResult,
val lifetimes: MutableMap<IrElement, Lifetime>) { val lifetimes: MutableMap<IrElement, Lifetime>) {
@@ -890,7 +899,7 @@ internal object EscapeAnalysis {
FunctionEscapeAnalysisResult((0..parameters.size).map { FunctionEscapeAnalysisResult((0..parameters.size).map {
val type = if (it < parameters.size) parameters[it].type else callee.returnType val type = if (it < parameters.size) parameters[it].type else callee.returnType
ParameterEscapeAnalysisResult( ParameterEscapeAnalysisResult(
escapes = isInteresting(type), // Conservatively assume all references escape. escapes = runtimeAware.isInteresting(type), // Conservatively assume all references escape.
pointsTo = IntArray(0) pointsTo = IntArray(0)
) )
}.toTypedArray()) }.toTypedArray())
@@ -1231,7 +1240,7 @@ internal object EscapeAnalysis {
if (index == parameters.size) // Return value. if (index == parameters.size) // Return value.
returnValues.any { nodes[it]!!.kind == PointsToGraphNodeKind.ESCAPES } returnValues.any { nodes[it]!!.kind == PointsToGraphNodeKind.ESCAPES }
else { else {
isInteresting(parameters[index].value.type) runtimeAware.isInteresting(parameters[index].value.type)
&& nodes[parameters[index].value]!!.kind == PointsToGraphNodeKind.ESCAPES && nodes[parameters[index].value]!!.kind == PointsToGraphNodeKind.ESCAPES
} }
ParameterEscapeAnalysisResult(escapes, reachability) ParameterEscapeAnalysisResult(escapes, reachability)
@@ -1264,7 +1273,7 @@ internal object EscapeAnalysis {
} }
} }
internal fun computeLifetimes(irModule: IrModuleFragment, context: Context, internal fun computeLifetimes(irModule: IrModuleFragment, context: Context, runtimeAware: RuntimeAware,
lifetimes: MutableMap<IrElement, Lifetime>) { lifetimes: MutableMap<IrElement, Lifetime>) {
assert(lifetimes.isEmpty()) assert(lifetimes.isEmpty())
@@ -1288,8 +1297,8 @@ internal object EscapeAnalysis {
} }
} }
} }
val intraproceduralAnalysisResult = IntraproceduralAnalysis().analyze(irModule) val intraproceduralAnalysisResult = IntraproceduralAnalysis(runtimeAware).analyze(irModule)
val interproceduralAnalysisResult = InterproceduralAnalysis(context, val interproceduralAnalysisResult = InterproceduralAnalysis(context, runtimeAware,
externalFunctionEAResults, intraproceduralAnalysisResult, lifetimes).analyze(irModule) externalFunctionEAResults, intraproceduralAnalysisResult, lifetimes).analyze(irModule)
if (isStdlib) { // Save only for stdlib for now. if (isStdlib) { // Save only for stdlib for now.
interproceduralAnalysisResult.functionEscapeAnalysisResults interproceduralAnalysisResult.functionEscapeAnalysisResults
@@ -72,12 +72,13 @@ internal fun emitLLVM(context: Context) {
generateDebugInfoHeader(context) generateDebugInfoHeader(context)
val lifetimes = mutableMapOf<IrElement, Lifetime>() val lifetimes = mutableMapOf<IrElement, Lifetime>()
val codegenVisitor = CodeGeneratorVisitor(context, lifetimes)
phaser.phase(KonanPhase.ESCAPE_ANALYSIS) { phaser.phase(KonanPhase.ESCAPE_ANALYSIS) {
EscapeAnalysis.computeLifetimes(irModule, context, lifetimes) EscapeAnalysis.computeLifetimes(irModule, context, codegenVisitor.codegen, lifetimes)
} }
phaser.phase(KonanPhase.CODEGEN) { phaser.phase(KonanPhase.CODEGEN) {
irModule.acceptVoid(CodeGeneratorVisitor(context, lifetimes)) irModule.acceptVoid(codegenVisitor)
} }
if (context.shouldContainDebugInfo()) { if (context.shouldContainDebugInfo()) {
+1 -1
View File
@@ -42,7 +42,7 @@ public final class Array<T> {
external public operator fun get(index: Int): T external public operator fun get(index: Int): T
@SymbolName("Kotlin_Array_set") @SymbolName("Kotlin_Array_set")
@PointsTo(0b0100) // <this> points to <value>. @PointsTo(0b0100, 0, 0b0001) // <this> points to <value>, <value> points to <this>.
external public operator fun set(index: Int, value: T): Unit external public operator fun set(index: Int, value: T): Unit
public operator fun iterator(): kotlin.collections.Iterator<T> { public operator fun iterator(): kotlin.collections.Iterator<T> {