/* * Check that analyze_enum_clinit returns the correct enum field -> ordinal * mapping. */ TEST_F(RedexTest, OrdinalAnalysis) { always_assert(load_class_file(std::getenv("enum_class_file"))); auto dexfile = std::getenv("dexfile"); std::vector<DexStore> stores; DexMetadata dm; dm.set_id("classes"); DexStore root_store(dm); root_store.add_classes(load_classes_from_dex(dexfile)); auto scope = build_class_scope(root_store.get_dexen()); auto enumA = type_class(DexType::get_type(ENUM_A)); auto enum_field_to_ordinal = optimize_enums::analyze_enum_clinit(enumA); auto enumA_zero = static_cast<DexField*>( DexField::get_field("Lcom/facebook/redextest/EnumA;.TYPE_A_0:Lcom/" "facebook/redextest/EnumA;")); auto enumA_one = static_cast<DexField*>( DexField::get_field("Lcom/facebook/redextest/EnumA;.TYPE_A_1:Lcom/" "facebook/redextest/EnumA;")); auto enumA_two = static_cast<DexField*>( DexField::get_field("Lcom/facebook/redextest/EnumA;.TYPE_A_2:Lcom/" "facebook/redextest/EnumA;")); EXPECT_EQ(enum_field_to_ordinal.at(enumA_zero), 0); EXPECT_EQ(enum_field_to_ordinal.at(enumA_one), 1); EXPECT_EQ(enum_field_to_ordinal.at(enumA_two), 2); }
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(); } } }
void run_passes(std::vector<Pass*> passes, std::vector<DexClass*> classes) { std::vector<DexStore> stores; DexMetadata dm; dm.set_id("classes"); DexStore store(dm); store.add_classes(classes); stores.emplace_back(std::move(store)); PassManager manager(passes); manager.set_testing_mode(); Scope external_classes; Json::Value conf_obj = Json::nullValue; ConfigFiles dummy_config(conf_obj); manager.run_passes(stores, external_classes, dummy_config); }
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); } } } } }
virtual void SetUp() override { saved_context = g_redex; g_redex = new RedexContext(); const char* dexfile = std::getenv("dexfile"); ASSERT_NE(nullptr, dexfile); 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)); ASSERT_EQ(classes.size(), 1) << "Expected exactly one class in " << dexfile; dex_class = classes.at(0); ASSERT_NE(nullptr, dex_class); }
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); }