Esempio n. 1
0
TEST(PropagationTest1, localDCE1) {
  g_redex = new RedexContext();

  const char* dexfile = std::getenv("dexfile");
  ASSERT_NE(nullptr, dexfile);

  std::vector<DexStore> stores;
  DexMetadata dm;
  dm.set_id("classes");
  DexStore root_store(dm);
  root_store.add_classes(load_classes_from_dex(dexfile));
  DexClasses& classes = root_store.get_dexen().back();
  stores.emplace_back(std::move(root_store));
  std::cout << "Loaded classes: " << classes.size() << std::endl ;

  TRACE(DCE, 2, "Code before:\n");
  for(const auto& cls : classes) {
    TRACE(DCE, 2, "Class %s\n", SHOW(cls));
    for (const auto& dm : cls->get_dmethods()) {
      TRACE(DCE, 2, "dmethod: %s\n",  dm->get_name()->c_str());
      if (strcmp(dm->get_name()->c_str(), "propagate") == 0) {
        TRACE(DCE, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
      }
    }
  }

  std::vector<Pass*> passes = {
    new PeepholePass(),
    new LocalDcePass(),
  };

  PassManager manager(passes);
  manager.set_testing_mode();

  Json::Value conf_obj = Json::nullValue;
  ConfigFiles dummy_cfg(conf_obj);
  manager.run_passes(stores, dummy_cfg);

  TRACE(DCE, 2, "Code after:\n");
  for(const auto& cls : classes) {
    TRACE(DCE, 2, "Class %s\n", SHOW(cls));
    for (const auto& dm : cls->get_dmethods()) {
      TRACE(DCE, 2, "dmethod: %s\n",  dm->get_name()->c_str());
      if (strcmp(dm->get_name()->c_str(), "propagate") == 0) {
        TRACE(DCE, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
        for (auto& mie : InstructionIterable(dm->get_code())) {
          auto instruction = mie.insn;
          // Make sure there is no invoke-virtual in the optimized method.
          ASSERT_NE(instruction->opcode(), OPCODE_INVOKE_VIRTUAL);
          // Make sure there is no const-class in the optimized method.
          ASSERT_NE(instruction->opcode(), OPCODE_CONST_CLASS);
        }
      }
    }
  }

}
Esempio n. 2
0
TEST(DedupBlocksTest, useSwitch) {
  g_redex = new RedexContext();

  const char* dexfile = std::getenv("dexfile");
  EXPECT_NE(nullptr, dexfile);

  std::vector<DexStore> stores;
  DexMetadata dm;
  dm.set_id("classes");
  DexStore root_store(dm);
  root_store.add_classes(load_classes_from_dex(dexfile));
  DexClasses& classes = root_store.get_dexen().back();
  stores.emplace_back(std::move(root_store));

  TRACE(RME, 1, "Code before:\n");
  for (const auto& cls : classes) {
    TRACE(RME, 1, "Class %s\n", SHOW(cls));
    for (const auto& m : cls->get_vmethods()) {
      TRACE(RME, 1, "\nmethod %s:\n", SHOW(m));
      IRCode* code = m->get_code();
      code->build_cfg(true);
      EXPECT_EQ(2, count_sgets(code->cfg()));
      code->clear_cfg();
    }
  }

  auto copy_prop = new CopyPropagationPass();
  copy_prop->m_config.static_finals = true;
  copy_prop->m_config.wide_registers = true;
  std::vector<Pass*> passes = {
    copy_prop
  };

  PassManager manager(passes);
  manager.set_testing_mode();

  Json::Value conf_obj = Json::nullValue;
  Scope external_classes;
  ConfigFiles dummy_cfg(conf_obj);
  manager.run_passes(stores, external_classes, dummy_cfg);

  TRACE(RME, 1, "Code after:\n");
  for (const auto& cls : classes) {
    for (const auto& m : cls->get_vmethods()) {
      TRACE(RME, 1, "\nmethod %s:\n", SHOW(m));
      IRCode* code = m->get_code();
      code->build_cfg(true);
      if (strcmp(m->get_name()->c_str(), "remove") == 0) {
        EXPECT_EQ(1, count_sgets(code->cfg()));
      } else {
        EXPECT_EQ(2, count_sgets(code->cfg()));
      }
      code->clear_cfg();
    }
  }
}
Esempio n. 3
0
TEST(ResultPropagationTest, useSwitch) {
  g_redex = new RedexContext();

  const char* dexfile = std::getenv("dexfile");
  EXPECT_NE(nullptr, dexfile);

  std::vector<DexStore> stores;
  DexMetadata dm;
  dm.set_id("classes");
  DexStore root_store(dm);
  root_store.add_classes(load_classes_from_dex(dexfile));
  DexClasses& classes = root_store.get_dexen().back();
  stores.emplace_back(std::move(root_store));

  std::vector<Pass*> passes = {
      new ResultPropagationPass(),
  };

  PassManager manager(passes);
  manager.set_testing_mode();

  Json::Value conf_obj = Json::nullValue;
  ConfigFiles dummy_cfg(conf_obj);
  manager.run_passes(stores, dummy_cfg);

  int num_test_classes = 0;
  const char* test_class_prefix = "Lcom/facebook/redextest/ResultPropagation$";
  const char* test_method_prefix = "returns_";
  for (const auto& cls : classes) {
    if (strncmp(cls->get_name()->c_str(), test_class_prefix,
                strlen(test_class_prefix)) == 0) {
      TRACE(RP, 1, "test class %s\n", cls->get_name()->c_str());
      num_test_classes++;
      int num_tests_in_class = 0;
      for (const auto& m : cls->get_vmethods()) {
        const auto method_name = m->get_name()->c_str();
        TRACE(RP, 1, " test method %s\n", method_name);
        EXPECT_EQ(strncmp(method_name, test_method_prefix,
                          strlen(test_method_prefix)),
                  0);
        const auto suffix = method_name + strlen(test_method_prefix);
        boost::optional<ParamIndex> expected;
        if (strcmp(suffix, "none") != 0) {
          expected = atoi(suffix);
        }

        IRCode* code = m->get_code();
        code->build_cfg(/* editable */ true);
        auto actual = find_return_param_index(code->cfg());
        code->clear_cfg();
        if (expected) {
          EXPECT_TRUE(actual);
          EXPECT_EQ(*actual, *expected);
        } else {
          EXPECT_FALSE(actual);
        }
        num_tests_in_class++;
      }
      EXPECT_EQ(num_tests_in_class, 1);
    }
  }
  EXPECT_EQ(num_test_classes, 6);
}
Esempio n. 4
0
TEST(ConstantPropagationTest1, constantpropagation) {
  g_redex = new RedexContext();

	const char* dexfile =
    "gen/native/redex/test/integ/constant-propagation-test-dex/constant-propagation.dex";
  if (access(dexfile, R_OK) != 0) {
    dexfile = std::getenv("dexfile");
    ASSERT_NE(nullptr, dexfile);
  }

  std::vector<DexClasses> dexen;
  dexen.emplace_back(load_classes_from_dex(dexfile));
  DexClasses& classes = dexen.back();
  std::cout << "Loaded classes: " << classes.size() << std::endl;

	TRACE(MAIN, 2, "Code before:\n");
  for(const auto& cls : classes) {
	  TRACE(MAIN, 2, "Class %s\n", SHOW(cls));
		for (const auto& dm : cls->get_dmethods()) {
		  TRACE(MAIN, 2, "dmethod: %s\n",  dm->get_name()->c_str());
			if (strcmp(dm->get_name()->c_str(), "propagation") == 0) {
			  TRACE(MAIN, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
			}
		}
	}

  std::vector<Pass*> passes = {
    new LocalDcePass(),
    new DelInitPass(),
    new RemoveEmptyClassesPass(),
    // TODO: add constant propagation and conditional pruning optimization
  };

  std::vector<KeepRule> null_rules;
  PassManager manager(passes, null_rules);

  Json::Value conf_obj = Json::nullValue;
  ConfigFiles dummy_cfg(conf_obj);
  manager.run_passes(dexen, dummy_cfg);

	TRACE(MAIN, 2, "Code after:\n");
	for(const auto& cls : classes) {
	  TRACE(MAIN, 2, "Class %s\n", SHOW(cls));
		for (const auto& dm : cls->get_dmethods()) {
		  TRACE(MAIN, 2, "dmethod: %s\n",  dm->get_name()->c_str());
			if (strcmp(dm->get_name()->c_str(), "propagation") == 0) {
			  TRACE(MAIN, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
			  for (auto const instruction : dm->get_code()->get_instructions()) {
          //The logic will be reverted when the future
          //development of constant propagation optimization is done, i.e.,
          //The code will be changed to ASSERT_TRUE(false)
          // if IF_EQZ or New Class Instance instruction is found
          if (instruction->opcode() == OPCODE_IF_EQZ ||
              instruction->opcode() == OPCODE_NEW_INSTANCE) {
                  ASSERT_TRUE(true);
              }
			  }
			}
		}
	}
}
TEST(ConstantPropagationTest1, constantpropagation) {
  g_redex = new RedexContext();

	const char* dexfile =
    "gen/native/redex/test/integ/constant-propagation-test-dex/constant-propagation.dex";
  if (access(dexfile, R_OK) != 0) {
    dexfile = std::getenv("dexfile");
    ASSERT_NE(nullptr, dexfile);
  }

  std::vector<DexClasses> dexen;
  dexen.emplace_back(load_classes_from_dex(dexfile));
  DexClasses& classes = dexen.back();
  std::cout << "Loaded classes: " << classes.size() << std::endl;

	TRACE(CONSTP, 2, "Code before:\n");
  for(const auto& cls : classes) {
    TRACE(CONSTP, 2, "Class %s\n", SHOW(cls));
    if (filter_test_classes(cls->get_name()) < 2) {
      TRACE(CONSTP, 2, "Class %s\n", SHOW(cls));
      for (const auto& dm : cls->get_dmethods()) {
        TRACE(CONSTP, 2, "dmethod: %s\n",  dm->get_name()->c_str());
        if (strcmp(dm->get_name()->c_str(), "propagation_1") == 0 ||
            strcmp(dm->get_name()->c_str(), "propagation_2") == 0 ||
            strcmp(dm->get_name()->c_str(), "propagation_3") == 0) {
          TRACE(CONSTP, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
        }
      }
    }
  }

  std::vector<Pass*> passes = {
    new ConstantPropagationPass(),
    new LocalDcePass()
  };

  std::vector<KeepRule> null_rules;
  PassManager manager(passes, null_rules);

  Json::Value conf_obj = Json::nullValue;
  ConfigFiles dummy_cfg(conf_obj);
  dummy_cfg.using_seeds = true;
  manager.run_passes(dexen, dummy_cfg);

  TRACE(CONSTP, 2, "Code after:\n");
  for(const auto& cls : classes) {
    TRACE(CONSTP, 2, "Class %s\n", SHOW(cls));
    //ASSERT_NE(filter_test_classes(cls->get_name()), REMOVEDCLASS);
    if (filter_test_classes(cls->get_name()) == MAINCLASS) {
      for (const auto& dm : cls->get_dmethods()) {
        TRACE(CONSTP, 2, "dmethod: %s\n",  dm->get_name()->c_str());
        if (strcmp(dm->get_name()->c_str(), "propagation_1") == 0) {
          TRACE(CONSTP, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
          for (auto const instruction : dm->get_code()->get_instructions()) {
            ASSERT_NE(instruction->opcode(), OPCODE_IF_EQZ);
            ASSERT_NE(instruction->opcode(), OPCODE_NEW_INSTANCE);
          }
        } else if (strcmp(dm->get_name()->c_str(), "propagation_2") == 0) {
          TRACE(CONSTP, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
          for (auto const instruction : dm->get_code()->get_instructions()) {
            ASSERT_NE(instruction->opcode(), OPCODE_IF_EQZ);
            ASSERT_NE(instruction->opcode(), OPCODE_INVOKE_STATIC);
          }
        } else if(strcmp(dm->get_name()->c_str(), "propagation_3") == 0) {
          TRACE(CONSTP, 2, "dmethod: %s\n",  SHOW(dm->get_code()));
          for (auto const instruction : dm->get_code()->get_instructions()) {
            //ASSERT_NE(instruction->opcode(), OPCODE_IF_EQZ);
            //ASSERT_NE(instruction->opcode(), OPCODE_INVOKE_STATIC);
          }
        }
      }
    }
  }
}
Esempio n. 6
0
TEST(EmptyClassesTest1, emptyclasses) {
  g_redex = new RedexContext();

  const char* dexfile = "empty-classes-test-class.dex";
  if (access(dexfile, R_OK) != 0) {
    dexfile = std::getenv("dexfile");
    ASSERT_NE(nullptr, dexfile);
  }

  std::vector<DexClasses> dexen;
  dexen.emplace_back(load_classes_from_dex(dexfile));
  DexClasses& classes = dexen.back();
  size_t before = classes.size();
  TRACE(EMPTY, 3, "Loaded classes: %ld\n", classes.size());
  // Report the classes that were loaded through tracing.
  for (const auto& cls : classes) {
    TRACE(EMPTY, 3, "Input class: %s\n",
        cls->get_type()->get_name()->c_str());
  }

  std::vector<Pass*> passes = {
    new DelInitPass(),
    new RemoveEmptyClassesPass(),
  };

  std::vector<KeepRule> null_rules;
  auto const keep = { "Lcom/facebook/redextest/DoNotStrip;" };
  const folly::dynamic conf_obj = folly::dynamic::object(
            "keep_annotations", folly::dynamic(keep.begin(), keep.end()));
  PassManager manager(
    passes,
    null_rules,
    conf_obj
  );
  ConfigFiles dummy_cfg(conf_obj);
  manager.run_passes(dexen, dummy_cfg);

  size_t after = 0;
  std::set<std::string> remaining_classes;
  for (const auto& dex_classes : dexen) {
    for (const auto cls : dex_classes) {
      TRACE(EMPTY, 3, "Output class: %s\n",
          cls->get_type()->get_name()->c_str());
      after++;
      remaining_classes.insert(SHOW(cls->get_type()->get_name()));
    }
  }
  TRACE(EMPTY, 2, "Removed %ld classes\n", before - after);
  ASSERT_EQ(0, remaining_classes.count("Lcom/facebook/redextest/EmptyClasses;"));
  ASSERT_EQ(0, remaining_classes.count("Lcom/facebook/redextest/InnerEmpty;"));
  ASSERT_EQ(0, remaining_classes.count("Lcom/facebook/redextest/InnerEmpty$InnerClass;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/InnerEmpty2;"));
  ASSERT_EQ(0, remaining_classes.count("Lcom/facebook/redextest/InnerEmpty2$InnerClass2;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/NotAnEmptyClass;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/NotAnEmptyClass2;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/NotAnEmptyClass3;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/NotAnEmptyClass4;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/NotAnEmptyClass5;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/NotAnEmptyClass5;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/YesNo;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/MyYesNo;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/EasilyDone;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/By2Or3;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/MyBy2Or3;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/WombatException;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/Wombat;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/EmptyButLaterExtended;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/Extender;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/NotUsedHere;"));
  ASSERT_EQ(1, remaining_classes.count("Lcom/facebook/redextest/DontKillMeNow;"));

  delete g_redex;
}