Repository: tetratelabs/wazero
Pull request #924 (2022-12-15 04:54:33)

Enables debug info (a.k.a. DWARF) by default
This makes DWARF enabled by default, with an opt-out flag. This didn't need to be experimental as the feature was requested for a long time and there's no API impact to using it.

Those who wish to disable this, can like so:
```go
r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfig().WithDebugInfoEnabled(false)
```


Patch:
diff --git a/cmd/wazero/wazero.go b/cmd/wazero/wazero.go
index 5923da26..a7ba882f 100644
--- a/cmd/wazero/wazero.go
+++ b/cmd/wazero/wazero.go
@@ -12,12 +12,11 @@ import (
 	"strings"
 
 	"github.com/tetratelabs/wazero"
-	"github.com/tetratelabs/wazero/experimental"
 	"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
 	"github.com/tetratelabs/wazero/sys"
 )
 
-var ctx = experimental.WithDWARFBasedStackTrace(context.Background())
+var ctx = context.Background()
 
 func main() {
 	doMain(os.Stdout, os.Stderr, os.Exit)
diff --git a/config.go b/config.go
index 5066e66b..788372ac 100644
--- a/config.go
+++ b/config.go
@@ -66,6 +66,41 @@ type RuntimeConfig interface {
 	//
 	// See https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/#grow-mem
 	WithMemoryCapacityFromMax(memoryCapacityFromMax bool) RuntimeConfig
+
+	// WithDebugInfoEnabled toggles DWARF based stack traces in the face of
+	// runtime errors. Defaults to true.
+	//
+	// Those who wish to disable this, can like so:
+	//
+	//	r := wazero.NewRuntimeWithConfig(wazero.NewRuntimeConfig().WithDebugInfoEnabled(false)
+	//
+	// When disabled, a stack trace message looks like:
+	//
+	//	wasm stack trace:
+	//		.runtime._panic(i32)
+	//		.myFunc()
+	//		.main.main()
+	//		.runtime.run()
+	//		._start()
+	//
+	// When enabled, the stack trace includes source code information:
+	//
+	//	wasm stack trace:
+	//		.runtime._panic(i32)
+	//		  0x16e2: /opt/homebrew/Cellar/tinygo/0.26.0/src/runtime/runtime_tinygowasm.go:73:6
+	//		.myFunc()
+	//		  0x190b: /Users/XXXXX/wazero/internal/testing/dwarftestdata/testdata/main.go:19:7
+	//		.main.main()
+	//		  0x18ed: /Users/XXXXX/wazero/internal/testing/dwarftestdata/testdata/main.go:4:3
+	//		.runtime.run()
+	//		  0x18cc: /opt/homebrew/Cellar/tinygo/0.26.0/src/runtime/scheduler_none.go:26:10
+	//		._start()
+	//		  0x18b6: /opt/homebrew/Cellar/tinygo/0.26.0/src/runtime/runtime_wasm_wasi.go:22:5
+	//
+	// Note: This only takes into effect when the original Wasm binary has the
+	// DWARF "custom sections" that are often stripped, depending on
+	// optimization flags passed to the compiler.
+	WithDebugInfoEnabled(bool) RuntimeConfig
 }
 
 // NewRuntimeConfig returns a RuntimeConfig using the compiler if it is supported in this environment,
@@ -79,6 +114,7 @@ type runtimeConfig struct {
 	memoryLimitPages      uint32
 	memoryCapacityFromMax bool
 	isInterpreter         bool
+	dwarfDisabled         bool // negative as defaults to enabled
 	newEngine             func(context.Context, api.CoreFeatures) wasm.Engine
 }
 
@@ -87,6 +123,7 @@ var engineLessConfig = &runtimeConfig{
 	enabledFeatures:       api.CoreFeaturesV2,
 	memoryLimitPages:      wasm.MemoryLimitPages,
 	memoryCapacityFromMax: false,
+	dwarfDisabled:         false,
 }
 
 // NewRuntimeConfigCompiler compiles WebAssembly modules into
@@ -148,6 +185,13 @@ func (c *runtimeConfig) WithMemoryCapacityFromMax(memoryCapacityFromMax bool) Ru
 	return ret
 }
 
+// WithDebugInfoEnabled implements RuntimeConfig.WithDebugInfoEnabled
+func (c *runtimeConfig) WithDebugInfoEnabled(dwarfEnabled bool) RuntimeConfig {
+	ret := c.clone()
+	ret.dwarfDisabled = !dwarfEnabled
+	return ret
+}
+
 // CompiledModule is a WebAssembly module ready to be instantiated (Runtime.InstantiateModule) as an api.Module.
 //
 // In WebAssembly terminology, this is a decoded, validated, and possibly also compiled module. wazero avoids using
diff --git a/experimental/dwarf.go b/experimental/dwarf.go
deleted file mode 100644
index 4409b217..00000000
--- a/experimental/dwarf.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package experimental
-
-import (
-	"context"
-)
-
-type enableDWARFBasedStackTraceKey struct{}
-
-// WithDWARFBasedStackTrace enables the DWARF based stack traces in the face of runtime errors.
-// This only takes into effect when the original Wasm binary has the DWARF "custom sections"
-// that are often stripped depending on the optimization options of the compilers.
-//
-// For example, when this is not enabled, the stack trace message looks like:
-//
-//	wasm stack trace:
-//		.runtime._panic(i32)
-//		.myFunc()
-//		.main.main()
-//		.runtime.run()
-//		._start()
-//
-// and when it is enabled:
-//
-//	wasm stack trace:
-//		.runtime._panic(i32)
-//		  0x16e2: /opt/homebrew/Cellar/tinygo/0.26.0/src/runtime/runtime_tinygowasm.go:73:6
-//		.myFunc()
-//		  0x190b: /Users/XXXXX/wazero/internal/testing/dwarftestdata/testdata/main.go:19:7
-//		.main.main()
-//		  0x18ed: /Users/XXXXX/wazero/internal/testing/dwarftestdata/testdata/main.go:4:3
-//		.runtime.run()
-//		  0x18cc: /opt/homebrew/Cellar/tinygo/0.26.0/src/runtime/scheduler_none.go:26:10
-//		._start()
-//		  0x18b6: /opt/homebrew/Cellar/tinygo/0.26.0/src/runtime/runtime_wasm_wasi.go:22:5
-//
-// which contains the source code information.
-//
-// See https://github.com/tetratelabs/wazero/pull/881 for more context.
-func WithDWARFBasedStackTrace(ctx context.Context) context.Context {
-	return context.WithValue(ctx, enableDWARFBasedStackTraceKey{}, struct{}{})
-}
-
-// DWARFBasedStackTraceEnabled returns true if the given context has the option enabling the DWARF
-// based stack trace, and false otherwise.
-func DWARFBasedStackTraceEnabled(ctx context.Context) bool {
-	return ctx.Value(enableDWARFBasedStackTraceKey{}) != nil
-}
diff --git a/runtime.go b/runtime.go
index 4c217663..3270533f 100644
--- a/runtime.go
+++ b/runtime.go
@@ -138,6 +138,7 @@ func NewRuntimeWithConfig(ctx context.Context, rConfig RuntimeConfig) Runtime {
 		memoryLimitPages:      config.memoryLimitPages,
 		memoryCapacityFromMax: config.memoryCapacityFromMax,
 		isInterpreter:         config.isInterpreter,
+		dwarfDisabled:         config.dwarfDisabled,
 	}
 }
 
@@ -149,6 +150,7 @@ type runtime struct {
 	memoryLimitPages      uint32
 	memoryCapacityFromMax bool
 	isInterpreter         bool
+	dwarfDisabled         bool
 	compiledModules       []*compiledModule
 }
 
@@ -172,9 +174,8 @@ func (r *runtime) CompileModule(ctx context.Context, binary []byte) (CompiledMod
 		return nil, errors.New("invalid binary")
 	}
 
-	dwarfEnabled := experimentalapi.DWARFBasedStackTraceEnabled(ctx)
 	internal, err := binaryformat.DecodeModule(binary, r.enabledFeatures,
-		r.memoryLimitPages, r.memoryCapacityFromMax, dwarfEnabled, false)
+		r.memoryLimitPages, r.memoryCapacityFromMax, !r.dwarfDisabled, false)
 	if err != nil {
 		return nil, err
 	} else if err = internal.Validate(r.enabledFeatures); err != nil {


Test patch:
diff --git a/cmd/wazero/wazero_test.go b/cmd/wazero/wazero_test.go
index bf43ee99..b301f1eb 100644
--- a/cmd/wazero/wazero_test.go
+++ b/cmd/wazero/wazero_test.go
@@ -9,7 +9,6 @@ import (
 	"path/filepath"
 	"testing"
 
-	"github.com/tetratelabs/wazero/experimental"
 	"github.com/tetratelabs/wazero/internal/testing/require"
 )
 
@@ -158,7 +157,3 @@ func runMain(t *testing.T, args []string) (int, string, string) {
 
 	return exitCode, stdOut.String(), stdErr.String()
 }
-
-func TestContext(t *testing.T) {
-	require.True(t, experimental.DWARFBasedStackTraceEnabled(ctx))
-}
diff --git a/config_test.go b/config_test.go
index dfdd59c5..dbf6d17a 100644
--- a/config_test.go
+++ b/config_test.go
@@ -50,6 +50,15 @@ func TestRuntimeConfig(t *testing.T) {
 				memoryCapacityFromMax: true,
 			},
 		},
+		{
+			name: "WithDebugInfoEnabled",
+			with: func(c RuntimeConfig) RuntimeConfig {
+				return c.WithDebugInfoEnabled(false)
+			},
+			expected: &runtimeConfig{
+				dwarfDisabled: true, // dwarf is a more technical name and ok here.
+			},
+		},
 	}
 
 	for _, tt := range tests {
diff --git a/experimental/dwarf_test.go b/dwarf_test.go
similarity index 90%
rename from experimental/dwarf_test.go
rename to dwarf_test.go
index aae8aa51..80c8f5ff 100644
--- a/experimental/dwarf_test.go
+++ b/dwarf_test.go
@@ -1,4 +1,4 @@
-package experimental_test
+package wazero_test
 
 import (
 	"bufio"
@@ -8,25 +8,24 @@ import (
 	"testing"
 
 	"github.com/tetratelabs/wazero"
-	"github.com/tetratelabs/wazero/experimental"
 	"github.com/tetratelabs/wazero/imports/wasi_snapshot_preview1"
 	"github.com/tetratelabs/wazero/internal/platform"
 	"github.com/tetratelabs/wazero/internal/testing/dwarftestdata"
 	"github.com/tetratelabs/wazero/internal/testing/require"
 )
 
-func TestWithDWARFBasedStackTrace(t *testing.T) {
+func TestWithDebugInfo(t *testing.T) {
 	ctx := context.Background()
-	require.False(t, experimental.DWARFBasedStackTraceEnabled(ctx))
-	ctx = experimental.WithDWARFBasedStackTrace(ctx)
-	require.True(t, experimental.DWARFBasedStackTraceEnabled(ctx))
 
 	type testCase struct {
 		name string
 		r    wazero.Runtime
 	}
 
-	tests := []testCase{{name: "interpreter", r: wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter())}}
+	tests := []testCase{{
+		name: "interpreter",
+		r:    wazero.NewRuntimeWithConfig(ctx, wazero.NewRuntimeConfigInterpreter()),
+	}}
 
 	if platform.CompilerSupported() {
 		tests = append(tests, testCase{
@@ -167,8 +166,7 @@ wasm stack trace:
 					compiled, err := r.CompileModule(ctx, lang.bin)
 					require.NoError(t, err)
 
-					// Use context.Background to ensure that DWARF is a compile-time option.
-					_, err = r.InstantiateModule(context.Background(), compiled, wazero.NewModuleConfig())
+					_, err = r.InstantiateModule(ctx, compiled, wazero.NewModuleConfig())
 					require.Error(t, err)
 
 					errStr := err.Error()