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) | ||||||
|  |  | ||||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 Ayke van Laethem
						Ayke van Laethem