JVM_IR: do not inherit delegated property trackers

This is no longer needed now that lambdas are generated before
`$$delegatedProperties`.
This commit is contained in:
pyos
2020-09-25 14:58:39 +02:00
committed by Alexander Udalov
parent 05c856f1f7
commit a6c62d3339
16 changed files with 97 additions and 40 deletions
@@ -1739,6 +1739,11 @@ public class FirBlackBoxInlineCodegenTestGenerated extends AbstractFirBlackBoxIn
runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
} }
@TestMetadata("localDeclaredInLambda.kt")
public void testLocalDeclaredInLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localDeclaredInLambda.kt");
}
@TestMetadata("localInAnonymousObject.kt") @TestMetadata("localInAnonymousObject.kt")
public void testLocalInAnonymousObject() throws Exception { public void testLocalInAnonymousObject() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
@@ -91,9 +91,12 @@ class ClassCodegen private constructor(
) )
} }
// TODO: the order of entries in this set depends on the order in which methods are generated; this means it is unstable
// under incremental compilation, as calls to `inline fun`s declared in this class cause them to be generated out of order.
private val innerClasses = linkedSetOf<IrClass>() private val innerClasses = linkedSetOf<IrClass>()
private var regeneratedObjectNameGenerators = mutableMapOf<String, NameGenerator>() // TODO: the names produced by generators in this map depend on the order in which methods are generated; see above.
private val regeneratedObjectNameGenerators = mutableMapOf<String, NameGenerator>()
fun getRegeneratedObjectNameGenerator(function: IrFunction): NameGenerator { fun getRegeneratedObjectNameGenerator(function: IrFunction): NameGenerator {
val name = if (function.name.isSpecial) "special" else function.name.asString() val name = if (function.name.isSpecial) "special" else function.name.asString()
@@ -104,19 +107,15 @@ class ClassCodegen private constructor(
private var generated = false private var generated = false
fun generate(parentDelegatedPropertyTracker: DelegatedPropertyOptimizer? = null) { fun generate() {
// TODO: reject repeated generate() calls; currently, these can happen for objects in finally // TODO: reject repeated generate() calls; currently, these can happen for objects in finally
// blocks since they are `accept`ed once per each CFG edge out of the try-finally. // blocks since they are `accept`ed once per each CFG edge out of the try-finally.
if (generated) return if (generated) return
generated = true generated = true
// We remove unused cached KProperties. // We remove reads of `$$delegatedProperties` (and the field itself) if they are not in fact used for anything.
val classDelegatedPropertiesArray = irClass.fields.singleOrNull { val delegatedProperties = irClass.fields.singleOrNull { it.origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE }
it.origin == JvmLoweredDeclarationOrigin.GENERATED_PROPERTY_REFERENCE val delegatedPropertyOptimizer = if (delegatedProperties != null) DelegatedPropertyOptimizer() else null
}
val delegatedPropertyTracker =
if (classDelegatedPropertiesArray != null) DelegatedPropertyOptimizer() else parentDelegatedPropertyTracker
// Generating a method node may cause the addition of a field with an initializer if an inline function // Generating a method node may cause the addition of a field with an initializer if an inline function
// call uses `assert` and the JVM assertions mode is enabled. To avoid concurrent modification errors, // call uses `assert` and the JVM assertions mode is enabled. To avoid concurrent modification errors,
// there is a very specific generation order. // there is a very specific generation order.
@@ -124,14 +123,14 @@ class ClassCodegen private constructor(
// 1. Any method other than `<clinit>` can add a field and a `<clinit>` statement: // 1. Any method other than `<clinit>` can add a field and a `<clinit>` statement:
for (method in irClass.declarations.filterIsInstance<IrFunction>()) { for (method in irClass.declarations.filterIsInstance<IrFunction>()) {
if (method.name.asString() != "<clinit>") { if (method.name.asString() != "<clinit>") {
generateMethod(method, smap, delegatedPropertyTracker) generateMethod(method, smap, delegatedPropertyOptimizer)
} }
} }
// 2. `<clinit>` itself can add a field, but the statement is generated via the `return init` hack: // 2. `<clinit>` itself can add a field, but the statement is generated via the `return init` hack:
irClass.functions.find { it.name.asString() == "<clinit>" }?.let { generateMethod(it, smap, delegatedPropertyTracker) } irClass.functions.find { it.name.asString() == "<clinit>" }?.let { generateMethod(it, smap, delegatedPropertyOptimizer) }
// 3. Now we have all the fields (`$$delegatedProperties` might be redundant if all reads were optimized out): // 3. Now we have all the fields (`$$delegatedProperties` might be redundant if all reads were optimized out):
for (field in irClass.fields) { for (field in irClass.fields) {
if (field !== classDelegatedPropertiesArray || delegatedPropertyTracker?.needsDelegatedProperties == true) { if (field !== delegatedProperties || delegatedPropertyOptimizer?.needsDelegatedProperties == true) {
generateField(field) generateField(field)
} }
} }
@@ -139,7 +138,7 @@ class ClassCodegen private constructor(
// everything moved to the outer class has already been recorded in `globalSerializationBindings`. // everything moved to the outer class has already been recorded in `globalSerializationBindings`.
for (declaration in irClass.declarations) { for (declaration in irClass.declarations) {
if (declaration is IrClass) { if (declaration is IrClass) {
getOrCreate(declaration, context).generate(delegatedPropertyTracker) getOrCreate(declaration, context).generate()
} }
} }
@@ -313,14 +312,14 @@ class ClassCodegen private constructor(
private val generatedInlineMethods = mutableMapOf<IrFunction, SMAPAndMethodNode>() private val generatedInlineMethods = mutableMapOf<IrFunction, SMAPAndMethodNode>()
fun generateMethodNode(method: IrFunction, delegatedPropertyOptimizer: DelegatedPropertyOptimizer?): SMAPAndMethodNode { fun generateMethodNode(method: IrFunction): SMAPAndMethodNode {
if (!method.isInline && !method.isSuspend) { if (!method.isInline && !method.isSuspend) {
// Inline methods can be used multiple times by `IrSourceCompilerForInline`, suspend methods // Inline methods can be used multiple times by `IrSourceCompilerForInline`, suspend methods
// could be used twice if they capture crossinline lambdas, and everything else is only // could be used twice if they capture crossinline lambdas, and everything else is only
// generated by `generateMethod` below so does not need caching. // generated by `generateMethod` below so does not need caching.
return FunctionCodegen(method, this).generate(delegatedPropertyOptimizer) return FunctionCodegen(method, this).generate()
} }
val (node, smap) = generatedInlineMethods.getOrPut(method) { FunctionCodegen(method, this).generate(delegatedPropertyOptimizer) } val (node, smap) = generatedInlineMethods.getOrPut(method) { FunctionCodegen(method, this).generate() }
val copy = with(node) { MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions.toTypedArray()) } val copy = with(node) { MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions.toTypedArray()) }
node.instructions.resetLabels() node.instructions.resetLabels()
node.accept(copy) node.accept(copy)
@@ -333,7 +332,7 @@ class ClassCodegen private constructor(
return return
} }
val (node, smap) = generateMethodNode(method, delegatedPropertyOptimizer) val (node, smap) = generateMethodNode(method)
if (delegatedPropertyOptimizer != null) { if (delegatedPropertyOptimizer != null) {
delegatedPropertyOptimizer.transform(node) delegatedPropertyOptimizer.transform(node)
if (method.name.asString() == "<clinit>") { if (method.name.asString() == "<clinit>") {
@@ -358,7 +357,7 @@ class ClassCodegen private constructor(
if (method.isSuspend) continuationClassCodegen.value.visitor else visitor if (method.isSuspend) continuationClassCodegen.value.visitor else visitor
} }
if (continuationClassCodegen.isInitialized() || method.alwaysNeedsContinuation()) { if (continuationClassCodegen.isInitialized() || method.alwaysNeedsContinuation()) {
continuationClassCodegen.value.generate(delegatedPropertyOptimizer) continuationClassCodegen.value.generate()
} }
} else { } else {
node.accept(smapCopyingVisitor) node.accept(smapCopyingVisitor)
@@ -111,7 +111,6 @@ class ExpressionCodegen(
val classCodegen: ClassCodegen, val classCodegen: ClassCodegen,
val inlinedInto: ExpressionCodegen?, val inlinedInto: ExpressionCodegen?,
val smap: SourceMapper, val smap: SourceMapper,
val delegatedPropertyOptimizer: DelegatedPropertyOptimizer?,
) : IrElementVisitor<PromisedValue, BlockInfo>, BaseExpressionCodegen { ) : IrElementVisitor<PromisedValue, BlockInfo>, BaseExpressionCodegen {
var finallyDepth = 0 var finallyDepth = 0
@@ -793,7 +792,7 @@ class ExpressionCodegen(
override fun visitClass(declaration: IrClass, data: BlockInfo): PromisedValue { override fun visitClass(declaration: IrClass, data: BlockInfo): PromisedValue {
if (declaration.origin != JvmLoweredDeclarationOrigin.CONTINUATION_CLASS) { if (declaration.origin != JvmLoweredDeclarationOrigin.CONTINUATION_CLASS) {
val childCodegen = ClassCodegen.getOrCreate(declaration, context, generateSequence(this) { it.inlinedInto }.last().irFunction) val childCodegen = ClassCodegen.getOrCreate(declaration, context, generateSequence(this) { it.inlinedInto }.last().irFunction)
childCodegen.generate(delegatedPropertyOptimizer) childCodegen.generate()
closureReifiedMarkers[declaration] = childCodegen.reifiedTypeParametersUsages closureReifiedMarkers[declaration] = childCodegen.reifiedTypeParametersUsages
} }
return unitValue return unitValue
@@ -46,14 +46,14 @@ class FunctionCodegen(
) { ) {
private val context = classCodegen.context private val context = classCodegen.context
fun generate(delegatedPropertyOptimizer: DelegatedPropertyOptimizer?): SMAPAndMethodNode = fun generate(): SMAPAndMethodNode =
try { try {
doGenerate(delegatedPropertyOptimizer) doGenerate()
} catch (e: Throwable) { } catch (e: Throwable) {
throw RuntimeException("Exception while generating code for:\n${irFunction.dump()}", e) throw RuntimeException("Exception while generating code for:\n${irFunction.dump()}", e)
} }
private fun doGenerate(delegatedPropertyOptimizer: DelegatedPropertyOptimizer?): SMAPAndMethodNode { private fun doGenerate(): SMAPAndMethodNode {
val signature = context.methodSignatureMapper.mapSignatureWithGeneric(irFunction) val signature = context.methodSignatureMapper.mapSignatureWithGeneric(irFunction)
val flags = irFunction.calculateMethodFlags() val flags = irFunction.calculateMethodFlags()
val methodNode = MethodNode( val methodNode = MethodNode(
@@ -104,7 +104,7 @@ class FunctionCodegen(
generateAnnotationDefaultValueIfNeeded(methodVisitor) generateAnnotationDefaultValueIfNeeded(methodVisitor)
SMAP(listOf()) SMAP(listOf())
} else if (notForInline != null) { } else if (notForInline != null) {
val (originalNode, smap) = classCodegen.generateMethodNode(notForInline, delegatedPropertyOptimizer) val (originalNode, smap) = classCodegen.generateMethodNode(notForInline)
originalNode.accept(MethodBodyVisitor(methodVisitor)) originalNode.accept(MethodBodyVisitor(methodVisitor))
smap smap
} else { } else {
@@ -113,16 +113,7 @@ class FunctionCodegen(
context.state.globalInlineContext.enterDeclaration(irFunction.suspendFunctionOriginal().toIrBasedDescriptor()) context.state.globalInlineContext.enterDeclaration(irFunction.suspendFunctionOriginal().toIrBasedDescriptor())
try { try {
val adapter = InstructionAdapter(methodVisitor) val adapter = InstructionAdapter(methodVisitor)
ExpressionCodegen( ExpressionCodegen(irFunction, signature, frameMap, adapter, classCodegen, inlinedInto, sourceMapper).generate()
irFunction,
signature,
frameMap,
adapter,
classCodegen,
inlinedInto,
sourceMapper,
delegatedPropertyOptimizer,
).generate()
} finally { } finally {
context.state.globalInlineContext.exitDeclaration() context.state.globalInlineContext.exitDeclaration()
} }
@@ -41,7 +41,7 @@ object IrInlineDefaultCodegen : IrInlineCallGenerator {
isInsideIfCondition: Boolean isInsideIfCondition: Boolean
) { ) {
val function = expression.symbol.owner val function = expression.symbol.owner
val nodeAndSmap = codegen.classCodegen.generateMethodNode(function, codegen.delegatedPropertyOptimizer) val nodeAndSmap = codegen.classCodegen.generateMethodNode(function)
val childSourceMapper = SourceMapCopier(codegen.smap, nodeAndSmap.classSMAP) val childSourceMapper = SourceMapCopier(codegen.smap, nodeAndSmap.classSMAP)
val argsSize = val argsSize =
@@ -94,16 +94,15 @@ class IrSourceCompilerForInline(
get() = codegen.smap get() = codegen.smap
override fun generateLambdaBody(lambdaInfo: ExpressionLambda): SMAPAndMethodNode = override fun generateLambdaBody(lambdaInfo: ExpressionLambda): SMAPAndMethodNode =
FunctionCodegen((lambdaInfo as IrExpressionLambdaImpl).function, codegen.classCodegen, codegen).generate(codegen.delegatedPropertyOptimizer) FunctionCodegen((lambdaInfo as IrExpressionLambdaImpl).function, codegen.classCodegen, codegen).generate()
override fun doCreateMethodNodeFromSource( override fun doCreateMethodNodeFromSource(
callableDescriptor: FunctionDescriptor, callableDescriptor: FunctionDescriptor,
jvmSignature: JvmMethodSignature, jvmSignature: JvmMethodSignature,
callDefault: Boolean, callDefault: Boolean,
asmMethod: Method asmMethod: Method
): SMAPAndMethodNode { ): SMAPAndMethodNode =
return ClassCodegen.getOrCreate(callee.parentAsClass, codegen.context).generateMethodNode(callee, null) ClassCodegen.getOrCreate(callee.parentAsClass, codegen.context).generateMethodNode(callee)
}
override fun hasFinallyBlocks() = data.hasFinallyBlocks() override fun hasFinallyBlocks() = data.hasFinallyBlocks()
@@ -115,7 +114,7 @@ class IrSourceCompilerForInline(
override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) = override fun createCodegenForExternalFinallyBlockGenerationOnNonLocalReturn(finallyNode: MethodNode, curFinallyDepth: Int) =
ExpressionCodegen( ExpressionCodegen(
codegen.irFunction, codegen.signature, codegen.frameMap, InstructionAdapter(finallyNode), codegen.classCodegen, codegen.irFunction, codegen.signature, codegen.frameMap, InstructionAdapter(finallyNode), codegen.classCodegen,
codegen.inlinedInto, codegen.smap, codegen.delegatedPropertyOptimizer codegen.inlinedInto, codegen.smap
).also { ).also {
it.finallyDepth = curFinallyDepth it.finallyDepth = curFinallyDepth
} }
@@ -0,0 +1,19 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM, JVM_MULTI_MODULE_IR_AGAINST_OLD
// FILE: test.kt
package test
import kotlin.reflect.KProperty
inline operator fun String.getValue(t:Any?, p: KProperty<*>): String = p.name + this
object C {
inline fun inlineFun() = {
val O by "K"
O
}()
}
// FILE: box.kt
import test.*
fun box(): String = C.inlineFun()
@@ -1739,6 +1739,11 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxInlineCo
runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
} }
@TestMetadata("localDeclaredInLambda.kt")
public void testLocalDeclaredInLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localDeclaredInLambda.kt");
}
@TestMetadata("localInAnonymousObject.kt") @TestMetadata("localInAnonymousObject.kt")
public void testLocalInAnonymousObject() throws Exception { public void testLocalInAnonymousObject() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
@@ -1739,6 +1739,11 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
} }
@TestMetadata("localDeclaredInLambda.kt")
public void testLocalDeclaredInLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localDeclaredInLambda.kt");
}
@TestMetadata("localInAnonymousObject.kt") @TestMetadata("localInAnonymousObject.kt")
public void testLocalInAnonymousObject() throws Exception { public void testLocalInAnonymousObject() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
@@ -1739,6 +1739,11 @@ public class IrBlackBoxInlineCodegenTestGenerated extends AbstractIrBlackBoxInli
runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
} }
@TestMetadata("localDeclaredInLambda.kt")
public void testLocalDeclaredInLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localDeclaredInLambda.kt");
}
@TestMetadata("localInAnonymousObject.kt") @TestMetadata("localInAnonymousObject.kt")
public void testLocalInAnonymousObject() throws Exception { public void testLocalInAnonymousObject() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
@@ -1739,6 +1739,11 @@ public class IrCompileKotlinAgainstInlineKotlinTestGenerated extends AbstractIrC
runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
} }
@TestMetadata("localDeclaredInLambda.kt")
public void testLocalDeclaredInLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localDeclaredInLambda.kt");
}
@TestMetadata("localInAnonymousObject.kt") @TestMetadata("localInAnonymousObject.kt")
public void testLocalInAnonymousObject() throws Exception { public void testLocalInAnonymousObject() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
@@ -1739,6 +1739,11 @@ public class JvmIrAgainstOldBoxInlineTestGenerated extends AbstractJvmIrAgainstO
runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
} }
@TestMetadata("localDeclaredInLambda.kt")
public void testLocalDeclaredInLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localDeclaredInLambda.kt");
}
@TestMetadata("localInAnonymousObject.kt") @TestMetadata("localInAnonymousObject.kt")
public void testLocalInAnonymousObject() throws Exception { public void testLocalInAnonymousObject() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
@@ -1739,6 +1739,11 @@ public class JvmOldAgainstIrBoxInlineTestGenerated extends AbstractJvmOldAgainst
runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
} }
@TestMetadata("localDeclaredInLambda.kt")
public void testLocalDeclaredInLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localDeclaredInLambda.kt");
}
@TestMetadata("localInAnonymousObject.kt") @TestMetadata("localInAnonymousObject.kt")
public void testLocalInAnonymousObject() throws Exception { public void testLocalInAnonymousObject() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
@@ -1574,6 +1574,11 @@ public class IrJsCodegenInlineES6TestGenerated extends AbstractIrJsCodegenInline
runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
} }
@TestMetadata("localDeclaredInLambda.kt")
public void testLocalDeclaredInLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localDeclaredInLambda.kt");
}
@TestMetadata("localInAnonymousObject.kt") @TestMetadata("localInAnonymousObject.kt")
public void testLocalInAnonymousObject() throws Exception { public void testLocalInAnonymousObject() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
@@ -1574,6 +1574,11 @@ public class IrJsCodegenInlineTestGenerated extends AbstractIrJsCodegenInlineTes
runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
} }
@TestMetadata("localDeclaredInLambda.kt")
public void testLocalDeclaredInLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localDeclaredInLambda.kt");
}
@TestMetadata("localInAnonymousObject.kt") @TestMetadata("localInAnonymousObject.kt")
public void testLocalInAnonymousObject() throws Exception { public void testLocalInAnonymousObject() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");
@@ -1574,6 +1574,11 @@ public class JsCodegenInlineTestGenerated extends AbstractJsCodegenInlineTest {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/local.kt");
} }
@TestMetadata("localDeclaredInLambda.kt")
public void testLocalDeclaredInLambda() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localDeclaredInLambda.kt");
}
@TestMetadata("localInAnonymousObject.kt") @TestMetadata("localInAnonymousObject.kt")
public void testLocalInAnonymousObject() throws Exception { public void testLocalInAnonymousObject() throws Exception {
runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt"); runTest("compiler/testData/codegen/boxInline/delegatedProperty/localInAnonymousObject.kt");