DexMethod* create_ctor_or_static_dispatch( const Spec& spec, const std::map<SwitchIndices, DexMethod*>& indices_to_callee) { always_assert(indices_to_callee.size() && spec.overridden_meth == nullptr); TRACE(SDIS, 5, "creating dispatch %s.%s for targets of size %d\n", SHOW(spec.owner_type), spec.name.c_str(), indices_to_callee.size()); auto orig_method = indices_to_callee.begin()->second; auto mc = init_method_creator(spec, orig_method); auto dispatch_arg_list = spec.proto->get_args(); auto type_tag_loc = mc->get_local(is_static(spec.access_flags) ? dispatch_arg_list->size() - 1 : dispatch_arg_list->size()); auto ret_loc = get_return_location(spec, mc); auto mb = mc->get_main_block(); // Set type tag field only when using synthesized type tags. // For the external type tag case (GQL), merged ctors take care of that // automatically. if (save_type_tag_to_field(spec)) { mb->iput(spec.type_tag_field, ret_loc, type_tag_loc); } // Setup switch cases // The MethodBlocks are to be initialized by switch_op() based on their // corresponding keys in the map. std::vector<Location> args = get_args_from(orig_method, mc); if (is_single_target_case(spec, indices_to_callee)) { invoke_static(spec, args, ret_loc, orig_method, mb); mb->ret(spec.proto->get_rtype(), ret_loc); return materialize_dispatch(orig_method, mc); } auto cases = get_switch_cases(indices_to_callee, is_ctor(spec)); // TODO (zwei): better dispatch? E.g., push down invoke-direct to the super // ctor to happen after the switch stmt. auto def_block = mb->switch_op(type_tag_loc, cases); handle_default_block(spec, indices_to_callee, args, ret_loc, def_block); mb->ret(spec.proto->get_rtype(), ret_loc); for (auto& case_it : cases) { auto case_block = case_it.second; always_assert(case_block != nullptr); auto callee = indices_to_callee.at(case_it.first); always_assert(is_static(callee)); invoke_static(spec, args, ret_loc, callee, case_block); } return materialize_dispatch(orig_method, mc); }
DexClass* create_class(const DexType* type, const DexType* super_type, const std::string& pkg_name, std::vector<DexField*> fields, const TypeSet& interfaces, bool with_default_ctor, DexAccessFlags access) { DexType* t = const_cast<DexType*>(type); always_assert(!pkg_name.empty()); auto name = std::string(type->get_name()->c_str()); name = pkg_name + "/" + name.substr(1); t->set_name(DexString::make_string(name)); // Create class. ClassCreator creator(t); creator.set_access(access); always_assert(super_type != nullptr); creator.set_super(const_cast<DexType*>(super_type)); for (const auto& itf : interfaces) { creator.add_interface(const_cast<DexType*>(itf)); } for (const auto& field : fields) { creator.add_field(field); } auto cls = creator.create(); // Keeping type-erasure generated classes from being renamed. cls->rstate.set_keep_name(); if (!with_default_ctor) { return cls; } // Create ctor. auto super_ctors = type_class(super_type)->get_ctors(); for (auto super_ctor : super_ctors) { auto mc = new MethodCreator(t, DexString::make_string("<init>"), super_ctor->get_proto(), ACC_PUBLIC | ACC_CONSTRUCTOR); // Call to super.<init> std::vector<Location> args; size_t args_size = super_ctor->get_proto()->get_args()->size(); for (size_t arg_loc = 0; arg_loc < args_size + 1; ++arg_loc) { args.push_back(mc->get_local(arg_loc)); } auto mb = mc->get_main_block(); mb->invoke(OPCODE_INVOKE_DIRECT, super_ctor, args); mb->ret_void(); auto ctor = mc->create(); TRACE(TERA, 4, " default ctor created %s\n", SHOW(ctor)); cls->add_method(ctor); } return cls; }