~ubuntu-branches/ubuntu/vivid/golang/vivid

« back to all changes in this revision

Viewing changes to src/pkg/runtime/stack.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-20 14:06:23 UTC
  • mfrom: (14.1.23 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130820140623-b414jfxi3m0qkmrq
Tags: 2:1.1.2-2ubuntu1
* Merge from Debian unstable (LP: #1211749, #1202027). Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - d/control,control.cross: Update Breaks/Replaces for Ubuntu
    versions to ensure smooth upgrades, regenerate control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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.
 
4
 
 
5
#include "runtime.h"
 
6
#include "arch_GOARCH.h"
 
7
#include "malloc.h"
 
8
#include "stack.h"
 
9
 
 
10
typedef struct StackCacheNode StackCacheNode;
 
11
struct StackCacheNode
 
12
{
 
13
        StackCacheNode *next;
 
14
        void*   batch[StackCacheBatch-1];
 
15
};
 
16
 
 
17
static StackCacheNode *stackcache;
 
18
static Lock stackcachemu;
 
19
 
 
20
// stackcacherefill/stackcacherelease implement a global cache of stack segments.
 
21
// The cache is required to prevent unlimited growth of per-thread caches.
 
22
static void
 
23
stackcacherefill(void)
 
24
{
 
25
        StackCacheNode *n;
 
26
        int32 i, pos;
 
27
 
 
28
        runtime·lock(&stackcachemu);
 
29
        n = stackcache;
 
30
        if(n)
 
31
                stackcache = n->next;
 
32
        runtime·unlock(&stackcachemu);
 
33
        if(n == nil) {
 
34
                n = (StackCacheNode*)runtime·SysAlloc(FixedStack*StackCacheBatch);
 
35
                if(n == nil)
 
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;
 
40
        }
 
41
        pos = m->stackcachepos;
 
42
        for(i = 0; i < StackCacheBatch-1; i++) {
 
43
                m->stackcache[pos] = n->batch[i];
 
44
                pos = (pos + 1) % StackCacheSize;
 
45
        }
 
46
        m->stackcache[pos] = n;
 
47
        pos = (pos + 1) % StackCacheSize;
 
48
        m->stackcachepos = pos;
 
49
        m->stackcachecnt += StackCacheBatch;
 
50
}
 
51
 
 
52
static void
 
53
stackcacherelease(void)
 
54
{
 
55
        StackCacheNode *n;
 
56
        uint32 i, pos;
 
57
 
 
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;
 
64
        }
 
65
        m->stackcachecnt -= StackCacheBatch;
 
66
        runtime·lock(&stackcachemu);
 
67
        n->next = stackcache;
 
68
        stackcache = n;
 
69
        runtime·unlock(&stackcachemu);
 
70
}
 
71
 
 
72
void*
 
73
runtime·stackalloc(uint32 n)
 
74
{
 
75
        uint32 pos;
 
76
        void *v;
 
77
 
 
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).
 
81
        if(g != m->g0)
 
82
                runtime·throw("stackalloc not on scheduler stack");
 
83
 
 
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) {
 
92
                if(n != FixedStack) {
 
93
                        runtime·printf("stackalloc: in malloc, size=%d want %d\n", FixedStack, n);
 
94
                        runtime·throw("stackalloc");
 
95
                }
 
96
                if(m->stackcachecnt == 0)
 
97
                        stackcacherefill();
 
98
                pos = m->stackcachepos;
 
99
                pos = (pos - 1) % StackCacheSize;
 
100
                v = m->stackcache[pos];
 
101
                m->stackcachepos = pos;
 
102
                m->stackcachecnt--;
 
103
                m->stackinuse++;
 
104
                return v;
 
105
        }
 
106
        return runtime·mallocgc(n, FlagNoProfiling|FlagNoGC, 0, 0);
 
107
}
 
108
 
 
109
void
 
110
runtime·stackfree(void *v, uintptr n)
 
111
{
 
112
        uint32 pos;
 
113
 
 
114
        if(n == FixedStack || m->mallocing || m->gcing) {
 
115
                if(m->stackcachecnt == StackCacheSize)
 
116
                        stackcacherelease();
 
117
                pos = m->stackcachepos;
 
118
                m->stackcache[pos] = v;
 
119
                m->stackcachepos = (pos + 1) % StackCacheSize;
 
120
                m->stackcachecnt++;
 
121
                m->stackinuse--;
 
122
                return;
 
123
        }
 
124
        runtime·free(v);
 
125
}
 
126
 
 
127
// Called from runtime·lessstack when returning from a function which
 
128
// allocated a new stack segment.  The function's return value is in
 
129
// m->cret.
 
130
void
 
131
runtime·oldstack(void)
 
132
{
 
133
        Stktop *top;
 
134
        Gobuf label;
 
135
        uint32 argsize;
 
136
        uintptr cret;
 
137
        byte *sp, *old;
 
138
        uintptr *src, *dst, *dstend;
 
139
        G *gp;
 
140
        int64 goid;
 
141
 
 
142
//printf("oldstack m->cret=%p\n", m->cret);
 
143
 
 
144
        gp = m->curg;
 
145
        top = (Stktop*)gp->stackbase;
 
146
        old = (byte*)gp->stackguard - StackGuard;
 
147
        sp = (byte*)top;
 
148
        argsize = top->argsize;
 
149
        if(argsize > 0) {
 
150
                sp -= argsize;
 
151
                dst = (uintptr*)top->argp;
 
152
                dstend = dst + argsize/sizeof(*dst);
 
153
                src = (uintptr*)sp;
 
154
                while(dst < dstend)
 
155
                        *dst++ = *src++;
 
156
        }
 
157
        goid = top->gobuf.g->goid;      // fault if g is bad, before gogo
 
158
        USED(goid);
 
159
 
 
160
        label = top->gobuf;
 
161
        gp->stackbase = (uintptr)top->stackbase;
 
162
        gp->stackguard = (uintptr)top->stackguard;
 
163
        if(top->free != 0)
 
164
                runtime·stackfree(old, top->free);
 
165
 
 
166
        cret = m->cret;
 
167
        m->cret = 0;  // drop reference
 
168
        runtime·gogo(&label, cret);
 
169
}
 
170
 
 
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
 
175
// m->morepc.
 
176
void
 
177
runtime·newstack(void)
 
178
{
 
179
        int32 framesize, minalloc, argsize;
 
180
        Stktop *top;
 
181
        byte *stk, *sp;
 
182
        uintptr *src, *dst, *dstend;
 
183
        G *gp;
 
184
        Gobuf label;
 
185
        bool reflectcall;
 
186
        uintptr free;
 
187
 
 
188
        framesize = m->moreframesize;
 
189
        argsize = m->moreargsize;
 
190
        gp = m->curg;
 
191
 
 
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");
 
195
        }
 
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");
 
199
        }
 
200
 
 
201
        minalloc = 0;
 
202
        reflectcall = framesize==1;
 
203
        if(reflectcall) {
 
204
                framesize = 0;
 
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;
 
211
        }
 
212
 
 
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;
 
221
                free = 0;
 
222
        } else {
 
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));
 
231
                free = framesize;
 
232
        }
 
233
 
 
234
        if(0) {
 
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);
 
237
        }
 
238
 
 
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;
 
244
        top->free = free;
 
245
        m->moreargp = nil;
 
246
        m->morebuf.pc = nil;
 
247
        m->morebuf.sp = (uintptr)nil;
 
248
 
 
249
        // copy flag from panic
 
250
        top->panic = gp->ispanic;
 
251
        gp->ispanic = false;
 
252
 
 
253
        gp->stackbase = (uintptr)top;
 
254
        gp->stackguard = (uintptr)stk + StackGuard;
 
255
 
 
256
        sp = (byte*)top;
 
257
        if(argsize > 0) {
 
258
                sp -= argsize;
 
259
                dst = (uintptr*)sp;
 
260
                dstend = dst + argsize/sizeof(*dst);
 
261
                src = (uintptr*)top->argp;
 
262
                while(dst < dstend)
 
263
                        *dst++ = *src++;
 
264
        }
 
265
        if(thechar == '5') {
 
266
                // caller would have saved its LR below args.
 
267
                sp -= sizeof(void*);
 
268
                *(void**)sp = nil;
 
269
        }
 
270
 
 
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;
 
275
        label.g = m->curg;
 
276
        if(reflectcall)
 
277
                runtime·gogocallfn(&label, (FuncVal*)m->morepc);
 
278
        else
 
279
                runtime·gogocall(&label, m->morepc, m->cret);
 
280
 
 
281
        *(int32*)345 = 123;     // never return
 
282
}