mirror of
https://github.com/golang/go
synced 2024-11-26 00:28:00 -07:00
internal/runtime/maps: don't copy indirect key/elem when growing maps
We can reuse the same indirect storage when growing, so we don't need an additional allocation. Change-Id: I57adb406becfbec648188ec66f4bb2e94d4b9cab Reviewed-on: https://go-review.googlesource.com/c/go/+/625902 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
parent
bcdaac6396
commit
d4b0bd28ee
@ -621,13 +621,7 @@ func (m *Map) growToTable(typ *abi.SwissMapType) {
|
|||||||
|
|
||||||
hash := typ.Hasher(key, m.seed)
|
hash := typ.Hasher(key, m.seed)
|
||||||
|
|
||||||
// TODO(prattmic): For indirect key/elem, this is
|
tab.uncheckedPutSlot(typ, hash, key, elem)
|
||||||
// allocating new objects for key/elem. That is
|
|
||||||
// unnecessary; the new table could simply point to the
|
|
||||||
// existing object.
|
|
||||||
slotElem := tab.uncheckedPutSlot(typ, hash, key)
|
|
||||||
typedmemmove(typ.Elem, slotElem, elem)
|
|
||||||
tab.used++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
directory := make([]*table, 1)
|
directory := make([]*table, 1)
|
||||||
|
@ -357,20 +357,23 @@ func (t *table) PutSlot(typ *abi.SwissMapType, m *Map, hash uintptr, key unsafe.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// uncheckedPutSlot inserts an entry known not to be in the table, returning an
|
// uncheckedPutSlot inserts an entry known not to be in the table.
|
||||||
// entry to the element slot where the element should be written. Used by
|
// This is used for grow/split where we are making a new table from
|
||||||
// PutSlot after it has failed to find an existing entry to overwrite duration
|
// entries in an existing table.
|
||||||
// insertion.
|
|
||||||
//
|
//
|
||||||
// Updates growthLeft if necessary, but does not update used.
|
// Decrements growthLeft and increments used.
|
||||||
//
|
//
|
||||||
// Requires that the entry does not exist in the table, and that the table has
|
// Requires that the entry does not exist in the table, and that the table has
|
||||||
// room for another element without rehashing.
|
// room for another element without rehashing.
|
||||||
//
|
//
|
||||||
// Requires that there are no deleted entries in the table.
|
// Requires that there are no deleted entries in the table.
|
||||||
//
|
//
|
||||||
// Never returns nil.
|
// For indirect keys and/or elements, the key and elem pointers can be
|
||||||
func (t *table) uncheckedPutSlot(typ *abi.SwissMapType, hash uintptr, key unsafe.Pointer) unsafe.Pointer {
|
// put directly into the map, they do not need to be copied. This
|
||||||
|
// requires the caller to ensure that the referenced memory never
|
||||||
|
// changes (by sourcing those pointers from another indirect key/elem
|
||||||
|
// map).
|
||||||
|
func (t *table) uncheckedPutSlot(typ *abi.SwissMapType, hash uintptr, key, elem unsafe.Pointer) {
|
||||||
if t.growthLeft == 0 {
|
if t.growthLeft == 0 {
|
||||||
panic("invariant failed: growthLeft is unexpectedly 0")
|
panic("invariant failed: growthLeft is unexpectedly 0")
|
||||||
}
|
}
|
||||||
@ -389,22 +392,22 @@ func (t *table) uncheckedPutSlot(typ *abi.SwissMapType, hash uintptr, key unsafe
|
|||||||
|
|
||||||
slotKey := g.key(typ, i)
|
slotKey := g.key(typ, i)
|
||||||
if typ.IndirectKey() {
|
if typ.IndirectKey() {
|
||||||
kmem := newobject(typ.Key)
|
*(*unsafe.Pointer)(slotKey) = key
|
||||||
*(*unsafe.Pointer)(slotKey) = kmem
|
} else {
|
||||||
slotKey = kmem
|
|
||||||
}
|
|
||||||
typedmemmove(typ.Key, slotKey, key)
|
typedmemmove(typ.Key, slotKey, key)
|
||||||
|
}
|
||||||
|
|
||||||
slotElem := g.elem(typ, i)
|
slotElem := g.elem(typ, i)
|
||||||
if typ.IndirectElem() {
|
if typ.IndirectElem() {
|
||||||
emem := newobject(typ.Elem)
|
*(*unsafe.Pointer)(slotElem) = elem
|
||||||
*(*unsafe.Pointer)(slotElem) = emem
|
} else {
|
||||||
slotElem = emem
|
typedmemmove(typ.Elem, slotElem, elem)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.growthLeft--
|
t.growthLeft--
|
||||||
|
t.used++
|
||||||
g.ctrls().set(i, ctrl(h2(hash)))
|
g.ctrls().set(i, ctrl(h2(hash)))
|
||||||
return slotElem
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1073,13 +1076,7 @@ func (t *table) split(typ *abi.SwissMapType, m *Map) {
|
|||||||
} else {
|
} else {
|
||||||
newTable = right
|
newTable = right
|
||||||
}
|
}
|
||||||
// TODO(prattmic): For indirect key/elem, this is
|
newTable.uncheckedPutSlot(typ, hash, key, elem)
|
||||||
// allocating new objects for key/elem. That is
|
|
||||||
// unnecessary; the new table could simply point to the
|
|
||||||
// existing object.
|
|
||||||
slotElem := newTable.uncheckedPutSlot(typ, hash, key)
|
|
||||||
typedmemmove(typ.Elem, slotElem, elem)
|
|
||||||
newTable.used++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1115,13 +1112,7 @@ func (t *table) grow(typ *abi.SwissMapType, m *Map, newCapacity uint16) {
|
|||||||
|
|
||||||
hash := typ.Hasher(key, m.seed)
|
hash := typ.Hasher(key, m.seed)
|
||||||
|
|
||||||
// TODO(prattmic): For indirect key/elem, this is
|
newTable.uncheckedPutSlot(typ, hash, key, elem)
|
||||||
// allocating new objects for key/elem. That is
|
|
||||||
// unnecessary; the new table could simply point to the
|
|
||||||
// existing object.
|
|
||||||
slotElem := newTable.uncheckedPutSlot(typ, hash, key)
|
|
||||||
typedmemmove(typ.Elem, slotElem, elem)
|
|
||||||
newTable.used++
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user