From da53d8cbf436f52e22886c5927590ec011f3186a Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 28 Dec 2015 09:54:39 +0300 Subject: [PATCH] Replace reified operations instanceof/checkcast with is/as It's more consistent with how they effectively work --- .../kotlin/codegen/ExpressionCodegen.java | 44 ++++++++++++------- .../codegen/inline/ReifiedTypeInliner.kt | 22 +++++----- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 64c3e569a4d..d1caad8c3b6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -3673,8 +3673,17 @@ The "returned" value of try expression with no finally is either the last expres StackValue.putUnitInstance(v); } + boolean safeAs = opToken == KtTokens.AS_SAFE; + if (TypeUtils.isReifiedTypeParameter(rightType)) { + putReifiedOperationMarkerIfTypeIsReifiedParameter(rightType, + safeAs ? ReifiedTypeInliner.OperationKind.SAFE_AS + : ReifiedTypeInliner.OperationKind.AS); + v.checkcast(boxType(asmType(rightType))); + return Unit.INSTANCE; + } + if (opToken != KtTokens.AS_SAFE) { - if (!TypeUtils.isNullableType(rightType) && !TypeUtils.isReifiedTypeParameter(rightType)) { + if (!TypeUtils.isNullableType(rightType)) { CodegenUtilKt.generateNullCheckForNonSafeAs(v, rightType); } } @@ -3688,7 +3697,7 @@ The "returned" value of try expression with no finally is either the last expres v.mark(ok); } - generateCheckCastInstruction(rightType, opToken == KtTokens.AS_SAFE); + generateCheckCastInstruction(rightType, safeAs); return Unit.INSTANCE; } }); @@ -3727,11 +3736,11 @@ The "returned" value of try expression with no finally is either the last expres private StackValue generateIsCheck(StackValue expressionToMatch, KtTypeReference typeReference, boolean negated) { KotlinType jetType = bindingContext.get(TYPE, typeReference); markStartLineNumber(typeReference); - StackValue value = generateInstanceOf(expressionToMatch, jetType, false); + StackValue value = generateIsCheck(expressionToMatch, jetType, false); return negated ? StackValue.not(value) : value; } - private StackValue generateInstanceOf(final StackValue expressionToGen, final KotlinType kotlinType, final boolean leaveExpressionOnStack) { + private StackValue generateIsCheck(final StackValue expressionToGen, final KotlinType kotlinType, final boolean leaveExpressionOnStack) { return StackValue.operation(Type.BOOLEAN_TYPE, new Function1() { @Override public Unit invoke(InstructionAdapter v) { @@ -3739,7 +3748,14 @@ The "returned" value of try expression with no finally is either the last expres if (leaveExpressionOnStack) { v.dup(); } - CodegenUtilKt.generateIsCheck(v, kotlinType.isMarkedNullable() && !TypeUtils.isReifiedTypeParameter(kotlinType), new Function1() { + + if (TypeUtils.isReifiedTypeParameter(kotlinType)) { + putReifiedOperationMarkerIfTypeIsReifiedParameter(kotlinType, ReifiedTypeInliner.OperationKind.IS); + v.instanceOf(boxType(asmType(kotlinType))); + return null; + } + + CodegenUtilKt.generateIsCheck(v, kotlinType.isMarkedNullable(), new Function1() { @Override public Unit invoke(InstructionAdapter adapter) { generateInstanceOfInstruction(kotlinType); @@ -3751,19 +3767,17 @@ The "returned" value of try expression with no finally is either the last expres }); } - private void generateInstanceOfInstruction(@NotNull KotlinType jetType) { - Type type = boxType(asmType(jetType)); - putReifiedOperationMarkerIfTypeIsReifiedParameter(jetType, ReifiedTypeInliner.OperationKind.INSTANCEOF); - TypeIntrinsics.instanceOf(v, jetType, type); + private void generateInstanceOfInstruction(@NotNull KotlinType kotlinType) { + Type type = boxType(asmType(kotlinType)); + assert !TypeUtils.isReifiedTypeParameter(kotlinType) : "This method should not be called with type based on reified type parameter, but found " + kotlinType; + TypeIntrinsics.instanceOf(v, kotlinType, type); } @NotNull - private StackValue generateCheckCastInstruction(@NotNull KotlinType jetType, boolean safeAs) { - Type type = boxType(asmType(jetType)); - putReifiedOperationMarkerIfTypeIsReifiedParameter(jetType, - safeAs ? ReifiedTypeInliner.OperationKind.SAFE_CHECKCAST - : ReifiedTypeInliner.OperationKind.CHECKCAST); - TypeIntrinsics.checkcast(v, jetType, type, safeAs); + private StackValue generateCheckCastInstruction(@NotNull KotlinType kotlinType, boolean safeAs) { + Type type = boxType(asmType(kotlinType)); + assert !TypeUtils.isReifiedTypeParameter(kotlinType) : "This method should not be called with type based on reified type parameter, but found " + kotlinType; + TypeIntrinsics.checkcast(v, kotlinType, type, safeAs); return StackValue.onStack(type); } 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 806fa291e4e..4518346d5c9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/inline/ReifiedTypeInliner.kt @@ -37,10 +37,10 @@ private class ParameterNameAndNullability(val name: String, val nullable: Boolea public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParameterMappings?) { enum class OperationKind { - NEW_ARRAY, CHECKCAST, SAFE_CHECKCAST, INSTANCEOF, JAVA_CLASS; + NEW_ARRAY, AS, SAFE_AS, IS, JAVA_CLASS; val id: Int get() = ordinal - val isTypeNullabilityAware: Boolean get() = this == CHECKCAST || this == INSTANCEOF + val isTypeNullabilityAware: Boolean get() = this == AS || this == IS } companion object { @@ -154,9 +154,9 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame // they return true if instruction is reified and marker can be deleted if (when (operationKind) { OperationKind.NEW_ARRAY -> processNewArray(insn, asmType) - OperationKind.CHECKCAST -> processCheckcast(insn, instructions, kotlinType, asmType, safe = false) - OperationKind.SAFE_CHECKCAST -> processCheckcast(insn, instructions, kotlinType, asmType, safe = true) - OperationKind.INSTANCEOF -> processInstanceof(insn, instructions, kotlinType, asmType) + OperationKind.AS -> processAs(insn, instructions, kotlinType, asmType, safe = false) + OperationKind.SAFE_AS -> processAs(insn, instructions, kotlinType, asmType, safe = true) + OperationKind.IS -> processIs(insn, instructions, kotlinType, asmType) OperationKind.JAVA_CLASS -> processJavaClass(insn, asmType) }) { instructions.remove(insn.previous.previous!!) // PUSH operation ID @@ -175,11 +175,11 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame private fun processNewArray(insn: MethodInsnNode, parameter: Type) = processNextTypeInsn(insn, parameter, Opcodes.ANEWARRAY) - private fun processCheckcast(insn: MethodInsnNode, - instructions: InsnList, - jetType: KotlinType, - asmType: Type, - safe: Boolean) = + private fun processAs(insn: MethodInsnNode, + instructions: InsnList, + jetType: KotlinType, + asmType: Type, + safe: Boolean) = rewriteNextTypeInsn(insn, Opcodes.CHECKCAST) { instanceofInsn: AbstractInsnNode -> if (instanceofInsn !is TypeInsnNode) return false @@ -198,7 +198,7 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame } } - private fun processInstanceof(insn: MethodInsnNode, instructions: InsnList, jetType: KotlinType, asmType: Type) = + private fun processIs(insn: MethodInsnNode, instructions: InsnList, jetType: KotlinType, asmType: Type) = rewriteNextTypeInsn(insn, Opcodes.INSTANCEOF) { instanceofInsn: AbstractInsnNode -> if (instanceofInsn !is TypeInsnNode) return false