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:
+67
-62
@@ -3,16 +3,16 @@ package org.jetbrains.kotlin.backend.common.lower
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
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.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
|
||||
// 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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
abstract class AbstractClosureAnnotator {
|
||||
protected abstract fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure)
|
||||
protected abstract fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure)
|
||||
class ClosureAnnotator {
|
||||
private val closureBuilders = mutableMapOf<DeclarationDescriptor, ClosureBuilder>()
|
||||
|
||||
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>()
|
||||
private val nestedBuilders = mutableSetOf<ClosureBuilder>()
|
||||
private val declaredValues = mutableSetOf<ValueDescriptor>()
|
||||
private val includes = mutableSetOf<ClosureBuilder>()
|
||||
|
||||
fun buildClosure() : Closure {
|
||||
val processed = mutableSetOf<ClosureBuilder>(this)
|
||||
val builderStack = mutableListOf<ClosureBuilder>().apply { addAll(nestedBuilders) }
|
||||
while (builderStack.isNotEmpty()) {
|
||||
val builder = builderStack.pop()
|
||||
if (!processed.contains(builder)) {
|
||||
processed.add(builder)
|
||||
builderStack.addAll(builder.nestedBuilders)
|
||||
fillInNestedClosure(capturedValues, builder.capturedValues)
|
||||
var processed = false
|
||||
|
||||
/*
|
||||
* Node's closure = variables captured by the node +
|
||||
* closure of all included nodes -
|
||||
* variables declared in the node.
|
||||
*/
|
||||
fun buildClosure(): Closure {
|
||||
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.
|
||||
return Closure(capturedValues.toList())
|
||||
// TODO: We can save the closure and reuse it.
|
||||
return Closure(result.toList())
|
||||
}
|
||||
|
||||
fun addNested(builder: ClosureBuilder) {
|
||||
nestedBuilders.add(builder)
|
||||
declaredValues.addAll(builder.declaredValues)
|
||||
}
|
||||
|
||||
private fun fillInNestedClosure(destination: MutableSet<ValueDescriptor>, nested: Collection<ValueDescriptor>) {
|
||||
nested.filterTo(destination) { isExternal(it) }
|
||||
fun include(includingBuilder: ClosureBuilder) {
|
||||
includes.add(includingBuilder)
|
||||
}
|
||||
|
||||
fun declareVariable(valueDescriptor: ValueDescriptor?) {
|
||||
@@ -66,27 +80,21 @@ abstract class AbstractClosureAnnotator {
|
||||
fun isExternal(valueDescriptor: ValueDescriptor): Boolean {
|
||||
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 {
|
||||
|
||||
protected val closuresStack = mutableListOf<ClosureBuilder>()
|
||||
protected val classClosures = mutableMapOf<ClassDescriptor, ClosureBuilder>()
|
||||
val closuresStack = mutableListOf<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) {
|
||||
element.acceptChildrenVoid(this)
|
||||
@@ -94,47 +102,43 @@ abstract class AbstractClosureAnnotator {
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
val classDescriptor = declaration.descriptor
|
||||
val closureBuilder = ClosureBuilder()
|
||||
val closureBuilder = ClosureBuilder(classDescriptor)
|
||||
closureBuilders[declaration.descriptor] = closureBuilder
|
||||
|
||||
closureBuilder.declareVariable(classDescriptor.thisAsReceiverParameter)
|
||||
if (classDescriptor.isInner)
|
||||
if (classDescriptor.isInner) {
|
||||
closureBuilder.declareVariable((classDescriptor.containingDeclaration as ClassDescriptor).thisAsReceiverParameter)
|
||||
includeInParent(closureBuilder)
|
||||
}
|
||||
|
||||
closuresStack.push(closureBuilder)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
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) {
|
||||
val functionDescriptor = declaration.descriptor
|
||||
val closureBuilder = ClosureBuilder()
|
||||
closureBuilders[declaration.descriptor] = closureBuilder
|
||||
val closureBuilder = ClosureBuilder(functionDescriptor)
|
||||
closureBuilders[functionDescriptor] = closureBuilder
|
||||
|
||||
functionDescriptor.valueParameters.forEach { closureBuilder.declareVariable(it) }
|
||||
closureBuilder.declareVariable(functionDescriptor.dispatchReceiverParameter)
|
||||
closureBuilder.declareVariable(functionDescriptor.extensionReceiverParameter)
|
||||
if (functionDescriptor is ConstructorDescriptor)
|
||||
if (functionDescriptor is ConstructorDescriptor) {
|
||||
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)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
closuresStack.pop()
|
||||
|
||||
closuresStack.peek()?.addNested(closureBuilder)
|
||||
includeInParent(closureBuilder)
|
||||
}
|
||||
|
||||
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty) {
|
||||
@@ -152,13 +156,14 @@ abstract class AbstractClosureAnnotator {
|
||||
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)
|
||||
val descriptor = expression.descriptor
|
||||
if (DescriptorUtils.isLocal(descriptor)) {
|
||||
val builder = closureBuilders[descriptor]
|
||||
builder?.let {
|
||||
closuresStack.peek()?.addNested(builder)
|
||||
closuresStack.peek()?.include(builder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-13
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
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.parentsWithSelf
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
@@ -505,14 +504,14 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
|
||||
return newValueParameters
|
||||
}
|
||||
|
||||
private fun createTransformedConstructorDescriptor(localFunctionContext: LocalClassConstructorContext) {
|
||||
val oldDescriptor = localFunctionContext.descriptor
|
||||
private fun createTransformedConstructorDescriptor(constructorContext: LocalClassConstructorContext) {
|
||||
val oldDescriptor = constructorContext.descriptor
|
||||
val localClassContext = localClasses[oldDescriptor.containingDeclaration]!!
|
||||
val newDescriptor = ClassConstructorDescriptorImpl.create(
|
||||
localClassContext.descriptor,
|
||||
Annotations.EMPTY, oldDescriptor.isPrimary, oldDescriptor.source)
|
||||
|
||||
localFunctionContext.transformedDescriptor = newDescriptor
|
||||
constructorContext.transformedDescriptor = newDescriptor
|
||||
transformedDescriptors[oldDescriptor] = newDescriptor
|
||||
|
||||
// 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 newValueParameters = createTransformedValueParameters(localFunctionContext, capturedValues)
|
||||
val newValueParameters = createTransformedValueParameters(constructorContext, capturedValues)
|
||||
|
||||
newDescriptor.initialize(
|
||||
newValueParameters,
|
||||
@@ -623,15 +622,14 @@ class LocalDeclarationsLowering(val context: BackendContext) : DeclarationContai
|
||||
|
||||
|
||||
private fun collectClosures() {
|
||||
object : AbstractClosureAnnotator() {
|
||||
override fun recordFunctionClosure(functionDescriptor: FunctionDescriptor, closure: Closure) {
|
||||
localFunctions[functionDescriptor]?.closure = closure
|
||||
}
|
||||
val annotator = ClosureAnnotator(memberDeclaration)
|
||||
localFunctions.forEach { descriptor, context ->
|
||||
context.closure = annotator.getFunctionClosure(descriptor)
|
||||
}
|
||||
|
||||
override fun recordClassClosure(classDescriptor: ClassDescriptor, closure: Closure) {
|
||||
localClasses[classDescriptor]?.closure = closure
|
||||
}
|
||||
}.annotate(memberDeclaration)
|
||||
localClasses.forEach { descriptor, context ->
|
||||
context.closure = annotator.getClassClosure(descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectLocalDeclarations() {
|
||||
|
||||
@@ -7,5 +7,17 @@ fun main(args : Array<String>) {
|
||||
}
|
||||
local0()
|
||||
}
|
||||
|
||||
fun l1() {
|
||||
var x = 1
|
||||
fun l2() {
|
||||
fun l3() {
|
||||
l1()
|
||||
x = 5
|
||||
}
|
||||
l3()
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
Reference in New Issue
Block a user