From eb4d831d2782584f98c237ac6e98ba0941566f0b Mon Sep 17 00:00:00 2001 From: pyos Date: Thu, 27 May 2021 16:18:06 +0200 Subject: [PATCH] JVM_IR: implement typeOf as a codegen intrinsic rather than a fake inline function. Also, generate more correct instructions for typeOf. Not sure how that even worked before - `aconst(Boolean)` isn't even valid. --- .../kotlin/codegen/BaseExpressionCodegen.kt | 17 +++++------- .../kotlin/codegen/ExpressionCodegen.java | 19 ++++---------- .../jetbrains/kotlin/codegen/codegenUtil.kt | 7 +++-- .../jetbrains/kotlin/codegen/inline/typeOf.kt | 8 +++--- .../KClassJavaObjectTypeProperty.kt | 1 + .../backend/jvm/codegen/ExpressionCodegen.kt | 6 ++--- .../jvm/codegen/IrInlineIntrinsicsSupport.kt | 4 +-- .../backend/jvm/intrinsics/EnumIntrinsics.kt | 1 + .../jvm/intrinsics/GetJavaObjectType.kt | 11 ++++---- .../jvm/intrinsics/IrIntrinsicMethods.kt | 2 ++ .../kotlin/backend/jvm/intrinsics/NewArray.kt | 3 ++- .../kotlin/backend/jvm/intrinsics/TypeOf.kt | 26 +++++++++++++++++++ 12 files changed, 62 insertions(+), 43 deletions(-) create mode 100644 compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/TypeOf.kt diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/BaseExpressionCodegen.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/BaseExpressionCodegen.kt index ef8917c66aa..aafad3af84f 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/BaseExpressionCodegen.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/BaseExpressionCodegen.kt @@ -41,14 +41,11 @@ interface BaseExpressionCodegen { fun markLineNumberAfterInlineIfNeeded(registerLineNumberAfterwards: Boolean) fun consumeReifiedOperationMarker(typeParameter: TypeParameterMarker) - - fun putReifiedOperationMarkerIfTypeIsReifiedParameter(type: KotlinTypeMarker, operationKind: OperationKind) { - with(typeSystem) { - val (typeParameter, second) = extractReificationArgument(type) ?: return - if (typeParameter.isReified()) { - consumeReifiedOperationMarker(typeParameter) - putReifiedOperationMarker(operationKind, second, visitor) - } - } - } +} + +fun BaseExpressionCodegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type: KotlinTypeMarker, operationKind: OperationKind): Boolean { + val (typeParameter, second) = typeSystem.extractReificationArgument(type) ?: return false + consumeReifiedOperationMarker(typeParameter) + putReifiedOperationMarker(operationKind, second, visitor) + return true } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 8a7554a08fb..9c53168b336 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -107,6 +107,7 @@ import java.util.stream.Collectors; import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt; import static org.jetbrains.kotlin.codegen.AsmUtil.boxType; import static org.jetbrains.kotlin.codegen.AsmUtil.*; +import static org.jetbrains.kotlin.codegen.BaseExpressionCodegenKt.putReifiedOperationMarkerIfTypeIsReifiedParameter; import static org.jetbrains.kotlin.codegen.CodegenUtilKt.*; import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.boxType; import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.*; @@ -3555,7 +3556,7 @@ public class ExpressionCodegen extends KtVisitor impleme if (TypeUtils.isTypeParameter(type)) { assert TypeUtils.isReifiedTypeParameter(type) : "Non-reified type parameter under ::class should be rejected by type checker: " + type; - putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS); + putReifiedOperationMarkerIfTypeIsReifiedParameter(this, type, ReifiedTypeInliner.OperationKind.JAVA_CLASS); } putJavaLangClassInstance(v, typeMapper.mapType(type), type, typeMapper); @@ -4928,10 +4929,7 @@ public class ExpressionCodegen extends KtVisitor impleme public void newArrayInstruction(@NotNull KotlinType arrayType) { if (KotlinBuiltIns.isArray(arrayType)) { KotlinType elementJetType = arrayType.getArguments().get(0).getType(); - putReifiedOperationMarkerIfTypeIsReifiedParameter( - elementJetType, - ReifiedTypeInliner.OperationKind.NEW_ARRAY - ); + putReifiedOperationMarkerIfTypeIsReifiedParameter(this, elementJetType, ReifiedTypeInliner.OperationKind.NEW_ARRAY); v.newarray(boxType(typeMapper.mapTypeAsDeclaration(elementJetType))); } else { @@ -5235,7 +5233,7 @@ The "returned" value of try expression with no finally is either the last expres boolean safeAs = opToken == KtTokens.AS_SAFE; if (TypeUtils.isReifiedTypeParameter(rightKotlinType)) { - putReifiedOperationMarkerIfTypeIsReifiedParameter(rightKotlinType, + putReifiedOperationMarkerIfTypeIsReifiedParameter(this, rightKotlinType, safeAs ? ReifiedTypeInliner.OperationKind.SAFE_AS : ReifiedTypeInliner.OperationKind.AS); v.checkcast(boxedRightType); @@ -5292,7 +5290,7 @@ The "returned" value of try expression with no finally is either the last expres Type type = boxType(typeMapper.mapTypeAsDeclaration(rhsKotlinType)); if (TypeUtils.isReifiedTypeParameter(rhsKotlinType)) { - putReifiedOperationMarkerIfTypeIsReifiedParameter(rhsKotlinType, ReifiedTypeInliner.OperationKind.IS); + putReifiedOperationMarkerIfTypeIsReifiedParameter(this, rhsKotlinType, ReifiedTypeInliner.OperationKind.IS); v.instanceOf(type); return null; } @@ -5544,11 +5542,4 @@ The "returned" value of try expression with no finally is either the last expres parentCodegen.getReifiedTypeParametersUsages().addUsedReifiedParameter(typeParameterDescriptor.getName().asString()); } } - - @Override - public void putReifiedOperationMarkerIfTypeIsReifiedParameter( - @NotNull KotlinTypeMarker type, @NotNull ReifiedTypeInliner.OperationKind operationKind - ) { - BaseExpressionCodegen.DefaultImpls.putReifiedOperationMarkerIfTypeIsReifiedParameter(this, type, operationKind); - } } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt index 94b7a4d8e76..680dee0c159 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/codegenUtil.kt @@ -393,13 +393,12 @@ fun TypeSystemCommonBackendContext.extractReificationArgument(initialType: Kotli while (type.isArrayOrNullableArray()) { arrayDepth++ val argument = type.getArgument(0) - type = - if (argument.isStarProjection()) nullableAnyType() - else argument.getType() + if (argument.isStarProjection()) return null + type = argument.getType() } val typeParameter = type.typeConstructor().getTypeParameterClassifier() ?: return null - + if (!typeParameter.isReified()) return null return Pair(typeParameter, ReificationArgument(typeParameter.getName().asString(), isNullable, arrayDepth)) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt index 65d329bfb3b..d39e5a50da2 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/typeOf.kt @@ -37,7 +37,7 @@ private fun TypeSystemCommonBackendContext.putTypeOfReifiedTypeParameter( v.aconst(null) } -internal fun TypeSystemCommonBackendContext.generateTypeOf( +fun TypeSystemCommonBackendContext.generateTypeOf( v: InstructionAdapter, type: KT, intrinsicsSupport: ReifiedTypeInliner.IntrinsicsSupport ) { val typeParameter = type.typeConstructor().getTypeParameterClassifier() @@ -103,7 +103,7 @@ private fun TypeSystemCommonBackendContext.generateNonRe TypeVariance.OUT -> KVariance.OUT } v.getstatic(K_VARIANCE.internalName, variance.name, K_VARIANCE.descriptor) - v.aconst(typeParameter.isReified()) + v.iconst(if (typeParameter.isReified()) 1 else 0) v.invokestatic( REFLECTION, "typeParameter", Type.getMethodDescriptor(K_TYPE_PARAMETER, OBJECT_TYPE, JAVA_STRING_TYPE, K_VARIANCE, Type.BOOLEAN_TYPE), @@ -119,11 +119,11 @@ private fun TypeSystemCommonBackendContext.generateNonRe if (bounds.size == 1) { generateTypeOf(v, bounds.single(), intrinsicsSupport) } else { - v.aconst(bounds.size) + v.iconst(bounds.size) v.newarray(K_TYPE) for ((i, bound) in bounds.withIndex()) { v.dup() - v.aconst(i) + v.iconst(i) generateTypeOf(v, bound, intrinsicsSupport) v.astore(K_TYPE) } diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KClassJavaObjectTypeProperty.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KClassJavaObjectTypeProperty.kt index 8fca452b548..553c865c305 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KClassJavaObjectTypeProperty.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/intrinsics/KClassJavaObjectTypeProperty.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner +import org.jetbrains.kotlin.codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter import org.jetbrains.kotlin.psi.KtClassLiteralExpression import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall 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 4fccb9f3858..e797a474f52 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 @@ -1342,10 +1342,10 @@ class ExpressionCodegen( val classType = classReference.classType val classifier = classType.classifierOrNull if (classifier is IrTypeParameterSymbol) { - assert(classifier.owner.isReified) { - "Non-reified type parameter under ::class should be rejected by type checker: ${classifier.owner.dump()}" + val success = putReifiedOperationMarkerIfTypeIsReifiedParameter(classType, ReifiedTypeInliner.OperationKind.JAVA_CLASS) + assert(success) { + "Non-reified type parameter under ::class should be rejected by type checker: ${classType.render()}" } - putReifiedOperationMarkerIfTypeIsReifiedParameter(classType, ReifiedTypeInliner.OperationKind.JAVA_CLASS) } generateClassInstance(mv, classType, typeMapper) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt index 7e916c196b5..64933e54658 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/codegen/IrInlineIntrinsicsSupport.kt @@ -77,13 +77,13 @@ class IrInlineIntrinsicsSupport( v.anew(implClass) v.dup() if (withArity) { - v.aconst(function.allParametersCount) + v.iconst(function.allParametersCount) } putClassInstance(v, FunctionReferenceLowering.getOwnerKClassType(declaration.parent, context)) v.aconst(declaration.name.asString()) // TODO: generate correct signature for functions and property accessors which have inline class types in the signature. SignatureString.generateSignatureString(v, function, context) - v.aconst(FunctionReferenceLowering.getCallableReferenceTopLevelFlag(declaration)) + v.iconst(FunctionReferenceLowering.getCallableReferenceTopLevelFlag(declaration)) val parameterTypes = (if (withArity) listOf(INT_TYPE) else emptyList()) + listOf(JAVA_CLASS_TYPE, JAVA_STRING_TYPE, JAVA_STRING_TYPE, INT_TYPE) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/EnumIntrinsics.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/EnumIntrinsics.kt index d02250af0dd..42be3e032ff 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/EnumIntrinsics.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/EnumIntrinsics.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.MaterialValue import org.jetbrains.kotlin.backend.jvm.codegen.materializedAt import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner +import org.jetbrains.kotlin.codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.org.objectweb.asm.Type diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/GetJavaObjectType.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/GetJavaObjectType.kt index 2d362d5e238..2d4242525bc 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/GetJavaObjectType.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/GetJavaObjectType.kt @@ -8,11 +8,12 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics import org.jetbrains.kotlin.backend.jvm.codegen.* import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner +import org.jetbrains.kotlin.codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter import org.jetbrains.kotlin.ir.expressions.IrClassReference import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrGetClass import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol -import org.jetbrains.kotlin.ir.util.dump +import org.jetbrains.kotlin.ir.util.render import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.org.objectweb.asm.Type @@ -23,13 +24,13 @@ object GetJavaObjectType : IntrinsicMethod() { is IrClassReference -> { val symbol = receiver.symbol if (symbol is IrTypeParameterSymbol) { - assert(symbol.owner.isReified) { - "Non-reified type parameter under ::class should be rejected by type checker: ${symbol.owner.dump()}" - } - codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter( + val success = codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter( receiver.classType, ReifiedTypeInliner.OperationKind.JAVA_CLASS ) + assert(success) { + "Non-reified type parameter under ::class should be rejected by type checker: ${receiver.render()}" + } } codegen.mv.aconst(AsmUtil.boxType(codegen.typeMapper.mapTypeAsDeclaration(receiver.classType))) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt index 798be9bd785..e7750f88c46 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/IrIntrinsicMethods.kt @@ -42,6 +42,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) { private val kotlinFqn = StandardNames.BUILT_INS_PACKAGE_FQ_NAME private val kotlinJvmFqn = FqName("kotlin.jvm") private val kotlinJvmInternalUnsafeFqn = FqName("kotlin.jvm.internal.unsafe") + private val kotlinReflectFqn = StandardNames.KOTLIN_REFLECT_FQ_NAME private val anyFqn = StandardNames.FqNames.any.toSafe() private val arrayFqn = StandardNames.FqNames.array.toSafe() @@ -64,6 +65,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) { Key(kotlinFqn, null, "enumValues", listOf()) to EnumValues, Key(kotlinFqn, null, "enumValueOf", listOf(stringFqn)) to EnumValueOf, Key(kotlinFqn, stringFqn, "plus", listOf(anyFqn)) to StringPlus, + Key(kotlinReflectFqn, null, "typeOf", listOf()) to TypeOf, irBuiltIns.eqeqSymbol.toKey()!! to Equals(KtTokens.EQEQ), irBuiltIns.eqeqeqSymbol.toKey()!! to Equals(KtTokens.EQEQEQ), irBuiltIns.ieee754equalsFunByOperandType[irBuiltIns.floatClass]!!.toKey()!! to Ieee754Equals(Type.FLOAT_TYPE), diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/NewArray.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/NewArray.kt index 6aa84fd3375..3a548be8b50 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/NewArray.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/NewArray.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner +import org.jetbrains.kotlin.codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.types.getArrayElementType import org.jetbrains.kotlin.ir.types.isArray @@ -16,7 +17,7 @@ import org.jetbrains.kotlin.ir.types.isNullableArray import org.jetbrains.org.objectweb.asm.Type object NewArray : IntrinsicMethod() { - override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue? { + override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo): PromisedValue { codegen.gen(expression.getValueArgument(0)!!, Type.INT_TYPE, codegen.context.irBuiltIns.intType, data) return with(codegen) { val elementIrType = expression.type.getArrayElementType(context.irBuiltIns) diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/TypeOf.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/TypeOf.kt new file mode 100644 index 00000000000..9615ed38b67 --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/intrinsics/TypeOf.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.backend.jvm.intrinsics + +import org.jetbrains.kotlin.backend.jvm.codegen.BlockInfo +import org.jetbrains.kotlin.backend.jvm.codegen.ExpressionCodegen +import org.jetbrains.kotlin.backend.jvm.codegen.IrInlineIntrinsicsSupport +import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner +import org.jetbrains.kotlin.codegen.inline.generateTypeOf +import org.jetbrains.kotlin.codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter +import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression + +object TypeOf : IntrinsicMethod() { + override fun invoke(expression: IrFunctionAccessExpression, codegen: ExpressionCodegen, data: BlockInfo) = with(codegen) { + val type = expression.getTypeArgument(0)!! + if (putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.TYPE_OF)) { + mv.aconst(null) // see ReifiedTypeInliner.processTypeOf + } else { + typeMapper.typeSystem.generateTypeOf(mv, type, IrInlineIntrinsicsSupport(context, typeMapper)) + } + expression.onStack + } +}