blob: 3acfb55803a832c5ea743febea5a9bcf3c875b3f [file] [log] [blame]
khenaidooab1f7bd2019-11-14 14:00:27 -05001package 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}