github.com/cloudwego/frugal@v0.1.15/internal/binary/encoder/compiler.go (about)

     1  /*
     2   * Copyright 2022 ByteDance Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package encoder
    18  
    19  import (
    20      `fmt`
    21      `reflect`
    22      `strings`
    23      `unsafe`
    24  
    25      `github.com/cloudwego/frugal/internal/binary/defs`
    26      `github.com/cloudwego/frugal/internal/opts`
    27      `github.com/cloudwego/frugal/internal/rt`
    28  )
    29  
    30  type Instr struct {
    31      Op OpCode
    32      Uv int32
    33      Iv int64
    34      To int
    35      Pr unsafe.Pointer
    36  }
    37  
    38  type (
    39      Program []Instr
    40  )
    41  
    42  func (self Instr) Vt() *rt.GoType {
    43      return (*rt.GoType)(self.Pr)
    44  }
    45  
    46  func (self Instr) Str() string {
    47      return rt.StringFrom(self.Pr, int(self.Uv))
    48  }
    49  
    50  func (self Instr) Byte(i int64) int8 {
    51      return *(*int8)(unsafe.Pointer(uintptr(self.Pr) + uintptr(i)))
    52  }
    53  
    54  func (self Instr) Word(i int64) int16 {
    55      return *(*int16)(unsafe.Pointer(uintptr(self.Pr) + uintptr(i)))
    56  }
    57  
    58  func (self Instr) Long(i int64) int32 {
    59      return *(*int32)(unsafe.Pointer(uintptr(self.Pr) + uintptr(i)))
    60  }
    61  
    62  func (self Instr) Quad(i int64) int64 {
    63      return *(*int64)(unsafe.Pointer(uintptr(self.Pr) + uintptr(i)))
    64  }
    65  
    66  func (self Instr) Disassemble() string {
    67      switch self.Op {
    68          case OP_size_check    : fallthrough
    69          case OP_size_const    : fallthrough
    70          case OP_size_map      : fallthrough
    71          case OP_seek          : fallthrough
    72          case OP_sint          : fallthrough
    73          case OP_length        : return fmt.Sprintf("%-18s%d", self.Op, self.Iv)
    74          case OP_size_dyn      : fallthrough
    75          case OP_memcpy_be     : return fmt.Sprintf("%-18s%d, %d", self.Op, self.Uv, self.Iv)
    76          case OP_size_defer    : fallthrough
    77          case OP_defer         : fallthrough
    78          case OP_map_begin     : fallthrough
    79          case OP_unique        : return fmt.Sprintf("%-18s%s", self.Op, self.Vt())
    80          case OP_byte          : return fmt.Sprintf("%-18s0x%02x", self.Op, self.Iv)
    81          case OP_word          : return fmt.Sprintf("%-18s0x%04x", self.Op, self.Iv)
    82          case OP_long          : return fmt.Sprintf("%-18s0x%08x", self.Op, self.Iv)
    83          case OP_quad          : return fmt.Sprintf("%-18s0x%016x", self.Op, self.Iv)
    84          case OP_map_if_next   : fallthrough
    85          case OP_map_if_empty  : fallthrough
    86          case OP_list_if_next  : fallthrough
    87          case OP_list_if_empty : fallthrough
    88          case OP_goto          : fallthrough
    89          case OP_if_nil        : fallthrough
    90          case OP_if_hasbuf     : return fmt.Sprintf("%-18sL_%d", self.Op, self.To)
    91          case OP_if_eq_imm     : return fmt.Sprintf("%-18s%d:%d, L_%d", self.Op, self.Iv, self.Uv, self.To)
    92          case OP_if_eq_str     : return fmt.Sprintf("%-18s%q, L_%d", self.Op, self.Str(), self.To)
    93          default               : return self.Op.String()
    94      }
    95  }
    96  
    97  func (self Program) pc() int   { return len(self) }
    98  func (self Program) pin(i int) { self[i].To = self.pc() }
    99  
   100  func (self Program) tag(n int) {
   101      if n >= defs.StackSize {
   102          panic("type nesting too deep")
   103      }
   104  }
   105  
   106  func (self *Program) ins(iv Instr)                      { *self = append(*self, iv) }
   107  func (self *Program) add(op OpCode)                     { self.ins(Instr { Op: op }) }
   108  func (self *Program) jmp(op OpCode, to int)             { self.ins(Instr { Op: op, To: to }) }
   109  func (self *Program) i64(op OpCode, iv int64)           { self.ins(Instr { Op: op, Iv: iv }) }
   110  func (self *Program) str(op OpCode, sv string)          { self.ins(Instr { Op: op, Iv: int64(len(sv)), Pr: rt.StringPtr(sv) }) }
   111  func (self *Program) rtt(op OpCode, vt reflect.Type)    { self.ins(Instr { Op: op, Pr: unsafe.Pointer(rt.UnpackType(vt)) }) }
   112  func (self *Program) dyn(op OpCode, uv int32, iv int64) { self.ins(Instr { Op: op, Uv: uv, Iv: iv }) }
   113  
   114  func (self Program) Free() {
   115      freeProgram(self)
   116  }
   117  
   118  func (self Program) Disassemble() string {
   119      nb  := len(self)
   120      tab := make([]bool, nb + 1)
   121      ret := make([]string, 0, nb + 1)
   122  
   123      /* prescan to get all the labels */
   124      for _, ins := range self {
   125          if _OpBranches[ins.Op] {
   126              tab[ins.To] = true
   127          }
   128      }
   129  
   130      /* disassemble each instruction */
   131      for i, ins := range self {
   132          if !tab[i] {
   133              ret = append(ret, "    " + ins.Disassemble())
   134          } else {
   135              ret = append(ret, fmt.Sprintf("L_%d:\n    %s", i, ins.Disassemble()))
   136          }
   137      }
   138  
   139      /* add an "end" indicator, and join all the strings */
   140      if !tab[nb] {
   141          return strings.Join(append(ret, "    end"), "\n")
   142      } else {
   143          return strings.Join(append(ret, fmt.Sprintf("L_%d:", nb), "    end"), "\n")
   144      }
   145  }
   146  
   147  type Compiler struct {
   148      o opts.Options
   149      t map[reflect.Type]bool
   150  }
   151  
   152  func CreateCompiler() *Compiler {
   153      return newCompiler()
   154  }
   155  
   156  func (self *Compiler) rescue(ep *error) {
   157      if val := recover(); val != nil {
   158          if err, ok := val.(error); ok {
   159              *ep = err
   160          } else {
   161              panic(val)
   162          }
   163      }
   164  }
   165  
   166  func (self *Compiler) Free() {
   167      freeCompiler(self)
   168  }
   169  
   170  func (self *Compiler) Apply(o opts.Options) *Compiler {
   171      self.o = o
   172      return self
   173  }
   174  
   175  func (self *Compiler) Compile(vt reflect.Type) (_ Program, err error) {
   176      ret := newProgram()
   177      vtp := (*defs.Type)(nil)
   178  
   179      /* parse the type */
   180      if vtp, err = defs.ParseType(vt, ""); err != nil {
   181          return nil, err
   182      }
   183  
   184      /* catch the exceptions, and free the type */
   185      defer self.rescue(&err)
   186      defer vtp.Free()
   187  
   188      /* object measuring */
   189      i := ret.pc()
   190      ret.add(OP_if_hasbuf)
   191      resetCompiler(self).measure(&ret, 0, vtp, ret.pc())
   192  
   193      /* object encoding */
   194      j := ret.pc()
   195      ret.add(OP_goto)
   196      ret.pin(i)
   197      resetCompiler(self).compile(&ret, 0, vtp, ret.pc())
   198  
   199      /* halt the program */
   200      ret.pin(j)
   201      ret.add(OP_halt)
   202      return Optimize(ret), nil
   203  }
   204  
   205  func (self *Compiler) CompileAndFree(vt reflect.Type) (ret Program, err error) {
   206      ret, err = self.Compile(vt)
   207      self.Free()
   208      return
   209  }