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 10 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
20 changes: 8 additions & 12 deletions vlib/builtin/backtraces.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,15 @@ 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)
}
}
}
27 changes: 19 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,13 +101,27 @@ 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) }
}
}
}
}
return true
}

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(' ')
}
}
}
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 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 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 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
8 changes: 1 addition & 7 deletions vlib/builtin/builtin.v
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,6 @@ pub fn isnil(v voidptr) bool {
return v == 0
}

/*
fn on_panic(f fn(int)int) {
// TODO
}
*/

struct VCastTypeIndexName {
tindex int
tname string
Expand All @@ -37,7 +31,7 @@ fn __as_cast(obj voidptr, obj_type int, expected_type int) voidptr {
expected_name = x.tname.clone()
}
}
panic('as cast: cannot cast `${obj_name}` to `${expected_name}`')
panic('as cast: cannot cast `' + obj_name + '` to `' + expected_name + '`')
}
return obj
}
Expand Down
5 changes: 4 additions & 1 deletion vlib/builtin/builtin_windows.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ fn builtin_init() {
$if !no_backtrace ? {
add_unhandled_exception_handler()
}
// On windows, the default buffering is block based (~4096bytes), which interferes badly with non cmd shells
// It is much better to have it off by default instead.
unbuffer_stdout()
}

// TODO: copypaste from os
Expand Down Expand Up @@ -109,7 +112,7 @@ fn unhandled_exception_handler(e &ExceptionPointers) int {
return 0
}
else {
println('Unhandled Exception 0x${e.exception_record.code:X}')
println('Unhandled Exception 0x' + ptr_str(e.exception_record.code))
print_backtrace_skipping_top_frames(5)
}
}
Expand Down
Loading
Loading