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.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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+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.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")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user