📄 specializer.cc
字号:
/* * specializer.{cc,hh} -- specializer * Eddie Kohler * * Copyright (c) 2000 Massachusetts Institute of Technology * Copyright (c) 2000 Mazu Networks, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, subject to the conditions * listed in the Click LICENSE file. These conditions include: you must * preserve this copyright notice, and you cannot mention the copyright * holders in advertising related to the Software without their permission. * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This * notice is a summary of the Click LICENSE file; the license in that file is * legally binding. */#include <click/config.h>#include <click/pathvars.h>#include "specializer.hh"#include "routert.hh"#include <click/error.hh>#include "toolutils.hh"#include "elementmap.hh"#include <click/straccum.hh>#include "signature.hh"#include <ctype.h>Specializer::Specializer(RouterT *router, const ElementMap &em) : _router(router), _nelements(router->nelements()), _ninputs(router->nelements(), 0), _noutputs(router->nelements(), 0), _etinfo_map(0), _header_file_map(-1), _parsed_sources(-1){ _etinfo.push_back(ElementTypeInfo()); for (RouterT::iterator x = router->begin_elements(); x; x++) { _noutputs[x->eindex()] = x->noutputs(); _ninputs[x->eindex()] = x->ninputs(); } // prepare from element map for (ElementMap::TraitsIterator x = em.begin_elements(); x; x++) { const Traits &e = x.value(); add_type_info(e.name, e.cxx, e.header_file, em.source_directory(e)); }}inline ElementTypeInfo &Specializer::etype_info(int eindex){ return type_info(_router->etype_name(eindex));}inline const ElementTypeInfo &Specializer::etype_info(int eindex) const{ return type_info(_router->etype_name(eindex));}voidSpecializer::add_type_info(const String &click_name, const String &cxx_name, const String &header_file, const String &source_dir){ ElementTypeInfo eti; eti.click_name = click_name; eti.cxx_name = cxx_name; eti.header_file = header_file; eti.source_directory = source_dir; _etinfo.push_back(eti); int i = _etinfo.size() - 1; _etinfo_map.insert(click_name, i); if (header_file) { int slash = header_file.find_right('/'); _header_file_map.insert(header_file.substring(slash < 0 ? 0 : slash + 1), i); }}voidElementTypeInfo::locate_header_file(RouterT *for_archive, ErrorHandler *errh){ if (!found_header_file) { if (!source_directory && for_archive->archive_index(header_file) >= 0) found_header_file = header_file; else if (String found = clickpath_find_file(header_file, 0, source_directory)) found_header_file = found; else { errh->warning("can't locate header file \"%s\"", header_file.cc()); found_header_file = header_file; } }}voidSpecializer::parse_source_file(ElementTypeInfo &etinfo, bool do_header, String *includes){ String fn = etinfo.header_file; if (!do_header && fn.substring(-3) == ".hh") fn = etinfo.header_file.substring(0, -3) + ".cc"; // don't parse a source file twice if (_parsed_sources[fn] < 0) { String text; if (!etinfo.source_directory && _router->archive_index(fn) >= 0) { text = _router->archive(fn).data; if (do_header) etinfo.found_header_file = fn; } else if (String found = clickpath_find_file(fn, 0, etinfo.source_directory)) { text = file_string(found); if (do_header) etinfo.found_header_file = found; } _cxxinfo.parse_file(text, do_header, includes); _parsed_sources.insert(fn, 1); }}voidSpecializer::read_source(ElementTypeInfo &etinfo, ErrorHandler *errh){ if (!etinfo.click_name || etinfo.read_source) return; etinfo.read_source = true; if (!etinfo.header_file) { errh->warning("element class '%s' has no source file", etinfo.click_name.cc()); return; } // parse source text String text, filename = etinfo.header_file; if (filename.substring(-3) == ".hh") parse_source_file(etinfo, true, 0); parse_source_file(etinfo, false, &etinfo.includes); // now, read source for the element class's parents CxxClass *cxxc = _cxxinfo.find_class(etinfo.cxx_name); if (cxxc) for (int i = 0; i < cxxc->nparents(); i++) { const String &p = cxxc->parent(i)->name(); if (p != "Element" && p != "TimedElement" && p != "UnlimitedElement") read_source(type_info(p), errh); }}voidSpecializer::check_specialize(int eindex, ErrorHandler *errh){ int sp = _specialize[eindex]; if (_specials[sp].eindex > SPCE_NOT_DONE) return; _specials[sp].eindex = SPCE_NOT_SPECIAL; // get type info ElementTypeInfo &old_eti = etype_info(eindex); if (!old_eti.click_name) { errh->warning("no information about element class '%s'", _router->etype_name(eindex).cc()); return; } // read source code if (!old_eti.read_source) read_source(old_eti, errh); CxxClass *old_cxxc = _cxxinfo.find_class(old_eti.cxx_name); if (!old_cxxc) { errh->warning("C++ class '%s' not found for element class '%s'", old_eti.cxx_name.cc(), old_eti.click_name.cc()); return; } // don't specialize if there are no reachable functions SpecializedClass &spc = _specials[sp]; spc.old_click_name = old_eti.click_name; spc.eindex = eindex; if (!old_cxxc->find_should_rewrite()) { spc.click_name = spc.old_click_name; spc.cxx_name = old_eti.cxx_name; } else { spc.click_name = specialized_click_name(_router->element(eindex)); spc.cxx_name = click_to_cxx_name(spc.click_name); add_type_info(spc.click_name, spc.cxx_name, String(), String()); }}boolSpecializer::create_class(SpecializedClass &spc){ assert(!spc.cxxc); int eindex = spc.eindex; if (spc.click_name == spc.old_click_name) return false; // create new C++ class const ElementTypeInfo &old_eti = etype_info(eindex); CxxClass *old_cxxc = _cxxinfo.find_class(old_eti.cxx_name); CxxClass *new_cxxc = _cxxinfo.make_class(spc.cxx_name); assert(old_cxxc && new_cxxc); bool specialize_away = (old_cxxc->find("devirtualize_all") != 0); String parent_cxx_name = old_eti.cxx_name; if (specialize_away) { CxxClass *parent = old_cxxc->parent(0); new_cxxc->add_parent(parent); parent_cxx_name = parent->name(); } else new_cxxc->add_parent(old_cxxc); spc.cxxc = new_cxxc; // add helper functions: constructor, destructor, class_name, cast if (specialize_away) { CxxFunction *f = old_cxxc->find(old_eti.cxx_name); new_cxxc->defun (CxxFunction(spc.cxx_name, true, "", "()", f->body(), f->clean_body())); f = old_cxxc->find("~" + old_eti.cxx_name); new_cxxc->defun (CxxFunction("~" + spc.cxx_name, true, "", "()", f->body(), f->clean_body())); } else { new_cxxc->defun (CxxFunction(spc.cxx_name, true, "", "()", " ", "")); new_cxxc->defun (CxxFunction("~" + spc.cxx_name, true, "", "()", " ", "")); } new_cxxc->defun (CxxFunction("class_name", true, "const char *", "() const", String(" return \"") + spc.click_name + "\"; ", "")); new_cxxc->defun (CxxFunction("cast", false, "void *", "(const char *n)", "\n if (void *v = " + parent_cxx_name + "::cast(n))\n\ return v;\n else if (strcmp(n, \"" + spc.click_name + "\") == 0\n\ || strcmp(n, \"" + old_eti.click_name + "\") == 0)\n\ return (Element *)this;\n else\n return 0;\n", "")); // placeholders for input_pull and output_push new_cxxc->defun (CxxFunction("input_pull", false, "inline Packet *", (_ninputs[eindex] ? "(int i) const" : "(int) const"), "", "")); new_cxxc->defun (CxxFunction("output_push", false, "inline void", (_noutputs[eindex] ? "(int i, Packet *p) const" : "(int, Packet *p) const"), "", "")); new_cxxc->defun (CxxFunction("output_push_checked", false, "inline void", (_noutputs[eindex] ? "(int i, Packet *p) const" : "(int, Packet *p) const"), "", "")); new_cxxc->defun (CxxFunction("never_devirtualize", true, "void", "()", "", "")); // transfer reachable rewritable functions to new C++ class // with pattern replacements { String ninputs_pat = compile_pattern("ninputs()"); String ninputs_repl = String(_ninputs[eindex]); String noutputs_pat = compile_pattern("noutputs()"); String noutputs_repl = String(_noutputs[eindex]); String push_pat = compile_pattern("output(#0).push(#1)"); String push_repl = "output_push(#0, #1)"; String checked_push_pat = compile_pattern("checked_output_push(#0, #1)"); String checked_push_repl = compile_pattern("output_push_checked(#0, #1)"); String pull_pat = compile_pattern("input(#0).pull()"); String pull_repl = "input_pull(#0)"; bool any_checked_push = false, any_push = false, any_pull = false; for (int i = 0; i < old_cxxc->nfunctions(); i++) if (old_cxxc->should_rewrite(i)) { const CxxFunction &old_fn = old_cxxc->function(i); if (new_cxxc->find(old_fn.name())) // don't add again continue; CxxFunction &new_fn = new_cxxc->defun(old_fn); while (new_fn.replace_expr(ninputs_pat, ninputs_repl)) ; while (new_fn.replace_expr(noutputs_pat, noutputs_repl)) ; while (new_fn.replace_expr(push_pat, push_repl)) any_push = true; while (new_fn.replace_expr(checked_push_pat, checked_push_repl)) any_checked_push = true; while (new_fn.replace_expr(pull_pat, pull_repl)) any_pull = true; } if (!any_push && !any_checked_push) new_cxxc->find("output_push")->kill(); if (!any_checked_push) new_cxxc->find("output_push_checked")->kill(); if (!any_pull) new_cxxc->find("input_pull")->kill(); } return true;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -