github.com/cloudwego/frugal@v0.1.7/internal/atm/hir/call.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 hir
    18  
    19  import (
    20      `fmt`
    21      `runtime`
    22      `unsafe`
    23  
    24      `github.com/cloudwego/frugal/internal/atm/abi`
    25      `github.com/cloudwego/frugal/internal/rt`
    26  )
    27  
    28  type (
    29      CallType uint8
    30  )
    31  
    32  const (
    33      CCall CallType = iota
    34      GCall
    35      ICall
    36  )
    37  
    38  type CallState interface {
    39      Gr(id GenericRegister) uint64
    40      Pr(id PointerRegister) unsafe.Pointer
    41      SetGr(id GenericRegister, val uint64)
    42      SetPr(id PointerRegister, val unsafe.Pointer)
    43  }
    44  
    45  type CallHandle struct {
    46      Id    int
    47      Slot  int
    48      Type  CallType
    49      Func  unsafe.Pointer
    50      proxy func(CallContext)
    51  }
    52  
    53  func (self *CallHandle) Name() string {
    54      return runtime.FuncForPC(uintptr(self.Func)).Name()
    55  }
    56  
    57  func (self *CallHandle) Call(r CallState, p *Ir) {
    58      self.proxy(CallContext {
    59          repo: r,
    60          kind: self.Type,
    61          argc: p.An,
    62          retc: p.Rn,
    63          argv: p.Ar,
    64          retv: p.Rr,
    65          itab: p.Ps,
    66          data: p.Pd,
    67      })
    68  }
    69  
    70  func (self *CallHandle) String() string {
    71      return fmt.Sprintf("*%#x[%s]", self.Func, self.Name())
    72  }
    73  
    74  type CallContext struct {
    75      kind CallType
    76      repo CallState
    77      itab PointerRegister
    78      data PointerRegister
    79      argc uint8
    80      retc uint8
    81      argv [8]uint8
    82      retv [8]uint8
    83  }
    84  
    85  func (self CallContext) Au(i int) uint64 {
    86      if p := self.argv[i]; p &ArgPointer != 0 {
    87          panic("invoke: invalid int argument")
    88      } else {
    89          return self.repo.Gr(GenericRegister(p & ArgMask))
    90      }
    91  }
    92  
    93  func (self CallContext) Ap(i int) unsafe.Pointer {
    94      if p := self.argv[i]; p &ArgPointer == 0 {
    95          panic("invoke: invalid pointer argument")
    96      } else {
    97          return self.repo.Pr(PointerRegister(p & ArgMask))
    98      }
    99  }
   100  
   101  func (self CallContext) Ru(i int, v uint64) {
   102      if p := self.retv[i]; p &ArgPointer != 0 {
   103          panic("invoke: invalid int return value")
   104      } else {
   105          self.repo.SetGr(GenericRegister(p &ArgMask), v)
   106      }
   107  }
   108  
   109  func (self CallContext) Rp(i int, v unsafe.Pointer) {
   110      if p := self.retv[i]; p &ArgPointer == 0 {
   111          panic("invoke: invalid pointer return value")
   112      } else {
   113          self.repo.SetPr(PointerRegister(p &ArgMask), v)
   114      }
   115  }
   116  
   117  func (self CallContext) Itab() *rt.GoItab {
   118      if self.kind != ICall {
   119          panic("invoke: itab is not available")
   120      } else {
   121          return (*rt.GoItab)(self.repo.Pr(self.itab))
   122      }
   123  }
   124  
   125  func (self CallContext) Data() unsafe.Pointer {
   126      if self.kind != ICall {
   127          panic("invoke: data is not available")
   128      } else {
   129          return self.repo.Pr(self.data)
   130      }
   131  }
   132  
   133  func (self CallContext) Verify(args string, rets string) bool {
   134      return self.verifySeq(args, self.argc, self.argv) && self.verifySeq(rets, self.retc, self.retv)
   135  }
   136  
   137  func (self CallContext) verifySeq(s string, n uint8, v [8]uint8) bool {
   138      nb := int(n)
   139      ne := len(s)
   140  
   141      /* sanity check */
   142      if ne > len(v) {
   143          panic("invoke: invalid descriptor")
   144      }
   145  
   146      /* check for value count */
   147      if nb != ne {
   148          return false
   149      }
   150  
   151      /* check for every argument */
   152      for i := 0; i < nb; i++ {
   153          switch s[i] {
   154              case 'i' : if v[i] &ArgPointer != 0 { return false }
   155              case '*' : if v[i] &ArgPointer == 0 { return false }
   156              default  : panic("invoke: invalid descriptor char: " + s[i:i + 1])
   157          }
   158      }
   159  
   160      /* all checked ok */
   161      return true
   162  }
   163  
   164  var (
   165      funcTab []*CallHandle
   166  )
   167  
   168  func LookupCall(id int64) *CallHandle {
   169      if id < 0 || id >= int64(len(funcTab)) {
   170          panic("invalid function ID")
   171      } else {
   172          return funcTab[id]
   173      }
   174  }
   175  
   176  func RegisterICall(mt rt.Method, proxy func(CallContext)) (h *CallHandle) {
   177      h       = new(CallHandle)
   178      h.Id    = len(funcTab)
   179      h.Type  = ICall
   180      h.Slot  = abi.ABI.RegisterMethod(h.Id, mt)
   181      h.proxy = proxy
   182      funcTab = append(funcTab, h)
   183      return
   184  }
   185  
   186  func RegisterGCall(fn interface{}, proxy func(CallContext)) (h *CallHandle) {
   187      h       = new(CallHandle)
   188      h.Id    = len(funcTab)
   189      h.Type  = GCall
   190      h.Func  = abi.ABI.RegisterFunction(h.Id, fn)
   191      h.proxy = proxy
   192      funcTab = append(funcTab, h)
   193      return
   194  }
   195  
   196  func RegisterCCall(fn unsafe.Pointer, proxy func(CallContext)) (h *CallHandle) {
   197      h       = new(CallHandle)
   198      h.Id    = len(funcTab)
   199      h.Type  = CCall
   200      h.Func  = fn
   201      h.proxy = proxy
   202      funcTab = append(funcTab, h)
   203      return
   204  }