Typecheck instructions are supported for reified T

This commit is contained in:
Denis Zharkov
2014-10-06 13:46:23 +04:00
committed by Andrey Breslav
parent 416ac7917b
commit f3c49c605f
10 changed files with 154 additions and 24 deletions
@@ -3401,16 +3401,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
if (isArray) {
gen(args.get(0), Type.INT_TYPE);
TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(
arrayType.getArguments().get(0).getType()
putReifierMarkerIfTypeIsReifiedParameter(
arrayType.getArguments().get(0).getType(),
ReifiedTypeInliner.NEW_ARRAY_MARKER_METHOD_NAME
);
if (parameterDescriptor != null && parameterDescriptor.isReified()) {
v.iconst(parameterDescriptor.getIndex());
v.invokestatic(
IntrinsicMethods.INTRINSICS_CLASS_NAME, ReifiedTypeInliner.NEW_ARRAY_MARKER_METHOD_NAME,
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE), false
);
}
v.newarray(boxType(asmType(arrayType.getArguments().get(0).getType())));
}
else {
@@ -3702,7 +3696,6 @@ The "returned" value of try expression with no finally is either the last expres
JetTypeReference typeReference = expression.getRight();
JetType rightType = bindingContext.get(TYPE, typeReference);
assert rightType != null;
Type rightTypeAsm = boxType(asmType(rightType));
JetExpression left = expression.getLeft();
DeclarationDescriptor descriptor = rightType.getConstructor().getDeclarationDescriptor();
if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) {
@@ -3724,7 +3717,7 @@ The "returned" value of try expression with no finally is either the last expres
}
else {
v.dup();
v.instanceOf(rightTypeAsm);
generateInstanceOfInstruction(rightType);
Label ok = new Label();
v.ifne(ok);
v.pop();
@@ -3732,8 +3725,7 @@ The "returned" value of try expression with no finally is either the last expres
v.mark(ok);
}
v.checkcast(rightTypeAsm);
return StackValue.onStack(rightTypeAsm);
return generateCheckCastInstruction(rightType);
}
else {
throw new UnsupportedOperationException("Don't know how to handle non-class types in as/as? : " + descriptor);
@@ -3786,14 +3778,13 @@ The "returned" value of try expression with no finally is either the last expres
if (leaveExpressionOnStack) {
v.dup();
}
Type type = boxType(asmType(jetType));
if (jetType.isNullable()) {
Label nope = new Label();
Label end = new Label();
v.dup();
v.ifnull(nope);
v.instanceOf(type);
generateInstanceOfInstruction(jetType);
v.goTo(end);
v.mark(nope);
v.pop();
@@ -3801,7 +3792,32 @@ The "returned" value of try expression with no finally is either the last expres
v.mark(end);
}
else {
v.instanceOf(type);
generateInstanceOfInstruction(jetType);
}
}
private void generateInstanceOfInstruction(@NotNull JetType jetType) {
Type type = boxType(asmType(jetType));
putReifierMarkerIfTypeIsReifiedParameter(jetType, ReifiedTypeInliner.INSTANCEOF_MARKER_METHOD_NAME);
v.instanceOf(type);
}
@NotNull
private StackValue generateCheckCastInstruction(@NotNull JetType jetType) {
Type type = boxType(asmType(jetType));
putReifierMarkerIfTypeIsReifiedParameter(jetType, ReifiedTypeInliner.CHECKCAST_MARKER_METHOD_NAME);
v.checkcast(type);
return StackValue.onStack(type);
}
private void putReifierMarkerIfTypeIsReifiedParameter(@NotNull JetType type, @NotNull String markerMethodName) {
TypeParameterDescriptor typeParameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(type);
if (typeParameterDescriptor != null && typeParameterDescriptor.isReified()) {
v.iconst(typeParameterDescriptor.getIndex());
v.invokestatic(
IntrinsicMethods.INTRINSICS_CLASS_NAME, markerMethodName,
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE), false
);
}
}
@@ -35,6 +35,8 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
class object {
public val NEW_ARRAY_MARKER_METHOD_NAME: String = "reifyNewArray"
public val CHECKCAST_MARKER_METHOD_NAME: String = "reifyCheckcast"
public val INSTANCEOF_MARKER_METHOD_NAME: String = "reifyInstanceof"
}
public fun reifyInstructions(instructions: InsnList) {
@@ -54,9 +56,12 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
private fun processReifyMarker(insn: MethodInsnNode, instructions: InsnList) {
val mapping = getTypeParameterMapping(insn) ?: return
if (mapping.asmType != null) {
val asmType = mapping.asmType
if (asmType != null) {
if (!when (insn.name) {
NEW_ARRAY_MARKER_METHOD_NAME -> processNewArray(insn, mapping.asmType)
NEW_ARRAY_MARKER_METHOD_NAME -> processNewArray(insn, asmType)
CHECKCAST_MARKER_METHOD_NAME -> processCheckcast(insn, asmType)
INSTANCEOF_MARKER_METHOD_NAME -> processInstanceof(insn, asmType)
else -> false
}) {
return
@@ -68,10 +73,18 @@ public class ReifiedTypeInliner(private val parametersMapping: ReifiedTypeParame
}
}
private fun processNewArray(insn: MethodInsnNode, parameter: Type): Boolean {
if (insn.getNext()?.getOpcode() != Opcodes.ANEWARRAY) return false
val next = insn.getNext() as TypeInsnNode
next.desc = parameter.getInternalName()
private fun processNewArray(insn: MethodInsnNode, parameter: Type) =
processNextTypeInsn(insn, parameter, Opcodes.ANEWARRAY)
private fun processCheckcast(insn: MethodInsnNode, parameter: Type) =
processNextTypeInsn(insn, parameter, Opcodes.CHECKCAST)
private fun processInstanceof(insn: MethodInsnNode, parameter: Type) =
processNextTypeInsn(insn, parameter, Opcodes.INSTANCEOF)
private fun processNextTypeInsn(insn: MethodInsnNode, parameter: Type, expectedNextOpcode: Int): Boolean {
if (insn.getNext()?.getOpcode() != expectedNextOpcode) return false
(insn.getNext() as TypeInsnNode).desc = parameter.getInternalName()
return true
}