@@ -38,12 +38,24 @@ type deferFrame struct {
38
38
JumpPC unsafe.Pointer // pc to return to
39
39
ExtraRegs [deferExtraRegs ]unsafe.Pointer // extra registers (depending on the architecture)
40
40
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
42
42
PanicValue interface {} // panic value, might be nil for panic(nil) for example
43
43
}
44
44
45
+ type panicState uint8
46
+
47
+ const (
48
+ panicFalse panicState = iota
49
+ panicTrue
50
+ panicGoexit
51
+ )
52
+
45
53
// Builtin function panic(msg), used as a compiler intrinsic.
46
54
func _panic (message interface {}) {
55
+ panicOrGoexit (message , panicTrue )
56
+ }
57
+
58
+ func panicOrGoexit (message interface {}, panicking panicState ) {
47
59
if panicStrategy () == tinygo .PanicStrategyTrap {
48
60
trap ()
49
61
}
@@ -53,11 +65,16 @@ func _panic(message interface{}) {
53
65
frame := (* deferFrame )(task .Current ().DeferFrame )
54
66
if frame != nil {
55
67
frame .PanicValue = message
56
- frame .Panicking = true
68
+ frame .Panicking = panicking
57
69
tinygo_longjmp (frame )
58
70
// unreachable
59
71
}
60
72
}
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
+ }
61
78
printstring ("panic: " )
62
79
printitf (message )
63
80
printnl ()
@@ -103,7 +120,7 @@ func setupDeferFrame(frame *deferFrame, jumpSP unsafe.Pointer) {
103
120
currentTask := task .Current ()
104
121
frame .Previous = (* deferFrame )(currentTask .DeferFrame )
105
122
frame .JumpSP = jumpSP
106
- frame .Panicking = false
123
+ frame .Panicking = panicFalse
107
124
currentTask .DeferFrame = unsafe .Pointer (frame )
108
125
}
109
126
@@ -115,10 +132,10 @@ func setupDeferFrame(frame *deferFrame, jumpSP unsafe.Pointer) {
115
132
//go:nobounds
116
133
func destroyDeferFrame (frame * deferFrame ) {
117
134
task .Current ().DeferFrame = unsafe .Pointer (frame .Previous )
118
- if frame .Panicking {
135
+ if frame .Panicking != panicFalse {
119
136
// We're still panicking!
120
137
// Re-raise the panic now.
121
- _panic (frame .PanicValue )
138
+ panicOrGoexit (frame .PanicValue , frame . Panicking )
122
139
}
123
140
}
124
141
@@ -143,10 +160,15 @@ func _recover(useParentFrame bool) interface{} {
143
160
// already), but instead from the previous frame.
144
161
frame = frame .Previous
145
162
}
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
+ }
147
169
// Only the first call to recover returns the panic value. It also stops
148
170
// the panicking sequence, hence setting panicking to false.
149
- frame .Panicking = false
171
+ frame .Panicking = panicFalse
150
172
return frame .PanicValue
151
173
}
152
174
// Not panicking, so return a nil interface.
0 commit comments