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; }