Skip to content

Commit

Permalink
markused,builtin,strconv,vlib: reduce generated C sizes for compilers…
Browse files Browse the repository at this point in the history
… != tcc, for short programs, by simplifying the generation of backtraces, and reducing string interpolations in panics (#23380)
  • Loading branch information
spytheman authored Jan 6, 2025
1 parent 738f847 commit e983d75
Show file tree
Hide file tree
Showing 31 changed files with 278 additions and 191 deletions.
42 changes: 25 additions & 17 deletions vlib/builtin/array.v
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,8 @@ fn (mut a array) ensure_cap(required int) {
return
}
if a.flags.has(.nogrow) {
panic('array.ensure_cap: array with the flag `.nogrow` cannot grow in size, array required new size: ${required}')
panic_n('array.ensure_cap: array with the flag `.nogrow` cannot grow in size, array required new size:',
required)
}
mut cap := if a.cap > 0 { i64(a.cap) } else { i64(2) }
for required > cap {
Expand All @@ -205,7 +206,8 @@ fn (mut a array) ensure_cap(required int) {
// limit the capacity, since bigger values, will overflow the 32bit integer used to store it
cap = max_int
} else {
panic('array.ensure_cap: array needs to grow to cap = ${cap}, which is > 2^31')
panic_n('array.ensure_cap: array needs to grow to cap (which is > 2^31):',
cap)
}
}
new_size := u64(cap) * u64(a.element_size)
Expand Down Expand Up @@ -240,7 +242,7 @@ pub fn (a array) repeat(count int) array {
@[direct_array_access; unsafe]
pub fn (a array) repeat_to_depth(count int, depth int) array {
if count < 0 {
panic('array.repeat: count is negative: ${count}')
panic_n('array.repeat: count is negative:', count)
}
mut size := u64(count) * u64(a.len) * u64(a.element_size)
if size == 0 {
Expand Down Expand Up @@ -293,7 +295,7 @@ pub fn (a array) repeat_to_depth(count int, depth int) array {
// ```
pub fn (mut a array) insert(i int, val voidptr) {
if i < 0 || i > a.len {
panic('array.insert: index out of range (i == ${i}, a.len == ${a.len})')
panic_n2('array.insert: index out of range (i,a.len):', i, a.len)
}
if a.len == max_int {
panic('array.insert: a.len reached max_int')
Expand All @@ -313,11 +315,11 @@ pub fn (mut a array) insert(i int, val voidptr) {
@[unsafe]
fn (mut a array) insert_many(i int, val voidptr, size int) {
if i < 0 || i > a.len {
panic('array.insert_many: index out of range (i == ${i}, a.len == ${a.len})')
panic_n2('array.insert_many: index out of range (i,a.len):', i, a.len)
}
new_len := i64(a.len) + i64(size)
if new_len > max_int {
panic('array.insert_many: a.len = ${new_len} will exceed max_int')
panic_n('array.insert_many: max_int will be exceeded by a.len:', new_len)
}
a.ensure_cap(int(new_len))
elem_size := a.element_size
Expand Down Expand Up @@ -374,8 +376,12 @@ pub fn (mut a array) delete(i int) {
// ```
pub fn (mut a array) delete_many(i int, size int) {
if i < 0 || i64(i) + i64(size) > i64(a.len) {
endidx := if size > 1 { '..${i + size}' } else { '' }
panic('array.delete: index out of range (i == ${i}${endidx}, a.len == ${a.len})')
if size > 1 {
panic_n3('array.delete: index out of range (i,i+size,a.len):', i, i + size,
a.len)
} else {
panic_n2('array.delete: index out of range (i,a.len):', i, a.len)
}
}
if a.flags.all(.noshrink | .noslices) {
unsafe {
Expand Down Expand Up @@ -465,7 +471,7 @@ fn (a array) get_unsafe(i int) voidptr {
fn (a array) get(i int) voidptr {
$if !no_bounds_checking {
if i < 0 || i >= a.len {
panic('array.get: index out of range (i == ${i}, a.len == ${a.len})')
panic_n2('array.get: index out of range (i,a.len):', i, a.len)
}
}
unsafe {
Expand Down Expand Up @@ -557,13 +563,15 @@ fn (a array) slice(start int, _end int) array {
end := if _end == max_int { a.len } else { _end } // max_int
$if !no_bounds_checking {
if start > end {
panic('array.slice: invalid slice index (${start} > ${end})')
panic('array.slice: invalid slice index (start>end):' + i64(start).str() + ', ' +
i64(end).str())
}
if end > a.len {
panic('array.slice: slice bounds out of range (${end} >= ${a.len})')
panic('array.slice: slice bounds out of range (' + i64(end).str() + ' >= ' +
i64(a.len).str() + ')')
}
if start < 0 {
panic('array.slice: slice bounds out of range (${start} < 0)')
panic('array.slice: slice bounds out of range (start<0):' + start.str())
}
}
// TODO: integrate reference counting
Expand Down Expand Up @@ -683,7 +691,7 @@ fn (mut a array) set_unsafe(i int, val voidptr) {
fn (mut a array) set(i int, val voidptr) {
$if !no_bounds_checking {
if i < 0 || i >= a.len {
panic('array.set: index out of range (i == ${i}, a.len == ${a.len})')
panic_n2('array.set: index out of range (i,a.len):', i, a.len)
}
}
unsafe { vmemcpy(&u8(a.data) + u64(a.element_size) * u64(i), val, a.element_size) }
Expand Down Expand Up @@ -1000,7 +1008,7 @@ pub fn copy(mut dst []u8, src []u8) int {
pub fn (mut a array) grow_cap(amount int) {
new_cap := i64(amount) + i64(a.cap)
if new_cap > max_int {
panic('array.grow_cap: new capacity ${new_cap} will exceed max_int')
panic_n('array.grow_cap: max_int will be exceeded by new cap:', new_cap)
}
a.ensure_cap(int(new_cap))
}
Expand All @@ -1013,7 +1021,7 @@ pub fn (mut a array) grow_cap(amount int) {
pub fn (mut a array) grow_len(amount int) {
new_len := i64(amount) + i64(a.len)
if new_len > max_int {
panic('array.grow_len: new len ${new_len} will exceed max_int')
panic_n('array.grow_len: max_int will be exceeded by new len:', new_len)
}
a.ensure_cap(int(new_len))
a.len = int(new_len)
Expand Down Expand Up @@ -1053,13 +1061,13 @@ pub fn (data &u8) vbytes(len int) []u8 {
@[if !no_bounds_checking ?; inline]
fn panic_on_negative_len(len int) {
if len < 0 {
panic('negative .len')
panic_n('negative .len:', len)
}
}

@[if !no_bounds_checking ?; inline]
fn panic_on_negative_cap(cap int) {
if cap < 0 {
panic('negative .cap')
panic_n('negative .cap:', cap)
}
}
18 changes: 10 additions & 8 deletions vlib/builtin/array_d_gcboehm_opt.v
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ fn (mut a array) ensure_cap_noscan(required int) {
return
}
if a.flags.has(.nogrow) {
panic('array.ensure_cap_noscan: array with the flag `.nogrow` cannot grow in size, array required new size: ${required}')
panic_n('array.ensure_cap_noscan: array with the flag `.nogrow` cannot grow in size, array required new size:',
required)
}
mut cap := if a.cap > 0 { i64(a.cap) } else { i64(2) }
for required > cap {
Expand All @@ -114,7 +115,8 @@ fn (mut a array) ensure_cap_noscan(required int) {
// limit the capacity, since bigger values, will overflow the 32bit integer used to store it
cap = max_int
} else {
panic('array.ensure_cap_noscan: array needs to grow to cap = ${cap}, which is > 2^31')
panic_n('array.ensure_cap_noscan: array needs to grow to cap (which is > 2^31):',
cap)
}
}
new_size := u64(cap) * u64(a.element_size)
Expand All @@ -136,7 +138,7 @@ fn (mut a array) ensure_cap_noscan(required int) {
@[unsafe]
fn (a array) repeat_to_depth_noscan(count int, depth int) array {
if count < 0 {
panic('array.repeat: count is negative: ${count}')
panic_n('array.repeat: count is negative:', count)
}
mut size := u64(count) * u64(a.len) * u64(a.element_size)
if size == 0 {
Expand Down Expand Up @@ -170,7 +172,7 @@ fn (a array) repeat_to_depth_noscan(count int, depth int) array {
// insert inserts a value in the array at index `i`
fn (mut a array) insert_noscan(i int, val voidptr) {
if i < 0 || i > a.len {
panic('array.insert_noscan: index out of range (i == ${i}, a.len == ${a.len})')
panic_n2('array.insert_noscan: index out of range (i,a.len):', i, a.len)
}
if a.len == max_int {
panic('array.insert_noscan: a.len reached max_int')
Expand All @@ -187,11 +189,11 @@ fn (mut a array) insert_noscan(i int, val voidptr) {
@[unsafe]
fn (mut a array) insert_many_noscan(i int, val voidptr, size int) {
if i < 0 || i > a.len {
panic('array.insert_many: index out of range (i == ${i}, a.len == ${a.len})')
panic_n2('array.insert_many: index out of range (i, a.len):', i, a.len)
}
new_len := i64(a.len) + i64(size)
if new_len > max_int {
panic('array.insert_many_noscan: a.len = ${new_len} will exceed max_int')
panic_n('array.insert_many_noscan: max_int will be exceeded by a.len:', new_len)
}
a.ensure_cap_noscan(a.len + size)
elem_size := a.element_size
Expand Down Expand Up @@ -328,7 +330,7 @@ fn (a array) reverse_noscan() array {
fn (mut a array) grow_cap_noscan(amount int) {
new_cap := i64(amount) + i64(a.cap)
if new_cap > max_int {
panic('array.grow_cap: new capacity ${new_cap} will exceed max_int')
panic_n('array.grow_cap: max_int will be exceeded by new cap:', new_cap)
}
a.ensure_cap_noscan(int(new_cap))
}
Expand All @@ -338,7 +340,7 @@ fn (mut a array) grow_cap_noscan(amount int) {
fn (mut a array) grow_len_noscan(amount int) {
new_len := i64(amount) + i64(a.len)
if new_len > max_int {
panic('array.grow_len: new len ${new_len} will exceed max_int')
panic_n('array.grow_len: max_int will be exceeded by new len:', new_len)
}
a.ensure_cap_noscan(int(new_len))
a.len = int(new_len)
Expand Down
29 changes: 17 additions & 12 deletions vlib/builtin/backtraces.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,24 @@ pub fn print_backtrace() {
$if !no_backtrace ? {
$if freestanding {
println(bare_backtrace())
} $else $if native {
// TODO: native backtrace solution
} $else $if tinyc {
C.tcc_backtrace(c'Backtrace')
} $else $if use_libbacktrace ? {
// NOTE: TCC doesn't have the unwind library
print_libbacktrace(1)
} $else {
$if native {
// TODO: native backtrace solution
} $else $if tinyc {
C.tcc_backtrace(c'Backtrace')
} $else {
// NOTE: TCC doesn't have the unwind library
$if use_libbacktrace ? {
print_libbacktrace(1)
} $else {
print_backtrace_skipping_top_frames(2)
}
}
print_backtrace_skipping_top_frames(2)
}
}
}

fn eprint_space_padding(output string, max_len int) {
padding_len := max_len - output.len
if padding_len > 0 {
for _ in 0 .. padding_len {
eprint(' ')
}
}
}
18 changes: 10 additions & 8 deletions vlib/builtin/backtraces_nix.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -67,17 +67,14 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
return false
}
nr_actual_frames := nr_ptrs - skipframes
mut sframes := []string{}
//////csymbols := backtrace_symbols(*voidptr(&buffer[skipframes]), nr_actual_frames)
csymbols := C.backtrace_symbols(voidptr(&buffer[skipframes]), nr_actual_frames)
for i in 0 .. nr_actual_frames {
sframes << unsafe { tos2(&u8(csymbols[i])) }
}
for sframe in sframes {
sframe := unsafe { tos2(&u8(csymbols[i])) }
executable := sframe.all_before('(')
addr := sframe.all_after('[').all_before(']')
beforeaddr := sframe.all_before('[')
cmd := 'addr2line -e ${executable} ${addr}'
cmd := 'addr2line -e ' + executable + ' ' + addr
// taken from os, to avoid depending on the os module inside builtin.v
f := C.popen(&char(cmd.str), c'r')
if f == unsafe { nil } {
Expand All @@ -92,7 +89,7 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
output += tos(bp, vstrlen(bp))
}
}
output = output.trim_space() + ':'
output = output.trim_chars(' \t\n', .trim_both) + ':'
if C.pclose(f) != 0 {
eprintln(sframe)
continue
Expand All @@ -104,9 +101,14 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
// Note: it is shortened here to just d. , just so that it fits, and so
// that the common error file:lineno: line format is enforced.
output = output.replace(' (discriminator', ': (d.')
eprintln('${output:-55s} | ${addr:14s} | ${beforeaddr}')
eprint(output)
eprint_space_padding(output, 55)
eprint(' | ')
eprint(addr)
eprint(' | ')
eprintln(beforeaddr)
}
if sframes.len > 0 {
if nr_actual_frames > 0 {
unsafe { C.free(csymbols) }
}
}
Expand Down
21 changes: 15 additions & 6 deletions vlib/builtin/backtraces_windows.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ pub fn print_backtrace_skipping_top_frames(skipframes int) bool {
return false
}

@[direct_array_access]
fn print_backtrace_skipping_top_frames_msvc(skipframes int) bool {
$if msvc {
mut offset := u64(0)
Expand Down Expand Up @@ -116,23 +117,31 @@ fn print_backtrace_skipping_top_frames_msvc(skipframes int) bool {
if C.SymGetLineFromAddr64(handle, frame_addr, &offset, &sline64) == 1 {
file_name := unsafe { tos3(sline64.f_file_name) }
lnumber := sline64.f_line_number
lineinfo = '${file_name}:${lnumber}'
lineinfo = file_name + i64(lnumber).str()
} else {
// addr:
lineinfo = '?? : address = 0x${(&frame_addr):x}'
lineinfo = '?? : address = 0x' + ptr_str(frame_addr)
}
sfunc := unsafe { tos3(fname) }
eprintln('${nframe:-2d}: ${sfunc:-25s} ${lineinfo}')
snframe := i64(nframe).str()
eprint_space_padding(snframe, 2)
eprint(': ')
eprint(sfunc)
eprint_space_padding(sfunc, 25)
eprint(' ')
eprint(lineinfo)
} else {
// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes
cerr := int(C.GetLastError())
eprint('SymFromAddr failure: ')
eprint(i64(cerr).str())
if cerr == 87 {
eprintln('SymFromAddr failure: ${cerr} = The parameter is incorrect)')
eprintln(' = The parameter is incorrect)')
} else if cerr == 487 {
// probably caused because the .pdb isn't in the executable folder
eprintln('SymFromAddr failure: ${cerr} = Attempt to access invalid address (Verify that you have the .pdb file in the right folder.)')
eprintln(' = Attempt to access invalid address (Verify that you have the .pdb file in the right folder.)')
} else {
eprintln('SymFromAddr failure: ${cerr} (see https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes)')
eprintln(' (see https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes)')
}
}
}
Expand Down
26 changes: 22 additions & 4 deletions vlib/builtin/builtin.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,14 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
// It ends the program with a panic.
@[noreturn]
pub fn panic_option_not_set(s string) {
panic('option not set (${s})')
panic('option not set (' + s + ')')
}

// panic_result_not_set is called by V, when you use result error propagation in your main function
// It ends the program with a panic.
@[noreturn]
pub fn panic_result_not_set(s string) {
panic('result not set (${s})')
panic('result not set (' + s + ')')
}

// panic prints a nice error message, then exits the process with exit code of 1.
Expand Down Expand Up @@ -175,6 +175,24 @@ pub fn c_error_number_str(errnum int) string {
return err_msg
}

// panic_n prints an error message, followed by the given number, then exits the process with exit code of 1.
@[noreturn]
pub fn panic_n(s string, number1 i64) {
panic(s + number1.str())
}

// panic_n2 prints an error message, followed by the given numbers, then exits the process with exit code of 1.
@[noreturn]
pub fn panic_n2(s string, number1 i64, number2 i64) {
panic(s + number1.str() + ', ' + number2.str())
}

// panic_n3 prints an error message, followed by the given numbers, then exits the process with exit code of 1.
@[noreturn]
fn panic_n3(s string, number1 i64, number2 i64, number3 i64) {
panic(s + number1.str() + ', ' + number2.str() + ', ' + number2.str())
}

// panic with a C-API error message matching `errnum`
@[noreturn]
pub fn panic_error_number(basestr string, errnum int) {
Expand Down Expand Up @@ -751,8 +769,8 @@ pub fn gc_memory_use() usize {
fn v_fixed_index(i int, len int) int {
$if !no_bounds_checking {
if i < 0 || i >= len {
s := 'fixed array index out of range (index: ${i}, len: ${len})'
panic(s)
panic('fixed array index out of range (index: ' + i64(i).str() + ', len: ' +
i64(len).str() + ')')
}
}
return i
Expand Down
Loading

0 comments on commit e983d75

Please sign in to comment.