JVM: add inline lambdas' captured parameters to constructor first
This makes the code a bit cleaner, but has no effect other than that.
This commit is contained in:
+13
-25
@@ -511,30 +511,20 @@ class AnonymousObjectTransformer(
|
|||||||
val capturedOuterThisTypes = mutableSetOf<String>()
|
val capturedOuterThisTypes = mutableSetOf<String>()
|
||||||
for (info in capturedLambdas) {
|
for (info in capturedLambdas) {
|
||||||
for (desc in info.capturedVars) {
|
for (desc in info.capturedVars) {
|
||||||
// Merge all outer `this` of the same type captured by inlined lambdas, since they have to be the same
|
val recapturedParamInfo = constructorParamBuilder.addCapturedParam(
|
||||||
// object. Outer `this` captured by the original object itself should have been renamed above,
|
desc,
|
||||||
// and can have a different value even if the same type is captured by a lambda.
|
// Merge all outer `this` of the same type captured by inlined lambdas, since they have to be the same
|
||||||
val recapturedParamInfo = if (isThis0(desc.fieldName))
|
// object. Outer `this` captured by the original object itself should have been renamed above,
|
||||||
capturedParamBuilder.addCapturedParam(desc, desc.fieldName, !capturedOuterThisTypes.add(desc.type.className))
|
// and can have a different value even if the same type is captured by a lambda.
|
||||||
else
|
if (isThis0(desc.fieldName)) desc.fieldName else addUniqueField(desc.fieldName + INLINE_TRANSFORMATION_SUFFIX),
|
||||||
capturedParamBuilder.addCapturedParam(desc, addUniqueField(desc.fieldName + INLINE_TRANSFORMATION_SUFFIX), false)
|
(isThis0(desc.fieldName) && !capturedOuterThisTypes.add(desc.type.className))
|
||||||
|
)
|
||||||
if (desc.isSuspend) {
|
if (desc.isSuspend) {
|
||||||
recapturedParamInfo.functionalArgument = NonInlineArgumentForInlineSuspendParameter.INLINE_LAMBDA_AS_VARIABLE
|
recapturedParamInfo.functionalArgument = NonInlineArgumentForInlineSuspendParameter.INLINE_LAMBDA_AS_VARIABLE
|
||||||
}
|
}
|
||||||
val composed = StackValue.field(
|
capturedParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.newFieldName).remapValue =
|
||||||
desc.type,
|
StackValue.field(desc.type, oldObjectType, recapturedParamInfo.newFieldName, false, StackValue.LOCAL_0)
|
||||||
oldObjectType, /*TODO owner type*/
|
|
||||||
recapturedParamInfo.newFieldName,
|
|
||||||
false,
|
|
||||||
StackValue.LOCAL_0
|
|
||||||
)
|
|
||||||
recapturedParamInfo.remapValue = composed
|
|
||||||
allRecapturedParameters.add(desc)
|
allRecapturedParameters.add(desc)
|
||||||
|
|
||||||
// DO NOT assign a remap value to the constructor parameter - this would cause the inliner to miscount
|
|
||||||
// the arguments, eventually generating code that overwrites some of these captures with other stuff.
|
|
||||||
// Plus we don't really want to remap local loads to field reads anyway, the latter are faster.
|
|
||||||
constructorParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.newFieldName).remapValue = null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (capturedLambdas.isNotEmpty()) {
|
} else if (capturedLambdas.isNotEmpty()) {
|
||||||
@@ -545,12 +535,10 @@ class AnonymousObjectTransformer(
|
|||||||
?: throw AssertionError("Expecting RegeneratedLambdaFieldRemapper, but ${parentFieldRemapper.parent}")
|
?: throw AssertionError("Expecting RegeneratedLambdaFieldRemapper, but ${parentFieldRemapper.parent}")
|
||||||
val ownerType = Type.getObjectType(parent.originalLambdaInternalName)
|
val ownerType = Type.getObjectType(parent.originalLambdaInternalName)
|
||||||
val desc = CapturedParamDesc(ownerType, AsmUtil.THIS, ownerType)
|
val desc = CapturedParamDesc(ownerType, AsmUtil.THIS, ownerType)
|
||||||
val recapturedParamInfo = capturedParamBuilder.addCapturedParam(desc, AsmUtil.CAPTURED_THIS_FIELD/*outer lambda/object*/, false)
|
val recapturedParamInfo =
|
||||||
val composed = StackValue.LOCAL_0
|
constructorParamBuilder.addCapturedParam(desc, AsmUtil.CAPTURED_THIS_FIELD/*outer lambda/object*/, false)
|
||||||
recapturedParamInfo.remapValue = composed
|
capturedParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.newFieldName).remapValue = StackValue.LOCAL_0
|
||||||
allRecapturedParameters.add(desc)
|
allRecapturedParameters.add(desc)
|
||||||
|
|
||||||
constructorParamBuilder.addCapturedParam(recapturedParamInfo, recapturedParamInfo.newFieldName).remapValue = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
transformationInfo.allRecapturedParameters = allRecapturedParameters
|
transformationInfo.allRecapturedParameters = allRecapturedParameters
|
||||||
|
|||||||
+3
-7
@@ -172,13 +172,9 @@ class LocalDeclarationsLowering(
|
|||||||
val capturedValueToField: MutableMap<IrValueDeclaration, PotentiallyUnusedField> = mutableMapOf()
|
val capturedValueToField: MutableMap<IrValueDeclaration, PotentiallyUnusedField> = mutableMapOf()
|
||||||
|
|
||||||
override fun irGet(startOffset: Int, endOffset: Int, valueDeclaration: IrValueDeclaration): IrExpression? {
|
override fun irGet(startOffset: Int, endOffset: Int, valueDeclaration: IrValueDeclaration): IrExpression? {
|
||||||
// On the JVM backend, `AnonymousObjectTransformer` in the bytecode inliner uses field assignment
|
// TODO: this used to be a hack for the JVM bytecode inliner (which misbehaved when inline lambdas had no fields),
|
||||||
// instructions to find captured parameters. Most of the time this is unimportant, as captured
|
// but it's no longer necessary. It is only here for backwards compatibility with old kotlinc versions
|
||||||
// parameters are effectively indistinguishable from normal ones; the exception is ones that can
|
// and can be removed, probably in 1.9.
|
||||||
// take an inline lambda value, as the parameter needs to be replaced with the lambda's capture.
|
|
||||||
// Thus we cannot erase the field - the inliner won't handle the inline lambda without it.
|
|
||||||
// (Most of the time this is inconsequential - if the object really is instantiated with an inline
|
|
||||||
// lambda, the field will be erased completely regardless of whether it's used.)
|
|
||||||
if (!forceFieldsForInlineCaptures || !valueDeclaration.isInlineDeclaration()) {
|
if (!forceFieldsForInlineCaptures || !valueDeclaration.isInlineDeclaration()) {
|
||||||
// We're in the initializer scope, which will be moved to a primary constructor later.
|
// We're in the initializer scope, which will be moved to a primary constructor later.
|
||||||
// Thus we can directly use that constructor's context and read from a parameter instead of a field.
|
// Thus we can directly use that constructor's context and read from a parameter instead of a field.
|
||||||
|
|||||||
Reference in New Issue
Block a user