text: package reflect2
  
  import (
  	"reflect"
  	"runtime"
  	"strings"
  	"sync"
  	"unsafe"
  )
  
  // typelinks1 for 1.5 ~ 1.6
  //go:linkname typelinks1 reflect.typelinks
  func typelinks1() [][]unsafe.Pointer
  
  // typelinks2 for 1.7 ~
  //go:linkname typelinks2 reflect.typelinks
  func typelinks2() (sections []unsafe.Pointer, offset [][]int32)
  
  // initOnce guards initialization of types and packages
  var initOnce sync.Once
  
  var types map[string]reflect.Type
  var packages map[string]map[string]reflect.Type
  
  // discoverTypes initializes types and packages
  func discoverTypes() {
  	types = make(map[string]reflect.Type)
  	packages = make(map[string]map[string]reflect.Type)
  
  	ver := runtime.Version()
  	if ver == "go1.5" || strings.HasPrefix(ver, "go1.5.") {
  		loadGo15Types()
  	} else if ver == "go1.6" || strings.HasPrefix(ver, "go1.6.") {
  		loadGo15Types()
  	} else {
  		loadGo17Types()
  	}
  }
  
  func loadGo15Types() {
  	var obj interface{} = reflect.TypeOf(0)
  	typePtrss := typelinks1()
  	for _, typePtrs := range typePtrss {
  		for _, typePtr := range typePtrs {
  			(*emptyInterface)(unsafe.Pointer(&obj)).word = typePtr
  			typ := obj.(reflect.Type)
  			if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
  				loadedType := typ.Elem()
  				pkgTypes := packages[loadedType.PkgPath()]
  				if pkgTypes == nil {
  					pkgTypes = map[string]reflect.Type{}
  					packages[loadedType.PkgPath()] = pkgTypes
  				}
  				types[loadedType.String()] = loadedType
  				pkgTypes[loadedType.Name()] = loadedType
  			}
  			if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Ptr &&
  				typ.Elem().Elem().Kind() == reflect.Struct {
  				loadedType := typ.Elem().Elem()
  				pkgTypes := packages[loadedType.PkgPath()]
  				if pkgTypes == nil {
  					pkgTypes = map[string]reflect.Type{}
  					packages[loadedType.PkgPath()] = pkgTypes
  				}
  				types[loadedType.String()] = loadedType
  				pkgTypes[loadedType.Name()] = loadedType
  			}
  		}
  	}
  }
  
  func loadGo17Types() {
  	var obj interface{} = reflect.TypeOf(0)
  	sections, offset := typelinks2()
  	for i, offs := range offset {
  		rodata := sections[i]
  		for _, off := range offs {
  			(*emptyInterface)(unsafe.Pointer(&obj)).word = resolveTypeOff(unsafe.Pointer(rodata), off)
  			typ := obj.(reflect.Type)
  			if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
  				loadedType := typ.Elem()
  				pkgTypes := packages[loadedType.PkgPath()]
  				if pkgTypes == nil {
  					pkgTypes = map[string]reflect.Type{}
  					packages[loadedType.PkgPath()] = pkgTypes
  				}
  				types[loadedType.String()] = loadedType
  				pkgTypes[loadedType.Name()] = loadedType
  			}
  		}
  	}
  }
  
  type emptyInterface struct {
  	typ  unsafe.Pointer
  	word unsafe.Pointer
  }
  
  // TypeByName return the type by its name, just like Class.forName in java
  func TypeByName(typeName string) Type {
  	initOnce.Do(discoverTypes)
  	return Type2(types[typeName])
  }
  
  // TypeByPackageName return the type by its package and name
  func TypeByPackageName(pkgPath string, name string) Type {
  	initOnce.Do(discoverTypes)
  	pkgTypes := packages[pkgPath]
  	if pkgTypes == nil {
  		return nil
  	}
  	return Type2(pkgTypes[name])
  }
  