diff --git a/libredex/IRInstruction.cpp b/libredex/IRInstruction.cpp index 70068bed820..9b114135246 100644 --- a/libredex/IRInstruction.cpp +++ b/libredex/IRInstruction.cpp @@ -64,13 +64,30 @@ IRInstruction* IRInstruction::set_data(std::unique_ptr data) { // Structural equality of opcodes except branches offsets are ignored // because they are unknown until we sync back to DexInstructions. bool IRInstruction::operator==(const IRInstruction& that) const { - bool simple_fields_match = - m_opcode == that.m_opcode && - m_num_inline_srcs == that.m_num_inline_srcs && m_dest == that.m_dest && - m_literal == that.m_literal; // just test one member of the union + bool simple_fields_match = m_opcode == that.m_opcode && + m_num_inline_srcs == that.m_num_inline_srcs && + m_dest == that.m_dest; if (!simple_fields_match) { return false; } + + // Avoid calling opcode::ref(); there's only one instruction that has data. + if (m_opcode == OPCODE_FILL_ARRAY_DATA) { + redex_assert(opcode::ref(m_opcode) == opcode::Ref::Data); + auto size = m_data->data_size(); + if (size != that.m_data->data_size() || + std::memcmp(m_data->data(), + that.m_data->data(), + size * sizeof(uint16_t)) != 0) { + return false; + } + } else { + redex_assert(opcode::ref(m_opcode) != opcode::Ref::Data); + if (m_literal != that.m_literal) { // just test one member of the union + return false; + } + } + // Check the source registers union if (m_num_inline_srcs <= MAX_NUM_INLINE_SRCS) { for (auto i = 0; i < m_num_inline_srcs; ++i) { diff --git a/test/unit/BranchPrefixHoistingTest.cpp b/test/unit/BranchPrefixHoistingTest.cpp index d2d78722906..bb6c4856f36 100644 --- a/test/unit/BranchPrefixHoistingTest.cpp +++ b/test/unit/BranchPrefixHoistingTest.cpp @@ -850,3 +850,40 @@ TEST_F(BranchPrefixHoistingTest, try_catch_in_succ_block) { )"; test(code_str, expected_str, 0, /* full_validation */ true); } + +TEST_F(BranchPrefixHoistingTest, fill_array_data) { + const auto& code_str = R"( + ( + (load-param v0) + (const v1 1) + (new-array v1 "[I") + (move-result-pseudo-object v1) + (if-eqz v0 :true) + (fill-array-data v1 #4 (0)) + (fill-array-data v1 #4 (1)) + (goto :end) + (:true) + (fill-array-data v1 #4 (0)) + (fill-array-data v1 #4 (2)) + (:end) + (return-void) + ) + )"; + const auto& expected_str = R"( + ( + (load-param v0) + (const v1 1) + (new-array v1 "[I") + (move-result-pseudo-object v1) + (fill-array-data v1 #4 (0)) + (if-eqz v0 :true) + (fill-array-data v1 #4 (1)) + (goto :end) + (:true) + (fill-array-data v1 #4 (2)) + (:end) + (return-void) + ) + )"; + test(code_str, expected_str, 1); +}