github.com/coyove/nj@v0.0.0-20221110084952-c7f8db1065c3/internal/vbyte.go (about) 1 package internal 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "unicode/utf8" 7 "unsafe" 8 9 "github.com/coyove/nj/typ" 10 ) 11 12 const ( 13 MaxStackSize = 0x0fffffff 14 ) 15 16 type VByte32 struct { 17 Name string 18 b []byte 19 Offset uint32 20 } 21 22 func (p *VByte32) Len() int { 23 return len(p.b) 24 } 25 26 func (p *VByte32) Append(idx uint32, line uint32) { 27 v := func(v uint64) { 28 p.b = append(p.b, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) 29 n := binary.PutUvarint(p.b[p.Len()-10:], v) 30 p.b = p.b[:p.Len()-10+n] 31 } 32 v(uint64(idx)) 33 v(uint64(line)) 34 } 35 36 func (p *VByte32) Pop() (idx, line uint32) { 37 rd := p.b 38 a, n := binary.Uvarint(rd) 39 b, n2 := binary.Uvarint(rd[n:]) 40 if n == 0 || n2 == 0 { 41 p.b = p.b[:0] 42 return 43 } 44 p.b = p.b[n+n2:] 45 return uint32(a) + p.Offset, uint32(b) 46 } 47 48 func (p *VByte32) Read(i int) (next int, idx, line uint32) { 49 rd := p.b[i:] 50 a, n := binary.Uvarint(rd) 51 b, n2 := binary.Uvarint(rd[n:]) 52 if n == 0 || n2 == 0 { 53 next = p.Len() + 1 54 return 55 } 56 return i + n + n2, uint32(a) + p.Offset, uint32(b) 57 } 58 59 type Packet struct { 60 Code []typ.Inst 61 Pos VByte32 62 } 63 64 func (b *Packet) CodePtr() uintptr { 65 return uintptr(*(*unsafe.Pointer)(unsafe.Pointer(&b.Code))) 66 } 67 68 func (b *Packet) check() { 69 if b.Len() >= MaxStackSize-1 { 70 panic("too much code") 71 } 72 } 73 74 func (b *Packet) WriteInst(op byte, opa, opb uint16) { 75 if op == typ.OpSet { 76 if opa == opb { 77 /* 78 form: 79 set v v 80 */ 81 return 82 } 83 if opb == typ.RegA && len(b.Code) > 0 { 84 /* 85 form: 86 load subject key $a 87 set dest $a 88 into: 89 load subject key dest 90 */ 91 x := b.LastInst() 92 if (x.Opcode == typ.OpLoad || x.OpcodeExt == typ.OpExtLoad16) && x.C == typ.RegA { 93 x.C = opa 94 return 95 } 96 } 97 if opb == typ.RegA && len(b.Code) > 0 { 98 /* 99 form: 100 add v num 101 set v $a 102 into: 103 inc v num 104 note that 'add num v' is not optimizable because 'add' also applies on strings 105 */ 106 x := b.LastInst() 107 if x.Opcode == typ.OpAdd && x.A == opa { 108 x.Opcode = typ.OpInc 109 return 110 } 111 } 112 if opb == typ.RegA && len(b.Code) > 0 { 113 /* 114 form: 115 copyclosure idx 1 $a 116 set v $a 117 into: 118 copyclosure idx 1 v 119 */ 120 x := b.LastInst() 121 if x.Opcode == typ.OpFunction && x.B == 1 { 122 x.C = opa 123 return 124 } 125 } 126 } 127 b.Code = append(b.Code, typ.Inst{Opcode: op, A: opa, B: opb}) 128 b.check() 129 } 130 131 func (b *Packet) WriteInst3(op byte, opa, opb, opc uint16) { 132 if op == typ.OpLoad && len(b.Code) > 0 { 133 /* 134 form: 135 loadtop idx phantom -> dest 136 load dest key -> dest2 137 into: 138 loadtop idx key -> dest2 139 */ 140 x := b.LastInst() 141 if x.Opcode == typ.OpLoadTop && x.B == typ.RegPhantom && opa == x.C { 142 x.B, x.C = opb, opc 143 return 144 } 145 } 146 b.Code = append(b.Code, typ.Inst{Opcode: op, A: opa, B: opb, C: opc}) 147 b.check() 148 } 149 150 func (b *Packet) WriteInst3Ext(sub byte, opa, opb, opc uint16) { 151 b.Code = append(b.Code, typ.Inst{Opcode: typ.OpExt, OpcodeExt: sub, A: opa, B: opb, C: opc}) 152 b.check() 153 } 154 155 func (b *Packet) WriteInst2Ext(sub byte, opa, opb uint16) { 156 b.Code = append(b.Code, typ.Inst{Opcode: typ.OpExt, OpcodeExt: sub, A: opa, B: opb}) 157 b.check() 158 } 159 160 func (b *Packet) WriteJmpInst(op byte, d int) { 161 b.Code = append(b.Code, typ.JmpInst(op, d)) 162 b.check() 163 } 164 165 func (b *Packet) WriteLineNum(line uint32) { 166 if line == 0 { 167 ShouldNotHappen() 168 } 169 b.Pos.Append(uint32(len(b.Code)-1), line) 170 } 171 172 func (b *Packet) TruncLast() { 173 if len(b.Code) > 0 { 174 b.Code = b.Code[:len(b.Code)-1] 175 } 176 } 177 178 func (b *Packet) Len() int { 179 return len(b.Code) 180 } 181 182 func (b *Packet) LastInst() *typ.Inst { 183 if len(b.Code) == 0 { 184 return nil 185 } 186 return &b.Code[len(b.Code)-1] 187 } 188 189 func (b *Packet) Copy() *Packet { 190 b2 := *b 191 b2.Code = append([]typ.Inst{}, b.Code...) 192 return &b2 193 } 194 195 type LimitedBuffer struct { 196 Limit int 197 bytes.Buffer 198 } 199 200 func (w *LimitedBuffer) Write(b []byte) (int, error) { 201 if w.Limit > 0 { 202 if w.Len()+len(b) > w.Limit { 203 if _, err := w.Buffer.Write(b[:w.Limit-w.Len()]); err != nil { 204 return 0, err 205 } 206 return len(b), nil 207 } 208 } 209 return w.Buffer.Write(b) 210 } 211 212 func (w *LimitedBuffer) WriteString(b string) (int, error) { 213 if w.Limit > 0 { 214 if w.Len()+len(b) > w.Limit { 215 if _, err := w.Buffer.WriteString(b[:w.Limit-w.Len()]); err != nil { 216 return 0, err 217 } 218 return len(b), nil 219 } 220 } 221 return w.Buffer.WriteString(b) 222 } 223 224 func (w *LimitedBuffer) WriteByte(b byte) error { 225 if w.Limit > 0 { 226 if w.Len()+1 > w.Limit { 227 return nil 228 } 229 } 230 return w.Buffer.WriteByte(b) 231 } 232 233 func (w *LimitedBuffer) WriteRune(b rune) (int, error) { 234 if w.Limit > 0 { 235 sz := utf8.RuneLen(b) 236 if w.Len()+sz > w.Limit { 237 return sz, nil 238 } 239 } 240 return w.Buffer.WriteRune(b) 241 } 242 243 func CreateRawBytesInst(name string) []typ.Inst { 244 bn := len(name) / int(typ.InstSize) 245 if bn*int(typ.InstSize) != len(name) { 246 bn++ 247 } 248 blocks := make([]typ.Inst, bn) 249 var dummy []byte 250 *(*[3]int)(unsafe.Pointer(&dummy)) = [3]int{*(*int)(unsafe.Pointer(&blocks)), len(name), len(name)} 251 copy(dummy, name) 252 return blocks 253 }