Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cgen, scanner: reduce allocations for the most common cases #22142

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 12 additions & 10 deletions vlib/v/gen/c/cgen.v
Original file line number Diff line number Diff line change
Expand Up @@ -1820,31 +1820,33 @@ pub fn (mut g Gen) write_multi_return_types() {
g.type_definitions.writeln('// END_multi_return_structs\n')
}

@[inline]
fn prefix_with_counter(prefix string, counter int) string {
mut sb := strings.new_builder(prefix.len + 5)
sb.write_string(prefix)
sb.write_decimal(counter)
return sb.str()
}

pub fn (mut g Gen) new_tmp_var() string {
g.tmp_count++
return '_t${g.tmp_count}'
return prefix_with_counter('_t', g.tmp_count)
}

pub fn (mut g Gen) new_global_tmp_var() string {
g.global_tmp_count++
return '_t${g.global_tmp_count}'
return prefix_with_counter('_t', g.global_tmp_count)
}

pub fn (mut g Gen) new_tmp_declaration_name() string {
g.tmp_count_declarations++
return '_d${g.tmp_count_declarations}'
return prefix_with_counter('_d', g.tmp_count_declarations)
}

pub fn (mut g Gen) current_tmp_var() string {
return '_t${g.tmp_count}'
return prefix_with_counter('_t', g.tmp_count)
}

/*
pub fn (mut g Gen) new_tmp_var2() string {
g.tmp_count_af++
return '_tt$g.tmp_count_af'
}
*/
pub fn (mut g Gen) reset_tmp_count() {
g.tmp_count = 0
}
Expand Down
55 changes: 31 additions & 24 deletions vlib/v/scanner/scanner.v
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ pub mut:
warnings []errors.Warning
notices []errors.Notice
should_abort bool // when too many errors/warnings/notices are accumulated, should_abort becomes true, and the scanner should stop

// the following are used only inside ident_string, but are here to avoid allocating new arrays for the most common case of strings without escapes
all_pos []int
u16_escapes_pos []int // pos list of \uXXXX
u32_escapes_pos []int // pos list of \UXXXXXXXX
h_escapes_pos []int // pos list of \xXX
str_segments []string
}

/*
Expand Down Expand Up @@ -1231,9 +1238,9 @@ pub fn (mut s Scanner) ident_string() string {
s.inc_line_number()
}
s.is_inside_string = false
mut u16_escapes_pos := []int{} // pos list of \uXXXX
mut u32_escapes_pos := []int{} // pos list of \UXXXXXXXX
mut h_escapes_pos := []int{} // pos list of \xXX
s.u16_escapes_pos.clear()
s.u32_escapes_pos.clear()
s.h_escapes_pos.clear()
mut backslash_count := if start_char == scanner.backslash { 1 } else { 0 }
for {
s.pos++
Expand Down Expand Up @@ -1271,7 +1278,7 @@ pub fn (mut s Scanner) ident_string() string {
&& s.text[s.pos + 2].is_hex_digit()) {
s.error(r'`\x` used without two following hex digits')
}
h_escapes_pos << s.pos - 1
s.h_escapes_pos << s.pos - 1
}
// Escape `\u`
if c == `u` {
Expand All @@ -1281,7 +1288,7 @@ pub fn (mut s Scanner) ident_string() string {
|| !s.text[s.pos + 3].is_hex_digit() || !s.text[s.pos + 4].is_hex_digit() {
s.error(r'`\u` incomplete 16 bit unicode character value')
}
u16_escapes_pos << s.pos - 1
s.u16_escapes_pos << s.pos - 1
}
// Escape `\U`
if c == `U` {
Expand All @@ -1295,7 +1302,7 @@ pub fn (mut s Scanner) ident_string() string {
|| !s.text[s.pos + 7].is_hex_digit() || !s.text[s.pos + 8].is_hex_digit() {
s.error(r'`\U` incomplete 32 bit unicode character value')
}
u32_escapes_pos << s.pos - 1
s.u32_escapes_pos << s.pos - 1
}
// Unknown escape sequence
if !util.is_escape_sequence(c) && !c.is_digit() && c != `\n` {
Expand Down Expand Up @@ -1336,41 +1343,41 @@ pub fn (mut s Scanner) ident_string() string {
mut string_so_far := s.text[start..end]
if !s.is_fmt {
mut segment_idx := 0
mut str_segments := []string{}
if u16_escapes_pos.len + h_escapes_pos.len + u32_escapes_pos.len > 0 {
mut all_pos := []int{}
all_pos << u16_escapes_pos
all_pos << u32_escapes_pos
all_pos << h_escapes_pos
all_pos.sort()

for pos in all_pos {
str_segments << string_so_far[segment_idx..(pos - start)]
s.str_segments.clear()
if s.u16_escapes_pos.len + s.h_escapes_pos.len + s.u32_escapes_pos.len > 0 {
s.all_pos.clear()
s.all_pos << s.u16_escapes_pos
s.all_pos << s.u32_escapes_pos
s.all_pos << s.h_escapes_pos
s.all_pos.sort()

for pos in s.all_pos {
s.str_segments << string_so_far[segment_idx..(pos - start)]
segment_idx = pos - start

if pos in u16_escapes_pos {
if pos in s.u16_escapes_pos {
end_idx, segment := s.decode_u16_escape_single(string_so_far,
segment_idx)
str_segments << segment
s.str_segments << segment
segment_idx = end_idx
}
if pos in u32_escapes_pos {
if pos in s.u32_escapes_pos {
end_idx, segment := s.decode_u32_escape_single(string_so_far,
segment_idx)
str_segments << segment
s.str_segments << segment
segment_idx = end_idx
}
if pos in h_escapes_pos {
if pos in s.h_escapes_pos {
end_idx, segment := s.decode_h_escape_single(string_so_far, segment_idx)
str_segments << segment
s.str_segments << segment
segment_idx = end_idx
}
}
}
if segment_idx < string_so_far.len {
str_segments << string_so_far[segment_idx..]
s.str_segments << string_so_far[segment_idx..]
}
string_so_far = str_segments.join('')
string_so_far = s.str_segments.join('')
}

if n_cr_chars > 0 {
Expand Down
Loading