Regex: Ensure we dont have a thread explosion in ThreadedRegexVM

Always remove threads with lower priority that end up on the same
instruction as a higher priority thread (as we know they will behave
the same from now on)
This commit is contained in:
Maxime Coste 2017-10-02 16:24:38 +08:00
parent b4f923b7fc
commit 5b0c2cbdc2

View File

@ -167,7 +167,6 @@ struct ThreadedRegexVM
break; break;
} }
case CompiledRegex::Match: case CompiledRegex::Match:
thread.inst = nullptr;
return StepResult::Matched; return StepResult::Matched;
} }
} }
@ -186,13 +185,16 @@ struct ThreadedRegexVM
for (m_pos = Utf8It{m_begin, m_begin, m_end}; m_pos != m_end; ++m_pos) for (m_pos = Utf8It{m_begin, m_begin, m_end}; m_pos != m_end; ++m_pos)
{ {
for (int i = 0; i < m_threads.size(); ++i) for (int i = 0; i < m_threads.size(); )
{ {
const auto res = step(i); const auto res = step(i);
if (res == StepResult::Matched) if (res == StepResult::Matched)
{ {
if (match) if (match)
{
m_threads.erase(m_threads.begin() + i);
continue; // We are not at end, this is not a full match continue; // We are not at end, this is not a full match
}
m_captures = std::move(m_threads[i].saves); m_captures = std::move(m_threads[i].saves);
found_match = true; found_match = true;
@ -201,10 +203,19 @@ struct ThreadedRegexVM
return true; return true;
} }
else if (res == StepResult::Failed) else if (res == StepResult::Failed)
m_threads[i].inst = nullptr; m_threads.erase(m_threads.begin() + i);
else
{
auto it = m_threads.begin() + i;
if (std::find_if(m_threads.begin(), it, [inst = it->inst](auto& t)
{ return t.inst == inst; }) != it)
m_threads.erase(it);
else
++i;
} }
m_threads.erase(std::remove_if(m_threads.begin(), m_threads.end(), }
[](const Thread& t) { return t.inst == nullptr; }), m_threads.end()); // we should never have more than one thread on the same instruction
kak_assert(m_threads.size() <= m_program.bytecode.size());
if (m_threads.empty()) if (m_threads.empty())
return found_match; return found_match;
} }
@ -230,6 +241,7 @@ struct ThreadedRegexVM
if (std::find_if(m_threads.begin(), m_threads.end(), if (std::find_if(m_threads.begin(), m_threads.end(),
[inst](const Thread& t) { return t.inst == inst; }) == m_threads.end()) [inst](const Thread& t) { return t.inst == inst; }) == m_threads.end())
m_threads.insert(m_threads.begin() + index, {inst, std::move(saves)}); m_threads.insert(m_threads.begin() + index, {inst, std::move(saves)});
kak_assert(m_threads.size() < m_program.bytecode.size());
} }
bool is_line_start() const bool is_line_start() const