JVM_IR: implement typeOf<T> 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.
This commit is contained in:
pyos
2021-05-27 16:18:06 +02:00
committed by max-kammerer
parent 7dbf08ae1c
commit eb4d831d27
12 changed files with 62 additions and 43 deletions
@@ -41,14 +41,11 @@ interface BaseExpressionCodegen {
fun markLineNumberAfterInlineIfNeeded(registerLineNumberAfterwards: Boolean) fun markLineNumberAfterInlineIfNeeded(registerLineNumberAfterwards: Boolean)
fun consumeReifiedOperationMarker(typeParameter: TypeParameterMarker) fun consumeReifiedOperationMarker(typeParameter: TypeParameterMarker)
}
fun putReifiedOperationMarkerIfTypeIsReifiedParameter(type: KotlinTypeMarker, operationKind: OperationKind) {
with(typeSystem) { fun BaseExpressionCodegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type: KotlinTypeMarker, operationKind: OperationKind): Boolean {
val (typeParameter, second) = extractReificationArgument(type) ?: return val (typeParameter, second) = typeSystem.extractReificationArgument(type) ?: return false
if (typeParameter.isReified()) { consumeReifiedOperationMarker(typeParameter)
consumeReifiedOperationMarker(typeParameter) putReifiedOperationMarker(operationKind, second, visitor)
putReifiedOperationMarker(operationKind, second, visitor) return true
}
}
}
} }
@@ -107,6 +107,7 @@ import java.util.stream.Collectors;
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt; import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt;
import static org.jetbrains.kotlin.codegen.AsmUtil.boxType; import static org.jetbrains.kotlin.codegen.AsmUtil.boxType;
import static org.jetbrains.kotlin.codegen.AsmUtil.*; 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.CodegenUtilKt.*;
import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.boxType; import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.boxType;
import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.*; import static org.jetbrains.kotlin.codegen.DescriptorAsmUtil.*;
@@ -3555,7 +3556,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (TypeUtils.isTypeParameter(type)) { if (TypeUtils.isTypeParameter(type)) {
assert TypeUtils.isReifiedTypeParameter(type) : assert TypeUtils.isReifiedTypeParameter(type) :
"Non-reified type parameter under ::class should be rejected by type checker: " + 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); putJavaLangClassInstance(v, typeMapper.mapType(type), type, typeMapper);
@@ -4928,10 +4929,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
public void newArrayInstruction(@NotNull KotlinType arrayType) { public void newArrayInstruction(@NotNull KotlinType arrayType) {
if (KotlinBuiltIns.isArray(arrayType)) { if (KotlinBuiltIns.isArray(arrayType)) {
KotlinType elementJetType = arrayType.getArguments().get(0).getType(); KotlinType elementJetType = arrayType.getArguments().get(0).getType();
putReifiedOperationMarkerIfTypeIsReifiedParameter( putReifiedOperationMarkerIfTypeIsReifiedParameter(this, elementJetType, ReifiedTypeInliner.OperationKind.NEW_ARRAY);
elementJetType,
ReifiedTypeInliner.OperationKind.NEW_ARRAY
);
v.newarray(boxType(typeMapper.mapTypeAsDeclaration(elementJetType))); v.newarray(boxType(typeMapper.mapTypeAsDeclaration(elementJetType)));
} }
else { 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; boolean safeAs = opToken == KtTokens.AS_SAFE;
if (TypeUtils.isReifiedTypeParameter(rightKotlinType)) { if (TypeUtils.isReifiedTypeParameter(rightKotlinType)) {
putReifiedOperationMarkerIfTypeIsReifiedParameter(rightKotlinType, putReifiedOperationMarkerIfTypeIsReifiedParameter(this, rightKotlinType,
safeAs ? ReifiedTypeInliner.OperationKind.SAFE_AS safeAs ? ReifiedTypeInliner.OperationKind.SAFE_AS
: ReifiedTypeInliner.OperationKind.AS); : ReifiedTypeInliner.OperationKind.AS);
v.checkcast(boxedRightType); 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)); Type type = boxType(typeMapper.mapTypeAsDeclaration(rhsKotlinType));
if (TypeUtils.isReifiedTypeParameter(rhsKotlinType)) { if (TypeUtils.isReifiedTypeParameter(rhsKotlinType)) {
putReifiedOperationMarkerIfTypeIsReifiedParameter(rhsKotlinType, ReifiedTypeInliner.OperationKind.IS); putReifiedOperationMarkerIfTypeIsReifiedParameter(this, rhsKotlinType, ReifiedTypeInliner.OperationKind.IS);
v.instanceOf(type); v.instanceOf(type);
return null; 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()); parentCodegen.getReifiedTypeParametersUsages().addUsedReifiedParameter(typeParameterDescriptor.getName().asString());
} }
} }
@Override
public void putReifiedOperationMarkerIfTypeIsReifiedParameter(
@NotNull KotlinTypeMarker type, @NotNull ReifiedTypeInliner.OperationKind operationKind
) {
BaseExpressionCodegen.DefaultImpls.putReifiedOperationMarkerIfTypeIsReifiedParameter(this, type, operationKind);
}
} }
@@ -393,13 +393,12 @@ fun TypeSystemCommonBackendContext.extractReificationArgument(initialType: Kotli
while (type.isArrayOrNullableArray()) { while (type.isArrayOrNullableArray()) {
arrayDepth++ arrayDepth++
val argument = type.getArgument(0) val argument = type.getArgument(0)
type = if (argument.isStarProjection()) return null
if (argument.isStarProjection()) nullableAnyType() type = argument.getType()
else argument.getType()
} }
val typeParameter = type.typeConstructor().getTypeParameterClassifier() ?: return null val typeParameter = type.typeConstructor().getTypeParameterClassifier() ?: return null
if (!typeParameter.isReified()) return null
return Pair(typeParameter, ReificationArgument(typeParameter.getName().asString(), isNullable, arrayDepth)) return Pair(typeParameter, ReificationArgument(typeParameter.getName().asString(), isNullable, arrayDepth))
} }
@@ -37,7 +37,7 @@ private fun TypeSystemCommonBackendContext.putTypeOfReifiedTypeParameter(
v.aconst(null) v.aconst(null)
} }
internal fun <KT : KotlinTypeMarker> TypeSystemCommonBackendContext.generateTypeOf( fun <KT : KotlinTypeMarker> TypeSystemCommonBackendContext.generateTypeOf(
v: InstructionAdapter, type: KT, intrinsicsSupport: ReifiedTypeInliner.IntrinsicsSupport<KT> v: InstructionAdapter, type: KT, intrinsicsSupport: ReifiedTypeInliner.IntrinsicsSupport<KT>
) { ) {
val typeParameter = type.typeConstructor().getTypeParameterClassifier() val typeParameter = type.typeConstructor().getTypeParameterClassifier()
@@ -103,7 +103,7 @@ private fun <KT : KotlinTypeMarker> TypeSystemCommonBackendContext.generateNonRe
TypeVariance.OUT -> KVariance.OUT TypeVariance.OUT -> KVariance.OUT
} }
v.getstatic(K_VARIANCE.internalName, variance.name, K_VARIANCE.descriptor) v.getstatic(K_VARIANCE.internalName, variance.name, K_VARIANCE.descriptor)
v.aconst(typeParameter.isReified()) v.iconst(if (typeParameter.isReified()) 1 else 0)
v.invokestatic( v.invokestatic(
REFLECTION, "typeParameter", REFLECTION, "typeParameter",
Type.getMethodDescriptor(K_TYPE_PARAMETER, OBJECT_TYPE, JAVA_STRING_TYPE, K_VARIANCE, Type.BOOLEAN_TYPE), Type.getMethodDescriptor(K_TYPE_PARAMETER, OBJECT_TYPE, JAVA_STRING_TYPE, K_VARIANCE, Type.BOOLEAN_TYPE),
@@ -119,11 +119,11 @@ private fun <KT : KotlinTypeMarker> TypeSystemCommonBackendContext.generateNonRe
if (bounds.size == 1) { if (bounds.size == 1) {
generateTypeOf(v, bounds.single(), intrinsicsSupport) generateTypeOf(v, bounds.single(), intrinsicsSupport)
} else { } else {
v.aconst(bounds.size) v.iconst(bounds.size)
v.newarray(K_TYPE) v.newarray(K_TYPE)
for ((i, bound) in bounds.withIndex()) { for ((i, bound) in bounds.withIndex()) {
v.dup() v.dup()
v.aconst(i) v.iconst(i)
generateTypeOf(v, bound, intrinsicsSupport) generateTypeOf(v, bound, intrinsicsSupport)
v.astore(K_TYPE) v.astore(K_TYPE)
} }
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.ExpressionCodegen import org.jetbrains.kotlin.codegen.ExpressionCodegen
import org.jetbrains.kotlin.codegen.StackValue import org.jetbrains.kotlin.codegen.StackValue
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
import org.jetbrains.kotlin.codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter
import org.jetbrains.kotlin.psi.KtClassLiteralExpression import org.jetbrains.kotlin.psi.KtClassLiteralExpression
import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS import org.jetbrains.kotlin.resolve.BindingContext.DOUBLE_COLON_LHS
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
@@ -1342,10 +1342,10 @@ class ExpressionCodegen(
val classType = classReference.classType val classType = classReference.classType
val classifier = classType.classifierOrNull val classifier = classType.classifierOrNull
if (classifier is IrTypeParameterSymbol) { if (classifier is IrTypeParameterSymbol) {
assert(classifier.owner.isReified) { val success = putReifiedOperationMarkerIfTypeIsReifiedParameter(classType, ReifiedTypeInliner.OperationKind.JAVA_CLASS)
"Non-reified type parameter under ::class should be rejected by type checker: ${classifier.owner.dump()}" 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) generateClassInstance(mv, classType, typeMapper)
@@ -77,13 +77,13 @@ class IrInlineIntrinsicsSupport(
v.anew(implClass) v.anew(implClass)
v.dup() v.dup()
if (withArity) { if (withArity) {
v.aconst(function.allParametersCount) v.iconst(function.allParametersCount)
} }
putClassInstance(v, FunctionReferenceLowering.getOwnerKClassType(declaration.parent, context)) putClassInstance(v, FunctionReferenceLowering.getOwnerKClassType(declaration.parent, context))
v.aconst(declaration.name.asString()) v.aconst(declaration.name.asString())
// TODO: generate correct signature for functions and property accessors which have inline class types in the signature. // TODO: generate correct signature for functions and property accessors which have inline class types in the signature.
SignatureString.generateSignatureString(v, function, context) SignatureString.generateSignatureString(v, function, context)
v.aconst(FunctionReferenceLowering.getCallableReferenceTopLevelFlag(declaration)) v.iconst(FunctionReferenceLowering.getCallableReferenceTopLevelFlag(declaration))
val parameterTypes = val parameterTypes =
(if (withArity) listOf(INT_TYPE) else emptyList()) + (if (withArity) listOf(INT_TYPE) else emptyList()) +
listOf(JAVA_CLASS_TYPE, JAVA_STRING_TYPE, JAVA_STRING_TYPE, INT_TYPE) listOf(JAVA_CLASS_TYPE, JAVA_STRING_TYPE, JAVA_STRING_TYPE, INT_TYPE)
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.MaterialValue
import org.jetbrains.kotlin.backend.jvm.codegen.materializedAt import org.jetbrains.kotlin.backend.jvm.codegen.materializedAt
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner 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.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -8,11 +8,12 @@ package org.jetbrains.kotlin.backend.jvm.intrinsics
import org.jetbrains.kotlin.backend.jvm.codegen.* import org.jetbrains.kotlin.backend.jvm.codegen.*
import org.jetbrains.kotlin.codegen.AsmUtil import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner 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.IrClassReference
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.expressions.IrGetClass import org.jetbrains.kotlin.ir.expressions.IrGetClass
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol 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.kotlin.resolve.jvm.AsmTypes
import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type
@@ -23,13 +24,13 @@ object GetJavaObjectType : IntrinsicMethod() {
is IrClassReference -> { is IrClassReference -> {
val symbol = receiver.symbol val symbol = receiver.symbol
if (symbol is IrTypeParameterSymbol) { if (symbol is IrTypeParameterSymbol) {
assert(symbol.owner.isReified) { val success = codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(
"Non-reified type parameter under ::class should be rejected by type checker: ${symbol.owner.dump()}"
}
codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(
receiver.classType, receiver.classType,
ReifiedTypeInliner.OperationKind.JAVA_CLASS 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))) codegen.mv.aconst(AsmUtil.boxType(codegen.typeMapper.mapTypeAsDeclaration(receiver.classType)))
@@ -42,6 +42,7 @@ class IrIntrinsicMethods(val irBuiltIns: IrBuiltIns, val symbols: JvmSymbols) {
private val kotlinFqn = StandardNames.BUILT_INS_PACKAGE_FQ_NAME private val kotlinFqn = StandardNames.BUILT_INS_PACKAGE_FQ_NAME
private val kotlinJvmFqn = FqName("kotlin.jvm") private val kotlinJvmFqn = FqName("kotlin.jvm")
private val kotlinJvmInternalUnsafeFqn = FqName("kotlin.jvm.internal.unsafe") 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 anyFqn = StandardNames.FqNames.any.toSafe()
private val arrayFqn = StandardNames.FqNames.array.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, "enumValues", listOf()) to EnumValues,
Key(kotlinFqn, null, "enumValueOf", listOf(stringFqn)) to EnumValueOf, Key(kotlinFqn, null, "enumValueOf", listOf(stringFqn)) to EnumValueOf,
Key(kotlinFqn, stringFqn, "plus", listOf(anyFqn)) to StringPlus, Key(kotlinFqn, stringFqn, "plus", listOf(anyFqn)) to StringPlus,
Key(kotlinReflectFqn, null, "typeOf", listOf()) to TypeOf,
irBuiltIns.eqeqSymbol.toKey()!! to Equals(KtTokens.EQEQ), irBuiltIns.eqeqSymbol.toKey()!! to Equals(KtTokens.EQEQ),
irBuiltIns.eqeqeqSymbol.toKey()!! to Equals(KtTokens.EQEQEQ), irBuiltIns.eqeqeqSymbol.toKey()!! to Equals(KtTokens.EQEQEQ),
irBuiltIns.ieee754equalsFunByOperandType[irBuiltIns.floatClass]!!.toKey()!! to Ieee754Equals(Type.FLOAT_TYPE), irBuiltIns.ieee754equalsFunByOperandType[irBuiltIns.floatClass]!!.toKey()!! to Ieee754Equals(Type.FLOAT_TYPE),
@@ -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.ExpressionCodegen
import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue import org.jetbrains.kotlin.backend.jvm.codegen.PromisedValue
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner 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.expressions.IrFunctionAccessExpression
import org.jetbrains.kotlin.ir.types.getArrayElementType import org.jetbrains.kotlin.ir.types.getArrayElementType
import org.jetbrains.kotlin.ir.types.isArray 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 import org.jetbrains.org.objectweb.asm.Type
object NewArray : IntrinsicMethod() { 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) codegen.gen(expression.getValueArgument(0)!!, Type.INT_TYPE, codegen.context.irBuiltIns.intType, data)
return with(codegen) { return with(codegen) {
val elementIrType = expression.type.getArrayElementType(context.irBuiltIns) val elementIrType = expression.type.getArrayElementType(context.irBuiltIns)
@@ -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
}
}