| | |
| | |
| | |
| |
|
| | package reflectdata |
| |
|
| | import ( |
| | "cmd/compile/internal/base" |
| | "cmd/compile/internal/ir" |
| | "cmd/compile/internal/rttype" |
| | "cmd/compile/internal/types" |
| | "cmd/internal/obj" |
| | "cmd/internal/objabi" |
| | "cmd/internal/src" |
| | "internal/abi" |
| | ) |
| |
|
| | |
| | func MapGroupType(t *types.Type) *types.Type { |
| | if t.MapType().Group != nil { |
| | return t.MapType().Group |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | keytype := t.Key() |
| | elemtype := t.Elem() |
| | types.CalcSize(keytype) |
| | types.CalcSize(elemtype) |
| | if keytype.Size() > abi.MapMaxKeyBytes { |
| | keytype = types.NewPtr(keytype) |
| | } |
| | if elemtype.Size() > abi.MapMaxElemBytes { |
| | elemtype = types.NewPtr(elemtype) |
| | } |
| |
|
| | slotFields := []*types.Field{ |
| | makefield("key", keytype), |
| | makefield("elem", elemtype), |
| | } |
| | slot := types.NewStruct(slotFields) |
| | slot.SetNoalg(true) |
| |
|
| | slotArr := types.NewArray(slot, abi.MapGroupSlots) |
| | slotArr.SetNoalg(true) |
| |
|
| | fields := []*types.Field{ |
| | makefield("ctrl", types.Types[types.TUINT64]), |
| | makefield("slots", slotArr), |
| | } |
| |
|
| | group := types.NewStruct(fields) |
| | group.SetNoalg(true) |
| | types.CalcSize(group) |
| |
|
| | |
| | if !types.IsComparable(t.Key()) { |
| | base.Fatalf("unsupported map key type for %v", t) |
| | } |
| | if group.Size() <= 8 { |
| | |
| | |
| | |
| | |
| | base.Fatalf("bad group size for %v", t) |
| | } |
| | if t.Key().Size() > abi.MapMaxKeyBytes && !keytype.IsPtr() { |
| | base.Fatalf("key indirect incorrect for %v", t) |
| | } |
| | if t.Elem().Size() > abi.MapMaxElemBytes && !elemtype.IsPtr() { |
| | base.Fatalf("elem indirect incorrect for %v", t) |
| | } |
| |
|
| | t.MapType().Group = group |
| | group.StructType().Map = t |
| | return group |
| | } |
| |
|
| | var cachedMapTableType *types.Type |
| |
|
| | |
| | |
| | func mapTableType() *types.Type { |
| | if cachedMapTableType != nil { |
| | return cachedMapTableType |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | fields := []*types.Field{ |
| | makefield("used", types.Types[types.TUINT16]), |
| | makefield("capacity", types.Types[types.TUINT16]), |
| | makefield("growthLeft", types.Types[types.TUINT16]), |
| | makefield("localDepth", types.Types[types.TUINT8]), |
| | makefield("index", types.Types[types.TINT]), |
| | makefield("groups_data", types.Types[types.TUNSAFEPTR]), |
| | makefield("groups_lengthMask", types.Types[types.TUINT64]), |
| | } |
| |
|
| | n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, ir.Pkgs.InternalMaps.Lookup("table")) |
| | table := types.NewNamed(n) |
| | n.SetType(table) |
| | n.SetTypecheck(1) |
| |
|
| | table.SetUnderlying(types.NewStruct(fields)) |
| | types.CalcSize(table) |
| |
|
| | |
| | |
| | if size := int64(3*2 + 2*1 + 1*8 + 2*types.PtrSize); table.Size() != size { |
| | base.Fatalf("internal/runtime/maps.table size not correct: got %d, want %d", table.Size(), size) |
| | } |
| |
|
| | cachedMapTableType = table |
| | return table |
| | } |
| |
|
| | var cachedMapType *types.Type |
| |
|
| | |
| | |
| | func MapType() *types.Type { |
| | if cachedMapType != nil { |
| | return cachedMapType |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | fields := []*types.Field{ |
| | makefield("used", types.Types[types.TUINT64]), |
| | makefield("seed", types.Types[types.TUINTPTR]), |
| | makefield("dirPtr", types.Types[types.TUNSAFEPTR]), |
| | makefield("dirLen", types.Types[types.TINT]), |
| | makefield("globalDepth", types.Types[types.TUINT8]), |
| | makefield("globalShift", types.Types[types.TUINT8]), |
| | makefield("writing", types.Types[types.TUINT8]), |
| | makefield("tombstonePossible", types.Types[types.TBOOL]), |
| | makefield("clearSeq", types.Types[types.TUINT64]), |
| | } |
| |
|
| | n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, ir.Pkgs.InternalMaps.Lookup("Map")) |
| | m := types.NewNamed(n) |
| | n.SetType(m) |
| | n.SetTypecheck(1) |
| |
|
| | m.SetUnderlying(types.NewStruct(fields)) |
| | types.CalcSize(m) |
| |
|
| | |
| | |
| | if size := int64(2*8 + 4*types.PtrSize ); m.Size() != size { |
| | base.Fatalf("internal/runtime/maps.Map size not correct: got %d, want %d", m.Size(), size) |
| | } |
| |
|
| | cachedMapType = m |
| | return m |
| | } |
| |
|
| | var cachedMapIterType *types.Type |
| |
|
| | |
| | |
| | func MapIterType() *types.Type { |
| | if cachedMapIterType != nil { |
| | return cachedMapIterType |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | fields := []*types.Field{ |
| | makefield("key", types.Types[types.TUNSAFEPTR]), |
| | makefield("elem", types.Types[types.TUNSAFEPTR]), |
| | makefield("typ", types.Types[types.TUNSAFEPTR]), |
| | makefield("m", types.NewPtr(MapType())), |
| | makefield("groupSlotOffset", types.Types[types.TUINT64]), |
| | makefield("dirOffset", types.Types[types.TUINT64]), |
| | makefield("clearSeq", types.Types[types.TUINT64]), |
| | makefield("globalDepth", types.Types[types.TUINT8]), |
| | makefield("dirIdx", types.Types[types.TINT]), |
| | makefield("tab", types.NewPtr(mapTableType())), |
| | makefield("group", types.Types[types.TUNSAFEPTR]), |
| | makefield("entryIdx", types.Types[types.TUINT64]), |
| | } |
| |
|
| | |
| | n := ir.NewDeclNameAt(src.NoXPos, ir.OTYPE, ir.Pkgs.InternalMaps.Lookup("Iter")) |
| | iter := types.NewNamed(n) |
| | n.SetType(iter) |
| | n.SetTypecheck(1) |
| |
|
| | iter.SetUnderlying(types.NewStruct(fields)) |
| | types.CalcSize(iter) |
| |
|
| | |
| | |
| | if size := 8*types.PtrSize + 4*8; iter.Size() != int64(size) { |
| | base.Fatalf("internal/runtime/maps.Iter size not correct: got %d, want %d", iter.Size(), size) |
| | } |
| |
|
| | cachedMapIterType = iter |
| | return iter |
| | } |
| |
|
| | func writeMapType(t *types.Type, lsym *obj.LSym, c rttype.Cursor) { |
| | |
| | gtyp := MapGroupType(t) |
| | s1 := writeType(t.Key()) |
| | s2 := writeType(t.Elem()) |
| | s3 := writeType(gtyp) |
| | hasher := genhash(t.Key()) |
| |
|
| | slotTyp := gtyp.Field(1).Type.Elem() |
| | elemOff := slotTyp.Field(1).Offset |
| | if AlgType(t.Key()) == types.AMEM64 && elemOff != 8 { |
| | base.Fatalf("runtime assumes elemOff for 8-byte keys is 8, got %d", elemOff) |
| | } |
| | if AlgType(t.Key()) == types.ASTRING && elemOff != int64(2*types.PtrSize) { |
| | base.Fatalf("runtime assumes elemOff for string keys is %d, got %d", 2*types.PtrSize, elemOff) |
| | } |
| |
|
| | c.Field("Key").WritePtr(s1) |
| | c.Field("Elem").WritePtr(s2) |
| | c.Field("Group").WritePtr(s3) |
| | c.Field("Hasher").WritePtr(hasher) |
| | c.Field("GroupSize").WriteUintptr(uint64(gtyp.Size())) |
| | c.Field("SlotSize").WriteUintptr(uint64(slotTyp.Size())) |
| | c.Field("ElemOff").WriteUintptr(uint64(elemOff)) |
| | var flags uint32 |
| | if needkeyupdate(t.Key()) { |
| | flags |= abi.MapNeedKeyUpdate |
| | } |
| | if hashMightPanic(t.Key()) { |
| | flags |= abi.MapHashMightPanic |
| | } |
| | if t.Key().Size() > abi.MapMaxKeyBytes { |
| | flags |= abi.MapIndirectKey |
| | } |
| | if t.Elem().Size() > abi.MapMaxKeyBytes { |
| | flags |= abi.MapIndirectElem |
| | } |
| | c.Field("Flags").WriteUint32(flags) |
| |
|
| | if u := t.Underlying(); u != t { |
| | |
| | |
| | |
| | |
| | lsym.AddRel(base.Ctxt, obj.Reloc{Type: objabi.R_KEEP, Sym: writeType(u)}) |
| | } |
| | } |
| |
|