Current Path : /usr/local/go/src/cmd/compile/internal/typecheck/ |
Current File : //usr/local/go/src/cmd/compile/internal/typecheck/iexport.go |
// Copyright 2018 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. // Indexed package export. // // The indexed export data format is an evolution of the previous // binary export data format. Its chief contribution is introducing an // index table, which allows efficient random access of individual // declarations and inline function bodies. In turn, this allows // avoiding unnecessary work for compilation units that import large // packages. // // // The top-level data format is structured as: // // Header struct { // Tag byte // 'i' // Version uvarint // StringSize uvarint // DataSize uvarint // } // // Strings [StringSize]byte // Data [DataSize]byte // // MainIndex []struct{ // PkgPath stringOff // PkgName stringOff // PkgHeight uvarint // // Decls []struct{ // Name stringOff // Offset declOff // } // } // // Fingerprint [8]byte // // uvarint means a uint64 written out using uvarint encoding. // // []T means a uvarint followed by that many T objects. In other // words: // // Len uvarint // Elems [Len]T // // stringOff means a uvarint that indicates an offset within the // Strings section. At that offset is another uvarint, followed by // that many bytes, which form the string value. // // declOff means a uvarint that indicates an offset within the Data // section where the associated declaration can be found. // // // There are five kinds of declarations, distinguished by their first // byte: // // type Var struct { // Tag byte // 'V' // Pos Pos // Type typeOff // } // // type Func struct { // Tag byte // 'F' or 'G' // Pos Pos // TypeParams []typeOff // only present if Tag == 'G' // Signature Signature // } // // type Const struct { // Tag byte // 'C' // Pos Pos // Value Value // } // // type Type struct { // Tag byte // 'T' or 'U' // Pos Pos // TypeParams []typeOff // only present if Tag == 'U' // Underlying typeOff // // Methods []struct{ // omitted if Underlying is an interface type // Pos Pos // Name stringOff // Recv Param // Signature Signature // } // } // // type Alias struct { // Tag byte // 'A' // Pos Pos // Type typeOff // } // // // "Automatic" declaration of each typeparam // type TypeParam struct { // Tag byte // 'P' // Pos Pos // Implicit bool // Constraint typeOff // } // // typeOff means a uvarint that either indicates a predeclared type, // or an offset into the Data section. If the uvarint is less than // predeclReserved, then it indicates the index into the predeclared // types list (see predeclared in bexport.go for order). Otherwise, // subtracting predeclReserved yields the offset of a type descriptor. // // Value means a type, kind, and type-specific value. See // (*exportWriter).value for details. // // // There are twelve kinds of type descriptors, distinguished by an itag: // // type DefinedType struct { // Tag itag // definedType // Name stringOff // PkgPath stringOff // } // // type PointerType struct { // Tag itag // pointerType // Elem typeOff // } // // type SliceType struct { // Tag itag // sliceType // Elem typeOff // } // // type ArrayType struct { // Tag itag // arrayType // Len uint64 // Elem typeOff // } // // type ChanType struct { // Tag itag // chanType // Dir uint64 // 1 RecvOnly; 2 SendOnly; 3 SendRecv // Elem typeOff // } // // type MapType struct { // Tag itag // mapType // Key typeOff // Elem typeOff // } // // type FuncType struct { // Tag itag // signatureType // PkgPath stringOff // Signature Signature // } // // type StructType struct { // Tag itag // structType // PkgPath stringOff // Fields []struct { // Pos Pos // Name stringOff // Type typeOff // Embedded bool // Note stringOff // } // } // // type InterfaceType struct { // Tag itag // interfaceType // PkgPath stringOff // Embeddeds []struct { // Pos Pos // Type typeOff // } // Methods []struct { // Pos Pos // Name stringOff // Signature Signature // } // } // // // Reference to a type param declaration // type TypeParamType struct { // Tag itag // typeParamType // Name stringOff // PkgPath stringOff // } // // // Instantiation of a generic type (like List[T2] or List[int]) // type InstanceType struct { // Tag itag // instanceType // Pos pos // TypeArgs []typeOff // BaseType typeOff // } // // type UnionType struct { // Tag itag // interfaceType // Terms []struct { // tilde bool // Type typeOff // } // } // // // // type Signature struct { // Params []Param // Results []Param // Variadic bool // omitted if Results is empty // } // // type Param struct { // Pos Pos // Name stringOff // Type typOff // } // // // Pos encodes a file:line:column triple, incorporating a simple delta // encoding scheme within a data object. See exportWriter.pos for // details. // // // Compiler-specific details. // // cmd/compile writes out a second index for inline bodies and also // appends additional compiler-specific details after declarations. // Third-party tools are not expected to depend on these details and // they're expected to change much more rapidly, so they're omitted // here. See exportWriter's varExt/funcExt/etc methods for details. package typecheck import ( "go/constant" "strconv" "strings" "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/types" ) // predeclReserved is the number of type offsets reserved for types // implicitly declared in the universe block. const predeclReserved = 32 // An itag distinguishes the kind of type that was written into the // indexed export format. type itag uint64 const ( // Types definedType itag = iota pointerType sliceType arrayType chanType mapType signatureType structType interfaceType typeParamType instanceType // Instantiation of a generic type unionType ) const ( debug = false magic = 0x6742937dc293105 ) // exportPath returns the path for pkg as it appears in the iexport // file format. For historical reasons (before cmd/compile required // the -p flag), the local package is represented as the empty string, // instead of its actual path. func exportPath(pkg *types.Pkg) string { if pkg == types.LocalPkg { return "" } return pkg.Path } const blankMarker = "$" // TparamExportName creates a unique name for type param in a method or a generic // type, using the specified unique prefix and the index of the type param. The index // is only used if the type param is blank, in which case the blank is replace by // "$<index>". A unique name is needed for later substitution in the compiler and // export/import that keeps blank type params associated with the correct constraint. func TparamExportName(prefix string, name string, index int) string { if name == "_" { name = blankMarker + strconv.Itoa(index) } return prefix + "." + name } // TparamName returns the real name of a type parameter, after stripping its // qualifying prefix and reverting blank-name encoding. See TparamExportName // for details. func TparamName(exportName string) string { // Remove the "path" from the type param name that makes it unique. ix := strings.LastIndex(exportName, ".") if ix < 0 { return "" } name := exportName[ix+1:] if strings.HasPrefix(name, blankMarker) { return "_" } return name } func constTypeOf(typ *types.Type) constant.Kind { switch typ { case types.UntypedInt, types.UntypedRune: return constant.Int case types.UntypedFloat: return constant.Float case types.UntypedComplex: return constant.Complex } switch typ.Kind() { case types.TBOOL: return constant.Bool case types.TSTRING: return constant.String case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64, types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR: return constant.Int case types.TFLOAT32, types.TFLOAT64: return constant.Float case types.TCOMPLEX64, types.TCOMPLEX128: return constant.Complex } base.Fatalf("unexpected constant type: %v", typ) return 0 } func intSize(typ *types.Type) (signed bool, maxBytes uint) { if typ.IsUntyped() { return true, ir.ConstPrec / 8 } switch typ.Kind() { case types.TFLOAT32, types.TCOMPLEX64: return true, 3 case types.TFLOAT64, types.TCOMPLEX128: return true, 7 } signed = typ.IsSigned() maxBytes = uint(typ.Size()) // The go/types API doesn't expose sizes to importers, so they // don't know how big these types are. switch typ.Kind() { case types.TINT, types.TUINT, types.TUINTPTR: maxBytes = 8 } return } func isNonEmptyAssign(n ir.Node) bool { switch n.Op() { case ir.OAS: if n.(*ir.AssignStmt).Y != nil { return true } case ir.OAS2, ir.OAS2DOTTYPE, ir.OAS2FUNC, ir.OAS2MAPR, ir.OAS2RECV: return true } return false } func isNamedTypeSwitch(x ir.Node) bool { guard, ok := x.(*ir.TypeSwitchGuard) return ok && guard.Tag != nil } func simplifyForExport(n ir.Node) ir.Node { switch n.Op() { case ir.OPAREN: n := n.(*ir.ParenExpr) return simplifyForExport(n.X) } return n } // The name used for dictionary parameters or local variables. const LocalDictName = ".dict"