Do not generate $$forInline suffix for enclosing method

in OUTERCLASS field.

The inliner generates two versions of suspend functions/lambdas in
inline functions: with state-machine and without. The former is used
to call the function from Java or via reflection and have ordinary
name, while the latter is used by inliner and have $$forInline suffix.
The inliner throws the state-machine version away, duplicates
$$forInline version and then call state-machine generator.

If these suspend functions/lambdas are not going to be inlined,
$$forInline version is not generated. However, all objects, which are
used in these suspend functions/lambdas, have $$forInline version
written to OUTERCLASS field. This leads to errors by proguard.
Since they are used in both state-machine version and for-inline ones,
we can simply remove $$forInline suffix from OUTERCLASS field and this
fixes the issue.

 #KT-31242 Fixed
This commit is contained in:
Ilmir Usmanov
2019-04-30 21:23:38 +03:00
parent dd6bc100ed
commit effbcdaf70
8 changed files with 126 additions and 32 deletions
@@ -10,7 +10,9 @@ import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.coroutines.DEBUG_METADATA_ANNOTATION_ASM_TYPE
import org.jetbrains.kotlin.codegen.coroutines.isCapturedSuspendLambda
import org.jetbrains.kotlin.codegen.coroutines.isCoroutineSuperClass
import org.jetbrains.kotlin.codegen.coroutines.isResumeImplMethodName
import org.jetbrains.kotlin.codegen.inline.coroutines.CoroutineTransformer
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
import org.jetbrains.kotlin.codegen.serialization.JvmCodegenStringTable
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.kotlin.FileBasedKotlinClass
@@ -244,7 +246,14 @@ class AnonymousObjectTransformer(
private fun writeOuterInfo(visitor: ClassVisitor) {
val info = inliningContext.callSiteInfo
visitor.visitOuterClass(info.ownerClassName, info.functionName, info.functionDesc)
// Since $$forInline functions are not generated if retransformation is the last one (i.e. call site is not inline)
// link to the function in OUTERCLASS field becomes invalid. However, since $$forInline function always has no-inline
// companion without the suffix, use it.
if (info.isSuspend && info.isInlineOrInsideInline) {
visitor.visitOuterClass(info.ownerClassName, info.functionName?.removeSuffix(FOR_INLINE_SUFFIX), info.functionDesc)
} else {
visitor.visitOuterClass(info.ownerClassName, info.functionName, info.functionDesc)
}
}
private fun inlineMethodAndUpdateGlobalResult(
@@ -288,7 +297,8 @@ class AnonymousObjectTransformer(
transformationInfo.oldClassName,
sourceNode.name,
if (isConstructor) transformationInfo.newConstructorDescriptor else sourceNode.desc,
inliningContext.callSiteInfo.isInlineOrInsideInline
inliningContext.callSiteInfo.isInlineOrInsideInline,
isSuspendFunctionOrLambda(sourceNode)
), null
)
@@ -298,6 +308,12 @@ class AnonymousObjectTransformer(
return result
}
private fun isSuspendFunctionOrLambda(sourceNode: MethodNode): Boolean =
(sourceNode.desc.endsWith(";Lkotlin/coroutines/Continuation;)Ljava/lang/Object;") ||
sourceNode.desc.endsWith(";Lkotlin/coroutines/experimental/Continuation;)Ljava/lang/Object;")) &&
(CoroutineTransformer.findFakeContinuationConstructorClassName(sourceNode) != null ||
languageVersionSettings.isResumeImplMethodName(sourceNode.name.removeSuffix(FOR_INLINE_SUFFIX)))
private fun generateConstructorAndFields(
classBuilder: ClassBuilder,
allCapturedBuilder: ParametersBuilder,
@@ -1,19 +1,14 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.codegen.inline
class InlineCallSiteInfo(val ownerClassName: String, val functionName: String?, val functionDesc: String?, val isInlineOrInsideInline: Boolean)
class InlineCallSiteInfo(
val ownerClassName: String,
val functionName: String?,
val functionDesc: String?,
val isInlineOrInsideInline: Boolean,
val isSuspend: Boolean
)
@@ -1,5 +1,5 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
@@ -122,7 +122,11 @@ class PsiSourceCompilerForInline(private val codegen: ExpressionCodegen, overrid
val signature = codegen.state.typeMapper.mapSignatureSkipGeneric(context.functionDescriptor, context.contextKind)
return InlineCallSiteInfo(
parentCodegen.className, signature.asmMethod.name, signature.asmMethod.descriptor, compilationContextFunctionDescriptor.isInlineOrInsideInline()
parentCodegen.className,
signature.asmMethod.name,
signature.asmMethod.descriptor,
compilationContextFunctionDescriptor.isInlineOrInsideInline(),
compilationContextFunctionDescriptor.isSuspend
)
}