From d1df453edc95fa3dbab82301a957809d540b409a Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 4 Sep 2019 16:05:50 +0200 Subject: [PATCH] Do not use KotlinTypeMapper in generateTypeOf inline intrinsic Make ReifiedTypeInliner and related classes generic over the KotlinTypeMarker subtype (KotlinType or IrType), add a typeSystem to get arguments/nullability and other properties of types regardless of their representation, but still fall back to KotlinType when generating the actual bytecode of other intrinsics (as/is) --- .../kotlin/codegen/ExpressionCodegen.java | 12 +- .../kotlin/codegen/inline/InlineCodegen.kt | 10 +- .../kotlin/codegen/inline/InliningContext.kt | 4 +- .../kotlin/codegen/inline/LambdaInfo.kt | 8 +- .../kotlin/codegen/inline/PsiInlineCodegen.kt | 15 ++- .../codegen/inline/ReifiedTypeInliner.kt | 111 ++++++++++-------- .../kotlin/codegen/inline/TypeRemapper.kt | 6 +- .../kotlin/codegen/inline/inlineIntrinsics.kt | 84 +++++++------ .../kotlin/fir/types/ConeTypeContext.kt | 6 + .../backend/jvm/codegen/ExpressionCodegen.kt | 43 ++++--- .../backend/jvm/codegen/IrInlineCodegen.kt | 9 +- .../kotlin/ir/types/IrTypeSystemContext.kt | 9 ++ .../types/TypeSystemCommonBackendContext.kt | 4 + .../types/checker/ClassicTypeSystemContext.kt | 13 +- .../types/checker/NewKotlinTypeChecker.kt | 3 + 15 files changed, 205 insertions(+), 132 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index b253893df34..4500f3c76dd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -77,10 +77,8 @@ import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.resolve.scopes.receivers.*; import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor; -import org.jetbrains.kotlin.types.KotlinType; -import org.jetbrains.kotlin.types.SimpleType; -import org.jetbrains.kotlin.types.TypeProjection; -import org.jetbrains.kotlin.types.TypeUtils; +import org.jetbrains.kotlin.types.*; +import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContextImpl; import org.jetbrains.kotlin.types.expressions.DoubleColonLHS; import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt; import org.jetbrains.kotlin.util.OperatorNameConventions; @@ -125,6 +123,7 @@ public class ExpressionCodegen extends KtVisitor impleme private final TailRecursionCodegen tailRecursionCodegen; public final CallGenerator defaultCallGenerator = new CallGenerator.DefaultCallGenerator(this); private final SwitchCodegenProvider switchCodegenProvider; + public final TypeSystemCommonBackendContext typeSystem; private final Stack blockStackElements = new Stack<>(); @@ -157,6 +156,7 @@ public class ExpressionCodegen extends KtVisitor impleme this.parentCodegen = parentCodegen; this.tailRecursionCodegen = new TailRecursionCodegen(context, this, this.v, state); this.switchCodegenProvider = new SwitchCodegenProvider(this); + this.typeSystem = new ClassicTypeSystemContextImpl(state.getModule().getBuiltIns()); } @Nullable @@ -2622,7 +2622,7 @@ public class ExpressionCodegen extends KtVisitor impleme private CallGenerator getOrCreateCallGenerator( @NotNull CallableDescriptor descriptor, @Nullable KtElement callElement, - @Nullable TypeParameterMappings typeParameterMappings, + @Nullable TypeParameterMappings typeParameterMappings, boolean isDefaultCompilation ) { if (callElement == null) return defaultCallGenerator; @@ -2672,7 +2672,7 @@ public class ExpressionCodegen extends KtVisitor impleme CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall resolvedCall, @NotNull CallableDescriptor descriptor) { Map typeArguments = getTypeArgumentsForResolvedCall(resolvedCall, descriptor); - TypeParameterMappings mappings = new TypeParameterMappings(); + TypeParameterMappings mappings = new TypeParameterMappings<>(); for (Map.Entry entry : typeArguments.entrySet()) { TypeParameterDescriptor key = entry.getKey(); KotlinType type = entry.getValue(); 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 ae54af65149..1ae11f7078d 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InlineCodegen.kt @@ -47,8 +47,9 @@ abstract class InlineCodegen( protected val functionDescriptor: FunctionDescriptor, private val methodOwner: Type, protected val jvmSignature: JvmMethodSignature, - private val typeParameterMappings: TypeParameterMappings, - protected val sourceCompiler: SourceCompilerForInline + private val typeParameterMappings: TypeParameterMappings<*>, + protected val sourceCompiler: SourceCompilerForInline, + private val reifiedTypeInliner: ReifiedTypeInliner<*> ) { init { assert(InlineUtil.isInline(functionDescriptor)) { @@ -59,13 +60,8 @@ abstract class InlineCodegen( // TODO: implement AS_FUNCTION inline strategy private val asFunctionInline = false - protected val typeMapper = state.typeMapper - private val initialFrameSize = codegen.frameMap.currentSize - private val reifiedTypeInliner = - ReifiedTypeInliner(typeParameterMappings, state.typeMapper, state.languageVersionSettings) - private val isSameModule: Boolean protected val invocationParamBuilder = ParametersBuilder.newBuilder() diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InliningContext.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InliningContext.kt index 929c38e2abe..4672c05d386 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InliningContext.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/InliningContext.kt @@ -14,8 +14,8 @@ class RootInliningContext( nameGenerator: NameGenerator, val sourceCompilerForInline: SourceCompilerForInline, override val callSiteInfo: InlineCallSiteInfo, - val inlineMethodReifier: ReifiedTypeInliner, - typeParameterMappings: TypeParameterMappings + val inlineMethodReifier: ReifiedTypeInliner<*>, + typeParameterMappings: TypeParameterMappings<*> ) : InliningContext( null, expressionMap, state, nameGenerator, TypeRemapper.createRoot(typeParameterMappings), null, false ) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt index 697041850d7..3f1648e6de6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/LambdaInfo.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.codegen.inline import com.intellij.psi.PsiElement import org.jetbrains.kotlin.codegen.AsmUtil -import org.jetbrains.kotlin.codegen.OwnerKind import org.jetbrains.kotlin.codegen.PropertyReferenceCodegen import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.binding.CalculatedClosure @@ -32,7 +31,6 @@ import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.Method import org.jetbrains.org.objectweb.asm.tree.FieldInsnNode -import org.jetbrains.org.objectweb.asm.tree.MethodNode import kotlin.properties.Delegates interface FunctionalArgument @@ -51,7 +49,7 @@ abstract class LambdaInfo(@JvmField val isCrossInline: Boolean) : FunctionalArgu lateinit var node: SMAPAndMethodNode - abstract fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner) + abstract fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner<*>) open val hasDispatchReceiver = true @@ -108,7 +106,7 @@ class DefaultLambda( var originalBoundReceiverType: Type? = null private set - override fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner) { + override fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner<*>) { val classReader = buildClassReaderByInternalName(sourceCompiler.state, lambdaClassType.internalName) var isPropertyReference = false var isFunctionReference = false @@ -189,7 +187,7 @@ internal fun Type.boxReceiverForBoundReference(kotlinType: KotlinType, typeMappe AsmUtil.boxType(this, kotlinType, typeMapper) abstract class ExpressionLambda(isCrossInline: Boolean) : LambdaInfo(isCrossInline) { - override fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner) { + override fun generateLambdaBody(sourceCompiler: SourceCompilerForInline, reifiedTypeInliner: ReifiedTypeInliner<*>) { node = sourceCompiler.generateLambdaBody(this) } } 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 4540cd22931..b50ce62de56 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/PsiInlineCodegen.kt @@ -23,8 +23,10 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue +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 class PsiInlineCodegen( codegen: ExpressionCodegen, @@ -32,10 +34,17 @@ class PsiInlineCodegen( function: FunctionDescriptor, methodOwner: Type, signature: JvmMethodSignature, - typeParameterMappings: TypeParameterMappings, + typeParameterMappings: TypeParameterMappings, sourceCompiler: SourceCompilerForInline ) : InlineCodegen( - codegen, state, function, methodOwner, signature, typeParameterMappings, sourceCompiler + codegen, state, function, methodOwner, signature, typeParameterMappings, sourceCompiler, + ReifiedTypeInliner(typeParameterMappings, object : ReifiedTypeInliner.IntrinsicsSupport { + override fun putClassInstance(v: InstructionAdapter, type: KotlinType) { + AsmUtil.putJavaLangClassInstance(v, state.typeMapper.mapType(type), type, state.typeMapper) + } + + override fun toKotlinType(type: KotlinType): KotlinType = type + }, codegen.typeSystem, state.languageVersionSettings) ), CallGenerator { override fun generateAssertFieldIfNeeded(info: RootInliningContext) { @@ -154,7 +163,7 @@ class PsiInlineCodegen( assert(isInlinableParameterExpression(ktLambda)) { "Couldn't find inline expression in ${expression.text}" } return PsiExpressionLambda( - ktLambda!!, typeMapper, state.languageVersionSettings, + ktLambda!!, state.typeMapper, state.languageVersionSettings, parameter.isCrossinline, getBoundCallableReferenceReceiver(expression) != null ).also { lambda -> val closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.index) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt index 044287b019b..bb24141e1cd 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -20,15 +20,13 @@ import org.jetbrains.kotlin.codegen.generateAsCast import org.jetbrains.kotlin.codegen.generateIsCheck import org.jetbrains.kotlin.codegen.intrinsics.IntrinsicMethods import org.jetbrains.kotlin.codegen.optimization.common.intConstant -import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.isReleaseCoroutines -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.Variance -import org.jetbrains.kotlin.types.typeUtil.builtIns +import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext +import org.jetbrains.kotlin.types.model.KotlinTypeMarker +import org.jetbrains.kotlin.types.model.TypeParameterMarker import org.jetbrains.org.objectweb.asm.MethodVisitor import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type @@ -37,37 +35,23 @@ import org.jetbrains.org.objectweb.asm.tree.* import kotlin.math.max class ReificationArgument( - val parameterName: String, val nullable: Boolean, private val arrayDepth: Int + val parameterName: String, val nullable: Boolean, val arrayDepth: Int ) { - fun asString() = "[".repeat(arrayDepth) + parameterName + (if (nullable) "?" else "") - fun combine(replacement: ReificationArgument) = + fun asString(): String = + "[".repeat(arrayDepth) + parameterName + (if (nullable) "?" else "") + + fun combine(replacement: ReificationArgument): ReificationArgument = ReificationArgument( replacement.parameterName, this.nullable || (replacement.nullable && this.arrayDepth == 0), this.arrayDepth + replacement.arrayDepth ) - - fun reify(replacementAsmType: Type, kotlinType: KotlinType) = - Pair( - Type.getType("[".repeat(arrayDepth) + replacementAsmType), - TypeUtils.makeNullableIfNeeded(kotlinType.arrayOf(arrayDepth), nullable) - ) - - private fun KotlinType.arrayOf(arrayDepth: Int): KotlinType { - val builtins = this.builtIns - var currentType = this - - repeat(arrayDepth) { - currentType = builtins.getArrayType(Variance.INVARIANT, currentType) - } - - return currentType - } } -class ReifiedTypeInliner( - private val parametersMapping: TypeParameterMappings?, - private val typeMapper: KotlinTypeMapper, +class ReifiedTypeInliner( + private val parametersMapping: TypeParameterMappings?, + private val intrinsicsSupport: IntrinsicsSupport, + private val typeSystem: TypeSystemCommonBackendContext, private val languageVersionSettings: LanguageVersionSettings ) { enum class OperationKind { @@ -76,6 +60,12 @@ class ReifiedTypeInliner( val id: Int get() = ordinal } + interface IntrinsicsSupport { + fun putClassInstance(v: InstructionAdapter, type: KT) + + fun toKotlinType(type: KT): KotlinType + } + companion object { const val REIFIED_OPERATION_MARKER_METHOD_NAME = "reifiedOperationMarker" const val NEED_CLASS_REIFICATION_MARKER_METHOD_NAME = "needClassReification" @@ -112,14 +102,17 @@ class ReifiedTypeInliner( } fun putReifiedOperationMarkerIfNeeded( - typeParameter: TypeParameterDescriptor, + typeParameter: TypeParameterMarker, isNullable: Boolean, operationKind: OperationKind, - v: InstructionAdapter + v: InstructionAdapter, + typeSystem: TypeSystemCommonBackendContext ) { - if (typeParameter.isReified) { - val argument = ReificationArgument(typeParameter.name.asString(), isNullable, 0) - putReifiedOperationMarker(operationKind, argument, v) + with(typeSystem) { + if (typeParameter.isReified()) { + val argument = ReificationArgument(typeParameter.getName().asString(), isNullable, 0) + putReifiedOperationMarker(operationKind, argument, v) + } } } } @@ -165,7 +158,9 @@ class ReifiedTypeInliner( // process* methods return false if marker should be reified further // or it's invalid (may be emitted explicitly in code) // they return true if instruction is reified and marker can be deleted - val (asmType, kotlinType) = reificationArgument.reify(mapping.asmType, mapping.type) + val (asmType, type) = reify(reificationArgument, mapping.asmType, mapping.type) + + val kotlinType = intrinsicsSupport.toKotlinType(type) if (when (operationKind) { OperationKind.NEW_ARRAY -> processNewArray(insn, asmType) @@ -174,7 +169,7 @@ class ReifiedTypeInliner( OperationKind.IS -> processIs(insn, instructions, kotlinType, asmType) OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType) OperationKind.ENUM_REIFIED -> processSpecialEnumFunction(insn, instructions, asmType) - OperationKind.TYPE_OF -> processTypeOf(insn, instructions, kotlinType) + OperationKind.TYPE_OF -> processTypeOf(insn, instructions, type) } ) { instructions.remove(insn.previous.previous!!) // PUSH operation ID @@ -190,6 +185,27 @@ class ReifiedTypeInliner( } } + private fun reify(argument: ReificationArgument, replacementAsmType: Type, type: KT): Pair = + with(typeSystem) { + val arrayType = type.arrayOf(argument.arrayDepth) + @Suppress("UNCHECKED_CAST") + Pair( + Type.getType("[".repeat(argument.arrayDepth) + replacementAsmType), + (if (argument.nullable) arrayType.makeNullable() else arrayType) as KT + ) + } + + private fun KotlinTypeMarker.arrayOf(arrayDepth: Int): KotlinTypeMarker { + var currentType = this + + repeat(arrayDepth) { + currentType = typeSystem.arrayType(currentType) + } + + return currentType + } + + private fun processNewArray(insn: MethodInsnNode, parameter: Type) = processNextTypeInsn(insn, parameter, Opcodes.ANEWARRAY) @@ -236,10 +252,10 @@ class ReifiedTypeInliner( private fun processTypeOf( insn: MethodInsnNode, instructions: InsnList, - kotlinType: KotlinType + type: KT ) = rewriteNextTypeInsn(insn, Opcodes.ACONST_NULL) { stubConstNull: AbstractInsnNode -> val newMethodNode = MethodNode(Opcodes.API_VERSION) - val stackSize = generateTypeOf(InstructionAdapter(newMethodNode), kotlinType, typeMapper) + val stackSize = typeSystem.generateTypeOf(InstructionAdapter(newMethodNode), type, intrinsicsSupport) instructions.insert(insn, newMethodNode.instructions) instructions.remove(stubConstNull) @@ -316,38 +332,33 @@ val MethodInsnNode.operationKind: ReifiedTypeInliner.OperationKind? ReifiedTypeInliner.OperationKind.values().getOrNull(it) } -class TypeParameterMappings() { - private val mappingsByName = hashMapOf() +class TypeParameterMappings { + private val mappingsByName = hashMapOf>() - fun addParameterMappingToType(name: String, type: KotlinType, asmType: Type, signature: String, isReified: Boolean) { + fun addParameterMappingToType(name: String, type: KT, asmType: Type, signature: String, isReified: Boolean) { mappingsByName[name] = TypeParameterMapping( name, type, asmType, reificationArgument = null, signature = signature, isReified = isReified ) } - fun addParameterMappingForFurtherReification( - name: String, - type: KotlinType, - reificationArgument: ReificationArgument, - isReified: Boolean - ) { + fun addParameterMappingForFurtherReification(name: String, type: KT, reificationArgument: ReificationArgument, isReified: Boolean) { mappingsByName[name] = TypeParameterMapping( name, type, asmType = null, reificationArgument = reificationArgument, signature = null, isReified = isReified ) } - operator fun get(name: String): TypeParameterMapping? = mappingsByName[name] + operator fun get(name: String): TypeParameterMapping? = mappingsByName[name] fun hasReifiedParameters() = mappingsByName.values.any { it.isReified } - internal inline fun forEach(l: (TypeParameterMapping) -> Unit) { + internal inline fun forEach(l: (TypeParameterMapping) -> Unit) { mappingsByName.values.forEach(l) } } -class TypeParameterMapping( +class TypeParameterMapping( val name: String, - val type: KotlinType, + val type: KT, val asmType: Type?, val reificationArgument: ReificationArgument?, val signature: String?, diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/TypeRemapper.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/TypeRemapper.kt index c0ff87950cc..a681eac0661 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/TypeRemapper.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/TypeRemapper.kt @@ -52,7 +52,7 @@ class TypeRemapper private constructor( typeParametersMapping[name] = TypeParameter(name, name, false, null) } - fun registerTypeParameter(mapping: TypeParameterMapping) { + fun registerTypeParameter(mapping: TypeParameterMapping<*>) { typeParametersMapping[mapping.name] = TypeParameter( mapping.name, mapping.reificationArgument?.parameterName, mapping.isReified, mapping.signature ) @@ -64,8 +64,8 @@ class TypeRemapper private constructor( companion object { @JvmStatic - fun createRoot(formalTypeParameters: TypeParameterMappings?): TypeRemapper { - return TypeRemapper(HashMap()).apply { + fun createRoot(formalTypeParameters: TypeParameterMappings<*>?): TypeRemapper { + return TypeRemapper(HashMap()).apply { formalTypeParameters?.forEach { registerTypeParameter(it) } 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 7683ee72961..7bae35a03ba 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineIntrinsics.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/inlineIntrinsics.kt @@ -23,9 +23,12 @@ import org.jetbrains.kotlin.resolve.calls.checkers.TypeOfChecker import org.jetbrains.kotlin.resolve.calls.checkers.isBuiltInCoroutineContext import org.jetbrains.kotlin.resolve.jvm.AsmTypes.* import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.TypeProjection -import org.jetbrains.kotlin.types.Variance -import org.jetbrains.kotlin.types.typeUtil.builtIns +import org.jetbrains.kotlin.types.TypeSystemCommonBackendContext +import org.jetbrains.kotlin.types.checker.ClassicTypeSystemContextImpl +import org.jetbrains.kotlin.types.model.KotlinTypeMarker +import org.jetbrains.kotlin.types.model.TypeArgumentMarker +import org.jetbrains.kotlin.types.model.TypeParameterMarker +import org.jetbrains.kotlin.types.model.TypeVariance import org.jetbrains.org.objectweb.asm.Opcodes import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter @@ -38,11 +41,15 @@ internal fun generateInlineIntrinsic( ): MethodNode? { val languageVersionSettings = state.languageVersionSettings val typeMapper = state.typeMapper + + // TODO + val typeSystem = ClassicTypeSystemContextImpl(state.module.builtIns) + return when { isSpecialEnumMethod(descriptor) -> - createSpecialEnumMethodBody(descriptor.name.asString(), typeArguments!!.keys.single(), typeMapper) + createSpecialEnumMethodBody(descriptor.name.asString(), typeArguments!!.keys.single(), typeMapper, typeSystem) TypeOfChecker.isTypeOf(descriptor) -> - createTypeOfMethodBody(typeArguments!!.keys.single()) + typeSystem.createTypeOfMethodBody(typeArguments!!.keys.single()) descriptor.isBuiltInIntercepted(languageVersionSettings) -> createMethodNodeForIntercepted(descriptor, typeMapper, languageVersionSettings) descriptor.isBuiltInCoroutineContext(languageVersionSettings) -> @@ -69,13 +76,15 @@ private fun isSpecialEnumMethod(descriptor: FunctionDescriptor): Boolean { (name == "enumValueOf" && parameters.size == 1 && KotlinBuiltIns.isString(parameters[0].type)) } -private fun createSpecialEnumMethodBody(name: String, typeParameter: TypeParameterDescriptor, typeMapper: KotlinTypeMapper): MethodNode { +private fun createSpecialEnumMethodBody( + name: String, typeParameter: TypeParameterDescriptor, typeMapper: KotlinTypeMapper, typeSystem: TypeSystemCommonBackendContext +): MethodNode { val isValueOf = "enumValueOf" == name val invokeType = typeMapper.mapType(typeParameter.defaultType) val desc = getSpecialEnumFunDescriptor(invokeType, isValueOf) val node = MethodNode(Opcodes.API_VERSION, Opcodes.ACC_STATIC, "fake", desc, null, null) ReifiedTypeInliner.putReifiedOperationMarkerIfNeeded( - typeParameter, false, ReifiedTypeInliner.OperationKind.ENUM_REIFIED, InstructionAdapter(node) + typeParameter, false, ReifiedTypeInliner.OperationKind.ENUM_REIFIED, InstructionAdapter(node), typeSystem ) if (isValueOf) { node.visitInsn(Opcodes.ACONST_NULL) @@ -98,7 +107,7 @@ internal fun getSpecialEnumFunDescriptor(type: Type, isValueOf: Boolean): String if (isValueOf) Type.getMethodDescriptor(type, JAVA_STRING_TYPE) else Type.getMethodDescriptor(AsmUtil.getArrayType(type)) -private fun createTypeOfMethodBody(typeParameter: TypeParameterDescriptor): MethodNode { +private fun TypeSystemCommonBackendContext.createTypeOfMethodBody(typeParameter: TypeParameterMarker): MethodNode { val node = MethodNode(Opcodes.API_VERSION, Opcodes.ACC_STATIC, "fake", Type.getMethodDescriptor(K_TYPE), null, null) val v = InstructionAdapter(node) @@ -110,33 +119,36 @@ private fun createTypeOfMethodBody(typeParameter: TypeParameterDescriptor): Meth return node } -private fun putTypeOfReifiedTypeParameter(v: InstructionAdapter, typeParameter: TypeParameterDescriptor, isNullable: Boolean) { - ReifiedTypeInliner.putReifiedOperationMarkerIfNeeded(typeParameter, isNullable, ReifiedTypeInliner.OperationKind.TYPE_OF, v) +private fun TypeSystemCommonBackendContext.putTypeOfReifiedTypeParameter( + v: InstructionAdapter, typeParameter: TypeParameterMarker, isNullable: Boolean +) { + ReifiedTypeInliner.putReifiedOperationMarkerIfNeeded(typeParameter, isNullable, ReifiedTypeInliner.OperationKind.TYPE_OF, v, this) v.aconst(null) } // Returns some upper bound on maximum stack size -internal fun generateTypeOf(v: InstructionAdapter, kotlinType: KotlinType, typeMapper: KotlinTypeMapper): Int { - val asmType = typeMapper.mapType(kotlinType) - AsmUtil.putJavaLangClassInstance(v, asmType, kotlinType, typeMapper) +internal fun TypeSystemCommonBackendContext.generateTypeOf( + v: InstructionAdapter, type: KT, intrinsicsSupport: ReifiedTypeInliner.IntrinsicsSupport +): Int { + intrinsicsSupport.putClassInstance(v, type) - val arguments = kotlinType.arguments - val useArray = arguments.size >= 3 + val argumentsSize = type.argumentsCount() + val useArray = argumentsSize >= 3 if (useArray) { - v.iconst(arguments.size) + v.iconst(argumentsSize) v.newarray(K_TYPE_PROJECTION) } var maxStackSize = 3 - for (i in 0 until arguments.size) { + for (i in 0 until argumentsSize) { if (useArray) { v.dup() v.iconst(i) } - val stackSize = doGenerateTypeProjection(v, arguments[i], typeMapper) + val stackSize = doGenerateTypeProjection(v, type.getArgument(i), intrinsicsSupport) maxStackSize = maxOf(maxStackSize, stackSize + i + 5) if (useArray) { @@ -144,9 +156,9 @@ internal fun generateTypeOf(v: InstructionAdapter, kotlinType: KotlinType, typeM } } - val methodName = if (kotlinType.isMarkedNullable) "nullableTypeOf" else "typeOf" + val methodName = if (type.isMarkedNullable()) "nullableTypeOf" else "typeOf" - val projections = when (arguments.size) { + val projections = when (argumentsSize) { 0 -> emptyArray() 1 -> arrayOf(K_TYPE_PROJECTION) 2 -> arrayOf(K_TYPE_PROJECTION, K_TYPE_PROJECTION) @@ -159,37 +171,39 @@ internal fun generateTypeOf(v: InstructionAdapter, kotlinType: KotlinType, typeM return maxStackSize } -private fun doGenerateTypeProjection( +private fun TypeSystemCommonBackendContext.doGenerateTypeProjection( v: InstructionAdapter, - projection: TypeProjection, - typeMapper: KotlinTypeMapper + projection: TypeArgumentMarker, + intrinsicsSupport: ReifiedTypeInliner.IntrinsicsSupport ): Int { // KTypeProjection members could be static, see KT-30083 and KT-30084 v.getstatic(K_TYPE_PROJECTION.internalName, "Companion", K_TYPE_PROJECTION_COMPANION.descriptor) - if (projection.isStarProjection) { + if (projection.isStarProjection()) { v.invokevirtual(K_TYPE_PROJECTION_COMPANION.internalName, "getSTAR", Type.getMethodDescriptor(K_TYPE_PROJECTION), false) return 1 } - val type = projection.type - val descriptor = type.constructor.declarationDescriptor - val stackSize = if (descriptor is TypeParameterDescriptor) { - if (descriptor.isReified) { - putTypeOfReifiedTypeParameter(v, descriptor, type.isMarkedNullable) + @Suppress("UNCHECKED_CAST") + val type = projection.getType() as KT + val typeParameterClassifier = type.typeConstructor().getTypeParameterClassifier() + val stackSize = if (typeParameterClassifier != null) { + if (typeParameterClassifier.isReified()) { + putTypeOfReifiedTypeParameter(v, typeParameterClassifier, type.isMarkedNullable()) 2 } else { // TODO: support non-reified type parameters in typeOf - generateTypeOf(v, type.builtIns.nullableAnyType, typeMapper) + @Suppress("UNCHECKED_CAST") + generateTypeOf(v, nullableAnyType() as KT, intrinsicsSupport) } } else { - generateTypeOf(v, type, typeMapper) + generateTypeOf(v, type, intrinsicsSupport) } - val methodName = when (projection.projectionKind) { - Variance.INVARIANT -> "invariant" - Variance.IN_VARIANCE -> "contravariant" - Variance.OUT_VARIANCE -> "covariant" + val methodName = when (projection.getVariance()) { + TypeVariance.INV -> "invariant" + TypeVariance.IN -> "contravariant" + TypeVariance.OUT -> "covariant" } v.invokevirtual(K_TYPE_PROJECTION_COMPANION.internalName, methodName, Type.getMethodDescriptor(K_TYPE_PROJECTION, K_TYPE), false) diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt index ce96102d769..ae7e04a54f9 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/types/ConeTypeContext.kt @@ -431,6 +431,10 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty return this.firSafeNullable() } + override fun nullableAnyType(): SimpleTypeMarker = TODO("not implemented") + + override fun arrayType(componentType: KotlinTypeMarker): SimpleTypeMarker = TODO("not implemented") + override fun TypeConstructorMarker.isFinalClassOrEnumEntryOrAnnotationClassConstructor(): Boolean { val firRegularClass = toFirRegularClass() ?: return false @@ -485,6 +489,8 @@ interface ConeTypeContext : TypeSystemContext, TypeSystemOptimizationContext, Ty override fun TypeParameterMarker.getName() = (this as ConeTypeParameterSymbol).name + override fun TypeParameterMarker.isReified(): Boolean = TODO("not implemented") + override fun KotlinTypeMarker.isInterfaceOrAnnotationClass(): Boolean { val classKind = typeConstructor().toFirRegularClass()?.classKind ?: return false return classKind == ClassKind.ANNOTATION_CLASS || classKind == ClassKind.INTERFACE diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt index faea2725cc2..982c5ef9db4 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/ExpressionCodegen.kt @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature +import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.keysToMap @@ -908,12 +909,7 @@ class ExpressionCodegen( putReifiedOperationMarkerIfTypeIsReifiedParameter(classType, ReifiedTypeInliner.OperationKind.JAVA_CLASS, mv, this) } - val asmType = typeMapper.mapType(classType) - if (classType.getClass()?.isInline == true || !isPrimitive(asmType)) { - mv.aconst(typeMapper.boxType(classType)) - } else { - mv.getstatic(boxType(asmType).internalName, "TYPE", "Ljava/lang/Class;") - } + generateClassInstance(mv, classType) } else { throw AssertionError("not an IrGetClass or IrClassReference: ${classReference.dump()}") } @@ -924,6 +920,15 @@ class ExpressionCodegen( return classReference.onStack } + private fun generateClassInstance(v: InstructionAdapter, classType: IrType) { + val asmType = typeMapper.mapType(classType) + if (classType.getClass()?.isInline == true || !isPrimitive(asmType)) { + v.aconst(typeMapper.boxType(classType)) + } else { + v.getstatic(boxType(asmType).internalName, "TYPE", "Ljava/lang/Class;") + } + } + private fun getOrCreateCallGenerator( element: IrFunctionAccessExpression, data: BlockInfo, signature: JvmMethodSignature ): IrCallGenerator { @@ -964,7 +969,19 @@ class ExpressionCodegen( val original = (callee as? IrSimpleFunction)?.resolveFakeOverride() ?: irFunction val methodOwner = callee.parent.safeAs()?.let(typeMapper::mapClass) ?: MethodSignatureMapper.FAKE_OWNER_TYPE val sourceCompiler = IrSourceCompilerForInline(state, element, this, data) - return IrInlineCodegen(this, state, original.descriptor, methodOwner, signature, mappings, sourceCompiler) + val typeParameterMappings = mappings.toTypeParameterMappings() + + val reifiedTypeInliner = ReifiedTypeInliner(typeParameterMappings, object : ReifiedTypeInliner.IntrinsicsSupport { + override fun putClassInstance(v: InstructionAdapter, type: IrType) { + generateClassInstance(v, type) + } + + override fun toKotlinType(type: IrType): KotlinType = type.toKotlinType() + }, IrTypeCheckerContext(context.irBuiltIns), state.languageVersionSettings) + + return IrInlineCodegen( + this, state, original.descriptor, methodOwner, signature, typeParameterMappings, sourceCompiler, reifiedTypeInliner + ) } private fun consumeReifiedOperationMarker(typeParameter: IrTypeParameter) { @@ -1099,23 +1116,17 @@ class IrTypeParameterMappings { mappingsByName.values.forEach(l) } - fun toTypeParameterMappings() = TypeParameterMappings().also { result -> + fun toTypeParameterMappings() = TypeParameterMappings().also { result -> mappingsByName.forEach { (_, value) -> if (value.asmType == null) { result.addParameterMappingForFurtherReification( value.name, - value.type.toKotlinType(), + value.type, value.reificationArgument!!.toReificationArgument(), value.isReified ) } else { - result.addParameterMappingToType( - value.name, - value.type.toKotlinType(), - value.asmType, - value.signature!!, - value.isReified - ) + result.addParameterMappingToType(value.name, value.type, value.asmType, value.signature!!, value.isReified) } } } 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 5a0f05980fd..1efa0995b07 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 @@ -33,10 +33,11 @@ class IrInlineCodegen( function: FunctionDescriptor, methodOwner: Type, signature: JvmMethodSignature, - typeParameterMappings: IrTypeParameterMappings, - sourceCompiler: SourceCompilerForInline + typeParameterMappings: TypeParameterMappings, + sourceCompiler: SourceCompilerForInline, + reifiedTypeInliner: ReifiedTypeInliner ) : InlineCodegen( - codegen, state, function, methodOwner, signature, typeParameterMappings.toTypeParameterMappings(), sourceCompiler + codegen, state, function, methodOwner, signature, typeParameterMappings, sourceCompiler, reifiedTypeInliner ), IrCallGenerator { override fun generateAssertFieldIfNeeded(info: RootInliningContext) { // TODO: JVM assertions are not implemented yet in IR backend @@ -141,7 +142,7 @@ class IrExpressionLambdaImpl( val reference: IrFunctionReference, val function: IrFunction, private val typeMapper: IrTypeMapper, - private val methodSignatureMapper: MethodSignatureMapper, + methodSignatureMapper: MethodSignatureMapper, isCrossInline: Boolean, override val isBoundCallableReference: Boolean, override val isExtensionLambda: Boolean diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt index fed837fbc14..775ddec6d57 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/IrTypeSystemContext.kt @@ -267,6 +267,12 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon override fun createErrorTypeWithCustomConstructor(debugName: String, constructor: TypeConstructorMarker): KotlinTypeMarker = TODO("IrTypeSystemContext doesn't support constraint system resolution") + override fun nullableAnyType(): SimpleTypeMarker = + irBuiltIns.anyNType as IrSimpleType + + override fun arrayType(componentType: KotlinTypeMarker): SimpleTypeMarker = + irBuiltIns.arrayClass.typeWith(componentType as IrType) + override fun TypeConstructorMarker.isFinalClassOrEnumEntryOrAnnotationClassConstructor(): Boolean { val symbol = this as IrClassifierSymbol return symbol is IrClassSymbol && symbol.owner.let { @@ -340,6 +346,9 @@ interface IrTypeSystemContext : TypeSystemContext, TypeSystemCommonSuperTypesCon override fun TypeParameterMarker.getName(): Name = (this as IrTypeParameterSymbol).owner.name + override fun TypeParameterMarker.isReified(): Boolean = + (this as IrTypeParameterSymbol).owner.isReified + override fun KotlinTypeMarker.isInterfaceOrAnnotationClass(): Boolean { val irClass = (this as IrType).classOrNull?.owner return irClass != null && (irClass.isInterface || irClass.isAnnotationClass) diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt index 128d8d5d7f8..a11ec9650d5 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/TypeSystemCommonBackendContext.kt @@ -12,6 +12,9 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.types.model.* interface TypeSystemCommonBackendContext : TypeSystemContext { + fun nullableAnyType(): SimpleTypeMarker + fun arrayType(componentType: KotlinTypeMarker): SimpleTypeMarker + fun TypeConstructorMarker.isFinalClassOrEnumEntryOrAnnotationClassConstructor(): Boolean fun KotlinTypeMarker.hasAnnotation(fqName: FqName): Boolean @@ -44,6 +47,7 @@ interface TypeSystemCommonBackendContext : TypeSystemContext { fun TypeConstructorMarker.getClassFqNameUnsafe(): FqNameUnsafe? fun TypeParameterMarker.getName(): Name + fun TypeParameterMarker.isReified(): Boolean fun KotlinTypeMarker.isInterfaceOrAnnotationClass(): Boolean } diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt index 6db28969a8e..8051b04fe5b 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/ClassicTypeSystemContext.kt @@ -341,7 +341,8 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return builtIns.anyType } - val builtIns: KotlinBuiltIns get() = throw UnsupportedOperationException("Not supported") + open val builtIns: KotlinBuiltIns + get() = throw UnsupportedOperationException("Not supported") override fun KotlinTypeMarker.makeDefinitelyNotNullOrNotNull(): KotlinTypeMarker { require(this is UnwrappedType, this::errorMessage) @@ -502,6 +503,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return this is NewCapturedTypeConstructor } + override fun arrayType(componentType: KotlinTypeMarker): SimpleTypeMarker { + require(componentType is KotlinType, this::errorMessage) + return builtIns.getArrayType(Variance.INVARIANT, componentType) + } + override fun KotlinTypeMarker.hasAnnotation(fqName: FqName): Boolean { require(this is KotlinType, this::errorMessage) return annotations.hasAnnotation(fqName) @@ -557,6 +563,11 @@ interface ClassicTypeSystemContext : TypeSystemInferenceExtensionContext, TypeSy return name } + override fun TypeParameterMarker.isReified(): Boolean { + require(this is TypeParameterDescriptor, this::errorMessage) + return isReified + } + override fun KotlinTypeMarker.isInterfaceOrAnnotationClass(): Boolean { require(this is KotlinType, this::errorMessage) val descriptor = constructor.declarationDescriptor diff --git a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt index 6a8b16352cd..e94cb892f80 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/types/checker/NewKotlinTypeChecker.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.types.checker +import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor import org.jetbrains.kotlin.resolve.OverridingUtil @@ -31,6 +32,8 @@ import org.jetbrains.kotlin.types.typeUtil.makeNullable object SimpleClassicTypeSystemContext : ClassicTypeSystemContext +class ClassicTypeSystemContextImpl(override val builtIns: KotlinBuiltIns) : ClassicTypeSystemContext + object StrictEqualityTypeChecker { /**