blob: a1662812de8c4dc1ae8322f1dd2697ada717dd05 [file] [log] [blame]
Keith Randall523aa932014-08-18 13:26:28 -07001// Copyright 2014 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package runtime
6
Keith Randallf4407372014-09-03 08:49:43 -07007import "unsafe"
8
Russ Cox7006aaf2014-08-30 14:18:41 -04009var indexError = error(errorString("index out of range"))
10
Keith Randall523aa932014-08-18 13:26:28 -070011func panicindex() {
Russ Cox7006aaf2014-08-30 14:18:41 -040012 panic(indexError)
Keith Randall523aa932014-08-18 13:26:28 -070013}
14
Russ Cox7006aaf2014-08-30 14:18:41 -040015var sliceError = error(errorString("slice bounds out of range"))
16
Keith Randall523aa932014-08-18 13:26:28 -070017func panicslice() {
Russ Cox7006aaf2014-08-30 14:18:41 -040018 panic(sliceError)
Keith Randall523aa932014-08-18 13:26:28 -070019}
Keith Randallf4407372014-09-03 08:49:43 -070020
21var divideError = error(errorString("integer divide by zero"))
22
23func panicdivide() {
24 panic(divideError)
25}
26
Russ Coxc81a0ed2014-09-08 14:05:23 -040027var overflowError = error(errorString("integer overflow"))
28
29func panicoverflow() {
30 panic(overflowError)
31}
32
33var floatError = error(errorString("floating point error"))
34
35func panicfloat() {
36 panic(floatError)
37}
38
39var memoryError = error(errorString("invalid memory address or nil pointer dereference"))
40
41func panicmem() {
42 panic(memoryError)
43}
44
Keith Randallf4407372014-09-03 08:49:43 -070045func throwreturn() {
Keith Randallb2a950b2014-12-27 20:58:00 -080046 throw("no return at end of a typed function - compiler is broken")
Keith Randallf4407372014-09-03 08:49:43 -070047}
48
49func throwinit() {
Keith Randallb2a950b2014-12-27 20:58:00 -080050 throw("recursive call during initialization - linker skew")
Keith Randallf4407372014-09-03 08:49:43 -070051}
52
53// Create a new deferred function fn with siz bytes of arguments.
54// The compiler turns a defer statement into a call to this.
55//go:nosplit
56func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
Russ Coxd98553a2014-11-11 17:04:34 -050057 if getg().m.curg != getg() {
Russ Cox656be312014-11-12 14:54:31 -050058 // go code on the system stack can't defer
Keith Randallb2a950b2014-12-27 20:58:00 -080059 throw("defer on system stack")
Russ Coxd98553a2014-11-11 17:04:34 -050060 }
61
Keith Randallf4407372014-09-03 08:49:43 -070062 // the arguments of fn are in a perilous state. The stack map
63 // for deferproc does not describe them. So we can't let garbage
64 // collection or stack copying trigger until we've copied them out
Keith Randall53c52262014-12-08 14:18:58 -080065 // to somewhere safe. The memmove below does that.
66 // Until the copy completes, we can only call nosplit routines.
67 sp := getcallersp(unsafe.Pointer(&siz))
68 argp := uintptr(unsafe.Pointer(&fn)) + unsafe.Sizeof(fn)
Russ Coxd98553a2014-11-11 17:04:34 -050069 callerpc := getcallerpc(unsafe.Pointer(&siz))
Keith Randallf4407372014-09-03 08:49:43 -070070
Russ Cox656be312014-11-12 14:54:31 -050071 systemstack(func() {
Russ Coxd98553a2014-11-11 17:04:34 -050072 d := newdefer(siz)
73 if d._panic != nil {
Keith Randallb2a950b2014-12-27 20:58:00 -080074 throw("deferproc: d.panic != nil after newdefer")
Russ Coxd98553a2014-11-11 17:04:34 -050075 }
76 d.fn = fn
77 d.pc = callerpc
Keith Randall53c52262014-12-08 14:18:58 -080078 d.sp = sp
Russ Coxd98553a2014-11-11 17:04:34 -050079 memmove(add(unsafe.Pointer(d), unsafe.Sizeof(*d)), unsafe.Pointer(argp), uintptr(siz))
80 })
Keith Randallf4407372014-09-03 08:49:43 -070081
82 // deferproc returns 0 normally.
83 // a deferred func that stops a panic
84 // makes the deferproc return 1.
85 // the code the compiler generates always
86 // checks the return value and jumps to the
87 // end of the function if deferproc returns != 0.
88 return0()
89 // No code can go here - the C return register has
90 // been set and must not be clobbered.
91}
92
Russ Coxf95beae2014-09-16 10:36:38 -040093// Small malloc size classes >= 16 are the multiples of 16: 16, 32, 48, 64, 80, 96, 112, 128, 144, ...
94// Each P holds a pool for defers with small arg sizes.
95// Assign defer allocations to pools by rounding to 16, to match malloc size classes.
96
97const (
98 deferHeaderSize = unsafe.Sizeof(_defer{})
99 minDeferAlloc = (deferHeaderSize + 15) &^ 15
100 minDeferArgs = minDeferAlloc - deferHeaderSize
101)
Keith Randallf4407372014-09-03 08:49:43 -0700102
103// defer size class for arg size sz
Russ Cox857d55a2014-09-08 17:37:49 -0400104//go:nosplit
Keith Randallf4407372014-09-03 08:49:43 -0700105func deferclass(siz uintptr) uintptr {
Russ Coxf95beae2014-09-16 10:36:38 -0400106 if siz <= minDeferArgs {
107 return 0
108 }
109 return (siz - minDeferArgs + 15) / 16
Keith Randallf4407372014-09-03 08:49:43 -0700110}
111
112// total size of memory block for defer with arg size sz
113func totaldefersize(siz uintptr) uintptr {
Russ Coxf95beae2014-09-16 10:36:38 -0400114 if siz <= minDeferArgs {
115 return minDeferAlloc
116 }
117 return deferHeaderSize + siz
Keith Randallf4407372014-09-03 08:49:43 -0700118}
119
120// Ensure that defer arg sizes that map to the same defer size class
121// also map to the same malloc size class.
122func testdefersizes() {
123 var m [len(p{}.deferpool)]int32
124
125 for i := range m {
126 m[i] = -1
127 }
128 for i := uintptr(0); ; i++ {
129 defersc := deferclass(i)
130 if defersc >= uintptr(len(m)) {
131 break
132 }
Keith Randall0bb8fc62014-12-28 23:16:32 -0800133 siz := roundupsize(totaldefersize(i))
Keith Randallf4407372014-09-03 08:49:43 -0700134 if m[defersc] < 0 {
135 m[defersc] = int32(siz)
136 continue
137 }
138 if m[defersc] != int32(siz) {
139 print("bad defer size class: i=", i, " siz=", siz, " defersc=", defersc, "\n")
Keith Randallb2a950b2014-12-27 20:58:00 -0800140 throw("bad defer size class")
Keith Randallf4407372014-09-03 08:49:43 -0700141 }
142 }
143}
144
Russ Coxf95beae2014-09-16 10:36:38 -0400145// The arguments associated with a deferred call are stored
146// immediately after the _defer header in memory.
147//go:nosplit
148func deferArgs(d *_defer) unsafe.Pointer {
149 return add(unsafe.Pointer(d), unsafe.Sizeof(*d))
150}
151
152var deferType *_type // type of _defer struct
153
154func init() {
155 var x interface{}
156 x = (*_defer)(nil)
157 deferType = (*(**ptrtype)(unsafe.Pointer(&x))).elem
158}
159
Keith Randallf4407372014-09-03 08:49:43 -0700160// Allocate a Defer, usually using per-P pool.
161// Each defer must be released with freedefer.
Austin Clements0e8fed02014-11-18 09:54:50 -0500162// Note: runs on g0 stack
Keith Randallf4407372014-09-03 08:49:43 -0700163func newdefer(siz int32) *_defer {
164 var d *_defer
165 sc := deferclass(uintptr(siz))
166 mp := acquirem()
167 if sc < uintptr(len(p{}.deferpool)) {
Russ Cox181e26b2015-04-17 00:21:30 -0400168 pp := mp.p.ptr()
Dmitry Vyukovb759e222015-02-05 13:35:41 +0000169 if len(pp.deferpool[sc]) == 0 && sched.deferpool[sc] != nil {
170 lock(&sched.deferlock)
171 for len(pp.deferpool[sc]) < cap(pp.deferpool[sc])/2 && sched.deferpool[sc] != nil {
172 d := sched.deferpool[sc]
173 sched.deferpool[sc] = d.link
174 d.link = nil
175 pp.deferpool[sc] = append(pp.deferpool[sc], d)
176 }
177 unlock(&sched.deferlock)
178 }
Russ Cox84f53332015-03-05 09:52:41 -0500179 if n := len(pp.deferpool[sc]); n > 0 {
180 d = pp.deferpool[sc][n-1]
181 pp.deferpool[sc][n-1] = nil
182 pp.deferpool[sc] = pp.deferpool[sc][:n-1]
Keith Randallf4407372014-09-03 08:49:43 -0700183 }
184 }
185 if d == nil {
Russ Coxf95beae2014-09-16 10:36:38 -0400186 // Allocate new defer+args.
Keith Randall0bb8fc62014-12-28 23:16:32 -0800187 total := roundupsize(totaldefersize(uintptr(siz)))
Russ Coxf95beae2014-09-16 10:36:38 -0400188 d = (*_defer)(mallocgc(total, deferType, 0))
Keith Randallf4407372014-09-03 08:49:43 -0700189 }
190 d.siz = siz
Keith Randallf4407372014-09-03 08:49:43 -0700191 gp := mp.curg
192 d.link = gp._defer
193 gp._defer = d
194 releasem(mp)
195 return d
196}
197
198// Free the given defer.
199// The defer cannot be used after this call.
200func freedefer(d *_defer) {
Russ Coxe6708ee9b2014-10-07 23:17:31 -0400201 if d._panic != nil {
Russ Coxf950a142014-10-07 23:39:00 -0400202 freedeferpanic()
Russ Coxe6708ee9b2014-10-07 23:17:31 -0400203 }
Russ Cox94bdf132014-10-08 00:03:50 -0400204 if d.fn != nil {
205 freedeferfn()
206 }
Keith Randallf4407372014-09-03 08:49:43 -0700207 sc := deferclass(uintptr(d.siz))
208 if sc < uintptr(len(p{}.deferpool)) {
209 mp := acquirem()
Russ Cox181e26b2015-04-17 00:21:30 -0400210 pp := mp.p.ptr()
Dmitry Vyukovb759e222015-02-05 13:35:41 +0000211 if len(pp.deferpool[sc]) == cap(pp.deferpool[sc]) {
212 // Transfer half of local cache to the central cache.
213 var first, last *_defer
214 for len(pp.deferpool[sc]) > cap(pp.deferpool[sc])/2 {
Russ Cox84f53332015-03-05 09:52:41 -0500215 n := len(pp.deferpool[sc])
216 d := pp.deferpool[sc][n-1]
217 pp.deferpool[sc][n-1] = nil
218 pp.deferpool[sc] = pp.deferpool[sc][:n-1]
Dmitry Vyukovb759e222015-02-05 13:35:41 +0000219 if first == nil {
220 first = d
221 } else {
222 last.link = d
223 }
224 last = d
225 }
226 lock(&sched.deferlock)
227 last.link = sched.deferpool[sc]
228 sched.deferpool[sc] = first
229 unlock(&sched.deferlock)
230 }
Russ Coxf95beae2014-09-16 10:36:38 -0400231 *d = _defer{}
Dmitry Vyukovb759e222015-02-05 13:35:41 +0000232 pp.deferpool[sc] = append(pp.deferpool[sc], d)
Keith Randallf4407372014-09-03 08:49:43 -0700233 releasem(mp)
Keith Randallf4407372014-09-03 08:49:43 -0700234 }
235}
236
Russ Coxf950a142014-10-07 23:39:00 -0400237// Separate function so that it can split stack.
238// Windows otherwise runs out of stack space.
239func freedeferpanic() {
240 // _panic must be cleared before d is unlinked from gp.
Keith Randallb2a950b2014-12-27 20:58:00 -0800241 throw("freedefer with d._panic != nil")
Russ Coxf950a142014-10-07 23:39:00 -0400242}
243
Russ Cox94bdf132014-10-08 00:03:50 -0400244func freedeferfn() {
245 // fn must be cleared before d is unlinked from gp.
Keith Randallb2a950b2014-12-27 20:58:00 -0800246 throw("freedefer with d.fn != nil")
Russ Cox94bdf132014-10-08 00:03:50 -0400247}
248
Keith Randallf4407372014-09-03 08:49:43 -0700249// Run a deferred function if there is one.
250// The compiler inserts a call to this at the end of any
251// function which calls defer.
252// If there is a deferred function, this will call runtime·jmpdefer,
253// which will jump to the deferred function such that it appears
254// to have been called by the caller of deferreturn at the point
255// just before deferreturn was called. The effect is that deferreturn
256// is called again and again until there are no more deferred functions.
257// Cannot split the stack because we reuse the caller's frame to
258// call the deferred function.
259
260// The single argument isn't actually used - it just has its address
261// taken so it can be matched against pending defers.
262//go:nosplit
263func deferreturn(arg0 uintptr) {
264 gp := getg()
265 d := gp._defer
266 if d == nil {
267 return
268 }
Keith Randall53c52262014-12-08 14:18:58 -0800269 sp := getcallersp(unsafe.Pointer(&arg0))
270 if d.sp != sp {
Keith Randallf4407372014-09-03 08:49:43 -0700271 return
272 }
273
274 // Moving arguments around.
275 // Do not allow preemption here, because the garbage collector
276 // won't know the form of the arguments until the jmpdefer can
277 // flip the PC over to fn.
278 mp := acquirem()
Keith Randall53c52262014-12-08 14:18:58 -0800279 memmove(unsafe.Pointer(&arg0), deferArgs(d), uintptr(d.siz))
Keith Randallf4407372014-09-03 08:49:43 -0700280 fn := d.fn
Russ Cox94bdf132014-10-08 00:03:50 -0400281 d.fn = nil
Keith Randallf4407372014-09-03 08:49:43 -0700282 gp._defer = d.link
Dmitry Vyukovb759e222015-02-05 13:35:41 +0000283 // Switch to systemstack merely to save nosplit stack space.
284 systemstack(func() {
285 freedefer(d)
286 })
Keith Randallf4407372014-09-03 08:49:43 -0700287 releasem(mp)
Keith Randall53c52262014-12-08 14:18:58 -0800288 jmpdefer(fn, uintptr(unsafe.Pointer(&arg0)))
Keith Randallf4407372014-09-03 08:49:43 -0700289}
290
291// Goexit terminates the goroutine that calls it. No other goroutine is affected.
Keith Randall15274e52014-09-16 12:50:05 -0700292// Goexit runs all deferred calls before terminating the goroutine. Because Goexit
293// is not panic, however, any recover calls in those deferred functions will return nil.
Keith Randallf4407372014-09-03 08:49:43 -0700294//
295// Calling Goexit from the main goroutine terminates that goroutine
296// without func main returning. Since func main has not returned,
297// the program continues execution of other goroutines.
298// If all other goroutines exit, the program crashes.
299func Goexit() {
300 // Run all deferred functions for the current goroutine.
Keith Randall03064782014-09-19 16:33:14 -0700301 // This code is similar to gopanic, see that implementation
302 // for detailed comments.
Keith Randallf4407372014-09-03 08:49:43 -0700303 gp := getg()
Keith Randall03064782014-09-19 16:33:14 -0700304 for {
Keith Randallf4407372014-09-03 08:49:43 -0700305 d := gp._defer
Keith Randall03064782014-09-19 16:33:14 -0700306 if d == nil {
307 break
308 }
309 if d.started {
310 if d._panic != nil {
311 d._panic.aborted = true
Russ Coxe6708ee9b2014-10-07 23:17:31 -0400312 d._panic = nil
Keith Randall03064782014-09-19 16:33:14 -0700313 }
Russ Cox94bdf132014-10-08 00:03:50 -0400314 d.fn = nil
Keith Randall03064782014-09-19 16:33:14 -0700315 gp._defer = d.link
316 freedefer(d)
317 continue
318 }
Russ Coxf95beae2014-09-16 10:36:38 -0400319 d.started = true
Russ Coxdf027ac2014-12-30 13:59:55 -0500320 reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
Keith Randall03064782014-09-19 16:33:14 -0700321 if gp._defer != d {
Keith Randallb2a950b2014-12-27 20:58:00 -0800322 throw("bad defer entry in Goexit")
Keith Randall03064782014-09-19 16:33:14 -0700323 }
Russ Coxe6708ee9b2014-10-07 23:17:31 -0400324 d._panic = nil
Russ Cox94bdf132014-10-08 00:03:50 -0400325 d.fn = nil
Keith Randallf4407372014-09-03 08:49:43 -0700326 gp._defer = d.link
Keith Randallf4407372014-09-03 08:49:43 -0700327 freedefer(d)
328 // Note: we ignore recovers here because Goexit isn't a panic
329 }
Austin Clementsad731882015-08-06 15:36:50 -0400330 goexit1()
Keith Randallf4407372014-09-03 08:49:43 -0700331}
Russ Coxc81a0ed2014-09-08 14:05:23 -0400332
Keith Randall3a3d47d2014-09-08 12:33:08 -0700333// Print all currently active panics. Used when crashing.
334func printpanics(p *_panic) {
335 if p.link != nil {
336 printpanics(p.link)
337 print("\t")
338 }
339 print("panic: ")
340 printany(p.arg)
341 if p.recovered {
342 print(" [recovered]")
343 }
344 print("\n")
345}
346
347// The implementation of the predeclared function panic.
348func gopanic(e interface{}) {
349 gp := getg()
350 if gp.m.curg != gp {
Russ Coxd98553a2014-11-11 17:04:34 -0500351 print("panic: ")
352 printany(e)
353 print("\n")
Keith Randallb2a950b2014-12-27 20:58:00 -0800354 throw("panic on system stack")
Keith Randall3a3d47d2014-09-08 12:33:08 -0700355 }
Russ Coxc3b5db82014-09-18 14:49:24 -0400356
357 // m.softfloat is set during software floating point.
358 // It increments m.locks to avoid preemption.
359 // We moved the memory loads out, so there shouldn't be
360 // any reason for it to panic anymore.
361 if gp.m.softfloat != 0 {
362 gp.m.locks--
363 gp.m.softfloat = 0
Keith Randallb2a950b2014-12-27 20:58:00 -0800364 throw("panic during softfloat")
Russ Coxc3b5db82014-09-18 14:49:24 -0400365 }
366 if gp.m.mallocing != 0 {
367 print("panic: ")
368 printany(e)
369 print("\n")
Keith Randallb2a950b2014-12-27 20:58:00 -0800370 throw("panic during malloc")
Russ Coxc3b5db82014-09-18 14:49:24 -0400371 }
Austin Clements28b51182015-01-30 15:30:41 -0500372 if gp.m.preemptoff != "" {
Russ Coxc3b5db82014-09-18 14:49:24 -0400373 print("panic: ")
374 printany(e)
375 print("\n")
Austin Clements28b51182015-01-30 15:30:41 -0500376 print("preempt off reason: ")
377 print(gp.m.preemptoff)
378 print("\n")
379 throw("panic during preemptoff")
Russ Coxc3b5db82014-09-18 14:49:24 -0400380 }
381 if gp.m.locks != 0 {
382 print("panic: ")
383 printany(e)
384 print("\n")
Keith Randallb2a950b2014-12-27 20:58:00 -0800385 throw("panic holding locks")
Russ Coxc3b5db82014-09-18 14:49:24 -0400386 }
387
Keith Randall3a3d47d2014-09-08 12:33:08 -0700388 var p _panic
Keith Randall3a3d47d2014-09-08 12:33:08 -0700389 p.arg = e
390 p.link = gp._panic
391 gp._panic = (*_panic)(noescape(unsafe.Pointer(&p)))
392
Keith Randall3a3d47d2014-09-08 12:33:08 -0700393 for {
394 d := gp._defer
395 if d == nil {
396 break
397 }
Keith Randall3a3d47d2014-09-08 12:33:08 -0700398
Russ Coxf95beae2014-09-16 10:36:38 -0400399 // If defer was started by earlier panic or Goexit (and, since we're back here, that triggered a new panic),
400 // take defer off list. The earlier panic or Goexit will not continue running.
401 if d.started {
402 if d._panic != nil {
403 d._panic.aborted = true
404 }
Russ Coxe6708ee9b2014-10-07 23:17:31 -0400405 d._panic = nil
Russ Cox94bdf132014-10-08 00:03:50 -0400406 d.fn = nil
Russ Coxf95beae2014-09-16 10:36:38 -0400407 gp._defer = d.link
408 freedefer(d)
409 continue
410 }
411
412 // Mark defer as started, but keep on list, so that traceback
413 // can find and update the defer's argument frame if stack growth
Ainar Garipov7f9f70e2015-06-11 16:49:38 +0300414 // or a garbage collection happens before reflectcall starts executing d.fn.
Russ Coxf95beae2014-09-16 10:36:38 -0400415 d.started = true
416
417 // Record the panic that is running the defer.
418 // If there is a new panic during the deferred call, that panic
419 // will find d in the list and will mark d._panic (this panic) aborted.
420 d._panic = (*_panic)(noescape((unsafe.Pointer)(&p)))
Keith Randall3a3d47d2014-09-08 12:33:08 -0700421
Russ Cox0f99a912014-09-08 21:02:36 -0400422 p.argp = unsafe.Pointer(getargp(0))
Russ Coxdf027ac2014-12-30 13:59:55 -0500423 reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
Russ Cox0f99a912014-09-08 21:02:36 -0400424 p.argp = nil
Keith Randall3a3d47d2014-09-08 12:33:08 -0700425
Russ Coxf95beae2014-09-16 10:36:38 -0400426 // reflectcall did not panic. Remove d.
427 if gp._defer != d {
Keith Randallb2a950b2014-12-27 20:58:00 -0800428 throw("bad defer entry in panic")
Keith Randall3a3d47d2014-09-08 12:33:08 -0700429 }
Russ Coxe6708ee9b2014-10-07 23:17:31 -0400430 d._panic = nil
Russ Cox94bdf132014-10-08 00:03:50 -0400431 d.fn = nil
Russ Coxf95beae2014-09-16 10:36:38 -0400432 gp._defer = d.link
Keith Randall3a3d47d2014-09-08 12:33:08 -0700433
434 // trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic
435 //GC()
436
Russ Coxf95beae2014-09-16 10:36:38 -0400437 pc := d.pc
Keith Randall53c52262014-12-08 14:18:58 -0800438 sp := unsafe.Pointer(d.sp) // must be pointer so it gets adjusted during stack copy
Keith Randall3a3d47d2014-09-08 12:33:08 -0700439 freedefer(d)
440 if p.recovered {
441 gp._panic = p.link
442 // Aborted panics are marked but remain on the g.panic list.
Russ Coxf95beae2014-09-16 10:36:38 -0400443 // Remove them from the list.
Keith Randall3a3d47d2014-09-08 12:33:08 -0700444 for gp._panic != nil && gp._panic.aborted {
Keith Randall3a3d47d2014-09-08 12:33:08 -0700445 gp._panic = gp._panic.link
446 }
447 if gp._panic == nil { // must be done with signal
448 gp.sig = 0
449 }
450 // Pass information about recovering frame to recovery.
Keith Randall53c52262014-12-08 14:18:58 -0800451 gp.sigcode0 = uintptr(sp)
Keith Randall3a3d47d2014-09-08 12:33:08 -0700452 gp.sigcode1 = pc
Russ Coxd98553a2014-11-11 17:04:34 -0500453 mcall(recovery)
Keith Randallb2a950b2014-12-27 20:58:00 -0800454 throw("recovery failed") // mcall should not return
Keith Randall3a3d47d2014-09-08 12:33:08 -0700455 }
456 }
457
458 // ran out of deferred calls - old-school panic now
459 startpanic()
460 printpanics(gp._panic)
461 dopanic(0) // should not return
462 *(*int)(nil) = 0 // not reached
463}
464
465// getargp returns the location where the caller
466// writes outgoing function call arguments.
467//go:nosplit
468func getargp(x int) uintptr {
469 // x is an argument mainly so that we can return its address.
470 // However, we need to make the function complex enough
471 // that it won't be inlined. We always pass x = 0, so this code
472 // does nothing other than keep the compiler from thinking
473 // the function is simple enough to inline.
474 if x > 0 {
475 return getcallersp(unsafe.Pointer(&x)) * 0
476 }
477 return uintptr(noescape(unsafe.Pointer(&x)))
478}
479
Keith Randall3a3d47d2014-09-08 12:33:08 -0700480// The implementation of the predeclared function recover.
481// Cannot split the stack because it needs to reliably
482// find the stack segment of its caller.
483//
484// TODO(rsc): Once we commit to CopyStackAlways,
485// this doesn't need to be nosplit.
486//go:nosplit
487func gorecover(argp uintptr) interface{} {
488 // Must be in a function running as part of a deferred call during the panic.
489 // Must be called from the topmost function of the call
490 // (the function used in the defer statement).
491 // p.argp is the argument pointer of that topmost deferred function call.
492 // Compare against argp reported by caller.
493 // If they match, the caller is the one who can recover.
494 gp := getg()
495 p := gp._panic
Russ Cox0f99a912014-09-08 21:02:36 -0400496 if p != nil && !p.recovered && argp == uintptr(p.argp) {
Keith Randall3a3d47d2014-09-08 12:33:08 -0700497 p.recovered = true
498 return p.arg
499 }
500 return nil
501}
502
503//go:nosplit
504func startpanic() {
Russ Cox656be312014-11-12 14:54:31 -0500505 systemstack(startpanic_m)
Keith Randall3a3d47d2014-09-08 12:33:08 -0700506}
507
508//go:nosplit
509func dopanic(unused int) {
Russ Cox656be312014-11-12 14:54:31 -0500510 pc := getcallerpc(unsafe.Pointer(&unused))
511 sp := getcallersp(unsafe.Pointer(&unused))
Keith Randall3a3d47d2014-09-08 12:33:08 -0700512 gp := getg()
Russ Cox656be312014-11-12 14:54:31 -0500513 systemstack(func() {
514 dopanic_m(gp, pc, sp) // should never return
515 })
Keith Randall3a3d47d2014-09-08 12:33:08 -0700516 *(*int)(nil) = 0
517}
518
519//go:nosplit
Keith Randallb2a950b2014-12-27 20:58:00 -0800520func throw(s string) {
Austin Clementsf0bd5392014-10-22 15:51:54 -0400521 print("fatal error: ", s, "\n")
Keith Randall3a3d47d2014-09-08 12:33:08 -0700522 gp := getg()
523 if gp.m.throwing == 0 {
524 gp.m.throwing = 1
525 }
526 startpanic()
Keith Randall3a3d47d2014-09-08 12:33:08 -0700527 dopanic(0)
528 *(*int)(nil) = 0 // not reached
529}