match_t<DexMethodRef, std::tuple<> > can_be_constructor() { return { [](const DexMethodRef* meth) { return is_constructor(meth); } }; }
match_t<DexMethod, std::tuple<> > is_constructor() { return { [](const DexMethod* meth) { return is_constructor(meth); } }; }
void Function::set_construct_destruct(int ftype, bool no_implicit_type_conversion) { m_ftype = ftype; Class *pc = class_context(); //if (!is_plain() && pc) fail("must be within class definition"); if (is_destructor()) { if(signature()->size() > 0) fail("destructor cannot be passed parameters"); pc->destructor(this); } else if (is_constructor()) pc->add_constructor(this,no_implicit_type_conversion); }
unsigned list_cases_on(vm_obj const & o, buffer<vm_obj> & data) { if (is_simple(o)) { return 0; } else if (is_constructor(o)) { data.append(csize(o), cfields(o)); return 1; } else { lean_assert(is_external(o)); if (auto l = dynamic_cast<vm_list<name>*>(to_external(o))) { return list_cases_on_core(l->m_val, data); } else if (auto l = dynamic_cast<vm_list<expr>*>(to_external(o))) { return list_cases_on_core(l->m_val, data); } else if (auto l = dynamic_cast<vm_list<level>*>(to_external(o))) { return list_cases_on_core(l->m_val, data); } else { lean_unreachable(); } } }
/* * There's no "good way" to differentiate blank vs. non-blank * finals. So, we just scan the code in the CL-init. If * it's sput there, then it's a blank. Lame, agreed, but functional. * */ void get_sput_in_clinit(DexClass* clazz, std::unordered_map<DexField*, bool>& blank_statics) { auto methods = clazz->get_dmethods(); for (auto method : methods) { if (is_clinit(method)) { always_assert_log(is_static(method) && is_constructor(method), "static constructor doesn't have the proper access bits set\n"); auto& code = method->get_code(); auto opcodes = code->get_instructions(); for (auto opcode : opcodes) { if (opcode->has_fields() && is_sput(opcode->opcode())) { auto fieldop = static_cast<DexOpcodeField*>(opcode); auto field = resolve_field(fieldop->field(), FieldSearch::Static); if (field == nullptr || !field->is_concrete()) continue; if (field->get_class() != clazz->get_type()) continue; blank_statics[field] = true; } } } } }
void Function::dump(ostream& os) { Signature::set_fun_name(name(),is_constructor(),is_destructor()); os << *signature(); }
/** * Remove any chance for collisions. */ void OptimizationImpl::rename_possible_collisions( DexType* intf, SingleImplData& data) { const auto& rename = [](DexMethodRef* meth, DexString* name) { DexMethodSpec spec; spec.cls = meth->get_class(); spec.name = name; spec.proto = meth->get_proto(); meth->change(spec, false); }; TRACE(INTF, 9, "Changing name related to %s\n", SHOW(intf)); for (const auto& meth : data.methoddefs) { if (!can_rename(meth)) { TRACE(INTF, 9, "Changing name but cannot rename %s, give up\n", SHOW(meth)); return; } } std::unordered_map<DexString*, DexString*> names; const auto new_name = [&](DexString* name) { const auto& name_it = names.find(name); if (name_it != names.end()) { return name_it->second; } DexString* possible_name = nullptr; static std::string sufx("$r"); static int intf_id = 0; while(true) { const auto& str = name->str() + sufx + std::to_string(intf_id++); possible_name = DexString::get_string(str.c_str()); if (possible_name == nullptr) { possible_name = DexString::make_string(str.c_str()); break; } } names[name] = possible_name; return possible_name; }; for (const auto& meth : data.methoddefs) { if (is_constructor(meth)) continue; auto name = new_name(meth->get_name()); TRACE(INTF, 9, "Changing name for %s to %s\n", SHOW(meth), SHOW(name)); rename(meth, name); } for (const auto& refs_it : data.methodrefs) { if (refs_it.first->is_def()) continue; static auto init = DexString::make_string("<init>"); always_assert(refs_it.first->get_name() != init); auto name = new_name(refs_it.first->get_name()); TRACE(INTF, 9, "Changing name for %s to %s\n", SHOW(refs_it.first), SHOW(name)); if (names.count(refs_it.first->get_name()) == 0) { TRACE(INTF, 9, "Changing name on missing method def %s", SHOW(refs_it.first)); } rename(refs_it.first, name); } }
/** * Collect all non virtual methods and make all small methods candidates * for inlining. */ std::unordered_set<DexMethod*> SimpleInlinePass::gather_non_virtual_methods( Scope& scope, const std::unordered_set<DexType*>& no_inline) { // trace counter size_t all_methods = 0; size_t direct_methods = 0; size_t direct_no_code = 0; size_t non_virtual_no_code = 0; size_t clinit = 0; size_t init = 0; size_t static_methods = 0; size_t private_methods = 0; size_t dont_strip = 0; size_t no_inline_anno_count = 0; size_t non_virt_dont_strip = 0; size_t non_virt_methods = 0; // collect all non virtual methods (dmethods and vmethods) std::unordered_set<DexMethod*> methods; const auto can_inline_method = [&](DexMethod* meth, DexCode* code) { if (has_anno(type_class(meth->get_class()), no_inline) || has_anno(meth, no_inline)) { no_inline_anno_count++; return; } if (code->get_instructions().size() < SMALL_CODE_SIZE) { // always inline small methods even if they are not deletable inlinable.insert(meth); } else { if (!can_delete(meth)) { // never inline methods that cannot be deleted TRACE(SINL, 4, "cannot_delete: %s\n", SHOW(meth)); dont_strip++; } else { methods.insert(meth); } } }; walk_methods(scope, [&](DexMethod* method) { all_methods++; if (method->is_virtual()) return; auto code = method->get_code(); bool dont_inline = code == nullptr; direct_methods++; if (code == nullptr) direct_no_code++; if (is_constructor(method)) { (is_static(method)) ? clinit++ : init++; dont_inline = true; } else { (is_static(method)) ? static_methods++ : private_methods++; } if (dont_inline) return; can_inline_method(method, code); }); if (m_virtual_inline) { auto non_virtual = devirtualize(scope); non_virt_methods = non_virtual.size(); for (const auto& vmeth : non_virtual) { auto code = vmeth->get_code(); if (code == nullptr) { non_virtual_no_code++; continue; } can_inline_method(vmeth, code); } } TRACE(SINL, 2, "All methods count: %ld\n", all_methods); TRACE(SINL, 2, "Direct methods count: %ld\n", direct_methods); TRACE(SINL, 2, "Virtual methods count: %ld\n", all_methods - direct_methods); TRACE(SINL, 2, "Direct methods no code: %ld\n", direct_no_code); TRACE(SINL, 2, "Direct methods with code: %ld\n", direct_methods - direct_no_code); TRACE(SINL, 2, "Constructors with or without code: %ld\n", init); TRACE(SINL, 2, "Static constructors: %ld\n", clinit); TRACE(SINL, 2, "Static methods: %ld\n", static_methods); TRACE(SINL, 2, "Private methods: %ld\n", private_methods); TRACE(SINL, 2, "Virtual methods non virtual count: %ld\n", non_virt_methods); TRACE(SINL, 2, "Non virtual no code count: %ld\n", non_virtual_no_code); TRACE(SINL, 2, "Non virtual no strip count: %ld\n", non_virt_dont_strip); TRACE(SINL, 2, "Small methods: %ld\n", inlinable.size()); TRACE(SINL, 2, "Don't strip inlinable methods count: %ld\n", dont_strip); TRACE(SINL, 2, "Don't inline annotation count: %ld\n", no_inline_anno_count); return methods; }