diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java index 0b6f77703d6..1b8569d2e9e 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/common/OptimizationBasicInterpreter.java @@ -18,16 +18,24 @@ package org.jetbrains.kotlin.codegen.optimization.common; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.org.objectweb.asm.Handle; import org.jetbrains.org.objectweb.asm.Opcodes; import org.jetbrains.org.objectweb.asm.Type; -import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode; +import org.jetbrains.org.objectweb.asm.tree.*; import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException; -import org.jetbrains.org.objectweb.asm.tree.analysis.BasicInterpreter; import org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue; +import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter; + +import java.util.List; import static org.jetbrains.kotlin.codegen.optimization.common.StrictBasicValue.*; -public class OptimizationBasicInterpreter extends BasicInterpreter { +public class OptimizationBasicInterpreter extends Interpreter implements Opcodes { + + public OptimizationBasicInterpreter() { + super(ASM5); + } + @Override @Nullable public StrictBasicValue newValue(@Nullable Type type) { @@ -67,7 +75,78 @@ public class OptimizationBasicInterpreter extends BasicInterpreter { if (insn.getOpcode() == Opcodes.ACONST_NULL) { return newValue(Type.getObjectType("java/lang/Object")); } - return super.newOperation(insn); + + switch (insn.getOpcode()) { + case ACONST_NULL: + return newValue(Type.getObjectType("null")); + case ICONST_M1: + case ICONST_0: + case ICONST_1: + case ICONST_2: + case ICONST_3: + case ICONST_4: + case ICONST_5: + return StrictBasicValue.INT_VALUE; + case LCONST_0: + case LCONST_1: + return StrictBasicValue.LONG_VALUE; + case FCONST_0: + case FCONST_1: + case FCONST_2: + return StrictBasicValue.FLOAT_VALUE; + case DCONST_0: + case DCONST_1: + return StrictBasicValue.DOUBLE_VALUE; + case BIPUSH: + case SIPUSH: + return StrictBasicValue.INT_VALUE; + case LDC: + Object cst = ((LdcInsnNode) insn).cst; + if (cst instanceof Integer) { + return StrictBasicValue.INT_VALUE; + } + else if (cst instanceof Float) { + return StrictBasicValue.FLOAT_VALUE; + } + else if (cst instanceof Long) { + return StrictBasicValue.LONG_VALUE; + } + else if (cst instanceof Double) { + return StrictBasicValue.DOUBLE_VALUE; + } + else if (cst instanceof String) { + return newValue(Type.getObjectType("java/lang/String")); + } + else if (cst instanceof Type) { + int sort = ((Type) cst).getSort(); + if (sort == Type.OBJECT || sort == Type.ARRAY) { + return newValue(Type.getObjectType("java/lang/Class")); + } + else if (sort == Type.METHOD) { + return newValue(Type.getObjectType("java/lang/invoke/MethodType")); + } + else { + throw new IllegalArgumentException("Illegal LDC constant " + cst); + } + } + else if (cst instanceof Handle) { + return newValue(Type.getObjectType("java/lang/invoke/MethodHandle")); + } + else { + throw new IllegalArgumentException("Illegal LDC constant " + cst); + } + case GETSTATIC: + return newValue(Type.getType(((FieldInsnNode) insn).desc)); + case NEW: + return newValue(Type.getObjectType(((TypeInsnNode) insn).desc)); + default: + throw new Error("Internal error."); + } + } + + @Override + public BasicValue copyOperation(@NotNull AbstractInsnNode insn, BasicValue value) throws AnalyzerException { + return value; } @Override @@ -79,11 +158,194 @@ public class OptimizationBasicInterpreter extends BasicInterpreter { if (insn.getOpcode() == Opcodes.AALOAD) { Type arrayType = value1.getType(); if (arrayType != null && arrayType.getSort() == Type.ARRAY) { - return new BasicValue(arrayType.getElementType()); + return new StrictBasicValue(arrayType.getElementType()); } } - return super.binaryOperation(insn, value1, value2); + switch (insn.getOpcode()) { + case IALOAD: + case BALOAD: + case CALOAD: + case SALOAD: + case IADD: + case ISUB: + case IMUL: + case IDIV: + case IREM: + case ISHL: + case ISHR: + case IUSHR: + case IAND: + case IOR: + case IXOR: + return StrictBasicValue.INT_VALUE; + case FALOAD: + case FADD: + case FSUB: + case FMUL: + case FDIV: + case FREM: + return StrictBasicValue.FLOAT_VALUE; + case LALOAD: + case LADD: + case LSUB: + case LMUL: + case LDIV: + case LREM: + case LSHL: + case LSHR: + case LUSHR: + case LAND: + case LOR: + case LXOR: + return StrictBasicValue.LONG_VALUE; + case DALOAD: + case DADD: + case DSUB: + case DMUL: + case DDIV: + case DREM: + return StrictBasicValue.DOUBLE_VALUE; + case AALOAD: + return StrictBasicValue.REFERENCE_VALUE; + case LCMP: + case FCMPL: + case FCMPG: + case DCMPL: + case DCMPG: + return StrictBasicValue.INT_VALUE; + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: + case IF_ACMPEQ: + case IF_ACMPNE: + case PUTFIELD: + return null; + default: + throw new Error("Internal error."); + } + } + + @Override + public BasicValue ternaryOperation( + AbstractInsnNode insn, BasicValue value1, BasicValue value2, BasicValue value3 + ) throws AnalyzerException { + return null; + } + + @Override + public BasicValue naryOperation( + AbstractInsnNode insn, List values + ) throws AnalyzerException { + int opcode = insn.getOpcode(); + if (opcode == MULTIANEWARRAY) { + return newValue(Type.getType(((MultiANewArrayInsnNode) insn).desc)); + } + else if (opcode == INVOKEDYNAMIC) { + return newValue(Type.getReturnType(((InvokeDynamicInsnNode) insn).desc)); + } + else { + return newValue(Type.getReturnType(((MethodInsnNode) insn).desc)); + } + } + + @Override + public void returnOperation( + AbstractInsnNode insn, BasicValue value, BasicValue expected + ) throws AnalyzerException { + } + + @Override + public BasicValue unaryOperation( + AbstractInsnNode insn, + BasicValue value + ) throws AnalyzerException { + switch (insn.getOpcode()) { + case INEG: + case IINC: + case L2I: + case F2I: + case D2I: + case I2B: + case I2C: + case I2S: + return StrictBasicValue.INT_VALUE; + case FNEG: + case I2F: + case L2F: + case D2F: + return StrictBasicValue.FLOAT_VALUE; + case LNEG: + case I2L: + case F2L: + case D2L: + return StrictBasicValue.LONG_VALUE; + case DNEG: + case I2D: + case L2D: + case F2D: + return StrictBasicValue.DOUBLE_VALUE; + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: + case TABLESWITCH: + case LOOKUPSWITCH: + case IRETURN: + case LRETURN: + case FRETURN: + case DRETURN: + case ARETURN: + case PUTSTATIC: + return null; + case GETFIELD: + return newValue(Type.getType(((FieldInsnNode) insn).desc)); + case NEWARRAY: + switch (((IntInsnNode) insn).operand) { + case T_BOOLEAN: + return newValue(Type.getType("[Z")); + case T_CHAR: + return newValue(Type.getType("[C")); + case T_BYTE: + return newValue(Type.getType("[B")); + case T_SHORT: + return newValue(Type.getType("[S")); + case T_INT: + return newValue(Type.getType("[I")); + case T_FLOAT: + return newValue(Type.getType("[F")); + case T_DOUBLE: + return newValue(Type.getType("[D")); + case T_LONG: + return newValue(Type.getType("[J")); + default: + throw new AnalyzerException(insn, "Invalid array type"); + } + case ANEWARRAY: + String desc = ((TypeInsnNode) insn).desc; + return newValue(Type.getType("[" + Type.getObjectType(desc))); + case ARRAYLENGTH: + return StrictBasicValue.INT_VALUE; + case ATHROW: + return null; + case CHECKCAST: + desc = ((TypeInsnNode) insn).desc; + return newValue(Type.getObjectType(desc)); + case INSTANCEOF: + return StrictBasicValue.INT_VALUE; + case MONITORENTER: + case MONITOREXIT: + case IFNULL: + case IFNONNULL: + return null; + default: + throw new Error("Internal error."); + } } @NotNull diff --git a/compiler/testData/codegen/box/regressions/kt14447.kt b/compiler/testData/codegen/box/regressions/kt14447.kt new file mode 100644 index 00000000000..7aab4c5003b --- /dev/null +++ b/compiler/testData/codegen/box/regressions/kt14447.kt @@ -0,0 +1,22 @@ +class ImpulsMigration +{ + fun migrate(oldVersion: Long) + { + var _oldVersion = oldVersion + + if (4 > 3) + { + _oldVersion = 1 + } + + if (1 > 3) + { + _oldVersion++ + } + } +} + +fun box(): String { + ImpulsMigration().migrate(1L) + return "OK" +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index f90a01c9ca3..74363bd5e89 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -13900,6 +13900,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes doTest(fileName); } + @TestMetadata("kt14447.kt") + public void testKt14447() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt14447.kt"); + doTest(fileName); + } + @TestMetadata("kt1515.kt") public void testKt1515() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt1515.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index e7a70fc5956..787fdade409 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -13900,6 +13900,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("kt14447.kt") + public void testKt14447() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt14447.kt"); + doTest(fileName); + } + @TestMetadata("kt1515.kt") public void testKt1515() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/regressions/kt1515.kt");