github.com/cloudwego/frugal@v0.1.15/internal/atm/abi/abi_amd64.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 abi
    18  
    19  import (
    20      `fmt`
    21      `reflect`
    22      `sort`
    23      `strings`
    24      `sync`
    25      `unsafe`
    26  
    27      `github.com/cloudwego/iasm/x86_64`
    28      `github.com/cloudwego/frugal/internal/rt`
    29  )
    30  
    31  const (
    32      PtrAlign = 8    // pointer alignment
    33  )
    34  
    35  type Parameter struct {
    36      Mem        uintptr
    37      Reg        x86_64.Register64
    38      Type       reflect.Type
    39      InRegister bool
    40  }
    41  
    42  var (
    43      intType = reflect.TypeOf(0)
    44      ptrType = reflect.TypeOf(unsafe.Pointer(nil))
    45  )
    46  
    47  func mkReg(vt reflect.Type, reg x86_64.Register64) (p Parameter) {
    48      p.Reg = reg
    49      p.Type = vt
    50      p.InRegister = true
    51      return
    52  }
    53  
    54  func mkStack(vt reflect.Type, mem uintptr) (p Parameter) {
    55      p.Mem = mem
    56      p.Type = vt
    57      p.InRegister = false
    58      return
    59  }
    60  
    61  func (self Parameter) String() string {
    62      if self.InRegister {
    63          return fmt.Sprintf("%%%s", self.Reg)
    64      } else {
    65          return fmt.Sprintf("%d(%%rsp)", self.Mem)
    66      }
    67  }
    68  
    69  func (self Parameter) IsPointer() bool {
    70      switch self.Type.Kind() {
    71          case reflect.Bool          : fallthrough
    72          case reflect.Int           : fallthrough
    73          case reflect.Int8          : fallthrough
    74          case reflect.Int16         : fallthrough
    75          case reflect.Int32         : fallthrough
    76          case reflect.Int64         : fallthrough
    77          case reflect.Uint          : fallthrough
    78          case reflect.Uint8         : fallthrough
    79          case reflect.Uint16        : fallthrough
    80          case reflect.Uint32        : fallthrough
    81          case reflect.Uint64        : fallthrough
    82          case reflect.Uintptr       : return false
    83          case reflect.Chan          : fallthrough
    84          case reflect.Func          : fallthrough
    85          case reflect.Map           : fallthrough
    86          case reflect.Ptr           : fallthrough
    87          case reflect.UnsafePointer : return true
    88          case reflect.Float32       : fallthrough
    89          case reflect.Float64       : fallthrough
    90          case reflect.Complex64     : fallthrough
    91          case reflect.Complex128    : fallthrough
    92          case reflect.Array         : fallthrough
    93          case reflect.Struct        : panic("abi: unsupported types")
    94          default                    : panic("abi: invalid value type")
    95      }
    96  }
    97  
    98  type _StackSlot struct {
    99      p bool
   100      m uintptr
   101  }
   102  
   103  type FunctionLayout struct {
   104      Id   int
   105      Sp   uintptr
   106      Args []Parameter
   107      Rets []Parameter
   108  }
   109  
   110  func (self *FunctionLayout) String() string {
   111      if self.Id < 0 {
   112          return fmt.Sprintf("{func,%s}", self.formatFn())
   113      } else {
   114          return fmt.Sprintf("{meth/%d,%s}", self.Id, self.formatFn())
   115      }
   116  }
   117  
   118  func (self *FunctionLayout) StackMap() *rt.StackMap {
   119      var st []_StackSlot
   120      var mb rt.StackMapBuilder
   121  
   122      /* add arguments */
   123      for _, v := range self.Args {
   124          st = append(st, _StackSlot {
   125              m: v.Mem,
   126              p: v.IsPointer(),
   127          })
   128      }
   129  
   130      /* add stack-passed return values */
   131      for _, v := range self.Rets {
   132          if !v.InRegister {
   133              st = append(st, _StackSlot {
   134                  m: v.Mem,
   135                  p: v.IsPointer(),
   136              })
   137          }
   138      }
   139  
   140      /* sort by memory offset */
   141      sort.Slice(st, func(i int, j int) bool {
   142          return st[i].m < st[j].m
   143      })
   144  
   145      /* add the bits */
   146      for _, v := range st {
   147          mb.AddField(v.p)
   148      }
   149  
   150      /* build the stack map */
   151      return mb.Build()
   152  }
   153  
   154  func (self *FunctionLayout) formatFn() string {
   155      return fmt.Sprintf("$%#x,(%s),(%s)", self.Sp, self.formatSeq(self.Args), self.formatSeq(self.Rets))
   156  }
   157  
   158  func (self *FunctionLayout) formatSeq(v []Parameter) string {
   159      nb := len(v)
   160      mm := make([]string, len(v))
   161  
   162      /* convert each part */
   163      for i := 0; i < nb; i++ {
   164          mm[i] = v[i].String()
   165      }
   166  
   167      /* join them together */
   168      return strings.Join(mm, ",")
   169  }
   170  
   171  type AMD64ABI struct {
   172      m     sync.RWMutex
   173      fnTab map[int]*FunctionLayout
   174  }
   175  
   176  func ArchCreateABI() *AMD64ABI {
   177      return &AMD64ABI {
   178          fnTab: make(map[int]*FunctionLayout),
   179      }
   180  }
   181  
   182  func (self *AMD64ABI) GetLayout(id int) (layout *FunctionLayout) {
   183      self.m.RLock()
   184      layout = self.fnTab[id]
   185      self.m.RUnlock()
   186      return
   187  }
   188  
   189  func (self *AMD64ABI) SetLayout(id int, layout *FunctionLayout) {
   190      self.m.Lock()
   191      self.fnTab[id] = layout
   192      self.m.Unlock()
   193  }
   194  
   195  func (self *AMD64ABI) DumpLayouts() map[int]*FunctionLayout {
   196      self.m.RLock()
   197      result := make(map[int]*FunctionLayout, len(self.fnTab))
   198      for k, v := range self.fnTab {
   199          result[k] = v
   200      }
   201      self.m.RUnlock()
   202      return result
   203  }
   204  
   205  func (self *AMD64ABI) RegisterMethod(id int, mt rt.Method) int {
   206      self.SetLayout(id, self.LayoutFunc(mt.Id, mt.Vt.Pack().Method(mt.Id).Type))
   207      return mt.Id
   208  }
   209  
   210  func (self *AMD64ABI) RegisterFunction(id int, fn interface{}) (fp unsafe.Pointer) {
   211      vv := rt.UnpackEface(fn)
   212      vt := vv.Type.Pack()
   213  
   214      /* must be a function */
   215      if vt.Kind() != reflect.Func {
   216          panic("fn is not a function")
   217      }
   218  
   219      /* layout the function, and get the real function address */
   220      self.SetLayout(id, self.LayoutFunc(-1, vt))
   221      return *(*unsafe.Pointer)(vv.Value)
   222  }