Skip to content

Commit 052da57

Browse files
committed
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 <[email protected]> Reviewed-by: Cuong Manh Le <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
1 parent 798ec73 commit 052da57

File tree

5 files changed

+40
-22
lines changed

5 files changed

+40
-22
lines changed

src/cmd/compile/internal/abi/abiutils.go

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -446,35 +446,20 @@ func (config *ABIConfig) ABIAnalyze(t *types.Type, setNname bool) *ABIParamResul
446446
return result
447447
}
448448

449-
// parameterUpdateMu protects the Offset field of function/method parameters (a subset of structure Fields)
450-
var parameterUpdateMu sync.Mutex
451-
452-
// FieldOffsetOf returns a concurrency-safe version of f.Offset
453-
func FieldOffsetOf(f *types.Field) int64 {
454-
parameterUpdateMu.Lock()
455-
defer parameterUpdateMu.Unlock()
456-
return f.Offset
457-
}
458-
459449
func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn, setNname bool) {
460450
// Everything except return values in registers has either a frame home (if not in a register) or a frame spill location.
461451
if !isReturn || len(a.Registers) == 0 {
462452
// The type frame offset DOES NOT show effects of minimum frame size.
463453
// Getting this wrong breaks stackmaps, see liveness/plive.go:WriteFuncMap and typebits/typebits.go:Set
464-
parameterUpdateMu.Lock()
465-
defer parameterUpdateMu.Unlock()
466454
off := a.FrameOffset(result)
467455
fOffset := f.Offset
468456
if fOffset == types.BOGUS_FUNARG_OFFSET {
469-
// Set the Offset the first time. After that, we may recompute it, but it should never change.
470-
f.Offset = off
471-
if f.Nname != nil {
472-
// always set it in this case.
457+
if setNname && f.Nname != nil {
473458
f.Nname.(*ir.Name).SetFrameOffset(off)
474459
f.Nname.(*ir.Name).SetIsOutputParamInRegisters(false)
475460
}
476-
} else if fOffset != off {
477-
base.Fatalf("offset for %s at %s changed from %d to %d", f.Sym.Name, base.FmtPos(f.Pos), fOffset, off)
461+
} else {
462+
base.Fatalf("field offset for %s at %s has been set to %d", f.Sym.Name, base.FmtPos(f.Pos), fOffset)
478463
}
479464
} else {
480465
if setNname && f.Nname != nil {

src/cmd/compile/internal/ssagen/ssa.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,7 +1296,7 @@ func (s *state) instrumentFields(t *types.Type, addr *ssa.Value, kind instrument
12961296
if f.Sym.IsBlank() {
12971297
continue
12981298
}
1299-
offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), abi.FieldOffsetOf(f), addr)
1299+
offptr := s.newValue1I(ssa.OpOffPtr, types.NewPtr(f.Type), f.Offset, addr)
13001300
s.instrumentFields(f.Type, offptr, kind)
13011301
}
13021302
}
@@ -5053,19 +5053,23 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
50535053
ft := fn.Type()
50545054
off := t.FieldOff(12) // TODO register args: be sure this isn't a hardcoded param stack offset.
50555055
args := n.Args
5056+
i0 := 0
50565057

50575058
// Set receiver (for interface calls). Always a pointer.
50585059
if rcvr != nil {
50595060
p := s.newValue1I(ssa.OpOffPtr, ft.Recv().Type.PtrTo(), off, addr)
50605061
s.store(types.Types[types.TUINTPTR], p, rcvr)
5062+
i0 = 1
50615063
}
50625064
// Set receiver (for method calls).
50635065
if n.Op() == ir.OCALLMETH {
50645066
base.Fatalf("OCALLMETH missed by walkCall")
50655067
}
50665068
// Set other args.
5067-
for _, f := range ft.Params().Fields().Slice() {
5068-
s.storeArgWithBase(args[0], f.Type, addr, off+abi.FieldOffsetOf(f))
5069+
// This code is only used when RegabiDefer is not enabled, and arguments are always
5070+
// passed on stack.
5071+
for i, f := range ft.Params().Fields().Slice() {
5072+
s.storeArgWithBase(args[0], f.Type, addr, off+params.InParam(i+i0).FrameOffset(params))
50695073
args = args[1:]
50705074
}
50715075

@@ -5078,7 +5082,6 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
50785082
if stksize < int64(types.PtrSize) {
50795083
// We need room for both the call to deferprocStack and the call to
50805084
// the deferred function.
5081-
// TODO(register args) Revisit this if/when we pass args in registers.
50825085
stksize = int64(types.PtrSize)
50835086
}
50845087
call.AuxInt = stksize

test/fixedbugs/issue47317.dir/a.s

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
TEXT ·G(SB),4,$0
6+
RET

test/fixedbugs/issue47317.dir/x.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright 2021 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Issue 47317: ICE when calling ABI0 function via func value.
6+
7+
package main
8+
9+
func main() { F() }
10+
11+
func F() interface{} {
12+
g := G
13+
g(1)
14+
return G
15+
}
16+
17+
func G(x int) [2]int

test/fixedbugs/issue47317.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// builddir
2+
3+
// Copyright 2021 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package ignored

0 commit comments

Comments
 (0)