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