...

Source file src/github.com/bytedance/sonic/loader/funcdata.go

Documentation: github.com/bytedance/sonic/loader

     1  /**
     2   * Copyright 2023 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 loader
    18  
    19  import (
    20      `encoding`
    21      `encoding/binary`
    22      `fmt`
    23      `reflect`
    24      `strings`
    25      `sync`
    26      `unsafe`
    27  )
    28  
    29  const (
    30      _MinLC uint8 = 1
    31      _PtrSize uint8 = 8
    32  )
    33  
    34  const (
    35      _N_FUNCDATA = 8
    36      _INVALID_FUNCDATA_OFFSET = ^uint32(0)
    37      _FUNC_SIZE = unsafe.Sizeof(_func{})
    38      
    39      _MINFUNC = 16 // minimum size for a function
    40      _BUCKETSIZE    = 256 * _MINFUNC
    41      _SUBBUCKETS    = 16
    42      _SUB_BUCKETSIZE = _BUCKETSIZE / _SUBBUCKETS
    43  )
    44  
    45  // Note: This list must match the list in runtime/symtab.go.
    46  const (
    47  	FuncFlag_TOPFRAME = 1 << iota
    48  	FuncFlag_SPWRITE
    49  	FuncFlag_ASM
    50  )
    51  
    52  // PCDATA and FUNCDATA table indexes.
    53  //
    54  // See funcdata.h and $GROOT/src/cmd/internal/objabi/funcdata.go.
    55  const (
    56      _FUNCDATA_ArgsPointerMaps    = 0
    57      _FUNCDATA_LocalsPointerMaps  = 1
    58      _FUNCDATA_StackObjects       = 2
    59      _FUNCDATA_InlTree            = 3
    60      _FUNCDATA_OpenCodedDeferInfo = 4
    61      _FUNCDATA_ArgInfo            = 5
    62      _FUNCDATA_ArgLiveInfo        = 6
    63      _FUNCDATA_WrapInfo           = 7
    64  
    65      // ArgsSizeUnknown is set in Func.argsize to mark all functions
    66      // whose argument size is unknown (C vararg functions, and
    67      // assembly code without an explicit specification).
    68      // This value is generated by the compiler, assembler, or linker.
    69      ArgsSizeUnknown = -0x80000000
    70  )
    71  
    72  // moduledata used to cache the funcdata and findfuncbucket of one module
    73  var moduleCache = struct {
    74      m map[*moduledata][]byte
    75      sync.Mutex
    76  }{
    77      m: make(map[*moduledata][]byte),
    78  }
    79  
    80  // Func contains information about a function.
    81  type Func struct {
    82      ID          uint8  // see runtime/symtab.go
    83      Flag        uint8  // see runtime/symtab.go
    84      ArgsSize    int32  // args byte size
    85      EntryOff    uint32 // start pc, offset to moduledata.text
    86      TextSize    uint32 // size of func text
    87      DeferReturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
    88      FileIndex   uint32 // index into filetab 
    89      Name        string // name of function
    90  
    91      // PC data
    92      Pcsp            *Pcdata // PC -> SP delta
    93      Pcfile          *Pcdata // PC -> file index
    94      Pcline          *Pcdata // PC -> line number
    95      PcUnsafePoint   *Pcdata // PC -> unsafe point, must be PCDATA_UnsafePointSafe or PCDATA_UnsafePointUnsafe
    96      PcStackMapIndex *Pcdata // PC -> stack map index, relative to ArgsPointerMaps and LocalsPointerMaps
    97      PcInlTreeIndex  *Pcdata // PC -> inlining tree index, relative to InlTree
    98      PcArgLiveIndex  *Pcdata // PC -> arg live index, relative to ArgLiveInfo
    99      
   100      // Func data, must implement encoding.BinaryMarshaler
   101      ArgsPointerMaps    encoding.BinaryMarshaler // concrete type: *StackMap
   102      LocalsPointerMaps  encoding.BinaryMarshaler // concrete type: *StackMap
   103      StackObjects       encoding.BinaryMarshaler
   104      InlTree            encoding.BinaryMarshaler
   105      OpenCodedDeferInfo encoding.BinaryMarshaler
   106      ArgInfo            encoding.BinaryMarshaler
   107      ArgLiveInfo        encoding.BinaryMarshaler
   108      WrapInfo           encoding.BinaryMarshaler
   109  }
   110  
   111  func getOffsetOf(data interface{}, field string) uintptr {
   112      t := reflect.TypeOf(data)
   113      fv, ok := t.FieldByName(field)
   114      if !ok {
   115          panic(fmt.Sprintf("field %s not found in struct %s", field, t.Name()))
   116      }
   117      return fv.Offset
   118  }
   119  
   120  func rnd(v int64, r int64) int64 {
   121      if r <= 0 {
   122          return v
   123      }
   124      v += r - 1
   125      c := v % r
   126      if c < 0 {
   127          c += r
   128      }
   129      v -= c
   130      return v
   131  }
   132  
   133  var (
   134      byteOrder binary.ByteOrder = binary.LittleEndian
   135  )
   136  
   137  func funcNameParts(name string) (string, string, string) {
   138      i := strings.IndexByte(name, '[')
   139      if i < 0 {
   140          return name, "", ""
   141      }
   142      // TODO: use LastIndexByte once the bootstrap compiler is >= Go 1.5.
   143      j := len(name) - 1
   144      for j > i && name[j] != ']' {
   145          j--
   146      }
   147      if j <= i {
   148          return name, "", ""
   149      }
   150      return name[:i], "[...]", name[j+1:]
   151  }
   152  
   153  
   154  // func name table format: 
   155  //   nameOff[0] -> namePartA namePartB namePartC \x00 
   156  //   nameOff[1] -> namePartA namePartB namePartC \x00
   157  //  ...
   158  func makeFuncnameTab(funcs []Func) (tab []byte, offs []int32) {
   159      offs = make([]int32, len(funcs))
   160      offset := 1
   161      tab = []byte{0}
   162  
   163      for i, f := range funcs {
   164          offs[i] = int32(offset)
   165  
   166          a, b, c := funcNameParts(f.Name)
   167          tab = append(tab, a...)
   168          tab = append(tab, b...)
   169          tab = append(tab, c...)
   170          tab = append(tab, 0)
   171          offset += len(a) + len(b) + len(c) + 1
   172      }
   173  
   174      return
   175  }
   176  
   177  // CU table format:
   178  //  cuOffsets[0] -> filetabOffset[0] filetabOffset[1] ... filetabOffset[len(CUs[0].fileNames)-1]
   179  //  cuOffsets[1] -> filetabOffset[len(CUs[0].fileNames)] ... filetabOffset[len(CUs[0].fileNames) + len(CUs[1].fileNames)-1]
   180  //  ...
   181  //
   182  // file name table format:
   183  //  filetabOffset[0] -> CUs[0].fileNames[0] \x00
   184  //  ...
   185  //  filetabOffset[len(CUs[0]-1)] -> CUs[0].fileNames[len(CUs[0].fileNames)-1] \x00
   186  //  ...
   187  //  filetabOffset[SUM(CUs,fileNames)-1] -> CUs[len(CU)-1].fileNames[len(CUs[len(CU)-1].fileNames)-1] \x00
   188  func makeFilenametab(cus []compilationUnit) (cutab []uint32, filetab []byte, cuOffsets []uint32) {
   189      cuOffsets = make([]uint32, len(cus))
   190      cuOffset := 0
   191      fileOffset := 0
   192  
   193      for i, cu := range cus {
   194          cuOffsets[i] = uint32(cuOffset)
   195  
   196          for _, name := range cu.fileNames {
   197              cutab = append(cutab, uint32(fileOffset))
   198  
   199              fileOffset += len(name) + 1
   200              filetab = append(filetab, name...)
   201              filetab = append(filetab, 0)
   202          }
   203  
   204          cuOffset += len(cu.fileNames)
   205      }
   206  
   207      return
   208  }
   209  
   210  func writeFuncdata(out *[]byte, funcs []Func) (fstart int, funcdataOffs [][]uint32) {
   211      fstart = len(*out)
   212      *out = append(*out, byte(0))
   213      offs := uint32(1)
   214  
   215      funcdataOffs = make([][]uint32, len(funcs))
   216      for i, f := range funcs {
   217  
   218          var writer = func(fd encoding.BinaryMarshaler) {
   219              var ab []byte
   220              var err error
   221              if fd != nil {
   222                  ab, err = fd.MarshalBinary()
   223                  if err != nil {
   224                      panic(err)
   225                  }
   226                  funcdataOffs[i] = append(funcdataOffs[i], offs)
   227              } else {
   228                  ab = []byte{0}
   229                  funcdataOffs[i] = append(funcdataOffs[i], _INVALID_FUNCDATA_OFFSET)
   230              }
   231              *out = append(*out, ab...)
   232              offs += uint32(len(ab))
   233          }
   234  
   235          writer(f.ArgsPointerMaps)
   236          writer(f.LocalsPointerMaps)
   237          writer(f.StackObjects)
   238          writer(f.InlTree)
   239          writer(f.OpenCodedDeferInfo)
   240          writer(f.ArgInfo)
   241          writer(f.ArgLiveInfo)
   242          writer(f.WrapInfo)
   243      }
   244      return 
   245  }
   246  

View as plain text