Skip to content

Commit

Permalink
perf: reduce check size for methods that are candidates for being tra…
Browse files Browse the repository at this point in the history
…nsformed
  • Loading branch information
oSumAtrIX committed May 21, 2023
1 parent bd09458 commit c10b2cc
Showing 1 changed file with 25 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.iface.instruction.Instruction

internal abstract class AbstractTransformInstructionsPatch<T> : BytecodePatch() {

abstract fun filterMap(
classDef: ClassDef,
method: Method,
Expand All @@ -21,41 +20,51 @@ internal abstract class AbstractTransformInstructionsPatch<T> : BytecodePatch()

abstract fun transform(mutableMethod: MutableMethod, entry: T)

private fun findPatchIndices(classDef: ClassDef, method: Method): Sequence<T>? {
return method.implementation?.instructions?.asSequence()?.withIndex()?.mapNotNull { (index, instruction) ->
/**
* Finds all indices of instructions that match the filter.
*
* @param classDef The class definition.
* @param method The method to check.
*/
private fun findPatchIndices(classDef: ClassDef, method: Method) = method.implementation?.let {
it.instructions.withIndex().mapNotNull { (index, instruction) ->
filterMap(classDef, method, instruction, index)
}
}

/**
* Checks if the method is a candidate for patching.
*
* @param classDef The class definition.
* @param method The method to check.
*/
private fun isMutableCandidate(classDef: ClassDef, method: Method) = method.implementation?.instructions?.any {
filterMap(classDef, method, it, 0) != null
} ?: false

override fun execute(context: BytecodeContext): PatchResult {
// Find all methods to patch
buildMap {
context.classes.forEach { classDef ->
val methods = buildList {
classDef.methods.forEach { method ->
val patchIndices = findPatchIndices(classDef, method)

if (patchIndices?.any() == true) {
add(method)
}
if (isMutableCandidate(classDef, method)) add(method)
}
}

if (methods.isNotEmpty()) {
put(classDef, methods)
}
if (methods.isEmpty()) return@forEach

put(classDef, methods)
}
}.forEach { (classDef, methods) ->
// And finally transform the methods...
val mutableClass = context.proxy(classDef).mutableClass

methods.map(mutableClass::findMutableMethodOf).forEach methods@{ mutableMethod ->
val patchIndices = findPatchIndices(mutableClass, mutableMethod)?.toCollection(ArrayDeque())
?: return@methods
val patchIndices = findPatchIndices(mutableClass, mutableMethod)
?.toCollection(ArrayDeque()) ?: return@methods

while (!patchIndices.isEmpty()) {
transform(mutableMethod, patchIndices.removeLast())
}
while (!patchIndices.isEmpty()) transform(mutableMethod, patchIndices.removeLast())
}
}

Expand Down

0 comments on commit c10b2cc

Please sign in to comment.