Skip to content

Commit eeb8f09

Browse files
committed
syscall: split out env logic so wasip2 can do non-libc version
1 parent 98609c5 commit eeb8f09

File tree

5 files changed

+111
-56
lines changed

5 files changed

+111
-56
lines changed

compiler/symbol.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
346346
// The list of allowed types is based on this proposal:
347347
// https://github.com/golang/go/issues/59149
348348
func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
349-
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" {
349+
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" || c.pkg.Path() == "syscall" {
350350
// The runtime is a special case. Allow all kinds of parameters
351351
// (importantly, including pointers).
352352
return

src/syscall/env_libc.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//go:build (darwin || nintendoswitch || wasi || wasip1) && !wasip2
2+
3+
package syscall
4+
5+
import (
6+
"unsafe"
7+
)
8+
9+
func Environ() []string {
10+
11+
// This function combines all the environment into a single allocation.
12+
// While this optimizes for memory usage and garbage collector
13+
// overhead, it does run the risk of potentially pinning a "large"
14+
// allocation if a user holds onto a single environment variable or
15+
// value. Having each variable be its own allocation would make the
16+
// trade-off in the other direction.
17+
18+
// calculate total memory required
19+
var length uintptr
20+
var vars int
21+
for environ := libc_environ; *environ != nil; {
22+
length += libc_strlen(*environ)
23+
vars++
24+
environ = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(environ), unsafe.Sizeof(environ)))
25+
}
26+
27+
// allocate our backing slice for the strings
28+
b := make([]byte, length)
29+
// and the slice we're going to return
30+
envs := make([]string, 0, vars)
31+
32+
// loop over the environment again, this time copying over the data to the backing slice
33+
for environ := libc_environ; *environ != nil; {
34+
length = libc_strlen(*environ)
35+
// construct a Go string pointing at the libc-allocated environment variable data
36+
var envVar string
37+
rawEnvVar := (*struct {
38+
ptr unsafe.Pointer
39+
length uintptr
40+
})(unsafe.Pointer(&envVar))
41+
rawEnvVar.ptr = *environ
42+
rawEnvVar.length = length
43+
// pull off the number of bytes we need for this environment variable
44+
var bs []byte
45+
bs, b = b[:length], b[length:]
46+
// copy over the bytes to the Go heap
47+
copy(bs, envVar)
48+
// convert trimmed slice to string
49+
s := *(*string)(unsafe.Pointer(&bs))
50+
// add s to our list of environment variables
51+
envs = append(envs, s)
52+
// environ++
53+
environ = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(environ), unsafe.Sizeof(environ)))
54+
}
55+
return envs
56+
}
57+
58+
//go:extern environ
59+
var libc_environ *unsafe.Pointer

src/syscall/env_wasip2.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//go:build wasip2
2+
3+
package syscall
4+
5+
import (
6+
"unsafe"
7+
)
8+
9+
type __wasi_list_tuple struct {
10+
ptr unsafe.Pointer
11+
len uint32
12+
}
13+
14+
type __wasi_tuple_string_string struct {
15+
first __wasi_string
16+
second __wasi_string
17+
}
18+
19+
type __wasi_string struct {
20+
data unsafe.Pointer
21+
len uint32
22+
}
23+
24+
type _string struct {
25+
ptr *byte
26+
length uintptr
27+
}
28+
29+
//go:wasmimport wasi:cli/[email protected] get-environment
30+
func __wasi_cli_environment_get_environment() __wasi_list_tuple
31+
32+
func Environ() []string {
33+
var envs []string
34+
list_tuple := __wasi_cli_environment_get_environment()
35+
envs = make([]string, list_tuple.len)
36+
ptr := list_tuple.ptr
37+
for i := uint32(0); i < list_tuple.len; i++ {
38+
tuple := *(*__wasi_tuple_string_string)(ptr)
39+
first, second := tuple.first, tuple.second
40+
envKey := _string{
41+
(*byte)(first.data), uintptr(first.len),
42+
}
43+
envValue := _string{
44+
(*byte)(second.data), uintptr(second.len),
45+
}
46+
envs[i] = *(*string)(unsafe.Pointer(&envKey)) + "=" + *(*string)(unsafe.Pointer(&envValue))
47+
ptr = unsafe.Add(ptr, unsafe.Sizeof(__wasi_tuple_string_string{}))
48+
}
49+
50+
return envs
51+
}

src/syscall/libc_wasip2.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,6 @@ func unlink(pathname *byte) int32 {
152152
return 0
153153
}
154154

155-
//go:export environ
156-
var environ *unsafe.Pointer
157-
158155
// int getpagesize(void);
159156
//
160157
//go:export getpagesize

src/syscall/syscall_libc.go

Lines changed: 0 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -250,55 +250,6 @@ func Mprotect(b []byte, prot int) (err error) {
250250
return
251251
}
252252

253-
func Environ() []string {
254-
255-
// This function combines all the environment into a single allocation.
256-
// While this optimizes for memory usage and garbage collector
257-
// overhead, it does run the risk of potentially pinning a "large"
258-
// allocation if a user holds onto a single environment variable or
259-
// value. Having each variable be its own allocation would make the
260-
// trade-off in the other direction.
261-
262-
// calculate total memory required
263-
var length uintptr
264-
var vars int
265-
for environ := libc_environ; *environ != nil; {
266-
length += libc_strlen(*environ)
267-
vars++
268-
environ = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(environ), unsafe.Sizeof(environ)))
269-
}
270-
271-
// allocate our backing slice for the strings
272-
b := make([]byte, length)
273-
// and the slice we're going to return
274-
envs := make([]string, 0, vars)
275-
276-
// loop over the environment again, this time copying over the data to the backing slice
277-
for environ := libc_environ; *environ != nil; {
278-
length = libc_strlen(*environ)
279-
// construct a Go string pointing at the libc-allocated environment variable data
280-
var envVar string
281-
rawEnvVar := (*struct {
282-
ptr unsafe.Pointer
283-
length uintptr
284-
})(unsafe.Pointer(&envVar))
285-
rawEnvVar.ptr = *environ
286-
rawEnvVar.length = length
287-
// pull off the number of bytes we need for this environment variable
288-
var bs []byte
289-
bs, b = b[:length], b[length:]
290-
// copy over the bytes to the Go heap
291-
copy(bs, envVar)
292-
// convert trimmed slice to string
293-
s := *(*string)(unsafe.Pointer(&bs))
294-
// add s to our list of environment variables
295-
envs = append(envs, s)
296-
// environ++
297-
environ = (*unsafe.Pointer)(unsafe.Add(unsafe.Pointer(environ), unsafe.Sizeof(environ)))
298-
}
299-
return envs
300-
}
301-
302253
// BytePtrFromString returns a pointer to a NUL-terminated array of
303254
// bytes containing the text of s. If s contains a NUL byte at any
304255
// location, it returns (nil, EINVAL).
@@ -430,6 +381,3 @@ func libc_readlink(path *byte, buf *byte, count uint) int
430381
//
431382
//export unlink
432383
func libc_unlink(pathname *byte) int32
433-
434-
//go:extern environ
435-
var libc_environ *unsafe.Pointer

0 commit comments

Comments
 (0)