freestanding: small fixes (#9760)
parent
cb70ffef59
commit
0a1d0e062d
|
@ -31,42 +31,51 @@ see also `v help build`.
|
||||||
-bare-builtin-dir <bare-builtin-dir>
|
-bare-builtin-dir <bare-builtin-dir>
|
||||||
Use with `-freestanding`. This specifies the directory to the
|
Use with `-freestanding`. This specifies the directory to the
|
||||||
implementation of some basic builtin functions. The list is as follows:
|
implementation of some basic builtin functions. The list is as follows:
|
||||||
memcpy(dest &byte, src &byte, n int) &byte
|
|
||||||
Moves n bytes from dest to src, and returns dest
|
|
||||||
[export: 'malloc']
|
|
||||||
__malloc(n int) &byte
|
|
||||||
Allocates n bytes of memory and returns the pointer to the first byte
|
|
||||||
strlen(s &byte) int
|
|
||||||
Returns the amount of bytes until the first `0`, starting at s
|
|
||||||
realloc(old_area &byte, new_size int) &byte
|
|
||||||
Allocates a new area of size new_size, copies old_area
|
|
||||||
to the new area, and returns a pointer to the new area.
|
|
||||||
memset(s &byte, c int, n int) &byte
|
|
||||||
Sets n bytes starting at s to c (c is casted to a char)
|
|
||||||
and returns s.
|
|
||||||
memmove(dest &byte, src &byte, n int) &byte
|
|
||||||
Like memcpy, but guaranteed to work if dest and src overlap.
|
|
||||||
[export: 'calloc']
|
|
||||||
__calloc(nmemb int, size int) &byte
|
|
||||||
Like malloc, but sets all the bytes to `0` first.
|
|
||||||
getchar() int
|
|
||||||
Read one character from stdin and return it.
|
|
||||||
memcmp(a &byte, b &byte, n int) int
|
|
||||||
Compare two buffers of length n. If a and b are equal, return 0.
|
|
||||||
Otherwise, return the difference between the first different letter.
|
|
||||||
[export: 'free']
|
|
||||||
__free(ptr &byte)
|
|
||||||
Free the block of memory ptr allocated by malloc.
|
|
||||||
vsprintf(str &char, format &char, ap va_list) int
|
|
||||||
See `man vsprintf`.
|
|
||||||
vsnprintf(str &char, size int, format &char, ap va_list) int
|
|
||||||
See `man vsnprintf`.
|
|
||||||
bare_print(buf &byte, len u64)
|
bare_print(buf &byte, len u64)
|
||||||
Print len charecters from the buffer pointed to by buf to stdout.
|
Print len charecters from the buffer pointed to by buf to stdout.
|
||||||
bare_eprint(buf &byte, len u64)
|
bare_eprint(buf &byte, len u64)
|
||||||
Print len charecters from the buffer pointed to by buf to stderr.
|
Print len charecters from the buffer pointed to by buf to stderr.
|
||||||
|
bare_panic(msg string)
|
||||||
|
Print "V panic: " + msg, along with an optional backtrace and/or the V commit hash, and then exit.
|
||||||
|
[export: 'malloc']
|
||||||
|
__malloc(n size_t) &C.void
|
||||||
|
Allocates n bytes of memory and returns the pointer to the first byte
|
||||||
|
[export: 'free']
|
||||||
|
__free(ptr &C.void)
|
||||||
|
Free the block of memory ptr allocated by malloc.
|
||||||
|
realloc(old_area &C.void, new_size size_t) &C.void
|
||||||
|
Allocates a new area of size new_size, copies old_area
|
||||||
|
to the new area, and returns a pointer to the new area.
|
||||||
|
[export: 'calloc']
|
||||||
|
__calloc(nmemb size_t, size size_t) &C.void
|
||||||
|
Like malloc, but sets all the bytes to `0` first.
|
||||||
|
memcpy(dest &C.void, src &C.void, n size_t) &C.void
|
||||||
|
Moves n bytes from dest to src, and returns dest
|
||||||
|
memmove(dest &C.void, src &C.void, n size_t) &C.void
|
||||||
|
Like memcpy, but guaranteed to work if dest and src overlap.
|
||||||
|
memcmp(a &C.void, b &C.void, n size_t) int
|
||||||
|
Compare two buffers of length n. If a and b are equal, return 0.
|
||||||
|
Otherwise, return the difference between the first different letter.
|
||||||
|
strlen(s &C.void) size_t
|
||||||
|
Returns the amount of bytes until the first `0`, starting at s
|
||||||
|
memset(s &C.void, c int, n size_t) &C.void
|
||||||
|
Sets n bytes starting at s to c (c is casted to a char)
|
||||||
|
and returns s.
|
||||||
|
getchar() int
|
||||||
|
Read one character from stdin and return it.
|
||||||
|
Print "V Panic" + msg, along with an optional backtrace, and then exit.
|
||||||
|
vsprintf(str &char, format &char, ap va_list) int
|
||||||
|
See `man vsprintf`.
|
||||||
|
vsnprintf(str &char, size size_t, format &char, ap va_list) int
|
||||||
|
See `man vsnprintf`.
|
||||||
|
bare_backtrace() string
|
||||||
|
Return a backtrace that can be printed. If backtraces are not
|
||||||
|
supported, return a message stating that backtraces do not work.
|
||||||
|
[export: 'exit']
|
||||||
|
__exit(code int)
|
||||||
|
Exit with code code. code is allowed to be ignored.
|
||||||
|
|
||||||
The module decleration should be `builtin`. The default linux
|
The module decleration should be `builtin`. The default Linux
|
||||||
implementation can be found in `vlib/builtin/linux_bare`.
|
implementation can be found in `vlib/builtin/linux_bare`.
|
||||||
|
|
||||||
-os <os>, -target-os <os>
|
-os <os>, -target-os <os>
|
||||||
|
|
|
@ -22,7 +22,9 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
|
||||||
// module is less likely to change than function, etc...
|
// module is less likely to change than function, etc...
|
||||||
// During edits, the line number will change most frequently,
|
// During edits, the line number will change most frequently,
|
||||||
// so it is last
|
// so it is last
|
||||||
$if !freestanding {
|
$if freestanding {
|
||||||
|
bare_panic(s)
|
||||||
|
} $else {
|
||||||
eprintln('================ V panic ================')
|
eprintln('================ V panic ================')
|
||||||
eprintln(' module: $mod')
|
eprintln(' module: $mod')
|
||||||
eprintln(' function: ${fn_name}()')
|
eprintln(' function: ${fn_name}()')
|
||||||
|
@ -30,31 +32,26 @@ fn panic_debug(line_no int, file string, mod string, fn_name string, s string) {
|
||||||
eprintln(' file: $file:$line_no')
|
eprintln(' file: $file:$line_no')
|
||||||
eprintln(' v hash: $vcommithash()')
|
eprintln(' v hash: $vcommithash()')
|
||||||
eprintln('=========================================')
|
eprintln('=========================================')
|
||||||
} $else {
|
$if exit_after_panic_message ? {
|
||||||
eprint('V panic: ')
|
|
||||||
eprintln(s)
|
|
||||||
}
|
|
||||||
$if exit_after_panic_message ? {
|
|
||||||
C.exit(1)
|
|
||||||
} $else {
|
|
||||||
$if no_backtrace ? {
|
|
||||||
C.exit(1)
|
C.exit(1)
|
||||||
} $else {
|
} $else {
|
||||||
$if tinyc {
|
$if no_backtrace ? {
|
||||||
|
C.exit(1)
|
||||||
|
} $else {
|
||||||
|
$if tinyc {
|
||||||
|
$if panics_break_into_debugger ? {
|
||||||
|
break_if_debugger_attached()
|
||||||
|
} $else {
|
||||||
|
C.tcc_backtrace(c'Backtrace')
|
||||||
|
}
|
||||||
|
C.exit(1)
|
||||||
|
}
|
||||||
|
print_backtrace_skipping_top_frames(1)
|
||||||
$if panics_break_into_debugger ? {
|
$if panics_break_into_debugger ? {
|
||||||
break_if_debugger_attached()
|
break_if_debugger_attached()
|
||||||
} $else {
|
|
||||||
C.tcc_backtrace(c'Backtrace')
|
|
||||||
}
|
}
|
||||||
C.exit(1)
|
C.exit(1)
|
||||||
}
|
}
|
||||||
$if !freestanding {
|
|
||||||
print_backtrace_skipping_top_frames(1)
|
|
||||||
}
|
|
||||||
$if panics_break_into_debugger ? {
|
|
||||||
break_if_debugger_attached()
|
|
||||||
}
|
|
||||||
C.exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,30 +63,32 @@ pub fn panic_optional_not_set(s string) {
|
||||||
// panic prints a nice error message, then exits the process with exit code of 1.
|
// panic prints a nice error message, then exits the process with exit code of 1.
|
||||||
// It also shows a backtrace on most platforms.
|
// It also shows a backtrace on most platforms.
|
||||||
pub fn panic(s string) {
|
pub fn panic(s string) {
|
||||||
eprint('V panic: ')
|
$if freestanding {
|
||||||
eprintln(s)
|
bare_panic(s)
|
||||||
eprintln('v hash: $vcommithash()')
|
|
||||||
$if exit_after_panic_message ? {
|
|
||||||
C.exit(1)
|
|
||||||
} $else {
|
} $else {
|
||||||
$if no_backtrace ? {
|
eprint('V panic: ')
|
||||||
|
eprintln(s)
|
||||||
|
eprintln('v hash: $vcommithash()')
|
||||||
|
$if exit_after_panic_message ? {
|
||||||
C.exit(1)
|
C.exit(1)
|
||||||
} $else {
|
} $else {
|
||||||
$if tinyc {
|
$if no_backtrace ? {
|
||||||
|
C.exit(1)
|
||||||
|
} $else {
|
||||||
|
$if tinyc {
|
||||||
|
$if panics_break_into_debugger ? {
|
||||||
|
break_if_debugger_attached()
|
||||||
|
} $else {
|
||||||
|
C.tcc_backtrace(c'Backtrace')
|
||||||
|
}
|
||||||
|
C.exit(1)
|
||||||
|
}
|
||||||
|
print_backtrace_skipping_top_frames(1)
|
||||||
$if panics_break_into_debugger ? {
|
$if panics_break_into_debugger ? {
|
||||||
break_if_debugger_attached()
|
break_if_debugger_attached()
|
||||||
} $else {
|
|
||||||
C.tcc_backtrace(c'Backtrace')
|
|
||||||
}
|
}
|
||||||
C.exit(1)
|
C.exit(1)
|
||||||
}
|
}
|
||||||
$if !freestanding {
|
|
||||||
print_backtrace_skipping_top_frames(1)
|
|
||||||
}
|
|
||||||
$if panics_break_into_debugger ? {
|
|
||||||
break_if_debugger_attached()
|
|
||||||
}
|
|
||||||
C.exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,9 @@ pub fn print_backtrace() {
|
||||||
// 1 frame for print_backtrace itself
|
// 1 frame for print_backtrace itself
|
||||||
// ... print the rest of the backtrace frames ...
|
// ... print the rest of the backtrace frames ...
|
||||||
// => top 2 frames should be skipped, since they will not be informative to the developer
|
// => top 2 frames should be skipped, since they will not be informative to the developer
|
||||||
$if !freestanding {
|
$if freestanding {
|
||||||
|
println(bare_backtrace())
|
||||||
|
} $else {
|
||||||
print_backtrace_skipping_top_frames(2)
|
print_backtrace_skipping_top_frames(2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,72 +1,76 @@
|
||||||
module builtin
|
module builtin
|
||||||
|
|
||||||
[unsafe]
|
[unsafe]
|
||||||
pub fn memcpy(dest &byte, src &byte, n int) &byte {
|
pub fn memcpy(dest &C.void, src &C.void, n size_t) &C.void {
|
||||||
|
dest_ := unsafe { &byte(dest) }
|
||||||
|
src_ := unsafe { &byte(src) }
|
||||||
unsafe {
|
unsafe {
|
||||||
for i in 0 .. n {
|
for i in 0 .. int(n) {
|
||||||
dest[i] = src[i]
|
dest_[i] = src_[i]
|
||||||
}
|
}
|
||||||
return dest
|
|
||||||
}
|
}
|
||||||
|
return dest
|
||||||
}
|
}
|
||||||
|
|
||||||
[export: 'malloc']
|
[export: 'malloc']
|
||||||
[unsafe]
|
[unsafe]
|
||||||
fn __malloc(n int) &byte {
|
fn __malloc(n size_t) &C.void {
|
||||||
return unsafe { malloc(n) }
|
return unsafe { malloc(int(n)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
[unsafe]
|
[unsafe]
|
||||||
fn strlen(s &byte) int {
|
fn strlen(_s &C.void) size_t {
|
||||||
|
s := unsafe { &byte(_s) }
|
||||||
mut i := 0
|
mut i := 0
|
||||||
for ; unsafe { s[i] } != 0; i++ {}
|
for ; unsafe { s[i] } != 0; i++ {}
|
||||||
return i
|
return size_t(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
[unsafe]
|
[unsafe]
|
||||||
fn realloc(old_area &byte, new_size int) &byte {
|
fn realloc(old_area &C.void, new_size size_t) &C.void {
|
||||||
if old_area == 0 {
|
if old_area == 0 {
|
||||||
return unsafe { malloc(new_size) }
|
return unsafe { malloc(int(new_size)) }
|
||||||
}
|
}
|
||||||
if new_size == 0 {
|
if new_size == size_t(0) {
|
||||||
unsafe { free(old_area) }
|
unsafe { free(old_area) }
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
old_size := unsafe { *(&u64(old_area - sizeof(u64))) }
|
old_size := unsafe { *(&u64(old_area - sizeof(u64))) }
|
||||||
if new_size <= old_size {
|
if u64(new_size) <= old_size {
|
||||||
return old_area
|
return old_area
|
||||||
} else {
|
} else {
|
||||||
new_area := unsafe { malloc(new_size) }
|
new_area := unsafe { malloc(int(new_size)) }
|
||||||
unsafe { memmove(new_area, old_area, int(old_size)) }
|
unsafe { memmove(new_area, old_area, size_t(old_size)) }
|
||||||
unsafe { free(old_area) }
|
unsafe { free(old_area) }
|
||||||
return new_area
|
return new_area
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[unsafe]
|
[unsafe]
|
||||||
fn memset(_s &byte, _c int, n int) &byte {
|
fn memset(s &C.void, c int, n size_t) &C.void {
|
||||||
c := char(_c)
|
mut s_ := unsafe { &char(s) }
|
||||||
mut s := unsafe { &char(_s) }
|
|
||||||
for i in 0 .. int(n) {
|
for i in 0 .. int(n) {
|
||||||
unsafe {
|
unsafe {
|
||||||
s[i] = c
|
s_[i] = char(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
[unsafe]
|
[unsafe]
|
||||||
fn memmove(dest &byte, src &byte, n int) &byte {
|
fn memmove(dest &C.void, src &C.void, n size_t) &C.void {
|
||||||
mut temp_buf := unsafe { malloc(n) }
|
dest_ := unsafe { &byte(dest) }
|
||||||
|
src_ := unsafe { &byte(src) }
|
||||||
|
mut temp_buf := unsafe { malloc(int(n)) }
|
||||||
for i in 0 .. int(n) {
|
for i in 0 .. int(n) {
|
||||||
unsafe {
|
unsafe {
|
||||||
temp_buf[i] = src[i]
|
temp_buf[i] = src_[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0 .. int(n) {
|
for i in 0 .. int(n) {
|
||||||
unsafe {
|
unsafe {
|
||||||
dest[i] = temp_buf[i]
|
dest_[i] = temp_buf[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unsafe { free(temp_buf) }
|
unsafe { free(temp_buf) }
|
||||||
|
@ -75,23 +79,25 @@ fn memmove(dest &byte, src &byte, n int) &byte {
|
||||||
|
|
||||||
[export: 'calloc']
|
[export: 'calloc']
|
||||||
[unsafe]
|
[unsafe]
|
||||||
fn __calloc(nmemb int, size int) &byte {
|
fn __calloc(nmemb size_t, size size_t) &C.void {
|
||||||
new_area := unsafe { malloc(nmemb * size) }
|
new_area := unsafe { malloc(int(nmemb) * int(size)) }
|
||||||
unsafe { memset(new_area, 0, nmemb * size) }
|
unsafe { memset(new_area, 0, nmemb * size) }
|
||||||
return new_area
|
return new_area
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getchar() int {
|
fn getchar() int {
|
||||||
x := byte(0)
|
x := byte(0)
|
||||||
sys_read(C.stdin, &x, 1)
|
sys_read(0, &x, 1)
|
||||||
return int(x)
|
return int(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn memcmp(a &byte, b &byte, n int) int {
|
fn memcmp(a &C.void, b &C.void, n size_t) int {
|
||||||
|
a_ := unsafe { &byte(a) }
|
||||||
|
b_ := unsafe { &byte(b) }
|
||||||
for i in 0 .. int(n) {
|
for i in 0 .. int(n) {
|
||||||
if unsafe { a[i] != b[i] } {
|
if unsafe { a_[i] != b_[i] } {
|
||||||
unsafe {
|
unsafe {
|
||||||
return a[i] - b[i]
|
return a_[i] - b_[i]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +106,7 @@ fn memcmp(a &byte, b &byte, n int) int {
|
||||||
|
|
||||||
[export: 'free']
|
[export: 'free']
|
||||||
[unsafe]
|
[unsafe]
|
||||||
fn __free(ptr &byte) {
|
fn __free(ptr &C.void) {
|
||||||
err := mm_free(ptr)
|
err := mm_free(ptr)
|
||||||
if err != .enoerror {
|
if err != .enoerror {
|
||||||
eprintln('free error:')
|
eprintln('free error:')
|
||||||
|
@ -112,7 +118,7 @@ fn vsprintf(str &char, format &char, ap &byte) int {
|
||||||
panic('vsprintf(): string interpolation is not supported in `-freestanding`')
|
panic('vsprintf(): string interpolation is not supported in `-freestanding`')
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vsnprintf(str &char, size int, format &char, ap &byte) int {
|
fn vsnprintf(str &char, size size_t, format &char, ap &byte) int {
|
||||||
panic('vsnprintf(): string interpolation is not supported in `-freestanding`')
|
panic('vsnprintf(): string interpolation is not supported in `-freestanding`')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,3 +134,17 @@ fn bare_print(buf &byte, len u64) {
|
||||||
fn bare_eprint(buf &byte, len u64) {
|
fn bare_eprint(buf &byte, len u64) {
|
||||||
sys_write(2, buf, len)
|
sys_write(2, buf, len)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn bare_panic(msg string) {
|
||||||
|
println('V panic' + msg)
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bare_backtrace() string {
|
||||||
|
return 'backtraces are not available with `-freestanding`'
|
||||||
|
}
|
||||||
|
|
||||||
|
[export: 'exit']
|
||||||
|
fn __exit(code int) {
|
||||||
|
sys_exit(code)
|
||||||
|
}
|
||||||
|
|
|
@ -735,50 +735,17 @@ typedef void (*MapFreeFn)(voidptr);
|
||||||
c_common_macros +
|
c_common_macros +
|
||||||
'
|
'
|
||||||
|
|
||||||
#ifndef exit
|
|
||||||
#define exit(rc) sys_exit(rc)
|
|
||||||
void sys_exit (int);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define stdin 0
|
|
||||||
#define stdout 1
|
|
||||||
#define stderr 2
|
|
||||||
|
|
||||||
#define _VFREESTANDING
|
#define _VFREESTANDING
|
||||||
|
|
||||||
typedef long unsigned int size_t;
|
typedef long unsigned int size_t;
|
||||||
|
|
||||||
// Memory allocation related headers
|
// Memory allocation related headers
|
||||||
// void *malloc(int size);
|
void *malloc(size_t size);
|
||||||
byte *calloc(int nitems, int size);
|
void *calloc(size_t nitems, size_t size);
|
||||||
byte *realloc(byte *ptr, int size);
|
void *realloc(void *ptr, size_t size);
|
||||||
byte *memcpy(byte *dest, byte *src, int n);
|
void *memcpy(void *dest, void *src, size_t n);
|
||||||
byte *memset(byte *s, int c, int n);
|
void *memset(void *s, int c, size_t n);
|
||||||
byte *memmove(byte *dest, byte *src, int n);
|
void *memmove(void *dest, void *src, size_t n);
|
||||||
|
|
||||||
// Backtrace headers
|
|
||||||
int backtrace(void **buffer, int size);
|
|
||||||
char **backtrace_symbols(void *const *buffer, int size);
|
|
||||||
void backtrace_symbols_fd(void *const *buffer, int size, int fd);
|
|
||||||
|
|
||||||
// I/O related headers
|
|
||||||
typedef void FILE;
|
|
||||||
FILE *popen(const char *command, const char *type);
|
|
||||||
int pclose(FILE *stream);
|
|
||||||
int fgetc(FILE *stream);
|
|
||||||
char *fgets(char *s, int size, FILE *stream);
|
|
||||||
int getc(FILE *stream);
|
|
||||||
int getchar(void);
|
|
||||||
int ungetc(int c, FILE *stream);
|
|
||||||
|
|
||||||
|
|
||||||
// char manipulation headers
|
|
||||||
int toupper(int c);
|
|
||||||
int tolower(int c);
|
|
||||||
// int toupper_l(int c, locale_t locale);
|
|
||||||
// int tolower_l(int c, locale_t locale);
|
|
||||||
|
|
||||||
int isatty(int fd);
|
|
||||||
|
|
||||||
// varargs implementation, TODO: works on tcc and gcc, but is very unportable and hacky
|
// varargs implementation, TODO: works on tcc and gcc, but is very unportable and hacky
|
||||||
typedef __builtin_va_list va_list;
|
typedef __builtin_va_list va_list;
|
||||||
|
@ -804,6 +771,5 @@ static voidptr memfreedup(voidptr ptr, voidptr src, int sz) {
|
||||||
return memdup(src, sz);
|
return memdup(src, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
' +
|
' + c_wyhash
|
||||||
c_wyhash
|
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue