gcc/libgo/runtime/malloc.goc

883 lines
26 KiB
Plaintext
Raw Normal View History

// 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 "runtime.h"
#include "arch.h"
#include "malloc.h"
#include "go-type.h"
// Map gccgo field names to gc field names.
// Type aka __go_type_descriptor
#define kind __code
#define string __reflection
// 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;
int32 runtime_checking;
extern volatile intgo runtime_MemProfileRate
__asm__ (GOSYM_PREFIX "runtime.MemProfileRate");
static MSpan* largealloc(uint32, uintptr*);
static void runtime_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;
MStats *pmstats;
if(size == 0) {
// All 0-length allocations use this pointer.
// The language does not require the allocations to
// have distinct values.
return runtime_getZerobase();
}
g = runtime_g();
runtime: use -fgo-c-header to build C header file Use the new -fgo-c-header option to build a header file for the Go runtime code in libgo/go/runtime, and use the new header file in the C runtime code in libgo/runtime. This will ensure that the Go code and C code share the same data structures as we convert the runtime from C to Go. The new file libgo/go/runtime/runtime2.go is copied from the Go 1.7 release, and then edited to remove unnecessary data structures and modify others for use with libgo. The new file libgo/go/runtime/mcache.go is an initial version of the same files in the Go 1.7 release, and will be replaced by the Go 1.7 file when we convert to the new memory allocator. The new file libgo/go/runtime/type.go describes the gccgo version of the reflection data structures, and replaces the Go 1.7 runtime file which describes the gc version of those structures. Using the new header file means changing a number of struct fields to use Go naming conventions (that is, no underscores) and to rename constants to have a leading underscore so that they are not exported from the Go package. These names were updated in the C code. The C code was also changed to drop the thread-local variable m, as was done some time ago in the gc sources. Now the m field is always accessed using g->m, where g is the single remaining thread-local variable. This in turn required some adjustments to set g->m correctly in all cases. Also pass the new -fgo-compiling-runtime option when compiling the runtime package, although that option doesn't do anything yet. Reviewed-on: https://go-review.googlesource.com/28051 From-SVN: r239872
2016-08-30 21:07:47 +00:00
m = g->m;
incallback = false;
runtime: use -fgo-c-header to build C header file Use the new -fgo-c-header option to build a header file for the Go runtime code in libgo/go/runtime, and use the new header file in the C runtime code in libgo/runtime. This will ensure that the Go code and C code share the same data structures as we convert the runtime from C to Go. The new file libgo/go/runtime/runtime2.go is copied from the Go 1.7 release, and then edited to remove unnecessary data structures and modify others for use with libgo. The new file libgo/go/runtime/mcache.go is an initial version of the same files in the Go 1.7 release, and will be replaced by the Go 1.7 file when we convert to the new memory allocator. The new file libgo/go/runtime/type.go describes the gccgo version of the reflection data structures, and replaces the Go 1.7 runtime file which describes the gc version of those structures. Using the new header file means changing a number of struct fields to use Go naming conventions (that is, no underscores) and to rename constants to have a leading underscore so that they are not exported from the Go package. These names were updated in the C code. The C code was also changed to drop the thread-local variable m, as was done some time ago in the gc sources. Now the m field is always accessed using g->m, where g is the single remaining thread-local variable. This in turn required some adjustments to set g->m correctly in all cases. Also pass the new -fgo-compiling-runtime option when compiling the runtime package, although that option doesn't do anything yet. Reviewed-on: https://go-review.googlesource.com/28051 From-SVN: r239872
2016-08-30 21:07:47 +00:00
if(m->mcache == nil && m->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(0);
m = runtime_m();
incallback = true;
flag |= FlagNoInvokeGC;
}
if((g->preempt || runtime_gcwaiting()) && g != m->g0 && m->locks == 0 && !(flag & FlagNoInvokeGC) && m->preemptoff.len == 0) {
g->preempt = false;
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);
runtime: use -fgo-c-header to build C header file Use the new -fgo-c-header option to build a header file for the Go runtime code in libgo/go/runtime, and use the new header file in the C runtime code in libgo/runtime. This will ensure that the Go code and C code share the same data structures as we convert the runtime from C to Go. The new file libgo/go/runtime/runtime2.go is copied from the Go 1.7 release, and then edited to remove unnecessary data structures and modify others for use with libgo. The new file libgo/go/runtime/mcache.go is an initial version of the same files in the Go 1.7 release, and will be replaced by the Go 1.7 file when we convert to the new memory allocator. The new file libgo/go/runtime/type.go describes the gccgo version of the reflection data structures, and replaces the Go 1.7 runtime file which describes the gc version of those structures. Using the new header file means changing a number of struct fields to use Go naming conventions (that is, no underscores) and to rename constants to have a leading underscore so that they are not exported from the Go package. These names were updated in the C code. The C code was also changed to drop the thread-local variable m, as was done some time ago in the gc sources. Now the m field is always accessed using g->m, where g is the single remaining thread-local variable. This in turn required some adjustments to set g->m correctly in all cases. Also pass the new -fgo-compiling-runtime option when compiling the runtime package, although that option doesn't do anything yet. Reviewed-on: https://go-review.googlesource.com/28051 From-SVN: r239872
2016-08-30 21:07:47 +00:00
size1 = size + (tiny - (byte*)c->tiny);
if(size1 <= tinysize) {
// The object fits into existing tiny block.
v = (MLink*)tiny;
runtime: use -fgo-c-header to build C header file Use the new -fgo-c-header option to build a header file for the Go runtime code in libgo/go/runtime, and use the new header file in the C runtime code in libgo/runtime. This will ensure that the Go code and C code share the same data structures as we convert the runtime from C to Go. The new file libgo/go/runtime/runtime2.go is copied from the Go 1.7 release, and then edited to remove unnecessary data structures and modify others for use with libgo. The new file libgo/go/runtime/mcache.go is an initial version of the same files in the Go 1.7 release, and will be replaced by the Go 1.7 file when we convert to the new memory allocator. The new file libgo/go/runtime/type.go describes the gccgo version of the reflection data structures, and replaces the Go 1.7 runtime file which describes the gc version of those structures. Using the new header file means changing a number of struct fields to use Go naming conventions (that is, no underscores) and to rename constants to have a leading underscore so that they are not exported from the Go package. These names were updated in the C code. The C code was also changed to drop the thread-local variable m, as was done some time ago in the gc sources. Now the m field is always accessed using g->m, where g is the single remaining thread-local variable. This in turn required some adjustments to set g->m correctly in all cases. Also pass the new -fgo-compiling-runtime option when compiling the runtime package, although that option doesn't do anything yet. Reviewed-on: https://go-review.googlesource.com/28051 From-SVN: r239872
2016-08-30 21:07:47 +00:00
c->tiny = (byte*)c->tiny + size1;
c->tinysize -= size1;
m->mallocing = 0;
m->locks--;
if(incallback)
runtime_entersyscall(0);
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
runtime_profilealloc(v, size);
}
m->locks--;
pmstats = mstats();
if(!(flag & FlagNoInvokeGC) && pmstats->heap_alloc >= pmstats->next_gc)
runtime_gc(0);
if(incallback)
runtime_entersyscall(0);
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");
runtime: use -fgo-c-header to build C header file Use the new -fgo-c-header option to build a header file for the Go runtime code in libgo/go/runtime, and use the new header file in the C runtime code in libgo/runtime. This will ensure that the Go code and C code share the same data structures as we convert the runtime from C to Go. The new file libgo/go/runtime/runtime2.go is copied from the Go 1.7 release, and then edited to remove unnecessary data structures and modify others for use with libgo. The new file libgo/go/runtime/mcache.go is an initial version of the same files in the Go 1.7 release, and will be replaced by the Go 1.7 file when we convert to the new memory allocator. The new file libgo/go/runtime/type.go describes the gccgo version of the reflection data structures, and replaces the Go 1.7 runtime file which describes the gc version of those structures. Using the new header file means changing a number of struct fields to use Go naming conventions (that is, no underscores) and to rename constants to have a leading underscore so that they are not exported from the Go package. These names were updated in the C code. The C code was also changed to drop the thread-local variable m, as was done some time ago in the gc sources. Now the m field is always accessed using g->m, where g is the single remaining thread-local variable. This in turn required some adjustments to set g->m correctly in all cases. Also pass the new -fgo-compiling-runtime option when compiling the runtime package, although that option doesn't do anything yet. Reviewed-on: https://go-review.googlesource.com/28051 From-SVN: r239872
2016-08-30 21:07:47 +00:00
s->limit = (uintptr)((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
runtime_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_fastrand() % (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);
}
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 += (intptr)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;
}
}
// 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;
uintptr *pend;
uintptr end;
uintptr limit;
uint64 i;
bool reserved;
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.
end = 0;
pend = &__go_end;
if(pend != nil)
end = *pend;
p = (byte*)ROUND(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();
}
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) {
compiler, runtime: replace hashmap code with Go 1.7 hashmap This change removes the gccgo-specific hashmap code and replaces it with the hashmap code from the Go 1.7 runtime. The Go 1.7 hashmap code is more efficient, does a better job on details like when to update a key, and provides some support against denial-of-service attacks. The compiler is changed to call the new hashmap functions instead of the old ones. The compiler now tracks which types are reflexive and which require updating when used as a map key, and records the information in map type descriptors. Map_index_expression is simplified. The special case for a map index on the right hand side of a tuple expression has been unnecessary for some time, and is removed. The support for specially marking a map index as an lvalue is removed, in favor of lowering an assignment to a map index into a function call. The long-obsolete support for a map index of a pointer to a map is removed. The __go_new_map_big function (known to the compiler as Runtime::MAKEMAPBIG) is no longer needed, as the new runtime.makemap function takes an int64 hint argument. The old map descriptor type and supporting expression is removed. The compiler was still supporting the long-obsolete syntax `m[k] = 0, false` to delete a value from a map. That is now removed, requiring a change to one of the gccgo-specific tests. The builtin len function applied to a map or channel p is now compiled as `p == nil ? 0 : *(*int)(p)`. The __go_chan_len function (known to the compiler as Runtime::CHAN_LEN) is removed. Support for a shared zero value for maps to large value types is introduced, along the lines of the gc compiler. The zero value is handled as a common variable. The hash function is changed to take a seed argument, changing the runtime hash functions and the compiler-generated hash functions. Unlike the gc compiler, both the hash and equal functions continue to take the type length. Types that can not be compared now store nil for the hash and equal functions, rather than pointing to functions that throw. Interface hash and comparison functions now check explicitly for nil. This matches the gc compiler and permits a simple implementation for ismapkey. The compiler is changed to permit marking struct and array types as incomparable, meaning that they have no hash or equal function. We use this for thunk types, removing the existing special code to avoid generating hash/equal functions for them. The C runtime code adds memclr, memequal, and memmove functions. The hashmap code uses go:linkname comments to make the functions visible, as otherwise the compiler would discard them. The hashmap code comments out the unused reference to the address of the first parameter in the race code, as otherwise the compiler thinks that the parameter escapes and copies it onto the heap. This is probably not needed when we enable escape analysis. Several runtime map tests that ere previously skipped for gccgo are now run. The Go runtime picks up type kind information and stubs. The type kind information causes the generated runtime header file to define some constants, including `empty`, and the C code is adjusted accordingly. A Go-callable version of runtime.throw, that takes a Go string, is added to be called from the hashmap code. Reviewed-on: https://go-review.googlesource.com/29447 * go.go-torture/execute/map-1.go: Replace old map deletion syntax with call to builtin delete function. From-SVN: r240334
2016-09-21 20:58:51 +00:00
ret = runtime_mallocgc(typ->__size, (uintptr)typ | TypeInfo_SingleObject, typ->kind&kindNoPointers ? FlagNoScan : 0);
}
static void*
runtime_docnew(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");
compiler, runtime: replace hashmap code with Go 1.7 hashmap This change removes the gccgo-specific hashmap code and replaces it with the hashmap code from the Go 1.7 runtime. The Go 1.7 hashmap code is more efficient, does a better job on details like when to update a key, and provides some support against denial-of-service attacks. The compiler is changed to call the new hashmap functions instead of the old ones. The compiler now tracks which types are reflexive and which require updating when used as a map key, and records the information in map type descriptors. Map_index_expression is simplified. The special case for a map index on the right hand side of a tuple expression has been unnecessary for some time, and is removed. The support for specially marking a map index as an lvalue is removed, in favor of lowering an assignment to a map index into a function call. The long-obsolete support for a map index of a pointer to a map is removed. The __go_new_map_big function (known to the compiler as Runtime::MAKEMAPBIG) is no longer needed, as the new runtime.makemap function takes an int64 hint argument. The old map descriptor type and supporting expression is removed. The compiler was still supporting the long-obsolete syntax `m[k] = 0, false` to delete a value from a map. That is now removed, requiring a change to one of the gccgo-specific tests. The builtin len function applied to a map or channel p is now compiled as `p == nil ? 0 : *(*int)(p)`. The __go_chan_len function (known to the compiler as Runtime::CHAN_LEN) is removed. Support for a shared zero value for maps to large value types is introduced, along the lines of the gc compiler. The zero value is handled as a common variable. The hash function is changed to take a seed argument, changing the runtime hash functions and the compiler-generated hash functions. Unlike the gc compiler, both the hash and equal functions continue to take the type length. Types that can not be compared now store nil for the hash and equal functions, rather than pointing to functions that throw. Interface hash and comparison functions now check explicitly for nil. This matches the gc compiler and permits a simple implementation for ismapkey. The compiler is changed to permit marking struct and array types as incomparable, meaning that they have no hash or equal function. We use this for thunk types, removing the existing special code to avoid generating hash/equal functions for them. The C runtime code adds memclr, memequal, and memmove functions. The hashmap code uses go:linkname comments to make the functions visible, as otherwise the compiler would discard them. The hashmap code comments out the unused reference to the address of the first parameter in the race code, as otherwise the compiler thinks that the parameter escapes and copies it onto the heap. This is probably not needed when we enable escape analysis. Several runtime map tests that ere previously skipped for gccgo are now run. The Go runtime picks up type kind information and stubs. The type kind information causes the generated runtime header file to define some constants, including `empty`, and the C code is adjusted accordingly. A Go-callable version of runtime.throw, that takes a Go string, is added to be called from the hashmap code. Reviewed-on: https://go-review.googlesource.com/29447 * go.go-torture/execute/map-1.go: Replace old map deletion syntax with call to builtin delete function. From-SVN: r240334
2016-09-21 20:58:51 +00:00
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 runtime_docnew(typ, 1, TypeInfo_SingleObject);
}
void*
runtime_cnewarray(const Type *typ, intgo n)
{
return runtime_docnew(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((Type*)obj._type == nil) {
runtime_printf("runtime.SetFinalizer: first argument is nil interface\n");
goto throw;
}
if((((Type*)obj._type)->kind&kindMask) != GO_PTR) {
runtime_printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *((Type*)obj._type)->__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.data < runtime_mheap.arena_start || runtime_mheap.arena_used <= (byte*)obj.data)
return;
if(!runtime_mlookup(obj.data, &base, &size, nil) || obj.data != 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).
compiler, runtime: replace hashmap code with Go 1.7 hashmap This change removes the gccgo-specific hashmap code and replaces it with the hashmap code from the Go 1.7 runtime. The Go 1.7 hashmap code is more efficient, does a better job on details like when to update a key, and provides some support against denial-of-service attacks. The compiler is changed to call the new hashmap functions instead of the old ones. The compiler now tracks which types are reflexive and which require updating when used as a map key, and records the information in map type descriptors. Map_index_expression is simplified. The special case for a map index on the right hand side of a tuple expression has been unnecessary for some time, and is removed. The support for specially marking a map index as an lvalue is removed, in favor of lowering an assignment to a map index into a function call. The long-obsolete support for a map index of a pointer to a map is removed. The __go_new_map_big function (known to the compiler as Runtime::MAKEMAPBIG) is no longer needed, as the new runtime.makemap function takes an int64 hint argument. The old map descriptor type and supporting expression is removed. The compiler was still supporting the long-obsolete syntax `m[k] = 0, false` to delete a value from a map. That is now removed, requiring a change to one of the gccgo-specific tests. The builtin len function applied to a map or channel p is now compiled as `p == nil ? 0 : *(*int)(p)`. The __go_chan_len function (known to the compiler as Runtime::CHAN_LEN) is removed. Support for a shared zero value for maps to large value types is introduced, along the lines of the gc compiler. The zero value is handled as a common variable. The hash function is changed to take a seed argument, changing the runtime hash functions and the compiler-generated hash functions. Unlike the gc compiler, both the hash and equal functions continue to take the type length. Types that can not be compared now store nil for the hash and equal functions, rather than pointing to functions that throw. Interface hash and comparison functions now check explicitly for nil. This matches the gc compiler and permits a simple implementation for ismapkey. The compiler is changed to permit marking struct and array types as incomparable, meaning that they have no hash or equal function. We use this for thunk types, removing the existing special code to avoid generating hash/equal functions for them. The C runtime code adds memclr, memequal, and memmove functions. The hashmap code uses go:linkname comments to make the functions visible, as otherwise the compiler would discard them. The hashmap code comments out the unused reference to the address of the first parameter in the race code, as otherwise the compiler thinks that the parameter escapes and copies it onto the heap. This is probably not needed when we enable escape analysis. Several runtime map tests that ere previously skipped for gccgo are now run. The Go runtime picks up type kind information and stubs. The type kind information causes the generated runtime header file to define some constants, including `empty`, and the C code is adjusted accordingly. A Go-callable version of runtime.throw, that takes a Go string, is added to be called from the hashmap code. Reviewed-on: https://go-review.googlesource.com/29447 * go.go-torture/execute/map-1.go: Replace old map deletion syntax with call to builtin delete function. From-SVN: r240334
2016-09-21 20:58:51 +00:00
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.data);
goto throw;
}
}
if((Type*)finalizer._type != nil) {
runtime_createfing();
if((((Type*)finalizer._type)->kind&kindMask) != GO_FUNC)
goto badfunc;
ft = (const FuncType*)finalizer._type;
if(ft->__dotdotdot || ft->__in.__count != 1)
goto badfunc;
fint = *(Type**)ft->__in.__values;
if(__go_type_descriptors_equal(fint, (Type*)obj._type)) {
// ok - same type
} else if((fint->kind&kindMask) == GO_PTR && (fint->__uncommon == nil || fint->__uncommon->__name == nil || ((Type*)obj._type)->__uncommon == nil || ((Type*)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 && getitab(fint, (Type*)obj._type, true) != nil) {
// ok - satisfies non-empty interface
} else
goto badfunc;
ot = (const PtrType*)obj._type;
if(!runtime_addfinalizer(obj.data, *(FuncVal**)finalizer.data, 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.data);
}
return;
badfunc:
runtime_printf("runtime.SetFinalizer: cannot pass %S to finalizer %S\n", *((Type*)obj._type)->__reflection, *((Type*)finalizer._type)->__reflection);
throw:
runtime_throw("runtime.SetFinalizer");
}
func KeepAlive(x Eface) {
USED(x);
}