Skip to content

Commit 477e46e

Browse files
authored
pkg/proc: support swiss table map implementation (#3838)
Adds support for the swiss table implementation for Go's maps.
1 parent 698f838 commit 477e46e

File tree

8 files changed

+760
-307
lines changed

8 files changed

+760
-307
lines changed

_fixtures/testvariables2.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ type astruct struct {
3434
B int
3535
}
3636

37+
type largestruct struct {
38+
name string
39+
v [256]byte
40+
}
41+
3742
type astructName1 astruct
3843
type astructName2 astruct
3944

@@ -267,6 +272,7 @@ func main() {
267272
m2 := map[int]*astruct{1: &astruct{10, 11}}
268273
m3 := map[astruct]int{{1, 1}: 42, {2, 2}: 43}
269274
m4 := map[astruct]astruct{{1, 1}: {11, 11}, {2, 2}: {22, 22}}
275+
mlarge := map[largestruct]largestruct{largestruct{name: "one"}: largestruct{name: "oneval"}}
270276
upnil := unsafe.Pointer(nil)
271277
up1 := unsafe.Pointer(&i1)
272278
i4 := 800
@@ -427,5 +433,5 @@ func main() {
427433
longslice := make([]int, 100, 100)
428434

429435
runtime.Breakpoint()
430-
fmt.Println(i1, i2, i3, p1, pp1, amb1, s1, s3, a0, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, m4, m5, upnil, up1, i4, i5, i6, err1, err2, errnil, iface1, iface2, ifacenil, arr1, parr, cpx1, const1, iface3, iface4, recursive1, recursive1.x, iface5, iface2fn1, iface2fn2, bencharr, benchparr, mapinf, mainMenu, b, b2, sd, anonstruct1, anonstruct2, anoniface1, anonfunc, mapanonstruct1, ifacearr, efacearr, ni8, ni16, ni32, ni64, pinf, ninf, nan, zsvmap, zsslice, zsvar, tm, rettm, errtypednil, emptyslice, emptymap, byteslice, bytestypeslice, runeslice, bytearray, bytetypearray, runearray, longstr, nilstruct, as2, as2.NonPointerReceiverMethod, s4, iface2map, issue1578, ll, unread, w2, w3, w4, w5, longarr, longslice, val, m6, m7, cl, tim1, tim2, typedstringvar, namedA1, namedA2, astructName1(namedA2), badslice, tim3, int3chan, longbyteslice, enum1, enum2, enum3, enum4, enum5, enum6, zeropoint4)
436+
fmt.Println(i1, i2, i3, p1, pp1, amb1, s1, s3, a0, a1, p2, p3, s2, as1, str1, f1, fn1, fn2, nilslice, nilptr, ch1, chnil, m1, mnil, m2, m3, m4, m5, upnil, up1, i4, i5, i6, err1, err2, errnil, iface1, iface2, ifacenil, arr1, parr, cpx1, const1, iface3, iface4, recursive1, recursive1.x, iface5, iface2fn1, iface2fn2, bencharr, benchparr, mapinf, mainMenu, b, b2, sd, anonstruct1, anonstruct2, anoniface1, anonfunc, mapanonstruct1, ifacearr, efacearr, ni8, ni16, ni32, ni64, pinf, ninf, nan, zsvmap, zsslice, zsvar, tm, rettm, errtypednil, emptyslice, emptymap, byteslice, bytestypeslice, runeslice, bytearray, bytetypearray, runearray, longstr, nilstruct, as2, as2.NonPointerReceiverMethod, s4, iface2map, issue1578, ll, unread, w2, w3, w4, w5, longarr, longslice, val, m6, m7, cl, tim1, tim2, typedstringvar, namedA1, namedA2, astructName1(namedA2), badslice, tim3, int3chan, longbyteslice, enum1, enum2, enum3, enum4, enum5, enum6, zeropoint4, mlarge)
431437
}

_scripts/rtype-out.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ const emptyOne = 1
6363

6464
const emptyRest = 0
6565

66+
const internal/runtime/maps.ctrlEmpty = 128
67+
6668
const kindDirectIface|internal/abi.KindDirectIface = 32
6769

6870
const kindGCProg|internal/abi.KindGCProg = 64

_scripts/rtype.go

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@
5656
// - a type defined in the runtime package, without the 'runtime.' prefix
5757
// - anytype to match all possible types
5858
// - an expression of the form T1|T2 where both T1 and T2 can be arbitrary type expressions
59+
//
60+
// GO VERSION RESTRICTIONS
61+
//
62+
// A rtype comment of this form:
63+
//
64+
// // +rtype go1.24 ...
65+
//
66+
// Will only be applied to versions of Go following version 1.24.0
5967

6068
package main
6169

@@ -70,6 +78,7 @@ import (
7078
"log"
7179
"os"
7280
"path/filepath"
81+
"runtime"
7382
"sort"
7483
"strconv"
7584
"strings"
@@ -78,6 +87,7 @@ import (
7887
)
7988

8089
const magicCommentPrefix = "+rtype"
90+
const gover = "go1."
8191

8292
var fset = &token.FileSet{}
8393
var checkVarTypeRules = []*checkVarType{}
@@ -97,6 +107,7 @@ type rtypeCmnt struct {
97107
type checkVarType struct {
98108
V, T string // V must have type T
99109
pos token.Pos
110+
firstMinor
100111
}
101112

102113
func (c *checkVarType) String() string {
@@ -111,6 +122,7 @@ type checkFieldType struct {
111122
S, F, T string // S.F must have type T
112123
opt bool
113124
pos token.Pos
125+
firstMinor
114126
}
115127

116128
func (c *checkFieldType) String() string {
@@ -122,6 +134,13 @@ type checkConstVal struct {
122134
C string // const C = V
123135
V constant.Value
124136
pos token.Pos
137+
firstMinor
138+
}
139+
140+
type firstMinor int
141+
142+
func (firstMinor firstMinor) versionOk(curminor int) bool {
143+
return curminor >= int(firstMinor)
125144
}
126145

127146
func (c *checkConstVal) String() string {
@@ -255,31 +274,38 @@ func process(pkg *packages.Package, rtcmnt *rtypeCmnt, cmntmap ast.CommentMap, r
255274
tinfo := pkg.TypesInfo
256275
fields := strings.Split(rtcmnt.txt, " ")
257276

277+
firstMinor := 0
278+
279+
if strings.HasPrefix(fields[1], gover) {
280+
firstMinor, _ = strconv.Atoi(fields[1][len(gover):])
281+
fields = fields[1:]
282+
}
283+
258284
switch fields[1] {
259285
case "-var":
260286
// -var V T
261287
// requests that variable V is of type T
262-
addCheckVarType(fields[2], fields[3], rtcmnt.slash)
288+
addCheckVarType(fields[2], fields[3], rtcmnt.slash, firstMinor)
263289
case "-field":
264290
// -field S.F T
265291
// requests that field F of type S is of type T
266292
v := strings.Split(fields[2], ".")
267-
addCheckFieldType(v[0], v[1], fields[3], false, rtcmnt.slash)
293+
addCheckFieldType(v[0], v[1], fields[3], false, rtcmnt.slash, firstMinor)
268294
default:
269295
ok := false
270296
if ident := isProcVariableDecl(rtcmnt.stmt, tinfo); ident != nil {
271297
if len(fields) == 2 {
272-
processProcVariableUses(rtcmnt.toplevel, tinfo, ident, cmntmap, rtcmnts, fields[1])
298+
processProcVariableUses(rtcmnt.toplevel, tinfo, ident, cmntmap, rtcmnts, fields[1], firstMinor)
273299
ok = true
274300
} else if len(fields) == 3 && fields[1] == "-opt" {
275-
processProcVariableUses(rtcmnt.toplevel, tinfo, ident, cmntmap, rtcmnts, fields[2])
301+
processProcVariableUses(rtcmnt.toplevel, tinfo, ident, cmntmap, rtcmnts, fields[2], firstMinor)
276302
ok = true
277303
}
278304
} else if ident := isConstDecl(rtcmnt.toplevel, rtcmnt.node); len(fields) == 2 && ident != nil {
279-
addCheckConstVal(fields[1], constValue(tinfo.Defs[ident]), rtcmnt.slash)
305+
addCheckConstVal(fields[1], constValue(tinfo.Defs[ident]), rtcmnt.slash, firstMinor)
280306
ok = true
281307
} else if F := isStringCaseClause(rtcmnt.stmt); F != "" && len(fields) == 4 && fields[1] == "-fieldof" {
282-
addCheckFieldType(fields[2], F, fields[3], false, rtcmnt.slash)
308+
addCheckFieldType(fields[2], F, fields[3], false, rtcmnt.slash, firstMinor)
283309
ok = true
284310
}
285311
if !ok {
@@ -359,7 +385,7 @@ func isStringCaseClause(stmt ast.Stmt) string {
359385
// processProcVariableUses scans the body of the function declaration 'decl'
360386
// looking for uses of 'procVarIdent' which is assumed to be an identifier
361387
// for a *proc.Variable variable.
362-
func processProcVariableUses(decl ast.Node, tinfo *types.Info, procVarIdent *ast.Ident, cmntmap ast.CommentMap, rtcmnts []*rtypeCmnt, S string) {
388+
func processProcVariableUses(decl ast.Node, tinfo *types.Info, procVarIdent *ast.Ident, cmntmap ast.CommentMap, rtcmnts []*rtypeCmnt, S string, firstMinor int) {
363389
if len(S) > 0 && S[0] == '*' {
364390
S = S[1:]
365391
}
@@ -435,7 +461,7 @@ func processProcVariableUses(decl ast.Node, tinfo *types.Info, procVarIdent *ast
435461
}
436462
}
437463
F, _ := strconv.Unquote(arg0.Value)
438-
addCheckFieldType(S, F, typ, opt, fncall.Pos())
464+
addCheckFieldType(S, F, typ, opt, fncall.Pos(), firstMinor)
439465
//printNode(fset, fncall)
440466
default:
441467
pos := fset.Position(n.Pos())
@@ -454,18 +480,18 @@ func findComment(slash token.Pos, rtcmnts []*rtypeCmnt) int {
454480
return -1
455481
}
456482

457-
func addCheckVarType(V, T string, pos token.Pos) {
458-
checkVarTypeRules = append(checkVarTypeRules, &checkVarType{V, T, pos})
483+
func addCheckVarType(V, T string, pos token.Pos, firstMinor_ int) {
484+
checkVarTypeRules = append(checkVarTypeRules, &checkVarType{V, T, pos, firstMinor(firstMinor_)})
459485
}
460486

461-
func addCheckFieldType(S, F, T string, opt bool, pos token.Pos) {
487+
func addCheckFieldType(S, F, T string, opt bool, pos token.Pos, firstMinor_ int) {
462488
if !strings.Contains(S, "|") {
463-
checkFieldTypeRules[S] = append(checkFieldTypeRules[S], &checkFieldType{S, F, T, opt, pos})
489+
checkFieldTypeRules[S] = append(checkFieldTypeRules[S], &checkFieldType{S, F, T, opt, pos, firstMinor(firstMinor_)})
464490
}
465491
}
466492

467-
func addCheckConstVal(C string, V constant.Value, pos token.Pos) {
468-
checkConstValRules[C] = append(checkConstValRules[C], &checkConstVal{C, V, pos})
493+
func addCheckConstVal(C string, V constant.Value, pos token.Pos, firstMinor_ int) {
494+
checkConstValRules[C] = append(checkConstValRules[C], &checkConstVal{C, V, pos, firstMinor(firstMinor_)})
469495
}
470496

471497
// report writes a report of all rules derived from the proc package to stdout.
@@ -548,7 +574,7 @@ func check() {
548574
pkgmap := map[string]*packages.Package{}
549575
allok := true
550576

551-
for _, rule := range checkVarTypeRules {
577+
for _, rule := range versionOkFilter(checkVarTypeRules) {
552578
pos := fset.Position(rule.pos)
553579
def := lookupPackage(pkgmap, "runtime").Types.Scope().Lookup(rule.V)
554580
if def == nil {
@@ -569,7 +595,10 @@ func check() {
569595
}
570596
sort.Strings(Ss)
571597
for _, S := range Ss {
572-
rules := checkFieldTypeRules[S]
598+
rules := versionOkFilter(checkFieldTypeRules[S])
599+
if len(rules) == 0 {
600+
continue
601+
}
573602
pos := fset.Position(rules[0].pos)
574603

575604
def := lookupTypeDef(pkgmap, S)
@@ -617,7 +646,10 @@ func check() {
617646
}
618647
sort.Strings(Cs)
619648
for _, C := range Cs {
620-
rules := checkConstValRules[C]
649+
rules := versionOkFilter(checkConstValRules[C])
650+
if len(rules) == 0 {
651+
continue
652+
}
621653
pos := fset.Position(rules[0].pos)
622654
def := findConst(pkgmap, C)
623655
if def == nil {
@@ -716,3 +748,14 @@ func relative(s string) string {
716748
}
717749
return r
718750
}
751+
752+
func versionOkFilter[T interface{ versionOk(int) bool }](rules []T) []T {
753+
curminor, _ := strconv.Atoi(strings.Split(runtime.Version()[len(gover):], ".")[0])
754+
r := []T{}
755+
for _, rule := range rules {
756+
if rule.versionOk(curminor) {
757+
rules = append(rules, rule)
758+
}
759+
}
760+
return r
761+
}

cmd/dlv/dlv_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,9 @@ func qf(*types.Package) string {
467467
}
468468

469469
func TestTypecheckRPC(t *testing.T) {
470+
if goversion.VersionAfterOrEqual(runtime.Version(), 1, 24) {
471+
t.Skip("disabled due to export format changes")
472+
}
470473
fset := &token.FileSet{}
471474
cfg := &packages.Config{
472475
Mode: packages.NeedSyntax | packages.NeedTypesInfo | packages.NeedName | packages.NeedCompiledGoFiles | packages.NeedTypes,
@@ -1349,6 +1352,9 @@ func TestVersion(t *testing.T) {
13491352
}
13501353

13511354
func TestStaticcheck(t *testing.T) {
1355+
if goversion.VersionAfterOrEqual(runtime.Version(), 1, 24) {
1356+
t.Skip("disabled due to export format changes")
1357+
}
13521358
_, err := exec.LookPath("staticcheck")
13531359
if err != nil {
13541360
t.Skip("staticcheck not installed")

pkg/proc/eval.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1840,7 +1840,7 @@ func lenBuiltin(args []*Variable, nodeargs []ast.Expr) (*Variable, error) {
18401840
}
18411841
return newConstant(arg.Children[0].Value, arg.mem), nil
18421842
case reflect.Map:
1843-
it := arg.mapIterator()
1843+
it := arg.mapIterator(0)
18441844
if arg.Unreadable != nil {
18451845
return nil, arg.Unreadable
18461846
}
@@ -2152,7 +2152,7 @@ func (scope *EvalScope) evalReslice(op *evalop.Reslice, stack *evalStack) {
21522152
return
21532153
}
21542154
xev.mapSkip += int(low)
2155-
xev.mapIterator() // reads map length
2155+
xev.mapIterator(0) // reads map length
21562156
if int64(xev.mapSkip) >= xev.Len {
21572157
stack.err = errors.New("map index out of bounds")
21582158
return
@@ -2755,7 +2755,7 @@ func (v *Variable) sliceAccess(idx int) (*Variable, error) {
27552755
}
27562756

27572757
func (v *Variable) mapAccess(idx *Variable) (*Variable, error) {
2758-
it := v.mapIterator()
2758+
it := v.mapIterator(0)
27592759
if it == nil {
27602760
return nil, fmt.Errorf("can not access unreadable map: %v", v.Unreadable)
27612761
}

0 commit comments

Comments
 (0)