diff options
| author | Ian Lance Taylor <iant@golang.org> | 2025-12-11 20:50:05 -0800 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2026-03-26 17:37:59 -0700 |
| commit | 87fae3622dacca9cfa5026c712df40af694a4e6a (patch) | |
| tree | f7bc61ad5a773db548366cb840e8483766b11b35 | |
| parent | 2dbd51e3b4bf29e6204caf0465258ced601494a2 (diff) | |
| download | go-87fae3622dacca9cfa5026c712df40af694a4e6a.tar.xz | |
reflect, runtime: replace reflect.typelinks to return types, not offsets
Change reflect to call a new function to get the compiled type descriptors,
returning the type pointers directly rather than the type offsets.
We have to keep the existing reflect.typelinks for third party
packages that break the rules and call it directly using linkname.
Change-Id: I476efb6bd7836a7a5f396c97bbe4b2c1a2428990
Reviewed-on: https://go-review.googlesource.com/c/go/+/729502
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Antonio Camacho <antoniocho444@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
| -rw-r--r-- | src/reflect/export_test.go | 18 | ||||
| -rw-r--r-- | src/reflect/type.go | 42 | ||||
| -rw-r--r-- | src/runtime/runtime1.go | 21 |
3 files changed, 51 insertions, 30 deletions
diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go index 51b57c780c..4ecdb1ef2e 100644 --- a/src/reflect/export_test.go +++ b/src/reflect/export_test.go @@ -72,15 +72,21 @@ func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, } func TypeLinks() []string { + first, rest := compiledTypelinks() + var r []string - sections, offset := typelinks() - for i, offs := range offset { - rodata := sections[i] - for _, off := range offs { - typ := (*rtype)(resolveTypeOff(rodata, off)) - r = append(r, typ.String()) + + addTypes := func(types []*abi.Type) { + for _, typ := range types { + r = append(r, stringFor(typ)) } } + + addTypes(first) + for _, rt := range rest { + addTypes(rt) + } + return r } diff --git a/src/reflect/type.go b/src/reflect/type.go index c58bbaa26d..47233af1a2 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -1710,26 +1710,16 @@ func haveIdenticalUnderlyingType(T, V *abi.Type, cmpTags bool) bool { return false } -// typelinks is implemented in package runtime. -// It returns a slice of the sections in each module, -// and a slice of *rtype offsets in each module. -// -// The types in each module are sorted by string. That is, the first -// two linked types of the first module are: -// -// d0 := sections[0] -// t1 := (*rtype)(add(d0, offset[0][0])) -// t2 := (*rtype)(add(d0, offset[0][1])) -// -// and -// -// t1.String() < t2.String() +// compiledTypelinks is implemented in package runtime. +// It returns the types defined by the first module, +// and a slice of types defined in any other modules. +// Each slice of types is sorted by string. // // Note that strings are not unique identifiers for types: // there can be more than one with a given string. // Only types we might want to look up are included: // pointers, channels, maps, slices, and arrays. -func typelinks() (sections []unsafe.Pointer, offset [][]int32) +func compiledTypelinks() ([]*abi.Type, [][]*abi.Type) // rtypeOff should be an internal detail, // but widely used packages access it using linkname. @@ -1744,7 +1734,7 @@ func rtypeOff(section unsafe.Pointer, off int32) *abi.Type { return (*abi.Type)(add(section, uintptr(off), "sizeof(rtype) > 0")) } -// typesByString returns the subslice of typelinks() whose elements have +// typesByString returns all known types whose elements have // the given string representation. // It may be empty (no known types with that string) or may have // multiple elements (multiple types with that string). @@ -1760,19 +1750,17 @@ func rtypeOff(section unsafe.Pointer, off int32) *abi.Type { // //go:linkname typesByString func typesByString(s string) []*abi.Type { - sections, offset := typelinks() + first, rest := compiledTypelinks() var ret []*abi.Type - for offsI, offs := range offset { - section := sections[offsI] - + searchTypes := func(types []*abi.Type) { // We are looking for the first index i where the string becomes >= s. // This is a copy of sort.Search, with f(h) replaced by (*typ[h].String() >= s). - i, j := 0, len(offs) + i, j := 0, len(types) for i < j { h := int(uint(i+j) >> 1) // avoid overflow when computing h // i ≤ h < j - if !(stringFor(rtypeOff(section, offs[h])) >= s) { + if !(stringFor(types[h]) >= s) { i = h + 1 // preserves f(i-1) == false } else { j = h // preserves f(j) == true @@ -1783,14 +1771,20 @@ func typesByString(s string) []*abi.Type { // Having found the first, linear scan forward to find the last. // We could do a second binary search, but the caller is going // to do a linear scan anyway. - for j := i; j < len(offs); j++ { - typ := rtypeOff(section, offs[j]) + for j := i; j < len(types); j++ { + typ := types[j] if stringFor(typ) != s { break } ret = append(ret, typ) } } + + searchTypes(first) + for _, r := range rest { + searchTypes(r) + } + return ret } diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go index 10754eee1c..8da3682261 100644 --- a/src/runtime/runtime1.go +++ b/src/runtime/runtime1.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "internal/bytealg" "internal/goarch" "internal/runtime/atomic" @@ -627,6 +628,9 @@ func releasem(mp *m) { // Do not remove or change the type signature. // See go.dev/issue/67401. // +// This is obsolete and only remains for external packages. +// New code should use reflect_compiledTypelinks. +// //go:linkname reflect_typelinks reflect.typelinks func reflect_typelinks() ([]unsafe.Pointer, [][]int32) { modules := activeModules() @@ -649,6 +653,23 @@ func reflect_typelinks() ([]unsafe.Pointer, [][]int32) { return sections, ret } +// reflect_compiledTypelinks returns the typelink types +// generated by the compiler for all current modules. +// The normal case is a single module, so this returns one +// slice for the main module, and a slice of slices, normally nil, +// for other modules. +// +//go:linkname reflect_compiledTypelinks reflect.compiledTypelinks +func reflect_compiledTypelinks() ([]*abi.Type, [][]*abi.Type) { + modules := activeModules() + firstTypes := moduleTypelinks(modules[0]) + var rest [][]*abi.Type + for _, md := range modules[1:] { + rest = append(rest, moduleTypelinks(md)) + } + return firstTypes, rest +} + // reflect_resolveNameOff resolves a name offset from a base pointer. // // reflect_resolveNameOff is for package reflect, |
