Control logic will be handled by interpreter loop
This commit is contained in:
@@ -38,14 +38,7 @@ trait Eval {
|
|||||||
fun invokeMethod(instance: Value, methodDesc: String, arguments: List<Value>, invokespecial: Boolean = false): Value
|
fun invokeMethod(instance: Value, methodDesc: String, arguments: List<Value>, invokespecial: Boolean = false): Value
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Control {
|
class SingleInstructionInterpreter(private val eval: Eval) : Interpreter<Value>(ASM4) {
|
||||||
fun jump(label: LabelNode)
|
|
||||||
|
|
||||||
fun returnValue(value: Value)
|
|
||||||
fun throwException(value: Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
class SingleInstructionInterpreter(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
|
||||||
@@ -141,17 +134,7 @@ class SingleInstructionInterpreter(private val eval: Eval, private val control:
|
|||||||
F2D -> double(value.float.toDouble())
|
F2D -> double(value.float.toDouble())
|
||||||
|
|
||||||
IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IFNULL, IFNONNULL -> {
|
IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, IFNULL, IFNONNULL -> {
|
||||||
val label = (insn as JumpInsnNode).label
|
// Handled by interpreter loop, see checkUnaryCondition()
|
||||||
when (insn.getOpcode()) {
|
|
||||||
IFEQ -> if (value.int == 0) control.jump(label)
|
|
||||||
IFNE -> if (value.int != 0) control.jump(label)
|
|
||||||
IFLT -> if (value.int < 0) control.jump(label)
|
|
||||||
IFGT -> if (value.int > 0) control.jump(label)
|
|
||||||
IFLE -> if (value.int <= 0) control.jump(label)
|
|
||||||
IFGE -> if (value.int >= 0) control.jump(label)
|
|
||||||
IFNULL -> if (value.obj == null) control.jump(label)
|
|
||||||
IFNONNULL -> if (value.obj != null) control.jump(label)
|
|
||||||
}
|
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +170,7 @@ class SingleInstructionInterpreter(private val eval: Eval, private val control:
|
|||||||
ARRAYLENGTH -> eval.getArrayLength(value)
|
ARRAYLENGTH -> eval.getArrayLength(value)
|
||||||
|
|
||||||
ATHROW -> {
|
ATHROW -> {
|
||||||
control.throwException(value)
|
// Handled by interpreter loop
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +191,20 @@ class SingleInstructionInterpreter(private val eval: Eval, private val control:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun checkUnaryCondition(value: Value, opcode: Int): Boolean {
|
||||||
|
return when (opcode) {
|
||||||
|
IFEQ -> value.int == 0
|
||||||
|
IFNE -> value.int != 0
|
||||||
|
IFLT -> value.int < 0
|
||||||
|
IFGT -> value.int > 0
|
||||||
|
IFLE -> value.int <= 0
|
||||||
|
IFGE -> value.int >= 0
|
||||||
|
IFNULL -> value.obj == null
|
||||||
|
IFNONNULL -> value.obj != null
|
||||||
|
else -> throw UnsupportedByteCodeException("Unknown opcode: $opcode")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun binaryOperation(insn: AbstractInsnNode, value1: Value, value2: Value): Value? {
|
override fun binaryOperation(insn: AbstractInsnNode, value1: Value, value2: Value): Value? {
|
||||||
return when (insn.getOpcode()) {
|
return when (insn.getOpcode()) {
|
||||||
IALOAD, BALOAD, CALOAD, SALOAD,
|
IALOAD, BALOAD, CALOAD, SALOAD,
|
||||||
@@ -290,18 +287,7 @@ class SingleInstructionInterpreter(private val eval: Eval, private val control:
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
// Handled by interpreter loop, see checkBinaryCondition()
|
||||||
when (insn.getOpcode()) {
|
|
||||||
IF_ICMPEQ -> if (value1.int == value2.int) control.jump(label)
|
|
||||||
IF_ICMPNE -> if (value1.int != value2.int) control.jump(label)
|
|
||||||
IF_ICMPLT -> if (value1.int < value2.int) control.jump(label)
|
|
||||||
IF_ICMPGT -> if (value1.int > value2.int) control.jump(label)
|
|
||||||
IF_ICMPLE -> if (value1.int <= value2.int) control.jump(label)
|
|
||||||
IF_ICMPGE -> if (value1.int >= value2.int) control.jump(label)
|
|
||||||
|
|
||||||
IF_ACMPEQ -> if (value1.obj == value2.obj) control.jump(label)
|
|
||||||
IF_ACMPNE -> if (value1.obj != value2.obj) control.jump(label)
|
|
||||||
}
|
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,6 +300,21 @@ class SingleInstructionInterpreter(private val eval: Eval, private val control:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun checkBinaryCondition(value1: Value, value2: Value, opcode: Int): Boolean {
|
||||||
|
return when (opcode) {
|
||||||
|
IF_ICMPEQ -> value1.int == value2.int
|
||||||
|
IF_ICMPNE -> value1.int != value2.int
|
||||||
|
IF_ICMPLT -> value1.int < value2.int
|
||||||
|
IF_ICMPGT -> value1.int > value2.int
|
||||||
|
IF_ICMPLE -> value1.int <= value2.int
|
||||||
|
IF_ICMPGE -> value1.int >= value2.int
|
||||||
|
|
||||||
|
IF_ACMPEQ -> value1.obj == value2.obj
|
||||||
|
IF_ACMPNE -> value1.obj != value2.obj
|
||||||
|
else -> throw UnsupportedByteCodeException("Unknown opcode: $opcode")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 -> {
|
||||||
@@ -357,7 +358,7 @@ class SingleInstructionInterpreter(private val eval: Eval, private val control:
|
|||||||
DRETURN,
|
DRETURN,
|
||||||
ARETURN -> {
|
ARETURN -> {
|
||||||
// TODO: coercion, maybe?
|
// TODO: coercion, maybe?
|
||||||
control.returnValue(value)
|
// Handled by interpreter loop
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> throw UnsupportedByteCodeException("$insn")
|
else -> throw UnsupportedByteCodeException("$insn")
|
||||||
|
|||||||
Reference in New Issue
Block a user