diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/BasicTypeInterpreter.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/BasicTypeInterpreter.kt new file mode 100644 index 00000000000..25bceacce77 --- /dev/null +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/BasicTypeInterpreter.kt @@ -0,0 +1,167 @@ +/* + * 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.codegen.optimization.fixStack + +import org.jetbrains.kotlin.codegen.inline.insnOpcodeText +import org.jetbrains.kotlin.resolve.jvm.AsmTypes +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.* +import org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException +import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter +import org.jetbrains.org.objectweb.asm.tree.analysis.Value + +abstract class BasicTypeInterpreter : Interpreter(API_VERSION) { + + protected abstract fun uninitializedValue(): V + protected abstract fun booleanValue(): V + protected abstract fun charValue(): V + protected abstract fun byteValue(): V + protected abstract fun shortValue(): V + protected abstract fun intValue(): V + protected abstract fun longValue(): V + protected abstract fun floatValue(): V + protected abstract fun doubleValue(): V + protected abstract fun nullValue(): V + protected abstract fun objectValue(type: Type): V + protected abstract fun arrayValue(type: Type): V + protected abstract fun methodValue(type: Type): V + protected abstract fun handleValue(handle: Handle): V + protected abstract fun typeConstValue(typeConst: Type): V + protected abstract fun aaLoadValue(arrayValue: V): V + + override fun newValue(type: Type?): V? = + if (type == null) + uninitializedValue() + else when (type.sort) { + Type.VOID -> null + Type.BOOLEAN -> booleanValue() + Type.CHAR -> charValue() + Type.BYTE -> byteValue() + Type.SHORT -> shortValue() + Type.INT -> intValue() + Type.FLOAT -> floatValue() + Type.LONG -> longValue() + Type.DOUBLE -> doubleValue() + Type.ARRAY -> arrayValue(type) + Type.OBJECT -> objectValue(type) + Type.METHOD -> methodValue(type) + else -> throw AssertionError("Unexpected type: $type") + } + + override fun newOperation(insn: AbstractInsnNode): V? = + when (insn.opcode) { + ACONST_NULL -> + nullValue() + ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5 -> + intValue() + LCONST_0, LCONST_1 -> + longValue() + FCONST_0, FCONST_1, FCONST_2 -> + floatValue() + DCONST_0, DCONST_1 -> + doubleValue() + BIPUSH, SIPUSH -> + intValue() + LDC -> { + when (val cst = (insn as LdcInsnNode).cst) { + is Int -> intValue() + is Float -> floatValue() + is Long -> longValue() + is Double -> doubleValue() + is String -> objectValue(AsmTypes.JAVA_STRING_TYPE) + is Handle -> handleValue(cst) + is Type -> typeConstValue(cst) + else -> throw IllegalArgumentException("Illegal LDC constant $cst") + } + } + GETSTATIC -> + newValue(Type.getType((insn as FieldInsnNode).desc)) + NEW -> + newValue(Type.getObjectType((insn as TypeInsnNode).desc)) + else -> + throw IllegalArgumentException("Unexpected instruction: " + insn.insnOpcodeText) + } + + override fun binaryOperation(insn: AbstractInsnNode, value1: V, value2: V): V? = + when (insn.opcode) { + IALOAD, BALOAD, CALOAD, SALOAD, IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IAND, IOR, IXOR -> + intValue() + FALOAD, FADD, FSUB, FMUL, FDIV, FREM -> + floatValue() + LALOAD, LADD, LSUB, LMUL, LDIV, LREM, LSHL, LSHR, LUSHR, LAND, LOR, LXOR -> + longValue() + DALOAD, DADD, DSUB, DMUL, DDIV, DREM -> + doubleValue() + AALOAD -> + aaLoadValue(value1) + LCMP, FCMPL, FCMPG, DCMPL, DCMPG -> + intValue() + IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, PUTFIELD -> + null + else -> + throw IllegalArgumentException("Unexpected instruction: " + insn.insnOpcodeText) + } + + override fun ternaryOperation(insn: AbstractInsnNode, value1: V, value2: V, value3: V): V? = + null + + override fun naryOperation(insn: AbstractInsnNode, values: List): V? = + when (insn.opcode) { + MULTIANEWARRAY -> + newValue(Type.getType((insn as MultiANewArrayInsnNode).desc)) + INVOKEDYNAMIC -> + newValue(Type.getReturnType((insn as InvokeDynamicInsnNode).desc)) + else -> + newValue(Type.getReturnType((insn as MethodInsnNode).desc)) + } + + override fun returnOperation(insn: AbstractInsnNode, value: V?, expected: V?) { + } + + override fun unaryOperation(insn: AbstractInsnNode, value: V): V? = + when (insn.opcode) { + INEG, IINC, L2I, F2I, D2I, I2B, I2C, I2S -> + intValue() + FNEG, I2F, L2F, D2F -> + floatValue() + LNEG, I2L, F2L, D2L -> + longValue() + DNEG, I2D, L2D, F2D -> + doubleValue() + IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, PUTSTATIC -> + null + GETFIELD -> + newValue(Type.getType((insn as FieldInsnNode).desc)) + NEWARRAY -> + when ((insn as IntInsnNode).operand) { + T_BOOLEAN -> newValue(Type.getType("[Z")) + T_CHAR -> newValue(Type.getType("[C")) + T_BYTE -> newValue(Type.getType("[B")) + T_SHORT -> newValue(Type.getType("[S")) + T_INT -> newValue(Type.getType("[I")) + T_FLOAT -> newValue(Type.getType("[F")) + T_DOUBLE -> newValue(Type.getType("[D")) + T_LONG -> newValue(Type.getType("[J")) + else -> throw AnalyzerException(insn, "Invalid array type") + } + ANEWARRAY -> + newValue(Type.getType("[" + Type.getObjectType((insn as TypeInsnNode).desc))) + ARRAYLENGTH -> + intValue() + ATHROW -> + null + CHECKCAST -> + newValue(Type.getObjectType((insn as TypeInsnNode).desc)) + INSTANCEOF -> + intValue() + MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL -> + null + else -> + throw IllegalArgumentException("Unexpected instruction: " + insn.insnOpcodeText) + } +} \ No newline at end of file diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackInterpreter.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackInterpreter.kt index 30e69f257c1..c82689ac789 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackInterpreter.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/optimization/fixStack/FixStackInterpreter.kt @@ -5,153 +5,42 @@ package org.jetbrains.kotlin.codegen.optimization.fixStack -import org.jetbrains.kotlin.codegen.inline.insnOpcodeText 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.* -import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter +import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode -open class FixStackInterpreter : Interpreter(API_VERSION) { +class FixStackInterpreter : BasicTypeInterpreter() { + override fun uninitializedValue() = FixStackValue.UNINITIALIZED + override fun booleanValue() = FixStackValue.INT + override fun charValue() = FixStackValue.INT + override fun byteValue() = FixStackValue.INT + override fun shortValue() = FixStackValue.INT + override fun intValue() = FixStackValue.INT + override fun longValue() = FixStackValue.LONG + override fun floatValue() = FixStackValue.FLOAT + override fun doubleValue() = FixStackValue.DOUBLE + override fun nullValue() = FixStackValue.OBJECT + override fun objectValue(type: Type) = FixStackValue.OBJECT + override fun arrayValue(type: Type) = FixStackValue.OBJECT + override fun methodValue(type: Type) = FixStackValue.OBJECT + override fun handleValue(handle: Handle) = FixStackValue.OBJECT + override fun typeConstValue(typeConst: Type) = FixStackValue.OBJECT + override fun aaLoadValue(arrayValue: FixStackValue) = FixStackValue.OBJECT - override fun newValue(type: Type?): FixStackValue = - type?.toFixStackValue() - ?: FixStackValue.UNINITIALIZED - - override fun newOperation(insn: AbstractInsnNode): FixStackValue? = - when (insn.opcode) { - ACONST_NULL -> - FixStackValue.OBJECT - ICONST_M1, ICONST_0, ICONST_1, ICONST_2, ICONST_3, ICONST_4, ICONST_5 -> - FixStackValue.INT - LCONST_0, LCONST_1 -> - FixStackValue.LONG - FCONST_0, FCONST_1, FCONST_2 -> - FixStackValue.FLOAT - DCONST_0, DCONST_1 -> - FixStackValue.DOUBLE - BIPUSH, SIPUSH -> - FixStackValue.INT - LDC -> { - when (val cst = (insn as LdcInsnNode).cst) { - is Int -> - FixStackValue.INT - is Float -> - FixStackValue.FLOAT - is Long -> - FixStackValue.LONG - is Double -> - FixStackValue.DOUBLE - is String, is Handle -> - FixStackValue.OBJECT - is Type -> { - val sort = cst.sort - if (sort == Type.OBJECT || sort == Type.ARRAY || sort == Type.METHOD) - FixStackValue.OBJECT - else - throw IllegalArgumentException("Illegal LDC constant $cst") - } - else -> - throw IllegalArgumentException("Illegal LDC constant $cst") - } - } - GETSTATIC -> - newValue(Type.getType((insn as FieldInsnNode).desc)) - NEW -> - newValue(Type.getObjectType((insn as TypeInsnNode).desc)) - else -> - throw IllegalArgumentException("Unexpected instruction: " + insn.insnOpcodeText) - } - - override fun copyOperation(insn: AbstractInsnNode, value: FixStackValue?): FixStackValue = + override fun copyOperation(insn: AbstractInsnNode, value: FixStackValue): FixStackValue = when (insn.opcode) { ILOAD -> FixStackValue.INT LLOAD -> FixStackValue.LONG FLOAD -> FixStackValue.FLOAT DLOAD -> FixStackValue.DOUBLE ALOAD -> FixStackValue.OBJECT - else -> value!! + else -> value } - override fun binaryOperation(insn: AbstractInsnNode, value1: FixStackValue?, value2: FixStackValue?): FixStackValue? = - when (insn.opcode) { - IALOAD, BALOAD, CALOAD, SALOAD, IADD, ISUB, IMUL, IDIV, IREM, ISHL, ISHR, IUSHR, IAND, IOR, IXOR -> - FixStackValue.INT - FALOAD, FADD, FSUB, FMUL, FDIV, FREM -> - FixStackValue.FLOAT - LALOAD, LADD, LSUB, LMUL, LDIV, LREM, LSHL, LSHR, LUSHR, LAND, LOR, LXOR -> - FixStackValue.LONG - DALOAD, DADD, DSUB, DMUL, DDIV, DREM -> - FixStackValue.DOUBLE - AALOAD -> - FixStackValue.OBJECT - LCMP, FCMPL, FCMPG, DCMPL, DCMPG -> - FixStackValue.INT - IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE, PUTFIELD -> - null - else -> - throw IllegalArgumentException("Unexpected instruction: " + insn.insnOpcodeText) - } - - override fun ternaryOperation( - insn: AbstractInsnNode, - value1: FixStackValue?, - value2: FixStackValue?, - value3: FixStackValue? - ): FixStackValue? = - null - - override fun naryOperation(insn: AbstractInsnNode, values: List): FixStackValue? = - when (insn.opcode) { - MULTIANEWARRAY -> - newValue(Type.getType((insn as MultiANewArrayInsnNode).desc)) - INVOKEDYNAMIC -> - newValue(Type.getReturnType((insn as InvokeDynamicInsnNode).desc)) - else -> - newValue(Type.getReturnType((insn as MethodInsnNode).desc)) - } - - override fun returnOperation(insn: AbstractInsnNode?, value: FixStackValue?, expected: FixStackValue?) { - } - - override fun unaryOperation(insn: AbstractInsnNode, value: FixStackValue?): FixStackValue? = - when (insn.opcode) { - INEG, IINC, L2I, F2I, D2I, I2B, I2C, I2S -> - FixStackValue.INT - FNEG, I2F, L2F, D2F -> - FixStackValue.FLOAT - LNEG, I2L, F2L, D2L -> - FixStackValue.LONG - DNEG, I2D, L2D, F2D -> - FixStackValue.DOUBLE - IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, TABLESWITCH, LOOKUPSWITCH, IRETURN, LRETURN, FRETURN, DRETURN, ARETURN, PUTSTATIC -> - null - GETFIELD -> - newValue(Type.getType((insn as FieldInsnNode).desc)) - NEWARRAY -> - FixStackValue.OBJECT - ANEWARRAY -> { - FixStackValue.OBJECT - } - ARRAYLENGTH -> - FixStackValue.INT - ATHROW -> - null - CHECKCAST -> - FixStackValue.OBJECT - INSTANCEOF -> - FixStackValue.INT - MONITORENTER, MONITOREXIT, IFNULL, IFNONNULL -> - null - else -> - throw IllegalArgumentException("Unexpected instruction: " + insn.insnOpcodeText) - } - - override fun merge(v: FixStackValue?, w: FixStackValue?): FixStackValue? = - when { - v == w -> v - v == null -> w - w == null -> v - else -> throw AssertionError("Mismatching value kinds: $v != $w") - } + override fun merge(v: FixStackValue, w: FixStackValue): FixStackValue = + if (v == w) + v + else + throw AssertionError("Mismatching value kinds: $v != $w") }