github.com/cloudwego/frugal@v0.1.15/internal/atm/abi/abi_regabi_amd64.go (about)

     1  // +build go1.17
     2  
     3  /*
     4   * Copyright 2022 ByteDance Inc.
     5   *
     6   * Licensed under the Apache License, Version 2.0 (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   *     http://www.apache.org/licenses/LICENSE-2.0
    11   *
    12   * Unless required by applicable law or agreed to in writing, software
    13   * distributed under the License is distributed on an "AS IS" BASIS,
    14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15   * See the License for the specific language governing permissions and
    16   * limitations under the License.
    17   */
    18  
    19  /** Go Internal ABI implementation
    20   *
    21   *  This module implements the function layout algorithm described by the Go internal ABI.
    22   *  See https://github.com/golang/go/blob/master/src/cmd/compile/abi-internal.md for more info.
    23   */
    24  
    25  package abi
    26  
    27  import (
    28      `reflect`
    29  
    30      `github.com/cloudwego/iasm/x86_64`
    31  )
    32  
    33  var regOrder = [...]x86_64.Register64 {
    34      x86_64.RAX,
    35      x86_64.RBX,
    36      x86_64.RCX,
    37      x86_64.RDI,
    38      x86_64.RSI,
    39      x86_64.R8,
    40      x86_64.R9,
    41      x86_64.R10,
    42      x86_64.R11,
    43  }
    44  
    45  type _StackAlloc struct {
    46      i int
    47      s uintptr
    48  }
    49  
    50  func (self *_StackAlloc) reg(vt reflect.Type) (p Parameter) {
    51      p = mkReg(vt, regOrder[self.i])
    52      self.i++
    53      return
    54  }
    55  
    56  func (self *_StackAlloc) stack(vt reflect.Type) (p Parameter) {
    57      p = mkStack(vt, self.s)
    58      self.s += vt.Size()
    59      return
    60  }
    61  
    62  func (self *_StackAlloc) spill(n uintptr, a int) uintptr {
    63      self.s = alignUp(self.s, a) + n
    64      return self.s
    65  }
    66  
    67  func (self *_StackAlloc) alloc(p []Parameter, vt reflect.Type) []Parameter {
    68      nb := vt.Size()
    69      vk := vt.Kind()
    70  
    71      /* zero-sized objects are allocated on stack */
    72      if nb == 0 {
    73          return append(p, mkStack(intType, self.s))
    74      }
    75  
    76      /* check for value type */
    77      switch vk {
    78          case reflect.Bool          : return self.valloc(p, reflect.TypeOf(false))
    79          case reflect.Int           : return self.valloc(p, intType)
    80          case reflect.Int8          : return self.valloc(p, reflect.TypeOf(int8(0)))
    81          case reflect.Int16         : return self.valloc(p, reflect.TypeOf(int16(0)))
    82          case reflect.Int32         : return self.valloc(p, reflect.TypeOf(int32(0)))
    83          case reflect.Int64         : return self.valloc(p, reflect.TypeOf(int64(0)))
    84          case reflect.Uint          : return self.valloc(p, reflect.TypeOf(uint(0)))
    85          case reflect.Uint8         : return self.valloc(p, reflect.TypeOf(uint8(0)))
    86          case reflect.Uint16        : return self.valloc(p, reflect.TypeOf(uint16(0)))
    87          case reflect.Uint32        : return self.valloc(p, reflect.TypeOf(uint32(0)))
    88          case reflect.Uint64        : return self.valloc(p, reflect.TypeOf(uint64(0)))
    89          case reflect.Uintptr       : return self.valloc(p, reflect.TypeOf(uintptr(0)))
    90          case reflect.Float32       : panic("abi: go117: not implemented: float32")
    91          case reflect.Float64       : panic("abi: go117: not implemented: float64")
    92          case reflect.Complex64     : panic("abi: go117: not implemented: complex64")
    93          case reflect.Complex128    : panic("abi: go117: not implemented: complex128")
    94          case reflect.Array         : panic("abi: go117: not implemented: arrays")
    95          case reflect.Chan          : return self.valloc(p, reflect.TypeOf((chan int)(nil)))
    96          case reflect.Func          : return self.valloc(p, reflect.TypeOf((func())(nil)))
    97          case reflect.Map           : return self.valloc(p, reflect.TypeOf((map[int]int)(nil)))
    98          case reflect.Ptr           : return self.valloc(p, reflect.TypeOf((*int)(nil)))
    99          case reflect.UnsafePointer : return self.valloc(p, ptrType)
   100          case reflect.Interface     : return self.valloc(p, ptrType, ptrType)
   101          case reflect.Slice         : return self.valloc(p, ptrType, intType, intType)
   102          case reflect.String        : return self.valloc(p, ptrType, intType)
   103          case reflect.Struct        : panic("abi: go117: not implemented: structs")
   104          default                    : panic("abi: invalid value type")
   105      }
   106  }
   107  
   108  func (self *_StackAlloc) ralloc(p []Parameter, vts ...reflect.Type) []Parameter {
   109      for _, vt := range vts { p = append(p, self.reg(vt)) }
   110      return p
   111  }
   112  
   113  func (self *_StackAlloc) salloc(p []Parameter, vts ...reflect.Type) []Parameter {
   114      for _, vt := range vts { p = append(p, self.stack(vt)) }
   115      return p
   116  }
   117  
   118  func (self *_StackAlloc) valloc(p []Parameter, vts ...reflect.Type) []Parameter {
   119      if self.i + len(vts) <= len(regOrder) {
   120          return self.ralloc(p, vts...)
   121      } else {
   122          return self.salloc(p, vts...)
   123      }
   124  }
   125  
   126  func (self *AMD64ABI) Reserved() map[x86_64.Register64]int32 {
   127      return map[x86_64.Register64]int32 {
   128          x86_64.R14: 0, // current goroutine
   129          x86_64.R15: 1, // GOT reference
   130      }
   131  }
   132  
   133  func (self *AMD64ABI) LayoutFunc(id int, ft reflect.Type) *FunctionLayout {
   134      var sa _StackAlloc
   135      var fn FunctionLayout
   136  
   137      /* allocate the receiver if any (interface call always uses pointer) */
   138      if id >= 0 {
   139          fn.Args = sa.alloc(fn.Args, ptrType)
   140      }
   141  
   142      /* assign every arguments */
   143      for i := 0; i < ft.NumIn(); i++ {
   144          fn.Args = sa.alloc(fn.Args, ft.In(i))
   145      }
   146  
   147      /* reset the register counter, and add a pointer alignment field */
   148      sa.i = 0
   149      sa.spill(0, PtrAlign)
   150  
   151      /* assign every return value */
   152      for i := 0; i < ft.NumOut(); i++ {
   153          fn.Rets = sa.alloc(fn.Rets, ft.Out(i))
   154      }
   155  
   156      /* assign spill slots */
   157      for i := 0; i < len(fn.Args); i++ {
   158          if fn.Args[i].InRegister {
   159              fn.Args[i].Mem = sa.spill(PtrSize, PtrAlign) - PtrSize
   160          }
   161      }
   162  
   163      /* add the final pointer alignment field */
   164      fn.Id = id
   165      fn.Sp = sa.spill(0, PtrAlign)
   166      return &fn
   167  }