github.com/cloudwego/frugal@v0.1.15/internal/loader/funcdata_go118_121.go (about)

     1  //go:build go1.18 && !go1.23
     2  // +build go1.18,!go1.23
     3  
     4  /*
     5   * Copyright 2022 ByteDance Inc.
     6   *
     7   * Licensed under the Apache License, Version 2.0 (the "License");
     8   * you may not use this file except in compliance with the License.
     9   * You may obtain a copy of the License at
    10   *
    11   *     http://www.apache.org/licenses/LICENSE-2.0
    12   *
    13   * Unless required by applicable law or agreed to in writing, software
    14   * distributed under the License is distributed on an "AS IS" BASIS,
    15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16   * See the License for the specific language governing permissions and
    17   * limitations under the License.
    18   */
    19  
    20  package loader
    21  
    22  import (
    23      `unsafe`
    24  
    25      `github.com/cloudwego/frugal/internal/rt`
    26      `github.com/cloudwego/frugal/internal/utils`
    27  )
    28  
    29  type _FuncTab struct {
    30      entry   uint32
    31      funcoff uint32
    32  }
    33  
    34  type _PCHeader struct {
    35      magic          uint32
    36      pad1, pad2     uint8
    37      minLC          uint8
    38      ptrSize        uint8
    39      nfunc          int
    40      nfiles         uint
    41      textStart      uintptr
    42      funcnameOffset uintptr
    43      cuOffset       uintptr
    44      filetabOffset  uintptr
    45      pctabOffset    uintptr
    46      pclnOffset     uintptr
    47  }
    48  
    49  type _BitVector struct {
    50      n        int32 // # of bits
    51      bytedata *uint8
    52  }
    53  
    54  type _FindFuncBucket struct {
    55      idx        uint32
    56      subbuckets [16]byte
    57  }
    58  
    59  const minfunc = 16
    60  const pcbucketsize = 256 * minfunc
    61  
    62  var (
    63      emptyByte byte
    64  
    65      /* retain local reference of all buckets to bypass gc */
    66      bucketList = &utils.ListNode{}
    67  )
    68  
    69  func registerFunction(name string, pc uintptr, size uintptr, frame rt.Frame) {
    70      var pbase uintptr
    71      var sbase uintptr
    72  
    73      /* PC ranges */
    74      minpc := pc
    75      maxpc := pc + size
    76      pctab := make([]byte, 1)
    77      ffunc := make([]_FindFuncBucket, size / pcbucketsize + 1)
    78  
    79      /* define the PC-SP ranges */
    80      for i, r := range frame.SpTab {
    81          nb := r.Nb
    82          ds := int(r.Sp - sbase)
    83  
    84          /* check for remaining size */
    85          if nb == 0 {
    86              if i == len(frame.SpTab) - 1 {
    87                  nb = size - pbase
    88              } else {
    89                  panic("invalid PC-SP tab")
    90              }
    91          }
    92  
    93          /* check for the first entry */
    94          if i == 0 {
    95              pctab = append(pctab, encodeFirst(ds)...)
    96          } else {
    97              pctab = append(pctab, encodeValue(ds)...)
    98          }
    99  
   100          /* encode the length */
   101          sbase = r.Sp
   102          pbase = pbase + nb
   103          pctab = append(pctab, encodeVariant(int(nb))...)
   104      }
   105  
   106      /* pin the find function bucket */
   107      ftab := &ffunc[0]
   108      pctab = append(pctab, 0)
   109      bucketList.Prepend(unsafe.Pointer(ftab))
   110  
   111  
   112      /* pin the pointer maps */
   113      argptrs := frame.ArgPtrs.Pin()
   114      localptrs := frame.LocalPtrs.Pin()
   115  
   116      /* find the lower base */
   117      if argptrs < localptrs {
   118          pbase = argptrs
   119      } else {
   120          pbase = localptrs
   121      }
   122  
   123      /* function entry */
   124      fn := _Func {
   125          entryOff  : 0,
   126          nameoff   : 1,
   127          args      : int32(frame.ArgSize),
   128          pcsp      : 1,
   129          npcdata   : 2,
   130          cuOffset  : 1,
   131          nfuncdata : 2,
   132          argptrs   : uint32(argptrs - pbase),
   133          localptrs : uint32(localptrs - pbase),
   134      }
   135  
   136      /* mark the entire function as a single line of code */
   137      fn.pcln = uint32(len(pctab))
   138      fn.pcfile = uint32(len(pctab))
   139      pctab = append(pctab, encodeFirst(1)...)
   140      pctab = append(pctab, encodeVariant(int(size))...)
   141      pctab = append(pctab, 0)
   142  
   143      /* set the entire function to use stack map 0 */
   144      fn.pcdata[_PCDATA_StackMapIndex] = uint32(len(pctab))
   145      pctab = append(pctab, encodeFirst(0)...)
   146      pctab = append(pctab, encodeVariant(int(size))...)
   147      pctab = append(pctab, 0)
   148  
   149      /* mark the entire function as unsafe to async-preempt */
   150      fn.pcdata[_PCDATA_UnsafePoint] = uint32(len(pctab))
   151      pctab = append(pctab, encodeFirst(_PCDATA_UnsafePointUnsafe)...)
   152      pctab = append(pctab, encodeVariant(int(size))...)
   153      pctab = append(pctab, 0)
   154  
   155      /* module header */
   156      hdr := &_PCHeader {
   157          magic     : _ModuleMagic,
   158          minLC     : 1,
   159          nfunc     : 1,
   160          ptrSize   : 4 << (^uintptr(0) >> 63),
   161          textStart : minpc,
   162      }
   163  
   164      /* function table */
   165      tab := []_FuncTab {
   166          { entry: 0 },
   167          { entry: uint32(size) },
   168      }
   169  
   170      /* module data */
   171      mod := &_ModuleData {
   172          pcHeader    : hdr,
   173          funcnametab : append(append([]byte{0}, name...), 0),
   174          cutab       : []uint32{0, 0, 1},
   175          filetab     : []byte("\x00(jit-generated)\x00"),
   176          pctab       : pctab,
   177          pclntable   : ((*[unsafe.Sizeof(_Func{})]byte)(unsafe.Pointer(&fn)))[:],
   178          ftab        : tab,
   179          findfunctab : uintptr(unsafe.Pointer(ftab)),
   180          minpc       : minpc,
   181          maxpc       : maxpc,
   182          text        : minpc,
   183          etext       : maxpc,
   184          modulename  : name,
   185          gcdata      : uintptr(unsafe.Pointer(&emptyByte)), 
   186          gcbss       : uintptr(unsafe.Pointer(&emptyByte)),
   187          gofunc      : pbase,
   188      }
   189  
   190      /* verify and register the new module */
   191      moduledataverify1(mod)
   192      registerModule(mod)
   193  }