Currently, the compiler already generates common symbols for type descriptors, so the type descriptors are unique. However, when a type is created through reflection, it is not deduplicated with compiler-generated types. As a consequence, we cannot assume type descriptors are unique, and cannot use pointer equality to compare them. Also, when constructing a reflect.Type, it has to go through a canonicalization map, which introduces overhead to reflect.TypeOf, and lock contentions in concurrent programs.
In order for the reflect package to deduplicate types with compiler-created types, we register all the compiler-created type descriptors at startup time. The reflect package, when it needs to create a type, looks up the registry of compiler-created types before creates a new one. There is no lock contention since the registry is read-only after initialization.
This lets us get rid of the canonicalization map, and also makes it possible to compare type descriptors with pointer equality.
03f42d617c8 compiler, runtime, reflect: generate unique type descriptors
gcc/go/gofrontend/MERGE | 2 +-
gcc/go/gofrontend/gogo.cc | 151 +++++++++++++++++++++++++++++++++++++++++-
gcc/go/gofrontend/gogo.h | 24 +++++++
gcc/go/gofrontend/names.cc | 23 +++++++
gcc/go/gofrontend/runtime.def | 4 ++
gcc/go/gofrontend/types.cc | 17 +++++
libgo/go/reflect/type.go | 131 ++++++++++++++++++------------------
libgo/go/runtime/type.go | 78 ++++++++++++++++++----
8 files changed, 349 insertions(+), 81 deletions(-)