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 }