Move generation of inline intrinsics to inlineIntrinsics.kt

This commit is contained in:
Alexander Udalov
2019-02-15 15:08:05 +01:00
parent 69eae035f6
commit 214ef0c3c2
3 changed files with 103 additions and 98 deletions
@@ -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<out T : BaseExpressionCodegen>(
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)
@@ -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
@@ -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<TypeParameterDescriptor, KotlinType>?
): 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))