1package reflect2 2 3import ( 4 "reflect" 5 "runtime" 6 "strings" 7 "sync" 8 "unsafe" 9) 10 11// typelinks1 for 1.5 ~ 1.6 12//go:linkname typelinks1 reflect.typelinks 13func typelinks1() [][]unsafe.Pointer 14 15// typelinks2 for 1.7 ~ 16//go:linkname typelinks2 reflect.typelinks 17func typelinks2() (sections []unsafe.Pointer, offset [][]int32) 18 19// initOnce guards initialization of types and packages 20var initOnce sync.Once 21 22var types map[string]reflect.Type 23var packages map[string]map[string]reflect.Type 24 25// discoverTypes initializes types and packages 26func discoverTypes() { 27 types = make(map[string]reflect.Type) 28 packages = make(map[string]map[string]reflect.Type) 29 30 ver := runtime.Version() 31 if ver == "go1.5" || strings.HasPrefix(ver, "go1.5.") { 32 loadGo15Types() 33 } else if ver == "go1.6" || strings.HasPrefix(ver, "go1.6.") { 34 loadGo15Types() 35 } else { 36 loadGo17Types() 37 } 38} 39 40func loadGo15Types() { 41 var obj interface{} = reflect.TypeOf(0) 42 typePtrss := typelinks1() 43 for _, typePtrs := range typePtrss { 44 for _, typePtr := range typePtrs { 45 (*emptyInterface)(unsafe.Pointer(&obj)).word = typePtr 46 typ := obj.(reflect.Type) 47 if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct { 48 loadedType := typ.Elem() 49 pkgTypes := packages[loadedType.PkgPath()] 50 if pkgTypes == nil { 51 pkgTypes = map[string]reflect.Type{} 52 packages[loadedType.PkgPath()] = pkgTypes 53 } 54 types[loadedType.String()] = loadedType 55 pkgTypes[loadedType.Name()] = loadedType 56 } 57 if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Ptr && 58 typ.Elem().Elem().Kind() == reflect.Struct { 59 loadedType := typ.Elem().Elem() 60 pkgTypes := packages[loadedType.PkgPath()] 61 if pkgTypes == nil { 62 pkgTypes = map[string]reflect.Type{} 63 packages[loadedType.PkgPath()] = pkgTypes 64 } 65 types[loadedType.String()] = loadedType 66 pkgTypes[loadedType.Name()] = loadedType 67 } 68 } 69 } 70} 71 72func loadGo17Types() { 73 var obj interface{} = reflect.TypeOf(0) 74 sections, offset := typelinks2() 75 for i, offs := range offset { 76 rodata := sections[i] 77 for _, off := range offs { 78 (*emptyInterface)(unsafe.Pointer(&obj)).word = resolveTypeOff(unsafe.Pointer(rodata), off) 79 typ := obj.(reflect.Type) 80 if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct { 81 loadedType := typ.Elem() 82 pkgTypes := packages[loadedType.PkgPath()] 83 if pkgTypes == nil { 84 pkgTypes = map[string]reflect.Type{} 85 packages[loadedType.PkgPath()] = pkgTypes 86 } 87 types[loadedType.String()] = loadedType 88 pkgTypes[loadedType.Name()] = loadedType 89 } 90 } 91 } 92} 93 94type emptyInterface struct { 95 typ unsafe.Pointer 96 word unsafe.Pointer 97} 98 99// TypeByName return the type by its name, just like Class.forName in java 100func TypeByName(typeName string) Type { 101 initOnce.Do(discoverTypes) 102 return Type2(types[typeName]) 103} 104 105// TypeByPackageName return the type by its package and name 106func TypeByPackageName(pkgPath string, name string) Type { 107 initOnce.Do(discoverTypes) 108 pkgTypes := packages[pkgPath] 109 if pkgTypes == nil { 110 return nil 111 } 112 return Type2(pkgTypes[name]) 113} 114