Commit ff3fa1b3 authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

runtime: make the GC bitmap a byte array

Half the code in the garbage collector 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.
Make the bitmap a byte array.
Simplifies markallocated, scanblock and span sweep along the way,
as we don't need to recalculate bitmap position for each word.

LGTM=khr
R=golang-codereviews, khr
CC=golang-codereviews, rlh, rsc
https://golang.org/cl/125250043
parent fb44fb6c
...@@ -619,6 +619,14 @@ TEXT runtime·atomicstore64(SB), NOSPLIT, $0-12 ...@@ -619,6 +619,14 @@ TEXT runtime·atomicstore64(SB), NOSPLIT, $0-12
XADDL AX, (SP) XADDL AX, (SP)
RET RET
// void runtime·atomicor8(byte volatile*, byte);
TEXT runtime·atomicor8(SB), NOSPLIT, $0-8
MOVL ptr+0(FP), AX
MOVB val+4(FP), BX
LOCK
ORB BX, (AX)
RET
// void jmpdefer(fn, sp); // void jmpdefer(fn, sp);
// called from deferreturn. // called from deferreturn.
// 1. pop the caller // 1. pop the caller
......
...@@ -702,6 +702,14 @@ TEXT runtime·atomicstore64(SB), NOSPLIT, $0-16 ...@@ -702,6 +702,14 @@ TEXT runtime·atomicstore64(SB), NOSPLIT, $0-16
XCHGQ AX, 0(BX) XCHGQ AX, 0(BX)
RET RET
// void runtime·atomicor8(byte volatile*, byte);
TEXT runtime·atomicor8(SB), NOSPLIT, $0-16
MOVQ ptr+0(FP), AX
MOVB val+8(FP), BX
LOCK
ORB BX, (AX)
RET
// void jmpdefer(fn, sp); // void jmpdefer(fn, sp);
// called from deferreturn. // called from deferreturn.
// 1. pop the caller // 1. pop the caller
......
...@@ -167,3 +167,19 @@ runtime·atomicstore64(uint64 volatile *addr, uint64 v) ...@@ -167,3 +167,19 @@ runtime·atomicstore64(uint64 volatile *addr, uint64 v)
*addr = v; *addr = v;
runtime·unlock(LOCK(addr)); runtime·unlock(LOCK(addr));
} }
#pragma textflag NOSPLIT
void
runtime·atomicor8(byte volatile *addr, byte v)
{
uint32 *addr32, old, word, shift;
// Align down to 4 bytes and use 32-bit CAS.
addr32 = (uint32*)((uintptr)addr & ~3);
word = ((uint32)v) << (((uintptr)addr & 3) * 8);
for(;;) {
old = *addr32;
if(runtime·cas(addr32, old, old|word))
break;
}
}
...@@ -820,7 +820,8 @@ dumpbvtypes(BitVector *bv, byte *base) ...@@ -820,7 +820,8 @@ dumpbvtypes(BitVector *bv, byte *base)
static BitVector static BitVector
makeheapobjbv(byte *p, uintptr size) makeheapobjbv(byte *p, uintptr size)
{ {
uintptr off, shift, *bitp, bits, nptr, i; uintptr off, nptr, i;
byte shift, *bitp, bits;
bool mw; bool mw;
// Extend the temp buffer if necessary. // Extend the temp buffer if necessary.
...@@ -838,13 +839,13 @@ makeheapobjbv(byte *p, uintptr size) ...@@ -838,13 +839,13 @@ makeheapobjbv(byte *p, uintptr size)
mw = false; mw = false;
for(i = 0; i < nptr; i++) { for(i = 0; i < nptr; i++) {
off = (uintptr*)(p + i*PtrSize) - (uintptr*)runtime·mheap.arena_start; off = (uintptr*)(p + i*PtrSize) - (uintptr*)runtime·mheap.arena_start;
bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; bitp = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
shift = (off % wordsPerBitmapWord) * gcBits; shift = (off % wordsPerBitmapByte) * gcBits;
bits = (*bitp >> (shift + 2)) & 3; bits = (*bitp >> (shift + 2)) & BitsMask;
if(!mw && bits == BitsDead) if(!mw && bits == BitsDead)
break; // end of heap object break; // end of heap object
mw = !mw && bits == BitsMultiWord; mw = !mw && bits == BitsMultiWord;
tmpbuf[i*BitsPerPointer/8] &= ~(3<<((i*BitsPerPointer)%8)); tmpbuf[i*BitsPerPointer/8] &= ~(BitsMask<<((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, (uint32*)tmpbuf};
......
...@@ -22,8 +22,8 @@ const ( ...@@ -22,8 +22,8 @@ const (
pageSize = 1 << pageShift pageSize = 1 << pageShift
pageMask = pageSize - 1 pageMask = pageSize - 1
wordsPerBitmapWord = ptrSize * 8 / 4
gcBits = 4 gcBits = 4
wordsPerBitmapByte = 8 / gcBits
bitsPerPointer = 2 bitsPerPointer = 2
bitsMask = 1<<bitsPerPointer - 1 bitsMask = 1<<bitsPerPointer - 1
pointersPerByte = 8 / bitsPerPointer pointersPerByte = 8 / bitsPerPointer
...@@ -211,8 +211,8 @@ func gomallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { ...@@ -211,8 +211,8 @@ func gomallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer {
{ {
arena_start := uintptr(unsafe.Pointer(mheap_.arena_start)) arena_start := uintptr(unsafe.Pointer(mheap_.arena_start))
off := (uintptr(x) - arena_start) / ptrSize off := (uintptr(x) - arena_start) / ptrSize
xbits := (*uintptr)(unsafe.Pointer(arena_start - off/wordsPerBitmapWord*ptrSize - ptrSize)) xbits := (*uint8)(unsafe.Pointer(arena_start - off/wordsPerBitmapByte - 1))
shift := (off % wordsPerBitmapWord) * gcBits shift := (off % wordsPerBitmapByte) * gcBits
if debugMalloc && ((*xbits>>shift)&(bitMask|bitPtrMask)) != bitBoundary { if debugMalloc && ((*xbits>>shift)&(bitMask|bitPtrMask)) != bitBoundary {
println("runtime: bits =", (*xbits>>shift)&(bitMask|bitPtrMask)) println("runtime: bits =", (*xbits>>shift)&(bitMask|bitPtrMask))
gothrow("bad bits in markallocated") gothrow("bad bits in markallocated")
...@@ -260,8 +260,7 @@ func gomallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { ...@@ -260,8 +260,7 @@ func gomallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer {
ptrmask = (*uint8)(unsafe.Pointer(&typ.gc[0])) // embed mask ptrmask = (*uint8)(unsafe.Pointer(&typ.gc[0])) // embed mask
} }
if size == 2*ptrSize { if size == 2*ptrSize {
xbitsb := (*uint8)(add(unsafe.Pointer(xbits), shift/8)) *xbits = *ptrmask | bitBoundary
*xbitsb = *ptrmask | bitBoundary
goto marked goto marked
} }
te = uintptr(typ.size) / ptrSize te = uintptr(typ.size) / ptrSize
...@@ -283,19 +282,12 @@ func gomallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer { ...@@ -283,19 +282,12 @@ func gomallocgc(size uintptr, typ *_type, flags int) unsafe.Pointer {
v &^= uint8(bitPtrMask << 4) v &^= uint8(bitPtrMask << 4)
} }
off := (uintptr(x) + i - arena_start) / ptrSize *xbits = v
xbits := (*uintptr)(unsafe.Pointer(arena_start - off/wordsPerBitmapWord*ptrSize - ptrSize)) xbits = (*byte)(add(unsafe.Pointer(xbits), ^uintptr(0)))
shift := (off % wordsPerBitmapWord) * gcBits
xbitsb := (*uint8)(add(unsafe.Pointer(xbits), shift/8))
*xbitsb = v
} }
if size0%(2*ptrSize) == 0 && size0 < size { if size0%(2*ptrSize) == 0 && size0 < size {
// Mark the word after last object's word as bitsDead. // Mark the word after last object's word as bitsDead.
off := (uintptr(x) + size0 - arena_start) / ptrSize *xbits = bitsDead << 2
xbits := (*uintptr)(unsafe.Pointer(arena_start - off/wordsPerBitmapWord*ptrSize - ptrSize))
shift := (off % wordsPerBitmapWord) * gcBits
xbitsb := (*uint8)(add(unsafe.Pointer(xbits), shift/8))
*xbitsb = bitsDead << 2
} }
} }
marked: marked:
......
This diff is collapsed.
...@@ -8,8 +8,8 @@ enum { ...@@ -8,8 +8,8 @@ enum {
ScanStackByFrames = 1, ScanStackByFrames = 1,
// Four bits per word (see #defines below). // Four bits per word (see #defines below).
wordsPerBitmapWord = sizeof(void*)*8/4,
gcBits = 4, gcBits = 4,
wordsPerBitmapByte = 8/gcBits,
// GC type info programs. // GC type info programs.
// The programs allow to store type info required for GC in a compact form. // The programs allow to store type info required for GC in a compact form.
......
...@@ -913,6 +913,7 @@ void runtime·atomicstore64(uint64 volatile*, uint64); ...@@ -913,6 +913,7 @@ void runtime·atomicstore64(uint64 volatile*, uint64);
uint64 runtime·atomicload64(uint64 volatile*); uint64 runtime·atomicload64(uint64 volatile*);
void* runtime·atomicloadp(void* volatile*); void* runtime·atomicloadp(void* volatile*);
void runtime·atomicstorep(void* volatile*, void*); void runtime·atomicstorep(void* volatile*, void*);
void runtime·atomicor8(byte volatile*, byte);
void runtime·setg(G*); void runtime·setg(G*);
void runtime·newextram(void); void runtime·newextram(void);
......
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