JVM_IR: Fix bridges generation for suspend functions

Use view's signature as jvm signature.
This commit is contained in:
Ilmir Usmanov
2019-12-24 21:01:50 +01:00
parent 2507e2b526
commit d17afddaa9
11 changed files with 112 additions and 23 deletions
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
import org.jetbrains.kotlin.backend.common.ir.copyValueParametersInsertingContinuationFrom
import org.jetbrains.kotlin.backend.common.ir.isSuspend
import org.jetbrains.kotlin.backend.common.lower.VariableRemapper
import org.jetbrains.kotlin.backend.common.lower.allOverridden
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.codegen.ClassBuilder
@@ -71,8 +72,8 @@ internal fun generateStateMachineForNamedFunction(
internalNameForDispatchReceiver = classCodegen.visitor.thisName,
putContinuationParameterToLvt = false,
disableTailCallOptimizationForFunctionReturningUnit = irFunction.returnType.isUnit() &&
(irFunction as? IrSimpleFunction)?.overriddenSymbols?.let { symbols ->
symbols.isNotEmpty() && symbols.any { !it.owner.returnType.isUnit() }
(irFunction as? IrSimpleFunction)?.allOverridden()?.toList()?.let { functions ->
functions.isNotEmpty() && functions.any { !it.returnType.isUnit() }
} == true
)
}
@@ -135,10 +136,10 @@ internal fun IrFunction.getOrCreateSuspendFunctionViewIfNeeded(context: JvmBacke
if (!isSuspend || origin == JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW ||
origin == JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW
) return this
return context.suspendFunctionOriginalToView[this] ?: suspendFunctionView(context)
return context.suspendFunctionOriginalToView[this] ?: suspendFunctionView(context, true)
}
private fun IrFunction.suspendFunctionView(context: JvmBackendContext): IrFunction {
fun IrFunction.suspendFunctionView(context: JvmBackendContext, generateBody: Boolean): IrFunction {
require(this.isSuspend && this is IrSimpleFunction)
// For SuspendFunction{N}.invoke we need to generate INVOKEINTERFACE Function{N+1}.invoke(...Ljava/lang/Object;)...
// instead of INVOKEINTERFACE Function{N+1}.invoke(...Lkotlin/coroutines/Continuation;)...
@@ -175,19 +176,21 @@ private fun IrFunction.suspendFunctionView(context: JvmBackendContext): IrFuncti
continuationValueParam = it.addValueParameter(SUSPEND_FUNCTION_COMPLETION_PARAMETER_NAME, continuationType)
}
// Add the suspend function view to the map before transforming the body to make sure
// that recursive suspend functions do not lead to unbounded recursion at compile time.
context.recordSuspendFunctionView(this, it)
if (generateBody) {
// Add the suspend function view to the map before transforming the body to make sure
// that recursive suspend functions do not lead to unbounded recursion at compile time.
context.recordSuspendFunctionView(this, it)
val valueParametersMapping = explicitParameters.zip(it.explicitParameters.filter { it != continuationValueParam }).toMap()
it.body = body?.deepCopyWithSymbols(this)
it.body?.transformChildrenVoid(object : VariableRemapper(valueParametersMapping) {
// Do not cross class boundaries inside functions. Otherwise, callable references will try to access wrong $completion.
override fun visitClass(declaration: IrClass): IrStatement = declaration
val valueParametersMapping = explicitParameters.zip(it.explicitParameters.filter { it != continuationValueParam }).toMap()
it.body = body?.deepCopyWithSymbols(this)
it.body?.transformChildrenVoid(object : VariableRemapper(valueParametersMapping) {
// Do not cross class boundaries inside functions. Otherwise, callable references will try to access wrong $completion.
override fun visitClass(declaration: IrClass): IrStatement = declaration
override fun visitCall(expression: IrCall): IrExpression =
super.visitCall(expression.createSuspendFunctionCallViewIfNeeded(context, it, callerIsInlineLambda = false))
})
override fun visitCall(expression: IrCall): IrExpression =
super.visitCall(expression.createSuspendFunctionCallViewIfNeeded(context, it, callerIsInlineLambda = false))
})
}
}
}
@@ -208,6 +208,13 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
}
}
if (function.isSuspend && function.origin != JvmLoweredDeclarationOrigin.SUSPEND_FUNCTION_VIEW &&
function.origin != JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE_CAPTURES_CROSSINLINE_VIEW &&
(function.parent as? IrClass)?.origin != JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
) {
return mapSignature(function.suspendFunctionView(context, false), skipGenericSignature)
}
val sw = if (skipGenericSignature) JvmSignatureWriter() else BothSignatureWriter(BothSignatureWriter.Mode.METHOD)
typeMapper.writeFormalTypeParameters(function.typeParameters, sw)
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// WITH_RUNTIME
// WITH_COROUTINES
@@ -0,0 +1,87 @@
@kotlin.Metadata
public interface Base {
public abstract @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
}
@kotlin.Metadata
@kotlin.coroutines.jvm.internal.DebugMetadata
final class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1$1 {
field L$0: java.lang.Object
field label: int
@org.jetbrains.annotations.NotNull field result: java.lang.Object
synthetic final field this$0: Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1
public method <init>(p0: Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1, p1: kotlin.coroutines.Continuation): void
public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object
}
@kotlin.Metadata
public final class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1$2 {
inner class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1
inner class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1$2
public method <init>(): void
public synthetic @org.jetbrains.annotations.Nullable method invoke(): java.lang.Object
public final method invoke(): void
}
@kotlin.Metadata
public final class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1 {
inner class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1
inner class Override5Kt$box$1$invokeSuspend$$inlined$inlineMe$1$2
public method <init>(): void
public @org.jetbrains.annotations.Nullable method generic$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
public @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
}
@kotlin.coroutines.jvm.internal.DebugMetadata
@kotlin.Metadata
final class Override5Kt$box$1 {
private field label: int
inner class Override5Kt$box$1
public method <init>(p0: kotlin.coroutines.Continuation): void
public final @org.jetbrains.annotations.NotNull method create(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): kotlin.coroutines.Continuation
public final method invoke(p0: java.lang.Object): java.lang.Object
public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object
}
@kotlin.Metadata
@kotlin.coroutines.jvm.internal.DebugMetadata
final class Override5Kt$inlineMe$1$generic$1 {
field L$0: java.lang.Object
field label: int
@org.jetbrains.annotations.NotNull field result: java.lang.Object
private field this$0: Override5Kt$inlineMe$1
public method <init>(p0: Override5Kt$inlineMe$1, p1: kotlin.coroutines.Continuation): void
public final @org.jetbrains.annotations.Nullable method invokeSuspend(@org.jetbrains.annotations.NotNull p0: java.lang.Object): java.lang.Object
}
@kotlin.Metadata
public final class Override5Kt$inlineMe$1$generic$2 {
inner class Override5Kt$inlineMe$1
inner class Override5Kt$inlineMe$1$generic$2
public method <init>(): void
public synthetic @org.jetbrains.annotations.Nullable method invoke(): java.lang.Object
public final method invoke(): void
}
@kotlin.Metadata
public final class Override5Kt$inlineMe$1 {
private synthetic final field $c: kotlin.jvm.functions.Function1
inner class Override5Kt$inlineMe$1
inner class Override5Kt$inlineMe$1$generic$2
public method <init>(p0: kotlin.jvm.functions.Function1): void
public @org.jetbrains.annotations.Nullable method generic$$forInline(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
public @org.jetbrains.annotations.Nullable method generic(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.Continuation): java.lang.Object
}
@kotlin.Metadata
public final class Override5Kt {
private static field c: kotlin.coroutines.Continuation
inner class Override5Kt$box$1
inner class Override5Kt$inlineMe$1
public final static method <clinit>(): void
public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String
public final static method builder(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): void
public final static @org.jetbrains.annotations.Nullable method getC(): kotlin.coroutines.Continuation
public final static @org.jetbrains.annotations.NotNull method inlineMe(@org.jetbrains.annotations.NotNull p0: kotlin.jvm.functions.Function1): Base
public final static method setC(@org.jetbrains.annotations.Nullable p0: kotlin.coroutines.Continuation): void
}
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// WITH_RUNTIME
// WITH_COROUTINES
@@ -1,6 +1,5 @@
// IGNORE_BACKEND_FIR: JVM_IR
// TARGET_BACKEND: JVM
// IGNORE_BACKEND: JVM_IR
// FULL_JDK
// WITH_RUNTIME
// WITH_COROUTINES