Move generation of inline intrinsics to inlineIntrinsics.kt
This commit is contained in:
@@ -7,16 +7,11 @@ package org.jetbrains.kotlin.codegen.inline
|
|||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
import com.intellij.util.ArrayUtil
|
import com.intellij.util.ArrayUtil
|
||||||
import org.jetbrains.kotlin.backend.common.isBuiltInIntercepted
|
|
||||||
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment
|
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment
|
||||||
import org.jetbrains.kotlin.codegen.*
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags
|
import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags
|
||||||
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.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.bytecode
|
||||||
import org.jetbrains.kotlin.codegen.intrinsics.classId
|
import org.jetbrains.kotlin.codegen.intrinsics.classId
|
||||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
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.DescriptorUtils
|
||||||
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
|
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.calls.checkers.isBuiltInCoroutineContext
|
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression
|
import org.jetbrains.kotlin.resolve.inline.InlineUtil.isInlinableParameterExpression
|
||||||
@@ -467,40 +461,9 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
|
|||||||
state: GenerationState,
|
state: GenerationState,
|
||||||
sourceCompilerForInline: SourceCompilerForInline
|
sourceCompilerForInline: SourceCompilerForInline
|
||||||
): SMAPAndMethodNode {
|
): SMAPAndMethodNode {
|
||||||
val languageVersionSettings = state.languageVersionSettings
|
val intrinsic = generateInlineIntrinsic(state, functionDescriptor, typeArguments)
|
||||||
when {
|
if (intrinsic != null) {
|
||||||
isSpecialEnumMethod(functionDescriptor) -> {
|
return SMAPAndMethodNode(intrinsic, createDefaultFakeSMAP())
|
||||||
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 asmMethod = if (callDefault)
|
val asmMethod = if (callDefault)
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ package org.jetbrains.kotlin.codegen.inline
|
|||||||
|
|
||||||
import com.intellij.openapi.vfs.VirtualFile
|
import com.intellij.openapi.vfs.VirtualFile
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
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.SamWrapperCodegen.SAM_WRAPPER_SUFFIX
|
||||||
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping
|
import org.jetbrains.kotlin.codegen.`when`.WhenByEnumsMapping
|
||||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
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.DescriptorToSourceUtils
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
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.jvm.JvmClassName
|
||||||
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
import org.jetbrains.kotlin.resolve.source.PsiSourceElement
|
||||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
|
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.TypeProjectionImpl
|
||||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
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 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
|
val FunctionDescriptor.sourceFilePath: String
|
||||||
get() {
|
get() {
|
||||||
val source = source as PsiSourceElement
|
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))
|
||||||
Reference in New Issue
Block a user