LEFT | RIGHT |
(no file at all) | |
1 // Copyright 2013 The Go Authors. All rights reserved. | 1 // Copyright 2013 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 #include "runtime.h" | 5 #include "runtime.h" |
6 #include "arch_GOARCH.h" | 6 #include "arch_GOARCH.h" |
7 #include "malloc.h" | 7 #include "malloc.h" |
8 #include "stack.h" | 8 #include "stack.h" |
9 #include "funcdata.h" | 9 #include "funcdata.h" |
10 #include "typekind.h" | 10 #include "typekind.h" |
11 #include "type.h" | 11 #include "type.h" |
12 #include "race.h" | 12 #include "race.h" |
13 #include "mgc0.h" | 13 #include "mgc0.h" |
14 #include "../../cmd/ld/textflag.h" | 14 #include "textflag.h" |
15 | 15 |
16 enum | 16 enum |
17 { | 17 { |
18 // StackDebug == 0: no logging | 18 // StackDebug == 0: no logging |
19 // == 1: logging of per-stack operations | 19 // == 1: logging of per-stack operations |
20 // == 2: logging of per-frame operations | 20 // == 2: logging of per-frame operations |
21 // == 3: logging of per-word updates | 21 // == 3: logging of per-word updates |
22 // == 4: logging of per-word reads | 22 // == 4: logging of per-word reads |
23 StackDebug = 0, | 23 StackDebug = 0, |
24 StackFromSystem = 0, // allocate stacks from system memory instead of
the heap | 24 StackFromSystem = 0, // allocate stacks from system memory instead of
the heap |
25 StackFaultOnFree = 0, // old stacks are mapped noaccess to detect use
after free | 25 StackFaultOnFree = 0, // old stacks are mapped noaccess to detect use
after free |
26 | 26 |
27 StackCache = 1, | 27 StackCache = 1, |
| 28 ········ |
| 29 StackCopyAlways = 0, // expect to be able to copy stacks 100% of the
time |
28 }; | 30 }; |
29 | 31 |
30 // Global pool of spans that have free stacks. | 32 // Global pool of spans that have free stacks. |
31 // Stacks are assigned an order according to size. | 33 // Stacks are assigned an order according to size. |
32 // order = log_2(size/FixedStack) | 34 // order = log_2(size/FixedStack) |
33 // There is a free list for each order. | 35 // There is a free list for each order. |
34 static MSpan stackpool[NumStackOrders]; | 36 static MSpan stackpool[NumStackOrders]; |
35 static Lock stackpoolmu; | 37 static Mutex stackpoolmu; |
36 // TODO: one lock per order? | 38 // TODO: one lock per order? |
37 | 39 |
38 void | 40 void |
39 runtime·stackinit(void) | 41 runtime·stackinit(void) |
40 { | 42 { |
41 int32 i; | 43 int32 i; |
42 | 44 |
43 if((StackCacheSize & PageMask) != 0) | 45 if((StackCacheSize & PageMask) != 0) |
44 runtime·throw("cache size must be a multiple of page size"); | 46 runtime·throw("cache size must be a multiple of page size"); |
45 | 47 |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
199 // Doing so would cause a deadlock (issue 1547). | 201 // Doing so would cause a deadlock (issue 1547). |
200 if(g != g->m->g0) | 202 if(g != g->m->g0) |
201 runtime·throw("stackalloc not on scheduler stack"); | 203 runtime·throw("stackalloc not on scheduler stack"); |
202 if((n & (n-1)) != 0) | 204 if((n & (n-1)) != 0) |
203 runtime·throw("stack size not a power of 2"); | 205 runtime·throw("stack size not a power of 2"); |
204 if(StackDebug >= 1) | 206 if(StackDebug >= 1) |
205 runtime·printf("stackalloc %d\n", n); | 207 runtime·printf("stackalloc %d\n", n); |
206 | 208 |
207 gp->stacksize += n; | 209 gp->stacksize += n; |
208 if(runtime·debug.efence || StackFromSystem) { | 210 if(runtime·debug.efence || StackFromSystem) { |
209 » » v = runtime·SysAlloc(ROUND(n, PageSize), &mstats.stacks_sys); | 211 » » v = runtime·sysAlloc(ROUND(n, PageSize), &mstats.stacks_sys); |
210 if(v == nil) | 212 if(v == nil) |
211 runtime·throw("out of memory (stackalloc)"); | 213 runtime·throw("out of memory (stackalloc)"); |
212 return v; | 214 return v; |
213 } | 215 } |
214 | 216 |
215 // Small stacks are allocated with a fixed-size free-list allocator. | 217 // Small stacks are allocated with a fixed-size free-list allocator. |
216 // If we need a stack of a bigger size, we fall back on allocating | 218 // If we need a stack of a bigger size, we fall back on allocating |
217 // a dedicated span. | 219 // a dedicated span. |
218 if(StackCache && n < FixedStack << NumStackOrders && n < StackCacheSize)
{ | 220 if(StackCache && n < FixedStack << NumStackOrders && n < StackCacheSize)
{ |
219 order = 0; | 221 order = 0; |
220 n2 = n; | 222 n2 = n; |
221 while(n2 > FixedStack) { | 223 while(n2 > FixedStack) { |
222 order++; | 224 order++; |
223 n2 >>= 1; | 225 n2 >>= 1; |
224 } | 226 } |
225 c = g->m->mcache; | 227 c = g->m->mcache; |
226 » » if(c == nil) { | 228 » » if(c == nil || g->m->gcing || g->m->helpgc) { |
227 » » » // This can happen in the guts of exitsyscall or | 229 » » » // c == nil can happen in the guts of exitsyscall or |
228 // procresize. Just get a stack from the global pool. | 230 // procresize. Just get a stack from the global pool. |
| 231 // Also don't touch stackcache during gc |
| 232 // as it's flushed concurrently. |
229 runtime·lock(&stackpoolmu); | 233 runtime·lock(&stackpoolmu); |
230 x = poolalloc(order); | 234 x = poolalloc(order); |
231 runtime·unlock(&stackpoolmu); | 235 runtime·unlock(&stackpoolmu); |
232 } else { | 236 } else { |
233 x = c->stackcache[order].list; | 237 x = c->stackcache[order].list; |
234 if(x == nil) { | 238 if(x == nil) { |
235 stackcacherefill(c, order); | 239 stackcacherefill(c, order); |
236 x = c->stackcache[order].list; | 240 x = c->stackcache[order].list; |
237 } | 241 } |
238 c->stackcache[order].list = x->next; | 242 c->stackcache[order].list = x->next; |
(...skipping 20 matching lines...) Expand all Loading... |
259 { | 263 { |
260 uint8 order; | 264 uint8 order; |
261 uintptr n, n2; | 265 uintptr n, n2; |
262 MSpan *s; | 266 MSpan *s; |
263 MLink *x; | 267 MLink *x; |
264 MCache *c; | 268 MCache *c; |
265 ········ | 269 ········ |
266 n = (uintptr)(top+1) - (uintptr)v; | 270 n = (uintptr)(top+1) - (uintptr)v; |
267 if(n & (n-1)) | 271 if(n & (n-1)) |
268 runtime·throw("stack not a power of 2"); | 272 runtime·throw("stack not a power of 2"); |
269 » if(StackDebug >= 1) | 273 » if(StackDebug >= 1) { |
270 runtime·printf("stackfree %p %d\n", v, (int32)n); | 274 runtime·printf("stackfree %p %d\n", v, (int32)n); |
| 275 runtime·memclr(v, n); // for testing, clobber stack data |
| 276 } |
271 gp->stacksize -= n; | 277 gp->stacksize -= n; |
272 if(runtime·debug.efence || StackFromSystem) { | 278 if(runtime·debug.efence || StackFromSystem) { |
273 if(runtime·debug.efence || StackFaultOnFree) | 279 if(runtime·debug.efence || StackFaultOnFree) |
274 runtime·SysFault(v, n); | 280 runtime·SysFault(v, n); |
275 else | 281 else |
276 runtime·SysFree(v, n, &mstats.stacks_sys); | 282 runtime·SysFree(v, n, &mstats.stacks_sys); |
277 return; | 283 return; |
278 } | 284 } |
279 if(StackCache && n < FixedStack << NumStackOrders && n < StackCacheSize)
{ | 285 if(StackCache && n < FixedStack << NumStackOrders && n < StackCacheSize)
{ |
280 order = 0; | 286 order = 0; |
281 n2 = n; | 287 n2 = n; |
282 while(n2 > FixedStack) { | 288 while(n2 > FixedStack) { |
283 order++; | 289 order++; |
284 n2 >>= 1; | 290 n2 >>= 1; |
285 } | 291 } |
286 x = (MLink*)v; | 292 x = (MLink*)v; |
287 c = g->m->mcache; | 293 c = g->m->mcache; |
288 » » if(c == nil) { | 294 » » if(c == nil || g->m->gcing || g->m->helpgc) { |
289 runtime·lock(&stackpoolmu); | 295 runtime·lock(&stackpoolmu); |
290 poolfree(x, order); | 296 poolfree(x, order); |
291 runtime·unlock(&stackpoolmu); | 297 runtime·unlock(&stackpoolmu); |
292 } else { | 298 } else { |
293 if(c->stackcache[order].size >= StackCacheSize) | 299 if(c->stackcache[order].size >= StackCacheSize) |
294 stackcacherelease(c, order); | 300 stackcacherelease(c, order); |
295 x->next = c->stackcache[order].list; | 301 x->next = c->stackcache[order].list; |
296 c->stackcache[order].list = x; | 302 c->stackcache[order].list = x; |
297 c->stackcache[order].size += n; | 303 c->stackcache[order].size += n; |
298 } | 304 } |
(...skipping 14 matching lines...) Expand all Loading... |
313 runtime·oldstack(void) | 319 runtime·oldstack(void) |
314 { | 320 { |
315 Stktop *top; | 321 Stktop *top; |
316 uint32 argsize; | 322 uint32 argsize; |
317 byte *sp, *old; | 323 byte *sp, *old; |
318 uintptr *src, *dst, *dstend; | 324 uintptr *src, *dst, *dstend; |
319 G *gp; | 325 G *gp; |
320 int64 goid; | 326 int64 goid; |
321 int32 oldstatus; | 327 int32 oldstatus; |
322 | 328 |
| 329 if(StackCopyAlways) |
| 330 runtime·throw("unexpected call to oldstack"); |
| 331 |
323 gp = g->m->curg; | 332 gp = g->m->curg; |
324 top = (Stktop*)gp->stackbase; | 333 top = (Stktop*)gp->stackbase; |
325 if(top == nil) | 334 if(top == nil) |
326 runtime·throw("nil stackbase"); | 335 runtime·throw("nil stackbase"); |
327 old = (byte*)gp->stackguard - StackGuard; | 336 old = (byte*)gp->stackguard - StackGuard; |
328 sp = (byte*)top; | 337 sp = (byte*)top; |
329 argsize = top->argsize; | 338 argsize = top->argsize; |
330 | 339 |
331 if(StackDebug >= 1) { | 340 if(StackDebug >= 1) { |
332 runtime·printf("runtime: oldstack gobuf={pc:%p sp:%p lr:%p} cret
=%p argsize=%p\n", | 341 runtime·printf("runtime: oldstack gobuf={pc:%p sp:%p lr:%p} cret
=%p argsize=%p\n", |
333 top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, (uintptr)g-
>m->cret, (uintptr)argsize); | 342 top->gobuf.pc, top->gobuf.sp, top->gobuf.lr, (uintptr)g-
>m->cret, (uintptr)argsize); |
334 } | 343 } |
335 | 344 |
336 // gp->status is usually Grunning, but it could be Gsyscall if a stack o
verflow | |
337 // happens during a function call inside entersyscall. | |
338 oldstatus = gp->status; | |
339 ········ | |
340 gp->sched = top->gobuf; | 345 gp->sched = top->gobuf; |
341 gp->sched.ret = g->m->cret; | 346 gp->sched.ret = g->m->cret; |
342 g->m->cret = 0; // drop reference | 347 g->m->cret = 0; // drop reference |
343 » gp->status = Gwaiting; | 348 » // gp->status is usually Grunning, but it could be Gsyscall if a stack o
verflow |
344 » gp->waitreason = "stack unsplit"; | 349 » // happens during a function call inside entersyscall. |
| 350 |
| 351 » oldstatus = runtime·readgstatus(gp); |
| 352 » oldstatus &= ~Gscan; |
| 353 » if(oldstatus != Grunning && oldstatus != Gsyscall) { |
| 354 » » runtime·printf("runtime: oldstack status=%d\n", oldstatus); |
| 355 » » runtime·throw("oldstack"); |
| 356 » } |
| 357 » runtime·casgstatus(gp, oldstatus, Gcopystack); |
| 358 » gp->waitreason = runtime·gostringnocopy((byte*)"stack unsplit");»······· |
345 | 359 |
346 if(argsize > 0) { | 360 if(argsize > 0) { |
347 sp -= argsize; | 361 sp -= argsize; |
348 dst = (uintptr*)top->argp; | 362 dst = (uintptr*)top->argp; |
349 dstend = dst + argsize/sizeof(*dst); | 363 dstend = dst + argsize/sizeof(*dst); |
350 src = (uintptr*)sp; | 364 src = (uintptr*)sp; |
351 while(dst < dstend) | 365 while(dst < dstend) |
352 *dst++ = *src++; | 366 *dst++ = *src++; |
353 } | 367 } |
354 goid = top->gobuf.g->goid; // fault if g is bad, before gogo | 368 goid = top->gobuf.g->goid; // fault if g is bad, before gogo |
355 USED(goid); | 369 USED(goid); |
356 | 370 |
357 gp->stackbase = top->stackbase; | 371 gp->stackbase = top->stackbase; |
358 gp->stackguard = top->stackguard; | 372 gp->stackguard = top->stackguard; |
359 gp->stackguard0 = gp->stackguard; | 373 gp->stackguard0 = gp->stackguard; |
360 gp->panicwrap = top->panicwrap; | |
361 runtime·stackfree(gp, old, top); | 374 runtime·stackfree(gp, old, top); |
362 | 375 » runtime·casgstatus(gp, Gcopystack, oldstatus); // oldstatus is Grunning
or Gsyscall |
363 » gp->status = oldstatus; | |
364 runtime·gogo(&gp->sched); | 376 runtime·gogo(&gp->sched); |
365 } | 377 } |
366 | 378 |
367 uintptr runtime·maxstacksize = 1<<20; // enough until runtime.main sets it for r
eal | 379 uintptr runtime·maxstacksize = 1<<20; // enough until runtime.main sets it for r
eal |
368 | 380 |
369 static uint8* | 381 static uint8* |
370 mapnames[] = { | 382 mapnames[] = { |
371 (uint8*)"---", | 383 (uint8*)"---", |
372 (uint8*)"scalar", | 384 (uint8*)"scalar", |
373 (uint8*)"ptr", | 385 (uint8*)"ptr", |
(...skipping 16 matching lines...) Expand all Loading... |
390 // (arm: TODO) | 402 // (arm: TODO) |
391 | 403 |
392 typedef struct CopyableInfo CopyableInfo; | 404 typedef struct CopyableInfo CopyableInfo; |
393 struct CopyableInfo { | 405 struct CopyableInfo { |
394 byte *stk; // bottom address of segment | 406 byte *stk; // bottom address of segment |
395 byte *base; // top address of segment (including Stktop) | 407 byte *base; // top address of segment (including Stktop) |
396 int32 frames; // count of copyable frames (-1 = not copyable) | 408 int32 frames; // count of copyable frames (-1 = not copyable) |
397 }; | 409 }; |
398 | 410 |
399 void runtime·main(void); | 411 void runtime·main(void); |
| 412 void runtime·switchtoM(void(*)(void)); |
400 | 413 |
401 static bool | 414 static bool |
402 checkframecopy(Stkframe *frame, void *arg) | 415 checkframecopy(Stkframe *frame, void *arg) |
403 { | 416 { |
404 CopyableInfo *cinfo; | 417 CopyableInfo *cinfo; |
405 Func *f; | 418 Func *f; |
406 StackMap *stackmap; | 419 StackMap *stackmap; |
407 | 420 |
408 cinfo = arg; | 421 cinfo = arg; |
409 f = frame->fn; | 422 f = frame->fn; |
410 if(StackDebug >= 2) | 423 if(StackDebug >= 2) |
411 runtime·printf(" checking %s frame=[%p,%p] stk=[%p,%p]\n", ru
ntime·funcname(f), frame->sp, frame->fp, cinfo->stk, cinfo->base); | 424 runtime·printf(" checking %s frame=[%p,%p] stk=[%p,%p]\n", ru
ntime·funcname(f), frame->sp, frame->fp, cinfo->stk, cinfo->base); |
412 // if we're not in the segment any more, return immediately. | 425 // if we're not in the segment any more, return immediately. |
413 » if(frame->varp < cinfo->stk || frame->varp >= cinfo->base) { | 426 » if((byte*)frame->varp < cinfo->stk || (byte*)frame->varp >= cinfo->base)
{ |
414 if(StackDebug >= 2) | 427 if(StackDebug >= 2) |
415 runtime·printf(" <next segment>\n"); | 428 runtime·printf(" <next segment>\n"); |
416 return false; // stop traceback | 429 return false; // stop traceback |
417 } | 430 } |
418 if(f->entry == (uintptr)runtime·main) { | 431 if(f->entry == (uintptr)runtime·main) { |
419 // A special routine at the TOS of the main routine. | 432 // A special routine at the TOS of the main routine. |
420 // We will allow it to be copied even though we don't | 433 // We will allow it to be copied even though we don't |
421 // have full GC info for it (because it is written in C). | 434 // have full GC info for it (because it is written in C). |
422 cinfo->frames++; | 435 cinfo->frames++; |
423 return false; // stop traceback | 436 return false; // stop traceback |
424 } | 437 } |
425 » if(frame->varp != (byte*)frame->sp) { // not in prologue (and has at lea
st one local or outarg) | 438 » if(f->entry == (uintptr)runtime·switchtoM) { |
| 439 » » // A special routine at the bottom of stack of a goroutine that
does onM call. |
| 440 » » // We will allow it to be copied even though we don't |
| 441 » » // have full GC info for it (because it is written in asm). |
| 442 » » cinfo->frames++; |
| 443 » » return true; |
| 444 » } |
| 445 » if((byte*)frame->varp != (byte*)frame->sp) { // not in prologue (and has
at least one local or outarg) |
426 stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); | 446 stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); |
427 if(stackmap == nil) { | 447 if(stackmap == nil) { |
428 cinfo->frames = -1; | 448 cinfo->frames = -1; |
429 » » » if(StackDebug >= 1) | 449 » » » if(StackDebug >= 1 || StackCopyAlways) |
430 » » » » runtime·printf("copystack: no locals info for %s
\n", runtime·funcname(f)); | 450 » » » » runtime·printf("runtime: copystack: no locals in
fo for %s\n", runtime·funcname(f)); |
431 return false; | 451 return false; |
432 } | 452 } |
433 if(stackmap->n <= 0) { | 453 if(stackmap->n <= 0) { |
434 cinfo->frames = -1; | 454 cinfo->frames = -1; |
435 » » » if(StackDebug >= 1) | 455 » » » if(StackDebug >= 1 || StackCopyAlways) |
436 » » » » runtime·printf("copystack: locals size info only
for %s\n", runtime·funcname(f)); | 456 » » » » runtime·printf("runtime: copystack: locals size
info only for %s\n", runtime·funcname(f)); |
437 return false; | 457 return false; |
438 } | 458 } |
439 } | 459 } |
440 if(frame->arglen != 0) { | 460 if(frame->arglen != 0) { |
441 stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); | 461 stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); |
442 if(stackmap == nil) { | 462 if(stackmap == nil) { |
443 cinfo->frames = -1; | 463 cinfo->frames = -1; |
444 » » » if(StackDebug >= 1) | 464 » » » if(StackDebug >= 1 || StackCopyAlways) |
445 » » » » runtime·printf("copystack: no arg info for %s\n"
, runtime·funcname(f)); | 465 » » » » runtime·printf("runtime: copystack: no arg info
for %s\n", runtime·funcname(f)); |
446 return false; | 466 return false; |
447 } | 467 } |
448 } | 468 } |
449 cinfo->frames++; | 469 cinfo->frames++; |
450 return true; // this frame is ok; keep going | 470 return true; // this frame is ok; keep going |
451 } | 471 } |
452 | 472 |
453 // If the top segment of the stack contains an uncopyable | 473 // If the top segment of the stack contains an uncopyable |
454 // frame, return -1. Otherwise return the number of frames | 474 // frame, return -1. Otherwise return the number of frames |
455 // in the top segment, all of which are copyable. | 475 // in the top segment, all of which are copyable. |
456 static int32 | 476 static int32 |
457 copyabletopsegment(G *gp) | 477 copyabletopsegment(G *gp) |
458 { | 478 { |
459 CopyableInfo cinfo; | 479 CopyableInfo cinfo; |
460 Defer *d; | 480 Defer *d; |
461 Func *f; | 481 Func *f; |
462 FuncVal *fn; | 482 FuncVal *fn; |
463 StackMap *stackmap; | 483 StackMap *stackmap; |
| 484 bool (*cb)(Stkframe*, void*); |
464 | 485 |
465 if(gp->stackbase == 0) | 486 if(gp->stackbase == 0) |
466 runtime·throw("stackbase == 0"); | 487 runtime·throw("stackbase == 0"); |
467 cinfo.stk = (byte*)gp->stackguard - StackGuard; | 488 cinfo.stk = (byte*)gp->stackguard - StackGuard; |
468 cinfo.base = (byte*)gp->stackbase + sizeof(Stktop); | 489 cinfo.base = (byte*)gp->stackbase + sizeof(Stktop); |
469 cinfo.frames = 0; | 490 cinfo.frames = 0; |
470 | 491 |
471 // Check that each frame is copyable. As a side effect, | 492 // Check that each frame is copyable. As a side effect, |
472 // count the frames. | 493 // count the frames. |
473 » runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff
, checkframecopy, &cinfo, false); | 494 » cb = checkframecopy; |
| 495 » runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff
, &cb, &cinfo, false); |
474 if(StackDebug >= 1 && cinfo.frames != -1) | 496 if(StackDebug >= 1 && cinfo.frames != -1) |
475 runtime·printf("copystack: %d copyable frames\n", cinfo.frames); | 497 runtime·printf("copystack: %d copyable frames\n", cinfo.frames); |
| 498 |
| 499 if(cinfo.frames == -1) |
| 500 return -1; |
476 | 501 |
477 // Check to make sure all Defers are copyable | 502 // Check to make sure all Defers are copyable |
478 for(d = gp->defer; d != nil; d = d->link) { | 503 for(d = gp->defer; d != nil; d = d->link) { |
479 if(cinfo.stk <= (byte*)d && (byte*)d < cinfo.base) { | 504 if(cinfo.stk <= (byte*)d && (byte*)d < cinfo.base) { |
480 // Defer is on the stack. Its copyableness has | 505 // Defer is on the stack. Its copyableness has |
481 // been established during stack walking. | 506 // been established during stack walking. |
482 // For now, this only happens with the Defer in runtime.
main. | 507 // For now, this only happens with the Defer in runtime.
main. |
483 continue; | 508 continue; |
484 } | 509 } |
485 » » if(d->argp < cinfo.stk || cinfo.base <= d->argp) | 510 » » if((byte*)d->argp < cinfo.stk || cinfo.base <= (byte*)d->argp) |
486 break; // a defer for the next segment | 511 break; // a defer for the next segment |
487 fn = d->fn; | 512 fn = d->fn; |
488 if(fn == nil) // See issue 8047 | 513 if(fn == nil) // See issue 8047 |
489 continue; | 514 continue; |
490 f = runtime·findfunc((uintptr)fn->fn); | 515 f = runtime·findfunc((uintptr)fn->fn); |
491 » » if(f == nil) | 516 » » if(f == nil) { |
| 517 » » » if(StackDebug >= 1 || StackCopyAlways) |
| 518 » » » » runtime·printf("runtime: copystack: no func for
deferred pc %p\n", fn->fn); |
492 return -1; | 519 return -1; |
| 520 } |
493 | 521 |
494 // Check to make sure we have an args pointer map for the defer'
s args. | 522 // Check to make sure we have an args pointer map for the defer'
s args. |
495 // We only need the args map, but we check | 523 // We only need the args map, but we check |
496 // for the locals map also, because when the locals map | 524 // for the locals map also, because when the locals map |
497 // isn't provided it means the ptr map came from C and | 525 // isn't provided it means the ptr map came from C and |
498 // C (particularly, cgo) lies to us. See issue 7695. | 526 // C (particularly, cgo) lies to us. See issue 7695. |
499 stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); | 527 stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); |
500 » » if(stackmap == nil || stackmap->n <= 0) | 528 » » if(stackmap == nil || stackmap->n <= 0) { |
| 529 » » » if(StackDebug >= 1 || StackCopyAlways) |
| 530 » » » » runtime·printf("runtime: copystack: no arg info
for deferred %s\n", runtime·funcname(f)); |
501 return -1; | 531 return -1; |
| 532 } |
502 stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); | 533 stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); |
503 » » if(stackmap == nil || stackmap->n <= 0) | 534 » » if(stackmap == nil || stackmap->n <= 0) { |
| 535 » » » if(StackDebug >= 1 || StackCopyAlways) |
| 536 » » » » runtime·printf("runtime: copystack: no local inf
o for deferred %s\n", runtime·funcname(f)); |
504 return -1; | 537 return -1; |
| 538 } |
505 | 539 |
506 if(cinfo.stk <= (byte*)fn && (byte*)fn < cinfo.base) { | 540 if(cinfo.stk <= (byte*)fn && (byte*)fn < cinfo.base) { |
507 // FuncVal is on the stack. Again, its copyableness | 541 // FuncVal is on the stack. Again, its copyableness |
508 // was established during stack walking. | 542 // was established during stack walking. |
509 continue; | 543 continue; |
510 } | 544 } |
511 // The FuncVal may have pointers in it, but fortunately for us | 545 // The FuncVal may have pointers in it, but fortunately for us |
512 // the compiler won't put pointers into the stack in a | 546 // the compiler won't put pointers into the stack in a |
513 // heap-allocated FuncVal. | 547 // heap-allocated FuncVal. |
514 // One day if we do need to check this, we'll need maps of the | 548 // One day if we do need to check this, we'll need maps of the |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
561 runtime·throw("bad pointer!"); | 595 runtime·throw("bad pointer!"); |
562 } | 596 } |
563 if(minp <= p && p < maxp) { | 597 if(minp <= p && p < maxp) { |
564 if(StackDebug >= 3) | 598 if(StackDebug >= 3) |
565 runtime·printf("adjust ptr %p %s\n", p,
runtime·funcname(f)); | 599 runtime·printf("adjust ptr %p %s\n", p,
runtime·funcname(f)); |
566 scanp[i] = p + delta; | 600 scanp[i] = p + delta; |
567 } | 601 } |
568 break; | 602 break; |
569 case BitsMultiWord: | 603 case BitsMultiWord: |
570 switch(bv->bytedata[(i+1) / (8 / BitsPerPointer)] >> ((i
+1) * BitsPerPointer & 7) & 3) { | 604 switch(bv->bytedata[(i+1) / (8 / BitsPerPointer)] >> ((i
+1) * BitsPerPointer & 7) & 3) { |
571 » » » case BitsString: | 605 » » » default: |
572 » » » » // string referents are never on the stack, neve
r need to be adjusted | 606 » » » » runtime·throw("unexpected garbage collection bit
s"); |
573 » » » » i++; // skip len | |
574 » » » » break; | |
575 » » » case BitsSlice: | |
576 » » » » p = scanp[i]; | |
577 » » » » if(minp <= p && p < maxp) { | |
578 » » » » » if(StackDebug >= 3) | |
579 » » » » » » runtime·printf("adjust slice %p\
n", p); | |
580 » » » » » scanp[i] = p + delta; | |
581 » » » » } | |
582 » » » » i += 2; // skip len, cap | |
583 » » » » break; | |
584 case BitsEface: | 607 case BitsEface: |
585 t = (Type*)scanp[i]; | 608 t = (Type*)scanp[i]; |
586 » » » » if(t != nil && (t->size > PtrSize || (t->kind &
KindNoPointers) == 0)) { | 609 » » » » if(t != nil && ((t->kind & KindDirectIface) == 0
|| (t->kind & KindNoPointers) == 0)) { |
587 p = scanp[i+1]; | 610 p = scanp[i+1]; |
588 if(minp <= p && p < maxp) { | 611 if(minp <= p && p < maxp) { |
589 if(StackDebug >= 3) | 612 if(StackDebug >= 3) |
590 runtime·printf("adjust e
face %p\n", p); | 613 runtime·printf("adjust e
face %p\n", p); |
591 if(t->size > PtrSize) // current
ly we always allocate such objects on the heap | 614 if(t->size > PtrSize) // current
ly we always allocate such objects on the heap |
592 runtime·throw("large int
erface value found on stack"); | 615 runtime·throw("large int
erface value found on stack"); |
593 scanp[i+1] = p + delta; | 616 scanp[i+1] = p + delta; |
594 } | 617 } |
595 } | 618 } |
596 i++; | 619 i++; |
597 break; | 620 break; |
598 case BitsIface: | 621 case BitsIface: |
599 tab = (Itab*)scanp[i]; | 622 tab = (Itab*)scanp[i]; |
600 if(tab != nil) { | 623 if(tab != nil) { |
601 t = tab->type; | 624 t = tab->type; |
602 //runtime·printf(" type=%p\n",
t); | 625 //runtime·printf(" type=%p\n",
t); |
603 » » » » » if(t->size > PtrSize || (t->kind & KindN
oPointers) == 0) { | 626 » » » » » if((t->kind & KindDirectIface) == 0 || (
t->kind & KindNoPointers) == 0) { |
604 p = scanp[i+1]; | 627 p = scanp[i+1]; |
605 if(minp <= p && p < maxp) { | 628 if(minp <= p && p < maxp) { |
606 if(StackDebug >= 3) | 629 if(StackDebug >= 3) |
607 runtime·printf("
adjust iface %p\n", p); | 630 runtime·printf("
adjust iface %p\n", p); |
608 if(t->size > PtrSize) //
currently we always allocate such objects on the heap | 631 if(t->size > PtrSize) //
currently we always allocate such objects on the heap |
609 runtime·throw("l
arge interface value found on stack"); | 632 runtime·throw("l
arge interface value found on stack"); |
610 scanp[i+1] = p + delta; | 633 scanp[i+1] = p + delta; |
611 } | 634 } |
612 } | 635 } |
613 } | 636 } |
(...skipping 13 matching lines...) Expand all Loading... |
627 Func *f; | 650 Func *f; |
628 StackMap *stackmap; | 651 StackMap *stackmap; |
629 int32 pcdata; | 652 int32 pcdata; |
630 BitVector bv; | 653 BitVector bv; |
631 uintptr targetpc; | 654 uintptr targetpc; |
632 | 655 |
633 adjinfo = arg; | 656 adjinfo = arg; |
634 f = frame->fn; | 657 f = frame->fn; |
635 if(StackDebug >= 2) | 658 if(StackDebug >= 2) |
636 runtime·printf(" adjusting %s frame=[%p,%p] pc=%p continpc=%p
\n", runtime·funcname(f), frame->sp, frame->fp, frame->pc, frame->continpc); | 659 runtime·printf(" adjusting %s frame=[%p,%p] pc=%p continpc=%p
\n", runtime·funcname(f), frame->sp, frame->fp, frame->pc, frame->continpc); |
637 » if(f->entry == (uintptr)runtime·main) | 660 » if(f->entry == (uintptr)runtime·main || |
| 661 » » f->entry == (uintptr)runtime·switchtoM) |
638 return true; | 662 return true; |
639 targetpc = frame->continpc; | 663 targetpc = frame->continpc; |
640 if(targetpc == 0) { | 664 if(targetpc == 0) { |
641 // Frame is dead. | 665 // Frame is dead. |
642 return true; | 666 return true; |
643 } | 667 } |
644 if(targetpc != f->entry) | 668 if(targetpc != f->entry) |
645 targetpc--; | 669 targetpc--; |
646 pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc); | 670 pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc); |
647 if(pcdata == -1) | 671 if(pcdata == -1) |
648 pcdata = 0; // in prologue | 672 pcdata = 0; // in prologue |
649 | 673 |
650 // adjust local pointers | 674 // adjust local pointers |
651 » if(frame->varp != (byte*)frame->sp) { | 675 » if((byte*)frame->varp != (byte*)frame->sp) { |
652 stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); | 676 stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); |
653 if(stackmap == nil) | 677 if(stackmap == nil) |
654 runtime·throw("no locals info"); | 678 runtime·throw("no locals info"); |
655 if(stackmap->n <= 0) | 679 if(stackmap->n <= 0) |
656 runtime·throw("locals size info only"); | 680 runtime·throw("locals size info only"); |
657 bv = runtime·stackmapdata(stackmap, pcdata); | 681 bv = runtime·stackmapdata(stackmap, pcdata); |
658 if(StackDebug >= 3) | 682 if(StackDebug >= 3) |
659 runtime·printf(" locals\n"); | 683 runtime·printf(" locals\n"); |
660 adjustpointers((byte**)frame->varp - bv.n / BitsPerPointer, &bv,
adjinfo, f); | 684 adjustpointers((byte**)frame->varp - bv.n / BitsPerPointer, &bv,
adjinfo, f); |
661 } | 685 } |
662 // adjust inargs and outargs | 686 // adjust inargs and outargs |
663 if(frame->arglen != 0) { | 687 if(frame->arglen != 0) { |
664 stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); | 688 stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); |
665 » » if(stackmap == nil) | 689 » » if(stackmap == nil) { |
| 690 » » » runtime·printf("size %d\n", (int32)frame->arglen); |
666 runtime·throw("no arg info"); | 691 runtime·throw("no arg info"); |
| 692 } |
667 bv = runtime·stackmapdata(stackmap, pcdata); | 693 bv = runtime·stackmapdata(stackmap, pcdata); |
668 if(StackDebug >= 3) | 694 if(StackDebug >= 3) |
669 runtime·printf(" args\n"); | 695 runtime·printf(" args\n"); |
670 adjustpointers((byte**)frame->argp, &bv, adjinfo, nil); | 696 adjustpointers((byte**)frame->argp, &bv, adjinfo, nil); |
671 } | 697 } |
672 return true; | 698 return true; |
673 } | 699 } |
674 | 700 |
675 static void | 701 static void |
676 adjustctxt(G *gp, AdjustInfo *adjinfo) | 702 adjustctxt(G *gp, AdjustInfo *adjinfo) |
677 { | 703 { |
678 if(adjinfo->oldstk <= (byte*)gp->sched.ctxt && (byte*)gp->sched.ctxt < a
djinfo->oldbase) | 704 if(adjinfo->oldstk <= (byte*)gp->sched.ctxt && (byte*)gp->sched.ctxt < a
djinfo->oldbase) |
679 gp->sched.ctxt = (byte*)gp->sched.ctxt + adjinfo->delta; | 705 gp->sched.ctxt = (byte*)gp->sched.ctxt + adjinfo->delta; |
680 } | 706 } |
681 | 707 |
682 static void | 708 static void |
683 adjustdefers(G *gp, AdjustInfo *adjinfo) | 709 adjustdefers(G *gp, AdjustInfo *adjinfo) |
684 { | 710 { |
685 Defer *d, **dp; | 711 Defer *d, **dp; |
686 Func *f; | 712 Func *f; |
687 FuncVal *fn; | 713 FuncVal *fn; |
688 StackMap *stackmap; | 714 StackMap *stackmap; |
689 BitVector bv; | 715 BitVector bv; |
690 | 716 |
691 for(dp = &gp->defer, d = *dp; d != nil; dp = &d->link, d = *dp) { | 717 for(dp = &gp->defer, d = *dp; d != nil; dp = &d->link, d = *dp) { |
692 if(adjinfo->oldstk <= (byte*)d && (byte*)d < adjinfo->oldbase) { | 718 if(adjinfo->oldstk <= (byte*)d && (byte*)d < adjinfo->oldbase) { |
693 // The Defer record is on the stack. Its fields will | 719 // The Defer record is on the stack. Its fields will |
694 // get adjusted appropriately. | 720 // get adjusted appropriately. |
695 » » » // This only happens for runtime.main now, but a compile
r | 721 » » » // This only happens for runtime.main and runtime.gopani
c now, |
696 » » » // optimization could do more of this. | 722 » » » // but a compiler optimization could do more of this. |
697 *dp = (Defer*)((byte*)d + adjinfo->delta); | 723 *dp = (Defer*)((byte*)d + adjinfo->delta); |
698 continue; | 724 continue; |
699 } | 725 } |
700 » » if(d->argp < adjinfo->oldstk || adjinfo->oldbase <= d->argp) | 726 » » if((byte*)d->argp < adjinfo->oldstk || adjinfo->oldbase <= (byte
*)d->argp) |
701 break; // a defer for the next segment | 727 break; // a defer for the next segment |
702 fn = d->fn; | 728 fn = d->fn; |
703 if(fn == nil) { | 729 if(fn == nil) { |
704 // Defer of nil function. It will panic when run, and t
here | 730 // Defer of nil function. It will panic when run, and t
here |
705 // aren't any args to adjust. See issue 8047. | 731 // aren't any args to adjust. See issue 8047. |
706 d->argp += adjinfo->delta; | 732 d->argp += adjinfo->delta; |
707 continue; | 733 continue; |
708 } | 734 } |
709 f = runtime·findfunc((uintptr)fn->fn); | 735 f = runtime·findfunc((uintptr)fn->fn); |
710 if(f == nil) | 736 if(f == nil) |
(...skipping 12 matching lines...) Expand all Loading... |
723 stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps)
; | 749 stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps)
; |
724 if(stackmap == nil) | 750 if(stackmap == nil) |
725 runtime·throw("runtime: deferred function has no
arg ptr map"); | 751 runtime·throw("runtime: deferred function has no
arg ptr map"); |
726 bv = runtime·stackmapdata(stackmap, 0); | 752 bv = runtime·stackmapdata(stackmap, 0); |
727 adjustpointers(d->args, &bv, adjinfo, f); | 753 adjustpointers(d->args, &bv, adjinfo, f); |
728 } | 754 } |
729 d->argp += adjinfo->delta; | 755 d->argp += adjinfo->delta; |
730 } | 756 } |
731 } | 757 } |
732 | 758 |
| 759 static void |
| 760 adjustpanics(G *gp, AdjustInfo *adjinfo) |
| 761 { |
| 762 Panic *p, **l; |
| 763 |
| 764 // only the topmost panic is on the current stack |
| 765 for(l = &gp->panic; (p = *l) != nil; ) { |
| 766 if(adjinfo->oldstk <= (byte*)p && (byte*)p < adjinfo->oldbase) |
| 767 *l = (Panic*)((byte*)p + adjinfo->delta); |
| 768 l = &p->link; |
| 769 ················ |
| 770 if(adjinfo->oldstk <= (byte*)p->argp && (byte*)p->argp < adjinfo
->oldbase) |
| 771 p->argp += adjinfo->delta; |
| 772 } |
| 773 } |
| 774 |
| 775 static void |
| 776 adjustsudogs(G *gp, AdjustInfo *adjinfo) |
| 777 { |
| 778 SudoG *s; |
| 779 byte *e; |
| 780 |
| 781 // the data elements pointed to by a SudoG structure |
| 782 // might be in the stack. |
| 783 for(s = gp->waiting; s != nil; s = s->waitlink) { |
| 784 e = s->elem; |
| 785 if(adjinfo->oldstk <= e && e < adjinfo->oldbase) |
| 786 s->elem = e + adjinfo->delta; |
| 787 e = (byte*)s->selectdone; |
| 788 if(adjinfo->oldstk <= e && e < adjinfo->oldbase) |
| 789 s->selectdone = (uint32*)(e + adjinfo->delta); |
| 790 } |
| 791 } |
| 792 |
733 // Copies the top stack segment of gp to a new stack segment of a | 793 // Copies the top stack segment of gp to a new stack segment of a |
734 // different size. The top segment must contain nframes frames. | 794 // different size. The top segment must contain nframes frames. |
735 static void | 795 static void |
736 copystack(G *gp, uintptr nframes, uintptr newsize) | 796 copystack(G *gp, uintptr nframes, uintptr newsize) |
737 { | 797 { |
738 byte *oldstk, *oldbase, *newstk, *newbase; | 798 byte *oldstk, *oldbase, *newstk, *newbase; |
739 uintptr oldsize, used; | 799 uintptr oldsize, used; |
740 AdjustInfo adjinfo; | 800 AdjustInfo adjinfo; |
741 Stktop *oldtop, *newtop; | 801 Stktop *oldtop, *newtop; |
| 802 uint32 oldstatus; |
| 803 bool (*cb)(Stkframe*, void*); |
742 | 804 |
743 if(gp->syscallstack != 0) | 805 if(gp->syscallstack != 0) |
744 runtime·throw("can't handle stack copy in syscall yet"); | 806 runtime·throw("can't handle stack copy in syscall yet"); |
745 oldstk = (byte*)gp->stackguard - StackGuard; | 807 oldstk = (byte*)gp->stackguard - StackGuard; |
746 if(gp->stackbase == 0) | 808 if(gp->stackbase == 0) |
747 runtime·throw("nil stackbase"); | 809 runtime·throw("nil stackbase"); |
748 oldbase = (byte*)gp->stackbase + sizeof(Stktop); | 810 oldbase = (byte*)gp->stackbase + sizeof(Stktop); |
749 oldsize = oldbase - oldstk; | 811 oldsize = oldbase - oldstk; |
750 used = oldbase - (byte*)gp->sched.sp; | 812 used = oldbase - (byte*)gp->sched.sp; |
751 oldtop = (Stktop*)gp->stackbase; | 813 oldtop = (Stktop*)gp->stackbase; |
752 | 814 |
753 // allocate new stack | 815 // allocate new stack |
754 newstk = runtime·stackalloc(gp, newsize); | 816 newstk = runtime·stackalloc(gp, newsize); |
755 newbase = newstk + newsize; | 817 newbase = newstk + newsize; |
756 newtop = (Stktop*)(newbase - sizeof(Stktop)); | 818 newtop = (Stktop*)(newbase - sizeof(Stktop)); |
757 | 819 |
758 if(StackDebug >= 1) | 820 if(StackDebug >= 1) |
759 runtime·printf("copystack gp=%p [%p %p]/%d -> [%p %p]/%d\n", gp,
oldstk, oldbase, (int32)oldsize, newstk, newbase, (int32)newsize); | 821 runtime·printf("copystack gp=%p [%p %p]/%d -> [%p %p]/%d\n", gp,
oldstk, oldbase, (int32)oldsize, newstk, newbase, (int32)newsize); |
760 USED(oldsize); | 822 USED(oldsize); |
761 ········ | 823 ········ |
762 // adjust pointers in the to-be-copied frames | 824 // adjust pointers in the to-be-copied frames |
763 adjinfo.oldstk = oldstk; | 825 adjinfo.oldstk = oldstk; |
764 adjinfo.oldbase = oldbase; | 826 adjinfo.oldbase = oldbase; |
765 adjinfo.delta = newbase - oldbase; | 827 adjinfo.delta = newbase - oldbase; |
766 » runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, nframes, a
djustframe, &adjinfo, false); | 828 » cb = adjustframe; |
| 829 » runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, nframes, &
cb, &adjinfo, false); |
767 ········ | 830 ········ |
768 // adjust other miscellaneous things that have pointers into stacks. | 831 // adjust other miscellaneous things that have pointers into stacks. |
769 adjustctxt(gp, &adjinfo); | 832 adjustctxt(gp, &adjinfo); |
770 adjustdefers(gp, &adjinfo); | 833 adjustdefers(gp, &adjinfo); |
| 834 adjustpanics(gp, &adjinfo); |
| 835 adjustsudogs(gp, &adjinfo); |
771 ········ | 836 ········ |
772 // copy the stack (including Stktop) to the new location | 837 // copy the stack (including Stktop) to the new location |
773 runtime·memmove(newbase - used, oldbase - used, used); | 838 runtime·memmove(newbase - used, oldbase - used, used); |
774 » | 839 » oldstatus = runtime·readgstatus(gp); |
| 840 » oldstatus &= ~Gscan; |
| 841 » if (oldstatus == Gwaiting || oldstatus == Grunnable) |
| 842 » » runtime·casgstatus(gp, oldstatus, Gcopystack); // oldstatus is G
waiting or Grunnable |
| 843 » else |
| 844 » » runtime·throw("copystack: bad status, not Gwaiting or Grunnable"
); |
775 // Swap out old stack for new one | 845 // Swap out old stack for new one |
776 gp->stackbase = (uintptr)newtop; | 846 gp->stackbase = (uintptr)newtop; |
777 gp->stackguard = (uintptr)newstk + StackGuard; | 847 gp->stackguard = (uintptr)newstk + StackGuard; |
778 gp->stackguard0 = (uintptr)newstk + StackGuard; // NOTE: might clobber a
preempt request | 848 gp->stackguard0 = (uintptr)newstk + StackGuard; // NOTE: might clobber a
preempt request |
779 if(gp->stack0 == (uintptr)oldstk) | 849 if(gp->stack0 == (uintptr)oldstk) |
780 gp->stack0 = (uintptr)newstk; | 850 gp->stack0 = (uintptr)newstk; |
781 gp->sched.sp = (uintptr)(newbase - used); | 851 gp->sched.sp = (uintptr)(newbase - used); |
782 | 852 |
| 853 runtime·casgstatus(gp, Gcopystack, oldstatus); // oldstatus is Gwaiting
or Grunnable |
| 854 |
783 // free old stack | 855 // free old stack |
784 runtime·stackfree(gp, oldstk, oldtop); | 856 runtime·stackfree(gp, oldstk, oldtop); |
785 } | 857 } |
786 | 858 |
787 // round x up to a power of 2. | 859 // round x up to a power of 2. |
788 int32 | 860 int32 |
789 runtime·round2(int32 x) | 861 runtime·round2(int32 x) |
790 { | 862 { |
791 int32 s; | 863 int32 s; |
792 | 864 |
793 s = 0; | 865 s = 0; |
794 while((1 << s) < x) | 866 while((1 << s) < x) |
795 s++; | 867 s++; |
796 return 1 << s; | 868 return 1 << s; |
797 } | 869 } |
798 | 870 |
799 // Called from runtime·newstackcall or from runtime·morestack when a new | 871 // Called from runtime·morestack when a new stack segment is needed. |
800 // stack segment is needed. Allocate a new stack big enough for | 872 // Allocate a new stack big enough for m->moreframesize bytes, |
801 // m->moreframesize bytes, copy m->moreargsize bytes to the new frame, | 873 // copy m->moreargsize bytes to the new frame, |
802 // and then act as though runtime·lessstack called the function at | 874 // and then act as though runtime·lessstack called the function at m->morepc. |
803 // m->morepc. | 875 // |
| 876 // g->atomicstatus will be Grunning, Gsyscall or Gscanrunning, Gscansyscall upon
entry.· |
| 877 // If the GC is trying to stop this g then it will set preemptscan to true. |
804 void | 878 void |
805 runtime·newstack(void) | 879 runtime·newstack(void) |
806 { | 880 { |
807 int32 framesize, argsize, oldstatus, oldsize, newsize, nframes; | 881 int32 framesize, argsize, oldstatus, oldsize, newsize, nframes; |
808 » Stktop *top, *oldtop; | 882 » Stktop *top; |
809 byte *stk, *oldstk, *oldbase; | 883 byte *stk, *oldstk, *oldbase; |
810 uintptr sp; | 884 uintptr sp; |
811 uintptr *src, *dst, *dstend; | 885 uintptr *src, *dst, *dstend; |
812 G *gp; | 886 G *gp; |
813 Gobuf label, morebuf; | 887 Gobuf label, morebuf; |
814 void *moreargp; | 888 void *moreargp; |
815 bool newstackcall; | |
816 | 889 |
817 if(g->m->forkstackguard) | 890 if(g->m->forkstackguard) |
818 runtime·throw("split stack after fork"); | 891 runtime·throw("split stack after fork"); |
819 if(g->m->morebuf.g != g->m->curg) { | 892 if(g->m->morebuf.g != g->m->curg) { |
820 runtime·printf("runtime: newstack called from g=%p\n" | 893 runtime·printf("runtime: newstack called from g=%p\n" |
821 "\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n", | 894 "\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n", |
822 g->m->morebuf.g, g->m, g->m->curg, g->m->g0, g->m->gsign
al); | 895 g->m->morebuf.g, g->m, g->m->curg, g->m->g0, g->m->gsign
al); |
| 896 morebuf = g->m->morebuf; |
| 897 runtime·traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g)
; |
823 runtime·throw("runtime: wrong goroutine in newstack"); | 898 runtime·throw("runtime: wrong goroutine in newstack"); |
824 } | 899 } |
| 900 if(g->throwsplit) |
| 901 runtime·throw("runtime: stack split at bad time"); |
| 902 |
| 903 // The goroutine must be executing in order to call newstack, so the pos
sible states are |
| 904 // Grunning and Gsyscall (and, due to GC, also Gscanrunning and Gscansys
call).·· |
825 | 905 |
826 // gp->status is usually Grunning, but it could be Gsyscall if a stack o
verflow | 906 // gp->status is usually Grunning, but it could be Gsyscall if a stack o
verflow |
827 // happens during a function call inside entersyscall. | 907 // happens during a function call inside entersyscall. |
828 gp = g->m->curg; | 908 gp = g->m->curg; |
829 » oldstatus = gp->status; | 909 » oldstatus = runtime·readgstatus(gp) & ~Gscan; |
830 | |
831 framesize = g->m->moreframesize; | 910 framesize = g->m->moreframesize; |
832 argsize = g->m->moreargsize; | 911 argsize = g->m->moreargsize; |
833 moreargp = g->m->moreargp; | 912 moreargp = g->m->moreargp; |
834 g->m->moreargp = nil; | 913 g->m->moreargp = nil; |
835 morebuf = g->m->morebuf; | 914 morebuf = g->m->morebuf; |
836 g->m->morebuf.pc = (uintptr)nil; | 915 g->m->morebuf.pc = (uintptr)nil; |
837 g->m->morebuf.lr = (uintptr)nil; | 916 g->m->morebuf.lr = (uintptr)nil; |
838 g->m->morebuf.sp = (uintptr)nil; | 917 g->m->morebuf.sp = (uintptr)nil; |
839 » gp->status = Gwaiting; | 918 |
840 » gp->waitreason = "stack growth"; | 919 » runtime·casgstatus(gp, oldstatus, Gwaiting); // oldstatus is not in a Gs
can status |
841 » newstackcall = framesize==1; | 920 » gp->waitreason = runtime·gostringnocopy((byte*)"stack growth"); |
842 » if(newstackcall) | 921 |
843 » » framesize = 0; | 922 » runtime·rewindmorestack(&gp->sched); |
844 | |
845 » // For newstackcall the context already points to beginning of runtime·n
ewstackcall. | |
846 » if(!newstackcall) | |
847 » » runtime·rewindmorestack(&gp->sched); | |
848 | 923 |
849 if(gp->stackbase == 0) | 924 if(gp->stackbase == 0) |
850 runtime·throw("nil stackbase"); | 925 runtime·throw("nil stackbase"); |
851 sp = gp->sched.sp; | 926 sp = gp->sched.sp; |
852 if(thechar == '6' || thechar == '8') { | 927 if(thechar == '6' || thechar == '8') { |
853 // The call to morestack cost a word. | 928 // The call to morestack cost a word. |
854 » » sp -= sizeof(uintptr); | 929 » » sp -= sizeof(uintreg); |
855 } | 930 } |
856 if(StackDebug >= 1 || sp < gp->stackguard - StackGuard) { | 931 if(StackDebug >= 1 || sp < gp->stackguard - StackGuard) { |
857 runtime·printf("runtime: newstack framesize=%p argsize=%p sp=%p
stack=[%p, %p]\n" | 932 runtime·printf("runtime: newstack framesize=%p argsize=%p sp=%p
stack=[%p, %p]\n" |
858 "\tmorebuf={pc:%p sp:%p lr:%p}\n" | 933 "\tmorebuf={pc:%p sp:%p lr:%p}\n" |
859 "\tsched={pc:%p sp:%p lr:%p ctxt:%p}\n", | 934 "\tsched={pc:%p sp:%p lr:%p ctxt:%p}\n", |
860 (uintptr)framesize, (uintptr)argsize, sp, gp->stackguard
- StackGuard, gp->stackbase, | 935 (uintptr)framesize, (uintptr)argsize, sp, gp->stackguard
- StackGuard, gp->stackbase, |
861 g->m->morebuf.pc, g->m->morebuf.sp, g->m->morebuf.lr, | 936 g->m->morebuf.pc, g->m->morebuf.sp, g->m->morebuf.lr, |
862 gp->sched.pc, gp->sched.sp, gp->sched.lr, gp->sched.ctxt
); | 937 gp->sched.pc, gp->sched.sp, gp->sched.lr, gp->sched.ctxt
); |
863 } | 938 } |
864 if(sp < gp->stackguard - StackGuard) { | 939 if(sp < gp->stackguard - StackGuard) { |
| 940 runtime·printf("runtime: gp=%p, gp->status=%d, oldstatus=%d\n ",
(void*)gp, runtime·readgstatus(gp), oldstatus); |
865 runtime·printf("runtime: split stack overflow: %p < %p\n", sp, g
p->stackguard - StackGuard); | 941 runtime·printf("runtime: split stack overflow: %p < %p\n", sp, g
p->stackguard - StackGuard); |
866 runtime·throw("runtime: split stack overflow"); | 942 runtime·throw("runtime: split stack overflow"); |
867 } | 943 } |
868 | 944 |
869 if(argsize % sizeof(uintptr) != 0) { | 945 if(argsize % sizeof(uintptr) != 0) { |
870 runtime·printf("runtime: stack growth with misaligned argsize %d
\n", argsize); | 946 runtime·printf("runtime: stack growth with misaligned argsize %d
\n", argsize); |
871 runtime·throw("runtime: stack growth argsize"); | 947 runtime·throw("runtime: stack growth argsize"); |
872 } | 948 } |
873 | 949 |
874 if(gp->stackguard0 == (uintptr)StackPreempt) { | 950 if(gp->stackguard0 == (uintptr)StackPreempt) { |
875 if(gp == g->m->g0) | 951 if(gp == g->m->g0) |
876 runtime·throw("runtime: preempt g0"); | 952 runtime·throw("runtime: preempt g0"); |
877 if(oldstatus == Grunning && g->m->p == nil && g->m->locks == 0) | 953 if(oldstatus == Grunning && g->m->p == nil && g->m->locks == 0) |
878 runtime·throw("runtime: g is running but p is not"); | 954 runtime·throw("runtime: g is running but p is not"); |
879 if(oldstatus == Gsyscall && g->m->locks == 0) | 955 if(oldstatus == Gsyscall && g->m->locks == 0) |
880 runtime·throw("runtime: stack growth during syscall"); | 956 runtime·throw("runtime: stack growth during syscall"); |
| 957 if(oldstatus == Grunning && gp->preemptscan) { |
| 958 runtime·gcphasework(gp); |
| 959 runtime·casgstatus(gp, Gwaiting, Grunning); |
| 960 gp->stackguard0 = gp->stackguard; |
| 961 gp->preempt = false;· |
| 962 gp->preemptscan = false; // Tells the GC premptio
n was successful. |
| 963 runtime·gogo(&gp->sched); // never return· |
| 964 } |
| 965 |
881 // Be conservative about where we preempt. | 966 // Be conservative about where we preempt. |
882 // We are interested in preempting user Go code, not runtime cod
e. | 967 // We are interested in preempting user Go code, not runtime cod
e. |
883 if(oldstatus != Grunning || g->m->locks || g->m->mallocing || g-
>m->gcing || g->m->p->status != Prunning) { | 968 if(oldstatus != Grunning || g->m->locks || g->m->mallocing || g-
>m->gcing || g->m->p->status != Prunning) { |
884 // Let the goroutine keep running for now. | 969 // Let the goroutine keep running for now. |
885 // gp->preempt is set, so it will be preempted next time
. | 970 // gp->preempt is set, so it will be preempted next time
. |
886 gp->stackguard0 = gp->stackguard; | 971 gp->stackguard0 = gp->stackguard; |
887 » » » gp->status = oldstatus; | 972 » » » runtime·casgstatus(gp, Gwaiting, oldstatus); // oldstatu
s is Gsyscall or Grunning |
888 runtime·gogo(&gp->sched); // never return | 973 runtime·gogo(&gp->sched); // never return |
889 } | 974 } |
890 // Act like goroutine called runtime.Gosched. | 975 // Act like goroutine called runtime.Gosched. |
891 » » gp->status = oldstatus; | 976 » » runtime·casgstatus(gp, Gwaiting, oldstatus); // oldstatus is Gsy
scall or Grunning |
892 » » runtime·gosched0(gp);» // never return | 977 » » runtime·gosched_m(gp);» // never return |
893 } | 978 } |
894 | 979 |
895 // If every frame on the top segment is copyable, allocate a bigger segm
ent | 980 // If every frame on the top segment is copyable, allocate a bigger segm
ent |
896 // and move the segment instead of allocating a new segment. | 981 // and move the segment instead of allocating a new segment. |
897 if(runtime·copystack) { | 982 if(runtime·copystack) { |
898 if(!runtime·precisestack) | 983 if(!runtime·precisestack) |
899 runtime·throw("can't copy stacks without precise stacks"
); | 984 runtime·throw("can't copy stacks without precise stacks"
); |
900 nframes = copyabletopsegment(gp); | 985 nframes = copyabletopsegment(gp); |
901 if(nframes != -1) { | 986 if(nframes != -1) { |
902 oldstk = (byte*)gp->stackguard - StackGuard; | 987 oldstk = (byte*)gp->stackguard - StackGuard; |
903 oldbase = (byte*)gp->stackbase + sizeof(Stktop); | 988 oldbase = (byte*)gp->stackbase + sizeof(Stktop); |
904 oldsize = oldbase - oldstk; | 989 oldsize = oldbase - oldstk; |
905 newsize = oldsize * 2; | 990 newsize = oldsize * 2; |
| 991 // Note that the concurrent GC might be scanning the sta
ck as we try to replace it. |
| 992 // copystack takes care of the appropriate coordination
with the stack scanner. |
906 copystack(gp, nframes, newsize); | 993 copystack(gp, nframes, newsize); |
907 if(StackDebug >= 1) | 994 if(StackDebug >= 1) |
908 runtime·printf("stack grow done\n"); | 995 runtime·printf("stack grow done\n"); |
909 if(gp->stacksize > runtime·maxstacksize) { | 996 if(gp->stacksize > runtime·maxstacksize) { |
910 runtime·printf("runtime: goroutine stack exceeds
%D-byte limit\n", (uint64)runtime·maxstacksize); | 997 runtime·printf("runtime: goroutine stack exceeds
%D-byte limit\n", (uint64)runtime·maxstacksize); |
911 runtime·throw("stack overflow"); | 998 runtime·throw("stack overflow"); |
912 } | 999 } |
913 » » » gp->status = oldstatus; | 1000 » » » runtime·casgstatus(gp, Gwaiting, oldstatus); // oldstatu
s is Gsyscall or Grunning |
914 runtime·gogo(&gp->sched); | 1001 runtime·gogo(&gp->sched); |
915 } | 1002 } |
916 // TODO: if stack is uncopyable because we're in C code, patch r
eturn value at | 1003 // TODO: if stack is uncopyable because we're in C code, patch r
eturn value at |
917 // end of C code to trigger a copy as soon as C code exits. Tha
t way, we'll | 1004 // end of C code to trigger a copy as soon as C code exits. Tha
t way, we'll |
918 // have stack available if we get this deep again. | 1005 // have stack available if we get this deep again. |
919 } | 1006 } |
| 1007 ········ |
| 1008 if(StackCopyAlways) |
| 1009 runtime·throw("split stack not allowed"); |
920 | 1010 |
921 // allocate new segment. | 1011 // allocate new segment. |
922 framesize += argsize; | 1012 framesize += argsize; |
923 framesize += StackExtra; // room for more functions, Stktop. | 1013 framesize += StackExtra; // room for more functions, Stktop. |
924 if(framesize < StackMin) | 1014 if(framesize < StackMin) |
925 framesize = StackMin; | 1015 framesize = StackMin; |
926 framesize += StackSystem; | 1016 framesize += StackSystem; |
927 framesize = runtime·round2(framesize); | 1017 framesize = runtime·round2(framesize); |
928 stk = runtime·stackalloc(gp, framesize); | 1018 stk = runtime·stackalloc(gp, framesize); |
929 if(gp->stacksize > runtime·maxstacksize) { | 1019 if(gp->stacksize > runtime·maxstacksize) { |
930 runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n
", (uint64)runtime·maxstacksize); | 1020 runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n
", (uint64)runtime·maxstacksize); |
931 runtime·throw("stack overflow"); | 1021 runtime·throw("stack overflow"); |
932 } | 1022 } |
933 top = (Stktop*)(stk+framesize-sizeof(*top)); | 1023 top = (Stktop*)(stk+framesize-sizeof(*top)); |
934 | 1024 |
935 if(StackDebug >= 1) { | 1025 if(StackDebug >= 1) { |
936 runtime·printf("\t-> new stack gp=%p [%p, %p]\n", gp, stk, top); | 1026 runtime·printf("\t-> new stack gp=%p [%p, %p]\n", gp, stk, top); |
937 } | 1027 } |
938 | 1028 |
939 top->stackbase = gp->stackbase; | 1029 top->stackbase = gp->stackbase; |
940 top->stackguard = gp->stackguard; | 1030 top->stackguard = gp->stackguard; |
941 top->gobuf = morebuf; | 1031 top->gobuf = morebuf; |
942 top->argp = moreargp; | 1032 top->argp = moreargp; |
943 top->argsize = argsize; | 1033 top->argsize = argsize; |
944 | 1034 |
945 // copy flag from panic | |
946 top->panic = gp->ispanic; | |
947 gp->ispanic = false; | |
948 ········ | |
949 // if this isn't a panic, maybe we're splitting the stack for a panic. | |
950 // if we're splitting in the top frame, propagate the panic flag | |
951 // forward so that recover will know we're in a panic. | |
952 oldtop = (Stktop*)top->stackbase; | |
953 if(oldtop != nil && oldtop->panic && top->argp == (byte*)oldtop - oldtop
->argsize - gp->panicwrap) | |
954 top->panic = true; | |
955 | |
956 top->panicwrap = gp->panicwrap; | |
957 gp->panicwrap = 0; | |
958 | |
959 gp->stackbase = (uintptr)top; | 1035 gp->stackbase = (uintptr)top; |
960 gp->stackguard = (uintptr)stk + StackGuard; | 1036 gp->stackguard = (uintptr)stk + StackGuard; |
961 gp->stackguard0 = gp->stackguard; | 1037 gp->stackguard0 = gp->stackguard; |
962 | 1038 |
963 sp = (uintptr)top; | 1039 sp = (uintptr)top; |
964 if(argsize > 0) { | 1040 if(argsize > 0) { |
965 sp -= argsize; | 1041 sp -= argsize; |
966 dst = (uintptr*)sp; | 1042 dst = (uintptr*)sp; |
967 dstend = dst + argsize/sizeof(*dst); | 1043 dstend = dst + argsize/sizeof(*dst); |
968 src = (uintptr*)top->argp; | 1044 src = (uintptr*)top->argp; |
969 while(dst < dstend) | 1045 while(dst < dstend) |
970 *dst++ = *src++; | 1046 *dst++ = *src++; |
971 } | 1047 } |
| 1048 ········ |
972 if(thechar == '5' || thechar == '9') { | 1049 if(thechar == '5' || thechar == '9') { |
973 // caller would have saved its LR below args. | 1050 // caller would have saved its LR below args. |
974 sp -= sizeof(void*); | 1051 sp -= sizeof(void*); |
975 *(void**)sp = nil; | 1052 *(void**)sp = nil; |
976 } | 1053 } |
977 | 1054 |
978 // Continue as if lessstack had just called m->morepc | 1055 // Continue as if lessstack had just called m->morepc |
979 // (the PC that decided to grow the stack). | 1056 // (the PC that decided to grow the stack). |
980 runtime·memclr((byte*)&label, sizeof label); | 1057 runtime·memclr((byte*)&label, sizeof label); |
981 label.sp = sp; | 1058 label.sp = sp; |
982 label.pc = (uintptr)runtime·lessstack; | 1059 label.pc = (uintptr)runtime·lessstack; |
983 label.g = g->m->curg; | 1060 label.g = g->m->curg; |
984 » if(newstackcall) | 1061 » runtime·gostartcall(&label, (void(*)(void))gp->sched.pc, gp->sched.ctxt)
; |
985 » » runtime·gostartcallfn(&label, (FuncVal*)g->m->cret); | 1062 » gp->sched.ctxt = nil; |
986 » else { | 1063 » runtime·casgstatus(gp, Gwaiting, oldstatus); // oldstatus is Grunning or
Gsyscall |
987 » » runtime·gostartcall(&label, (void(*)(void))gp->sched.pc, gp->sch
ed.ctxt); | |
988 » » gp->sched.ctxt = nil; | |
989 » } | |
990 » gp->status = oldstatus; | |
991 runtime·gogo(&label); | 1064 runtime·gogo(&label); |
992 | 1065 |
993 *(int32*)345 = 123; // never return | 1066 *(int32*)345 = 123; // never return |
994 } | 1067 } |
995 | 1068 |
996 #pragma textflag NOSPLIT | 1069 #pragma textflag NOSPLIT |
997 void | 1070 void |
998 runtime·nilfunc(void) | 1071 runtime·nilfunc(void) |
999 { | 1072 { |
1000 *(byte*)0 = 0; | 1073 *(byte*)0 = 0; |
(...skipping 17 matching lines...) Expand all Loading... |
1018 // Called at garbage collection time. | 1091 // Called at garbage collection time. |
1019 void | 1092 void |
1020 runtime·shrinkstack(G *gp) | 1093 runtime·shrinkstack(G *gp) |
1021 { | 1094 { |
1022 int32 nframes; | 1095 int32 nframes; |
1023 byte *oldstk, *oldbase; | 1096 byte *oldstk, *oldbase; |
1024 uintptr used, oldsize, newsize; | 1097 uintptr used, oldsize, newsize; |
1025 | 1098 |
1026 if(!runtime·copystack) | 1099 if(!runtime·copystack) |
1027 return; | 1100 return; |
1028 » if(gp->status == Gdead) | 1101 » if(runtime·readgstatus(gp) == Gdead) |
1029 return; | 1102 return; |
1030 if(gp->stackbase == 0) | 1103 if(gp->stackbase == 0) |
1031 runtime·throw("stackbase == 0"); | 1104 runtime·throw("stackbase == 0"); |
1032 //return; // TODO: why does this happen? | 1105 //return; // TODO: why does this happen? |
1033 oldstk = (byte*)gp->stackguard - StackGuard; | 1106 oldstk = (byte*)gp->stackguard - StackGuard; |
1034 oldbase = (byte*)gp->stackbase + sizeof(Stktop); | 1107 oldbase = (byte*)gp->stackbase + sizeof(Stktop); |
1035 oldsize = oldbase - oldstk; | 1108 oldsize = oldbase - oldstk; |
1036 newsize = oldsize / 2; | 1109 newsize = oldsize / 2; |
1037 if(newsize < FixedStack) | 1110 if(newsize < FixedStack) |
1038 return; // don't shrink below the minimum-sized stack | 1111 return; // don't shrink below the minimum-sized stack |
1039 used = oldbase - (byte*)gp->sched.sp; | 1112 used = oldbase - (byte*)gp->sched.sp; |
1040 if(used >= oldsize / 4) | 1113 if(used >= oldsize / 4) |
1041 return; // still using at least 1/4 of the segment. | 1114 return; // still using at least 1/4 of the segment. |
1042 | 1115 |
1043 if(gp->syscallstack != (uintptr)nil) // TODO: can we handle this case? | 1116 if(gp->syscallstack != (uintptr)nil) // TODO: can we handle this case? |
1044 return; | 1117 return; |
1045 #ifdef GOOS_windows | 1118 #ifdef GOOS_windows |
1046 if(gp->m != nil && gp->m->libcallsp != 0) | 1119 if(gp->m != nil && gp->m->libcallsp != 0) |
1047 return; | 1120 return; |
1048 #endif | 1121 #endif |
| 1122 if(StackDebug > 0) |
| 1123 runtime·printf("shrinking stack %D->%D\n", (uint64)oldsize, (uin
t64)newsize); |
1049 nframes = copyabletopsegment(gp); | 1124 nframes = copyabletopsegment(gp); |
1050 if(nframes == -1) | 1125 if(nframes == -1) |
1051 return; | 1126 return; |
1052 copystack(gp, nframes, newsize); | 1127 copystack(gp, nframes, newsize); |
1053 } | 1128 } |
LEFT | RIGHT |