Skip to content

Commit efa8f54

Browse files
committed
ssa,runtime: tighten recover to direct deferred calls (Defer-node model)
Re-expresses xgo-dev#1918 on the xgo-dev#2023 base (its remaining ~11k diff lines were the pre-xgo-dev#2012 funcinfo draft, superseded by the stage-5 chain): - recover() only succeeds when called directly by a deferred function (gc semantics): the panic node records the owning Defer frame at rethrow (panicKey/panicNode + GoDeferData), and Recover checks the caller is that frame's direct deferred call. Closure wraps carry StartRecoverFrameAlias/EndRecoverFrame so method-value and closure adapters stay transparent to the ownership check. - Rethrow keeps the xgo-dev#2023 PanicTraceback hook on the unrecovered path. - xfail: retire fixedbugs/issue4066 (2m-timeout entries; now runs in ~2.7s), fixedbugs/issue73916 and issue73916b (go1.26 recover semantics), validated on darwin/arm64 go1.26. Supersedes xgo-dev#1918.
1 parent 34206e9 commit efa8f54

15 files changed

Lines changed: 615 additions & 156 deletions

File tree

cl/_testgo/cgodefer/cgodefer.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,20 @@ import "C"
9090
// CHECK-NEXT: store ptr %32, ptr %18, align 8
9191
// CHECK-NEXT: %33 = extractvalue { ptr, i64, { ptr, ptr } } %31, 2
9292
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.FreeDeferNode"(ptr %30)
93-
// CHECK-NEXT: %34 = extractvalue { ptr, ptr } %33, 1
94-
// CHECK-NEXT: %35 = extractvalue { ptr, ptr } %33, 0
95-
// CHECK-NEXT: call void %35(ptr %34)
93+
// CHECK-NEXT: %34 = extractvalue { ptr, ptr } %33, 0
94+
// CHECK-NEXT: %35 = call ptr @"{{.*}}/runtime/internal/runtime.StartRecoverFrame"(ptr %34)
95+
// CHECK-NEXT: %36 = extractvalue { ptr, ptr } %33, 1
96+
// CHECK-NEXT: %37 = extractvalue { ptr, ptr } %33, 0
97+
// CHECK-NEXT: call void %37(ptr %36)
98+
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.EndRecoverFrame"(ptr %35)
9699
// CHECK-NEXT: br label %_llgo_8
97100
// CHECK-EMPTY:
98101
// CHECK-NEXT: _llgo_8: ; preds = %_llgo_7, %_llgo_2
99-
// CHECK-NEXT: %36 = load %"{{.*}}/runtime/internal/runtime.Defer", ptr %10, align 8
100-
// CHECK-NEXT: %37 = extractvalue %"{{.*}}/runtime/internal/runtime.Defer" %36, 2
101-
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.SetThreadDefer"(ptr %37)
102-
// CHECK-NEXT: %38 = load ptr, ptr %17, align 8
103-
// CHECK-NEXT: indirectbr ptr %38, [label %_llgo_3, label %_llgo_6]
102+
// CHECK-NEXT: %38 = load %"{{.*}}/runtime/internal/runtime.Defer", ptr %10, align 8
103+
// CHECK-NEXT: %39 = extractvalue %"{{.*}}/runtime/internal/runtime.Defer" %38, 2
104+
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.SetThreadDefer"(ptr %39)
105+
// CHECK-NEXT: %40 = load ptr, ptr %17, align 8
106+
// CHECK-NEXT: indirectbr ptr %40, [label %_llgo_3, label %_llgo_6]
104107
// CHECK-NEXT: }
105108
func main() {
106109
// CHECK-LABEL: define { ptr, ptr } @"{{.*}}/cl/_testgo/cgodefer.main$1"(ptr %0){{.*}} {

cl/_testgo/recoverthenpanic/in.go

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ package main
77

88
// CHECK-LABEL: define void @"{{.*}}/cl/_testgo/recoverthenpanic.End"(){{.*}} {
99
// CHECK-NEXT: _llgo_0:
10-
// CHECK-NEXT: %0 = call %"{{.*}}/runtime/internal/runtime.eface" @"{{.*}}/runtime/internal/runtime.Recover"()
10+
// CHECK-NEXT: %0 = call %"{{.*}}/runtime/internal/runtime.eface" @"{{.*}}/runtime/internal/runtime.Recover"(ptr @"{{.*}}/cl/_testgo/recoverthenpanic.End")
1111
// CHECK-NEXT: %1 = call i1 @"{{.*}}/runtime/internal/runtime.EfaceEqual"(%"{{.*}}/runtime/internal/runtime.eface" %0, %"{{.*}}/runtime/internal/runtime.eface" zeroinitializer)
1212
// CHECK-NEXT: %2 = xor i1 %1, true
1313
// CHECK-NEXT: %3 = call ptr @"{{.*}}/runtime/internal/runtime.GetThreadDefer"()
@@ -161,26 +161,28 @@ func main() {
161161
// CHECK-NEXT: _llgo_2: ; preds = %_llgo_5
162162
// CHECK-NEXT: store ptr blockaddress(@"{{.*}}/cl/_testgo/recoverthenpanic.main", %_llgo_3), ptr %8, align 8
163163
// CHECK-NEXT: %13 = load i64, ptr %7, align 8
164+
// CHECK-NEXT: %14 = call ptr @"{{.*}}/runtime/internal/runtime.StartRecoverFrame"(ptr @"{{.*}}/cl/_testgo/recoverthenpanic.End")
164165
// CHECK-NEXT: call void @"{{.*}}/cl/_testgo/recoverthenpanic.End"()
165-
// CHECK-NEXT: %14 = load %"{{.*}}/runtime/internal/runtime.Defer", ptr %2, align 8
166-
// CHECK-NEXT: %15 = extractvalue %"{{.*}}/runtime/internal/runtime.Defer" %14, 2
167-
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.SetThreadDefer"(ptr %15)
168-
// CHECK-NEXT: %16 = load ptr, ptr %9, align 8
169-
// CHECK-NEXT: indirectbr ptr %16, [label %_llgo_3]
166+
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.EndRecoverFrame"(ptr %14)
167+
// CHECK-NEXT: %15 = load %"{{.*}}/runtime/internal/runtime.Defer", ptr %2, align 8
168+
// CHECK-NEXT: %16 = extractvalue %"{{.*}}/runtime/internal/runtime.Defer" %15, 2
169+
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.SetThreadDefer"(ptr %16)
170+
// CHECK-NEXT: %17 = load ptr, ptr %9, align 8
171+
// CHECK-NEXT: indirectbr ptr %17, [label %_llgo_3]
170172
// CHECK-EMPTY:
171173
// CHECK-NEXT: _llgo_3: ; preds = %_llgo_5, %_llgo_2
172174
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Rethrow"(ptr %0)
173175
// CHECK-NEXT: br label %_llgo_1
174176
// CHECK-EMPTY:
175177
// CHECK-NEXT: _llgo_4: ; preds = %_llgo_0
176-
// CHECK-NEXT: %17 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16)
177-
// CHECK-NEXT: store %"{{.*}}/runtime/internal/runtime.String" { ptr @2, i64 13 }, ptr %17, align 8
178-
// CHECK-NEXT: %18 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %17, 1
179-
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %18)
178+
// CHECK-NEXT: %18 = call ptr @"{{.*}}/runtime/internal/runtime.AllocU"(i64 16)
179+
// CHECK-NEXT: store %"{{.*}}/runtime/internal/runtime.String" { ptr @2, i64 13 }, ptr %18, align 8
180+
// CHECK-NEXT: %19 = insertvalue %"{{.*}}/runtime/internal/runtime.eface" { ptr @_llgo_string, ptr undef }, ptr %18, 1
181+
// CHECK-NEXT: call void @"{{.*}}/runtime/internal/runtime.Panic"(%"{{.*}}/runtime/internal/runtime.eface" %19)
180182
// CHECK-NEXT: unreachable
181183
// CHECK-EMPTY:
182184
// CHECK-NEXT: _llgo_5: ; preds = %_llgo_0
183185
// CHECK-NEXT: store ptr blockaddress(@"{{.*}}/cl/_testgo/recoverthenpanic.main", %_llgo_3), ptr %9, align 8
184-
// CHECK-NEXT: %19 = load ptr, ptr %8, align 8
185-
// CHECK-NEXT: indirectbr ptr %19, [label %_llgo_3, label %_llgo_2]
186+
// CHECK-NEXT: %20 = load ptr, ptr %8, align 8
187+
// CHECK-NEXT: indirectbr ptr %20, [label %_llgo_3, label %_llgo_2]
186188
// CHECK-NEXT: }

cl/cgo_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,47 @@ func findStaticCall(t *testing.T, fn *gossa.Function, name string) *gossa.Call {
207207
return nil
208208
}
209209

210+
func TestRecoverCallClassificationHelpers(t *testing.T) {
211+
if functionUsesRecover(nil) {
212+
t.Fatal("nil function should not report recover use")
213+
}
214+
215+
ssaPkg, _, _ := buildGoSSAPkg(t, `
216+
package foo
217+
218+
func usesRecover() {
219+
recover()
220+
}
221+
222+
func plain() {}
223+
`)
224+
usesRecover := ssaPkg.Members["usesRecover"].(*gossa.Function)
225+
plain := ssaPkg.Members["plain"].(*gossa.Function)
226+
ctx := &context{}
227+
228+
if !functionUsesRecover(usesRecover) {
229+
t.Fatal("usesRecover should report direct recover use")
230+
}
231+
if functionUsesRecover(plain) {
232+
t.Fatal("plain should not report recover use")
233+
}
234+
if !ctx.callMayRecover(usesRecover) {
235+
t.Fatal("function using recover should be recover-capable")
236+
}
237+
if ctx.callMayRecover(plain) {
238+
t.Fatal("plain static function should not be recover-capable")
239+
}
240+
if !ctx.callMayRecover(&gossa.MakeClosure{}) {
241+
t.Fatal("unknown closure target should conservatively be recover-capable")
242+
}
243+
if !ctx.callMayRecover(&gossa.Call{}) {
244+
t.Fatal("function value returned by a call should conservatively be recover-capable")
245+
}
246+
if !ctx.callMayRecover(nil) {
247+
t.Fatal("unknown call value should conservatively be recover-capable")
248+
}
249+
}
250+
210251
func TestCgoCgocall_InitArgsFromParams(t *testing.T) {
211252
ssaPkg, _, _ := buildGoSSAPkg(t, `
212253
package foo

cl/compile.go

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ type context struct {
179179
paramDIVars map[*types.Var]llssa.DIVar
180180
runtimeCallerFuncs map[*ssa.Function]bool
181181
pcLineSeq uint64
182+
recoverSlots map[*ssa.Alloc]none
182183

183184
patches Patches
184185
blkInfos []blocks.Info
@@ -552,12 +553,15 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
552553
noInlineDirective := hasNoInlineDirective(f)
553554
runtimeStackNoInline := needsRuntimeStackNoInline(pkgTypes, f)
554555
pcLineNoInline := p.needsPCLineNoInline(f)
555-
if disableInline || noInlineDirective || runtimeStackNoInline || pcLineNoInline {
556+
if disableInline || noInlineDirective || runtimeStackNoInline || pcLineNoInline || functionUsesRecover(f) {
556557
fn.Inline(llssa.NoInline)
557558
}
558559
if noInlineDirective || runtimeStackNoInline || pcLineNoInline {
559560
fn.DisableTailCalls()
560561
}
562+
if functionUsesRecover(f) {
563+
fn.Expr = fn.Expr.MarkMayRecover()
564+
}
561565
p.funcs[f] = fn
562566
isCgo := isCgoExternSymbol(f)
563567
if nblk := len(f.Blocks); nblk > 0 {
@@ -594,12 +598,19 @@ func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Fun
594598
dbgSymsEnabled := enableDbgSyms && (f == nil || f.Origin() == nil)
595599
p.inits = append(p.inits, func() {
596600
oldFn, oldGoFn, oldMethodNilDerefChecks, oldCallerFrameMark := p.fn, p.goFn, p.methodNilDerefChecks, p.callerFrameMark
601+
oldRecoverSlots := p.recoverSlots
597602
p.fn = fn
598603
p.goFn = f
599604
p.callerFrameMark = llssa.Nil
600605
p.state = state // restore pkgState when compiling funcBody
606+
if f.Recover != nil {
607+
p.recoverSlots = make(map[*ssa.Alloc]none)
608+
} else {
609+
p.recoverSlots = nil
610+
}
601611
defer func() {
602612
p.fn, p.goFn, p.methodNilDerefChecks, p.callerFrameMark = oldFn, oldGoFn, oldMethodNilDerefChecks, oldCallerFrameMark
613+
p.recoverSlots = oldRecoverSlots
603614
}()
604615
p.phis = nil
605616
if dbgSymsEnabled {
@@ -1096,6 +1107,29 @@ func (p *context) syntheticMakeSliceCap(v *ssa.Slice) (llssa.Expr, bool) {
10961107
return p.prog.IntVal(uint64(arr.Len()), p.prog.Int()), true
10971108
}
10981109

1110+
func (p *context) markRecoverSlot(v *ssa.Alloc) {
1111+
if p.recoverSlots == nil || v.Heap {
1112+
return
1113+
}
1114+
p.recoverSlots[v] = none{}
1115+
}
1116+
1117+
func (p *context) isRecoverSlotAddr(v ssa.Value) bool {
1118+
if p.recoverSlots == nil {
1119+
return false
1120+
}
1121+
switch v := v.(type) {
1122+
case *ssa.Alloc:
1123+
_, ok := p.recoverSlots[v]
1124+
return ok
1125+
case *ssa.FieldAddr:
1126+
return p.isRecoverSlotAddr(v.X)
1127+
case *ssa.IndexAddr:
1128+
return p.isRecoverSlotAddr(v.X)
1129+
}
1130+
return false
1131+
}
1132+
10991133
func isAllocVargs(ctx *context, v *ssa.Alloc) bool {
11001134
refs := *v.Referrers()
11011135
n := len(refs)
@@ -1273,6 +1307,9 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
12731307
}
12741308
}
12751309
ret = b.UnOp(v.Op, x)
1310+
if v.Op == token.MUL && p.isRecoverSlotAddr(v.X) {
1311+
ret = ret.SetVolatile(true)
1312+
}
12761313
}
12771314
case *ssa.ChangeType:
12781315
t := v.Type()
@@ -1307,6 +1344,10 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
13071344
}
13081345
elem := p.type_(t.Elem(), llssa.InGo)
13091346
ret = b.Alloc(elem, v.Heap)
1347+
p.markRecoverSlot(v)
1348+
if p.isRecoverSlotAddr(v) {
1349+
b.Store(ret, p.prog.Zero(elem)).SetVolatile(true)
1350+
}
13101351
case *ssa.IndexAddr:
13111352
vx := v.X
13121353
if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs index
@@ -1573,7 +1614,10 @@ func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) {
15731614
}
15741615
ptr := p.compileValue(b, va)
15751616
val := p.compileValue(b, v.Val)
1576-
b.Store(ptr, val)
1617+
store := b.Store(ptr, val)
1618+
if p.isRecoverSlotAddr(va) {
1619+
store.SetVolatile(true)
1620+
}
15771621
case *ssa.Jump:
15781622
jmpb := p.jumpTo(v)
15791623
b.Jump(jmpb)
@@ -1647,6 +1691,25 @@ func (p *context) getLocalVariable(b llssa.Builder, fn *ssa.Function, v *types.V
16471691
return b.DIVarAuto(scope, pos, v.Name(), t)
16481692
}
16491693

1694+
func functionUsesRecover(fn *ssa.Function) bool {
1695+
if fn == nil {
1696+
return false
1697+
}
1698+
for _, block := range fn.Blocks {
1699+
for _, instr := range block.Instrs {
1700+
call, ok := instr.(ssa.CallInstruction)
1701+
if !ok {
1702+
continue
1703+
}
1704+
builtin, ok := call.Common().Value.(*ssa.Builtin)
1705+
if ok && builtin.Name() == "recover" {
1706+
return true
1707+
}
1708+
}
1709+
}
1710+
return false
1711+
}
1712+
16501713
func (p *context) compileFunction(v *ssa.Function) (goFn llssa.Function, pyFn llssa.PyObjRef, kind int) {
16511714
// TODO(xsw) v.Pkg == nil: means auto generated function?
16521715
if v.Pkg == p.goPkg || v.Pkg == nil {

cl/instr.go

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1765,12 +1765,36 @@ func (p *context) deferStackOwner(fn *ssa.Function) llssa.Function {
17651765
return owner
17661766
}
17671767

1768-
func (p *context) emitDo(b llssa.Builder, act llssa.DoAction, ds *explicitDeferStack, fn llssa.Expr, buildCall func(llssa.Builder, llssa.Expr, ...llssa.Expr) llssa.Expr, args ...llssa.Expr) llssa.Expr {
1768+
func (p *context) emitDo(b llssa.Builder, act llssa.DoAction, ds *explicitDeferStack, mayRecover bool, fn llssa.Expr, buildCall func(llssa.Builder, llssa.Expr, ...llssa.Expr) llssa.Expr, args ...llssa.Expr) llssa.Expr {
17691769
if ds != nil {
1770-
b.DeferTo(ds.owner, ds.stack, fn, buildCall, args...)
1770+
b.DeferToRecover(ds.owner, ds.stack, mayRecover, fn, buildCall, args...)
17711771
return llssa.Nil
17721772
}
1773-
return b.Do(act, fn, buildCall, args...)
1773+
switch act {
1774+
case llssa.Call, llssa.Go:
1775+
return b.Do(act, fn, buildCall, args...)
1776+
default:
1777+
b.DeferRecover(act, mayRecover, fn, buildCall, args...)
1778+
return llssa.Nil
1779+
}
1780+
}
1781+
1782+
func (p *context) callMayRecover(v ssa.Value) bool {
1783+
switch v := v.(type) {
1784+
case *ssa.Builtin:
1785+
return false
1786+
case *ssa.Function:
1787+
return functionUsesRecover(v)
1788+
case *ssa.MakeClosure:
1789+
if fn, ok := v.Fn.(*ssa.Function); ok {
1790+
return functionUsesRecover(fn)
1791+
}
1792+
return true
1793+
case *ssa.Call:
1794+
// The deferred callee is the call result, not the factory function.
1795+
return true
1796+
}
1797+
return true
17741798
}
17751799

17761800
func (p *context) staticArrayLenBuiltinArg(b llssa.Builder, arg ssa.Value) (llssa.Expr, bool) {
@@ -1925,6 +1949,7 @@ func (p *context) callEx(b llssa.Builder, act llssa.DoAction, call *ssa.CallComm
19251949
p.recordCallerLocationForCall(b, call)
19261950
p.emitPCLineLabel(b, call.Pos())
19271951
cv := call.Value
1952+
mayRecover := p.callMayRecover(cv)
19281953
if mthd := call.Method; mthd != nil {
19291954
reflectCheck := p.reflectTypeMethodCheck(call, mthd)
19301955
o := p.compileValue(b, cv)
@@ -1934,7 +1959,7 @@ func (p *context) callEx(b llssa.Builder, act llssa.DoAction, call *ssa.CallComm
19341959
hasVArg = fnHasVArg
19351960
}
19361961
args := p.compileValues(b, call.Args, hasVArg)
1937-
ret = p.emitDo(b, act, ds, fn, llssa.Builder.Call, args...)
1962+
ret = p.emitDo(b, act, ds, true, fn, llssa.Builder.Call, args...)
19381963
if reflectCheck.Kind&llssa.ReflectTypeMethodByName != 0 && reflectCheck.Name == "" {
19391964
b.MarkReflectTypeMethodByNameExpr(ret, 1)
19401965
}
@@ -1968,7 +1993,7 @@ func (p *context) callEx(b llssa.Builder, act llssa.DoAction, call *ssa.CallComm
19681993
}
19691994
}
19701995
args := p.compileValues(b, args, kind)
1971-
ret = p.emitDo(b, act, ds, llssa.Builtin(fn), llssa.Builder.Call, args...)
1996+
ret = p.emitDo(b, act, ds, false, llssa.Builtin(fn), llssa.Builder.Call, args...)
19721997
case *ssa.Function:
19731998
aFn, pyFn, ftype := p.compileFunction(cv)
19741999
// TODO(xsw): check ca != llssa.Call
@@ -1977,13 +2002,13 @@ func (p *context) callEx(b llssa.Builder, act llssa.DoAction, call *ssa.CallComm
19772002
p.inCFunc = true
19782003
args := p.compileValues(b, args, kind)
19792004
p.inCFunc = false
1980-
ret = p.emitDo(b, act, ds, aFn.Expr, llssa.Builder.Call, args...)
2005+
ret = p.emitDo(b, act, ds, mayRecover, aFn.Expr, llssa.Builder.Call, args...)
19812006
case goFunc:
19822007
args := p.compileValues(b, args, kind)
1983-
ret = p.emitDo(b, act, ds, aFn.Expr, llssa.Builder.Call, args...)
2008+
ret = p.emitDo(b, act, ds, mayRecover, aFn.Expr, llssa.Builder.Call, args...)
19842009
case pyFunc:
19852010
args := p.compileValues(b, args, kind)
1986-
ret = p.emitDo(b, act, ds, pyFn.Expr, llssa.Builder.Call, args...)
2011+
ret = p.emitDo(b, act, ds, mayRecover, pyFn.Expr, llssa.Builder.Call, args...)
19872012
case llgoPyList:
19882013
args := p.compileValues(b, args, fnHasVArg)
19892014
ret = b.PyList(args...)
@@ -2057,33 +2082,33 @@ func (p *context) callEx(b llssa.Builder, act llssa.DoAction, call *ssa.CallComm
20572082
b.Unreachable()
20582083
case llgoAtomicLoad:
20592084
args := p.compileValues(b, args, kind)
2060-
ret = p.emitDo(b, act, ds, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr {
2085+
ret = p.emitDo(b, act, ds, false, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr {
20612086
return p.atomicLoad(b, args)
20622087
}, args...)
20632088
case llgoAtomicStore:
20642089
args := p.compileValues(b, args, kind)
2065-
p.emitDo(b, act, ds, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr {
2090+
p.emitDo(b, act, ds, false, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr {
20662091
return p.atomicStore(b, args)
20672092
}, args...)
20682093
case llgoAtomicCmpXchg:
20692094
args := p.compileValues(b, args, kind)
2070-
ret = p.emitDo(b, act, ds, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr {
2095+
ret = p.emitDo(b, act, ds, false, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr {
20712096
return p.atomicCmpXchg(b, args)
20722097
}, args...)
20732098
case llgoAtomicCmpXchgOK:
20742099
args := p.compileValues(b, args, kind)
2075-
ret = p.emitDo(b, act, ds, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr {
2100+
ret = p.emitDo(b, act, ds, false, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr {
20762101
return p.atomicCmpXchgOK(b, args)
20772102
}, args...)
20782103
case llgoAtomicAddReturnNew:
20792104
args := p.compileValues(b, args, kind)
2080-
ret = p.emitDo(b, act, ds, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr {
2105+
ret = p.emitDo(b, act, ds, false, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr {
20812106
return b.BinOp(token.ADD, p.atomic(b, llssa.OpAdd, args), args[1])
20822107
}, args...)
20832108
default:
20842109
if ftype >= llgoAtomicOpBase && ftype <= llgoAtomicOpLast {
20852110
args := p.compileValues(b, args, kind)
2086-
ret = p.emitDo(b, act, ds, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr {
2111+
ret = p.emitDo(b, act, ds, false, llssa.Nil, func(b llssa.Builder, _ llssa.Expr, args ...llssa.Expr) llssa.Expr {
20872112
return p.atomic(b, llssa.AtomicOp(ftype-llgoAtomicOpBase), args)
20882113
}, args...)
20892114
} else {
@@ -2093,7 +2118,7 @@ func (p *context) callEx(b llssa.Builder, act llssa.DoAction, call *ssa.CallComm
20932118
default:
20942119
fn := p.compileValue(b, cv)
20952120
args := p.compileValues(b, args, kind)
2096-
ret = p.emitDo(b, act, ds, fn, llssa.Builder.Call, args...)
2121+
ret = p.emitDo(b, act, ds, mayRecover, fn, llssa.Builder.Call, args...)
20972122
}
20982123
return
20992124
}

0 commit comments

Comments
 (0)