From ed26e97df8c73bb3c86f094ede51a2c3ae0ef065 Mon Sep 17 00:00:00 2001 From: pyos Date: Thu, 27 May 2021 11:25:21 +0200 Subject: [PATCH] JVM: refactor loading of inline functions from binaries The IR path no longer does any descriptor unwrapping or old-style type mapping. --- .../DelegatedPropertiesCodegenHelper.kt | 11 +- .../kotlin/codegen/inline/InlineCodegen.kt | 168 +++++------------- .../inline/InlineCodegenForDefaultBody.kt | 2 +- .../kotlin/codegen/inline/PsiInlineCodegen.kt | 4 - .../inline/PsiSourceCompilerForInline.kt | 36 +++- .../codegen/inline/SourceCompilerForInline.kt | 5 +- .../kotlin/codegen/inline/inlineIntrinsics.kt | 9 + .../intrinsics/IntrinsicArrayConstructors.kt | 13 ++ .../backend/jvm/codegen/IrInlineCodegen.kt | 4 - .../jvm/codegen/IrSourceCompilerForInline.kt | 6 +- 10 files changed, 114 insertions(+), 144 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/DelegatedPropertiesCodegenHelper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/DelegatedPropertiesCodegenHelper.kt index 11cf6c63aed..25d4be238ac 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/DelegatedPropertiesCodegenHelper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/DelegatedPropertiesCodegenHelper.kt @@ -9,11 +9,13 @@ import org.jetbrains.kotlin.codegen.binding.CodegenBinding import org.jetbrains.kotlin.codegen.inline.InlineCodegen import org.jetbrains.kotlin.codegen.optimization.nullCheck.isCheckParameterIsNotNull 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.VariableDescriptorWithAccessors import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.FunctionImportedFromObject 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.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode @@ -65,13 +67,14 @@ class DelegatedPropertiesCodegenHelper(private val state: GenerationState) { this private fun isDelegatedPropertyMetadataRequiredForFunctionFromBinaries(calleeDescriptor: FunctionDescriptor): Boolean { - assert(calleeDescriptor is DescriptorWithContainerSource) { + require(calleeDescriptor is DescriptorWithContainerSource) { "Function descriptor from binaries expected: $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) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt index 2bcc208d399..9c093b6c20a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -6,28 +6,23 @@ package org.jetbrains.kotlin.codegen.inline import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive import org.jetbrains.kotlin.codegen.context.ClosureContext 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.KotlinTypeMapper import org.jetbrains.kotlin.config.CommonConfigurationKeys -import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.incremental.components.Position import org.jetbrains.kotlin.incremental.components.ScopeKind +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils 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.isInlineOnly import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature 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.model.TypeParameterMarker import org.jetbrains.org.objectweb.asm.Label @@ -250,8 +245,6 @@ abstract class InlineCodegen( abstract fun extractDefaultLambdas(node: MethodNode): List - abstract fun descriptorIsDeserialized(memberDescriptor: CallableMemberDescriptor): Boolean - private fun generateAndInsertFinallyBlocks( intoNode: MethodNode, insertPoints: List, @@ -433,144 +426,63 @@ abstract class InlineCodegen( typeArguments: List?, typeSystem: TypeSystemCommonBackendContext ): SMAPAndMethodNode { - val intrinsic = generateInlineIntrinsic(state, functionDescriptor, typeArguments, typeSystem) + val intrinsic = generateInlineIntrinsic(state, functionDescriptor, jvmSignature.asmMethod, typeArguments, typeSystem) if (intrinsic != null) { - return SMAPAndMethodNode(intrinsic, createDefaultFakeSMAP()) + return SMAPAndMethodNode(intrinsic, SMAP(listOf())) } - - var asmMethod = mapMethod(callDefault) - if (asmMethod.name.contains("-") && - !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 + sourceCompiler.inlineFunctionSignature(jvmSignature, callDefault)?.let { (containerId, asmMethod) -> + val isMangled = requiresFunctionNameManglingForReturnType(functionDescriptor) + return loadCompiledInlineFunction(containerId, asmMethod, functionDescriptor.isSuspend, isMangled, state) } - - val directMember = getDirectMemberAndCallableFromObject(functionDescriptor) - if (!isBuiltInArrayIntrinsic(functionDescriptor) && !descriptorIsDeserialized(directMember)) { - val node = sourceCompiler.compileInlineFunction(jvmSignature, callDefault, asmMethod) - node.node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false) - return node + return sourceCompiler.compileInlineFunction(jvmSignature, callDefault).apply { + node.preprocessSuspendMarkers(forInline = true, keepFakeContinuation = false) } - - 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 { - - internal fun createSpecialInlineMethodNodeFromBinaries(functionDescriptor: FunctionDescriptor, state: GenerationState): MethodNode { - 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, + internal fun loadCompiledInlineFunction( + containerId: ClassId, asmMethod: Method, - methodOwner: Type, - state: GenerationState, - jvmSignature: JvmMethodSignature + isSuspend: Boolean, + isMangled: Boolean, + state: GenerationState ): SMAPAndMethodNode { - val methodId = MethodId(methodOwner.internalName, asmMethod) - - 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 containerType = AsmUtil.asmTypeByClassId(containerId) val bytes = state.inlineCache.classBytes.getOrPut(containerId) { findVirtualFile(state, containerId)?.contentsToByteArray() ?: 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) - val methodNode = getMethodNode(bytes, asmMethod.name, asmMethod.descriptor, classType) - if (methodNode == null && requiresFunctionNameManglingForReturnType(callableDescriptor)) { - val nameWithoutManglingSuffix = asmMethod.name.stripManglingSuffixOrNull() - if (nameWithoutManglingSuffix != null) { - val methodWithoutMangling = getMethodNode(bytes, nameWithoutManglingSuffix, asmMethod.descriptor, classType) - if (methodWithoutMangling != null) return methodWithoutMangling + private fun getMethodNode( + owner: Type, + bytes: ByteArray, + name: String, + descriptor: String, + isSuspend: Boolean, + 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 } } - - return methodNode + throw IllegalStateException("couldn't find inline method $owner.$name$descriptor") } - private fun String.stripManglingSuffixOrNull(): String? { - val dashIndex = indexOf('-') - return if (dashIndex < 0) null else substring(0, dashIndex) - } - - 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 - } - } + // If an `inline suspend fun` has a state machine, it should have a `$$forInline` version without one. + private fun getMethodNode(owner: Type, bytes: ByteArray, name: String, descriptor: String, isSuspend: Boolean) = + (if (isSuspend) getMethodNode(bytes, name + FOR_INLINE_SUFFIX, descriptor, owner) else null) + ?: getMethodNode(bytes, name, descriptor, owner) private fun StackValue.isCapturedInlineParameter(): Boolean { val field = if (this is StackValue.FieldForSharedVar) receiver else this diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt index eb68684c870..d8b3fbac565 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegenForDefaultBody.kt @@ -38,7 +38,7 @@ class InlineCodegenForDefaultBody( override fun genCallInner(callableMethod: Callable, resolvedCall: ResolvedCall<*>?, callDefault: Boolean, codegen: ExpressionCodegen) { 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 argsSize = diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt index 3a87f6639b1..d7e43fa077d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt @@ -28,7 +28,6 @@ import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind 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.util.OperatorNameConventions import org.jetbrains.org.objectweb.asm.Label @@ -219,9 +218,6 @@ class PsiInlineCodegen( ::PsiDefaultLambda ) } - - override fun descriptorIsDeserialized(memberDescriptor: CallableMemberDescriptor): Boolean = - memberDescriptor is DescriptorWithContainerSource } private val FunctionDescriptor.explicitParameters diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiSourceCompilerForInline.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiSourceCompilerForInline.kt index 85475259d18..82bf5aab292 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiSourceCompilerForInline.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiSourceCompilerForInline.kt @@ -11,16 +11,21 @@ import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.context.* import org.jetbrains.kotlin.codegen.coroutines.getOrCreateJvmSuspendFunctionView 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.descriptors.* import org.jetbrains.kotlin.incremental.KotlinLookupLocation +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils 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.isInlineClass import org.jetbrains.kotlin.resolve.jvm.annotations.isCallableMemberCompiledToJvmDefault 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.LabelResolver 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? { + 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) if (!(element is KtNamedFunction || element is KtPropertyAccessor)) { @@ -222,6 +252,10 @@ class PsiSourceCompilerForInline( } val inliningFunction = element as KtDeclarationWithBody? + val asmMethod = if (callDefault) + state.typeMapper.mapDefaultMethod(functionDescriptor, contextKind) + else + jvmSignature.asmMethod val node = MethodNode( Opcodes.API_VERSION, DescriptorAsmUtil.getMethodAsmFlags(functionDescriptor, context.contextKind, state) or diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt index 80db374c058..26679241aca 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/SourceCompilerForInline.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.incremental.components.LookupLocation +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.org.objectweb.asm.Label import org.jetbrains.org.objectweb.asm.Type @@ -37,7 +38,9 @@ interface SourceCompilerForInline { fun generateLambdaBody(lambdaInfo: ExpressionLambda, reifiedTypeParameters: ReifiedTypeParametersUsages): SMAPAndMethodNode - fun compileInlineFunction(jvmSignature: JvmMethodSignature, callDefault: Boolean, asmMethod: Method): SMAPAndMethodNode + fun inlineFunctionSignature(jvmSignature: JvmMethodSignature, callDefault: Boolean): Pair? + + fun compileInlineFunction(jvmSignature: JvmMethodSignature, callDefault: Boolean): SMAPAndMethodNode fun hasFinallyBlocks(): Boolean diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineIntrinsics.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineIntrinsics.kt index 73e0bcaef8d..b059be8079a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineIntrinsics.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineIntrinsics.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForCoroutineConte import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForIntercepted import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineUninterceptedOrReturn import org.jetbrains.kotlin.codegen.createMethodNodeForAlwaysEnabledAssert +import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicArrayConstructors import org.jetbrains.kotlin.codegen.isBuiltinAlwaysEnabledAssert import org.jetbrains.kotlin.codegen.state.GenerationState 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.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter +import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.tree.MethodNode internal fun generateInlineIntrinsic( state: GenerationState, descriptor: FunctionDescriptor, + asmMethod: Method, typeParameters: List?, typeSystem: TypeSystemCommonBackendContext ): MethodNode? { @@ -49,6 +52,12 @@ internal fun generateInlineIntrinsic( createMethodNodeForSuspendCoroutineUninterceptedOrReturn(languageVersionSettings) descriptor.isBuiltinAlwaysEnabledAssert() -> createMethodNodeForAlwaysEnabledAssert(descriptor) + descriptor is FictitiousArrayConstructor -> + IntrinsicArrayConstructors.generateArrayConstructorBody(asmMethod) + IntrinsicArrayConstructors.isArrayOf(descriptor) -> + IntrinsicArrayConstructors.generateArrayOfBody(asmMethod) + IntrinsicArrayConstructors.isEmptyArray(descriptor) -> + IntrinsicArrayConstructors.generateEmptyArrayBody(asmMethod) else -> null } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicArrayConstructors.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicArrayConstructors.kt index f1fbc775d52..30d9aed8c3b 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicArrayConstructors.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/IntrinsicArrayConstructors.kt @@ -16,10 +16,14 @@ package org.jetbrains.kotlin.codegen.intrinsics +import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.inline.ReificationArgument 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.util.OperatorNameConventions 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 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 { val node = MethodNode( Opcodes.ASM6, Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC or Opcodes.ACC_FINAL, method.name, method.descriptor, null, null diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt index 25dffc09ff5..e9d7f3621f5 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineCodegen.kt @@ -16,7 +16,6 @@ import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.ValueKind import org.jetbrains.kotlin.codegen.inline.* import org.jetbrains.kotlin.codegen.state.GenerationState -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.descriptors.* import org.jetbrains.kotlin.ir.expressions.* @@ -150,9 +149,6 @@ class IrInlineCodegen( ::IrDefaultLambda ) } - - override fun descriptorIsDeserialized(memberDescriptor: CallableMemberDescriptor): Boolean = - ((memberDescriptor as IrBasedDeclarationDescriptor<*>).owner as IrMemberWithContainerSource).parentClassId != null } class IrExpressionLambdaImpl( diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt index 4568cea5e6e..6f441631042 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrSourceCompilerForInline.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.ir.expressions.IrLoop import org.jetbrains.kotlin.ir.util.isSuspend import org.jetbrains.kotlin.ir.util.module import org.jetbrains.kotlin.ir.util.parentAsClass +import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.doNotAnalyze 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) } - override fun compileInlineFunction(jvmSignature: JvmMethodSignature, callDefault: Boolean, asmMethod: Method): SMAPAndMethodNode = + override fun inlineFunctionSignature(jvmSignature: JvmMethodSignature, callDefault: Boolean): Pair? = + callee.parentClassId?.let { it to jvmSignature.asmMethod } + + override fun compileInlineFunction(jvmSignature: JvmMethodSignature, callDefault: Boolean): SMAPAndMethodNode = ClassCodegen.getOrCreate(callee.parentAsClass, codegen.context).generateMethodNode(callee) override fun hasFinallyBlocks() = data.hasFinallyBlocks()