// The racewalk pass modifies the code tree for the function as follows:
//
-// 1. It inserts a call to racefuncenter at the beginning of each function.
+// 1. It inserts a call to racefuncenterfp at the beginning of each function.
// 2. It inserts a call to racefuncexit at the end of each function.
// 3. It inserts a call to raceread before each memory read.
// 4. It inserts a call to racewrite before each memory write.
// at best instrumentation would cause infinite recursion.
var omit_pkgs = []string{"runtime", "runtime/race"}
-// Only insert racefuncenter/racefuncexit into the following packages.
+// Only insert racefuncenterfp/racefuncexit into the following packages.
// Memory accesses in the packages are either uninteresting or will cause false positives.
var noinst_pkgs = []string{"sync", "sync/atomic"}
racewalklist(fn.Func.Exit, nil)
}
- // nodpc is the PC of the caller as extracted by
- // getcallerpc. We use -widthptr(FP) for x86.
- // BUG: this will not work on arm.
- nodpc := Nod(OXXX, nil, nil)
-
- *nodpc = *nodfp
- nodpc.Type = Types[TUINTPTR]
- nodpc.Xoffset = int64(-Widthptr)
- nd := mkcall("racefuncenter", nil, nil, nodpc)
+ nd := mkcall("racefuncenterfp", nil, nil, Nod(OADDR, nodfp, nil))
fn.Func.Enter = concat(list1(nd), fn.Func.Enter)
nd = mkcall("racefuncexit", nil, nil)
fn.Func.Exit = list(fn.Func.Exit, nd)
aux := &ssa.ExternSymbol{n.Type, n.Left.Sym}
return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
case OPARAM:
- addr := s.addr(n)
+ addr := s.addr(n, false)
return s.newValue2(ssa.OpLoad, n.Left.Type, addr, s.mem())
case ONAME:
if n.Class == PFUNC {
if canSSA(n) {
return s.variable(n, n.Type)
}
- addr := s.addr(n)
+ addr := s.addr(n, false)
return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
case OCLOSUREVAR:
- addr := s.addr(n)
+ addr := s.addr(n, false)
return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
case OLITERAL:
switch n.Val().Ctype() {
}
if flag_race != 0 {
- s.Unimplementedf("questionable CONVNOP from race detector %v -> %v\n", from, to)
- return nil
+ // These appear to be fine, but they fail the
+ // integer constraint below, so okay them here.
+ // Sample non-integer conversion: map[string]string -> *uint8
+ return v
}
if etypesign(from.Etype) == 0 {
return s.expr(n.Left)
case OADDR:
- return s.addr(n.Left)
+ return s.addr(n.Left, n.Bounded)
case OINDREG:
if int(n.Reg) != Thearch.REGSP {
case ODOT:
// TODO: fix when we can SSA struct types.
- p := s.addr(n)
+ p := s.addr(n, false)
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
case ODOTPTR:
ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
case n.Left.Type.IsSlice():
- p := s.addr(n)
+ p := s.addr(n, false)
return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
case n.Left.Type.IsArray():
// TODO: fix when we can SSA arrays of length 1.
- p := s.addr(n)
+ p := s.addr(n, false)
return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
default:
s.Fatalf("bad type for index %v", n.Left.Type)
args = append(args, s.expr(l.N))
store = append(store, true)
} else {
- args = append(args, s.addr(l.N))
+ args = append(args, s.addr(l.N, false))
store = append(store, false)
}
}
// right == nil means use the zero value of the assigned type.
if !canSSA(left) {
// if we can't ssa this memory, treat it as just zeroing out the backing memory
- addr := s.addr(left)
+ addr := s.addr(left, false)
if left.Op == ONAME {
s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
}
return
}
// not ssa-able. Treat as a store.
- addr := s.addr(left)
+ addr := s.addr(left, false)
if left.Op == ONAME {
s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
}
// addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
// The value that the returned Value represents is guaranteed to be non-nil.
-func (s *state) addr(n *Node) *ssa.Value {
+// If bounded is true then this address does not require a nil check for its operand
+// even if that would otherwise be implied.
+func (s *state) addr(n *Node, bounded bool) *ssa.Value {
switch n.Op {
case ONAME:
switch n.Class {
p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), a)
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i)
} else { // array
- a := s.addr(n.Left)
+ a := s.addr(n.Left, bounded)
i := s.expr(n.Right)
i = s.extendIndex(i)
len := s.constInt(Types[TINT], n.Left.Type.Bound)
}
case OIND:
p := s.expr(n.Left)
- s.nilCheck(p)
+ if !bounded {
+ s.nilCheck(p)
+ }
return p
case ODOT:
- p := s.addr(n.Left)
+ p := s.addr(n.Left, bounded)
return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(Types[TUINTPTR], n.Xoffset))
case ODOTPTR:
p := s.expr(n.Left)
- s.nilCheck(p)
+ if !bounded {
+ s.nilCheck(p)
+ }
return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(Types[TUINTPTR], n.Xoffset))
case OCLOSUREVAR:
return s.newValue2(ssa.OpAddPtr, Ptrto(n.Type),
original_p.Xoffset = n.Xoffset
aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p}
return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
+ case OCONVNOP:
+ addr := s.addr(n.Left, bounded)
+ to := Ptrto(n.Type)
+ return s.newValue1(ssa.OpCopy, to, addr) // ensure that addr has the right type
+
default:
s.Unimplementedf("unhandled addr %v", Oconv(int(n.Op), 0))
return nil
ret:
RET
+// func runtime·racefuncenterfp(fp uintptr)
+// Called from instrumented code.
+// Like racefuncenter but passes FP, not PC
+TEXT runtime·racefuncenterfp(SB), NOSPLIT, $0-8
+ MOVQ fp+0(FP), R11
+ MOVQ -8(R11), R11
+ JMP racefuncenter<>(SB)
+
// func runtime·racefuncenter(pc uintptr)
// Called from instrumented code.
TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8
+ MOVQ callpc+0(FP), R11
+ JMP racefuncenter<>(SB)
+
+// Common code for racefuncenter/racefuncenterfp
+// R11 = caller's return address
+TEXT racefuncenter<>(SB), NOSPLIT, $0-0
MOVQ DX, R15 // save function entry context (for closures)
get_tls(R12)
MOVQ g(R12), R14
MOVQ g_racectx(R14), RARG0 // goroutine context
- MOVQ callpc+0(FP), RARG1
+ MOVQ R11, RARG1
// void __tsan_func_enter(ThreadState *thr, void *pc);
MOVQ $__tsan_func_enter(SB), AX
// racecall<> preserves R15