Move Js suspend functions lowerings to common code
This commit is contained in:
committed by
Space Team
parent
7d8636aac4
commit
8886e1b8b4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2022 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.
|
||||
*/
|
||||
|
||||
@@ -243,6 +243,8 @@ class JsIrBackendContext(
|
||||
|
||||
override val getContinuation = symbolTable.referenceSimpleFunction(getJsInternalFunction("getContinuation"))
|
||||
|
||||
override val continuationClass = context.coroutineSymbols.continuationClass
|
||||
|
||||
override val coroutineContextGetter =
|
||||
symbolTable.referenceSimpleFunction(context.coroutineSymbols.coroutineContextProperty.getter!!)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2022 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.
|
||||
*/
|
||||
|
||||
@@ -7,6 +7,8 @@ package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.coroutines.AddContinuationToLocalSuspendFunctionsLowering
|
||||
import org.jetbrains.kotlin.backend.common.lower.coroutines.AddContinuationToNonLocalSuspendFunctionsLowering
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.FunctionInlining
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesExtractionFromInlineFunctionsLowering
|
||||
import org.jetbrains.kotlin.backend.common.lower.inline.LocalClassesInInlineFunctionsLowering
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2022 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.
|
||||
*/
|
||||
|
||||
@@ -31,9 +31,6 @@ class JsMapping : DefaultMapping() {
|
||||
val fieldToEnumEntry = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrField, IrEnumEntry>()
|
||||
val enumClassToInitEntryInstancesFun = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrSimpleFunction>()
|
||||
|
||||
val suspendFunctionsToFunctionWithContinuations =
|
||||
DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrSimpleFunction, IrSimpleFunction>()
|
||||
|
||||
val suspendArityStore = DefaultDelegateFactory.newDeclarationToDeclarationCollectionMapping<IrClass, Collection<IrSimpleFunction>>()
|
||||
|
||||
// Wasm mappings
|
||||
|
||||
+14
-66
@@ -1,79 +1,27 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2022 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.ir.backend.js.lower.coroutines
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||
import org.jetbrains.kotlin.backend.common.lower.coroutines.AbstractAddContinuationToFunctionCallsLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.util.irCall
|
||||
import org.jetbrains.kotlin.ir.util.isSuspend
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
|
||||
/**
|
||||
* Add continuation to suspend function calls. Requires [AddContinuationToLocalSuspendFunctionsLowering] and
|
||||
* Requires [AddContinuationToLocalSuspendFunctionsLowering] and
|
||||
* [AddContinuationToNonLocalSuspendFunctionsLowering] to transform function declarations first.
|
||||
*
|
||||
* Additionally materialize continuation for `getContinuation` intrinsic calls.
|
||||
*/
|
||||
class AddContinuationToFunctionCallsLowering(val context: JsCommonBackendContext) : BodyLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
runOnFilePostfix(irFile, withLocalDeclarations = true)
|
||||
}
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
val continuation: IrValueParameter by lazy {
|
||||
val function = container as IrSimpleFunction
|
||||
if (function.overriddenSymbols
|
||||
.any { it.owner.name.asString() == "doResume" && it.owner.parent == context.coroutineSymbols.coroutineImpl.owner }
|
||||
) {
|
||||
function.dispatchReceiverParameter!!
|
||||
} else {
|
||||
function.valueParameters.last()
|
||||
class AddContinuationToFunctionCallsLowering(override val context: JsCommonBackendContext) : AbstractAddContinuationToFunctionCallsLowering() {
|
||||
override fun IrSimpleFunction.getContinuationParameter(): IrValueParameter =
|
||||
if (overriddenSymbols.any {
|
||||
it.owner.name.asString() == "doResume" && it.owner.parent == context.coroutineSymbols.coroutineImpl.owner
|
||||
}
|
||||
) {
|
||||
dispatchReceiverParameter!!
|
||||
} else {
|
||||
valueParameters.last()
|
||||
}
|
||||
|
||||
val builder by lazy { context.createIrBuilder(container.symbol) }
|
||||
fun getContinuation() = builder.irGet(continuation)
|
||||
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitBody(body: IrBody): IrBody {
|
||||
// Nested bodies are covered by separate `lower` invocation
|
||||
return body
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
|
||||
if (!expression.isSuspend) {
|
||||
if (expression.symbol == context.ir.symbols.getContinuation)
|
||||
return getContinuation()
|
||||
return expression
|
||||
}
|
||||
|
||||
val oldFun = expression.symbol.owner
|
||||
// TODO: investigate why mapping might be unavailable for SuspendFunction4.invoke
|
||||
val newFun: IrSimpleFunction = oldFun.getOrCreateFunctionWithContinuationStub(context)
|
||||
|
||||
return irCall(
|
||||
expression,
|
||||
newFun.symbol,
|
||||
newReturnType = newFun.returnType,
|
||||
newSuperQualifierSymbol = expression.superQualifierSymbol
|
||||
).also {
|
||||
it.putValueArgument(it.valueArgumentsCount - 1, getContinuation())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-132
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.ir.backend.js.lower.coroutines
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||
import org.jetbrains.kotlin.backend.common.ir.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.builders.irReturnUnit
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrReturn
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
/**
|
||||
* Replaces suspend functions with regular non-suspend functions with additional
|
||||
* continuation parameter `$cont` of type [kotlin.coroutines.Continuation].
|
||||
*
|
||||
* Replaces return type with `Any?` or `Any` (for non-nullable types) to indicate that suspend
|
||||
* functions can return special values like [kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED]
|
||||
* which might not be a subtype of original return type.
|
||||
*/
|
||||
class AddContinuationToNonLocalSuspendFunctionsLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? =
|
||||
if (declaration is IrSimpleFunction && declaration.isSuspend) {
|
||||
listOf(transformSuspendFunction(context, declaration))
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to [AddContinuationToNonLocalSuspendFunctionsLowering] but processes local functions.
|
||||
* Useful for Kotlin/JS IR backend which keeps local declarations up until code generation.
|
||||
*/
|
||||
class AddContinuationToLocalSuspendFunctionsLowering(val context: JsCommonBackendContext) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction): IrStatement {
|
||||
declaration.transformChildrenVoid()
|
||||
return if (declaration.isSuspend) {
|
||||
transformSuspendFunction(context, declaration)
|
||||
} else {
|
||||
declaration
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun transformSuspendFunction(context: JsCommonBackendContext, function: IrSimpleFunction): IrSimpleFunction {
|
||||
val newFunctionWithContinuation = function.getOrCreateFunctionWithContinuationStub(context)
|
||||
// Using custom mapping because number of parameters doesn't match
|
||||
val parameterMapping = function.explicitParameters.zip(newFunctionWithContinuation.explicitParameters).toMap()
|
||||
val newBody = function.moveBodyTo(newFunctionWithContinuation, parameterMapping)
|
||||
|
||||
// Since we are changing return type to Any, function can no longer return unit implicitly.
|
||||
if (
|
||||
function.returnType == context.irBuiltIns.unitType &&
|
||||
newBody is IrBlockBody &&
|
||||
newBody.statements.lastOrNull() !is IrReturn
|
||||
) {
|
||||
// Adding explicit return of Unit.
|
||||
newBody.statements += context.createIrBuilder(newFunctionWithContinuation.symbol).irReturnUnit()
|
||||
}
|
||||
|
||||
newFunctionWithContinuation.body = newBody
|
||||
return newFunctionWithContinuation
|
||||
}
|
||||
|
||||
|
||||
fun IrSimpleFunction.getOrCreateFunctionWithContinuationStub(context: JsCommonBackendContext): IrSimpleFunction {
|
||||
return context.mapping.suspendFunctionsToFunctionWithContinuations.getOrPut(this) {
|
||||
createSuspendFunctionStub(context)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.createSuspendFunctionStub(context: JsCommonBackendContext): IrSimpleFunction {
|
||||
require(this.isSuspend)
|
||||
return factory.buildFun {
|
||||
updateFrom(this@createSuspendFunctionStub)
|
||||
isSuspend = false
|
||||
name = this@createSuspendFunctionStub.name
|
||||
origin = IrDeclarationOrigin.LOWERED_SUSPEND_FUNCTION
|
||||
returnType = loweredSuspendFunctionReturnType(this@createSuspendFunctionStub, context.irBuiltIns)
|
||||
}.also { function ->
|
||||
function.parent = parent
|
||||
|
||||
function.annotations += annotations
|
||||
function.metadata = metadata
|
||||
|
||||
function.copyAttributes(this)
|
||||
function.copyTypeParametersFrom(this)
|
||||
val substitutionMap = makeTypeParameterSubstitutionMap(this, function)
|
||||
function.copyReceiverParametersFrom(this, substitutionMap)
|
||||
|
||||
function.overriddenSymbols += overriddenSymbols.map {
|
||||
it.owner.getOrCreateFunctionWithContinuationStub(context).symbol
|
||||
}
|
||||
function.valueParameters = valueParameters.map { it.copyTo(function) }
|
||||
|
||||
val mapping = mutableMapOf<IrValueSymbol, IrValueSymbol>()
|
||||
valueParameters.forEach { mapping[it.symbol] = function.valueParameters[it.index].symbol }
|
||||
val remapper = ValueRemapper(mapping)
|
||||
function.valueParameters.forEach { it.defaultValue = it.defaultValue?.transform(remapper, null) }
|
||||
|
||||
function.addValueParameter(
|
||||
"\$cont",
|
||||
continuationType(context).substitute(substitutionMap),
|
||||
IrDeclarationOrigin.CONTINUATION
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.continuationType(context: JsCommonBackendContext): IrType {
|
||||
return context.coroutineSymbols.continuationClass.typeWith(returnType)
|
||||
}
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2022 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.
|
||||
*/
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.backend.common.lower.FinallyBlocksLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.backend.common.lower.ReturnableBlockTransformer
|
||||
import org.jetbrains.kotlin.backend.common.lower.coroutines.loweredSuspendFunctionReturnType
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
|
||||
+1
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Copyright 2010-2022 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.
|
||||
*/
|
||||
|
||||
@@ -111,6 +111,3 @@ class LiveLocalsTransformer(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun loweredSuspendFunctionReturnType(function: IrFunction, irBuiltIns: IrBuiltIns): IrType =
|
||||
if (function.returnType.isNullable()) irBuiltIns.anyNType else irBuiltIns.anyType
|
||||
Reference in New Issue
Block a user