mirror of
https://github.com/rui314/mold.git
synced 2024-11-13 09:39:13 +03:00
[ELF] Make version script application faster
Instead of calling regex match multiple times, create a single regex and call regex match function only once. https://github.com/rui314/mold/issues/156
This commit is contained in:
parent
36633895e5
commit
455e729393
@ -255,9 +255,9 @@ static bool read_label(std::span<std::string_view> &tok,
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
static void read_version_script_commands(Context<E> &ctx,
|
||||
std::span<std::string_view> &tok,
|
||||
i16 &ver, bool is_extern_cpp) {
|
||||
static void
|
||||
read_version_script_commands(Context<E> &ctx, std::span<std::string_view> &tok,
|
||||
VersionPattern &pat, bool is_extern_cpp) {
|
||||
bool is_global = true;
|
||||
|
||||
while (!tok.empty() && tok[0] != "}") {
|
||||
@ -284,16 +284,19 @@ static void read_version_script_commands(Context<E> &ctx,
|
||||
}
|
||||
|
||||
tok = skip(ctx, tok, "{");
|
||||
read_version_script_commands(ctx, tok, ver, is_cpp);
|
||||
read_version_script_commands(ctx, tok, pat, is_cpp);
|
||||
tok = skip(ctx, tok, "}");
|
||||
tok = skip(ctx, tok, ";");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tok[0] == "*")
|
||||
ctx.arg.default_version = (is_global ? ver : VER_NDX_LOCAL);
|
||||
ctx.arg.default_version = (is_global ? pat.ver_idx : VER_NDX_LOCAL);
|
||||
else if (is_extern_cpp)
|
||||
pat.cpp_patterns.push_back(tok[0]);
|
||||
else
|
||||
ctx.arg.version_patterns.push_back({tok[0], ver, is_extern_cpp});
|
||||
pat.patterns.push_back(tok[0]);
|
||||
|
||||
tok = tok.subspan(1);
|
||||
|
||||
if (!tok.empty() && tok[0] == "}")
|
||||
@ -307,19 +310,24 @@ void read_version_script(Context<E> &ctx, std::span<std::string_view> &tok) {
|
||||
i16 next_ver = VER_NDX_LAST_RESERVED + 1;
|
||||
|
||||
while (!tok.empty() && tok[0] != "}") {
|
||||
i16 ver = VER_NDX_GLOBAL;
|
||||
if (tok[0] != "{") {
|
||||
ver = next_ver++;
|
||||
VersionPattern pat;
|
||||
|
||||
if (tok[0] == "{") {
|
||||
pat.ver_idx = VER_NDX_GLOBAL;
|
||||
} else {
|
||||
pat.ver_idx = next_ver++;
|
||||
ctx.arg.version_definitions.push_back(tok[0]);
|
||||
tok = tok.subspan(1);
|
||||
}
|
||||
|
||||
tok = skip(ctx, tok, "{");
|
||||
read_version_script_commands(ctx, tok, ver, false);
|
||||
read_version_script_commands(ctx, tok, pat, false);
|
||||
tok = skip(ctx, tok, "}");
|
||||
if (!tok.empty() && tok[0] != ";")
|
||||
tok = tok.subspan(1);
|
||||
tok = skip(ctx, tok, ";");
|
||||
|
||||
ctx.arg.version_patterns.push_back(pat);
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,10 +364,15 @@ void parse_dynamic_list(Context<E> &ctx, std::string path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tok[0] == "*")
|
||||
if (tok[0] == "*") {
|
||||
ctx.arg.default_version = ver;
|
||||
else
|
||||
ctx.arg.version_patterns.push_back({tok[0], ver, false});
|
||||
} else {
|
||||
VersionPattern pat;
|
||||
pat.ver_idx = ver;
|
||||
pat.patterns.push_back(tok[0]);
|
||||
ctx.arg.version_patterns.push_back(pat);
|
||||
}
|
||||
|
||||
tok = skip(ctx, tok.subspan(1), ";");
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
namespace mold::elf {
|
||||
|
||||
std::regex glob_to_regex(std::string_view pattern) {
|
||||
std::string glob_to_regex(std::string_view pattern) {
|
||||
std::stringstream ss;
|
||||
for (u8 c : pattern) {
|
||||
if (c == '*')
|
||||
@ -24,7 +24,7 @@ std::regex glob_to_regex(std::string_view pattern) {
|
||||
else
|
||||
ss << "\\x" << std::hex << std::setw(2) << std::setfill('0') << (int)c;
|
||||
}
|
||||
return std::regex(ss.str(), std::regex::optimize);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
|
@ -1156,9 +1156,9 @@ typedef enum { COMPRESS_NONE, COMPRESS_GABI, COMPRESS_GNU } CompressKind;
|
||||
typedef enum { ERROR, WARN, IGNORE } UnresolvedKind;
|
||||
|
||||
struct VersionPattern {
|
||||
std::string_view pattern;
|
||||
i16 ver_idx;
|
||||
bool is_extern_cpp;
|
||||
std::vector<std::string_view> patterns;
|
||||
std::vector<std::string_view> cpp_patterns;
|
||||
};
|
||||
|
||||
template <typename E, typename T>
|
||||
@ -1403,7 +1403,7 @@ MappedFile<Context<E>> *find_library(Context<E> &ctx, std::string path);
|
||||
template <typename E>
|
||||
void read_file(Context<E> &ctx, MappedFile<Context<E>> *mf);
|
||||
|
||||
std::regex glob_to_regex(std::string_view pat);
|
||||
std::string glob_to_regex(std::string_view pat);
|
||||
|
||||
int main(int argc, char **argv);
|
||||
|
||||
|
@ -589,26 +589,55 @@ template <typename E>
|
||||
void apply_version_script(Context<E> &ctx) {
|
||||
Timer t(ctx, "apply_version_script");
|
||||
|
||||
for (VersionPattern &elem : ctx.arg.version_patterns) {
|
||||
assert(elem.pattern != "*");
|
||||
auto to_regex = [](std::span<std::string_view> vec) -> std::string {
|
||||
switch (vec.size()) {
|
||||
case 0:
|
||||
return "";
|
||||
case 1:
|
||||
return glob_to_regex(vec[0]);
|
||||
default:
|
||||
std::string re = glob_to_regex(vec[0]);
|
||||
for (std::string_view s : vec.subspan(1))
|
||||
re += "|" + glob_to_regex(s);
|
||||
return re;
|
||||
}
|
||||
};
|
||||
|
||||
if (!elem.is_extern_cpp &&
|
||||
elem.pattern.find('*') == elem.pattern.npos) {
|
||||
Symbol<E> *sym = intern(ctx, elem.pattern);
|
||||
if (sym->file && !sym->file->is_dso)
|
||||
sym->ver_idx = elem.ver_idx;
|
||||
continue;
|
||||
for (VersionPattern &elem : ctx.arg.version_patterns) {
|
||||
std::vector<std::string_view> vec;
|
||||
|
||||
for (std::string_view pat : elem.patterns) {
|
||||
if (pat.find('*') == pat.npos) {
|
||||
Symbol<E> *sym = intern(ctx, pat);
|
||||
if (sym->file && !sym->file->is_dso)
|
||||
sym->ver_idx = elem.ver_idx;
|
||||
} else {
|
||||
vec.push_back(pat);
|
||||
}
|
||||
}
|
||||
|
||||
std::regex re = glob_to_regex(elem.pattern);
|
||||
if (vec.empty() && elem.cpp_patterns.empty())
|
||||
continue;
|
||||
|
||||
auto flags = std::regex_constants::optimize | std::regex_constants::nosubs;
|
||||
std::regex re(to_regex(vec), flags);
|
||||
std::regex cpp_re(to_regex(elem.cpp_patterns), flags);
|
||||
|
||||
tbb::parallel_for_each(ctx.objs, [&](ObjectFile<E> *file) {
|
||||
for (Symbol<E> *sym : file->get_global_syms()) {
|
||||
if (sym->file == file) {
|
||||
std::string_view name = sym->name();
|
||||
if (elem.is_extern_cpp)
|
||||
name = demangle(name);
|
||||
if (std::regex_match(name.begin(), name.end(), re))
|
||||
if (sym->file != file)
|
||||
continue;
|
||||
|
||||
std::string_view name = sym->name();
|
||||
|
||||
if (!vec.empty() && std::regex_match(name.begin(), name.end(), re)) {
|
||||
sym->ver_idx = elem.ver_idx;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!elem.cpp_patterns.empty()) {
|
||||
std::string_view s = demangle(name);
|
||||
if (std::regex_match(s.begin(), s.end(), cpp_re))
|
||||
sym->ver_idx = elem.ver_idx;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user