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)
}
private fun isInteresting(type: KotlinType?): Boolean =
type != null && !type.isUnit() && !type.isNothing()
private fun RuntimeAware.isInteresting(type: KotlinType?): Boolean =
type != null && !type.isUnit() && !type.isNothing() && isObjectType(type)
private class Roles {
val data = HashMap<Role, RoleInfo>()
@@ -265,7 +265,7 @@ internal object EscapeAnalysis {
private class IntraproceduralAnalysisResult(val functionAnalysisResults: Map<FunctionDescriptor, FunctionAnalysisResult>,
val expressionValuesExtractor: ExpressionValuesExtractor)
private class IntraproceduralAnalysis {
private class IntraproceduralAnalysis(val context: RuntimeAware) {
// Possible values of a returnable block.
private val returnableBlockValues = mutableMapOf<IrReturnableBlock, MutableList<IrExpression>>()
@@ -276,12 +276,12 @@ internal object EscapeAnalysis {
private val expressionValuesExtractor = ExpressionValuesExtractor(returnableBlockValues, suspendableExpressionValues)
private fun isInteresting(expression: IrExpression) =
(expression is IrMemberAccessExpression && isInteresting(expression.type))
|| (expression is IrGetValue && isInteresting(expression.type))
|| (expression is IrGetField && isInteresting(expression.type))
(expression is IrMemberAccessExpression && context.isInteresting(expression.type))
|| (expression is IrGetValue && context.isInteresting(expression.type))
|| (expression is IrGetField && context.isInteresting(expression.type))
|| 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 {
val result = mutableMapOf<FunctionDescriptor, FunctionAnalysisResult>()
@@ -465,6 +465,14 @@ internal object EscapeAnalysis {
variableValues = if (useVarValues) variableValues else null
)
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)
}
@@ -624,6 +632,7 @@ internal object EscapeAnalysis {
private class InterproceduralAnalysisResult(val functionEscapeAnalysisResults: Map<FunctionDescriptor, FunctionEscapeAnalysisResult>)
private class InterproceduralAnalysis(context: Context,
val runtimeAware: RuntimeAware,
val externalFunctionEscapeAnalysisResults: Map<String, FunctionEscapeAnalysisResult>,
val intraproceduralAnalysisResult: IntraproceduralAnalysisResult,
val lifetimes: MutableMap<IrElement, Lifetime>) {
@@ -890,7 +899,7 @@ internal object EscapeAnalysis {
FunctionEscapeAnalysisResult((0..parameters.size).map {
val type = if (it < parameters.size) parameters[it].type else callee.returnType
ParameterEscapeAnalysisResult(
escapes = isInteresting(type), // Conservatively assume all references escape.
escapes = runtimeAware.isInteresting(type), // Conservatively assume all references escape.
pointsTo = IntArray(0)
)
}.toTypedArray())
@@ -1231,7 +1240,7 @@ internal object EscapeAnalysis {
if (index == parameters.size) // Return value.
returnValues.any { nodes[it]!!.kind == PointsToGraphNodeKind.ESCAPES }
else {
isInteresting(parameters[index].value.type)
runtimeAware.isInteresting(parameters[index].value.type)
&& nodes[parameters[index].value]!!.kind == PointsToGraphNodeKind.ESCAPES
}
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>) {
assert(lifetimes.isEmpty())
@@ -1288,8 +1297,8 @@ internal object EscapeAnalysis {
}
}
}
val intraproceduralAnalysisResult = IntraproceduralAnalysis().analyze(irModule)
val interproceduralAnalysisResult = InterproceduralAnalysis(context,
val intraproceduralAnalysisResult = IntraproceduralAnalysis(runtimeAware).analyze(irModule)
val interproceduralAnalysisResult = InterproceduralAnalysis(context, runtimeAware,
externalFunctionEAResults, intraproceduralAnalysisResult, lifetimes).analyze(irModule)
if (isStdlib) { // Save only for stdlib for now.
interproceduralAnalysisResult.functionEscapeAnalysisResults
@@ -72,12 +72,13 @@ internal fun emitLLVM(context: Context) {
generateDebugInfoHeader(context)
val lifetimes = mutableMapOf<IrElement, Lifetime>()
val codegenVisitor = CodeGeneratorVisitor(context, lifetimes)
phaser.phase(KonanPhase.ESCAPE_ANALYSIS) {
EscapeAnalysis.computeLifetimes(irModule, context, lifetimes)
EscapeAnalysis.computeLifetimes(irModule, context, codegenVisitor.codegen, lifetimes)
}
phaser.phase(KonanPhase.CODEGEN) {
irModule.acceptVoid(CodeGeneratorVisitor(context, lifetimes))
irModule.acceptVoid(codegenVisitor)
}
if (context.shouldContainDebugInfo()) {
+1 -1
View File
@@ -42,7 +42,7 @@ public final class Array<T> {
external public operator fun get(index: Int): T
@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
public operator fun iterator(): kotlin.collections.Iterator<T> {