github.com/goplus/reflectx@v1.2.2/rtype.go (about) 1 //go:build !js || (js && wasm) 2 // +build !js js,wasm 3 4 package reflectx 5 6 import ( 7 "fmt" 8 "io" 9 "reflect" 10 "unsafe" 11 ) 12 13 func toStructType(t *rtype) *structType { 14 return (*structType)(unsafe.Pointer(t)) 15 } 16 17 func toKindType(t *rtype) unsafe.Pointer { 18 return unsafe.Pointer(t) 19 } 20 21 //go:linkname toUncommonType reflect.(*rtype).uncommon 22 func toUncommonType(t *rtype) *uncommonType 23 24 // uncommonType is present only for defined types or types with methods 25 // (if T is a defined type, the uncommonTypes for T and *T have methods). 26 // Using a pointer to this struct reduces the overall size required 27 // to describe a non-defined type with no methods. 28 type uncommonType struct { 29 pkgPath nameOff // import path; empty for built-in types like int, string 30 mcount uint16 // number of methods 31 xcount uint16 // number of exported methods 32 moff uint32 // offset from this uncommontype to [mcount]method 33 _ uint32 // unused 34 } 35 36 type funcTypeFixed1 struct { 37 funcType 38 args [1]*rtype 39 } 40 41 type funcTypeFixed4 struct { 42 funcType 43 args [4]*rtype 44 } 45 type funcTypeFixed8 struct { 46 funcType 47 args [8]*rtype 48 } 49 type funcTypeFixed16 struct { 50 funcType 51 args [16]*rtype 52 } 53 type funcTypeFixed32 struct { 54 funcType 55 args [32]*rtype 56 } 57 type funcTypeFixed64 struct { 58 funcType 59 args [64]*rtype 60 } 61 type funcTypeFixed128 struct { 62 funcType 63 args [128]*rtype 64 } 65 66 // emptyInterface is the header for an interface{} value. 67 type emptyInterface struct { 68 typ *rtype 69 word unsafe.Pointer 70 } 71 72 func totype(typ reflect.Type) *rtype { 73 e := (*emptyInterface)(unsafe.Pointer(&typ)) 74 return (*rtype)(e.word) 75 } 76 77 //go:nocheckptr 78 func (t *uncommonType) methods() []method { 79 if t == nil || t.mcount == 0 { 80 return nil 81 } 82 return (*[1 << 16]method)(add(unsafe.Pointer(t), uintptr(t.moff), "t.mcount > 0"))[:t.mcount:t.mcount] 83 } 84 85 //go:nocheckptr 86 func (t *uncommonType) exportedMethods() []method { 87 if t == nil || t.xcount == 0 { 88 return nil 89 } 90 return (*[1 << 16]method)(add(unsafe.Pointer(t), uintptr(t.moff), "t.xcount > 0"))[:t.xcount:t.xcount] 91 } 92 93 func tovalue(v *reflect.Value) *Value { 94 return (*Value)(unsafe.Pointer(v)) 95 } 96 97 func toValue(v Value) reflect.Value { 98 return *(*reflect.Value)(unsafe.Pointer(&v)) 99 } 100 101 func (t *rtype) uncommon() *uncommonType { 102 return toUncommonType(t) 103 } 104 105 func (t *rtype) exportedMethods() []method { 106 ut := t.uncommon() 107 if ut == nil { 108 return nil 109 } 110 return ut.exportedMethods() 111 } 112 113 func (t *rtype) methods() []method { 114 ut := t.uncommon() 115 if ut == nil { 116 return nil 117 } 118 return ut.methods() 119 } 120 121 func (t *funcType) in() []*rtype { 122 uadd := unsafe.Sizeof(*t) 123 if t.tflag&tflagUncommon != 0 { 124 uadd += unsafe.Sizeof(uncommonType{}) 125 } 126 if t.inCount == 0 { 127 return nil 128 } 129 return (*[1 << 20]*rtype)(add(unsafe.Pointer(t), uadd, "t.inCount > 0"))[:t.inCount:t.inCount] 130 } 131 132 func (t *funcType) out() []*rtype { 133 uadd := unsafe.Sizeof(*t) 134 if t.tflag&tflagUncommon != 0 { 135 uadd += unsafe.Sizeof(uncommonType{}) 136 } 137 outCount := t.outCount & (1<<15 - 1) 138 if outCount == 0 { 139 return nil 140 } 141 return (*[1 << 20]*rtype)(add(unsafe.Pointer(t), uadd, "outCount > 0"))[t.inCount : t.inCount+outCount : t.inCount+outCount] 142 } 143 144 func (t *rtype) IsVariadic() bool { 145 if t.Kind() != reflect.Func { 146 panic("reflect: IsVariadic of non-func type " + toType(t).String()) 147 } 148 tt := (*funcType)(unsafe.Pointer(t)) 149 return tt.outCount&(1<<15) != 0 150 } 151 152 type bitVector struct { 153 n uint32 // number of bits 154 data []byte 155 } 156 157 // funcType represents a function type. 158 // 159 // A *rtype for each in and out parameter is stored in an array that 160 // directly follows the funcType (and possibly its uncommonType). So 161 // a function type with one method, one input, and one output is: 162 // 163 // struct { 164 // funcType 165 // uncommonType 166 // [2]*rtype // [0] is in, [1] is out 167 // } 168 type funcType struct { 169 rtype 170 inCount uint16 171 outCount uint16 // top bit is set if last input parameter is ... 172 } 173 174 type uncommonFuncType struct { 175 funcType 176 uncommonType 177 args [1]*rtype 178 } 179 180 func uncommonFuncTypeArgs(rt *rtype, nargs int) []*rtype { 181 f := (*uncommonFuncType)(unsafe.Pointer(rt)) 182 return (*[1 << 16]*rtype)(unsafe.Pointer(&f.args))[:nargs:nargs] 183 } 184 185 func SetUnderlying(typ reflect.Type, styp reflect.Type) { 186 rt := totype(typ) 187 ort := totype(styp) 188 switch styp.Kind() { 189 case reflect.Struct: 190 st := (*structType)(unsafe.Pointer(rt)) 191 ost := (*structType)(unsafe.Pointer(ort)) 192 st.fields = ost.fields 193 case reflect.Ptr: 194 st := (*ptrType)(unsafe.Pointer(rt)) 195 ost := (*ptrType)(unsafe.Pointer(ort)) 196 st.elem = ost.elem 197 case reflect.Slice: 198 st := (*sliceType)(unsafe.Pointer(rt)) 199 ost := (*sliceType)(unsafe.Pointer(ort)) 200 st.elem = ost.elem 201 case reflect.Array: 202 st := (*arrayType)(unsafe.Pointer(rt)) 203 ost := (*arrayType)(unsafe.Pointer(ort)) 204 st.elem = ost.elem 205 st.slice = ost.slice 206 st.len = ost.len 207 case reflect.Chan: 208 st := (*chanType)(unsafe.Pointer(rt)) 209 ost := (*chanType)(unsafe.Pointer(ort)) 210 st.elem = ost.elem 211 st.dir = ost.dir 212 case reflect.Interface: 213 st := (*interfaceType)(unsafe.Pointer(rt)) 214 ost := (*interfaceType)(unsafe.Pointer(ort)) 215 st.methods = ost.methods 216 case reflect.Map: 217 st := (*mapType)(unsafe.Pointer(rt)) 218 ost := (*mapType)(unsafe.Pointer(ort)) 219 st.key = ost.key 220 st.elem = ost.elem 221 st.bucket = ost.bucket 222 st.hasher = ost.hasher 223 st.keysize = ost.keysize 224 st.valuesize = ost.valuesize 225 st.bucketsize = ost.bucketsize 226 st.flags = ost.flags 227 case reflect.Func: 228 st := (*funcType)(unsafe.Pointer(rt)) 229 ost := (*funcType)(unsafe.Pointer(ort)) 230 st.inCount = ost.inCount 231 st.outCount = ost.outCount 232 numIn := typ.NumIn() 233 numOut := typ.NumOut() 234 narg := numIn + numOut 235 if narg > 0 { 236 args := uncommonFuncTypeArgs(rt, narg) 237 var i int 238 for i = 0; i < numIn; i++ { 239 args[i] = totype(styp.In(i)) 240 } 241 for j := 0; j < numOut; j++ { 242 args[i+j] = totype(styp.Out(j)) 243 } 244 } 245 } 246 rt.size = ort.size 247 rt.tflag |= tflagUncommon | tflagExtraStar | tflagNamed 248 rt.kind = ort.kind 249 rt.align = ort.align 250 rt.fieldAlign = ort.fieldAlign 251 rt.gcdata = ort.gcdata 252 rt.ptrdata = ort.ptrdata 253 rt.equal = ort.equal 254 //rt.str = resolveReflectName(ort.nameOff(ort.str)) 255 if isRegularMemory(typ) { 256 rt.tflag |= tflagRegularMemory 257 } 258 } 259 260 func newType(pkg string, name string, styp reflect.Type, mcount int, xcount int) (*rtype, []method) { 261 var rt *rtype 262 var fnoff uint32 263 var tt reflect.Value 264 ort := totype(styp) 265 skind := styp.Kind() 266 switch skind { 267 case reflect.Struct: 268 tt = reflect.New(reflect.StructOf([]reflect.StructField{ 269 {Name: "S", Type: reflect.TypeOf(structType{})}, 270 {Name: "U", Type: reflect.TypeOf(uncommonType{})}, 271 {Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))}, 272 })) 273 st := (*structType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr())) 274 ost := (*structType)(unsafe.Pointer(ort)) 275 st.fields = ost.fields 276 case reflect.Ptr: 277 tt = reflect.New(reflect.StructOf([]reflect.StructField{ 278 {Name: "S", Type: reflect.TypeOf(ptrType{})}, 279 {Name: "U", Type: reflect.TypeOf(uncommonType{})}, 280 {Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))}, 281 })) 282 st := (*ptrType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr())) 283 st.elem = totype(styp.Elem()) 284 case reflect.Interface: 285 tt = reflect.New(reflect.StructOf([]reflect.StructField{ 286 {Name: "S", Type: reflect.TypeOf(interfaceType{})}, 287 {Name: "U", Type: reflect.TypeOf(uncommonType{})}, 288 })) 289 st := (*interfaceType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr())) 290 ost := (*interfaceType)(unsafe.Pointer(ort)) 291 for _, m := range ost.methods { 292 st.methods = append(st.methods, imethod{ 293 name: resolveReflectName(ost.nameOff(m.name)), 294 typ: resolveReflectType(ost.typeOff(m.typ)), 295 }) 296 } 297 case reflect.Slice: 298 tt = reflect.New(reflect.StructOf([]reflect.StructField{ 299 {Name: "S", Type: reflect.TypeOf(sliceType{})}, 300 {Name: "U", Type: reflect.TypeOf(uncommonType{})}, 301 {Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))}, 302 })) 303 st := (*sliceType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr())) 304 st.elem = totype(styp.Elem()) 305 case reflect.Array: 306 tt = reflect.New(reflect.StructOf([]reflect.StructField{ 307 {Name: "S", Type: reflect.TypeOf(arrayType{})}, 308 {Name: "U", Type: reflect.TypeOf(uncommonType{})}, 309 {Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))}, 310 })) 311 st := (*arrayType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr())) 312 ost := (*arrayType)(unsafe.Pointer(ort)) 313 st.elem = ost.elem 314 st.slice = ost.slice 315 st.len = ost.len 316 case reflect.Chan: 317 tt = reflect.New(reflect.StructOf([]reflect.StructField{ 318 {Name: "S", Type: reflect.TypeOf(chanType{})}, 319 {Name: "U", Type: reflect.TypeOf(uncommonType{})}, 320 {Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))}, 321 })) 322 st := (*chanType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr())) 323 ost := (*chanType)(unsafe.Pointer(ort)) 324 st.elem = ost.elem 325 st.dir = ost.dir 326 case reflect.Func: 327 numIn := styp.NumIn() 328 numOut := styp.NumOut() 329 narg := numIn + numOut 330 tt = reflect.New(reflect.StructOf([]reflect.StructField{ 331 {Name: "S", Type: reflect.TypeOf(funcType{})}, 332 {Name: "U", Type: reflect.TypeOf(uncommonType{})}, 333 {Name: "N", Type: reflect.ArrayOf(narg, reflect.TypeOf((*rtype)(nil)))}, 334 {Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))}, 335 })) 336 st := (*funcType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr())) 337 ost := (*funcType)(unsafe.Pointer(ort)) 338 st.inCount = ost.inCount 339 st.outCount = ost.outCount 340 if narg > 0 { 341 args := make([]*rtype, narg, narg) 342 fnoff = uint32(unsafe.Sizeof((*rtype)(nil))) * uint32(narg) 343 var i int 344 for i = 0; i < numIn; i++ { 345 args[i] = totype(styp.In(i)) 346 } 347 for j := 0; j < numOut; j++ { 348 args[i+j] = totype(styp.Out(j)) 349 } 350 copy(tt.Elem().Field(2).Slice(0, narg).Interface().([]*rtype), args) 351 } 352 case reflect.Map: 353 tt = reflect.New(reflect.StructOf([]reflect.StructField{ 354 {Name: "S", Type: reflect.TypeOf(mapType{})}, 355 {Name: "U", Type: reflect.TypeOf(uncommonType{})}, 356 {Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))}, 357 })) 358 st := (*mapType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr())) 359 ost := (*mapType)(unsafe.Pointer(ort)) 360 st.key = ost.key 361 st.elem = ost.elem 362 st.bucket = ost.bucket 363 st.hasher = ost.hasher 364 st.keysize = ost.keysize 365 st.valuesize = ost.valuesize 366 st.bucketsize = ost.bucketsize 367 st.flags = ost.flags 368 default: 369 tt = reflect.New(reflect.StructOf([]reflect.StructField{ 370 {Name: "S", Type: reflect.TypeOf(rtype{})}, 371 {Name: "U", Type: reflect.TypeOf(uncommonType{})}, 372 {Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))}, 373 })) 374 } 375 rt = (*rtype)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr())) 376 rt.size = ort.size 377 rt.tflag = ort.tflag | tflagUncommon 378 rt.kind = ort.kind 379 rt.align = ort.align 380 rt.fieldAlign = ort.fieldAlign 381 rt.gcdata = ort.gcdata 382 rt.ptrdata = ort.ptrdata 383 rt.equal = ort.equal 384 rt.str = resolveReflectName(ort.nameOff(ort.str)) 385 ut := (*uncommonType)(unsafe.Pointer(tt.Elem().Field(1).UnsafeAddr())) 386 ut.mcount = uint16(mcount) 387 ut.xcount = uint16(xcount) 388 ut.moff = uint32(unsafe.Sizeof(uncommonType{})) 389 if skind == reflect.Interface { 390 return rt, nil 391 } else if skind == reflect.Func { 392 ut.moff += fnoff 393 return rt, tt.Elem().Field(3).Slice(0, mcount).Interface().([]method) 394 } 395 return rt, tt.Elem().Field(2).Slice(0, mcount).Interface().([]method) 396 } 397 398 func NamedTypeOf(pkgpath string, name string, from reflect.Type) reflect.Type { 399 rt, _ := newType(pkgpath, name, from, 0, 0) 400 setTypeName(rt, pkgpath, name) 401 return toType(rt) 402 } 403 404 //go:linkname typesByString reflect.typesByString 405 func typesByString(s string) []*rtype 406 407 //go:linkname typelinks reflect.typelinks 408 func typelinks() (sections []unsafe.Pointer, offset [][]int32) 409 410 //go:linkname rtypeOff reflect.rtypeOff 411 func rtypeOff(section unsafe.Pointer, off int32) *rtype 412 413 func TypeLinks() []reflect.Type { 414 var r []reflect.Type 415 sections, offset := typelinks() 416 for i, offs := range offset { 417 rodata := sections[i] 418 for _, off := range offs { 419 typ := (*rtype)(resolveTypeOff(unsafe.Pointer(rodata), off)) 420 r = append(r, toType(typ)) 421 } 422 } 423 return r 424 } 425 426 func TypesByString(s string) []reflect.Type { 427 sections, offset := typelinks() 428 var ret []reflect.Type 429 430 for offsI, offs := range offset { 431 section := sections[offsI] 432 433 // We are looking for the first index i where the string becomes >= s. 434 // This is a copy of sort.Search, with f(h) replaced by (*typ[h].String() >= s). 435 i, j := 0, len(offs) 436 for i < j { 437 h := i + (j-i)/2 // avoid overflow when computing h 438 // i ≤ h < j 439 typ := toType(rtypeOff(section, offs[h])) 440 if !(typ.String() >= s) { 441 i = h + 1 // preserves f(i-1) == false 442 } else { 443 j = h // preserves f(j) == true 444 } 445 } 446 // i == j, f(i-1) == false, and f(j) (= f(i)) == true => answer is i. 447 448 // Having found the first, linear scan forward to find the last. 449 // We could do a second binary search, but the caller is going 450 // to do a linear scan anyway. 451 for j := i; j < len(offs); j++ { 452 typ := toType(rtypeOff(section, offs[j])) 453 if typ.String() != s { 454 break 455 } 456 ret = append(ret, typ) 457 } 458 } 459 return ret 460 } 461 462 func DumpType(w io.Writer, typ reflect.Type) { 463 rt := totype(typ) 464 fmt.Fprintf(w, "%#v\n", rt) 465 for _, m := range rt.methods() { 466 fmt.Fprintf(w, "%v %v (%v)\t\t%#v\n", 467 rt.nameOff(m.name).name(), 468 rt.nameOff(m.name).pkgPath(), 469 toType(rt.typeOff(m.mtyp)), 470 m) 471 } 472 } 473 474 func NumMethodX(typ reflect.Type) int { 475 return totype(typ).NumMethodX() 476 } 477 478 func MethodX(typ reflect.Type, i int) reflect.Method { 479 return totype(typ).MethodX(i) 480 } 481 482 func (t *rtype) NumMethodX() int { 483 return len(t.methods()) 484 } 485 486 func (t *rtype) MethodX(i int) (m reflect.Method) { 487 if t.Kind() == reflect.Interface { 488 return toType(t).Method(i) 489 } 490 methods := t.methods() 491 if i < 0 || i >= len(methods) { 492 panic("reflect: Method index out of range") 493 } 494 p := methods[i] 495 pname := t.nameOff(p.name) 496 m.Name = pname.name() 497 m.Index = i 498 fl := flag(reflect.Func) 499 if t.tflag&tflagUserMethod != 0 { 500 fl |= flagIndir 501 } 502 mtyp := t.typeOff(p.mtyp) 503 if mtyp == nil { 504 return 505 } 506 ft := (*funcType)(unsafe.Pointer(mtyp)) 507 in := make([]reflect.Type, 0, 1+len(ft.in())) 508 in = append(in, toType(t)) 509 for _, arg := range ft.in() { 510 in = append(in, toType(arg)) 511 } 512 out := make([]reflect.Type, 0, len(ft.out())) 513 for _, ret := range ft.out() { 514 out = append(out, toType(ret)) 515 } 516 mt := reflect.FuncOf(in, out, ft.IsVariadic()) 517 m.Type = mt 518 tfn := t.textOff(p.tfn) 519 fn := unsafe.Pointer(&tfn) 520 m.Func = toValue(Value{totype(mt), fn, fl}) 521 return m 522 } 523 524 func (t *rtype) MethodByNameX(name string) (m reflect.Method, ok bool) { 525 if t.Kind() == reflect.Interface { 526 return toType(t).MethodByName(name) 527 } 528 if ut := t.uncommon(); ut != nil { 529 for i, p := range ut.methods() { 530 if t.nameOff(p.name).name() == name { 531 return t.MethodX(i), true 532 } 533 } 534 } 535 return reflect.Method{}, false 536 } 537 538 // Field returns the i'th field of the struct v. 539 // It panics if v's Kind is not Struct or i is out of range. 540 func FieldX(v reflect.Value, i int) reflect.Value { 541 mustBe("reflect.Value.Field", v, reflect.Struct) 542 rv := tovalue(&v) 543 tt := (*structType)(unsafe.Pointer(rv.typ)) 544 if uint(i) >= uint(len(tt.fields)) { 545 panic("reflect: Field index out of range") 546 } 547 field := &tt.fields[i] 548 typ := field.typ 549 550 // Inherit permission bits from v, but clear flagEmbedRO. 551 fl := rv.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind()) 552 // Using an unexported field forces flagRO. 553 // if !field.name.isExported() { 554 // if field.embedded() { 555 // fl |= flagEmbedRO 556 // } else { 557 // fl |= flagStickyRO 558 // } 559 // } 560 // Either flagIndir is set and v.ptr points at struct, 561 // or flagIndir is not set and v.ptr is the actual struct data. 562 // In the former case, we want v.ptr + offset. 563 // In the latter case, we must have field.offset = 0, 564 // so v.ptr + field.offset is still the correct address. 565 ptr := add(rv.ptr, field.offset(), "same as non-reflect &v.field") 566 return toValue(Value{typ, ptr, fl}) 567 }