@@ -38,12 +38,24 @@ type deferFrame struct {
3838 JumpPC unsafe.Pointer // pc to return to
3939 ExtraRegs [deferExtraRegs ]unsafe.Pointer // extra registers (depending on the architecture)
4040 Previous * deferFrame // previous recover buffer pointer
41- Panicking bool // true iff this defer frame is panicking
41+ Panicking panicState // not panicking, panicking, or in Goexit
4242 PanicValue interface {} // panic value, might be nil for panic(nil) for example
4343}
4444
45+ type panicState uint8
46+
47+ const (
48+ panicFalse panicState = iota
49+ panicTrue
50+ panicGoexit
51+ )
52+
4553// Builtin function panic(msg), used as a compiler intrinsic.
4654func _panic (message interface {}) {
55+ panicOrGoexit (message , panicTrue )
56+ }
57+
58+ func panicOrGoexit (message interface {}, panicking panicState ) {
4759 if panicStrategy () == tinygo .PanicStrategyTrap {
4860 trap ()
4961 }
@@ -53,11 +65,16 @@ func _panic(message interface{}) {
5365 frame := (* deferFrame )(task .Current ().DeferFrame )
5466 if frame != nil {
5567 frame .PanicValue = message
56- frame .Panicking = true
68+ frame .Panicking = panicking
5769 tinygo_longjmp (frame )
5870 // unreachable
5971 }
6072 }
73+ if panicking == panicGoexit {
74+ // Call to Goexit() instead of a panic.
75+ // Exit the goroutine instead of printing a panic message.
76+ deadlock ()
77+ }
6178 printstring ("panic: " )
6279 printitf (message )
6380 printnl ()
@@ -103,7 +120,7 @@ func setupDeferFrame(frame *deferFrame, jumpSP unsafe.Pointer) {
103120 currentTask := task .Current ()
104121 frame .Previous = (* deferFrame )(currentTask .DeferFrame )
105122 frame .JumpSP = jumpSP
106- frame .Panicking = false
123+ frame .Panicking = panicFalse
107124 currentTask .DeferFrame = unsafe .Pointer (frame )
108125}
109126
@@ -115,10 +132,10 @@ func setupDeferFrame(frame *deferFrame, jumpSP unsafe.Pointer) {
115132//go:nobounds
116133func destroyDeferFrame (frame * deferFrame ) {
117134 task .Current ().DeferFrame = unsafe .Pointer (frame .Previous )
118- if frame .Panicking {
135+ if frame .Panicking != panicFalse {
119136 // We're still panicking!
120137 // Re-raise the panic now.
121- _panic (frame .PanicValue )
138+ panicOrGoexit (frame .PanicValue , frame . Panicking )
122139 }
123140}
124141
@@ -143,10 +160,15 @@ func _recover(useParentFrame bool) interface{} {
143160 // already), but instead from the previous frame.
144161 frame = frame .Previous
145162 }
146- if frame != nil && frame .Panicking {
163+ if frame != nil && frame .Panicking != panicFalse {
164+ if frame .Panicking == panicGoexit {
165+ // Special value that indicates we're exiting the goroutine using
166+ // Goexit(). Therefore, make this recover call a no-op.
167+ return nil
168+ }
147169 // Only the first call to recover returns the panic value. It also stops
148170 // the panicking sequence, hence setting panicking to false.
149- frame .Panicking = false
171+ frame .Panicking = panicFalse
150172 return frame .PanicValue
151173 }
152174 // Not panicking, so return a nil interface.
0 commit comments