asyncio: trap on unexpected resume

This commit is contained in:
Li Jie
2024-08-05 15:19:42 +08:00
parent a1fdc05e26
commit 3bf0780a67
6 changed files with 34 additions and 10 deletions

View File

@@ -67,7 +67,7 @@ func (p *context) coAwait(b llssa.Builder, args []ssa.Value) llssa.Expr {
} }
func (p *context) coSuspend(b llssa.Builder, final llssa.Expr) { func (p *context) coSuspend(b llssa.Builder, final llssa.Expr) {
b.CoSuspend(b.AsyncToken(), final) b.CoSuspend(b.AsyncToken(), final, nil)
} }
func (p *context) coDone(b llssa.Builder, args []ssa.Value) llssa.Expr { func (p *context) coDone(b llssa.Builder, args []ssa.Value) llssa.Expr {

View File

@@ -232,11 +232,12 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
nBlkOff := 0 nBlkOff := 0
if nblk := len(f.Blocks); nblk > 0 { if nblk := len(f.Blocks); nblk > 0 {
if async { if async {
nBlkOff = 4 nBlkOff = 5
fn.MakeBlock("entry") fn.MakeBlock("entry")
fn.MakeBlock("alloc") fn.MakeBlock("alloc")
fn.MakeBlock("clean") fn.MakeBlock("clean")
fn.MakeBlock("suspend") fn.MakeBlock("suspend")
fn.MakeBlock("trap")
} }
fn.MakeBlocks(nblk) // to set fn.HasBody() = true fn.MakeBlocks(nblk) // to set fn.HasBody() = true
if f.Recover != nil { // set recover block if f.Recover != nil { // set recover block

View File

@@ -378,8 +378,7 @@ func (b Builder) SetAsyncToken(token Expr) {
} }
func (b Builder) EndAsync() { func (b Builder) EndAsync() {
_, _, cleanBlk := b.onSuspBlk(b.blk) b.onReturn()
b.Jump(cleanBlk)
} }
/* /*
@@ -409,7 +408,8 @@ func (b Builder) BeginAsync(fn Function) {
allocBlk := fn.Block(1) allocBlk := fn.Block(1)
cleanBlk := fn.Block(2) cleanBlk := fn.Block(2)
suspdBlk := fn.Block(3) suspdBlk := fn.Block(3)
beginBlk := fn.Block(4) trapBlk := fn.Block(4)
beginBlk := fn.Block(5)
b.SetBlock(entryBlk) b.SetBlock(entryBlk)
promiseSize := b.Const(constant.MakeUint64(b.Prog.SizeOf(promiseTy)), b.Prog.Int64()).SetName("promise.size") promiseSize := b.Const(constant.MakeUint64(b.Prog.SizeOf(promiseTy)), b.Prog.Int64()).SetName("promise.size")
@@ -448,9 +448,16 @@ func (b Builder) BeginAsync(fn Function) {
b.CoEnd(hdl, b.Prog.BoolVal(false), b.Prog.TokenNone()) b.CoEnd(hdl, b.Prog.BoolVal(false), b.Prog.TokenNone())
b.Return(promise) b.Return(promise)
b.SetBlock(trapBlk)
b.LLVMTrap()
b.Unreachable()
b.onSuspBlk = func(nextBlk BasicBlock) (BasicBlock, BasicBlock, BasicBlock) { b.onSuspBlk = func(nextBlk BasicBlock) (BasicBlock, BasicBlock, BasicBlock) {
return suspdBlk, nextBlk, cleanBlk return suspdBlk, nextBlk, cleanBlk
} }
b.onReturn = func() {
b.CoSuspend(b.asyncToken, b.Prog.BoolVal(true), trapBlk)
}
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@@ -600,14 +607,15 @@ func (b Builder) coSuspend(save, final Expr) Expr {
return b.Call(fn, save, final) return b.Call(fn, save, final)
} }
func (b Builder) CoSuspend(save, final Expr) { func (b Builder) CoSuspend(save, final Expr, nextBlk BasicBlock) {
if !b.async { if !b.async {
panic(fmt.Errorf("suspend %v not in async block", b.Func.Name())) panic(fmt.Errorf("suspend %v not in async block", b.Func.Name()))
} }
if nextBlk == nil {
b.Func.MakeBlock("")
nextBlk = b.Func.Block(b.blk.idx + 1)
}
ret := b.coSuspend(save, final) ret := b.coSuspend(save, final)
// add resume block
b.Func.MakeBlock("")
nextBlk := b.Func.Block(b.blk.idx + 1)
susp, next, clean := b.onSuspBlk(nextBlk) susp, next, clean := b.onSuspBlk(nextBlk)
swt := b.Switch(ret, susp) swt := b.Switch(ret, susp)
swt.Case(b.Const(constant.MakeInt64(0), b.Prog.Byte()), next) swt.Case(b.Const(constant.MakeInt64(0), b.Prog.Byte()), next)
@@ -669,5 +677,5 @@ func (b Builder) CoYield(setValueFn Function, value Expr, final Expr) {
panic(fmt.Errorf("yield %v not in async block", b.Func.Name())) panic(fmt.Errorf("yield %v not in async block", b.Func.Name()))
} }
b.Call(setValueFn.Expr, b.promise, value) b.Call(setValueFn.Expr, b.promise, value)
b.CoSuspend(b.AsyncToken(), b.Prog.BoolVal(false)) b.CoSuspend(b.AsyncToken(), final, nil)
} }

View File

@@ -55,6 +55,13 @@ func (p Program) tySiglongjmp() *types.Signature {
return p.sigljmpTy return p.sigljmpTy
} }
func (p Program) tyLLVMTrap() *types.Signature {
if p.llvmTrapTy == nil {
p.llvmTrapTy = types.NewSignatureType(nil, nil, nil, nil, nil, false)
}
return p.llvmTrapTy
}
func (b Builder) AllocaSigjmpBuf() Expr { func (b Builder) AllocaSigjmpBuf() Expr {
prog := b.Prog prog := b.Prog
n := unsafe.Sizeof(sigjmpbuf{}) n := unsafe.Sizeof(sigjmpbuf{})
@@ -77,6 +84,11 @@ func (b Builder) Siglongjmp(jb, retval Expr) {
// b.Unreachable() // b.Unreachable()
} }
func (b Builder) LLVMTrap() {
fn := b.Pkg.cFunc("llvm.trap", b.Prog.tyLLVMTrap())
b.Call(fn)
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
const ( const (

View File

@@ -193,6 +193,8 @@ type aProgram struct {
sigsetjmpTy *types.Signature sigsetjmpTy *types.Signature
sigljmpTy *types.Signature sigljmpTy *types.Signature
llvmTrapTy *types.Signature
// coroutine manipulation intrinsics (ordered by LLVM coroutine doc) // coroutine manipulation intrinsics (ordered by LLVM coroutine doc)
coDestroyTy *types.Signature coDestroyTy *types.Signature
coResumeTy *types.Signature coResumeTy *types.Signature

View File

@@ -68,6 +68,7 @@ type aBuilder struct {
asyncToken Expr asyncToken Expr
promise Expr promise Expr
onSuspBlk func(blk BasicBlock) (susp BasicBlock, next BasicBlock, clean BasicBlock) onSuspBlk func(blk BasicBlock) (susp BasicBlock, next BasicBlock, clean BasicBlock)
onReturn func()
blkOffset int blkOffset int
} }