OSDN Git Service

196271abd04dd62ece4d9c60d31ed0bdce63c908
[pf3gnuchains/gcc-fork.git] / libgo / runtime / malloc.goc
1 // Copyright 2009 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 // See malloc.h for overview.
6 //
7 // TODO(rsc): double-check stats.
8
9 package runtime
10 #include <stddef.h>
11 #include <errno.h>
12 #include <stdlib.h>
13 #include "go-alloc.h"
14 #include "runtime.h"
15 #include "malloc.h"
16 #include "go-string.h"
17 #include "interface.h"
18 #include "go-type.h"
19 typedef struct __go_empty_interface Eface;
20 typedef struct __go_type_descriptor Type;
21 typedef struct __go_func_type FuncType;
22
23 MHeap runtime_mheap;
24 extern MStats mstats;   // defined in extern.go
25
26 extern volatile int32 runtime_MemProfileRate
27   __asm__ ("libgo_runtime.runtime.MemProfileRate");
28
29 // Same algorithm from chan.c, but a different
30 // instance of the static uint32 x.
31 // Not protected by a lock - let the threads use
32 // the same random number if they like.
33 static uint32
34 fastrand1(void)
35 {
36         static uint32 x = 0x49f6428aUL;
37
38         x += x;
39         if(x & 0x80000000L)
40                 x ^= 0x88888eefUL;
41         return x;
42 }
43
44 // Allocate an object of at least size bytes.
45 // Small objects are allocated from the per-thread cache's free lists.
46 // Large objects (> 32 kB) are allocated straight from the heap.
47 void*
48 runtime_mallocgc(uintptr size, uint32 flag, int32 dogc, int32 zeroed)
49 {
50         int32 sizeclass, rate;
51         MCache *c;
52         uintptr npages;
53         MSpan *s;
54         void *v;
55
56         if(!__sync_bool_compare_and_swap(&m->mallocing, 0, 1))
57                 runtime_throw("malloc/free - deadlock");
58         if(size == 0)
59                 size = 1;
60
61         mstats.nmalloc++;
62         if(size <= MaxSmallSize) {
63                 // Allocate from mcache free lists.
64                 sizeclass = runtime_SizeToClass(size);
65                 size = runtime_class_to_size[sizeclass];
66                 c = m->mcache;
67                 v = runtime_MCache_Alloc(c, sizeclass, size, zeroed);
68                 if(v == nil)
69                         runtime_throw("out of memory");
70                 mstats.alloc += size;
71                 mstats.total_alloc += size;
72                 mstats.by_size[sizeclass].nmalloc++;
73         } else {
74                 // TODO(rsc): Report tracebacks for very large allocations.
75
76                 // Allocate directly from heap.
77                 npages = size >> PageShift;
78                 if((size & PageMask) != 0)
79                         npages++;
80                 s = runtime_MHeap_Alloc(&runtime_mheap, npages, 0, 1);
81                 if(s == nil)
82                         runtime_throw("out of memory");
83                 size = npages<<PageShift;
84                 mstats.alloc += size;
85                 mstats.total_alloc += size;
86                 v = (void*)(s->start << PageShift);
87
88                 // setup for mark sweep
89                 runtime_markspan(v, 0, 0, true);
90         }
91         if(!(flag & FlagNoGC))
92                 runtime_markallocated(v, size, (flag&FlagNoPointers) != 0);
93
94         __sync_bool_compare_and_swap(&m->mallocing, 1, 0);
95
96         if(__sync_bool_compare_and_swap(&m->gcing, 1, 0)) {
97                 if(!(flag & FlagNoProfiling))
98                         __go_run_goroutine_gc(0);
99                 else {
100                         // We are being called from the profiler.  Tell it
101                         // to invoke the garbage collector when it is
102                         // done.  No need to use a sync function here.
103                         m->gcing_for_prof = 1;
104                 }
105         }
106
107         if(!(flag & FlagNoProfiling) && (rate = runtime_MemProfileRate) > 0) {
108                 if(size >= (uint32) rate)
109                         goto profile;
110                 if((uint32) m->mcache->next_sample > size)
111                         m->mcache->next_sample -= size;
112                 else {
113                         // pick next profile time
114                         if(rate > 0x3fffffff)   // make 2*rate not overflow
115                                 rate = 0x3fffffff;
116                         m->mcache->next_sample = fastrand1() % (2*rate);
117                 profile:
118                         runtime_setblockspecial(v);
119                         runtime_MProf_Malloc(v, size);
120                 }
121         }
122
123         if(dogc && mstats.heap_alloc >= mstats.next_gc)
124                 runtime_gc(0);
125         return v;
126 }
127
128 void*
129 __go_alloc(uintptr size)
130 {
131         return runtime_mallocgc(size, 0, 0, 1);
132 }
133
134 // Free the object whose base pointer is v.
135 void
136 __go_free(void *v)
137 {
138         int32 sizeclass;
139         MSpan *s;
140         MCache *c;
141         uint32 prof;
142         uintptr size;
143
144         if(v == nil)
145                 return;
146         
147         // If you change this also change mgc0.c:/^sweepspan,
148         // which has a copy of the guts of free.
149
150         if(!__sync_bool_compare_and_swap(&m->mallocing, 0, 1))
151                 runtime_throw("malloc/free - deadlock");
152
153         if(!runtime_mlookup(v, nil, nil, &s)) {
154                 // runtime_printf("free %p: not an allocated block\n", v);
155                 runtime_throw("free runtime_mlookup");
156         }
157         prof = runtime_blockspecial(v);
158
159         // Find size class for v.
160         sizeclass = s->sizeclass;
161         if(sizeclass == 0) {
162                 // Large object.
163                 size = s->npages<<PageShift;
164                 *(uintptr*)(s->start<<PageShift) = 1;   // mark as "needs to be zeroed"
165                 // Must mark v freed before calling unmarkspan and MHeap_Free:
166                 // they might coalesce v into other spans and change the bitmap further.
167                 runtime_markfreed(v, size);
168                 runtime_unmarkspan(v, 1<<PageShift);
169                 runtime_MHeap_Free(&runtime_mheap, s, 1);
170         } else {
171                 // Small object.
172                 c = m->mcache;
173                 size = runtime_class_to_size[sizeclass];
174                 if(size > (int32)sizeof(uintptr))
175                         ((uintptr*)v)[1] = 1;   // mark as "needs to be zeroed"
176                 // Must mark v freed before calling MCache_Free:
177                 // it might coalesce v and other blocks into a bigger span
178                 // and change the bitmap further.
179                 runtime_markfreed(v, size);
180                 mstats.by_size[sizeclass].nfree++;
181                 runtime_MCache_Free(c, v, sizeclass, size);
182         }
183         mstats.alloc -= size;
184         if(prof)
185                 runtime_MProf_Free(v, size);
186
187         __sync_bool_compare_and_swap(&m->mallocing, 1, 0);
188
189         if(__sync_bool_compare_and_swap(&m->gcing, 1, 0))
190                 __go_run_goroutine_gc(1);
191 }
192
193 int32
194 runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
195 {
196         uintptr n, i;
197         byte *p;
198         MSpan *s;
199
200         mstats.nlookup++;
201         s = runtime_MHeap_LookupMaybe(&runtime_mheap, v);
202         if(sp)
203                 *sp = s;
204         if(s == nil) {
205                 runtime_checkfreed(v, 1);
206                 if(base)
207                         *base = nil;
208                 if(size)
209                         *size = 0;
210                 return 0;
211         }
212
213         p = (byte*)((uintptr)s->start<<PageShift);
214         if(s->sizeclass == 0) {
215                 // Large object.
216                 if(base)
217                         *base = p;
218                 if(size)
219                         *size = s->npages<<PageShift;
220                 return 1;
221         }
222
223         if((byte*)v >= (byte*)s->limit) {
224                 // pointers past the last block do not count as pointers.
225                 return 0;
226         }
227
228         n = runtime_class_to_size[s->sizeclass];
229         i = ((byte*)v - p)/n;
230         if(base)
231                 *base = p + i*n;
232         if(size)
233                 *size = n;
234
235         return 1;
236 }
237
238 MCache*
239 runtime_allocmcache(void)
240 {
241         MCache *c;
242
243         if(!__sync_bool_compare_and_swap(&m->mallocing, 0, 1))
244                 runtime_throw("allocmcache - deadlock");
245
246         runtime_lock(&runtime_mheap);
247         c = runtime_FixAlloc_Alloc(&runtime_mheap.cachealloc);
248
249         // Clear the free list used by FixAlloc; assume the rest is zeroed.
250         c->list[0].list = nil;
251
252         mstats.mcache_inuse = runtime_mheap.cachealloc.inuse;
253         mstats.mcache_sys = runtime_mheap.cachealloc.sys;
254         runtime_unlock(&runtime_mheap);
255
256         __sync_bool_compare_and_swap(&m->mallocing, 1, 0);
257         if(__sync_bool_compare_and_swap(&m->gcing, 1, 0))
258                 __go_run_goroutine_gc(2);
259
260         return c;
261 }
262
263 extern int32 runtime_sizeof_C_MStats
264   __asm__ ("libgo_runtime.runtime.Sizeof_C_MStats");
265
266 #define MaxArena32 (2U<<30)
267
268 void
269 runtime_mallocinit(void)
270 {
271         byte *p;
272         uintptr arena_size, bitmap_size;
273         extern byte end[];
274
275         runtime_sizeof_C_MStats = sizeof(MStats);
276
277         runtime_InitSizes();
278
279         // Set up the allocation arena, a contiguous area of memory where
280         // allocated data will be found.  The arena begins with a bitmap large
281         // enough to hold 4 bits per allocated word.
282         if(sizeof(void*) == 8) {
283                 // On a 64-bit machine, allocate from a single contiguous reservation.
284                 // 16 GB should be big enough for now.
285                 //
286                 // The code will work with the reservation at any address, but ask
287                 // SysReserve to use 0x000000f800000000 if possible.
288                 // Allocating a 16 GB region takes away 36 bits, and the amd64
289                 // doesn't let us choose the top 17 bits, so that leaves the 11 bits
290                 // in the middle of 0x00f8 for us to choose.  Choosing 0x00f8 means
291                 // that the valid memory addresses will begin 0x00f8, 0x00f9, 0x00fa, 0x00fb.
292                 // None of the bytes f8 f9 fa fb can appear in valid UTF-8, and
293                 // they are otherwise as far from ff (likely a common byte) as possible.
294                 // Choosing 0x00 for the leading 6 bits was more arbitrary, but it
295                 // is not a common ASCII code point either.  Using 0x11f8 instead
296                 // caused out of memory errors on OS X during thread allocations.
297                 // These choices are both for debuggability and to reduce the
298                 // odds of the conservative garbage collector not collecting memory
299                 // because some non-pointer block of memory had a bit pattern
300                 // that matched a memory address.
301                 //
302                 // Actually we reserve 17 GB (because the bitmap ends up being 1 GB)
303                 // but it hardly matters: fc is not valid UTF-8 either, and we have to
304                 // allocate 15 GB before we get that far.
305                 arena_size = (uintptr)(16LL<<30);
306                 bitmap_size = arena_size / (sizeof(void*)*8/4);
307                 p = runtime_SysReserve((void*)(0x00f8ULL<<32), bitmap_size + arena_size);
308                 if(p == nil)
309                         runtime_throw("runtime: cannot reserve arena virtual address space");
310         } else {
311                 // On a 32-bit machine, we can't typically get away
312                 // with a giant virtual address space reservation.
313                 // Instead we map the memory information bitmap
314                 // immediately after the data segment, large enough
315                 // to handle another 2GB of mappings (256 MB),
316                 // along with a reservation for another 512 MB of memory.
317                 // When that gets used up, we'll start asking the kernel
318                 // for any memory anywhere and hope it's in the 2GB
319                 // following the bitmap (presumably the executable begins
320                 // near the bottom of memory, so we'll have to use up
321                 // most of memory before the kernel resorts to giving out
322                 // memory before the beginning of the text segment).
323                 //
324                 // Alternatively we could reserve 512 MB bitmap, enough
325                 // for 4GB of mappings, and then accept any memory the
326                 // kernel threw at us, but normally that's a waste of 512 MB
327                 // of address space, which is probably too much in a 32-bit world.
328                 bitmap_size = MaxArena32 / (sizeof(void*)*8/4);
329                 arena_size = 512<<20;
330                 
331                 // SysReserve treats the address we ask for, end, as a hint,
332                 // not as an absolute requirement.  If we ask for the end
333                 // of the data segment but the operating system requires
334                 // a little more space before we can start allocating, it will
335                 // give out a slightly higher pointer.  That's fine.  
336                 // Run with what we get back.
337                 p = runtime_SysReserve(end, bitmap_size + arena_size);
338                 if(p == nil)
339                         runtime_throw("runtime: cannot reserve arena virtual address space");
340         }
341         if((uintptr)p & (((uintptr)1<<PageShift)-1))
342                 runtime_throw("runtime: SysReserve returned unaligned address");
343
344         runtime_mheap.bitmap = p;
345         runtime_mheap.arena_start = p + bitmap_size;
346         runtime_mheap.arena_used = runtime_mheap.arena_start;
347         runtime_mheap.arena_end = runtime_mheap.arena_start + arena_size;
348
349         // Initialize the rest of the allocator.        
350         runtime_MHeap_Init(&runtime_mheap, runtime_SysAlloc);
351         m->mcache = runtime_allocmcache();
352
353         // Initialize malloc profiling.
354         runtime_Mprof_Init();
355
356         // Initialize finalizer.
357         runtime_initfintab();
358
359         // See if it works.
360         runtime_free(runtime_malloc(1));
361 }
362
363 void*
364 runtime_MHeap_SysAlloc(MHeap *h, uintptr n)
365 {
366         byte *p;
367
368         if(n <= (uintptr)(h->arena_end - h->arena_used)) {
369                 // Keep taking from our reservation.
370                 p = h->arena_used;
371                 runtime_SysMap(p, n);
372                 h->arena_used += n;
373                 runtime_MHeap_MapBits(h);
374                 return p;
375         }
376         
377         // On 64-bit, our reservation is all we have.
378         if(sizeof(void*) == 8)
379                 return nil;
380
381         // On 32-bit, once the reservation is gone we can
382         // try to get memory at a location chosen by the OS
383         // and hope that it is in the range we allocated bitmap for.
384         p = runtime_SysAlloc(n);
385         if(p == nil)
386                 return nil;
387
388         if(p < h->arena_start || (uintptr)(p+n - h->arena_start) >= MaxArena32) {
389                 runtime_printf("runtime: memory allocated by OS not in usable range");
390                 runtime_SysFree(p, n);
391                 return nil;
392         }
393
394         if(p+n > h->arena_used) {
395                 h->arena_used = p+n;
396                 if(h->arena_used > h->arena_end)
397                         h->arena_end = h->arena_used;
398                 runtime_MHeap_MapBits(h);
399         }
400         
401         return p;
402 }
403
404 // Runtime stubs.
405
406 void*
407 runtime_mal(uintptr n)
408 {
409         return runtime_mallocgc(n, 0, 1, 1);
410 }
411
412 func new(n uint32) (ret *uint8) {
413         ret = runtime_mal(n);
414 }
415
416 func Alloc(n uintptr) (p *byte) {
417         p = runtime_malloc(n);
418 }
419
420 func Free(p *byte) {
421         runtime_free(p);
422 }
423
424 func Lookup(p *byte) (base *byte, size uintptr) {
425         runtime_mlookup(p, &base, &size, nil);
426 }
427
428 func GC() {
429         runtime_gc(1);
430 }
431
432 func SetFinalizer(obj Eface, finalizer Eface) {
433         byte *base;
434         uintptr size;
435         const FuncType *ft;
436
437         if(obj.__type_descriptor == nil) {
438                 // runtime_printf("runtime.SetFinalizer: first argument is nil interface\n");
439         throw:
440                 runtime_throw("runtime.SetFinalizer");
441         }
442         if(obj.__type_descriptor->__code != GO_PTR) {
443                 // runtime_printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.type->string);
444                 goto throw;
445         }
446         if(!runtime_mlookup(obj.__object, &base, &size, nil) || obj.__object != base) {
447                 // runtime_printf("runtime.SetFinalizer: pointer not at beginning of allocated block\n");
448                 goto throw;
449         }
450         ft = nil;
451         if(finalizer.__type_descriptor != nil) {
452                 if(finalizer.__type_descriptor->__code != GO_FUNC) {
453                 badfunc:
454                         // runtime_printf("runtime.SetFinalizer: second argument is %S, not func(%S)\n", *finalizer.type->string, *obj.type->string);
455                         goto throw;
456                 }
457                 ft = (const FuncType*)finalizer.__type_descriptor;
458                 if(ft->__dotdotdot || ft->__in.__count != 1 || !__go_type_descriptors_equal(*(Type**)ft->__in.__values, obj.__type_descriptor))
459                         goto badfunc;
460
461                 if(runtime_getfinalizer(obj.__object, 0)) {
462                         // runtime_printf("runtime.SetFinalizer: finalizer already set");
463                         goto throw;
464                 }
465         }
466         runtime_addfinalizer(obj.__object, finalizer.__type_descriptor != nil ? *(void**)finalizer.__object : nil, ft);
467 }