Skip to content

Commit 4293862

Browse files
committed
Add support for using wizer to handle running initAll()
1 parent 2b1dc4f commit 4293862

File tree

11 files changed

+143
-10
lines changed

11 files changed

+143
-10
lines changed

Diff for: builder/build.go

+32-4
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,33 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
834834
}
835835
}
836836

837+
if config.Options.WizerInit {
838+
var args []string
839+
840+
resultWizer := result.Executable + "-wizer"
841+
842+
args = append(args,
843+
"--allow-wasi",
844+
"--wasm-bulk-memory=true",
845+
"-f", "runtime.wizerInit",
846+
result.Executable,
847+
"-o", resultWizer,
848+
)
849+
850+
cmd := exec.Command(goenv.Get("WIZER"), args...)
851+
cmd.Stdout = os.Stdout
852+
cmd.Stderr = os.Stderr
853+
854+
err := cmd.Run()
855+
if err != nil {
856+
return fmt.Errorf("wizer failed: %w", err)
857+
}
858+
859+
if err := os.Rename(resultWizer, result.Executable); err != nil {
860+
return fmt.Errorf("rename failed: %w", err)
861+
}
862+
}
863+
837864
// Print code size if requested.
838865
if config.Options.PrintSizes == "short" || config.Options.PrintSizes == "full" {
839866
packagePathMap := make(map[string]string, len(lprogram.Packages))
@@ -1036,9 +1063,10 @@ func createEmbedObjectFile(data, hexSum, sourceFile, sourceDir, tmpdir string, c
10361063
// needed to convert a program to its final form. Some transformations are not
10371064
// optional and must be run as the compiler expects them to run.
10381065
func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
1039-
err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA())
1040-
if err != nil {
1041-
return err
1066+
if !config.Options.WizerInit {
1067+
if err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA()); err != nil {
1068+
return err
1069+
}
10421070
}
10431071
if config.VerifyIR() {
10441072
// Only verify if we really need it.
@@ -1054,7 +1082,7 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
10541082
}
10551083

10561084
// Insert values from -ldflags="-X ..." into the IR.
1057-
err = setGlobalValues(mod, config.Options.GlobalValues)
1085+
err := setGlobalValues(mod, config.Options.GlobalValues)
10581086
if err != nil {
10591087
return err
10601088
}

Diff for: compileopts/options.go

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ type Options struct {
5252
Monitor bool
5353
BaudRate int
5454
Timeout time.Duration
55+
WizerInit bool
5556
}
5657

5758
// Verify performs a validation on the given options, raising an error if options are not valid.

Diff for: goenv/goenv.go

+29
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,35 @@ func Get(name string) string {
107107
}
108108

109109
return findWasmOpt()
110+
111+
case "WIZER":
112+
if path := os.Getenv("WIZER"); path != "" {
113+
wizerBin := "wizer"
114+
if runtime.GOOS == "windows" {
115+
wizerBin += ".exe"
116+
}
117+
118+
_, err := exec.LookPath(wizerBin)
119+
if err != nil {
120+
fmt.Fprintf(os.Stderr, "cannot use %q as wasm-opt (from WASMOPT environment variable): %s", path, err.Error())
121+
os.Exit(1)
122+
}
123+
124+
return path
125+
}
126+
127+
wizerBin := "wizer"
128+
if runtime.GOOS == "windows" {
129+
wizerBin += ".exe"
130+
}
131+
132+
path, err := exec.LookPath(wizerBin)
133+
if err != nil {
134+
fmt.Fprintf(os.Stderr, "cannot use %q as wizer: %s", path, err.Error())
135+
os.Exit(1)
136+
}
137+
return path
138+
110139
default:
111140
return ""
112141
}

Diff for: main.go

+8
Original file line numberDiff line numberDiff line change
@@ -1420,6 +1420,7 @@ func main() {
14201420
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
14211421
monitor := flag.Bool("monitor", false, "enable serial monitor")
14221422
baudrate := flag.Int("baudrate", 115200, "baudrate of serial monitor")
1423+
wizerInit := flag.Bool("wizer-init", false, "use wizer for package initialization")
14231424

14241425
var flagJSON, flagDeps, flagTest bool
14251426
if command == "help" || command == "list" || command == "info" || command == "build" {
@@ -1481,6 +1482,11 @@ func main() {
14811482
ocdCommands = strings.Split(*ocdCommandsString, ",")
14821483
}
14831484

1485+
if *wizerInit && *target != "wasi" {
1486+
fmt.Fprintf(os.Stderr, "-wizer-init only makes sense with -target=wasi, got -target=%q\n", *target)
1487+
os.Exit(1)
1488+
}
1489+
14841490
options := &compileopts.Options{
14851491
GOOS: goenv.Get("GOOS"),
14861492
GOARCH: goenv.Get("GOARCH"),
@@ -1512,7 +1518,9 @@ func main() {
15121518
Monitor: *monitor,
15131519
BaudRate: *baudrate,
15141520
Timeout: *timeout,
1521+
WizerInit: *wizerInit,
15151522
}
1523+
15161524
if *printCommands {
15171525
options.PrintCommands = printCommand
15181526
}

Diff for: src/runtime/runtime.go

+6
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ const Compiler = "tinygo"
1212
// package.
1313
func initAll()
1414

15+
var runtimeInitialized = false
16+
17+
func runtime_is_initialized() bool {
18+
return runtimeInitialized
19+
}
20+
1521
//go:linkname callMain main.main
1622
func callMain()
1723

Diff for: src/runtime/runtime_wasm_wasi.go

+35-2
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,29 @@ func __wasm_call_ctors()
1515

1616
//export _start
1717
func _start() {
18+
runtimeInitialize()
19+
run()
20+
}
21+
22+
//export runtime.wizerInit
23+
func runtimeInitialize() {
24+
if runtimeInitialized {
25+
// Second time initialization is happening. Refresh environment
26+
// to whatever our current host gives us instead of whatever
27+
// libc cached.
28+
reset_libc_environment()
29+
return
30+
}
1831
// These need to be initialized early so that the heap can be initialized.
1932
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
2033
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
21-
run()
34+
initHeap()
35+
if hasScheduler {
36+
go initAll()
37+
} else {
38+
initAll()
39+
}
40+
runtimeInitialized = true
2241
}
2342

2443
// Read the command line arguments from WASI.
@@ -29,6 +48,17 @@ func init() {
2948
__wasm_call_ctors()
3049
}
3150

51+
//export __wasilibc_deinitialize_environ
52+
func __wasilibc_deinitialize_environ()
53+
54+
//export __wasilibc_initialize_environ
55+
func __wasilibc_initialize_environ()
56+
57+
func reset_libc_environment() {
58+
__wasilibc_deinitialize_environ()
59+
__wasilibc_initialize_environ()
60+
}
61+
3262
var args []string
3363

3464
//go:linkname os_runtime_args os.runtime_args
@@ -39,7 +69,10 @@ func os_runtime_args() []string {
3969
var argc, argv_buf_size uint32
4070
args_sizes_get(&argc, &argv_buf_size)
4171
if argc == 0 {
42-
return nil
72+
// Most things expect os.Args to have at least the
73+
// program name. We don't have one, but also don't
74+
// return just a nil slice.
75+
return []string{""}
4376
}
4477

4578
// Obtain the command line arguments

Diff for: src/runtime/scheduler_any.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,14 @@ func sleep(duration int64) {
1919
// run is called by the program entry point to execute the go program.
2020
// With a scheduler, init and the main function are invoked in a goroutine before starting the scheduler.
2121
func run() {
22-
initHeap()
22+
if !runtimeInitialized {
23+
initHeap()
24+
}
2325
go func() {
24-
initAll()
26+
if !runtimeInitialized {
27+
initAll()
28+
runtimeInitialized = true
29+
}
2530
callMain()
2631
schedulerDone = true
2732
}()

Diff for: src/runtime/scheduler_none.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@ func getSystemStackPointer() uintptr {
2020
// run is called by the program entry point to execute the go program.
2121
// With the "none" scheduler, init and the main function are invoked directly.
2222
func run() {
23-
initHeap()
24-
initAll()
23+
if !runtimeInitialized {
24+
initHeap()
25+
initAll()
26+
runtimeInitialized = true
27+
}
2528
callMain()
2629
}
2730

Diff for: src/syscall/build_asserts.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//go:build syscall_asserts
2+
3+
package syscall
4+
5+
// enable assertions for checking Environ during runtime preinitialization.
6+
// This is to catch people using os.Environ() during package inits with wizer.
7+
const panicOnEnvironDuringInitAll = true

Diff for: src/syscall/build_noasserts.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//go:build !syscall_asserts
2+
3+
package syscall
4+
5+
// enable assertions for checking Environ during runtime preinitialization.
6+
// This is to catch people using os.Environ() during package init with wizer.
7+
const panicOnEnvironDuringInitAll = false

Diff for: src/syscall/syscall_libc.go

+6
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,13 @@ func Mprotect(b []byte, prot int) (err error) {
243243
return
244244
}
245245

246+
//go:linkname runtime_is_initialized runtime.runtime_is_initialized
247+
func runtime_is_initialized() bool
248+
246249
func Environ() []string {
250+
if panicOnEnvironDuringInitAll && !runtime_is_initialized() {
251+
panic("syscall.Environ() called during runtime preinitialization")
252+
}
247253

248254
// This function combines all the environment into a single allocation.
249255
// While this optimizes for memory usage and garbage collector

0 commit comments

Comments
 (0)