JVM: remove functionDescriptor from InlineCodegen

This commit is contained in:
pyos
2021-05-27 17:34:41 +02:00
committed by max-kammerer
parent d89e2d9f08
commit b6e9f64e18
7 changed files with 52 additions and 83 deletions
@@ -10,15 +10,11 @@ import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive
import org.jetbrains.kotlin.codegen.context.ClosureContext
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.Position
import org.jetbrains.kotlin.incremental.components.ScopeKind
import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.inline.isInlineOnly
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Opcodes
@@ -29,18 +25,11 @@ import kotlin.math.max
abstract class InlineCodegen<out T : BaseExpressionCodegen>(
protected val codegen: T,
protected val state: GenerationState,
protected val functionDescriptor: FunctionDescriptor,
protected val jvmSignature: JvmMethodSignature,
private val typeParameterMappings: TypeParameterMappings<*>,
protected val sourceCompiler: SourceCompilerForInline,
protected val reifiedTypeInliner: ReifiedTypeInliner<*>
) {
init {
assert(InlineUtil.isInline(functionDescriptor)) {
"InlineCodegen can inline only inline functions: $functionDescriptor"
}
}
// TODO: implement AS_FUNCTION inline strategy
private val asFunctionInline = false
@@ -52,15 +41,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
protected var maskStartIndex = -1
protected var methodHandleInDefaultMethodIndex = -1
init {
if (functionDescriptor !is FictitiousArrayConstructor) {
//track changes for property accessor and @JvmName inline functions/property accessors
if (jvmSignature.asmMethod.name != functionDescriptor.name.asString()) {
trackLookup(functionDescriptor)
}
}
}
protected fun throwCompilationException(
nodeAndSmap: SMAPAndMethodNode?, e: Exception, generateNodeText: Boolean
): CompilationException {
@@ -68,7 +48,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
val element = DescriptorToSourceUtils.descriptorToDeclaration(contextDescriptor)
val node = nodeAndSmap?.node
throw CompilationException(
"Couldn't inline method call '" + functionDescriptor.name + "' into\n" +
"Couldn't inline method call '${jvmSignature.asmMethod}' into\n" +
DescriptorRenderer.DEBUG_TEXT.render(contextDescriptor) + "\n" +
(element?.text ?: "<no source>") +
if (generateNodeText) "\nCause: " + node.nodeText else "",
@@ -81,13 +61,13 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
AsmUtil.genThrow(codegen.visitor, "java/lang/UnsupportedOperationException", "Call is part of inline cycle: $text")
}
fun performInline(inlineDefaultLambdas: Boolean, registerLineNumberAfterwards: Boolean) {
fun performInline(registerLineNumberAfterwards: Boolean, isInlineOnly: Boolean, isSuspend: Boolean) {
var nodeAndSmap: SMAPAndMethodNode? = null
try {
nodeAndSmap = sourceCompiler.compileInlineFunction(jvmSignature).apply {
node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
}
val result = inlineCall(nodeAndSmap, inlineDefaultLambdas)
val result = inlineCall(nodeAndSmap, isInlineOnly, isSuspend)
leaveTemps()
codegen.propagateChildReifiedTypeParametersUsages(result.reifiedTypeParametersUsages)
codegen.markLineNumberAfterInlineIfNeeded(registerLineNumberAfterwards)
@@ -109,8 +89,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
//
// Instead of checking for loops precisely, we just check if there are any backward jumps -
// that is, a jump from instruction #i to instruction #j where j < i
if (functionDescriptor.isSuspend) return false
if (methodNode.tryCatchBlocks.isNotEmpty()) return false
fun isBackwardJump(fromIndex: Int, toLabel: LabelNode) =
@@ -162,9 +140,9 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
expressionMap[closureInfo.index] = lambdaInfo
}
private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, inlineDefaultLambda: Boolean): InlineResult {
private fun inlineCall(nodeAndSmap: SMAPAndMethodNode, isInlineOnly: Boolean, isSuspend: Boolean): InlineResult {
val node = nodeAndSmap.node
if (inlineDefaultLambda) {
if (maskStartIndex != -1) {
for (lambda in extractDefaultLambdas(node)) {
invocationParamBuilder.buildParameters().getParameterByDeclarationSlot(lambda.offset).functionalArgument = lambda
val prev = expressionMap.put(lambda.offset, lambda)
@@ -190,7 +168,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
node, parameters, info, FieldRemapper(null, null, parameters), sourceCompiler.isCallInsideSameModuleAsCallee,
"Method inlining " + sourceCompiler.callElementText,
SourceMapCopier(sourceMapper, nodeAndSmap.classSMAP, callSite),
info.callSiteInfo, if (functionDescriptor.isInlineOnly()) InlineOnlySmapSkipper(codegen) else null,
info.callSiteInfo, if (isInlineOnly) InlineOnlySmapSkipper(codegen) else null,
!isInlinedToInlineFunInKotlinRuntime()
) //with captured
@@ -215,7 +193,7 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
// needs to be inserted before the code that actually uses it.
generateAssertFieldIfNeeded(info)
val shouldSpillStack = !canSkipStackSpillingOnInline(node)
val shouldSpillStack = isSuspend || !canSkipStackSpillingOnInline(node)
if (shouldSpillStack) {
addInlineMarker(codegen.visitor, true)
}
@@ -389,21 +367,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
return true
}
private fun trackLookup(functionOrAccessor: FunctionDescriptor) {
val functionOrAccessorName = jvmSignature.asmMethod.name
val lookupTracker = state.configuration.get(CommonConfigurationKeys.LOOKUP_TRACKER) ?: return
val location = sourceCompiler.lookupLocation.location ?: return
val position = if (lookupTracker.requiresPosition) location.position else Position.NO_POSITION
val classOrPackageFragment = functionOrAccessor.containingDeclaration
lookupTracker.record(
location.filePath,
position,
DescriptorUtils.getFqName(classOrPackageFragment).asString(),
ScopeKind.CLASSIFIER,
functionOrAccessorName
)
}
companion object {
private fun StackValue.isCapturedInlineParameter(): Boolean {
val field = if (this is StackValue.FieldForSharedVar) receiver else this
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression
import org.jetbrains.kotlin.resolve.inline.isInlineOnly
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.types.KotlinType
@@ -39,14 +40,14 @@ import org.jetbrains.org.objectweb.asm.tree.MethodNode
class PsiInlineCodegen(
codegen: ExpressionCodegen,
state: GenerationState,
function: FunctionDescriptor,
private val functionDescriptor: FunctionDescriptor,
signature: JvmMethodSignature,
typeParameterMappings: TypeParameterMappings<KotlinType>,
sourceCompiler: SourceCompilerForInline,
private val methodOwner: Type,
private val actualDispatchReceiver: Type
) : InlineCodegen<ExpressionCodegen>(
codegen, state, function, signature, typeParameterMappings, sourceCompiler,
codegen, state, signature, typeParameterMappings, sourceCompiler,
ReifiedTypeInliner(
typeParameterMappings, PsiInlineIntrinsicsSupport(state), codegen.typeSystem,
state.languageVersionSettings, state.unifiedNullChecks
@@ -83,7 +84,7 @@ class PsiInlineCodegen(
}
}
}
performInline(callDefault, registerLineNumber)
performInline(registerLineNumber, functionDescriptor.isInlineOnly(), functionDescriptor.isSuspend)
} finally {
state.globalInlineContext.exitFromInlining()
}
@@ -52,7 +52,7 @@ class PsiSourceCompilerForInline(
codegen.state,
DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor)?.containingFile as? KtFile,
additionalInnerClasses
)
) as MethodContext
override val lookupLocation = KotlinLookupLocation(callElement)
@@ -246,6 +246,9 @@ class PsiSourceCompilerForInline(
}
val asmMethod = if (callDefault) mapDefault() else jvmSignature.asmMethod
if (asmMethod.name != functionDescriptor.name.asString()) {
trackLookup(DescriptorUtils.getFqNameSafe(functionDescriptor.containingDeclaration), asmMethod.name) // ?
}
val directMember = getDirectMemberAndCallableFromObject()
if (directMember is DescriptorWithContainerSource) {
@@ -254,12 +257,8 @@ class PsiSourceCompilerForInline(
return loadCompiledInlineFunction(containerId, asmMethod, functionDescriptor.isSuspend, isMangled, state)
}
val element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor)
if (!(element is KtNamedFunction || element is KtPropertyAccessor)) {
throw IllegalStateException("Couldn't find declaration for function $functionDescriptor")
}
val inliningFunction = element as KtDeclarationWithBody?
val element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor) as? KtDeclarationWithBody
?: throw IllegalStateException("Couldn't find declaration for function $functionDescriptor")
val node = MethodNode(
Opcodes.API_VERSION,
@@ -271,13 +270,10 @@ class PsiSourceCompilerForInline(
//for maxLocals calculation
val maxCalcAdapter = wrapWithMaxLocalCalc(node)
val parentContext = context.parentContext ?: error("Context has no parent: $context")
val methodContext = parentContext.intoFunction(functionDescriptor)
val smap = if (callDefault) {
val implementationOwner = state.typeMapper.mapImplementationOwner(functionDescriptor)
val parentCodegen = FakeMemberCodegen(
codegen.parentCodegen, inliningFunction!!, methodContext.parentContext as FieldOwnerContext<*>,
codegen.parentCodegen, element, context.parentContext as FieldOwnerContext<*>,
implementationOwner.internalName,
additionalInnerClasses,
false
@@ -286,12 +282,12 @@ class PsiSourceCompilerForInline(
throw IllegalStateException("Property accessors with default parameters not supported $functionDescriptor")
}
FunctionCodegen.generateDefaultImplBody(
methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
inliningFunction as KtNamedFunction?, parentCodegen, asmMethod
context, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
element as KtNamedFunction?, parentCodegen, asmMethod
)
SMAP(parentCodegen.orCreateSourceMapper.resultMappings)
} else {
generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction!!, jvmSignature, null)
generateMethodBody(maxCalcAdapter, functionDescriptor, context, element, jvmSignature, null)
}
maxCalcAdapter.visitMaxs(-1, -1)
maxCalcAdapter.visitEnd()
@@ -11,10 +11,14 @@ import org.jetbrains.kotlin.codegen.BaseExpressionCodegen
import org.jetbrains.kotlin.codegen.OwnerKind
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.Position
import org.jetbrains.kotlin.incremental.components.ScopeKind
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type
@@ -64,6 +68,19 @@ interface SourceCompilerForInline {
fun reportSuspensionPointInsideMonitor(stackTraceElement: String)
}
fun SourceCompilerForInline.trackLookup(container: FqName, functionName: String) {
val lookupTracker = state.configuration.get(CommonConfigurationKeys.LOOKUP_TRACKER) ?: return
val location = lookupLocation.location ?: return
val position = if (lookupTracker.requiresPosition) location.position else Position.NO_POSITION
lookupTracker.record(
location.filePath,
position,
container.asString(),
ScopeKind.CLASSIFIER,
functionName
)
}
fun loadCompiledInlineFunction(
containerId: ClassId,
asmMethod: Method,
@@ -41,9 +41,7 @@ class IrInlineCodegen(
sourceCompiler: SourceCompilerForInline,
reifiedTypeInliner: ReifiedTypeInliner<IrType>
) :
InlineCodegen<ExpressionCodegen>(
codegen, state, function.toIrBasedDescriptor(), signature, typeParameterMappings, sourceCompiler, reifiedTypeInliner
),
InlineCodegen<ExpressionCodegen>(codegen, state, signature, typeParameterMappings, sourceCompiler, reifiedTypeInliner),
IrInlineCallGenerator {
override fun generateAssertFieldIfNeeded(info: RootInliningContext) {
@@ -126,8 +124,7 @@ class IrInlineCodegen(
expression: IrFunctionAccessExpression,
isInsideIfCondition: Boolean,
) {
// Always look for default lambdas to allow custom default argument handling in compiler plugins.
performInline(inlineDefaultLambdas = true, registerLineNumberAfterwards = isInsideIfCondition)
performInline(isInsideIfCondition, function.isInlineOnly(), function.isSuspend)
}
override fun genCycleStub(text: String, codegen: ExpressionCodegen) {
@@ -135,7 +132,6 @@ class IrInlineCodegen(
}
override fun extractDefaultLambdas(node: MethodNode): List<DefaultLambda> {
if (maskStartIndex == -1) return listOf()
return expandMaskConditionsAndUpdateVariableNodes(
node, maskStartIndex, maskValues, methodHandleInDefaultMethodIndex,
extractDefaultLambdaOffsetAndDescriptor(jvmSignature, function),
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.ir.descriptors.toIrBasedDescriptor
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.util.isSuspend
import org.jetbrains.kotlin.ir.util.kotlinFqName
import org.jetbrains.kotlin.ir.util.module
import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.psi.KtElement
@@ -108,6 +109,9 @@ class IrSourceCompilerForInline(
generateInlineIntrinsicForIr(state.languageVersionSettings, callee.toIrBasedDescriptor())?.let {
return it
}
if (jvmSignature.asmMethod.name != callee.name.asString()) {
trackLookup(callee.parentAsClass.kotlinFqName, jvmSignature.asmMethod.name) // ?
}
callee.parentClassId?.let {
return loadCompiledInlineFunction(it, jvmSignature.asmMethod, callee.isSuspend, callee.hasMangledReturnType, state)
}
@@ -179,7 +179,7 @@ private fun IrDeclarationWithVisibility.specialCaseVisibility(kind: OwnerKind?):
return Opcodes.ACC_PRIVATE
}
if (isInlineOnlyPrivateInBytecode() || isInlineOnlyPropertyAccessor()) {
if (isInlineOnlyPrivateInBytecode()) {
return Opcodes.ACC_PRIVATE
}
@@ -223,26 +223,18 @@ private tailrec fun isInlineOrContainedInInline(declaration: IrDeclaration?): Bo
/* Borrowed from inlineOnly.kt */
fun IrDeclarationWithVisibility.isInlineOnlyOrReifiable(): Boolean =
this is IrFunction && (isReifiable() || isInlineOnly())
fun IrDeclarationWithVisibility.isEffectivelyInlineOnly(): Boolean =
isInlineOnlyOrReifiable() || isInlineOnlyPrivateInBytecode() || isInlineOnlyPropertyAccessor()
this is IrFunction && (isReifiable() || isInlineOnly() || isPrivateInlineSuspend())
fun IrDeclarationWithVisibility.isInlineOnlyPrivateInBytecode(): Boolean =
(this is IrFunction && isInlineOnly()) || isPrivateInlineSuspend()
private fun IrDeclarationWithVisibility.isInlineOnlyPrivateInBytecode(): Boolean =
this is IrFunction && (isInlineOnly() || isPrivateInlineSuspend())
private fun IrDeclarationWithVisibility.isPrivateInlineSuspend(): Boolean =
this is IrFunction && isSuspend && isInline && visibility == DescriptorVisibilities.PRIVATE
private fun IrDeclarationWithVisibility.isInlineOnlyPropertyAccessor(): Boolean {
if (this !is IrSimpleFunction) return false
val propertySymbol = correspondingPropertySymbol ?: return false
return propertySymbol.owner.hasAnnotation(INLINE_ONLY_ANNOTATION_FQ_NAME)
}
private fun IrFunction.isPrivateInlineSuspend(): Boolean =
isSuspend && isInline && visibility == DescriptorVisibilities.PRIVATE
fun IrFunction.isInlineOnly() =
isInline && hasAnnotation(INLINE_ONLY_ANNOTATION_FQ_NAME)
(isInline && hasAnnotation(INLINE_ONLY_ANNOTATION_FQ_NAME)) ||
(this is IrSimpleFunction && correspondingPropertySymbol?.owner?.hasAnnotation(INLINE_ONLY_ANNOTATION_FQ_NAME) == true)
fun IrFunction.isReifiable() = typeParameters.any { it.isReified }