refactor: Add more opcodes to findFreeRegister

This commit is contained in:
LisoUseInAIKyrios
2025-04-01 20:17:00 +02:00
parent d6cc665f71
commit 4a897fdb98
3 changed files with 58 additions and 19 deletions

View File

@ -269,7 +269,7 @@ val hideLayoutComponentsPatch = bytecodePatch(
move-object v$returnEmptyComponentRegister, p1 # Required for 19.47
goto :return_empty_component
:show
const/4 v$freeRegister, 0x0 # Restore register, required for 19.16
nop
""",
ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
)

View File

@ -179,9 +179,6 @@ val returnYouTubeDislikePatch = bytecodePatch(
// region Hook rolling numbers.
// Do this last to allow patching old unsupported versions (if the user really wants),
// On older unsupported version this will fail to match and throw an exception,
// but everything will still work correctly anyway.
val dislikesIndex = rollingNumberSetterFingerprint.patternMatch!!.endIndex
rollingNumberSetterFingerprint.method.apply {

View File

@ -70,21 +70,53 @@ internal fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude:
}
val writeOpcodes = EnumSet.of(
ARRAY_LENGTH,
NEW_INSTANCE, NEW_ARRAY,
MOVE, MOVE_FROM16, MOVE_16, MOVE_WIDE, MOVE_WIDE_FROM16, MOVE_WIDE_16, MOVE_OBJECT,
MOVE_OBJECT_FROM16, MOVE_OBJECT_16, MOVE_RESULT, MOVE_RESULT_WIDE, MOVE_RESULT_OBJECT, MOVE_EXCEPTION,
CONST, CONST_4, CONST_16, CONST_HIGH16, CONST_WIDE_16, CONST_WIDE_32,
CONST_WIDE, CONST_WIDE_HIGH16, CONST_STRING, CONST_STRING_JUMBO,
IGET, IGET_WIDE, IGET_OBJECT, IGET_BOOLEAN, IGET_BYTE, IGET_CHAR, IGET_SHORT,
IGET_VOLATILE, IGET_WIDE_VOLATILE, IGET_OBJECT_VOLATILE,
SGET, SGET_WIDE, SGET_OBJECT, SGET_BOOLEAN, SGET_BYTE, SGET_CHAR, SGET_SHORT,
SGET_VOLATILE, SGET_WIDE_VOLATILE, SGET_OBJECT_VOLATILE,
AGET, AGET_WIDE, AGET_OBJECT, AGET_BOOLEAN, AGET_BYTE, AGET_CHAR, AGET_SHORT,
// Arithmetic and logical operations.
ADD_DOUBLE_2ADDR, ADD_DOUBLE, ADD_FLOAT_2ADDR, ADD_FLOAT, ADD_INT_2ADDR,
ADD_INT_LIT8, ADD_INT, ADD_LONG_2ADDR, ADD_LONG, ADD_INT_LIT16,
AND_INT_2ADDR, AND_INT_LIT8, AND_INT_LIT16, AND_INT, AND_LONG_2ADDR, AND_LONG,
DIV_DOUBLE_2ADDR, DIV_DOUBLE, DIV_FLOAT_2ADDR, DIV_FLOAT, DIV_INT_2ADDR,
DIV_INT_LIT16, DIV_INT_LIT8, DIV_INT, DIV_LONG_2ADDR, DIV_LONG,
DOUBLE_TO_FLOAT, DOUBLE_TO_INT, DOUBLE_TO_LONG,
FLOAT_TO_DOUBLE, FLOAT_TO_INT, FLOAT_TO_LONG,
INT_TO_BYTE, INT_TO_CHAR, INT_TO_DOUBLE, INT_TO_FLOAT, INT_TO_LONG, INT_TO_SHORT,
LONG_TO_DOUBLE, LONG_TO_FLOAT, LONG_TO_INT,
MUL_DOUBLE_2ADDR, MUL_DOUBLE, MUL_FLOAT_2ADDR, MUL_FLOAT, MUL_INT_2ADDR,
MUL_INT_LIT16, MUL_INT_LIT8, MUL_INT, MUL_LONG_2ADDR, MUL_LONG,
NEG_DOUBLE, NEG_FLOAT, NEG_INT, NEG_LONG,
NOT_INT, NOT_LONG,
OR_INT_2ADDR, OR_INT_LIT16, OR_INT_LIT8, OR_INT, OR_LONG_2ADDR, OR_LONG,
REM_DOUBLE_2ADDR, REM_DOUBLE, REM_FLOAT_2ADDR, REM_FLOAT, REM_INT_2ADDR,
REM_INT_LIT16, REM_INT_LIT8, REM_INT, REM_LONG_2ADDR, REM_LONG,
RSUB_INT_LIT8, RSUB_INT,
SHL_INT_2ADDR, SHL_INT_LIT8, SHL_INT, SHL_LONG_2ADDR, SHL_LONG,
SHR_INT_2ADDR, SHR_INT_LIT8, SHR_INT, SHR_LONG_2ADDR, SHR_LONG,
SUB_DOUBLE_2ADDR, SUB_DOUBLE, SUB_FLOAT_2ADDR, SUB_FLOAT, SUB_INT_2ADDR,
SUB_INT, SUB_LONG_2ADDR, SUB_LONG,
USHR_INT_2ADDR, USHR_INT_LIT8, USHR_INT, USHR_LONG_2ADDR, USHR_LONG,
XOR_INT_2ADDR, XOR_INT_LIT16, XOR_INT_LIT8, XOR_INT, XOR_LONG_2ADDR, XOR_LONG,
)
val branchOpcodes = EnumSet.of(
GOTO, GOTO_16, GOTO_32,
IF_EQ, IF_NE, IF_LT, IF_GE, IF_GT, IF_LE,
IF_EQZ, IF_NEZ, IF_LTZ, IF_GEZ, IF_GTZ, IF_LEZ,
PACKED_SWITCH_PAYLOAD, SPARSE_SWITCH_PAYLOAD
)
val returnOpcodes = EnumSet.of(
RETURN_VOID, RETURN, RETURN_WIDE, RETURN_OBJECT,
RETURN_VOID, RETURN, RETURN_WIDE, RETURN_OBJECT, RETURN_VOID_NO_BARRIER,
THROW
)
// Highest 4-bit register available, exclusive. Ideally return a free register less than this.
@ -94,9 +126,13 @@ internal fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude:
for (i in startIndex until instructions.count()) {
val instruction = getInstruction(i)
val instructionRegisters = instruction.getRegistersUsed()
if (instruction.opcode in returnOpcodes) {
// Method returns. Use lowest register that hasn't been encountered.
// Method returns.
usedRegisters.addAll(instructionRegisters)
// Use lowest register that hasn't been encountered.
val freeRegister = (0 until implementation!!.registerCount).find {
it !in usedRegisters
}
@ -122,26 +158,32 @@ internal fun Method.findFreeRegister(startIndex: Int, vararg registersToExclude:
}
if (instruction.opcode in writeOpcodes) {
val freeRegister = instruction.getRegisterWritten()
if (freeRegister !in usedRegisters) {
if (freeRegister < maxRegister4Bits) {
// Found an ideal register.
return freeRegister
}
val writeRegister = instruction.getRegisterWritten()
// Continue searching for a 4-bit register if available.
if (bestFreeRegisterFound == null || freeRegister < bestFreeRegisterFound) {
bestFreeRegisterFound = freeRegister
if (writeRegister !in usedRegisters) {
// Verify the register is only used for write and not also as a parameter.
// If the instruction uses the write register once then it's not also a read register.
if (instructionRegisters.count { register -> register == writeRegister } == 1) {
if (writeRegister < maxRegister4Bits) {
// Found an ideal register.
return writeRegister
}
// Continue searching for a 4-bit register if available.
if (bestFreeRegisterFound == null || writeRegister < bestFreeRegisterFound) {
bestFreeRegisterFound = writeRegister
}
}
}
}
usedRegisters.addAll(instruction.getRegistersUsed())
usedRegisters.addAll(instructionRegisters)
}
// Cannot be reached since a branch or return statement will
// be encountered before the end of the method.
throw IllegalStateException()
// Some methods can have array payloads at the end of the method after a return statement.
// But in normal usage this cannot be reached since a branch or return statement
// will be encountered before the end of the method.
throw IllegalArgumentException("Start index is outside the range of normal control flow: $startIndex")
}