runtime: only initialize os.runtime_args when needed
This generally means that code size is reduced, especially when the os package is not imported. Specifically: - On Linux (which currently statically links musl), it avoids calling malloc, which avoids including the musl C heap for small programs saving around 1.6kB. - On WASI, it avoids initializing the args slice when the os package is not used. This reduces binary size by around 1kB.
Этот коммит содержится в:
родитель
670fcf59d8
коммит
fb33f3813d
4 изменённых файлов: 67 добавлений и 52 удалений
|
@ -11,6 +11,14 @@ package runtime
|
||||||
// The primary use case is `tinygo test`, which takes some parameters (such as
|
// The primary use case is `tinygo test`, which takes some parameters (such as
|
||||||
// -test.v).
|
// -test.v).
|
||||||
|
|
||||||
|
// This is the default set of arguments, if nothing else has been set.
|
||||||
|
var args = []string{"/proc/self/exe"}
|
||||||
|
|
||||||
|
//go:linkname os_runtime_args os.runtime_args
|
||||||
|
func os_runtime_args() []string {
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
var env []string
|
var env []string
|
||||||
|
|
||||||
//go:linkname syscall_runtime_envs syscall.runtime_envs
|
//go:linkname syscall_runtime_envs syscall.runtime_envs
|
||||||
|
|
|
@ -23,16 +23,6 @@ func GOROOT() string {
|
||||||
return "/usr/local/go"
|
return "/usr/local/go"
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the default set of arguments, if nothing else has been set.
|
|
||||||
// This may be overriden by modifying this global at runtime init (for example,
|
|
||||||
// on Linux where there are real command line arguments).
|
|
||||||
var args = []string{"/proc/self/exe"}
|
|
||||||
|
|
||||||
//go:linkname os_runtime_args os.runtime_args
|
|
||||||
func os_runtime_args() []string {
|
|
||||||
return args
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy size bytes from src to dst. The memory areas must not overlap.
|
// Copy size bytes from src to dst. The memory areas must not overlap.
|
||||||
// Calls to this function are converted to LLVM intrinsic calls such as
|
// Calls to this function are converted to LLVM intrinsic calls such as
|
||||||
// llvm.memcpy.p0i8.p0i8.i32(dst, src, size, false).
|
// llvm.memcpy.p0i8.p0i8.i32(dst, src, size, false).
|
||||||
|
|
|
@ -74,28 +74,9 @@ func postinit() {}
|
||||||
func main(argc int32, argv *unsafe.Pointer) int {
|
func main(argc int32, argv *unsafe.Pointer) int {
|
||||||
preinit()
|
preinit()
|
||||||
|
|
||||||
// Make args global big enough so that it can store all command line
|
// Store argc and argv for later use.
|
||||||
// arguments. Unfortunately this has to be done with some magic as the heap
|
main_argc = argc
|
||||||
// is not yet initialized.
|
main_argv = argv
|
||||||
argsSlice := (*struct {
|
|
||||||
ptr unsafe.Pointer
|
|
||||||
len uintptr
|
|
||||||
cap uintptr
|
|
||||||
})(unsafe.Pointer(&args))
|
|
||||||
argsSlice.ptr = malloc(uintptr(argc) * (unsafe.Sizeof(uintptr(0))) * 3)
|
|
||||||
argsSlice.len = uintptr(argc)
|
|
||||||
argsSlice.cap = uintptr(argc)
|
|
||||||
|
|
||||||
// Initialize command line parameters.
|
|
||||||
for i := 0; i < int(argc); i++ {
|
|
||||||
// Convert the C string to a Go string.
|
|
||||||
length := strlen(*argv)
|
|
||||||
arg := (*_string)(unsafe.Pointer(&args[i]))
|
|
||||||
arg.length = length
|
|
||||||
arg.ptr = (*byte)(*argv)
|
|
||||||
// This is the Go equivalent of "argc++" in C.
|
|
||||||
argv = (*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(argv)) + unsafe.Sizeof(argv)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain the initial stack pointer right before calling the run() function.
|
// Obtain the initial stack pointer right before calling the run() function.
|
||||||
// The run function has been moved to a separate (non-inlined) function so
|
// The run function has been moved to a separate (non-inlined) function so
|
||||||
|
@ -107,6 +88,34 @@ func main(argc int32, argv *unsafe.Pointer) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
main_argc int32
|
||||||
|
main_argv *unsafe.Pointer
|
||||||
|
args []string
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:linkname os_runtime_args os.runtime_args
|
||||||
|
func os_runtime_args() []string {
|
||||||
|
if args == nil {
|
||||||
|
// Make args slice big enough so that it can store all command line
|
||||||
|
// arguments.
|
||||||
|
args = make([]string, main_argc)
|
||||||
|
|
||||||
|
// Initialize command line parameters.
|
||||||
|
argv := main_argv
|
||||||
|
for i := 0; i < int(main_argc); i++ {
|
||||||
|
// Convert the C string to a Go string.
|
||||||
|
length := strlen(*argv)
|
||||||
|
arg := (*_string)(unsafe.Pointer(&args[i]))
|
||||||
|
arg.length = length
|
||||||
|
arg.ptr = (*byte)(*argv)
|
||||||
|
// This is the Go equivalent of "argv++" in C.
|
||||||
|
argv = (*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(argv)) + unsafe.Sizeof(argv)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
// Must be a separate function to get the correct stack pointer.
|
// Must be a separate function to get the correct stack pointer.
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func runMain() {
|
func runMain() {
|
||||||
|
|
|
@ -26,13 +26,19 @@ func _start() {
|
||||||
// wasmtime ./program.wasm arg1 arg2
|
// wasmtime ./program.wasm arg1 arg2
|
||||||
func init() {
|
func init() {
|
||||||
__wasm_call_ctors()
|
__wasm_call_ctors()
|
||||||
|
}
|
||||||
|
|
||||||
// Read the number of args (argc) and the buffer size required to store all
|
var args []string
|
||||||
// these args (argv).
|
|
||||||
|
//go:linkname os_runtime_args os.runtime_args
|
||||||
|
func os_runtime_args() []string {
|
||||||
|
if args == nil {
|
||||||
|
// Read the number of args (argc) and the buffer size required to store
|
||||||
|
// all these args (argv).
|
||||||
var argc, argv_buf_size uint32
|
var argc, argv_buf_size uint32
|
||||||
args_sizes_get(&argc, &argv_buf_size)
|
args_sizes_get(&argc, &argv_buf_size)
|
||||||
if argc == 0 {
|
if argc == 0 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtain the command line arguments
|
// Obtain the command line arguments
|
||||||
|
@ -51,6 +57,8 @@ func init() {
|
||||||
args[i] = *(*string)(unsafe.Pointer(&argString))
|
args[i] = *(*string)(unsafe.Pointer(&argString))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
return int64(ticks)
|
return int64(ticks)
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче