mirror of
https://github.com/RGBCube/serenity
synced 2025-05-30 21:28:11 +00:00
LibJS: Make Error stack trace generation faster with a line break cache
Generating Error objects got a lot slower after the introduction of
SourceCode in b0b022507b
.
This was noticeable with `test-js` which generates a lot of errors,
so walking the source code over and over to compute (line, column)
was eating a ton of time.
This patch makes repeated lookups a lot faster by building a cache
of line break offsets in the source code. The cache is built on first
offset lookup, so we only pay for this in code that actually throws.
On my machine, this takes `test-js` runtime from 6.7 sec to 4.3 sec.
This commit is contained in:
parent
e7ba03ddd1
commit
f0482b61bf
2 changed files with 43 additions and 3 deletions
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/BinarySearch.h>
|
||||
#include <AK/Utf8View.h>
|
||||
#include <LibJS/SourceCode.h>
|
||||
#include <LibJS/SourceRange.h>
|
||||
|
@ -32,18 +33,52 @@ String const& SourceCode::code() const
|
|||
return m_code;
|
||||
}
|
||||
|
||||
void SourceCode::compute_line_break_offsets() const
|
||||
{
|
||||
m_line_break_offsets = Vector<size_t> {};
|
||||
|
||||
if (m_code.is_empty())
|
||||
return;
|
||||
|
||||
bool previous_code_point_was_carriage_return = false;
|
||||
Utf8View view(m_code.view());
|
||||
for (auto it = view.begin(); it != view.end(); ++it) {
|
||||
u32 code_point = *it;
|
||||
bool is_line_terminator = code_point == '\r' || (code_point == '\n' && !previous_code_point_was_carriage_return) || code_point == LINE_SEPARATOR || code_point == PARAGRAPH_SEPARATOR;
|
||||
previous_code_point_was_carriage_return = code_point == '\r';
|
||||
|
||||
if (is_line_terminator)
|
||||
m_line_break_offsets->append(view.byte_offset_of(it));
|
||||
}
|
||||
}
|
||||
|
||||
SourceRange SourceCode::range_from_offsets(u32 start_offset, u32 end_offset) const
|
||||
{
|
||||
if (m_code.is_empty())
|
||||
return { *this, {}, {} };
|
||||
|
||||
if (!m_line_break_offsets.has_value())
|
||||
compute_line_break_offsets();
|
||||
|
||||
size_t line = 1;
|
||||
size_t nearest_line_break_index = 0;
|
||||
size_t nearest_preceding_line_break_offset = 0;
|
||||
|
||||
if (!m_line_break_offsets->is_empty()) {
|
||||
binary_search(*m_line_break_offsets, start_offset, &nearest_line_break_index);
|
||||
line = 1 + nearest_line_break_index;
|
||||
nearest_preceding_line_break_offset = (*m_line_break_offsets)[nearest_line_break_index];
|
||||
}
|
||||
|
||||
Position start;
|
||||
Position end;
|
||||
|
||||
size_t line = 1;
|
||||
size_t column = 1;
|
||||
|
||||
bool previous_code_point_was_carriage_return = false;
|
||||
|
||||
Utf8View view(m_code);
|
||||
for (auto it = view.begin(); it != view.end(); ++it) {
|
||||
Utf8View view(m_code.view());
|
||||
for (auto it = view.iterator_at_byte_offset_without_validation(nearest_preceding_line_break_offset); it != view.end(); ++it) {
|
||||
|
||||
if (start_offset == view.byte_offset_of(it)) {
|
||||
start = Position {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue