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
  • Loading branch information
spytheman committed Jan 5, 2025
1 parent af1ef92 commit 3ea7622
Show file tree
Hide file tree
Showing 26 changed files with 110 additions and 119 deletions.
40 changes: 23 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,13 @@ 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_n2('array.slice: invalid slice index (start>end):', start, end)
}
if end > a.len {
panic('array.slice: slice bounds out of range (${end} >= ${a.len})')
panic_n2('array.slice: slice bounds out of range (end>=a.len):', end, a.len)
}
if start < 0 {
panic('array.slice: slice bounds out of range (${start} < 0)')
panic_n('array.slice: slice bounds out of range (start<0):', start)
}
}
// TODO: integrate reference counting
Expand Down Expand Up @@ -683,7 +689,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 +1006,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 +1019,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 +1059,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)
}
}
}
18 changes: 16 additions & 2 deletions vlib/builtin/backtraces_nix.c.v
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
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 @@ -104,7 +104,12 @@ 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 {
unsafe { C.free(csymbols) }
Expand All @@ -114,3 +119,12 @@ fn print_backtrace_skipping_top_frames_linux(skipframes int) bool {
}
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(' ')
}
}
}
22 changes: 18 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,21 @@ pub fn c_error_number_str(errnum int) string {
return err_msg
}

@[noreturn]
pub fn panic_n(s string, number1 i64) {
panic(s + number1.str())
}

@[noreturn]
pub fn panic_n2(s string, number1 i64, number2 i64) {
panic(s + number1.str() + ', ' + number2.str())
}

@[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 +766,7 @@ 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_n2('fixed array index out of range (index, len):', i, len)
}
}
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
3 changes: 3 additions & 0 deletions 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
Loading

0 comments on commit 3ea7622

Please sign in to comment.