github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libgo/go/runtime/panic.go (about) 1 // 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 5 package runtime 6 7 import "unsafe" 8 9 var indexError = error(errorString("index out of range")) 10 11 func panicindex() { 12 panic(indexError) 13 } 14 15 var sliceError = error(errorString("slice bounds out of range")) 16 17 func panicslice() { 18 panic(sliceError) 19 } 20 21 var divideError = error(errorString("integer divide by zero")) 22 23 func panicdivide() { 24 panic(divideError) 25 } 26 27 var overflowError = error(errorString("integer overflow")) 28 29 func panicoverflow() { 30 panic(overflowError) 31 } 32 33 var floatError = error(errorString("floating point error")) 34 35 func panicfloat() { 36 panic(floatError) 37 } 38 39 var memoryError = error(errorString("invalid memory address or nil pointer dereference")) 40 41 func panicmem() { 42 panic(memoryError) 43 } 44 45 func throwreturn() { 46 gothrow("no return at end of a typed function - compiler is broken") 47 } 48 49 func throwinit() { 50 gothrow("recursive call during initialization - linker skew") 51 } 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 56 func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn 57 // the arguments of fn are in a perilous state. The stack map 58 // for deferproc does not describe them. So we can't let garbage 59 // collection or stack copying trigger until we've copied them out 60 // to somewhere safe. deferproc_m does that. Until deferproc_m, 61 // we can only call nosplit routines. 62 argp := uintptr(unsafe.Pointer(&fn)) 63 argp += unsafe.Sizeof(fn) 64 if GOARCH == "arm" { 65 argp += ptrSize // skip caller's saved link register 66 } 67 mp := acquirem() 68 mp.scalararg[0] = uintptr(siz) 69 mp.ptrarg[0] = unsafe.Pointer(fn) 70 mp.scalararg[1] = argp 71 mp.scalararg[2] = getcallerpc(unsafe.Pointer(&siz)) 72 73 if mp.curg != getg() { 74 // go code on the m stack can't defer 75 gothrow("defer on m") 76 } 77 78 onM(deferproc_m) 79 80 releasem(mp) 81 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 93 // 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 97 const ( 98 deferHeaderSize = unsafe.Sizeof(_defer{}) 99 minDeferAlloc = (deferHeaderSize + 15) &^ 15 100 minDeferArgs = minDeferAlloc - deferHeaderSize 101 ) 102 103 // defer size class for arg size sz 104 //go:nosplit 105 func deferclass(siz uintptr) uintptr { 106 if siz <= minDeferArgs { 107 return 0 108 } 109 return (siz - minDeferArgs + 15) / 16 110 } 111 112 // total size of memory block for defer with arg size sz 113 func totaldefersize(siz uintptr) uintptr { 114 if siz <= minDeferArgs { 115 return minDeferAlloc 116 } 117 return deferHeaderSize + siz 118 } 119 120 // Ensure that defer arg sizes that map to the same defer size class 121 // also map to the same malloc size class. 122 func 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 } 133 siz := goroundupsize(totaldefersize(i)) 134 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") 140 gothrow("bad defer size class") 141 } 142 } 143 } 144 145 // The arguments associated with a deferred call are stored 146 // immediately after the _defer header in memory. 147 //go:nosplit 148 func deferArgs(d *_defer) unsafe.Pointer { 149 return add(unsafe.Pointer(d), unsafe.Sizeof(*d)) 150 } 151 152 var deferType *_type // type of _defer struct 153 154 func init() { 155 var x interface{} 156 x = (*_defer)(nil) 157 deferType = (*(**ptrtype)(unsafe.Pointer(&x))).elem 158 } 159 160 // Allocate a Defer, usually using per-P pool. 161 // Each defer must be released with freedefer. 162 // Note: runs on M stack 163 func newdefer(siz int32) *_defer { 164 var d *_defer 165 sc := deferclass(uintptr(siz)) 166 mp := acquirem() 167 if sc < uintptr(len(p{}.deferpool)) { 168 pp := mp.p 169 d = pp.deferpool[sc] 170 if d != nil { 171 pp.deferpool[sc] = d.link 172 } 173 } 174 if d == nil { 175 // Allocate new defer+args. 176 total := goroundupsize(totaldefersize(uintptr(siz))) 177 d = (*_defer)(mallocgc(total, deferType, 0)) 178 } 179 d.siz = siz 180 gp := mp.curg 181 d.link = gp._defer 182 gp._defer = d 183 releasem(mp) 184 return d 185 } 186 187 // Free the given defer. 188 // The defer cannot be used after this call. 189 //go:nosplit 190 func freedefer(d *_defer) { 191 if d._panic != nil { 192 freedeferpanic() 193 } 194 if d.fn != nil { 195 freedeferfn() 196 } 197 sc := deferclass(uintptr(d.siz)) 198 if sc < uintptr(len(p{}.deferpool)) { 199 mp := acquirem() 200 pp := mp.p 201 *d = _defer{} 202 d.link = pp.deferpool[sc] 203 pp.deferpool[sc] = d 204 releasem(mp) 205 } 206 } 207 208 // Separate function so that it can split stack. 209 // Windows otherwise runs out of stack space. 210 func freedeferpanic() { 211 // _panic must be cleared before d is unlinked from gp. 212 gothrow("freedefer with d._panic != nil") 213 } 214 215 func freedeferfn() { 216 // fn must be cleared before d is unlinked from gp. 217 gothrow("freedefer with d.fn != nil") 218 } 219 220 // Run a deferred function if there is one. 221 // The compiler inserts a call to this at the end of any 222 // function which calls defer. 223 // If there is a deferred function, this will call runtime·jmpdefer, 224 // which will jump to the deferred function such that it appears 225 // to have been called by the caller of deferreturn at the point 226 // just before deferreturn was called. The effect is that deferreturn 227 // is called again and again until there are no more deferred functions. 228 // Cannot split the stack because we reuse the caller's frame to 229 // call the deferred function. 230 231 // The single argument isn't actually used - it just has its address 232 // taken so it can be matched against pending defers. 233 //go:nosplit 234 func deferreturn(arg0 uintptr) { 235 gp := getg() 236 d := gp._defer 237 if d == nil { 238 return 239 } 240 argp := uintptr(unsafe.Pointer(&arg0)) 241 if d.argp != argp { 242 return 243 } 244 245 // Moving arguments around. 246 // Do not allow preemption here, because the garbage collector 247 // won't know the form of the arguments until the jmpdefer can 248 // flip the PC over to fn. 249 mp := acquirem() 250 memmove(unsafe.Pointer(argp), deferArgs(d), uintptr(d.siz)) 251 fn := d.fn 252 d.fn = nil 253 gp._defer = d.link 254 freedefer(d) 255 releasem(mp) 256 jmpdefer(fn, argp) 257 } 258 259 // Goexit terminates the goroutine that calls it. No other goroutine is affected. 260 // Goexit runs all deferred calls before terminating the goroutine. Because Goexit 261 // is not panic, however, any recover calls in those deferred functions will return nil. 262 // 263 // Calling Goexit from the main goroutine terminates that goroutine 264 // without func main returning. Since func main has not returned, 265 // the program continues execution of other goroutines. 266 // If all other goroutines exit, the program crashes. 267 func Goexit() { 268 // Run all deferred functions for the current goroutine. 269 // This code is similar to gopanic, see that implementation 270 // for detailed comments. 271 gp := getg() 272 for { 273 d := gp._defer 274 if d == nil { 275 break 276 } 277 if d.started { 278 if d._panic != nil { 279 d._panic.aborted = true 280 d._panic = nil 281 } 282 d.fn = nil 283 gp._defer = d.link 284 freedefer(d) 285 continue 286 } 287 d.started = true 288 reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz)) 289 if gp._defer != d { 290 gothrow("bad defer entry in Goexit") 291 } 292 d._panic = nil 293 d.fn = nil 294 gp._defer = d.link 295 freedefer(d) 296 // Note: we ignore recovers here because Goexit isn't a panic 297 } 298 goexit() 299 } 300 301 func canpanic(*g) bool 302 303 // Print all currently active panics. Used when crashing. 304 func printpanics(p *_panic) { 305 if p.link != nil { 306 printpanics(p.link) 307 print("\t") 308 } 309 print("panic: ") 310 printany(p.arg) 311 if p.recovered { 312 print(" [recovered]") 313 } 314 print("\n") 315 } 316 317 // The implementation of the predeclared function panic. 318 func gopanic(e interface{}) { 319 gp := getg() 320 if gp.m.curg != gp { 321 gothrow("panic on m stack") 322 } 323 324 // m.softfloat is set during software floating point. 325 // It increments m.locks to avoid preemption. 326 // We moved the memory loads out, so there shouldn't be 327 // any reason for it to panic anymore. 328 if gp.m.softfloat != 0 { 329 gp.m.locks-- 330 gp.m.softfloat = 0 331 gothrow("panic during softfloat") 332 } 333 if gp.m.mallocing != 0 { 334 print("panic: ") 335 printany(e) 336 print("\n") 337 gothrow("panic during malloc") 338 } 339 if gp.m.gcing != 0 { 340 print("panic: ") 341 printany(e) 342 print("\n") 343 gothrow("panic during gc") 344 } 345 if gp.m.locks != 0 { 346 print("panic: ") 347 printany(e) 348 print("\n") 349 gothrow("panic holding locks") 350 } 351 352 var p _panic 353 p.arg = e 354 p.link = gp._panic 355 gp._panic = (*_panic)(noescape(unsafe.Pointer(&p))) 356 357 for { 358 d := gp._defer 359 if d == nil { 360 break 361 } 362 363 // If defer was started by earlier panic or Goexit (and, since we're back here, that triggered a new panic), 364 // take defer off list. The earlier panic or Goexit will not continue running. 365 if d.started { 366 if d._panic != nil { 367 d._panic.aborted = true 368 } 369 d._panic = nil 370 d.fn = nil 371 gp._defer = d.link 372 freedefer(d) 373 continue 374 } 375 376 // Mark defer as started, but keep on list, so that traceback 377 // can find and update the defer's argument frame if stack growth 378 // or a garbage collection hapens before reflectcall starts executing d.fn. 379 d.started = true 380 381 // Record the panic that is running the defer. 382 // If there is a new panic during the deferred call, that panic 383 // will find d in the list and will mark d._panic (this panic) aborted. 384 d._panic = (*_panic)(noescape((unsafe.Pointer)(&p))) 385 386 p.argp = unsafe.Pointer(getargp(0)) 387 reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz)) 388 p.argp = nil 389 390 // reflectcall did not panic. Remove d. 391 if gp._defer != d { 392 gothrow("bad defer entry in panic") 393 } 394 d._panic = nil 395 d.fn = nil 396 gp._defer = d.link 397 398 // trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic 399 //GC() 400 401 pc := d.pc 402 argp := unsafe.Pointer(d.argp) // must be pointer so it gets adjusted during stack copy 403 freedefer(d) 404 if p.recovered { 405 gp._panic = p.link 406 // Aborted panics are marked but remain on the g.panic list. 407 // Remove them from the list. 408 for gp._panic != nil && gp._panic.aborted { 409 gp._panic = gp._panic.link 410 } 411 if gp._panic == nil { // must be done with signal 412 gp.sig = 0 413 } 414 // Pass information about recovering frame to recovery. 415 gp.sigcode0 = uintptr(argp) 416 gp.sigcode1 = pc 417 mcall(recovery_m) 418 gothrow("recovery failed") // mcall should not return 419 } 420 } 421 422 // ran out of deferred calls - old-school panic now 423 startpanic() 424 printpanics(gp._panic) 425 dopanic(0) // should not return 426 *(*int)(nil) = 0 // not reached 427 } 428 429 // getargp returns the location where the caller 430 // writes outgoing function call arguments. 431 //go:nosplit 432 func getargp(x int) uintptr { 433 // x is an argument mainly so that we can return its address. 434 // However, we need to make the function complex enough 435 // that it won't be inlined. We always pass x = 0, so this code 436 // does nothing other than keep the compiler from thinking 437 // the function is simple enough to inline. 438 if x > 0 { 439 return getcallersp(unsafe.Pointer(&x)) * 0 440 } 441 return uintptr(noescape(unsafe.Pointer(&x))) 442 } 443 444 // The implementation of the predeclared function recover. 445 // Cannot split the stack because it needs to reliably 446 // find the stack segment of its caller. 447 // 448 // TODO(rsc): Once we commit to CopyStackAlways, 449 // this doesn't need to be nosplit. 450 //go:nosplit 451 func gorecover(argp uintptr) interface{} { 452 // Must be in a function running as part of a deferred call during the panic. 453 // Must be called from the topmost function of the call 454 // (the function used in the defer statement). 455 // p.argp is the argument pointer of that topmost deferred function call. 456 // Compare against argp reported by caller. 457 // If they match, the caller is the one who can recover. 458 gp := getg() 459 p := gp._panic 460 if p != nil && !p.recovered && argp == uintptr(p.argp) { 461 p.recovered = true 462 return p.arg 463 } 464 return nil 465 } 466 467 //go:nosplit 468 func startpanic() { 469 onM_signalok(startpanic_m) 470 } 471 472 //go:nosplit 473 func dopanic(unused int) { 474 gp := getg() 475 mp := acquirem() 476 mp.ptrarg[0] = unsafe.Pointer(gp) 477 mp.scalararg[0] = getcallerpc((unsafe.Pointer)(&unused)) 478 mp.scalararg[1] = getcallersp((unsafe.Pointer)(&unused)) 479 onM_signalok(dopanic_m) // should never return 480 *(*int)(nil) = 0 481 } 482 483 //go:nosplit 484 func throw(s *byte) { 485 gp := getg() 486 if gp.m.throwing == 0 { 487 gp.m.throwing = 1 488 } 489 startpanic() 490 print("fatal error: ", gostringnocopy(s), "\n") 491 dopanic(0) 492 *(*int)(nil) = 0 // not reached 493 } 494 495 //go:nosplit 496 func gothrow(s string) { 497 gp := getg() 498 if gp.m.throwing == 0 { 499 gp.m.throwing = 1 500 } 501 startpanic() 502 print("fatal error: ", s, "\n") 503 dopanic(0) 504 *(*int)(nil) = 0 // not reached 505 }