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

markused,builtin,strconv,vlib: reduce generated C sizes for compilers != tcc, for short programs, by simplifying the generation of backtraces, and reducing string interpolations in panics #23380

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
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
Loading