JVM: refactor loading of inline functions from binaries

The IR path no longer does any descriptor unwrapping or old-style type
mapping.
This commit is contained in:
pyos
2021-05-27 11:25:21 +02:00
committed by max-kammerer
parent 7bcd738bb1
commit ed26e97df8
10 changed files with 114 additions and 144 deletions
@@ -9,11 +9,13 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.inline.InlineCodegen import org.jetbrains.kotlin.codegen.inline.InlineCodegen
import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.FunctionImportedFromObject import org.jetbrains.kotlin.resolve.FunctionImportedFromObject
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode
@@ -65,13 +67,14 @@ class DelegatedPropertiesCodegenHelper(private val state: GenerationState) {
this this
private fun isDelegatedPropertyMetadataRequiredForFunctionFromBinaries(calleeDescriptor: FunctionDescriptor): Boolean { private fun isDelegatedPropertyMetadataRequiredForFunctionFromBinaries(calleeDescriptor: FunctionDescriptor): Boolean {
assert(calleeDescriptor is DescriptorWithContainerSource) { require(calleeDescriptor is DescriptorWithContainerSource) {
"Function descriptor from binaries expected: $calleeDescriptor" "Function descriptor from binaries expected: $calleeDescriptor"
} }
val metadataParameterIndex = getMetadataParameterIndex(calleeDescriptor) val metadataParameterIndex = getMetadataParameterIndex(calleeDescriptor)
val methodNode = InlineCodegen.createSpecialInlineMethodNodeFromBinaries(calleeDescriptor, state) val containerId = KotlinTypeMapper.getContainingClassesForDeserializedCallable(calleeDescriptor).implClassId
val asmMethod = state.typeMapper.mapAsmMethod(calleeDescriptor)
val isMangled = requiresFunctionNameManglingForReturnType(calleeDescriptor)
val methodNode = InlineCodegen.loadCompiledInlineFunction(containerId, asmMethod, calleeDescriptor.isSuspend, isMangled, state).node
return isMetadataParameterUsedInCompiledMethodBody(metadataParameterIndex, methodNode) return isMetadataParameterUsedInCompiledMethodBody(metadataParameterIndex, methodNode)
} }
@@ -6,28 +6,23 @@
package org.jetbrains.kotlin.codegen.inline package org.jetbrains.kotlin.codegen.inline
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive
import org.jetbrains.kotlin.codegen.context.ClosureContext import org.jetbrains.kotlin.codegen.context.ClosureContext
import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX import org.jetbrains.kotlin.codegen.inline.coroutines.FOR_INLINE_SUFFIX
import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.components.Position import org.jetbrains.kotlin.incremental.components.Position
import org.jetbrains.kotlin.incremental.components.ScopeKind import org.jetbrains.kotlin.incremental.components.ScopeKind
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.DescriptorRenderer
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
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.resolve.jvm.requiresFunctionNameManglingForReturnType import org.jetbrains.kotlin.resolve.jvm.requiresFunctionNameManglingForReturnType
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext
import org.jetbrains.kotlin.types.model.TypeParameterMarker import org.jetbrains.kotlin.types.model.TypeParameterMarker
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
@@ -250,8 +245,6 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
abstract fun extractDefaultLambdas(node: MethodNode): List<DefaultLambda> abstract fun extractDefaultLambdas(node: MethodNode): List<DefaultLambda>
abstract fun descriptorIsDeserialized(memberDescriptor: CallableMemberDescriptor): Boolean
private fun generateAndInsertFinallyBlocks( private fun generateAndInsertFinallyBlocks(
intoNode: MethodNode, intoNode: MethodNode,
insertPoints: List<MethodInliner.PointForExternalFinallyBlocks>, insertPoints: List<MethodInliner.PointForExternalFinallyBlocks>,
@@ -433,144 +426,63 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
typeArguments: List<TypeParameterMarker>?, typeArguments: List<TypeParameterMarker>?,
typeSystem: TypeSystemCommonBackendContext typeSystem: TypeSystemCommonBackendContext
): SMAPAndMethodNode { ): SMAPAndMethodNode {
val intrinsic = generateInlineIntrinsic(state, functionDescriptor, typeArguments, typeSystem) val intrinsic = generateInlineIntrinsic(state, functionDescriptor, jvmSignature.asmMethod, typeArguments, typeSystem)
if (intrinsic != null) { if (intrinsic != null) {
return SMAPAndMethodNode(intrinsic, createDefaultFakeSMAP()) return SMAPAndMethodNode(intrinsic, SMAP(listOf()))
} }
sourceCompiler.inlineFunctionSignature(jvmSignature, callDefault)?.let { (containerId, asmMethod) ->
var asmMethod = mapMethod(callDefault) val isMangled = requiresFunctionNameManglingForReturnType(functionDescriptor)
if (asmMethod.name.contains("-") && return loadCompiledInlineFunction(containerId, asmMethod, functionDescriptor.isSuspend, isMangled, state)
!state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_INLINE_CLASSES_MANGLING_SCHEME) &&
classFileContainsMethod(functionDescriptor, state, asmMethod) == false
) {
state.typeMapper.useOldManglingRulesForFunctionAcceptingInlineClass = true
asmMethod = mapMethod(callDefault)
state.typeMapper.useOldManglingRulesForFunctionAcceptingInlineClass = false
} }
return sourceCompiler.compileInlineFunction(jvmSignature, callDefault).apply {
val directMember = getDirectMemberAndCallableFromObject(functionDescriptor) node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
if (!isBuiltInArrayIntrinsic(functionDescriptor) && !descriptorIsDeserialized(directMember)) {
val node = sourceCompiler.compileInlineFunction(jvmSignature, callDefault, asmMethod)
node.node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false)
return node
} }
return getCompiledMethodNodeInner(functionDescriptor, directMember, asmMethod, methodOwner, state, jvmSignature)
} }
private fun mapMethod(callDefault: Boolean): Method =
if (callDefault) state.typeMapper.mapDefaultMethod(functionDescriptor, sourceCompiler.contextKind)
else mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor, jvmSignature.asmMethod)
companion object { companion object {
internal fun loadCompiledInlineFunction(
internal fun createSpecialInlineMethodNodeFromBinaries(functionDescriptor: FunctionDescriptor, state: GenerationState): MethodNode { containerId: ClassId,
val directMember = getDirectMemberAndCallableFromObject(functionDescriptor)
assert(directMember is DescriptorWithContainerSource) {
"Function is not in binaries: $functionDescriptor"
}
assert(directMember is FunctionDescriptor && directMember.isOperator) {
"Operator function expected: $directMember"
}
val methodOwner = state.typeMapper.mapImplementationOwner(functionDescriptor)
val jvmSignature = state.typeMapper.mapSignatureWithGeneric(functionDescriptor, OwnerKind.IMPLEMENTATION)
val asmMethod = mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor, jvmSignature.asmMethod)
return getCompiledMethodNodeInner(functionDescriptor, directMember, asmMethod, methodOwner, state, jvmSignature).node
}
private fun getCompiledMethodNodeInner(
functionDescriptor: FunctionDescriptor,
directMember: CallableMemberDescriptor,
asmMethod: Method, asmMethod: Method,
methodOwner: Type, isSuspend: Boolean,
state: GenerationState, isMangled: Boolean,
jvmSignature: JvmMethodSignature state: GenerationState
): SMAPAndMethodNode { ): SMAPAndMethodNode {
val methodId = MethodId(methodOwner.internalName, asmMethod) val containerType = AsmUtil.asmTypeByClassId(containerId)
val resultInCache = state.inlineCache.methodNodeById.getOrPut(methodId) {
val result = doCreateMethodNodeFromCompiled(directMember, state, asmMethod)
?: if (functionDescriptor.isSuspend)
doCreateMethodNodeFromCompiled(directMember, state, jvmSignature.asmMethod)
else
null
result ?: throw IllegalStateException("Couldn't obtain compiled function body for $functionDescriptor")
}
return SMAPAndMethodNode(cloneMethodNode(resultInCache.node), resultInCache.classSMAP)
}
private fun createDefaultFakeSMAP() = SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
// For suspend inline functions we generate two methods:
// 1) normal one: with state machine to call directly
// 2) for inliner: with mangled name and without state machine
private fun mangleSuspendInlineFunctionAsmMethodIfNeeded(functionDescriptor: FunctionDescriptor, asmMethod: Method): Method {
if (!functionDescriptor.isSuspend) return asmMethod
return Method("${asmMethod.name}$FOR_INLINE_SUFFIX", asmMethod.descriptor)
}
private fun getDirectMemberAndCallableFromObject(functionDescriptor: FunctionDescriptor): CallableMemberDescriptor {
val directMember = JvmCodegenUtil.getDirectMember(functionDescriptor)
return (directMember as? ImportedFromObjectCallableDescriptor<*>)?.callableFromObject ?: directMember
}
private fun doCreateMethodNodeFromCompiled(
callableDescriptor: CallableMemberDescriptor,
state: GenerationState,
asmMethod: Method
): SMAPAndMethodNode? {
if (isBuiltInArrayIntrinsic(callableDescriptor)) {
val body = when {
callableDescriptor is FictitiousArrayConstructor -> IntrinsicArrayConstructors.generateArrayConstructorBody(asmMethod)
callableDescriptor.name.asString() == "emptyArray" -> IntrinsicArrayConstructors.generateEmptyArrayBody(asmMethod)
callableDescriptor.name.asString() == "arrayOf" -> IntrinsicArrayConstructors.generateArrayOfBody(asmMethod)
else -> throw UnsupportedOperationException("Not an array intrinsic: $callableDescriptor")
}
return SMAPAndMethodNode(body, SMAP(listOf()))
}
assert(callableDescriptor is DescriptorWithContainerSource) { "Not a deserialized function or proper: $callableDescriptor" }
val containingClasses =
KotlinTypeMapper.getContainingClassesForDeserializedCallable(callableDescriptor as DescriptorWithContainerSource)
val containerId = containingClasses.implClassId
val bytes = state.inlineCache.classBytes.getOrPut(containerId) { val bytes = state.inlineCache.classBytes.getOrPut(containerId) {
findVirtualFile(state, containerId)?.contentsToByteArray() findVirtualFile(state, containerId)?.contentsToByteArray()
?: throw IllegalStateException("Couldn't find declaration file for $containerId") ?: throw IllegalStateException("Couldn't find declaration file for $containerId")
} }
val resultInCache = state.inlineCache.methodNodeById.getOrPut(MethodId(containerType.descriptor, asmMethod)) {
getMethodNode(containerType, bytes, asmMethod.name, asmMethod.descriptor, isSuspend, isMangled)
}
return SMAPAndMethodNode(cloneMethodNode(resultInCache.node), resultInCache.classSMAP)
}
val classType = AsmUtil.asmTypeByClassId(containerId) private fun getMethodNode(
val methodNode = getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, classType) owner: Type,
if (methodNode == null && requiresFunctionNameManglingForReturnType(callableDescriptor)) { bytes: ByteArray,
val nameWithoutManglingSuffix = asmMethod.name.stripManglingSuffixOrNull() name: String,
if (nameWithoutManglingSuffix != null) { descriptor: String,
val methodWithoutMangling = getMethodNode(bytes, nameWithoutManglingSuffix, asmMethod.descriptor, classType) isSuspend: Boolean,
if (methodWithoutMangling != null) return methodWithoutMangling isMangled: Boolean
): SMAPAndMethodNode {
getMethodNode(owner, bytes, name, descriptor, isSuspend)?.let { return it }
if (isMangled) {
// Compatibility with old inline class ABI versions.
val dashIndex = name.indexOf('-')
val nameWithoutManglingSuffix = if (dashIndex > 0) name.substring(0, dashIndex) else name
if (nameWithoutManglingSuffix != name) {
getMethodNode(owner, bytes, nameWithoutManglingSuffix, descriptor, isSuspend)?.let { return it }
} }
return getMethodNode(bytes, "$nameWithoutManglingSuffix-impl", asmMethod.descriptor, classType) getMethodNode(owner, bytes, "$nameWithoutManglingSuffix-impl", descriptor, isSuspend)?.let { return it }
} }
throw IllegalStateException("couldn't find inline method $owner.$name$descriptor")
return methodNode
} }
private fun String.stripManglingSuffixOrNull(): String? { // If an `inline suspend fun` has a state machine, it should have a `$$forInline` version without one.
val dashIndex = indexOf('-') private fun getMethodNode(owner: Type, bytes: ByteArray, name: String, descriptor: String, isSuspend: Boolean) =
return if (dashIndex < 0) null else substring(0, dashIndex) (if (isSuspend) getMethodNode(bytes, name + FOR_INLINE_SUFFIX, descriptor, owner) else null)
} ?: getMethodNode(bytes, name, descriptor, owner)
private fun isBuiltInArrayIntrinsic(callableDescriptor: CallableMemberDescriptor): Boolean {
if (callableDescriptor is FictitiousArrayConstructor) return true
val name = callableDescriptor.name.asString()
return (name == "arrayOf" || name == "emptyArray") && callableDescriptor.containingDeclaration.let { container ->
container is PackageFragmentDescriptor && container.fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME
}
}
private fun StackValue.isCapturedInlineParameter(): Boolean { private fun StackValue.isCapturedInlineParameter(): Boolean {
val field = if (this is StackValue.FieldForSharedVar) receiver else this val field = if (this is StackValue.FieldForSharedVar) receiver else this
@@ -38,7 +38,7 @@ class InlineCodegenForDefaultBody(
override fun genCallInner(callableMethod: Callable, resolvedCall: ResolvedCall<*>?, callDefault: Boolean, codegen: ExpressionCodegen) { override fun genCallInner(callableMethod: Callable, resolvedCall: ResolvedCall<*>?, callDefault: Boolean, codegen: ExpressionCodegen) {
assert(!callDefault) { "inlining default stub into another default stub" } assert(!callDefault) { "inlining default stub into another default stub" }
val (node, smap) = sourceCompilerForInline.compileInlineFunction(jvmSignature, callDefault, jvmSignature.asmMethod) val (node, smap) = sourceCompilerForInline.compileInlineFunction(jvmSignature, callDefault)
val childSourceMapper = SourceMapCopier(sourceMapper, smap) val childSourceMapper = SourceMapCopier(sourceMapper, smap)
val argsSize = val argsSize =
@@ -28,7 +28,6 @@ import org.jetbrains.kotlin.resolve.inline.InlineUtil
import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
@@ -219,9 +218,6 @@ class PsiInlineCodegen(
::PsiDefaultLambda ::PsiDefaultLambda
) )
} }
override fun descriptorIsDeserialized(memberDescriptor: CallableMemberDescriptor): Boolean =
memberDescriptor is DescriptorWithContainerSource
} }
private val FunctionDescriptor.explicitParameters private val FunctionDescriptor.explicitParameters
@@ -11,16 +11,21 @@ import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.context.* import org.jetbrains.kotlin.codegen.context.*
import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.isReleaseCoroutines import org.jetbrains.kotlin.config.isReleaseCoroutines
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.incremental.KotlinLookupLocation import org.jetbrains.kotlin.incremental.KotlinLookupLocation
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCallWithAssert
import org.jetbrains.kotlin.resolve.isInlineClass import org.jetbrains.kotlin.resolve.isInlineClass
import org.jetbrains.kotlin.resolve.jvm.annotations.isCallableMemberCompiledToJvmDefault import org.jetbrains.kotlin.resolve.jvm.annotations.isCallableMemberCompiledToJvmDefault
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DescriptorWithContainerSource
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
import org.jetbrains.kotlin.types.expressions.LabelResolver import org.jetbrains.kotlin.types.expressions.LabelResolver
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
@@ -214,7 +219,32 @@ class PsiSourceCompilerForInline(
} }
} }
override fun compileInlineFunction(jvmSignature: JvmMethodSignature, callDefault: Boolean, asmMethod: Method): SMAPAndMethodNode { private fun getDirectMemberAndCallableFromObject(): CallableMemberDescriptor {
val directMember = JvmCodegenUtil.getDirectMember(functionDescriptor)
return (directMember as? ImportedFromObjectCallableDescriptor<*>)?.callableFromObject ?: directMember
}
override fun inlineFunctionSignature(jvmSignature: JvmMethodSignature, callDefault: Boolean): Pair<ClassId, Method>? {
val directMember = getDirectMemberAndCallableFromObject() as? DescriptorWithContainerSource
?: return null
val containerId = KotlinTypeMapper.getContainingClassesForDeserializedCallable(directMember).implClassId
if (!callDefault) {
return containerId to jvmSignature.asmMethod
}
// This is all available in the `Callable` passed to `PsiInlineCodegen.genCallInner`, but it's not forwarded through the inliner...
var result = state.typeMapper.mapDefaultMethod(functionDescriptor, contextKind)
if (result.name.contains("-") &&
!state.configuration.getBoolean(JVMConfigurationKeys.USE_OLD_INLINE_CLASSES_MANGLING_SCHEME) &&
classFileContainsMethod(functionDescriptor, state, result) == false
) {
state.typeMapper.useOldManglingRulesForFunctionAcceptingInlineClass = true
result = state.typeMapper.mapDefaultMethod(functionDescriptor, contextKind)
state.typeMapper.useOldManglingRulesForFunctionAcceptingInlineClass = false
}
return containerId to result
}
override fun compileInlineFunction(jvmSignature: JvmMethodSignature, callDefault: Boolean): SMAPAndMethodNode {
val element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor) val element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor)
if (!(element is KtNamedFunction || element is KtPropertyAccessor)) { if (!(element is KtNamedFunction || element is KtPropertyAccessor)) {
@@ -222,6 +252,10 @@ class PsiSourceCompilerForInline(
} }
val inliningFunction = element as KtDeclarationWithBody? val inliningFunction = element as KtDeclarationWithBody?
val asmMethod = if (callDefault)
state.typeMapper.mapDefaultMethod(functionDescriptor, contextKind)
else
jvmSignature.asmMethod
val node = MethodNode( val node = MethodNode(
Opcodes.API_VERSION, Opcodes.API_VERSION,
DescriptorAsmUtil.getMethodAsmFlags(functionDescriptor, context.contextKind, state) or DescriptorAsmUtil.getMethodAsmFlags(functionDescriptor, context.contextKind, state) or
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.incremental.components.LookupLocation import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -37,7 +38,9 @@ interface SourceCompilerForInline {
fun generateLambdaBody(lambdaInfo: ExpressionLambda, reifiedTypeParameters: ReifiedTypeParametersUsages): SMAPAndMethodNode fun generateLambdaBody(lambdaInfo: ExpressionLambda, reifiedTypeParameters: ReifiedTypeParametersUsages): SMAPAndMethodNode
fun compileInlineFunction(jvmSignature: JvmMethodSignature, callDefault: Boolean, asmMethod: Method): SMAPAndMethodNode fun inlineFunctionSignature(jvmSignature: JvmMethodSignature, callDefault: Boolean): Pair<ClassId, Method>?
fun compileInlineFunction(jvmSignature: JvmMethodSignature, callDefault: Boolean): SMAPAndMethodNode
fun hasFinallyBlocks(): Boolean fun hasFinallyBlocks(): Boolean
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForCoroutineConte
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForIntercepted import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForIntercepted
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineUninterceptedOrReturn import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineUninterceptedOrReturn
import org.jetbrains.kotlin.codegen.createMethodNodeForAlwaysEnabledAssert import org.jetbrains.kotlin.codegen.createMethodNodeForAlwaysEnabledAssert
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.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -26,11 +27,13 @@ import org.jetbrains.kotlin.types.model.TypeParameterMarker
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.commons.Method
import org.jetbrains.org.objectweb.asm.tree.MethodNode import org.jetbrains.org.objectweb.asm.tree.MethodNode
internal fun generateInlineIntrinsic( internal fun generateInlineIntrinsic(
state: GenerationState, state: GenerationState,
descriptor: FunctionDescriptor, descriptor: FunctionDescriptor,
asmMethod: Method,
typeParameters: List<TypeParameterMarker>?, typeParameters: List<TypeParameterMarker>?,
typeSystem: TypeSystemCommonBackendContext typeSystem: TypeSystemCommonBackendContext
): MethodNode? { ): MethodNode? {
@@ -49,6 +52,12 @@ internal fun generateInlineIntrinsic(
createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSettings)
descriptor.isBuiltinAlwaysEnabledAssert() -> descriptor.isBuiltinAlwaysEnabledAssert() ->
createMethodNodeForAlwaysEnabledAssert(descriptor) createMethodNodeForAlwaysEnabledAssert(descriptor)
descriptor is FictitiousArrayConstructor ->
IntrinsicArrayConstructors.generateArrayConstructorBody(asmMethod)
IntrinsicArrayConstructors.isArrayOf(descriptor) ->
IntrinsicArrayConstructors.generateArrayOfBody(asmMethod)
IntrinsicArrayConstructors.isEmptyArray(descriptor) ->
IntrinsicArrayConstructors.generateEmptyArrayBody(asmMethod)
else -> null else -> null
} }
} }
@@ -16,10 +16,14 @@
package org.jetbrains.kotlin.codegen.intrinsics package org.jetbrains.kotlin.codegen.intrinsics
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.inline.ReificationArgument import org.jetbrains.kotlin.codegen.inline.ReificationArgument
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Label
@@ -30,6 +34,15 @@ 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 object IntrinsicArrayConstructors { internal object IntrinsicArrayConstructors {
fun isArrayOf(descriptor: FunctionDescriptor): Boolean =
descriptor.name.asString() == "arrayOf" && descriptor.containingDeclaration.isBuiltInsPackage
fun isEmptyArray(descriptor: FunctionDescriptor): Boolean =
descriptor.name.asString() == "emptyArray" && descriptor.containingDeclaration.isBuiltInsPackage
private val DeclarationDescriptor.isBuiltInsPackage: Boolean
get() = this is PackageFragmentDescriptor && fqName == StandardNames.BUILT_INS_PACKAGE_FQ_NAME
fun generateArrayConstructorBody(method: Method): MethodNode { fun generateArrayConstructorBody(method: Method): MethodNode {
val node = MethodNode( val node = MethodNode(
Opcodes.ASM6, Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC or Opcodes.ACC_FINAL, method.name, method.descriptor, null, null Opcodes.ASM6, Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC or Opcodes.ACC_FINAL, method.name, method.descriptor, null, null
@@ -16,7 +16,6 @@ import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.ValueKind 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.CallableMemberDescriptor
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.descriptors.* import org.jetbrains.kotlin.ir.descriptors.*
import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.expressions.*
@@ -150,9 +149,6 @@ class IrInlineCodegen(
::IrDefaultLambda ::IrDefaultLambda
) )
} }
override fun descriptorIsDeserialized(memberDescriptor: CallableMemberDescriptor): Boolean =
((memberDescriptor as IrBasedDeclarationDescriptor<*>).owner as IrMemberWithContainerSource).parentClassId != null
} }
class IrExpressionLambdaImpl( class IrExpressionLambdaImpl(
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.ir.expressions.IrLoop
import org.jetbrains.kotlin.ir.util.isSuspend import org.jetbrains.kotlin.ir.util.isSuspend
import org.jetbrains.kotlin.ir.util.module import org.jetbrains.kotlin.ir.util.module
import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.doNotAnalyze import org.jetbrains.kotlin.psi.doNotAnalyze
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR
@@ -104,7 +105,10 @@ 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, callDefault: Boolean, asmMethod: Method): SMAPAndMethodNode = override fun inlineFunctionSignature(jvmSignature: JvmMethodSignature, callDefault: Boolean): Pair<ClassId, Method>? =
callee.parentClassId?.let { it to jvmSignature.asmMethod }
override fun compileInlineFunction(jvmSignature: JvmMethodSignature, callDefault: Boolean): SMAPAndMethodNode =
ClassCodegen.getOrCreate(callee.parentAsClass, codegen.context).generateMethodNode(callee) ClassCodegen.getOrCreate(callee.parentAsClass, codegen.context).generateMethodNode(callee)
override fun hasFinallyBlocks() = data.hasFinallyBlocks() override fun hasFinallyBlocks() = data.hasFinallyBlocks()