1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package gcprog
25
26 import (
27 "fmt"
28 "io"
29 )
30
31 const progMaxLiteral = 127
32
33
34
35
36
37
38 type Writer struct {
39 writeByte func(byte)
40 index int64
41 b [progMaxLiteral]byte
42 nb int
43 debug io.Writer
44 debugBuf []byte
45 }
46
47
48
49 func (w *Writer) Init(writeByte func(byte)) {
50 w.writeByte = writeByte
51 }
52
53
54
55
56 func (w *Writer) Debug(out io.Writer) {
57 w.debug = out
58 }
59
60
61 func (w *Writer) BitIndex() int64 {
62 return w.index
63 }
64
65
66 func (w *Writer) byte(x byte) {
67 if w.debug != nil {
68 w.debugBuf = append(w.debugBuf, x)
69 }
70 w.writeByte(x)
71 }
72
73
74 func (w *Writer) End() {
75 w.flushlit()
76 w.byte(0)
77 if w.debug != nil {
78 index := progbits(w.debugBuf)
79 if index != w.index {
80 println("gcprog: End wrote program for", index, "bits, but current index is", w.index)
81 panic("gcprog: out of sync")
82 }
83 }
84 }
85
86
87
88
89
90 func (w *Writer) Ptr(index int64) {
91 if index < w.index {
92 println("gcprog: Ptr at index", index, "but current index is", w.index)
93 panic("gcprog: invalid Ptr index")
94 }
95 w.ZeroUntil(index)
96 if w.debug != nil {
97 fmt.Fprintf(w.debug, "gcprog: ptr at %d\n", index)
98 }
99 w.lit(1)
100 }
101
102
103
104
105 func (w *Writer) ShouldRepeat(n, c int64) bool {
106
107
108
109
110
111
112
113 return c > 1 && c*n > 4*8
114 }
115
116
117
118 func (w *Writer) Repeat(n, c int64) {
119 if n == 0 || c == 0 {
120 return
121 }
122 w.flushlit()
123 if w.debug != nil {
124 fmt.Fprintf(w.debug, "gcprog: repeat %d × %d\n", n, c)
125 }
126 if n < 128 {
127 w.byte(0x80 | byte(n))
128 } else {
129 w.byte(0x80)
130 w.varint(n)
131 }
132 w.varint(c)
133 w.index += n * c
134 }
135
136
137
138
139
140 func (w *Writer) ZeroUntil(index int64) {
141 if index < w.index {
142 println("gcprog: Advance", index, "but index is", w.index)
143 panic("gcprog: invalid Advance index")
144 }
145 skip := (index - w.index)
146 if skip == 0 {
147 return
148 }
149 if skip < 4*8 {
150 if w.debug != nil {
151 fmt.Fprintf(w.debug, "gcprog: advance to %d by literals\n", index)
152 }
153 for i := int64(0); i < skip; i++ {
154 w.lit(0)
155 }
156 return
157 }
158
159 if w.debug != nil {
160 fmt.Fprintf(w.debug, "gcprog: advance to %d by repeat\n", index)
161 }
162 w.lit(0)
163 w.flushlit()
164 w.Repeat(1, skip-1)
165 }
166
167
168
169
170 func (w *Writer) Append(prog []byte, n int64) {
171 w.flushlit()
172 if w.debug != nil {
173 fmt.Fprintf(w.debug, "gcprog: append prog for %d ptrs\n", n)
174 fmt.Fprintf(w.debug, "\t")
175 }
176 n1 := progbits(prog)
177 if n1 != n {
178 panic("gcprog: wrong bit count in append")
179 }
180
181
182 for i, x := range prog[:len(prog)-1] {
183 if w.debug != nil {
184 if i > 0 {
185 fmt.Fprintf(w.debug, " ")
186 }
187 fmt.Fprintf(w.debug, "%02x", x)
188 }
189 w.byte(x)
190 }
191 if w.debug != nil {
192 fmt.Fprintf(w.debug, "\n")
193 }
194 w.index += n
195 }
196
197
198 func progbits(p []byte) int64 {
199 var n int64
200 for len(p) > 0 {
201 x := p[0]
202 p = p[1:]
203 if x == 0 {
204 break
205 }
206 if x&0x80 == 0 {
207 count := x &^ 0x80
208 n += int64(count)
209 p = p[(count+7)/8:]
210 continue
211 }
212 nbit := int64(x &^ 0x80)
213 if nbit == 0 {
214 nbit, p = readvarint(p)
215 }
216 var count int64
217 count, p = readvarint(p)
218 n += nbit * count
219 }
220 if len(p) > 0 {
221 println("gcprog: found end instruction after", n, "ptrs, with", len(p), "bytes remaining")
222 panic("gcprog: extra data at end of program")
223 }
224 return n
225 }
226
227
228 func readvarint(p []byte) (int64, []byte) {
229 var v int64
230 var nb uint
231 for {
232 c := p[0]
233 p = p[1:]
234 v |= int64(c&^0x80) << nb
235 nb += 7
236 if c&0x80 == 0 {
237 break
238 }
239 }
240 return v, p
241 }
242
243
244 func (w *Writer) lit(x byte) {
245 if w.nb == progMaxLiteral {
246 w.flushlit()
247 }
248 w.b[w.nb] = x
249 w.nb++
250 w.index++
251 }
252
253
254 func (w *Writer) varint(x int64) {
255 if x < 0 {
256 panic("gcprog: negative varint")
257 }
258 for x >= 0x80 {
259 w.byte(byte(0x80 | x))
260 x >>= 7
261 }
262 w.byte(byte(x))
263 }
264
265
266 func (w *Writer) flushlit() {
267 if w.nb == 0 {
268 return
269 }
270 if w.debug != nil {
271 fmt.Fprintf(w.debug, "gcprog: flush %d literals\n", w.nb)
272 fmt.Fprintf(w.debug, "\t%v\n", w.b[:w.nb])
273 fmt.Fprintf(w.debug, "\t%02x", byte(w.nb))
274 }
275 w.byte(byte(w.nb))
276 var bits uint8
277 for i := 0; i < w.nb; i++ {
278 bits |= w.b[i] << uint(i%8)
279 if (i+1)%8 == 0 {
280 if w.debug != nil {
281 fmt.Fprintf(w.debug, " %02x", bits)
282 }
283 w.byte(bits)
284 bits = 0
285 }
286 }
287 if w.nb%8 != 0 {
288 if w.debug != nil {
289 fmt.Fprintf(w.debug, " %02x", bits)
290 }
291 w.byte(bits)
292 }
293 if w.debug != nil {
294 fmt.Fprintf(w.debug, "\n")
295 }
296 w.nb = 0
297 }
298
View as plain text