JS IR: move inliner to common part; inline suspendCoroutineUninterceptedOrReturnJS

This commit is contained in:
Anton Bannykh
2019-06-17 18:57:26 +03:00
parent e3c9134904
commit d6c10d24e1
9 changed files with 76 additions and 60 deletions
@@ -179,6 +179,14 @@ abstract class Symbols<out T : CommonBackendContext>(val context: T, private val
abstract val getContinuation: IrSimpleFunctionSymbol abstract val getContinuation: IrSimpleFunctionSymbol
abstract val coroutineContextGetter: IrSimpleFunctionSymbol
abstract val suspendCoroutineUninterceptedOrReturn: IrSimpleFunctionSymbol
abstract val coroutineGetContext: IrSimpleFunctionSymbol
abstract val returnIfSuspended: IrSimpleFunctionSymbol
private val binaryOperatorCache = mutableMapOf<Triple<Name, KotlinType, KotlinType>, IrSimpleFunctionSymbol>() private val binaryOperatorCache = mutableMapOf<Triple<Name, KotlinType, KotlinType>, IrSimpleFunctionSymbol>()
fun getBinaryOperator(name: Name, lhsType: KotlinType, rhsType: KotlinType): IrSimpleFunctionSymbol { fun getBinaryOperator(name: Name, lhsType: KotlinType, rhsType: KotlinType): IrSimpleFunctionSymbol {
@@ -1,15 +1,15 @@
/* /*
* 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. * 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.inline package org.jetbrains.kotlin.backend.common.lower.inline
import org.jetbrains.kotlin.backend.common.CommonBackendContext
import org.jetbrains.kotlin.backend.common.descriptors.* import org.jetbrains.kotlin.backend.common.descriptors.*
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.IrCall
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.symbols.* import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.ir.visitors.acceptVoid
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
internal class DeepCopyIrTreeWithSymbolsForInliner( internal class DeepCopyIrTreeWithSymbolsForInliner(
val context: Context, val context: CommonBackendContext,
val typeArguments: Map<IrTypeParameterSymbol, IrType?>?, val typeArguments: Map<IrTypeParameterSymbol, IrType?>?,
val parent: IrDeclarationParent? val parent: IrDeclarationParent?
) { ) {
@@ -1,24 +1,19 @@
/* /*
* 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. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@file:Suppress("FoldInitializerAndIfToElvis") package org.jetbrains.kotlin.backend.common.lower.inline
package org.jetbrains.kotlin.ir.backend.js.lower.inline
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.ScopeWithIr
import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.ir.createTemporaryVariableWithWrappedDescriptor import org.jetbrains.kotlin.backend.common.ir.createTemporaryVariableWithWrappedDescriptor
import org.jetbrains.kotlin.backend.common.isBuiltInIntercepted import org.jetbrains.kotlin.backend.common.ir.Symbols
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.backend.common.lower.CoroutineIntrinsicLambdaOrigin import org.jetbrains.kotlin.backend.common.lower.CoroutineIntrinsicLambdaOrigin
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.ir.IrElement import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.IrStatement import org.jetbrains.kotlin.ir.IrStatement
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
import org.jetbrains.kotlin.ir.builders.irReturn import org.jetbrains.kotlin.ir.builders.irReturn
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
@@ -30,62 +25,47 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
typealias Context = JsIrBackendContext class FunctionInlining(val context: CommonBackendContext) : IrElementTransformerVoidWithContext() {
// backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/lower/FunctionInlining.kt fun inline(irModule: IrModuleFragment) = irModule.accept(this, data = null)
internal class FunctionInlining(val context: Context): IrElementTransformerVoidWithContext() {
//-------------------------------------------------------------------------//
fun inline(irModule: IrModuleFragment): IrElement {
return irModule.accept(this, data = null)
}
override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression { override fun visitFunctionAccess(expression: IrFunctionAccessExpression): IrExpression {
expression.transformChildrenVoid(this) expression.transformChildrenVoid(this)
val callee = when (expression) {
if (!(expression is IrCall || expression is IrConstructorCall) || !expression.symbol.owner.needsInlining) is IrCall -> expression.symbol.owner
is IrConstructorCall -> expression.symbol.owner
else -> return expression
}
if (!callee.needsInlining)
return expression
if (Symbols.isLateinitIsInitializedPropertyGetter(callee.symbol))
return expression return expression
val languageVersionSettings = context.configuration.languageVersionSettings val actualCallee = getFunctionDeclaration(callee.symbol)
when {
Symbols.isLateinitIsInitializedPropertyGetter(expression.symbol) ->
return expression
// Handle coroutine intrinsics
// TODO These should actually be inlined.
expression.descriptor.isBuiltInIntercepted(languageVersionSettings) ->
error("Continuation.intercepted is not available with release coroutines")
expression.symbol.descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
return irCall(expression, context.coroutineSuspendOrReturn)
expression.symbol == context.intrinsics.jsCoroutineContext ->
return irCall(expression, context.coroutineGetContextJs)
}
val callee = getFunctionDeclaration(expression.symbol) // Get declaration of the function to be inlined. actualCallee.transformChildrenVoid(this) // Process recursive inline.
callee.transformChildrenVoid(this) // Process recursive inline.
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull() val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
val inliner = Inliner(expression, callee, currentScope!!, parent, context) val inliner = Inliner(expression, actualCallee, currentScope!!, parent, context)
return inliner.inline() return inliner.inline()
} }
private fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction { private fun getFunctionDeclaration(symbol: IrFunctionSymbol): IrFunction {
// val descriptor = symbol.descriptor.original val descriptor = symbol.descriptor.original
// val languageVersionSettings = context.configuration.languageVersionSettings val languageVersionSettings = context.configuration.languageVersionSettings
// // TODO: Remove these hacks when coroutine intrinsics are fixed. // TODO: Remove these hacks when coroutine intrinsics are fixed.
// return when { return when {
// descriptor.isBuiltInIntercepted(languageVersionSettings) -> descriptor.isBuiltInIntercepted(languageVersionSettings) ->
// error("Continuation.intercepted is not available with release coroutines") error("Continuation.intercepted is not available with release coroutines")
//
// descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
// context.ir.symbols.konanSuspendCoroutineUninterceptedOrReturn.owner
//
// descriptor == context.ir.symbols.coroutineContextGetter ->
// context.ir.symbols.konanCoroutineContextGetter.owner
//
// else -> (symbol.owner as? IrSimpleFunction)?.resolveFakeOverride() ?: symbol.owner
// }
return (symbol.owner as? IrSimpleFunction)?.resolveFakeOverride() ?: symbol.owner descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
context.ir.symbols.suspendCoroutineUninterceptedOrReturn.owner
symbol == context.ir.symbols.coroutineContextGetter ->
context.ir.symbols.coroutineGetContext.owner
else -> (symbol.owner as? IrSimpleFunction)?.resolveFakeOverride() ?: symbol.owner
}
} }
private val IrFunction.needsInlining get() = (this.isInline && !this.isExternal) private val IrFunction.needsInlining get() = (this.isInline && !this.isExternal)
@@ -94,7 +74,7 @@ internal class FunctionInlining(val context: Context): IrElementTransformerVoidW
val callee: IrFunction, val callee: IrFunction,
val currentScope: ScopeWithIr, val currentScope: ScopeWithIr,
val parent: IrDeclarationParent?, val parent: IrDeclarationParent?,
val context: Context) { val context: CommonBackendContext) {
val copyIrElement = run { val copyIrElement = run {
val typeParameters = val typeParameters =
@@ -159,7 +159,8 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
// Coroutines // Coroutines
val jsCoroutineContext = context.symbolTable.referenceSimpleFunction(context.coroutineContextProperty.getter!!) val jsCoroutineContext
get() = context.ir.symbols.coroutineContextGetter
val jsGetContinuation = getInternalFunction("getContinuation") val jsGetContinuation = getInternalFunction("getContinuation")
val jsGetKClass = getInternalWithoutPackage("getKClass") val jsGetKClass = getInternalWithoutPackage("getKClass")
@@ -187,6 +187,14 @@ class JsIrBackendContext(
) )
override val getContinuation = symbolTable.referenceSimpleFunction(getJsInternalFunction("getContinuation")) override val getContinuation = symbolTable.referenceSimpleFunction(getJsInternalFunction("getContinuation"))
override val coroutineContextGetter = symbolTable.referenceSimpleFunction(context.coroutineContextProperty.getter!!)
override val suspendCoroutineUninterceptedOrReturn = symbolTable.referenceSimpleFunction(getJsInternalFunction(COROUTINE_SUSPEND_OR_RETURN_JS_NAME))
override val coroutineGetContext = symbolTable.referenceSimpleFunction(getJsInternalFunction(GET_COROUTINE_CONTEXT_NAME))
override val returnIfSuspended = symbolTable.referenceSimpleFunction(getJsInternalFunction("returnIfSuspended"))
} }
override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true
@@ -213,7 +221,7 @@ class JsIrBackendContext(
// Top-level functions forced to be loaded // Top-level functions forced to be loaded
val coroutineSuspendOrReturn = symbolTable.referenceSimpleFunction(getJsInternalFunction(COROUTINE_SUSPEND_OR_RETURN_JS_NAME)) val coroutineSuspendOrReturn = ir.symbols.suspendCoroutineUninterceptedOrReturn
val coroutineSuspendGetter = ir.symbols.coroutineSuspendedGetter val coroutineSuspendGetter = ir.symbols.coroutineSuspendedGetter
val coroutineGetContext: IrSimpleFunctionSymbol val coroutineGetContext: IrSimpleFunctionSymbol
get() { get() {
@@ -223,7 +231,9 @@ class JsIrBackendContext(
return contextGetter.symbol return contextGetter.symbol
} }
val coroutineGetContextJs = symbolTable.referenceSimpleFunction(getJsInternalFunction(GET_COROUTINE_CONTEXT_NAME)) val coroutineGetContextJs
get() = ir.symbols.coroutineGetContext
val coroutineEmptyContinuation = symbolTable.referenceField(getProperty(FqName.fromSegments(listOf("kotlin", "coroutines", "js", "internal", "EmptyContinuation")))) val coroutineEmptyContinuation = symbolTable.referenceField(getProperty(FqName.fromSegments(listOf("kotlin", "coroutines", "js", "internal", "EmptyContinuation"))))
val coroutineContextProperty: PropertyDescriptor val coroutineContextProperty: PropertyDescriptor
@@ -7,11 +7,11 @@ package org.jetbrains.kotlin.ir.backend.js
import org.jetbrains.kotlin.backend.common.* import org.jetbrains.kotlin.backend.common.*
import org.jetbrains.kotlin.backend.common.lower.* import org.jetbrains.kotlin.backend.common.lower.*
import org.jetbrains.kotlin.backend.common.lower.inline.FunctionInlining
import org.jetbrains.kotlin.backend.common.phaser.* import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.ir.backend.js.lower.* import org.jetbrains.kotlin.ir.backend.js.lower.*
import org.jetbrains.kotlin.ir.backend.js.lower.calls.CallsLowering import org.jetbrains.kotlin.ir.backend.js.lower.calls.CallsLowering
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.JsSuspendFunctionsLowering import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.JsSuspendFunctionsLowering
import org.jetbrains.kotlin.ir.backend.js.lower.inline.FunctionInlining
import org.jetbrains.kotlin.ir.backend.js.lower.inline.RemoveInlineFunctionsWithReifiedTypeParametersLowering import org.jetbrains.kotlin.ir.backend.js.lower.inline.RemoveInlineFunctionsWithReifiedTypeParametersLowering
import org.jetbrains.kotlin.ir.backend.js.lower.inline.ReturnableBlockLowering import org.jetbrains.kotlin.ir.backend.js.lower.inline.ReturnableBlockLowering
import org.jetbrains.kotlin.ir.declarations.IrFile import org.jetbrains.kotlin.ir.declarations.IrFile
@@ -155,6 +155,11 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
context.continuation context.continuation
} }
add(backendContext.ir.symbols.returnIfSuspended) { call, context ->
val args = translateCallArguments(call, context)
args[0]
}
add(intrinsics.jsCoroutineContext) { _, context: JsGenerationContext -> add(intrinsics.jsCoroutineContext) { _, context: JsGenerationContext ->
val contextGetter = backendContext.coroutineGetContext val contextGetter = backendContext.coroutineGetContext
val getterName = context.getNameForStaticFunction(contextGetter.owner) val getterName = context.getNameForStaticFunction(contextGetter.owner)
@@ -96,6 +96,18 @@ class JvmSymbols(
override val getContinuation: IrSimpleFunctionSymbol override val getContinuation: IrSimpleFunctionSymbol
get() = TODO("not implemented") get() = TODO("not implemented")
override val coroutineContextGetter: IrSimpleFunctionSymbol
get() = TODO("not implemented")
override val suspendCoroutineUninterceptedOrReturn: IrSimpleFunctionSymbol
get() = TODO("not implemented")
override val coroutineGetContext: IrSimpleFunctionSymbol
get() = TODO("not implemented")
override val returnIfSuspended: IrSimpleFunctionSymbol
get() = TODO("not implemented")
val javaLangClass: IrClassSymbol = val javaLangClass: IrClassSymbol =
if (firMode) createClass(FqName("java.lang.Class")) {}.symbol else context.getTopLevelClass(FqName("java.lang.Class")) if (firMode) createClass(FqName("java.lang.Class")) {}.symbol else context.getTopLevelClass(FqName("java.lang.Class"))