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

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))
}
}
}