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 }