mirror of
https://github.com/golang/go
synced 2024-11-19 13:04:45 -07:00
runtime: buffered write barrier for amd64p32
Updates #22460. Change-Id: I6656d478625e5e54aa2eaa38d99dfb0f71ea1fdd Reviewed-on: https://go-review.googlesource.com/92697 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
parent
252f1170e5
commit
24dd83d7eb
@ -408,7 +408,7 @@ func Main(archInit func(*Arch)) {
|
||||
}
|
||||
|
||||
switch objabi.GOARCH {
|
||||
case "amd64", "386":
|
||||
case "amd64", "amd64p32", "386":
|
||||
default:
|
||||
// Other architectures don't support the buffered
|
||||
// write barrier yet.
|
||||
|
@ -298,6 +298,9 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config
|
||||
// Returns clobber BP on nacl/386, so the write
|
||||
// barrier does.
|
||||
opcodeTable[Op386LoweredWB].reg.clobbers |= 1 << 5 // BP
|
||||
|
||||
// ... and SI on nacl/amd64.
|
||||
opcodeTable[OpAMD64LoweredWB].reg.clobbers |= 1 << 6 // SI
|
||||
}
|
||||
|
||||
if ctxt.Flag_shared {
|
||||
|
@ -567,7 +567,7 @@ func init() {
|
||||
|
||||
// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
|
||||
// It saves all GP registers if necessary, but may clobber others.
|
||||
{name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("DI"), ax}, clobbers: callerSave ^ gp}, clobberFlags: true, aux: "Sym", symEffect: "None"},
|
||||
{name: "LoweredWB", argLength: 3, reg: regInfo{inputs: []regMask{buildReg("DI"), ax}, clobbers: callerSave &^ gp}, clobberFlags: true, aux: "Sym", symEffect: "None"},
|
||||
|
||||
// MOVQconvert converts between pointers and integers.
|
||||
// We have a special op for this so as to not confuse GC
|
||||
|
@ -27,3 +27,5 @@ runtime/asm_amd64p32.s: [amd64p32] indexbytebody: function indexbytebody missing
|
||||
runtime/asm_amd64p32.s: [amd64p32] asmcgocall: RET without writing to 4-byte ret+8(FP)
|
||||
|
||||
runtime/asm_amd64p32.s: [amd64p32] stackcheck: function stackcheck missing Go declaration
|
||||
|
||||
runtime/asm_ARCHSUFF.s: [GOARCH] gcWriteBarrier: function gcWriteBarrier missing Go declaration
|
||||
|
@ -973,3 +973,84 @@ TEXT runtime·goexit(SB),NOSPLIT,$0-0
|
||||
TEXT ·checkASM(SB),NOSPLIT,$0-1
|
||||
MOVB $1, ret+0(FP)
|
||||
RET
|
||||
|
||||
// gcWriteBarrier performs a heap pointer write and informs the GC.
|
||||
//
|
||||
// gcWriteBarrier does NOT follow the Go ABI. It takes two arguments:
|
||||
// - DI is the destination of the write
|
||||
// - AX is the value being written at DI
|
||||
// It clobbers FLAGS and SI. It does not clobber any other general-purpose registers,
|
||||
// but may clobber others (e.g., SSE registers).
|
||||
TEXT runtime·gcWriteBarrier(SB),NOSPLIT,$88
|
||||
// Save the registers clobbered by the fast path. This is slightly
|
||||
// faster than having the caller spill these.
|
||||
MOVQ R14, 72(SP)
|
||||
MOVQ R13, 80(SP)
|
||||
// TODO: Consider passing g.m.p in as an argument so they can be shared
|
||||
// across a sequence of write barriers.
|
||||
get_tls(R13)
|
||||
MOVL g(R13), R13
|
||||
MOVL g_m(R13), R13
|
||||
MOVL m_p(R13), R13
|
||||
MOVL (p_wbBuf+wbBuf_next)(R13), R14
|
||||
// Increment wbBuf.next position.
|
||||
LEAL 8(R14), R14
|
||||
MOVL R14, (p_wbBuf+wbBuf_next)(R13)
|
||||
CMPL R14, (p_wbBuf+wbBuf_end)(R13)
|
||||
// Record the write.
|
||||
MOVL AX, -8(R14) // Record value
|
||||
MOVL (DI), R13 // TODO: This turns bad writes into bad reads.
|
||||
MOVL R13, -4(R14) // Record *slot
|
||||
// Is the buffer full? (flags set in CMPL above)
|
||||
JEQ flush
|
||||
ret:
|
||||
MOVQ 72(SP), R14
|
||||
MOVQ 80(SP), R13
|
||||
// Do the write.
|
||||
MOVL AX, (DI)
|
||||
RET // Clobbers SI on NaCl
|
||||
|
||||
flush:
|
||||
// Save all general purpose registers since these could be
|
||||
// clobbered by wbBufFlush and were not saved by the caller.
|
||||
// It is possible for wbBufFlush to clobber other registers
|
||||
// (e.g., SSE registers), but the compiler takes care of saving
|
||||
// those in the caller if necessary. This strikes a balance
|
||||
// with registers that are likely to be used.
|
||||
//
|
||||
// We don't have type information for these, but all code under
|
||||
// here is NOSPLIT, so nothing will observe these.
|
||||
//
|
||||
// TODO: We could strike a different balance; e.g., saving X0
|
||||
// and not saving GP registers that are less likely to be used.
|
||||
MOVL DI, 0(SP) // Also first argument to wbBufFlush
|
||||
MOVL AX, 4(SP) // Also second argument to wbBufFlush
|
||||
MOVQ BX, 8(SP)
|
||||
MOVQ CX, 16(SP)
|
||||
MOVQ DX, 24(SP)
|
||||
// DI already saved
|
||||
// SI is always clobbered on nacl
|
||||
// BP is reserved on nacl
|
||||
MOVQ R8, 32(SP)
|
||||
MOVQ R9, 40(SP)
|
||||
MOVQ R10, 48(SP)
|
||||
MOVQ R11, 56(SP)
|
||||
MOVQ R12, 64(SP)
|
||||
// R13 already saved
|
||||
// R14 already saved
|
||||
// R15 is reserved on nacl
|
||||
|
||||
// This takes arguments DI and AX
|
||||
CALL runtime·wbBufFlush(SB)
|
||||
|
||||
MOVL 0(SP), DI
|
||||
MOVL 4(SP), AX
|
||||
MOVQ 8(SP), BX
|
||||
MOVQ 16(SP), CX
|
||||
MOVQ 24(SP), DX
|
||||
MOVQ 32(SP), R8
|
||||
MOVQ 40(SP), R9
|
||||
MOVQ 48(SP), R10
|
||||
MOVQ 56(SP), R11
|
||||
MOVQ 64(SP), R12
|
||||
JMP ret
|
||||
|
Loading…
Reference in New Issue
Block a user