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

wasm: add recover() support #4380

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
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 @@ -747,6 +747,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
}
ldflags = append(ldflags, "-mllvm", "-mcpu="+config.CPU())
ldflags = append(ldflags, "-mllvm", "-mattr="+config.Features()) // needed for MIPS softfloat
ldflags = append(ldflags, "-mllvm", "-wasm-enable-eh")
if config.GOOS() == "windows" {
// Options for the MinGW wrapper for the lld COFF linker.
ldflags = append(ldflags,
Expand Down
31 changes: 23 additions & 8 deletions compiler/calls.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,21 +70,25 @@ func (b *builder) createRuntimeInvoke(fnName string, args []llvm.Value, name str
// createCall creates a call to the given function with the arguments possibly
// expanded.
func (b *builder) createCall(fnType llvm.Type, fn llvm.Value, args []llvm.Value, name string) llvm.Value {
expanded := make([]llvm.Value, 0, len(args))
for _, arg := range args {
fragments := b.expandFormalParam(arg)
expanded = append(expanded, fragments...)
}
return b.CreateCall(fnType, fn, expanded, name)
return b.CreateCall(fnType, fn, b.expandFormalParams(args), name)
}

// createInvoke is like createCall but continues execution at the landing pad if
// the call resulted in a panic.
func (b *builder) createInvoke(fnType llvm.Type, fn llvm.Value, args []llvm.Value, name string) llvm.Value {
if b.hasDeferFrame() {
switch b.deferFrameType() {
case recoverInlineAsm:
b.createInvokeCheckpoint()
return b.createCall(fnType, fn, args, name)
case recoverWasmEH:
continueBB := b.insertBasicBlock("invoke.cont")
call := b.CreateInvoke(fnType, fn, b.expandFormalParams(args), continueBB, b.landingpad, name)
b.SetInsertPointAtEnd(continueBB)
b.blockExits[b.currentBlock] = continueBB
return call
default:
return b.createCall(fnType, fn, args, name)
}
return b.createCall(fnType, fn, args, name)
}

// Expand an argument type to a list that can be used in a function call
Expand Down Expand Up @@ -123,6 +127,17 @@ func (b *builder) expandFormalParamOffsets(t llvm.Type) []uint64 {
}
}

// expandFormalParams expands every param in the params slice like
// expandFormalParam.
func (b *builder) expandFormalParams(params []llvm.Value) []llvm.Value {
expanded := make([]llvm.Value, 0, len(params))
for _, arg := range params {
fragments := b.expandFormalParam(arg)
expanded = append(expanded, fragments...)
}
return expanded
}

// expandFormalParam splits a formal param value into pieces, so it can be
// passed directly as part of a function call. For example, it splits up small
// structs into individual fields. It is the equivalent of expandFormalParamType
Expand Down
23 changes: 13 additions & 10 deletions compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,10 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
}

func (c *compilerContext) getRuntimeType(name string) types.Type {
return c.runtimePkg.Scope().Lookup(name).(*types.TypeName).Type()
if typ, ok := c.runtimePkg.Scope().Lookup(name).(*types.TypeName); ok {
return typ.Type()
}
panic("runtime type not found: " + name)
}

// getLLVMRuntimeType obtains a named type from the runtime package and returns
Expand Down Expand Up @@ -1350,7 +1353,7 @@ func (b *builder) createFunction() {
b.CreateBr(b.afterDefersBlock[i])
}

if b.hasDeferFrame() {
if b.deferFrameType() != recoverNone {
// Create the landing pad block, where execution continues after a
// panic.
b.createLandingPad()
Expand Down Expand Up @@ -1487,8 +1490,11 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
b.createRuntimeInvoke("_panic", []llvm.Value{value}, "")
b.CreateUnreachable()
case *ssa.Return:
if b.hasDeferFrame() {
b.createRuntimeCall("destroyDeferFrame", []llvm.Value{b.deferFrame}, "")
switch b.deferFrameType() {
case recoverInlineAsm:
b.createRuntimeCall("destroyDeferFrameInlineAsm", []llvm.Value{b.deferFrame}, "")
case recoverWasmEH:
b.createRuntimeCall("destroyDeferFrameWasmEH", []llvm.Value{b.deferFrame}, "")
}
if len(instr.Results) == 0 {
b.CreateRetVoid()
Expand Down Expand Up @@ -1741,7 +1747,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
return b.CreateExtractValue(cplx, 0, "real"), nil
case "recover":
useParentFrame := uint64(0)
if b.hasDeferFrame() {
if b.fn.Recover != nil {
// recover() should return the panic value of the parent function,
// not of the current function.
useParentFrame = 1
Expand Down Expand Up @@ -1851,11 +1857,8 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"):
return b.createRawSyscallNoError(instr)
case name == "runtime.supportsRecover":
supportsRecover := uint64(0)
if b.supportsRecover() {
supportsRecover = 1
}
return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil
supportsRecover := uint64(b.supportsRecover())
return llvm.ConstInt(b.ctx.Int8Type(), supportsRecover, false), nil
case name == "runtime.panicStrategy":
// These constants are defined in src/runtime/panic.go.
panicStrategy := map[string]uint64{
Expand Down
1 change: 1 addition & 0 deletions compiler/compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ func TestCompiler(t *testing.T) {
{"interface.go", "", ""},
{"func.go", "", ""},
{"defer.go", "cortex-m-qemu", ""},
{"defer.go", "wasm", "none"},
{"pragma.go", "", ""},
{"goroutine.go", "wasm", "asyncify"},
{"goroutine.go", "cortex-m-qemu", "tasks"},
Expand Down
Loading
Loading