Source file src/cmd/go/internal/modindex/write.go

     1  // Copyright 2022 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package modindex
     6  
     7  import (
     8  	"cmd/go/internal/base"
     9  	"encoding/binary"
    10  	"go/token"
    11  	"sort"
    12  )
    13  
    14  const indexVersion = "go index v2" // 11 bytes (plus \n), to align uint32s in index
    15  
    16  // encodeModuleBytes produces the encoded representation of the module index.
    17  // encodeModuleBytes may modify the packages slice.
    18  func encodeModuleBytes(packages []*rawPackage) []byte {
    19  	e := newEncoder()
    20  	e.Bytes([]byte(indexVersion + "\n"))
    21  	stringTableOffsetPos := e.Pos() // fill this at the end
    22  	e.Uint32(0)                     // string table offset
    23  	sort.Slice(packages, func(i, j int) bool {
    24  		return packages[i].dir < packages[j].dir
    25  	})
    26  	e.Int(len(packages))
    27  	packagesPos := e.Pos()
    28  	for _, p := range packages {
    29  		e.String(p.dir)
    30  		e.Int(0)
    31  	}
    32  	for i, p := range packages {
    33  		e.IntAt(e.Pos(), packagesPos+8*i+4)
    34  		encodePackage(e, p)
    35  	}
    36  	e.IntAt(e.Pos(), stringTableOffsetPos)
    37  	e.Bytes(e.stringTable)
    38  	e.Bytes([]byte{0xFF}) // end of string table marker
    39  	return e.b
    40  }
    41  
    42  func encodePackageBytes(p *rawPackage) []byte {
    43  	return encodeModuleBytes([]*rawPackage{p})
    44  }
    45  
    46  func encodePackage(e *encoder, p *rawPackage) {
    47  	e.String(p.error)
    48  	e.String(p.dir)
    49  	e.Int(len(p.sourceFiles))      // number of source files
    50  	sourceFileOffsetPos := e.Pos() // the pos of the start of the source file offsets
    51  	for range p.sourceFiles {
    52  		e.Int(0)
    53  	}
    54  	for i, f := range p.sourceFiles {
    55  		e.IntAt(e.Pos(), sourceFileOffsetPos+4*i)
    56  		encodeFile(e, f)
    57  	}
    58  }
    59  
    60  func encodeFile(e *encoder, f *rawFile) {
    61  	e.String(f.error)
    62  	e.String(f.parseError)
    63  	e.String(f.synopsis)
    64  	e.String(f.name)
    65  	e.String(f.pkgName)
    66  	e.Bool(f.ignoreFile)
    67  	e.Bool(f.binaryOnly)
    68  	e.String(f.cgoDirectives)
    69  	e.String(f.goBuildConstraint)
    70  
    71  	e.Int(len(f.plusBuildConstraints))
    72  	for _, s := range f.plusBuildConstraints {
    73  		e.String(s)
    74  	}
    75  
    76  	e.Int(len(f.imports))
    77  	for _, m := range f.imports {
    78  		e.String(m.path)
    79  		e.Position(m.position)
    80  	}
    81  
    82  	e.Int(len(f.embeds))
    83  	for _, embed := range f.embeds {
    84  		e.String(embed.pattern)
    85  		e.Position(embed.position)
    86  	}
    87  
    88  	e.Int(len(f.directives))
    89  	for _, d := range f.directives {
    90  		e.String(d.Text)
    91  		e.Position(d.Pos)
    92  	}
    93  }
    94  
    95  func newEncoder() *encoder {
    96  	e := &encoder{strings: make(map[string]int)}
    97  
    98  	// place the empty string at position 0 in the string table
    99  	e.stringTable = append(e.stringTable, 0)
   100  	e.strings[""] = 0
   101  
   102  	return e
   103  }
   104  
   105  func (e *encoder) Position(position token.Position) {
   106  	e.String(position.Filename)
   107  	e.Int(position.Offset)
   108  	e.Int(position.Line)
   109  	e.Int(position.Column)
   110  }
   111  
   112  type encoder struct {
   113  	b           []byte
   114  	stringTable []byte
   115  	strings     map[string]int
   116  }
   117  
   118  func (e *encoder) Pos() int {
   119  	return len(e.b)
   120  }
   121  
   122  func (e *encoder) Bytes(b []byte) {
   123  	e.b = append(e.b, b...)
   124  }
   125  
   126  func (e *encoder) String(s string) {
   127  	if n, ok := e.strings[s]; ok {
   128  		e.Int(n)
   129  		return
   130  	}
   131  	pos := len(e.stringTable)
   132  	e.strings[s] = pos
   133  	e.Int(pos)
   134  	e.stringTable = binary.AppendUvarint(e.stringTable, uint64(len(s)))
   135  	e.stringTable = append(e.stringTable, s...)
   136  }
   137  
   138  func (e *encoder) Bool(b bool) {
   139  	if b {
   140  		e.Uint32(1)
   141  	} else {
   142  		e.Uint32(0)
   143  	}
   144  }
   145  
   146  func (e *encoder) Uint32(n uint32) {
   147  	e.b = binary.LittleEndian.AppendUint32(e.b, n)
   148  }
   149  
   150  // Int encodes n. Note that all ints are written to the index as uint32s,
   151  // and to avoid problems on 32-bit systems we require fitting into a 32-bit int.
   152  func (e *encoder) Int(n int) {
   153  	if n < 0 || int(int32(n)) != n {
   154  		base.Fatalf("go: attempting to write an int to the index that overflows int32")
   155  	}
   156  	e.Uint32(uint32(n))
   157  }
   158  
   159  func (e *encoder) IntAt(n int, at int) {
   160  	if n < 0 || int(int32(n)) != n {
   161  		base.Fatalf("go: attempting to write an int to the index that overflows int32")
   162  	}
   163  	binary.LittleEndian.PutUint32(e.b[at:], uint32(n))
   164  }
   165  

View as plain text