mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Change-Id: I0490098a7235458c5aede1135426a9f19f8584a7 Reviewed-on: https://go-review.googlesource.com/c/76312 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
203 lines
4.4 KiB
Go
203 lines
4.4 KiB
Go
// Copyright 2015 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 gc
|
|
|
|
import (
|
|
"cmd/compile/internal/types"
|
|
)
|
|
|
|
type exporter struct {
|
|
marked map[*types.Type]bool // types already seen by markType
|
|
}
|
|
|
|
// markType recursively visits types reachable from t to identify
|
|
// functions whose inline bodies may be needed.
|
|
func (p *exporter) markType(t *types.Type) {
|
|
if p.marked[t] {
|
|
return
|
|
}
|
|
p.marked[t] = true
|
|
|
|
// If this is a named 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.Etype != TINTER {
|
|
for _, m := range t.Methods().Slice() {
|
|
if types.IsExported(m.Sym.Name) {
|
|
p.markType(m.Type)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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.Etype {
|
|
case TPTR, TARRAY, TSLICE, TCHAN:
|
|
// TODO(mdempsky): Skip marking element type for
|
|
// send-only channels?
|
|
p.markType(t.Elem())
|
|
|
|
case TMAP:
|
|
p.markType(t.Key())
|
|
p.markType(t.Elem())
|
|
|
|
case TSTRUCT:
|
|
for _, f := range t.FieldSlice() {
|
|
if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
|
|
p.markType(f.Type)
|
|
}
|
|
}
|
|
|
|
case TFUNC:
|
|
// If t is the type of a function or method, then
|
|
// t.Nname() is its ONAME. Mark its inline body and
|
|
// any recursively called functions for export.
|
|
inlFlood(asNode(t.Nname()))
|
|
|
|
for _, f := range t.Results().FieldSlice() {
|
|
p.markType(f.Type)
|
|
}
|
|
|
|
case TINTER:
|
|
for _, f := range t.FieldSlice() {
|
|
if types.IsExported(f.Sym.Name) {
|
|
p.markType(f.Type)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// deltaNewFile is a magic line delta offset indicating a new file.
|
|
// We use -64 because it is rare; see issue 20080 and CL 41619.
|
|
// -64 is the smallest int that fits in a single byte as a varint.
|
|
const deltaNewFile = -64
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Export format
|
|
|
|
// Tags. Must be < 0.
|
|
const (
|
|
// Objects
|
|
packageTag = -(iota + 1)
|
|
constTag
|
|
typeTag
|
|
varTag
|
|
funcTag
|
|
endTag
|
|
|
|
// Types
|
|
namedTag
|
|
arrayTag
|
|
sliceTag
|
|
dddTag
|
|
structTag
|
|
pointerTag
|
|
signatureTag
|
|
interfaceTag
|
|
mapTag
|
|
chanTag
|
|
|
|
// Values
|
|
falseTag
|
|
trueTag
|
|
int64Tag
|
|
floatTag
|
|
fractionTag // not used by gc
|
|
complexTag
|
|
stringTag
|
|
nilTag
|
|
unknownTag // not used by gc (only appears in packages with errors)
|
|
|
|
// Type aliases
|
|
aliasTag
|
|
)
|
|
|
|
// untype returns the "pseudo" untyped type for a Ctype (import/export use only).
|
|
// (we can't use an pre-initialized array because we must be sure all types are
|
|
// set up)
|
|
func untype(ctype Ctype) *types.Type {
|
|
switch ctype {
|
|
case CTINT:
|
|
return types.Idealint
|
|
case CTRUNE:
|
|
return types.Idealrune
|
|
case CTFLT:
|
|
return types.Idealfloat
|
|
case CTCPLX:
|
|
return types.Idealcomplex
|
|
case CTSTR:
|
|
return types.Idealstring
|
|
case CTBOOL:
|
|
return types.Idealbool
|
|
case CTNIL:
|
|
return types.Types[TNIL]
|
|
}
|
|
Fatalf("exporter: unknown Ctype")
|
|
return nil
|
|
}
|
|
|
|
var predecl []*types.Type // initialized lazily
|
|
|
|
func predeclared() []*types.Type {
|
|
if predecl == nil {
|
|
// initialize lazily to be sure that all
|
|
// elements have been initialized before
|
|
predecl = []*types.Type{
|
|
// basic types
|
|
types.Types[TBOOL],
|
|
types.Types[TINT],
|
|
types.Types[TINT8],
|
|
types.Types[TINT16],
|
|
types.Types[TINT32],
|
|
types.Types[TINT64],
|
|
types.Types[TUINT],
|
|
types.Types[TUINT8],
|
|
types.Types[TUINT16],
|
|
types.Types[TUINT32],
|
|
types.Types[TUINT64],
|
|
types.Types[TUINTPTR],
|
|
types.Types[TFLOAT32],
|
|
types.Types[TFLOAT64],
|
|
types.Types[TCOMPLEX64],
|
|
types.Types[TCOMPLEX128],
|
|
types.Types[TSTRING],
|
|
|
|
// basic type aliases
|
|
types.Bytetype,
|
|
types.Runetype,
|
|
|
|
// error
|
|
types.Errortype,
|
|
|
|
// untyped types
|
|
untype(CTBOOL),
|
|
untype(CTINT),
|
|
untype(CTRUNE),
|
|
untype(CTFLT),
|
|
untype(CTCPLX),
|
|
untype(CTSTR),
|
|
untype(CTNIL),
|
|
|
|
// package unsafe
|
|
types.Types[TUNSAFEPTR],
|
|
|
|
// invalid type (package contains errors)
|
|
types.Types[Txxx],
|
|
|
|
// any type, for builtin export data
|
|
types.Types[TANY],
|
|
}
|
|
}
|
|
return predecl
|
|
}
|