mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: do not change field offset in ABI analysis
Currently, the ABI analysis assigns parameter/result offsets to the fields of function *Type. In some cases, we may have an ABI0 function reference and an ABIInternal reference share the same function *Type. For example, for an ABI0 function F, "f := F" will make f and (ABI0) F having the same *Type. But f, as a func value, should use ABIInternal. Analyses on F and f will collide and cause ICE. Also, changing field offsets in ABI analysis has to be done very carefully to avoid data races. It has been causing trickiness/difficulty. This CL removes the change of field offsets in ABI analysis altogether. The analysis result is stored in ABIParamAssignment, which is the only way to access parameter/result stack offset now. Fixes #47317. Fixes #47227. Change-Id: I23a3e081a6cf327ac66855da222daaa636ed1ead Reviewed-on: https://go-review.googlesource.com/c/go/+/336629 Trust: Cherry Mui <cherryyz@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
798ec73519
commit
052da5717e
5 changed files with 40 additions and 22 deletions
|
|
@ -446,35 +446,20 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type, setNname bool) *ABIParamResul
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// parameterUpdateMu protects the Offset field of function/method parameters (a subset of structure Fields)
|
|
||||||
var parameterUpdateMu sync.Mutex
|
|
||||||
|
|
||||||
// FieldOffsetOf returns a concurrency-safe version of f.Offset
|
|
||||||
func FieldOffsetOf(f *types.Field) int64 {
|
|
||||||
parameterUpdateMu.Lock()
|
|
||||||
defer parameterUpdateMu.Unlock()
|
|
||||||
return f.Offset
|
|
||||||
}
|
|
||||||
|
|
||||||
func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn, setNname bool) {
|
func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn, setNname bool) {
|
||||||
// Everything except return values in registers has either a frame home (if not in a register) or a frame spill location.
|
// Everything except return values in registers has either a frame home (if not in a register) or a frame spill location.
|
||||||
if !isReturn || len(a.Registers) == 0 {
|
if !isReturn || len(a.Registers) == 0 {
|
||||||
// The type frame offset DOES NOT show effects of minimum frame size.
|
// The type frame offset DOES NOT show effects of minimum frame size.
|
||||||
// Getting this wrong breaks stackmaps, see liveness/plive.go:WriteFuncMap and typebits/typebits.go:Set
|
// Getting this wrong breaks stackmaps, see liveness/plive.go:WriteFuncMap and typebits/typebits.go:Set
|
||||||
parameterUpdateMu.Lock()
|
|
||||||
defer parameterUpdateMu.Unlock()
|
|
||||||
off := a.FrameOffset(result)
|
off := a.FrameOffset(result)
|
||||||
fOffset := f.Offset
|
fOffset := f.Offset
|
||||||
if fOffset == types.BOGUS_FUNARG_OFFSET {
|
if fOffset == types.BOGUS_FUNARG_OFFSET {
|
||||||
// Set the Offset the first time. After that, we may recompute it, but it should never change.
|
if setNname && f.Nname != nil {
|
||||||
f.Offset = off
|
|
||||||
if f.Nname != nil {
|
|
||||||
// always set it in this case.
|
|
||||||
f.Nname.(*ir.Name).SetFrameOffset(off)
|
f.Nname.(*ir.Name).SetFrameOffset(off)
|
||||||
f.Nname.(*ir.Name).SetIsOutputParamInRegisters(false)
|
f.Nname.(*ir.Name).SetIsOutputParamInRegisters(false)
|
||||||
}
|
}
|
||||||
} else if fOffset != off {
|
} else {
|
||||||
base.Fatalf("offset for %s at %s changed from %d to %d", f.Sym.Name, base.FmtPos(f.Pos), fOffset, off)
|
base.Fatalf("field offset for %s at %s has been set to %d", f.Sym.Name, base.FmtPos(f.Pos), fOffset)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if setNname && f.Nname != nil {
|
if setNname && f.Nname != nil {
|
||||||
|
|
|
||||||
|
|
@ -1296,7 +1296,7 @@ func (s *state) instrumentFields(t *types.Type, addr *ssa.Value, kind instrument
|
||||||
if f.Sym.IsBlank() {
|
if f.Sym.IsBlank() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), abi.FieldOffsetOf(f), addr)
|
offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), f.Offset, addr)
|
||||||
s.instrumentFields(f.Type, offptr, kind)
|
s.instrumentFields(f.Type, offptr, kind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5053,19 +5053,23 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
|
||||||
ft := fn.Type()
|
ft := fn.Type()
|
||||||
off := t.FieldOff(12) // TODO register args: be sure this isn't a hardcoded param stack offset.
|
off := t.FieldOff(12) // TODO register args: be sure this isn't a hardcoded param stack offset.
|
||||||
args := n.Args
|
args := n.Args
|
||||||
|
i0 := 0
|
||||||
|
|
||||||
// Set receiver (for interface calls). Always a pointer.
|
// Set receiver (for interface calls). Always a pointer.
|
||||||
if rcvr != nil {
|
if rcvr != nil {
|
||||||
p := s.newValue1I(ssa.OpOffPtr, ft.Recv().Type.PtrTo(), off, addr)
|
p := s.newValue1I(ssa.OpOffPtr, ft.Recv().Type.PtrTo(), off, addr)
|
||||||
s.store(types.Types[types.TUINTPTR], p, rcvr)
|
s.store(types.Types[types.TUINTPTR], p, rcvr)
|
||||||
|
i0 = 1
|
||||||
}
|
}
|
||||||
// Set receiver (for method calls).
|
// Set receiver (for method calls).
|
||||||
if n.Op() == ir.OCALLMETH {
|
if n.Op() == ir.OCALLMETH {
|
||||||
base.Fatalf("OCALLMETH missed by walkCall")
|
base.Fatalf("OCALLMETH missed by walkCall")
|
||||||
}
|
}
|
||||||
// Set other args.
|
// Set other args.
|
||||||
for _, f := range ft.Params().Fields().Slice() {
|
// This code is only used when RegabiDefer is not enabled, and arguments are always
|
||||||
s.storeArgWithBase(args[0], f.Type, addr, off+abi.FieldOffsetOf(f))
|
// passed on stack.
|
||||||
|
for i, f := range ft.Params().Fields().Slice() {
|
||||||
|
s.storeArgWithBase(args[0], f.Type, addr, off+params.InParam(i+i0).FrameOffset(params))
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5078,7 +5082,6 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
|
||||||
if stksize < int64(types.PtrSize) {
|
if stksize < int64(types.PtrSize) {
|
||||||
// We need room for both the call to deferprocStack and the call to
|
// We need room for both the call to deferprocStack and the call to
|
||||||
// the deferred function.
|
// the deferred function.
|
||||||
// TODO(register args) Revisit this if/when we pass args in registers.
|
|
||||||
stksize = int64(types.PtrSize)
|
stksize = int64(types.PtrSize)
|
||||||
}
|
}
|
||||||
call.AuxInt = stksize
|
call.AuxInt = stksize
|
||||||
|
|
|
||||||
6
test/fixedbugs/issue47317.dir/a.s
Normal file
6
test/fixedbugs/issue47317.dir/a.s
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
TEXT ·G(SB),4,$0
|
||||||
|
RET
|
||||||
17
test/fixedbugs/issue47317.dir/x.go
Normal file
17
test/fixedbugs/issue47317.dir/x.go
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Issue 47317: ICE when calling ABI0 function via func value.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
func main() { F() }
|
||||||
|
|
||||||
|
func F() interface{} {
|
||||||
|
g := G
|
||||||
|
g(1)
|
||||||
|
return G
|
||||||
|
}
|
||||||
|
|
||||||
|
func G(x int) [2]int
|
||||||
7
test/fixedbugs/issue47317.go
Normal file
7
test/fixedbugs/issue47317.go
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
// builddir
|
||||||
|
|
||||||
|
// Copyright 2021 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package ignored
|
||||||
Loading…
Add table
Add a link
Reference in a new issue