Introduce add continuation pass, which transforms each suspend function
and call to have additional continuation parameter.
This commit is contained in:
+14
-2
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.ReceiverParameterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBasedDeclarationDescriptor
|
||||
@@ -452,7 +453,18 @@ open class WrappedSimpleFunctionDescriptor(
|
||||
override fun <V : Any?> getUserData(key: CallableDescriptor.UserDataKey<V>?): V? = null
|
||||
|
||||
override fun newCopyBuilder(): FunctionDescriptor.CopyBuilder<out SimpleFunctionDescriptor> {
|
||||
TODO("not implemented")
|
||||
return SimpleFunctionDescriptorImpl
|
||||
.create(containingDeclaration, annotations, name, kind, source)
|
||||
.initialize(
|
||||
extensionReceiverParameter,
|
||||
dispatchReceiverParameter,
|
||||
typeParameters,
|
||||
valueParameters,
|
||||
returnType,
|
||||
modality,
|
||||
visibility,
|
||||
null
|
||||
).newCopyBuilder()
|
||||
}
|
||||
|
||||
override fun <R, D> accept(visitor: DeclarationDescriptorVisitor<R, D>?, data: D) =
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -12,16 +12,19 @@ import org.jetbrains.kotlin.backend.jvm.descriptors.JvmDeclarationFactory
|
||||
import org.jetbrains.kotlin.backend.jvm.descriptors.JvmSharedVariablesManager
|
||||
import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.coroutinesPackageFqName
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.util.ReferenceSymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi2ir.PsiSourceManager
|
||||
|
||||
class JvmBackendContext(
|
||||
@@ -48,6 +51,16 @@ class JvmBackendContext(
|
||||
|
||||
override val internalPackageFqn = FqName("kotlin.jvm")
|
||||
|
||||
val transformedSuspendFunctionsCache = mutableMapOf<IrSimpleFunction, IrSimpleFunction>()
|
||||
|
||||
private val coroutinePackage = state.module.getPackage(state.languageVersionSettings.coroutinesPackageFqName())
|
||||
|
||||
val continuationClass = symbolTable.referenceClass(
|
||||
coroutinePackage.memberScope.getContributedClassifier(
|
||||
Name.identifier("Continuation"), NoLookupLocation.FROM_BACKEND
|
||||
) as ClassDescriptor
|
||||
)
|
||||
|
||||
internal fun getTopLevelClass(fqName: FqName): IrClassSymbol {
|
||||
val descriptor = state.module.getPackage(fqName.parent()).memberScope.getContributedClassifier(
|
||||
fqName.shortName(), NoLookupLocation.FROM_BACKEND
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.backend.jvm
|
||||
@@ -129,6 +118,7 @@ val jvmPhases = namedIrFilePhase<JvmBackendContext>(
|
||||
singletonReferencesPhase then
|
||||
localDeclarationsPhase then
|
||||
singleAbstractMethodPhase then
|
||||
addContinuationPhase then
|
||||
callableReferencePhase then
|
||||
functionNVarargInvokePhase then
|
||||
|
||||
|
||||
+11
-1
@@ -1,18 +1,27 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.codegen
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.createType
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_SYNTHETIC_ANNOTATION_FQ_NAME
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.STRICTFP_ANNOTATION_FQ_NAME
|
||||
@@ -20,6 +29,7 @@ import org.jetbrains.kotlin.resolve.jvm.annotations.SYNCHRONIZED_ANNOTATION_FQ_N
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
|
||||
+198
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* 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.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.WrappedValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
|
||||
import org.jetbrains.kotlin.backend.common.ir.isSuspend
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.createType
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import java.util.*
|
||||
|
||||
// TODO: Move to common prefix
|
||||
internal val addContinuationPhase = makeIrFilePhase(
|
||||
::AddContinuationLowering,
|
||||
"AddContinuation",
|
||||
"Add continuation parameter to suspend functions and suspend calls"
|
||||
)
|
||||
|
||||
private class AddContinuationLowering(private val context: JvmBackendContext) : FileLoweringPass {
|
||||
object CONTINUATION_PARAMETER : IrDeclarationOriginImpl("CONTINUATION_PARAMETER")
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
val suspendLambdas = markSuspendLambdas(irFile)
|
||||
addContinuationParameter(irFile)
|
||||
transformSuspendCalls(irFile, suspendLambdas)
|
||||
}
|
||||
|
||||
private fun addContinuationParameter(irFile: IrFile) {
|
||||
fun tryAddContinuationParameter(element: IrElement): List<IrDeclaration>? {
|
||||
return if (element is IrSimpleFunction && element.isSuspend) {
|
||||
listOf(element.getOrCreateView())
|
||||
} else null
|
||||
}
|
||||
|
||||
irFile.transformDeclarationsFlat(::tryAddContinuationParameter)
|
||||
irFile.acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
declaration.acceptChildrenVoid(this)
|
||||
declaration.transformDeclarationsFlat(::tryAddContinuationParameter)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun markSuspendLambdas(irElement: IrElement): List<IrFunction> {
|
||||
val suspendLambdas = arrayListOf<IrFunction>()
|
||||
irElement.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference) {
|
||||
expression.acceptChildrenVoid(this)
|
||||
|
||||
if (expression.isSuspend) {
|
||||
suspendLambdas += expression.symbol.owner
|
||||
}
|
||||
}
|
||||
})
|
||||
return suspendLambdas
|
||||
}
|
||||
|
||||
private fun transformSuspendCalls(irFile: IrFile, suspendLambdas: List<IrFunction>) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
private val functionStack = Stack<IrFunction>()
|
||||
|
||||
override fun visitElement(element: IrElement): IrElement {
|
||||
element.transformChildrenVoid(this)
|
||||
return element
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||
functionStack.push(declaration)
|
||||
val res = super.visitFunction(declaration)
|
||||
functionStack.pop()
|
||||
return res
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
if (!expression.isSuspend) return super.visitCall(expression)
|
||||
val caller = functionStack.peek()
|
||||
val continuationArgument = IrGetValueImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
continuationType(caller.returnType),
|
||||
if (caller in suspendLambdas) (caller.dispatchReceiverParameter as IrValueParameter).symbol
|
||||
else caller.valueParameters.last().symbol
|
||||
)
|
||||
val view = (expression.symbol.owner as IrSimpleFunction).getOrCreateView()
|
||||
val res = IrCallImpl(expression.startOffset, expression.endOffset, expression.type, view.symbol).apply {
|
||||
copyTypeArgumentsFrom(expression)
|
||||
dispatchReceiver = expression.dispatchReceiver
|
||||
for (i in 0 until expression.valueArgumentsCount) {
|
||||
putValueArgument(i, expression.getValueArgument(i))
|
||||
}
|
||||
putValueArgument(expression.valueArgumentsCount, continuationArgument)
|
||||
}
|
||||
return super.visitCall(res)
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||
if (!expression.isSuspend) return super.visitFunctionReference(expression)
|
||||
val view = (expression.symbol.owner as IrSimpleFunction).getOrCreateView()
|
||||
val res = IrFunctionReferenceImpl(
|
||||
expression.startOffset,
|
||||
expression.endOffset,
|
||||
expression.type,
|
||||
view.symbol,
|
||||
view.descriptor,
|
||||
expression.typeArgumentsCount,
|
||||
expression.origin
|
||||
).apply {
|
||||
copyTypeArgumentsFrom(expression)
|
||||
dispatchReceiver = expression.dispatchReceiver
|
||||
for (i in 0 until expression.valueArgumentsCount) {
|
||||
putValueArgument(i, expression.getValueArgument(i))
|
||||
}
|
||||
}
|
||||
return super.visitFunctionReference(res)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.getOrCreateView(): IrSimpleFunction =
|
||||
context.transformedSuspendFunctionsCache.getOrPut(this) {
|
||||
IrFunctionImpl(
|
||||
startOffset, endOffset, origin, getOrCreateJvmSuspendFunctionView(descriptor, context.state), returnType
|
||||
).also {
|
||||
it.parent = parent
|
||||
it.copyTypeParametersFrom(this)
|
||||
|
||||
it.dispatchReceiverParameter = dispatchReceiverParameter?.copyTo(it)
|
||||
|
||||
valueParameters.mapTo(it.valueParameters) { p -> p.copyTo(it) }
|
||||
it.valueParameters += createContinuationValueParameter(it.valueParameters.size, returnType).apply { parent = it }
|
||||
|
||||
// Fix links to parameters
|
||||
val valueParametersMapping = (valueParameters + dispatchReceiverParameter)
|
||||
.zip(it.valueParameters.dropLast(1) + it.dispatchReceiverParameter).toMap()
|
||||
it.body = body?.deepCopyWithSymbols(this)
|
||||
it.body?.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue) =
|
||||
valueParametersMapping[expression.symbol.owner]?.let { newParam ->
|
||||
expression.run { IrGetValueImpl(startOffset, endOffset, type, newParam.symbol, origin) }
|
||||
} ?: expression
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun createContinuationValueParameter(index: Int, returnType: IrType): IrValueParameter {
|
||||
val descriptor = WrappedValueParameterDescriptor()
|
||||
return IrValueParameterImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
CONTINUATION_PARAMETER,
|
||||
IrValueParameterSymbolImpl(descriptor),
|
||||
Name.identifier("\$completion"),
|
||||
index,
|
||||
continuationType(returnType),
|
||||
null, isCrossinline = false, isNoinline = false
|
||||
).also {
|
||||
descriptor.bind(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun continuationType(returnType: IrType) = context.continuationClass.createType(
|
||||
hasQuestionMark = false,
|
||||
arguments = listOf(makeTypeProjection(returnType, Variance.INVARIANT))
|
||||
)
|
||||
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
// COMMON_COROUTINES_TEST
|
||||
|
||||
Reference in New Issue
Block a user