builtin,v: reduce overhead and memory usage for very frequently called methods (#21540)

This commit is contained in:
Delyan Angelov 2024-05-21 09:11:56 +03:00 committed by GitHub
parent 9997ac4367
commit 84fbe2728d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 70 additions and 41 deletions

View file

@ -212,38 +212,45 @@ fn (data &StrIntpData) process_str_intp_data(mut sb strings.Builder) {
unsafe {
// strings
if typ == .si_s {
mut s := ''
if upper_case {
s = data.d.d_s.to_upper()
s := data.d.d_s.to_upper()
if width == 0 {
sb.write_string(s)
} else {
strconv.format_str_sb(s, bf, mut sb)
}
s.free()
} else {
s = data.d.d_s.clone()
if width == 0 {
sb.write_string(data.d.d_s)
} else {
strconv.format_str_sb(data.d.d_s, bf, mut sb)
}
}
if width == 0 {
sb.write_string(s)
} else {
strconv.format_str_sb(s, bf, mut sb)
}
s.free()
return
}
if typ == .si_r {
if width > 0 {
mut s := ''
if upper_case {
s = data.d.d_s.to_upper()
s := data.d.d_s.to_upper()
for _ in 1 .. (1 + (if width > 0 {
width
} else {
0
})) {
sb.write_string(s)
}
s.free()
} else {
s = data.d.d_s.clone()
for _ in 1 .. (1 + (if width > 0 {
width
} else {
0
})) {
sb.write_string(data.d.d_s)
}
}
for _ in 1 .. (1 + (if width > 0 {
width
} else {
0
})) {
sb.write_string(s)
}
s.free()
}
return
}

View file

@ -65,11 +65,13 @@ pub fn (mut b Builder) clear() {
}
// write_u8 appends a single `data` byte to the accumulated buffer
@[inline]
pub fn (mut b Builder) write_u8(data u8) {
b << data
}
// write_byte appends a single `data` byte to the accumulated buffer
@[inline]
pub fn (mut b Builder) write_byte(data u8) {
b << data
}

View file

@ -676,9 +676,10 @@ pub fn (t &Table) sym_by_idx(idx int) &TypeSymbol {
return t.type_symbols[idx]
}
@[direct_array_access]
pub fn (t &Table) sym(typ Type) &TypeSymbol {
idx := typ.idx()
if idx > 0 {
if idx > 0 && idx < t.type_symbols.len {
return t.type_symbols[idx]
}
// this should never happen
@ -688,10 +689,10 @@ pub fn (t &Table) sym(typ Type) &TypeSymbol {
}
// final_sym follows aliases until it gets to a "real" Type
@[inline]
@[direct_array_access]
pub fn (t &Table) final_sym(typ Type) &TypeSymbol {
mut idx := typ.idx()
if idx > 0 {
if idx > 0 && idx < t.type_symbols.len {
cur_sym := t.type_symbols[idx]
if cur_sym.info is Alias {
idx = cur_sym.info.parent_type.idx()

View file

@ -312,7 +312,7 @@ pub fn (t Type) nr_muls() int {
pub fn (t Type) is_ptr() bool {
// any normal pointer, i.e. &Type, &&Type etc;
// Note: voidptr, charptr and byteptr are NOT included!
return (int(t) >> 16) & 0xff > 0
return (int(t) >> 16) & 0xff != 0
}
// is_pointer returns true if `typ` is any of the builtin pointer types (voidptr, byteptr, charptr)
@ -331,7 +331,7 @@ pub fn (typ Type) is_voidptr() bool {
// is_any_kind_of_pointer returns true if t is any type of pointer
@[inline]
pub fn (t Type) is_any_kind_of_pointer() bool {
return (int(t) >> 16) & 0xff > 0 || (u16(t) & 0xffff) in ast.pointer_type_idxs
return (int(t) >> 16) & 0xff != 0 || (u16(t) & 0xffff) in ast.pointer_type_idxs
}
// set nr_muls on `t` and return it
@ -398,7 +398,7 @@ pub fn (t Type) clear_option_and_result() Type {
// return true if `flag` is set on `t`
@[inline]
pub fn (t Type) has_flag(flag TypeFlag) bool {
return int(t) & (1 << (int(flag) + 24)) > 0
return int(t) & (1 << (int(flag) + 24)) != 0
}
@[inline]

View file

@ -1437,8 +1437,10 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
using_new_err_struct_save := c.using_new_err_struct
// TODO: remove; this avoids a breaking change in syntax
if '${node.expr}' == 'err' {
c.using_new_err_struct = true
if node.expr is ast.Ident {
if node.expr.str() == 'err' {
c.using_new_err_struct = true
}
}
// T.name, typeof(expr).name
@ -1545,7 +1547,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
return ast.u32_type
}
}
mut unknown_field_msg := 'type `${sym.name}` has no field named `${field_name}`'
mut unknown_field_msg := ''
mut has_field := false
mut field := ast.StructField{}
if field_name.len > 0 && field_name[0].is_capital() && sym.info is ast.Struct
@ -1698,6 +1700,9 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
c.error('`${unwrapped_sym.name}` has no property `${node.field_name}`', node.pos)
}
} else {
if unknown_field_msg == '' {
unknown_field_msg = 'type `${sym.name}` has no field named `${field_name}`'
}
if sym.info is ast.Struct {
if c.smartcast_mut_pos != token.Pos{} {
c.note('smartcasting requires either an immutable value, or an explicit mut keyword before the value',

View file

@ -2650,7 +2650,7 @@ fn cescape_nonascii(original string) string {
write_octal_escape(mut b, c)
continue
}
b.write_u8(c)
b << c
}
res := b.str()
return res

View file

@ -890,7 +890,7 @@ fn (mut g Gen) call_expr(node ast.CallExpr) {
}
}
if node.is_method && !node.is_field {
if node.name == 'writeln' && g.pref.experimental && node.args.len > 0
if g.pref.experimental && node.args.len > 0 && node.name == 'writeln'
&& node.args[0].expr is ast.StringInterLiteral
&& g.table.sym(node.receiver_type).name == 'strings.Builder' {
g.string_inter_literal_sb_optimized(node)

View file

@ -8,9 +8,13 @@ import v.util
fn (mut g Gen) string_literal(node ast.StringLiteral) {
escaped_val := cescape_nonascii(util.smart_quote(node.val, node.is_raw))
if node.language == .c {
g.write('"${escaped_val}"')
g.write('"')
g.write(escaped_val)
g.write('"')
} else {
g.write('_SLIT("${escaped_val}")')
g.write('_SLIT("')
g.write(escaped_val)
g.write('")')
}
}
@ -149,7 +153,8 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype ast.Type) {
g.write(') ? _SLIT("nil") : ')
}
}
g.write('${str_fn_name}(')
g.write(str_fn_name)
g.write('(')
if str_method_expects_ptr && !is_ptr {
if is_dump_expr || (g.pref.ccompiler_type != .tinyc && expr is ast.CallExpr) {
g.write('ADDR(${g.typ(typ)}, ')

View file

@ -261,14 +261,18 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
}
}
}
g.write(' str_intp(${node.vals.len}, ')
g.write(' str_intp(')
g.write(node.vals.len.str())
g.write(', ')
g.write('_MOV((StrIntpData[]){')
for i, val in node.vals {
mut escaped_val := cescape_nonascii(util.smart_quote(val, false))
escaped_val = escaped_val.replace('\0', '\\0')
if escaped_val.len > 0 {
g.write('{_SLIT("${escaped_val}"), ')
g.write('{_SLIT("')
g.write(escaped_val)
g.write('"), ')
} else {
g.write('{_SLIT0, ')
}
@ -280,7 +284,11 @@ fn (mut g Gen) string_inter_literal(node ast.StringInterLiteral) {
}
ft_u64, ft_str := g.str_format(node, i, fmts)
g.write('0x${ft_u64.hex()}, {.d_${ft_str} = ')
g.write('0x')
g.write(ft_u64.hex())
g.write(', {.d_')
g.write(ft_str)
g.write(' = ')
// for pointers we need a void* cast
if unsafe { ft_str.str[0] } == `p` {

View file

@ -16,7 +16,7 @@ import runtime
// math.bits is needed by strconv.ftoa
pub const builtin_module_parts = ['math.bits', 'strconv', 'dlmalloc', 'strconv.ftoa', 'strings',
'builtin']
pub const bundle_modules = ['clipboard', 'fontstash', 'gg', 'gx', 'sokol', 'szip', 'ui']
pub const bundle_modules = ['clipboard', 'fontstash', 'gg', 'gx', 'sokol', 'szip', 'ui']!
pub const external_module_dependencies_for_tool = {
'vdoc': ['markdown']
@ -34,7 +34,7 @@ const const_tabs = [
'\t\t\t\t\t\t\t\t',
'\t\t\t\t\t\t\t\t\t',
'\t\t\t\t\t\t\t\t\t\t',
]
]!
pub const nr_jobs = runtime.nr_jobs()
@ -42,8 +42,9 @@ pub fn module_is_builtin(mod string) bool {
return mod in util.builtin_module_parts
}
@[direct_array_access]
pub fn tabs(n int) string {
return if n < util.const_tabs.len { util.const_tabs[n] } else { '\t'.repeat(n) }
return if n >= 0 && n < util.const_tabs.len { util.const_tabs[n] } else { '\t'.repeat(n) }
}
//