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 }