From 7b2edc6de849c302f4e74468e5a362b404833d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Steven=20Sch=C3=A4fer?= Date: Fri, 5 Jul 2019 15:29:18 +0200 Subject: [PATCH] Extract simple inlining utility from ArrayConstructorLowering --- .../kotlin/backend/common/ir/IrInlineUtils.kt | 51 +++++++++++++++++++ .../common/lower/ArrayConstructorLowering.kt | 51 +++++-------------- .../kotlin/backend/common/lower/LowerUtils.kt | 2 +- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 4 +- 4 files changed, 68 insertions(+), 40 deletions(-) create mode 100644 compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrInlineUtils.kt diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrInlineUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrInlineUtils.kt new file mode 100644 index 00000000000..0e5adb5ba68 --- /dev/null +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/ir/IrInlineUtils.kt @@ -0,0 +1,51 @@ +/* + * 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.common.ir + +import org.jetbrains.kotlin.backend.common.lower.VariableRemapper +import org.jetbrains.kotlin.ir.declarations.IrFunction +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl +import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl +import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl +import org.jetbrains.kotlin.ir.util.isVararg +import org.jetbrains.kotlin.ir.util.statements + +// Return the underlying function for a lambda argument without bound or default parameters or varargs. +fun IrExpression.asSimpleLambda(): IrSimpleFunction? { + // A lambda is represented as a block with a function declaration and a reference to it. + if (this !is IrBlock || statements.size != 2) + return null + val (function, reference) = statements + if (function !is IrSimpleFunction || reference !is IrFunctionReference || function.symbol != reference.symbol) + return null + if ((0 until reference.valueArgumentsCount).any { reference.getValueArgument(it) != null }) + return null + if (function.valueParameters.any { it.isVararg || it.defaultValue != null }) + return null + return function +} + +// TODO use a generic inliner (e.g. JS/Native's FunctionInlining.Inliner) +// Inline simple function calls without type parameters, default parameters, or varargs. +fun IrFunction.inline(arguments: List = listOf()): IrReturnableBlock { + require(body != null) + val argumentMap = valueParameters.zip(arguments).toMap() + val blockSymbol = IrReturnableBlockSymbolImpl(descriptor) + val block = IrReturnableBlockImpl(startOffset, endOffset, returnType, blockSymbol, null, symbol) + val remapper = object : VariableRemapper(argumentMap) { + override fun visitReturn(expression: IrReturn): IrExpression = super.visitReturn( + if (expression.returnTargetSymbol == symbol) + IrReturnImpl(expression.startOffset, expression.endOffset, expression.type, blockSymbol, expression.value) + else + expression + ) + } + body!!.statements.mapTo(block.statements) { it.transform(remapper, null) } + return block +} diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ArrayConstructorLowering.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ArrayConstructorLowering.kt index b1c0c1b33b3..2ec7f11a433 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ArrayConstructorLowering.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/ArrayConstructorLowering.kt @@ -8,16 +8,22 @@ package org.jetbrains.kotlin.backend.common.lower import org.jetbrains.kotlin.backend.common.CommonBackendContext import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext +import org.jetbrains.kotlin.backend.common.ir.asSimpleLambda +import org.jetbrains.kotlin.backend.common.ir.inline import org.jetbrains.kotlin.ir.builders.* -import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.expressions.* -import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl -import org.jetbrains.kotlin.ir.expressions.impl.IrReturnableBlockImpl +import org.jetbrains.kotlin.ir.declarations.IrConstructor +import org.jetbrains.kotlin.ir.declarations.IrFile +import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction +import org.jetbrains.kotlin.ir.expressions.IrConstructorCall +import org.jetbrains.kotlin.ir.expressions.IrExpression +import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol -import org.jetbrains.kotlin.ir.symbols.impl.IrReturnableBlockSymbolImpl import org.jetbrains.kotlin.ir.types.getClass import org.jetbrains.kotlin.ir.types.toKotlinType -import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.util.constructedClass +import org.jetbrains.kotlin.ir.util.constructors +import org.jetbrains.kotlin.ir.util.functions +import org.jetbrains.kotlin.ir.util.patchDeclarationParents import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.util.OperatorNameConventions @@ -38,15 +44,10 @@ class ArrayConstructorLowering(val context: CommonBackendContext) : IrElementTra } private fun IrExpression.asSingleArgumentLambda(): IrSimpleFunction? { - // A lambda is represented as a block with a function declaration and a reference to it. - if (this !is IrBlock || statements.size != 2) - return null - val (function, reference) = statements - if (function !is IrSimpleFunction || reference !is IrFunctionReference || function.symbol != reference.symbol) - return null + val function = asSimpleLambda() ?: return null // Only match the one that has exactly one non-vararg argument, as the code below // does not handle defaults or varargs. - if (function.valueParameters.size != 1 || function.valueParameters[0].isVararg || reference.getValueArgument(0) != null) + if (function.valueParameters.size != 1) return null return function } @@ -105,28 +106,4 @@ class ArrayConstructorLowering(val context: CommonBackendContext) : IrElementTra it.patchDeclarationParents(scope.getLocalDeclarationParent()) } } - - // TODO use a generic inliner (e.g. JS/Native's FunctionInlining.Inliner) - private fun IrFunction.inline(arguments: List): IrReturnableBlock { - val argumentMap = valueParameters.zip(arguments).toMap() - val blockSymbol = IrReturnableBlockSymbolImpl(descriptor) - val block = IrReturnableBlockImpl(startOffset, endOffset, returnType, blockSymbol, null, symbol) - val remapper = object : AbstractVariableRemapper() { - override fun remapVariable(value: IrValueDeclaration): IrValueDeclaration? = - argumentMap[value] - - override fun visitReturn(expression: IrReturn): IrExpression = super.visitReturn( - if (expression.returnTargetSymbol == symbol) - IrReturnImpl(expression.startOffset, expression.endOffset, expression.type, blockSymbol, expression.value) - else - expression - ) - } - when (val transformed = body?.transform(remapper, null)) { - is IrBlockBody -> block.statements += transformed.statements - is IrExpressionBody -> block.statements += transformed.expression - else -> throw AssertionError("unexpected body type: $this") - } - return block - } } diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt index e79691dc927..49cbbdfc201 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/LowerUtils.kt @@ -61,7 +61,7 @@ abstract class AbstractVariableRemapper : IrElementTransformerVoid() { } ?: expression } -class VariableRemapper(val mapping: Map) : AbstractVariableRemapper() { +open class VariableRemapper(val mapping: Map) : AbstractVariableRemapper() { override fun remapVariable(value: IrValueDeclaration): IrValueDeclaration? = mapping[value] } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index 1e1808e083b..9370a42c10f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -203,8 +203,8 @@ val IrBody.statements: List get() = when (this) { is IrBlockBody -> statements is IrExpressionBody -> listOf(expression) - is IrSyntheticBody -> error("Synthetic body contains no statements $this") - else -> error("Unknown subclass of IrBody") + is IrSyntheticBody -> error("Synthetic body contains no statements: $this") + else -> error("Unknown subclass of IrBody: $this") } val IrClass.defaultType: IrSimpleType