aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/reflectdata/reflect.go
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2021-06-24 11:31:56 -0700
committerMatthew Dempsky <mdempsky@google.com>2021-06-25 05:00:04 +0000
commit3f1a517a45d2e443a327e0b28df17698e299ea50 (patch)
treeb94f274e4638ce10d413772400adc39239e25850 /src/cmd/compile/internal/reflectdata/reflect.go
parentbadb98364b3710933de89bfe579fb8d1f82741c8 (diff)
downloadgo-3f1a517a45d2e443a327e0b28df17698e299ea50.tar.gz
go-3f1a517a45d2e443a327e0b28df17698e299ea50.zip
[dev.typeparams] cmd/compile: refactor "need to emit" logic for types
This CL refactors out a single reflectdata.NeedEmit function that reports whether the current compilation unit needs to emit the runtime type descriptor and method wrappers for a given type. As a minor side bonus, this CL also skips compiling the "error.Error" wrapper in non-runtime packages. Package runtime already unconditionally emitted the runtime type descriptor for error, so we just need to make sure it emits the wrapper and other packages don't. Passes toolstash -cmp. Change-Id: Ic9ea219dfba8a0a57f2f42f817bdff7618732bff Reviewed-on: https://go-review.googlesource.com/c/go/+/330754 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Diffstat (limited to 'src/cmd/compile/internal/reflectdata/reflect.go')
-rw-r--r--src/cmd/compile/internal/reflectdata/reflect.go91
1 files changed, 55 insertions, 36 deletions
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 8378fab36d..ba4bbc7631 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -927,29 +927,27 @@ func writeType(t *types.Type) *obj.LSym {
if t.IsPtr() && t.Sym() == nil && t.Elem().Sym() != nil {
tbase = t.Elem()
}
+ if tbase.Kind() == types.TFORW {
+ base.Fatalf("unresolved defined type: %v", tbase)
+ }
+
dupok := 0
- if tbase.Sym() == nil {
+ if tbase.Sym() == nil { // TODO(mdempsky): Probably need DUPOK for instantiated types too.
dupok = obj.DUPOK
}
- if base.Ctxt.Pkgpath != "runtime" || (tbase != types.Types[tbase.Kind()] && tbase != types.ByteType && tbase != types.RuneType && tbase != types.ErrorType) { // int, float, etc
- // Named types from other files are defined only by those files.
- // However, as an exception, we can write out instantiated types
- // in the local package, even if they may be marked as part of
- // another package (the package of their base generic type).
- if tbase.Sym() != nil && tbase.Sym().Pkg != types.LocalPkg &&
- !tbase.IsFullyInstantiated() {
- if i := typecheck.BaseTypeIndex(t); i >= 0 {
- lsym.Pkg = tbase.Sym().Pkg.Prefix
- lsym.SymIdx = int32(i)
- lsym.Set(obj.AttrIndexed, true)
- }
- return lsym
- }
- // TODO(mdempsky): Investigate whether this can happen.
- if tbase.Kind() == types.TFORW {
- return lsym
+ if !NeedEmit(tbase) {
+ if i := typecheck.BaseTypeIndex(t); i >= 0 {
+ lsym.Pkg = tbase.Sym().Pkg.Prefix
+ lsym.SymIdx = int32(i)
+ lsym.Set(obj.AttrIndexed, true)
}
+
+ // TODO(mdempsky): Investigate whether this still happens.
+ // If we know we don't need to emit code for a type,
+ // we should have a link-symbol index for it.
+ // See also TODO in NeedEmit.
+ return lsym
}
ot := 0
@@ -1678,6 +1676,44 @@ func CollectPTabs() {
}
}
+// NeedEmit reports whether typ is a type that we need to emit code
+// for (e.g., runtime type descriptors, method wrappers).
+func NeedEmit(typ *types.Type) bool {
+ // TODO(mdempsky): Export data should keep track of which anonymous
+ // and instantiated types were emitted, so at least downstream
+ // packages can skip re-emitting them.
+ //
+ // Perhaps we can just generalize the linker-symbol indexing to
+ // track the index of arbitrary types, not just defined types, and
+ // use its presence to detect this. The same idea would work for
+ // instantiated generic functions too.
+
+ switch sym := typ.Sym(); {
+ case sym == nil:
+ // Anonymous type; possibly never seen before or ever again.
+ // Need to emit to be safe (however, see TODO above).
+ return true
+
+ case sym.Pkg == types.LocalPkg:
+ // Local defined type; our responsibility.
+ return true
+
+ case base.Ctxt.Pkgpath == "runtime" && (sym.Pkg == types.BuiltinPkg || sym.Pkg == ir.Pkgs.Unsafe):
+ // Package runtime is responsible for including code for builtin
+ // types (predeclared and package unsafe).
+ return true
+
+ case typ.IsFullyInstantiated():
+ // Instantiated type; possibly instantiated with unique type arguments.
+ // Need to emit to be safe (however, see TODO above).
+ return true
+
+ default:
+ // Should have been emitted by an imported package.
+ return false
+ }
+}
+
// Generate a wrapper function to convert from
// a receiver of type T to a receiver of type U.
// That is,
@@ -1739,24 +1775,7 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
return lsym
}
- // imported reports whether typ is a defined type that was declared
- // in an imported package, and therefore must have been compiled in
- // that package.
- importedType := func(typ *types.Type) bool {
- return typ.Sym() != nil && typ.Sym().Pkg != types.LocalPkg &&
-
- // Exception: need wrapper for error.Error (#29304).
- // TODO(mdempsky): Put this in package runtime, like we do for
- // the type descriptors for predeclared types.
- typ != types.ErrorType &&
-
- // Exception: parameterized types may have been instantiated
- // with new type arguments, so we don't assume they've been
- // compiled before.
- !typ.IsFullyInstantiated()
- }
-
- if importedType(rcvr) || rcvr.IsPtr() && importedType(rcvr.Elem()) {
+ if !NeedEmit(rcvr) || rcvr.IsPtr() && !NeedEmit(rcvr.Elem()) {
return lsym
}