Support default lambda inlining in IR

This commit is contained in:
Mikhael Bogdanov
2019-11-15 08:59:28 +01:00
parent 8adac2d1ea
commit ac31e0e8c7
43 changed files with 170 additions and 88 deletions
@@ -130,16 +130,16 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
fun performInline( fun performInline(
typeArguments: List<TypeParameterMarker>?, typeArguments: List<TypeParameterMarker>?,
callDefault: Boolean, inlineDefaultLambdas: Boolean,
typeSystem: TypeSystemCommonBackendContext, mapDefaultSignature: Boolean,
codegen: BaseExpressionCodegen typeSystem: TypeSystemCommonBackendContext
) { ) {
var nodeAndSmap: SMAPAndMethodNode? = null var nodeAndSmap: SMAPAndMethodNode? = null
try { try {
nodeAndSmap = createInlineMethodNode( nodeAndSmap = createInlineMethodNode(
functionDescriptor, methodOwner, jvmSignature, callDefault, typeArguments, typeSystem, state, sourceCompiler functionDescriptor, methodOwner, jvmSignature, mapDefaultSignature, typeArguments, typeSystem, state, sourceCompiler
) )
endCall(inlineCall(nodeAndSmap, callDefault)) endCall(inlineCall(nodeAndSmap, inlineDefaultLambdas))
} catch (e: CompilationException) { } catch (e: CompilationException) {
throw e throw e
} catch (e: InlineException) { } catch (e: InlineException) {
@@ -210,16 +210,12 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
?: error("No stack value for continuation parameter of suspend function") ?: error("No stack value for continuation parameter of suspend function")
} }
protected fun inlineCall(nodeAndSmap: SMAPAndMethodNode, callDefault: Boolean): InlineResult { protected fun inlineCall(nodeAndSmap: SMAPAndMethodNode, inlineDefaultLambda: Boolean): InlineResult {
assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" } assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" }
defaultSourceMapper.callSiteMarker = CallSiteMarker(codegen.lastLineNumber) defaultSourceMapper.callSiteMarker = CallSiteMarker(codegen.lastLineNumber)
val node = nodeAndSmap.node val node = nodeAndSmap.node
if (callDefault) { if (inlineDefaultLambda) {
val defaultLambdas = expandMaskConditionsAndUpdateVariableNodes( for (lambda in extractDefaultLambdas(node)) {
node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex,
extractDefaultLambdaOffsetAndDescriptor(jvmSignature, functionDescriptor)
)
for (lambda in defaultLambdas) {
invocationParamBuilder.buildParameters().getParameterByDeclarationSlot(lambda.offset).functionalArgument = lambda invocationParamBuilder.buildParameters().getParameterByDeclarationSlot(lambda.offset).functionalArgument = lambda
val prev = expressionMap.put(lambda.offset, lambda) val prev = expressionMap.put(lambda.offset, lambda)
assert(prev == null) { "Lambda with offset ${lambda.offset} already exists: $prev" } assert(prev == null) { "Lambda with offset ${lambda.offset} already exists: $prev" }
@@ -283,6 +279,8 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
return result return result
} }
abstract fun extractDefaultLambdas(node: MethodNode): List<DefaultLambda>
fun generateAndInsertFinallyBlocks( fun generateAndInsertFinallyBlocks(
intoNode: MethodNode, intoNode: MethodNode,
insertPoints: List<MethodInliner.PointForExternalFinallyBlocks>, insertPoints: List<MethodInliner.PointForExternalFinallyBlocks>,
@@ -486,7 +484,9 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
if (kind !== ValueKind.DEFAULT_MASK && kind !== ValueKind.METHOD_HANDLE_IN_DEFAULT) { if (kind !== ValueKind.DEFAULT_MASK && kind !== ValueKind.METHOD_HANDLE_IN_DEFAULT) {
return false return false
} }
assert(value is StackValue.Constant) { "Additional default method argument should be constant, but " + value } assert(value is StackValue.Constant) {
"Additional default method argument should be constant, but " + value
}
val constantValue = (value as StackValue.Constant).value val constantValue = (value as StackValue.Constant).value
if (kind === ValueKind.DEFAULT_MASK) { if (kind === ValueKind.DEFAULT_MASK) {
assert(constantValue is Int) { "Mask should be of Integer type, but " + constantValue } assert(constantValue is Int) { "Mask should be of Integer type, but " + constantValue }
@@ -714,6 +714,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
return NestedSourceMapper(parent, nodeAndSmap.sortedRanges, nodeAndSmap.classSMAP.sourceInfo) return NestedSourceMapper(parent, nodeAndSmap.sortedRanges, nodeAndSmap.classSMAP.sourceInfo)
} }
} }
} }
val BaseExpressionCodegen.v: InstructionAdapter val BaseExpressionCodegen.v: InstructionAdapter
@@ -85,7 +85,20 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgu
class NonInlineableArgumentForInlineableParameterCalledInSuspend(val isSuspend: Boolean) : FunctionalArgument class NonInlineableArgumentForInlineableParameterCalledInSuspend(val isSuspend: Boolean) : FunctionalArgument
object NonInlineableArgumentForInlineableSuspendParameter : FunctionalArgument object NonInlineableArgumentForInlineableSuspendParameter : FunctionalArgument
class DefaultLambda(
class PsiDefaultLambda(
lambdaClassType: Type,
capturedArgs: Array<Type>,
parameterDescriptor: ValueParameterDescriptor,
offset: Int,
needReification: Boolean
) : DefaultLambda(lambdaClassType, capturedArgs, parameterDescriptor, offset, needReification) {
override fun mapAsmSignature(sourceCompiler: SourceCompilerForInline): Method {
return sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod
}
}
abstract class DefaultLambda(
override val lambdaClassType: Type, override val lambdaClassType: Type,
private val capturedArgs: Array<Type>, private val capturedArgs: Array<Type>,
val parameterDescriptor: ValueParameterDescriptor, val parameterDescriptor: ValueParameterDescriptor,
@@ -93,17 +106,17 @@ class DefaultLambda(
val needReification: Boolean val needReification: Boolean
) : LambdaInfo(parameterDescriptor.isCrossinline) { ) : LambdaInfo(parameterDescriptor.isCrossinline) {
override var isBoundCallableReference by Delegates.notNull<Boolean>() final override var isBoundCallableReference by Delegates.notNull<Boolean>()
private set private set
val parameterOffsetsInDefault: MutableList<Int> = arrayListOf() val parameterOffsetsInDefault: MutableList<Int> = arrayListOf()
override lateinit var invokeMethod: Method final override lateinit var invokeMethod: Method
private set private set
override lateinit var invokeMethodDescriptor: FunctionDescriptor override lateinit var invokeMethodDescriptor: FunctionDescriptor
override lateinit var capturedVars: List<CapturedParamDesc> final override lateinit var capturedVars: List<CapturedParamDesc>
private set private set
override fun isReturnFromMe(labelName: String): Boolean = false override fun isReturnFromMe(labelName: String): Boolean = false
@@ -168,12 +181,13 @@ class DefaultLambda(
isBoundCallableReference = (isFunctionReference || isPropertyReference) && capturedVars.isNotEmpty() isBoundCallableReference = (isFunctionReference || isPropertyReference) && capturedVars.isNotEmpty()
val methodName = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString() val methodName = (if (isPropertyReference) OperatorNameConventions.GET else OperatorNameConventions.INVOKE).asString()
val signature = sourceCompiler.state.typeMapper.mapSignatureSkipGeneric(invokeMethodDescriptor).asmMethod.descriptor
val signature = mapAsmSignature(sourceCompiler)
node = getMethodNode( node = getMethodNode(
classReader.b, classReader.b,
methodName, methodName,
signature, signature.descriptor,
lambdaClassType, lambdaClassType,
signatureAmbiguity = true signatureAmbiguity = true
) ?: error("Can't find method '$methodName$signature' in '${classReader.className}'") ) ?: error("Can't find method '$methodName$signature' in '${classReader.className}'")
@@ -185,6 +199,8 @@ class DefaultLambda(
reifiedTypeInliner.reifyInstructions(node.node) reifiedTypeInliner.reifyInstructions(node.node)
} }
} }
protected abstract fun mapAsmSignature(sourceCompiler: SourceCompilerForInline): Method
} }
internal fun Type.boxReceiverForBoundReference() = internal fun Type.boxReceiverForBoundReference() =
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.tree.MethodNode
class PsiInlineCodegen( class PsiInlineCodegen(
codegen: ExpressionCodegen, codegen: ExpressionCodegen,
@@ -64,7 +65,7 @@ class PsiInlineCodegen(
return return
} }
try { try {
performInline(resolvedCall?.typeArguments?.keys?.toList(), callDefault, codegen.typeSystem, codegen) performInline(resolvedCall?.typeArguments?.keys?.toList(), callDefault, callDefault, codegen.typeSystem)
} finally { } finally {
state.globalInlineContext.exitFromInliningOf(resolvedCall) state.globalInlineContext.exitFromInliningOf(resolvedCall)
} }
@@ -193,4 +194,12 @@ class PsiInlineCodegen(
delayedHiddenWriting!!.invoke() delayedHiddenWriting!!.invoke()
delayedHiddenWriting = null delayedHiddenWriting = null
} }
override fun extractDefaultLambdas(node: MethodNode): List<DefaultLambda> {
return expandMaskConditionsAndUpdateVariableNodes(
node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex,
extractDefaultLambdaOffsetAndDescriptor(jvmSignature, functionDescriptor),
::PsiDefaultLambda
)
}
} }
@@ -61,13 +61,14 @@ fun extractDefaultLambdaOffsetAndDescriptor(
} }
fun expandMaskConditionsAndUpdateVariableNodes( fun <T, R : DefaultLambda> expandMaskConditionsAndUpdateVariableNodes(
node: MethodNode, node: MethodNode,
maskStartIndex: Int, maskStartIndex: Int,
masks: List<Int>, masks: List<Int>,
methodHandlerIndex: Int, methodHandlerIndex: Int,
defaultLambdas: Map<Int, ValueParameterDescriptor> defaultLambdas: Map<Int, T>,
): List<DefaultLambda> { lambdaConstructor: (Type, Array<Type>, T, Int, Boolean) -> R
): List<R> {
fun isMaskIndex(varIndex: Int): Boolean { fun isMaskIndex(varIndex: Int): Boolean {
return maskStartIndex <= varIndex && varIndex < maskStartIndex + masks.size return maskStartIndex <= varIndex && varIndex < maskStartIndex + masks.size
} }
@@ -110,7 +111,7 @@ fun expandMaskConditionsAndUpdateVariableNodes(
val toDelete = linkedSetOf<AbstractInsnNode>() val toDelete = linkedSetOf<AbstractInsnNode>()
val toInsert = arrayListOf<Pair<AbstractInsnNode, AbstractInsnNode>>() val toInsert = arrayListOf<Pair<AbstractInsnNode, AbstractInsnNode>>()
val defaultLambdasInfo = extractDefaultLambdasInfo(conditions, defaultLambdas, toDelete, toInsert) val defaultLambdasInfo = extractDefaultLambdasInfo(conditions, defaultLambdas, toDelete, toInsert, lambdaConstructor)
val indexToVarNode = node.localVariables?.filter { it.index < maskStartIndex }?.associateBy { it.index } ?: emptyMap() val indexToVarNode = node.localVariables?.filter { it.index < maskStartIndex }?.associateBy { it.index } ?: emptyMap()
conditions.forEach { conditions.forEach {
@@ -137,12 +138,13 @@ fun expandMaskConditionsAndUpdateVariableNodes(
} }
private fun extractDefaultLambdasInfo( private fun <T, R : DefaultLambda> extractDefaultLambdasInfo(
conditions: List<Condition>, conditions: List<Condition>,
defaultLambdas: Map<Int, ValueParameterDescriptor>, defaultLambdas: Map<Int, T>,
toDelete: MutableCollection<AbstractInsnNode>, toDelete: MutableCollection<AbstractInsnNode>,
toInsert: MutableList<Pair<AbstractInsnNode, AbstractInsnNode>> toInsert: MutableList<Pair<AbstractInsnNode, AbstractInsnNode>>,
): List<DefaultLambda> { lambdaConstructor: (Type, Array<Type>, T, Int, Boolean) -> R
): List<R> {
val defaultLambdaConditions = conditions.filter { it.expandNotDelete && defaultLambdas.contains(it.varIndex) } val defaultLambdaConditions = conditions.filter { it.expandNotDelete && defaultLambdas.contains(it.varIndex) }
return defaultLambdaConditions.map { return defaultLambdaConditions.map {
val varAssignmentInstruction = it.varInsNode!! val varAssignmentInstruction = it.varInsNode!!
@@ -186,7 +188,7 @@ private fun extractDefaultLambdasInfo(
toInsert.add(varAssignmentInstruction to defaultLambdaFakeCallStub(argTypes, it.varIndex)) toInsert.add(varAssignmentInstruction to defaultLambdaFakeCallStub(argTypes, it.varIndex))
DefaultLambda(owner, argTypes, defaultLambdas[it.varIndex]!!, it.varIndex, needReification) lambdaConstructor(owner, argTypes, defaultLambdas[it.varIndex]!!, it.varIndex, needReification)
} }
} }
@@ -985,7 +985,7 @@ class ExpressionCodegen(
override fun toKotlinType(type: IrType): KotlinType = type.toKotlinType() override fun toKotlinType(type: IrType): KotlinType = type.toKotlinType()
}, IrTypeCheckerContext(context.irBuiltIns), state.languageVersionSettings) }, IrTypeCheckerContext(context.irBuiltIns), state.languageVersionSettings)
return IrInlineCodegen(this, state, callee.descriptor, methodOwner, signature, mappings, sourceCompiler, reifiedTypeInliner) return IrInlineCodegen(this, state, callee, methodOwner, signature, mappings, sourceCompiler, reifiedTypeInliner)
} }
override fun consumeReifiedOperationMarker(typeParameter: TypeParameterMarker) { override fun consumeReifiedOperationMarker(typeParameter: TypeParameterMarker) {
@@ -15,31 +15,36 @@ import org.jetbrains.kotlin.codegen.ValueKind
import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.inline.*
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrFunction import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.ir.declarations.IrVariable import org.jetbrains.kotlin.ir.declarations.IrVariable
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.ir.types.toKotlinType import org.jetbrains.kotlin.ir.types.toKotlinType
import org.jetbrains.kotlin.ir.util.dump import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.getArgumentsWithIr import org.jetbrains.kotlin.ir.util.getArgumentsWithIr
import org.jetbrains.kotlin.ir.util.isSuspend import org.jetbrains.kotlin.ir.util.isSuspend
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.MethodNode
class IrInlineCodegen( class IrInlineCodegen(
codegen: ExpressionCodegen, codegen: ExpressionCodegen,
state: GenerationState, state: GenerationState,
function: FunctionDescriptor, private val function: IrFunction,
methodOwner: Type, methodOwner: Type,
signature: JvmMethodSignature, signature: JvmMethodSignature,
typeParameterMappings: TypeParameterMappings<IrType>, typeParameterMappings: TypeParameterMappings<IrType>,
sourceCompiler: SourceCompilerForInline, sourceCompiler: SourceCompilerForInline,
reifiedTypeInliner: ReifiedTypeInliner<IrType> reifiedTypeInliner: ReifiedTypeInliner<IrType>
) : InlineCodegen<ExpressionCodegen>( ) : InlineCodegen<ExpressionCodegen>(
codegen, state, function, methodOwner, signature, typeParameterMappings, sourceCompiler, reifiedTypeInliner codegen, state, function.descriptor, methodOwner, signature, typeParameterMappings, sourceCompiler, reifiedTypeInliner
), IrCallGenerator { ), IrCallGenerator {
override fun generateAssertFieldIfNeeded(info: RootInliningContext) { override fun generateAssertFieldIfNeeded(info: RootInliningContext) {
if (info.generateAssertField && (sourceCompiler as IrSourceCompilerForInline).isPrimaryCopy) { if (info.generateAssertField && (sourceCompiler as IrSourceCompilerForInline).isPrimaryCopy) {
@@ -52,12 +57,16 @@ class IrInlineCodegen(
} }
override fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?) { override fun putClosureParametersOnStack(next: LambdaInfo, functionReferenceReceiver: StackValue?) {
val lambdaInfo = next as IrExpressionLambdaImpl activeLambda = next
activeLambda = lambdaInfo
lambdaInfo.reference.getArgumentsWithIr().forEachIndexed { index, (_, ir) -> when (next) {
putCapturedValueOnStack(ir, lambdaInfo.capturedParamsInDesc[index], index) is IrExpressionLambdaImpl -> next.reference.getArgumentsWithIr().forEachIndexed { index, (_, ir) ->
putCapturedValueOnStack(ir, next.capturedParamsInDesc[index], index)
}
is IrDefaultLambda -> rememberCapturedForDefaultLambda(next)
else -> throw RuntimeException("Unknown lambda: $next")
} }
activeLambda = null activeLambda = null
} }
@@ -68,7 +77,11 @@ class IrInlineCodegen(
codegen: ExpressionCodegen, codegen: ExpressionCodegen,
blockInfo: BlockInfo blockInfo: BlockInfo
) { ) {
if (irValueParameter.isInlineParameter() && isInlineIrExpression(argumentExpression)) { if (irValueParameter.isInlineParameter(
/*after transformation inlinable lambda parameter with default value would have nullable type: check default value type first*/
irValueParameter.defaultValue?.expression?.type ?: irValueParameter.type
) && isInlineIrExpression(argumentExpression)
) {
val irReference: IrFunctionReference = val irReference: IrFunctionReference =
(argumentExpression as IrBlock).statements.filterIsInstance<IrFunctionReference>().single() (argumentExpression as IrBlock).statements.filterIsInstance<IrFunctionReference>().single()
val boundReceiver = argumentExpression.statements.filterIsInstance<IrVariable>().singleOrNull() val boundReceiver = argumentExpression.statements.filterIsInstance<IrVariable>().singleOrNull()
@@ -81,20 +94,39 @@ class IrInlineCodegen(
activeLambda = null activeLambda = null
} }
} else { } else {
val onStack = if (irValueParameter.index >= 0) val kind = when (irValueParameter.origin) {
// Reuse an existing local if possible. NOTE: when stopping at a breakpoint placed IrDeclarationOrigin.MASK_FOR_DEFAULT_FUNCTION -> ValueKind.DEFAULT_MASK
// in an inline function, arguments which reuse an existing local will not be visible IrDeclarationOrigin.METHOD_HANDLER_IN_DEFAULT_FUNCTION -> ValueKind.METHOD_HANDLE_IN_DEFAULT
// in the debugger. //TODO: support DEFAULT_PARAMETER
codegen.genOrGetLocal(argumentExpression, blockInfo) else -> ValueKind.CAPTURED
else }
// Do not reuse locals for receivers. While it's actually completely fine, the non-IR
// backend does not do it for internal reasons, and here we replicate the debugging val onStack = when {
// experience. kind == ValueKind.METHOD_HANDLE_IN_DEFAULT -> StackValue.constant(null, AsmTypes.OBJECT_TYPE)
codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo) kind == ValueKind.DEFAULT_MASK -> StackValue.constant((argumentExpression as IrConst<*>).value, Type.INT_TYPE)
// TODO support default argument erasure: do nothing if the parameter is a default mask, the argument is a constant int, kind == ValueKind.DEFAULT_PARAMETER -> StackValue.constant(null, AsmTypes.OBJECT_TYPE)
// and processDefaultMaskOrMethodHandler(StackValue.constant(...), ValueKind.DEFAULT_MASK) is true. irValueParameter.index >= 0
val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toKotlinType()) // Reuse an existing local if possible. NOTE: when stopping at a breakpoint placed
putArgumentOrCapturedToLocalVal(expectedType, onStack, -1, irValueParameter.index, ValueKind.CAPTURED) // in an inline function, arguments which reuse an existing local will not be visible
// in the debugger.
-> codegen.genOrGetLocal(argumentExpression, blockInfo)
else
// Do not reuse locals for receivers. While it's actually completely fine, the non-IR
// backend does not do it for internal reasons, and here we replicate the debugging
// experience.
-> codegen.gen(argumentExpression, parameterType, irValueParameter.type, blockInfo)
}
//TODO support default argument erasure
if (!processDefaultMaskOrMethodHandler(
onStack,
kind
)
) {
val expectedType = JvmKotlinType(parameterType, irValueParameter.type.toKotlinType())
putArgumentOrCapturedToLocalVal(expectedType, onStack, -1, irValueParameter.index, kind)
}
} }
} }
@@ -116,7 +148,12 @@ class IrInlineCodegen(
// TODO port inlining cycle detection to IrFunctionAccessExpression & pass it // TODO port inlining cycle detection to IrFunctionAccessExpression & pass it
state.globalInlineContext.enterIntoInlining(null) state.globalInlineContext.enterIntoInlining(null)
try { try {
performInline(expression.symbol.owner.typeParameters.map { it.symbol }, false, codegen.typeMapper.typeSystem, codegen) performInline(
expression.symbol.owner.typeParameters.map { it.symbol },
function.origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER,
false,
codegen.typeMapper.typeSystem
)
} finally { } finally {
state.globalInlineContext.exitFromInliningOf(null) state.globalInlineContext.exitFromInliningOf(null)
} }
@@ -138,6 +175,14 @@ class IrInlineCodegen(
expressionMap[closureInfo.index] = lambda expressionMap[closureInfo.index] = lambda
} }
} }
override fun extractDefaultLambdas(node: MethodNode): List<DefaultLambda> {
return expandMaskConditionsAndUpdateVariableNodes(
node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex,
extractDefaultLambdaOffsetAndDescriptor(jvmSignature, function),
::IrDefaultLambda
)
}
} }
class IrExpressionLambdaImpl( class IrExpressionLambdaImpl(
@@ -194,6 +239,21 @@ class IrExpressionLambdaImpl(
} }
} }
class IrDefaultLambda(
lambdaClassType: Type,
capturedArgs: Array<Type>,
private val irValueParameter: IrValueParameter,
offset: Int,
needReification: Boolean
) : DefaultLambda(lambdaClassType, capturedArgs, irValueParameter.descriptor as ValueParameterDescriptor, offset, needReification) {
override fun mapAsmSignature(sourceCompiler: SourceCompilerForInline): Method {
val invoke =
irValueParameter.type.classOrNull!!.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "invoke" }
return (sourceCompiler as IrSourceCompilerForInline).codegen.context.methodSignatureMapper.mapSignatureSkipGeneric(invoke).asmMethod
}
}
fun isInlineIrExpression(argumentExpression: IrExpression) = fun isInlineIrExpression(argumentExpression: IrExpression) =
when (argumentExpression) { when (argumentExpression) {
is IrBlock -> argumentExpression.isInlineIrBlock() is IrBlock -> argumentExpression.isInlineIrBlock()
@@ -40,7 +40,7 @@ class IrSourceCompilerForInline(
override val state: GenerationState, override val state: GenerationState,
override val callElement: IrMemberAccessExpression, override val callElement: IrMemberAccessExpression,
private val callee: IrFunction, private val callee: IrFunction,
private val codegen: ExpressionCodegen, internal val codegen: ExpressionCodegen,
private val data: BlockInfo private val data: BlockInfo
) : SourceCompilerForInline { ) : SourceCompilerForInline {
@@ -0,0 +1,28 @@
/*
* 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.jvm.ir.isInlineParameter
import org.jetbrains.kotlin.codegen.inline.parameterOffsets
import org.jetbrains.kotlin.ir.declarations.IrFunction
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
fun extractDefaultLambdaOffsetAndDescriptor(
jvmSignature: JvmMethodSignature,
irFunction: IrFunction
): Map<Int, IrValueParameter> {
val valueParameters = jvmSignature.valueParameters
val parameterOffsets = parameterOffsets(irFunction.isStatic, valueParameters)
val valueParameterOffset = if (irFunction.extensionReceiverParameter != null) 1 else 0
return irFunction.valueParameters.filter {
it.defaultValue != null && it.isInlineParameter(it.defaultValue!!.expression.type)
}.associateBy {
parameterOffsets[valueParameterOffset + it.index]
}
}
@@ -96,7 +96,7 @@ val IrFunction.propertyIfAccessor: IrDeclaration
fun IrFunction.hasJvmDefault(): Boolean = propertyIfAccessor.hasAnnotation(JVM_DEFAULT_FQ_NAME) fun IrFunction.hasJvmDefault(): Boolean = propertyIfAccessor.hasAnnotation(JVM_DEFAULT_FQ_NAME)
fun IrValueParameter.isInlineParameter() = fun IrValueParameter.isInlineParameter(type: IrType = this.type) =
index >= 0 && !isNoinline && !type.isNullable() && (type.isFunction() || type.isSuspendFunctionTypeOrSubtype()) index >= 0 && !isNoinline && !type.isNullable() && (type.isFunction() || type.isSuspendFunctionTypeOrSubtype())
val IrType.isBoxedArray: Boolean val IrType.isBoxedArray: Boolean
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: bar$default // SKIP_INLINE_CHECK_IN: bar$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,7 +1,6 @@
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
//WITH_RUNTIME //WITH_RUNTIME
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: lParams$default // SKIP_INLINE_CHECK_IN: lParams$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,5 +1,4 @@
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: enumOrThrow$default // SKIP_INLINE_CHECK_IN: enumOrThrow$default
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,4 +1,3 @@
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
package test package test
@@ -1,5 +1,4 @@
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// IGNORE_BACKEND_MULTI_MODULE: JVM_IR
// FILE: 1.kt // FILE: 1.kt
// SKIP_INLINE_CHECK_IN: inlineFun$default // SKIP_INLINE_CHECK_IN: inlineFun$default
// WITH_RUNTIME // WITH_RUNTIME
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
inline fun inlineFunVoid(f: () -> Unit): Unit { inline fun inlineFunVoid(f: () -> Unit): Unit {
return f() return f()
} }