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
|
//go:linkname Printf C.printf
|
||||||
func Printf(format *Char, __llgo_va_list ...any) Int
|
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
|
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
|
return
|
||||||
}
|
}
|
||||||
fail()
|
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 {
|
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)
|
b.SetBlockEx(ret, llssa.AtEnd, false)
|
||||||
if ninstr := len(block.Instrs); ninstr > 0 {
|
if ninstr := len(block.Instrs); ninstr > 0 {
|
||||||
if isPhi(block.Instrs[0]) {
|
if isPhi(block.Instrs[0]) {
|
||||||
|
|||||||
@@ -34,10 +34,21 @@ type Defer struct {
|
|||||||
Rund unsafe.Pointer // block address after RunDefers
|
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.
|
// Panic panics with a value.
|
||||||
func Panic(v Eface) {
|
func Panic(v any) {
|
||||||
ptr := c.Malloc(unsafe.Sizeof(v))
|
ptr := c.Malloc(unsafe.Sizeof(v))
|
||||||
*(*Eface)(ptr) = v
|
*(*any)(ptr) = v
|
||||||
excepKey.Set(ptr)
|
excepKey.Set(ptr)
|
||||||
|
|
||||||
Rethrow((*Defer)(c.GoDeferData()))
|
Rethrow((*Defer)(c.GoDeferData()))
|
||||||
@@ -45,13 +56,14 @@ func Panic(v Eface) {
|
|||||||
|
|
||||||
// Rethrow rethrows a panic.
|
// Rethrow rethrows a panic.
|
||||||
func Rethrow(link *Defer) {
|
func Rethrow(link *Defer) {
|
||||||
if link == nil {
|
if ptr := excepKey.Get(); ptr != nil {
|
||||||
ptr := excepKey.Get()
|
if link == nil {
|
||||||
TracePanic(*(*Eface)(ptr))
|
TracePanic(*(*Eface)(ptr))
|
||||||
c.Free(ptr)
|
c.Free(ptr)
|
||||||
c.Exit(2)
|
c.Exit(2)
|
||||||
} else {
|
} else {
|
||||||
c.Siglongjmp(link.Addr, 1)
|
c.Siglongjmp(link.Addr, 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ type aFunction struct {
|
|||||||
blks []BasicBlock
|
blks []BasicBlock
|
||||||
|
|
||||||
defer_ *aDefer
|
defer_ *aDefer
|
||||||
|
recov BasicBlock
|
||||||
|
|
||||||
params []Type
|
params []Type
|
||||||
freeVars Expr
|
freeVars Expr
|
||||||
@@ -329,4 +330,9 @@ func (p Function) Block(idx int) BasicBlock {
|
|||||||
return p.blks[idx]
|
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 (
|
import (
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
|
"log"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"github.com/goplus/llvm"
|
"github.com/goplus/llvm"
|
||||||
@@ -174,7 +175,7 @@ func (b Builder) getDefer(kind DoAction) *aDefer {
|
|||||||
|
|
||||||
b.SetBlockEx(rethrowBlk, AtEnd, false) // rethrow
|
b.SetBlockEx(rethrowBlk, AtEnd, false) // rethrow
|
||||||
b.Call(b.Pkg.rtFunc("Rethrow"), link)
|
b.Call(b.Pkg.rtFunc("Rethrow"), link)
|
||||||
b.Unreachable() // TODO: func supports noreturn attribute
|
b.Jump(self.recov)
|
||||||
|
|
||||||
if kind == DeferAlways {
|
if kind == DeferAlways {
|
||||||
b.SetBlockEx(next, AtEnd, false)
|
b.SetBlockEx(next, AtEnd, false)
|
||||||
@@ -266,16 +267,14 @@ func (b Builder) Unreachable() {
|
|||||||
b.impl.CreateUnreachable()
|
b.impl.CreateUnreachable()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// Recover emits a recover instruction.
|
// Recover emits a recover instruction.
|
||||||
func (b Builder) Recover() (v Expr) {
|
func (b Builder) Recover() Expr {
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Println("Recover")
|
log.Println("Recover")
|
||||||
}
|
}
|
||||||
prog := b.Prog
|
// TODO(xsw): recover can't be a function call in Go
|
||||||
return prog.Zero(prog.Any())
|
return b.Call(b.Pkg.rtFunc("Recover"))
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// Panic emits a panic instruction.
|
// Panic emits a panic instruction.
|
||||||
func (b Builder) Panic(v Expr) {
|
func (b Builder) Panic(v Expr) {
|
||||||
|
|||||||
@@ -898,8 +898,8 @@ func (b Builder) BuiltinCall(fn string, args ...Expr) (ret Expr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//case "recover":
|
case "recover":
|
||||||
// return b.Recover()
|
return b.Recover()
|
||||||
case "print", "println":
|
case "print", "println":
|
||||||
return b.PrintEx(fn == "println", args...)
|
return b.PrintEx(fn == "println", args...)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user