JVM: split inline intrinsics into "needed by JVM_IR" and "not"

or, alternatively, "suspend" and "not".
This commit is contained in:
pyos
2021-05-27 16:45:17 +02:00
committed by max-kammerer
parent eb4d831d27
commit d89e2d9f08
6 changed files with 44 additions and 53 deletions
@@ -20,8 +20,6 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.inline.isInlineOnly import org.jetbrains.kotlin.resolve.inline.isInlineOnly
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlin.types.model.TypeParameterMarker
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
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
@@ -83,31 +81,17 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
AsmUtil.genThrow(codegen.visitor, "java/lang/UnsupportedOperationException", "Call is part of inline cycle: $text") AsmUtil.genThrow(codegen.visitor, "java/lang/UnsupportedOperationException", "Call is part of inline cycle: $text")
} }
protected fun endCall(result: InlineResult, registerLineNumberAfterwards: Boolean) { fun performInline(inlineDefaultLambdas: Boolean, registerLineNumberAfterwards: Boolean) {
leaveTemps()
codegen.propagateChildReifiedTypeParametersUsages(result.reifiedTypeParametersUsages)
state.factory.removeClasses(result.calcClassesToRemove())
codegen.markLineNumberAfterInlineIfNeeded(registerLineNumberAfterwards)
}
fun performInline(
typeArguments: List<TypeParameterMarker>?,
inlineDefaultLambdas: Boolean,
typeSystem: TypeSystemCommonBackendContext,
registerLineNumberAfterwards: Boolean,
) {
var nodeAndSmap: SMAPAndMethodNode? = null var nodeAndSmap: SMAPAndMethodNode? = null
try { try {
nodeAndSmap = nodeAndSmap = sourceCompiler.compileInlineFunction(jvmSignature).apply {
generateInlineIntrinsic(state, functionDescriptor, jvmSignature.asmMethod, typeArguments, typeSystem)?.let { node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
SMAPAndMethodNode(it, SMAP(listOf())) }
} ?: sourceCompiler.compileInlineFunction(jvmSignature).apply { val result = inlineCall(nodeAndSmap, inlineDefaultLambdas)
node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false) leaveTemps()
} codegen.propagateChildReifiedTypeParametersUsages(result.reifiedTypeParametersUsages)
endCall(inlineCall(nodeAndSmap, inlineDefaultLambdas), registerLineNumberAfterwards) codegen.markLineNumberAfterInlineIfNeeded(registerLineNumberAfterwards)
state.factory.removeClasses(result.calcClassesToRemove())
} catch (e: CompilationException) { } catch (e: CompilationException) {
throw e throw e
} catch (e: InlineException) { } catch (e: InlineException) {
@@ -83,7 +83,7 @@ class PsiInlineCodegen(
} }
} }
} }
performInline(resolvedCall?.typeArguments?.keys?.toList(), callDefault, codegen.typeSystem, registerLineNumber) performInline(callDefault, registerLineNumber)
} finally { } finally {
state.globalInlineContext.exitFromInlining() state.globalInlineContext.exitFromInlining()
} }
@@ -241,6 +241,10 @@ class PsiSourceCompilerForInline(
} }
override fun compileInlineFunction(jvmSignature: JvmMethodSignature): SMAPAndMethodNode { override fun compileInlineFunction(jvmSignature: JvmMethodSignature): SMAPAndMethodNode {
generateInlineIntrinsic(state.languageVersionSettings, functionDescriptor, jvmSignature.asmMethod, codegen.typeSystem)?.let {
return it
}
val asmMethod = if (callDefault) mapDefault() else jvmSignature.asmMethod val asmMethod = if (callDefault) mapDefault() else jvmSignature.asmMethod
val directMember = getDirectMemberAndCallableFromObject() val directMember = getDirectMemberAndCallableFromObject()
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCorouti
import org.jetbrains.kotlin.codegen.createMethodNodeForAlwaysEnabledAssert import org.jetbrains.kotlin.codegen.createMethodNodeForAlwaysEnabledAssert
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors
import org.jetbrains.kotlin.codegen.isBuiltinAlwaysEnabledAssert import org.jetbrains.kotlin.codegen.isBuiltinAlwaysEnabledAssert
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.resolve.calls.checkers.TypeOfChecker import org.jetbrains.kotlin.resolve.calls.checkers.TypeOfChecker
@@ -30,26 +30,29 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.commons.Method
import org.jetbrains.org.objectweb.asm.tree.MethodNode import org.jetbrains.org.objectweb.asm.tree.MethodNode
internal fun generateInlineIntrinsic( fun generateInlineIntrinsicForIr(languageVersionSettings: LanguageVersionSettings, descriptor: FunctionDescriptor): SMAPAndMethodNode? =
state: GenerationState, when {
descriptor: FunctionDescriptor, // TODO: implement these as codegen intrinsics (see IrIntrinsicMethods)
asmMethod: Method,
typeParameters: List<TypeParameterMarker>?,
typeSystem: TypeSystemCommonBackendContext
): MethodNode? {
val languageVersionSettings = state.languageVersionSettings
return when {
isSpecialEnumMethod(descriptor) ->
createSpecialEnumMethodBody(descriptor.name.asString(), typeParameters!!.single(), typeSystem)
TypeOfChecker.isTypeOf(descriptor) ->
typeSystem.createTypeOfMethodBody(typeParameters!!.single())
descriptor.isBuiltInIntercepted(languageVersionSettings) -> descriptor.isBuiltInIntercepted(languageVersionSettings) ->
createMethodNodeForIntercepted(languageVersionSettings) createMethodNodeForIntercepted(languageVersionSettings)
descriptor.isBuiltInCoroutineContext(languageVersionSettings) -> descriptor.isBuiltInCoroutineContext(languageVersionSettings) ->
createMethodNodeForCoroutineContext(descriptor, languageVersionSettings) createMethodNodeForCoroutineContext(descriptor, languageVersionSettings)
descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) -> descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) ->
createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSettings)
else -> null
}?.let { SMAPAndMethodNode(it, SMAP(listOf())) }
internal fun generateInlineIntrinsic(
languageVersionSettings: LanguageVersionSettings,
descriptor: FunctionDescriptor,
asmMethod: Method,
typeSystem: TypeSystemCommonBackendContext
): SMAPAndMethodNode? {
return generateInlineIntrinsicForIr(languageVersionSettings, descriptor) ?: when {
isSpecialEnumMethod(descriptor) ->
createSpecialEnumMethodBody(descriptor.name.asString(), descriptor.original.typeParameters.single(), typeSystem)
TypeOfChecker.isTypeOf(descriptor) ->
typeSystem.createTypeOfMethodBody(descriptor.original.typeParameters.single())
descriptor.isBuiltinAlwaysEnabledAssert() -> descriptor.isBuiltinAlwaysEnabledAssert() ->
createMethodNodeForAlwaysEnabledAssert(descriptor) createMethodNodeForAlwaysEnabledAssert(descriptor)
descriptor is FictitiousArrayConstructor -> descriptor is FictitiousArrayConstructor ->
@@ -59,7 +62,7 @@ internal fun generateInlineIntrinsic(
IntrinsicArrayConstructors.isEmptyArray(descriptor) -> IntrinsicArrayConstructors.isEmptyArray(descriptor) ->
IntrinsicArrayConstructors.generateEmptyArrayBody(asmMethod) IntrinsicArrayConstructors.generateEmptyArrayBody(asmMethod)
else -> null else -> null
} }?.let { SMAPAndMethodNode(it, SMAP(listOf())) }
} }
private fun isSpecialEnumMethod(descriptor: FunctionDescriptor): Boolean { private fun isSpecialEnumMethod(descriptor: FunctionDescriptor): Boolean {
@@ -126,13 +126,8 @@ class IrInlineCodegen(
expression: IrFunctionAccessExpression, expression: IrFunctionAccessExpression,
isInsideIfCondition: Boolean, isInsideIfCondition: Boolean,
) { ) {
performInline( // Always look for default lambdas to allow custom default argument handling in compiler plugins.
expression.symbol.owner.typeParameters.map { it.symbol }, performInline(inlineDefaultLambdas = true, registerLineNumberAfterwards = isInsideIfCondition)
// Always look for default lambdas to allow custom default argument handling in compiler plugins.
inlineDefaultLambdas = true,
codegen.typeMapper.typeSystem,
registerLineNumberAfterwards = isInsideIfCondition,
)
} }
override fun genCycleStub(text: String, codegen: ExpressionCodegen) { override fun genCycleStub(text: String, codegen: ExpressionCodegen) {
@@ -104,10 +104,15 @@ class IrSourceCompilerForInline(
return FunctionCodegen(lambdaInfo.function, codegen.classCodegen).generate(codegen, reifiedTypeParameters) return FunctionCodegen(lambdaInfo.function, codegen.classCodegen).generate(codegen, reifiedTypeParameters)
} }
override fun compileInlineFunction(jvmSignature: JvmMethodSignature): SMAPAndMethodNode = override fun compileInlineFunction(jvmSignature: JvmMethodSignature): SMAPAndMethodNode {
callee.parentClassId?.let { containerId -> generateInlineIntrinsicForIr(state.languageVersionSettings, callee.toIrBasedDescriptor())?.let {
loadCompiledInlineFunction(containerId, jvmSignature.asmMethod, callee.isSuspend, callee.hasMangledReturnType, state) return it
} ?: ClassCodegen.getOrCreate(callee.parentAsClass, codegen.context).generateMethodNode(callee) }
callee.parentClassId?.let {
return loadCompiledInlineFunction(it, jvmSignature.asmMethod, callee.isSuspend, callee.hasMangledReturnType, state)
}
return ClassCodegen.getOrCreate(callee.parentAsClass, codegen.context).generateMethodNode(callee)
}
override fun hasFinallyBlocks() = data.hasFinallyBlocks() override fun hasFinallyBlocks() = data.hasFinallyBlocks()