Replace reified operations instanceof/checkcast with is/as

It's more consistent with how they effectively work
This commit is contained in:
Denis Zharkov
2015-12-28 09:54:39 +03:00
parent 87b6374351
commit da53d8cbf4
2 changed files with 40 additions and 26 deletions
@@ -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<InstructionAdapter, Unit>() {
@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<InstructionAdapter, Unit>() {
if (TypeUtils.isReifiedTypeParameter(kotlinType)) {
putReifiedOperationMarkerIfTypeIsReifiedParameter(kotlinType, ReifiedTypeInliner.OperationKind.IS);
v.instanceOf(boxType(asmType(kotlinType)));
return null;
}
CodegenUtilKt.generateIsCheck(v, kotlinType.isMarkedNullable(), new Function1<InstructionAdapter, Unit>() {
@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);
}
@@ -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