github.com/cloudwego/frugal@v0.1.15/internal/binary/decoder/skipping_emu.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      `math/bits`
    21      `unsafe`
    22  
    23      `github.com/cloudwego/frugal/internal/atm/hir`
    24      `github.com/cloudwego/frugal/internal/binary/defs`
    25  )
    26  
    27  type (
    28      _skipbuf_t [defs.StackSize]SkipItem
    29  )
    30  
    31  var _SkipSizeFixed = [256]int {
    32      defs.T_bool   : 1,
    33      defs.T_i8     : 1,
    34      defs.T_double : 8,
    35      defs.T_i16    : 2,
    36      defs.T_i32    : 4,
    37      defs.T_i64    : 8,
    38  }
    39  
    40  const (
    41      _T_list_elem defs.Tag = 0xfe
    42      _T_map_pair  defs.Tag = 0xff
    43  )
    44  
    45  func u32be(s unsafe.Pointer) int {
    46      return int(bits.ReverseBytes32(*(*uint32)(s)))
    47  }
    48  
    49  func stpop(s *_skipbuf_t, p *int) bool {
    50      if s[*p].N == 0 {
    51          *p--
    52          return true
    53      } else {
    54          s[*p].N--
    55          return false
    56      }
    57  }
    58  
    59  func stadd(s *_skipbuf_t, p *int, t defs.Tag) bool {
    60      if *p++; *p >= defs.StackSize {
    61          return false
    62      } else {
    63          s[*p].T, s[*p].N = t, 0
    64          return true
    65      }
    66  }
    67  
    68  func mvbuf(s *unsafe.Pointer, n *int, r *int, nb int) {
    69      *n = *n - nb
    70      *r = *r + nb
    71      *s = unsafe.Pointer(uintptr(*s) + uintptr(nb))
    72  }
    73  
    74  func do_skip(st *_skipbuf_t, s unsafe.Pointer, n int, t defs.Tag) (rv int) {
    75      sp := 0
    76      st[0].T = t
    77  
    78      /* run until drain */
    79      for sp >= 0 {
    80          switch st[sp].T {
    81              default: {
    82                  return ETAG
    83              }
    84  
    85              /* simple fixed types */
    86              case defs.T_bool   : fallthrough
    87              case defs.T_i8     : fallthrough
    88              case defs.T_double : fallthrough
    89              case defs.T_i16    : fallthrough
    90              case defs.T_i32    : fallthrough
    91              case defs.T_i64    : {
    92                  if nb := _SkipSizeFixed[st[sp].T]; n < nb {
    93                      return EEOF
    94                  } else {
    95                      stpop(st, &sp)
    96                      mvbuf(&s, &n, &rv, nb)
    97                  }
    98              }
    99  
   100              /* strings & binaries */
   101              case defs.T_string: {
   102                  if n < 4 {
   103                      return EEOF
   104                  } else if nb := u32be(s) + 4; n < nb {
   105                      return EEOF
   106                  } else {
   107                      stpop(st, &sp)
   108                      mvbuf(&s, &n, &rv, nb)
   109                  }
   110              }
   111  
   112              /* structs */
   113              case defs.T_struct: {
   114                  var nb int
   115                  var vt defs.Tag
   116  
   117                  /* must have at least 1 byte */
   118                  if n < 1 {
   119                      return EEOF
   120                  }
   121  
   122                  /* check for end of tag */
   123                  if vt = *(*defs.Tag)(s); vt == 0 {
   124                      stpop(st, &sp)
   125                      mvbuf(&s, &n, &rv, 1)
   126                      continue
   127                  }
   128  
   129                  /* check for tag value */
   130                  if !vt.IsWireTag() {
   131                      return ETAG
   132                  }
   133  
   134                  /* fast-path for primitive fields */
   135                  if nb = _SkipSizeFixed[vt]; nb != 0 {
   136                      if n < nb + 3 {
   137                          return EEOF
   138                      } else {
   139                          mvbuf(&s, &n, &rv, nb + 3)
   140                          continue
   141                      }
   142                  }
   143  
   144                  /* must have more than 3 bytes (fields cannot have a size of zero), also skip the field ID cause we don't care */
   145                  if n <= 3 {
   146                      return EEOF
   147                  } else if !stadd(st, &sp, vt) {
   148                      return ESTACK
   149                  } else {
   150                      mvbuf(&s, &n, &rv, 3)
   151                  }
   152              }
   153  
   154              /* maps */
   155              case defs.T_map: {
   156                  var np int
   157                  var kt defs.Tag
   158                  var vt defs.Tag
   159  
   160                  /* must have at least 6 bytes */
   161                  if n < 6 {
   162                      return EEOF
   163                  }
   164  
   165                  /* get the element type and count */
   166                  kt = (*[2]defs.Tag)(s)[0]
   167                  vt = (*[2]defs.Tag)(s)[1]
   168                  np = u32be(unsafe.Pointer(uintptr(s) + 2))
   169  
   170                  /* check for tag value */
   171                  if !kt.IsWireTag() || !vt.IsWireTag() {
   172                      return ETAG
   173                  }
   174  
   175                  /* empty map */
   176                  if np == 0 {
   177                      stpop(st, &sp)
   178                      mvbuf(&s, &n, &rv, 6)
   179                      continue
   180                  }
   181  
   182                  /* fast path for fixed key and value */
   183                  if nk, nv := _SkipSizeFixed[kt], _SkipSizeFixed[vt]; nk != 0 && nv != 0 {
   184                      if nb := np * (nk + nv) + 6; n < nb {
   185                          return EEOF
   186                      } else {
   187                          stpop(st, &sp)
   188                          mvbuf(&s, &n, &rv, nb)
   189                          continue
   190                      }
   191                  }
   192  
   193                  /* set to parse the map pairs */
   194                  st[sp].K = kt
   195                  st[sp].V = vt
   196                  st[sp].T = _T_map_pair
   197                  st[sp].N = uint32(np) * 2 - 1
   198                  mvbuf(&s, &n, &rv, 6)
   199              }
   200  
   201              /* map pairs */
   202              case _T_map_pair: {
   203                  if vt := st[sp].V; stpop(st, &sp) || st[sp].N & 1 != 0 {
   204                      if !stadd(st, &sp, vt) {
   205                          return ESTACK
   206                      }
   207                  } else {
   208                      if !stadd(st, &sp, st[sp].K) {
   209                          return ESTACK
   210                      }
   211                  }
   212              }
   213  
   214              /* sets and lists */
   215              case defs.T_set  : fallthrough
   216              case defs.T_list : {
   217                  var nv int
   218                  var et defs.Tag
   219  
   220                  /* must have at least 5 bytes */
   221                  if n < 5 {
   222                      return EEOF
   223                  }
   224  
   225                  /* get the element type and count */
   226                  et = *(*defs.Tag)(s)
   227                  nv = u32be(unsafe.Pointer(uintptr(s) + 1))
   228  
   229                  /* check for tag value */
   230                  if !et.IsWireTag() {
   231                      return ETAG
   232                  }
   233  
   234                  /* empty sequence */
   235                  if nv == 0 {
   236                      stpop(st, &sp)
   237                      mvbuf(&s, &n, &rv, 5)
   238                      continue
   239                  }
   240  
   241                  /* fast path for fixed types */
   242                  if nt := _SkipSizeFixed[et]; nt != 0 {
   243                      if nb := nv * nt + 5; n < nb {
   244                          return EEOF
   245                      } else {
   246                          stpop(st, &sp)
   247                          mvbuf(&s, &n, &rv, nb)
   248                          continue
   249                      }
   250                  }
   251  
   252                  /* set to parse the elements */
   253                  st[sp].T = _T_list_elem
   254                  st[sp].V = et
   255                  st[sp].N = uint32(nv) - 1
   256                  mvbuf(&s, &n, &rv, 5)
   257              }
   258  
   259              /* list elem */
   260              case _T_list_elem: {
   261                  et := st[sp].V
   262                  stpop(st, &sp)
   263  
   264                  /* push the element onto stack */
   265                  if !stadd(st, &sp, et) {
   266                     return ESTACK
   267                  }
   268              }
   269          }
   270      }
   271  
   272      /* all done */
   273      return
   274  }
   275  
   276  func emu_ccall_skip(ctx hir.CallContext) {
   277      if !ctx.Verify("**ii", "i") {
   278          panic("invalid skip call")
   279      } else {
   280          ctx.Ru(0, uint64(do_skip((*_skipbuf_t)(ctx.Ap(0)), ctx.Ap(1), int(ctx.Au(2)), defs.Tag(ctx.Au(3)))))
   281      }
   282  }