Пример #1
0
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;
}
Пример #2
0
 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;
 }
Пример #3
0
 // Performs one peephole test. Applies peephole optimizations to the given
 // source instruction stream, and checks that it equals the expected result
 void test_1(const std::string& name,
             const IRInstructionList& src,
             const IRInstructionList& expected) {
   DexMethod* method = make_void_method(name.c_str(), src);
   dex_class->add_method(method);
   manager.run_passes(stores, config);
   IRInstructionList result(method->get_code());
   EXPECT_EQ(result, expected) << " for test " << name;
   dex_class->remove_method(method);
 }
Пример #4
0
/*
 * 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;
}
Пример #5
0
/* Given a list of class/method pairs, finds all non-abstract
   candidates to be made abstract, then mutates them.
 */
void make_methods_abstract(std::vector<DexClass*>& classes, CMethodStrs cMethodStrs) {
  CMethods methods;
  std::cout << "Marking methods to make abstract..." << std::endl;
  int64_t markedForAbstraction = 0;
  mark_methods(classes, cMethodStrs, methods, markedForAbstraction);

  int64_t madeAbstract = 0;
  for (auto const& cm : methods) {
    DexMethod* m = cm.second;
    std::string descriptor = gen_method_desc(cm);
    if (is_abstract(m)) {
      std::cout << descriptor << " is already abstract" << std::endl;
    } else {
      DexAccessFlags original_access = m->get_access();
      DexMethodSpec ref(m->get_class(), m->get_name(), m->get_proto());
      m->change(ref, false);
      if (m->is_def()) {
        std::cout << "Making " << descriptor << " abstract" << std::endl;
        m->set_access(original_access | ACC_ABSTRACT);
      } else {
        std::cout << descriptor << " has false is_def()" << std::endl;
      }
      madeAbstract++;
    }
  }

  std::cout << madeAbstract << " methods made abstract (from " << markedForAbstraction << " marked)." << std::endl;
}
Пример #6
0
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);
}
Пример #7
0
  // 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;
  }
Пример #8
0
 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);
 }
Пример #9
0
// in Code:     A B E C D          (where C == D)
// in CFG:      A -> B -> C -> E
//               \            /
//                >  --   D  >
//
// out Code:    A B E C
// out CFG:     A -> B -> C -> E
//               \       /
//                > --- >
TEST_F(DedupBlocksTest, simplestCase) {
  using namespace dex_asm;
  DexMethod* method = get_fresh_method("simplestCase");

  auto A_if_D = create_branch(OPCODE_IF_EQZ);
  auto B_goto_C = create_branch(OPCODE_GOTO);
  auto C_goto_E = create_branch(OPCODE_GOTO);
  auto D_goto_E = create_branch(OPCODE_GOTO);

  auto code = method->get_code();
  ASSERT_NE(code, nullptr);

  // A
  code->push_back(dasm(OPCODE_CONST, {0_v, 0_L}));
  code->push_back(dasm(OPCODE_MUL_INT, {0_v, 0_v, 0_v}));
  code->push_back(*A_if_D.source);

  // B
  code->push_back(dasm(OPCODE_MUL_INT, {0_v, 0_v, 0_v}));
  code->push_back(*B_goto_C.source);

  // E
  code->push_back(*C_goto_E.target);
  code->push_back(*D_goto_E.target);
  code->push_back(dasm(OPCODE_RETURN_VOID));

  // C
  code->push_back(*B_goto_C.target);
  code->push_back(dasm(OPCODE_ADD_INT, {0_v, 0_v, 0_v}));
  code->push_back(*C_goto_E.source);

  // D
  code->push_back(*A_if_D.target);
  code->push_back(dasm(OPCODE_ADD_INT, {0_v, 0_v, 0_v}));
  code->push_back(*D_goto_E.source);

  code->build_cfg(true);
  EXPECT_EQ(5, code->cfg().blocks().size());
  printf("Input cfg:\n%s\n", SHOW(code->cfg()));
  code->clear_cfg();

  run_dedup_blocks();

  code->build_cfg(true);
  printf("Result cfg:\n%s\n", SHOW(code->cfg()));
  EXPECT_EQ(4, code->cfg().blocks().size());
  code->clear_cfg();

  auto mie = code->begin();

  // A
  EXPECT_EQ(OPCODE_CONST, mie->insn->opcode());
  ++mie;
  EXPECT_EQ(OPCODE_MUL_INT, mie->insn->opcode());
  ++mie;
  EXPECT_EQ(OPCODE_IF_EQZ, mie->insn->opcode());
  auto a_c = mie;
  ++mie;

  // B
  EXPECT_EQ(OPCODE_MUL_INT, mie->insn->opcode());
  ++mie;
  EXPECT_EQ(OPCODE_GOTO, mie->insn->opcode());
  auto b_c = mie;
  ++mie;

  // E
  EXPECT_EQ(MFLOW_TARGET, mie->type);
  auto c_e = mie->target->src;
  ++mie;
  EXPECT_EQ(OPCODE_RETURN_VOID, mie->insn->opcode());
  ++mie;

  // C
  EXPECT_EQ(MFLOW_TARGET, mie->type);
  EXPECT_TRUE(mie->target->src == &*a_c || mie->target->src == &*b_c);
  ++mie;
  EXPECT_EQ(MFLOW_TARGET, mie->type);
  EXPECT_TRUE(mie->target->src == &*a_c || mie->target->src == &*b_c);
  ++mie;
  EXPECT_EQ(OPCODE_ADD_INT, mie->insn->opcode());
  ++mie;
  EXPECT_EQ(OPCODE_GOTO, mie->insn->opcode());
  EXPECT_EQ(c_e, &*mie);
  ++mie;

  // no D!
  EXPECT_EQ(code->end(), mie);
}