backend: Use simple DFS during closure building.

Now closure builder can contain includes. Includes
are another builders which closures must be added
to the building one.
Includes are:

For function closure:
	call targets (including constructors)
	callable reference targets

For class:
	all children declarations
	call targets (including constructors)
        callable reference targets

For constructor:
	call and callable reference targets
	delegating constructor call target
	constructing class closure
This commit is contained in:
Ilya Matveev
2017-02-10 17:37:03 +03:00
committed by ilmat192
parent 95a9f65afd
commit c68c4d3b6d
6 changed files with 127 additions and 75 deletions
@@ -3,16 +3,16 @@ package org.jetbrains.kotlin.backend.common.lower
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall import org.jetbrains.kotlin.ir.expressions.IrMemberAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression import org.jetbrains.kotlin.ir.expressions.IrValueAccessExpression
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
import org.jetbrains.kotlin.ir.visitors.acceptVoid import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
// TODO: synchronize with JVM BE // TODO: synchronize with JVM BE
class Closure(val capturedValues: List<ValueDescriptor>) // TODO: rename the file.
class Closure(val capturedValues: List<ValueDescriptor> = emptyList())
private fun <E> MutableList<E>.push(element: E) = this.add(element) private fun <E> MutableList<E>.push(element: E) = this.add(element)
@@ -20,37 +20,51 @@ private fun <E> MutableList<E>.pop() = this.removeAt(size - 1)
private fun <E> MutableList<E>.peek(): E? = if (size == 0) null else this[size - 1] private fun <E> MutableList<E>.peek(): E? = if (size == 0) null else this[size - 1]
abstract class AbstractClosureAnnotator { class ClosureAnnotator {
protected abstract fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) private val closureBuilders = mutableMapOf<DeclarationDescriptor, ClosureBuilder>()
protected abstract fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure)
private class ClosureBuilder { constructor(declaration: IrDeclaration) {
// Collect all closures for classes and functions. Collect call graph
declaration.acceptChildrenVoid(ClosureCollectorVisitor())
}
fun getFunctionClosure(descriptor: FunctionDescriptor) = getClosure(descriptor)
fun getClassClosure(descriptor: ClassDescriptor) = getClosure(descriptor)
private fun getClosure(descriptor: DeclarationDescriptor) : Closure {
closureBuilders.values.forEach { it.processed = false }
return closureBuilders
.getOrElse(descriptor) { throw AssertionError("No closure builder for passed descriptor.") }
.buildClosure()
}
private class ClosureBuilder(val owner: DeclarationDescriptor) {
val capturedValues = mutableSetOf<ValueDescriptor>() val capturedValues = mutableSetOf<ValueDescriptor>()
private val nestedBuilders = mutableSetOf<ClosureBuilder>()
private val declaredValues = mutableSetOf<ValueDescriptor>() private val declaredValues = mutableSetOf<ValueDescriptor>()
private val includes = mutableSetOf<ClosureBuilder>()
fun buildClosure() : Closure { var processed = false
val processed = mutableSetOf<ClosureBuilder>(this)
val builderStack = mutableListOf<ClosureBuilder>().apply { addAll(nestedBuilders) } /*
while (builderStack.isNotEmpty()) { * Node's closure = variables captured by the node +
val builder = builderStack.pop() * closure of all included nodes -
if (!processed.contains(builder)) { * variables declared in the node.
processed.add(builder) */
builderStack.addAll(builder.nestedBuilders) fun buildClosure(): Closure {
fillInNestedClosure(capturedValues, builder.capturedValues) val result = mutableSetOf<ValueDescriptor>().apply { addAll(capturedValues) }
includes.forEach {
if (!it.processed) {
it.processed = true
it.buildClosure().capturedValues.filterTo(result) { isExternal(it) }
} }
} }
// TODO: Save the closure and reuse it. // TODO: We can save the closure and reuse it.
return Closure(capturedValues.toList()) return Closure(result.toList())
} }
fun addNested(builder: ClosureBuilder) {
nestedBuilders.add(builder)
declaredValues.addAll(builder.declaredValues)
}
private fun fillInNestedClosure(destination: MutableSet<ValueDescriptor>, nested: Collection<ValueDescriptor>) { fun include(includingBuilder: ClosureBuilder) {
nested.filterTo(destination) { isExternal(it) } includes.add(includingBuilder)
} }
fun declareVariable(valueDescriptor: ValueDescriptor?) { fun declareVariable(valueDescriptor: ValueDescriptor?) {
@@ -66,27 +80,21 @@ abstract class AbstractClosureAnnotator {
fun isExternal(valueDescriptor: ValueDescriptor): Boolean { fun isExternal(valueDescriptor: ValueDescriptor): Boolean {
return !declaredValues.contains(valueDescriptor) return !declaredValues.contains(valueDescriptor)
} }
}
private val closureBuilders = mutableMapOf<DeclarationDescriptor, ClosureBuilder>()
fun annotate(declaration: IrDeclaration) {
// First pass - collect all closures for classes and functions. Collect call graph
declaration.acceptChildrenVoid(ClosureCollectorVisitor())
// Second pass - build closures on basis of calls.
closureBuilders.forEach { descriptor, builder ->
when(descriptor) {
is FunctionDescriptor -> recordFunctionClosure(descriptor, builder.buildClosure())
is ClassDescriptor -> recordClassClosure(descriptor, builder.buildClosure())
else -> throw AssertionError("Unexpected descriptor type.")
}
}
} }
private inner class ClosureCollectorVisitor : IrElementVisitorVoid { private inner class ClosureCollectorVisitor : IrElementVisitorVoid {
protected val closuresStack = mutableListOf<ClosureBuilder>() val closuresStack = mutableListOf<ClosureBuilder>()
protected val classClosures = mutableMapOf<ClassDescriptor, ClosureBuilder>()
fun includeInParent(builder: ClosureBuilder) {
// We don't include functions or classes in a parent function when they are declared.
// Instead we will include them when are is used (use = call for a function or constructor call for a class).
val parentBuilder = closuresStack.peek()
if (parentBuilder != null && parentBuilder.owner !is FunctionDescriptor) {
parentBuilder.include(builder)
}
}
override fun visitElement(element: IrElement) { override fun visitElement(element: IrElement) {
element.acceptChildrenVoid(this) element.acceptChildrenVoid(this)
@@ -94,47 +102,43 @@ abstract class AbstractClosureAnnotator {
override fun visitClass(declaration: IrClass) { override fun visitClass(declaration: IrClass) {
val classDescriptor = declaration.descriptor val classDescriptor = declaration.descriptor
val closureBuilder = ClosureBuilder() val closureBuilder = ClosureBuilder(classDescriptor)
closureBuilders[declaration.descriptor] = closureBuilder closureBuilders[declaration.descriptor] = closureBuilder
closureBuilder.declareVariable(classDescriptor.thisAsReceiverParameter) closureBuilder.declareVariable(classDescriptor.thisAsReceiverParameter)
if (classDescriptor.isInner) if (classDescriptor.isInner) {
closureBuilder.declareVariable((classDescriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter) closureBuilder.declareVariable((classDescriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter)
includeInParent(closureBuilder)
}
closuresStack.push(closureBuilder) closuresStack.push(closureBuilder)
declaration.acceptChildrenVoid(this) declaration.acceptChildrenVoid(this)
closuresStack.pop() closuresStack.pop()
val superClassClosure = classClosures[classDescriptor.getSuperClassOrAny()]
if (superClassClosure != null) {
// Capture all values from the super class since we need to call constructor of super class
// with its captured values.
closureBuilder.addNested(superClassClosure)
}
if (DescriptorUtils.isLocal(classDescriptor)) {
classClosures[classDescriptor] = closureBuilder
}
closuresStack.peek()?.addNested(closureBuilder)
} }
override fun visitFunction(declaration: IrFunction) { override fun visitFunction(declaration: IrFunction) {
val functionDescriptor = declaration.descriptor val functionDescriptor = declaration.descriptor
val closureBuilder = ClosureBuilder() val closureBuilder = ClosureBuilder(functionDescriptor)
closureBuilders[declaration.descriptor] = closureBuilder closureBuilders[functionDescriptor] = closureBuilder
functionDescriptor.valueParameters.forEach { closureBuilder.declareVariable(it) } functionDescriptor.valueParameters.forEach { closureBuilder.declareVariable(it) }
closureBuilder.declareVariable(functionDescriptor.dispatchReceiverParameter) closureBuilder.declareVariable(functionDescriptor.dispatchReceiverParameter)
closureBuilder.declareVariable(functionDescriptor.extensionReceiverParameter) closureBuilder.declareVariable(functionDescriptor.extensionReceiverParameter)
if (functionDescriptor is ConstructorDescriptor) if (functionDescriptor is ConstructorDescriptor) {
closureBuilder.declareVariable(functionDescriptor.constructedClass.thisAsReceiverParameter) closureBuilder.declareVariable(functionDescriptor.constructedClass.thisAsReceiverParameter)
// Include closure of the class in the constructor closure.
val classBuilder = closuresStack.peek()
classBuilder?.let {
assert(classBuilder.owner == functionDescriptor.constructedClass)
closureBuilder.include(classBuilder)
}
}
closuresStack.push(closureBuilder) closuresStack.push(closureBuilder)
declaration.acceptChildrenVoid(this) declaration.acceptChildrenVoid(this)
closuresStack.pop() closuresStack.pop()
closuresStack.peek()?.addNested(closureBuilder) includeInParent(closureBuilder)
} }
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty) { override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty) {
@@ -152,13 +156,14 @@ abstract class AbstractClosureAnnotator {
super.visitVariable(declaration) super.visitVariable(declaration)
} }
override fun visitCall(expression: IrCall) { // Process delegating constructor calls, enum constructor calls, calls and callable references.
override fun visitMemberAccess(expression: IrMemberAccessExpression) {
expression.acceptChildrenVoid(this) expression.acceptChildrenVoid(this)
val descriptor = expression.descriptor val descriptor = expression.descriptor
if (DescriptorUtils.isLocal(descriptor)) { if (DescriptorUtils.isLocal(descriptor)) {
val builder = closureBuilders[descriptor] val builder = closureBuilders[descriptor]
builder?.let { builder?.let {
closuresStack.peek()?.addNested(builder) closuresStack.peek()?.include(builder)
} }
} }
} }
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.util.transformFlat
import org.jetbrains.kotlin.ir.visitors.* import org.jetbrains.kotlin.ir.visitors.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
import org.jetbrains.kotlin.resolve.descriptorUtil.parents import org.jetbrains.kotlin.resolve.descriptorUtil.parents
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -505,14 +504,14 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
return newValueParameters return newValueParameters
} }
private fun createTransformedConstructorDescriptor(localFunctionContext: LocalClassConstructorContext) { private fun createTransformedConstructorDescriptor(constructorContext: LocalClassConstructorContext) {
val oldDescriptor = localFunctionContext.descriptor val oldDescriptor = constructorContext.descriptor
val localClassContext = localClasses[oldDescriptor.containingDeclaration]!! val localClassContext = localClasses[oldDescriptor.containingDeclaration]!!
val newDescriptor = ClassConstructorDescriptorImpl.create( val newDescriptor = ClassConstructorDescriptorImpl.create(
localClassContext.descriptor, localClassContext.descriptor,
Annotations.EMPTY, oldDescriptor.isPrimary, oldDescriptor.source) Annotations.EMPTY, oldDescriptor.isPrimary, oldDescriptor.source)
localFunctionContext.transformedDescriptor = newDescriptor constructorContext.transformedDescriptor = newDescriptor
transformedDescriptors[oldDescriptor] = newDescriptor transformedDescriptors[oldDescriptor] = newDescriptor
// Do not substitute type parameters for now. // Do not substitute type parameters for now.
@@ -520,7 +519,7 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
val capturedValues = localClasses[oldDescriptor.containingDeclaration]!!.closure.capturedValues val capturedValues = localClasses[oldDescriptor.containingDeclaration]!!.closure.capturedValues
val newValueParameters = createTransformedValueParameters(localFunctionContext, capturedValues) val newValueParameters = createTransformedValueParameters(constructorContext, capturedValues)
newDescriptor.initialize( newDescriptor.initialize(
newValueParameters, newValueParameters,
@@ -623,15 +622,14 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
private fun collectClosures() { private fun collectClosures() {
object : AbstractClosureAnnotator() { val annotator = ClosureAnnotator(memberDeclaration)
override fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) { localFunctions.forEach { descriptor, context ->
localFunctions[functionDescriptor]?.closure = closure context.closure = annotator.getFunctionClosure(descriptor)
} }
override fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure) { localClasses.forEach { descriptor, context ->
localClasses[classDescriptor]?.closure = closure context.closure = annotator.getClassClosure(descriptor)
} }
}.annotate(memberDeclaration)
} }
private fun collectLocalDeclarations() { private fun collectLocalDeclarations() {
@@ -7,5 +7,17 @@ fun main(args : Array<String>) {
} }
local0() local0()
} }
fun l1() {
var x = 1
fun l2() {
fun l3() {
l1()
x = 5
}
l3()
}
}
println("OK") println("OK")
} }
@@ -0,0 +1,16 @@
fun main(args: Array<String>) {
var a = 0
fun local() {
class A {
val b = 0
fun f() {
a = b
}
}
fun local2() : A {
return A()
}
}
println("OK")
}
@@ -0,0 +1,21 @@
fun main(args : Array<String>) {
var x = 0
class A {
fun bar() {
fun local() {
class B {
fun baz() {
fun local2() {
x++
}
local2()
}
}
B().baz()
}
local()
}
}
A().bar()
println("OK")
}