recover
This commit is contained in:
8
c/c.go
8
c/c.go
@@ -103,6 +103,11 @@ func Qsort(base Pointer, count, elem uintptr, compar func(a, b Pointer) Int)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Atoi C.atoi
|
||||
func Atoi(s *Char) Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Printf C.printf
|
||||
func Printf(format *Char, __llgo_va_list ...any) Int
|
||||
|
||||
@@ -171,6 +176,3 @@ func GetoptLong(argc Int, argv **Char, optstring *Char, longopts *Option, longin
|
||||
func GetoptLongOnly(argc Int, argv **Char, optstring *Char, longopts *Option, longindex *Int) Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Atoi C.atoi
|
||||
func Atoi(s *Char) Int
|
||||
|
||||
@@ -20,4 +20,5 @@ func main() {
|
||||
return
|
||||
}
|
||||
fail()
|
||||
println("unreachable")
|
||||
}
|
||||
|
||||
29
cl/_testgo/defer4/in.go
Normal file
29
cl/_testgo/defer4/in.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
func f(s string) bool {
|
||||
return len(s) > 2
|
||||
}
|
||||
|
||||
func fail() {
|
||||
defer println("bye")
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
println("recover:", e.(string))
|
||||
}
|
||||
}()
|
||||
panic("panic message")
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
println("hi")
|
||||
}()
|
||||
if s := "hello"; f(s) {
|
||||
defer println(s)
|
||||
} else {
|
||||
defer println("world")
|
||||
return
|
||||
}
|
||||
fail()
|
||||
println("reachable")
|
||||
}
|
||||
1
cl/_testgo/defer4/out.ll
Normal file
1
cl/_testgo/defer4/out.ll
Normal file
@@ -0,0 +1 @@
|
||||
;
|
||||
@@ -555,7 +555,11 @@ func isPhi(i ssa.Instruction) bool {
|
||||
}
|
||||
|
||||
func (p *context) compilePhis(b llssa.Builder, block *ssa.BasicBlock) int {
|
||||
ret := p.fn.Block(block.Index)
|
||||
fn := p.fn
|
||||
ret := fn.Block(block.Index)
|
||||
if block.Comment == "recover" { // set recover block
|
||||
fn.SetRecover(ret)
|
||||
}
|
||||
b.SetBlockEx(ret, llssa.AtEnd, false)
|
||||
if ninstr := len(block.Instrs); ninstr > 0 {
|
||||
if isPhi(block.Instrs[0]) {
|
||||
|
||||
@@ -34,10 +34,21 @@ type Defer struct {
|
||||
Rund unsafe.Pointer // block address after RunDefers
|
||||
}
|
||||
|
||||
// Recover recovers a panic.
|
||||
func Recover() (ret any) {
|
||||
ptr := excepKey.Get()
|
||||
if ptr != nil {
|
||||
excepKey.Set(nil)
|
||||
ret = *(*any)(ptr)
|
||||
c.Free(ptr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Panic panics with a value.
|
||||
func Panic(v Eface) {
|
||||
func Panic(v any) {
|
||||
ptr := c.Malloc(unsafe.Sizeof(v))
|
||||
*(*Eface)(ptr) = v
|
||||
*(*any)(ptr) = v
|
||||
excepKey.Set(ptr)
|
||||
|
||||
Rethrow((*Defer)(c.GoDeferData()))
|
||||
@@ -45,13 +56,14 @@ func Panic(v Eface) {
|
||||
|
||||
// Rethrow rethrows a panic.
|
||||
func Rethrow(link *Defer) {
|
||||
if link == nil {
|
||||
ptr := excepKey.Get()
|
||||
TracePanic(*(*Eface)(ptr))
|
||||
c.Free(ptr)
|
||||
c.Exit(2)
|
||||
} else {
|
||||
c.Siglongjmp(link.Addr, 1)
|
||||
if ptr := excepKey.Get(); ptr != nil {
|
||||
if link == nil {
|
||||
TracePanic(*(*Eface)(ptr))
|
||||
c.Free(ptr)
|
||||
c.Exit(2)
|
||||
} else {
|
||||
c.Siglongjmp(link.Addr, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -179,6 +179,7 @@ type aFunction struct {
|
||||
blks []BasicBlock
|
||||
|
||||
defer_ *aDefer
|
||||
recov BasicBlock
|
||||
|
||||
params []Type
|
||||
freeVars Expr
|
||||
@@ -329,4 +330,9 @@ func (p Function) Block(idx int) BasicBlock {
|
||||
return p.blks[idx]
|
||||
}
|
||||
|
||||
// SetRecover sets the recover block for the function.
|
||||
func (p Function) SetRecover(blk BasicBlock) {
|
||||
p.recov = blk
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
11
ssa/eh.go
11
ssa/eh.go
@@ -22,6 +22,7 @@ import "C"
|
||||
import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
"log"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llvm"
|
||||
@@ -174,7 +175,7 @@ func (b Builder) getDefer(kind DoAction) *aDefer {
|
||||
|
||||
b.SetBlockEx(rethrowBlk, AtEnd, false) // rethrow
|
||||
b.Call(b.Pkg.rtFunc("Rethrow"), link)
|
||||
b.Unreachable() // TODO: func supports noreturn attribute
|
||||
b.Jump(self.recov)
|
||||
|
||||
if kind == DeferAlways {
|
||||
b.SetBlockEx(next, AtEnd, false)
|
||||
@@ -266,16 +267,14 @@ func (b Builder) Unreachable() {
|
||||
b.impl.CreateUnreachable()
|
||||
}
|
||||
|
||||
/*
|
||||
// Recover emits a recover instruction.
|
||||
func (b Builder) Recover() (v Expr) {
|
||||
func (b Builder) Recover() Expr {
|
||||
if debugInstr {
|
||||
log.Println("Recover")
|
||||
}
|
||||
prog := b.Prog
|
||||
return prog.Zero(prog.Any())
|
||||
// TODO(xsw): recover can't be a function call in Go
|
||||
return b.Call(b.Pkg.rtFunc("Recover"))
|
||||
}
|
||||
*/
|
||||
|
||||
// Panic emits a panic instruction.
|
||||
func (b Builder) Panic(v Expr) {
|
||||
|
||||
@@ -898,8 +898,8 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
//case "recover":
|
||||
// return b.Recover()
|
||||
case "recover":
|
||||
return b.Recover()
|
||||
case "print", "println":
|
||||
return b.PrintEx(fn == "println", args...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user