die = prototypedies[name]
}
if die == nil {
- log.Fatalf("internal error: DIE generation failed for %s\nprototypedies: %+v", name, prototypedies)
+ log.Fatalf("internal error: DIE generation failed for %s\n", name)
}
return die
}
}
func (d *dwctxt) synthesizemaptypesSwiss(ctxt *Link, die *dwarf.DWDie) {
- hash := walktypedef(d.findprotodie(ctxt, "type:internal/runtime/maps.table"))
- //bucket := walktypedef(d.findprotodie(ctxt, "type:internal/runtime/maps.Map"))
-
- if hash == nil {
- return
- }
+ mapType := walktypedef(d.findprotodie(ctxt, "type:internal/runtime/maps.Map"))
+ tableType := walktypedef(d.findprotodie(ctxt, "type:internal/runtime/maps.table"))
+ tableSliceType := walktypedef(d.findprotodie(ctxt, "type:[]*internal/runtime/maps.table"))
+ groupsReferenceType := walktypedef(d.findprotodie(ctxt, "type:internal/runtime/maps.groupsReference"))
for ; die != nil; die = die.Link {
if die.Abbrev != dwarf.DW_ABRV_MAPTYPE {
continue
}
gotype := loader.Sym(getattr(die, dwarf.DW_AT_type).Data.(dwSym))
- keytype := decodetypeMapKey(d.ldr, d.arch, gotype)
- valtype := decodetypeMapValue(d.ldr, d.arch, gotype)
- //keydata := d.ldr.Data(keytype)
- //valdata := d.ldr.Data(valtype)
- //keysize, valsize := decodetypeSize(d.arch, keydata), decodetypeSize(d.arch, valdata)
- keytype, valtype = d.walksymtypedef(d.defgotype(keytype)), d.walksymtypedef(d.defgotype(valtype))
-
- // compute size info like hashmap.c does.
- //indirectKey, indirectVal := false, false
- //if keysize > abi.SwissMapMaxKeyBytes {
- // keysize = int64(d.arch.PtrSize)
- // indirectKey = true
- //}
- //if valsize > abi.SwissMapMaxElemBytes {
- // valsize = int64(d.arch.PtrSize)
- // indirectVal = true
- //}
- // Construct type to represent an array of BucketSize keys
- // TODO
- keyname := d.nameFromDIESym(keytype)
- //dwhks := d.mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]key", keyname, "", func(dwhk *dwarf.DWDie) {
- // newattr(dwhk, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, abi.SwissMapBucketCount*keysize, 0)
- // t := keytype
- // if indirectKey {
- // t = d.defptrto(keytype)
- // }
- // d.newrefattr(dwhk, dwarf.DW_AT_type, t)
- // fld := d.newdie(dwhk, dwarf.DW_ABRV_ARRAYRANGE, "size")
- // newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, abi.SwissMapBucketCount, 0)
- // d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
- //})
+ keyType := decodetypeMapKey(d.ldr, d.arch, gotype)
+ valType := decodetypeMapValue(d.ldr, d.arch, gotype)
+ groupType := decodetypeMapSwissGroup(d.ldr, d.arch, gotype)
+
+ keyType = d.walksymtypedef(d.defgotype(keyType))
+ valType = d.walksymtypedef(d.defgotype(valType))
+ groupType = d.walksymtypedef(d.defgotype(groupType))
+
+ keyName := d.nameFromDIESym(keyType)
+ valName := d.nameFromDIESym(valType)
+
+ // Construct groupsReference[K,V]
+ dwGroupsReference := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "groupReference", keyName, valName, func(dwh *dwarf.DWDie) {
+ d.copychildren(ctxt, dwh, groupsReferenceType)
+ // data *group[K,V]
+ //
+ // This is actually a pointer to an array
+ // *[lengthMask+1]group[K,V], but the length is
+ // variable, so we can't statically record the length.
+ d.substitutetype(dwh, "data", d.defptrto(groupType))
+ newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(groupsReferenceType, dwarf.DW_AT_byte_size).Value, nil)
+ newattr(dwh, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, int64(abi.Struct), 0)
+ })
- // Construct type to represent an array of BucketSize values
- // TODO
- valname := d.nameFromDIESym(valtype)
- //dwhvs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_ARRAYTYPE, "[]val", valname, "", func(dwhv *dwarf.DWDie) {
- // newattr(dwhv, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, abi.SwissMapBucketCount*valsize, 0)
- // t := valtype
- // if indirectVal {
- // t = d.defptrto(valtype)
- // }
- // d.newrefattr(dwhv, dwarf.DW_AT_type, t)
- // fld := d.newdie(dwhv, dwarf.DW_ABRV_ARRAYRANGE, "size")
- // newattr(fld, dwarf.DW_AT_count, dwarf.DW_CLS_CONSTANT, abi.SwissMapBucketCount, 0)
- // d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
- //})
+ // Construct table[K,V]
+ dwTable := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "table", keyName, valName, func(dwh *dwarf.DWDie) {
+ d.copychildren(ctxt, dwh, tableType)
+ d.substitutetype(dwh, "groups", dwGroupsReference)
+ newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(tableType, dwarf.DW_AT_byte_size).Value, nil)
+ newattr(dwh, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, int64(abi.Struct), 0)
+ })
- // Construct bucket<K,V>
- // TODO
- //dwhbs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "bucket", keyname, valname, func(dwhb *dwarf.DWDie) {
- // // Copy over all fields except the field "data" from the generic
- // // bucket. "data" will be replaced with keys/values below.
- // d.copychildrenexcept(ctxt, dwhb, bucket, findchild(bucket, "data"))
-
- // fld := d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "keys")
- // d.newrefattr(fld, dwarf.DW_AT_type, dwhks)
- // newmemberoffsetattr(fld, abi.SwissMapBucketCount)
- // fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "values")
- // d.newrefattr(fld, dwarf.DW_AT_type, dwhvs)
- // newmemberoffsetattr(fld, abi.SwissMapBucketCount+abi.SwissMapBucketCount*int32(keysize))
- // fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "overflow")
- // d.newrefattr(fld, dwarf.DW_AT_type, d.defptrto(d.dtolsym(dwhb.Sym)))
- // newmemberoffsetattr(fld, abi.SwissMapBucketCount+abi.SwissMapBucketCount*(int32(keysize)+int32(valsize)))
- // if d.arch.RegSize > d.arch.PtrSize {
- // fld = d.newdie(dwhb, dwarf.DW_ABRV_STRUCTFIELD, "pad")
- // d.newrefattr(fld, dwarf.DW_AT_type, d.uintptrInfoSym)
- // newmemberoffsetattr(fld, abi.SwissMapBucketCount+abi.SwissMapBucketCount*(int32(keysize)+int32(valsize))+int32(d.arch.PtrSize))
- // }
-
- // newattr(dwhb, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, abi.SwissMapBucketCount+abi.SwissMapBucketCount*keysize+abi.SwissMapBucketCount*valsize+int64(d.arch.RegSize), 0)
- //})
+ // Construct type to represent []*table[K,V].
+ dwTableSlice := d.mkinternaltype(ctxt, dwarf.DW_ABRV_SLICETYPE, "[]*table", keyName, valName, func(dwh *dwarf.DWDie) {
+ d.copychildren(ctxt, dwh, tableSliceType)
+ d.substitutetype(dwh, "array", d.defptrto(d.defptrto(dwTable)))
+ d.newrefattr(dwh, dwarf.DW_AT_go_elem, d.defptrto(dwTable))
+ newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(tableSliceType, dwarf.DW_AT_byte_size).Value, nil)
+ newattr(dwh, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, int64(abi.Slice), 0)
+ })
- // Construct hash<K,V>
- dwhs := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "hash", keyname, valname, func(dwh *dwarf.DWDie) {
- d.copychildren(ctxt, dwh, hash)
- //d.substitutetype(dwh, "buckets", d.defptrto(dwhbs))
- //d.substitutetype(dwh, "oldbuckets", d.defptrto(dwhbs))
- newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(hash, dwarf.DW_AT_byte_size).Value, nil)
+ // Construct map[K,V]
+ dwMap := d.mkinternaltype(ctxt, dwarf.DW_ABRV_STRUCTTYPE, "map", keyName, valName, func(dwh *dwarf.DWDie) {
+ d.copychildren(ctxt, dwh, mapType)
+ d.substitutetype(dwh, "directory", dwTableSlice)
+ newattr(dwh, dwarf.DW_AT_byte_size, dwarf.DW_CLS_CONSTANT, getattr(mapType, dwarf.DW_AT_byte_size).Value, nil)
+ newattr(dwh, dwarf.DW_AT_go_kind, dwarf.DW_CLS_CONSTANT, int64(abi.Struct), 0)
})
- // make map type a pointer to hash<K,V>
- d.newrefattr(die, dwarf.DW_AT_type, d.defptrto(dwhs))
+ // make map type a pointer to map[K,V]
+ d.newrefattr(die, dwarf.DW_AT_type, d.defptrto(dwMap))
}
}
"type:runtime.hchan": nil,
}
if buildcfg.Experiment.SwissMap {
+ prototypedies["type:internal/runtime/maps.Map"] = nil
prototypedies["type:internal/runtime/maps.table"] = nil
+ prototypedies["type:[]*internal/runtime/maps.table"] = nil
+ prototypedies["type:internal/runtime/maps.groupsReference"] = nil
} else {
prototypedies["type:runtime.hmap"] = nil
prototypedies["type:runtime.bmap"] = nil
yield ('[{0}]'.format(idx), item)
-# TODO(go.dev/issue/54766): Support swisstable maps.
class MapTypePrinter:
"""Pretty print map[K]V types.
return str(self.val.type)
def children(self):
- MapBucketCount = 8 # see internal/abi.go:MapBucketCount
+ fields = [f.name for f in self.val.type.strip_typedefs().target().fields()]
+ if 'buckets' in fields:
+ yield from self.old_map_children()
+ else:
+ yield from self.swiss_map_children()
+
+ def swiss_map_children(self):
+ SwissMapGroupSlots = 8 # see internal/abi:SwissMapGroupSlots
+
+ cnt = 0
+ directory = SliceValue(self.val['directory'])
+ for table in directory:
+ table = table.dereference()
+ groups = table['groups']['data']
+ length = table['groups']['lengthMask'] + 1
+
+ # The linker DWARF generation
+ # (cmd/link/internal/ld.(*dwctxt).synthesizemaptypesSwiss) records
+ # groups.data as a *group[K,V], but it is actually a pointer to
+ # variable length array *[length]group[K,V].
+ #
+ # N.B. array() takes an _inclusive_ upper bound.
+
+ # group[K,V]
+ group_type = groups.type.target()
+ # [length]group[K,V]
+ array_group_type = group_type.array(length-1)
+ # *[length]group[K,V]
+ ptr_array_group_type = array_group_type.pointer()
+ # groups = (*[length]group[K,V])(groups.data)
+ groups = groups.cast(ptr_array_group_type)
+ groups = groups.dereference()
+
+ for i in xrange(length):
+ group = groups[i]
+ ctrl = group['ctrl']
+
+ for i in xrange(SwissMapGroupSlots):
+ c = (ctrl >> (8*i)) & 0xff
+ if (c & 0x80) != 0:
+ # Empty or deleted
+ continue
+
+ # Full
+ yield str(cnt), group['slots'][i]['key']
+ yield str(cnt+1), group['slots'][i]['elem']
+
+
+ def old_map_children(self):
+ MapBucketCount = 8 # see internal/abi:OldMapBucketCount
B = self.val['B']
buckets = self.val['buckets']
oldbuckets = self.val['oldbuckets']
class GoLenFunc(gdb.Function):
"Length of strings, slices, maps or channels"
- how = ((StringTypePrinter, 'len'), (SliceTypePrinter, 'len'), (MapTypePrinter, 'count'), (ChanTypePrinter, 'qcount'))
+ how = ((StringTypePrinter, 'len'), (SliceTypePrinter, 'len'), (MapTypePrinter, 'used'), (ChanTypePrinter, 'qcount'))
def __init__(self):
gdb.Function.__init__(self, "len")
typename = str(obj.type)
for klass, fld in self.how:
if klass.pattern.match(typename) or paramtypematch(obj.type, klass.pattern):
+ if klass == MapTypePrinter:
+ fields = [f.name for f in self.val.type.strip_typedefs().target().fields()]
+ if 'buckets' in fields:
+ # Old maps.
+ fld = 'count'
+
return obj[fld]