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  }