remove Elem() optimization

This commit is contained in:
Mateusz Poliwczak 2025-02-12 08:08:49 +01:00
parent 27a902127c
commit 64d2ac5bb2
6 changed files with 23 additions and 54 deletions

View File

@ -415,14 +415,6 @@ var kinds = []abi.Kind{
types.TUNSAFEPTR: abi.UnsafePointer,
}
var elemKinds = []abi.Kind{
abi.Array,
abi.Chan,
abi.Map,
abi.Pointer,
abi.Slice,
}
var (
memhashvarlen *obj.LSym
memequalvarlen *obj.LSym
@ -481,14 +473,6 @@ func dcommontype(c rttype.Cursor, t *types.Type) {
tflag |= abi.TFlagGCMaskOnDemand
}
kind := kinds[t.Kind()]
if slices.Contains(elemKinds, kind) {
tflag |= abi.TFlagHasElem
if kind == abi.Map {
tflag |= abi.TFlagHasElemSecond
}
}
exported := false
p := t.NameString()
// If we're writing out type T,
@ -526,6 +510,7 @@ func dcommontype(c rttype.Cursor, t *types.Type) {
c.Field("Align_").WriteUint8(uint8(t.Alignment()))
c.Field("FieldAlign_").WriteUint8(uint8(t.Alignment()))
kind := kinds[t.Kind()]
if types.IsDirectIface(t) {
kind |= abi.KindDirectIface
}

View File

@ -5,7 +5,6 @@
package abi
import (
"internal/goarch"
"unsafe"
)
@ -126,12 +125,6 @@ const (
// has type **byte instead of *byte. The runtime will store a
// pointer to the GC pointer bitmask in *GCData.
TFlagGCMaskOnDemand TFlag = 1 << 4
// TFlagHasElem signals that the Type has an Elem.
TFlagHasElem TFlag = 1 << 5
// TFlagHasElem signals that the Type has an Elem, but at an PtrBytes higher offset.
TFlagHasElemSecond TFlag = 1 << 6
)
// NameOff is the offset to a name from moduledata.types. See resolveNameOff in runtime.
@ -383,25 +376,24 @@ func (t *Type) Uncommon() *UncommonType {
}
}
// Compile time asserts for (*Type).Elem().
func _() {
const _, _ = unsafe.Offsetof(ChanType{}.Elem) - baseElemOffset, baseElemOffset - unsafe.Offsetof(ChanType{}.Elem)
const _, _ = unsafe.Offsetof(mapType{}.Elem) - baseElemOffset + goarch.PtrSize, baseElemOffset + goarch.PtrSize - unsafe.Offsetof(mapType{}.Elem)
const _, _ = unsafe.Offsetof(PtrType{}.Elem) - baseElemOffset, baseElemOffset - unsafe.Offsetof(PtrType{}.Elem)
const _, _ = unsafe.Offsetof(SliceType{}.Elem) - baseElemOffset, baseElemOffset - unsafe.Offsetof(SliceType{}.Elem)
var _, _, _, _, _ *Type = ArrayType{}.Elem, ChanType{}.Elem, mapType{}.Elem, PtrType{}.Elem, SliceType{}.Elem
}
const baseElemOffset = unsafe.Offsetof(ArrayType{}.Elem)
// Elem returns the element type for t if t is an array, channel, map, pointer, or slice, otherwise nil.
func (t *Type) Elem() *Type {
if t.TFlag&TFlagHasElem != 0 {
// Unfortunately, the mapType does not have the Elem field at the same offset as other
// types do, it is PtrBytes ahead. So we have to calculate the offset based on TFlagHasElemSecond flag.
// Currently we can't really change the definition of mapType to reorder these fields,
// because mapType is referenced with linknames from other modules (non-std).
return *(**Type)(unsafe.Add(unsafe.Pointer(t), baseElemOffset+(goarch.PtrSize*uintptr((t.TFlag&TFlagHasElemSecond)>>6))))
switch t.Kind() {
case Array:
tt := (*ArrayType)(unsafe.Pointer(t))
return tt.Elem
case Chan:
tt := (*ChanType)(unsafe.Pointer(t))
return tt.Elem
case Map:
tt := (*mapType)(unsafe.Pointer(t))
return tt.Elem
case Pointer:
tt := (*PtrType)(unsafe.Pointer(t))
return tt.Elem
case Slice:
tt := (*SliceType)(unsafe.Pointer(t))
return tt.Elem
}
return nil
}

View File

@ -69,7 +69,7 @@ func MapOf(key, elem Type) Type {
var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil)
mt := **(**mapType)(unsafe.Pointer(&imap))
mt.Str = resolveReflectName(newName(s, "", false, false))
mt.TFlag = abi.TFlagHasElem | abi.TFlagHasElemSecond
mt.TFlag = 0
mt.Hash = fnv1(etyp.Hash, 'm', byte(ktyp.Hash>>24), byte(ktyp.Hash>>16), byte(ktyp.Hash>>8), byte(ktyp.Hash))
mt.Key = ktyp
mt.Elem = etyp

View File

@ -65,7 +65,7 @@ func MapOf(key, elem Type) Type {
var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil)
mt := **(**mapType)(unsafe.Pointer(&imap))
mt.Str = resolveReflectName(newName(s, "", false, false))
mt.TFlag = abi.TFlagHasElem | abi.TFlagHasElemSecond
mt.TFlag = 0
mt.Hash = fnv1(etyp.Hash, 'm', byte(ktyp.Hash>>24), byte(ktyp.Hash>>16), byte(ktyp.Hash>>8), byte(ktyp.Hash))
mt.Key = ktyp
mt.Elem = etyp

View File

@ -1361,7 +1361,6 @@ func (t *rtype) ptrTo() *abi.Type {
pp.Str = resolveReflectName(newName(s, "", false, false))
pp.PtrToThis = 0
pp.TFlag = abi.TFlagHasElem
// For the type structures linked into the binary, the
// compiler provides a good hash of the string.
@ -2086,7 +2085,7 @@ func SliceOf(t Type) Type {
var islice any = ([]unsafe.Pointer)(nil)
prototype := *(**sliceType)(unsafe.Pointer(&islice))
slice := *prototype
slice.TFlag = abi.TFlagHasElem
slice.TFlag = 0
slice.Str = resolveReflectName(newName(s, "", false, false))
slice.Hash = fnv1(typ.Hash, '[')
slice.Elem = typ
@ -2472,9 +2471,9 @@ func StructOf(fields []StructField) Type {
typ.Str = resolveReflectName(newName(str, "", false, false))
if isRegularMemory(toType(&typ.Type)) {
typ.TFlag = abi.TFlagRegularMemory & abi.TFlagHasElem
typ.TFlag = abi.TFlagRegularMemory
} else {
typ.TFlag = abi.TFlagHasElem
typ.TFlag = 0
}
typ.Hash = hash
typ.Size_ = size
@ -2612,7 +2611,7 @@ func ArrayOf(length int, elem Type) Type {
var iarray any = [1]unsafe.Pointer{}
prototype := *(**arrayType)(unsafe.Pointer(&iarray))
array := *prototype
array.TFlag = (typ.TFlag & abi.TFlagRegularMemory) | abi.TFlagHasElem
array.TFlag = typ.TFlag & abi.TFlagRegularMemory
array.Str = resolveReflectName(newName(s, "", false, false))
array.Hash = fnv1(typ.Hash, '[')
for n := uint32(length); n > 0; n >>= 8 {

View File

@ -118,13 +118,6 @@ func BenchmarkTypeForError(b *testing.B) {
}
}
func BenchmarkSliceTypeElem(b *testing.B) {
slice := reflect.TypeFor[[]int]()
for i := 0; i < b.N; i++ {
sinkType = slice.Elem()
}
}
func TestType_CanSeq(t *testing.T) {
tests := []struct {
name string