Open-source multiplayer game server compatible with the RuneScape client
https://www.openrs2.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
97 lines
3.3 KiB
97 lines
3.3 KiB
package org.openrs2.deob.bytecode.analysis
|
|
|
|
import org.objectweb.asm.Opcodes
|
|
import org.objectweb.asm.tree.AbstractInsnNode
|
|
import org.objectweb.asm.tree.ClassNode
|
|
import org.objectweb.asm.tree.FieldInsnNode
|
|
import org.objectweb.asm.tree.MethodNode
|
|
import org.objectweb.asm.tree.analysis.Frame
|
|
import org.openrs2.asm.MemberDesc
|
|
import org.openrs2.asm.classpath.ClassPath
|
|
|
|
public class FieldWriteAnalyzer(
|
|
private val clazz: ClassNode,
|
|
private val method: MethodNode,
|
|
private val classPath: ClassPath,
|
|
private val frames: Array<Frame<ThisValue>>
|
|
) : DataFlowAnalyzer<Map<MemberDesc, FieldWriteCount>>(clazz.name, method) {
|
|
private val methodStatic = (method.access and Opcodes.ACC_STATIC) != 0
|
|
|
|
override fun createEntrySet(): Map<MemberDesc, FieldWriteCount> {
|
|
val set = mutableMapOf<MemberDesc, FieldWriteCount>()
|
|
|
|
for (field in clazz.fields) {
|
|
val fieldStatic = (field.access and Opcodes.ACC_STATIC) != 0
|
|
if (methodStatic == fieldStatic) {
|
|
set[MemberDesc(field)] = FieldWriteCount.NEVER
|
|
}
|
|
}
|
|
|
|
return set
|
|
}
|
|
|
|
override fun createInitialSet(): Map<MemberDesc, FieldWriteCount> {
|
|
return emptyMap()
|
|
}
|
|
|
|
override fun join(
|
|
set1: Map<MemberDesc, FieldWriteCount>,
|
|
set2: Map<MemberDesc, FieldWriteCount>
|
|
): Map<MemberDesc, FieldWriteCount> {
|
|
if (set1 == set2) {
|
|
return set1
|
|
}
|
|
|
|
val set = mutableMapOf<MemberDesc, FieldWriteCount>()
|
|
|
|
for (member in set1.keys union set2.keys) {
|
|
val count1 = set1[member]
|
|
val count2 = set2[member]
|
|
|
|
set[member] = when {
|
|
count1 == null && count2 != null -> count2
|
|
count2 == null && count1 != null -> count1
|
|
count1 == count2 -> count1!!
|
|
else -> FieldWriteCount.ONCE_OR_MORE
|
|
}
|
|
}
|
|
|
|
return set
|
|
}
|
|
|
|
override fun transfer(
|
|
set: Map<MemberDesc, FieldWriteCount>,
|
|
insn: AbstractInsnNode
|
|
): Map<MemberDesc, FieldWriteCount> {
|
|
if (insn !is FieldInsnNode) {
|
|
return set
|
|
} else if (methodStatic && insn.opcode != Opcodes.PUTSTATIC) {
|
|
return set
|
|
} else if (!methodStatic && insn.opcode != Opcodes.PUTFIELD) {
|
|
return set
|
|
}
|
|
|
|
val member = MemberDesc(insn)
|
|
val declaredOwner = classPath[insn.owner]!!.resolveField(member)!!.name
|
|
if (declaredOwner != clazz.name) {
|
|
return set
|
|
}
|
|
|
|
val isThis = if (insn.opcode == Opcodes.PUTFIELD) {
|
|
val insnIndex = method.instructions.indexOf(insn)
|
|
val frame = frames[insnIndex]
|
|
frame.getStack(frame.stackSize - 2).isThis
|
|
} else {
|
|
true
|
|
}
|
|
|
|
val count = set.getOrDefault(member, FieldWriteCount.NEVER)
|
|
return when {
|
|
isThis && count == FieldWriteCount.NEVER -> set.plus(Pair(member, FieldWriteCount.EXACTLY_ONCE))
|
|
isThis && count == FieldWriteCount.EXACTLY_ONCE -> set.plus(Pair(member, FieldWriteCount.ONCE_OR_MORE))
|
|
// save an allocation if count is already set to UNKNOWN
|
|
count == FieldWriteCount.ONCE_OR_MORE -> set
|
|
else -> set.plus(Pair(member, FieldWriteCount.ONCE_OR_MORE))
|
|
}
|
|
}
|
|
}
|
|
|