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