github.com/bytedance/mockey@v1.2.10/internal/unsafereflect/type.go (about) 1 /* 2 * Copyright 2023 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 * Unsafe reflect package for mockey, copy most code from go/src/reflect/type.go, 17 * allow to export the address of private member methods. 18 */ 19 20 package unsafereflect 21 22 import ( 23 "reflect" 24 "unsafe" 25 ) 26 27 func MethodByName(target interface{}, name string) (typ reflect.Type, fn unsafe.Pointer, ok bool) { 28 r := reflect.TypeOf(target) 29 rt := (*rtype)((*struct { 30 _ uintptr 31 data unsafe.Pointer 32 })(unsafe.Pointer(&r)).data) 33 34 for _, p := range rt.methods() { 35 if rt.nameOff(p.name).name() == name { 36 return toType(rt.typeOff(p.mtyp)), rt.Method(p), true 37 } 38 } 39 return nil, nil, false 40 } 41 42 // copy from src/reflect/type.go 43 // rtype is the common implementation of most values. 44 // It is embedded in other struct types. 45 // 46 // rtype must be kept in sync with src/runtime/type.go:/^type._type. 47 type rtype struct { 48 size uintptr 49 ptrdata uintptr // number of bytes in the type that can contain pointers 50 hash uint32 // hash of type; avoids computation in hash tables 51 tflag tflag // extra type information flags 52 align uint8 // alignment of variable with this type 53 fieldAlign uint8 // alignment of struct field with this type 54 kind uint8 // enumeration for C 55 56 // In go 1.13 equal was replaced with "alg *typeAlg". 57 // Since size(func) == size(ptr), the total size of rtype 58 // and alignment of other field keeps the same, we do not 59 // need to make an adaption for go1.13. 60 equal func(unsafe.Pointer, unsafe.Pointer) bool 61 gcdata *byte // garbage collection data 62 str nameOff // string form 63 ptrToThis typeOff // type for pointer to this type, may be zero 64 } 65 66 func (t *rtype) Method(p method) (fn unsafe.Pointer) { 67 tfn := t.textOff(p.tfn) 68 fn = unsafe.Pointer(&tfn) 69 return 70 } 71 72 const kindMask = (1 << 5) - 1 73 74 func (t *rtype) Kind() reflect.Kind { return reflect.Kind(t.kind & kindMask) } 75 76 type ( 77 tflag uint8 78 nameOff int32 // offset to a name 79 typeOff int32 // offset to an *rtype 80 textOff int32 // offset from top of text section 81 ) 82 83 // resolveNameOff resolves a name offset from a base pointer. 84 // The (*rtype).nameOff method is a convenience wrapper for this function. 85 // Implemented in the runtime package. 86 // 87 //go:linkname resolveNameOff reflect.resolveNameOff 88 func resolveNameOff(unsafe.Pointer, int32) unsafe.Pointer 89 90 func (t *rtype) nameOff(off nameOff) name { 91 return name{(*byte)(resolveNameOff(unsafe.Pointer(t), int32(off)))} 92 } 93 94 // resolveTypeOff resolves an *rtype offset from a base type. 95 // The (*rtype).typeOff method is a convenience wrapper for this function. 96 // 97 //go:linkname resolveTypeOff reflect.resolveTypeOff 98 func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer 99 100 func (t *rtype) typeOff(off typeOff) *rtype { 101 return (*rtype)(resolveTypeOff(unsafe.Pointer(t), int32(off))) 102 } 103 104 // toType convert rtype to reflect.Type 105 // 106 // The conversion is not guaranteed to be successful. 107 // If conversion failed, response will be nil 108 func toType(r *rtype) reflect.Type { 109 var vt interface{} 110 *(*uintptr)(unsafe.Pointer(&vt)) = uintptr(unsafe.Pointer(r)) 111 return reflect.TypeOf(vt) 112 } 113 114 // resolveTextOff resolves a function pointer offset from a base type. 115 // The (*rtype).textOff method is a convenience wrapper for this function. 116 // Implemented in the runtime package. 117 // 118 //go:linkname resolveTextOff reflect.resolveTextOff 119 func resolveTextOff(unsafe.Pointer, int32) unsafe.Pointer 120 121 func (t *rtype) textOff(off textOff) unsafe.Pointer { 122 return resolveTextOff(unsafe.Pointer(t), int32(off)) 123 } 124 125 const tflagUncommon tflag = 1 << 0 126 127 // uncommonType is present only for defined types or types with methods 128 type uncommonType struct { 129 pkgPath nameOff // import path; empty for built-in types like int, string 130 mcount uint16 // number of methods 131 xcount uint16 // number of exported methods 132 moff uint32 // offset from this uncommontype to [mcount]method 133 _ uint32 // unused 134 } 135 136 // ptrType represents a pointer type. 137 type ptrType struct { 138 rtype 139 elem *rtype // pointer element (pointed at) type 140 } 141 142 // funcType represents a function type. 143 type funcType struct { 144 rtype 145 inCount uint16 146 outCount uint16 // top bit is set if last input parameter is ... 147 } 148 149 func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { 150 return unsafe.Pointer(uintptr(p) + x) 151 } 152 153 // interfaceType represents an interface type. 154 type interfaceType struct { 155 rtype 156 pkgPath name // import path 157 methods []imethod // sorted by hash 158 } 159 160 type imethod struct { 161 _ nameOff // unused name of method 162 _ typeOff // unused .(*FuncType) underneath 163 } 164 165 func (t *rtype) methods() []method { 166 if t.tflag&tflagUncommon == 0 { 167 return nil 168 } 169 switch t.Kind() { 170 case reflect.Ptr: 171 return (*struct { 172 ptrType 173 u uncommonType 174 })(unsafe.Pointer(t)).u.methods() 175 case reflect.Func: 176 return (*struct { 177 funcType 178 u uncommonType 179 })(unsafe.Pointer(t)).u.methods() 180 case reflect.Interface: 181 return (*struct { 182 interfaceType 183 u uncommonType 184 })(unsafe.Pointer(t)).u.methods() 185 case reflect.Struct: 186 return (*struct { 187 structType 188 u uncommonType 189 })(unsafe.Pointer(t)).u.methods() 190 default: 191 return nil 192 } 193 } 194 195 // Method on non-interface type 196 type method struct { 197 name nameOff // name of method 198 mtyp typeOff // method type (without receiver), not valid for private methods 199 _ textOff // unused fn used in interface call (one-word receiver) 200 tfn textOff // fn used for normal method call 201 } 202 203 func (t *uncommonType) methods() []method { 204 if t.mcount == 0 { 205 return nil 206 } 207 return (*[1 << 16]method)(add(unsafe.Pointer(t), uintptr(t.moff), "t.mcount > 0"))[:t.mcount:t.mcount] 208 } 209 210 // Struct field 211 type structField struct { 212 _ name // unused name is always non-empty 213 _ *rtype // unused type of field 214 _ uintptr // unused byte offset of field 215 } 216 217 // structType 218 type structType struct { 219 rtype 220 pkgPath name 221 fields []structField // sorted by offset 222 } 223 224 type _String struct { 225 Data unsafe.Pointer 226 Len int 227 }