github.com/goplusjs/reflectx@v0.5.4/methodof.go (about) 1 //go:build !js || (js && wasm) 2 // +build !js js,wasm 3 4 package reflectx 5 6 import ( 7 "fmt" 8 "log" 9 "reflect" 10 "sort" 11 "strings" 12 "sync" 13 "unsafe" 14 ) 15 16 var ( 17 typInfoMap = make(map[reflect.Type][]*methodInfo) 18 valueInfoMap = make(map[reflect.Value]typeInfo) 19 ) 20 21 func isMethod(typ reflect.Type) (ok bool) { 22 _, ok = typInfoMap[typ] 23 return 24 } 25 26 type typeInfo struct { 27 typ reflect.Type 28 oneFieldPtr bool 29 } 30 31 type methodInfo struct { 32 Type reflect.Type 33 Func reflect.Value 34 inTyp reflect.Type 35 outTyp reflect.Type 36 name string 37 index int 38 isz uintptr 39 osz uintptr 40 pointer bool 41 variadic bool 42 onePtr bool 43 } 44 45 func MethodByIndex(typ reflect.Type, index int) reflect.Method { 46 m := MethodX(typ, index) 47 if isMethod(typ) { 48 tovalue(&m.Func).flag |= flagIndir 49 } 50 return m 51 } 52 53 func MethodByName(typ reflect.Type, name string) (m reflect.Method, ok bool) { 54 m, ok = MethodByNameX(typ, name) 55 if !ok { 56 return 57 } 58 if isMethod(typ) { 59 tovalue(&m.Func).flag |= flagIndir 60 } 61 return 62 } 63 64 func checkStoreMethodValue(v reflect.Value) { 65 if v.Kind() == reflect.Ptr { 66 v = v.Elem() 67 } 68 if !v.IsValid() { 69 return 70 } 71 typ := v.Type() 72 if isMethod(typ) { 73 valueInfoMap[v] = typeInfo{typ, checkOneFieldPtr(typ)} 74 } 75 if v.Kind() == reflect.Struct { 76 for i := 0; i < v.NumField(); i++ { 77 sf := v.Field(i) 78 checkStoreMethodValue(sf) 79 } 80 } 81 } 82 83 func resizeMethod(typ reflect.Type, mcount int, xcount int) error { 84 rt := totype(typ) 85 ut := toUncommonType(rt) 86 if ut == nil { 87 return fmt.Errorf("not found uncommonType of %v", typ) 88 } 89 if uint16(mcount) > ut.mcount { 90 return fmt.Errorf("too many methods of %v", typ) 91 } 92 ut.xcount = uint16(xcount) 93 return nil 94 } 95 96 // func updateMethod(typ reflect.Type, methods []Method, rmap map[reflect.Type]reflect.Type) bool { 97 // ptyp := reflect.PtrTo(typ) 98 // pinfos, ok := typInfoMap[ptyp] 99 // if !ok && ptyp.NumMethod() > 0 { 100 // log.Printf("warning cannot found type info: %v\n", ptyp) 101 // return false 102 // } 103 // infos, ok := typInfoMap[typ] 104 // if !ok && typ.NumMethod() > 0 { 105 // log.Printf("warning cannot found type info: %v\n", typ) 106 // return false 107 // } 108 // rt := totype(typ) 109 // prt := totype(ptyp) 110 // ms := toUncommonType(rt).exportedMethods() 111 // pms := toUncommonType(prt).exportedMethods() 112 // itype := itypeIndex(typ) 113 // for _, m := range methods { 114 // var i int 115 // var index int 116 // f, ok := ptyp.MethodByName(m.Name) 117 // if !ok { 118 // log.Printf("warning cannot found method: (%v).%v\n", ptyp, m.Name) 119 // continue 120 // } 121 // i = f.Index 122 // if !m.Pointer { 123 // f, ok := typ.MethodByName(m.Name) 124 // if !ok { 125 // log.Printf("warning cannot found method: (%v).%v\n", typ, m.Name) 126 // } 127 // index = f.Index 128 // } 129 // inTyp, outTyp, mtyp, tfn, ifn, ptfn, pifn := createMethod(itype, typ, ptyp, m, i, index, rmap) 130 // isz := argsTypeSize(inTyp, true) 131 // osz := argsTypeSize(outTyp, false) 132 // pindex := i 133 // if !m.Pointer { 134 // pindex = index 135 // } 136 // pms[i].mtyp = mtyp 137 // pms[i].tfn = ptfn 138 // pms[i].ifn = pifn 139 // onePtr := checkOneFieldPtr(typ) 140 // pinfos[i] = &methodInfo{ 141 // inTyp: inTyp, 142 // outTyp: outTyp, 143 // name: m.Name, 144 // index: pindex, 145 // isz: isz, 146 // osz: osz, 147 // pointer: m.Pointer, 148 // variadic: m.Type.IsVariadic(), 149 // onePtr: onePtr, 150 // } 151 // if !m.Pointer { 152 // ms[index].mtyp = mtyp 153 // ms[index].tfn = tfn 154 // ms[index].ifn = ifn 155 // infos[index] = &methodInfo{ 156 // inTyp: inTyp, 157 // outTyp: outTyp, 158 // name: m.Name, 159 // index: index, 160 // isz: isz, 161 // osz: osz, 162 // pointer: m.Pointer, 163 // variadic: m.Type.IsVariadic(), 164 // onePtr: onePtr, 165 // } 166 // } 167 // } 168 // return true 169 // } 170 171 func createMethod(itype int, typ reflect.Type, ptyp reflect.Type, m Method, i int, index int, max int, pmax int, isexport bool) (mfn reflect.Value, inTyp, outTyp reflect.Type, mtyp typeOff, tfn, ifn, ptfn, pifn textOff) { 172 var in []reflect.Type 173 var out []reflect.Type 174 var ntyp reflect.Type 175 in, out, ntyp, inTyp, outTyp = parserMethodType(m.Type, nil) 176 mtyp = resolveReflectType(totype(ntyp)) 177 var ftyp reflect.Type 178 if m.Pointer { 179 ftyp = reflect.FuncOf(append([]reflect.Type{ptyp}, in...), out, m.Type.IsVariadic()) 180 } else { 181 ftyp = reflect.FuncOf(append([]reflect.Type{typ}, in...), out, m.Type.IsVariadic()) 182 } 183 output := len(out) > 0 184 185 mfn = reflect.MakeFunc(ftyp, m.Func) 186 ptr := tovalue(&mfn).ptr 187 188 sz := int(inTyp.Size()) 189 ifunc := icall(itype, i, pmax, true, output) 190 191 if ifunc == nil { 192 log.Printf("warning cannot wrapper method index:%v, size: %v\n", i, sz) 193 } else { 194 pifn = resolveReflectText(unsafe.Pointer(reflect.ValueOf(ifunc).Pointer())) 195 } 196 tfn = resolveReflectText(unsafe.Pointer(ptr)) 197 if !m.Pointer { 198 ctyp := reflect.FuncOf(append([]reflect.Type{ptyp}, in...), out, m.Type.IsVariadic()) 199 cv := reflect.MakeFunc(ctyp, func(args []reflect.Value) (results []reflect.Value) { 200 return args[0].Elem().Method(index).Call(args[1:]) 201 }) 202 ptfn = resolveReflectText(tovalue(&cv).ptr) 203 ifunc := icall(itype, index, max, false, output) 204 if ifunc == nil { 205 log.Printf("warning cannot wrapper method index:%v, size: %v\n", i, sz) 206 } else { 207 ifn = resolveReflectText(unsafe.Pointer(reflect.ValueOf(ifunc).Pointer())) 208 } 209 } else { 210 ptfn = tfn 211 } 212 return 213 } 214 215 func setMethodSet(typ reflect.Type, methods []Method) error { 216 sort.Slice(methods, func(i, j int) bool { 217 n := strings.Compare(methods[i].Name, methods[j].Name) 218 if n == 0 && methods[i].Type == methods[j].Type { 219 panic(fmt.Sprintf("method redeclared: %v", methods[j].Name)) 220 } 221 return n < 0 222 }) 223 var mcount, pcount int 224 var xcount, pxcount int 225 pcount = len(methods) 226 var mlist []string 227 for _, m := range methods { 228 isexport := methodIsExported(m.Name) 229 if isexport { 230 pxcount++ 231 } 232 if !m.Pointer { 233 if isexport { 234 xcount++ 235 } 236 mlist = append(mlist, m.Name) 237 mcount++ 238 } 239 } 240 ptyp := reflect.PtrTo(typ) 241 if err := resizeMethod(typ, mcount, xcount); err != nil { 242 return err 243 } 244 if err := resizeMethod(ptyp, pcount, pxcount); err != nil { 245 return err 246 } 247 rt := totype(typ) 248 prt := totype(ptyp) 249 250 ms := rt.methods() 251 pms := prt.methods() 252 253 infos := make([]*methodInfo, mcount, mcount) 254 pinfos := make([]*methodInfo, pcount, pcount) 255 itype := itypeIndex(typ) 256 var index int 257 for i, m := range methods { 258 isexport := methodIsExported(m.Name) 259 nm := newNameEx(m.Name, "", isexport, !isexport) 260 mname := resolveReflectName(nm) 261 if !isexport { 262 nm.setPkgPath(resolveReflectName(newName(m.PkgPath, "", false))) 263 } 264 mfn, inTyp, outTyp, mtyp, tfn, ifn, ptfn, pifn := createMethod(itype, typ, ptyp, m, i, index, mcount, pcount, isexport) 265 isz := argsTypeSize(inTyp, true) 266 osz := argsTypeSize(outTyp, false) 267 pindex := i 268 if !m.Pointer { 269 pindex = index 270 } 271 onePtr := checkOneFieldPtr(typ) || typ.Kind() == reflect.Func 272 pms[i].name = mname 273 pms[i].mtyp = mtyp 274 pms[i].tfn = ptfn 275 pms[i].ifn = pifn 276 pinfos[i] = &methodInfo{ 277 Type: ptyp, 278 Func: mfn, 279 inTyp: inTyp, 280 outTyp: outTyp, 281 name: m.Name, 282 index: pindex, 283 isz: isz, 284 osz: osz, 285 pointer: m.Pointer, 286 variadic: m.Type.IsVariadic(), 287 onePtr: onePtr, 288 } 289 if !m.Pointer { 290 ms[index].name = mname 291 ms[index].mtyp = mtyp 292 ms[index].tfn = tfn 293 ms[index].ifn = ifn 294 infos[index] = &methodInfo{ 295 Type: typ, 296 Func: mfn, 297 inTyp: inTyp, 298 outTyp: outTyp, 299 name: m.Name, 300 index: index, 301 isz: isz, 302 osz: osz, 303 pointer: m.Pointer, 304 variadic: m.Type.IsVariadic(), 305 onePtr: onePtr, 306 } 307 index++ 308 } 309 } 310 typInfoMap[typ] = infos 311 typInfoMap[ptyp] = pinfos 312 return nil 313 } 314 315 func newMethodSet(styp reflect.Type, maxmfunc, maxpfunc int) reflect.Type { 316 rt, _ := newType("", "", styp, maxmfunc, 0) 317 prt, _ := newType("", "", reflect.PtrTo(styp), maxpfunc, 0) 318 rt.ptrToThis = resolveReflectType(prt) 319 (*ptrType)(unsafe.Pointer(prt)).elem = rt 320 setTypeName(rt, styp.PkgPath(), styp.Name()) 321 prt.uncommon().pkgPath = resolveReflectName(newName(styp.PkgPath(), "", false)) 322 typ := toType(rt) 323 if nt, ok := ntypeMap[styp]; ok { 324 ntypeMap[typ] = &Named{Name: nt.Name, PkgPath: nt.PkgPath, Type: typ, From: nt.From, Kind: nt.Kind} 325 } 326 return typ 327 } 328 329 // func _methodOf(styp reflect.Type, methods []Method) reflect.Type { 330 // sort.Slice(methods, func(i, j int) bool { 331 // n := strings.Compare(methods[i].Name, methods[j].Name) 332 // if n == 0 && methods[i].Type == methods[j].Type { 333 // panic(fmt.Sprintf("method redeclared: %v", methods[j].Name)) 334 // } 335 // return n < 0 336 // }) 337 // var mcount, pcount int 338 // pcount = len(methods) 339 // var mlist []string 340 // for _, m := range methods { 341 // if !m.Pointer { 342 // mlist = append(mlist, m.Name) 343 // mcount++ 344 // } 345 // } 346 // rt, tt := newType("", "", styp, mcount, mcount) 347 // prt, ptt := newType("", "", reflect.PtrTo(styp), mcount, pcount) 348 // rt.ptrToThis = resolveReflectType(prt) 349 350 // (*ptrType)(unsafe.Pointer(prt)).elem = rt 351 // setTypeName(rt, styp.PkgPath(), styp.Name()) 352 // typ := toType(rt) 353 // ptyp := reflect.PtrTo(typ) 354 // ms := make([]method, mcount, mcount) 355 // pms := make([]method, pcount, pcount) 356 // infos := make([]*methodInfo, mcount, mcount) 357 // pinfos := make([]*methodInfo, pcount, pcount) 358 // rmap := make(map[reflect.Type]reflect.Type) 359 // rmap[styp] = typ 360 // itype := itypeIndex(typ) 361 // var index int 362 // for i, m := range methods { 363 // name := resolveReflectName(newName(m.Name, "", true)) 364 // inTyp, outTyp, mtyp, tfn, ifn, ptfn, pifn := createMethod(itype, typ, ptyp, m, i, index, rmap) 365 // isz := argsTypeSize(inTyp, true) 366 // osz := argsTypeSize(outTyp, false) 367 // pindex := i 368 // if !m.Pointer { 369 // pindex = index 370 // } 371 // onePtr := checkOneFieldPtr(typ) 372 // pms[i].name = name 373 // pms[i].mtyp = mtyp 374 // pms[i].tfn = ptfn 375 // pms[i].ifn = pifn 376 // pinfos[i] = &methodInfo{ 377 // inTyp: inTyp, 378 // outTyp: outTyp, 379 // name: m.Name, 380 // index: pindex, 381 // isz: isz, 382 // osz: osz, 383 // pointer: m.Pointer, 384 // variadic: m.Type.IsVariadic(), 385 // onePtr: onePtr, 386 // } 387 // if !m.Pointer { 388 // ms[index].name = name 389 // ms[index].mtyp = mtyp 390 // ms[index].tfn = tfn 391 // ms[index].ifn = ifn 392 // infos[index] = &methodInfo{ 393 // inTyp: inTyp, 394 // outTyp: outTyp, 395 // name: m.Name, 396 // index: index, 397 // isz: isz, 398 // osz: osz, 399 // pointer: m.Pointer, 400 // variadic: m.Type.IsVariadic(), 401 // onePtr: onePtr, 402 // } 403 // index++ 404 // } 405 // } 406 // copy(tt, ms) 407 // copy(ptt, pms) 408 // typInfoMap[typ] = infos 409 // typInfoMap[ptyp] = pinfos 410 // return typ 411 // } 412 413 func checkOneFieldPtr(typ reflect.Type) bool { 414 return typ.Kind() == reflect.Struct && 415 typ.NumField() == 1 && 416 typ.Field(0).Type.Kind() == reflect.Ptr 417 } 418 419 const ( 420 uintptrAligin = unsafe.Sizeof(uintptr(0)) 421 ) 422 423 func argsTypeSize(typ reflect.Type, offset bool) (off uintptr) { 424 numIn := typ.NumField() 425 if numIn == 0 { 426 return 0 427 } 428 for i := 0; i < numIn; i++ { 429 t := typ.Field(i).Type 430 targ := totype(t) 431 a := uintptr(targ.align) 432 off = (off + a - 1) &^ (a - 1) 433 n := targ.size 434 if n == 0 { 435 continue 436 } 437 off += n 438 } 439 if offset { 440 off = (off + uintptrAligin - 1) &^ (uintptrAligin - 1) 441 if off == 0 { 442 return uintptrAligin 443 } 444 } 445 return 446 } 447 448 func resetTypeList() { 449 itypList = nil 450 typInfoMap = make(map[reflect.Type][]*methodInfo) 451 valueInfoMap = make(map[reflect.Value]typeInfo) 452 } 453 454 var ( 455 itypList []reflect.Type 456 ) 457 458 var ( 459 mu sync.Mutex 460 ) 461 462 func isUserType(typ reflect.Type) bool { 463 for _, t := range itypList { 464 if t == typ { 465 return true 466 } 467 } 468 return false 469 } 470 471 func itypeIndex(typ reflect.Type) int { 472 mu.Lock() 473 defer mu.Unlock() 474 for i, t := range itypList { 475 if t == typ { 476 return i 477 } 478 } 479 itypList = append(itypList, typ) 480 return len(itypList) - 1 481 } 482 483 type iparam struct { 484 data []byte 485 } 486 487 type unsafeptr = unsafe.Pointer 488 489 func i_y(itype int, index int, ptr unsafeptr, pin iparam, ptrto bool) (pout iparam) { 490 typ := itypList[itype] 491 otyp := typ 492 if ptrto { 493 typ = reflect.PtrTo(typ) 494 } 495 infos, ok := typInfoMap[typ] 496 if !ok { 497 log.Panicln("cannot found type info", typ) 498 return 499 } 500 info := infos[index] 501 var method reflect.Method 502 if ptrto && !info.pointer { 503 method.Func = info.Func 504 } else { 505 method = MethodByIndex(typ, info.index) 506 method.Func = info.Func 507 } 508 var receiver reflect.Value 509 if !ptrto && info.onePtr { 510 receiver = reflect.NewAt(otyp, unsafe.Pointer(&ptr)).Elem() //.Elem().Field(0) 511 } else { 512 receiver = reflect.NewAt(otyp, ptr) 513 if !ptrto || !info.pointer { 514 receiver = receiver.Elem() 515 } 516 } 517 in := []reflect.Value{receiver} 518 if inCount := method.Func.Type().NumIn(); inCount > 1 { 519 sz := info.inTyp.Size() 520 var inArgs reflect.Value 521 if sz == 0 { 522 inArgs = reflect.New(info.inTyp).Elem() 523 } else { 524 inArgs = reflect.NewAt(info.inTyp, unsafe.Pointer(&pin)).Elem() 525 } 526 if info.variadic { 527 for i := 1; i < inCount-1; i++ { 528 in = append(in, inArgs.Field(i-1)) 529 } 530 slice := inArgs.Field(inCount - 2) 531 for i := 0; i < slice.Len(); i++ { 532 in = append(in, slice.Index(i)) 533 } 534 } else { 535 for i := 1; i < inCount; i++ { 536 in = append(in, inArgs.Field(i-1)) 537 } 538 } 539 } 540 r := method.Func.Call(in) 541 if info.outTyp.NumField() > 0 { 542 out := reflect.New(info.outTyp).Elem() 543 for i, v := range r { 544 out.Field(i).Set(v) 545 } 546 pout.data = make([]byte, info.osz, info.osz) 547 memmove(unsafe.Pointer(&pout), unsafe.Pointer(out.UnsafeAddr()), info.osz) 548 // po := unsafe.Pointer(out.UnsafeAddr()) 549 // p := unsafe.Pointer(&pout) 550 // for i := uintptr(0); i < info.osz; i++ { 551 // *(*byte)(add(p, i, "")) = *(*byte)(add(po, uintptr(i), "")) 552 // } 553 } 554 return 555 } 556 557 func i_x(itype int, index int, ptr unsafe.Pointer, p unsafe.Pointer, ptrto bool) { 558 typ := itypList[itype] 559 otyp := typ 560 if ptrto { 561 typ = reflect.PtrTo(typ) 562 } 563 infos, ok := typInfoMap[typ] 564 if !ok { 565 log.Panicln("cannot found type info", typ) 566 return 567 } 568 info := infos[index] 569 var method reflect.Method 570 if ptrto && !info.pointer { 571 method.Func = info.Func 572 } else { 573 method = MethodByIndex(typ, info.index) 574 method.Func = info.Func 575 } 576 var receiver reflect.Value 577 if !ptrto && info.onePtr { 578 receiver = reflect.NewAt(otyp, unsafe.Pointer(&ptr)).Elem() //.Elem().Field(0) 579 } else { 580 receiver = reflect.NewAt(otyp, ptr) 581 if !ptrto || !info.pointer { 582 receiver = receiver.Elem() 583 } 584 } 585 in := []reflect.Value{receiver} 586 if inCount := method.Func.Type().NumIn(); inCount > 1 { 587 sz := info.inTyp.Size() 588 buf := make([]byte, sz, sz) 589 if sz > info.isz { 590 sz = info.isz 591 } 592 for i := uintptr(0); i < sz; i++ { 593 buf[i] = *(*byte)(add(p, i, "")) 594 } 595 var inArgs reflect.Value 596 if sz == 0 { 597 inArgs = reflect.New(info.inTyp).Elem() 598 } else { 599 inArgs = reflect.NewAt(info.inTyp, unsafe.Pointer(&buf[0])).Elem() 600 } 601 if info.variadic { 602 for i := 1; i < inCount-1; i++ { 603 in = append(in, inArgs.Field(i-1)) 604 } 605 slice := inArgs.Field(inCount - 2) 606 for i := 0; i < slice.Len(); i++ { 607 in = append(in, slice.Index(i)) 608 } 609 } else { 610 for i := 1; i < inCount; i++ { 611 in = append(in, inArgs.Field(i-1)) 612 } 613 } 614 } 615 r := method.Func.Call(in) 616 if info.outTyp.NumField() > 0 { 617 out := reflect.New(info.outTyp).Elem() 618 for i, v := range r { 619 out.Field(i).Set(v) 620 } 621 po := unsafe.Pointer(out.UnsafeAddr()) 622 for i := uintptr(0); i < info.osz; i++ { 623 *(*byte)(add(p, info.isz+i, "")) = *(*byte)(add(po, uintptr(i), "")) 624 } 625 } 626 } 627 628 func i_x_dyn(i int, ptr unsafe.Pointer, p unsafe.Pointer, ptrto bool) bool { 629 var receiver reflect.Value 630 var typ reflect.Type 631 if !ptrto { 632 for v, t := range valueInfoMap { 633 if t.oneFieldPtr { 634 if ptr == unsafe.Pointer(*(**uintptr)(tovalue(&v).ptr)) { 635 receiver = v 636 typ = t.typ 637 break 638 } 639 } 640 } 641 } 642 if typ == nil { 643 for v, t := range valueInfoMap { 644 if ptr == tovalue(&v).ptr { 645 receiver = v 646 typ = t.typ 647 break 648 } 649 } 650 } 651 if typ == nil { 652 log.Panicln("cannot found ptr type", i, ptr) 653 return false 654 } 655 if ptrto { 656 typ = reflect.PtrTo(typ) 657 } 658 infos, ok := typInfoMap[typ] 659 if !ok { 660 log.Panicln("cannot found type info", typ) 661 return false 662 } 663 info := infos[i] 664 var method reflect.Method 665 if ptrto && !info.pointer { 666 method = MethodByIndex(typ.Elem(), info.index) 667 } else { 668 method = MethodByIndex(typ, info.index) 669 } 670 if ptrto && info.pointer { 671 receiver = receiver.Addr() 672 } 673 in := []reflect.Value{receiver} 674 if inCount := method.Type.NumIn(); inCount > 1 { 675 sz := info.inTyp.Size() 676 buf := make([]byte, sz, sz) 677 if sz > info.isz { 678 sz = info.isz 679 } 680 for i := uintptr(0); i < sz; i++ { 681 buf[i] = *(*byte)(add(p, i, "")) 682 } 683 var inArgs reflect.Value 684 if sz == 0 { 685 inArgs = reflect.New(info.inTyp).Elem() 686 } else { 687 inArgs = reflect.NewAt(info.inTyp, unsafe.Pointer(&buf[0])).Elem() 688 } 689 if info.variadic { 690 for i := 1; i < inCount-1; i++ { 691 in = append(in, inArgs.Field(i-1)) 692 } 693 slice := inArgs.Field(inCount - 2) 694 for i := 0; i < slice.Len(); i++ { 695 in = append(in, slice.Index(i)) 696 } 697 } else { 698 for i := 1; i < inCount; i++ { 699 in = append(in, inArgs.Field(i-1)) 700 } 701 } 702 } 703 r := method.Func.Call(in) 704 if info.outTyp.NumField() > 0 { 705 out := reflect.New(info.outTyp).Elem() 706 for i, v := range r { 707 out.Field(i).Set(v) 708 } 709 po := unsafe.Pointer(out.UnsafeAddr()) 710 for i := uintptr(0); i < info.osz; i++ { 711 *(*byte)(add(p, info.isz+i, "")) = *(*byte)(add(po, uintptr(i), "")) 712 } 713 } 714 return true 715 }