|
|
|
package org.openrs2.deob.bytecode.analysis
|
|
|
|
|
|
|
|
import org.objectweb.asm.Opcodes
|
|
|
|
import org.objectweb.asm.Type
|
|
|
|
import org.objectweb.asm.tree.AbstractInsnNode
|
|
|
|
import org.objectweb.asm.tree.IincInsnNode
|
|
|
|
import org.objectweb.asm.tree.analysis.BasicInterpreter
|
|
|
|
import org.objectweb.asm.tree.analysis.Interpreter
|
|
|
|
import org.openrs2.asm.intConstant
|
|
|
|
|
|
|
|
public class IntInterpreter(private val args: Array<IntValueSet>) : Interpreter<IntValue>(Opcodes.ASM9) {
|
|
|
|
private val basicInterpreter = BasicInterpreter()
|
|
|
|
|
|
|
|
override fun newValue(type: Type?): IntValue? {
|
|
|
|
val basicValue = basicInterpreter.newValue(type) ?: return null
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
return IntValue(basicValue)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun newParameterValue(isInstanceMethod: Boolean, local: Int, type: Type): IntValue {
|
|
|
|
val basicValue = basicInterpreter.newParameterValue(isInstanceMethod, local, type)
|
|
|
|
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
val index = when {
|
|
|
|
isInstanceMethod && local == 0 -> return IntValue(basicValue)
|
|
|
|
isInstanceMethod -> local - 1
|
|
|
|
else -> local
|
|
|
|
}
|
|
|
|
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
return IntValue(basicValue, args[index])
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun newOperation(insn: AbstractInsnNode): IntValue {
|
|
|
|
val basicValue = basicInterpreter.newOperation(insn)
|
|
|
|
val v = insn.intConstant
|
|
|
|
return if (v != null) {
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
IntValue(basicValue, IntValueSet.singleton(v))
|
|
|
|
} else {
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
IntValue(basicValue)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun copyOperation(insn: AbstractInsnNode, value: IntValue): IntValue {
|
|
|
|
return value
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun unaryOperation(insn: AbstractInsnNode, value: IntValue): IntValue? {
|
|
|
|
val basicValue = basicInterpreter.unaryOperation(insn, value.basicValue) ?: return null
|
|
|
|
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
if (value.set !is IntValueSet.Constant) {
|
|
|
|
return IntValue(basicValue)
|
|
|
|
}
|
|
|
|
|
|
|
|
val set = mutableSetOf<Int>()
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
for (v in value.set.values) {
|
|
|
|
val result = when {
|
|
|
|
insn.opcode == Opcodes.INEG -> -v
|
|
|
|
insn is IincInsnNode -> v + insn.incr
|
|
|
|
insn.opcode == Opcodes.I2B -> v.toByte().toInt()
|
|
|
|
insn.opcode == Opcodes.I2C -> v.toChar().code
|
|
|
|
insn.opcode == Opcodes.I2S -> v.toShort().toInt()
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
else -> return IntValue(basicValue)
|
|
|
|
}
|
|
|
|
set.add(result)
|
|
|
|
}
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
return IntValue(basicValue, IntValueSet.Constant(set))
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun binaryOperation(insn: AbstractInsnNode, value1: IntValue, value2: IntValue): IntValue? {
|
|
|
|
val basicValue = basicInterpreter.binaryOperation(insn, value1.basicValue, value2.basicValue) ?: return null
|
|
|
|
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
if (value1.set !is IntValueSet.Constant || value2.set !is IntValueSet.Constant) {
|
|
|
|
return IntValue(basicValue)
|
|
|
|
}
|
|
|
|
|
|
|
|
val set = mutableSetOf<Int>()
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
for (v1 in value1.set.values) {
|
|
|
|
for (v2 in value2.set.values) {
|
|
|
|
val result = when (insn.opcode) {
|
|
|
|
Opcodes.IADD -> v1 + v2
|
|
|
|
Opcodes.ISUB -> v1 - v2
|
|
|
|
Opcodes.IMUL -> v1 * v2
|
|
|
|
Opcodes.IDIV -> {
|
|
|
|
if (v2 == 0) {
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
return IntValue(basicValue)
|
|
|
|
}
|
|
|
|
v1 / v2
|
|
|
|
}
|
|
|
|
Opcodes.IREM -> {
|
|
|
|
if (v2 == 0) {
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
return IntValue(basicValue)
|
|
|
|
}
|
|
|
|
v1 % v2
|
|
|
|
}
|
|
|
|
Opcodes.ISHL -> v1 shl v2
|
|
|
|
Opcodes.ISHR -> v1 shr v2
|
|
|
|
Opcodes.IUSHR -> v1 ushr v2
|
|
|
|
Opcodes.IAND -> v1 and v2
|
|
|
|
Opcodes.IOR -> v1 or v2
|
|
|
|
Opcodes.IXOR -> v1 xor v2
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
else -> return IntValue(basicValue)
|
|
|
|
}
|
|
|
|
set.add(result)
|
|
|
|
}
|
|
|
|
}
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
return IntValue(basicValue, IntValueSet.Constant(set))
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun ternaryOperation(
|
|
|
|
insn: AbstractInsnNode,
|
|
|
|
value1: IntValue,
|
|
|
|
value2: IntValue,
|
|
|
|
value3: IntValue
|
|
|
|
): IntValue? {
|
|
|
|
val basicValue =
|
|
|
|
basicInterpreter.ternaryOperation(insn, value1.basicValue, value2.basicValue, value3.basicValue)
|
|
|
|
?: return null
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
return IntValue(basicValue)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun naryOperation(insn: AbstractInsnNode, values: List<IntValue>): IntValue? {
|
|
|
|
val args = values.map(IntValue::basicValue)
|
|
|
|
val basicValue = basicInterpreter.naryOperation(insn, args) ?: return null
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
return IntValue(basicValue)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun returnOperation(insn: AbstractInsnNode, value: IntValue, expected: IntValue) {
|
|
|
|
basicInterpreter.returnOperation(insn, value.basicValue, expected.basicValue)
|
|
|
|
}
|
|
|
|
|
|
|
|
override fun merge(value1: IntValue, value2: IntValue): IntValue {
|
|
|
|
val basicValue = basicInterpreter.merge(value1.basicValue, value2.basicValue)
|
|
|
|
|
|
|
|
if (value1 == value2) {
|
|
|
|
return value1
|
|
|
|
}
|
|
|
|
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
if (value1.set !is IntValueSet.Constant || value2.set !is IntValueSet.Constant) {
|
|
|
|
return IntValue(basicValue)
|
|
|
|
}
|
|
|
|
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
val set = value1.set union value2.set
|
|
|
|
return if (set is IntValueSet.Constant && set.values.size > MAX_TRACKED_VALUES) {
|
|
|
|
IntValue(basicValue)
|
|
|
|
} else {
|
Replace DummyArgTransformer with new ConstantArgTransformer
The new transformer uses a different approach to the old one. It starts
exploring the call graph from the entry points, recursively analysing
method calls. Methods are only re-analysed if their possible argument
values change, with the Unknown value being used if we can't identify a
single integer constant at a call site. This prevents us from recursing
infinitely if the client code does.
While this first pass does simplify branches in order to ignore dummy
method calls that are never evaluated at runtime, it operates on a copy
of the method (as we initially ignore more calls while the argument
value sets are smaller, ignoring fewer calls as they build up).
A separate second pass simplifies branches on the original method and
inlines singleton constants, paving the way for the UnusedArgTransformer
to actually remove the newly unused arguments.
This new approach has several benefits:
- It is much faster than the old approach, as we only re-analyse methods
as required by argument value changes, rather than re-analysing every
method during every pass.
- It doesn't require special cases for dealing with mutually recursive
dummy calls. The old approach hard-coded special cases for mutually
recursive calls involving groups of 1 and 2 methods. The code for this
wasn't clean. Furthermore, while it was just about good enough for the
HD client, the SD client contains a mutually recursive group of 3
methods. The new approach is capable of dealing with mutually
recursive groups of any size.
Finally, the new transformer has a much cleaner implementation.
Signed-off-by: Graham <gpe@openrs2.dev>
4 years ago
|
|
|
IntValue(basicValue, set)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private companion object {
|
|
|
|
private const val MAX_TRACKED_VALUES = 1
|
|
|
|
}
|
|
|
|
}
|