Commit fd21b9f8 authored by Russ Cox's avatar Russ Cox

[dev.power64] runtime: make all bitmaps arrays of bytes

The "simpler faster garbage collector" is full of little-endian assumptions.
Instead of trying to correct all the mistakes, just give in and make
everything use bytes.

LGTM=minux
R=minux
CC=dvyukov, golang-codereviews
https://golang.org/cl/124400043
parent f9fdc887
...@@ -1939,7 +1939,11 @@ twobitwritesymbol(Array *arr, Sym *sym) ...@@ -1939,7 +1939,11 @@ twobitwritesymbol(Array *arr, Sym *sym)
break; break;
for(j = 0; j < bv->n; j += 32) { for(j = 0; j < bv->n; j += 32) {
word = bv->b[j/32]; word = bv->b[j/32];
off = duint32(sym, off, word); // Runtime reads the bitmaps as byte arrays. Oblige.
off = duint8(sym, off, word);
off = duint8(sym, off, word>>8);
off = duint8(sym, off, word>>16);
off = duint8(sym, off, word>>24);
} }
} }
duint32(sym, 0, i); // number of bitmaps duint32(sym, 0, i); // number of bitmaps
......
...@@ -252,7 +252,7 @@ dumpbv(BitVector *bv, uintptr offset) ...@@ -252,7 +252,7 @@ dumpbv(BitVector *bv, uintptr offset)
uintptr i; uintptr i;
for(i = 0; i < bv->n; i += BitsPerPointer) { for(i = 0; i < bv->n; i += BitsPerPointer) {
switch(bv->data[i/32] >> i%32 & 3) { switch(bv->bytedata[i/8] >> i%8 & 3) {
case BitsDead: case BitsDead:
case BitsScalar: case BitsScalar:
break; break;
...@@ -261,7 +261,7 @@ dumpbv(BitVector *bv, uintptr offset) ...@@ -261,7 +261,7 @@ dumpbv(BitVector *bv, uintptr offset)
dumpint(offset + i / BitsPerPointer * PtrSize); dumpint(offset + i / BitsPerPointer * PtrSize);
break; break;
case BitsMultiWord: case BitsMultiWord:
switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) { switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) {
case BitsString: case BitsString:
dumpint(FieldKindString); dumpint(FieldKindString);
dumpint(offset + i / BitsPerPointer * PtrSize); dumpint(offset + i / BitsPerPointer * PtrSize);
...@@ -497,13 +497,13 @@ dumproots(void) ...@@ -497,13 +497,13 @@ dumproots(void)
dumpint(TagData); dumpint(TagData);
dumpint((uintptr)data); dumpint((uintptr)data);
dumpmemrange(data, edata - data); dumpmemrange(data, edata - data);
dumpfields((BitVector){(edata - data)*8, (uint32*)gcdata}); dumpfields((BitVector){(edata - data)*8, (byte*)gcdata}); /* WRONG! gcbss is not a bitmap */
// bss segment // bss segment
dumpint(TagBss); dumpint(TagBss);
dumpint((uintptr)bss); dumpint((uintptr)bss);
dumpmemrange(bss, ebss - bss); dumpmemrange(bss, ebss - bss);
dumpfields((BitVector){(ebss - bss)*8, (uint32*)gcbss}); dumpfields((BitVector){(ebss - bss)*8, (byte*)gcbss}); /* WRONG! gcbss is not a bitmap */
// MSpan.types // MSpan.types
allspans = runtime·mheap.allspans; allspans = runtime·mheap.allspans;
...@@ -795,9 +795,9 @@ dumpbvtypes(BitVector *bv, byte *base) ...@@ -795,9 +795,9 @@ dumpbvtypes(BitVector *bv, byte *base)
uintptr i; uintptr i;
for(i = 0; i < bv->n; i += BitsPerPointer) { for(i = 0; i < bv->n; i += BitsPerPointer) {
if((bv->data[i/32] >> i%32 & 3) != BitsMultiWord) if((bv->bytedata[i/8] >> i%8 & 3) != BitsMultiWord)
continue; continue;
switch(bv->data[(i+BitsPerPointer)/32] >> (i+BitsPerPointer)%32 & 3) { switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) {
case BitsString: case BitsString:
case BitsIface: case BitsIface:
i += BitsPerPointer; i += BitsPerPointer;
...@@ -843,5 +843,5 @@ makeheapobjbv(byte *p, uintptr size) ...@@ -843,5 +843,5 @@ makeheapobjbv(byte *p, uintptr size)
tmpbuf[i*BitsPerPointer/8] &= ~(3<<((i*BitsPerPointer)%8)); tmpbuf[i*BitsPerPointer/8] &= ~(3<<((i*BitsPerPointer)%8));
tmpbuf[i*BitsPerPointer/8] |= bits<<((i*BitsPerPointer)%8); tmpbuf[i*BitsPerPointer/8] |= bits<<((i*BitsPerPointer)%8);
} }
return (BitVector){i*BitsPerPointer, (uint32*)tmpbuf}; return (BitVector){i*BitsPerPointer, (byte*)tmpbuf};
} }
...@@ -4,9 +4,7 @@ ...@@ -4,9 +4,7 @@
package runtime package runtime
import ( import "unsafe"
"unsafe"
)
const ( const (
flagNoScan = 1 << 0 // GC doesn't have to scan object flagNoScan = 1 << 0 // GC doesn't have to scan object
...@@ -278,7 +276,10 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) { ...@@ -278,7 +276,10 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
// force = 1 - do GC regardless of current heap usage // force = 1 - do GC regardless of current heap usage
// force = 2 - go GC and eager sweep // force = 2 - go GC and eager sweep
func gogc(force int32) { func gogc(force int32) {
if GOARCH == "power64" || GOARCH == "power64le" || memstats.enablegc == 0 { if false && (GOARCH == "power64" || GOARCH == "power64le") {
return
}
if memstats.enablegc == 0 {
return return
} }
......
...@@ -568,14 +568,14 @@ typedef struct BitVector BitVector; ...@@ -568,14 +568,14 @@ typedef struct BitVector BitVector;
struct BitVector struct BitVector
{ {
int32 n; // # of bits int32 n; // # of bits
uint32 *data; uint8 *bytedata;
}; };
typedef struct StackMap StackMap; typedef struct StackMap StackMap;
struct StackMap struct StackMap
{ {
int32 n; // number of bitmaps int32 n; // number of bitmaps
int32 nbit; // number of bits in each bitmap int32 nbit; // number of bits in each bitmap
uint32 data[]; uint8 bytedata[];
}; };
// Returns pointer map data for the given stackmap index // Returns pointer map data for the given stackmap index
// (the index is encoded in PCDATA_StackMapIndex). // (the index is encoded in PCDATA_StackMapIndex).
......
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,7 @@
enum { enum {
Debug = 0, Debug = 0,
ConcurrentSweep = 1, ConcurrentSweep = 0,
PreciseScan = 1, PreciseScan = 1,
WorkbufSize = 4*1024, WorkbufSize = 4*1024,
...@@ -75,6 +75,12 @@ enum { ...@@ -75,6 +75,12 @@ enum {
RootSpans = 3, RootSpans = 3,
RootFlushCaches = 4, RootFlushCaches = 4,
RootCount = 5, RootCount = 5,
#ifdef _64BIT
byteEndian = BigEndian*7,
#else
byteEndian = BigEndian*3,
#endif
}; };
#define ScanConservatively ((byte*)1) #define ScanConservatively ((byte*)1)
...@@ -669,7 +675,7 @@ runtime·stackmapdata(StackMap *stackmap, int32 n) ...@@ -669,7 +675,7 @@ runtime·stackmapdata(StackMap *stackmap, int32 n)
{ {
if(n < 0 || n >= stackmap->n) if(n < 0 || n >= stackmap->n)
runtime·throw("stackmapdata: index out of range"); runtime·throw("stackmapdata: index out of range");
return (BitVector){stackmap->nbit, stackmap->data + n*((stackmap->nbit+31)/32)}; return (BitVector){stackmap->nbit, stackmap->bytedata + 4*n*((stackmap->nbit+31)/32)};
} }
// Scan a stack frame: local variables and function arguments/results. // Scan a stack frame: local variables and function arguments/results.
...@@ -727,7 +733,7 @@ scanframe(Stkframe *frame, void *unused) ...@@ -727,7 +733,7 @@ scanframe(Stkframe *frame, void *unused)
} }
bv = runtime·stackmapdata(stackmap, pcdata); bv = runtime·stackmapdata(stackmap, pcdata);
size = (bv.n * PtrSize) / BitsPerPointer; size = (bv.n * PtrSize) / BitsPerPointer;
scanblock(frame->varp - size, bv.n/BitsPerPointer*PtrSize, (byte*)bv.data); scanblock(frame->varp - size, bv.n/BitsPerPointer*PtrSize, (byte*)bv.bytedata);
} }
// Scan arguments. // Scan arguments.
...@@ -735,7 +741,7 @@ scanframe(Stkframe *frame, void *unused) ...@@ -735,7 +741,7 @@ scanframe(Stkframe *frame, void *unused)
stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
if(stackmap != nil) { if(stackmap != nil) {
bv = runtime·stackmapdata(stackmap, pcdata); bv = runtime·stackmapdata(stackmap, pcdata);
scanblock(frame->argp, bv.n/BitsPerPointer*PtrSize, (byte*)bv.data); scanblock(frame->argp, bv.n/BitsPerPointer*PtrSize, (byte*)bv.bytedata);
} else { } else {
if(Debug > 2) if(Debug > 2)
runtime·printf("frame %s conservative args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen); runtime·printf("frame %s conservative args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen);
...@@ -1292,6 +1298,8 @@ runtime·gc(int32 force) ...@@ -1292,6 +1298,8 @@ runtime·gc(int32 force)
struct gc_args a; struct gc_args a;
int32 i; int32 i;
//if(thechar == '9') return;
if(sizeof(Workbuf) != WorkbufSize) if(sizeof(Workbuf) != WorkbufSize)
runtime·throw("runtime: size of Workbuf is suboptimal"); runtime·throw("runtime: size of Workbuf is suboptimal");
// The gc is turned off (via enablegc) until // The gc is turned off (via enablegc) until
...@@ -1305,10 +1313,6 @@ runtime·gc(int32 force) ...@@ -1305,10 +1313,6 @@ runtime·gc(int32 force)
if(!mstats.enablegc || g == g->m->g0 || g->m->locks > 0 || runtime·panicking) if(!mstats.enablegc || g == g->m->g0 || g->m->locks > 0 || runtime·panicking)
return; return;
if(thechar == '9') {
runtime·gcpercent = -1;
return;
}
if(runtime·gcpercent == GcpercentUnknown) { // first time through if(runtime·gcpercent == GcpercentUnknown) { // first time through
runtime·lock(&runtime·mheap); runtime·lock(&runtime·mheap);
if(runtime·gcpercent == GcpercentUnknown) if(runtime·gcpercent == GcpercentUnknown)
...@@ -1777,8 +1781,8 @@ unrollgcprog1(byte *mask, byte *prog, uintptr *ppos, bool inplace, bool sparse) ...@@ -1777,8 +1781,8 @@ unrollgcprog1(byte *mask, byte *prog, uintptr *ppos, bool inplace, bool sparse)
b = (uintptr*)arena_start - off/wordsPerBitmapWord - 1; b = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
shift = (off % wordsPerBitmapWord) * gcBits; shift = (off % wordsPerBitmapWord) * gcBits;
if((shift%8)==0) if((shift%8)==0)
((byte*)b)[shift/8] = 0; ((byte*)b)[(shift/8)^byteEndian] = 0;
((byte*)b)[shift/8] |= v<<((shift%8)+2); ((byte*)b)[(shift/8)^byteEndian] |= v<<((shift%8)+2);
pos += PtrSize; pos += PtrSize;
} else if(sparse) { } else if(sparse) {
// 4-bits per word // 4-bits per word
...@@ -1873,7 +1877,7 @@ unrollgcprog(Type *typ) ...@@ -1873,7 +1877,7 @@ unrollgcprog(Type *typ)
static Lock lock; static Lock lock;
byte *mask, *prog; byte *mask, *prog;
uintptr pos; uintptr pos;
uint32 x; uintptr x;
runtime·lock(&lock); runtime·lock(&lock);
mask = (byte*)typ->gc[0]; mask = (byte*)typ->gc[0];
...@@ -1888,9 +1892,11 @@ unrollgcprog(Type *typ) ...@@ -1888,9 +1892,11 @@ unrollgcprog(Type *typ)
prog = (byte*)typ->gc[1]; prog = (byte*)typ->gc[1];
unrollgcprog1(mask, prog, &pos, false, true); unrollgcprog1(mask, prog, &pos, false, true);
} }
// atomic way to say mask[0] = 1 // atomic way to say mask[0] = 1
x = ((uint32*)mask)[0]; x = typ->gc[0];
runtime·atomicstore((uint32*)mask, x|1); ((byte*)&x)[0] = 1;
runtime·atomicstorep((void**)mask, (void*)x);
} }
runtime·unlock(&lock); runtime·unlock(&lock);
} }
...@@ -1898,7 +1904,7 @@ unrollgcprog(Type *typ) ...@@ -1898,7 +1904,7 @@ unrollgcprog(Type *typ)
void void
runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool scan) runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool scan)
{ {
uintptr *b, off, shift, i, ti, te, nptr, masksize; uintptr *b, off, shift, i, ti, te, nptr, masksize, maskword;
byte *arena_start, x; byte *arena_start, x;
bool *ptrmask; bool *ptrmask;
...@@ -1907,7 +1913,7 @@ runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool sca ...@@ -1907,7 +1913,7 @@ runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool sca
b = (uintptr*)arena_start - off/wordsPerBitmapWord - 1; b = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
shift = (off % wordsPerBitmapWord) * gcBits; shift = (off % wordsPerBitmapWord) * gcBits;
if(Debug && (((*b)>>shift)&bitMask) != bitBoundary) { if(Debug && (((*b)>>shift)&bitMask) != bitBoundary) {
runtime·printf("runtime: bad bits in markallocated (%p) b=%p[%p]\n", v, b, *b); runtime·printf("runtime: bad bits in markallocated (%p) b=%p[%p] off=%p shift=%d\n", v, b, *b, off, (int32)shift);
runtime·throw("bad bits in markallocated"); runtime·throw("bad bits in markallocated");
} }
...@@ -1916,7 +1922,7 @@ runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool sca ...@@ -1916,7 +1922,7 @@ runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool sca
if(size == PtrSize) if(size == PtrSize)
*b = (*b & ~((bitBoundary|bitPtrMask)<<shift)) | ((bitAllocated+(BitsDead<<2))<<shift); *b = (*b & ~((bitBoundary|bitPtrMask)<<shift)) | ((bitAllocated+(BitsDead<<2))<<shift);
else else
((byte*)b)[shift/8] = bitAllocated+(BitsDead<<2); ((byte*)b)[(shift/8)^byteEndian] = bitAllocated+(BitsDead<<2);
return; return;
} }
if(size == PtrSize) { if(size == PtrSize) {
...@@ -1944,13 +1950,14 @@ runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool sca ...@@ -1944,13 +1950,14 @@ runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool sca
} }
ptrmask = (byte*)typ->gc[0]; ptrmask = (byte*)typ->gc[0];
// check whether the program is already unrolled // check whether the program is already unrolled
if((runtime·atomicload((uint32*)ptrmask)&0xff) == 0) maskword = (uintptr)runtime·atomicloadp((void*)&typ->gc[0]);
if(((byte*)&maskword)[0] == 0)
unrollgcprog(typ); unrollgcprog(typ);
ptrmask++; // skip the unroll flag byte ptrmask++; // skip the unroll flag byte
} else } else
ptrmask = (byte*)&typ->gc[0]; // embed mask ptrmask = (byte*)&typ->gc[0]; // embed mask
if(size == 2*PtrSize) { if(size == 2*PtrSize) {
((byte*)b)[shift/8] = ptrmask[0] | bitAllocated; ((byte*)b)[(shift/8)^byteEndian] = ptrmask[0] | bitAllocated;
return; return;
} }
te = typ->size/PtrSize; te = typ->size/PtrSize;
...@@ -1959,7 +1966,7 @@ runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool sca ...@@ -1959,7 +1966,7 @@ runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool sca
te /= 2; te /= 2;
} }
if(size == 2*PtrSize) { if(size == 2*PtrSize) {
((byte*)b)[shift/8] = (BitsPointer<<2) | (BitsPointer<<6) | bitAllocated; ((byte*)b)[(shift/8)^byteEndian] = (BitsPointer<<2) | (BitsPointer<<6) | bitAllocated;
return; return;
} }
// Copy pointer bitmask into the bitmap. // Copy pointer bitmask into the bitmap.
...@@ -1977,14 +1984,14 @@ runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool sca ...@@ -1977,14 +1984,14 @@ runtime·markallocated(void *v, uintptr size, uintptr size0, Type *typ, bool sca
x |= bitAllocated; x |= bitAllocated;
if(i+PtrSize == size0) if(i+PtrSize == size0)
x &= ~(bitPtrMask<<4); x &= ~(bitPtrMask<<4);
((byte*)b)[shift/8] = x; ((byte*)b)[(shift/8)^byteEndian] = x;
} }
if(size0 == i && size0 < size) { if(size0 == i && size0 < size) {
// mark the word after last object's word as BitsDead // mark the word after last object's word as BitsDead
off = (uintptr*)((byte*)v + size0) - (uintptr*)arena_start; off = (uintptr*)((byte*)v + size0) - (uintptr*)arena_start;
b = (uintptr*)arena_start - off/wordsPerBitmapWord - 1; b = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
shift = (off % wordsPerBitmapWord) * gcBits; shift = (off % wordsPerBitmapWord) * gcBits;
((byte*)b)[shift/8] = 0; ((byte*)b)[(shift/8)^byteEndian] = 0;
} }
} }
...@@ -2174,7 +2181,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len) ...@@ -2174,7 +2181,7 @@ runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
*mask = runtime·mallocgc(*len, nil, 0); *mask = runtime·mallocgc(*len, nil, 0);
for(i = 0; i < n; i += PtrSize) { for(i = 0; i < n; i += PtrSize) {
off = (p+i-frame.varp+size)/PtrSize; off = (p+i-frame.varp+size)/PtrSize;
bits = (bv.data[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask; bits = (bv.bytedata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
(*mask)[i/PtrSize] = bits; (*mask)[i/PtrSize] = bits;
} }
} }
......
...@@ -7,6 +7,13 @@ ...@@ -7,6 +7,13 @@
enum { enum {
ScanStackByFrames = 1, ScanStackByFrames = 1,
// TODO(rsc): Half the code in the garbage collector
// now accesses the bitmap as an array of bytes
// instead of as an array of uintptrs.
// This is tricky to do correctly in a portable fashion.
// (It breaks on big-endian systems.)
// Should we just make the bitmap a byte array?
// Four bits per word (see #defines below). // Four bits per word (see #defines below).
wordsPerBitmapWord = sizeof(void*)*8/4, wordsPerBitmapWord = sizeof(void*)*8/4,
gcBits = 4, gcBits = 4,
......
...@@ -543,8 +543,8 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f) ...@@ -543,8 +543,8 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
num = bv->n / BitsPerPointer; num = bv->n / BitsPerPointer;
for(i = 0; i < num; i++) { for(i = 0; i < num; i++) {
if(StackDebug >= 4) if(StackDebug >= 4)
runtime·printf(" %p:%s:%p\n", &scanp[i], mapnames[bv->data[i / (32 / BitsPerPointer)] >> (i * BitsPerPointer & 31) & 3], scanp[i]); runtime·printf(" %p:%s:%p\n", &scanp[i], mapnames[bv->bytedata[i / (8 / BitsPerPointer)] >> (i * BitsPerPointer & 7) & 3], scanp[i]);
switch(bv->data[i / (32 / BitsPerPointer)] >> (i * BitsPerPointer & 31) & 3) { switch(bv->bytedata[i / (8 / BitsPerPointer)] >> (i * BitsPerPointer & 7) & 3) {
case BitsDead: case BitsDead:
if(runtime·debug.gcdead) if(runtime·debug.gcdead)
scanp[i] = (byte*)PoisonStack; scanp[i] = (byte*)PoisonStack;
...@@ -567,7 +567,7 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f) ...@@ -567,7 +567,7 @@ adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
} }
break; break;
case BitsMultiWord: case BitsMultiWord:
switch(bv->data[(i+1) / (32 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 31) & 3) { switch(bv->bytedata[(i+1) / (8 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 7) & 3) {
case BitsString: case BitsString:
// string referents are never on the stack, never need to be adjusted // string referents are never on the stack, never need to be adjusted
i++; // skip len i++; // skip len
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment