Skip to content

Commit

Permalink
cmd/compile/internal/noder: set ir.Name.DictIndex for unified IR
Browse files Browse the repository at this point in the history
For local variables of derived type, Delve relies on ir.Name.DictIndex
being set to the type's rtype index within the function's dictionary.
This CL implements that functionality within unified IR.

Manually double checked that Delve behaves correctly, at least as far
as I can tell from casual use. Specifically, I confirmed that running
the test program from TestDictIndex, stepping into testfn, and then
running `print mapvar` prints `map[int]main.CustomInt []`, which
matches the behavior under GOEXPERIMENT=nounified. (Also compare that
when ir.Name.DictIndex is *not* set by unified IR, `print mapvar`
instead prints `map[int]go.shape.int []`.)

Fixes #54514.

Change-Id: I90d443945895abfba04dc018f15e00217930091c
Reviewed-on: https://go-review.googlesource.com/c/go/+/424735
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Keith Randall <khr@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
  • Loading branch information
mdempsky committed Aug 18, 2022
1 parent b23d469 commit 07cf24b
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 17 deletions.
17 changes: 13 additions & 4 deletions src/cmd/compile/internal/noder/reader.go
Expand Up @@ -1490,20 +1490,18 @@ func (r *reader) addLocal(name *ir.Name, ctxt ir.Class) {
if name.Sym().Name == dictParamName {
r.dictParam = name
} else {
if ctxt == ir.PAUTO {
if r.synthetic == nil {
r.Sync(pkgbits.SyncAddLocal)
if r.p.SyncMarkers() {
want := r.Int()
if have := len(r.locals); have != want {
base.FatalfAt(name.Pos(), "locals table has desynced")
}
}
r.varDictIndex(name)
}

r.locals = append(r.locals, name)

// TODO(go.dev/issue/54514): Set name.DictIndex for variables of
// derived type and enable cmd/link/internal/ld.TestDictIndex.
}

name.SetUsed(true)
Expand Down Expand Up @@ -3062,6 +3060,17 @@ func (r *reader) rtype0(pos src.XPos) (typ *types.Type, rtype ir.Node) {
return
}

// varDictIndex populates name.DictIndex if name is a derived type.
func (r *reader) varDictIndex(name *ir.Name) {
if r.Bool() {
idx := 1 + r.dict.rtypesOffset() + r.Len()
if int(uint16(idx)) != idx {
base.FatalfAt(name.Pos(), "DictIndex overflow for %v: %v", name, idx)
}
name.DictIndex = uint16(idx)
}
}

func (r *reader) itab(pos src.XPos) (typ *types.Type, typRType ir.Node, iface *types.Type, ifaceRType ir.Node, itab ir.Node) {
if r.Bool() { // derived types
idx := r.Len()
Expand Down
26 changes: 17 additions & 9 deletions src/cmd/compile/internal/noder/writer.go
Expand Up @@ -1090,20 +1090,19 @@ func (w *writer) funcargs(sig *types2.Signature) {

func (w *writer) funcarg(param *types2.Var, result bool) {
if param.Name() != "" || result {
w.addLocal(param, true)
w.addLocal(param)
}
}

// addLocal records the declaration of a new local variable.
func (w *writer) addLocal(obj *types2.Var, isParam bool) {
func (w *writer) addLocal(obj *types2.Var) {
idx := len(w.localsIdx)

if !isParam {
w.Sync(pkgbits.SyncAddLocal)
if w.p.SyncMarkers() {
w.Int(idx)
}
w.Sync(pkgbits.SyncAddLocal)
if w.p.SyncMarkers() {
w.Int(idx)
}
w.varDictIndex(obj)

if w.localsIdx == nil {
w.localsIdx = make(map[*types2.Var]int)
Expand Down Expand Up @@ -1295,7 +1294,7 @@ func (w *writer) assign(expr syntax.Expr) {

// TODO(mdempsky): Minimize locals index size by deferring
// this until the variables actually come into scope.
w.addLocal(obj, false)
w.addLocal(obj)
return
}
}
Expand Down Expand Up @@ -1558,7 +1557,7 @@ func (w *writer) switchStmt(stmt *syntax.SwitchStmt) {

obj := obj.(*types2.Var)
w.typ(obj.Type())
w.addLocal(obj, false)
w.addLocal(obj)
}

w.stmts(clause.Body)
Expand Down Expand Up @@ -2177,6 +2176,15 @@ func (w *writer) rtype(typ types2.Type) {
}
}

// varDictIndex writes out information for populating DictIndex for
// the ir.Name that will represent obj.
func (w *writer) varDictIndex(obj *types2.Var) {
info := w.p.typIdx(obj.Type(), w.dict)
if w.Bool(info.derived) {
w.Len(w.dict.rtypeIdx(info))
}
}

func isUntyped(typ types2.Type) bool {
basic, ok := typ.(*types2.Basic)
return ok && basic.Info()&types2.IsUntyped != 0
Expand Down
4 changes: 0 additions & 4 deletions src/cmd/link/internal/ld/dwarf_test.go
Expand Up @@ -11,7 +11,6 @@ import (
"debug/dwarf"
"debug/pe"
"fmt"
"internal/buildcfg"
"internal/testenv"
"io"
"io/ioutil"
Expand Down Expand Up @@ -1597,9 +1596,6 @@ func TestDictIndex(t *testing.T) {
if runtime.GOOS == "plan9" {
t.Skip("skipping on plan9; no DWARF symbol table in executables")
}
if buildcfg.Experiment.Unified {
t.Skip("GOEXPERIMENT=unified does not emit dictionaries yet")
}
t.Parallel()

const prog = `
Expand Down

0 comments on commit 07cf24b

Please sign in to comment.