1
// Copyright 2013 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.
6
#include "arch_GOARCH.h"
10
typedef struct StackCacheNode StackCacheNode;
14
void* batch[StackCacheBatch-1];
17
static StackCacheNode *stackcache;
18
static Lock stackcachemu;
20
// stackcacherefill/stackcacherelease implement a global cache of stack segments.
21
// The cache is required to prevent unlimited growth of per-thread caches.
23
stackcacherefill(void)
28
runtime·lock(&stackcachemu);
32
runtime·unlock(&stackcachemu);
34
n = (StackCacheNode*)runtime·SysAlloc(FixedStack*StackCacheBatch);
36
runtime·throw("out of memory (stackcacherefill)");
37
runtime·xadd64(&mstats.stacks_sys, FixedStack*StackCacheBatch);
38
for(i = 0; i < StackCacheBatch-1; i++)
39
n->batch[i] = (byte*)n + (i+1)*FixedStack;
41
pos = m->stackcachepos;
42
for(i = 0; i < StackCacheBatch-1; i++) {
43
m->stackcache[pos] = n->batch[i];
44
pos = (pos + 1) % StackCacheSize;
46
m->stackcache[pos] = n;
47
pos = (pos + 1) % StackCacheSize;
48
m->stackcachepos = pos;
49
m->stackcachecnt += StackCacheBatch;
53
stackcacherelease(void)
58
pos = (m->stackcachepos - m->stackcachecnt) % StackCacheSize;
59
n = (StackCacheNode*)m->stackcache[pos];
60
pos = (pos + 1) % StackCacheSize;
61
for(i = 0; i < StackCacheBatch-1; i++) {
62
n->batch[i] = m->stackcache[pos];
63
pos = (pos + 1) % StackCacheSize;
65
m->stackcachecnt -= StackCacheBatch;
66
runtime·lock(&stackcachemu);
69
runtime·unlock(&stackcachemu);
73
runtime·stackalloc(uint32 n)
78
// Stackalloc must be called on scheduler stack, so that we
79
// never try to grow the stack during the code that stackalloc runs.
80
// Doing so would cause a deadlock (issue 1547).
82
runtime·throw("stackalloc not on scheduler stack");
84
// Stack allocator uses malloc/free most of the time,
85
// but if we're in the middle of malloc and need stack,
86
// we have to do something else to avoid deadlock.
87
// In that case, we fall back on a fixed-size free-list
88
// allocator, assuming that inside malloc all the stack
89
// frames are small, so that all the stack allocations
90
// will be a single size, the minimum (right now, 5k).
91
if(n == FixedStack || m->mallocing || m->gcing) {
93
runtime·printf("stackalloc: in malloc, size=%d want %d\n", FixedStack, n);
94
runtime·throw("stackalloc");
96
if(m->stackcachecnt == 0)
98
pos = m->stackcachepos;
99
pos = (pos - 1) % StackCacheSize;
100
v = m->stackcache[pos];
101
m->stackcachepos = pos;
106
return runtime·mallocgc(n, FlagNoProfiling|FlagNoGC, 0, 0);
110
runtime·stackfree(void *v, uintptr n)
114
if(n == FixedStack || m->mallocing || m->gcing) {
115
if(m->stackcachecnt == StackCacheSize)
117
pos = m->stackcachepos;
118
m->stackcache[pos] = v;
119
m->stackcachepos = (pos + 1) % StackCacheSize;
127
// Called from runtime·lessstack when returning from a function which
128
// allocated a new stack segment. The function's return value is in
131
runtime·oldstack(void)
138
uintptr *src, *dst, *dstend;
142
//printf("oldstack m->cret=%p\n", m->cret);
145
top = (Stktop*)gp->stackbase;
146
old = (byte*)gp->stackguard - StackGuard;
148
argsize = top->argsize;
151
dst = (uintptr*)top->argp;
152
dstend = dst + argsize/sizeof(*dst);
157
goid = top->gobuf.g->goid; // fault if g is bad, before gogo
161
gp->stackbase = (uintptr)top->stackbase;
162
gp->stackguard = (uintptr)top->stackguard;
164
runtime·stackfree(old, top->free);
167
m->cret = 0; // drop reference
168
runtime·gogo(&label, cret);
171
// Called from reflect·call or from runtime·morestack when a new
172
// stack segment is needed. Allocate a new stack big enough for
173
// m->moreframesize bytes, copy m->moreargsize bytes to the new frame,
174
// and then act as though runtime·lessstack called the function at
177
runtime·newstack(void)
179
int32 framesize, minalloc, argsize;
182
uintptr *src, *dst, *dstend;
188
framesize = m->moreframesize;
189
argsize = m->moreargsize;
192
if(m->morebuf.sp < gp->stackguard - StackGuard) {
193
runtime·printf("runtime: split stack overflow: %p < %p\n", m->morebuf.sp, gp->stackguard - StackGuard);
194
runtime·throw("runtime: split stack overflow");
196
if(argsize % sizeof(uintptr) != 0) {
197
runtime·printf("runtime: stack split with misaligned argsize %d\n", argsize);
198
runtime·throw("runtime: stack split argsize");
202
reflectcall = framesize==1;
205
// moreframesize_minalloc is only set in runtime·gc(),
206
// that calls newstack via reflect·call().
207
minalloc = m->moreframesize_minalloc;
208
m->moreframesize_minalloc = 0;
209
if(framesize < minalloc)
210
framesize = minalloc;
213
if(reflectcall && minalloc == 0 && m->morebuf.sp - sizeof(Stktop) - argsize - 32 > gp->stackguard) {
214
// special case: called from reflect.call (framesize==1)
215
// to call code with an arbitrary argument size,
216
// and we have enough space on the current stack.
217
// the new Stktop* is necessary to unwind, but
218
// we don't need to create a new segment.
219
top = (Stktop*)(m->morebuf.sp - sizeof(*top));
220
stk = (byte*)gp->stackguard - StackGuard;
223
// allocate new segment.
224
framesize += argsize;
225
framesize += StackExtra; // room for more functions, Stktop.
226
if(framesize < StackMin)
227
framesize = StackMin;
228
framesize += StackSystem;
229
stk = runtime·stackalloc(framesize);
230
top = (Stktop*)(stk+framesize-sizeof(*top));
235
runtime·printf("newstack framesize=%d argsize=%d morepc=%p moreargp=%p gobuf=%p, %p top=%p old=%p\n",
236
framesize, argsize, m->morepc, m->moreargp, m->morebuf.pc, m->morebuf.sp, top, gp->stackbase);
239
top->stackbase = (byte*)gp->stackbase;
240
top->stackguard = (byte*)gp->stackguard;
241
top->gobuf = m->morebuf;
242
top->argp = m->moreargp;
243
top->argsize = argsize;
247
m->morebuf.sp = (uintptr)nil;
249
// copy flag from panic
250
top->panic = gp->ispanic;
253
gp->stackbase = (uintptr)top;
254
gp->stackguard = (uintptr)stk + StackGuard;
260
dstend = dst + argsize/sizeof(*dst);
261
src = (uintptr*)top->argp;
266
// caller would have saved its LR below args.
271
// Continue as if lessstack had just called m->morepc
272
// (the PC that decided to grow the stack).
273
label.sp = (uintptr)sp;
274
label.pc = (byte*)runtime·lessstack;
277
runtime·gogocallfn(&label, (FuncVal*)m->morepc);
279
runtime·gogocall(&label, m->morepc, m->cret);
281
*(int32*)345 = 123; // never return