JVM_IR: Support inline suspend functions

Only no state-machine version for now.
This commit is contained in:
Ilmir Usmanov
2019-09-12 20:56:07 +03:00
parent 2ec3417e0e
commit 402a77126f
19 changed files with 20 additions and 24 deletions
@@ -54,6 +54,9 @@ internal fun generateStateMachineForNamedFunction(
element: KtElement element: KtElement
): MethodVisitor { ): MethodVisitor {
assert(irFunction.isSuspend) assert(irFunction.isSuspend)
assert(continuationClassBuilder != null) {
"Class builder for continuation is null"
}
val state = classCodegen.state val state = classCodegen.state
val languageVersionSettings = state.languageVersionSettings val languageVersionSettings = state.languageVersionSettings
assert(languageVersionSettings.isReleaseCoroutines()) { "Experimental coroutines are unsupported in JVM_IR backend" } assert(languageVersionSettings.isReleaseCoroutines()) { "Experimental coroutines are unsupported in JVM_IR backend" }
@@ -56,7 +56,7 @@ open class FunctionCodegen(
if (irFunction.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) { if (irFunction.origin != IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) {
AnnotationCodegen(classCodegen, context, methodVisitor::visitAnnotation).genAnnotations( AnnotationCodegen(classCodegen, context, methodVisitor::visitAnnotation).genAnnotations(
irFunction, functionView,
signature.asmMethod.returnType signature.asmMethod.returnType
) )
} }
@@ -70,7 +70,7 @@ open class FunctionCodegen(
//TODO: investigate this case: annotation here is generated twice in lowered function and in interface method overload //TODO: investigate this case: annotation here is generated twice in lowered function and in interface method overload
irFunction.origin == JvmLoweredDeclarationOrigin.GENERATED_SAM_IMPLEMENTATION irFunction.origin == JvmLoweredDeclarationOrigin.GENERATED_SAM_IMPLEMENTATION
) { ) {
generateParameterAnnotations(irFunction, methodVisitor, signature, classCodegen, context) generateParameterAnnotations(functionView, methodVisitor, signature, classCodegen, context)
} }
if (!state.classBuilderMode.generateBodies || flags.and(Opcodes.ACC_ABSTRACT) != 0 || irFunction.isExternal) { if (!state.classBuilderMode.generateBodies || flags.and(Opcodes.ACC_ABSTRACT) != 0 || irFunction.isExternal) {
@@ -82,8 +82,11 @@ open class FunctionCodegen(
?: context.suspendLambdaToOriginalFunctionMap[irFunction.parent]?.symbol?.descriptor?.psiElement) as? KtElement ?: context.suspendLambdaToOriginalFunctionMap[irFunction.parent]?.symbol?.descriptor?.psiElement) as? KtElement
val continuationClassBuilder = context.continuationClassBuilders[irClass] val continuationClassBuilder = context.continuationClassBuilders[irClass]
methodVisitor = when { methodVisitor = when {
// We do not generate continuation and state-machine for synthetic accessors, in a sence, they are tail-call irFunction.isSuspend &&
irFunction.isSuspend && irFunction.origin != JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR -> // We do not generate continuation and state-machine for synthetic accessors, in a sense, they are tail-call
!irFunction.isDefault() &&
// TODO: We should generate two versions of inline suspend function: one with state-machine and one without
!irFunction.isInline ->
generateStateMachineForNamedFunction( generateStateMachineForNamedFunction(
irFunction, classCodegen, methodVisitor, flags, signature, continuationClassBuilder, element!! irFunction, classCodegen, methodVisitor, flags, signature, continuationClassBuilder, element!!
) )
@@ -101,6 +104,9 @@ open class FunctionCodegen(
return signature return signature
} }
private fun IrFunction.isDefault(): Boolean =
origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || origin == JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR
private fun calculateMethodFlags(isStatic: Boolean): Int { private fun calculateMethodFlags(isStatic: Boolean): Int {
if (irFunction.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) { if (irFunction.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER) {
return Opcodes.ACC_PUBLIC or Opcodes.ACC_SYNTHETIC.let { return Opcodes.ACC_PUBLIC or Opcodes.ACC_SYNTHETIC.let {
@@ -94,8 +94,8 @@ class IrSourceCompilerForInline(
callDefault: Boolean, callDefault: Boolean,
asmMethod: Method asmMethod: Method
): SMAPAndMethodNode { ): SMAPAndMethodNode {
assert(callableDescriptor == callElement.descriptor.original) assert(callableDescriptor == callElement.descriptor.original) { "Expected $callableDescriptor got ${callElement.descriptor.original}" }
assert(codegen.lastLineNumber >= 0) assert(codegen.lastLineNumber >= 0) { "lastLineNumber shall be not negative, but is ${codegen.lastLineNumber}" }
val irFunction = getFunctionToInline(callElement as IrCall, jvmSignature, callDefault) val irFunction = getFunctionToInline(callElement as IrCall, jvmSignature, callDefault)
return makeInlineNode(irFunction, FakeClassCodegen(irFunction, codegen.classCodegen), CallSiteMarker(codegen.lastLineNumber)) return makeInlineNode(irFunction, FakeClassCodegen(irFunction, codegen.classCodegen), CallSiteMarker(codegen.lastLineNumber))
@@ -385,6 +385,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
} }
} }
// TODO: Generate two copies of inline suspend functions
private fun markSuspendFunctions(irFile: IrFile, suspendLambdas: Set<IrFunction>): Set<IrFunction> { private fun markSuspendFunctions(irFile: IrFile, suspendLambdas: Set<IrFunction>): Set<IrFunction> {
val result = hashSetOf<IrFunction>() val result = hashSetOf<IrFunction>()
@@ -395,7 +396,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
override fun visitFunction(declaration: IrFunction) { override fun visitFunction(declaration: IrFunction) {
super.visitFunction(declaration) super.visitFunction(declaration)
if (declaration.isSuspend && declaration !in suspendLambdas) { if (declaration.isSuspend && declaration !in suspendLambdas && !declaration.isInline) {
result.add(declaration) result.add(declaration)
} }
} }
@@ -1,5 +1,4 @@
// IGNORE_BACKEND: NATIVE // IGNORE_BACKEND: NATIVE
// IGNORE_BACKEND: JVM_IR
// WITH_REFLECT // WITH_REFLECT
// WITH_COROUTINES // WITH_COROUTINES
@@ -1,5 +1,4 @@
// KJS_WITH_FULL_RUNTIME // KJS_WITH_FULL_RUNTIME
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES
// COMMON_COROUTINES_TEST // COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES
// COMMON_COROUTINES_TEST // COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES
// COMMON_COROUTINES_TEST // COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES
// COMMON_COROUTINES_TEST // COMMON_COROUTINES_TEST
+2 -3
View File
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES
// COMMON_COROUTINES_TEST // COMMON_COROUTINES_TEST
@@ -20,8 +19,8 @@ fun box(): String {
var result = "" var result = ""
builder { builder {
result = try { suspendInlineThrow("OK") } catch (e: RuntimeException) { e.message!! } result = try { suspendInlineThrow("O") } catch (e: RuntimeException) { e.message!! }
// result = suspendInline("OK") result += suspendInline("K")
} }
return result return result
+1 -1
View File
@@ -1,5 +1,5 @@
// !LANGUAGE: +NewInference // !LANGUAGE: +NewInference
// IGNORE_BACKEND: JVM_IR, NATIVE // IGNORE_BACKEND: NATIVE
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// WITH_COROUTINES // WITH_COROUTINES
// WITH_RUNTIME // WITH_RUNTIME
// COMMON_COROUTINES_TEST // COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND: NATIVE // IGNORE_BACKEND: NATIVE
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES
// COMMON_COROUTINES_TEST // COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES
// COMMON_COROUTINES_TEST // COMMON_COROUTINES_TEST
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FULL_JDK // FULL_JDK
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR // IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: inline.kt // FILE: inline.kt
// COMMON_COROUTINES_TEST // COMMON_COROUTINES_TEST