diff options
author | Matthew Dempsky <mdempsky@google.com> | 2022-12-01 16:27:34 -0800 |
---|---|---|
committer | Matthew Dempsky <mdempsky@google.com> | 2023-01-26 21:52:50 +0000 |
commit | da9761303c439041251931c32b6e86bdbe739183 (patch) | |
tree | 50a79b91fa2b6b31126ce56b23aa4ac3942d4647 /src/cmd/compile/internal/typecheck/crawler.go | |
parent | a7de684e1b6f460aae7d4dbf2568cb21130ec520 (diff) | |
download | go-da9761303c439041251931c32b6e86bdbe739183.tar.gz go-da9761303c439041251931c32b6e86bdbe739183.zip |
cmd/compile: remove GOEXPERIMENT=nounified frontend
This CL removes most of the code specific to the nounified
frontend. To simplify review, it's a strict remove-only CL.
Updates #57410.
Change-Id: Ic3196570aa4286618c1d5e7fd0d0e6601a18195b
Reviewed-on: https://go-review.googlesource.com/c/go/+/458620
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/typecheck/crawler.go')
-rw-r--r-- | src/cmd/compile/internal/typecheck/crawler.go | 378 |
1 files changed, 0 insertions, 378 deletions
diff --git a/src/cmd/compile/internal/typecheck/crawler.go b/src/cmd/compile/internal/typecheck/crawler.go deleted file mode 100644 index a4a507dfec..0000000000 --- a/src/cmd/compile/internal/typecheck/crawler.go +++ /dev/null @@ -1,378 +0,0 @@ -// Copyright 2021 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package typecheck - -import ( - "cmd/compile/internal/base" - "cmd/compile/internal/ir" - "cmd/compile/internal/types" - "cmd/internal/src" -) - -// crawlExports crawls the type/object graph rooted at the given list of exported -// objects (which are variables, functions, and types). It descends through all parts -// of types and follows methods on defined types. Any functions that are found to be -// potentially callable by importers directly or after inlining are marked with -// ExportInline, so that iexport.go knows to export their inline body. -// -// The overall purpose of crawlExports is to AVOID exporting inlineable methods -// that cannot actually be referenced, thereby reducing the size of the exports -// significantly. -// -// For non-generic defined types reachable from global variables, we only set -// ExportInline for exported methods. For defined types that are directly named or are -// embedded recursively in such a type, we set ExportInline for all methods, since -// these types can be embedded in another local type. For instantiated types that are -// used anywhere in a inlineable function, we set ExportInline on all methods of the -// base generic type, since all methods will be needed for creating any instantiated -// type. -func crawlExports(exports []*ir.Name) { - p := crawler{ - marked: make(map[*types.Type]bool), - embedded: make(map[*types.Type]bool), - generic: make(map[*types.Type]bool), - checkFullyInst: make(map[*types.Type]bool), - } - for _, n := range exports { - p.markObject(n) - } -} - -type crawler struct { - marked map[*types.Type]bool // types already seen by markType - embedded map[*types.Type]bool // types already seen by markEmbed - generic map[*types.Type]bool // types already seen by markGeneric - checkFullyInst map[*types.Type]bool // types already seen by checkForFullyInst -} - -// markObject visits a reachable object (function, method, global type, or global variable) -func (p *crawler) markObject(n *ir.Name) { - if n.Op() == ir.ONAME && n.Class == ir.PFUNC { - p.markInlBody(n) - } - - // If a declared type name is reachable, users can embed it in their - // own types, which makes even its unexported methods reachable. - if n.Op() == ir.OTYPE { - p.markEmbed(n.Type()) - } - - p.markType(n.Type()) -} - -// markType recursively visits types reachable from t to identify functions whose -// inline bodies may be needed. For instantiated generic types, it visits the base -// generic type, which has the relevant methods. -func (p *crawler) markType(t *types.Type) { - if orig := t.OrigType(); orig != nil { - // Convert to the base generic type. - t = orig - } - if p.marked[t] { - return - } - p.marked[t] = true - - // If this is a defined type, mark all of its associated - // methods. Skip interface types because t.Methods contains - // only their unexpanded method set (i.e., exclusive of - // interface embeddings), and the switch statement below - // handles their full method set. - if t.Sym() != nil && t.Kind() != types.TINTER { - for _, m := range t.Methods().Slice() { - if types.IsExported(m.Sym.Name) { - p.markObject(m.Nname.(*ir.Name)) - } - } - } - - // Recursively mark any types that can be produced given a - // value of type t: dereferencing a pointer; indexing or - // iterating over an array, slice, or map; receiving from a - // channel; accessing a struct field or interface method; or - // calling a function. - // - // Notably, we don't mark function parameter types, because - // the user already needs some way to construct values of - // those types. - switch t.Kind() { - case types.TPTR, types.TARRAY, types.TSLICE: - p.markType(t.Elem()) - - case types.TCHAN: - if t.ChanDir().CanRecv() { - p.markType(t.Elem()) - } - - case types.TMAP: - p.markType(t.Key()) - p.markType(t.Elem()) - - case types.TSTRUCT: - if t.IsFuncArgStruct() { - break - } - for _, f := range t.FieldSlice() { - // Mark the type of a unexported field if it is a - // fully-instantiated type, since we create and instantiate - // the methods of any fully-instantiated type that we see - // during import (see end of typecheck.substInstType). - if types.IsExported(f.Sym.Name) || f.Embedded != 0 || - isPtrFullyInstantiated(f.Type) { - p.markType(f.Type) - } - } - - case types.TFUNC: - for _, f := range t.Results().FieldSlice() { - p.markType(f.Type) - } - - case types.TINTER: - for _, f := range t.AllMethods().Slice() { - if types.IsExported(f.Sym.Name) { - p.markType(f.Type) - } - } - - case types.TTYPEPARAM: - // No other type that needs to be followed. - } -} - -// markEmbed is similar to markType, but handles finding methods that -// need to be re-exported because t can be embedded in user code -// (possibly transitively). -func (p *crawler) markEmbed(t *types.Type) { - if t.IsPtr() { - // Defined pointer type; not allowed to embed anyway. - if t.Sym() != nil { - return - } - t = t.Elem() - } - - if orig := t.OrigType(); orig != nil { - // Convert to the base generic type. - t = orig - } - - if p.embedded[t] { - return - } - p.embedded[t] = true - - // If t is a defined type, then re-export all of its methods. Unlike - // in markType, we include even unexported methods here, because we - // still need to generate wrappers for them, even if the user can't - // refer to them directly. - if t.Sym() != nil && t.Kind() != types.TINTER { - for _, m := range t.Methods().Slice() { - p.markObject(m.Nname.(*ir.Name)) - } - } - - // If t is a struct, recursively visit its embedded fields. - if t.IsStruct() { - for _, f := range t.FieldSlice() { - if f.Embedded != 0 { - p.markEmbed(f.Type) - } - } - } -} - -// markGeneric takes an instantiated type or a base generic type t, and marks all the -// methods of the base generic type of t. If a base generic type is written out for -// export, even if not explicitly marked for export, then all of its methods need to -// be available for instantiation, since we always create all methods of a specified -// instantiated type. Non-exported methods must generally be instantiated, since they may -// be called by the exported methods or other generic function in the same package. -func (p *crawler) markGeneric(t *types.Type) { - if t.IsPtr() { - t = t.Elem() - } - if orig := t.OrigType(); orig != nil { - // Convert to the base generic type. - t = orig - } - if p.generic[t] { - return - } - p.generic[t] = true - - if t.Sym() != nil && t.Kind() != types.TINTER { - for _, m := range t.Methods().Slice() { - p.markObject(m.Nname.(*ir.Name)) - } - } -} - -// checkForFullyInst looks for fully-instantiated types in a type (at any nesting -// level). If it finds a fully-instantiated type, it ensures that the necessary -// dictionary and shape methods are exported. It updates p.checkFullyInst, so it -// traverses each particular type only once. -func (p *crawler) checkForFullyInst(t *types.Type) { - if p.checkFullyInst[t] { - return - } - p.checkFullyInst[t] = true - - if t.IsFullyInstantiated() && !t.HasShape() && !t.IsInterface() && t.Methods().Len() > 0 { - // For any fully-instantiated type, the relevant - // dictionaries and shape instantiations will have - // already been created or are in the import data. - // Make sure that they are exported, so that any - // other package that inlines this function will have - // them available for import, and so will not need - // another round of method and dictionary - // instantiation after inlining. - baseType := t.OrigType() - shapes := make([]*types.Type, len(t.RParams())) - for i, t1 := range t.RParams() { - shapes[i] = Shapify(t1, i, baseType.RParams()[i]) - } - for j, tmethod := range t.Methods().Slice() { - baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name) - dictsym := MakeDictSym(baseNname.Sym(), t.RParams(), true) - if dictsym.Def == nil { - in := Resolve(ir.NewIdent(src.NoXPos, dictsym)) - dictsym = in.Sym() - } - Export(dictsym.Def.(*ir.Name)) - methsym := MakeFuncInstSym(baseNname.Sym(), shapes, false, true) - if methsym.Def == nil { - in := Resolve(ir.NewIdent(src.NoXPos, methsym)) - methsym = in.Sym() - } - methNode := methsym.Def.(*ir.Name) - Export(methNode) - if HaveInlineBody(methNode.Func) { - // Export the body as well if - // instantiation is inlineable. - ImportedBody(methNode.Func) - methNode.Func.SetExportInline(true) - } - // Make sure that any associated types are also exported. (See #52279) - p.checkForFullyInst(tmethod.Type) - } - } - - // Descend into the type. We descend even if it is a fully-instantiated type, - // since the instantiated type may have other instantiated types inside of - // it (in fields, methods, etc.). - switch t.Kind() { - case types.TPTR, types.TARRAY, types.TSLICE: - p.checkForFullyInst(t.Elem()) - - case types.TCHAN: - p.checkForFullyInst(t.Elem()) - - case types.TMAP: - p.checkForFullyInst(t.Key()) - p.checkForFullyInst(t.Elem()) - - case types.TSTRUCT: - if t.IsFuncArgStruct() { - break - } - for _, f := range t.FieldSlice() { - p.checkForFullyInst(f.Type) - } - - case types.TFUNC: - if recv := t.Recv(); recv != nil { - p.checkForFullyInst(t.Recv().Type) - } - for _, f := range t.Params().FieldSlice() { - p.checkForFullyInst(f.Type) - } - for _, f := range t.Results().FieldSlice() { - p.checkForFullyInst(f.Type) - } - - case types.TINTER: - for _, f := range t.AllMethods().Slice() { - p.checkForFullyInst(f.Type) - } - } -} - -// markInlBody marks n's inline body for export and recursively -// ensures all called functions are marked too. -func (p *crawler) markInlBody(n *ir.Name) { - if n == nil { - return - } - if n.Op() != ir.ONAME || n.Class != ir.PFUNC { - base.Fatalf("markInlBody: unexpected %v, %v, %v", n, n.Op(), n.Class) - } - fn := n.Func - if fn == nil { - base.Fatalf("markInlBody: missing Func on %v", n) - } - if !HaveInlineBody(fn) { - return - } - - if fn.ExportInline() { - return - } - fn.SetExportInline(true) - - ImportedBody(fn) - - var doFlood func(n ir.Node) - doFlood = func(n ir.Node) { - t := n.Type() - if t != nil { - if t.HasTParam() { - // If any generic types are used, then make sure that - // the methods of the generic type are exported and - // scanned for other possible exports. - p.markGeneric(t) - } else { - p.checkForFullyInst(t) - } - } - - switch n.Op() { - case ir.OMETHEXPR, ir.ODOTMETH: - p.markInlBody(ir.MethodExprName(n)) - case ir.ONAME: - n := n.(*ir.Name) - switch n.Class { - case ir.PFUNC: - p.markInlBody(n) - // Note: this Export() and the one below seem unneeded, - // since any function/extern name encountered in an - // exported function body will be exported - // automatically via qualifiedIdent() in iexport.go. - Export(n) - case ir.PEXTERN: - Export(n) - } - case ir.OMETHVALUE: - // Okay, because we don't yet inline indirect - // calls to method values. - case ir.OCLOSURE: - // VisitList doesn't visit closure bodies, so force a - // recursive call to VisitList on the body of the closure. - ir.VisitList(n.(*ir.ClosureExpr).Func.Body, doFlood) - } - } - - // Recursively identify all referenced functions for - // reexport. We want to include even non-called functions, - // because after inlining they might be callable. - ir.VisitList(fn.Inl.Body, doFlood) -} - -// isPtrFullyInstantiated returns true if t is a fully-instantiated type, or it is a -// pointer to a fully-instantiated type. -func isPtrFullyInstantiated(t *types.Type) bool { - return t.IsPtr() && t.Elem().IsFullyInstantiated() || - t.IsFullyInstantiated() -} |