diff --git a/internal/runtime/z_rt.go b/internal/runtime/z_rt.go index c100ade5..fa43c104 100644 --- a/internal/runtime/z_rt.go +++ b/internal/runtime/z_rt.go @@ -30,6 +30,7 @@ type Defer struct { Addr unsafe.Pointer // sigjmpbuf Bits uintptr Link *Defer + Reth unsafe.Pointer // block address after Rethrow Rund unsafe.Pointer // block address after RunDefers } @@ -82,10 +83,6 @@ func init() { // ----------------------------------------------------------------------------- -func unpackEface(i any) *eface { - return (*eface)(unsafe.Pointer(&i)) -} - // TracePanic prints panic message. func TracePanic(v any) { print("panic: ") @@ -94,6 +91,10 @@ func TracePanic(v any) { } /* +func unpackEface(i any) *eface { + return (*eface)(unsafe.Pointer(&i)) +} + func stringTracef(fp c.FilePtr, format *c.Char, s String) { cs := c.Alloca(uintptr(s.len) + 1) c.Fprintf(fp, format, CStrCopy(cs, s)) diff --git a/ssa/eh.go b/ssa/eh.go index dfbfcb89..28f8ea71 100644 --- a/ssa/eh.go +++ b/ssa/eh.go @@ -86,14 +86,17 @@ func (p Function) deferInitBuilder() (b Builder, next BasicBlock) { } type aDefer struct { - nextBit int // next defer bit - key Expr // pthread TLS key - data Expr // pointer to runtime.Defer - bitsPtr Expr // pointer to defer bits - rundPtr Expr // pointer to RunDefers index - procBlk BasicBlock // deferProc block - runsNext []BasicBlock // next blocks of RunDefers - stmts []func(bits Expr) + nextBit int // next defer bit + key Expr // pthread TLS key + data Expr // pointer to runtime.Defer + bitsPtr Expr // pointer to defer bits + rethPtr Expr // next block of Rethrow + rundPtr Expr // next block of RunDefers + procBlk BasicBlock // deferProc block + panicBlk BasicBlock // panic block (runDefers and rethrow) + rethsNext []BasicBlock // next blocks of Rethrow + rundsNext []BasicBlock // next blocks of RunDefers + stmts []func(bits Expr) } func (p Package) keyInit(name string) { @@ -124,53 +127,60 @@ const ( // 0: addr sigjmpbuf // 1: bits uintptr // 2: link *Defer - // 3: rund voidptr + // 3: reth voidptr: block address after Rethrow + // 4: rund voidptr: block address after RunDefers deferSigjmpbuf = iota deferBits deferLink - deferRund + deferRethrow + deferRunDefers ) func (b Builder) getDefer(kind DoAction) *aDefer { self := b.Func if self.defer_ == nil { // TODO(xsw): check if in pkg.init - var next, rundBlk BasicBlock + var next, panicBlk BasicBlock if kind != DeferAlways { b, next = self.deferInitBuilder() } + prog := b.Prog + blks := self.MakeBlocks(2) + procBlk, rethrowBlk := blks[0], blks[1] + key := b.deferKey() zero := prog.Val(uintptr(0)) link := Expr{b.pthreadGetspecific(key).impl, prog.DeferPtr()} jb := b.AllocaSigjmpBuf() - ptr := b.aggregateAlloca(prog.Defer(), jb.impl, zero.impl, link.impl) + ptr := b.aggregateAlloca(prog.Defer(), jb.impl, zero.impl, link.impl, procBlk.Addr().impl) deferData := Expr{ptr, prog.DeferPtr()} b.pthreadSetspecific(key, deferData) - blks := self.MakeBlocks(2) - procBlk, rethrowBlk := blks[0], blks[1] bitsPtr := b.FieldAddr(deferData, deferBits) - rundPtr := b.FieldAddr(deferData, deferRund) - self.defer_ = &aDefer{ - key: key, - data: deferData, - bitsPtr: bitsPtr, - rundPtr: rundPtr, - procBlk: procBlk, - runsNext: []BasicBlock{rethrowBlk}, - } + rethPtr := b.FieldAddr(deferData, deferRethrow) + rundPtr := b.FieldAddr(deferData, deferRunDefers) + czero := prog.IntVal(0, prog.CInt()) retval := b.Sigsetjmp(jb, czero) if kind != DeferAlways { - rundBlk = self.MakeBlock() + panicBlk = self.MakeBlock() } else { blks = self.MakeBlocks(2) - next, rundBlk = blks[0], blks[1] + next, panicBlk = blks[0], blks[1] + } + b.If(b.BinOp(token.EQL, retval, czero), next, panicBlk) + + self.defer_ = &aDefer{ + key: key, + data: deferData, + bitsPtr: bitsPtr, + rethPtr: rethPtr, + rundPtr: rundPtr, + procBlk: procBlk, + panicBlk: panicBlk, + rethsNext: []BasicBlock{procBlk}, + rundsNext: []BasicBlock{rethrowBlk}, } - b.If(b.BinOp(token.EQL, retval, czero), next, rundBlk) - b.SetBlockEx(rundBlk, AtEnd, false) // exec runDefers and rethrow - b.Store(rundPtr, rethrowBlk.Addr()) - b.Jump(procBlk) b.SetBlockEx(rethrowBlk, AtEnd, false) // rethrow b.Call(b.Pkg.rtFunc("Rethrow"), link) @@ -229,7 +239,7 @@ func (b Builder) Defer(kind DoAction, fn Expr, args ...Expr) { func (b Builder) RunDefers() { self := b.getDefer(DeferInCond) blk := b.Func.MakeBlock() - self.runsNext = append(self.runsNext, blk) + self.rundsNext = append(self.rundsNext, blk) b.Store(self.rundPtr, blk.Addr()) b.Jump(self.procBlk) @@ -243,11 +253,14 @@ func (p Function) endDefer(b Builder) { if self == nil { return } - nexts := self.runsNext + procBlk := self.procBlk + panicBlk := self.panicBlk + rundPtr := self.rundPtr + nexts := self.rundsNext if len(nexts) == 0 { return } - b.SetBlockEx(self.procBlk, AtEnd, true) + b.SetBlockEx(procBlk, AtEnd, true) bits := b.Load(self.bitsPtr) stmts := self.stmts for i := len(stmts) - 1; i >= 0; i-- { @@ -256,7 +269,11 @@ func (p Function) endDefer(b Builder) { link := b.getField(b.Load(self.data), deferLink) b.pthreadSetspecific(self.key, link) - b.IndirectJump(b.Load(self.rundPtr), nexts) + b.IndirectJump(b.Load(rundPtr), nexts) + + b.SetBlockEx(panicBlk, AtEnd, false) // exec runDefers and rethrow + b.Store(rundPtr, nexts[0].Addr()) // nexts[0] is rethrowBlk + b.Jump(procBlk) } // -----------------------------------------------------------------------------