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