123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993 |
- // Copyright 2009 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // See malloc.h for overview.
- //
- // TODO(rsc): double-check stats.
- package runtime
- #include <stddef.h>
- #include <errno.h>
- #include <stdlib.h>
- #include "go-alloc.h"
- #include "runtime.h"
- #include "arch.h"
- #include "malloc.h"
- #include "interface.h"
- #include "go-type.h"
- // Map gccgo field names to gc field names.
- // Eface aka __go_empty_interface.
- #define type __type_descriptor
- // Type aka __go_type_descriptor
- #define kind __code
- #define string __reflection
- #define KindPtr GO_PTR
- #define KindNoPointers GO_NO_POINTERS
- #define kindMask GO_CODE_MASK
- // GCCGO SPECIFIC CHANGE
- //
- // There is a long comment in runtime_mallocinit about where to put the heap
- // on a 64-bit system. It makes assumptions that are not valid on linux/arm64
- // -- it assumes user space can choose the lower 47 bits of a pointer, but on
- // linux/arm64 we can only choose the lower 39 bits. This means the heap is
- // roughly a quarter of the available address space and we cannot choose a bit
- // pattern that all pointers will have -- luckily the GC is mostly precise
- // these days so this doesn't matter all that much. The kernel (as of 3.13)
- // will allocate address space starting either down from 0x7fffffffff or up
- // from 0x2000000000, so we put the heap roughly in the middle of these two
- // addresses to minimize the chance that a non-heap allocation will get in the
- // way of the heap.
- //
- // This all means that there isn't much point in trying 256 different
- // locations for the heap on such systems.
- #ifdef __aarch64__
- #define HeapBase(i) ((void*)(uintptr)(0x40ULL<<32))
- #define HeapBaseOptions 1
- #else
- #define HeapBase(i) ((void*)(uintptr)(i<<40|0x00c0ULL<<32))
- #define HeapBaseOptions 0x80
- #endif
- // END GCCGO SPECIFIC CHANGE
- // Mark mheap as 'no pointers', it does not contain interesting pointers but occupies ~45K.
- MHeap runtime_mheap;
- MStats mstats;
- int32 runtime_checking;
- extern MStats mstats; // defined in zruntime_def_$GOOS_$GOARCH.go
- extern volatile intgo runtime_MemProfileRate
- __asm__ (GOSYM_PREFIX "runtime.MemProfileRate");
- static MSpan* largealloc(uint32, uintptr*);
- static void profilealloc(void *v, uintptr size);
- static void settype(MSpan *s, void *v, uintptr typ);
- // Allocate an object of at least size bytes.
- // Small objects are allocated from the per-thread cache's free lists.
- // Large objects (> 32 kB) are allocated straight from the heap.
- // If the block will be freed with runtime_free(), typ must be 0.
- void*
- runtime_mallocgc(uintptr size, uintptr typ, uint32 flag)
- {
- M *m;
- G *g;
- int32 sizeclass;
- uintptr tinysize, size1;
- intgo rate;
- MCache *c;
- MSpan *s;
- MLink *v, *next;
- byte *tiny;
- bool incallback;
- if(size == 0) {
- // All 0-length allocations use this pointer.
- // The language does not require the allocations to
- // have distinct values.
- return &runtime_zerobase;
- }
- m = runtime_m();
- g = runtime_g();
- incallback = false;
- if(m->mcache == nil && g->ncgo > 0) {
- // For gccgo this case can occur when a cgo or SWIG function
- // has an interface return type and the function
- // returns a non-pointer, so memory allocation occurs
- // after syscall.Cgocall but before syscall.CgocallDone.
- // We treat it as a callback.
- runtime_exitsyscall();
- m = runtime_m();
- incallback = true;
- flag |= FlagNoInvokeGC;
- }
- if(runtime_gcwaiting() && g != m->g0 && m->locks == 0 && !(flag & FlagNoInvokeGC)) {
- runtime_gosched();
- m = runtime_m();
- }
- if(m->mallocing)
- runtime_throw("malloc/free - deadlock");
- // Disable preemption during settype.
- // We can not use m->mallocing for this, because settype calls mallocgc.
- m->locks++;
- m->mallocing = 1;
- if(DebugTypeAtBlockEnd)
- size += sizeof(uintptr);
- c = m->mcache;
- if(!runtime_debug.efence && size <= MaxSmallSize) {
- if((flag&(FlagNoScan|FlagNoGC)) == FlagNoScan && size < TinySize) {
- // Tiny allocator.
- //
- // Tiny allocator combines several tiny allocation requests
- // into a single memory block. The resulting memory block
- // is freed when all subobjects are unreachable. The subobjects
- // must be FlagNoScan (don't have pointers), this ensures that
- // the amount of potentially wasted memory is bounded.
- //
- // Size of the memory block used for combining (TinySize) is tunable.
- // Current setting is 16 bytes, which relates to 2x worst case memory
- // wastage (when all but one subobjects are unreachable).
- // 8 bytes would result in no wastage at all, but provides less
- // opportunities for combining.
- // 32 bytes provides more opportunities for combining,
- // but can lead to 4x worst case wastage.
- // The best case winning is 8x regardless of block size.
- //
- // Objects obtained from tiny allocator must not be freed explicitly.
- // So when an object will be freed explicitly, we ensure that
- // its size >= TinySize.
- //
- // SetFinalizer has a special case for objects potentially coming
- // from tiny allocator, it such case it allows to set finalizers
- // for an inner byte of a memory block.
- //
- // The main targets of tiny allocator are small strings and
- // standalone escaping variables. On a json benchmark
- // the allocator reduces number of allocations by ~12% and
- // reduces heap size by ~20%.
- tinysize = c->tinysize;
- if(size <= tinysize) {
- tiny = c->tiny;
- // Align tiny pointer for required (conservative) alignment.
- if((size&7) == 0)
- tiny = (byte*)ROUND((uintptr)tiny, 8);
- else if((size&3) == 0)
- tiny = (byte*)ROUND((uintptr)tiny, 4);
- else if((size&1) == 0)
- tiny = (byte*)ROUND((uintptr)tiny, 2);
- size1 = size + (tiny - c->tiny);
- if(size1 <= tinysize) {
- // The object fits into existing tiny block.
- v = (MLink*)tiny;
- c->tiny += size1;
- c->tinysize -= size1;
- m->mallocing = 0;
- m->locks--;
- if(incallback)
- runtime_entersyscall();
- return v;
- }
- }
- // Allocate a new TinySize block.
- s = c->alloc[TinySizeClass];
- if(s->freelist == nil)
- s = runtime_MCache_Refill(c, TinySizeClass);
- v = s->freelist;
- next = v->next;
- s->freelist = next;
- s->ref++;
- if(next != nil) // prefetching nil leads to a DTLB miss
- PREFETCH(next);
- ((uint64*)v)[0] = 0;
- ((uint64*)v)[1] = 0;
- // See if we need to replace the existing tiny block with the new one
- // based on amount of remaining free space.
- if(TinySize-size > tinysize) {
- c->tiny = (byte*)v + size;
- c->tinysize = TinySize - size;
- }
- size = TinySize;
- goto done;
- }
- // Allocate from mcache free lists.
- // Inlined version of SizeToClass().
- if(size <= 1024-8)
- sizeclass = runtime_size_to_class8[(size+7)>>3];
- else
- sizeclass = runtime_size_to_class128[(size-1024+127) >> 7];
- size = runtime_class_to_size[sizeclass];
- s = c->alloc[sizeclass];
- if(s->freelist == nil)
- s = runtime_MCache_Refill(c, sizeclass);
- v = s->freelist;
- next = v->next;
- s->freelist = next;
- s->ref++;
- if(next != nil) // prefetching nil leads to a DTLB miss
- PREFETCH(next);
- if(!(flag & FlagNoZero)) {
- v->next = nil;
- // block is zeroed iff second word is zero ...
- if(size > 2*sizeof(uintptr) && ((uintptr*)v)[1] != 0)
- runtime_memclr((byte*)v, size);
- }
- done:
- c->local_cachealloc += size;
- } else {
- // Allocate directly from heap.
- s = largealloc(flag, &size);
- v = (void*)(s->start << PageShift);
- }
- if(flag & FlagNoGC)
- runtime_marknogc(v);
- else if(!(flag & FlagNoScan))
- runtime_markscan(v);
- if(DebugTypeAtBlockEnd)
- *(uintptr*)((uintptr)v+size-sizeof(uintptr)) = typ;
- m->mallocing = 0;
- // TODO: save type even if FlagNoScan? Potentially expensive but might help
- // heap profiling/tracing.
- if(UseSpanType && !(flag & FlagNoScan) && typ != 0)
- settype(s, v, typ);
- if(runtime_debug.allocfreetrace)
- runtime_tracealloc(v, size, typ);
- if(!(flag & FlagNoProfiling) && (rate = runtime_MemProfileRate) > 0) {
- if(size < (uintptr)rate && size < (uintptr)(uint32)c->next_sample)
- c->next_sample -= size;
- else
- profilealloc(v, size);
- }
- m->locks--;
- if(!(flag & FlagNoInvokeGC) && mstats.heap_alloc >= mstats.next_gc)
- runtime_gc(0);
- if(incallback)
- runtime_entersyscall();
- return v;
- }
- static MSpan*
- largealloc(uint32 flag, uintptr *sizep)
- {
- uintptr npages, size;
- MSpan *s;
- void *v;
- // Allocate directly from heap.
- size = *sizep;
- if(size + PageSize < size)
- runtime_throw("out of memory");
- npages = size >> PageShift;
- if((size & PageMask) != 0)
- npages++;
- s = runtime_MHeap_Alloc(&runtime_mheap, npages, 0, 1, !(flag & FlagNoZero));
- if(s == nil)
- runtime_throw("out of memory");
- s->limit = (byte*)(s->start<<PageShift) + size;
- *sizep = npages<<PageShift;
- v = (void*)(s->start << PageShift);
- // setup for mark sweep
- runtime_markspan(v, 0, 0, true);
- return s;
- }
- static void
- profilealloc(void *v, uintptr size)
- {
- uintptr rate;
- int32 next;
- MCache *c;
- c = runtime_m()->mcache;
- rate = runtime_MemProfileRate;
- if(size < rate) {
- // pick next profile time
- // If you change this, also change allocmcache.
- if(rate > 0x3fffffff) // make 2*rate not overflow
- rate = 0x3fffffff;
- next = runtime_fastrand1() % (2*rate);
- // Subtract the "remainder" of the current allocation.
- // Otherwise objects that are close in size to sampling rate
- // will be under-sampled, because we consistently discard this remainder.
- next -= (size - c->next_sample);
- if(next < 0)
- next = 0;
- c->next_sample = next;
- }
- runtime_MProf_Malloc(v, size);
- }
- void*
- __go_alloc(uintptr size)
- {
- return runtime_mallocgc(size, 0, FlagNoInvokeGC);
- }
- // Free the object whose base pointer is v.
- void
- __go_free(void *v)
- {
- M *m;
- int32 sizeclass;
- MSpan *s;
- MCache *c;
- uintptr size;
- if(v == nil)
- return;
-
- // If you change this also change mgc0.c:/^sweep,
- // which has a copy of the guts of free.
- m = runtime_m();
- if(m->mallocing)
- runtime_throw("malloc/free - deadlock");
- m->mallocing = 1;
- if(!runtime_mlookup(v, nil, nil, &s)) {
- runtime_printf("free %p: not an allocated block\n", v);
- runtime_throw("free runtime_mlookup");
- }
- size = s->elemsize;
- sizeclass = s->sizeclass;
- // Objects that are smaller than TinySize can be allocated using tiny alloc,
- // if then such object is combined with an object with finalizer, we will crash.
- if(size < TinySize)
- runtime_throw("freeing too small block");
- if(runtime_debug.allocfreetrace)
- runtime_tracefree(v, size);
- // Ensure that the span is swept.
- // If we free into an unswept span, we will corrupt GC bitmaps.
- runtime_MSpan_EnsureSwept(s);
- if(s->specials != nil)
- runtime_freeallspecials(s, v, size);
- c = m->mcache;
- if(sizeclass == 0) {
- // Large object.
- s->needzero = 1;
- // Must mark v freed before calling unmarkspan and MHeap_Free:
- // they might coalesce v into other spans and change the bitmap further.
- runtime_markfreed(v);
- runtime_unmarkspan(v, 1<<PageShift);
- // NOTE(rsc,dvyukov): The original implementation of efence
- // in CL 22060046 used SysFree instead of SysFault, so that
- // the operating system would eventually give the memory
- // back to us again, so that an efence program could run
- // longer without running out of memory. Unfortunately,
- // calling SysFree here without any kind of adjustment of the
- // heap data structures means that when the memory does
- // come back to us, we have the wrong metadata for it, either in
- // the MSpan structures or in the garbage collection bitmap.
- // Using SysFault here means that the program will run out of
- // memory fairly quickly in efence mode, but at least it won't
- // have mysterious crashes due to confused memory reuse.
- // It should be possible to switch back to SysFree if we also
- // implement and then call some kind of MHeap_DeleteSpan.
- if(runtime_debug.efence)
- runtime_SysFault((void*)(s->start<<PageShift), size);
- else
- runtime_MHeap_Free(&runtime_mheap, s, 1);
- c->local_nlargefree++;
- c->local_largefree += size;
- } else {
- // Small object.
- if(size > 2*sizeof(uintptr))
- ((uintptr*)v)[1] = (uintptr)0xfeedfeedfeedfeedll; // mark as "needs to be zeroed"
- else if(size > sizeof(uintptr))
- ((uintptr*)v)[1] = 0;
- // Must mark v freed before calling MCache_Free:
- // it might coalesce v and other blocks into a bigger span
- // and change the bitmap further.
- c->local_nsmallfree[sizeclass]++;
- c->local_cachealloc -= size;
- if(c->alloc[sizeclass] == s) {
- // We own the span, so we can just add v to the freelist
- runtime_markfreed(v);
- ((MLink*)v)->next = s->freelist;
- s->freelist = v;
- s->ref--;
- } else {
- // Someone else owns this span. Add to free queue.
- runtime_MCache_Free(c, v, sizeclass, size);
- }
- }
- m->mallocing = 0;
- }
- int32
- runtime_mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
- {
- M *m;
- uintptr n, i;
- byte *p;
- MSpan *s;
- m = runtime_m();
- m->mcache->local_nlookup++;
- if (sizeof(void*) == 4 && m->mcache->local_nlookup >= (1<<30)) {
- // purge cache stats to prevent overflow
- runtime_lock(&runtime_mheap);
- runtime_purgecachedstats(m->mcache);
- runtime_unlock(&runtime_mheap);
- }
- s = runtime_MHeap_LookupMaybe(&runtime_mheap, v);
- if(sp)
- *sp = s;
- if(s == nil) {
- runtime_checkfreed(v, 1);
- if(base)
- *base = nil;
- if(size)
- *size = 0;
- return 0;
- }
- p = (byte*)((uintptr)s->start<<PageShift);
- if(s->sizeclass == 0) {
- // Large object.
- if(base)
- *base = p;
- if(size)
- *size = s->npages<<PageShift;
- return 1;
- }
- n = s->elemsize;
- if(base) {
- i = ((byte*)v - p)/n;
- *base = p + i*n;
- }
- if(size)
- *size = n;
- return 1;
- }
- void
- runtime_purgecachedstats(MCache *c)
- {
- MHeap *h;
- int32 i;
- // Protected by either heap or GC lock.
- h = &runtime_mheap;
- mstats.heap_alloc += c->local_cachealloc;
- c->local_cachealloc = 0;
- mstats.nlookup += c->local_nlookup;
- c->local_nlookup = 0;
- h->largefree += c->local_largefree;
- c->local_largefree = 0;
- h->nlargefree += c->local_nlargefree;
- c->local_nlargefree = 0;
- for(i=0; i<(int32)nelem(c->local_nsmallfree); i++) {
- h->nsmallfree[i] += c->local_nsmallfree[i];
- c->local_nsmallfree[i] = 0;
- }
- }
- extern uintptr runtime_sizeof_C_MStats
- __asm__ (GOSYM_PREFIX "runtime.Sizeof_C_MStats");
- // Size of the trailing by_size array differs between Go and C,
- // NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
- // sizeof_C_MStats is what C thinks about size of Go struct.
- // Initialized in mallocinit because it's defined in go/runtime/mem.go.
- #define MaxArena32 (2U<<30)
- void
- runtime_mallocinit(void)
- {
- byte *p, *p1;
- uintptr arena_size, bitmap_size, spans_size, p_size;
- extern byte _end[];
- uintptr limit;
- uint64 i;
- bool reserved;
- runtime_sizeof_C_MStats = sizeof(MStats) - (NumSizeClasses - 61) * sizeof(mstats.by_size[0]);
- p = nil;
- p_size = 0;
- arena_size = 0;
- bitmap_size = 0;
- spans_size = 0;
- reserved = false;
- // for 64-bit build
- USED(p);
- USED(p_size);
- USED(arena_size);
- USED(bitmap_size);
- USED(spans_size);
- runtime_InitSizes();
- if(runtime_class_to_size[TinySizeClass] != TinySize)
- runtime_throw("bad TinySizeClass");
- // limit = runtime_memlimit();
- // See https://code.google.com/p/go/issues/detail?id=5049
- // TODO(rsc): Fix after 1.1.
- limit = 0;
- // Set up the allocation arena, a contiguous area of memory where
- // allocated data will be found. The arena begins with a bitmap large
- // enough to hold 4 bits per allocated word.
- if(sizeof(void*) == 8 && (limit == 0 || limit > (1<<30))) {
- // On a 64-bit machine, allocate from a single contiguous reservation.
- // 128 GB (MaxMem) should be big enough for now.
- //
- // The code will work with the reservation at any address, but ask
- // SysReserve to use 0x0000XXc000000000 if possible (XX=00...7f).
- // Allocating a 128 GB region takes away 37 bits, and the amd64
- // doesn't let us choose the top 17 bits, so that leaves the 11 bits
- // in the middle of 0x00c0 for us to choose. Choosing 0x00c0 means
- // that the valid memory addresses will begin 0x00c0, 0x00c1, ..., 0x00df.
- // In little-endian, that's c0 00, c1 00, ..., df 00. None of those are valid
- // UTF-8 sequences, and they are otherwise as far away from
- // ff (likely a common byte) as possible. If that fails, we try other 0xXXc0
- // addresses. An earlier attempt to use 0x11f8 caused out of memory errors
- // on OS X during thread allocations. 0x00c0 causes conflicts with
- // AddressSanitizer which reserves all memory up to 0x0100.
- // These choices are both for debuggability and to reduce the
- // odds of the conservative garbage collector not collecting memory
- // because some non-pointer block of memory had a bit pattern
- // that matched a memory address.
- //
- // Actually we reserve 136 GB (because the bitmap ends up being 8 GB)
- // but it hardly matters: e0 00 is not valid UTF-8 either.
- //
- // If this fails we fall back to the 32 bit memory mechanism
- arena_size = MaxMem;
- bitmap_size = arena_size / (sizeof(void*)*8/4);
- spans_size = arena_size / PageSize * sizeof(runtime_mheap.spans[0]);
- spans_size = ROUND(spans_size, PageSize);
- for(i = 0; i < HeapBaseOptions; i++) {
- p = HeapBase(i);
- p_size = bitmap_size + spans_size + arena_size + PageSize;
- p = runtime_SysReserve(p, p_size, &reserved);
- if(p != nil)
- break;
- }
- }
- if (p == nil) {
- // On a 32-bit machine, we can't typically get away
- // with a giant virtual address space reservation.
- // Instead we map the memory information bitmap
- // immediately after the data segment, large enough
- // to handle another 2GB of mappings (256 MB),
- // along with a reservation for another 512 MB of memory.
- // When that gets used up, we'll start asking the kernel
- // for any memory anywhere and hope it's in the 2GB
- // following the bitmap (presumably the executable begins
- // near the bottom of memory, so we'll have to use up
- // most of memory before the kernel resorts to giving out
- // memory before the beginning of the text segment).
- //
- // Alternatively we could reserve 512 MB bitmap, enough
- // for 4GB of mappings, and then accept any memory the
- // kernel threw at us, but normally that's a waste of 512 MB
- // of address space, which is probably too much in a 32-bit world.
- bitmap_size = MaxArena32 / (sizeof(void*)*8/4);
- arena_size = 512<<20;
- spans_size = MaxArena32 / PageSize * sizeof(runtime_mheap.spans[0]);
- if(limit > 0 && arena_size+bitmap_size+spans_size > limit) {
- bitmap_size = (limit / 9) & ~((1<<PageShift) - 1);
- arena_size = bitmap_size * 8;
- spans_size = arena_size / PageSize * sizeof(runtime_mheap.spans[0]);
- }
- spans_size = ROUND(spans_size, PageSize);
- // SysReserve treats the address we ask for, end, as a hint,
- // not as an absolute requirement. If we ask for the end
- // of the data segment but the operating system requires
- // a little more space before we can start allocating, it will
- // give out a slightly higher pointer. Except QEMU, which
- // is buggy, as usual: it won't adjust the pointer upward.
- // So adjust it upward a little bit ourselves: 1/4 MB to get
- // away from the running binary image and then round up
- // to a MB boundary.
- p = (byte*)ROUND((uintptr)_end + (1<<18), 1<<20);
- p_size = bitmap_size + spans_size + arena_size + PageSize;
- p = runtime_SysReserve(p, p_size, &reserved);
- if(p == nil)
- runtime_throw("runtime: cannot reserve arena virtual address space");
- }
- // PageSize can be larger than OS definition of page size,
- // so SysReserve can give us a PageSize-unaligned pointer.
- // To overcome this we ask for PageSize more and round up the pointer.
- p1 = (byte*)ROUND((uintptr)p, PageSize);
- runtime_mheap.spans = (MSpan**)p1;
- runtime_mheap.bitmap = p1 + spans_size;
- runtime_mheap.arena_start = p1 + spans_size + bitmap_size;
- runtime_mheap.arena_used = runtime_mheap.arena_start;
- runtime_mheap.arena_end = p + p_size;
- runtime_mheap.arena_reserved = reserved;
- if(((uintptr)runtime_mheap.arena_start & (PageSize-1)) != 0)
- runtime_throw("misrounded allocation in mallocinit");
- // Initialize the rest of the allocator.
- runtime_MHeap_Init(&runtime_mheap);
- runtime_m()->mcache = runtime_allocmcache();
- // See if it works.
- runtime_free(runtime_malloc(TinySize));
- }
- void*
- runtime_MHeap_SysAlloc(MHeap *h, uintptr n)
- {
- byte *p, *p_end;
- uintptr p_size;
- bool reserved;
- if(n > (uintptr)(h->arena_end - h->arena_used)) {
- // We are in 32-bit mode, maybe we didn't use all possible address space yet.
- // Reserve some more space.
- byte *new_end;
- p_size = ROUND(n + PageSize, 256<<20);
- new_end = h->arena_end + p_size;
- if(new_end <= h->arena_start + MaxArena32) {
- // TODO: It would be bad if part of the arena
- // is reserved and part is not.
- p = runtime_SysReserve(h->arena_end, p_size, &reserved);
- if(p == h->arena_end) {
- h->arena_end = new_end;
- h->arena_reserved = reserved;
- }
- else if(p+p_size <= h->arena_start + MaxArena32) {
- // Keep everything page-aligned.
- // Our pages are bigger than hardware pages.
- h->arena_end = p+p_size;
- h->arena_used = p + (-(uintptr)p&(PageSize-1));
- h->arena_reserved = reserved;
- } else {
- uint64 stat;
- stat = 0;
- runtime_SysFree(p, p_size, &stat);
- }
- }
- }
- if(n <= (uintptr)(h->arena_end - h->arena_used)) {
- // Keep taking from our reservation.
- p = h->arena_used;
- runtime_SysMap(p, n, h->arena_reserved, &mstats.heap_sys);
- h->arena_used += n;
- runtime_MHeap_MapBits(h);
- runtime_MHeap_MapSpans(h);
-
- if(((uintptr)p & (PageSize-1)) != 0)
- runtime_throw("misrounded allocation in MHeap_SysAlloc");
- return p;
- }
-
- // If using 64-bit, our reservation is all we have.
- if((uintptr)(h->arena_end - h->arena_start) >= MaxArena32)
- return nil;
- // On 32-bit, once the reservation is gone we can
- // try to get memory at a location chosen by the OS
- // and hope that it is in the range we allocated bitmap for.
- p_size = ROUND(n, PageSize) + PageSize;
- p = runtime_SysAlloc(p_size, &mstats.heap_sys);
- if(p == nil)
- return nil;
- if(p < h->arena_start || (uintptr)(p+p_size - h->arena_start) >= MaxArena32) {
- runtime_printf("runtime: memory allocated by OS (%p) not in usable range [%p,%p)\n",
- p, h->arena_start, h->arena_start+MaxArena32);
- runtime_SysFree(p, p_size, &mstats.heap_sys);
- return nil;
- }
-
- p_end = p + p_size;
- p += -(uintptr)p & (PageSize-1);
- if(p+n > h->arena_used) {
- h->arena_used = p+n;
- if(p_end > h->arena_end)
- h->arena_end = p_end;
- runtime_MHeap_MapBits(h);
- runtime_MHeap_MapSpans(h);
- }
-
- if(((uintptr)p & (PageSize-1)) != 0)
- runtime_throw("misrounded allocation in MHeap_SysAlloc");
- return p;
- }
- static struct
- {
- Lock;
- byte* pos;
- byte* end;
- } persistent;
- enum
- {
- PersistentAllocChunk = 256<<10,
- PersistentAllocMaxBlock = 64<<10, // VM reservation granularity is 64K on windows
- };
- // Wrapper around SysAlloc that can allocate small chunks.
- // There is no associated free operation.
- // Intended for things like function/type/debug-related persistent data.
- // If align is 0, uses default align (currently 8).
- void*
- runtime_persistentalloc(uintptr size, uintptr align, uint64 *stat)
- {
- byte *p;
- if(align != 0) {
- if(align&(align-1))
- runtime_throw("persistentalloc: align is not a power of 2");
- if(align > PageSize)
- runtime_throw("persistentalloc: align is too large");
- } else
- align = 8;
- if(size >= PersistentAllocMaxBlock)
- return runtime_SysAlloc(size, stat);
- runtime_lock(&persistent);
- persistent.pos = (byte*)ROUND((uintptr)persistent.pos, align);
- if(persistent.pos + size > persistent.end) {
- persistent.pos = runtime_SysAlloc(PersistentAllocChunk, &mstats.other_sys);
- if(persistent.pos == nil) {
- runtime_unlock(&persistent);
- runtime_throw("runtime: cannot allocate memory");
- }
- persistent.end = persistent.pos + PersistentAllocChunk;
- }
- p = persistent.pos;
- persistent.pos += size;
- runtime_unlock(&persistent);
- if(stat != &mstats.other_sys) {
- // reaccount the allocation against provided stat
- runtime_xadd64(stat, size);
- runtime_xadd64(&mstats.other_sys, -(uint64)size);
- }
- return p;
- }
- static void
- settype(MSpan *s, void *v, uintptr typ)
- {
- uintptr size, ofs, j, t;
- uintptr ntypes, nbytes2, nbytes3;
- uintptr *data2;
- byte *data3;
- if(s->sizeclass == 0) {
- s->types.compression = MTypes_Single;
- s->types.data = typ;
- return;
- }
- size = s->elemsize;
- ofs = ((uintptr)v - (s->start<<PageShift)) / size;
- switch(s->types.compression) {
- case MTypes_Empty:
- ntypes = (s->npages << PageShift) / size;
- nbytes3 = 8*sizeof(uintptr) + 1*ntypes;
- data3 = runtime_mallocgc(nbytes3, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
- s->types.compression = MTypes_Bytes;
- s->types.data = (uintptr)data3;
- ((uintptr*)data3)[1] = typ;
- data3[8*sizeof(uintptr) + ofs] = 1;
- break;
-
- case MTypes_Words:
- ((uintptr*)s->types.data)[ofs] = typ;
- break;
-
- case MTypes_Bytes:
- data3 = (byte*)s->types.data;
- for(j=1; j<8; j++) {
- if(((uintptr*)data3)[j] == typ) {
- break;
- }
- if(((uintptr*)data3)[j] == 0) {
- ((uintptr*)data3)[j] = typ;
- break;
- }
- }
- if(j < 8) {
- data3[8*sizeof(uintptr) + ofs] = j;
- } else {
- ntypes = (s->npages << PageShift) / size;
- nbytes2 = ntypes * sizeof(uintptr);
- data2 = runtime_mallocgc(nbytes2, 0, FlagNoProfiling|FlagNoScan|FlagNoInvokeGC);
- s->types.compression = MTypes_Words;
- s->types.data = (uintptr)data2;
-
- // Move the contents of data3 to data2. Then deallocate data3.
- for(j=0; j<ntypes; j++) {
- t = data3[8*sizeof(uintptr) + j];
- t = ((uintptr*)data3)[t];
- data2[j] = t;
- }
- data2[ofs] = typ;
- }
- break;
- }
- }
- uintptr
- runtime_gettype(void *v)
- {
- MSpan *s;
- uintptr t, ofs;
- byte *data;
- s = runtime_MHeap_LookupMaybe(&runtime_mheap, v);
- if(s != nil) {
- t = 0;
- switch(s->types.compression) {
- case MTypes_Empty:
- break;
- case MTypes_Single:
- t = s->types.data;
- break;
- case MTypes_Words:
- ofs = (uintptr)v - (s->start<<PageShift);
- t = ((uintptr*)s->types.data)[ofs/s->elemsize];
- break;
- case MTypes_Bytes:
- ofs = (uintptr)v - (s->start<<PageShift);
- data = (byte*)s->types.data;
- t = data[8*sizeof(uintptr) + ofs/s->elemsize];
- t = ((uintptr*)data)[t];
- break;
- default:
- runtime_throw("runtime_gettype: invalid compression kind");
- }
- if(0) {
- runtime_printf("%p -> %d,%X\n", v, (int32)s->types.compression, (int64)t);
- }
- return t;
- }
- return 0;
- }
- // Runtime stubs.
- void*
- runtime_mal(uintptr n)
- {
- return runtime_mallocgc(n, 0, 0);
- }
- func new(typ *Type) (ret *uint8) {
- ret = runtime_mallocgc(typ->__size, (uintptr)typ | TypeInfo_SingleObject, typ->kind&KindNoPointers ? FlagNoScan : 0);
- }
- static void*
- cnew(const Type *typ, intgo n, int32 objtyp)
- {
- if((objtyp&(PtrSize-1)) != objtyp)
- runtime_throw("runtime: invalid objtyp");
- if(n < 0 || (typ->__size > 0 && (uintptr)n > (MaxMem/typ->__size)))
- runtime_panicstring("runtime: allocation size out of range");
- return runtime_mallocgc(typ->__size*n, (uintptr)typ | objtyp, typ->kind&KindNoPointers ? FlagNoScan : 0);
- }
- // same as runtime_new, but callable from C
- void*
- runtime_cnew(const Type *typ)
- {
- return cnew(typ, 1, TypeInfo_SingleObject);
- }
- void*
- runtime_cnewarray(const Type *typ, intgo n)
- {
- return cnew(typ, n, TypeInfo_Array);
- }
- func GC() {
- runtime_gc(2); // force GC and do eager sweep
- }
- func SetFinalizer(obj Eface, finalizer Eface) {
- byte *base;
- uintptr size;
- const FuncType *ft;
- const Type *fint;
- const PtrType *ot;
- if(obj.__type_descriptor == nil) {
- runtime_printf("runtime.SetFinalizer: first argument is nil interface\n");
- goto throw;
- }
- if((obj.__type_descriptor->kind&kindMask) != GO_PTR) {
- runtime_printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.__type_descriptor->__reflection);
- goto throw;
- }
- ot = (const PtrType*)obj.type;
- // As an implementation detail we do not run finalizers for zero-sized objects,
- // because we use &runtime_zerobase for all such allocations.
- if(ot->__element_type != nil && ot->__element_type->__size == 0)
- return;
- // The following check is required for cases when a user passes a pointer to composite literal,
- // but compiler makes it a pointer to global. For example:
- // var Foo = &Object{}
- // func main() {
- // runtime.SetFinalizer(Foo, nil)
- // }
- // See issue 7656.
- if((byte*)obj.__object < runtime_mheap.arena_start || runtime_mheap.arena_used <= (byte*)obj.__object)
- return;
- if(!runtime_mlookup(obj.__object, &base, &size, nil) || obj.__object != base) {
- // As an implementation detail we allow to set finalizers for an inner byte
- // of an object if it could come from tiny alloc (see mallocgc for details).
- if(ot->__element_type == nil || (ot->__element_type->kind&KindNoPointers) == 0 || ot->__element_type->__size >= TinySize) {
- runtime_printf("runtime.SetFinalizer: pointer not at beginning of allocated block (%p)\n", obj.__object);
- goto throw;
- }
- }
- if(finalizer.__type_descriptor != nil) {
- runtime_createfing();
- if((finalizer.__type_descriptor->kind&kindMask) != GO_FUNC)
- goto badfunc;
- ft = (const FuncType*)finalizer.__type_descriptor;
- if(ft->__dotdotdot || ft->__in.__count != 1)
- goto badfunc;
- fint = *(Type**)ft->__in.__values;
- if(__go_type_descriptors_equal(fint, obj.__type_descriptor)) {
- // ok - same type
- } else if((fint->kind&kindMask) == GO_PTR && (fint->__uncommon == nil || fint->__uncommon->__name == nil || obj.type->__uncommon == nil || obj.type->__uncommon->__name == nil) && __go_type_descriptors_equal(((const PtrType*)fint)->__element_type, ((const PtrType*)obj.type)->__element_type)) {
- // ok - not same type, but both pointers,
- // one or the other is unnamed, and same element type, so assignable.
- } else if((fint->kind&kindMask) == GO_INTERFACE && ((const InterfaceType*)fint)->__methods.__count == 0) {
- // ok - satisfies empty interface
- } else if((fint->kind&kindMask) == GO_INTERFACE && __go_convert_interface_2(fint, obj.__type_descriptor, 1) != nil) {
- // ok - satisfies non-empty interface
- } else
- goto badfunc;
- ot = (const PtrType*)obj.__type_descriptor;
- if(!runtime_addfinalizer(obj.__object, *(FuncVal**)finalizer.__object, ft, ot)) {
- runtime_printf("runtime.SetFinalizer: finalizer already set\n");
- goto throw;
- }
- } else {
- // NOTE: asking to remove a finalizer when there currently isn't one set is OK.
- runtime_removefinalizer(obj.__object);
- }
- return;
- badfunc:
- runtime_printf("runtime.SetFinalizer: cannot pass %S to finalizer %S\n", *obj.__type_descriptor->__reflection, *finalizer.__type_descriptor->__reflection);
- throw:
- runtime_throw("runtime.SetFinalizer");
- }
|