From be32f4072eddcff9699678846a15411925743061 Mon Sep 17 00:00:00 2001 From: visualfc Date: Thu, 4 Jul 2024 07:33:01 +0800 Subject: [PATCH] internal/runtime: check abi.TFlagRegularMemory --- internal/runtime/alg.go | 21 +++-------- internal/runtime/z_type.go | 71 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 73 insertions(+), 19 deletions(-) diff --git a/internal/runtime/alg.go b/internal/runtime/alg.go index de7857048..4b2edd201 100644 --- a/internal/runtime/alg.go +++ b/internal/runtime/alg.go @@ -134,21 +134,8 @@ func nilinterhash(p unsafe.Pointer, h uintptr) uintptr { // Note: this function must match the compiler generated // functions exactly. See issue 37716. func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { - // if t.TFlag&abi.TFlagRegularMemory != 0 { - // // Handle ptr sizes specially, see issue 37086. - // switch t.Size_ { - // case 4: - // return memhash32(p, h) - // case 8: - // return memhash64(p, h) - // default: - // return memhash(p, h, t.Size_) - // } - // } - switch t.Kind() { - case abi.Bool, abi.Int, abi.Int8, abi.Int16, abi.Int32, abi.Int64, - abi.Uint, abi.Uint8, abi.Uint16, abi.Uint32, abi.Uint64, - abi.Uintptr, abi.UnsafePointer, abi.Pointer: + if t.TFlag&abi.TFlagRegularMemory != 0 { + // Handle ptr sizes specially, see issue 37086. switch t.Size_ { case 4: return memhash32(p, h) @@ -157,6 +144,8 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { default: return memhash(p, h, t.Size_) } + } + switch t.Kind() { case abi.Float32: return f32hash(p, h) case abi.Float64: @@ -179,8 +168,6 @@ func typehash(t *_type, p unsafe.Pointer, h uintptr) uintptr { h = typehash(a.Elem, add(p, i*a.Elem.Size_), h) } return h - case abi.Chan: - return typehash(t.Elem(), p, h) case abi.Struct: s := (*structtype)(unsafe.Pointer(t)) for _, f := range s.Fields { diff --git a/internal/runtime/z_type.go b/internal/runtime/z_type.go index a0d3d3199..b4cdb4ab7 100644 --- a/internal/runtime/z_type.go +++ b/internal/runtime/z_type.go @@ -60,6 +60,14 @@ func basicEqual(kind Kind, size uintptr) func(a, b unsafe.Pointer) bool { panic("unreachable") } +func basicFlags(kind Kind) abi.TFlag { + switch kind { + case abi.Float32, abi.Float64, abi.Complex64, abi.Complex128, abi.String: + return 0 + } + return abi.TFlagRegularMemory +} + func Basic(kind Kind) *Type { if tyBasic[kind] == nil { name, size, align := basicTypeInfo(kind) @@ -70,6 +78,7 @@ func Basic(kind Kind) *Type { FieldAlign_: uint8(align), Kind_: uint8(kind), Equal: basicEqual(kind, size), + TFlag: basicFlags(kind), Str_: name, } } @@ -170,6 +179,9 @@ func Struct(pkgPath string, size uintptr, fields ...abi.StructField) *Type { } } } + if isRegularMemory(&ret.Type) { + ret.TFlag = abi.TFlagRegularMemory + } return &ret.Type } @@ -196,13 +208,14 @@ func newPointer(elem *Type) *Type { FieldAlign_: pointerAlign, Kind_: uint8(abi.Pointer), Equal: memequalptr, + TFlag: abi.TFlagRegularMemory, }, Elem: elem, } if (elem.TFlag & abi.TFlagExtraStar) != 0 { ptr.Str_ = "**" + elem.Str_ } else { - ptr.TFlag = abi.TFlagExtraStar + ptr.TFlag |= abi.TFlagExtraStar ptr.Str_ = elem.Str_ } return &ptr.Type @@ -255,6 +268,9 @@ func ArrayOf(length uintptr, elem *Type) *Type { } } } + if ret.Len == 0 || ret.Elem.TFlag&abi.TFlagRegularMemory != 0 { + ret.TFlag = abi.TFlagRegularMemory + } return &ret.Type } @@ -264,6 +280,7 @@ func ChanOf(dir int, strChan string, elem *Type) *Type { Size_: 8, Hash: uint32(abi.Chan), Align_: pointerAlign, + TFlag: abi.TFlagRegularMemory, FieldAlign_: pointerAlign, Kind_: uint8(abi.Chan), Equal: memequalptr, @@ -272,7 +289,6 @@ func ChanOf(dir int, strChan string, elem *Type) *Type { Elem: elem, Dir: abi.ChanDir(dir), } - return &ret.Type } @@ -300,4 +316,55 @@ func MapOf(key, elem *Type, bucket *Type, flags int) *Type { return &ret.Type } +func isRegularMemory(t *_type) bool { + switch t.Kind() { + case abi.Func, abi.Map, abi.Slice, abi.String, abi.Interface: + return false + case abi.Float32, abi.Float64, abi.Complex64, abi.Complex128: + return false + case abi.Array: + at := t.ArrayType() + b := isRegularMemory(at.Elem) + if b { + return true + } + if at.Len == 0 { + return true + } + return b + case abi.Struct: + st := t.StructType() + n := len(st.Fields) + switch n { + case 0: + return true + case 1: + f := st.Fields[0] + if f.Name_ == "_" { + return false + } + return isRegularMemory(f.Typ) + default: + for i := 0; i < n; i++ { + f := st.Fields[i] + if f.Name_ == "_" || !isRegularMemory(f.Typ) || ispaddedfield(st, i) { + return false + } + } + } + } + return true +} + +// ispaddedfield reports whether the i'th field of struct type t is followed +// by padding. +func ispaddedfield(st *structtype, i int) bool { + end := st.Size() + if i+1 < len(st.Fields) { + end = st.Fields[i+1].Offset + } + fd := st.Fields[i] + return fd.Offset+fd.Typ.Size_ != end +} + // -----------------------------------------------------------------------------