From 214ef0c3c2859bb3bb0d1b7f6810e5b796d0036d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 15 Feb 2019 15:08:05 +0100 Subject: [PATCH] Move generation of inline intrinsics to inlineIntrinsics.kt --- .../kotlin/codegen/inline/InlineCodegen.kt | 43 +-------- .../codegen/inline/inlineCodegenUtils.kt | 62 +----------- .../kotlin/codegen/inline/inlineIntrinsics.kt | 96 +++++++++++++++++++ 3 files changed, 103 insertions(+), 98 deletions(-) create mode 100644 compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineIntrinsics.kt 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 9f0afff50ab..5ce27b3b529 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -7,16 +7,11 @@ package org.jetbrains.kotlin.codegen.inline import com.intellij.psi.PsiElement import com.intellij.util.ArrayUtil -import org.jetbrains.kotlin.backend.common.isBuiltInIntercepted import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive import org.jetbrains.kotlin.codegen.context.ClosureContext -import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForCoroutineContext -import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForIntercepted -import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineUninterceptedOrReturn -import org.jetbrains.kotlin.codegen.coroutines.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm import org.jetbrains.kotlin.codegen.intrinsics.bytecode import org.jetbrains.kotlin.codegen.intrinsics.classId import org.jetbrains.kotlin.codegen.state.GenerationState @@ -32,7 +27,6 @@ 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.calls.checkers.isBuiltInCoroutineContext import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression @@ -467,40 +461,9 @@ abstract class InlineCodegen( state: GenerationState, sourceCompilerForInline: SourceCompilerForInline ): SMAPAndMethodNode { - val languageVersionSettings = state.languageVersionSettings - when { - isSpecialEnumMethod(functionDescriptor) -> { - val node = createSpecialEnumMethodBody( - functionDescriptor.name.asString(), - typeArguments!!.keys.single().defaultType, - state.typeMapper - ) - return SMAPAndMethodNode(node, createDefaultFakeSMAP()) - } - functionDescriptor.isBuiltInIntercepted(languageVersionSettings) -> - return SMAPAndMethodNode( - createMethodNodeForIntercepted(functionDescriptor, state.typeMapper, languageVersionSettings), - createDefaultFakeSMAP() - ) - functionDescriptor.isBuiltInCoroutineContext(languageVersionSettings) -> - return SMAPAndMethodNode( - createMethodNodeForCoroutineContext(functionDescriptor, languageVersionSettings), - createDefaultFakeSMAP() - ) - functionDescriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm(languageVersionSettings) -> - return SMAPAndMethodNode( - createMethodNodeForSuspendCoroutineUninterceptedOrReturn( - functionDescriptor, - state.typeMapper, - languageVersionSettings - ), - createDefaultFakeSMAP() - ) - functionDescriptor.isBuiltinAlwaysEnabledAssert() -> - return SMAPAndMethodNode( - createMethodNodeForAlwaysEnabledAssert(functionDescriptor, state.typeMapper), - createDefaultFakeSMAP() - ) + val intrinsic = generateInlineIntrinsic(state, functionDescriptor, typeArguments) + if (intrinsic != null) { + return SMAPAndMethodNode(intrinsic, createDefaultFakeSMAP()) } val asmMethod = if (callDefault) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt index 96982573414..bb6cf4343f6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineCodegenUtils.kt @@ -7,7 +7,10 @@ package org.jetbrains.kotlin.codegen.inline import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.codegen.* +import org.jetbrains.kotlin.codegen.ASSERTIONS_DISABLED_FIELD_NAME +import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.BaseExpressionCodegen +import org.jetbrains.kotlin.codegen.JvmCodegenUtil import org.jetbrains.kotlin.codegen.SamWrapperCodegen.SAM_WRAPPER_SUFFIX import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping import org.jetbrains.kotlin.codegen.binding.CodegenBinding @@ -33,12 +36,9 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.jvm.AsmTypes -import org.jetbrains.kotlin.resolve.jvm.AsmTypes.ENUM_TYPE -import org.jetbrains.kotlin.resolve.jvm.AsmTypes.JAVA_CLASS_TYPE import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.source.PsiSourceElement import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor -import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeProjectionImpl import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.util.OperatorNameConventions @@ -531,60 +531,6 @@ fun isFakeLocalVariableForInline(name: String): Boolean { internal fun isThis0(name: String): Boolean = AsmUtil.CAPTURED_THIS_FIELD == name -internal fun isSpecialEnumMethod(functionDescriptor: FunctionDescriptor): Boolean { - val containingDeclaration = functionDescriptor.containingDeclaration as? PackageFragmentDescriptor ?: return false - if (containingDeclaration.fqName != KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME) { - return false - } - if (functionDescriptor.typeParameters.size != 1) { - return false - } - val name = functionDescriptor.name.asString() - val parameters = functionDescriptor.valueParameters - return "enumValues" == name && parameters.size == 0 || - ("enumValueOf" == name && parameters.size == 1 && - KotlinBuiltIns.isString(parameters[0].type)) -} - -internal fun createSpecialEnumMethodBody( - name: String, - type: KotlinType, - typeMapper: KotlinTypeMapper -): MethodNode { - val isValueOf = "enumValueOf" == name - val invokeType = typeMapper.mapType(type) - val desc = getSpecialEnumFunDescriptor(invokeType, isValueOf) - val node = MethodNode(Opcodes.API_VERSION, Opcodes.ACC_STATIC, "fake", desc, null, null) - ExpressionCodegen.putReifiedOperationMarkerIfTypeIsReifiedParameterWithoutPropagation( - type, - ReifiedTypeInliner.OperationKind.ENUM_REIFIED, - InstructionAdapter(node) - ) - if (isValueOf) { - node.visitInsn(Opcodes.ACONST_NULL) - node.visitVarInsn(Opcodes.ALOAD, 0) - - node.visitMethodInsn( - Opcodes.INVOKESTATIC, ENUM_TYPE.internalName, "valueOf", - Type.getMethodDescriptor(ENUM_TYPE, JAVA_CLASS_TYPE, AsmTypes.JAVA_STRING_TYPE), false - ) - } else { - node.visitInsn(Opcodes.ICONST_0) - node.visitTypeInsn(Opcodes.ANEWARRAY, ENUM_TYPE.internalName) - } - node.visitInsn(Opcodes.ARETURN) - node.visitMaxs(if (isValueOf) 3 else 2, if (isValueOf) 1 else 0) - return node -} - -internal fun getSpecialEnumFunDescriptor(type: Type, isValueOf: Boolean): String { - return if (isValueOf) Type.getMethodDescriptor( - type, - AsmTypes.JAVA_STRING_TYPE - ) else Type.getMethodDescriptor(AsmUtil.getArrayType(type)) -} - - val FunctionDescriptor.sourceFilePath: String get() { val source = source as PsiSourceElement diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineIntrinsics.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineIntrinsics.kt new file mode 100644 index 00000000000..c5ffa406eee --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineIntrinsics.kt @@ -0,0 +1,96 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. 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.codegen.inline + +import org.jetbrains.kotlin.backend.common.isBuiltInIntercepted +import org.jetbrains.kotlin.builtins.KotlinBuiltIns +import org.jetbrains.kotlin.codegen.AsmUtil +import org.jetbrains.kotlin.codegen.ExpressionCodegen +import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForCoroutineContext +import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForIntercepted +import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineUninterceptedOrReturn +import org.jetbrains.kotlin.codegen.coroutines.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm +import org.jetbrains.kotlin.codegen.createMethodNodeForAlwaysEnabledAssert +import org.jetbrains.kotlin.codegen.isBuiltinAlwaysEnabledAssert +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.PackageFragmentDescriptor +import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.resolve.calls.checkers.isBuiltInCoroutineContext +import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* +import org.jetbrains.kotlin.types.KotlinType +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.tree.MethodNode + +internal fun generateInlineIntrinsic( + state: GenerationState, + descriptor: FunctionDescriptor, + typeArguments: Map? +): MethodNode? { + val languageVersionSettings = state.languageVersionSettings + val typeMapper = state.typeMapper + return when { + isSpecialEnumMethod(descriptor) -> + createSpecialEnumMethodBody(descriptor.name.asString(), typeArguments!!.keys.single().defaultType, typeMapper) + descriptor.isBuiltInIntercepted(languageVersionSettings) -> + createMethodNodeForIntercepted(descriptor, typeMapper, languageVersionSettings) + descriptor.isBuiltInCoroutineContext(languageVersionSettings) -> + createMethodNodeForCoroutineContext(descriptor, languageVersionSettings) + descriptor.isBuiltInSuspendCoroutineUninterceptedOrReturnInJvm(languageVersionSettings) -> + createMethodNodeForSuspendCoroutineUninterceptedOrReturn(descriptor, typeMapper, languageVersionSettings) + descriptor.isBuiltinAlwaysEnabledAssert() -> + createMethodNodeForAlwaysEnabledAssert(descriptor, typeMapper) + else -> null + } +} + +private fun isSpecialEnumMethod(descriptor: FunctionDescriptor): Boolean { + val containingDeclaration = descriptor.containingDeclaration as? PackageFragmentDescriptor ?: return false + if (containingDeclaration.fqName != KotlinBuiltIns.BUILT_INS_PACKAGE_FQ_NAME) { + return false + } + if (descriptor.typeParameters.size != 1) { + return false + } + val name = descriptor.name.asString() + val parameters = descriptor.valueParameters + return name == "enumValues" && parameters.size == 0 || + (name == "enumValueOf" && parameters.size == 1 && KotlinBuiltIns.isString(parameters[0].type)) +} + +private fun createSpecialEnumMethodBody(name: String, type: KotlinType, typeMapper: KotlinTypeMapper): MethodNode { + val isValueOf = "enumValueOf" == name + val invokeType = typeMapper.mapType(type) + val desc = getSpecialEnumFunDescriptor(invokeType, isValueOf) + val node = MethodNode(Opcodes.API_VERSION, Opcodes.ACC_STATIC, "fake", desc, null, null) + ExpressionCodegen.putReifiedOperationMarkerIfTypeIsReifiedParameterWithoutPropagation( + type, + ReifiedTypeInliner.OperationKind.ENUM_REIFIED, + InstructionAdapter(node) + ) + if (isValueOf) { + node.visitInsn(Opcodes.ACONST_NULL) + node.visitVarInsn(Opcodes.ALOAD, 0) + + node.visitMethodInsn( + Opcodes.INVOKESTATIC, ENUM_TYPE.internalName, "valueOf", + Type.getMethodDescriptor(ENUM_TYPE, JAVA_CLASS_TYPE, JAVA_STRING_TYPE), false + ) + } else { + node.visitInsn(Opcodes.ICONST_0) + node.visitTypeInsn(Opcodes.ANEWARRAY, ENUM_TYPE.internalName) + } + node.visitInsn(Opcodes.ARETURN) + node.visitMaxs(if (isValueOf) 3 else 2, if (isValueOf) 1 else 0) + return node +} + +internal fun getSpecialEnumFunDescriptor(type: Type, isValueOf: Boolean): String = + if (isValueOf) Type.getMethodDescriptor(type, JAVA_STRING_TYPE) + else Type.getMethodDescriptor(AsmUtil.getArrayType(type))