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