TEST(IRInstruction, SelectCheckCast) { using namespace dex_asm; g_redex = new RedexContext(); DexMethod* method = static_cast<DexMethod*>(DexMethod::make_method("Lfoo;", "bar", "V", {})); method->make_concrete(ACC_STATIC, 0); method->set_code(std::make_unique<IRCode>(method, 0)); auto code = method->get_code(); code->push_back(dasm(OPCODE_CHECK_CAST, get_object_type(), {1_v})); code->push_back(dasm(IOPCODE_MOVE_RESULT_PSEUDO_OBJECT, {0_v})); instruction_lowering::lower(method); // check that we inserted a move opcode before the check-cast auto it = code->begin(); EXPECT_EQ( *it->dex_insn, *(new DexInstruction(DOPCODE_MOVE_OBJECT))->set_dest(0)->set_src(0, 1)); ++it; EXPECT_EQ(*it->dex_insn, *(new DexOpcodeType(DOPCODE_CHECK_CAST, get_object_type())) ->set_src(0, 0)); delete g_redex; }
DexMethod* get_fresh_method(const std::string& name) { DexMethod* method = static_cast<DexMethod*>(DexMethod::make_method( m_type, DexString::make_string(name), m_proto)); method->make_concrete(ACC_PUBLIC | ACC_STATIC, false); method->set_code(std::make_unique<IRCode>(method, 1)); m_creator->add_method(method); return method; }
/* * Helper function to run select and then extract the resulting instruction * from the instruction list. The only reason it's a list is that const-cast * IRInstructions can expand into two instructions due to select. Everything * else is a simple one-to-one instruction mapping, and that's the case that * this makes easy to test. */ IRInstruction* select_instruction(IRInstruction* insn) { DexMethod* method = static_cast<DexMethod*>(DexMethod::make_method("Lfoo;", "bar", "V", {})); method->make_concrete(ACC_STATIC, 0); method->set_code(std::make_unique<IRCode>(method, 0)); auto code = method->get_code(); code->push_back(insn); instruction_lowering::lower(method); return code->begin()->insn; }
void EquivalenceTest::generate(DexClass* cls) { setup(cls); auto ret = DexType::make_type("I"); auto args = DexTypeList::make_type_list({}); auto proto = DexProto::make_proto(ret, args); // I() DexMethod* before = static_cast<DexMethod*>(DexMethod::make_method( cls->get_type(), DexString::make_string("before_" + test_name()), proto)); before->make_concrete(ACC_PUBLIC | ACC_STATIC, false); before->set_code(std::make_unique<IRCode>(before, 0)); build_method(before); cls->add_method(before); auto after = DexMethod::make_method_from( before, cls->get_type(), DexString::make_string("after_" + test_name())); cls->add_method(after); transform_method(after); }
// add a void->void static method to our dex_class DexMethod* make_void_method(const char* method_name, const IRInstructionList& insns) const { auto ret = get_void_type(); auto args = DexTypeList::make_type_list({}); auto proto = DexProto::make_proto(ret, args); // I() DexMethod* method = static_cast<DexMethod*>(DexMethod::make_method( dex_class->get_type(), DexString::make_string(method_name), proto)); method->make_concrete(ACC_PUBLIC | ACC_STATIC, false); // FIXME we should determine the actual number of temp regs used from // the IRInstructionList method->set_code(std::make_unique<IRCode>(method, 0)); // import our instructions auto mt = method->get_code(); for (const auto& insn_ptr : insns.instructions) { mt->push_back(new IRInstruction(*insn_ptr)); } return method; }
virtual void setup(DexClass* cls) { auto ret = DexType::make_type("I"); auto arg = DexType::make_type("I"); auto args = DexTypeList::make_type_list({arg, arg}); auto proto = DexProto::make_proto(ret, args); // I(I, I) m_callee = DexMethod::make_method(cls->get_type(), DexString::make_string("callee_" + test_name()), proto); m_callee->make_concrete( ACC_PUBLIC | ACC_STATIC, std::make_unique<DexCode>(), false); { using namespace dex_asm; MethodTransformer mt(m_callee); // note that this method will not behave the same way if v0 and v1 get // mapped to the same register mt->push_back(dasm(OPCODE_ADD_INT_2ADDR, {0_v, 1_v})); mt->push_back(dasm(OPCODE_ADD_INT_2ADDR, {1_v, 0_v})); mt->push_back(dasm(OPCODE_RETURN, {1_v})); m_callee->get_code()->set_registers_size(2); m_callee->get_code()->set_ins_size(2); } cls->add_method(m_callee); }