github.com/cloudwego/frugal@v0.1.15/internal/binary/decoder/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 decoder
    18  
    19  import (
    20      `fmt`
    21      `reflect`
    22      `sort`
    23      `strconv`
    24      `strings`
    25      `unsafe`
    26  
    27      `github.com/cloudwego/frugal/internal/binary/defs`
    28      `github.com/cloudwego/frugal/internal/opts`
    29      `github.com/cloudwego/frugal/internal/rt`
    30      `github.com/cloudwego/frugal/internal/utils`
    31  )
    32  
    33  type Instr struct {
    34      Op OpCode
    35      Tx defs.Tag
    36      Id uint16
    37      To int
    38      Iv int64
    39      Sw *int
    40      Vt *rt.GoType
    41      Fn unsafe.Pointer
    42  }
    43  
    44  func (self Instr) stab() string {
    45      t := self.IntSeq()
    46      s := make([]string, 0, self.Iv)
    47  
    48      /* convert to strings */
    49      for i, v := range t {
    50          if v >= 0 {
    51              s = append(s, fmt.Sprintf("%4ccase %d: L_%d\n", ' ', i, v))
    52          }
    53      }
    54  
    55      /* join them together */
    56      return fmt.Sprintf(
    57          "{\n%s}",
    58          strings.Join(s, ""),
    59      )
    60  }
    61  
    62  func (self Instr) rtab() string {
    63      t := self.IntSeq()
    64      s := make([]string, 0, self.Iv)
    65  
    66      /* convert to strings */
    67      for _, v := range t {
    68          s = append(s, strconv.Itoa(v))
    69      }
    70  
    71      /* join with ',' */
    72      return strings.Join(s, ", ")
    73  }
    74  
    75  func (self Instr) IntSeq() (p []int) {
    76      (*rt.GoSlice)(unsafe.Pointer(&p)).Cap = int(self.Iv)
    77      (*rt.GoSlice)(unsafe.Pointer(&p)).Len = int(self.Iv)
    78      (*rt.GoSlice)(unsafe.Pointer(&p)).Ptr = unsafe.Pointer(self.Sw)
    79      return
    80  }
    81  
    82  func (self Instr) Disassemble() string {
    83      switch self.Op {
    84          case OP_int               : fallthrough
    85          case OP_size              : fallthrough
    86          case OP_seek              : fallthrough
    87          case OP_struct_mark_tag   : return fmt.Sprintf("%-18s%d", self.Op, self.Iv)
    88          case OP_type              : return fmt.Sprintf("%-18s%d", self.Op, self.Tx)
    89          case OP_deref             : fallthrough
    90          case OP_map_alloc         : fallthrough
    91          case OP_map_set_i8        : fallthrough
    92          case OP_map_set_i16       : fallthrough
    93          case OP_map_set_i32       : fallthrough
    94          case OP_map_set_i64       : fallthrough
    95          case OP_map_set_str       : fallthrough
    96          case OP_map_set_enum      : fallthrough
    97          case OP_map_set_pointer   : fallthrough
    98          case OP_list_alloc        : fallthrough
    99          case OP_construct         : fallthrough
   100          case OP_defer             : return fmt.Sprintf("%-18s%s", self.Op, self.Vt)
   101          case OP_ctr_is_zero       : fallthrough
   102          case OP_struct_is_stop    : fallthrough
   103          case OP_goto              : return fmt.Sprintf("%-18sL_%d", self.Op, self.To)
   104          case OP_struct_bitmap     : fallthrough
   105          case OP_struct_require    : return fmt.Sprintf("%-18s%s", self.Op, self.rtab())
   106          case OP_struct_switch     : return fmt.Sprintf("%-18s%s", self.Op, self.stab())
   107          case OP_struct_check_type : return fmt.Sprintf("%-18s%d, L_%d", self.Op, self.Tx, self.To)
   108          case OP_initialize        : return fmt.Sprintf("%-18s*%p [%s]", self.Op, self.Fn, rt.FuncName(self.Fn))
   109          default                   : return self.Op.String()
   110      }
   111  }
   112  
   113  func mkins(op OpCode, dt defs.Tag, id uint16, to int, iv int64, sw []int, vt reflect.Type, fn unsafe.Pointer) Instr {
   114      return Instr {
   115          Op: op,
   116          Tx: dt,
   117          Id: id,
   118          To: to,
   119          Fn: fn,
   120          Vt: rt.UnpackType(vt),
   121          Iv: int64(len(sw)) | iv,
   122          Sw: (*int)((*rt.GoSlice)(unsafe.Pointer(&sw)).Ptr),
   123      }
   124  }
   125  
   126  type (
   127      Program []Instr
   128  )
   129  
   130  func (self Program) pc() int {
   131      return len(self)
   132  }
   133  
   134  func (self Program) pin(i int) {
   135      self[i].To = self.pc()
   136  }
   137  
   138  func (self Program) use(n int) {
   139      if n >= defs.StackSize {
   140          panic("type nesting too deep")
   141      }
   142  }
   143  
   144  func (self *Program) ins(iv Instr)                             { *self = append(*self, iv) }
   145  func (self *Program) add(op OpCode)                            { self.ins(mkins(op, 0, 0, 0, 0, nil, nil, nil)) }
   146  func (self *Program) jmp(op OpCode, to int)                    { self.ins(mkins(op, 0, 0, to, 0, nil, nil, nil)) }
   147  func (self *Program) i64(op OpCode, iv int64)                  { self.ins(mkins(op, 0, 0, 0, iv, nil, nil, nil)) }
   148  func (self *Program) tab(op OpCode, tv []int)                  { self.ins(mkins(op, 0, 0, 0, 0, tv, nil, nil)) }
   149  func (self *Program) tag(op OpCode, vt defs.Tag)               { self.ins(mkins(op, vt, 0, 0, 0, nil, nil, nil)) }
   150  func (self *Program) rtt(op OpCode, vt reflect.Type)           { self.ins(mkins(op, 0, 0, 0, 0, nil, vt, nil)) }
   151  func (self *Program) jsr(op OpCode, fn unsafe.Pointer)         { self.ins(mkins(op, 0, 0, 0, 0, nil, nil, fn)) }
   152  func (self *Program) jcc(op OpCode, vt defs.Tag, to int)       { self.ins(mkins(op, vt, 0, to, 0, nil, nil, nil)) }
   153  func (self *Program) req(op OpCode, vt reflect.Type, fv []int) { self.ins(mkins(op, 0, 0, 0, 0, fv, vt, nil)) }
   154  
   155  func (self Program) Free() {
   156      freeProgram(self)
   157  }
   158  
   159  func (self Program) Disassemble() string {
   160      nb  := len(self)
   161      tab := make([]bool, nb + 1)
   162      ret := make([]string, 0, nb + 1)
   163  
   164      /* prescan to get all the labels */
   165      for _, ins := range self {
   166          if _OpBranches[ins.Op] {
   167              if ins.Op != OP_struct_switch {
   168                  tab[ins.To] = true
   169              } else {
   170                  for _, v := range ins.IntSeq() {
   171                      if v >= 0 {
   172                          tab[v] = true
   173                      }
   174                  }
   175              }
   176          }
   177      }
   178  
   179      /* disassemble each instruction */
   180      for i, ins := range self {
   181          ln := ""
   182          ds := ins.Disassemble()
   183  
   184          /* check for label reference */
   185          if tab[i] {
   186              ret = append(ret, fmt.Sprintf("L_%d:", i))
   187          }
   188  
   189          /* indent each line */
   190          for _, ln = range strings.Split(ds, "\n") {
   191              ret = append(ret, "    " + ln)
   192          }
   193      }
   194  
   195      /* add the last label, if needed */
   196      if tab[nb] {
   197          ret = append(ret, fmt.Sprintf("L_%d:", nb))
   198      }
   199  
   200      /* add an "end" indicator, and join all the strings */
   201      return strings.Join(append(ret, "    end"), "\n")
   202  }
   203  
   204  type Compiler struct {
   205      o opts.Options
   206      t map[reflect.Type]bool
   207      d map[reflect.Type]struct{}
   208  }
   209  
   210  func CreateCompiler() *Compiler {
   211      return newCompiler()
   212  }
   213  
   214  func (self *Compiler) rescue(ep *error) {
   215      if val := recover(); val != nil {
   216          if err, ok := val.(error); ok {
   217              *ep = err
   218          } else {
   219              panic(val)
   220          }
   221      }
   222  }
   223  
   224  func (self *Compiler) compileDef(p *Program, vt *defs.Type) {
   225      p.rtt(OP_defer, vt.S)
   226      self.d[vt.S] = struct{}{}
   227  }
   228  
   229  func (self *Compiler) compileOne(p *Program, sp int, vt *defs.Type) {
   230      if vt.T == defs.T_pointer {
   231          self.compilePtr(p, sp, vt)
   232      } else if vt.T != defs.T_struct {
   233          self.compileRec(p, sp, vt)
   234      } else if _, ok := self.t[vt.S]; !ok && self.o.CanInline(sp, p.pc()) {
   235          self.compileTag(p, sp, vt)
   236      } else {
   237          self.compileDef(p, vt)
   238      }
   239  }
   240  
   241  func (self *Compiler) compileTag(p *Program, sp int, vt *defs.Type) {
   242      self.t[vt.S] = true
   243      self.compileRec(p, sp, vt)
   244      delete(self.t, vt.S)
   245  }
   246  
   247  func (self *Compiler) compileRec(p *Program, sp int, vt *defs.Type) {
   248      switch vt.T {
   249          case defs.T_bool   : p.i64(OP_size, 1); p.i64(OP_int, 1)
   250          case defs.T_i8     : p.i64(OP_size, 1); p.i64(OP_int, 1)
   251          case defs.T_i16    : p.i64(OP_size, 2); p.i64(OP_int, 2)
   252          case defs.T_i32    : p.i64(OP_size, 4); p.i64(OP_int, 4)
   253          case defs.T_i64    : p.i64(OP_size, 8); p.i64(OP_int, 8)
   254          case defs.T_double : p.i64(OP_size, 8); p.i64(OP_int, 8)
   255          case defs.T_string : p.i64(OP_size, 4); p.add(OP_str)
   256          case defs.T_binary : p.i64(OP_size, 4); p.add(OP_bin)
   257          case defs.T_enum   : p.i64(OP_size, 4); p.add(OP_enum)
   258          case defs.T_struct : self.compileStruct  (p, sp, vt)
   259          case defs.T_map    : self.compileMap     (p, sp, vt)
   260          case defs.T_set    : self.compileSetList (p, sp, vt.V)
   261          case defs.T_list   : self.compileSetList (p, sp, vt.V)
   262          default            : panic("unreachable")
   263      }
   264  }
   265  
   266  func (self *Compiler) compilePtr(p *Program, sp int, vt *defs.Type) {
   267      p.use(sp)
   268      p.add(OP_make_state)
   269      p.rtt(OP_deref, vt.V.S)
   270      self.compileOne(p, sp + 1, vt.V)
   271      p.add(OP_drop_state)
   272  }
   273  
   274  func (self *Compiler) compileMap(p *Program, sp int, vt *defs.Type) {
   275      p.use(sp)
   276      p.i64(OP_size, 6)
   277      p.tag(OP_type, vt.K.Tag())
   278      p.tag(OP_type, vt.V.Tag())
   279      p.add(OP_make_state)
   280      p.add(OP_ctr_load)
   281      p.rtt(OP_map_alloc, vt.S)
   282      i := p.pc()
   283      p.add(OP_ctr_is_zero)
   284      self.compileKey(p, sp + 1, vt)
   285      self.compileOne(p, sp + 1, vt.V)
   286      p.add(OP_ctr_decr)
   287      p.jmp(OP_goto, i)
   288      p.pin(i)
   289      p.add(OP_map_close)
   290      p.add(OP_drop_state)
   291  }
   292  
   293  func (self *Compiler) compileKey(p *Program, sp int, vt *defs.Type) {
   294      switch vt.K.T {
   295          case defs.T_bool    : p.i64(OP_size, 1); p.rtt(OP_map_set_i8, vt.S)
   296          case defs.T_i8      : p.i64(OP_size, 1); p.rtt(OP_map_set_i8, vt.S)
   297          case defs.T_double  : p.i64(OP_size, 8); p.rtt(OP_map_set_i64, vt.S)
   298          case defs.T_i16     : p.i64(OP_size, 2); p.rtt(OP_map_set_i16, vt.S)
   299          case defs.T_i32     : p.i64(OP_size, 4); p.rtt(OP_map_set_i32, vt.S)
   300          case defs.T_i64     : p.i64(OP_size, 8); p.rtt(OP_map_set_i64, vt.S)
   301          case defs.T_binary  : p.i64(OP_size, 4); p.rtt(OP_map_set_str, vt.S)
   302          case defs.T_string  : p.i64(OP_size, 4); p.rtt(OP_map_set_str, vt.S)
   303          case defs.T_enum    : p.i64(OP_size, 4); p.rtt(OP_map_set_enum, vt.S)
   304          case defs.T_pointer : self.compileKeyPtr(p, sp, vt)
   305          default             : panic("unreachable")
   306      }
   307  }
   308  
   309  func (self *Compiler) compileNoCopy(p *Program, sp int, vt *defs.Type) {
   310      switch {
   311          default: {
   312              panic("invalid nocopy type: " + vt.String())
   313          }
   314  
   315          /* simple strings */
   316          case vt.T == defs.T_string: {
   317              p.i64(OP_size, 4)
   318              p.add(OP_str_nocopy)
   319          }
   320  
   321          /* simple binaries */
   322          case vt.T == defs.T_binary: {
   323              p.i64(OP_size, 4)
   324              p.add(OP_bin_nocopy)
   325          }
   326  
   327          /* string pointers */
   328          case vt.T == defs.T_pointer && vt.V.T == defs.T_string: {
   329              p.use(sp)
   330              p.add(OP_make_state)
   331              p.rtt(OP_deref, vt.V.S)
   332              p.i64(OP_size, 4)
   333              p.add(OP_str_nocopy)
   334              p.add(OP_drop_state)
   335          }
   336  
   337          /* binary pointers */
   338          case vt.T == defs.T_pointer && vt.V.T == defs.T_binary: {
   339              p.use(sp)
   340              p.add(OP_make_state)
   341              p.rtt(OP_deref, vt.V.S)
   342              p.i64(OP_size, 4)
   343              p.add(OP_bin_nocopy)
   344              p.add(OP_drop_state)
   345          }
   346      }
   347  }
   348  
   349  func (self *Compiler) compileKeyPtr(p *Program, sp int, vt *defs.Type) {
   350      pt := vt.K
   351      st := pt.V
   352  
   353      /* must be a struct */
   354      if st.T != defs.T_struct {
   355          panic("map key cannot be non-struct pointers")
   356      }
   357  
   358      /* construct a new object */
   359      p.rtt(OP_construct, st.S)
   360      self.compileOne(p, sp, st)
   361      p.rtt(OP_map_set_pointer, vt.S)
   362  }
   363  
   364  func (self *Compiler) compileStruct(p *Program, sp int, vt *defs.Type) {
   365      var fid int
   366      var err error
   367      var req []int
   368      var fvs []defs.Field
   369      var ifn unsafe.Pointer
   370  
   371      /* resolve the fields */
   372      if fvs, err = defs.ResolveFields(vt.S); err != nil {
   373          panic(err)
   374      }
   375  
   376      /* empty struct */
   377      if len(fvs) == 0 {
   378          p.add(OP_struct_ignore)
   379          return
   380      }
   381  
   382      /* find the default initializer */
   383      if ifn, err = defs.GetDefaultInitializer(vt.S); err != nil {
   384          panic(err)
   385      }
   386  
   387      /* call the initializer if any */
   388      if ifn != nil {
   389          p.jsr(OP_initialize, ifn)
   390      }
   391  
   392      /* find the maximum field IDs */
   393      for _, fv := range fvs {
   394          if fid = utils.MaxInt(fid, int(fv.ID)); fv.Spec == defs.Required {
   395              req = append(req, int(fv.ID))
   396          }
   397      }
   398  
   399      /* save the current state */
   400      p.use(sp)
   401      p.add(OP_make_state)
   402  
   403      /* allocate bitmap for required fields, if needed */
   404      if sort.Ints(req); len(req) != 0 {
   405          p.tab(OP_struct_bitmap, req)
   406      }
   407  
   408      /* switch jump buffer */
   409      i := p.pc()
   410      s := make([]int, fid + 1)
   411  
   412      /* set the default branch */
   413      for v := range s {
   414          s[v] = -1
   415      }
   416  
   417      /* dispatch the next field */
   418      p.i64(OP_size, 1)
   419      p.add(OP_struct_read_type)
   420      j := p.pc()
   421      p.add(OP_struct_is_stop)
   422      p.i64(OP_size, 2)
   423      p.tab(OP_struct_switch, s)
   424      k := p.pc()
   425      p.add(OP_struct_skip)
   426      p.jmp(OP_goto, i)
   427  
   428      /* assemble every field */
   429      for _, fv := range fvs {
   430          s[fv.ID] = p.pc()
   431          p.jcc(OP_struct_check_type, fv.Type.Tag(), k)
   432  
   433          /* mark the field as seen, if needed */
   434          if fv.Spec == defs.Required {
   435              p.i64(OP_struct_mark_tag, int64(fv.ID))
   436          }
   437  
   438          /* seek to the field */
   439          off := int64(fv.F)
   440          p.i64(OP_seek, off)
   441  
   442          /* check for no-copy strings */
   443          if fv.Opts & defs.NoCopy == 0 {
   444              self.compileOne(p, sp + 1, fv.Type)
   445          } else if fv.Type.Tag() == defs.T_string {
   446              self.compileNoCopy(p, sp + 1, fv.Type)
   447          } else {
   448              panic(`"nocopy" is only applicable to "string" or "binary" types`)
   449          }
   450  
   451          /* seek back to the beginning */
   452          p.i64(OP_seek, -off)
   453          p.jmp(OP_goto, i)
   454      }
   455  
   456      /* no required fields */
   457      if p.pin(j); len(req) == 0 {
   458          p.add(OP_drop_state)
   459          return
   460      }
   461  
   462      /* check all the required fields */
   463      p.req(OP_struct_require, vt.S, req)
   464      p.add(OP_drop_state)
   465  }
   466  
   467  func (self *Compiler) compileSetList(p *Program, sp int, et *defs.Type) {
   468      p.use(sp)
   469      p.i64(OP_size, 5)
   470      p.tag(OP_type, et.Tag())
   471      p.add(OP_make_state)
   472      p.add(OP_ctr_load)
   473      p.rtt(OP_list_alloc, et.S)
   474      i := p.pc()
   475      p.add(OP_ctr_is_zero)
   476      j := p.pc()
   477      self.compileOne(p, sp + 1, et)
   478      p.add(OP_ctr_decr)
   479      k := p.pc()
   480      p.add(OP_ctr_is_zero)
   481      p.i64(OP_seek, int64(et.S.Size()))
   482      p.jmp(OP_goto, j)
   483      p.pin(i)
   484      p.pin(k)
   485      p.add(OP_drop_state)
   486  }
   487  
   488  func (self *Compiler) Free() {
   489      freeCompiler(self)
   490  }
   491  
   492  func (self *Compiler) Apply(o opts.Options) *Compiler {
   493      self.o = o
   494      return self
   495  }
   496  
   497  func (self *Compiler) Compile(vt reflect.Type) (_ Program, err error) {
   498      ret := newProgram()
   499      vtp := (*defs.Type)(nil)
   500  
   501      /* parse the type */
   502      if vtp, err = defs.ParseType(vt, ""); err != nil {
   503          return nil, err
   504      }
   505  
   506      /* catch the exceptions, and free the type */
   507      defer self.rescue(&err)
   508      defer vtp.Free()
   509  
   510      /* compile the actual type */
   511      self.compileOne(&ret, 0, vtp)
   512      ret.add(OP_halt)
   513      return Optimize(ret), nil
   514  }
   515  
   516  func (self *Compiler) CompileAndFree(vt reflect.Type) (ret Program, err error) {
   517      ret, err = self.Compile(vt)
   518      self.Free()
   519      return
   520  }