1
0
mirror of https://github.com/golang/go synced 2024-10-05 16:51:21 -06:00

[dev.ssa] cmd/compile: implement more panic stuff

Implement index check panics (and slice check panics, for when
we need those).

Clean up nil check.  Now that the new regalloc is in we can use
the register we just tested as the address 0 destination.

Remove jumps after panic calls, they are unreachable.

Change-Id: Ifee6e510cdea49cc7c7056887e4f06c67488d491
Reviewed-on: https://go-review.googlesource.com/13687
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
This commit is contained in:
Keith Randall 2015-08-18 15:25:40 -07:00
parent 46e62f873a
commit 8d23681cc8
6 changed files with 104 additions and 15 deletions

View File

@ -1617,6 +1617,9 @@ func (s *state) nilCheck(ptr *ssa.Value) {
// boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
// Starts a new block on return.
func (s *state) boundsCheck(idx, len *ssa.Value) {
if Debug['B'] != 0 {
return
}
// TODO: convert index to full width?
// TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
@ -1627,9 +1630,15 @@ func (s *state) boundsCheck(idx, len *ssa.Value) {
b.Control = cmp
b.Likely = ssa.BranchLikely
bNext := s.f.NewBlock(ssa.BlockPlain)
bPanic := s.f.NewBlock(ssa.BlockPlain)
addEdge(b, bNext)
addEdge(b, s.exit)
// TODO: don't go directly to s.exit. Go to a stub that calls panicindex first.
addEdge(b, bPanic)
addEdge(bPanic, s.exit)
s.startBlock(bPanic)
// The panic check takes/returns memory to ensure that the right
// memory state is observed if the panic happens.
s.vars[&memvar] = s.newValue1(ssa.OpPanicIndexCheck, ssa.TypeMem, s.mem())
s.endBlock()
s.startBlock(bNext)
}
@ -2416,20 +2425,26 @@ func genValue(v *ssa.Value) {
Warnl(int(v.Line), "generated nil check")
}
// Write to memory address 0. It doesn't matter what we write; use AX.
// XORL AX, AX; MOVL AX, (AX) is shorter than MOVL AX, 0.
// TODO: If we had the pointer (v.Args[0]) in a register r,
// we could use MOVL AX, (r) instead of having to zero AX.
// But it isn't worth loading r just to accomplish that.
p := Prog(x86.AXORL)
p.From.Type = obj.TYPE_REG
p.From.Reg = x86.REG_AX
p.To.Type = obj.TYPE_REG
p.To.Reg = x86.REG_AX
// Input 0 is the pointer we just checked, use it as the destination.
r := regnum(v.Args[0])
q := Prog(x86.AMOVL)
q.From.Type = obj.TYPE_REG
q.From.Reg = x86.REG_AX
q.To.Type = obj.TYPE_MEM
q.To.Reg = x86.REG_AX
q.To.Reg = r
// TODO: need AUNDEF here?
case ssa.OpAMD64LoweredPanicIndexCheck:
p := Prog(obj.ACALL)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = Linksym(Panicindex.Sym)
// TODO: need AUNDEF here?
case ssa.OpAMD64LoweredPanicSliceCheck:
p := Prog(obj.ACALL)
p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN
p.To.Sym = Linksym(panicslice.Sym)
// TODO: need AUNDEF here?
case ssa.OpAMD64LoweredGetG:
r := regnum(v)
// See the comments in cmd/internal/obj/x86/obj6.go
@ -2545,6 +2560,17 @@ var blockJump = [...]struct{ asm, invasm int }{
func genBlock(b, next *ssa.Block, branches []branch) []branch {
lineno = b.Line
// after a panic call, don't emit any branch code
if len(b.Values) > 0 {
switch b.Values[len(b.Values)-1].Op {
case ssa.OpAMD64LoweredPanicNilCheck,
ssa.OpAMD64LoweredPanicIndexCheck,
ssa.OpAMD64LoweredPanicSliceCheck:
return branches
}
}
switch b.Kind {
case ssa.BlockPlain:
if b.Succs[0] != next {

View File

@ -245,6 +245,8 @@
(IsInBounds idx len) -> (SETB (CMPQ <TypeFlags> idx len))
(PanicNilCheck ptr mem) -> (LoweredPanicNilCheck ptr mem)
(PanicIndexCheck mem) -> (LoweredPanicIndexCheck mem)
(PanicSliceCheck mem) -> (LoweredPanicSliceCheck mem)
(GetG) -> (LoweredGetG)
(Move [size] dst src mem) -> (REPMOVSB dst src (MOVQconst <config.Frontend().TypeUInt64()> [size]) mem)

View File

@ -103,6 +103,7 @@ func init() {
clobbers: dx | flags}
gp11hmul = regInfo{inputs: []regMask{ax, gpsp}, outputs: []regMask{dx},
clobbers: ax | flags}
gp10 = regInfo{inputs: []regMask{gp}}
gp2flags = regInfo{inputs: []regMask{gpsp, gpsp}, outputs: flagsonly}
gp1flags = regInfo{inputs: []regMask{gpsp}, outputs: flagsonly}
@ -353,7 +354,9 @@ func init() {
{name: "InvertFlags"}, // reverse direction of arg0
// Pseudo-ops
{name: "LoweredPanicNilCheck"},
{name: "LoweredPanicNilCheck", reg: gp10},
{name: "LoweredPanicIndexCheck"},
{name: "LoweredPanicSliceCheck"},
{name: "LoweredGetG", reg: gp01},
}

View File

@ -282,8 +282,10 @@ var genericOps = []opData{
{name: "IsInBounds"}, // 0 <= arg0 < arg1
// Pseudo-ops
{name: "PanicNilCheck"}, // trigger a dereference fault; arg0=nil ptr, arg1=mem
{name: "GetG"}, // runtime.getg() (read g pointer)
{name: "PanicNilCheck"}, // trigger a dereference fault; arg0=nil ptr, arg1=mem, returns mem
{name: "PanicIndexCheck"}, // trigger a bounds check failure, arg0=mem, returns mem
{name: "PanicSliceCheck"}, // trigger a slice bounds check failure, arg0=mem, returns mem
{name: "GetG"}, // runtime.getg() (read g pointer)
// Indexing operations
{name: "ArrayIndex"}, // arg0=array, arg1=index. Returns a[i]

View File

@ -227,6 +227,8 @@ const (
OpAMD64REPMOVSB
OpAMD64InvertFlags
OpAMD64LoweredPanicNilCheck
OpAMD64LoweredPanicIndexCheck
OpAMD64LoweredPanicSliceCheck
OpAMD64LoweredGetG
OpAdd8
@ -426,6 +428,8 @@ const (
OpIsNonNil
OpIsInBounds
OpPanicNilCheck
OpPanicIndexCheck
OpPanicSliceCheck
OpGetG
OpArrayIndex
OpPtrIndex
@ -2686,6 +2690,18 @@ var opcodeTable = [...]opInfo{
},
{
name: "LoweredPanicNilCheck",
reg: regInfo{
inputs: []inputInfo{
{0, 65519}, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
},
},
},
{
name: "LoweredPanicIndexCheck",
reg: regInfo{},
},
{
name: "LoweredPanicSliceCheck",
reg: regInfo{},
},
{
@ -3486,6 +3502,14 @@ var opcodeTable = [...]opInfo{
name: "PanicNilCheck",
generic: true,
},
{
name: "PanicIndexCheck",
generic: true,
},
{
name: "PanicSliceCheck",
generic: true,
},
{
name: "GetG",
generic: true,

View File

@ -5789,6 +5789,22 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
goto end6f8a8c559a167d1f0a5901d09a1fb248
end6f8a8c559a167d1f0a5901d09a1fb248:
;
case OpPanicIndexCheck:
// match: (PanicIndexCheck mem)
// cond:
// result: (LoweredPanicIndexCheck mem)
{
mem := v.Args[0]
v.Op = OpAMD64LoweredPanicIndexCheck
v.AuxInt = 0
v.Aux = nil
v.resetArgs()
v.AddArg(mem)
return true
}
goto enda5014ba73d3550a5b66424044395c70f
enda5014ba73d3550a5b66424044395c70f:
;
case OpPanicNilCheck:
// match: (PanicNilCheck ptr mem)
// cond:
@ -5807,6 +5823,22 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
goto enda02b1ad5a6f929b782190145f2c8628b
enda02b1ad5a6f929b782190145f2c8628b:
;
case OpPanicSliceCheck:
// match: (PanicSliceCheck mem)
// cond:
// result: (LoweredPanicSliceCheck mem)
{
mem := v.Args[0]
v.Op = OpAMD64LoweredPanicSliceCheck
v.AuxInt = 0
v.Aux = nil
v.resetArgs()
v.AddArg(mem)
return true
}
goto end238ed0074810b55bd2bba7b45cdeed68
end238ed0074810b55bd2bba7b45cdeed68:
;
case OpRsh16Ux16:
// match: (Rsh16Ux16 <t> x y)
// cond: