Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

all: move -panic=trap support to the compiler/runtime #4195

Merged
merged 1 commit into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
MaxStackAlloc: config.MaxStackAlloc(),
NeedsStackObjects: config.NeedsStackObjects(),
Debug: !config.Options.SkipDWARF, // emit DWARF except when -internal-nodwarf is passed
PanicStrategy: config.PanicStrategy(),
}

// Load the target machine, which is the LLVM object that contains all
Expand Down
8 changes: 8 additions & 0 deletions compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ type Config struct {
MaxStackAlloc uint64
NeedsStackObjects bool
Debug bool // Whether to emit debug information in the LLVM module.
PanicStrategy string
}

// compilerContext contains function-independent data that should still be
Expand Down Expand Up @@ -1855,6 +1856,13 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
supportsRecover = 1
}
return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil
case name == "runtime.panicStrategy":
// These constants are defined in src/runtime/panic.go.
panicStrategy := map[string]uint64{
"print": 1, // panicStrategyPrint
"trap": 2, // panicStrategyTrap
}[b.Config.PanicStrategy]
return llvm.ConstInt(b.ctx.Int8Type(), panicStrategy, false), nil
case name == "runtime/interrupt.New":
return b.createInterruptGlobal(instr)
}
Expand Down
60 changes: 60 additions & 0 deletions main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import (
"reflect"
"regexp"
"runtime"
"slices"
"strings"
"sync"
"testing"
"time"

"github.com/aykevl/go-wasm"
"github.com/tinygo-org/tinygo/builder"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
Expand Down Expand Up @@ -404,6 +406,64 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
}
}

// Test WebAssembly files for certain properties.
func TestWebAssembly(t *testing.T) {
t.Parallel()
type testCase struct {
name string
panicStrategy string
imports []string
}
for _, tc := range []testCase{
// Test whether there really are no imports when using -panic=trap. This
// tests the bugfix for https://github.com/tinygo-org/tinygo/issues/4161.
{name: "panic-default", imports: []string{"wasi_snapshot_preview1.fd_write"}},
{name: "panic-trap", panicStrategy: "trap", imports: []string{}},
} {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
tmpdir := t.TempDir()
options := optionsFromTarget("wasi", sema)
options.PanicStrategy = tc.panicStrategy
config, err := builder.NewConfig(&options)
if err != nil {
t.Fatal(err)
}

result, err := builder.Build("testdata/trivialpanic.go", ".wasm", tmpdir, config)
if err != nil {
t.Fatal("failed to build binary:", err)
}
f, err := os.Open(result.Binary)
if err != nil {
t.Fatal("could not open output binary:", err)
}
defer f.Close()
module, err := wasm.Parse(f)
if err != nil {
t.Fatal("could not parse output binary:", err)
}

// Test the list of imports.
if tc.imports != nil {
var imports []string
for _, section := range module.Sections {
switch section := section.(type) {
case *wasm.SectionImport:
for _, symbol := range section.Entries {
imports = append(imports, symbol.Module+"."+symbol.Field)
}
}
}
if !slices.Equal(imports, tc.imports) {
t.Errorf("import list not as expected!\nexpected: %v\nactual: %v", tc.imports, imports)
}
}
})
}
}

func TestTest(t *testing.T) {
t.Parallel()

Expand Down
16 changes: 16 additions & 0 deletions src/runtime/panic.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ func tinygo_longjmp(frame *deferFrame)
// Returns whether recover is supported on the current architecture.
func supportsRecover() bool

const (
panicStrategyPrint = 1
panicStrategyTrap = 2
)

// Compile intrinsic.
// Returns which strategy is used. This is usually "print" but can be changed
// using the -panic= compiler flag.
func panicStrategy() uint8

// DeferFrame is a stack allocated object that stores information for the
// current "defer frame", which is used in functions that use the `defer`
// keyword.
Expand All @@ -37,6 +47,9 @@ type deferFrame struct {

// Builtin function panic(msg), used as a compiler intrinsic.
func _panic(message interface{}) {
if panicStrategy() == panicStrategyTrap {
trap()
}
if supportsRecover() {
frame := (*deferFrame)(task.Current().DeferFrame)
if frame != nil {
Expand All @@ -60,6 +73,9 @@ func runtimePanic(msg string) {
}

func runtimePanicAt(addr unsafe.Pointer, msg string) {
if panicStrategy() == panicStrategyTrap {
trap()
}
if hasReturnAddr {
printstring("panic: runtime error at ")
printptr(uintptr(addr) - callInstSize)
Expand Down
4 changes: 0 additions & 4 deletions transform/optimizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@ func Optimize(mod llvm.Module, config *compileopts.Config) []error {
fn.SetLinkage(llvm.ExternalLinkage)
}

if config.PanicStrategy() == "trap" {
ReplacePanicsWithTrap(mod) // -panic=trap
}

// run a check of all of our code
if config.VerifyIR() {
errs := ircheck.Module(mod)
Expand Down
33 changes: 0 additions & 33 deletions transform/panic.go

This file was deleted.

12 changes: 0 additions & 12 deletions transform/panic_test.go

This file was deleted.

22 changes: 0 additions & 22 deletions transform/testdata/panic.ll

This file was deleted.

25 changes: 0 additions & 25 deletions transform/testdata/panic.out.ll

This file was deleted.

1 change: 1 addition & 0 deletions transform/transform_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ func compileGoFileForTesting(t *testing.T, filename string) llvm.Module {
Scheduler: config.Scheduler(),
AutomaticStackSize: config.AutomaticStackSize(),
Debug: true,
PanicStrategy: config.PanicStrategy(),
}
machine, err := compiler.NewTargetMachine(compilerConfig)
if err != nil {
Expand Down
Loading