Consider static and instance fields separately in FieldWriteAnalyzer

This fixes a bug where fields could never become static if a class had a
mixture of static and non-static fields and constructors.

Signed-off-by: Graham <gpe@openrs2.dev>
Graham 5 years ago
parent 2cbe6ce8e0
commit d410f87240
  1. 11
      deob/src/main/java/dev/openrs2/deob/analysis/FieldWriteAnalyzer.kt
  2. 11
      deob/src/main/java/dev/openrs2/deob/transform/FinalFieldTransformer.kt

@ -15,11 +15,16 @@ class FieldWriteAnalyzer(
private val classPath: ClassPath, private val classPath: ClassPath,
private val frames: Array<Frame<ThisValue>> private val frames: Array<Frame<ThisValue>>
) : DataFlowAnalyzer<Map<MemberDesc, FieldWriteCount>>(clazz.name, method) { ) : DataFlowAnalyzer<Map<MemberDesc, FieldWriteCount>>(clazz.name, method) {
private val methodStatic = (method.access and Opcodes.ACC_STATIC) != 0
override fun createEntrySet(): Map<MemberDesc, FieldWriteCount> { override fun createEntrySet(): Map<MemberDesc, FieldWriteCount> {
val set = mutableMapOf<MemberDesc, FieldWriteCount>() val set = mutableMapOf<MemberDesc, FieldWriteCount>()
for (field in clazz.fields) { for (field in clazz.fields) {
set[MemberDesc(field)] = FieldWriteCount.NEVER val fieldStatic = (field.access and Opcodes.ACC_STATIC) != 0
if (methodStatic == fieldStatic) {
set[MemberDesc(field)] = FieldWriteCount.NEVER
}
} }
return set return set
@ -60,7 +65,9 @@ class FieldWriteAnalyzer(
): Map<MemberDesc, FieldWriteCount> { ): Map<MemberDesc, FieldWriteCount> {
if (insn !is FieldInsnNode) { if (insn !is FieldInsnNode) {
return set return set
} else if (insn.opcode != Opcodes.PUTFIELD && insn.opcode != Opcodes.PUTSTATIC) { } else if (methodStatic && insn.opcode != Opcodes.PUTSTATIC) {
return set
} else if (!methodStatic && insn.opcode != Opcodes.PUTFIELD) {
return set return set
} }

@ -29,7 +29,8 @@ class FinalFieldTransformer : Transformer() {
override fun transformCode(classPath: ClassPath, library: Library, clazz: ClassNode, method: MethodNode): Boolean { override fun transformCode(classPath: ClassPath, library: Library, clazz: ClassNode, method: MethodNode): Boolean {
val constructor = method.name == "<init>" || method.name == "<clinit>" val constructor = method.name == "<init>" || method.name == "<clinit>"
val thisCall = if (constructor && method.name == "<init>") { val constructorStatic = (method.access and Opcodes.ACC_STATIC) != 0
val thisCall = if (constructor && !constructorStatic) {
method.instructions.filterIsInstance<MethodInsnNode>() method.instructions.filterIsInstance<MethodInsnNode>()
.any { it.opcode == Opcodes.INVOKESPECIAL && it.owner == clazz.name && it.name == "<init>" } .any { it.opcode == Opcodes.INVOKESPECIAL && it.owner == clazz.name && it.name == "<init>" }
} else { } else {
@ -61,7 +62,8 @@ class FinalFieldTransformer : Transformer() {
} }
val declaredOwner = classPath[insn.owner]!!.resolveField(MemberDesc(insn))!!.name val declaredOwner = classPath[insn.owner]!!.resolveField(MemberDesc(insn))!!.name
if (isThis && declaredOwner == clazz.name) { val fieldStatic = insn.opcode == Opcodes.PUTSTATIC
if (isThis && declaredOwner == clazz.name && fieldStatic == constructorStatic) {
/* /*
* Writes inside constructors without a this(...) call to * Writes inside constructors without a this(...) call to
* fields owned by the same class are analyzed separately - if * fields owned by the same class are analyzed separately - if
@ -84,10 +86,9 @@ class FinalFieldTransformer : Transformer() {
for (insn in exits) { for (insn in exits) {
val counts = analyzer.getOutSet(insn) ?: emptyMap() val counts = analyzer.getOutSet(insn) ?: emptyMap()
for (field in clazz.fields) { for ((field, count) in counts) {
val count = counts.getOrDefault(MemberDesc(field), FieldWriteCount.NEVER)
if (count != FieldWriteCount.EXACTLY_ONCE) { if (count != FieldWriteCount.EXACTLY_ONCE) {
val partition = inheritedFieldSets[MemberRef(clazz, field)]!! val partition = inheritedFieldSets[MemberRef(clazz.name, field)]!!
nonFinalFields += partition nonFinalFields += partition
} }
} }

Loading…
Cancel
Save