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