Eval and Control separated
This commit is contained in:
@@ -17,7 +17,7 @@ import org.objectweb.asm.Label
|
|||||||
|
|
||||||
class UnsupportedByteCodeException(message: String) : RuntimeException(message)
|
class UnsupportedByteCodeException(message: String) : RuntimeException(message)
|
||||||
|
|
||||||
trait EvalStrategy {
|
trait Eval {
|
||||||
fun loadClass(classType: Type): Value
|
fun loadClass(classType: Type): Value
|
||||||
fun newInstance(classType: Type): Value
|
fun newInstance(classType: Type): Value
|
||||||
fun checkCast(value: Value, targetType: Type): Value
|
fun checkCast(value: Value, targetType: Type): Value
|
||||||
@@ -39,14 +39,16 @@ trait EvalStrategy {
|
|||||||
|
|
||||||
fun getLocalVariable(index: Int): Value
|
fun getLocalVariable(index: Int): Value
|
||||||
fun setLocalVariable(index: Int, newValue: Value)
|
fun setLocalVariable(index: Int, newValue: Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Control {
|
||||||
fun jump(label: Label)
|
fun jump(label: Label)
|
||||||
|
|
||||||
fun returnValue(value: Value)
|
fun returnValue(value: Value)
|
||||||
fun throwException(value: Value)
|
fun throwException(value: Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
class EvalInterpreter(private val evalStrategy: EvalStrategy) : Interpreter<Value>(ASM4) {
|
class EvalInterpreter(private val eval: Eval, private val control: Control) : Interpreter<Value>(ASM4) {
|
||||||
override fun newValue(`type`: Type?): Value? {
|
override fun newValue(`type`: Type?): Value? {
|
||||||
if (`type` == null) {
|
if (`type` == null) {
|
||||||
return NOT_A_VALUE
|
return NOT_A_VALUE
|
||||||
@@ -95,7 +97,7 @@ class EvalInterpreter(private val evalStrategy: EvalStrategy) : Interpreter<Valu
|
|||||||
is Type -> {
|
is Type -> {
|
||||||
val sort = (cst as Type).getSort()
|
val sort = (cst as Type).getSort()
|
||||||
when (sort) {
|
when (sort) {
|
||||||
Type.OBJECT, Type.ARRAY -> evalStrategy.loadClass(cst)
|
Type.OBJECT, Type.ARRAY -> eval.loadClass(cst)
|
||||||
Type.METHOD -> throw UnsupportedByteCodeException("Mothod handles are not supported")
|
Type.METHOD -> throw UnsupportedByteCodeException("Mothod handles are not supported")
|
||||||
else -> throw UnsupportedByteCodeException("Illegal LDC constant " + cst)
|
else -> throw UnsupportedByteCodeException("Illegal LDC constant " + cst)
|
||||||
}
|
}
|
||||||
@@ -105,8 +107,8 @@ class EvalInterpreter(private val evalStrategy: EvalStrategy) : Interpreter<Valu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
JSR -> LabelValue((insn as JumpInsnNode).label.getLabel())
|
JSR -> LabelValue((insn as JumpInsnNode).label.getLabel())
|
||||||
GETSTATIC -> evalStrategy.getStaticField((insn as FieldInsnNode).desc)
|
GETSTATIC -> eval.getStaticField((insn as FieldInsnNode).desc)
|
||||||
NEW -> evalStrategy.newInstance(Type.getType((insn as TypeInsnNode).desc))
|
NEW -> eval.newInstance(Type.getType((insn as TypeInsnNode).desc))
|
||||||
else -> throw UnsupportedByteCodeException("$insn")
|
else -> throw UnsupportedByteCodeException("$insn")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,14 +146,14 @@ class EvalInterpreter(private val evalStrategy: EvalStrategy) : Interpreter<Valu
|
|||||||
IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IFNULL, IFNONNULL -> {
|
IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IFNULL, IFNONNULL -> {
|
||||||
val label = (insn as JumpInsnNode).label.getLabel()
|
val label = (insn as JumpInsnNode).label.getLabel()
|
||||||
when (insn.getOpcode()) {
|
when (insn.getOpcode()) {
|
||||||
IFEQ -> if (value.int == 0) evalStrategy.jump(label)
|
IFEQ -> if (value.int == 0) control.jump(label)
|
||||||
IFNE -> if (value.int != 0) evalStrategy.jump(label)
|
IFNE -> if (value.int != 0) control.jump(label)
|
||||||
IFLT -> if (value.int < 0) evalStrategy.jump(label)
|
IFLT -> if (value.int < 0) control.jump(label)
|
||||||
IFGT -> if (value.int > 0) evalStrategy.jump(label)
|
IFGT -> if (value.int > 0) control.jump(label)
|
||||||
IFLE -> if (value.int <= 0) evalStrategy.jump(label)
|
IFLE -> if (value.int <= 0) control.jump(label)
|
||||||
IFGE -> if (value.int >= 0) evalStrategy.jump(label)
|
IFGE -> if (value.int >= 0) control.jump(label)
|
||||||
IFNULL -> if (value.obj == null) evalStrategy.jump(label)
|
IFNULL -> if (value.obj == null) control.jump(label)
|
||||||
IFNONNULL -> if (value.obj != null) evalStrategy.jump(label)
|
IFNONNULL -> if (value.obj != null) control.jump(label)
|
||||||
}
|
}
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@@ -161,11 +163,11 @@ class EvalInterpreter(private val evalStrategy: EvalStrategy) : Interpreter<Valu
|
|||||||
LOOKUPSWITCH -> throw UnsupportedByteCodeException("Switch is not supported yet")
|
LOOKUPSWITCH -> throw UnsupportedByteCodeException("Switch is not supported yet")
|
||||||
|
|
||||||
PUTSTATIC -> {
|
PUTSTATIC -> {
|
||||||
evalStrategy.setStaticField((insn as FieldInsnNode).desc, value)
|
eval.setStaticField((insn as FieldInsnNode).desc, value)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
GETFIELD -> evalStrategy.getField(value, (insn as FieldInsnNode).desc)
|
GETFIELD -> eval.getField(value, (insn as FieldInsnNode).desc)
|
||||||
|
|
||||||
NEWARRAY -> {
|
NEWARRAY -> {
|
||||||
val typeStr = when ((insn as IntInsnNode).operand) {
|
val typeStr = when ((insn as IntInsnNode).operand) {
|
||||||
@@ -179,27 +181,27 @@ class EvalInterpreter(private val evalStrategy: EvalStrategy) : Interpreter<Valu
|
|||||||
T_LONG -> "[J"
|
T_LONG -> "[J"
|
||||||
else -> throw AnalyzerException(insn, "Invalid array type")
|
else -> throw AnalyzerException(insn, "Invalid array type")
|
||||||
}
|
}
|
||||||
evalStrategy.newArray(Type.getType(typeStr), value.int)
|
eval.newArray(Type.getType(typeStr), value.int)
|
||||||
}
|
}
|
||||||
ANEWARRAY -> {
|
ANEWARRAY -> {
|
||||||
val desc = (insn as TypeInsnNode).desc
|
val desc = (insn as TypeInsnNode).desc
|
||||||
evalStrategy.newArray(Type.getType("[" + Type.getObjectType(desc)), value.int)
|
eval.newArray(Type.getType("[" + Type.getObjectType(desc)), value.int)
|
||||||
}
|
}
|
||||||
ARRAYLENGTH -> evalStrategy.getArrayLength(value)
|
ARRAYLENGTH -> eval.getArrayLength(value)
|
||||||
|
|
||||||
ATHROW -> {
|
ATHROW -> {
|
||||||
evalStrategy.throwException(value)
|
control.throwException(value)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECKCAST -> {
|
CHECKCAST -> {
|
||||||
val targetType = Type.getObjectType((insn as TypeInsnNode).desc)
|
val targetType = Type.getObjectType((insn as TypeInsnNode).desc)
|
||||||
evalStrategy.checkCast(value, targetType)
|
eval.checkCast(value, targetType)
|
||||||
}
|
}
|
||||||
|
|
||||||
INSTANCEOF -> {
|
INSTANCEOF -> {
|
||||||
val targetType = Type.getObjectType((insn as TypeInsnNode).desc)
|
val targetType = Type.getObjectType((insn as TypeInsnNode).desc)
|
||||||
boolean(evalStrategy.isInsetanceOf(value, targetType))
|
boolean(eval.isInsetanceOf(value, targetType))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: maybe just do nothing?
|
// TODO: maybe just do nothing?
|
||||||
@@ -213,7 +215,7 @@ class EvalInterpreter(private val evalStrategy: EvalStrategy) : Interpreter<Valu
|
|||||||
return when (insn.getOpcode()) {
|
return when (insn.getOpcode()) {
|
||||||
IALOAD, BALOAD, CALOAD, SALOAD,
|
IALOAD, BALOAD, CALOAD, SALOAD,
|
||||||
FALOAD, LALOAD, DALOAD,
|
FALOAD, LALOAD, DALOAD,
|
||||||
AALOAD -> evalStrategy.getArrayElement(value1, value2)
|
AALOAD -> eval.getArrayElement(value1, value2)
|
||||||
|
|
||||||
IADD -> int(value1.int + value2.int)
|
IADD -> int(value1.int + value2.int)
|
||||||
ISUB -> int(value1.int - value2.int)
|
ISUB -> int(value1.int - value2.int)
|
||||||
@@ -293,21 +295,21 @@ class EvalInterpreter(private val evalStrategy: EvalStrategy) : Interpreter<Valu
|
|||||||
IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE -> {
|
IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IF_ACMPEQ, IF_ACMPNE -> {
|
||||||
val label = (insn as JumpInsnNode).label.getLabel()
|
val label = (insn as JumpInsnNode).label.getLabel()
|
||||||
when (insn.getOpcode()) {
|
when (insn.getOpcode()) {
|
||||||
IF_ICMPEQ -> if (value1.int == value2.int) evalStrategy.jump(label)
|
IF_ICMPEQ -> if (value1.int == value2.int) control.jump(label)
|
||||||
IF_ICMPNE -> if (value1.int != value2.int) evalStrategy.jump(label)
|
IF_ICMPNE -> if (value1.int != value2.int) control.jump(label)
|
||||||
IF_ICMPLT -> if (value1.int < value2.int) evalStrategy.jump(label)
|
IF_ICMPLT -> if (value1.int < value2.int) control.jump(label)
|
||||||
IF_ICMPGT -> if (value1.int > value2.int) evalStrategy.jump(label)
|
IF_ICMPGT -> if (value1.int > value2.int) control.jump(label)
|
||||||
IF_ICMPLE -> if (value1.int <= value2.int) evalStrategy.jump(label)
|
IF_ICMPLE -> if (value1.int <= value2.int) control.jump(label)
|
||||||
IF_ICMPGE -> if (value1.int >= value2.int) evalStrategy.jump(label)
|
IF_ICMPGE -> if (value1.int >= value2.int) control.jump(label)
|
||||||
|
|
||||||
IF_ACMPEQ -> if (value1.obj == value2.obj) evalStrategy.jump(label)
|
IF_ACMPEQ -> if (value1.obj == value2.obj) control.jump(label)
|
||||||
IF_ACMPNE -> if (value1.obj != value2.obj) evalStrategy.jump(label)
|
IF_ACMPNE -> if (value1.obj != value2.obj) control.jump(label)
|
||||||
}
|
}
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
PUTFIELD -> {
|
PUTFIELD -> {
|
||||||
evalStrategy.setField(value1, (insn as FieldInsnNode).desc, value2)
|
eval.setField(value1, (insn as FieldInsnNode).desc, value2)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -318,7 +320,7 @@ class EvalInterpreter(private val evalStrategy: EvalStrategy) : Interpreter<Valu
|
|||||||
override fun ternaryOperation(insn: AbstractInsnNode, value1: Value, value2: Value, value3: Value): Value? {
|
override fun ternaryOperation(insn: AbstractInsnNode, value1: Value, value2: Value, value3: Value): Value? {
|
||||||
return when (insn.getOpcode()) {
|
return when (insn.getOpcode()) {
|
||||||
IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE -> {
|
IASTORE, LASTORE, FASTORE, DASTORE, AASTORE, BASTORE, CASTORE, SASTORE -> {
|
||||||
evalStrategy.setArrayElement(value1, value2, value3)
|
eval.setArrayElement(value1, value2, value3)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
else -> throw UnsupportedByteCodeException("$insn")
|
else -> throw UnsupportedByteCodeException("$insn")
|
||||||
@@ -329,12 +331,12 @@ class EvalInterpreter(private val evalStrategy: EvalStrategy) : Interpreter<Valu
|
|||||||
return when (insn.getOpcode()) {
|
return when (insn.getOpcode()) {
|
||||||
MULTIANEWARRAY -> {
|
MULTIANEWARRAY -> {
|
||||||
val node = insn as MultiANewArrayInsnNode
|
val node = insn as MultiANewArrayInsnNode
|
||||||
evalStrategy.newMultiDimensionalArray(Type.getType(node.desc), values.map { v -> v.int })
|
eval.newMultiDimensionalArray(Type.getType(node.desc), values.map { v -> v.int })
|
||||||
}
|
}
|
||||||
|
|
||||||
INVOKEVIRTUAL, INVOKESPECIAL, INVOKEINTERFACE -> {
|
INVOKEVIRTUAL, INVOKESPECIAL, INVOKEINTERFACE -> {
|
||||||
val desc = (insn as MethodInsnNode).desc
|
val desc = (insn as MethodInsnNode).desc
|
||||||
evalStrategy.invokeMethod(
|
eval.invokeMethod(
|
||||||
values[0],
|
values[0],
|
||||||
desc,
|
desc,
|
||||||
values.subList(1, values.size()),
|
values.subList(1, values.size()),
|
||||||
@@ -342,7 +344,7 @@ class EvalInterpreter(private val evalStrategy: EvalStrategy) : Interpreter<Valu
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
INVOKESTATIC -> evalStrategy.invokeStaticMethod((insn as MethodInsnNode).desc, values)
|
INVOKESTATIC -> eval.invokeStaticMethod((insn as MethodInsnNode).desc, values)
|
||||||
|
|
||||||
INVOKEDYNAMIC -> throw UnsupportedByteCodeException("INVOKEDYNAMIC is not supported")
|
INVOKEDYNAMIC -> throw UnsupportedByteCodeException("INVOKEDYNAMIC is not supported")
|
||||||
else -> throw UnsupportedByteCodeException("$insn")
|
else -> throw UnsupportedByteCodeException("$insn")
|
||||||
@@ -358,7 +360,7 @@ class EvalInterpreter(private val evalStrategy: EvalStrategy) : Interpreter<Valu
|
|||||||
DRETURN,
|
DRETURN,
|
||||||
ARETURN -> {
|
ARETURN -> {
|
||||||
// TODO: coercion, maybe?
|
// TODO: coercion, maybe?
|
||||||
evalStrategy.returnValue(value)
|
control.returnValue(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> throw UnsupportedByteCodeException("$insn")
|
else -> throw UnsupportedByteCodeException("$insn")
|
||||||
|
|||||||
Reference in New Issue
Block a user