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)
This commit is contained in:
Alexander Udalov
2019-09-04 16:05:50 +02:00
parent ece09866f0
commit d1df453edc
15 changed files with 205 additions and 132 deletions
@@ -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<StackValue, StackValue> impleme
private final TailRecursionCodegen tailRecursionCodegen;
public final CallGenerator defaultCallGenerator = new CallGenerator.DefaultCallGenerator(this);
private final SwitchCodegenProvider switchCodegenProvider;
public final TypeSystemCommonBackendContext typeSystem;
private final Stack<BlockStackElement> blockStackElements = new Stack<>();
@@ -157,6 +156,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> 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<StackValue, StackValue> impleme
private CallGenerator getOrCreateCallGenerator(
@NotNull CallableDescriptor descriptor,
@Nullable KtElement callElement,
@Nullable TypeParameterMappings typeParameterMappings,
@Nullable TypeParameterMappings<KotlinType> typeParameterMappings,
boolean isDefaultCompilation
) {
if (callElement == null) return defaultCallGenerator;
@@ -2672,7 +2672,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall, @NotNull CallableDescriptor descriptor) {
Map<TypeParameterDescriptor, KotlinType> typeArguments = getTypeArgumentsForResolvedCall(resolvedCall, descriptor);
TypeParameterMappings mappings = new TypeParameterMappings();
TypeParameterMappings<KotlinType> mappings = new TypeParameterMappings<>();
for (Map.Entry<TypeParameterDescriptor, KotlinType> entry : typeArguments.entrySet()) {
TypeParameterDescriptor key = entry.getKey();
KotlinType type = entry.getValue();
@@ -47,8 +47,9 @@ abstract class InlineCodegen<out T : BaseExpressionCodegen>(
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<out T : BaseExpressionCodegen>(
// 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()
@@ -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
)
@@ -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)
}
}
@@ -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<KotlinType>,
sourceCompiler: SourceCompilerForInline
) : InlineCodegen<ExpressionCodegen>(
codegen, state, function, methodOwner, signature, typeParameterMappings, sourceCompiler
codegen, state, function, methodOwner, signature, typeParameterMappings, sourceCompiler,
ReifiedTypeInliner(typeParameterMappings, object : ReifiedTypeInliner.IntrinsicsSupport<KotlinType> {
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)
@@ -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<KT : KotlinTypeMarker>(
private val parametersMapping: TypeParameterMappings<KT>?,
private val intrinsicsSupport: IntrinsicsSupport<KT>,
private val typeSystem: TypeSystemCommonBackendContext,
private val languageVersionSettings: LanguageVersionSettings
) {
enum class OperationKind {
@@ -76,6 +60,12 @@ class ReifiedTypeInliner(
val id: Int get() = ordinal
}
interface IntrinsicsSupport<KT : KotlinTypeMarker> {
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<Type, KT> =
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<String, TypeParameterMapping>()
class TypeParameterMappings<KT : KotlinTypeMarker> {
private val mappingsByName = hashMapOf<String, TypeParameterMapping<KT>>()
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<KT>? = mappingsByName[name]
fun hasReifiedParameters() = mappingsByName.values.any { it.isReified }
internal inline fun forEach(l: (TypeParameterMapping) -> Unit) {
internal inline fun forEach(l: (TypeParameterMapping<KT>) -> Unit) {
mappingsByName.values.forEach(l)
}
}
class TypeParameterMapping(
class TypeParameterMapping<KT : KotlinTypeMarker>(
val name: String,
val type: KotlinType,
val type: KT,
val asmType: Type?,
val reificationArgument: ReificationArgument?,
val signature: String?,
@@ -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<String, String?>()).apply {
fun createRoot(formalTypeParameters: TypeParameterMappings<*>?): TypeRemapper {
return TypeRemapper(HashMap()).apply {
formalTypeParameters?.forEach {
registerTypeParameter(it)
}
@@ -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 <KT : KotlinTypeMarker> TypeSystemCommonBackendContext.generateTypeOf(
v: InstructionAdapter, type: KT, intrinsicsSupport: ReifiedTypeInliner.IntrinsicsSupport<KT>
): 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 <KT : KotlinTypeMarker> TypeSystemCommonBackendContext.doGenerateTypeProjection(
v: InstructionAdapter,
projection: TypeProjection,
typeMapper: KotlinTypeMapper
projection: TypeArgumentMarker,
intrinsicsSupport: ReifiedTypeInliner.IntrinsicsSupport<KT>
): 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)
@@ -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
@@ -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<IrClass>()?.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<IrType> {
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<IrType>().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)
}
}
}
@@ -33,10 +33,11 @@ class IrInlineCodegen(
function: FunctionDescriptor,
methodOwner: Type,
signature: JvmMethodSignature,
typeParameterMappings: IrTypeParameterMappings,
sourceCompiler: SourceCompilerForInline
typeParameterMappings: TypeParameterMappings<IrType>,
sourceCompiler: SourceCompilerForInline,
reifiedTypeInliner: ReifiedTypeInliner<IrType>
) : InlineCodegen<ExpressionCodegen>(
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
@@ -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)
@@ -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
}
@@ -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
@@ -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 {
/**