mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
[dev.link] all: merge branch 'master' into dev.link
Clean merge. Change-Id: Ia7b2808bc649790198d34c226a61d9e569084dc5
This commit is contained in:
commit
a16e30d162
228
api/except.txt
228
api/except.txt
@ -2,12 +2,56 @@ pkg encoding/json, method (*RawMessage) MarshalJSON() ([]uint8, error)
|
||||
pkg math/big, const MaxBase = 36
|
||||
pkg math/big, type Word uintptr
|
||||
pkg net, func ListenUnixgram(string, *UnixAddr) (*UDPConn, error)
|
||||
pkg os (linux-arm), const O_SYNC = 1052672
|
||||
pkg os (linux-arm), const O_SYNC = 4096
|
||||
pkg os (linux-arm-cgo), const O_SYNC = 1052672
|
||||
pkg os (linux-arm-cgo), const O_SYNC = 4096
|
||||
pkg os, const ModeAppend FileMode
|
||||
pkg os, const ModeCharDevice FileMode
|
||||
pkg os, const ModeDevice FileMode
|
||||
pkg os, const ModeDir FileMode
|
||||
pkg os, const ModeExclusive FileMode
|
||||
pkg os, const ModeIrregular FileMode
|
||||
pkg os, const ModeNamedPipe FileMode
|
||||
pkg os, const ModePerm FileMode
|
||||
pkg os, const ModeSetgid FileMode
|
||||
pkg os, const ModeSetuid FileMode
|
||||
pkg os, const ModeSocket FileMode
|
||||
pkg os, const ModeSticky FileMode
|
||||
pkg os, const ModeSymlink FileMode
|
||||
pkg os, const ModeTemporary FileMode
|
||||
pkg os, const ModeType = 2399141888
|
||||
pkg os, const ModeType = 2399666176
|
||||
pkg os (linux-arm), const O_SYNC = 4096
|
||||
pkg os (linux-arm-cgo), const O_SYNC = 4096
|
||||
pkg os (linux-arm), const O_SYNC = 1052672
|
||||
pkg os (linux-arm-cgo), const O_SYNC = 1052672
|
||||
pkg os, const ModeType FileMode
|
||||
pkg os, func Chmod(string, FileMode) error
|
||||
pkg os, func Lstat(string) (FileInfo, error)
|
||||
pkg os, func Mkdir(string, FileMode) error
|
||||
pkg os, func MkdirAll(string, FileMode) error
|
||||
pkg os, func OpenFile(string, int, FileMode) (*File, error)
|
||||
pkg os, func SameFile(FileInfo, FileInfo) bool
|
||||
pkg os, func Stat(string) (FileInfo, error)
|
||||
pkg os, method (*File) Chmod(FileMode) error
|
||||
pkg os, method (*File) Readdir(int) ([]FileInfo, error)
|
||||
pkg os, method (*File) Stat() (FileInfo, error)
|
||||
pkg os, method (*PathError) Error() string
|
||||
pkg os, method (*PathError) Timeout() bool
|
||||
pkg os, method (*PathError) Unwrap() error
|
||||
pkg os, method (FileMode) IsDir() bool
|
||||
pkg os, method (FileMode) IsRegular() bool
|
||||
pkg os, method (FileMode) Perm() FileMode
|
||||
pkg os, method (FileMode) String() string
|
||||
pkg os, type FileInfo interface { IsDir, ModTime, Mode, Name, Size, Sys }
|
||||
pkg os, type FileInfo interface, IsDir() bool
|
||||
pkg os, type FileInfo interface, ModTime() time.Time
|
||||
pkg os, type FileInfo interface, Mode() FileMode
|
||||
pkg os, type FileInfo interface, Name() string
|
||||
pkg os, type FileInfo interface, Size() int64
|
||||
pkg os, type FileInfo interface, Sys() interface{}
|
||||
pkg os, type FileMode uint32
|
||||
pkg os, type PathError struct
|
||||
pkg os, type PathError struct, Err error
|
||||
pkg os, type PathError struct, Op string
|
||||
pkg os, type PathError struct, Path string
|
||||
pkg syscall (darwin-amd64), const ImplementsGetwd = false
|
||||
pkg syscall (darwin-amd64), func Fchflags(string, int) error
|
||||
pkg syscall (darwin-amd64-cgo), const ImplementsGetwd = false
|
||||
@ -18,22 +62,72 @@ pkg syscall (freebsd-386), const ELAST = 94
|
||||
pkg syscall (freebsd-386), const ImplementsGetwd = false
|
||||
pkg syscall (freebsd-386), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-386), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-386), func Mknod(string, uint32, int) error
|
||||
pkg syscall (freebsd-386), type Dirent struct, Fileno uint32
|
||||
pkg syscall (freebsd-386), type Dirent struct, Namlen uint8
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Blksize uint32
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Dev uint32
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Gen uint32
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Ino uint32
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Lspare int32
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Nlink uint16
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Pad_cgo_0 [8]uint8
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Rdev uint32
|
||||
pkg syscall (freebsd-386), type Statfs_t struct, Mntfromname [88]int8
|
||||
pkg syscall (freebsd-386), type Statfs_t struct, Mntonname [88]int8
|
||||
pkg syscall (freebsd-386-cgo), const AF_MAX = 38
|
||||
pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-386-cgo), const ELAST = 94
|
||||
pkg syscall (freebsd-386-cgo), const ImplementsGetwd = false
|
||||
pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-386-cgo), func Mknod(string, uint32, int) error
|
||||
pkg syscall (freebsd-386-cgo), type Dirent struct, Fileno uint32
|
||||
pkg syscall (freebsd-386-cgo), type Dirent struct, Namlen uint8
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Blksize uint32
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Dev uint32
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Gen uint32
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Ino uint32
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Lspare int32
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Nlink uint16
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Pad_cgo_0 [8]uint8
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Rdev uint32
|
||||
pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntfromname [88]int8
|
||||
pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntonname [88]int8
|
||||
pkg syscall (freebsd-amd64), const AF_MAX = 38
|
||||
pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-amd64), const ELAST = 94
|
||||
pkg syscall (freebsd-amd64), const ImplementsGetwd = false
|
||||
pkg syscall (freebsd-amd64), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-amd64), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-amd64), func Mknod(string, uint32, int) error
|
||||
pkg syscall (freebsd-amd64), type Dirent struct, Fileno uint32
|
||||
pkg syscall (freebsd-amd64), type Dirent struct, Namlen uint8
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Blksize uint32
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Dev uint32
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Gen uint32
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Ino uint32
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Lspare int32
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Nlink uint16
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Rdev uint32
|
||||
pkg syscall (freebsd-amd64), type Statfs_t struct, Mntfromname [88]int8
|
||||
pkg syscall (freebsd-amd64), type Statfs_t struct, Mntonname [88]int8
|
||||
pkg syscall (freebsd-amd64-cgo), const AF_MAX = 38
|
||||
pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242
|
||||
pkg syscall (freebsd-amd64-cgo), const ELAST = 94
|
||||
pkg syscall (freebsd-amd64-cgo), const ImplementsGetwd = false
|
||||
pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 0
|
||||
pkg syscall (freebsd-amd64-cgo), func Mknod(string, uint32, int) error
|
||||
pkg syscall (freebsd-amd64-cgo), type Dirent struct, Fileno uint32
|
||||
pkg syscall (freebsd-amd64-cgo), type Dirent struct, Namlen uint8
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Blksize uint32
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Dev uint32
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Gen uint32
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Ino uint32
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Lspare int32
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Nlink uint16
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Rdev uint32
|
||||
pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntfromname [88]int8
|
||||
pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntonname [88]int8
|
||||
pkg syscall (freebsd-arm), const AF_MAX = 38
|
||||
pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262
|
||||
pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148287085
|
||||
@ -62,10 +156,22 @@ pkg syscall (freebsd-arm), const SizeofSockaddrDatalink = 56
|
||||
pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 108
|
||||
pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041
|
||||
pkg syscall (freebsd-arm), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-arm), func Mknod(string, uint32, int) error
|
||||
pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm), type Dirent struct, Fileno uint32
|
||||
pkg syscall (freebsd-arm), type Dirent struct, Namlen uint8
|
||||
pkg syscall (freebsd-arm), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Blksize uint32
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Dev uint32
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Gen uint32
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Ino uint32
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Lspare int32
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Nlink uint16
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Rdev uint32
|
||||
pkg syscall (freebsd-arm), type Statfs_t struct, Mntfromname [88]int8
|
||||
pkg syscall (freebsd-arm), type Statfs_t struct, Mntonname [88]int8
|
||||
pkg syscall (freebsd-arm-cgo), const AF_MAX = 38
|
||||
pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262
|
||||
pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148287085
|
||||
@ -94,10 +200,22 @@ pkg syscall (freebsd-arm-cgo), const SizeofSockaddrDatalink = 56
|
||||
pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 108
|
||||
pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041
|
||||
pkg syscall (freebsd-arm-cgo), func Fchflags(string, int) error
|
||||
pkg syscall (freebsd-arm-cgo), func Mknod(string, uint32, int) error
|
||||
pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type Dirent struct, Fileno uint32
|
||||
pkg syscall (freebsd-arm-cgo), type Dirent struct, Namlen uint8
|
||||
pkg syscall (freebsd-arm-cgo), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Blksize uint32
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Dev uint32
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Gen uint32
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Ino uint32
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Lspare int32
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Nlink uint16
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Rdev uint32
|
||||
pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntfromname [88]int8
|
||||
pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntonname [88]int8
|
||||
pkg syscall (linux-386), type Cmsghdr struct, X__cmsg_data [0]uint8
|
||||
pkg syscall (linux-386-cgo), type Cmsghdr struct, X__cmsg_data [0]uint8
|
||||
pkg syscall (linux-amd64), type Cmsghdr struct, X__cmsg_data [0]uint8
|
||||
@ -109,10 +227,10 @@ pkg syscall (netbsd-386-cgo), const ImplementsGetwd = false
|
||||
pkg syscall (netbsd-amd64), const ImplementsGetwd = false
|
||||
pkg syscall (netbsd-amd64-cgo), const ImplementsGetwd = false
|
||||
pkg syscall (netbsd-arm), const ImplementsGetwd = false
|
||||
pkg syscall (netbsd-arm-cgo), const ImplementsGetwd = false
|
||||
pkg syscall (netbsd-arm), const SizeofIfData = 132
|
||||
pkg syscall (netbsd-arm), func Fchflags(string, int) error
|
||||
pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||
pkg syscall (netbsd-arm-cgo), const ImplementsGetwd = false
|
||||
pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132
|
||||
pkg syscall (netbsd-arm-cgo), func Fchflags(string, int) error
|
||||
pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||
@ -140,6 +258,7 @@ pkg syscall (openbsd-386), const SYS_GETITIMER = 86
|
||||
pkg syscall (openbsd-386), const SYS_GETRUSAGE = 117
|
||||
pkg syscall (openbsd-386), const SYS_GETTIMEOFDAY = 116
|
||||
pkg syscall (openbsd-386), const SYS_KEVENT = 270
|
||||
pkg syscall (openbsd-386), const SYS_KILL = 37
|
||||
pkg syscall (openbsd-386), const SYS_LSTAT = 293
|
||||
pkg syscall (openbsd-386), const SYS_NANOSLEEP = 240
|
||||
pkg syscall (openbsd-386), const SYS_SELECT = 93
|
||||
@ -193,6 +312,7 @@ pkg syscall (openbsd-386-cgo), const SYS_GETITIMER = 86
|
||||
pkg syscall (openbsd-386-cgo), const SYS_GETRUSAGE = 117
|
||||
pkg syscall (openbsd-386-cgo), const SYS_GETTIMEOFDAY = 116
|
||||
pkg syscall (openbsd-386-cgo), const SYS_KEVENT = 270
|
||||
pkg syscall (openbsd-386-cgo), const SYS_KILL = 37
|
||||
pkg syscall (openbsd-386-cgo), const SYS_LSTAT = 293
|
||||
pkg syscall (openbsd-386-cgo), const SYS_NANOSLEEP = 240
|
||||
pkg syscall (openbsd-386-cgo), const SYS_SELECT = 93
|
||||
@ -257,6 +377,7 @@ pkg syscall (openbsd-amd64), const SYS_GETITIMER = 86
|
||||
pkg syscall (openbsd-amd64), const SYS_GETRUSAGE = 117
|
||||
pkg syscall (openbsd-amd64), const SYS_GETTIMEOFDAY = 116
|
||||
pkg syscall (openbsd-amd64), const SYS_KEVENT = 270
|
||||
pkg syscall (openbsd-amd64), const SYS_KILL = 37
|
||||
pkg syscall (openbsd-amd64), const SYS_LSTAT = 293
|
||||
pkg syscall (openbsd-amd64), const SYS_NANOSLEEP = 240
|
||||
pkg syscall (openbsd-amd64), const SYS_SELECT = 93
|
||||
@ -320,6 +441,7 @@ pkg syscall (openbsd-amd64-cgo), const SYS_GETITIMER = 86
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_GETRUSAGE = 117
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_GETTIMEOFDAY = 116
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_KEVENT = 270
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_KILL = 37
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_LSTAT = 293
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_NANOSLEEP = 240
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_SELECT = 93
|
||||
@ -348,19 +470,6 @@ pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_spare [3]uint32
|
||||
pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [4]uint8
|
||||
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Pad_cgo_0 [4]uint8
|
||||
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int32
|
||||
pkg testing, func RegisterCover(Cover)
|
||||
pkg testing, func MainStart(func(string, string) (bool, error), []InternalTest, []InternalBenchmark, []InternalExample) *M
|
||||
pkg text/template/parse, type DotNode bool
|
||||
pkg text/template/parse, type Node interface { Copy, String, Type }
|
||||
pkg unicode, const Version = "6.2.0"
|
||||
pkg unicode, const Version = "6.3.0"
|
||||
pkg unicode, const Version = "7.0.0"
|
||||
pkg unicode, const Version = "8.0.0"
|
||||
pkg syscall (openbsd-386), const SYS_KILL = 37
|
||||
pkg syscall (openbsd-386-cgo), const SYS_KILL = 37
|
||||
pkg syscall (openbsd-amd64), const SYS_KILL = 37
|
||||
pkg syscall (openbsd-amd64-cgo), const SYS_KILL = 37
|
||||
pkg unicode, const Version = "9.0.0"
|
||||
pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983295
|
||||
pkg syscall (windows-386), type AddrinfoW struct, Addr uintptr
|
||||
pkg syscall (windows-386), type CertChainPolicyPara struct, ExtraPolicyPara uintptr
|
||||
@ -379,81 +488,16 @@ pkg syscall (windows-amd64), type CertRevocationInfo struct, CrlInfo uintptr
|
||||
pkg syscall (windows-amd64), type CertRevocationInfo struct, OidSpecificInfo uintptr
|
||||
pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr
|
||||
pkg syscall (windows-amd64), type RawSockaddrAny struct, Pad [96]int8
|
||||
pkg syscall (freebsd-386), func Mknod(string, uint32, int) error
|
||||
pkg syscall (freebsd-386), type Dirent struct, Fileno uint32
|
||||
pkg syscall (freebsd-386), type Dirent struct, Namlen uint8
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Blksize uint32
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Dev uint32
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Gen uint32
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Ino uint32
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Lspare int32
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Nlink uint16
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Pad_cgo_0 [8]uint8
|
||||
pkg syscall (freebsd-386), type Stat_t struct, Rdev uint32
|
||||
pkg syscall (freebsd-386), type Statfs_t struct, Mntfromname [88]int8
|
||||
pkg syscall (freebsd-386), type Statfs_t struct, Mntonname [88]int8
|
||||
pkg syscall (freebsd-386-cgo), func Mknod(string, uint32, int) error
|
||||
pkg syscall (freebsd-386-cgo), type Dirent struct, Fileno uint32
|
||||
pkg syscall (freebsd-386-cgo), type Dirent struct, Namlen uint8
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Blksize uint32
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Dev uint32
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Gen uint32
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Ino uint32
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Lspare int32
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Nlink uint16
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Pad_cgo_0 [8]uint8
|
||||
pkg syscall (freebsd-386-cgo), type Stat_t struct, Rdev uint32
|
||||
pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntfromname [88]int8
|
||||
pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntonname [88]int8
|
||||
pkg syscall (freebsd-amd64), func Mknod(string, uint32, int) error
|
||||
pkg syscall (freebsd-amd64), type Dirent struct, Fileno uint32
|
||||
pkg syscall (freebsd-amd64), type Dirent struct, Namlen uint8
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Blksize uint32
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Dev uint32
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Gen uint32
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Ino uint32
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Lspare int32
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Nlink uint16
|
||||
pkg syscall (freebsd-amd64), type Stat_t struct, Rdev uint32
|
||||
pkg syscall (freebsd-amd64), type Statfs_t struct, Mntfromname [88]int8
|
||||
pkg syscall (freebsd-amd64), type Statfs_t struct, Mntonname [88]int8
|
||||
pkg syscall (freebsd-amd64-cgo), func Mknod(string, uint32, int) error
|
||||
pkg syscall (freebsd-amd64-cgo), type Dirent struct, Fileno uint32
|
||||
pkg syscall (freebsd-amd64-cgo), type Dirent struct, Namlen uint8
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Blksize uint32
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Dev uint32
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Gen uint32
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Ino uint32
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Lspare int32
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Nlink uint16
|
||||
pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Rdev uint32
|
||||
pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntfromname [88]int8
|
||||
pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntonname [88]int8
|
||||
pkg syscall (freebsd-arm), func Mknod(string, uint32, int) error
|
||||
pkg syscall (freebsd-arm), type Dirent struct, Fileno uint32
|
||||
pkg syscall (freebsd-arm), type Dirent struct, Namlen uint8
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Blksize uint32
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Dev uint32
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Gen uint32
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Ino uint32
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Lspare int32
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Nlink uint16
|
||||
pkg syscall (freebsd-arm), type Stat_t struct, Rdev uint32
|
||||
pkg syscall (freebsd-arm), type Statfs_t struct, Mntfromname [88]int8
|
||||
pkg syscall (freebsd-arm), type Statfs_t struct, Mntonname [88]int8
|
||||
pkg syscall (freebsd-arm-cgo), func Mknod(string, uint32, int) error
|
||||
pkg syscall (freebsd-arm-cgo), type Dirent struct, Fileno uint32
|
||||
pkg syscall (freebsd-arm-cgo), type Dirent struct, Namlen uint8
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Blksize uint32
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Dev uint32
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Gen uint32
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Ino uint32
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Lspare int32
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Nlink uint16
|
||||
pkg syscall (freebsd-arm-cgo), type Stat_t struct, Rdev uint32
|
||||
pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntfromname [88]int8
|
||||
pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntonname [88]int8
|
||||
pkg testing, func MainStart(func(string, string) (bool, error), []InternalTest, []InternalBenchmark, []InternalExample) *M
|
||||
pkg testing, func RegisterCover(Cover)
|
||||
pkg text/scanner, const GoTokens = 1012
|
||||
pkg text/template/parse, type DotNode bool
|
||||
pkg text/template/parse, type Node interface { Copy, String, Type }
|
||||
pkg unicode, const Version = "10.0.0"
|
||||
pkg unicode, const Version = "11.0.0"
|
||||
pkg unicode, const Version = "12.0.0"
|
||||
pkg unicode, const Version = "6.2.0"
|
||||
pkg unicode, const Version = "6.3.0"
|
||||
pkg unicode, const Version = "7.0.0"
|
||||
pkg unicode, const Version = "8.0.0"
|
||||
pkg unicode, const Version = "9.0.0"
|
||||
|
328
api/next.txt
328
api/next.txt
@ -1,8 +1,321 @@
|
||||
pkg unicode, const Version = "13.0.0"
|
||||
pkg unicode, var Chorasmian *RangeTable
|
||||
pkg unicode, var Dives_Akuru *RangeTable
|
||||
pkg unicode, var Khitan_Small_Script *RangeTable
|
||||
pkg unicode, var Yezidi *RangeTable
|
||||
pkg debug/elf, const DT_ADDRRNGHI = 1879047935
|
||||
pkg debug/elf, const DT_ADDRRNGHI DynTag
|
||||
pkg debug/elf, const DT_ADDRRNGLO = 1879047680
|
||||
pkg debug/elf, const DT_ADDRRNGLO DynTag
|
||||
pkg debug/elf, const DT_AUDIT = 1879047932
|
||||
pkg debug/elf, const DT_AUDIT DynTag
|
||||
pkg debug/elf, const DT_AUXILIARY = 2147483645
|
||||
pkg debug/elf, const DT_AUXILIARY DynTag
|
||||
pkg debug/elf, const DT_CHECKSUM = 1879047672
|
||||
pkg debug/elf, const DT_CHECKSUM DynTag
|
||||
pkg debug/elf, const DT_CONFIG = 1879047930
|
||||
pkg debug/elf, const DT_CONFIG DynTag
|
||||
pkg debug/elf, const DT_DEPAUDIT = 1879047931
|
||||
pkg debug/elf, const DT_DEPAUDIT DynTag
|
||||
pkg debug/elf, const DT_FEATURE = 1879047676
|
||||
pkg debug/elf, const DT_FEATURE DynTag
|
||||
pkg debug/elf, const DT_FILTER = 2147483647
|
||||
pkg debug/elf, const DT_FILTER DynTag
|
||||
pkg debug/elf, const DT_FLAGS_1 = 1879048187
|
||||
pkg debug/elf, const DT_FLAGS_1 DynTag
|
||||
pkg debug/elf, const DT_GNU_CONFLICT = 1879047928
|
||||
pkg debug/elf, const DT_GNU_CONFLICT DynTag
|
||||
pkg debug/elf, const DT_GNU_CONFLICTSZ = 1879047670
|
||||
pkg debug/elf, const DT_GNU_CONFLICTSZ DynTag
|
||||
pkg debug/elf, const DT_GNU_HASH = 1879047925
|
||||
pkg debug/elf, const DT_GNU_HASH DynTag
|
||||
pkg debug/elf, const DT_GNU_LIBLIST = 1879047929
|
||||
pkg debug/elf, const DT_GNU_LIBLIST DynTag
|
||||
pkg debug/elf, const DT_GNU_LIBLISTSZ = 1879047671
|
||||
pkg debug/elf, const DT_GNU_LIBLISTSZ DynTag
|
||||
pkg debug/elf, const DT_GNU_PRELINKED = 1879047669
|
||||
pkg debug/elf, const DT_GNU_PRELINKED DynTag
|
||||
pkg debug/elf, const DT_MIPS_AUX_DYNAMIC = 1879048241
|
||||
pkg debug/elf, const DT_MIPS_AUX_DYNAMIC DynTag
|
||||
pkg debug/elf, const DT_MIPS_BASE_ADDRESS = 1879048198
|
||||
pkg debug/elf, const DT_MIPS_BASE_ADDRESS DynTag
|
||||
pkg debug/elf, const DT_MIPS_COMPACT_SIZE = 1879048239
|
||||
pkg debug/elf, const DT_MIPS_COMPACT_SIZE DynTag
|
||||
pkg debug/elf, const DT_MIPS_CONFLICT = 1879048200
|
||||
pkg debug/elf, const DT_MIPS_CONFLICT DynTag
|
||||
pkg debug/elf, const DT_MIPS_CONFLICTNO = 1879048203
|
||||
pkg debug/elf, const DT_MIPS_CONFLICTNO DynTag
|
||||
pkg debug/elf, const DT_MIPS_CXX_FLAGS = 1879048226
|
||||
pkg debug/elf, const DT_MIPS_CXX_FLAGS DynTag
|
||||
pkg debug/elf, const DT_MIPS_DELTA_CLASS = 1879048215
|
||||
pkg debug/elf, const DT_MIPS_DELTA_CLASS DynTag
|
||||
pkg debug/elf, const DT_MIPS_DELTA_CLASSSYM = 1879048224
|
||||
pkg debug/elf, const DT_MIPS_DELTA_CLASSSYM DynTag
|
||||
pkg debug/elf, const DT_MIPS_DELTA_CLASSSYM_NO = 1879048225
|
||||
pkg debug/elf, const DT_MIPS_DELTA_CLASSSYM_NO DynTag
|
||||
pkg debug/elf, const DT_MIPS_DELTA_CLASS_NO = 1879048216
|
||||
pkg debug/elf, const DT_MIPS_DELTA_CLASS_NO DynTag
|
||||
pkg debug/elf, const DT_MIPS_DELTA_INSTANCE = 1879048217
|
||||
pkg debug/elf, const DT_MIPS_DELTA_INSTANCE DynTag
|
||||
pkg debug/elf, const DT_MIPS_DELTA_INSTANCE_NO = 1879048218
|
||||
pkg debug/elf, const DT_MIPS_DELTA_INSTANCE_NO DynTag
|
||||
pkg debug/elf, const DT_MIPS_DELTA_RELOC = 1879048219
|
||||
pkg debug/elf, const DT_MIPS_DELTA_RELOC DynTag
|
||||
pkg debug/elf, const DT_MIPS_DELTA_RELOC_NO = 1879048220
|
||||
pkg debug/elf, const DT_MIPS_DELTA_RELOC_NO DynTag
|
||||
pkg debug/elf, const DT_MIPS_DELTA_SYM = 1879048221
|
||||
pkg debug/elf, const DT_MIPS_DELTA_SYM DynTag
|
||||
pkg debug/elf, const DT_MIPS_DELTA_SYM_NO = 1879048222
|
||||
pkg debug/elf, const DT_MIPS_DELTA_SYM_NO DynTag
|
||||
pkg debug/elf, const DT_MIPS_DYNSTR_ALIGN = 1879048235
|
||||
pkg debug/elf, const DT_MIPS_DYNSTR_ALIGN DynTag
|
||||
pkg debug/elf, const DT_MIPS_FLAGS = 1879048197
|
||||
pkg debug/elf, const DT_MIPS_FLAGS DynTag
|
||||
pkg debug/elf, const DT_MIPS_GOTSYM = 1879048211
|
||||
pkg debug/elf, const DT_MIPS_GOTSYM DynTag
|
||||
pkg debug/elf, const DT_MIPS_GP_VALUE = 1879048240
|
||||
pkg debug/elf, const DT_MIPS_GP_VALUE DynTag
|
||||
pkg debug/elf, const DT_MIPS_HIDDEN_GOTIDX = 1879048231
|
||||
pkg debug/elf, const DT_MIPS_HIDDEN_GOTIDX DynTag
|
||||
pkg debug/elf, const DT_MIPS_HIPAGENO = 1879048212
|
||||
pkg debug/elf, const DT_MIPS_HIPAGENO DynTag
|
||||
pkg debug/elf, const DT_MIPS_ICHECKSUM = 1879048195
|
||||
pkg debug/elf, const DT_MIPS_ICHECKSUM DynTag
|
||||
pkg debug/elf, const DT_MIPS_INTERFACE = 1879048234
|
||||
pkg debug/elf, const DT_MIPS_INTERFACE DynTag
|
||||
pkg debug/elf, const DT_MIPS_INTERFACE_SIZE = 1879048236
|
||||
pkg debug/elf, const DT_MIPS_INTERFACE_SIZE DynTag
|
||||
pkg debug/elf, const DT_MIPS_IVERSION = 1879048196
|
||||
pkg debug/elf, const DT_MIPS_IVERSION DynTag
|
||||
pkg debug/elf, const DT_MIPS_LIBLIST = 1879048201
|
||||
pkg debug/elf, const DT_MIPS_LIBLIST DynTag
|
||||
pkg debug/elf, const DT_MIPS_LIBLISTNO = 1879048208
|
||||
pkg debug/elf, const DT_MIPS_LIBLISTNO DynTag
|
||||
pkg debug/elf, const DT_MIPS_LOCALPAGE_GOTIDX = 1879048229
|
||||
pkg debug/elf, const DT_MIPS_LOCALPAGE_GOTIDX DynTag
|
||||
pkg debug/elf, const DT_MIPS_LOCAL_GOTIDX = 1879048230
|
||||
pkg debug/elf, const DT_MIPS_LOCAL_GOTIDX DynTag
|
||||
pkg debug/elf, const DT_MIPS_LOCAL_GOTNO = 1879048202
|
||||
pkg debug/elf, const DT_MIPS_LOCAL_GOTNO DynTag
|
||||
pkg debug/elf, const DT_MIPS_MSYM = 1879048199
|
||||
pkg debug/elf, const DT_MIPS_MSYM DynTag
|
||||
pkg debug/elf, const DT_MIPS_OPTIONS = 1879048233
|
||||
pkg debug/elf, const DT_MIPS_OPTIONS DynTag
|
||||
pkg debug/elf, const DT_MIPS_PERF_SUFFIX = 1879048238
|
||||
pkg debug/elf, const DT_MIPS_PERF_SUFFIX DynTag
|
||||
pkg debug/elf, const DT_MIPS_PIXIE_INIT = 1879048227
|
||||
pkg debug/elf, const DT_MIPS_PIXIE_INIT DynTag
|
||||
pkg debug/elf, const DT_MIPS_PLTGOT = 1879048242
|
||||
pkg debug/elf, const DT_MIPS_PLTGOT DynTag
|
||||
pkg debug/elf, const DT_MIPS_PROTECTED_GOTIDX = 1879048232
|
||||
pkg debug/elf, const DT_MIPS_PROTECTED_GOTIDX DynTag
|
||||
pkg debug/elf, const DT_MIPS_RLD_MAP = 1879048214
|
||||
pkg debug/elf, const DT_MIPS_RLD_MAP DynTag
|
||||
pkg debug/elf, const DT_MIPS_RLD_MAP_REL = 1879048245
|
||||
pkg debug/elf, const DT_MIPS_RLD_MAP_REL DynTag
|
||||
pkg debug/elf, const DT_MIPS_RLD_TEXT_RESOLVE_ADDR = 1879048237
|
||||
pkg debug/elf, const DT_MIPS_RLD_TEXT_RESOLVE_ADDR DynTag
|
||||
pkg debug/elf, const DT_MIPS_RLD_VERSION = 1879048193
|
||||
pkg debug/elf, const DT_MIPS_RLD_VERSION DynTag
|
||||
pkg debug/elf, const DT_MIPS_RWPLT = 1879048244
|
||||
pkg debug/elf, const DT_MIPS_RWPLT DynTag
|
||||
pkg debug/elf, const DT_MIPS_SYMBOL_LIB = 1879048228
|
||||
pkg debug/elf, const DT_MIPS_SYMBOL_LIB DynTag
|
||||
pkg debug/elf, const DT_MIPS_SYMTABNO = 1879048209
|
||||
pkg debug/elf, const DT_MIPS_SYMTABNO DynTag
|
||||
pkg debug/elf, const DT_MIPS_TIME_STAMP = 1879048194
|
||||
pkg debug/elf, const DT_MIPS_TIME_STAMP DynTag
|
||||
pkg debug/elf, const DT_MIPS_UNREFEXTNO = 1879048210
|
||||
pkg debug/elf, const DT_MIPS_UNREFEXTNO DynTag
|
||||
pkg debug/elf, const DT_MOVEENT = 1879047674
|
||||
pkg debug/elf, const DT_MOVEENT DynTag
|
||||
pkg debug/elf, const DT_MOVESZ = 1879047675
|
||||
pkg debug/elf, const DT_MOVESZ DynTag
|
||||
pkg debug/elf, const DT_MOVETAB = 1879047934
|
||||
pkg debug/elf, const DT_MOVETAB DynTag
|
||||
pkg debug/elf, const DT_PLTPAD = 1879047933
|
||||
pkg debug/elf, const DT_PLTPAD DynTag
|
||||
pkg debug/elf, const DT_PLTPADSZ = 1879047673
|
||||
pkg debug/elf, const DT_PLTPADSZ DynTag
|
||||
pkg debug/elf, const DT_POSFLAG_1 = 1879047677
|
||||
pkg debug/elf, const DT_POSFLAG_1 DynTag
|
||||
pkg debug/elf, const DT_PPC64_GLINK = 1879048192
|
||||
pkg debug/elf, const DT_PPC64_GLINK DynTag
|
||||
pkg debug/elf, const DT_PPC64_OPD = 1879048193
|
||||
pkg debug/elf, const DT_PPC64_OPD DynTag
|
||||
pkg debug/elf, const DT_PPC64_OPDSZ = 1879048194
|
||||
pkg debug/elf, const DT_PPC64_OPDSZ DynTag
|
||||
pkg debug/elf, const DT_PPC64_OPT = 1879048195
|
||||
pkg debug/elf, const DT_PPC64_OPT DynTag
|
||||
pkg debug/elf, const DT_PPC_GOT = 1879048192
|
||||
pkg debug/elf, const DT_PPC_GOT DynTag
|
||||
pkg debug/elf, const DT_PPC_OPT = 1879048193
|
||||
pkg debug/elf, const DT_PPC_OPT DynTag
|
||||
pkg debug/elf, const DT_RELACOUNT = 1879048185
|
||||
pkg debug/elf, const DT_RELACOUNT DynTag
|
||||
pkg debug/elf, const DT_RELCOUNT = 1879048186
|
||||
pkg debug/elf, const DT_RELCOUNT DynTag
|
||||
pkg debug/elf, const DT_SPARC_REGISTER = 1879048193
|
||||
pkg debug/elf, const DT_SPARC_REGISTER DynTag
|
||||
pkg debug/elf, const DT_SYMINENT = 1879047679
|
||||
pkg debug/elf, const DT_SYMINENT DynTag
|
||||
pkg debug/elf, const DT_SYMINFO = 1879047935
|
||||
pkg debug/elf, const DT_SYMINFO DynTag
|
||||
pkg debug/elf, const DT_SYMINSZ = 1879047678
|
||||
pkg debug/elf, const DT_SYMINSZ DynTag
|
||||
pkg debug/elf, const DT_SYMTAB_SHNDX = 34
|
||||
pkg debug/elf, const DT_SYMTAB_SHNDX DynTag
|
||||
pkg debug/elf, const DT_TLSDESC_GOT = 1879047927
|
||||
pkg debug/elf, const DT_TLSDESC_GOT DynTag
|
||||
pkg debug/elf, const DT_TLSDESC_PLT = 1879047926
|
||||
pkg debug/elf, const DT_TLSDESC_PLT DynTag
|
||||
pkg debug/elf, const DT_USED = 2147483646
|
||||
pkg debug/elf, const DT_USED DynTag
|
||||
pkg debug/elf, const DT_VALRNGHI = 1879047679
|
||||
pkg debug/elf, const DT_VALRNGHI DynTag
|
||||
pkg debug/elf, const DT_VALRNGLO = 1879047424
|
||||
pkg debug/elf, const DT_VALRNGLO DynTag
|
||||
pkg debug/elf, const DT_VERDEF = 1879048188
|
||||
pkg debug/elf, const DT_VERDEF DynTag
|
||||
pkg debug/elf, const DT_VERDEFNUM = 1879048189
|
||||
pkg debug/elf, const DT_VERDEFNUM DynTag
|
||||
pkg debug/elf, const PT_AARCH64_ARCHEXT = 1879048192
|
||||
pkg debug/elf, const PT_AARCH64_ARCHEXT ProgType
|
||||
pkg debug/elf, const PT_AARCH64_UNWIND = 1879048193
|
||||
pkg debug/elf, const PT_AARCH64_UNWIND ProgType
|
||||
pkg debug/elf, const PT_ARM_ARCHEXT = 1879048192
|
||||
pkg debug/elf, const PT_ARM_ARCHEXT ProgType
|
||||
pkg debug/elf, const PT_ARM_EXIDX = 1879048193
|
||||
pkg debug/elf, const PT_ARM_EXIDX ProgType
|
||||
pkg debug/elf, const PT_GNU_EH_FRAME = 1685382480
|
||||
pkg debug/elf, const PT_GNU_EH_FRAME ProgType
|
||||
pkg debug/elf, const PT_GNU_MBIND_HI = 1685386580
|
||||
pkg debug/elf, const PT_GNU_MBIND_HI ProgType
|
||||
pkg debug/elf, const PT_GNU_MBIND_LO = 1685382485
|
||||
pkg debug/elf, const PT_GNU_MBIND_LO ProgType
|
||||
pkg debug/elf, const PT_GNU_PROPERTY = 1685382483
|
||||
pkg debug/elf, const PT_GNU_PROPERTY ProgType
|
||||
pkg debug/elf, const PT_GNU_RELRO = 1685382482
|
||||
pkg debug/elf, const PT_GNU_RELRO ProgType
|
||||
pkg debug/elf, const PT_GNU_STACK = 1685382481
|
||||
pkg debug/elf, const PT_GNU_STACK ProgType
|
||||
pkg debug/elf, const PT_MIPS_ABIFLAGS = 1879048195
|
||||
pkg debug/elf, const PT_MIPS_ABIFLAGS ProgType
|
||||
pkg debug/elf, const PT_MIPS_OPTIONS = 1879048194
|
||||
pkg debug/elf, const PT_MIPS_OPTIONS ProgType
|
||||
pkg debug/elf, const PT_MIPS_REGINFO = 1879048192
|
||||
pkg debug/elf, const PT_MIPS_REGINFO ProgType
|
||||
pkg debug/elf, const PT_MIPS_RTPROC = 1879048193
|
||||
pkg debug/elf, const PT_MIPS_RTPROC ProgType
|
||||
pkg debug/elf, const PT_OPENBSD_BOOTDATA = 1705253862
|
||||
pkg debug/elf, const PT_OPENBSD_BOOTDATA ProgType
|
||||
pkg debug/elf, const PT_OPENBSD_RANDOMIZE = 1705237478
|
||||
pkg debug/elf, const PT_OPENBSD_RANDOMIZE ProgType
|
||||
pkg debug/elf, const PT_OPENBSD_WXNEEDED = 1705237479
|
||||
pkg debug/elf, const PT_OPENBSD_WXNEEDED ProgType
|
||||
pkg debug/elf, const PT_PAX_FLAGS = 1694766464
|
||||
pkg debug/elf, const PT_PAX_FLAGS ProgType
|
||||
pkg debug/elf, const PT_S390_PGSTE = 1879048192
|
||||
pkg debug/elf, const PT_S390_PGSTE ProgType
|
||||
pkg debug/elf, const PT_SUNWSTACK = 1879048187
|
||||
pkg debug/elf, const PT_SUNWSTACK ProgType
|
||||
pkg debug/elf, const PT_SUNW_EH_FRAME = 1685382480
|
||||
pkg debug/elf, const PT_SUNW_EH_FRAME ProgType
|
||||
pkg flag, func Func(string, string, func(string) error)
|
||||
pkg flag, method (*FlagSet) Func(string, string, func(string) error)
|
||||
pkg go/build, type Package struct, IgnoredOtherFiles []string
|
||||
pkg io, type ReadSeekCloser interface { Close, Read, Seek }
|
||||
pkg io, type ReadSeekCloser interface, Close() error
|
||||
pkg io, type ReadSeekCloser interface, Read([]uint8) (int, error)
|
||||
pkg io, type ReadSeekCloser interface, Seek(int64, int) (int64, error)
|
||||
pkg io/fs, const ModeAppend = 1073741824
|
||||
pkg io/fs, const ModeAppend FileMode
|
||||
pkg io/fs, const ModeCharDevice = 2097152
|
||||
pkg io/fs, const ModeCharDevice FileMode
|
||||
pkg io/fs, const ModeDevice = 67108864
|
||||
pkg io/fs, const ModeDevice FileMode
|
||||
pkg io/fs, const ModeDir = 2147483648
|
||||
pkg io/fs, const ModeDir FileMode
|
||||
pkg io/fs, const ModeExclusive = 536870912
|
||||
pkg io/fs, const ModeExclusive FileMode
|
||||
pkg io/fs, const ModeIrregular = 524288
|
||||
pkg io/fs, const ModeIrregular FileMode
|
||||
pkg io/fs, const ModeNamedPipe = 33554432
|
||||
pkg io/fs, const ModeNamedPipe FileMode
|
||||
pkg io/fs, const ModePerm = 511
|
||||
pkg io/fs, const ModePerm FileMode
|
||||
pkg io/fs, const ModeSetgid = 4194304
|
||||
pkg io/fs, const ModeSetgid FileMode
|
||||
pkg io/fs, const ModeSetuid = 8388608
|
||||
pkg io/fs, const ModeSetuid FileMode
|
||||
pkg io/fs, const ModeSocket = 16777216
|
||||
pkg io/fs, const ModeSocket FileMode
|
||||
pkg io/fs, const ModeSticky = 1048576
|
||||
pkg io/fs, const ModeSticky FileMode
|
||||
pkg io/fs, const ModeSymlink = 134217728
|
||||
pkg io/fs, const ModeSymlink FileMode
|
||||
pkg io/fs, const ModeTemporary = 268435456
|
||||
pkg io/fs, const ModeTemporary FileMode
|
||||
pkg io/fs, const ModeType = 2401763328
|
||||
pkg io/fs, const ModeType FileMode
|
||||
pkg io/fs, method (*PathError) Error() string
|
||||
pkg io/fs, method (*PathError) Timeout() bool
|
||||
pkg io/fs, method (*PathError) Unwrap() error
|
||||
pkg io/fs, method (FileMode) IsDir() bool
|
||||
pkg io/fs, method (FileMode) IsRegular() bool
|
||||
pkg io/fs, method (FileMode) Perm() FileMode
|
||||
pkg io/fs, method (FileMode) String() string
|
||||
pkg io/fs, method (FileMode) Type() FileMode
|
||||
pkg io/fs, type FileInfo interface { IsDir, ModTime, Mode, Name, Size, Sys }
|
||||
pkg io/fs, type FileInfo interface, IsDir() bool
|
||||
pkg io/fs, type FileInfo interface, ModTime() time.Time
|
||||
pkg io/fs, type FileInfo interface, Mode() FileMode
|
||||
pkg io/fs, type FileInfo interface, Name() string
|
||||
pkg io/fs, type FileInfo interface, Size() int64
|
||||
pkg io/fs, type FileInfo interface, Sys() interface{}
|
||||
pkg io/fs, type FileMode uint32
|
||||
pkg io/fs, type PathError struct
|
||||
pkg io/fs, type PathError struct, Err error
|
||||
pkg io/fs, type PathError struct, Op string
|
||||
pkg io/fs, type PathError struct, Path string
|
||||
pkg io/fs, var ErrClosed error
|
||||
pkg io/fs, var ErrExist error
|
||||
pkg io/fs, var ErrInvalid error
|
||||
pkg io/fs, var ErrNotExist error
|
||||
pkg io/fs, var ErrPermission error
|
||||
pkg net, var ErrClosed error
|
||||
pkg net/http, type Transport struct, GetProxyConnectHeader func(context.Context, *url.URL, string) (Header, error)
|
||||
pkg os, const ModeAppend fs.FileMode
|
||||
pkg os, const ModeCharDevice fs.FileMode
|
||||
pkg os, const ModeDevice fs.FileMode
|
||||
pkg os, const ModeDir fs.FileMode
|
||||
pkg os, const ModeExclusive fs.FileMode
|
||||
pkg os, const ModeIrregular fs.FileMode
|
||||
pkg os, const ModeNamedPipe fs.FileMode
|
||||
pkg os, const ModePerm fs.FileMode
|
||||
pkg os, const ModeSetgid fs.FileMode
|
||||
pkg os, const ModeSetuid fs.FileMode
|
||||
pkg os, const ModeSocket fs.FileMode
|
||||
pkg os, const ModeSticky fs.FileMode
|
||||
pkg os, const ModeSymlink fs.FileMode
|
||||
pkg os, const ModeTemporary fs.FileMode
|
||||
pkg os, const ModeType fs.FileMode
|
||||
pkg os, func Chmod(string, fs.FileMode) error
|
||||
pkg os, func Lstat(string) (fs.FileInfo, error)
|
||||
pkg os, func Mkdir(string, fs.FileMode) error
|
||||
pkg os, func MkdirAll(string, fs.FileMode) error
|
||||
pkg os, func OpenFile(string, int, fs.FileMode) (*File, error)
|
||||
pkg os, func SameFile(fs.FileInfo, fs.FileInfo) bool
|
||||
pkg os, func Stat(string) (fs.FileInfo, error)
|
||||
pkg os, method (*File) Chmod(fs.FileMode) error
|
||||
pkg os, method (*File) ReadDir(int) ([]DirEntry, error)
|
||||
pkg os, method (*File) Readdir(int) ([]fs.FileInfo, error)
|
||||
pkg os, method (*File) Stat() (fs.FileInfo, error)
|
||||
pkg os, type DirEntry interface { Info, IsDir, Name, Type }
|
||||
pkg os, type DirEntry interface, Info() (fs.FileInfo, error)
|
||||
pkg os, type DirEntry interface, IsDir() bool
|
||||
pkg os, type DirEntry interface, Name() string
|
||||
pkg os, type DirEntry interface, Type() fs.FileMode
|
||||
pkg os, type FileInfo = fs.FileInfo
|
||||
pkg os, type FileMode = fs.FileMode
|
||||
pkg os, type PathError = fs.PathError
|
||||
pkg os/signal, func NotifyContext(context.Context, ...os.Signal) (context.Context, context.CancelFunc)
|
||||
pkg testing/iotest, func ErrReader(error) io.Reader
|
||||
pkg text/template/parse, const NodeComment = 20
|
||||
pkg text/template/parse, const NodeComment NodeType
|
||||
pkg text/template/parse, const ParseComments = 1
|
||||
@ -17,3 +330,8 @@ pkg text/template/parse, type CommentNode struct, embedded NodeType
|
||||
pkg text/template/parse, type CommentNode struct, embedded Pos
|
||||
pkg text/template/parse, type Mode uint
|
||||
pkg text/template/parse, type Tree struct, Mode Mode
|
||||
pkg unicode, const Version = "13.0.0"
|
||||
pkg unicode, var Chorasmian *RangeTable
|
||||
pkg unicode, var Dives_Akuru *RangeTable
|
||||
pkg unicode, var Khitan_Small_Script *RangeTable
|
||||
pkg unicode, var Yezidi *RangeTable
|
||||
|
@ -806,10 +806,9 @@ tracker will automatically mark the issue as fixed.
|
||||
|
||||
<p>
|
||||
If the change is a partial step towards the resolution of the issue,
|
||||
uses the notation "Updates #12345".
|
||||
This will leave a comment in the issue
|
||||
linking back to the change in Gerrit, but it will not close the issue
|
||||
when the change is applied.
|
||||
write "Updates #12345" instead.
|
||||
This will leave a comment in the issue linking back to the change in
|
||||
Gerrit, but it will not close the issue when the change is applied.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
@ -454,6 +454,8 @@ environmental variable is set accordingly.</p>
|
||||
<li>GODEBUG=gctrace=1 prints garbage collector events at
|
||||
each collection, summarizing the amount of memory collected
|
||||
and the length of the pause.</li>
|
||||
<li>GODEBUG=inittrace=1 prints a summary of execution time and memory allocation
|
||||
information for completed package initilization work.</li>
|
||||
<li>GODEBUG=schedtrace=X prints scheduling events every X milliseconds.</li>
|
||||
</ul>
|
||||
|
||||
|
153
doc/go1.16.html
153
doc/go1.16.html
@ -31,8 +31,22 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
|
||||
<h2 id="ports">Ports</h2>
|
||||
|
||||
<p>
|
||||
TODO
|
||||
<h3 id="netbsd">NetBSD</h3>
|
||||
|
||||
<p><!-- golang.org/issue/30824 -->
|
||||
Go now supports the 64-bit ARM architecture on NetBSD (the
|
||||
<code>netbsd/arm64</code> port).
|
||||
</p>
|
||||
|
||||
<h3 id="386">386</h3>
|
||||
|
||||
<p><!-- golang.org/issue/40255, golang.org/issue/41848, CL 258957, and CL 260017 -->
|
||||
As <a href="go1.15#386">announced</a> in the Go 1.15 release notes,
|
||||
Go 1.16 drops support for x87 mode compilation (<code>GO386=387</code>).
|
||||
Support for non-SSE2 processors is now available using soft float
|
||||
mode (<code>GO386=softfloat</code>).
|
||||
Users running on non-SSE2 processors should replace <code>GO386=387</code>
|
||||
with <code>GO386=softfloat</code>.
|
||||
</p>
|
||||
|
||||
<h2 id="tools">Tools</h2>
|
||||
@ -87,12 +101,13 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
|
||||
<p><!-- golang.org/issue/37519 -->
|
||||
The <code>go</code> <code>get</code> <code>-insecure</code> flag is
|
||||
deprecated and will be removed in a future version. The <code>GOINSECURE</code>
|
||||
environment variable should be used instead, since it provides control
|
||||
over which modules may be retrieved using an insecure scheme. Unlike the
|
||||
<code>-insecure</code> flag, <code>GOINSECURE</code> does not disable module
|
||||
sum validation using the checksum database. The <code>GOPRIVATE</code> or
|
||||
<code>GONOSUMDB</code> environment variables may be used instead.
|
||||
deprecated and will be removed in a future version. This flag permits
|
||||
fetching from repositories and resolving custom domains using insecure
|
||||
schemes such as HTTP, and also bypassess module sum validation using the
|
||||
checksum database. To permit the use of insecure schemes, use the
|
||||
<code>GOINSECURE</code> environment variable instead. To bypass module
|
||||
sum validation, use <code>GOPRIVATE</code> or <code>GONOSUMDB</code>.
|
||||
See <code>go</code> <code>help</code> <code>environment</code> for details.
|
||||
</p>
|
||||
|
||||
<h4 id="all-pattern">The <code>all</code> pattern</h4>
|
||||
@ -107,6 +122,25 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
by <code>go</code> <code>mod</code> <code>vendor</code> since Go 1.11.
|
||||
</p>
|
||||
|
||||
<h4 id="toolexec">The <code>-toolexec</code> build flag</h4>
|
||||
|
||||
<p><!-- golang.org/cl/263357 -->
|
||||
When the <code>-toolexec</code> build flag is specified to use a program when
|
||||
invoking toolchain programs like compile or asm, the environment variable
|
||||
<code>TOOLEXEC_IMPORTPATH</code> is now set to the import path of the package
|
||||
being built.
|
||||
</p>
|
||||
|
||||
<h4 id="list-buildid">The <code>list</code> command</h4>
|
||||
|
||||
<p><!-- golang.org/cl/263542 -->
|
||||
When the <code>-export</code> flag is specified, the <code>BuildID</code>
|
||||
field is now set to the build ID of the compiled package. This is equivalent
|
||||
to running <code>go</code> <code>tool</code> <code>buildid</code> on
|
||||
<code>go</code> <code>list</code> <code>-exported</code> <code>-f</code> <code>{{.Export}</code>,
|
||||
but without the extra step.
|
||||
</p>
|
||||
|
||||
<h3 id="cgo">Cgo</h3>
|
||||
|
||||
<p> <!-- CL 252378 -->
|
||||
@ -158,13 +192,26 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
TODO: update with final numbers later in the release.
|
||||
</p>
|
||||
|
||||
<p> <!-- CL 255259 -->
|
||||
On Windows, <code>go build -buildmode=c-shared</code> now generates Windows
|
||||
ASLR DLLs by default. ASLR can be disabled with <code>--ldflags=-aslr=false</code>.
|
||||
</p>
|
||||
|
||||
<h2 id="library">Core library</h2>
|
||||
|
||||
<p>
|
||||
TODO
|
||||
</p>
|
||||
|
||||
<h3 id="ctypto/tls"><a href="/pkg/crypto/tls">crypto/tls</a></h3>
|
||||
<h3 id="crypto/hmac"><a href="/pkg/crypto/hmac">crypto/hmac</a></h3>
|
||||
|
||||
<p><!-- CL 261960 -->
|
||||
<a href="/pkg/crypto/hmac/#New">New</a> will now panic if separate calls to
|
||||
the hash generation function fail to return new values. Previously, the
|
||||
behavior was undefined and invalid outputs were sometimes generated.
|
||||
</p>
|
||||
|
||||
<h3 id="crypto/tls"><a href="/pkg/crypto/tls">crypto/tls</a></h3>
|
||||
|
||||
<p><!-- CL 256897 -->
|
||||
I/O operations on closing or closed TLS connections can now be detected using
|
||||
@ -184,6 +231,21 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
contain strings with characters within the ASCII range.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 259697 -->
|
||||
<a href="/pkg/crypto/x509/#CreateCertificate">CreateCertificate</a> now
|
||||
verifies the generated certificate's signature using the signer's
|
||||
public key. If the signature is invalid, an error is returned, instead
|
||||
of a malformed certificate.
|
||||
</p>
|
||||
|
||||
<h3 id="encoding/json"><a href="/pkg/encoding/json">encoding/json</a></h3>
|
||||
|
||||
<p><!-- CL 263619 -->
|
||||
The error message for
|
||||
<a href="/pkg/encoding/json/#SyntaxError">SyntaxError</a>
|
||||
now begins with "json: ", matching the other errors in the package.
|
||||
</p>
|
||||
|
||||
<h3 id="net"><a href="/pkg/net/">net</a></h3>
|
||||
|
||||
<p><!-- CL 250357 -->
|
||||
@ -196,6 +258,20 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
with <code>"use of closed network connection"</code>.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 255898 -->
|
||||
In previous Go releases the default TCP listener backlog size on Linux systems,
|
||||
set by <code>/proc/sys/net/core/somaxconn</code>, was limited to a maximum of <code>65535</code>.
|
||||
On Linux kernel version 4.1 and above, the maximum is now <code>4294967295</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="reflect"><a href="/pkg/reflect/">reflect</a></h3>
|
||||
|
||||
<p><!-- CL 259237, golang.org/issue/22075 -->
|
||||
For interface types and values, <a href="/pkg/reflect/#Value.Method">Method</a>,
|
||||
<a href="/pkg/reflect/#Value.MethodByName">MethodByName</a>, and
|
||||
<a href="/pkg/reflect/#Value.NumMethod">NumMethod</a> now
|
||||
operate on the interface's exported method set, rather than its full method set.
|
||||
</p>
|
||||
|
||||
<h3 id="text/template/parse"><a href="/pkg/text/template/parse/">text/template/parse</a></h3>
|
||||
|
||||
@ -229,6 +305,39 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
TODO
|
||||
</p>
|
||||
|
||||
<dl id="crypto/dsa"><dt><a href="/pkg/crypto/dsa/">crypto/dsa</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 257939 -->
|
||||
The <a href="/pkg/crypto/dsa/"><code>crypto/dsa</code></a> package is now deprecated.
|
||||
See <a href="https://golang.org/issue/40337">issue #40337</a>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/dsa -->
|
||||
|
||||
<dl id="crypto/x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 257939 -->
|
||||
DSA signature verification is no longer supported. Note that DSA signature
|
||||
generation was never supported.
|
||||
See <a href="https://golang.org/issue/40337">issue #40337</a>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- crypto/x509 -->
|
||||
|
||||
<dl id="encoding/xml"><dt><a href="/pkg/encoding/xml/">encoding/xml</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 264024 -->
|
||||
The encoder has always taken care to avoid using namespace prefixes
|
||||
beginning with <code>xml</code>, which are reserved by the XML
|
||||
specification.
|
||||
Now, following the specification more closely, that check is
|
||||
case-insensitive, so that prefixes beginning
|
||||
with <code>XML</code>, <code>XmL</code>, and so on are also
|
||||
avoided.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- encoding/xml -->
|
||||
|
||||
<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 233637 -->
|
||||
@ -250,5 +359,31 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
of the form <code>"Range": "bytes=--N"</code> where <code>"-N"</code> is a negative suffix length, for
|
||||
example <code>"Range": "bytes=--2"</code>. It now replies with a <code>416 "Range Not Satisfiable"</code> response.
|
||||
</p>
|
||||
|
||||
<p><!-- CL 256498, golang.org/issue/36990 -->
|
||||
Cookies set with <code>SameSiteDefaultMode</code> now behave according to the current
|
||||
spec (no attribute is set) instead of generating a SameSite key without a value.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- net/http -->
|
||||
|
||||
<dl id="runtime/debug"><dt><a href="/pkg/runtime/debug/">runtime/debug</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 249677 -->
|
||||
TODO: <a href="https://golang.org/cl/249677">https://golang.org/cl/249677</a>: provide Addr method for errors from SetPanicOnFault
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- runtime/debug -->
|
||||
|
||||
<dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
|
||||
<dd>
|
||||
<p><!-- CL 260858 -->
|
||||
<a href="/pkg/strconv/#ParseFloat"><code>ParseFloat</code></a> now uses
|
||||
the <a
|
||||
href="https://nigeltao.github.io/blog/2020/eisel-lemire.html">Eisel-Lemire
|
||||
algorithm</a>, improving performance by up to a factor of 2. This can
|
||||
also speed up decoding textual formats like <a
|
||||
href="/pkg/encoding/json/"><code>encoding/json</code></a>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl><!-- strconv -->
|
||||
|
@ -666,16 +666,13 @@ For example, you should not set <code>$GOHOSTARCH</code> to
|
||||
<code>arm</code> on an x86 system.
|
||||
</p>
|
||||
|
||||
<li><code>$GO386</code> (for <code>386</code> only, default is auto-detected
|
||||
if built on either <code>386</code> or <code>amd64</code>, <code>387</code> otherwise)
|
||||
<li><code>$GO386</code> (for <code>386</code> only, defaults to <code>sse2</code>)
|
||||
<p>
|
||||
This controls the code generated by gc to use either the 387 floating-point unit
|
||||
(set to <code>387</code>) or SSE2 instructions (set to <code>sse2</code>) for
|
||||
floating point computations.
|
||||
This variable controls how gc implements floating point computations.
|
||||
</p>
|
||||
<ul>
|
||||
<li><code>GO386=387</code>: use x87 for floating point operations; should support all x86 chips (Pentium MMX or later).</li>
|
||||
<li><code>GO386=sse2</code>: use SSE2 for floating point operations; has better performance than 387, but only available on Pentium 4/Opteron/Athlon 64 or later.</li>
|
||||
<li><code>GO386=softfloat</code>: use software floating point operations; should support all x86 chips (Pentium MMX or later).</li>
|
||||
<li><code>GO386=sse2</code>: use SSE2 for floating point operations; has better performance but only available on Pentium 4/Opteron/Athlon 64 or later.</li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
|
@ -8,8 +8,8 @@
|
||||
# Consult https://www.iana.org/time-zones for the latest versions.
|
||||
|
||||
# Versions to use.
|
||||
CODE=2020a
|
||||
DATA=2020a
|
||||
CODE=2020d
|
||||
DATA=2020d
|
||||
|
||||
set -e
|
||||
rm -rf work
|
||||
|
Binary file not shown.
@ -181,7 +181,7 @@ func testCallbackCallers(t *testing.T) {
|
||||
name := []string{
|
||||
"runtime.cgocallbackg1",
|
||||
"runtime.cgocallbackg",
|
||||
"runtime.cgocallback_gofunc",
|
||||
"runtime.cgocallback",
|
||||
"runtime.asmcgocall",
|
||||
"runtime.cgocall",
|
||||
"test._Cfunc_callback",
|
||||
|
@ -15,5 +15,6 @@ func TestSetgid(t *testing.T) {
|
||||
}
|
||||
testSetgid(t)
|
||||
}
|
||||
func Test1435(t *testing.T) { test1435(t) }
|
||||
func Test6997(t *testing.T) { test6997(t) }
|
||||
func TestBuildID(t *testing.T) { testBuildID(t) }
|
||||
|
@ -76,6 +76,8 @@ func TestCheckConst(t *testing.T) { testCheckConst(t) }
|
||||
func TestConst(t *testing.T) { testConst(t) }
|
||||
func TestCthread(t *testing.T) { testCthread(t) }
|
||||
func TestEnum(t *testing.T) { testEnum(t) }
|
||||
func TestNamedEnum(t *testing.T) { testNamedEnum(t) }
|
||||
func TestCastToEnum(t *testing.T) { testCastToEnum(t) }
|
||||
func TestErrno(t *testing.T) { testErrno(t) }
|
||||
func TestFpVar(t *testing.T) { testFpVar(t) }
|
||||
func TestHelpers(t *testing.T) { testHelpers(t) }
|
||||
|
152
misc/cgo/test/issue1435.go
Normal file
152
misc/cgo/test/issue1435.go
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build linux,cgo
|
||||
|
||||
package cgotest
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// #include <stdio.h>
|
||||
// #include <stdlib.h>
|
||||
// #include <pthread.h>
|
||||
// #include <unistd.h>
|
||||
// #include <sys/types.h>
|
||||
//
|
||||
// pthread_t *t = NULL;
|
||||
// pthread_mutex_t mu;
|
||||
// int nts = 0;
|
||||
// int all_done = 0;
|
||||
//
|
||||
// static void *aFn(void *vargp) {
|
||||
// int done = 0;
|
||||
// while (!done) {
|
||||
// usleep(100);
|
||||
// pthread_mutex_lock(&mu);
|
||||
// done = all_done;
|
||||
// pthread_mutex_unlock(&mu);
|
||||
// }
|
||||
// return NULL;
|
||||
// }
|
||||
//
|
||||
// void trial(int argc) {
|
||||
// int i;
|
||||
// nts = argc;
|
||||
// t = calloc(nts, sizeof(pthread_t));
|
||||
// pthread_mutex_init(&mu, NULL);
|
||||
// for (i = 0; i < nts; i++) {
|
||||
// pthread_create(&t[i], NULL, aFn, NULL);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void cleanup(void) {
|
||||
// int i;
|
||||
// pthread_mutex_lock(&mu);
|
||||
// all_done = 1;
|
||||
// pthread_mutex_unlock(&mu);
|
||||
// for (i = 0; i < nts; i++) {
|
||||
// pthread_join(t[i], NULL);
|
||||
// }
|
||||
// pthread_mutex_destroy(&mu);
|
||||
// free(t);
|
||||
// }
|
||||
import "C"
|
||||
|
||||
// compareStatus is used to confirm the contents of the thread
|
||||
// specific status files match expectations.
|
||||
func compareStatus(filter, expect string) error {
|
||||
expected := filter + "\t" + expect
|
||||
pid := syscall.Getpid()
|
||||
fs, err := ioutil.ReadDir(fmt.Sprintf("/proc/%d/task", pid))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to find %d tasks: %v", pid, err)
|
||||
}
|
||||
for _, f := range fs {
|
||||
tf := fmt.Sprintf("/proc/%s/status", f.Name())
|
||||
d, err := ioutil.ReadFile(tf)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read %q: %v", tf, err)
|
||||
}
|
||||
lines := strings.Split(string(d), "\n")
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, filter) {
|
||||
if line != expected {
|
||||
return fmt.Errorf("%s %s (bad)\n", tf, line)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// test1435 test 9 glibc implemented setuid/gid syscall functions are
|
||||
// mapped. This test is a slightly more expansive test than that of
|
||||
// src/syscall/syscall_linux_test.go:TestSetuidEtc() insofar as it
|
||||
// launches concurrent threads from C code via CGo and validates that
|
||||
// they are subject to the system calls being tested. For the actual
|
||||
// Go functionality being tested here, the syscall_linux_test version
|
||||
// is considered authoritative, but non-trivial improvements to that
|
||||
// should be mirrored here.
|
||||
func test1435(t *testing.T) {
|
||||
if syscall.Getuid() != 0 {
|
||||
t.Skip("skipping root only test")
|
||||
}
|
||||
|
||||
// Launch some threads in C.
|
||||
const cts = 5
|
||||
C.trial(cts)
|
||||
defer C.cleanup()
|
||||
|
||||
vs := []struct {
|
||||
call string
|
||||
fn func() error
|
||||
filter, expect string
|
||||
}{
|
||||
{call: "Setegid(1)", fn: func() error { return syscall.Setegid(1) }, filter: "Gid:", expect: "0\t1\t0\t1"},
|
||||
{call: "Setegid(0)", fn: func() error { return syscall.Setegid(0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
|
||||
|
||||
{call: "Seteuid(1)", fn: func() error { return syscall.Seteuid(1) }, filter: "Uid:", expect: "0\t1\t0\t1"},
|
||||
{call: "Setuid(0)", fn: func() error { return syscall.Setuid(0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
|
||||
|
||||
{call: "Setgid(1)", fn: func() error { return syscall.Setgid(1) }, filter: "Gid:", expect: "1\t1\t1\t1"},
|
||||
{call: "Setgid(0)", fn: func() error { return syscall.Setgid(0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
|
||||
|
||||
{call: "Setgroups([]int{0,1,2,3})", fn: func() error { return syscall.Setgroups([]int{0, 1, 2, 3}) }, filter: "Groups:", expect: "0 1 2 3 "},
|
||||
{call: "Setgroups(nil)", fn: func() error { return syscall.Setgroups(nil) }, filter: "Groups:", expect: " "},
|
||||
{call: "Setgroups([]int{0})", fn: func() error { return syscall.Setgroups([]int{0}) }, filter: "Groups:", expect: "0 "},
|
||||
|
||||
{call: "Setregid(101,0)", fn: func() error { return syscall.Setregid(101, 0) }, filter: "Gid:", expect: "101\t0\t0\t0"},
|
||||
{call: "Setregid(0,102)", fn: func() error { return syscall.Setregid(0, 102) }, filter: "Gid:", expect: "0\t102\t102\t102"},
|
||||
{call: "Setregid(0,0)", fn: func() error { return syscall.Setregid(0, 0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
|
||||
|
||||
{call: "Setreuid(1,0)", fn: func() error { return syscall.Setreuid(1, 0) }, filter: "Uid:", expect: "1\t0\t0\t0"},
|
||||
{call: "Setreuid(0,2)", fn: func() error { return syscall.Setreuid(0, 2) }, filter: "Uid:", expect: "0\t2\t2\t2"},
|
||||
{call: "Setreuid(0,0)", fn: func() error { return syscall.Setreuid(0, 0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
|
||||
|
||||
{call: "Setresgid(101,0,102)", fn: func() error { return syscall.Setresgid(101, 0, 102) }, filter: "Gid:", expect: "101\t0\t102\t0"},
|
||||
{call: "Setresgid(0,102,101)", fn: func() error { return syscall.Setresgid(0, 102, 101) }, filter: "Gid:", expect: "0\t102\t101\t102"},
|
||||
{call: "Setresgid(0,0,0)", fn: func() error { return syscall.Setresgid(0, 0, 0) }, filter: "Gid:", expect: "0\t0\t0\t0"},
|
||||
|
||||
{call: "Setresuid(1,0,2)", fn: func() error { return syscall.Setresuid(1, 0, 2) }, filter: "Uid:", expect: "1\t0\t2\t0"},
|
||||
{call: "Setresuid(0,2,1)", fn: func() error { return syscall.Setresuid(0, 2, 1) }, filter: "Uid:", expect: "0\t2\t1\t2"},
|
||||
{call: "Setresuid(0,0,0)", fn: func() error { return syscall.Setresuid(0, 0, 0) }, filter: "Uid:", expect: "0\t0\t0\t0"},
|
||||
}
|
||||
|
||||
for i, v := range vs {
|
||||
if err := v.fn(); err != nil {
|
||||
t.Errorf("[%d] %q failed: %v", i, v.call, err)
|
||||
continue
|
||||
}
|
||||
if err := compareStatus(v.filter, v.expect); err != nil {
|
||||
t.Errorf("[%d] %q comparison: %v", i, v.call, err)
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !windows,!static
|
||||
// +build !darwin !internal_pie,!arm64
|
||||
|
||||
#include <stdint.h>
|
||||
#include <dlfcn.h>
|
||||
|
@ -3,6 +3,11 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !windows,!static
|
||||
// +build !darwin !internal_pie,!arm64
|
||||
|
||||
// Excluded in darwin internal linking PIE mode, as dynamic export is not
|
||||
// supported.
|
||||
// Excluded in internal linking mode on darwin/arm64, as it is always PIE.
|
||||
|
||||
package cgotest
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build windows static
|
||||
// +build windows static darwin,internal_pie darwin,arm64
|
||||
|
||||
package cgotest
|
||||
|
||||
|
@ -62,7 +62,7 @@ import (
|
||||
|
||||
func testSigaltstack(t *testing.T) {
|
||||
switch {
|
||||
case runtime.GOOS == "solaris", runtime.GOOS == "illumos", (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64":
|
||||
case runtime.GOOS == "solaris", runtime.GOOS == "illumos", runtime.GOOS == "ios" && runtime.GOARCH == "arm64":
|
||||
t.Skipf("switching signal stack not implemented on %s/%s", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
|
||||
|
@ -1000,6 +1000,32 @@ func testEnum(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func testNamedEnum(t *testing.T) {
|
||||
e := new(C.enum_E)
|
||||
|
||||
*e = C.Enum1
|
||||
if *e != 1 {
|
||||
t.Error("bad enum", C.Enum1)
|
||||
}
|
||||
|
||||
*e = C.Enum2
|
||||
if *e != 2 {
|
||||
t.Error("bad enum", C.Enum2)
|
||||
}
|
||||
}
|
||||
|
||||
func testCastToEnum(t *testing.T) {
|
||||
e := C.enum_E(C.Enum1)
|
||||
if e != 1 {
|
||||
t.Error("bad enum", C.Enum1)
|
||||
}
|
||||
|
||||
e = C.enum_E(C.Enum2)
|
||||
if e != 2 {
|
||||
t.Error("bad enum", C.Enum2)
|
||||
}
|
||||
}
|
||||
|
||||
func testAtol(t *testing.T) {
|
||||
l := Atol("123")
|
||||
if l != 123 {
|
||||
|
20
misc/cgo/test/testdata/issue41761.go
vendored
Normal file
20
misc/cgo/test/testdata/issue41761.go
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
typedef struct S S;
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"cgotest/issue41761a"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func test41761(t *testing.T) {
|
||||
var x issue41761a.T
|
||||
_ = (*C.struct_S)(x.X)
|
||||
}
|
14
misc/cgo/test/testdata/issue41761a/a.go
vendored
Normal file
14
misc/cgo/test/testdata/issue41761a/a.go
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package issue41761a
|
||||
|
||||
/*
|
||||
typedef struct S S;
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type T struct {
|
||||
X *C.S
|
||||
}
|
@ -603,7 +603,7 @@ func TestExtar(t *testing.T) {
|
||||
if runtime.Compiler == "gccgo" {
|
||||
t.Skip("skipping -extar test when using gccgo")
|
||||
}
|
||||
if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && runtime.GOARCH == "arm64" {
|
||||
if runtime.GOOS == "ios" {
|
||||
t.Skip("shell scripts are not executable on iOS hosts")
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,8 @@ package cshared_test
|
||||
import (
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"debug/pe"
|
||||
"encoding/binary"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@ -355,6 +357,100 @@ func TestExportedSymbols(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func checkNumberOfExportedFunctionsWindows(t *testing.T, exportAllSymbols bool) {
|
||||
const prog = `
|
||||
package main
|
||||
|
||||
import "C"
|
||||
|
||||
//export GoFunc
|
||||
func GoFunc() {
|
||||
println(42)
|
||||
}
|
||||
|
||||
//export GoFunc2
|
||||
func GoFunc2() {
|
||||
println(24)
|
||||
}
|
||||
|
||||
func main() {
|
||||
}
|
||||
`
|
||||
|
||||
tmpdir := t.TempDir()
|
||||
|
||||
srcfile := filepath.Join(tmpdir, "test.go")
|
||||
objfile := filepath.Join(tmpdir, "test.dll")
|
||||
if err := ioutil.WriteFile(srcfile, []byte(prog), 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
argv := []string{"build", "-buildmode=c-shared"}
|
||||
if exportAllSymbols {
|
||||
argv = append(argv, "-ldflags", "-extldflags=-Wl,--export-all-symbols")
|
||||
}
|
||||
argv = append(argv, "-o", objfile, srcfile)
|
||||
out, err := exec.Command("go", argv...).CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("build failure: %s\n%s\n", err, string(out))
|
||||
}
|
||||
|
||||
f, err := pe.Open(objfile)
|
||||
if err != nil {
|
||||
t.Fatalf("pe.Open failed: %v", err)
|
||||
}
|
||||
defer f.Close()
|
||||
section := f.Section(".edata")
|
||||
if section == nil {
|
||||
t.Error(".edata section is not present")
|
||||
}
|
||||
|
||||
// TODO: deduplicate this struct from cmd/link/internal/ld/pe.go
|
||||
type IMAGE_EXPORT_DIRECTORY struct {
|
||||
_ [2]uint32
|
||||
_ [2]uint16
|
||||
_ [2]uint32
|
||||
NumberOfFunctions uint32
|
||||
NumberOfNames uint32
|
||||
_ [3]uint32
|
||||
}
|
||||
var e IMAGE_EXPORT_DIRECTORY
|
||||
if err := binary.Read(section.Open(), binary.LittleEndian, &e); err != nil {
|
||||
t.Fatalf("binary.Read failed: %v", err)
|
||||
}
|
||||
|
||||
expectedNumber := uint32(2)
|
||||
|
||||
if exportAllSymbols {
|
||||
if e.NumberOfFunctions <= expectedNumber {
|
||||
t.Fatalf("missing exported functions: %v", e.NumberOfFunctions)
|
||||
}
|
||||
if e.NumberOfNames <= expectedNumber {
|
||||
t.Fatalf("missing exported names: %v", e.NumberOfNames)
|
||||
}
|
||||
} else {
|
||||
if e.NumberOfFunctions != expectedNumber {
|
||||
t.Fatalf("too many exported functions: %v", e.NumberOfFunctions)
|
||||
}
|
||||
if e.NumberOfNames != expectedNumber {
|
||||
t.Fatalf("too many exported names: %v", e.NumberOfNames)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNumberOfExportedFunctions(t *testing.T) {
|
||||
if GOOS != "windows" {
|
||||
t.Skip("skipping windows only test")
|
||||
}
|
||||
t.Parallel()
|
||||
|
||||
t.Run("OnlyExported", func(t *testing.T) {
|
||||
checkNumberOfExportedFunctionsWindows(t, false)
|
||||
})
|
||||
t.Run("All", func(t *testing.T) {
|
||||
checkNumberOfExportedFunctionsWindows(t, true)
|
||||
})
|
||||
}
|
||||
|
||||
// test1: shared library can be dynamically loaded and exported symbols are accessible.
|
||||
func TestExportedSymbolsWithDynamicLoad(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
@ -1,13 +1,20 @@
|
||||
Go on iOS
|
||||
=========
|
||||
|
||||
For details on developing Go for iOS on macOS, see the documentation in the mobile
|
||||
subrepository:
|
||||
To run the standard library tests, run all.bash as usual, but with the compiler
|
||||
set to the clang wrapper that invokes clang for iOS. For example, this command runs
|
||||
all.bash on the iOS emulator:
|
||||
|
||||
https://github.com/golang/mobile
|
||||
GOOS=ios GOARCH=amd64 CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/ios/clangwrap.sh ./all.bash
|
||||
|
||||
It is necessary to set up the environment before running tests or programs directly on a
|
||||
device.
|
||||
To use the go tool to run individual programs and tests, put $GOROOT/bin into PATH to ensure
|
||||
the go_ios_$GOARCH_exec wrapper is found. For example, to run the archive/tar tests:
|
||||
|
||||
export PATH=$GOROOT/bin:$PATH
|
||||
GOOS=ios GOARCH=amd64 CGO_ENABLED=1 go test archive/tar
|
||||
|
||||
The go_ios_exec wrapper uses GOARCH to select the emulator (amd64) or the device (arm64).
|
||||
However, further setup is required to run tests or programs directly on a device.
|
||||
|
||||
First make sure you have a valid developer certificate and have setup your device properly
|
||||
to run apps signed by your developer certificate. Then install the libimobiledevice and
|
||||
@ -29,18 +36,10 @@ which will output something similar to
|
||||
export GOIOS_TEAM_ID=ZZZZZZZZ
|
||||
|
||||
If you have multiple devices connected, specify the device UDID with the GOIOS_DEVICE_ID
|
||||
variable. Use `idevice_id -l` to list all available UDIDs.
|
||||
variable. Use `idevice_id -l` to list all available UDIDs. Then, setting GOARCH to arm64
|
||||
will select the device:
|
||||
|
||||
Finally, to run the standard library tests, run all.bash as usual, but with the compiler
|
||||
set to the clang wrapper that invokes clang for iOS. For example,
|
||||
|
||||
GOARCH=arm64 CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/ios/clangwrap.sh ./all.bash
|
||||
|
||||
To use the go tool directly to run programs and tests, put $GOROOT/bin into PATH to ensure
|
||||
the go_darwin_$GOARCH_exec wrapper is found. For example, to run the archive/tar tests
|
||||
|
||||
export PATH=$GOROOT/bin:$PATH
|
||||
GOARCH=arm64 CGO_ENABLED=1 go test archive/tar
|
||||
GOOS=ios GOARCH=arm64 CGO_ENABLED=1 CC_FOR_TARGET=$(pwd)/../misc/ios/clangwrap.sh ./all.bash
|
||||
|
||||
Note that the go_darwin_$GOARCH_exec wrapper uninstalls any existing app identified by
|
||||
the bundle id before installing a new app. If the uninstalled app is the last app by
|
||||
|
@ -2,17 +2,19 @@
|
||||
# This uses the latest available iOS SDK, which is recommended.
|
||||
# To select a specific SDK, run 'xcodebuild -showsdks'
|
||||
# to see the available SDKs and replace iphoneos with one of them.
|
||||
SDK=iphoneos
|
||||
if [ "$GOARCH" == "arm64" ]; then
|
||||
SDK=iphoneos
|
||||
PLATFORM=ios
|
||||
CLANGARCH="arm64"
|
||||
else
|
||||
SDK=iphonesimulator
|
||||
PLATFORM=ios-simulator
|
||||
CLANGARCH="x86_64"
|
||||
fi
|
||||
|
||||
SDK_PATH=`xcrun --sdk $SDK --show-sdk-path`
|
||||
export IPHONEOS_DEPLOYMENT_TARGET=5.1
|
||||
# cmd/cgo doesn't support llvm-gcc-4.2, so we have to use clang.
|
||||
CLANG=`xcrun --sdk $SDK --find clang`
|
||||
|
||||
if [ "$GOARCH" == "arm64" ]; then
|
||||
CLANGARCH="arm64"
|
||||
else
|
||||
echo "unknown GOARCH=$GOARCH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec "$CLANG" -arch $CLANGARCH -isysroot "$SDK_PATH" -mios-version-min=10.0 "$@"
|
||||
exec "$CLANG" -arch $CLANGARCH -isysroot "$SDK_PATH" -m${PLATFORM}-version-min=10.0 "$@"
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
// detect attempts to autodetect the correct
|
||||
// values of the environment variables
|
||||
// used by go_darwin_arm_exec.
|
||||
// used by go_ios_exec.
|
||||
// detect shells out to ideviceinfo, a third party program that can
|
||||
// be obtained by following the instructions at
|
||||
// https://github.com/libimobiledevice/libimobiledevice.
|
||||
|
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This program can be used as go_darwin_arm_exec by the Go tool.
|
||||
// This program can be used as go_ios_$GOARCH_exec by the Go tool.
|
||||
// It executes binaries on an iOS device using the XCode toolchain
|
||||
// and the ios-deploy program: https://github.com/phonegap/ios-deploy
|
||||
//
|
||||
@ -34,6 +34,7 @@ import (
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
@ -58,34 +59,16 @@ var lock *os.File
|
||||
|
||||
func main() {
|
||||
log.SetFlags(0)
|
||||
log.SetPrefix("go_darwin_arm_exec: ")
|
||||
log.SetPrefix("go_ios_exec: ")
|
||||
if debug {
|
||||
log.Println(strings.Join(os.Args, " "))
|
||||
}
|
||||
if len(os.Args) < 2 {
|
||||
log.Fatal("usage: go_darwin_arm_exec a.out")
|
||||
log.Fatal("usage: go_ios_exec a.out")
|
||||
}
|
||||
|
||||
// e.g. B393DDEB490947F5A463FD074299B6C0AXXXXXXX
|
||||
devID = getenv("GOIOS_DEV_ID")
|
||||
|
||||
// e.g. Z8B3JBXXXX.org.golang.sample, Z8B3JBXXXX prefix is available at
|
||||
// https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
|
||||
appID = getenv("GOIOS_APP_ID")
|
||||
|
||||
// e.g. Z8B3JBXXXX, available at
|
||||
// https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
|
||||
teamID = getenv("GOIOS_TEAM_ID")
|
||||
|
||||
// Device IDs as listed with ios-deploy -c.
|
||||
deviceID = os.Getenv("GOIOS_DEVICE_ID")
|
||||
|
||||
parts := strings.SplitN(appID, ".", 2)
|
||||
// For compatibility with the old builders, use a fallback bundle ID
|
||||
bundleID = "golang.gotest"
|
||||
if len(parts) == 2 {
|
||||
bundleID = parts[1]
|
||||
}
|
||||
|
||||
exitCode, err := runMain()
|
||||
if err != nil {
|
||||
@ -96,7 +79,7 @@ func main() {
|
||||
|
||||
func runMain() (int, error) {
|
||||
var err error
|
||||
tmpdir, err = ioutil.TempDir("", "go_darwin_arm_exec_")
|
||||
tmpdir, err = ioutil.TempDir("", "go_ios_exec_")
|
||||
if err != nil {
|
||||
return 1, err
|
||||
}
|
||||
@ -117,7 +100,7 @@ func runMain() (int, error) {
|
||||
//
|
||||
// The lock file is never deleted, to avoid concurrent locks on distinct
|
||||
// files with the same path.
|
||||
lockName := filepath.Join(os.TempDir(), "go_darwin_arm_exec-"+deviceID+".lock")
|
||||
lockName := filepath.Join(os.TempDir(), "go_ios_exec-"+deviceID+".lock")
|
||||
lock, err = os.OpenFile(lockName, os.O_CREATE|os.O_RDONLY, 0666)
|
||||
if err != nil {
|
||||
return 1, err
|
||||
@ -126,28 +109,12 @@ func runMain() (int, error) {
|
||||
return 1, err
|
||||
}
|
||||
|
||||
if err := uninstall(bundleID); err != nil {
|
||||
return 1, err
|
||||
if goarch := os.Getenv("GOARCH"); goarch == "arm64" {
|
||||
err = runOnDevice(appdir)
|
||||
} else {
|
||||
err = runOnSimulator(appdir)
|
||||
}
|
||||
|
||||
if err := install(appdir); err != nil {
|
||||
return 1, err
|
||||
}
|
||||
|
||||
if err := mountDevImage(); err != nil {
|
||||
return 1, err
|
||||
}
|
||||
|
||||
// Kill any hanging debug bridges that might take up port 3222.
|
||||
exec.Command("killall", "idevicedebugserverproxy").Run()
|
||||
|
||||
closer, err := startDebugBridge()
|
||||
if err != nil {
|
||||
return 1, err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
if err := run(appdir, bundleID, os.Args[2:]); err != nil {
|
||||
// If the lldb driver completed with an exit code, use that.
|
||||
if err, ok := err.(*exec.ExitError); ok {
|
||||
if ws, ok := err.Sys().(interface{ ExitStatus() int }); ok {
|
||||
@ -159,6 +126,62 @@ func runMain() (int, error) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func runOnSimulator(appdir string) error {
|
||||
if err := installSimulator(appdir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return runSimulator(appdir, bundleID, os.Args[2:])
|
||||
}
|
||||
|
||||
func runOnDevice(appdir string) error {
|
||||
// e.g. B393DDEB490947F5A463FD074299B6C0AXXXXXXX
|
||||
devID = getenv("GOIOS_DEV_ID")
|
||||
|
||||
// e.g. Z8B3JBXXXX.org.golang.sample, Z8B3JBXXXX prefix is available at
|
||||
// https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
|
||||
appID = getenv("GOIOS_APP_ID")
|
||||
|
||||
// e.g. Z8B3JBXXXX, available at
|
||||
// https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
|
||||
teamID = getenv("GOIOS_TEAM_ID")
|
||||
|
||||
// Device IDs as listed with ios-deploy -c.
|
||||
deviceID = os.Getenv("GOIOS_DEVICE_ID")
|
||||
|
||||
parts := strings.SplitN(appID, ".", 2)
|
||||
if len(parts) == 2 {
|
||||
bundleID = parts[1]
|
||||
}
|
||||
|
||||
if err := signApp(appdir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := uninstallDevice(bundleID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := installDevice(appdir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := mountDevImage(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Kill any hanging debug bridges that might take up port 3222.
|
||||
exec.Command("killall", "idevicedebugserverproxy").Run()
|
||||
|
||||
closer, err := startDebugBridge()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
|
||||
return runDevice(appdir, bundleID, os.Args[2:])
|
||||
}
|
||||
|
||||
func getenv(envvar string) string {
|
||||
s := os.Getenv(envvar)
|
||||
if s == "" {
|
||||
@ -191,7 +214,11 @@ func assembleApp(appdir, bin string) error {
|
||||
if err := ioutil.WriteFile(filepath.Join(appdir, "ResourceRules.plist"), []byte(resourceRules), 0744); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func signApp(appdir string) error {
|
||||
entitlementsPath := filepath.Join(tmpdir, "Entitlements.plist")
|
||||
cmd := exec.Command(
|
||||
"codesign",
|
||||
"-f",
|
||||
@ -421,7 +448,20 @@ func parsePlistDict(dict []byte) (map[string]string, error) {
|
||||
return values, nil
|
||||
}
|
||||
|
||||
func uninstall(bundleID string) error {
|
||||
func installSimulator(appdir string) error {
|
||||
cmd := exec.Command(
|
||||
"xcrun", "simctl", "install",
|
||||
"booted", // Install to the booted simulator.
|
||||
appdir,
|
||||
)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
os.Stderr.Write(out)
|
||||
return fmt.Errorf("xcrun simctl install booted %q: %v", appdir, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func uninstallDevice(bundleID string) error {
|
||||
cmd := idevCmd(exec.Command(
|
||||
"ideviceinstaller",
|
||||
"-U", bundleID,
|
||||
@ -433,7 +473,7 @@ func uninstall(bundleID string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func install(appdir string) error {
|
||||
func installDevice(appdir string) error {
|
||||
attempt := 0
|
||||
for {
|
||||
cmd := idevCmd(exec.Command(
|
||||
@ -464,15 +504,28 @@ func idevCmd(cmd *exec.Cmd) *exec.Cmd {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func run(appdir, bundleID string, args []string) error {
|
||||
var env []string
|
||||
for _, e := range os.Environ() {
|
||||
// Don't override TMPDIR, HOME, GOCACHE on the device.
|
||||
if strings.HasPrefix(e, "TMPDIR=") || strings.HasPrefix(e, "HOME=") || strings.HasPrefix(e, "GOCACHE=") {
|
||||
continue
|
||||
func runSimulator(appdir, bundleID string, args []string) error {
|
||||
cmd := exec.Command(
|
||||
"xcrun", "simctl", "launch",
|
||||
"--wait-for-debugger",
|
||||
"booted",
|
||||
bundleID,
|
||||
)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
os.Stderr.Write(out)
|
||||
return fmt.Errorf("xcrun simctl launch booted %q: %v", bundleID, err)
|
||||
}
|
||||
env = append(env, e)
|
||||
var processID int
|
||||
var ignore string
|
||||
if _, err := fmt.Sscanf(string(out), "%s %d", &ignore, &processID); err != nil {
|
||||
return fmt.Errorf("runSimulator: couldn't find processID from `simctl launch`: %v (%q)", err, out)
|
||||
}
|
||||
_, err = runLLDB("ios-simulator", appdir, strconv.Itoa(processID), args)
|
||||
return err
|
||||
}
|
||||
|
||||
func runDevice(appdir, bundleID string, args []string) error {
|
||||
attempt := 0
|
||||
for {
|
||||
// The device app path reported by the device might be stale, so retry
|
||||
@ -487,9 +540,33 @@ func run(appdir, bundleID string, args []string) error {
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
out, err := runLLDB("remote-ios", appdir, deviceapp, args)
|
||||
// If the program was not started it can be retried without papering over
|
||||
// real test failures.
|
||||
started := bytes.HasPrefix(out, []byte("lldb: running program"))
|
||||
if started || err == nil || attempt == 5 {
|
||||
return err
|
||||
}
|
||||
// Sometimes, the app was not yet ready to launch or the device path was
|
||||
// stale. Retry.
|
||||
attempt++
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func runLLDB(target, appdir, deviceapp string, args []string) ([]byte, error) {
|
||||
var env []string
|
||||
for _, e := range os.Environ() {
|
||||
// Don't override TMPDIR, HOME, GOCACHE on the device.
|
||||
if strings.HasPrefix(e, "TMPDIR=") || strings.HasPrefix(e, "HOME=") || strings.HasPrefix(e, "GOCACHE=") {
|
||||
continue
|
||||
}
|
||||
env = append(env, e)
|
||||
}
|
||||
lldb := exec.Command(
|
||||
"python",
|
||||
"-", // Read script from stdin.
|
||||
target,
|
||||
appdir,
|
||||
deviceapp,
|
||||
)
|
||||
@ -499,7 +576,7 @@ func run(appdir, bundleID string, args []string) error {
|
||||
lldb.Stdout = os.Stdout
|
||||
var out bytes.Buffer
|
||||
lldb.Stderr = io.MultiWriter(&out, os.Stderr)
|
||||
err = lldb.Start()
|
||||
err := lldb.Start()
|
||||
if err == nil {
|
||||
// Forward SIGQUIT to the lldb driver which in turn will forward
|
||||
// to the running program.
|
||||
@ -515,17 +592,7 @@ func run(appdir, bundleID string, args []string) error {
|
||||
signal.Stop(sigs)
|
||||
close(sigs)
|
||||
}
|
||||
// If the program was not started it can be retried without papering over
|
||||
// real test failures.
|
||||
started := bytes.HasPrefix(out.Bytes(), []byte("lldb: running program"))
|
||||
if started || err == nil || attempt == 5 {
|
||||
return err
|
||||
}
|
||||
// Sometimes, the app was not yet ready to launch or the device path was
|
||||
// stale. Retry.
|
||||
attempt++
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
return out.Bytes(), err
|
||||
}
|
||||
|
||||
func copyLocalDir(dst, src string) error {
|
||||
@ -679,6 +746,7 @@ func infoPlist(pkgpath string) string {
|
||||
<key>CFBundleSupportedPlatforms</key><array><string>iPhoneOS</string></array>
|
||||
<key>CFBundleExecutable</key><string>gotest</string>
|
||||
<key>CFBundleVersion</key><string>1.0</string>
|
||||
<key>CFBundleShortVersionString</key><string>1.0</string>
|
||||
<key>CFBundleIdentifier</key><string>` + bundleID + `</string>
|
||||
<key>CFBundleResourceSpecification</key><string>ResourceRules.plist</string>
|
||||
<key>LSRequiresIPhoneOS</key><true/>
|
||||
@ -739,7 +807,7 @@ import sys
|
||||
import os
|
||||
import signal
|
||||
|
||||
exe, device_exe, args = sys.argv[1], sys.argv[2], sys.argv[3:]
|
||||
platform, exe, device_exe_or_pid, args = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4:]
|
||||
|
||||
env = []
|
||||
for k, v in os.environ.items():
|
||||
@ -754,17 +822,21 @@ debugger.SetAsync(True)
|
||||
debugger.SkipLLDBInitFiles(True)
|
||||
|
||||
err = lldb.SBError()
|
||||
target = debugger.CreateTarget(exe, None, 'remote-ios', True, err)
|
||||
target = debugger.CreateTarget(exe, None, platform, True, err)
|
||||
if not target.IsValid() or not err.Success():
|
||||
sys.stderr.write("lldb: failed to setup up target: %s\n" % (err))
|
||||
sys.exit(1)
|
||||
|
||||
target.modules[0].SetPlatformFileSpec(lldb.SBFileSpec(device_exe))
|
||||
|
||||
listener = debugger.GetListener()
|
||||
process = target.ConnectRemote(listener, 'connect://localhost:3222', None, err)
|
||||
|
||||
if platform == 'remote-ios':
|
||||
target.modules[0].SetPlatformFileSpec(lldb.SBFileSpec(device_exe_or_pid))
|
||||
process = target.ConnectRemote(listener, 'connect://localhost:3222', None, err)
|
||||
else:
|
||||
process = target.AttachToProcessWithID(listener, int(device_exe_or_pid), err)
|
||||
|
||||
if not err.Success():
|
||||
sys.stderr.write("lldb: failed to connect to remote target: %s\n" % (err))
|
||||
sys.stderr.write("lldb: failed to connect to remote target %s: %s\n" % (device_exe_or_pid, err))
|
||||
sys.exit(1)
|
||||
|
||||
# Don't stop on signals.
|
||||
@ -777,6 +849,25 @@ for i in range(0, sigs.GetNumSignals()):
|
||||
event = lldb.SBEvent()
|
||||
running = False
|
||||
prev_handler = None
|
||||
|
||||
def signal_handler(signal, frame):
|
||||
process.Signal(signal)
|
||||
|
||||
def run_program():
|
||||
# Forward SIGQUIT to the program.
|
||||
prev_handler = signal.signal(signal.SIGQUIT, signal_handler)
|
||||
# Tell the Go driver that the program is running and should not be retried.
|
||||
sys.stderr.write("lldb: running program\n")
|
||||
running = True
|
||||
# Process is stopped at attach/launch. Let it run.
|
||||
process.Continue()
|
||||
|
||||
if platform != 'remote-ios':
|
||||
# For the local emulator the program is ready to run.
|
||||
# For remote device runs, we need to wait for eStateConnected,
|
||||
# below.
|
||||
run_program()
|
||||
|
||||
while True:
|
||||
if not listener.WaitForEvent(1, event):
|
||||
continue
|
||||
@ -800,24 +891,22 @@ while True:
|
||||
signal.signal(signal.SIGQUIT, prev_handler)
|
||||
break
|
||||
elif state == lldb.eStateConnected:
|
||||
if platform == 'remote-ios':
|
||||
process.RemoteLaunch(args, env, None, None, None, None, 0, False, err)
|
||||
if not err.Success():
|
||||
sys.stderr.write("lldb: failed to launch remote process: %s\n" % (err))
|
||||
process.Kill()
|
||||
debugger.Terminate()
|
||||
sys.exit(1)
|
||||
# Forward SIGQUIT to the program.
|
||||
def signal_handler(signal, frame):
|
||||
process.Signal(signal)
|
||||
prev_handler = signal.signal(signal.SIGQUIT, signal_handler)
|
||||
# Tell the Go driver that the program is running and should not be retried.
|
||||
sys.stderr.write("lldb: running program\n")
|
||||
running = True
|
||||
# Process stops once at the beginning. Continue.
|
||||
process.Continue()
|
||||
run_program()
|
||||
|
||||
exitStatus = process.GetExitStatus()
|
||||
exitDesc = process.GetExitDescription()
|
||||
process.Kill()
|
||||
debugger.Terminate()
|
||||
if exitStatus == 0 and exitDesc is not None:
|
||||
# Ensure tests fail when killed by a signal.
|
||||
exitStatus = 123
|
||||
|
||||
sys.exit(exitStatus)
|
||||
`
|
@ -102,7 +102,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (!global.crypto) {
|
||||
if (!global.crypto && global.require) {
|
||||
const nodeCrypto = require("crypto");
|
||||
global.crypto = {
|
||||
getRandomValues(b) {
|
||||
@ -110,6 +110,9 @@
|
||||
},
|
||||
};
|
||||
}
|
||||
if (!global.crypto) {
|
||||
throw new Error("global.crypto is not available, polyfill required (getRandomValues only)");
|
||||
}
|
||||
|
||||
if (!global.performance) {
|
||||
global.performance = {
|
||||
@ -120,13 +123,19 @@
|
||||
};
|
||||
}
|
||||
|
||||
if (!global.TextEncoder) {
|
||||
if (!global.TextEncoder && global.require) {
|
||||
global.TextEncoder = require("util").TextEncoder;
|
||||
}
|
||||
if (!global.TextEncoder) {
|
||||
throw new Error("global.TextEncoder is not available, polyfill required");
|
||||
}
|
||||
|
||||
if (!global.TextDecoder) {
|
||||
if (!global.TextDecoder && global.require) {
|
||||
global.TextDecoder = require("util").TextDecoder;
|
||||
}
|
||||
if (!global.TextDecoder) {
|
||||
throw new Error("global.TextDecoder is not available, polyfill required");
|
||||
}
|
||||
|
||||
// End of polyfills for common API.
|
||||
|
||||
@ -255,6 +264,7 @@
|
||||
|
||||
// func wasmExit(code int32)
|
||||
"runtime.wasmExit": (sp) => {
|
||||
sp >>>= 0;
|
||||
const code = this.mem.getInt32(sp + 8, true);
|
||||
this.exited = true;
|
||||
delete this._inst;
|
||||
@ -267,6 +277,7 @@
|
||||
|
||||
// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
|
||||
"runtime.wasmWrite": (sp) => {
|
||||
sp >>>= 0;
|
||||
const fd = getInt64(sp + 8);
|
||||
const p = getInt64(sp + 16);
|
||||
const n = this.mem.getInt32(sp + 24, true);
|
||||
@ -275,16 +286,19 @@
|
||||
|
||||
// func resetMemoryDataView()
|
||||
"runtime.resetMemoryDataView": (sp) => {
|
||||
sp >>>= 0;
|
||||
this.mem = new DataView(this._inst.exports.mem.buffer);
|
||||
},
|
||||
|
||||
// func nanotime1() int64
|
||||
"runtime.nanotime1": (sp) => {
|
||||
sp >>>= 0;
|
||||
setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
|
||||
},
|
||||
|
||||
// func walltime1() (sec int64, nsec int32)
|
||||
"runtime.walltime1": (sp) => {
|
||||
sp >>>= 0;
|
||||
const msec = (new Date).getTime();
|
||||
setInt64(sp + 8, msec / 1000);
|
||||
this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
|
||||
@ -292,6 +306,7 @@
|
||||
|
||||
// func scheduleTimeoutEvent(delay int64) int32
|
||||
"runtime.scheduleTimeoutEvent": (sp) => {
|
||||
sp >>>= 0;
|
||||
const id = this._nextCallbackTimeoutID;
|
||||
this._nextCallbackTimeoutID++;
|
||||
this._scheduledTimeouts.set(id, setTimeout(
|
||||
@ -311,6 +326,7 @@
|
||||
|
||||
// func clearTimeoutEvent(id int32)
|
||||
"runtime.clearTimeoutEvent": (sp) => {
|
||||
sp >>>= 0;
|
||||
const id = this.mem.getInt32(sp + 8, true);
|
||||
clearTimeout(this._scheduledTimeouts.get(id));
|
||||
this._scheduledTimeouts.delete(id);
|
||||
@ -318,11 +334,13 @@
|
||||
|
||||
// func getRandomData(r []byte)
|
||||
"runtime.getRandomData": (sp) => {
|
||||
sp >>>= 0;
|
||||
crypto.getRandomValues(loadSlice(sp + 8));
|
||||
},
|
||||
|
||||
// func finalizeRef(v ref)
|
||||
"syscall/js.finalizeRef": (sp) => {
|
||||
sp >>>= 0;
|
||||
const id = this.mem.getUint32(sp + 8, true);
|
||||
this._goRefCounts[id]--;
|
||||
if (this._goRefCounts[id] === 0) {
|
||||
@ -335,44 +353,51 @@
|
||||
|
||||
// func stringVal(value string) ref
|
||||
"syscall/js.stringVal": (sp) => {
|
||||
sp >>>= 0;
|
||||
storeValue(sp + 24, loadString(sp + 8));
|
||||
},
|
||||
|
||||
// func valueGet(v ref, p string) ref
|
||||
"syscall/js.valueGet": (sp) => {
|
||||
sp >>>= 0;
|
||||
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
|
||||
sp = this._inst.exports.getsp(); // see comment above
|
||||
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||
storeValue(sp + 32, result);
|
||||
},
|
||||
|
||||
// func valueSet(v ref, p string, x ref)
|
||||
"syscall/js.valueSet": (sp) => {
|
||||
sp >>>= 0;
|
||||
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
|
||||
},
|
||||
|
||||
// func valueDelete(v ref, p string)
|
||||
"syscall/js.valueDelete": (sp) => {
|
||||
sp >>>= 0;
|
||||
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
|
||||
},
|
||||
|
||||
// func valueIndex(v ref, i int) ref
|
||||
"syscall/js.valueIndex": (sp) => {
|
||||
sp >>>= 0;
|
||||
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
|
||||
},
|
||||
|
||||
// valueSetIndex(v ref, i int, x ref)
|
||||
"syscall/js.valueSetIndex": (sp) => {
|
||||
sp >>>= 0;
|
||||
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
|
||||
},
|
||||
|
||||
// func valueCall(v ref, m string, args []ref) (ref, bool)
|
||||
"syscall/js.valueCall": (sp) => {
|
||||
sp >>>= 0;
|
||||
try {
|
||||
const v = loadValue(sp + 8);
|
||||
const m = Reflect.get(v, loadString(sp + 16));
|
||||
const args = loadSliceOfValues(sp + 32);
|
||||
const result = Reflect.apply(m, v, args);
|
||||
sp = this._inst.exports.getsp(); // see comment above
|
||||
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||
storeValue(sp + 56, result);
|
||||
this.mem.setUint8(sp + 64, 1);
|
||||
} catch (err) {
|
||||
@ -383,11 +408,12 @@
|
||||
|
||||
// func valueInvoke(v ref, args []ref) (ref, bool)
|
||||
"syscall/js.valueInvoke": (sp) => {
|
||||
sp >>>= 0;
|
||||
try {
|
||||
const v = loadValue(sp + 8);
|
||||
const args = loadSliceOfValues(sp + 16);
|
||||
const result = Reflect.apply(v, undefined, args);
|
||||
sp = this._inst.exports.getsp(); // see comment above
|
||||
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||
storeValue(sp + 40, result);
|
||||
this.mem.setUint8(sp + 48, 1);
|
||||
} catch (err) {
|
||||
@ -398,11 +424,12 @@
|
||||
|
||||
// func valueNew(v ref, args []ref) (ref, bool)
|
||||
"syscall/js.valueNew": (sp) => {
|
||||
sp >>>= 0;
|
||||
try {
|
||||
const v = loadValue(sp + 8);
|
||||
const args = loadSliceOfValues(sp + 16);
|
||||
const result = Reflect.construct(v, args);
|
||||
sp = this._inst.exports.getsp(); // see comment above
|
||||
sp = this._inst.exports.getsp() >>> 0; // see comment above
|
||||
storeValue(sp + 40, result);
|
||||
this.mem.setUint8(sp + 48, 1);
|
||||
} catch (err) {
|
||||
@ -413,11 +440,13 @@
|
||||
|
||||
// func valueLength(v ref) int
|
||||
"syscall/js.valueLength": (sp) => {
|
||||
sp >>>= 0;
|
||||
setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
|
||||
},
|
||||
|
||||
// valuePrepareString(v ref) (ref, int)
|
||||
"syscall/js.valuePrepareString": (sp) => {
|
||||
sp >>>= 0;
|
||||
const str = encoder.encode(String(loadValue(sp + 8)));
|
||||
storeValue(sp + 16, str);
|
||||
setInt64(sp + 24, str.length);
|
||||
@ -425,17 +454,20 @@
|
||||
|
||||
// valueLoadString(v ref, b []byte)
|
||||
"syscall/js.valueLoadString": (sp) => {
|
||||
sp >>>= 0;
|
||||
const str = loadValue(sp + 8);
|
||||
loadSlice(sp + 16).set(str);
|
||||
},
|
||||
|
||||
// func valueInstanceOf(v ref, t ref) bool
|
||||
"syscall/js.valueInstanceOf": (sp) => {
|
||||
sp >>>= 0;
|
||||
this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
|
||||
},
|
||||
|
||||
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
||||
"syscall/js.copyBytesToGo": (sp) => {
|
||||
sp >>>= 0;
|
||||
const dst = loadSlice(sp + 8);
|
||||
const src = loadValue(sp + 32);
|
||||
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
|
||||
@ -450,6 +482,7 @@
|
||||
|
||||
// func copyBytesToJS(dst ref, src []byte) (int, bool)
|
||||
"syscall/js.copyBytesToJS": (sp) => {
|
||||
sp >>>= 0;
|
||||
const dst = loadValue(sp + 8);
|
||||
const src = loadSlice(sp + 16);
|
||||
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
|
||||
|
@ -13,8 +13,8 @@ package tar
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
"reflect"
|
||||
"strconv"
|
||||
@ -525,12 +525,12 @@ func (h Header) allowedFormats() (format Format, paxHdrs map[string]string, err
|
||||
return format, paxHdrs, err
|
||||
}
|
||||
|
||||
// FileInfo returns an os.FileInfo for the Header.
|
||||
func (h *Header) FileInfo() os.FileInfo {
|
||||
// FileInfo returns an fs.FileInfo for the Header.
|
||||
func (h *Header) FileInfo() fs.FileInfo {
|
||||
return headerFileInfo{h}
|
||||
}
|
||||
|
||||
// headerFileInfo implements os.FileInfo.
|
||||
// headerFileInfo implements fs.FileInfo.
|
||||
type headerFileInfo struct {
|
||||
h *Header
|
||||
}
|
||||
@ -549,57 +549,57 @@ func (fi headerFileInfo) Name() string {
|
||||
}
|
||||
|
||||
// Mode returns the permission and mode bits for the headerFileInfo.
|
||||
func (fi headerFileInfo) Mode() (mode os.FileMode) {
|
||||
func (fi headerFileInfo) Mode() (mode fs.FileMode) {
|
||||
// Set file permission bits.
|
||||
mode = os.FileMode(fi.h.Mode).Perm()
|
||||
mode = fs.FileMode(fi.h.Mode).Perm()
|
||||
|
||||
// Set setuid, setgid and sticky bits.
|
||||
if fi.h.Mode&c_ISUID != 0 {
|
||||
mode |= os.ModeSetuid
|
||||
mode |= fs.ModeSetuid
|
||||
}
|
||||
if fi.h.Mode&c_ISGID != 0 {
|
||||
mode |= os.ModeSetgid
|
||||
mode |= fs.ModeSetgid
|
||||
}
|
||||
if fi.h.Mode&c_ISVTX != 0 {
|
||||
mode |= os.ModeSticky
|
||||
mode |= fs.ModeSticky
|
||||
}
|
||||
|
||||
// Set file mode bits; clear perm, setuid, setgid, and sticky bits.
|
||||
switch m := os.FileMode(fi.h.Mode) &^ 07777; m {
|
||||
switch m := fs.FileMode(fi.h.Mode) &^ 07777; m {
|
||||
case c_ISDIR:
|
||||
mode |= os.ModeDir
|
||||
mode |= fs.ModeDir
|
||||
case c_ISFIFO:
|
||||
mode |= os.ModeNamedPipe
|
||||
mode |= fs.ModeNamedPipe
|
||||
case c_ISLNK:
|
||||
mode |= os.ModeSymlink
|
||||
mode |= fs.ModeSymlink
|
||||
case c_ISBLK:
|
||||
mode |= os.ModeDevice
|
||||
mode |= fs.ModeDevice
|
||||
case c_ISCHR:
|
||||
mode |= os.ModeDevice
|
||||
mode |= os.ModeCharDevice
|
||||
mode |= fs.ModeDevice
|
||||
mode |= fs.ModeCharDevice
|
||||
case c_ISSOCK:
|
||||
mode |= os.ModeSocket
|
||||
mode |= fs.ModeSocket
|
||||
}
|
||||
|
||||
switch fi.h.Typeflag {
|
||||
case TypeSymlink:
|
||||
mode |= os.ModeSymlink
|
||||
mode |= fs.ModeSymlink
|
||||
case TypeChar:
|
||||
mode |= os.ModeDevice
|
||||
mode |= os.ModeCharDevice
|
||||
mode |= fs.ModeDevice
|
||||
mode |= fs.ModeCharDevice
|
||||
case TypeBlock:
|
||||
mode |= os.ModeDevice
|
||||
mode |= fs.ModeDevice
|
||||
case TypeDir:
|
||||
mode |= os.ModeDir
|
||||
mode |= fs.ModeDir
|
||||
case TypeFifo:
|
||||
mode |= os.ModeNamedPipe
|
||||
mode |= fs.ModeNamedPipe
|
||||
}
|
||||
|
||||
return mode
|
||||
}
|
||||
|
||||
// sysStat, if non-nil, populates h from system-dependent fields of fi.
|
||||
var sysStat func(fi os.FileInfo, h *Header) error
|
||||
var sysStat func(fi fs.FileInfo, h *Header) error
|
||||
|
||||
const (
|
||||
// Mode constants from the USTAR spec:
|
||||
@ -623,10 +623,10 @@ const (
|
||||
// If fi describes a symlink, FileInfoHeader records link as the link target.
|
||||
// If fi describes a directory, a slash is appended to the name.
|
||||
//
|
||||
// Since os.FileInfo's Name method only returns the base name of
|
||||
// Since fs.FileInfo's Name method only returns the base name of
|
||||
// the file it describes, it may be necessary to modify Header.Name
|
||||
// to provide the full path name of the file.
|
||||
func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
|
||||
func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) {
|
||||
if fi == nil {
|
||||
return nil, errors.New("archive/tar: FileInfo is nil")
|
||||
}
|
||||
@ -643,29 +643,29 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
|
||||
case fi.IsDir():
|
||||
h.Typeflag = TypeDir
|
||||
h.Name += "/"
|
||||
case fm&os.ModeSymlink != 0:
|
||||
case fm&fs.ModeSymlink != 0:
|
||||
h.Typeflag = TypeSymlink
|
||||
h.Linkname = link
|
||||
case fm&os.ModeDevice != 0:
|
||||
if fm&os.ModeCharDevice != 0 {
|
||||
case fm&fs.ModeDevice != 0:
|
||||
if fm&fs.ModeCharDevice != 0 {
|
||||
h.Typeflag = TypeChar
|
||||
} else {
|
||||
h.Typeflag = TypeBlock
|
||||
}
|
||||
case fm&os.ModeNamedPipe != 0:
|
||||
case fm&fs.ModeNamedPipe != 0:
|
||||
h.Typeflag = TypeFifo
|
||||
case fm&os.ModeSocket != 0:
|
||||
case fm&fs.ModeSocket != 0:
|
||||
return nil, fmt.Errorf("archive/tar: sockets not supported")
|
||||
default:
|
||||
return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm)
|
||||
}
|
||||
if fm&os.ModeSetuid != 0 {
|
||||
if fm&fs.ModeSetuid != 0 {
|
||||
h.Mode |= c_ISUID
|
||||
}
|
||||
if fm&os.ModeSetgid != 0 {
|
||||
if fm&fs.ModeSetgid != 0 {
|
||||
h.Mode |= c_ISGID
|
||||
}
|
||||
if fm&os.ModeSticky != 0 {
|
||||
if fm&fs.ModeSticky != 0 {
|
||||
h.Mode |= c_ISVTX
|
||||
}
|
||||
// If possible, populate additional fields from OS-specific
|
||||
|
@ -7,7 +7,6 @@ package tar
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -104,7 +103,7 @@ func (tr *Reader) next() (*Header, error) {
|
||||
continue // This is a meta header affecting the next header
|
||||
case TypeGNULongName, TypeGNULongLink:
|
||||
format.mayOnlyBe(FormatGNU)
|
||||
realname, err := ioutil.ReadAll(tr)
|
||||
realname, err := io.ReadAll(tr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -294,7 +293,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) {
|
||||
// parsePAX parses PAX headers.
|
||||
// If an extended header (type 'x') is invalid, ErrHeader is returned
|
||||
func parsePAX(r io.Reader) (map[string]string, error) {
|
||||
buf, err := ioutil.ReadAll(r)
|
||||
buf, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -850,7 +849,7 @@ func discard(r io.Reader, n int64) error {
|
||||
}
|
||||
}
|
||||
|
||||
copySkipped, err := io.CopyN(ioutil.Discard, r, n-seekSkipped)
|
||||
copySkipped, err := io.CopyN(io.Discard, r, n-seekSkipped)
|
||||
if err == io.EOF && seekSkipped+copySkipped < n {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
|
@ -865,7 +865,7 @@ func TestReadTruncation(t *testing.T) {
|
||||
}
|
||||
cnt++
|
||||
if s2 == "manual" {
|
||||
if _, err = tr.writeTo(ioutil.Discard); err != nil {
|
||||
if _, err = tr.writeTo(io.Discard); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
package tar
|
||||
|
||||
import (
|
||||
"os"
|
||||
"io/fs"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"strconv"
|
||||
@ -23,7 +23,7 @@ func init() {
|
||||
// The downside is that renaming uname or gname by the OS never takes effect.
|
||||
var userMap, groupMap sync.Map // map[int]string
|
||||
|
||||
func statUnix(fi os.FileInfo, h *Header) error {
|
||||
func statUnix(fi fs.FileInfo, h *Header) error {
|
||||
sys, ok := fi.Sys().(*syscall.Stat_t)
|
||||
if !ok {
|
||||
return nil
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
@ -327,7 +328,7 @@ func TestRoundTrip(t *testing.T) {
|
||||
if !reflect.DeepEqual(rHdr, hdr) {
|
||||
t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr)
|
||||
}
|
||||
rData, err := ioutil.ReadAll(tr)
|
||||
rData, err := io.ReadAll(tr)
|
||||
if err != nil {
|
||||
t.Fatalf("Read: %v", err)
|
||||
}
|
||||
@ -338,7 +339,7 @@ func TestRoundTrip(t *testing.T) {
|
||||
|
||||
type headerRoundTripTest struct {
|
||||
h *Header
|
||||
fm os.FileMode
|
||||
fm fs.FileMode
|
||||
}
|
||||
|
||||
func TestHeaderRoundTrip(t *testing.T) {
|
||||
@ -361,7 +362,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360600852, 0),
|
||||
Typeflag: TypeSymlink,
|
||||
},
|
||||
fm: 0777 | os.ModeSymlink,
|
||||
fm: 0777 | fs.ModeSymlink,
|
||||
}, {
|
||||
// character device node.
|
||||
h: &Header{
|
||||
@ -371,7 +372,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360578951, 0),
|
||||
Typeflag: TypeChar,
|
||||
},
|
||||
fm: 0666 | os.ModeDevice | os.ModeCharDevice,
|
||||
fm: 0666 | fs.ModeDevice | fs.ModeCharDevice,
|
||||
}, {
|
||||
// block device node.
|
||||
h: &Header{
|
||||
@ -381,7 +382,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360578954, 0),
|
||||
Typeflag: TypeBlock,
|
||||
},
|
||||
fm: 0660 | os.ModeDevice,
|
||||
fm: 0660 | fs.ModeDevice,
|
||||
}, {
|
||||
// directory.
|
||||
h: &Header{
|
||||
@ -391,7 +392,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360601116, 0),
|
||||
Typeflag: TypeDir,
|
||||
},
|
||||
fm: 0755 | os.ModeDir,
|
||||
fm: 0755 | fs.ModeDir,
|
||||
}, {
|
||||
// fifo node.
|
||||
h: &Header{
|
||||
@ -401,7 +402,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360578949, 0),
|
||||
Typeflag: TypeFifo,
|
||||
},
|
||||
fm: 0600 | os.ModeNamedPipe,
|
||||
fm: 0600 | fs.ModeNamedPipe,
|
||||
}, {
|
||||
// setuid.
|
||||
h: &Header{
|
||||
@ -411,7 +412,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1355405093, 0),
|
||||
Typeflag: TypeReg,
|
||||
},
|
||||
fm: 0755 | os.ModeSetuid,
|
||||
fm: 0755 | fs.ModeSetuid,
|
||||
}, {
|
||||
// setguid.
|
||||
h: &Header{
|
||||
@ -421,7 +422,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360602346, 0),
|
||||
Typeflag: TypeReg,
|
||||
},
|
||||
fm: 0750 | os.ModeSetgid,
|
||||
fm: 0750 | fs.ModeSetgid,
|
||||
}, {
|
||||
// sticky.
|
||||
h: &Header{
|
||||
@ -431,7 +432,7 @@ func TestHeaderRoundTrip(t *testing.T) {
|
||||
ModTime: time.Unix(1360602540, 0),
|
||||
Typeflag: TypeReg,
|
||||
},
|
||||
fm: 0600 | os.ModeSticky,
|
||||
fm: 0600 | fs.ModeSticky,
|
||||
}, {
|
||||
// hard link.
|
||||
h: &Header{
|
||||
@ -804,9 +805,9 @@ func Benchmark(b *testing.B) {
|
||||
b.Run(v.label, func(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// Writing to ioutil.Discard because we want to
|
||||
// Writing to io.Discard because we want to
|
||||
// test purely the writer code and not bring in disk performance into this.
|
||||
tw := NewWriter(ioutil.Discard)
|
||||
tw := NewWriter(io.Discard)
|
||||
for _, file := range v.files {
|
||||
if err := tw.WriteHeader(file.hdr); err != nil {
|
||||
b.Errorf("unexpected WriteHeader error: %v", err)
|
||||
@ -844,7 +845,7 @@ func Benchmark(b *testing.B) {
|
||||
if _, err := tr.Next(); err != nil {
|
||||
b.Errorf("unexpected Next error: %v", err)
|
||||
}
|
||||
if _, err := io.Copy(ioutil.Discard, tr); err != nil {
|
||||
if _, err := io.Copy(io.Discard, tr); err != nil {
|
||||
b.Errorf("unexpected Copy error : %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,12 @@ import (
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -21,18 +26,28 @@ var (
|
||||
ErrChecksum = errors.New("zip: checksum error")
|
||||
)
|
||||
|
||||
// A Reader serves content from a ZIP archive.
|
||||
type Reader struct {
|
||||
r io.ReaderAt
|
||||
File []*File
|
||||
Comment string
|
||||
decompressors map[uint16]Decompressor
|
||||
|
||||
// fileList is a list of files sorted by ename,
|
||||
// for use by the Open method.
|
||||
fileListOnce sync.Once
|
||||
fileList []fileListEntry
|
||||
}
|
||||
|
||||
// A ReadCloser is a Reader that must be closed when no longer needed.
|
||||
type ReadCloser struct {
|
||||
f *os.File
|
||||
Reader
|
||||
}
|
||||
|
||||
// A File is a single file in a ZIP archive.
|
||||
// The file information is in the embedded FileHeader.
|
||||
// The file content can be accessed by calling Open.
|
||||
type File struct {
|
||||
FileHeader
|
||||
zip *Reader
|
||||
@ -187,6 +202,10 @@ type checksumReader struct {
|
||||
err error // sticky error
|
||||
}
|
||||
|
||||
func (r *checksumReader) Stat() (fs.FileInfo, error) {
|
||||
return headerFileInfo{&r.f.FileHeader}, nil
|
||||
}
|
||||
|
||||
func (r *checksumReader) Read(b []byte) (n int, err error) {
|
||||
if r.err != nil {
|
||||
return 0, r.err
|
||||
@ -607,3 +626,173 @@ func (b *readBuf) sub(n int) readBuf {
|
||||
*b = (*b)[n:]
|
||||
return b2
|
||||
}
|
||||
|
||||
// A fileListEntry is a File and its ename.
|
||||
// If file == nil, the fileListEntry describes a directory, without metadata.
|
||||
type fileListEntry struct {
|
||||
name string
|
||||
file *File // nil for directories
|
||||
}
|
||||
|
||||
type fileInfoDirEntry interface {
|
||||
fs.FileInfo
|
||||
fs.DirEntry
|
||||
}
|
||||
|
||||
func (e *fileListEntry) stat() fileInfoDirEntry {
|
||||
if e.file != nil {
|
||||
return headerFileInfo{&e.file.FileHeader}
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
// Only used for directories.
|
||||
func (f *fileListEntry) Name() string { _, elem, _ := split(f.name); return elem }
|
||||
func (f *fileListEntry) Size() int64 { return 0 }
|
||||
func (f *fileListEntry) ModTime() time.Time { return time.Time{} }
|
||||
func (f *fileListEntry) Mode() fs.FileMode { return fs.ModeDir | 0555 }
|
||||
func (f *fileListEntry) Type() fs.FileMode { return fs.ModeDir }
|
||||
func (f *fileListEntry) IsDir() bool { return true }
|
||||
func (f *fileListEntry) Sys() interface{} { return nil }
|
||||
|
||||
func (f *fileListEntry) Info() (fs.FileInfo, error) { return f, nil }
|
||||
|
||||
// toValidName coerces name to be a valid name for fs.FS.Open.
|
||||
func toValidName(name string) string {
|
||||
name = strings.ReplaceAll(name, `\`, `/`)
|
||||
p := path.Clean(name)
|
||||
if strings.HasPrefix(p, "/") {
|
||||
p = p[len("/"):]
|
||||
}
|
||||
for strings.HasPrefix(name, "../") {
|
||||
p = p[len("../"):]
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (r *Reader) initFileList() {
|
||||
r.fileListOnce.Do(func() {
|
||||
dirs := make(map[string]bool)
|
||||
for _, file := range r.File {
|
||||
name := toValidName(file.Name)
|
||||
for dir := path.Dir(name); dir != "."; dir = path.Dir(dir) {
|
||||
dirs[dir] = true
|
||||
}
|
||||
r.fileList = append(r.fileList, fileListEntry{name, file})
|
||||
}
|
||||
for dir := range dirs {
|
||||
r.fileList = append(r.fileList, fileListEntry{dir + "/", nil})
|
||||
}
|
||||
|
||||
sort.Slice(r.fileList, func(i, j int) bool { return fileEntryLess(r.fileList[i].name, r.fileList[j].name) })
|
||||
})
|
||||
}
|
||||
|
||||
func fileEntryLess(x, y string) bool {
|
||||
xdir, xelem, _ := split(x)
|
||||
ydir, yelem, _ := split(y)
|
||||
return xdir < ydir || xdir == ydir && xelem < yelem
|
||||
}
|
||||
|
||||
// Open opens the named file in the ZIP archive,
|
||||
// using the semantics of io.FS.Open:
|
||||
// paths are always slash separated, with no
|
||||
// leading / or ../ elements.
|
||||
func (r *Reader) Open(name string) (fs.File, error) {
|
||||
r.initFileList()
|
||||
|
||||
e := r.openLookup(name)
|
||||
if e == nil || !fs.ValidPath(name) {
|
||||
return nil, &fs.PathError{Op: "open", Path: name, Err: fs.ErrNotExist}
|
||||
}
|
||||
if e.file == nil || strings.HasSuffix(e.file.Name, "/") {
|
||||
return &openDir{e, r.openReadDir(name), 0}, nil
|
||||
}
|
||||
rc, err := e.file.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rc.(fs.File), nil
|
||||
}
|
||||
|
||||
func split(name string) (dir, elem string, isDir bool) {
|
||||
if name[len(name)-1] == '/' {
|
||||
isDir = true
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
i := len(name) - 1
|
||||
for i >= 0 && name[i] != '/' {
|
||||
i--
|
||||
}
|
||||
if i < 0 {
|
||||
return ".", name, isDir
|
||||
}
|
||||
return name[:i], name[i+1:], isDir
|
||||
}
|
||||
|
||||
var dotFile = &fileListEntry{name: "./"}
|
||||
|
||||
func (r *Reader) openLookup(name string) *fileListEntry {
|
||||
if name == "." {
|
||||
return dotFile
|
||||
}
|
||||
|
||||
dir, elem, _ := split(name)
|
||||
files := r.fileList
|
||||
i := sort.Search(len(files), func(i int) bool {
|
||||
idir, ielem, _ := split(files[i].name)
|
||||
return idir > dir || idir == dir && ielem >= elem
|
||||
})
|
||||
if i < len(files) {
|
||||
fname := files[i].name
|
||||
if fname == name || len(fname) == len(name)+1 && fname[len(name)] == '/' && fname[:len(name)] == name {
|
||||
return &files[i]
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Reader) openReadDir(dir string) []fileListEntry {
|
||||
files := r.fileList
|
||||
i := sort.Search(len(files), func(i int) bool {
|
||||
idir, _, _ := split(files[i].name)
|
||||
return idir >= dir
|
||||
})
|
||||
j := sort.Search(len(files), func(j int) bool {
|
||||
jdir, _, _ := split(files[j].name)
|
||||
return jdir > dir
|
||||
})
|
||||
return files[i:j]
|
||||
}
|
||||
|
||||
type openDir struct {
|
||||
e *fileListEntry
|
||||
files []fileListEntry
|
||||
offset int
|
||||
}
|
||||
|
||||
func (d *openDir) Close() error { return nil }
|
||||
func (d *openDir) Stat() (fs.FileInfo, error) { return d.e.stat(), nil }
|
||||
|
||||
func (d *openDir) Read([]byte) (int, error) {
|
||||
return 0, &fs.PathError{Op: "read", Path: d.e.name, Err: errors.New("is a directory")}
|
||||
}
|
||||
|
||||
func (d *openDir) ReadDir(count int) ([]fs.DirEntry, error) {
|
||||
n := len(d.files) - d.offset
|
||||
if count > 0 && n > count {
|
||||
n = count
|
||||
}
|
||||
if n == 0 {
|
||||
if count <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, io.EOF
|
||||
}
|
||||
list := make([]fs.DirEntry, n)
|
||||
for i := range list {
|
||||
list[i] = d.files[d.offset+i].stat()
|
||||
}
|
||||
d.offset += n
|
||||
return list, nil
|
||||
}
|
||||
|
@ -10,12 +10,14 @@ import (
|
||||
"encoding/hex"
|
||||
"internal/obscuretestdata"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -30,7 +32,7 @@ type ZipTest struct {
|
||||
|
||||
type ZipTestFile struct {
|
||||
Name string
|
||||
Mode os.FileMode
|
||||
Mode fs.FileMode
|
||||
NonUTF8 bool
|
||||
ModTime time.Time
|
||||
Modified time.Time
|
||||
@ -107,7 +109,7 @@ var tests = []ZipTest{
|
||||
Name: "symlink",
|
||||
Content: []byte("../target"),
|
||||
Modified: time.Date(2012, 2, 3, 19, 56, 48, 0, timeZone(-2*time.Hour)),
|
||||
Mode: 0777 | os.ModeSymlink,
|
||||
Mode: 0777 | fs.ModeSymlink,
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -149,7 +151,7 @@ var tests = []ZipTest{
|
||||
Name: "dir/empty/",
|
||||
Content: []byte{},
|
||||
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, time.UTC),
|
||||
Mode: os.ModeDir | 0777,
|
||||
Mode: fs.ModeDir | 0777,
|
||||
},
|
||||
{
|
||||
Name: "readonly",
|
||||
@ -179,7 +181,7 @@ var tests = []ZipTest{
|
||||
Name: "dir/empty/",
|
||||
Content: []byte{},
|
||||
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, timeZone(0)),
|
||||
Mode: os.ModeDir | 0777,
|
||||
Mode: fs.ModeDir | 0777,
|
||||
},
|
||||
{
|
||||
Name: "readonly",
|
||||
@ -645,7 +647,7 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) {
|
||||
}
|
||||
}
|
||||
|
||||
func testFileMode(t *testing.T, f *File, want os.FileMode) {
|
||||
func testFileMode(t *testing.T, f *File, want fs.FileMode) {
|
||||
mode := f.Mode()
|
||||
if want == 0 {
|
||||
t.Errorf("%s mode: got %v, want none", f.Name, mode)
|
||||
@ -928,7 +930,7 @@ func returnBigZipBytes() (r io.ReaderAt, size int64) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
b, err = ioutil.ReadAll(f)
|
||||
b, err = io.ReadAll(f)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -985,7 +987,7 @@ func TestIssue10957(t *testing.T) {
|
||||
continue
|
||||
}
|
||||
if f.UncompressedSize64 < 1e6 {
|
||||
n, err := io.Copy(ioutil.Discard, r)
|
||||
n, err := io.Copy(io.Discard, r)
|
||||
if i == 3 && err != io.ErrUnexpectedEOF {
|
||||
t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err)
|
||||
}
|
||||
@ -1027,7 +1029,7 @@ func TestIssue11146(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, err = ioutil.ReadAll(r)
|
||||
_, err = io.ReadAll(r)
|
||||
if err != io.ErrUnexpectedEOF {
|
||||
t.Errorf("File[0] error = %v; want io.ErrUnexpectedEOF", err)
|
||||
}
|
||||
@ -1070,3 +1072,13 @@ func TestIssue12449(t *testing.T) {
|
||||
t.Errorf("Error reading the archive: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFS(t *testing.T) {
|
||||
z, err := OpenReader("testdata/unix.zip")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := fstest.TestFS(z, "hello", "dir/bar", "dir/empty", "readonly"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"compress/flate"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@ -111,7 +110,7 @@ func init() {
|
||||
compressors.Store(Store, Compressor(func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil }))
|
||||
compressors.Store(Deflate, Compressor(func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil }))
|
||||
|
||||
decompressors.Store(Store, Decompressor(ioutil.NopCloser))
|
||||
decompressors.Store(Store, Decompressor(io.NopCloser))
|
||||
decompressors.Store(Deflate, Decompressor(newFlateReader))
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ fields must be used instead.
|
||||
package zip
|
||||
|
||||
import (
|
||||
"os"
|
||||
"io/fs"
|
||||
"path"
|
||||
"time"
|
||||
)
|
||||
@ -137,12 +137,12 @@ type FileHeader struct {
|
||||
ExternalAttrs uint32 // Meaning depends on CreatorVersion
|
||||
}
|
||||
|
||||
// FileInfo returns an os.FileInfo for the FileHeader.
|
||||
func (h *FileHeader) FileInfo() os.FileInfo {
|
||||
// FileInfo returns an fs.FileInfo for the FileHeader.
|
||||
func (h *FileHeader) FileInfo() fs.FileInfo {
|
||||
return headerFileInfo{h}
|
||||
}
|
||||
|
||||
// headerFileInfo implements os.FileInfo.
|
||||
// headerFileInfo implements fs.FileInfo.
|
||||
type headerFileInfo struct {
|
||||
fh *FileHeader
|
||||
}
|
||||
@ -161,17 +161,20 @@ func (fi headerFileInfo) ModTime() time.Time {
|
||||
}
|
||||
return fi.fh.Modified.UTC()
|
||||
}
|
||||
func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() }
|
||||
func (fi headerFileInfo) Mode() fs.FileMode { return fi.fh.Mode() }
|
||||
func (fi headerFileInfo) Type() fs.FileMode { return fi.fh.Mode().Type() }
|
||||
func (fi headerFileInfo) Sys() interface{} { return fi.fh }
|
||||
|
||||
func (fi headerFileInfo) Info() (fs.FileInfo, error) { return fi, nil }
|
||||
|
||||
// FileInfoHeader creates a partially-populated FileHeader from an
|
||||
// os.FileInfo.
|
||||
// Because os.FileInfo's Name method returns only the base name of
|
||||
// fs.FileInfo.
|
||||
// Because fs.FileInfo's Name method returns only the base name of
|
||||
// the file it describes, it may be necessary to modify the Name field
|
||||
// of the returned header to provide the full path name of the file.
|
||||
// If compression is desired, callers should set the FileHeader.Method
|
||||
// field; it is unset by default.
|
||||
func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) {
|
||||
func FileInfoHeader(fi fs.FileInfo) (*FileHeader, error) {
|
||||
size := fi.Size()
|
||||
fh := &FileHeader{
|
||||
Name: fi.Name(),
|
||||
@ -280,7 +283,7 @@ const (
|
||||
)
|
||||
|
||||
// Mode returns the permission and mode bits for the FileHeader.
|
||||
func (h *FileHeader) Mode() (mode os.FileMode) {
|
||||
func (h *FileHeader) Mode() (mode fs.FileMode) {
|
||||
switch h.CreatorVersion >> 8 {
|
||||
case creatorUnix, creatorMacOSX:
|
||||
mode = unixModeToFileMode(h.ExternalAttrs >> 16)
|
||||
@ -288,18 +291,18 @@ func (h *FileHeader) Mode() (mode os.FileMode) {
|
||||
mode = msdosModeToFileMode(h.ExternalAttrs)
|
||||
}
|
||||
if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
|
||||
mode |= os.ModeDir
|
||||
mode |= fs.ModeDir
|
||||
}
|
||||
return mode
|
||||
}
|
||||
|
||||
// SetMode changes the permission and mode bits for the FileHeader.
|
||||
func (h *FileHeader) SetMode(mode os.FileMode) {
|
||||
func (h *FileHeader) SetMode(mode fs.FileMode) {
|
||||
h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
|
||||
h.ExternalAttrs = fileModeToUnixMode(mode) << 16
|
||||
|
||||
// set MSDOS attributes too, as the original zip does.
|
||||
if mode&os.ModeDir != 0 {
|
||||
if mode&fs.ModeDir != 0 {
|
||||
h.ExternalAttrs |= msdosDir
|
||||
}
|
||||
if mode&0200 == 0 {
|
||||
@ -312,9 +315,9 @@ func (h *FileHeader) isZip64() bool {
|
||||
return h.CompressedSize64 >= uint32max || h.UncompressedSize64 >= uint32max
|
||||
}
|
||||
|
||||
func msdosModeToFileMode(m uint32) (mode os.FileMode) {
|
||||
func msdosModeToFileMode(m uint32) (mode fs.FileMode) {
|
||||
if m&msdosDir != 0 {
|
||||
mode = os.ModeDir | 0777
|
||||
mode = fs.ModeDir | 0777
|
||||
} else {
|
||||
mode = 0666
|
||||
}
|
||||
@ -324,64 +327,64 @@ func msdosModeToFileMode(m uint32) (mode os.FileMode) {
|
||||
return mode
|
||||
}
|
||||
|
||||
func fileModeToUnixMode(mode os.FileMode) uint32 {
|
||||
func fileModeToUnixMode(mode fs.FileMode) uint32 {
|
||||
var m uint32
|
||||
switch mode & os.ModeType {
|
||||
switch mode & fs.ModeType {
|
||||
default:
|
||||
m = s_IFREG
|
||||
case os.ModeDir:
|
||||
case fs.ModeDir:
|
||||
m = s_IFDIR
|
||||
case os.ModeSymlink:
|
||||
case fs.ModeSymlink:
|
||||
m = s_IFLNK
|
||||
case os.ModeNamedPipe:
|
||||
case fs.ModeNamedPipe:
|
||||
m = s_IFIFO
|
||||
case os.ModeSocket:
|
||||
case fs.ModeSocket:
|
||||
m = s_IFSOCK
|
||||
case os.ModeDevice:
|
||||
if mode&os.ModeCharDevice != 0 {
|
||||
case fs.ModeDevice:
|
||||
if mode&fs.ModeCharDevice != 0 {
|
||||
m = s_IFCHR
|
||||
} else {
|
||||
m = s_IFBLK
|
||||
}
|
||||
}
|
||||
if mode&os.ModeSetuid != 0 {
|
||||
if mode&fs.ModeSetuid != 0 {
|
||||
m |= s_ISUID
|
||||
}
|
||||
if mode&os.ModeSetgid != 0 {
|
||||
if mode&fs.ModeSetgid != 0 {
|
||||
m |= s_ISGID
|
||||
}
|
||||
if mode&os.ModeSticky != 0 {
|
||||
if mode&fs.ModeSticky != 0 {
|
||||
m |= s_ISVTX
|
||||
}
|
||||
return m | uint32(mode&0777)
|
||||
}
|
||||
|
||||
func unixModeToFileMode(m uint32) os.FileMode {
|
||||
mode := os.FileMode(m & 0777)
|
||||
func unixModeToFileMode(m uint32) fs.FileMode {
|
||||
mode := fs.FileMode(m & 0777)
|
||||
switch m & s_IFMT {
|
||||
case s_IFBLK:
|
||||
mode |= os.ModeDevice
|
||||
mode |= fs.ModeDevice
|
||||
case s_IFCHR:
|
||||
mode |= os.ModeDevice | os.ModeCharDevice
|
||||
mode |= fs.ModeDevice | fs.ModeCharDevice
|
||||
case s_IFDIR:
|
||||
mode |= os.ModeDir
|
||||
mode |= fs.ModeDir
|
||||
case s_IFIFO:
|
||||
mode |= os.ModeNamedPipe
|
||||
mode |= fs.ModeNamedPipe
|
||||
case s_IFLNK:
|
||||
mode |= os.ModeSymlink
|
||||
mode |= fs.ModeSymlink
|
||||
case s_IFREG:
|
||||
// nothing to do
|
||||
case s_IFSOCK:
|
||||
mode |= os.ModeSocket
|
||||
mode |= fs.ModeSocket
|
||||
}
|
||||
if m&s_ISGID != 0 {
|
||||
mode |= os.ModeSetgid
|
||||
mode |= fs.ModeSetgid
|
||||
}
|
||||
if m&s_ISUID != 0 {
|
||||
mode |= os.ModeSetuid
|
||||
mode |= fs.ModeSetuid
|
||||
}
|
||||
if m&s_ISVTX != 0 {
|
||||
mode |= os.ModeSticky
|
||||
mode |= fs.ModeSticky
|
||||
}
|
||||
return mode
|
||||
}
|
||||
|
@ -9,9 +9,9 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@ -23,7 +23,7 @@ type WriteTest struct {
|
||||
Name string
|
||||
Data []byte
|
||||
Method uint16
|
||||
Mode os.FileMode
|
||||
Mode fs.FileMode
|
||||
}
|
||||
|
||||
var writeTests = []WriteTest{
|
||||
@ -43,19 +43,19 @@ var writeTests = []WriteTest{
|
||||
Name: "setuid",
|
||||
Data: []byte("setuid file"),
|
||||
Method: Deflate,
|
||||
Mode: 0755 | os.ModeSetuid,
|
||||
Mode: 0755 | fs.ModeSetuid,
|
||||
},
|
||||
{
|
||||
Name: "setgid",
|
||||
Data: []byte("setgid file"),
|
||||
Method: Deflate,
|
||||
Mode: 0755 | os.ModeSetgid,
|
||||
Mode: 0755 | fs.ModeSetgid,
|
||||
},
|
||||
{
|
||||
Name: "symlink",
|
||||
Data: []byte("../link/target"),
|
||||
Method: Deflate,
|
||||
Mode: 0755 | os.ModeSymlink,
|
||||
Mode: 0755 | fs.ModeSymlink,
|
||||
},
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@ func TestWriterFlush(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestWriterDir(t *testing.T) {
|
||||
w := NewWriter(ioutil.Discard)
|
||||
w := NewWriter(io.Discard)
|
||||
dw, err := w.Create("dir/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -380,7 +380,7 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
|
||||
if err != nil {
|
||||
t.Fatal("opening:", err)
|
||||
}
|
||||
b, err := ioutil.ReadAll(rc)
|
||||
b, err := io.ReadAll(rc)
|
||||
if err != nil {
|
||||
t.Fatal("reading:", err)
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
"hash"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
@ -620,7 +619,7 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
|
||||
t.Fatal("read:", err)
|
||||
}
|
||||
}
|
||||
gotEnd, err := ioutil.ReadAll(rc)
|
||||
gotEnd, err := io.ReadAll(rc)
|
||||
if err != nil {
|
||||
t.Fatal("read end:", err)
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/iotest"
|
||||
@ -886,7 +885,7 @@ func TestReadEmptyBuffer(t *testing.T) {
|
||||
|
||||
func TestLinesAfterRead(t *testing.T) {
|
||||
l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize)
|
||||
_, err := ioutil.ReadAll(l)
|
||||
_, err := io.ReadAll(l)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
@ -1130,7 +1129,7 @@ func TestWriterReadFromCounts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// A writeCountingDiscard is like ioutil.Discard and counts the number of times
|
||||
// A writeCountingDiscard is like io.Discard and counts the number of times
|
||||
// Write is called on it.
|
||||
type writeCountingDiscard int
|
||||
|
||||
@ -1300,7 +1299,7 @@ func TestReaderReset(t *testing.T) {
|
||||
t.Errorf("buf = %q; want foo", buf)
|
||||
}
|
||||
r.Reset(strings.NewReader("bar bar"))
|
||||
all, err := ioutil.ReadAll(r)
|
||||
all, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -1645,13 +1644,13 @@ func BenchmarkReaderWriteToOptimal(b *testing.B) {
|
||||
buf := make([]byte, bufSize)
|
||||
r := bytes.NewReader(buf)
|
||||
srcReader := NewReaderSize(onlyReader{r}, 1<<10)
|
||||
if _, ok := ioutil.Discard.(io.ReaderFrom); !ok {
|
||||
b.Fatal("ioutil.Discard doesn't support ReaderFrom")
|
||||
if _, ok := io.Discard.(io.ReaderFrom); !ok {
|
||||
b.Fatal("io.Discard doesn't support ReaderFrom")
|
||||
}
|
||||
for i := 0; i < b.N; i++ {
|
||||
r.Seek(0, io.SeekStart)
|
||||
srcReader.Reset(onlyReader{r})
|
||||
n, err := srcReader.WriteTo(ioutil.Discard)
|
||||
n, err := srcReader.WriteTo(io.Discard)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@ -1722,7 +1721,7 @@ func BenchmarkReaderEmpty(b *testing.B) {
|
||||
str := strings.Repeat("x", 16<<10)
|
||||
for i := 0; i < b.N; i++ {
|
||||
br := NewReader(strings.NewReader(str))
|
||||
n, err := io.Copy(ioutil.Discard, br)
|
||||
n, err := io.Copy(io.Discard, br)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@ -1737,7 +1736,7 @@ func BenchmarkWriterEmpty(b *testing.B) {
|
||||
str := strings.Repeat("x", 1<<10)
|
||||
bs := []byte(str)
|
||||
for i := 0; i < b.N; i++ {
|
||||
bw := NewWriter(ioutil.Discard)
|
||||
bw := NewWriter(io.Discard)
|
||||
bw.Flush()
|
||||
bw.WriteByte('a')
|
||||
bw.Flush()
|
||||
@ -1752,7 +1751,7 @@ func BenchmarkWriterEmpty(b *testing.B) {
|
||||
|
||||
func BenchmarkWriterFlush(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
bw := NewWriter(ioutil.Discard)
|
||||
bw := NewWriter(io.Discard)
|
||||
str := strings.Repeat("x", 50)
|
||||
for i := 0; i < b.N; i++ {
|
||||
bw.WriteString(str)
|
||||
|
@ -3,10 +3,10 @@
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
# Usage: buildall.sh [-e] [pattern]
|
||||
# Usage: buildall.bash [-e] [pattern]
|
||||
#
|
||||
# buildall.bash builds the standard library for all Go-supported
|
||||
# architectures. It is used by the "all-compile" trybot builder,
|
||||
# architectures. It is used by the "misc-compile" trybot builders,
|
||||
# as a smoke test to quickly flag portability issues.
|
||||
#
|
||||
# Options:
|
||||
@ -37,12 +37,11 @@ GOROOT="$(cd .. && pwd)"
|
||||
|
||||
gettargets() {
|
||||
../bin/go tool dist list | sed -e 's|/|-|'
|
||||
echo linux-386-387
|
||||
echo linux-arm-arm5
|
||||
}
|
||||
|
||||
selectedtargets() {
|
||||
gettargets | egrep -v 'android-arm|darwin-arm64' | egrep "$pattern"
|
||||
gettargets | egrep "$pattern"
|
||||
}
|
||||
|
||||
# put linux first in the target list to get all the architectures up front.
|
||||
@ -64,15 +63,11 @@ do
|
||||
echo "### Building $target"
|
||||
export GOOS=$(echo $target | sed 's/-.*//')
|
||||
export GOARCH=$(echo $target | sed 's/.*-//')
|
||||
unset GO386 GOARM
|
||||
unset GOARM
|
||||
if [ "$GOARCH" = "arm5" ]; then
|
||||
export GOARCH=arm
|
||||
export GOARM=5
|
||||
fi
|
||||
if [ "$GOARCH" = "387" ]; then
|
||||
export GOARCH=386
|
||||
export GO386=387
|
||||
fi
|
||||
|
||||
# Build and vet everything.
|
||||
# cmd/go/internal/work/exec.go enables the same vet flags during go test of std cmd
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
. "bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
@ -235,7 +234,7 @@ func TestReaderCopyNothing(t *testing.T) {
|
||||
type justWriter struct {
|
||||
io.Writer
|
||||
}
|
||||
discard := justWriter{ioutil.Discard} // hide ReadFrom
|
||||
discard := justWriter{io.Discard} // hide ReadFrom
|
||||
|
||||
var with, withOut nErr
|
||||
with.n, with.err = io.Copy(discard, NewReader(nil))
|
||||
@ -248,7 +247,7 @@ func TestReaderCopyNothing(t *testing.T) {
|
||||
// tests that Len is affected by reads, but Size is not.
|
||||
func TestReaderLenSize(t *testing.T) {
|
||||
r := NewReader([]byte("abc"))
|
||||
io.CopyN(ioutil.Discard, r, 1)
|
||||
io.CopyN(io.Discard, r, 1)
|
||||
if r.Len() != 2 {
|
||||
t.Errorf("Len = %d; want 2", r.Len())
|
||||
}
|
||||
@ -268,7 +267,7 @@ func TestReaderReset(t *testing.T) {
|
||||
if err := r.UnreadRune(); err == nil {
|
||||
t.Errorf("UnreadRune: expected error, got nil")
|
||||
}
|
||||
buf, err := ioutil.ReadAll(r)
|
||||
buf, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
t.Errorf("ReadAll: unexpected error: %v", err)
|
||||
}
|
||||
@ -314,7 +313,7 @@ func TestReaderZero(t *testing.T) {
|
||||
t.Errorf("UnreadRune: got nil, want error")
|
||||
}
|
||||
|
||||
if n, err := (&Reader{}).WriteTo(ioutil.Discard); n != 0 || err != nil {
|
||||
if n, err := (&Reader{}).WriteTo(io.Discard); n != 0 || err != nil {
|
||||
t.Errorf("WriteTo: got %d, %v; want 0, nil", n, err)
|
||||
}
|
||||
}
|
||||
|
@ -326,6 +326,18 @@ func compareAPI(w io.Writer, features, required, optional, exception []string, a
|
||||
return
|
||||
}
|
||||
|
||||
// aliasReplacer applies type aliases to earlier API files,
|
||||
// to avoid misleading negative results.
|
||||
// This makes all the references to os.FileInfo in go1.txt
|
||||
// be read as if they said fs.FileInfo, since os.FileInfo is now an alias.
|
||||
// If there are many of these, we could do a more general solution,
|
||||
// but for now the replacer is fine.
|
||||
var aliasReplacer = strings.NewReplacer(
|
||||
"os.FileInfo", "fs.FileInfo",
|
||||
"os.FileMode", "fs.FileMode",
|
||||
"os.PathError", "fs.PathError",
|
||||
)
|
||||
|
||||
func fileFeatures(filename string) []string {
|
||||
if filename == "" {
|
||||
return nil
|
||||
@ -334,7 +346,9 @@ func fileFeatures(filename string) []string {
|
||||
if err != nil {
|
||||
log.Fatalf("Error reading file %s: %v", filename, err)
|
||||
}
|
||||
lines := strings.Split(string(bs), "\n")
|
||||
s := string(bs)
|
||||
s = aliasReplacer.Replace(s)
|
||||
lines := strings.Split(s, "\n")
|
||||
var nonblank []string
|
||||
for _, line := range lines {
|
||||
line = strings.TrimSpace(line)
|
||||
@ -856,6 +870,10 @@ func (w *Walker) emitObj(obj types.Object) {
|
||||
func (w *Walker) emitType(obj *types.TypeName) {
|
||||
name := obj.Name()
|
||||
typ := obj.Type()
|
||||
if obj.IsAlias() {
|
||||
w.emitf("type %s = %s", name, w.typeString(typ))
|
||||
return
|
||||
}
|
||||
switch typ := typ.Underlying().(type) {
|
||||
case *types.Struct:
|
||||
w.emitStructType(name, typ)
|
||||
|
@ -181,7 +181,7 @@ func (p *Parser) asmText(operands [][]lex.Token) {
|
||||
// Argsize set below.
|
||||
},
|
||||
}
|
||||
nameAddr.Sym.Func.Text = prog
|
||||
nameAddr.Sym.Func().Text = prog
|
||||
prog.To.Val = int32(argSize)
|
||||
p.append(prog, "", true)
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ func testEndToEnd(t *testing.T, goarch, file string) {
|
||||
architecture, ctxt := setArch(goarch)
|
||||
architecture.Init(ctxt)
|
||||
lexer := lex.NewLexer(input)
|
||||
parser := NewParser(ctxt, architecture, lexer)
|
||||
parser := NewParser(ctxt, architecture, lexer, false)
|
||||
pList := new(obj.Plist)
|
||||
var ok bool
|
||||
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
|
||||
@ -257,11 +257,11 @@ func isHexes(s string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// It would be nice if the error messages began with
|
||||
// It would be nice if the error messages always began with
|
||||
// the standard file:line: prefix,
|
||||
// but that's not where we are today.
|
||||
// It might be at the beginning but it might be in the middle of the printed instruction.
|
||||
var fileLineRE = regexp.MustCompile(`(?:^|\()(testdata[/\\][0-9a-z]+\.s:[0-9]+)(?:$|\))`)
|
||||
var fileLineRE = regexp.MustCompile(`(?:^|\()(testdata[/\\][0-9a-z]+\.s:[0-9]+)(?:$|\)|:)`)
|
||||
|
||||
// Same as in test/run.go
|
||||
var (
|
||||
@ -273,7 +273,7 @@ func testErrors(t *testing.T, goarch, file string) {
|
||||
input := filepath.Join("testdata", file+".s")
|
||||
architecture, ctxt := setArch(goarch)
|
||||
lexer := lex.NewLexer(input)
|
||||
parser := NewParser(ctxt, architecture, lexer)
|
||||
parser := NewParser(ctxt, architecture, lexer, false)
|
||||
pList := new(obj.Plist)
|
||||
var ok bool
|
||||
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
|
||||
@ -281,6 +281,7 @@ func testErrors(t *testing.T, goarch, file string) {
|
||||
defer ctxt.Bso.Flush()
|
||||
failed := false
|
||||
var errBuf bytes.Buffer
|
||||
parser.errorWriter = &errBuf
|
||||
ctxt.DiagFunc = func(format string, args ...interface{}) {
|
||||
failed = true
|
||||
s := fmt.Sprintf(format, args...)
|
||||
@ -292,7 +293,7 @@ func testErrors(t *testing.T, goarch, file string) {
|
||||
pList.Firstpc, ok = parser.Parse()
|
||||
obj.Flushplist(ctxt, pList, nil, "")
|
||||
if ok && !failed {
|
||||
t.Errorf("asm: %s had no errors", goarch)
|
||||
t.Errorf("asm: %s had no errors", file)
|
||||
}
|
||||
|
||||
errors := map[string]string{}
|
||||
@ -353,12 +354,7 @@ func testErrors(t *testing.T, goarch, file string) {
|
||||
}
|
||||
|
||||
func Test386EndToEnd(t *testing.T) {
|
||||
defer func(old string) { objabi.GO386 = old }(objabi.GO386)
|
||||
for _, go386 := range []string{"387", "sse2"} {
|
||||
t.Logf("GO386=%v", go386)
|
||||
objabi.GO386 = go386
|
||||
testEndToEnd(t, "386", "386")
|
||||
}
|
||||
}
|
||||
|
||||
func TestARMEndToEnd(t *testing.T) {
|
||||
@ -373,6 +369,10 @@ func TestARMEndToEnd(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoBuildErrors(t *testing.T) {
|
||||
testErrors(t, "amd64", "buildtagerror")
|
||||
}
|
||||
|
||||
func TestARMErrors(t *testing.T) {
|
||||
testErrors(t, "arm", "armerror")
|
||||
}
|
||||
@ -442,10 +442,6 @@ func TestPPC64EndToEnd(t *testing.T) {
|
||||
testEndToEnd(t, "ppc64", "ppc64")
|
||||
}
|
||||
|
||||
func TestPPC64Encoder(t *testing.T) {
|
||||
testEndToEnd(t, "ppc64", "ppc64enc")
|
||||
}
|
||||
|
||||
func TestRISCVEncoder(t *testing.T) {
|
||||
testEndToEnd(t, "riscv64", "riscvenc")
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ var exprTests = []exprTest{
|
||||
}
|
||||
|
||||
func TestExpr(t *testing.T) {
|
||||
p := NewParser(nil, nil, nil) // Expression evaluation uses none of these fields of the parser.
|
||||
p := NewParser(nil, nil, nil, false) // Expression evaluation uses none of these fields of the parser.
|
||||
for i, test := range exprTests {
|
||||
p.start(lex.Tokenize(test.input))
|
||||
result := int64(p.expr())
|
||||
@ -113,7 +113,7 @@ func TestBadExpr(t *testing.T) {
|
||||
}
|
||||
|
||||
func runBadTest(i int, test badExprTest, t *testing.T) (err error) {
|
||||
p := NewParser(nil, nil, nil) // Expression evaluation uses none of these fields of the parser.
|
||||
p := NewParser(nil, nil, nil, false) // Expression evaluation uses none of these fields of the parser.
|
||||
p.start(lex.Tokenize(test.input))
|
||||
return tryParse(t, func() {
|
||||
p.expr()
|
||||
|
@ -39,7 +39,7 @@ func testBadInstParser(t *testing.T, goarch string, tests []badInstTest) {
|
||||
for i, test := range tests {
|
||||
arch, ctxt := setArch(goarch)
|
||||
tokenizer := lex.NewTokenizer("", strings.NewReader(test.input+"\n"), nil)
|
||||
parser := NewParser(ctxt, arch, tokenizer)
|
||||
parser := NewParser(ctxt, arch, tokenizer, false)
|
||||
|
||||
err := tryParse(t, func() {
|
||||
parser.Parse()
|
||||
|
@ -28,7 +28,7 @@ func setArch(goarch string) (*arch.Arch, *obj.Link) {
|
||||
|
||||
func newParser(goarch string) *Parser {
|
||||
architecture, ctxt := setArch(goarch)
|
||||
return NewParser(ctxt, architecture, nil)
|
||||
return NewParser(ctxt, architecture, nil, false)
|
||||
}
|
||||
|
||||
// tryParse executes parse func in panicOnError=true context.
|
||||
@ -75,7 +75,12 @@ func testOperandParser(t *testing.T, parser *Parser, tests []operandTest) {
|
||||
parser.start(lex.Tokenize(test.input))
|
||||
addr := obj.Addr{}
|
||||
parser.operand(&addr)
|
||||
result := obj.Dconv(&emptyProg, &addr)
|
||||
var result string
|
||||
if parser.compilingRuntime {
|
||||
result = obj.DconvWithABIDetail(&emptyProg, &addr)
|
||||
} else {
|
||||
result = obj.Dconv(&emptyProg, &addr)
|
||||
}
|
||||
if result != test.output {
|
||||
t.Errorf("fail at %s: got %s; expected %s\n", test.input, result, test.output)
|
||||
}
|
||||
@ -86,6 +91,9 @@ func TestAMD64OperandParser(t *testing.T) {
|
||||
parser := newParser("amd64")
|
||||
testOperandParser(t, parser, amd64OperandTests)
|
||||
testBadOperandParser(t, parser, amd64BadOperandTests)
|
||||
parser.compilingRuntime = true
|
||||
testOperandParser(t, parser, amd64RuntimeOperandTests)
|
||||
testBadOperandParser(t, parser, amd64BadOperandRuntimeTests)
|
||||
}
|
||||
|
||||
func Test386OperandParser(t *testing.T) {
|
||||
@ -141,7 +149,7 @@ func TestFuncAddress(t *testing.T) {
|
||||
parser := newParser(sub.arch)
|
||||
for _, test := range sub.tests {
|
||||
parser.start(lex.Tokenize(test.input))
|
||||
name, ok := parser.funcAddress()
|
||||
name, _, ok := parser.funcAddress()
|
||||
|
||||
isFuncSym := strings.HasSuffix(test.input, "(SB)") &&
|
||||
// Ignore static symbols.
|
||||
@ -298,6 +306,11 @@ var amd64OperandTests = []operandTest{
|
||||
{"[):[o-FP", ""}, // Issue 12469 - asm hung parsing the o-FP range on non ARM platforms.
|
||||
}
|
||||
|
||||
var amd64RuntimeOperandTests = []operandTest{
|
||||
{"$bar<ABI0>(SB)", "$bar<ABI0>(SB)"},
|
||||
{"$foo<ABIInternal>(SB)", "$foo<ABIInternal>(SB)"},
|
||||
}
|
||||
|
||||
var amd64BadOperandTests = []badOperandTest{
|
||||
{"[", "register list: expected ']', found EOF"},
|
||||
{"[4", "register list: bad low register in `[4`"},
|
||||
@ -311,6 +324,11 @@ var amd64BadOperandTests = []badOperandTest{
|
||||
{"[X0-X1-X2]", "register list: expected ']' after `[X0-X1`, found '-'"},
|
||||
{"[X0,X3]", "register list: expected '-' after `[X0`, found ','"},
|
||||
{"[X0,X1,X2,X3]", "register list: expected '-' after `[X0`, found ','"},
|
||||
{"$foo<ABI0>", "ABI selector only permitted when compiling runtime, reference was to \"foo\""},
|
||||
}
|
||||
|
||||
var amd64BadOperandRuntimeTests = []badOperandTest{
|
||||
{"$foo<bletch>", "malformed ABI selector \"bletch\" in reference to \"foo\""},
|
||||
}
|
||||
|
||||
var x86OperandTests = []operandTest{
|
||||
|
@ -29,6 +29,7 @@ type Parser struct {
|
||||
lineNum int // Line number in source file.
|
||||
errorLine int // Line number of last error.
|
||||
errorCount int // Number of errors.
|
||||
sawCode bool // saw code in this file (as opposed to comments and blank lines)
|
||||
pc int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA.
|
||||
input []lex.Token
|
||||
inputPos int
|
||||
@ -42,6 +43,7 @@ type Parser struct {
|
||||
lastProg *obj.Prog
|
||||
dataAddr map[string]int64 // Most recent address for DATA for this symbol.
|
||||
isJump bool // Instruction being assembled is a jump.
|
||||
compilingRuntime bool
|
||||
errorWriter io.Writer
|
||||
}
|
||||
|
||||
@ -50,7 +52,7 @@ type Patch struct {
|
||||
label string
|
||||
}
|
||||
|
||||
func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser {
|
||||
func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader, compilingRuntime bool) *Parser {
|
||||
return &Parser{
|
||||
ctxt: ctxt,
|
||||
arch: ar,
|
||||
@ -58,6 +60,7 @@ func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser {
|
||||
labels: make(map[string]*obj.Prog),
|
||||
dataAddr: make(map[string]int64),
|
||||
errorWriter: os.Stderr,
|
||||
compilingRuntime: compilingRuntime,
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,6 +135,30 @@ func (p *Parser) ParseSymABIs(w io.Writer) bool {
|
||||
return p.errorCount == 0
|
||||
}
|
||||
|
||||
// nextToken returns the next non-build-comment token from the lexer.
|
||||
// It reports misplaced //go:build comments but otherwise discards them.
|
||||
func (p *Parser) nextToken() lex.ScanToken {
|
||||
for {
|
||||
tok := p.lex.Next()
|
||||
if tok == lex.BuildComment {
|
||||
if p.sawCode {
|
||||
p.errorf("misplaced //go:build comment")
|
||||
}
|
||||
continue
|
||||
}
|
||||
if tok != '\n' {
|
||||
p.sawCode = true
|
||||
}
|
||||
if tok == '#' {
|
||||
// A leftover wisp of a #include/#define/etc,
|
||||
// to let us know that p.sawCode should be true now.
|
||||
// Otherwise ignored.
|
||||
continue
|
||||
}
|
||||
return tok
|
||||
}
|
||||
}
|
||||
|
||||
// line consumes a single assembly line from p.lex of the form
|
||||
//
|
||||
// {label:} WORD[.cond] [ arg {, arg} ] (';' | '\n')
|
||||
@ -146,7 +173,7 @@ next:
|
||||
// Skip newlines.
|
||||
var tok lex.ScanToken
|
||||
for {
|
||||
tok = p.lex.Next()
|
||||
tok = p.nextToken()
|
||||
// We save the line number here so error messages from this instruction
|
||||
// are labeled with this line. Otherwise we complain after we've absorbed
|
||||
// the terminating newline and the line numbers are off by one in errors.
|
||||
@ -179,11 +206,11 @@ next:
|
||||
items = make([]lex.Token, 0, 3)
|
||||
}
|
||||
for {
|
||||
tok = p.lex.Next()
|
||||
tok = p.nextToken()
|
||||
if len(operands) == 0 && len(items) == 0 {
|
||||
if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386) && tok == '.' {
|
||||
// Suffixes: ARM conditionals or x86 modifiers.
|
||||
tok = p.lex.Next()
|
||||
tok = p.nextToken()
|
||||
str := p.lex.Text()
|
||||
if tok != scanner.Ident {
|
||||
p.errorf("instruction suffix expected identifier, found %s", str)
|
||||
@ -285,8 +312,8 @@ func (p *Parser) symDefRef(w io.Writer, word string, operands [][]lex.Token) {
|
||||
// Defines text symbol in operands[0].
|
||||
if len(operands) > 0 {
|
||||
p.start(operands[0])
|
||||
if name, ok := p.funcAddress(); ok {
|
||||
fmt.Fprintf(w, "def %s ABI0\n", name)
|
||||
if name, abi, ok := p.funcAddress(); ok {
|
||||
fmt.Fprintf(w, "def %s %s\n", name, abi)
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -304,8 +331,8 @@ func (p *Parser) symDefRef(w io.Writer, word string, operands [][]lex.Token) {
|
||||
// Search for symbol references.
|
||||
for _, op := range operands {
|
||||
p.start(op)
|
||||
if name, ok := p.funcAddress(); ok {
|
||||
fmt.Fprintf(w, "ref %s ABI0\n", name)
|
||||
if name, abi, ok := p.funcAddress(); ok {
|
||||
fmt.Fprintf(w, "ref %s %s\n", name, abi)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -740,20 +767,19 @@ func (p *Parser) symbolReference(a *obj.Addr, name string, prefix rune) {
|
||||
case '*':
|
||||
a.Type = obj.TYPE_INDIR
|
||||
}
|
||||
// Weirdness with statics: Might now have "<>".
|
||||
isStatic := false
|
||||
if p.peek() == '<' {
|
||||
isStatic = true
|
||||
p.next()
|
||||
p.get('>')
|
||||
}
|
||||
|
||||
// Parse optional <> (indicates a static symbol) or
|
||||
// <ABIxxx> (selecting text symbol with specific ABI).
|
||||
doIssueError := true
|
||||
isStatic, abi := p.symRefAttrs(name, doIssueError)
|
||||
|
||||
if p.peek() == '+' || p.peek() == '-' {
|
||||
a.Offset = int64(p.expr())
|
||||
}
|
||||
if isStatic {
|
||||
a.Sym = p.ctxt.LookupStatic(name)
|
||||
} else {
|
||||
a.Sym = p.ctxt.Lookup(name)
|
||||
a.Sym = p.ctxt.LookupABI(name, abi)
|
||||
}
|
||||
if p.peek() == scanner.EOF {
|
||||
if prefix == 0 && p.isJump {
|
||||
@ -798,12 +824,60 @@ func (p *Parser) setPseudoRegister(addr *obj.Addr, reg string, isStatic bool, pr
|
||||
}
|
||||
}
|
||||
|
||||
// symRefAttrs parses an optional function symbol attribute clause for
|
||||
// the function symbol 'name', logging an error for a malformed
|
||||
// attribute clause if 'issueError' is true. The return value is a
|
||||
// (boolean, ABI) pair indicating that the named symbol is either
|
||||
// static or a particular ABI specification.
|
||||
//
|
||||
// The expected form of the attribute clause is:
|
||||
//
|
||||
// empty, yielding (false, obj.ABI0)
|
||||
// "<>", yielding (true, obj.ABI0)
|
||||
// "<ABI0>" yielding (false, obj.ABI0)
|
||||
// "<ABIInternal>" yielding (false, obj.ABIInternal)
|
||||
//
|
||||
// Anything else beginning with "<" logs an error if issueError is
|
||||
// true, otherwise returns (false, obj.ABI0).
|
||||
//
|
||||
func (p *Parser) symRefAttrs(name string, issueError bool) (bool, obj.ABI) {
|
||||
abi := obj.ABI0
|
||||
isStatic := false
|
||||
if p.peek() != '<' {
|
||||
return isStatic, abi
|
||||
}
|
||||
p.next()
|
||||
tok := p.peek()
|
||||
if tok == '>' {
|
||||
isStatic = true
|
||||
} else if tok == scanner.Ident {
|
||||
abistr := p.get(scanner.Ident).String()
|
||||
if !p.compilingRuntime {
|
||||
if issueError {
|
||||
p.errorf("ABI selector only permitted when compiling runtime, reference was to %q", name)
|
||||
}
|
||||
} else {
|
||||
theabi, valid := obj.ParseABI(abistr)
|
||||
if !valid {
|
||||
if issueError {
|
||||
p.errorf("malformed ABI selector %q in reference to %q",
|
||||
abistr, name)
|
||||
}
|
||||
} else {
|
||||
abi = theabi
|
||||
}
|
||||
}
|
||||
}
|
||||
p.get('>')
|
||||
return isStatic, abi
|
||||
}
|
||||
|
||||
// funcAddress parses an external function address. This is a
|
||||
// constrained form of the operand syntax that's always SB-based,
|
||||
// non-static, and has at most a simple integer offset:
|
||||
//
|
||||
// [$|*]sym[+Int](SB)
|
||||
func (p *Parser) funcAddress() (string, bool) {
|
||||
// [$|*]sym[<abi>][+Int](SB)
|
||||
func (p *Parser) funcAddress() (string, obj.ABI, bool) {
|
||||
switch p.peek() {
|
||||
case '$', '*':
|
||||
// Skip prefix.
|
||||
@ -813,25 +887,32 @@ func (p *Parser) funcAddress() (string, bool) {
|
||||
tok := p.next()
|
||||
name := tok.String()
|
||||
if tok.ScanToken != scanner.Ident || p.atStartOfRegister(name) {
|
||||
return "", false
|
||||
return "", obj.ABI0, false
|
||||
}
|
||||
// Parse optional <> (indicates a static symbol) or
|
||||
// <ABIxxx> (selecting text symbol with specific ABI).
|
||||
noErrMsg := false
|
||||
isStatic, abi := p.symRefAttrs(name, noErrMsg)
|
||||
if isStatic {
|
||||
return "", obj.ABI0, false // This function rejects static symbols.
|
||||
}
|
||||
tok = p.next()
|
||||
if tok.ScanToken == '+' {
|
||||
if p.next().ScanToken != scanner.Int {
|
||||
return "", false
|
||||
return "", obj.ABI0, false
|
||||
}
|
||||
tok = p.next()
|
||||
}
|
||||
if tok.ScanToken != '(' {
|
||||
return "", false
|
||||
return "", obj.ABI0, false
|
||||
}
|
||||
if reg := p.next(); reg.ScanToken != scanner.Ident || reg.String() != "SB" {
|
||||
return "", false
|
||||
return "", obj.ABI0, false
|
||||
}
|
||||
if p.next().ScanToken != ')' || p.peek() != scanner.EOF {
|
||||
return "", false
|
||||
return "", obj.ABI0, false
|
||||
}
|
||||
return name, true
|
||||
return name, abi, true
|
||||
}
|
||||
|
||||
// registerIndirect parses the general form of a register indirection.
|
||||
|
@ -37,6 +37,7 @@ func TestErroneous(t *testing.T) {
|
||||
{"TEXT", "$0É:0, 0, $1", "expected end of operand, found É"}, // Issue #12467.
|
||||
{"TEXT", "$:0:(SB, 0, $1", "expected '(', found 0"}, // Issue 12468.
|
||||
{"TEXT", "@B(SB),0,$0", "expected '(', found B"}, // Issue 23580.
|
||||
{"TEXT", "foo<ABIInternal>(SB),0", "ABI selector only permitted when compiling runtime, reference was to \"foo\""},
|
||||
{"FUNCDATA", "", "expect two operands for FUNCDATA"},
|
||||
{"FUNCDATA", "(SB ", "expect two operands for FUNCDATA"},
|
||||
{"DATA", "", "expect two operands for DATA"},
|
||||
|
4
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
4
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
@ -81,6 +81,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
SHA512H2 V4.D2, V3, V2 // 628464ce
|
||||
SHA512SU0 V9.D2, V8.D2 // 2881c0ce
|
||||
SHA512SU1 V7.D2, V6.D2, V5.D2 // c58867ce
|
||||
VRAX1 V26.D2, V29.D2, V30.D2 // be8f7ace
|
||||
VXAR $63, V27.D2, V21.D2, V26.D2 // bafe9bce
|
||||
VADDV V0.S4, V0 // 00b8b14e
|
||||
VMOVI $82, V0.B16 // 40e6024f
|
||||
VUADDLV V6.B16, V6 // c638306e
|
||||
@ -139,6 +141,8 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
|
||||
VTBL V14.B16, [V3.B16, V4.B16, V5.B16], V17.B16 // 71400e4e
|
||||
VTBL V13.B16, [V29.B16, V30.B16, V31.B16, V0.B16], V28.B16 // bc630d4e
|
||||
VTBL V3.B8, [V27.B16], V8.B8 // 6803030e
|
||||
VEOR3 V2.B16, V7.B16, V12.B16, V25.B16 // 990907ce
|
||||
VBCAX V1.B16, V2.B16, V26.B16, V31.B16 // 5f0722ce
|
||||
VZIP1 V16.H8, V3.H8, V19.H8 // 7338504e
|
||||
VZIP2 V22.D2, V25.D2, V21.D2 // 357bd64e
|
||||
VZIP1 V6.D2, V9.D2, V11.D2 // 2b39c64e
|
||||
|
8
src/cmd/asm/internal/asm/testdata/buildtagerror.s
vendored
Normal file
8
src/cmd/asm/internal/asm/testdata/buildtagerror.s
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#define X 1
|
||||
|
||||
//go:build x // ERROR "misplaced //go:build comment"
|
||||
|
2002
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
2002
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
File diff suppressed because it is too large
Load Diff
638
src/cmd/asm/internal/asm/testdata/ppc64enc.s
vendored
638
src/cmd/asm/internal/asm/testdata/ppc64enc.s
vendored
@ -1,638 +0,0 @@
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Initial set of opcode combinations based on
|
||||
// improvements to processing of constant
|
||||
// operands.
|
||||
|
||||
// Full set will be added at a later date.
|
||||
|
||||
#include "../../../../../runtime/textflag.h"
|
||||
|
||||
TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
||||
// move constants
|
||||
MOVD $1, R3 // 38600001
|
||||
MOVD $-1, R4 // 3880ffff
|
||||
MOVD $65535, R5 // 6005ffff
|
||||
MOVD $65536, R6 // 64060001
|
||||
MOVD $-32767, R5 // 38a08001
|
||||
MOVD $-32768, R6 // 38c08000
|
||||
MOVD $1234567, R5 // 6405001260a5d687
|
||||
MOVW $1, R3 // 38600001
|
||||
MOVW $-1, R4 // 3880ffff
|
||||
MOVW $65535, R5 // 6005ffff
|
||||
MOVW $65536, R6 // 64060001
|
||||
MOVW $-32767, R5 // 38a08001
|
||||
MOVW $-32768, R6 // 38c08000
|
||||
MOVW $1234567, R5 // 6405001260a5d687
|
||||
MOVD 8(R3), R4 // e8830008
|
||||
MOVD (R3)(R4), R5 // 7ca4182a
|
||||
MOVW 4(R3), R4 // e8830006
|
||||
MOVW (R3)(R4), R5 // 7ca41aaa
|
||||
MOVWZ 4(R3), R4 // 80830004
|
||||
MOVWZ (R3)(R4), R5 // 7ca4182e
|
||||
MOVH 4(R3), R4 // a8830004
|
||||
MOVH (R3)(R4), R5 // 7ca41aae
|
||||
MOVHZ 2(R3), R4 // a0830002
|
||||
MOVHZ (R3)(R4), R5 // 7ca41a2e
|
||||
MOVB 1(R3), R4 // 888300017c840774
|
||||
MOVB (R3)(R4), R5 // 7ca418ae7ca50774
|
||||
MOVBZ 1(R3), R4 // 88830001
|
||||
MOVBZ (R3)(R4), R5 // 7ca418ae
|
||||
MOVDBR (R3)(R4), R5 // 7ca41c28
|
||||
MOVWBR (R3)(R4), R5 // 7ca41c2c
|
||||
MOVHBR (R3)(R4), R5 // 7ca41e2c
|
||||
|
||||
MOVDU 8(R3), R4 // e8830009
|
||||
MOVDU (R3)(R4), R5 // 7ca4186a
|
||||
MOVWU (R3)(R4), R5 // 7ca41aea
|
||||
MOVWZU 4(R3), R4 // 84830004
|
||||
MOVWZU (R3)(R4), R5 // 7ca4186e
|
||||
MOVHU 2(R3), R4 // ac830002
|
||||
MOVHU (R3)(R4), R5 // 7ca41aee
|
||||
MOVHZU 2(R3), R4 // a4830002
|
||||
MOVHZU (R3)(R4), R5 // 7ca41a6e
|
||||
MOVBU 1(R3), R4 // 8c8300017c840774
|
||||
MOVBU (R3)(R4), R5 // 7ca418ee7ca50774
|
||||
MOVBZU 1(R3), R4 // 8c830001
|
||||
MOVBZU (R3)(R4), R5 // 7ca418ee
|
||||
|
||||
MOVD R4, 8(R3) // f8830008
|
||||
MOVD R5, (R3)(R4) // 7ca4192a
|
||||
MOVW R4, 4(R3) // 90830004
|
||||
MOVW R5, (R3)(R4) // 7ca4192e
|
||||
MOVH R4, 2(R3) // b0830002
|
||||
MOVH R5, (R3)(R4) // 7ca41b2e
|
||||
MOVB R4, 1(R3) // 98830001
|
||||
MOVB R5, (R3)(R4) // 7ca419ae
|
||||
MOVDBR R5, (R3)(R4) // 7ca41d28
|
||||
MOVWBR R5, (R3)(R4) // 7ca41d2c
|
||||
MOVHBR R5, (R3)(R4) // 7ca41f2c
|
||||
|
||||
MOVDU R4, 8(R3) // f8830009
|
||||
MOVDU R5, (R3)(R4) // 7ca4196a
|
||||
MOVWU R4, 4(R3) // 94830004
|
||||
MOVWU R5, (R3)(R4) // 7ca4196e
|
||||
MOVHU R4, 2(R3) // b4830002
|
||||
MOVHU R5, (R3)(R4) // 7ca41b6e
|
||||
MOVBU R4, 1(R3) // 9c830001
|
||||
MOVBU R5, (R3)(R4) // 7ca419ee
|
||||
|
||||
ADD $1, R3 // 38630001
|
||||
ADD $1, R3, R4 // 38830001
|
||||
ADD $-1, R4 // 3884ffff
|
||||
ADD $-1, R4, R5 // 38a4ffff
|
||||
ADD $65535, R5 // 601fffff7cbf2a14
|
||||
ADD $65535, R5, R6 // 601fffff7cdf2a14
|
||||
ADD $65536, R6 // 3cc60001
|
||||
ADD $65536, R6, R7 // 3ce60001
|
||||
ADD $-32767, R5 // 38a58001
|
||||
ADD $-32767, R5, R4 // 38858001
|
||||
ADD $-32768, R6 // 38c68000
|
||||
ADD $-32768, R6, R5 // 38a68000
|
||||
ADD $1234567, R5 // 641f001263ffd6877cbf2a14
|
||||
ADD $1234567, R5, R6 // 641f001263ffd6877cdf2a14
|
||||
ADDIS $8, R3 // 3c630008
|
||||
ADDIS $1000, R3, R4 // 3c8303e8
|
||||
|
||||
ANDCC $1, R3 // 70630001
|
||||
ANDCC $1, R3, R4 // 70640001
|
||||
ANDCC $-1, R4 // 3be0ffff7fe42039
|
||||
ANDCC $-1, R4, R5 // 3be0ffff7fe52039
|
||||
ANDCC $65535, R5 // 70a5ffff
|
||||
ANDCC $65535, R5, R6 // 70a6ffff
|
||||
ANDCC $65536, R6 // 74c60001
|
||||
ANDCC $65536, R6, R7 // 74c70001
|
||||
ANDCC $-32767, R5 // 3be080017fe52839
|
||||
ANDCC $-32767, R5, R4 // 3be080017fe42839
|
||||
ANDCC $-32768, R6 // 3be080007fe63039
|
||||
ANDCC $-32768, R5, R6 // 3be080007fe62839
|
||||
ANDCC $1234567, R5 // 641f001263ffd6877fe52839
|
||||
ANDCC $1234567, R5, R6 // 641f001263ffd6877fe62839
|
||||
ANDISCC $1, R3 // 74630001
|
||||
ANDISCC $1000, R3, R4 // 746403e8
|
||||
|
||||
OR $1, R3 // 60630001
|
||||
OR $1, R3, R4 // 60640001
|
||||
OR $-1, R4 // 3be0ffff7fe42378
|
||||
OR $-1, R4, R5 // 3be0ffff7fe52378
|
||||
OR $65535, R5 // 60a5ffff
|
||||
OR $65535, R5, R6 // 60a6ffff
|
||||
OR $65536, R6 // 64c60001
|
||||
OR $65536, R6, R7 // 64c70001
|
||||
OR $-32767, R5 // 3be080017fe52b78
|
||||
OR $-32767, R5, R6 // 3be080017fe62b78
|
||||
OR $-32768, R6 // 3be080007fe63378
|
||||
OR $-32768, R6, R7 // 3be080007fe73378
|
||||
OR $1234567, R5 // 641f001263ffd6877fe52b78
|
||||
OR $1234567, R5, R3 // 641f001263ffd6877fe32b78
|
||||
|
||||
XOR $1, R3 // 68630001
|
||||
XOR $1, R3, R4 // 68640001
|
||||
XOR $-1, R4 // 3be0ffff7fe42278
|
||||
XOR $-1, R4, R5 // 3be0ffff7fe52278
|
||||
XOR $65535, R5 // 68a5ffff
|
||||
XOR $65535, R5, R6 // 68a6ffff
|
||||
XOR $65536, R6 // 6cc60001
|
||||
XOR $65536, R6, R7 // 6cc70001
|
||||
XOR $-32767, R5 // 3be080017fe52a78
|
||||
XOR $-32767, R5, R6 // 3be080017fe62a78
|
||||
XOR $-32768, R6 // 3be080007fe63278
|
||||
XOR $-32768, R6, R7 // 3be080007fe73278
|
||||
XOR $1234567, R5 // 641f001263ffd6877fe52a78
|
||||
XOR $1234567, R5, R3 // 641f001263ffd6877fe32a78
|
||||
|
||||
// TODO: the order of CR operands don't match
|
||||
CMP R3, R4 // 7c232000
|
||||
CMPU R3, R4 // 7c232040
|
||||
CMPW R3, R4 // 7c032000
|
||||
CMPWU R3, R4 // 7c032040
|
||||
|
||||
// TODO: constants for ADDC?
|
||||
ADD R3, R4 // 7c841a14
|
||||
ADD R3, R4, R5 // 7ca41a14
|
||||
ADDC R3, R4 // 7c841814
|
||||
ADDC R3, R4, R5 // 7ca41814
|
||||
ADDE R3, R4 // 7c841914
|
||||
ADDECC R3, R4 // 7c841915
|
||||
ADDEV R3, R4 // 7c841d14
|
||||
ADDEVCC R3, R4 // 7c841d15
|
||||
ADDV R3, R4 // 7c841e14
|
||||
ADDVCC R3, R4 // 7c841e15
|
||||
ADDCCC R3, R4, R5 // 7ca41815
|
||||
ADDME R3, R4 // 7c8301d4
|
||||
ADDMECC R3, R4 // 7c8301d5
|
||||
ADDMEV R3, R4 // 7c8305d4
|
||||
ADDMEVCC R3, R4 // 7c8305d5
|
||||
ADDCV R3, R4 // 7c841c14
|
||||
ADDCVCC R3, R4 // 7c841c15
|
||||
ADDZE R3, R4 // 7c830194
|
||||
ADDZECC R3, R4 // 7c830195
|
||||
ADDZEV R3, R4 // 7c830594
|
||||
ADDZEVCC R3, R4 // 7c830595
|
||||
SUBME R3, R4 // 7c8301d0
|
||||
SUBMECC R3, R4 // 7c8301d1
|
||||
SUBMEV R3, R4 // 7c8305d0
|
||||
SUBZE R3, R4 // 7c830190
|
||||
SUBZECC R3, R4 // 7c830191
|
||||
SUBZEV R3, R4 // 7c830590
|
||||
SUBZEVCC R3, R4 // 7c830591
|
||||
|
||||
AND R3, R4 // 7c841838
|
||||
AND R3, R4, R5 // 7c851838
|
||||
ANDN R3, R4, R5 // 7c851878
|
||||
ANDCC R3, R4, R5 // 7c851839
|
||||
OR R3, R4 // 7c841b78
|
||||
OR R3, R4, R5 // 7c851b78
|
||||
ORN R3, R4, R5 // 7c851b38
|
||||
ORCC R3, R4, R5 // 7c851b79
|
||||
XOR R3, R4 // 7c841a78
|
||||
XOR R3, R4, R5 // 7c851a78
|
||||
XORCC R3, R4, R5 // 7c851a79
|
||||
NAND R3, R4, R5 // 7c851bb8
|
||||
NANDCC R3, R4, R5 // 7c851bb9
|
||||
EQV R3, R4, R5 // 7c851a38
|
||||
EQVCC R3, R4, R5 // 7c851a39
|
||||
NOR R3, R4, R5 // 7c8518f8
|
||||
NORCC R3, R4, R5 // 7c8518f9
|
||||
|
||||
SUB R3, R4 // 7c832050
|
||||
SUB R3, R4, R5 // 7ca32050
|
||||
SUBC R3, R4 // 7c832010
|
||||
SUBC R3, R4, R5 // 7ca32010
|
||||
|
||||
MULLW R3, R4 // 7c8419d6
|
||||
MULLW R3, R4, R5 // 7ca419d6
|
||||
MULLWCC R3, R4, R5 // 7ca419d7
|
||||
MULHW R3, R4, R5 // 7ca41896
|
||||
|
||||
MULHWU R3, R4, R5 // 7ca41816
|
||||
MULLD R3, R4 // 7c8419d2
|
||||
MULLD R4, R4, R5 // 7ca421d2
|
||||
MULLDCC R3, R4, R5 // 7ca419d3
|
||||
MULHD R3, R4, R5 // 7ca41892
|
||||
MULHDCC R3, R4, R5 // 7ca41893
|
||||
|
||||
MULLWV R3, R4 // 7c841dd6
|
||||
MULLWV R3, R4, R5 // 7ca41dd6
|
||||
MULLWVCC R3, R4, R5 // 7ca41dd7
|
||||
MULHWUCC R3, R4, R5 // 7ca41817
|
||||
MULLDV R3, R4, R5 // 7ca41dd2
|
||||
MULLDVCC R3, R4, R5 // 7ca41dd3
|
||||
|
||||
DIVD R3,R4 // 7c841bd2
|
||||
DIVD R3, R4, R5 // 7ca41bd2
|
||||
DIVDCC R3,R4, R5 // 7ca41bd3
|
||||
DIVDU R3, R4, R5 // 7ca41b92
|
||||
DIVDV R3, R4, R5 // 7ca41fd2
|
||||
DIVDUCC R3, R4, R5 // 7ca41b93
|
||||
DIVDVCC R3, R4, R5 // 7ca41fd3
|
||||
DIVDUV R3, R4, R5 // 7ca41f92
|
||||
DIVDUVCC R3, R4, R5 // 7ca41f93
|
||||
DIVDE R3, R4, R5 // 7ca41b52
|
||||
DIVDECC R3, R4, R5 // 7ca41b53
|
||||
DIVDEU R3, R4, R5 // 7ca41b12
|
||||
DIVDEUCC R3, R4, R5 // 7ca41b13
|
||||
|
||||
REM R3, R4, R5 // 7fe41bd67fff19d67cbf2050
|
||||
REMU R3, R4, R5 // 7fe41b967fff19d67bff00287cbf2050
|
||||
REMD R3, R4, R5 // 7fe41bd27fff19d27cbf2050
|
||||
REMDU R3, R4, R5 // 7fe41b927fff19d27cbf2050
|
||||
|
||||
MODUD R3, R4, R5 // 7ca41a12
|
||||
MODUW R3, R4, R5 // 7ca41a16
|
||||
MODSD R3, R4, R5 // 7ca41e12
|
||||
MODSW R3, R4, R5 // 7ca41e16
|
||||
|
||||
SLW $8, R3, R4 // 5464402e
|
||||
SLW R3, R4, R5 // 7c851830
|
||||
SLWCC R3, R4 // 7c841831
|
||||
SLD $16, R3, R4 // 786483e4
|
||||
SLD R3, R4, R5 // 7c851836
|
||||
SLDCC R3, R4 // 7c841837
|
||||
|
||||
SRW $8, R3, R4 // 5464c23e
|
||||
SRW R3, R4, R5 // 7c851c30
|
||||
SRWCC R3, R4 // 7c841c31
|
||||
SRAW $8, R3, R4 // 7c644670
|
||||
SRAW R3, R4, R5 // 7c851e30
|
||||
SRAWCC R3, R4 // 7c841e31
|
||||
SRD $16, R3, R4 // 78648402
|
||||
SRD R3, R4, R5 // 7c851c36
|
||||
SRDCC R3, R4 // 7c841c37
|
||||
SRAD $16, R3, R4 // 7c648674
|
||||
SRAD R3, R4, R5 // 7c851e34
|
||||
SRDCC R3, R4 // 7c841c37
|
||||
ROTLW $16, R3, R4 // 5464803e
|
||||
ROTLW R3, R4, R5 // 5c85183e
|
||||
EXTSWSLI $3, R4, R5 // 7c851ef4
|
||||
RLWMI $7, R3, $65535, R6 // 50663c3e
|
||||
RLWMICC $7, R3, $65535, R6 // 50663c3f
|
||||
RLWNM $3, R4, $7, R6 // 54861f7e
|
||||
RLWNMCC $3, R4, $7, R6 // 54861f7f
|
||||
RLDMI $0, R4, $7, R6 // 7886076c
|
||||
RLDMICC $0, R4, $7, R6 // 7886076d
|
||||
RLDIMI $0, R4, $7, R6 // 788601cc
|
||||
RLDIMICC $0, R4, $7, R6 // 788601cd
|
||||
RLDC $0, R4, $15, R6 // 78860728
|
||||
RLDCCC $0, R4, $15, R6 // 78860729
|
||||
RLDCL $0, R4, $7, R6 // 78860770
|
||||
RLDCLCC $0, R4, $15, R6 // 78860721
|
||||
RLDCR $0, R4, $-16, R6 // 788606f2
|
||||
RLDCRCC $0, R4, $-16, R6 // 788606f3
|
||||
RLDICL $0, R4, $15, R6 // 788603c0
|
||||
RLDICLCC $0, R4, $15, R6 // 788603c1
|
||||
RLDICR $0, R4, $15, R6 // 788603c4
|
||||
RLDICRCC $0, R4, $15, R6 // 788603c5
|
||||
RLDIC $0, R4, $15, R6 // 788603c8
|
||||
RLDICCC $0, R4, $15, R6 // 788603c9
|
||||
CLRLSLWI $16, R5, $8, R4 // 54a4861e
|
||||
CLRLSLDI $2, R4, $24, R3 // 78831588
|
||||
|
||||
BEQ 0(PC) // 41820000
|
||||
BGE 0(PC) // 40800000
|
||||
BGT 4(PC) // 41810030
|
||||
BLE 0(PC) // 40810000
|
||||
BLT 0(PC) // 41800000
|
||||
BNE 0(PC) // 40820000
|
||||
JMP 8(PC) // 48000020
|
||||
|
||||
CRAND CR1, CR2, CR3 // 4c620a02
|
||||
CRANDN CR1, CR2, CR3 // 4c620902
|
||||
CREQV CR1, CR2, CR3 // 4c620a42
|
||||
CRNAND CR1, CR2, CR3 // 4c6209c2
|
||||
CRNOR CR1, CR2, CR3 // 4c620842
|
||||
CROR CR1, CR2, CR3 // 4c620b82
|
||||
CRORN CR1, CR2, CR3 // 4c620b42
|
||||
CRXOR CR1, CR2, CR3 // 4c620982
|
||||
|
||||
ISEL $1, R3, R4, R5 // 7ca3205e
|
||||
ISEL $0, R3, R4, R5 // 7ca3201e
|
||||
ISEL $2, R3, R4, R5 // 7ca3209e
|
||||
ISEL $3, R3, R4, R5 // 7ca320de
|
||||
ISEL $4, R3, R4, R5 // 7ca3211e
|
||||
POPCNTB R3, R4 // 7c6400f4
|
||||
POPCNTW R3, R4 // 7c6402f4
|
||||
POPCNTD R3, R4 // 7c6403f4
|
||||
|
||||
PASTECC R3, R4 // 7c23270d
|
||||
COPY R3, R4 // 7c23260c
|
||||
|
||||
// load-and-reserve
|
||||
LBAR (R4)(R3*1),$1,R5 // 7ca32069
|
||||
LBAR (R4),$0,R5 // 7ca02068
|
||||
LBAR (R3),R5 // 7ca01868
|
||||
LHAR (R4)(R3*1),$1,R5 // 7ca320e9
|
||||
LHAR (R4),$0,R5 // 7ca020e8
|
||||
LHAR (R3),R5 // 7ca018e8
|
||||
LWAR (R4)(R3*1),$1,R5 // 7ca32029
|
||||
LWAR (R4),$0,R5 // 7ca02028
|
||||
LWAR (R3),R5 // 7ca01828
|
||||
LDAR (R4)(R3*1),$1,R5 // 7ca320a9
|
||||
LDAR (R4),$0,R5 // 7ca020a8
|
||||
LDAR (R3),R5 // 7ca018a8
|
||||
|
||||
STBCCC R3, (R4)(R5) // 7c65256d
|
||||
STWCCC R3, (R4)(R5) // 7c65212d
|
||||
STDCCC R3, (R4)(R5) // 7c6521ad
|
||||
STHCCC R3, (R4)(R5)
|
||||
|
||||
SYNC // 7c0004ac
|
||||
ISYNC // 4c00012c
|
||||
LWSYNC // 7c2004ac
|
||||
|
||||
DCBF (R3)(R4) // 7c0418ac
|
||||
DCBI (R3)(R4) // 7c041bac
|
||||
DCBST (R3)(R4) // 7c04186c
|
||||
DCBZ (R3)(R4) // 7c041fec
|
||||
DCBT (R3)(R4) // 7c041a2c
|
||||
ICBI (R3)(R4) // 7c041fac
|
||||
|
||||
// float constants
|
||||
FMOVD $(0.0), F1 // f0210cd0
|
||||
FMOVD $(-0.0), F1 // f0210cd0fc200850
|
||||
|
||||
FMOVD 8(R3), F1 // c8230008
|
||||
FMOVD (R3)(R4), F1 // 7c241cae
|
||||
FMOVDU 8(R3), F1 // cc230008
|
||||
FMOVDU (R3)(R4), F1 // 7c241cee
|
||||
FMOVS 4(R3), F1 // c0230004
|
||||
FMOVS (R3)(R4), F1 // 7c241c2e
|
||||
FMOVSU 4(R3), F1 // c4230004
|
||||
FMOVSU (R3)(R4), F1 // 7c241c6e
|
||||
|
||||
FMOVD F1, 8(R3) // d8230008
|
||||
FMOVD F1, (R3)(R4) // 7c241dae
|
||||
FMOVDU F1, 8(R3) // dc230008
|
||||
FMOVDU F1, (R3)(R4) // 7c241dee
|
||||
FMOVS F1, 4(R3) // d0230004
|
||||
FMOVS F1, (R3)(R4) // 7c241d2e
|
||||
FMOVSU F1, 4(R3) // d4230004
|
||||
FMOVSU F1, (R3)(R4) // 7c241d6e
|
||||
FADD F1, F2 // fc42082a
|
||||
FADD F1, F2, F3 // fc62082a
|
||||
FADDCC F1, F2, F3 // fc62082b
|
||||
FADDS F1, F2 // ec42082a
|
||||
FADDS F1, F2, F3 // ec62082a
|
||||
FADDSCC F1, F2, F3 // ec62082b
|
||||
FSUB F1, F2 // fc420828
|
||||
FSUB F1, F2, F3 // fc620828
|
||||
FSUBCC F1, F2, F3 // fc620829
|
||||
FSUBS F1, F2 // ec420828
|
||||
FSUBS F1, F2, F3 // ec620828
|
||||
FSUBCC F1, F2, F3 // fc620829
|
||||
FMUL F1, F2 // fc420072
|
||||
FMUL F1, F2, F3 // fc620072
|
||||
FMULCC F1, F2, F3 // fc620073
|
||||
FMULS F1, F2 // ec420072
|
||||
FMULS F1, F2, F3 // ec620072
|
||||
FMULSCC F1, F2, F3 // ec620073
|
||||
FDIV F1, F2 // fc420824
|
||||
FDIV F1, F2, F3 // fc620824
|
||||
FDIVCC F1, F2, F3 // fc620825
|
||||
FDIVS F1, F2 // ec420824
|
||||
FDIVS F1, F2, F3 // ec620824
|
||||
FDIVSCC F1, F2, F3 // ec620825
|
||||
FMADD F1, F2, F3, F4 // fc8110fa
|
||||
FMADDCC F1, F2, F3, F4 // fc8110fb
|
||||
FMADDS F1, F2, F3, F4 // ec8110fa
|
||||
FMADDSCC F1, F2, F3, F4 // ec8110fb
|
||||
FMSUB F1, F2, F3, F4 // fc8110f8
|
||||
FMSUBCC F1, F2, F3, F4 // fc8110f9
|
||||
FMSUBS F1, F2, F3, F4 // ec8110f8
|
||||
FMSUBSCC F1, F2, F3, F4 // ec8110f9
|
||||
FNMADD F1, F2, F3, F4 // fc8110fe
|
||||
FNMADDCC F1, F2, F3, F4 // fc8110ff
|
||||
FNMADDS F1, F2, F3, F4 // ec8110fe
|
||||
FNMADDSCC F1, F2, F3, F4 // ec8110ff
|
||||
FNMSUB F1, F2, F3, F4 // fc8110fc
|
||||
FNMSUBCC F1, F2, F3, F4 // fc8110fd
|
||||
FNMSUBS F1, F2, F3, F4 // ec8110fc
|
||||
FNMSUBSCC F1, F2, F3, F4 // ec8110fd
|
||||
FSEL F1, F2, F3, F4 // fc8110ee
|
||||
FSELCC F1, F2, F3, F4 // fc8110ef
|
||||
FABS F1, F2 // fc400a10
|
||||
FABSCC F1, F2 // fc400a11
|
||||
FNEG F1, F2 // fc400850
|
||||
FABSCC F1, F2 // fc400a11
|
||||
FRSP F1, F2 // fc400818
|
||||
FRSPCC F1, F2 // fc400819
|
||||
FCTIW F1, F2 // fc40081c
|
||||
FCTIWCC F1, F2 // fc40081d
|
||||
FCTIWZ F1, F2 // fc40081e
|
||||
FCTIWZCC F1, F2 // fc40081f
|
||||
FCTID F1, F2 // fc400e5c
|
||||
FCTIDCC F1, F2 // fc400e5d
|
||||
FCTIDZ F1, F2 // fc400e5e
|
||||
FCTIDZCC F1, F2 // fc400e5f
|
||||
FCFID F1, F2 // fc400e9c
|
||||
FCFIDCC F1, F2 // fc400e9d
|
||||
FCFIDU F1, F2 // fc400f9c
|
||||
FCFIDUCC F1, F2 // fc400f9d
|
||||
FCFIDS F1, F2 // ec400e9c
|
||||
FCFIDSCC F1, F2 // ec400e9d
|
||||
FRES F1, F2 // ec400830
|
||||
FRESCC F1, F2 // ec400831
|
||||
FRIM F1, F2 // fc400bd0
|
||||
FRIMCC F1, F2 // fc400bd1
|
||||
FRIP F1, F2 // fc400b90
|
||||
FRIPCC F1, F2 // fc400b91
|
||||
FRIZ F1, F2 // fc400b50
|
||||
FRIZCC F1, F2 // fc400b51
|
||||
FRIN F1, F2 // fc400b10
|
||||
FRINCC F1, F2 // fc400b11
|
||||
FRSQRTE F1, F2 // fc400834
|
||||
FRSQRTECC F1, F2 // fc400835
|
||||
FSQRT F1, F2 // fc40082c
|
||||
FSQRTCC F1, F2 // fc40082d
|
||||
FSQRTS F1, F2 // ec40082c
|
||||
FSQRTSCC F1, F2 // ec40082d
|
||||
FCPSGN F1, F2 // fc420810
|
||||
FCPSGNCC F1, F2 // fc420811
|
||||
FCMPO F1, F2 // fc011040
|
||||
FCMPU F1, F2 // fc011000
|
||||
LVX (R3)(R4), V1 // 7c2418ce
|
||||
LVXL (R3)(R4), V1 // 7c241ace
|
||||
LVSL (R3)(R4), V1 // 7c24180c
|
||||
LVSR (R3)(R4), V1 // 7c24184c
|
||||
LVEBX (R3)(R4), V1 // 7c24180e
|
||||
LVEHX (R3)(R4), V1 // 7c24184e
|
||||
LVEWX (R3)(R4), V1 // 7c24188e
|
||||
STVX V1, (R3)(R4) // 7c2419ce
|
||||
STVXL V1, (R3)(R4) // 7c241bce
|
||||
STVEBX V1, (R3)(R4) // 7c24190e
|
||||
STVEHX V1, (R3)(R4) // 7c24194e
|
||||
STVEWX V1, (R3)(R4) // 7c24198e
|
||||
|
||||
VAND V1, V2, V3 // 10611404
|
||||
VANDC V1, V2, V3 // 10611444
|
||||
VNAND V1, V2, V3 // 10611584
|
||||
VOR V1, V2, V3 // 10611484
|
||||
VORC V1, V2, V3 // 10611544
|
||||
VXOR V1, V2, V3 // 106114c4
|
||||
VNOR V1, V2, V3 // 10611504
|
||||
VEQV V1, V2, V3 // 10611684
|
||||
VADDUBM V1, V2, V3 // 10611000
|
||||
VADDUHM V1, V2, V3 // 10611040
|
||||
VADDUWM V1, V2, V3 // 10611080
|
||||
VADDUDM V1, V2, V3 // 106110c0
|
||||
VADDUQM V1, V2, V3 // 10611100
|
||||
VADDCUQ V1, V2, V3 // 10611140
|
||||
VADDCUW V1, V2, V3 // 10611180
|
||||
VADDUBS V1, V2, V3 // 10611200
|
||||
VADDUHS V1, V2, V3 // 10611240
|
||||
VADDUWS V1, V2, V3 // 10611280
|
||||
VSUBUBM V1, V2, V3 // 10611400
|
||||
VSUBUHM V1, V2, V3 // 10611440
|
||||
VSUBUWM V1, V2, V3 // 10611480
|
||||
VSUBUDM V1, V2, V3 // 106114c0
|
||||
VSUBUQM V1, V2, V3 // 10611500
|
||||
VSUBCUQ V1, V2, V3 // 10611540
|
||||
VSUBCUW V1, V2, V3 // 10611580
|
||||
VSUBUBS V1, V2, V3 // 10611600
|
||||
VSUBUHS V1, V2, V3 // 10611640
|
||||
VSUBUWS V1, V2, V3 // 10611680
|
||||
VSUBSBS V1, V2, V3 // 10611700
|
||||
VSUBSHS V1, V2, V3 // 10611740
|
||||
VSUBSWS V1, V2, V3 // 10611780
|
||||
VSUBEUQM V1, V2, V3, V4 // 108110fe
|
||||
VSUBECUQ V1, V2, V3, V4 // 108110ff
|
||||
VMULESB V1, V2, V3 // 10611308
|
||||
VMULOSB V1, V2, V3 // 10611108
|
||||
VMULEUB V1, V2, V3 // 10611208
|
||||
VMULOUB V1, V2, V3 // 10611008
|
||||
VMULESH V1, V2, V3 // 10611348
|
||||
VMULOSH V1, V2, V3 // 10611148
|
||||
VMULEUH V1, V2, V3 // 10611248
|
||||
VMULOUH V1, V2, V3 // 10611048
|
||||
VMULESH V1, V2, V3 // 10611348
|
||||
VMULOSW V1, V2, V3 // 10611188
|
||||
VMULEUW V1, V2, V3 // 10611288
|
||||
VMULOUW V1, V2, V3 // 10611088
|
||||
VMULUWM V1, V2, V3 // 10611089
|
||||
VPMSUMB V1, V2, V3 // 10611408
|
||||
VPMSUMH V1, V2, V3 // 10611448
|
||||
VPMSUMW V1, V2, V3 // 10611488
|
||||
VPMSUMD V1, V2, V3 // 106114c8
|
||||
VMSUMUDM V1, V2, V3, V4 // 108110e3
|
||||
VRLB V1, V2, V3 // 10611004
|
||||
VRLH V1, V2, V3 // 10611044
|
||||
VRLW V1, V2, V3 // 10611084
|
||||
VRLD V1, V2, V3 // 106110c4
|
||||
VSLB V1, V2, V3 // 10611104
|
||||
VSLH V1, V2, V3 // 10611144
|
||||
VSLW V1, V2, V3 // 10611184
|
||||
VSL V1, V2, V3 // 106111c4
|
||||
VSLO V1, V2, V3 // 1061140c
|
||||
VSRB V1, V2, V3 // 10611204
|
||||
VSRH V1, V2, V3 // 10611244
|
||||
VSRW V1, V2, V3 // 10611284
|
||||
VSR V1, V2, V3 // 106112c4
|
||||
VSRO V1, V2, V3 // 1061144c
|
||||
VSLD V1, V2, V3 // 106115c4
|
||||
VSRAB V1, V2, V3 // 10611304
|
||||
VSRAH V1, V2, V3 // 10611344
|
||||
VSRAW V1, V2, V3 // 10611384
|
||||
VSRAD V1, V2, V3 // 106113c4
|
||||
VSLDOI $3, V1, V2, V3 // 106110ec
|
||||
VCLZB V1, V2 // 10400f02
|
||||
VCLZH V1, V2 // 10400f42
|
||||
VCLZW V1, V2 // 10400f82
|
||||
VCLZD V1, V2 // 10400fc2
|
||||
VPOPCNTB V1, V2 // 10400f03
|
||||
VPOPCNTH V1, V2 // 10400f43
|
||||
VPOPCNTW V1, V2 // 10400f83
|
||||
VPOPCNTD V1, V2 // 10400fc3
|
||||
VCMPEQUB V1, V2, V3 // 10611006
|
||||
VCMPEQUBCC V1, V2, V3 // 10611406
|
||||
VCMPEQUH V1, V2, V3 // 10611046
|
||||
VCMPEQUHCC V1, V2, V3 // 10611446
|
||||
VCMPEQUW V1, V2, V3 // 10611086
|
||||
VCMPEQUWCC V1, V2, V3 // 10611486
|
||||
VCMPEQUD V1, V2, V3 // 106110c7
|
||||
VCMPEQUDCC V1, V2, V3 // 106114c7
|
||||
VCMPGTUB V1, V2, V3 // 10611206
|
||||
VCMPGTUBCC V1, V2, V3 // 10611606
|
||||
VCMPGTUH V1, V2, V3 // 10611246
|
||||
VCMPGTUHCC V1, V2, V3 // 10611646
|
||||
VCMPGTUW V1, V2, V3 // 10611286
|
||||
VCMPGTUWCC V1, V2, V3 // 10611686
|
||||
VCMPGTUD V1, V2, V3 // 106112c7
|
||||
VCMPGTUDCC V1, V2, V3 // 106116c7
|
||||
VCMPGTSB V1, V2, V3 // 10611306
|
||||
VCMPGTSBCC V1, V2, V3 // 10611706
|
||||
VCMPGTSH V1, V2, V3 // 10611346
|
||||
VCMPGTSHCC V1, V2, V3 // 10611746
|
||||
VCMPGTSW V1, V2, V3 // 10611386
|
||||
VCMPGTSWCC V1, V2, V3 // 10611786
|
||||
VCMPGTSD V1, V2, V3 // 106113c7
|
||||
VCMPGTSDCC V1, V2, V3 // 106117c7
|
||||
VCMPNEZB V1, V2, V3 // 10611107
|
||||
VCMPNEZBCC V1, V2, V3 // 10611507
|
||||
VCMPNEB V1, V2, V3 // 10611007
|
||||
VCMPNEBCC V1, V2, V3 // 10611407
|
||||
VCMPNEH V1, V2, V3 // 10611047
|
||||
VCMPNEHCC V1, V2, V3 // 10611447
|
||||
VCMPNEW V1, V2, V3 // 10611087
|
||||
VCMPNEWCC V1, V2, V3 // 10611487
|
||||
VPERM V1, V2, V3, V4 // 108110eb
|
||||
VPERMR V1, V2, V3, V4 // 108110fb
|
||||
VPERMXOR V1, V2, V3, V4 // 108110ed
|
||||
VBPERMQ V1, V2, V3 // 1061154c
|
||||
VBPERMD V1, V2, V3 // 106115cc
|
||||
VSEL V1, V2, V3, V4 // 108110ea
|
||||
VSPLTB $1, V1, V2 // 10410a0c
|
||||
VSPLTH $1, V1, V2 // 10410a4c
|
||||
VSPLTW $1, V1, V2 // 10410a8c
|
||||
VSPLTISB $1, V1 // 1021030c
|
||||
VSPLTISW $1, V1 // 1021038c
|
||||
VSPLTISH $1, V1 // 1021034c
|
||||
VCIPHER V1, V2, V3 // 10611508
|
||||
VCIPHERLAST V1, V2, V3 // 10611509
|
||||
VNCIPHER V1, V2, V3 // 10611548
|
||||
VNCIPHERLAST V1, V2, V3 // 10611549
|
||||
VSBOX V1, V2 // 104105c8
|
||||
VSHASIGMAW $1, V1, $15, V2 // 10418e82
|
||||
VSHASIGMAD $2, V1, $15, V2 // 104196c2
|
||||
|
||||
LXVD2X (R3)(R4), VS1 // 7c241e98
|
||||
LXV 16(R3), VS1 // f4230011
|
||||
LXVL R3, R4, VS1 // 7c23221a
|
||||
LXVLL R3, R4, VS1 // 7c23225a
|
||||
LXVX R3, R4, VS1 // 7c232218
|
||||
LXSDX (R3)(R4), VS1 // 7c241c98
|
||||
STXVD2X VS1, (R3)(R4) // 7c241f98
|
||||
STXV VS1,16(R3) // f4230015
|
||||
STXVL VS1, R3, R4 // 7c23231a
|
||||
STXVLL VS1, R3, R4 // 7c23235a
|
||||
STXVX VS1, R3, R4 // 7c232318
|
||||
STXSDX VS1, (R3)(R4) // 7c241d98
|
||||
LXSIWAX (R3)(R4), VS1 // 7c241898
|
||||
STXSIWX VS1, (R3)(R4) // 7c241918
|
||||
MFVSRD VS1, R3 // 7c230066
|
||||
MTVSRD R3, VS1 // 7c230166
|
||||
XXLAND VS1, VS2, VS3 // f0611410
|
||||
XXLOR VS1, VS2, VS3 // f0611490
|
||||
XXLORC VS1, VS2, VS3 // f0611550
|
||||
XXLXOR VS1, VS2, VS3 // f06114d0
|
||||
XXSEL VS1, VS2, VS3, VS4 // f08110f0
|
||||
XXMRGHW VS1, VS2, VS3 // f0611090
|
||||
XXSPLTW VS1, $1, VS2 // f0410a90
|
||||
XXPERM VS1, VS2, VS3 // f06110d0
|
||||
XXSLDWI VS1, VS2, $1, VS3 // f0611110
|
||||
XSCVDPSP VS1, VS2 // f0400c24
|
||||
XVCVDPSP VS1, VS2 // f0400e24
|
||||
XSCVSXDDP VS1, VS2 // f0400de0
|
||||
XVCVDPSXDS VS1, VS2 // f0400f60
|
||||
XVCVSXDDP VS1, VS2 // f0400fe0
|
||||
|
||||
MOVD R3, LR // 7c6803a6
|
||||
MOVD R3, CTR // 7c6903a6
|
||||
MOVD R3, XER // 7c6103a6
|
||||
MOVD LR, R3 // 7c6802a6
|
||||
MOVD CTR, R3 // 7c6902a6
|
||||
MOVD XER, R3 // 7c6102a6
|
||||
MOVFL CR3, CR1 // 4c8c0000
|
||||
|
||||
RET
|
29
src/cmd/asm/internal/asm/testdata/riscvenc.s
vendored
29
src/cmd/asm/internal/asm/testdata/riscvenc.s
vendored
@ -297,6 +297,13 @@ start:
|
||||
MOVW X5, (X6) // 23205300
|
||||
MOVW X5, 4(X6) // 23225300
|
||||
|
||||
MOVB X5, X6 // 1393820313538343
|
||||
MOVH X5, X6 // 1393020313530343
|
||||
MOVW X5, X6 // 1b830200
|
||||
MOVBU X5, X6 // 13f3f20f
|
||||
MOVHU X5, X6 // 1393020313530303
|
||||
MOVWU X5, X6 // 1393020213530302
|
||||
|
||||
MOVF 4(X5), F0 // 07a04200
|
||||
MOVF F0, 4(X5) // 27a20200
|
||||
MOVF F0, F1 // d3000020
|
||||
@ -318,7 +325,7 @@ start:
|
||||
// These jumps can get printed as jumps to 2 because they go to the
|
||||
// second instruction in the function (the first instruction is an
|
||||
// invisible stack pointer adjustment).
|
||||
JMP start // JMP 2 // 6ff01fc5
|
||||
JMP start // JMP 2 // 6ff09fc2
|
||||
JMP (X5) // 67800200
|
||||
JMP 4(X5) // 67804200
|
||||
|
||||
@ -331,16 +338,16 @@ start:
|
||||
JMP asmtest(SB) // 970f0000
|
||||
|
||||
// Branch pseudo-instructions
|
||||
BEQZ X5, start // BEQZ X5, 2 // e38a02c2
|
||||
BGEZ X5, start // BGEZ X5, 2 // e3d802c2
|
||||
BGT X5, X6, start // BGT X5, X6, 2 // e3c662c2
|
||||
BGTU X5, X6, start // BGTU X5, X6, 2 // e3e462c2
|
||||
BGTZ X5, start // BGTZ X5, 2 // e34250c2
|
||||
BLE X5, X6, start // BLE X5, X6, 2 // e3d062c2
|
||||
BLEU X5, X6, start // BLEU X5, X6, 2 // e3fe62c0
|
||||
BLEZ X5, start // BLEZ X5, 2 // e35c50c0
|
||||
BLTZ X5, start // BLTZ X5, 2 // e3ca02c0
|
||||
BNEZ X5, start // BNEZ X5, 2 // e39802c0
|
||||
BEQZ X5, start // BEQZ X5, 2 // e38602c0
|
||||
BGEZ X5, start // BGEZ X5, 2 // e3d402c0
|
||||
BGT X5, X6, start // BGT X5, X6, 2 // e3c262c0
|
||||
BGTU X5, X6, start // BGTU X5, X6, 2 // e3e062c0
|
||||
BGTZ X5, start // BGTZ X5, 2 // e34e50be
|
||||
BLE X5, X6, start // BLE X5, X6, 2 // e3dc62be
|
||||
BLEU X5, X6, start // BLEU X5, X6, 2 // e3fa62be
|
||||
BLEZ X5, start // BLEZ X5, 2 // e35850be
|
||||
BLTZ X5, start // BLTZ X5, 2 // e3c602be
|
||||
BNEZ X5, start // BNEZ X5, 2 // e39402be
|
||||
|
||||
// Set pseudo-instructions
|
||||
SEQZ X15, X15 // 93b71700
|
||||
|
@ -24,6 +24,7 @@ var (
|
||||
SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble")
|
||||
Importpath = flag.String("p", "", "set expected package import to path")
|
||||
Spectre = flag.String("spectre", "", "enable spectre mitigations in `list` (all, ret)")
|
||||
CompilingRuntime = flag.Bool("compiling-runtime", false, "source to be compiled is part of the Go runtime")
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -109,6 +109,9 @@ func (in *Input) Next() ScanToken {
|
||||
in.Error("'#' must be first item on line")
|
||||
}
|
||||
in.beginningOfLine = in.hash()
|
||||
in.text = "#"
|
||||
return '#'
|
||||
|
||||
case scanner.Ident:
|
||||
// Is it a macro name?
|
||||
name := in.Stack.Text()
|
||||
|
@ -26,6 +26,8 @@ const (
|
||||
RSH // >> Logical right shift.
|
||||
ARR // -> Used on ARM for shift type 3, arithmetic right shift.
|
||||
ROT // @> Used on ARM for shift type 4, rotate right.
|
||||
Include // included file started here
|
||||
BuildComment // //go:build or +build comment
|
||||
macroName // name of macro that should not be expanded
|
||||
)
|
||||
|
||||
|
@ -281,6 +281,9 @@ func drain(input *Input) string {
|
||||
if tok == scanner.EOF {
|
||||
return buf.String()
|
||||
}
|
||||
if tok == '#' {
|
||||
continue
|
||||
}
|
||||
if buf.Len() > 0 {
|
||||
buf.WriteByte('.')
|
||||
}
|
||||
|
@ -107,10 +107,13 @@ func (t *Tokenizer) Next() ScanToken {
|
||||
if t.tok != scanner.Comment {
|
||||
break
|
||||
}
|
||||
length := strings.Count(s.TokenText(), "\n")
|
||||
t.line += length
|
||||
// TODO: If we ever have //go: comments in assembly, will need to keep them here.
|
||||
// For now, just discard all comments.
|
||||
text := s.TokenText()
|
||||
t.line += strings.Count(text, "\n")
|
||||
// TODO: Use constraint.IsGoBuild once it exists.
|
||||
if strings.HasPrefix(text, "//go:build") {
|
||||
t.tok = BuildComment
|
||||
break
|
||||
}
|
||||
}
|
||||
switch t.tok {
|
||||
case '\n':
|
||||
|
@ -74,7 +74,8 @@ func main() {
|
||||
var failedFile string
|
||||
for _, f := range flag.Args() {
|
||||
lexer := lex.NewLexer(f)
|
||||
parser := asm.NewParser(ctxt, architecture, lexer)
|
||||
parser := asm.NewParser(ctxt, architecture, lexer,
|
||||
*flags.CompilingRuntime)
|
||||
ctxt.DiagFunc = func(format string, args ...interface{}) {
|
||||
diag = true
|
||||
log.Printf(format, args...)
|
||||
|
@ -721,7 +721,7 @@ linkage to the desired libraries. The main function is provided by
|
||||
_cgo_main.c:
|
||||
|
||||
int main() { return 0; }
|
||||
void crosscall2(void(*fn)(void*, int, uintptr_t), void *a, int c, uintptr_t ctxt) { }
|
||||
void crosscall2(void(*fn)(void*), void *a, int c, uintptr_t ctxt) { }
|
||||
uintptr_t _cgo_wait_runtime_init_done(void) { return 0; }
|
||||
void _cgo_release_context(uintptr_t ctxt) { }
|
||||
char* _cgo_topofstack(void) { return (char*)0; }
|
||||
|
@ -170,35 +170,51 @@ func usage() {
|
||||
|
||||
var ptrSizeMap = map[string]int64{
|
||||
"386": 4,
|
||||
"alpha": 8,
|
||||
"amd64": 8,
|
||||
"arm": 4,
|
||||
"arm64": 8,
|
||||
"m68k": 4,
|
||||
"mips": 4,
|
||||
"mipsle": 4,
|
||||
"mips64": 8,
|
||||
"mips64le": 8,
|
||||
"nios2": 4,
|
||||
"ppc": 4,
|
||||
"ppc64": 8,
|
||||
"ppc64le": 8,
|
||||
"riscv": 4,
|
||||
"riscv64": 8,
|
||||
"s390": 4,
|
||||
"s390x": 8,
|
||||
"sh": 4,
|
||||
"shbe": 4,
|
||||
"sparc": 4,
|
||||
"sparc64": 8,
|
||||
}
|
||||
|
||||
var intSizeMap = map[string]int64{
|
||||
"386": 4,
|
||||
"alpha": 8,
|
||||
"amd64": 8,
|
||||
"arm": 4,
|
||||
"arm64": 8,
|
||||
"m68k": 4,
|
||||
"mips": 4,
|
||||
"mipsle": 4,
|
||||
"mips64": 8,
|
||||
"mips64le": 8,
|
||||
"nios2": 4,
|
||||
"ppc": 4,
|
||||
"ppc64": 8,
|
||||
"ppc64le": 8,
|
||||
"riscv": 4,
|
||||
"riscv64": 8,
|
||||
"s390": 4,
|
||||
"s390x": 8,
|
||||
"sh": 4,
|
||||
"shbe": 4,
|
||||
"sparc": 4,
|
||||
"sparc64": 8,
|
||||
}
|
||||
|
||||
@ -224,8 +240,7 @@ var exportHeader = flag.String("exportheader", "", "where to write export header
|
||||
var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
|
||||
var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
|
||||
var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo")
|
||||
var gccgoMangleCheckDone bool
|
||||
var gccgoNewmanglingInEffect bool
|
||||
var gccgoMangler func(string) string
|
||||
var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code")
|
||||
var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code")
|
||||
var goarch, goos string
|
||||
|
@ -6,6 +6,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/pkgpath"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
@ -15,7 +16,6 @@ import (
|
||||
"go/token"
|
||||
"internal/xcoff"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@ -59,14 +59,14 @@ func (p *Package) writeDefs() {
|
||||
// Write C main file for using gcc to resolve imports.
|
||||
fmt.Fprintf(fm, "int main() { return 0; }\n")
|
||||
if *importRuntimeCgo {
|
||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
|
||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt) { }\n")
|
||||
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void) { return 0; }\n")
|
||||
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__ ctxt) { }\n")
|
||||
fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
|
||||
} else {
|
||||
// If we're not importing runtime/cgo, we *are* runtime/cgo,
|
||||
// which provides these functions. We just need a prototype.
|
||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int, __SIZE_TYPE__), void *a, int c, __SIZE_TYPE__ ctxt);\n")
|
||||
fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*), void *a, int c, __SIZE_TYPE__ ctxt);\n")
|
||||
fmt.Fprintf(fm, "__SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
||||
fmt.Fprintf(fm, "void _cgo_release_context(__SIZE_TYPE__);\n")
|
||||
}
|
||||
@ -852,7 +852,7 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Wpragmas\"\n")
|
||||
fmt.Fprintf(fgcc, "#pragma GCC diagnostic ignored \"-Waddress-of-packed-member\"\n")
|
||||
|
||||
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int, __SIZE_TYPE__), void *, int, __SIZE_TYPE__);\n")
|
||||
fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *), void *, int, __SIZE_TYPE__);\n")
|
||||
fmt.Fprintf(fgcc, "extern __SIZE_TYPE__ _cgo_wait_runtime_init_done(void);\n")
|
||||
fmt.Fprintf(fgcc, "extern void _cgo_release_context(__SIZE_TYPE__);\n\n")
|
||||
fmt.Fprintf(fgcc, "extern char* _cgo_topofstack(void);")
|
||||
@ -862,59 +862,48 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
for _, exp := range p.ExpFunc {
|
||||
fn := exp.Func
|
||||
|
||||
// Construct a gcc struct matching the gc argument and
|
||||
// result frame. The gcc struct will be compiled with
|
||||
// __attribute__((packed)) so all padding must be accounted
|
||||
// for explicitly.
|
||||
// Construct a struct that will be used to communicate
|
||||
// arguments from C to Go. The C and Go definitions
|
||||
// just have to agree. The gcc struct will be compiled
|
||||
// with __attribute__((packed)) so all padding must be
|
||||
// accounted for explicitly.
|
||||
ctype := "struct {\n"
|
||||
gotype := new(bytes.Buffer)
|
||||
fmt.Fprintf(gotype, "struct {\n")
|
||||
off := int64(0)
|
||||
npad := 0
|
||||
if fn.Recv != nil {
|
||||
t := p.cgoType(fn.Recv.List[0].Type)
|
||||
ctype += fmt.Sprintf("\t\t%s recv;\n", t.C)
|
||||
argField := func(typ ast.Expr, namePat string, args ...interface{}) {
|
||||
name := fmt.Sprintf(namePat, args...)
|
||||
t := p.cgoType(typ)
|
||||
if off%t.Align != 0 {
|
||||
pad := t.Align - off%t.Align
|
||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
||||
off += pad
|
||||
npad++
|
||||
}
|
||||
ctype += fmt.Sprintf("\t\t%s %s;\n", t.C, name)
|
||||
fmt.Fprintf(gotype, "\t\t%s ", name)
|
||||
noSourceConf.Fprint(gotype, fset, typ)
|
||||
fmt.Fprintf(gotype, "\n")
|
||||
off += t.Size
|
||||
}
|
||||
if fn.Recv != nil {
|
||||
argField(fn.Recv.List[0].Type, "recv")
|
||||
}
|
||||
fntype := fn.Type
|
||||
forFieldList(fntype.Params,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
t := p.cgoType(atype)
|
||||
if off%t.Align != 0 {
|
||||
pad := t.Align - off%t.Align
|
||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
||||
off += pad
|
||||
npad++
|
||||
}
|
||||
ctype += fmt.Sprintf("\t\t%s p%d;\n", t.C, i)
|
||||
off += t.Size
|
||||
argField(atype, "p%d", i)
|
||||
})
|
||||
if off%p.PtrSize != 0 {
|
||||
pad := p.PtrSize - off%p.PtrSize
|
||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
||||
off += pad
|
||||
npad++
|
||||
}
|
||||
forFieldList(fntype.Results,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
t := p.cgoType(atype)
|
||||
if off%t.Align != 0 {
|
||||
pad := t.Align - off%t.Align
|
||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
||||
off += pad
|
||||
npad++
|
||||
}
|
||||
ctype += fmt.Sprintf("\t\t%s r%d;\n", t.C, i)
|
||||
off += t.Size
|
||||
argField(atype, "r%d", i)
|
||||
})
|
||||
if off%p.PtrSize != 0 {
|
||||
pad := p.PtrSize - off%p.PtrSize
|
||||
ctype += fmt.Sprintf("\t\tchar __pad%d[%d];\n", npad, pad)
|
||||
off += pad
|
||||
npad++
|
||||
}
|
||||
if ctype == "struct {\n" {
|
||||
ctype += "\t\tchar unused;\n" // avoid empty struct
|
||||
}
|
||||
ctype += "\t}"
|
||||
fmt.Fprintf(gotype, "\t}")
|
||||
|
||||
// Get the return type of the wrapper function
|
||||
// compiled by gcc.
|
||||
@ -939,7 +928,11 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
}
|
||||
|
||||
// Build the wrapper function compiled by gcc.
|
||||
s := fmt.Sprintf("%s %s(", gccResult, exp.ExpName)
|
||||
gccExport := ""
|
||||
if goos == "windows" {
|
||||
gccExport = "__declspec(dllexport)"
|
||||
}
|
||||
s := fmt.Sprintf("%s %s %s(", gccExport, gccResult, exp.ExpName)
|
||||
if fn.Recv != nil {
|
||||
s += p.cgoType(fn.Recv.List[0].Type).C.String()
|
||||
s += " recv"
|
||||
@ -961,12 +954,15 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
}
|
||||
fmt.Fprintf(fgcch, "extern %s;\n", s)
|
||||
|
||||
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int, __SIZE_TYPE__);\n", cPrefix, exp.ExpName)
|
||||
fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *);\n", cPrefix, exp.ExpName)
|
||||
fmt.Fprintf(fgcc, "\nCGO_NO_SANITIZE_THREAD")
|
||||
fmt.Fprintf(fgcc, "\n%s\n", s)
|
||||
fmt.Fprintf(fgcc, "{\n")
|
||||
fmt.Fprintf(fgcc, "\t__SIZE_TYPE__ _cgo_ctxt = _cgo_wait_runtime_init_done();\n")
|
||||
fmt.Fprintf(fgcc, "\t%s %v _cgo_a;\n", ctype, p.packedAttribute())
|
||||
// The results part of the argument structure must be
|
||||
// initialized to 0 so the write barriers generated by
|
||||
// the assignments to these fields in Go are safe.
|
||||
fmt.Fprintf(fgcc, "\t%s %v _cgo_a = {0};\n", ctype, p.packedAttribute())
|
||||
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
|
||||
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
|
||||
}
|
||||
@ -995,82 +991,28 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
fmt.Fprintf(fgcc, "}\n")
|
||||
|
||||
// Build the wrapper function compiled by cmd/compile.
|
||||
goname := "_cgoexpwrap" + cPrefix + "_"
|
||||
if fn.Recv != nil {
|
||||
goname += fn.Recv.List[0].Names[0].Name + "_"
|
||||
}
|
||||
goname += exp.Func.Name.Name
|
||||
// This unpacks the argument struct above and calls the Go function.
|
||||
fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", exp.ExpName)
|
||||
fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
|
||||
fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
|
||||
fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
|
||||
fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted
|
||||
fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32, ctxt uintptr) {\n", cPrefix, exp.ExpName)
|
||||
fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
|
||||
// The indirect here is converting from a Go function pointer to a C function pointer.
|
||||
fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n), ctxt);\n")
|
||||
fmt.Fprintf(fgo2, "}\n")
|
||||
fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a *%s) {\n", cPrefix, exp.ExpName, gotype)
|
||||
|
||||
fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
|
||||
|
||||
// This code uses printer.Fprint, not conf.Fprint,
|
||||
// because we don't want //line comments in the middle
|
||||
// of the function types.
|
||||
fmt.Fprintf(fgo2, "\n")
|
||||
fmt.Fprintf(fgo2, "func %s(", goname)
|
||||
comma := false
|
||||
if fn.Recv != nil {
|
||||
fmt.Fprintf(fgo2, "recv ")
|
||||
printer.Fprint(fgo2, fset, fn.Recv.List[0].Type)
|
||||
comma = true
|
||||
}
|
||||
forFieldList(fntype.Params,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
if comma {
|
||||
fmt.Fprintf(fgo2, ", ")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "p%d ", i)
|
||||
printer.Fprint(fgo2, fset, atype)
|
||||
comma = true
|
||||
})
|
||||
fmt.Fprintf(fgo2, ")")
|
||||
if gccResult != "void" {
|
||||
fmt.Fprint(fgo2, " (")
|
||||
// Write results back to frame.
|
||||
fmt.Fprintf(fgo2, "\t")
|
||||
forFieldList(fntype.Results,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
if i > 0 {
|
||||
fmt.Fprint(fgo2, ", ")
|
||||
fmt.Fprintf(fgo2, ", ")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "r%d ", i)
|
||||
printer.Fprint(fgo2, fset, atype)
|
||||
fmt.Fprintf(fgo2, "a.r%d", i)
|
||||
})
|
||||
fmt.Fprint(fgo2, ")")
|
||||
}
|
||||
fmt.Fprint(fgo2, " {\n")
|
||||
if gccResult == "void" {
|
||||
fmt.Fprint(fgo2, "\t")
|
||||
} else {
|
||||
// Verify that any results don't contain any
|
||||
// Go pointers.
|
||||
addedDefer := false
|
||||
forFieldList(fntype.Results,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
if !p.hasPointer(nil, atype, false) {
|
||||
return
|
||||
}
|
||||
if !addedDefer {
|
||||
fmt.Fprint(fgo2, "\tdefer func() {\n")
|
||||
addedDefer = true
|
||||
}
|
||||
fmt.Fprintf(fgo2, "\t\t_cgoCheckResult(r%d)\n", i)
|
||||
})
|
||||
if addedDefer {
|
||||
fmt.Fprint(fgo2, "\t}()\n")
|
||||
}
|
||||
fmt.Fprint(fgo2, "\treturn ")
|
||||
fmt.Fprintf(fgo2, " = ")
|
||||
}
|
||||
if fn.Recv != nil {
|
||||
fmt.Fprintf(fgo2, "recv.")
|
||||
fmt.Fprintf(fgo2, "a.recv.")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "%s(", exp.Func.Name)
|
||||
forFieldList(fntype.Params,
|
||||
@ -1078,9 +1020,20 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
||||
if i > 0 {
|
||||
fmt.Fprint(fgo2, ", ")
|
||||
}
|
||||
fmt.Fprintf(fgo2, "p%d", i)
|
||||
fmt.Fprintf(fgo2, "a.p%d", i)
|
||||
})
|
||||
fmt.Fprint(fgo2, ")\n")
|
||||
if gccResult != "void" {
|
||||
// Verify that any results don't contain any
|
||||
// Go pointers.
|
||||
forFieldList(fntype.Results,
|
||||
func(i int, aname string, atype ast.Expr) {
|
||||
if !p.hasPointer(nil, atype, false) {
|
||||
return
|
||||
}
|
||||
fmt.Fprintf(fgo2, "\t_cgoCheckResult(a.r%d)\n", i)
|
||||
})
|
||||
}
|
||||
fmt.Fprint(fgo2, "}\n")
|
||||
}
|
||||
|
||||
@ -1282,112 +1235,24 @@ func (p *Package) writeExportHeader(fgcch io.Writer) {
|
||||
fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
|
||||
}
|
||||
|
||||
// gccgoUsesNewMangling reports whether gccgo uses the new collision-free
|
||||
// packagepath mangling scheme (see determineGccgoManglingScheme for more
|
||||
// info).
|
||||
func gccgoUsesNewMangling() bool {
|
||||
if !gccgoMangleCheckDone {
|
||||
gccgoNewmanglingInEffect = determineGccgoManglingScheme()
|
||||
gccgoMangleCheckDone = true
|
||||
}
|
||||
return gccgoNewmanglingInEffect
|
||||
}
|
||||
|
||||
const mangleCheckCode = `
|
||||
package läufer
|
||||
func Run(x int) int {
|
||||
return 1
|
||||
}
|
||||
`
|
||||
|
||||
// determineGccgoManglingScheme performs a runtime test to see which
|
||||
// flavor of packagepath mangling gccgo is using. Older versions of
|
||||
// gccgo use a simple mangling scheme where there can be collisions
|
||||
// between packages whose paths are different but mangle to the same
|
||||
// string. More recent versions of gccgo use a new mangler that avoids
|
||||
// these collisions. Return value is whether gccgo uses the new mangling.
|
||||
func determineGccgoManglingScheme() bool {
|
||||
|
||||
// Emit a small Go file for gccgo to compile.
|
||||
filepat := "*_gccgo_manglecheck.go"
|
||||
var f *os.File
|
||||
var err error
|
||||
if f, err = ioutil.TempFile(*objDir, filepat); err != nil {
|
||||
fatalf("%v", err)
|
||||
}
|
||||
gofilename := f.Name()
|
||||
defer os.Remove(gofilename)
|
||||
|
||||
if err = ioutil.WriteFile(gofilename, []byte(mangleCheckCode), 0666); err != nil {
|
||||
fatalf("%v", err)
|
||||
}
|
||||
|
||||
// Compile with gccgo, capturing generated assembly.
|
||||
gccgocmd := os.Getenv("GCCGO")
|
||||
if gccgocmd == "" {
|
||||
gpath, gerr := exec.LookPath("gccgo")
|
||||
if gerr != nil {
|
||||
fatalf("unable to locate gccgo: %v", gerr)
|
||||
}
|
||||
gccgocmd = gpath
|
||||
}
|
||||
cmd := exec.Command(gccgocmd, "-S", "-o", "-", gofilename)
|
||||
buf, cerr := cmd.CombinedOutput()
|
||||
if cerr != nil {
|
||||
fatalf("%s", cerr)
|
||||
}
|
||||
|
||||
// New mangling: expect go.l..u00e4ufer.Run
|
||||
// Old mangling: expect go.l__ufer.Run
|
||||
return regexp.MustCompile(`go\.l\.\.u00e4ufer\.Run`).Match(buf)
|
||||
}
|
||||
|
||||
// gccgoPkgpathToSymbolNew converts a package path to a gccgo-style
|
||||
// package symbol.
|
||||
func gccgoPkgpathToSymbolNew(ppath string) string {
|
||||
bsl := []byte{}
|
||||
changed := false
|
||||
for _, c := range []byte(ppath) {
|
||||
switch {
|
||||
case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z',
|
||||
'0' <= c && c <= '9', c == '_':
|
||||
bsl = append(bsl, c)
|
||||
case c == '.':
|
||||
bsl = append(bsl, ".x2e"...)
|
||||
default:
|
||||
changed = true
|
||||
encbytes := []byte(fmt.Sprintf("..z%02x", c))
|
||||
bsl = append(bsl, encbytes...)
|
||||
}
|
||||
}
|
||||
if !changed {
|
||||
return ppath
|
||||
}
|
||||
return string(bsl)
|
||||
}
|
||||
|
||||
// gccgoPkgpathToSymbolOld converts a package path to a gccgo-style
|
||||
// package symbol using the older mangling scheme.
|
||||
func gccgoPkgpathToSymbolOld(ppath string) string {
|
||||
clean := func(r rune) rune {
|
||||
switch {
|
||||
case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z',
|
||||
'0' <= r && r <= '9':
|
||||
return r
|
||||
}
|
||||
return '_'
|
||||
}
|
||||
return strings.Map(clean, ppath)
|
||||
}
|
||||
|
||||
// gccgoPkgpathToSymbol converts a package path to a mangled packagepath
|
||||
// symbol.
|
||||
func gccgoPkgpathToSymbol(ppath string) string {
|
||||
if gccgoUsesNewMangling() {
|
||||
return gccgoPkgpathToSymbolNew(ppath)
|
||||
} else {
|
||||
return gccgoPkgpathToSymbolOld(ppath)
|
||||
if gccgoMangler == nil {
|
||||
var err error
|
||||
cmd := os.Getenv("GCCGO")
|
||||
if cmd == "" {
|
||||
cmd, err = exec.LookPath("gccgo")
|
||||
if err != nil {
|
||||
fatalf("unable to locate gccgo: %v", err)
|
||||
}
|
||||
}
|
||||
gccgoMangler, err = pkgpath.ToSymbolFunc(cmd, *objDir)
|
||||
if err != nil {
|
||||
fatalf("%v", err)
|
||||
}
|
||||
}
|
||||
return gccgoMangler(ppath)
|
||||
}
|
||||
|
||||
// Return the package prefix when using gccgo.
|
||||
@ -1666,9 +1531,6 @@ const goProlog = `
|
||||
//go:linkname _cgo_runtime_cgocall runtime.cgocall
|
||||
func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
|
||||
|
||||
//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
|
||||
func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr, uintptr)
|
||||
|
||||
//go:linkname _cgoCheckPointer runtime.cgoCheckPointer
|
||||
func _cgoCheckPointer(interface{}, interface{})
|
||||
|
||||
|
@ -136,6 +136,7 @@ var knownFormats = map[string]string{
|
||||
"cmd/compile/internal/types.EType %s": "",
|
||||
"cmd/compile/internal/types.EType %v": "",
|
||||
"cmd/internal/obj.ABI %v": "",
|
||||
"cmd/internal/src.XPos %v": "",
|
||||
"error %v": "",
|
||||
"float64 %.2f": "",
|
||||
"float64 %.3f": "",
|
||||
|
@ -1210,7 +1210,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
p = s.Prog(x86.ASETEQ)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg0()
|
||||
case ssa.OpAMD64ANDBlock, ssa.OpAMD64ORBlock:
|
||||
case ssa.OpAMD64ANDBlock, ssa.OpAMD64ANDLlock, ssa.OpAMD64ORBlock, ssa.OpAMD64ORLlock:
|
||||
s.Prog(x86.ALOCK)
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG
|
||||
|
@ -688,15 +688,23 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
p5.To.Reg = out
|
||||
gc.Patch(p2, p5)
|
||||
case ssa.OpARM64LoweredAtomicAnd8,
|
||||
ssa.OpARM64LoweredAtomicOr8:
|
||||
// LDAXRB (Rarg0), Rout
|
||||
ssa.OpARM64LoweredAtomicAnd32,
|
||||
ssa.OpARM64LoweredAtomicOr8,
|
||||
ssa.OpARM64LoweredAtomicOr32:
|
||||
// LDAXRB/LDAXRW (Rarg0), Rout
|
||||
// AND/OR Rarg1, Rout
|
||||
// STLXRB Rout, (Rarg0), Rtmp
|
||||
// STLXRB/STLXRB Rout, (Rarg0), Rtmp
|
||||
// CBNZ Rtmp, -3(PC)
|
||||
ld := arm64.ALDAXRB
|
||||
st := arm64.ASTLXRB
|
||||
if v.Op == ssa.OpARM64LoweredAtomicAnd32 || v.Op == ssa.OpARM64LoweredAtomicOr32 {
|
||||
ld = arm64.ALDAXRW
|
||||
st = arm64.ASTLXRW
|
||||
}
|
||||
r0 := v.Args[0].Reg()
|
||||
r1 := v.Args[1].Reg()
|
||||
out := v.Reg0()
|
||||
p := s.Prog(arm64.ALDAXRB)
|
||||
p := s.Prog(ld)
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Reg = r0
|
||||
p.To.Type = obj.TYPE_REG
|
||||
@ -706,7 +714,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
p1.From.Reg = r1
|
||||
p1.To.Type = obj.TYPE_REG
|
||||
p1.To.Reg = out
|
||||
p2 := s.Prog(arm64.ASTLXRB)
|
||||
p2 := s.Prog(st)
|
||||
p2.From.Type = obj.TYPE_REG
|
||||
p2.From.Reg = out
|
||||
p2.To.Type = obj.TYPE_MEM
|
||||
|
@ -282,7 +282,7 @@ func genhash(t *types.Type) *obj.LSym {
|
||||
}
|
||||
|
||||
sym := typesymprefix(".hash", t)
|
||||
if Debug['r'] != 0 {
|
||||
if Debug.r != 0 {
|
||||
fmt.Printf("genhash %v %v %v\n", closure, sym, t)
|
||||
}
|
||||
|
||||
@ -374,7 +374,7 @@ func genhash(t *types.Type) *obj.LSym {
|
||||
r.List.Append(nh)
|
||||
fn.Nbody.Append(r)
|
||||
|
||||
if Debug['r'] != 0 {
|
||||
if Debug.r != 0 {
|
||||
dumplist("genhash body", fn.Nbody)
|
||||
}
|
||||
|
||||
@ -509,7 +509,7 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
return closure
|
||||
}
|
||||
sym := typesymprefix(".eq", t)
|
||||
if Debug['r'] != 0 {
|
||||
if Debug.r != 0 {
|
||||
fmt.Printf("geneq %v\n", t)
|
||||
}
|
||||
|
||||
@ -529,6 +529,10 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
fn := dclfunc(sym, tfn)
|
||||
np := asNode(tfn.Type.Params().Field(0).Nname)
|
||||
nq := asNode(tfn.Type.Params().Field(1).Nname)
|
||||
nr := asNode(tfn.Type.Results().Field(0).Nname)
|
||||
|
||||
// Label to jump to if an equality test fails.
|
||||
neq := autolabel(".neq")
|
||||
|
||||
// We reach here only for types that have equality but
|
||||
// cannot be handled by the standard algorithms,
|
||||
@ -555,13 +559,13 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
// for i := 0; i < nelem; i++ {
|
||||
// if eq(p[i], q[i]) {
|
||||
// } else {
|
||||
// return
|
||||
// goto neq
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// TODO(josharian): consider doing some loop unrolling
|
||||
// for larger nelem as well, processing a few elements at a time in a loop.
|
||||
checkAll := func(unroll int64, eq func(pi, qi *Node) *Node) {
|
||||
checkAll := func(unroll int64, last bool, eq func(pi, qi *Node) *Node) {
|
||||
// checkIdx generates a node to check for equality at index i.
|
||||
checkIdx := func(i *Node) *Node {
|
||||
// pi := p[i]
|
||||
@ -576,23 +580,21 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
}
|
||||
|
||||
if nelem <= unroll {
|
||||
if last {
|
||||
// Do last comparison in a different manner.
|
||||
nelem--
|
||||
}
|
||||
// Generate a series of checks.
|
||||
var cond *Node
|
||||
for i := int64(0); i < nelem; i++ {
|
||||
c := nodintconst(i)
|
||||
check := checkIdx(c)
|
||||
if cond == nil {
|
||||
cond = check
|
||||
continue
|
||||
}
|
||||
cond = nod(OANDAND, cond, check)
|
||||
}
|
||||
nif := nod(OIF, cond, nil)
|
||||
nif.Rlist.Append(nod(ORETURN, nil, nil))
|
||||
// if check {} else { goto neq }
|
||||
nif := nod(OIF, checkIdx(nodintconst(i)), nil)
|
||||
nif.Rlist.Append(nodSym(OGOTO, nil, neq))
|
||||
fn.Nbody.Append(nif)
|
||||
return
|
||||
}
|
||||
|
||||
if last {
|
||||
fn.Nbody.Append(nod(OAS, nr, checkIdx(nodintconst(nelem))))
|
||||
}
|
||||
} else {
|
||||
// Generate a for loop.
|
||||
// for i := 0; i < nelem; i++
|
||||
i := temp(types.Types[TINT])
|
||||
@ -601,12 +603,15 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
post := nod(OAS, i, nod(OADD, i, nodintconst(1)))
|
||||
loop := nod(OFOR, cond, post)
|
||||
loop.Ninit.Append(init)
|
||||
// if eq(pi, qi) {} else { return }
|
||||
check := checkIdx(i)
|
||||
nif := nod(OIF, check, nil)
|
||||
nif.Rlist.Append(nod(ORETURN, nil, nil))
|
||||
// if eq(pi, qi) {} else { goto neq }
|
||||
nif := nod(OIF, checkIdx(i), nil)
|
||||
nif.Rlist.Append(nodSym(OGOTO, nil, neq))
|
||||
loop.Nbody.Append(nif)
|
||||
fn.Nbody.Append(loop)
|
||||
if last {
|
||||
fn.Nbody.Append(nod(OAS, nr, nodbool(true)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch t.Elem().Etype {
|
||||
@ -614,32 +619,28 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
// Do two loops. First, check that all the lengths match (cheap).
|
||||
// Second, check that all the contents match (expensive).
|
||||
// TODO: when the array size is small, unroll the length match checks.
|
||||
checkAll(3, func(pi, qi *Node) *Node {
|
||||
checkAll(3, false, func(pi, qi *Node) *Node {
|
||||
// Compare lengths.
|
||||
eqlen, _ := eqstring(pi, qi)
|
||||
return eqlen
|
||||
})
|
||||
checkAll(1, func(pi, qi *Node) *Node {
|
||||
checkAll(1, true, func(pi, qi *Node) *Node {
|
||||
// Compare contents.
|
||||
_, eqmem := eqstring(pi, qi)
|
||||
return eqmem
|
||||
})
|
||||
case TFLOAT32, TFLOAT64:
|
||||
checkAll(2, func(pi, qi *Node) *Node {
|
||||
checkAll(2, true, func(pi, qi *Node) *Node {
|
||||
// p[i] == q[i]
|
||||
return nod(OEQ, pi, qi)
|
||||
})
|
||||
// TODO: pick apart structs, do them piecemeal too
|
||||
default:
|
||||
checkAll(1, func(pi, qi *Node) *Node {
|
||||
checkAll(1, true, func(pi, qi *Node) *Node {
|
||||
// p[i] == q[i]
|
||||
return nod(OEQ, pi, qi)
|
||||
})
|
||||
}
|
||||
// return true
|
||||
ret := nod(ORETURN, nil, nil)
|
||||
ret.List.Append(nodbool(true))
|
||||
fn.Nbody.Append(ret)
|
||||
|
||||
case TSTRUCT:
|
||||
// Build a list of conditions to satisfy.
|
||||
@ -717,22 +718,42 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
flatConds = append(flatConds, c...)
|
||||
}
|
||||
|
||||
var cond *Node
|
||||
if len(flatConds) == 0 {
|
||||
cond = nodbool(true)
|
||||
fn.Nbody.Append(nod(OAS, nr, nodbool(true)))
|
||||
} else {
|
||||
cond = flatConds[0]
|
||||
for _, c := range flatConds[1:] {
|
||||
cond = nod(OANDAND, cond, c)
|
||||
for _, c := range flatConds[:len(flatConds)-1] {
|
||||
// if cond {} else { goto neq }
|
||||
n := nod(OIF, c, nil)
|
||||
n.Rlist.Append(nodSym(OGOTO, nil, neq))
|
||||
fn.Nbody.Append(n)
|
||||
}
|
||||
fn.Nbody.Append(nod(OAS, nr, flatConds[len(flatConds)-1]))
|
||||
}
|
||||
}
|
||||
|
||||
ret := nod(ORETURN, nil, nil)
|
||||
ret.List.Append(cond)
|
||||
fn.Nbody.Append(ret)
|
||||
}
|
||||
// ret:
|
||||
// return
|
||||
ret := autolabel(".ret")
|
||||
fn.Nbody.Append(nodSym(OLABEL, nil, ret))
|
||||
fn.Nbody.Append(nod(ORETURN, nil, nil))
|
||||
|
||||
if Debug['r'] != 0 {
|
||||
// neq:
|
||||
// r = false
|
||||
// return (or goto ret)
|
||||
fn.Nbody.Append(nodSym(OLABEL, nil, neq))
|
||||
fn.Nbody.Append(nod(OAS, nr, nodbool(false)))
|
||||
if EqCanPanic(t) || hasCall(fn) {
|
||||
// Epilogue is large, so share it with the equal case.
|
||||
fn.Nbody.Append(nodSym(OGOTO, nil, ret))
|
||||
} else {
|
||||
// Epilogue is small, so don't bother sharing.
|
||||
fn.Nbody.Append(nod(ORETURN, nil, nil))
|
||||
}
|
||||
// TODO(khr): the epilogue size detection condition above isn't perfect.
|
||||
// We should really do a generic CL that shares epilogues across
|
||||
// the board. See #24936.
|
||||
|
||||
if Debug.r != 0 {
|
||||
dumplist("geneq body", fn.Nbody)
|
||||
}
|
||||
|
||||
@ -762,6 +783,39 @@ func geneq(t *types.Type) *obj.LSym {
|
||||
return closure
|
||||
}
|
||||
|
||||
func hasCall(n *Node) bool {
|
||||
if n.Op == OCALL || n.Op == OCALLFUNC {
|
||||
return true
|
||||
}
|
||||
if n.Left != nil && hasCall(n.Left) {
|
||||
return true
|
||||
}
|
||||
if n.Right != nil && hasCall(n.Right) {
|
||||
return true
|
||||
}
|
||||
for _, x := range n.Ninit.Slice() {
|
||||
if hasCall(x) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, x := range n.Nbody.Slice() {
|
||||
if hasCall(x) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, x := range n.List.Slice() {
|
||||
if hasCall(x) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, x := range n.Rlist.Slice() {
|
||||
if hasCall(x) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// eqfield returns the node
|
||||
// p.field == q.field
|
||||
func eqfield(p *Node, q *Node, field *types.Sym) *Node {
|
||||
|
@ -86,7 +86,7 @@ func expandiface(t *types.Type) {
|
||||
sort.Sort(methcmp(methods))
|
||||
|
||||
if int64(len(methods)) >= thearch.MAXWIDTH/int64(Widthptr) {
|
||||
yyerror("interface too large")
|
||||
yyerrorl(typePos(t), "interface too large")
|
||||
}
|
||||
for i, m := range methods {
|
||||
m.Offset = int64(i) * int64(Widthptr)
|
||||
@ -150,7 +150,7 @@ func widstruct(errtype *types.Type, t *types.Type, o int64, flag int) int64 {
|
||||
maxwidth = 1<<31 - 1
|
||||
}
|
||||
if o >= maxwidth {
|
||||
yyerror("type %L too large", errtype)
|
||||
yyerrorl(typePos(errtype), "type %L too large", errtype)
|
||||
o = 8 // small but nonzero
|
||||
}
|
||||
}
|
||||
@ -199,7 +199,7 @@ func findTypeLoop(t *types.Type, path *[]*types.Type) bool {
|
||||
}
|
||||
|
||||
*path = append(*path, t)
|
||||
if findTypeLoop(asNode(t.Nod).Name.Param.Ntype.Type, path) {
|
||||
if p := asNode(t.Nod).Name.Param; p != nil && findTypeLoop(p.Ntype.Type, path) {
|
||||
return true
|
||||
}
|
||||
*path = (*path)[:len(*path)-1]
|
||||
@ -381,7 +381,7 @@ func dowidth(t *types.Type) {
|
||||
t1 := t.ChanArgs()
|
||||
dowidth(t1) // just in case
|
||||
if t1.Elem().Width >= 1<<16 {
|
||||
yyerror("channel element type too large (>64kB)")
|
||||
yyerrorl(typePos(t1), "channel element type too large (>64kB)")
|
||||
}
|
||||
w = 1 // anything will do
|
||||
|
||||
@ -414,7 +414,7 @@ func dowidth(t *types.Type) {
|
||||
if t.Elem().Width != 0 {
|
||||
cap := (uint64(thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
|
||||
if uint64(t.NumElem()) > cap {
|
||||
yyerror("type %L larger than address space", t)
|
||||
yyerrorl(typePos(t), "type %L larger than address space", t)
|
||||
}
|
||||
}
|
||||
w = t.NumElem() * t.Elem().Width
|
||||
@ -456,7 +456,7 @@ func dowidth(t *types.Type) {
|
||||
}
|
||||
|
||||
if Widthptr == 4 && w != int64(int32(w)) {
|
||||
yyerror("type %v too large", t)
|
||||
yyerrorl(typePos(t), "type %v too large", t)
|
||||
}
|
||||
|
||||
t.Width = w
|
||||
|
@ -7,6 +7,7 @@ package gc
|
||||
import "testing"
|
||||
|
||||
var globl int64
|
||||
var globl32 int32
|
||||
|
||||
func BenchmarkLoadAdd(b *testing.B) {
|
||||
x := make([]int64, 1024)
|
||||
@ -42,6 +43,17 @@ func BenchmarkModify(b *testing.B) {
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkMullImm(b *testing.B) {
|
||||
x := make([]int32, 1024)
|
||||
for i := 0; i < b.N; i++ {
|
||||
var s int32
|
||||
for i := range x {
|
||||
s += x[i] * 100
|
||||
}
|
||||
globl32 = s
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConstModify(b *testing.B) {
|
||||
a := make([]int64, 1024)
|
||||
for i := 0; i < b.N; i++ {
|
||||
|
@ -81,11 +81,6 @@ func (p *exporter) markType(t *types.Type) {
|
||||
}
|
||||
}
|
||||
|
||||
// deltaNewFile is a magic line delta offset indicating a new file.
|
||||
// We use -64 because it is rare; see issue 20080 and CL 41619.
|
||||
// -64 is the smallest int that fits in a single byte as a varint.
|
||||
const deltaNewFile = -64
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Export format
|
||||
|
||||
@ -126,30 +121,6 @@ const (
|
||||
aliasTag
|
||||
)
|
||||
|
||||
// untype returns the "pseudo" untyped type for a Ctype (import/export use only).
|
||||
// (we can't use a pre-initialized array because we must be sure all types are
|
||||
// set up)
|
||||
func untype(ctype Ctype) *types.Type {
|
||||
switch ctype {
|
||||
case CTINT:
|
||||
return types.Idealint
|
||||
case CTRUNE:
|
||||
return types.Idealrune
|
||||
case CTFLT:
|
||||
return types.Idealfloat
|
||||
case CTCPLX:
|
||||
return types.Idealcomplex
|
||||
case CTSTR:
|
||||
return types.Idealstring
|
||||
case CTBOOL:
|
||||
return types.Idealbool
|
||||
case CTNIL:
|
||||
return types.Types[TNIL]
|
||||
}
|
||||
Fatalf("exporter: unknown Ctype")
|
||||
return nil
|
||||
}
|
||||
|
||||
var predecl []*types.Type // initialized lazily
|
||||
|
||||
func predeclared() []*types.Type {
|
||||
@ -184,13 +155,13 @@ func predeclared() []*types.Type {
|
||||
types.Errortype,
|
||||
|
||||
// untyped types
|
||||
untype(CTBOOL),
|
||||
untype(CTINT),
|
||||
untype(CTRUNE),
|
||||
untype(CTFLT),
|
||||
untype(CTCPLX),
|
||||
untype(CTSTR),
|
||||
untype(CTNIL),
|
||||
types.UntypedBool,
|
||||
types.UntypedInt,
|
||||
types.UntypedRune,
|
||||
types.UntypedFloat,
|
||||
types.UntypedComplex,
|
||||
types.UntypedString,
|
||||
types.Types[TNIL],
|
||||
|
||||
// package unsafe
|
||||
types.Types[TUNSAFEPTR],
|
||||
|
@ -44,6 +44,7 @@ var runtimeDecls = [...]struct {
|
||||
{"printcomplex", funcTag, 27},
|
||||
{"printstring", funcTag, 29},
|
||||
{"printpointer", funcTag, 30},
|
||||
{"printuintptr", funcTag, 31},
|
||||
{"printiface", funcTag, 30},
|
||||
{"printeface", funcTag, 30},
|
||||
{"printslice", funcTag, 30},
|
||||
@ -51,134 +52,134 @@ var runtimeDecls = [...]struct {
|
||||
{"printsp", funcTag, 9},
|
||||
{"printlock", funcTag, 9},
|
||||
{"printunlock", funcTag, 9},
|
||||
{"concatstring2", funcTag, 33},
|
||||
{"concatstring3", funcTag, 34},
|
||||
{"concatstring4", funcTag, 35},
|
||||
{"concatstring5", funcTag, 36},
|
||||
{"concatstrings", funcTag, 38},
|
||||
{"cmpstring", funcTag, 39},
|
||||
{"intstring", funcTag, 42},
|
||||
{"slicebytetostring", funcTag, 43},
|
||||
{"slicebytetostringtmp", funcTag, 44},
|
||||
{"slicerunetostring", funcTag, 47},
|
||||
{"stringtoslicebyte", funcTag, 49},
|
||||
{"stringtoslicerune", funcTag, 52},
|
||||
{"slicecopy", funcTag, 53},
|
||||
{"decoderune", funcTag, 54},
|
||||
{"countrunes", funcTag, 55},
|
||||
{"convI2I", funcTag, 56},
|
||||
{"convT16", funcTag, 57},
|
||||
{"convT32", funcTag, 57},
|
||||
{"convT64", funcTag, 57},
|
||||
{"convTstring", funcTag, 57},
|
||||
{"convTslice", funcTag, 57},
|
||||
{"convT2E", funcTag, 58},
|
||||
{"convT2Enoptr", funcTag, 58},
|
||||
{"convT2I", funcTag, 58},
|
||||
{"convT2Inoptr", funcTag, 58},
|
||||
{"assertE2I", funcTag, 56},
|
||||
{"assertE2I2", funcTag, 59},
|
||||
{"assertI2I", funcTag, 56},
|
||||
{"assertI2I2", funcTag, 59},
|
||||
{"panicdottypeE", funcTag, 60},
|
||||
{"panicdottypeI", funcTag, 60},
|
||||
{"panicnildottype", funcTag, 61},
|
||||
{"ifaceeq", funcTag, 63},
|
||||
{"efaceeq", funcTag, 63},
|
||||
{"fastrand", funcTag, 65},
|
||||
{"makemap64", funcTag, 67},
|
||||
{"makemap", funcTag, 68},
|
||||
{"makemap_small", funcTag, 69},
|
||||
{"mapaccess1", funcTag, 70},
|
||||
{"mapaccess1_fast32", funcTag, 71},
|
||||
{"mapaccess1_fast64", funcTag, 71},
|
||||
{"mapaccess1_faststr", funcTag, 71},
|
||||
{"mapaccess1_fat", funcTag, 72},
|
||||
{"mapaccess2", funcTag, 73},
|
||||
{"mapaccess2_fast32", funcTag, 74},
|
||||
{"mapaccess2_fast64", funcTag, 74},
|
||||
{"mapaccess2_faststr", funcTag, 74},
|
||||
{"mapaccess2_fat", funcTag, 75},
|
||||
{"mapassign", funcTag, 70},
|
||||
{"mapassign_fast32", funcTag, 71},
|
||||
{"mapassign_fast32ptr", funcTag, 71},
|
||||
{"mapassign_fast64", funcTag, 71},
|
||||
{"mapassign_fast64ptr", funcTag, 71},
|
||||
{"mapassign_faststr", funcTag, 71},
|
||||
{"mapiterinit", funcTag, 76},
|
||||
{"mapdelete", funcTag, 76},
|
||||
{"mapdelete_fast32", funcTag, 77},
|
||||
{"mapdelete_fast64", funcTag, 77},
|
||||
{"mapdelete_faststr", funcTag, 77},
|
||||
{"mapiternext", funcTag, 78},
|
||||
{"mapclear", funcTag, 79},
|
||||
{"makechan64", funcTag, 81},
|
||||
{"makechan", funcTag, 82},
|
||||
{"chanrecv1", funcTag, 84},
|
||||
{"chanrecv2", funcTag, 85},
|
||||
{"chansend1", funcTag, 87},
|
||||
{"concatstring2", funcTag, 34},
|
||||
{"concatstring3", funcTag, 35},
|
||||
{"concatstring4", funcTag, 36},
|
||||
{"concatstring5", funcTag, 37},
|
||||
{"concatstrings", funcTag, 39},
|
||||
{"cmpstring", funcTag, 40},
|
||||
{"intstring", funcTag, 43},
|
||||
{"slicebytetostring", funcTag, 44},
|
||||
{"slicebytetostringtmp", funcTag, 45},
|
||||
{"slicerunetostring", funcTag, 48},
|
||||
{"stringtoslicebyte", funcTag, 50},
|
||||
{"stringtoslicerune", funcTag, 53},
|
||||
{"slicecopy", funcTag, 54},
|
||||
{"decoderune", funcTag, 55},
|
||||
{"countrunes", funcTag, 56},
|
||||
{"convI2I", funcTag, 57},
|
||||
{"convT16", funcTag, 58},
|
||||
{"convT32", funcTag, 58},
|
||||
{"convT64", funcTag, 58},
|
||||
{"convTstring", funcTag, 58},
|
||||
{"convTslice", funcTag, 58},
|
||||
{"convT2E", funcTag, 59},
|
||||
{"convT2Enoptr", funcTag, 59},
|
||||
{"convT2I", funcTag, 59},
|
||||
{"convT2Inoptr", funcTag, 59},
|
||||
{"assertE2I", funcTag, 57},
|
||||
{"assertE2I2", funcTag, 60},
|
||||
{"assertI2I", funcTag, 57},
|
||||
{"assertI2I2", funcTag, 60},
|
||||
{"panicdottypeE", funcTag, 61},
|
||||
{"panicdottypeI", funcTag, 61},
|
||||
{"panicnildottype", funcTag, 62},
|
||||
{"ifaceeq", funcTag, 64},
|
||||
{"efaceeq", funcTag, 64},
|
||||
{"fastrand", funcTag, 66},
|
||||
{"makemap64", funcTag, 68},
|
||||
{"makemap", funcTag, 69},
|
||||
{"makemap_small", funcTag, 70},
|
||||
{"mapaccess1", funcTag, 71},
|
||||
{"mapaccess1_fast32", funcTag, 72},
|
||||
{"mapaccess1_fast64", funcTag, 72},
|
||||
{"mapaccess1_faststr", funcTag, 72},
|
||||
{"mapaccess1_fat", funcTag, 73},
|
||||
{"mapaccess2", funcTag, 74},
|
||||
{"mapaccess2_fast32", funcTag, 75},
|
||||
{"mapaccess2_fast64", funcTag, 75},
|
||||
{"mapaccess2_faststr", funcTag, 75},
|
||||
{"mapaccess2_fat", funcTag, 76},
|
||||
{"mapassign", funcTag, 71},
|
||||
{"mapassign_fast32", funcTag, 72},
|
||||
{"mapassign_fast32ptr", funcTag, 72},
|
||||
{"mapassign_fast64", funcTag, 72},
|
||||
{"mapassign_fast64ptr", funcTag, 72},
|
||||
{"mapassign_faststr", funcTag, 72},
|
||||
{"mapiterinit", funcTag, 77},
|
||||
{"mapdelete", funcTag, 77},
|
||||
{"mapdelete_fast32", funcTag, 78},
|
||||
{"mapdelete_fast64", funcTag, 78},
|
||||
{"mapdelete_faststr", funcTag, 78},
|
||||
{"mapiternext", funcTag, 79},
|
||||
{"mapclear", funcTag, 80},
|
||||
{"makechan64", funcTag, 82},
|
||||
{"makechan", funcTag, 83},
|
||||
{"chanrecv1", funcTag, 85},
|
||||
{"chanrecv2", funcTag, 86},
|
||||
{"chansend1", funcTag, 88},
|
||||
{"closechan", funcTag, 30},
|
||||
{"writeBarrier", varTag, 89},
|
||||
{"typedmemmove", funcTag, 90},
|
||||
{"typedmemclr", funcTag, 91},
|
||||
{"typedslicecopy", funcTag, 92},
|
||||
{"selectnbsend", funcTag, 93},
|
||||
{"selectnbrecv", funcTag, 94},
|
||||
{"selectnbrecv2", funcTag, 96},
|
||||
{"selectsetpc", funcTag, 97},
|
||||
{"selectgo", funcTag, 98},
|
||||
{"writeBarrier", varTag, 90},
|
||||
{"typedmemmove", funcTag, 91},
|
||||
{"typedmemclr", funcTag, 92},
|
||||
{"typedslicecopy", funcTag, 93},
|
||||
{"selectnbsend", funcTag, 94},
|
||||
{"selectnbrecv", funcTag, 95},
|
||||
{"selectnbrecv2", funcTag, 97},
|
||||
{"selectsetpc", funcTag, 98},
|
||||
{"selectgo", funcTag, 99},
|
||||
{"block", funcTag, 9},
|
||||
{"makeslice", funcTag, 99},
|
||||
{"makeslice64", funcTag, 100},
|
||||
{"makeslicecopy", funcTag, 101},
|
||||
{"growslice", funcTag, 103},
|
||||
{"memmove", funcTag, 104},
|
||||
{"memclrNoHeapPointers", funcTag, 105},
|
||||
{"memclrHasPointers", funcTag, 105},
|
||||
{"memequal", funcTag, 106},
|
||||
{"memequal0", funcTag, 107},
|
||||
{"memequal8", funcTag, 107},
|
||||
{"memequal16", funcTag, 107},
|
||||
{"memequal32", funcTag, 107},
|
||||
{"memequal64", funcTag, 107},
|
||||
{"memequal128", funcTag, 107},
|
||||
{"f32equal", funcTag, 108},
|
||||
{"f64equal", funcTag, 108},
|
||||
{"c64equal", funcTag, 108},
|
||||
{"c128equal", funcTag, 108},
|
||||
{"strequal", funcTag, 108},
|
||||
{"interequal", funcTag, 108},
|
||||
{"nilinterequal", funcTag, 108},
|
||||
{"memhash", funcTag, 109},
|
||||
{"memhash0", funcTag, 110},
|
||||
{"memhash8", funcTag, 110},
|
||||
{"memhash16", funcTag, 110},
|
||||
{"memhash32", funcTag, 110},
|
||||
{"memhash64", funcTag, 110},
|
||||
{"memhash128", funcTag, 110},
|
||||
{"f32hash", funcTag, 110},
|
||||
{"f64hash", funcTag, 110},
|
||||
{"c64hash", funcTag, 110},
|
||||
{"c128hash", funcTag, 110},
|
||||
{"strhash", funcTag, 110},
|
||||
{"interhash", funcTag, 110},
|
||||
{"nilinterhash", funcTag, 110},
|
||||
{"int64div", funcTag, 111},
|
||||
{"uint64div", funcTag, 112},
|
||||
{"int64mod", funcTag, 111},
|
||||
{"uint64mod", funcTag, 112},
|
||||
{"float64toint64", funcTag, 113},
|
||||
{"float64touint64", funcTag, 114},
|
||||
{"float64touint32", funcTag, 115},
|
||||
{"int64tofloat64", funcTag, 116},
|
||||
{"uint64tofloat64", funcTag, 117},
|
||||
{"uint32tofloat64", funcTag, 118},
|
||||
{"complex128div", funcTag, 119},
|
||||
{"racefuncenter", funcTag, 120},
|
||||
{"makeslice", funcTag, 100},
|
||||
{"makeslice64", funcTag, 101},
|
||||
{"makeslicecopy", funcTag, 102},
|
||||
{"growslice", funcTag, 104},
|
||||
{"memmove", funcTag, 105},
|
||||
{"memclrNoHeapPointers", funcTag, 106},
|
||||
{"memclrHasPointers", funcTag, 106},
|
||||
{"memequal", funcTag, 107},
|
||||
{"memequal0", funcTag, 108},
|
||||
{"memequal8", funcTag, 108},
|
||||
{"memequal16", funcTag, 108},
|
||||
{"memequal32", funcTag, 108},
|
||||
{"memequal64", funcTag, 108},
|
||||
{"memequal128", funcTag, 108},
|
||||
{"f32equal", funcTag, 109},
|
||||
{"f64equal", funcTag, 109},
|
||||
{"c64equal", funcTag, 109},
|
||||
{"c128equal", funcTag, 109},
|
||||
{"strequal", funcTag, 109},
|
||||
{"interequal", funcTag, 109},
|
||||
{"nilinterequal", funcTag, 109},
|
||||
{"memhash", funcTag, 110},
|
||||
{"memhash0", funcTag, 111},
|
||||
{"memhash8", funcTag, 111},
|
||||
{"memhash16", funcTag, 111},
|
||||
{"memhash32", funcTag, 111},
|
||||
{"memhash64", funcTag, 111},
|
||||
{"memhash128", funcTag, 111},
|
||||
{"f32hash", funcTag, 111},
|
||||
{"f64hash", funcTag, 111},
|
||||
{"c64hash", funcTag, 111},
|
||||
{"c128hash", funcTag, 111},
|
||||
{"strhash", funcTag, 111},
|
||||
{"interhash", funcTag, 111},
|
||||
{"nilinterhash", funcTag, 111},
|
||||
{"int64div", funcTag, 112},
|
||||
{"uint64div", funcTag, 113},
|
||||
{"int64mod", funcTag, 112},
|
||||
{"uint64mod", funcTag, 113},
|
||||
{"float64toint64", funcTag, 114},
|
||||
{"float64touint64", funcTag, 115},
|
||||
{"float64touint32", funcTag, 116},
|
||||
{"int64tofloat64", funcTag, 117},
|
||||
{"uint64tofloat64", funcTag, 118},
|
||||
{"uint32tofloat64", funcTag, 119},
|
||||
{"complex128div", funcTag, 120},
|
||||
{"racefuncenter", funcTag, 31},
|
||||
{"racefuncenterfp", funcTag, 9},
|
||||
{"racefuncexit", funcTag, 9},
|
||||
{"raceread", funcTag, 120},
|
||||
{"racewrite", funcTag, 120},
|
||||
{"raceread", funcTag, 31},
|
||||
{"racewrite", funcTag, 31},
|
||||
{"racereadrange", funcTag, 121},
|
||||
{"racewriterange", funcTag, 121},
|
||||
{"msanread", funcTag, 121},
|
||||
@ -233,96 +234,96 @@ func runtimeTypes() []*types.Type {
|
||||
typs[28] = types.Types[TSTRING]
|
||||
typs[29] = functype(nil, []*Node{anonfield(typs[28])}, nil)
|
||||
typs[30] = functype(nil, []*Node{anonfield(typs[2])}, nil)
|
||||
typs[31] = types.NewArray(typs[0], 32)
|
||||
typs[32] = types.NewPtr(typs[31])
|
||||
typs[33] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||
typs[34] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||
typs[35] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||
typs[36] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||
typs[37] = types.NewSlice(typs[28])
|
||||
typs[38] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[37])}, []*Node{anonfield(typs[28])})
|
||||
typs[39] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
|
||||
typs[40] = types.NewArray(typs[0], 4)
|
||||
typs[41] = types.NewPtr(typs[40])
|
||||
typs[42] = functype(nil, []*Node{anonfield(typs[41]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
|
||||
typs[43] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
|
||||
typs[44] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
|
||||
typs[45] = types.Runetype
|
||||
typs[46] = types.NewSlice(typs[45])
|
||||
typs[47] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[46])}, []*Node{anonfield(typs[28])})
|
||||
typs[48] = types.NewSlice(typs[0])
|
||||
typs[49] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28])}, []*Node{anonfield(typs[48])})
|
||||
typs[50] = types.NewArray(typs[45], 32)
|
||||
typs[51] = types.NewPtr(typs[50])
|
||||
typs[52] = functype(nil, []*Node{anonfield(typs[51]), anonfield(typs[28])}, []*Node{anonfield(typs[46])})
|
||||
typs[53] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*Node{anonfield(typs[15])})
|
||||
typs[54] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[45]), anonfield(typs[15])})
|
||||
typs[55] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
|
||||
typs[56] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
|
||||
typs[57] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])})
|
||||
typs[58] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
|
||||
typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])})
|
||||
typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
|
||||
typs[61] = functype(nil, []*Node{anonfield(typs[1])}, nil)
|
||||
typs[62] = types.NewPtr(typs[5])
|
||||
typs[63] = functype(nil, []*Node{anonfield(typs[62]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
|
||||
typs[64] = types.Types[TUINT32]
|
||||
typs[65] = functype(nil, nil, []*Node{anonfield(typs[64])})
|
||||
typs[66] = types.NewMap(typs[2], typs[2])
|
||||
typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
|
||||
typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
|
||||
typs[69] = functype(nil, nil, []*Node{anonfield(typs[66])})
|
||||
typs[70] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
|
||||
typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
|
||||
typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
|
||||
typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
|
||||
typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
|
||||
typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
|
||||
typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, nil)
|
||||
typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, nil)
|
||||
typs[78] = functype(nil, []*Node{anonfield(typs[3])}, nil)
|
||||
typs[79] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66])}, nil)
|
||||
typs[80] = types.NewChan(typs[2], types.Cboth)
|
||||
typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[80])})
|
||||
typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[80])})
|
||||
typs[83] = types.NewChan(typs[2], types.Crecv)
|
||||
typs[84] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, nil)
|
||||
typs[85] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
||||
typs[86] = types.NewChan(typs[2], types.Csend)
|
||||
typs[87] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, nil)
|
||||
typs[88] = types.NewArray(typs[0], 3)
|
||||
typs[89] = tostruct([]*Node{namedfield("enabled", typs[6]), namedfield("pad", typs[88]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
|
||||
typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
|
||||
typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
|
||||
typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
|
||||
typs[93] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
||||
typs[94] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[83])}, []*Node{anonfield(typs[6])})
|
||||
typs[95] = types.NewPtr(typs[6])
|
||||
typs[96] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[95]), anonfield(typs[83])}, []*Node{anonfield(typs[6])})
|
||||
typs[97] = functype(nil, []*Node{anonfield(typs[62])}, nil)
|
||||
typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[62]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[6])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
|
||||
typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
|
||||
typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
|
||||
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
|
||||
typs[102] = types.NewSlice(typs[2])
|
||||
typs[103] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[102]), anonfield(typs[15])}, []*Node{anonfield(typs[102])})
|
||||
typs[104] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
|
||||
typs[105] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
|
||||
typs[106] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*Node{anonfield(typs[6])})
|
||||
typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
||||
typs[108] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
|
||||
typs[109] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
|
||||
typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
|
||||
typs[111] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
|
||||
typs[112] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
|
||||
typs[113] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
|
||||
typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
|
||||
typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[64])})
|
||||
typs[116] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
|
||||
typs[117] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
|
||||
typs[118] = functype(nil, []*Node{anonfield(typs[64])}, []*Node{anonfield(typs[20])})
|
||||
typs[119] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
|
||||
typs[120] = functype(nil, []*Node{anonfield(typs[5])}, nil)
|
||||
typs[31] = functype(nil, []*Node{anonfield(typs[5])}, nil)
|
||||
typs[32] = types.NewArray(typs[0], 32)
|
||||
typs[33] = types.NewPtr(typs[32])
|
||||
typs[34] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||
typs[35] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||
typs[36] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||
typs[37] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
|
||||
typs[38] = types.NewSlice(typs[28])
|
||||
typs[39] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[38])}, []*Node{anonfield(typs[28])})
|
||||
typs[40] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
|
||||
typs[41] = types.NewArray(typs[0], 4)
|
||||
typs[42] = types.NewPtr(typs[41])
|
||||
typs[43] = functype(nil, []*Node{anonfield(typs[42]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
|
||||
typs[44] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
|
||||
typs[45] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
|
||||
typs[46] = types.Runetype
|
||||
typs[47] = types.NewSlice(typs[46])
|
||||
typs[48] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[47])}, []*Node{anonfield(typs[28])})
|
||||
typs[49] = types.NewSlice(typs[0])
|
||||
typs[50] = functype(nil, []*Node{anonfield(typs[33]), anonfield(typs[28])}, []*Node{anonfield(typs[49])})
|
||||
typs[51] = types.NewArray(typs[46], 32)
|
||||
typs[52] = types.NewPtr(typs[51])
|
||||
typs[53] = functype(nil, []*Node{anonfield(typs[52]), anonfield(typs[28])}, []*Node{anonfield(typs[47])})
|
||||
typs[54] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*Node{anonfield(typs[15])})
|
||||
typs[55] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[46]), anonfield(typs[15])})
|
||||
typs[56] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
|
||||
typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
|
||||
typs[58] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])})
|
||||
typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
|
||||
typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])})
|
||||
typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
|
||||
typs[62] = functype(nil, []*Node{anonfield(typs[1])}, nil)
|
||||
typs[63] = types.NewPtr(typs[5])
|
||||
typs[64] = functype(nil, []*Node{anonfield(typs[63]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
|
||||
typs[65] = types.Types[TUINT32]
|
||||
typs[66] = functype(nil, nil, []*Node{anonfield(typs[65])})
|
||||
typs[67] = types.NewMap(typs[2], typs[2])
|
||||
typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
|
||||
typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
|
||||
typs[70] = functype(nil, nil, []*Node{anonfield(typs[67])})
|
||||
typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
|
||||
typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
|
||||
typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
|
||||
typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
|
||||
typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
|
||||
typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
|
||||
typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, nil)
|
||||
typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, nil)
|
||||
typs[79] = functype(nil, []*Node{anonfield(typs[3])}, nil)
|
||||
typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67])}, nil)
|
||||
typs[81] = types.NewChan(typs[2], types.Cboth)
|
||||
typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[81])})
|
||||
typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[81])})
|
||||
typs[84] = types.NewChan(typs[2], types.Crecv)
|
||||
typs[85] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, nil)
|
||||
typs[86] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
||||
typs[87] = types.NewChan(typs[2], types.Csend)
|
||||
typs[88] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, nil)
|
||||
typs[89] = types.NewArray(typs[0], 3)
|
||||
typs[90] = tostruct([]*Node{namedfield("enabled", typs[6]), namedfield("pad", typs[89]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
|
||||
typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
|
||||
typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
|
||||
typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
|
||||
typs[94] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
||||
typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
|
||||
typs[96] = types.NewPtr(typs[6])
|
||||
typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
|
||||
typs[98] = functype(nil, []*Node{anonfield(typs[63])}, nil)
|
||||
typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[63]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[6])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
|
||||
typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
|
||||
typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
|
||||
typs[102] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
|
||||
typs[103] = types.NewSlice(typs[2])
|
||||
typs[104] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[103]), anonfield(typs[15])}, []*Node{anonfield(typs[103])})
|
||||
typs[105] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
|
||||
typs[106] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
|
||||
typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*Node{anonfield(typs[6])})
|
||||
typs[108] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
|
||||
typs[109] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
|
||||
typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
|
||||
typs[111] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
|
||||
typs[112] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
|
||||
typs[113] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
|
||||
typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
|
||||
typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
|
||||
typs[116] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[65])})
|
||||
typs[117] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
|
||||
typs[118] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
|
||||
typs[119] = functype(nil, []*Node{anonfield(typs[65])}, []*Node{anonfield(typs[20])})
|
||||
typs[120] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
|
||||
typs[121] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
|
||||
typs[122] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
|
||||
typs[123] = types.NewSlice(typs[7])
|
||||
@ -331,7 +332,7 @@ func runtimeTypes() []*types.Type {
|
||||
typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
|
||||
typs[127] = types.Types[TUINT16]
|
||||
typs[128] = functype(nil, []*Node{anonfield(typs[127]), anonfield(typs[127])}, nil)
|
||||
typs[129] = functype(nil, []*Node{anonfield(typs[64]), anonfield(typs[64])}, nil)
|
||||
typs[129] = functype(nil, []*Node{anonfield(typs[65]), anonfield(typs[65])}, nil)
|
||||
typs[130] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
|
||||
return typs[:]
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ func printuint(uint64)
|
||||
func printcomplex(complex128)
|
||||
func printstring(string)
|
||||
func printpointer(any)
|
||||
func printuintptr(uintptr)
|
||||
func printiface(any)
|
||||
func printeface(any)
|
||||
func printslice(any)
|
||||
|
@ -198,7 +198,7 @@ func capturevars(xfunc *Node) {
|
||||
outer = nod(OADDR, outer, nil)
|
||||
}
|
||||
|
||||
if Debug['m'] > 1 {
|
||||
if Debug.m > 1 {
|
||||
var name *types.Sym
|
||||
if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil {
|
||||
name = v.Name.Curfn.Func.Nname.Sym
|
||||
@ -434,6 +434,8 @@ func typecheckpartialcall(fn *Node, sym *types.Sym) {
|
||||
fn.Type = xfunc.Type
|
||||
}
|
||||
|
||||
// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
|
||||
// for partial calls.
|
||||
func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
|
||||
rcvrtype := fn.Left.Type
|
||||
sym := methodSymSuffix(rcvrtype, meth, "-fm")
|
||||
@ -500,6 +502,10 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
|
||||
funcbody()
|
||||
|
||||
xfunc = typecheck(xfunc, ctxStmt)
|
||||
// Need to typecheck the body of the just-generated wrapper.
|
||||
// typecheckslice() requires that Curfn is set when processing an ORETURN.
|
||||
Curfn = xfunc
|
||||
typecheckslice(xfunc.Nbody.Slice(), ctxStmt)
|
||||
sym.Def = asTypesNode(xfunc)
|
||||
xtop = append(xtop, xfunc)
|
||||
Curfn = savecurfn
|
||||
|
@ -114,16 +114,16 @@ func (v Val) Interface() interface{} {
|
||||
|
||||
type NilVal struct{}
|
||||
|
||||
// Int64 returns n as an int64.
|
||||
// Int64Val returns n as an int64.
|
||||
// n must be an integer or rune constant.
|
||||
func (n *Node) Int64() int64 {
|
||||
func (n *Node) Int64Val() int64 {
|
||||
if !Isconst(n, CTINT) {
|
||||
Fatalf("Int64(%v)", n)
|
||||
Fatalf("Int64Val(%v)", n)
|
||||
}
|
||||
return n.Val().U.(*Mpint).Int64()
|
||||
}
|
||||
|
||||
// CanInt64 reports whether it is safe to call Int64() on n.
|
||||
// CanInt64 reports whether it is safe to call Int64Val() on n.
|
||||
func (n *Node) CanInt64() bool {
|
||||
if !Isconst(n, CTINT) {
|
||||
return false
|
||||
@ -131,18 +131,27 @@ func (n *Node) CanInt64() bool {
|
||||
|
||||
// if the value inside n cannot be represented as an int64, the
|
||||
// return value of Int64 is undefined
|
||||
return n.Val().U.(*Mpint).CmpInt64(n.Int64()) == 0
|
||||
return n.Val().U.(*Mpint).CmpInt64(n.Int64Val()) == 0
|
||||
}
|
||||
|
||||
// Bool returns n as a bool.
|
||||
// BoolVal returns n as a bool.
|
||||
// n must be a boolean constant.
|
||||
func (n *Node) Bool() bool {
|
||||
func (n *Node) BoolVal() bool {
|
||||
if !Isconst(n, CTBOOL) {
|
||||
Fatalf("Bool(%v)", n)
|
||||
Fatalf("BoolVal(%v)", n)
|
||||
}
|
||||
return n.Val().U.(bool)
|
||||
}
|
||||
|
||||
// StringVal returns the value of a literal string Node as a string.
|
||||
// n must be a string constant.
|
||||
func (n *Node) StringVal() string {
|
||||
if !Isconst(n, CTSTR) {
|
||||
Fatalf("StringVal(%v)", n)
|
||||
}
|
||||
return n.Val().U.(string)
|
||||
}
|
||||
|
||||
// truncate float literal fv to 32-bit or 64-bit precision
|
||||
// according to type; return truncated value.
|
||||
func truncfltlit(oldv *Mpflt, t *types.Type) *Mpflt {
|
||||
@ -612,7 +621,7 @@ func evconst(n *Node) {
|
||||
var strs []string
|
||||
i2 := i1
|
||||
for i2 < len(s) && Isconst(s[i2], CTSTR) {
|
||||
strs = append(strs, strlit(s[i2]))
|
||||
strs = append(strs, s[i2].StringVal())
|
||||
i2++
|
||||
}
|
||||
|
||||
@ -635,7 +644,7 @@ func evconst(n *Node) {
|
||||
switch nl.Type.Etype {
|
||||
case TSTRING:
|
||||
if Isconst(nl, CTSTR) {
|
||||
setintconst(n, int64(len(strlit(nl))))
|
||||
setintconst(n, int64(len(nl.StringVal())))
|
||||
}
|
||||
case TARRAY:
|
||||
if !hascallchan(nl) {
|
||||
@ -1019,17 +1028,17 @@ func nodlit(v Val) *Node {
|
||||
func idealType(ct Ctype) *types.Type {
|
||||
switch ct {
|
||||
case CTSTR:
|
||||
return types.Idealstring
|
||||
return types.UntypedString
|
||||
case CTBOOL:
|
||||
return types.Idealbool
|
||||
return types.UntypedBool
|
||||
case CTINT:
|
||||
return types.Idealint
|
||||
return types.UntypedInt
|
||||
case CTRUNE:
|
||||
return types.Idealrune
|
||||
return types.UntypedRune
|
||||
case CTFLT:
|
||||
return types.Idealfloat
|
||||
return types.UntypedFloat
|
||||
case CTCPLX:
|
||||
return types.Idealcomplex
|
||||
return types.UntypedComplex
|
||||
case CTNIL:
|
||||
return types.Types[TNIL]
|
||||
}
|
||||
@ -1080,17 +1089,17 @@ func defaultlit2(l *Node, r *Node, force bool) (*Node, *Node) {
|
||||
|
||||
func ctype(t *types.Type) Ctype {
|
||||
switch t {
|
||||
case types.Idealbool:
|
||||
case types.UntypedBool:
|
||||
return CTBOOL
|
||||
case types.Idealstring:
|
||||
case types.UntypedString:
|
||||
return CTSTR
|
||||
case types.Idealint:
|
||||
case types.UntypedInt:
|
||||
return CTINT
|
||||
case types.Idealrune:
|
||||
case types.UntypedRune:
|
||||
return CTRUNE
|
||||
case types.Idealfloat:
|
||||
case types.UntypedFloat:
|
||||
return CTFLT
|
||||
case types.Idealcomplex:
|
||||
case types.UntypedComplex:
|
||||
return CTCPLX
|
||||
}
|
||||
Fatalf("bad type %v", t)
|
||||
@ -1111,17 +1120,17 @@ func defaultType(t *types.Type) *types.Type {
|
||||
}
|
||||
|
||||
switch t {
|
||||
case types.Idealbool:
|
||||
case types.UntypedBool:
|
||||
return types.Types[TBOOL]
|
||||
case types.Idealstring:
|
||||
case types.UntypedString:
|
||||
return types.Types[TSTRING]
|
||||
case types.Idealint:
|
||||
case types.UntypedInt:
|
||||
return types.Types[TINT]
|
||||
case types.Idealrune:
|
||||
case types.UntypedRune:
|
||||
return types.Runetype
|
||||
case types.Idealfloat:
|
||||
case types.UntypedFloat:
|
||||
return types.Types[TFLOAT64]
|
||||
case types.Idealcomplex:
|
||||
case types.UntypedComplex:
|
||||
return types.Types[TCOMPLEX128]
|
||||
}
|
||||
|
||||
@ -1129,12 +1138,6 @@ func defaultType(t *types.Type) *types.Type {
|
||||
return nil
|
||||
}
|
||||
|
||||
// strlit returns the value of a literal string Node as a string.
|
||||
func strlit(n *Node) string {
|
||||
return n.Val().U.(string)
|
||||
}
|
||||
|
||||
// TODO(gri) smallintconst is only used in one place - can we used indexconst?
|
||||
func smallintconst(n *Node) bool {
|
||||
if n.Op == OLITERAL && Isconst(n, CTINT) && n.Type != nil {
|
||||
switch simtype[n.Type.Etype] {
|
||||
|
@ -283,7 +283,7 @@ func oldname(s *types.Sym) *Node {
|
||||
c.Name.Defn = n
|
||||
|
||||
// Link into list of active closure variables.
|
||||
// Popped from list in func closurebody.
|
||||
// Popped from list in func funcLit.
|
||||
c.Name.Param.Outer = n.Name.Param.Innermost
|
||||
n.Name.Param.Innermost = c
|
||||
|
||||
|
@ -34,7 +34,7 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
|
||||
|
||||
// Walk progs to build up the InlCalls data structure
|
||||
var prevpos src.XPos
|
||||
for p := fnsym.Func.Text; p != nil; p = p.Link {
|
||||
for p := fnsym.Func().Text; p != nil; p = p.Link {
|
||||
if p.Pos == prevpos {
|
||||
continue
|
||||
}
|
||||
@ -150,7 +150,7 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
|
||||
start := int64(-1)
|
||||
curii := -1
|
||||
var prevp *obj.Prog
|
||||
for p := fnsym.Func.Text; p != nil; prevp, p = p, p.Link {
|
||||
for p := fnsym.Func().Text; p != nil; prevp, p = p, p.Link {
|
||||
if prevp != nil && p.Pos == prevp.Pos {
|
||||
continue
|
||||
}
|
||||
|
273
src/cmd/compile/internal/gc/embed.go
Normal file
273
src/cmd/compile/internal/gc/embed.go
Normal file
@ -0,0 +1,273 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gc
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/syntax"
|
||||
"cmd/compile/internal/types"
|
||||
"cmd/internal/obj"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var embedlist []*Node
|
||||
|
||||
var embedCfg struct {
|
||||
Patterns map[string][]string
|
||||
Files map[string]string
|
||||
}
|
||||
|
||||
func readEmbedCfg(file string) {
|
||||
data, err := ioutil.ReadFile(file)
|
||||
if err != nil {
|
||||
log.Fatalf("-embedcfg: %v", err)
|
||||
}
|
||||
if err := json.Unmarshal(data, &embedCfg); err != nil {
|
||||
log.Fatalf("%s: %v", file, err)
|
||||
}
|
||||
if embedCfg.Patterns == nil {
|
||||
log.Fatalf("%s: invalid embedcfg: missing Patterns", file)
|
||||
}
|
||||
if embedCfg.Files == nil {
|
||||
log.Fatalf("%s: invalid embedcfg: missing Files", file)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
embedUnknown = iota
|
||||
embedBytes
|
||||
embedString
|
||||
embedFiles
|
||||
)
|
||||
|
||||
var numLocalEmbed int
|
||||
|
||||
func varEmbed(p *noder, names []*Node, typ *Node, exprs []*Node, embeds []PragmaEmbed) (newExprs []*Node) {
|
||||
haveEmbed := false
|
||||
for _, decl := range p.file.DeclList {
|
||||
imp, ok := decl.(*syntax.ImportDecl)
|
||||
if !ok {
|
||||
// imports always come first
|
||||
break
|
||||
}
|
||||
path, _ := strconv.Unquote(imp.Path.Value)
|
||||
if path == "embed" {
|
||||
haveEmbed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
pos := embeds[0].Pos
|
||||
if !haveEmbed {
|
||||
p.yyerrorpos(pos, "invalid go:embed: missing import \"embed\"")
|
||||
return exprs
|
||||
}
|
||||
if embedCfg.Patterns == nil {
|
||||
p.yyerrorpos(pos, "invalid go:embed: build system did not supply embed configuration")
|
||||
return exprs
|
||||
}
|
||||
if len(names) > 1 {
|
||||
p.yyerrorpos(pos, "go:embed cannot apply to multiple vars")
|
||||
return exprs
|
||||
}
|
||||
if len(exprs) > 0 {
|
||||
p.yyerrorpos(pos, "go:embed cannot apply to var with initializer")
|
||||
return exprs
|
||||
}
|
||||
if typ == nil {
|
||||
// Should not happen, since len(exprs) == 0 now.
|
||||
p.yyerrorpos(pos, "go:embed cannot apply to var without type")
|
||||
return exprs
|
||||
}
|
||||
|
||||
kind := embedKindApprox(typ)
|
||||
if kind == embedUnknown {
|
||||
p.yyerrorpos(pos, "go:embed cannot apply to var of type %v", typ)
|
||||
return exprs
|
||||
}
|
||||
|
||||
// Build list of files to store.
|
||||
have := make(map[string]bool)
|
||||
var list []string
|
||||
for _, e := range embeds {
|
||||
for _, pattern := range e.Patterns {
|
||||
files, ok := embedCfg.Patterns[pattern]
|
||||
if !ok {
|
||||
p.yyerrorpos(e.Pos, "invalid go:embed: build system did not map pattern: %s", pattern)
|
||||
}
|
||||
for _, file := range files {
|
||||
if embedCfg.Files[file] == "" {
|
||||
p.yyerrorpos(e.Pos, "invalid go:embed: build system did not map file: %s", file)
|
||||
continue
|
||||
}
|
||||
if !have[file] {
|
||||
have[file] = true
|
||||
list = append(list, file)
|
||||
}
|
||||
if kind == embedFiles {
|
||||
for dir := path.Dir(file); dir != "." && !have[dir]; dir = path.Dir(dir) {
|
||||
have[dir] = true
|
||||
list = append(list, dir+"/")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sort.Slice(list, func(i, j int) bool {
|
||||
return embedFileLess(list[i], list[j])
|
||||
})
|
||||
|
||||
if kind == embedString || kind == embedBytes {
|
||||
if len(list) > 1 {
|
||||
p.yyerrorpos(pos, "invalid go:embed: multiple files for type %v", typ)
|
||||
return exprs
|
||||
}
|
||||
}
|
||||
|
||||
v := names[0]
|
||||
if dclcontext != PEXTERN {
|
||||
numLocalEmbed++
|
||||
v = newnamel(v.Pos, lookupN("embed.", numLocalEmbed))
|
||||
v.Sym.Def = asTypesNode(v)
|
||||
v.Name.Param.Ntype = typ
|
||||
v.SetClass(PEXTERN)
|
||||
externdcl = append(externdcl, v)
|
||||
exprs = []*Node{v}
|
||||
}
|
||||
|
||||
v.Name.Param.SetEmbedFiles(list)
|
||||
embedlist = append(embedlist, v)
|
||||
return exprs
|
||||
}
|
||||
|
||||
// embedKindApprox determines the kind of embedding variable, approximately.
|
||||
// The match is approximate because we haven't done scope resolution yet and
|
||||
// can't tell whether "string" and "byte" really mean "string" and "byte".
|
||||
// The result must be confirmed later, after type checking, using embedKind.
|
||||
func embedKindApprox(typ *Node) int {
|
||||
if typ.Sym != nil && typ.Sym.Name == "FS" && (typ.Sym.Pkg.Path == "embed" || (typ.Sym.Pkg == localpkg && myimportpath == "embed")) {
|
||||
return embedFiles
|
||||
}
|
||||
// These are not guaranteed to match only string and []byte -
|
||||
// maybe the local package has redefined one of those words.
|
||||
// But it's the best we can do now during the noder.
|
||||
// The stricter check happens later, in initEmbed calling embedKind.
|
||||
if typ.Sym != nil && typ.Sym.Name == "string" && typ.Sym.Pkg == localpkg {
|
||||
return embedString
|
||||
}
|
||||
if typ.Op == OTARRAY && typ.Left == nil && typ.Right.Sym != nil && typ.Right.Sym.Name == "byte" && typ.Right.Sym.Pkg == localpkg {
|
||||
return embedBytes
|
||||
}
|
||||
return embedUnknown
|
||||
}
|
||||
|
||||
// embedKind determines the kind of embedding variable.
|
||||
func embedKind(typ *types.Type) int {
|
||||
if typ.Sym != nil && typ.Sym.Name == "FS" && (typ.Sym.Pkg.Path == "embed" || (typ.Sym.Pkg == localpkg && myimportpath == "embed")) {
|
||||
return embedFiles
|
||||
}
|
||||
if typ == types.Types[TSTRING] {
|
||||
return embedString
|
||||
}
|
||||
if typ.Sym == nil && typ.IsSlice() && typ.Elem() == types.Bytetype {
|
||||
return embedBytes
|
||||
}
|
||||
return embedUnknown
|
||||
}
|
||||
|
||||
func embedFileNameSplit(name string) (dir, elem string, isDir bool) {
|
||||
if name[len(name)-1] == '/' {
|
||||
isDir = true
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
i := len(name) - 1
|
||||
for i >= 0 && name[i] != '/' {
|
||||
i--
|
||||
}
|
||||
if i < 0 {
|
||||
return ".", name, isDir
|
||||
}
|
||||
return name[:i], name[i+1:], isDir
|
||||
}
|
||||
|
||||
// embedFileLess implements the sort order for a list of embedded files.
|
||||
// See the comment inside ../../../../embed/embed.go's Files struct for rationale.
|
||||
func embedFileLess(x, y string) bool {
|
||||
xdir, xelem, _ := embedFileNameSplit(x)
|
||||
ydir, yelem, _ := embedFileNameSplit(y)
|
||||
return xdir < ydir || xdir == ydir && xelem < yelem
|
||||
}
|
||||
|
||||
func dumpembeds() {
|
||||
for _, v := range embedlist {
|
||||
initEmbed(v)
|
||||
}
|
||||
}
|
||||
|
||||
// initEmbed emits the init data for a //go:embed variable,
|
||||
// which is either a string, a []byte, or an embed.FS.
|
||||
func initEmbed(v *Node) {
|
||||
files := v.Name.Param.EmbedFiles()
|
||||
switch kind := embedKind(v.Type); kind {
|
||||
case embedUnknown:
|
||||
yyerrorl(v.Pos, "go:embed cannot apply to var of type %v", v.Type)
|
||||
|
||||
case embedString, embedBytes:
|
||||
file := files[0]
|
||||
fsym, size, err := fileStringSym(v.Pos, embedCfg.Files[file], kind == embedString, nil)
|
||||
if err != nil {
|
||||
yyerrorl(v.Pos, "embed %s: %v", file, err)
|
||||
}
|
||||
sym := v.Sym.Linksym()
|
||||
off := 0
|
||||
off = dsymptr(sym, off, fsym, 0) // data string
|
||||
off = duintptr(sym, off, uint64(size)) // len
|
||||
if kind == embedBytes {
|
||||
duintptr(sym, off, uint64(size)) // cap for slice
|
||||
}
|
||||
|
||||
case embedFiles:
|
||||
slicedata := Ctxt.Lookup(`"".` + v.Sym.Name + `.files`)
|
||||
off := 0
|
||||
// []files pointed at by Files
|
||||
off = dsymptr(slicedata, off, slicedata, 3*Widthptr) // []file, pointing just past slice
|
||||
off = duintptr(slicedata, off, uint64(len(files)))
|
||||
off = duintptr(slicedata, off, uint64(len(files)))
|
||||
|
||||
// embed/embed.go type file is:
|
||||
// name string
|
||||
// data string
|
||||
// hash [16]byte
|
||||
// Emit one of these per file in the set.
|
||||
const hashSize = 16
|
||||
hash := make([]byte, hashSize)
|
||||
for _, file := range files {
|
||||
off = dsymptr(slicedata, off, stringsym(v.Pos, file), 0) // file string
|
||||
off = duintptr(slicedata, off, uint64(len(file)))
|
||||
if strings.HasSuffix(file, "/") {
|
||||
// entry for directory - no data
|
||||
off = duintptr(slicedata, off, 0)
|
||||
off = duintptr(slicedata, off, 0)
|
||||
off += hashSize
|
||||
} else {
|
||||
fsym, size, err := fileStringSym(v.Pos, embedCfg.Files[file], true, hash)
|
||||
if err != nil {
|
||||
yyerrorl(v.Pos, "embed %s: %v", file, err)
|
||||
}
|
||||
off = dsymptr(slicedata, off, fsym, 0) // data string
|
||||
off = duintptr(slicedata, off, uint64(size))
|
||||
off = int(slicedata.WriteBytes(Ctxt, int64(off), hash))
|
||||
}
|
||||
}
|
||||
ggloblsym(slicedata, int32(off), obj.RODATA|obj.LOCAL)
|
||||
sym := v.Sym.Linksym()
|
||||
dsymptr(sym, 0, slicedata, 0)
|
||||
}
|
||||
}
|
@ -169,36 +169,47 @@ func mayAffectMemory(n *Node) bool {
|
||||
}
|
||||
}
|
||||
|
||||
func mustHeapAlloc(n *Node) bool {
|
||||
// heapAllocReason returns the reason the given Node must be heap
|
||||
// allocated, or the empty string if it doesn't.
|
||||
func heapAllocReason(n *Node) string {
|
||||
if n.Type == nil {
|
||||
return false
|
||||
return ""
|
||||
}
|
||||
|
||||
// Parameters are always passed via the stack.
|
||||
if n.Op == ONAME && (n.Class() == PPARAM || n.Class() == PPARAMOUT) {
|
||||
return false
|
||||
return ""
|
||||
}
|
||||
|
||||
if n.Type.Width > maxStackVarSize {
|
||||
return true
|
||||
return "too large for stack"
|
||||
}
|
||||
|
||||
if (n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= maxImplicitStackVarSize {
|
||||
return true
|
||||
return "too large for stack"
|
||||
}
|
||||
|
||||
if n.Op == OCLOSURE && closureType(n).Size() >= maxImplicitStackVarSize {
|
||||
return true
|
||||
return "too large for stack"
|
||||
}
|
||||
if n.Op == OCALLPART && partialCallType(n).Size() >= maxImplicitStackVarSize {
|
||||
return true
|
||||
return "too large for stack"
|
||||
}
|
||||
|
||||
if n.Op == OMAKESLICE && !isSmallMakeSlice(n) {
|
||||
return true
|
||||
if n.Op == OMAKESLICE {
|
||||
r := n.Right
|
||||
if r == nil {
|
||||
r = n.Left
|
||||
}
|
||||
if !smallintconst(r) {
|
||||
return "non-constant size"
|
||||
}
|
||||
if t := n.Type; t.Elem().Width != 0 && r.Int64Val() >= maxImplicitStackVarSize/t.Elem().Width {
|
||||
return "too large for stack"
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return ""
|
||||
}
|
||||
|
||||
// addrescapes tags node n as having had its address taken
|
||||
@ -271,7 +282,7 @@ func addrescapes(n *Node) {
|
||||
|
||||
// moveToHeap records the parameter or local variable n as moved to the heap.
|
||||
func moveToHeap(n *Node) {
|
||||
if Debug['r'] != 0 {
|
||||
if Debug.r != 0 {
|
||||
Dump("MOVE", n)
|
||||
}
|
||||
if compiling_runtime {
|
||||
@ -348,7 +359,7 @@ func moveToHeap(n *Node) {
|
||||
n.Xoffset = 0
|
||||
n.Name.Param.Heapaddr = heapaddr
|
||||
n.Esc = EscHeap
|
||||
if Debug['m'] != 0 {
|
||||
if Debug.m != 0 {
|
||||
Warnl(n.Pos, "moved to heap: %v", n)
|
||||
}
|
||||
}
|
||||
@ -378,7 +389,7 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
|
||||
// but we are reusing the ability to annotate an individual function
|
||||
// argument and pass those annotations along to importing code.
|
||||
if f.Type.IsUintptr() {
|
||||
if Debug['m'] != 0 {
|
||||
if Debug.m != 0 {
|
||||
Warnl(f.Pos, "assuming %v is unsafe uintptr", name())
|
||||
}
|
||||
return unsafeUintptrTag
|
||||
@ -393,11 +404,11 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
|
||||
// External functions are assumed unsafe, unless
|
||||
// //go:noescape is given before the declaration.
|
||||
if fn.Func.Pragma&Noescape != 0 {
|
||||
if Debug['m'] != 0 && f.Sym != nil {
|
||||
if Debug.m != 0 && f.Sym != nil {
|
||||
Warnl(f.Pos, "%v does not escape", name())
|
||||
}
|
||||
} else {
|
||||
if Debug['m'] != 0 && f.Sym != nil {
|
||||
if Debug.m != 0 && f.Sym != nil {
|
||||
Warnl(f.Pos, "leaking param: %v", name())
|
||||
}
|
||||
esc.AddHeap(0)
|
||||
@ -408,14 +419,14 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
|
||||
|
||||
if fn.Func.Pragma&UintptrEscapes != 0 {
|
||||
if f.Type.IsUintptr() {
|
||||
if Debug['m'] != 0 {
|
||||
if Debug.m != 0 {
|
||||
Warnl(f.Pos, "marking %v as escaping uintptr", name())
|
||||
}
|
||||
return uintptrEscapesTag
|
||||
}
|
||||
if f.IsDDD() && f.Type.Elem().IsUintptr() {
|
||||
// final argument is ...uintptr.
|
||||
if Debug['m'] != 0 {
|
||||
if Debug.m != 0 {
|
||||
Warnl(f.Pos, "marking %v as escaping ...uintptr", name())
|
||||
}
|
||||
return uintptrEscapesTag
|
||||
@ -437,7 +448,7 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
|
||||
esc := loc.paramEsc
|
||||
esc.Optimize()
|
||||
|
||||
if Debug['m'] != 0 && !loc.escapes {
|
||||
if Debug.m != 0 && !loc.escapes {
|
||||
if esc.Empty() {
|
||||
Warnl(f.Pos, "%v does not escape", name())
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ func (e *Escape) initFunc(fn *Node) {
|
||||
Fatalf("unexpected node: %v", fn)
|
||||
}
|
||||
fn.Esc = EscFuncPlanned
|
||||
if Debug['m'] > 3 {
|
||||
if Debug.m > 3 {
|
||||
Dump("escAnalyze", fn)
|
||||
}
|
||||
|
||||
@ -247,7 +247,7 @@ func (e *Escape) stmt(n *Node) {
|
||||
lineno = lno
|
||||
}()
|
||||
|
||||
if Debug['m'] > 2 {
|
||||
if Debug.m > 2 {
|
||||
fmt.Printf("%v:[%d] %v stmt: %v\n", linestr(lineno), e.loopDepth, funcSym(e.curfn), n)
|
||||
}
|
||||
|
||||
@ -275,11 +275,11 @@ func (e *Escape) stmt(n *Node) {
|
||||
case OLABEL:
|
||||
switch asNode(n.Sym.Label) {
|
||||
case &nonlooping:
|
||||
if Debug['m'] > 2 {
|
||||
if Debug.m > 2 {
|
||||
fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n)
|
||||
}
|
||||
case &looping:
|
||||
if Debug['m'] > 2 {
|
||||
if Debug.m > 2 {
|
||||
fmt.Printf("%v: %v looping label\n", linestr(lineno), n)
|
||||
}
|
||||
e.loopDepth++
|
||||
@ -717,7 +717,7 @@ func (e *Escape) addrs(l Nodes) []EscHole {
|
||||
func (e *Escape) assign(dst, src *Node, why string, where *Node) {
|
||||
// Filter out some no-op assignments for escape analysis.
|
||||
ignore := dst != nil && src != nil && isSelfAssign(dst, src)
|
||||
if ignore && Debug['m'] != 0 {
|
||||
if ignore && Debug.m != 0 {
|
||||
Warnl(where.Pos, "%v ignoring self-assignment in %S", funcSym(e.curfn), where)
|
||||
}
|
||||
|
||||
@ -771,10 +771,11 @@ func (e *Escape) call(ks []EscHole, call, where *Node) {
|
||||
var fn *Node
|
||||
switch call.Op {
|
||||
case OCALLFUNC:
|
||||
if call.Left.Op == ONAME && call.Left.Class() == PFUNC {
|
||||
fn = call.Left
|
||||
} else if call.Left.Op == OCLOSURE {
|
||||
fn = call.Left.Func.Closure.Func.Nname
|
||||
switch v := staticValue(call.Left); {
|
||||
case v.Op == ONAME && v.Class() == PFUNC:
|
||||
fn = v
|
||||
case v.Op == OCLOSURE:
|
||||
fn = v.Func.Closure.Func.Nname
|
||||
}
|
||||
case OCALLMETH:
|
||||
fn = asNode(call.Left.Type.FuncType().Nname)
|
||||
@ -930,7 +931,7 @@ func (k EscHole) note(where *Node, why string) EscHole {
|
||||
if where == nil || why == "" {
|
||||
Fatalf("note: missing where/why")
|
||||
}
|
||||
if Debug['m'] >= 2 || logopt.Enabled() {
|
||||
if Debug.m >= 2 || logopt.Enabled() {
|
||||
k.notes = &EscNote{
|
||||
next: k.notes,
|
||||
where: where,
|
||||
@ -1051,11 +1052,7 @@ func (e *Escape) newLoc(n *Node, transient bool) *EscLocation {
|
||||
}
|
||||
n.SetOpt(loc)
|
||||
|
||||
if mustHeapAlloc(n) {
|
||||
why := "too large for stack"
|
||||
if n.Op == OMAKESLICE && (!Isconst(n.Left, CTINT) || (n.Right != nil && !Isconst(n.Right, CTINT))) {
|
||||
why = "non-constant size"
|
||||
}
|
||||
if why := heapAllocReason(n); why != "" {
|
||||
e.flow(e.heapHole().addr(n, why), loc)
|
||||
}
|
||||
}
|
||||
@ -1080,9 +1077,9 @@ func (e *Escape) flow(k EscHole, src *EscLocation) {
|
||||
return
|
||||
}
|
||||
if dst.escapes && k.derefs < 0 { // dst = &src
|
||||
if Debug['m'] >= 2 || logopt.Enabled() {
|
||||
if Debug.m >= 2 || logopt.Enabled() {
|
||||
pos := linestr(src.n.Pos)
|
||||
if Debug['m'] >= 2 {
|
||||
if Debug.m >= 2 {
|
||||
fmt.Printf("%s: %v escapes to heap:\n", pos, src.n)
|
||||
}
|
||||
explanation := e.explainFlow(pos, dst, src, k.derefs, k.notes, []*logopt.LoggedOpt{})
|
||||
@ -1182,8 +1179,8 @@ func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLoc
|
||||
// that value flow for tagging the function
|
||||
// later.
|
||||
if l.isName(PPARAM) {
|
||||
if (logopt.Enabled() || Debug['m'] >= 2) && !l.escapes {
|
||||
if Debug['m'] >= 2 {
|
||||
if (logopt.Enabled() || Debug.m >= 2) && !l.escapes {
|
||||
if Debug.m >= 2 {
|
||||
fmt.Printf("%s: parameter %v leaks to %s with derefs=%d:\n", linestr(l.n.Pos), l.n, e.explainLoc(root), base)
|
||||
}
|
||||
explanation := e.explainPath(root, l)
|
||||
@ -1199,8 +1196,8 @@ func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLoc
|
||||
// outlives it, then l needs to be heap
|
||||
// allocated.
|
||||
if addressOf && !l.escapes {
|
||||
if logopt.Enabled() || Debug['m'] >= 2 {
|
||||
if Debug['m'] >= 2 {
|
||||
if logopt.Enabled() || Debug.m >= 2 {
|
||||
if Debug.m >= 2 {
|
||||
fmt.Printf("%s: %v escapes to heap:\n", linestr(l.n.Pos), l.n)
|
||||
}
|
||||
explanation := e.explainPath(root, l)
|
||||
@ -1238,7 +1235,7 @@ func (e *Escape) explainPath(root, src *EscLocation) []*logopt.LoggedOpt {
|
||||
for {
|
||||
// Prevent infinite loop.
|
||||
if visited[src] {
|
||||
if Debug['m'] >= 2 {
|
||||
if Debug.m >= 2 {
|
||||
fmt.Printf("%s: warning: truncated explanation due to assignment cycle; see golang.org/issue/35518\n", pos)
|
||||
}
|
||||
break
|
||||
@ -1266,7 +1263,7 @@ func (e *Escape) explainFlow(pos string, dst, srcloc *EscLocation, derefs int, n
|
||||
if derefs >= 0 {
|
||||
ops = strings.Repeat("*", derefs)
|
||||
}
|
||||
print := Debug['m'] >= 2
|
||||
print := Debug.m >= 2
|
||||
|
||||
flow := fmt.Sprintf(" flow: %s = %s%v:", e.explainLoc(dst), ops, e.explainLoc(srcloc))
|
||||
if print {
|
||||
@ -1420,7 +1417,7 @@ func (e *Escape) finish(fns []*Node) {
|
||||
|
||||
if loc.escapes {
|
||||
if n.Op != ONAME {
|
||||
if Debug['m'] != 0 {
|
||||
if Debug.m != 0 {
|
||||
Warnl(n.Pos, "%S escapes to heap", n)
|
||||
}
|
||||
if logopt.Enabled() {
|
||||
@ -1430,7 +1427,7 @@ func (e *Escape) finish(fns []*Node) {
|
||||
n.Esc = EscHeap
|
||||
addrescapes(n)
|
||||
} else {
|
||||
if Debug['m'] != 0 && n.Op != ONAME {
|
||||
if Debug.m != 0 && n.Op != ONAME {
|
||||
Warnl(n.Pos, "%S does not escape", n)
|
||||
}
|
||||
n.Esc = EscNone
|
||||
|
@ -31,7 +31,7 @@ func exportsym(n *Node) {
|
||||
}
|
||||
n.Sym.SetOnExportList(true)
|
||||
|
||||
if Debug['E'] != 0 {
|
||||
if Debug.E != 0 {
|
||||
fmt.Printf("export symbol %v\n", n.Sym)
|
||||
}
|
||||
|
||||
@ -96,7 +96,7 @@ func importsym(ipkg *types.Pkg, s *types.Sym, op Op) *Node {
|
||||
return n
|
||||
}
|
||||
|
||||
// pkgtype returns the named type declared by symbol s.
|
||||
// importtype returns the named type declared by symbol s.
|
||||
// If no such type has been declared yet, a forward declaration is returned.
|
||||
// ipkg is the package being imported
|
||||
func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *types.Type {
|
||||
@ -150,7 +150,7 @@ func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val
|
||||
|
||||
n.SetVal(val)
|
||||
|
||||
if Debug['E'] != 0 {
|
||||
if Debug.E != 0 {
|
||||
fmt.Printf("import const %v %L = %v\n", s, t, val)
|
||||
}
|
||||
}
|
||||
@ -166,7 +166,7 @@ func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
|
||||
n.Func = new(Func)
|
||||
t.SetNname(asTypesNode(n))
|
||||
|
||||
if Debug['E'] != 0 {
|
||||
if Debug.E != 0 {
|
||||
fmt.Printf("import func %v%S\n", s, t)
|
||||
}
|
||||
}
|
||||
@ -179,7 +179,7 @@ func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
|
||||
return
|
||||
}
|
||||
|
||||
if Debug['E'] != 0 {
|
||||
if Debug.E != 0 {
|
||||
fmt.Printf("import var %v %L\n", s, t)
|
||||
}
|
||||
}
|
||||
@ -192,7 +192,7 @@ func importalias(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) {
|
||||
return
|
||||
}
|
||||
|
||||
if Debug['E'] != 0 {
|
||||
if Debug.E != 0 {
|
||||
fmt.Printf("import type %v = %L\n", s, t)
|
||||
}
|
||||
}
|
||||
|
@ -6,17 +6,9 @@ package gc
|
||||
|
||||
import (
|
||||
"math"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// For GO386=387, make sure fucomi* opcodes are not used
|
||||
// for comparison operations.
|
||||
// Note that this test will fail only on a Pentium MMX
|
||||
// processor (with GOARCH=386 GO386=387), as it just runs
|
||||
// some code and looks for an unimplemented instruction fault.
|
||||
|
||||
//go:noinline
|
||||
func compare1(a, b float64) bool {
|
||||
return a < b
|
||||
@ -137,9 +129,6 @@ func TestFloatCompareFolded(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// For GO386=387, make sure fucomi* opcodes are not used
|
||||
// for float->int conversions.
|
||||
|
||||
//go:noinline
|
||||
func cvt1(a float64) uint64 {
|
||||
return uint64(a)
|
||||
@ -370,14 +359,6 @@ func TestFloat32StoreToLoadConstantFold(t *testing.T) {
|
||||
// are not converted to quiet NaN (qNaN) values during compilation.
|
||||
// See issue #27193 for more information.
|
||||
|
||||
// TODO: this method for detecting 387 won't work if the compiler has been
|
||||
// built using GOARCH=386 GO386=387 and either the target is a different
|
||||
// architecture or the GO386=387 environment variable is not set when the
|
||||
// test is run.
|
||||
if runtime.GOARCH == "386" && os.Getenv("GO386") == "387" {
|
||||
t.Skip("signaling NaNs are not propagated on 387 (issue #27516)")
|
||||
}
|
||||
|
||||
// signaling NaNs
|
||||
{
|
||||
const nan = uint32(0x7f800001) // sNaN
|
||||
|
@ -773,17 +773,17 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
|
||||
if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
|
||||
var name string
|
||||
switch t {
|
||||
case types.Idealbool:
|
||||
case types.UntypedBool:
|
||||
name = "untyped bool"
|
||||
case types.Idealstring:
|
||||
case types.UntypedString:
|
||||
name = "untyped string"
|
||||
case types.Idealint:
|
||||
case types.UntypedInt:
|
||||
name = "untyped int"
|
||||
case types.Idealrune:
|
||||
case types.UntypedRune:
|
||||
name = "untyped rune"
|
||||
case types.Idealfloat:
|
||||
case types.UntypedFloat:
|
||||
name = "untyped float"
|
||||
case types.Idealcomplex:
|
||||
case types.UntypedComplex:
|
||||
name = "untyped complex"
|
||||
default:
|
||||
name = basicnames[t.Etype]
|
||||
@ -792,6 +792,13 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
|
||||
return
|
||||
}
|
||||
|
||||
if mode == FDbg {
|
||||
b.WriteString(t.Etype.String())
|
||||
b.WriteByte('-')
|
||||
tconv2(b, t, flag, FErr, visited)
|
||||
return
|
||||
}
|
||||
|
||||
// At this point, we might call tconv2 recursively. Add the current type to the visited list so we don't
|
||||
// try to print it recursively.
|
||||
// We record the offset in the result buffer where the type's text starts. This offset serves as a reference
|
||||
@ -805,12 +812,6 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
|
||||
visited[t] = b.Len()
|
||||
defer delete(visited, t)
|
||||
|
||||
if mode == FDbg {
|
||||
b.WriteString(t.Etype.String())
|
||||
b.WriteByte('-')
|
||||
tconv2(b, t, flag, FErr, visited)
|
||||
return
|
||||
}
|
||||
switch t.Etype {
|
||||
case TPTR:
|
||||
b.WriteByte('*')
|
||||
@ -1333,7 +1334,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
|
||||
n.Orig.exprfmt(s, prec, mode)
|
||||
return
|
||||
}
|
||||
if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && n.Type != types.Idealbool && n.Type != types.Idealstring {
|
||||
if n.Type != nil && !n.Type.IsUntyped() {
|
||||
// Need parens when type begins with what might
|
||||
// be misinterpreted as a unary operator: * or <-.
|
||||
if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == types.Crecv) {
|
||||
|
@ -61,12 +61,12 @@ type Class uint8
|
||||
//go:generate stringer -type=Class
|
||||
const (
|
||||
Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
|
||||
PEXTERN // global variable
|
||||
PEXTERN // global variables
|
||||
PAUTO // local variables
|
||||
PAUTOHEAP // local variable or parameter moved to heap
|
||||
PAUTOHEAP // local variables or parameters moved to heap
|
||||
PPARAM // input arguments
|
||||
PPARAMOUT // output results
|
||||
PFUNC // global function
|
||||
PFUNC // global functions
|
||||
|
||||
// Careful: Class is stored in three bits in Node.flags.
|
||||
_ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
|
||||
@ -116,7 +116,15 @@ var decldepth int32
|
||||
|
||||
var nolocalimports bool
|
||||
|
||||
var Debug [256]int
|
||||
// gc debug flags
|
||||
type DebugFlags struct {
|
||||
P, B, C, E,
|
||||
K, L, N, S,
|
||||
W, e, h, j,
|
||||
l, m, r, w int
|
||||
}
|
||||
|
||||
var Debug DebugFlags
|
||||
|
||||
var debugstr string
|
||||
|
||||
@ -259,7 +267,6 @@ type Arch struct {
|
||||
|
||||
REGSP int
|
||||
MAXWIDTH int64
|
||||
Use387 bool // should 386 backend use 387 FP instructions instead of sse2.
|
||||
SoftFloat bool
|
||||
|
||||
PadFrame func(int64) int64
|
||||
@ -328,10 +335,6 @@ var (
|
||||
BoundsCheckFunc [ssa.BoundsKindCount]*obj.LSym
|
||||
ExtendCheckFunc [ssa.BoundsKindCount]*obj.LSym
|
||||
|
||||
// GO386=387
|
||||
ControlWord64trunc,
|
||||
ControlWord32 *obj.LSym
|
||||
|
||||
// Wasm
|
||||
WasmMove,
|
||||
WasmZero,
|
||||
|
@ -153,7 +153,7 @@ func (pp *Progs) Prog(as obj.As) *obj.Prog {
|
||||
pp.clearp(pp.next)
|
||||
p.Link = pp.next
|
||||
|
||||
if !pp.pos.IsKnown() && Debug['K'] != 0 {
|
||||
if !pp.pos.IsKnown() && Debug.K != 0 {
|
||||
Warn("prog: unknown position (line 0)")
|
||||
}
|
||||
|
||||
@ -199,7 +199,7 @@ func (pp *Progs) settext(fn *Node) {
|
||||
ptxt := pp.Prog(obj.ATEXT)
|
||||
pp.Text = ptxt
|
||||
|
||||
fn.Func.lsym.Func.Text = ptxt
|
||||
fn.Func.lsym.Func().Text = ptxt
|
||||
ptxt.From.Type = obj.TYPE_MEM
|
||||
ptxt.From.Name = obj.NAME_EXTERN
|
||||
ptxt.From.Sym = fn.Func.lsym
|
||||
|
@ -751,11 +751,11 @@ func (w *exportWriter) param(f *types.Field) {
|
||||
|
||||
func constTypeOf(typ *types.Type) Ctype {
|
||||
switch typ {
|
||||
case types.Idealint, types.Idealrune:
|
||||
case types.UntypedInt, types.UntypedRune:
|
||||
return CTINT
|
||||
case types.Idealfloat:
|
||||
case types.UntypedFloat:
|
||||
return CTFLT
|
||||
case types.Idealcomplex:
|
||||
case types.UntypedComplex:
|
||||
return CTCPLX
|
||||
}
|
||||
|
||||
@ -780,8 +780,8 @@ func constTypeOf(typ *types.Type) Ctype {
|
||||
}
|
||||
|
||||
func (w *exportWriter) value(typ *types.Type, v Val) {
|
||||
if typ.IsUntyped() {
|
||||
typ = untype(v.Ctype())
|
||||
if vt := idealType(v.Ctype()); typ.IsUntyped() && typ != vt {
|
||||
Fatalf("exporter: untyped type mismatch, have: %v, want: %v", typ, vt)
|
||||
}
|
||||
w.typ(typ)
|
||||
|
||||
@ -1017,6 +1017,8 @@ func (w *exportWriter) symIdx(s *types.Sym) {
|
||||
}
|
||||
|
||||
func (w *exportWriter) typeExt(t *types.Type) {
|
||||
// Export whether this type is marked notinheap.
|
||||
w.bool(t.NotInHeap())
|
||||
// For type T, export the index of type descriptor symbols of T and *T.
|
||||
if i, ok := typeSymIdx[t]; ok {
|
||||
w.int64(i[0])
|
||||
@ -1264,8 +1266,13 @@ func (w *exportWriter) expr(n *Node) {
|
||||
// case OSTRUCTKEY:
|
||||
// unreachable - handled in case OSTRUCTLIT by elemList
|
||||
|
||||
// case OCALLPART:
|
||||
// unimplemented - handled by default case
|
||||
case OCALLPART:
|
||||
// An OCALLPART is an OXDOT before type checking.
|
||||
w.op(OXDOT)
|
||||
w.pos(n.Pos)
|
||||
w.expr(n.Left)
|
||||
// Right node should be ONAME
|
||||
w.selector(n.Right.Sym)
|
||||
|
||||
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
||||
w.op(OXDOT)
|
||||
|
@ -375,7 +375,7 @@ func (p *importReader) value() (typ *types.Type, v Val) {
|
||||
v.U = p.string()
|
||||
case CTINT:
|
||||
x := new(Mpint)
|
||||
x.Rune = typ == types.Idealrune
|
||||
x.Rune = typ == types.UntypedRune
|
||||
p.mpint(&x.Val, typ)
|
||||
v.U = x
|
||||
case CTFLT:
|
||||
@ -596,7 +596,6 @@ func (r *importReader) typ1() *types.Type {
|
||||
|
||||
// Ensure we expand the interface in the frontend (#25055).
|
||||
checkwidth(t)
|
||||
|
||||
return t
|
||||
}
|
||||
}
|
||||
@ -711,6 +710,7 @@ func (r *importReader) symIdx(s *types.Sym) {
|
||||
}
|
||||
|
||||
func (r *importReader) typeExt(t *types.Type) {
|
||||
t.SetNotInHeap(r.bool())
|
||||
i, pi := r.int64(), r.int64()
|
||||
if i != -1 && pi != -1 {
|
||||
typeSymIdx[t] = [2]int64{i, pi}
|
||||
@ -742,8 +742,8 @@ func (r *importReader) doInline(n *Node) {
|
||||
|
||||
importlist = append(importlist, n)
|
||||
|
||||
if Debug['E'] > 0 && Debug['m'] > 2 {
|
||||
if Debug['m'] > 3 {
|
||||
if Debug.E > 0 && Debug.m > 2 {
|
||||
if Debug.m > 3 {
|
||||
fmt.Printf("inl body for %v %#v: %+v\n", n, n.Type, asNodes(n.Func.Inl.Body))
|
||||
} else {
|
||||
fmt.Printf("inl body for %v %#v: %v\n", n, n.Type, asNodes(n.Func.Inl.Body))
|
||||
@ -866,7 +866,7 @@ func (r *importReader) node() *Node {
|
||||
// unreachable - handled in case OSTRUCTLIT by elemList
|
||||
|
||||
// case OCALLPART:
|
||||
// unimplemented
|
||||
// unreachable - mapped to case OXDOT below by exporter
|
||||
|
||||
// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
||||
// unreachable - mapped to case OXDOT below by exporter
|
||||
|
@ -7,7 +7,7 @@
|
||||
// saves a copy of the body. Then inlcalls walks each function body to
|
||||
// expand calls to inlinable functions.
|
||||
//
|
||||
// The debug['l'] flag controls the aggressiveness. Note that main() swaps level 0 and 1,
|
||||
// The Debug.l flag controls the aggressiveness. Note that main() swaps level 0 and 1,
|
||||
// making 1 the default and -l disable. Additional levels (beyond -l) may be buggy and
|
||||
// are not supported.
|
||||
// 0: disabled
|
||||
@ -21,7 +21,7 @@
|
||||
// The -d typcheckinl flag enables early typechecking of all imported bodies,
|
||||
// which is useful to flush out bugs.
|
||||
//
|
||||
// The debug['m'] flag enables diagnostic output. a single -m is useful for verifying
|
||||
// The Debug.m flag enables diagnostic output. a single -m is useful for verifying
|
||||
// which calls get inlined or not, more is for debugging, and may go away at any point.
|
||||
|
||||
package gc
|
||||
@ -85,7 +85,7 @@ func typecheckinl(fn *Node) {
|
||||
return // typecheckinl on local function
|
||||
}
|
||||
|
||||
if Debug['m'] > 2 || Debug_export != 0 {
|
||||
if Debug.m > 2 || Debug_export != 0 {
|
||||
fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, asNodes(fn.Func.Inl.Body))
|
||||
}
|
||||
|
||||
@ -116,10 +116,10 @@ func caninl(fn *Node) {
|
||||
}
|
||||
|
||||
var reason string // reason, if any, that the function was not inlined
|
||||
if Debug['m'] > 1 || logopt.Enabled() {
|
||||
if Debug.m > 1 || logopt.Enabled() {
|
||||
defer func() {
|
||||
if reason != "" {
|
||||
if Debug['m'] > 1 {
|
||||
if Debug.m > 1 {
|
||||
fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
|
||||
}
|
||||
if logopt.Enabled() {
|
||||
@ -187,7 +187,7 @@ func caninl(fn *Node) {
|
||||
defer n.Func.SetInlinabilityChecked(true)
|
||||
|
||||
cc := int32(inlineExtraCallCost)
|
||||
if Debug['l'] == 4 {
|
||||
if Debug.l == 4 {
|
||||
cc = 1 // this appears to yield better performance than 0.
|
||||
}
|
||||
|
||||
@ -224,9 +224,9 @@ func caninl(fn *Node) {
|
||||
// this is so export can find the body of a method
|
||||
fn.Type.FuncType().Nname = asTypesNode(n)
|
||||
|
||||
if Debug['m'] > 1 {
|
||||
if Debug.m > 1 {
|
||||
fmt.Printf("%v: can inline %#v with cost %d as: %#v { %#v }\n", fn.Line(), n, inlineMaxBudget-visitor.budget, fn.Type, asNodes(n.Func.Inl.Body))
|
||||
} else if Debug['m'] != 0 {
|
||||
} else if Debug.m != 0 {
|
||||
fmt.Printf("%v: can inline %v\n", fn.Line(), n)
|
||||
}
|
||||
if logopt.Enabled() {
|
||||
@ -325,18 +325,10 @@ func (v *hairyVisitor) visit(n *Node) bool {
|
||||
break
|
||||
}
|
||||
|
||||
if fn := n.Left.Func; fn != nil && fn.Inl != nil {
|
||||
v.budget -= fn.Inl.Cost
|
||||
if fn := inlCallee(n.Left); fn != nil && fn.Func.Inl != nil {
|
||||
v.budget -= fn.Func.Inl.Cost
|
||||
break
|
||||
}
|
||||
if n.Left.isMethodExpression() {
|
||||
if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl != nil {
|
||||
v.budget -= d.Func.Inl.Cost
|
||||
break
|
||||
}
|
||||
}
|
||||
// TODO(mdempsky): Budget for OCLOSURE calls if we
|
||||
// ever allow that. See #15561 and #23093.
|
||||
|
||||
// Call cost for non-leaf inlining.
|
||||
v.budget -= v.extraCallCost
|
||||
@ -382,17 +374,16 @@ func (v *hairyVisitor) visit(n *Node) bool {
|
||||
v.reason = "call to recover"
|
||||
return true
|
||||
|
||||
case OCALLPART:
|
||||
// OCALLPART is inlineable, but no extra cost to the budget
|
||||
|
||||
case OCLOSURE,
|
||||
OCALLPART,
|
||||
ORANGE,
|
||||
OFOR,
|
||||
OFORUNTIL,
|
||||
OSELECT,
|
||||
OTYPESW,
|
||||
OGO,
|
||||
ODEFER,
|
||||
ODCLTYPE, // can't print yet
|
||||
OBREAK,
|
||||
ORETJMP:
|
||||
v.reason = "unhandled op " + n.Op.String()
|
||||
return true
|
||||
@ -400,10 +391,23 @@ func (v *hairyVisitor) visit(n *Node) bool {
|
||||
case OAPPEND:
|
||||
v.budget -= inlineExtraAppendCost
|
||||
|
||||
case ODCLCONST, OEMPTY, OFALL, OLABEL:
|
||||
case ODCLCONST, OEMPTY, OFALL:
|
||||
// These nodes don't produce code; omit from inlining budget.
|
||||
return false
|
||||
|
||||
case OLABEL:
|
||||
// TODO(mdempsky): Add support for inlining labeled control statements.
|
||||
if n.labeledControl() != nil {
|
||||
v.reason = "labeled control"
|
||||
return true
|
||||
}
|
||||
|
||||
case OBREAK, OCONTINUE:
|
||||
if n.Sym != nil {
|
||||
// Should have short-circuited due to labeledControl above.
|
||||
Fatalf("unexpected labeled break/continue: %v", n)
|
||||
}
|
||||
|
||||
case OIF:
|
||||
if Isconst(n.Left, CTBOOL) {
|
||||
// This if and the condition cost nothing.
|
||||
@ -421,7 +425,7 @@ func (v *hairyVisitor) visit(n *Node) bool {
|
||||
v.budget--
|
||||
|
||||
// When debugging, don't stop early, to get full cost of inlining this function
|
||||
if v.budget < 0 && Debug['m'] < 2 && !logopt.Enabled() {
|
||||
if v.budget < 0 && Debug.m < 2 && !logopt.Enabled() {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -452,7 +456,7 @@ func inlcopy(n *Node) *Node {
|
||||
}
|
||||
|
||||
m := n.copy()
|
||||
if m.Func != nil {
|
||||
if n.Op != OCALLPART && m.Func != nil {
|
||||
Fatalf("unexpected Func: %v", m)
|
||||
}
|
||||
m.Left = inlcopy(n.Left)
|
||||
@ -666,60 +670,18 @@ func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
|
||||
switch n.Op {
|
||||
case OCALLFUNC:
|
||||
if Debug['m'] > 3 {
|
||||
if Debug.m > 3 {
|
||||
fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
|
||||
}
|
||||
if n.Left.Func != nil && n.Left.Func.Inl != nil && !isIntrinsicCall(n) { // normal case
|
||||
n = mkinlcall(n, n.Left, maxCost, inlMap)
|
||||
} else if n.Left.isMethodExpression() && asNode(n.Left.Sym.Def) != nil {
|
||||
n = mkinlcall(n, asNode(n.Left.Sym.Def), maxCost, inlMap)
|
||||
} else if n.Left.Op == OCLOSURE {
|
||||
if f := inlinableClosure(n.Left); f != nil {
|
||||
n = mkinlcall(n, f, maxCost, inlMap)
|
||||
}
|
||||
} else if n.Left.Op == ONAME && n.Left.Name != nil && n.Left.Name.Defn != nil {
|
||||
if d := n.Left.Name.Defn; d.Op == OAS && d.Right.Op == OCLOSURE {
|
||||
if f := inlinableClosure(d.Right); f != nil {
|
||||
// NB: this check is necessary to prevent indirect re-assignment of the variable
|
||||
// having the address taken after the invocation or only used for reads is actually fine
|
||||
// but we have no easy way to distinguish the safe cases
|
||||
if d.Left.Name.Addrtaken() {
|
||||
if Debug['m'] > 1 {
|
||||
fmt.Printf("%v: cannot inline escaping closure variable %v\n", n.Line(), n.Left)
|
||||
}
|
||||
if logopt.Enabled() {
|
||||
logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
|
||||
fmt.Sprintf("%v cannot be inlined (escaping closure variable)", n.Left))
|
||||
}
|
||||
if isIntrinsicCall(n) {
|
||||
break
|
||||
}
|
||||
|
||||
// ensure the variable is never re-assigned
|
||||
if unsafe, a := reassigned(n.Left); unsafe {
|
||||
if Debug['m'] > 1 {
|
||||
if a != nil {
|
||||
fmt.Printf("%v: cannot inline re-assigned closure variable at %v: %v\n", n.Line(), a.Line(), a)
|
||||
if logopt.Enabled() {
|
||||
logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
|
||||
fmt.Sprintf("%v cannot be inlined (re-assigned closure variable)", a))
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("%v: cannot inline global closure variable %v\n", n.Line(), n.Left)
|
||||
if logopt.Enabled() {
|
||||
logopt.LogOpt(n.Pos, "cannotInlineCall", "inline", Curfn.funcname(),
|
||||
fmt.Sprintf("%v cannot be inlined (global closure variable)", n.Left))
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
n = mkinlcall(n, f, maxCost, inlMap)
|
||||
}
|
||||
}
|
||||
if fn := inlCallee(n.Left); fn != nil && fn.Func.Inl != nil {
|
||||
n = mkinlcall(n, fn, maxCost, inlMap)
|
||||
}
|
||||
|
||||
case OCALLMETH:
|
||||
if Debug['m'] > 3 {
|
||||
if Debug.m > 3 {
|
||||
fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right)
|
||||
}
|
||||
|
||||
@ -739,16 +701,73 @@ func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
return n
|
||||
}
|
||||
|
||||
// inlinableClosure takes an OCLOSURE node and follows linkage to the matching ONAME with
|
||||
// the inlinable body. Returns nil if the function is not inlinable.
|
||||
func inlinableClosure(n *Node) *Node {
|
||||
c := n.Func.Closure
|
||||
// inlCallee takes a function-typed expression and returns the underlying function ONAME
|
||||
// that it refers to if statically known. Otherwise, it returns nil.
|
||||
func inlCallee(fn *Node) *Node {
|
||||
fn = staticValue(fn)
|
||||
switch {
|
||||
case fn.Op == ONAME && fn.Class() == PFUNC:
|
||||
if fn.isMethodExpression() {
|
||||
return asNode(fn.Sym.Def)
|
||||
}
|
||||
return fn
|
||||
case fn.Op == OCLOSURE:
|
||||
c := fn.Func.Closure
|
||||
caninl(c)
|
||||
f := c.Func.Nname
|
||||
if f == nil || f.Func.Inl == nil {
|
||||
return c.Func.Nname
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func staticValue(n *Node) *Node {
|
||||
for {
|
||||
n1 := staticValue1(n)
|
||||
if n1 == nil {
|
||||
return n
|
||||
}
|
||||
n = n1
|
||||
}
|
||||
}
|
||||
|
||||
// staticValue1 implements a simple SSA-like optimization. If n is a local variable
|
||||
// that is initialized and never reassigned, staticValue1 returns the initializer
|
||||
// expression. Otherwise, it returns nil.
|
||||
func staticValue1(n *Node) *Node {
|
||||
if n.Op != ONAME || n.Class() != PAUTO || n.Name.Addrtaken() {
|
||||
return nil
|
||||
}
|
||||
return f
|
||||
|
||||
defn := n.Name.Defn
|
||||
if defn == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
var rhs *Node
|
||||
FindRHS:
|
||||
switch defn.Op {
|
||||
case OAS:
|
||||
rhs = defn.Right
|
||||
case OAS2:
|
||||
for i, lhs := range defn.List.Slice() {
|
||||
if lhs == n {
|
||||
rhs = defn.Rlist.Index(i)
|
||||
break FindRHS
|
||||
}
|
||||
}
|
||||
Fatalf("%v missing from LHS of %v", n, defn)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
if rhs == nil {
|
||||
Fatalf("RHS is nil: %v", defn)
|
||||
}
|
||||
|
||||
unsafe, _ := reassigned(n)
|
||||
if unsafe {
|
||||
return nil
|
||||
}
|
||||
|
||||
return rhs
|
||||
}
|
||||
|
||||
// reassigned takes an ONAME node, walks the function in which it is defined, and returns a boolean
|
||||
@ -831,16 +850,19 @@ func (v *reassignVisitor) visitList(l Nodes) *Node {
|
||||
return nil
|
||||
}
|
||||
|
||||
func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node {
|
||||
if n := asNode(t.Nname); n != nil && !n.isBlank() {
|
||||
inlvar := inlvars[n]
|
||||
if inlvar == nil {
|
||||
Fatalf("missing inlvar for %v\n", n)
|
||||
}
|
||||
return inlvar
|
||||
func inlParam(t *types.Field, as *Node, inlvars map[*Node]*Node) *Node {
|
||||
n := asNode(t.Nname)
|
||||
if n == nil || n.isBlank() {
|
||||
return nblank
|
||||
}
|
||||
|
||||
return typecheck(nblank, ctxExpr|ctxAssign)
|
||||
inlvar := inlvars[n]
|
||||
if inlvar == nil {
|
||||
Fatalf("missing inlvar for %v", n)
|
||||
}
|
||||
as.Ninit.Append(nod(ODCL, inlvar, nil))
|
||||
inlvar.Name.Defn = as
|
||||
return inlvar
|
||||
}
|
||||
|
||||
var inlgen int
|
||||
@ -889,7 +911,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
}
|
||||
|
||||
if inlMap[fn] {
|
||||
if Debug['m'] > 1 {
|
||||
if Debug.m > 1 {
|
||||
fmt.Printf("%v: cannot inline %v into %v: repeated recursive cycle\n", n.Line(), fn, Curfn.funcname())
|
||||
}
|
||||
return n
|
||||
@ -903,12 +925,12 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
}
|
||||
|
||||
// We have a function node, and it has an inlineable body.
|
||||
if Debug['m'] > 1 {
|
||||
if Debug.m > 1 {
|
||||
fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, asNodes(fn.Func.Inl.Body))
|
||||
} else if Debug['m'] != 0 {
|
||||
} else if Debug.m != 0 {
|
||||
fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
|
||||
}
|
||||
if Debug['m'] > 2 {
|
||||
if Debug.m > 2 {
|
||||
fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
|
||||
}
|
||||
|
||||
@ -970,14 +992,15 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
continue
|
||||
}
|
||||
if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
|
||||
continue
|
||||
}
|
||||
inlvars[ln] = typecheck(inlvar(ln), ctxExpr)
|
||||
if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM {
|
||||
ninit.Append(nod(ODCL, inlvars[ln], nil))
|
||||
// TODO(mdempsky): Remove once I'm confident
|
||||
// this never actually happens. We currently
|
||||
// perform inlining before escape analysis, so
|
||||
// nothing should have moved to the heap yet.
|
||||
Fatalf("impossible: %v", ln)
|
||||
}
|
||||
inlf := typecheck(inlvar(ln), ctxExpr)
|
||||
inlvars[ln] = inlf
|
||||
if genDwarfInline > 0 {
|
||||
inlf := inlvars[ln]
|
||||
if ln.Class() == PPARAM {
|
||||
inlf.Name.SetInlFormal(true)
|
||||
} else {
|
||||
@ -1019,56 +1042,42 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
|
||||
// Assign arguments to the parameters' temp names.
|
||||
as := nod(OAS2, nil, nil)
|
||||
as.Rlist.Set(n.List.Slice())
|
||||
as.SetColas(true)
|
||||
if n.Op == OCALLMETH {
|
||||
if n.Left.Left == nil {
|
||||
Fatalf("method call without receiver: %+v", n)
|
||||
}
|
||||
as.Rlist.Append(n.Left.Left)
|
||||
}
|
||||
as.Rlist.Append(n.List.Slice()...)
|
||||
|
||||
// For non-dotted calls to variadic functions, we assign the
|
||||
// variadic parameter's temp name separately.
|
||||
var vas *Node
|
||||
|
||||
if fn.IsMethod() {
|
||||
rcv := fn.Type.Recv()
|
||||
|
||||
if n.Left.Op == ODOTMETH {
|
||||
// For x.M(...), assign x directly to the
|
||||
// receiver parameter.
|
||||
if n.Left.Left == nil {
|
||||
Fatalf("method call without receiver: %+v", n)
|
||||
if recv := fn.Type.Recv(); recv != nil {
|
||||
as.List.Append(inlParam(recv, as, inlvars))
|
||||
}
|
||||
ras := nod(OAS, tinlvar(rcv, inlvars), n.Left.Left)
|
||||
ras = typecheck(ras, ctxStmt)
|
||||
ninit.Append(ras)
|
||||
} else {
|
||||
// For T.M(...), add the receiver parameter to
|
||||
// as.List, so it's assigned by the normal
|
||||
// arguments.
|
||||
if as.Rlist.Len() == 0 {
|
||||
Fatalf("non-method call to method without first arg: %+v", n)
|
||||
}
|
||||
as.List.Append(tinlvar(rcv, inlvars))
|
||||
}
|
||||
}
|
||||
|
||||
for _, param := range fn.Type.Params().Fields().Slice() {
|
||||
// For ordinary parameters or variadic parameters in
|
||||
// dotted calls, just add the variable to the
|
||||
// assignment list, and we're done.
|
||||
if !param.IsDDD() || n.IsDDD() {
|
||||
as.List.Append(tinlvar(param, inlvars))
|
||||
as.List.Append(inlParam(param, as, inlvars))
|
||||
continue
|
||||
}
|
||||
|
||||
// Otherwise, we need to collect the remaining values
|
||||
// to pass as a slice.
|
||||
|
||||
numvals := n.List.Len()
|
||||
|
||||
x := as.List.Len()
|
||||
for as.List.Len() < numvals {
|
||||
for as.List.Len() < as.Rlist.Len() {
|
||||
as.List.Append(argvar(param.Type, as.List.Len()))
|
||||
}
|
||||
varargs := as.List.Slice()[x:]
|
||||
|
||||
vas = nod(OAS, tinlvar(param, inlvars), nil)
|
||||
vas = nod(OAS, nil, nil)
|
||||
vas.Left = inlParam(param, vas, inlvars)
|
||||
if len(varargs) == 0 {
|
||||
vas.Right = nodnil()
|
||||
vas.Right.Type = param.Type
|
||||
@ -1165,7 +1174,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
}
|
||||
}
|
||||
|
||||
if Debug['m'] > 2 {
|
||||
if Debug.m > 2 {
|
||||
fmt.Printf("%v: After inlining %+v\n\n", call.Line(), call)
|
||||
}
|
||||
|
||||
@ -1176,7 +1185,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
|
||||
// PAUTO's in the calling functions, and link them off of the
|
||||
// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
|
||||
func inlvar(var_ *Node) *Node {
|
||||
if Debug['m'] > 3 {
|
||||
if Debug.m > 3 {
|
||||
fmt.Printf("inlvar %+v\n", var_)
|
||||
}
|
||||
|
||||
@ -1255,13 +1264,13 @@ func (subst *inlsubst) node(n *Node) *Node {
|
||||
switch n.Op {
|
||||
case ONAME:
|
||||
if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
|
||||
if Debug['m'] > 2 {
|
||||
if Debug.m > 2 {
|
||||
fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
|
||||
}
|
||||
return inlvar
|
||||
}
|
||||
|
||||
if Debug['m'] > 2 {
|
||||
if Debug.m > 2 {
|
||||
fmt.Printf("not substituting name %+v\n", n)
|
||||
}
|
||||
return n
|
||||
|
@ -83,7 +83,7 @@ func TestIntendedInlining(t *testing.T) {
|
||||
"puintptr.ptr",
|
||||
"spanOf",
|
||||
"spanOfUnchecked",
|
||||
//"(*gcWork).putFast", // TODO(austin): For debugging #27993
|
||||
"(*gcWork).putFast",
|
||||
"(*gcWork).tryGetFast",
|
||||
"(*guintptr).set",
|
||||
"(*markBits).advance",
|
||||
@ -115,6 +115,7 @@ func TestIntendedInlining(t *testing.T) {
|
||||
"byLiteral.Len",
|
||||
"byLiteral.Less",
|
||||
"byLiteral.Swap",
|
||||
"(*dictDecoder).tryWriteCopy",
|
||||
},
|
||||
"encoding/base64": {
|
||||
"assemble32",
|
||||
|
@ -48,8 +48,11 @@ const (
|
||||
Nowritebarrierrec // error on write barrier in this or recursive callees
|
||||
Yeswritebarrierrec // cancels Nowritebarrierrec in this function and callees
|
||||
|
||||
// Runtime-only type pragmas
|
||||
// Runtime and cgo type pragmas
|
||||
NotInHeap // values of this type must not be heap allocated
|
||||
|
||||
// Go command pragmas
|
||||
GoBuildPragma
|
||||
)
|
||||
|
||||
const (
|
||||
@ -71,6 +74,8 @@ const (
|
||||
|
||||
func pragmaFlag(verb string) PragmaFlag {
|
||||
switch verb {
|
||||
case "go:build":
|
||||
return GoBuildPragma
|
||||
case "go:nointerface":
|
||||
if objabi.Fieldtrack_enabled != 0 {
|
||||
return Nointerface
|
||||
|
@ -34,8 +34,6 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
var imported_unsafe bool
|
||||
|
||||
var (
|
||||
buildid string
|
||||
spectre string
|
||||
@ -132,7 +130,7 @@ func hidePanic() {
|
||||
// supportsDynlink reports whether or not the code generator for the given
|
||||
// architecture supports the -shared and -dynlink flags.
|
||||
func supportsDynlink(arch *sys.Arch) bool {
|
||||
return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.S390X)
|
||||
return arch.InFamily(sys.AMD64, sys.ARM, sys.ARM64, sys.I386, sys.PPC64, sys.RISCV64, sys.S390X)
|
||||
}
|
||||
|
||||
// timing data for compiler phases
|
||||
@ -211,18 +209,27 @@ func Main(archInit func(*Arch)) {
|
||||
|
||||
flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
|
||||
flag.BoolVar(&compiling_std, "std", false, "compiling standard library")
|
||||
objabi.Flagcount("%", "debug non-static initializers", &Debug['%'])
|
||||
objabi.Flagcount("B", "disable bounds checking", &Debug['B'])
|
||||
objabi.Flagcount("C", "disable printing of columns in error messages", &Debug['C']) // TODO(gri) remove eventually
|
||||
flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
|
||||
objabi.Flagcount("E", "debug symbol export", &Debug['E'])
|
||||
|
||||
objabi.Flagcount("%", "debug non-static initializers", &Debug.P)
|
||||
objabi.Flagcount("B", "disable bounds checking", &Debug.B)
|
||||
objabi.Flagcount("C", "disable printing of columns in error messages", &Debug.C)
|
||||
objabi.Flagcount("E", "debug symbol export", &Debug.E)
|
||||
objabi.Flagcount("K", "debug missing line numbers", &Debug.K)
|
||||
objabi.Flagcount("L", "show full file names in error messages", &Debug.L)
|
||||
objabi.Flagcount("N", "disable optimizations", &Debug.N)
|
||||
objabi.Flagcount("S", "print assembly listing", &Debug.S)
|
||||
objabi.Flagcount("W", "debug parse tree after type checking", &Debug.W)
|
||||
objabi.Flagcount("e", "no limit on number of errors reported", &Debug.e)
|
||||
objabi.Flagcount("h", "halt on error", &Debug.h)
|
||||
objabi.Flagcount("j", "debug runtime-initialized variables", &Debug.j)
|
||||
objabi.Flagcount("l", "disable inlining", &Debug.l)
|
||||
objabi.Flagcount("m", "print optimization decisions", &Debug.m)
|
||||
objabi.Flagcount("r", "debug generated wrappers", &Debug.r)
|
||||
objabi.Flagcount("w", "debug type checking", &Debug.w)
|
||||
|
||||
objabi.Flagfn1("I", "add `directory` to import search path", addidir)
|
||||
objabi.Flagcount("K", "debug missing line numbers", &Debug['K'])
|
||||
objabi.Flagcount("L", "show full file names in error messages", &Debug['L'])
|
||||
objabi.Flagcount("N", "disable optimizations", &Debug['N'])
|
||||
objabi.Flagcount("S", "print assembly listing", &Debug['S'])
|
||||
objabi.AddVersionFlag() // -V
|
||||
objabi.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
|
||||
flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
|
||||
flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata")
|
||||
flag.IntVar(&nBackendWorkers, "c", 1, "concurrency during compilation, 1 means no concurrency")
|
||||
@ -231,17 +238,13 @@ func Main(archInit func(*Arch)) {
|
||||
flag.BoolVar(&flagDWARF, "dwarf", !Wasm, "generate DWARF symbols")
|
||||
flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode")
|
||||
flag.IntVar(&genDwarfInline, "gendwarfinl", 2, "generate DWARF inline info records")
|
||||
objabi.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
|
||||
objabi.Flagcount("h", "halt on error", &Debug['h'])
|
||||
objabi.Flagfn1("embedcfg", "read go:embed configuration from `file`", readEmbedCfg)
|
||||
objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
|
||||
objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
|
||||
flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
|
||||
objabi.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
|
||||
objabi.Flagcount("l", "disable inlining", &Debug['l'])
|
||||
flag.StringVar(&flag_lang, "lang", "", "release to compile for")
|
||||
flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
|
||||
objabi.Flagcount("live", "debug liveness analysis", &debuglive)
|
||||
objabi.Flagcount("m", "print optimization decisions", &Debug['m'])
|
||||
if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) {
|
||||
flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
|
||||
}
|
||||
@ -249,7 +252,6 @@ func Main(archInit func(*Arch)) {
|
||||
flag.StringVar(&outfile, "o", "", "write output to `file`")
|
||||
flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
|
||||
flag.BoolVar(&writearchive, "pack", false, "write to file.a instead of file.o")
|
||||
objabi.Flagcount("r", "debug generated wrappers", &Debug['r'])
|
||||
if sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) {
|
||||
flag.BoolVar(&flag_race, "race", false, "enable race detector")
|
||||
}
|
||||
@ -259,7 +261,6 @@ func Main(archInit func(*Arch)) {
|
||||
}
|
||||
flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
|
||||
flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
|
||||
objabi.Flagcount("w", "debug type checking", &Debug['w'])
|
||||
flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
|
||||
var flag_shared bool
|
||||
var flag_dynlink bool
|
||||
@ -325,9 +326,9 @@ func Main(archInit func(*Arch)) {
|
||||
|
||||
Ctxt.Flag_shared = flag_dynlink || flag_shared
|
||||
Ctxt.Flag_dynlink = flag_dynlink
|
||||
Ctxt.Flag_optimize = Debug['N'] == 0
|
||||
Ctxt.Flag_optimize = Debug.N == 0
|
||||
|
||||
Ctxt.Debugasm = Debug['S']
|
||||
Ctxt.Debugasm = Debug.S
|
||||
Ctxt.Debugvlog = Debug_vlog
|
||||
if flagDWARF {
|
||||
Ctxt.DebugInfo = debuginfo
|
||||
@ -399,7 +400,7 @@ func Main(archInit func(*Arch)) {
|
||||
instrumenting = true
|
||||
}
|
||||
|
||||
if compiling_runtime && Debug['N'] != 0 {
|
||||
if compiling_runtime && Debug.N != 0 {
|
||||
log.Fatal("cannot disable optimizations while compiling runtime")
|
||||
}
|
||||
if nBackendWorkers < 1 {
|
||||
@ -504,11 +505,11 @@ func Main(archInit func(*Arch)) {
|
||||
}
|
||||
|
||||
// enable inlining. for now:
|
||||
// default: inlining on. (debug['l'] == 1)
|
||||
// -l: inlining off (debug['l'] == 0)
|
||||
// -l=2, -l=3: inlining on again, with extra debugging (debug['l'] > 1)
|
||||
if Debug['l'] <= 1 {
|
||||
Debug['l'] = 1 - Debug['l']
|
||||
// default: inlining on. (Debug.l == 1)
|
||||
// -l: inlining off (Debug.l == 0)
|
||||
// -l=2, -l=3: inlining on again, with extra debugging (Debug.l > 1)
|
||||
if Debug.l <= 1 {
|
||||
Debug.l = 1 - Debug.l
|
||||
}
|
||||
|
||||
if jsonLogOpt != "" { // parse version,destination from json logging optimization.
|
||||
@ -516,6 +517,7 @@ func Main(archInit func(*Arch)) {
|
||||
}
|
||||
|
||||
ssaDump = os.Getenv("GOSSAFUNC")
|
||||
ssaDir = os.Getenv("GOSSADIR")
|
||||
if ssaDump != "" {
|
||||
if strings.HasSuffix(ssaDump, "+") {
|
||||
ssaDump = ssaDump[:len(ssaDump)-1]
|
||||
@ -594,7 +596,7 @@ func Main(archInit func(*Arch)) {
|
||||
timings.Start("fe", "typecheck", "top1")
|
||||
for i := 0; i < len(xtop); i++ {
|
||||
n := xtop[i]
|
||||
if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
|
||||
if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias()) {
|
||||
xtop[i] = typecheck(n, ctxStmt)
|
||||
}
|
||||
}
|
||||
@ -606,7 +608,7 @@ func Main(archInit func(*Arch)) {
|
||||
timings.Start("fe", "typecheck", "top2")
|
||||
for i := 0; i < len(xtop); i++ {
|
||||
n := xtop[i]
|
||||
if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
|
||||
if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias() {
|
||||
xtop[i] = typecheck(n, ctxStmt)
|
||||
}
|
||||
}
|
||||
@ -665,7 +667,7 @@ func Main(archInit func(*Arch)) {
|
||||
// Phase 5: Inlining
|
||||
timings.Start("fe", "inlining")
|
||||
if Debug_typecheckinl != 0 {
|
||||
// Typecheck imported function bodies if debug['l'] > 1,
|
||||
// Typecheck imported function bodies if Debug.l > 1,
|
||||
// otherwise lazily when used or re-exported.
|
||||
for _, n := range importlist {
|
||||
if n.Func.Inl != nil {
|
||||
@ -679,7 +681,7 @@ func Main(archInit func(*Arch)) {
|
||||
}
|
||||
}
|
||||
|
||||
if Debug['l'] != 0 {
|
||||
if Debug.l != 0 {
|
||||
// Find functions that can be inlined and clone them before walk expands them.
|
||||
visitBottomUp(xtop, func(list []*Node, recursive bool) {
|
||||
numfns := numNonClosures(list)
|
||||
@ -690,7 +692,7 @@ func Main(archInit func(*Arch)) {
|
||||
// across more than one function.
|
||||
caninl(n)
|
||||
} else {
|
||||
if Debug['m'] > 1 {
|
||||
if Debug.m > 1 {
|
||||
fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
|
||||
}
|
||||
}
|
||||
@ -967,9 +969,10 @@ func readSymABIs(file, myimportpath string) {
|
||||
if len(parts) != 3 {
|
||||
log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
|
||||
}
|
||||
sym, abi := parts[1], parts[2]
|
||||
if abi != "ABI0" { // Only supported external ABI right now
|
||||
log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abi)
|
||||
sym, abistr := parts[1], parts[2]
|
||||
abi, valid := obj.ParseABI(abistr)
|
||||
if !valid {
|
||||
log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abistr)
|
||||
}
|
||||
|
||||
// If the symbol is already prefixed with
|
||||
@ -982,9 +985,9 @@ func readSymABIs(file, myimportpath string) {
|
||||
|
||||
// Record for later.
|
||||
if parts[0] == "def" {
|
||||
symabiDefs[sym] = obj.ABI0
|
||||
symabiDefs[sym] = abi
|
||||
} else {
|
||||
symabiRefs[sym] = obj.ABI0
|
||||
symabiRefs[sym] = abi
|
||||
}
|
||||
default:
|
||||
log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
|
||||
@ -1173,7 +1176,6 @@ func importfile(f *Val) *types.Pkg {
|
||||
}
|
||||
|
||||
if path_ == "unsafe" {
|
||||
imported_unsafe = true
|
||||
return unsafepkg
|
||||
}
|
||||
|
||||
@ -1406,29 +1408,34 @@ func IsAlias(sym *types.Sym) bool {
|
||||
return sym.Def != nil && asNode(sym.Def).Sym != sym
|
||||
}
|
||||
|
||||
// By default, assume any debug flags are incompatible with concurrent compilation.
|
||||
// A few are safe and potentially in common use for normal compiles, though; mark them as such here.
|
||||
var concurrentFlagOK = [256]bool{
|
||||
'B': true, // disabled bounds checking
|
||||
'C': true, // disable printing of columns in error messages
|
||||
'e': true, // no limit on errors; errors all come from non-concurrent code
|
||||
'I': true, // add `directory` to import search path
|
||||
'N': true, // disable optimizations
|
||||
'l': true, // disable inlining
|
||||
'w': true, // all printing happens before compilation
|
||||
'W': true, // all printing happens before compilation
|
||||
'S': true, // printing disassembly happens at the end (but see concurrentBackendAllowed below)
|
||||
// By default, assume any debug flags are incompatible with concurrent
|
||||
// compilation. A few are safe and potentially in common use for
|
||||
// normal compiles, though; return true for those.
|
||||
func concurrentFlagOk() bool {
|
||||
// Report whether any debug flag that would prevent concurrent
|
||||
// compilation is set, by zeroing out the allowed ones and then
|
||||
// checking if the resulting struct is zero.
|
||||
d := Debug
|
||||
d.B = 0 // disable bounds checking
|
||||
d.C = 0 // disable printing of columns in error messages
|
||||
d.e = 0 // no limit on errors; errors all come from non-concurrent code
|
||||
d.N = 0 // disable optimizations
|
||||
d.l = 0 // disable inlining
|
||||
d.w = 0 // all printing happens before compilation
|
||||
d.W = 0 // all printing happens before compilation
|
||||
d.S = 0 // printing disassembly happens at the end (but see concurrentBackendAllowed below)
|
||||
|
||||
return d == DebugFlags{}
|
||||
}
|
||||
|
||||
func concurrentBackendAllowed() bool {
|
||||
for i, x := range &Debug {
|
||||
if x != 0 && !concurrentFlagOK[i] {
|
||||
if !concurrentFlagOk() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// Debug['S'] by itself is ok, because all printing occurs
|
||||
|
||||
// Debug.S by itself is ok, because all printing occurs
|
||||
// while writing the object file, and that is non-concurrent.
|
||||
// Adding Debug_vlog, however, causes Debug['S'] to also print
|
||||
// Adding Debug_vlog, however, causes Debug.S to also print
|
||||
// while flushing the plist, which happens concurrently.
|
||||
if Debug_vlog || debugstr != "" || debuglive > 0 {
|
||||
return false
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"cmd/compile/internal/syntax"
|
||||
@ -90,7 +91,11 @@ func (p *noder) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase {
|
||||
} else {
|
||||
// line directive base
|
||||
p0 := b0.Pos()
|
||||
p1 := src.MakePos(p.makeSrcPosBase(p0.Base()), p0.Line(), p0.Col())
|
||||
p0b := p0.Base()
|
||||
if p0b == b0 {
|
||||
panic("infinite recursion in makeSrcPosBase")
|
||||
}
|
||||
p1 := src.MakePos(p.makeSrcPosBase(p0b), p0.Line(), p0.Col())
|
||||
b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line(), b0.Col())
|
||||
}
|
||||
p.basemap[b0] = b1
|
||||
@ -135,6 +140,8 @@ type noder struct {
|
||||
pragcgobuf [][]string
|
||||
err chan syntax.Error
|
||||
scope ScopeID
|
||||
importedUnsafe bool
|
||||
importedEmbed bool
|
||||
|
||||
// scopeVars is a stack tracking the number of variables declared in the
|
||||
// current function at the moment each open scope was opened.
|
||||
@ -236,19 +243,21 @@ type linkname struct {
|
||||
|
||||
func (p *noder) node() {
|
||||
types.Block = 1
|
||||
imported_unsafe = false
|
||||
p.importedUnsafe = false
|
||||
p.importedEmbed = false
|
||||
|
||||
p.setlineno(p.file.PkgName)
|
||||
mkpackage(p.file.PkgName.Value)
|
||||
|
||||
if pragma, ok := p.file.Pragma.(*Pragma); ok {
|
||||
pragma.Flag &^= GoBuildPragma
|
||||
p.checkUnused(pragma)
|
||||
}
|
||||
|
||||
xtop = append(xtop, p.decls(p.file.DeclList)...)
|
||||
|
||||
for _, n := range p.linknames {
|
||||
if !imported_unsafe {
|
||||
if !p.importedUnsafe {
|
||||
p.yyerrorpos(n.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
|
||||
continue
|
||||
}
|
||||
@ -323,7 +332,6 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
|
||||
|
||||
val := p.basicLit(imp.Path)
|
||||
ipkg := importfile(&val)
|
||||
|
||||
if ipkg == nil {
|
||||
if nerrors == 0 {
|
||||
Fatalf("phase error in import")
|
||||
@ -331,6 +339,13 @@ func (p *noder) importDecl(imp *syntax.ImportDecl) {
|
||||
return
|
||||
}
|
||||
|
||||
if ipkg == unsafepkg {
|
||||
p.importedUnsafe = true
|
||||
}
|
||||
if ipkg.Path == "embed" {
|
||||
p.importedEmbed = true
|
||||
}
|
||||
|
||||
ipkg.Direct = true
|
||||
|
||||
var my *types.Sym
|
||||
@ -372,6 +387,20 @@ func (p *noder) varDecl(decl *syntax.VarDecl) []*Node {
|
||||
}
|
||||
|
||||
if pragma, ok := decl.Pragma.(*Pragma); ok {
|
||||
if len(pragma.Embeds) > 0 {
|
||||
if !p.importedEmbed {
|
||||
// This check can't be done when building the list pragma.Embeds
|
||||
// because that list is created before the noder starts walking over the file,
|
||||
// so at that point it hasn't seen the imports.
|
||||
// We're left to check now, just before applying the //go:embed lines.
|
||||
for _, e := range pragma.Embeds {
|
||||
p.yyerrorpos(e.Pos, "//go:embed only allowed in Go files that import \"embed\"")
|
||||
}
|
||||
} else {
|
||||
exprs = varEmbed(p, names, typ, exprs, pragma.Embeds)
|
||||
}
|
||||
pragma.Embeds = nil
|
||||
}
|
||||
p.checkUnused(pragma)
|
||||
}
|
||||
|
||||
@ -454,17 +483,17 @@ func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
|
||||
|
||||
param := n.Name.Param
|
||||
param.Ntype = typ
|
||||
param.Alias = decl.Alias
|
||||
param.SetAlias(decl.Alias)
|
||||
if pragma, ok := decl.Pragma.(*Pragma); ok {
|
||||
if !decl.Alias {
|
||||
param.Pragma = pragma.Flag & TypePragmas
|
||||
param.SetPragma(pragma.Flag & TypePragmas)
|
||||
pragma.Flag &^= TypePragmas
|
||||
}
|
||||
p.checkUnused(pragma)
|
||||
}
|
||||
|
||||
nod := p.nod(decl, ODCLTYPE, n, nil)
|
||||
if param.Alias && !langSupported(1, 9, localpkg) {
|
||||
if param.Alias() && !langSupported(1, 9, localpkg) {
|
||||
yyerrorl(nod.Pos, "type aliases only supported as of -lang=go1.9")
|
||||
}
|
||||
return nod
|
||||
@ -773,7 +802,7 @@ func (p *noder) sum(x syntax.Expr) *Node {
|
||||
n := p.expr(x)
|
||||
if Isconst(n, CTSTR) && n.Sym == nil {
|
||||
nstr = n
|
||||
chunks = append(chunks, strlit(nstr))
|
||||
chunks = append(chunks, nstr.StringVal())
|
||||
}
|
||||
|
||||
for i := len(adds) - 1; i >= 0; i-- {
|
||||
@ -783,12 +812,12 @@ func (p *noder) sum(x syntax.Expr) *Node {
|
||||
if Isconst(r, CTSTR) && r.Sym == nil {
|
||||
if nstr != nil {
|
||||
// Collapse r into nstr instead of adding to n.
|
||||
chunks = append(chunks, strlit(r))
|
||||
chunks = append(chunks, r.StringVal())
|
||||
continue
|
||||
}
|
||||
|
||||
nstr = r
|
||||
chunks = append(chunks, strlit(nstr))
|
||||
chunks = append(chunks, nstr.StringVal())
|
||||
} else {
|
||||
if len(chunks) > 1 {
|
||||
nstr.SetVal(Val{U: strings.Join(chunks, "")})
|
||||
@ -1437,11 +1466,6 @@ func (p *noder) mkname(name *syntax.Name) *Node {
|
||||
return mkname(p.name(name))
|
||||
}
|
||||
|
||||
func (p *noder) newname(name *syntax.Name) *Node {
|
||||
// TODO(mdempsky): Set line number?
|
||||
return newname(p.name(name))
|
||||
}
|
||||
|
||||
func (p *noder) wrapname(n syntax.Node, x *Node) *Node {
|
||||
// These nodes do not carry line numbers.
|
||||
// Introduce a wrapper node to give them the correct line.
|
||||
@ -1497,6 +1521,7 @@ var allowedStdPragmas = map[string]bool{
|
||||
"go:cgo_import_dynamic": true,
|
||||
"go:cgo_ldflag": true,
|
||||
"go:cgo_dynamic_linker": true,
|
||||
"go:embed": true,
|
||||
"go:generate": true,
|
||||
}
|
||||
|
||||
@ -1504,6 +1529,7 @@ var allowedStdPragmas = map[string]bool{
|
||||
type Pragma struct {
|
||||
Flag PragmaFlag // collected bits
|
||||
Pos []PragmaPos // position of each individual flag
|
||||
Embeds []PragmaEmbed
|
||||
}
|
||||
|
||||
type PragmaPos struct {
|
||||
@ -1511,12 +1537,22 @@ type PragmaPos struct {
|
||||
Pos syntax.Pos
|
||||
}
|
||||
|
||||
type PragmaEmbed struct {
|
||||
Pos syntax.Pos
|
||||
Patterns []string
|
||||
}
|
||||
|
||||
func (p *noder) checkUnused(pragma *Pragma) {
|
||||
for _, pos := range pragma.Pos {
|
||||
if pos.Flag&pragma.Flag != 0 {
|
||||
p.yyerrorpos(pos.Pos, "misplaced compiler directive")
|
||||
}
|
||||
}
|
||||
if len(pragma.Embeds) > 0 {
|
||||
for _, e := range pragma.Embeds {
|
||||
p.yyerrorpos(e.Pos, "misplaced go:embed directive")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *noder) checkUnusedDuringParse(pragma *Pragma) {
|
||||
@ -1525,6 +1561,11 @@ func (p *noder) checkUnusedDuringParse(pragma *Pragma) {
|
||||
p.error(syntax.Error{Pos: pos.Pos, Msg: "misplaced compiler directive"})
|
||||
}
|
||||
}
|
||||
if len(pragma.Embeds) > 0 {
|
||||
for _, e := range pragma.Embeds {
|
||||
p.error(syntax.Error{Pos: e.Pos, Msg: "misplaced go:embed directive"})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pragma is called concurrently if files are parsed concurrently.
|
||||
@ -1569,6 +1610,17 @@ func (p *noder) pragma(pos syntax.Pos, blankLine bool, text string, old syntax.P
|
||||
}
|
||||
p.linknames = append(p.linknames, linkname{pos, f[1], target})
|
||||
|
||||
case text == "go:embed", strings.HasPrefix(text, "go:embed "):
|
||||
args, err := parseGoEmbed(text[len("go:embed"):])
|
||||
if err != nil {
|
||||
p.error(syntax.Error{Pos: pos, Msg: err.Error()})
|
||||
}
|
||||
if len(args) == 0 {
|
||||
p.error(syntax.Error{Pos: pos, Msg: "usage: //go:embed pattern..."})
|
||||
break
|
||||
}
|
||||
pragma.Embeds = append(pragma.Embeds, PragmaEmbed{pos, args})
|
||||
|
||||
case strings.HasPrefix(text, "go:cgo_import_dynamic "):
|
||||
// This is permitted for general use because Solaris
|
||||
// code relies on it in golang.org/x/sys/unix and others.
|
||||
@ -1641,3 +1693,64 @@ func mkname(sym *types.Sym) *Node {
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// parseGoEmbed parses the text following "//go:embed" to extract the glob patterns.
|
||||
// It accepts unquoted space-separated patterns as well as double-quoted and back-quoted Go strings.
|
||||
// go/build/read.go also processes these strings and contains similar logic.
|
||||
func parseGoEmbed(args string) ([]string, error) {
|
||||
var list []string
|
||||
for args = strings.TrimSpace(args); args != ""; args = strings.TrimSpace(args) {
|
||||
var path string
|
||||
Switch:
|
||||
switch args[0] {
|
||||
default:
|
||||
i := len(args)
|
||||
for j, c := range args {
|
||||
if unicode.IsSpace(c) {
|
||||
i = j
|
||||
break
|
||||
}
|
||||
}
|
||||
path = args[:i]
|
||||
args = args[i:]
|
||||
|
||||
case '`':
|
||||
i := strings.Index(args[1:], "`")
|
||||
if i < 0 {
|
||||
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
|
||||
}
|
||||
path = args[1 : 1+i]
|
||||
args = args[1+i+1:]
|
||||
|
||||
case '"':
|
||||
i := 1
|
||||
for ; i < len(args); i++ {
|
||||
if args[i] == '\\' {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
if args[i] == '"' {
|
||||
q, err := strconv.Unquote(args[:i+1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args[:i+1])
|
||||
}
|
||||
path = q
|
||||
args = args[i+1:]
|
||||
break Switch
|
||||
}
|
||||
}
|
||||
if i >= len(args) {
|
||||
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
|
||||
}
|
||||
}
|
||||
|
||||
if args != "" {
|
||||
r, _ := utf8.DecodeRuneInString(args)
|
||||
if !unicode.IsSpace(r) {
|
||||
return nil, fmt.Errorf("invalid quoted string in //go:embed: %s", args)
|
||||
}
|
||||
}
|
||||
list = append(list, path)
|
||||
}
|
||||
return list, nil
|
||||
}
|
||||
|
@ -14,6 +14,8 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
@ -125,6 +127,7 @@ func dumpdata() {
|
||||
itabsLen := len(itabs)
|
||||
dumpimportstrings()
|
||||
dumpbasictypes()
|
||||
dumpembeds()
|
||||
|
||||
// Calls to dumpsignats can generate functions,
|
||||
// like method wrappers and hash and equality routines.
|
||||
@ -272,7 +275,7 @@ func dumpGlobalConst(n *Node) {
|
||||
default:
|
||||
return
|
||||
}
|
||||
Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), n.Int64())
|
||||
Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), n.Int64Val())
|
||||
}
|
||||
|
||||
func dumpglobls() {
|
||||
@ -305,20 +308,21 @@ func dumpglobls() {
|
||||
// global symbols can't be declared during parallel compilation.
|
||||
func addGCLocals() {
|
||||
for _, s := range Ctxt.Text {
|
||||
if s.Func == nil {
|
||||
fn := s.Func()
|
||||
if fn == nil {
|
||||
continue
|
||||
}
|
||||
for _, gcsym := range []*obj.LSym{s.Func.GCArgs, s.Func.GCLocals, s.Func.GCRegs} {
|
||||
for _, gcsym := range []*obj.LSym{fn.GCArgs, fn.GCLocals, fn.GCRegs} {
|
||||
if gcsym != nil && !gcsym.OnList() {
|
||||
ggloblsym(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
|
||||
}
|
||||
}
|
||||
if x := s.Func.StackObjects; x != nil {
|
||||
if x := fn.StackObjects; x != nil {
|
||||
attr := int16(obj.RODATA)
|
||||
ggloblsym(x, int32(len(x.P)), attr)
|
||||
x.Set(obj.AttrStatic, true)
|
||||
}
|
||||
if x := s.Func.OpenCodedDeferInfo; x != nil {
|
||||
if x := fn.OpenCodedDeferInfo; x != nil {
|
||||
ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
|
||||
}
|
||||
}
|
||||
@ -357,28 +361,31 @@ func dbvec(s *obj.LSym, off int, bv bvec) int {
|
||||
return off
|
||||
}
|
||||
|
||||
const (
|
||||
stringSymPrefix = "go.string."
|
||||
stringSymPattern = ".gostring.%d.%x"
|
||||
)
|
||||
|
||||
// stringsym returns a symbol containing the string s.
|
||||
// The symbol contains the string data, not a string header.
|
||||
func stringsym(pos src.XPos, s string) (data *obj.LSym) {
|
||||
var symname string
|
||||
if len(s) > 100 {
|
||||
// Huge strings are hashed to avoid long names in object files.
|
||||
// Indulge in some paranoia by writing the length of s, too,
|
||||
// as protection against length extension attacks.
|
||||
// Same pattern is known to fileStringSym below.
|
||||
h := sha256.New()
|
||||
io.WriteString(h, s)
|
||||
symname = fmt.Sprintf(".gostring.%d.%x", len(s), h.Sum(nil))
|
||||
symname = fmt.Sprintf(stringSymPattern, len(s), h.Sum(nil))
|
||||
} else {
|
||||
// Small strings get named directly by their contents.
|
||||
symname = strconv.Quote(s)
|
||||
}
|
||||
|
||||
const prefix = "go.string."
|
||||
symdataname := prefix + symname
|
||||
|
||||
symdata := Ctxt.Lookup(symdataname)
|
||||
|
||||
symdata := Ctxt.Lookup(stringSymPrefix + symname)
|
||||
if !symdata.OnList() {
|
||||
// string data
|
||||
off := dsname(symdata, 0, s, pos, "string")
|
||||
off := dstringdata(symdata, 0, s, pos, "string")
|
||||
ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
|
||||
symdata.Set(obj.AttrContentAddressable, true)
|
||||
}
|
||||
@ -386,26 +393,122 @@ func stringsym(pos src.XPos, s string) (data *obj.LSym) {
|
||||
return symdata
|
||||
}
|
||||
|
||||
var slicebytes_gen int
|
||||
// fileStringSym returns a symbol for the contents and the size of file.
|
||||
// If readonly is true, the symbol shares storage with any literal string
|
||||
// or other file with the same content and is placed in a read-only section.
|
||||
// If readonly is false, the symbol is a read-write copy separate from any other,
|
||||
// for use as the backing store of a []byte.
|
||||
// The content hash of file is copied into hash. (If hash is nil, nothing is copied.)
|
||||
// The returned symbol contains the data itself, not a string header.
|
||||
func fileStringSym(pos src.XPos, file string, readonly bool, hash []byte) (*obj.LSym, int64, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer f.Close()
|
||||
info, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if !info.Mode().IsRegular() {
|
||||
return nil, 0, fmt.Errorf("not a regular file")
|
||||
}
|
||||
size := info.Size()
|
||||
if size <= 1*1024 {
|
||||
data, err := ioutil.ReadAll(f)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if int64(len(data)) != size {
|
||||
return nil, 0, fmt.Errorf("file changed between reads")
|
||||
}
|
||||
var sym *obj.LSym
|
||||
if readonly {
|
||||
sym = stringsym(pos, string(data))
|
||||
} else {
|
||||
sym = slicedata(pos, string(data)).Sym.Linksym()
|
||||
}
|
||||
if len(hash) > 0 {
|
||||
sum := sha256.Sum256(data)
|
||||
copy(hash, sum[:])
|
||||
}
|
||||
return sym, size, nil
|
||||
}
|
||||
if size > 2e9 {
|
||||
// ggloblsym takes an int32,
|
||||
// and probably the rest of the toolchain
|
||||
// can't handle such big symbols either.
|
||||
// See golang.org/issue/9862.
|
||||
return nil, 0, fmt.Errorf("file too large")
|
||||
}
|
||||
|
||||
func slicebytes(nam *Node, s string) {
|
||||
slicebytes_gen++
|
||||
symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen)
|
||||
// File is too big to read and keep in memory.
|
||||
// Compute hash if needed for read-only content hashing or if the caller wants it.
|
||||
var sum []byte
|
||||
if readonly || len(hash) > 0 {
|
||||
h := sha256.New()
|
||||
n, err := io.Copy(h, f)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if n != size {
|
||||
return nil, 0, fmt.Errorf("file changed between reads")
|
||||
}
|
||||
sum = h.Sum(nil)
|
||||
copy(hash, sum)
|
||||
}
|
||||
|
||||
var symdata *obj.LSym
|
||||
if readonly {
|
||||
symname := fmt.Sprintf(stringSymPattern, size, sum)
|
||||
symdata = Ctxt.Lookup(stringSymPrefix + symname)
|
||||
if !symdata.OnList() {
|
||||
info := symdata.NewFileInfo()
|
||||
info.Name = file
|
||||
info.Size = size
|
||||
ggloblsym(symdata, int32(size), obj.DUPOK|obj.RODATA|obj.LOCAL)
|
||||
// Note: AttrContentAddressable cannot be set here,
|
||||
// because the content-addressable-handling code
|
||||
// does not know about file symbols.
|
||||
}
|
||||
} else {
|
||||
// Emit a zero-length data symbol
|
||||
// and then fix up length and content to use file.
|
||||
symdata = slicedata(pos, "").Sym.Linksym()
|
||||
symdata.Size = size
|
||||
symdata.Type = objabi.SNOPTRDATA
|
||||
info := symdata.NewFileInfo()
|
||||
info.Name = file
|
||||
info.Size = size
|
||||
}
|
||||
|
||||
return symdata, size, nil
|
||||
}
|
||||
|
||||
var slicedataGen int
|
||||
|
||||
func slicedata(pos src.XPos, s string) *Node {
|
||||
slicedataGen++
|
||||
symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
|
||||
sym := localpkg.Lookup(symname)
|
||||
symnode := newname(sym)
|
||||
sym.Def = asTypesNode(symnode)
|
||||
|
||||
lsym := sym.Linksym()
|
||||
off := dsname(lsym, 0, s, nam.Pos, "slice")
|
||||
off := dstringdata(lsym, 0, s, pos, "slice")
|
||||
ggloblsym(lsym, int32(off), obj.NOPTR|obj.LOCAL)
|
||||
|
||||
return symnode
|
||||
}
|
||||
|
||||
func slicebytes(nam *Node, s string) {
|
||||
if nam.Op != ONAME {
|
||||
Fatalf("slicebytes %v", nam)
|
||||
}
|
||||
slicesym(nam, symnode, int64(len(s)))
|
||||
slicesym(nam, slicedata(nam.Pos, s), int64(len(s)))
|
||||
}
|
||||
|
||||
func dsname(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
|
||||
func dstringdata(s *obj.LSym, off int, t string, pos src.XPos, what string) int {
|
||||
// Objects that are too large will cause the data section to overflow right away,
|
||||
// causing a cryptic error message by the linker. Check for oversize objects here
|
||||
// and provide a useful error message instead.
|
||||
|
@ -50,7 +50,7 @@ type Order struct {
|
||||
// Order rewrites fn.Nbody to apply the ordering constraints
|
||||
// described in the comment at the top of the file.
|
||||
func order(fn *Node) {
|
||||
if Debug['W'] > 1 {
|
||||
if Debug.W > 1 {
|
||||
s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym)
|
||||
dumplist(s, fn.Nbody)
|
||||
}
|
||||
@ -323,12 +323,7 @@ func (o *Order) stmtList(l Nodes) {
|
||||
// and rewrites it to:
|
||||
// m = OMAKESLICECOPY([]T, x, s); nil
|
||||
func orderMakeSliceCopy(s []*Node) {
|
||||
const go115makeslicecopy = true
|
||||
if !go115makeslicecopy {
|
||||
return
|
||||
}
|
||||
|
||||
if Debug['N'] != 0 || instrumenting {
|
||||
if Debug.N != 0 || instrumenting {
|
||||
return
|
||||
}
|
||||
|
||||
@ -1102,7 +1097,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
|
||||
haslit := false
|
||||
for _, n1 := range n.List.Slice() {
|
||||
hasbyte = hasbyte || n1.Op == OBYTES2STR
|
||||
haslit = haslit || n1.Op == OLITERAL && len(strlit(n1)) != 0
|
||||
haslit = haslit || n1.Op == OLITERAL && len(n1.StringVal()) != 0
|
||||
}
|
||||
|
||||
if haslit && hasbyte {
|
||||
@ -1274,7 +1269,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
|
||||
var t *types.Type
|
||||
switch n.Op {
|
||||
case OSLICELIT:
|
||||
t = types.NewArray(n.Type.Elem(), n.Right.Int64())
|
||||
t = types.NewArray(n.Type.Elem(), n.Right.Int64Val())
|
||||
case OCALLPART:
|
||||
t = partialCallType(n)
|
||||
}
|
||||
|
@ -266,8 +266,8 @@ func compile(fn *Node) {
|
||||
dtypesym(n.Type)
|
||||
// Also make sure we allocate a linker symbol
|
||||
// for the stack object data, for the same reason.
|
||||
if fn.Func.lsym.Func.StackObjects == nil {
|
||||
fn.Func.lsym.Func.StackObjects = Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj")
|
||||
if fn.Func.lsym.Func().StackObjects == nil {
|
||||
fn.Func.lsym.Func().StackObjects = Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -415,7 +415,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
|
||||
case PAUTO:
|
||||
if !n.Name.Used() {
|
||||
// Text == nil -> generating abstract function
|
||||
if fnsym.Func.Text != nil {
|
||||
if fnsym.Func().Text != nil {
|
||||
Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
|
||||
}
|
||||
continue
|
||||
@ -425,7 +425,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
|
||||
continue
|
||||
}
|
||||
apdecls = append(apdecls, n)
|
||||
fnsym.Func.RecordAutoType(ngotype(n).Linksym())
|
||||
fnsym.Func().RecordAutoType(ngotype(n).Linksym())
|
||||
}
|
||||
|
||||
decls, dwarfVars := createDwarfVars(fnsym, fn.Func, apdecls)
|
||||
@ -435,7 +435,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
|
||||
// the function symbol to insure that the type included in DWARF
|
||||
// processing during linking.
|
||||
typesyms := []*obj.LSym{}
|
||||
for t, _ := range fnsym.Func.Autot {
|
||||
for t, _ := range fnsym.Func().Autot {
|
||||
typesyms = append(typesyms, t)
|
||||
}
|
||||
sort.Sort(obj.BySymName(typesyms))
|
||||
@ -444,7 +444,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
|
||||
r.Sym = sym
|
||||
r.Type = objabi.R_USETYPE
|
||||
}
|
||||
fnsym.Func.Autot = nil
|
||||
fnsym.Func().Autot = nil
|
||||
|
||||
var varScopes []ScopeID
|
||||
for _, decl := range decls {
|
||||
@ -522,7 +522,7 @@ func createSimpleVar(fnsym *obj.LSym, n *Node) *dwarf.Var {
|
||||
}
|
||||
|
||||
typename := dwarf.InfoPrefix + typesymname(n.Type)
|
||||
delete(fnsym.Func.Autot, ngotype(n).Linksym())
|
||||
delete(fnsym.Func().Autot, ngotype(n).Linksym())
|
||||
inlIndex := 0
|
||||
if genDwarfInline > 1 {
|
||||
if n.Name.InlFormal() || n.Name.InlLocal() {
|
||||
@ -667,7 +667,7 @@ func createDwarfVars(fnsym *obj.LSym, fn *Func, apDecls []*Node) ([]*Node, []*dw
|
||||
ChildIndex: -1,
|
||||
})
|
||||
// Record go type of to insure that it gets emitted by the linker.
|
||||
fnsym.Func.RecordAutoType(ngotype(n).Linksym())
|
||||
fnsym.Func().RecordAutoType(ngotype(n).Linksym())
|
||||
}
|
||||
|
||||
return decls, vars
|
||||
@ -731,7 +731,7 @@ func createComplexVar(fnsym *obj.LSym, fn *Func, varID ssa.VarID) *dwarf.Var {
|
||||
}
|
||||
|
||||
gotype := ngotype(n).Linksym()
|
||||
delete(fnsym.Func.Autot, gotype)
|
||||
delete(fnsym.Func().Autot, gotype)
|
||||
typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
|
||||
inlIndex := 0
|
||||
if genDwarfInline > 1 {
|
||||
|
@ -1552,26 +1552,27 @@ func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
|
||||
|
||||
// Emit the live pointer map data structures
|
||||
ls := e.curfn.Func.lsym
|
||||
ls.Func.GCArgs, ls.Func.GCLocals, ls.Func.GCRegs = lv.emit()
|
||||
fninfo := ls.Func()
|
||||
fninfo.GCArgs, fninfo.GCLocals, fninfo.GCRegs = lv.emit()
|
||||
|
||||
p := pp.Prog(obj.AFUNCDATA)
|
||||
Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_EXTERN
|
||||
p.To.Sym = ls.Func.GCArgs
|
||||
p.To.Sym = fninfo.GCArgs
|
||||
|
||||
p = pp.Prog(obj.AFUNCDATA)
|
||||
Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_EXTERN
|
||||
p.To.Sym = ls.Func.GCLocals
|
||||
p.To.Sym = fninfo.GCLocals
|
||||
|
||||
if !go115ReduceLiveness {
|
||||
p = pp.Prog(obj.AFUNCDATA)
|
||||
Addrconst(&p.From, objabi.FUNCDATA_RegPointerMaps)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_EXTERN
|
||||
p.To.Sym = ls.Func.GCRegs
|
||||
p.To.Sym = fninfo.GCRegs
|
||||
}
|
||||
|
||||
return lv.livenessMap
|
||||
|
@ -112,22 +112,25 @@ func typecheckrangeExpr(n *Node) {
|
||||
v2 = nil
|
||||
}
|
||||
|
||||
var why string
|
||||
if v1 != nil {
|
||||
if v1.Name != nil && v1.Name.Defn == n {
|
||||
v1.Type = t1
|
||||
} else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 {
|
||||
} else if v1.Type != nil {
|
||||
if op, why := assignop(t1, v1.Type); op == OXXX {
|
||||
yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t1, v1, why)
|
||||
}
|
||||
}
|
||||
checkassign(n, v1)
|
||||
}
|
||||
|
||||
if v2 != nil {
|
||||
if v2.Name != nil && v2.Name.Defn == n {
|
||||
v2.Type = t2
|
||||
} else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 {
|
||||
} else if v2.Type != nil {
|
||||
if op, why := assignop(t2, v2.Type); op == OXXX {
|
||||
yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t2, v2, why)
|
||||
}
|
||||
}
|
||||
checkassign(n, v2)
|
||||
}
|
||||
}
|
||||
@ -463,7 +466,7 @@ func walkrange(n *Node) *Node {
|
||||
//
|
||||
// where == for keys of map m is reflexive.
|
||||
func isMapClear(n *Node) bool {
|
||||
if Debug['N'] != 0 || instrumenting {
|
||||
if Debug.N != 0 || instrumenting {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -530,7 +533,7 @@ func mapClear(m *Node) *Node {
|
||||
//
|
||||
// Parameters are as in walkrange: "for v1, v2 = range a".
|
||||
func arrayClear(n, v1, v2, a *Node) bool {
|
||||
if Debug['N'] != 0 || instrumenting {
|
||||
if Debug.N != 0 || instrumenting {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -1275,8 +1275,9 @@ func dtypesym(t *types.Type) *obj.LSym {
|
||||
}
|
||||
ot = dgopkgpath(lsym, ot, tpkg)
|
||||
|
||||
xcount := sort.Search(n, func(i int) bool { return !types.IsExported(m[i].name.Name) })
|
||||
ot = dsymptr(lsym, ot, lsym, ot+3*Widthptr+uncommonSize(t))
|
||||
ot = duintptr(lsym, ot, uint64(n))
|
||||
ot = duintptr(lsym, ot, uint64(xcount))
|
||||
ot = duintptr(lsym, ot, uint64(n))
|
||||
dataAdd := imethodSize() * n
|
||||
ot = dextratype(lsym, ot, t, dataAdd)
|
||||
|
@ -62,9 +62,9 @@ func scopePCs(fnsym *obj.LSym, marks []Mark, dwarfScopes []dwarf.Scope) {
|
||||
if len(marks) == 0 {
|
||||
return
|
||||
}
|
||||
p0 := fnsym.Func.Text
|
||||
p0 := fnsym.Func().Text
|
||||
scope := findScope(marks, p0.Pos)
|
||||
for p := fnsym.Func.Text; p != nil; p = p.Link {
|
||||
for p := p0; p != nil; p = p.Link {
|
||||
if p.Pos == p0.Pos {
|
||||
continue
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ func (s *InitSchedule) append(n *Node) {
|
||||
// staticInit adds an initialization statement n to the schedule.
|
||||
func (s *InitSchedule) staticInit(n *Node) {
|
||||
if !s.tryStaticInit(n) {
|
||||
if Debug['%'] != 0 {
|
||||
if Debug.P != 0 {
|
||||
Dump("nonstatic", n)
|
||||
}
|
||||
s.append(n)
|
||||
@ -128,7 +128,7 @@ func (s *InitSchedule) staticcopy(l *Node, r *Node) bool {
|
||||
case OSLICELIT:
|
||||
// copy slice
|
||||
a := s.inittemps[r]
|
||||
slicesym(l, a, r.Right.Int64())
|
||||
slicesym(l, a, r.Right.Int64Val())
|
||||
return true
|
||||
|
||||
case OARRAYLIT, OSTRUCTLIT:
|
||||
@ -205,7 +205,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
|
||||
|
||||
case OSTR2BYTES:
|
||||
if l.Class() == PEXTERN && r.Left.Op == OLITERAL {
|
||||
sval := strlit(r.Left)
|
||||
sval := r.Left.StringVal()
|
||||
slicebytes(l, sval)
|
||||
return true
|
||||
}
|
||||
@ -213,7 +213,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
|
||||
case OSLICELIT:
|
||||
s.initplan(r)
|
||||
// Init slice.
|
||||
bound := r.Right.Int64()
|
||||
bound := r.Right.Int64Val()
|
||||
ta := types.NewArray(r.Type.Elem(), bound)
|
||||
ta.SetNoalg(true)
|
||||
a := staticname(ta)
|
||||
@ -375,11 +375,6 @@ func readonlystaticname(t *types.Type) *Node {
|
||||
return n
|
||||
}
|
||||
|
||||
func isLiteral(n *Node) bool {
|
||||
// Treat nils as zeros rather than literals.
|
||||
return n.Op == OLITERAL && n.Val().Ctype() != CTNIL
|
||||
}
|
||||
|
||||
func (n *Node) isSimpleName() bool {
|
||||
return n.Op == ONAME && n.Class() != PAUTOHEAP && n.Class() != PEXTERN
|
||||
}
|
||||
@ -404,7 +399,7 @@ const (
|
||||
func getdyn(n *Node, top bool) initGenType {
|
||||
switch n.Op {
|
||||
default:
|
||||
if isLiteral(n) {
|
||||
if n.isGoConst() {
|
||||
return initConst
|
||||
}
|
||||
return initDynamic
|
||||
@ -413,7 +408,7 @@ func getdyn(n *Node, top bool) initGenType {
|
||||
if !top {
|
||||
return initDynamic
|
||||
}
|
||||
if n.Right.Int64()/4 > int64(n.List.Len()) {
|
||||
if n.Right.Int64Val()/4 > int64(n.List.Len()) {
|
||||
// <25% of entries have explicit values.
|
||||
// Very rough estimation, it takes 4 bytes of instructions
|
||||
// to initialize 1 byte of result. So don't use a static
|
||||
@ -559,7 +554,7 @@ func fixedlit(ctxt initContext, kind initKind, n *Node, var_ *Node, init *Nodes)
|
||||
continue
|
||||
}
|
||||
|
||||
islit := isLiteral(value)
|
||||
islit := value.isGoConst()
|
||||
if (kind == initKindStatic && !islit) || (kind == initKindDynamic && islit) {
|
||||
continue
|
||||
}
|
||||
@ -589,12 +584,12 @@ func isSmallSliceLit(n *Node) bool {
|
||||
|
||||
r := n.Right
|
||||
|
||||
return smallintconst(r) && (n.Type.Elem().Width == 0 || r.Int64() <= smallArrayBytes/n.Type.Elem().Width)
|
||||
return smallintconst(r) && (n.Type.Elem().Width == 0 || r.Int64Val() <= smallArrayBytes/n.Type.Elem().Width)
|
||||
}
|
||||
|
||||
func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
|
||||
// make an array type corresponding the number of elements we have
|
||||
t := types.NewArray(n.Type.Elem(), n.Right.Int64())
|
||||
t := types.NewArray(n.Type.Elem(), n.Right.Int64Val())
|
||||
dowidth(t)
|
||||
|
||||
if ctxt == inNonInitFunction {
|
||||
@ -732,7 +727,7 @@ func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
|
||||
continue
|
||||
}
|
||||
|
||||
if vstat != nil && isLiteral(value) { // already set by copy from static value
|
||||
if vstat != nil && value.isGoConst() { // already set by copy from static value
|
||||
continue
|
||||
}
|
||||
|
||||
@ -993,7 +988,7 @@ func oaslit(n *Node, init *Nodes) bool {
|
||||
|
||||
func getlit(lit *Node) int {
|
||||
if smallintconst(lit) {
|
||||
return int(lit.Int64())
|
||||
return int(lit.Int64Val())
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
@ -9,8 +9,8 @@ import (
|
||||
"fmt"
|
||||
"html"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"bufio"
|
||||
"bytes"
|
||||
@ -27,6 +27,7 @@ var ssaConfig *ssa.Config
|
||||
var ssaCaches []ssa.Cache
|
||||
|
||||
var ssaDump string // early copy of $GOSSAFUNC; the func name to dump output for
|
||||
var ssaDir string // optional destination for ssa dump file
|
||||
var ssaDumpStdout bool // whether to dump to stdout
|
||||
var ssaDumpCFG string // generate CFGs for these phases
|
||||
const ssaDumpFile = "ssa.html"
|
||||
@ -49,21 +50,16 @@ func initssaconfig() {
|
||||
// Caching is disabled in the backend, so generating these here avoids allocations.
|
||||
_ = types.NewPtr(types.Types[TINTER]) // *interface{}
|
||||
_ = types.NewPtr(types.NewPtr(types.Types[TSTRING])) // **string
|
||||
_ = types.NewPtr(types.NewPtr(types.Idealstring)) // **string
|
||||
_ = types.NewPtr(types.NewSlice(types.Types[TINTER])) // *[]interface{}
|
||||
_ = types.NewPtr(types.NewPtr(types.Bytetype)) // **byte
|
||||
_ = types.NewPtr(types.NewSlice(types.Bytetype)) // *[]byte
|
||||
_ = types.NewPtr(types.NewSlice(types.Types[TSTRING])) // *[]string
|
||||
_ = types.NewPtr(types.NewSlice(types.Idealstring)) // *[]string
|
||||
_ = types.NewPtr(types.NewPtr(types.NewPtr(types.Types[TUINT8]))) // ***uint8
|
||||
_ = types.NewPtr(types.Types[TINT16]) // *int16
|
||||
_ = types.NewPtr(types.Types[TINT64]) // *int64
|
||||
_ = types.NewPtr(types.Errortype) // *error
|
||||
types.NewPtrCacheEnabled = false
|
||||
ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, *types_, Ctxt, Debug['N'] == 0)
|
||||
if thearch.LinkArch.Name == "386" {
|
||||
ssaConfig.Set387(thearch.Use387)
|
||||
}
|
||||
ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, *types_, Ctxt, Debug.N == 0)
|
||||
ssaConfig.SoftFloat = thearch.SoftFloat
|
||||
ssaConfig.Race = flag_race
|
||||
ssaCaches = make([]ssa.Cache, nBackendWorkers)
|
||||
@ -174,10 +170,6 @@ func initssaconfig() {
|
||||
ExtendCheckFunc[ssa.BoundsSlice3CU] = sysvar("panicExtendSlice3CU")
|
||||
}
|
||||
|
||||
// GO386=387 runtime definitions
|
||||
ControlWord64trunc = sysvar("controlWord64trunc") // uint16
|
||||
ControlWord32 = sysvar("controlWord32") // uint16
|
||||
|
||||
// Wasm (all asm funcs with special ABIs)
|
||||
WasmMove = sysvar("wasmMove")
|
||||
WasmZero = sysvar("wasmZero")
|
||||
@ -248,7 +240,7 @@ func dvarint(x *obj.LSym, off int, v int64) int {
|
||||
// - Offset of where argument should be placed in the args frame when making call
|
||||
func (s *state) emitOpenDeferInfo() {
|
||||
x := Ctxt.Lookup(s.curfn.Func.lsym.Name + ".opendefer")
|
||||
s.curfn.Func.lsym.Func.OpenCodedDeferInfo = x
|
||||
s.curfn.Func.lsym.Func().OpenCodedDeferInfo = x
|
||||
off := 0
|
||||
|
||||
// Compute maxargsize (max size of arguments for all defers)
|
||||
@ -347,7 +339,13 @@ func buildssa(fn *Node, worker int) *ssa.Func {
|
||||
s.f.Entry.Pos = fn.Pos
|
||||
|
||||
if printssa {
|
||||
s.f.HTMLWriter = ssa.NewHTMLWriter(ssaDumpFile, s.f, ssaDumpCFG)
|
||||
ssaDF := ssaDumpFile
|
||||
if ssaDir != "" {
|
||||
ssaDF = filepath.Join(ssaDir, myimportpath+"."+name+".html")
|
||||
ssaD := filepath.Dir(ssaDF)
|
||||
os.MkdirAll(ssaD, 0755)
|
||||
}
|
||||
s.f.HTMLWriter = ssa.NewHTMLWriter(ssaDF, s.f, ssaDumpCFG)
|
||||
// TODO: generate and print a mapping from nodes to values and blocks
|
||||
dumpSourcesColumn(s.f.HTMLWriter, fn)
|
||||
s.f.HTMLWriter.WriteAST("AST", astBuf)
|
||||
@ -359,7 +357,7 @@ func buildssa(fn *Node, worker int) *ssa.Func {
|
||||
s.fwdVars = map[*Node]*ssa.Value{}
|
||||
s.startmem = s.entryNewValue0(ssa.OpInitMem, types.TypeMem)
|
||||
|
||||
s.hasOpenDefers = Debug['N'] == 0 && s.hasdefer && !s.curfn.Func.OpenCodedDeferDisallowed()
|
||||
s.hasOpenDefers = Debug.N == 0 && s.hasdefer && !s.curfn.Func.OpenCodedDeferDisallowed()
|
||||
switch {
|
||||
case s.hasOpenDefers && (Ctxt.Flag_shared || Ctxt.Flag_dynlink) && thearch.LinkArch.Name == "386":
|
||||
// Don't support open-coded defers for 386 ONLY when using shared
|
||||
@ -743,7 +741,7 @@ func (s *state) pushLine(line src.XPos) {
|
||||
// the frontend may emit node with line number missing,
|
||||
// use the parent line number in this case.
|
||||
line = s.peekPos()
|
||||
if Debug['K'] != 0 {
|
||||
if Debug.K != 0 {
|
||||
Warn("buildssa: unknown position (line 0)")
|
||||
}
|
||||
} else {
|
||||
@ -1216,7 +1214,7 @@ func (s *state) stmt(n *Node) {
|
||||
// Check whether we're writing the result of an append back to the same slice.
|
||||
// If so, we handle it specially to avoid write barriers on the fast
|
||||
// (non-growth) path.
|
||||
if !samesafeexpr(n.Left, rhs.List.First()) || Debug['N'] != 0 {
|
||||
if !samesafeexpr(n.Left, rhs.List.First()) || Debug.N != 0 {
|
||||
break
|
||||
}
|
||||
// If the slice can be SSA'd, it'll be on the stack,
|
||||
@ -1273,7 +1271,7 @@ func (s *state) stmt(n *Node) {
|
||||
// We're assigning a slicing operation back to its source.
|
||||
// Don't write back fields we aren't changing. See issue #14855.
|
||||
i, j, k := rhs.SliceBounds()
|
||||
if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64() == 0) {
|
||||
if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64Val() == 0) {
|
||||
// [0:...] is the same as [:...]
|
||||
i = nil
|
||||
}
|
||||
@ -1303,7 +1301,7 @@ func (s *state) stmt(n *Node) {
|
||||
case OIF:
|
||||
if Isconst(n.Left, CTBOOL) {
|
||||
s.stmtList(n.Left.Ninit)
|
||||
if n.Left.Bool() {
|
||||
if n.Left.BoolVal() {
|
||||
s.stmtList(n.Nbody)
|
||||
} else {
|
||||
s.stmtList(n.Rlist)
|
||||
@ -2474,6 +2472,11 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||
a := s.expr(n.Left)
|
||||
b := s.expr(n.Right)
|
||||
return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
|
||||
case OANDNOT:
|
||||
a := s.expr(n.Left)
|
||||
b := s.expr(n.Right)
|
||||
b = s.newValue1(s.ssaOp(OBITNOT, b.Type), b.Type, b)
|
||||
return s.newValue2(s.ssaOp(OAND, n.Type), a.Type, a, b)
|
||||
case OLSH, ORSH:
|
||||
a := s.expr(n.Left)
|
||||
b := s.expr(n.Right)
|
||||
@ -2557,22 +2560,22 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||
return s.addr(n.Left)
|
||||
|
||||
case ORESULT:
|
||||
if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall {
|
||||
if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
|
||||
// Do the old thing
|
||||
addr := s.constOffPtrSP(types.NewPtr(n.Type), n.Xoffset)
|
||||
return s.load(n.Type, addr)
|
||||
return s.rawLoad(n.Type, addr)
|
||||
}
|
||||
which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffset(n.Xoffset)
|
||||
if which == -1 {
|
||||
// Do the old thing // TODO: Panic instead.
|
||||
addr := s.constOffPtrSP(types.NewPtr(n.Type), n.Xoffset)
|
||||
return s.load(n.Type, addr)
|
||||
return s.rawLoad(n.Type, addr)
|
||||
}
|
||||
if canSSAType(n.Type) {
|
||||
return s.newValue1I(ssa.OpSelectN, n.Type, which, s.prevCall)
|
||||
} else {
|
||||
addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(n.Type), which, s.prevCall)
|
||||
return s.load(n.Type, addr)
|
||||
return s.rawLoad(n.Type, addr)
|
||||
}
|
||||
|
||||
case ODEREF:
|
||||
@ -2612,7 +2615,7 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||
// Replace "abc"[1] with 'b'.
|
||||
// Delayed until now because "abc"[1] is not an ideal constant.
|
||||
// See test/fixedbugs/issue11370.go.
|
||||
return s.newValue0I(ssa.OpConst8, types.Types[TUINT8], int64(int8(strlit(n.Left)[n.Right.Int64()])))
|
||||
return s.newValue0I(ssa.OpConst8, types.Types[TUINT8], int64(int8(n.Left.StringVal()[n.Right.Int64Val()])))
|
||||
}
|
||||
a := s.expr(n.Left)
|
||||
i := s.expr(n.Right)
|
||||
@ -2621,7 +2624,7 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||
ptrtyp := s.f.Config.Types.BytePtr
|
||||
ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
|
||||
if Isconst(n.Right, CTINT) {
|
||||
ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64(), ptr)
|
||||
ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64Val(), ptr)
|
||||
} else {
|
||||
ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
|
||||
}
|
||||
@ -3391,6 +3394,13 @@ func init() {
|
||||
return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
|
||||
},
|
||||
sys.PPC64, sys.S390X)
|
||||
addF("runtime/internal/atomic", "LoadAcq64",
|
||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||
v := s.newValue2(ssa.OpAtomicLoadAcq64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], s.mem())
|
||||
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
|
||||
return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
|
||||
},
|
||||
sys.PPC64)
|
||||
addF("runtime/internal/atomic", "Loadp",
|
||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||
v := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(s.f.Config.Types.BytePtr, types.TypeMem), args[0], s.mem())
|
||||
@ -3429,6 +3439,12 @@ func init() {
|
||||
return nil
|
||||
},
|
||||
sys.PPC64, sys.S390X)
|
||||
addF("runtime/internal/atomic", "StoreRel64",
|
||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||
s.vars[&memVar] = s.newValue3(ssa.OpAtomicStoreRel64, types.TypeMem, args[0], args[1], s.mem())
|
||||
return nil
|
||||
},
|
||||
sys.PPC64)
|
||||
|
||||
addF("runtime/internal/atomic", "Xchg",
|
||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||
@ -3530,12 +3546,24 @@ func init() {
|
||||
return nil
|
||||
},
|
||||
sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
|
||||
addF("runtime/internal/atomic", "And",
|
||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||
s.vars[&memVar] = s.newValue3(ssa.OpAtomicAnd32, types.TypeMem, args[0], args[1], s.mem())
|
||||
return nil
|
||||
},
|
||||
sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
|
||||
addF("runtime/internal/atomic", "Or8",
|
||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||
s.vars[&memVar] = s.newValue3(ssa.OpAtomicOr8, types.TypeMem, args[0], args[1], s.mem())
|
||||
return nil
|
||||
},
|
||||
sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
|
||||
addF("runtime/internal/atomic", "Or",
|
||||
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
|
||||
s.vars[&memVar] = s.newValue3(ssa.OpAtomicOr32, types.TypeMem, args[0], args[1], s.mem())
|
||||
return nil
|
||||
},
|
||||
sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X)
|
||||
|
||||
alias("runtime/internal/atomic", "Loadint64", "runtime/internal/atomic", "Load64", all...)
|
||||
alias("runtime/internal/atomic", "Xaddint64", "runtime/internal/atomic", "Xadd64", all...)
|
||||
@ -3544,9 +3572,19 @@ func init() {
|
||||
alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load", p4...)
|
||||
alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load64", p8...)
|
||||
alias("runtime/internal/atomic", "LoadAcq", "runtime/internal/atomic", "Load", lwatomics...)
|
||||
alias("runtime/internal/atomic", "LoadAcq64", "runtime/internal/atomic", "Load64", lwatomics...)
|
||||
alias("runtime/internal/atomic", "LoadAcquintptr", "runtime/internal/atomic", "LoadAcq", p4...)
|
||||
alias("sync", "runtime_LoadAcquintptr", "runtime/internal/atomic", "LoadAcq", p4...) // linknamed
|
||||
alias("runtime/internal/atomic", "LoadAcquintptr", "runtime/internal/atomic", "LoadAcq64", p8...)
|
||||
alias("sync", "runtime_LoadAcquintptr", "runtime/internal/atomic", "LoadAcq64", p8...) // linknamed
|
||||
alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store", p4...)
|
||||
alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store64", p8...)
|
||||
alias("runtime/internal/atomic", "StoreRel", "runtime/internal/atomic", "Store", lwatomics...)
|
||||
alias("runtime/internal/atomic", "StoreRel64", "runtime/internal/atomic", "Store64", lwatomics...)
|
||||
alias("runtime/internal/atomic", "StoreReluintptr", "runtime/internal/atomic", "StoreRel", p4...)
|
||||
alias("sync", "runtime_StoreReluintptr", "runtime/internal/atomic", "StoreRel", p4...) // linknamed
|
||||
alias("runtime/internal/atomic", "StoreReluintptr", "runtime/internal/atomic", "StoreRel64", p8...)
|
||||
alias("sync", "runtime_StoreReluintptr", "runtime/internal/atomic", "StoreRel64", p8...) // linknamed
|
||||
alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg", p4...)
|
||||
alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg64", p8...)
|
||||
alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd", p4...)
|
||||
@ -4251,6 +4289,7 @@ func (s *state) openDeferExit() {
|
||||
s.lastDeferExit = deferExit
|
||||
s.lastDeferCount = len(s.openDefers)
|
||||
zeroval := s.constInt8(types.Types[TUINT8], 0)
|
||||
testLateExpansion := ssa.LateCallExpansionEnabledWithin(s.f)
|
||||
// Test for and run defers in reverse order
|
||||
for i := len(s.openDefers) - 1; i >= 0; i-- {
|
||||
r := s.openDefers[i]
|
||||
@ -4288,18 +4327,32 @@ func (s *state) openDeferExit() {
|
||||
stksize := fn.Type.ArgWidth()
|
||||
var ACArgs []ssa.Param
|
||||
var ACResults []ssa.Param
|
||||
var callArgs []*ssa.Value
|
||||
if r.rcvr != nil {
|
||||
// rcvr in case of OCALLINTER
|
||||
v := s.load(r.rcvr.Type.Elem(), r.rcvr)
|
||||
addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart)
|
||||
ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart)})
|
||||
if testLateExpansion {
|
||||
callArgs = append(callArgs, v)
|
||||
} else {
|
||||
s.store(types.Types[TUINTPTR], addr, v)
|
||||
}
|
||||
}
|
||||
for j, argAddrVal := range r.argVals {
|
||||
f := getParam(r.n, j)
|
||||
pt := types.NewPtr(f.Type)
|
||||
ACArgs = append(ACArgs, ssa.Param{Type: f.Type, Offset: int32(argStart + f.Offset)})
|
||||
if testLateExpansion {
|
||||
var a *ssa.Value
|
||||
if !canSSAType(f.Type) {
|
||||
a = s.newValue2(ssa.OpDereference, f.Type, argAddrVal, s.mem())
|
||||
} else {
|
||||
a = s.load(f.Type, argAddrVal)
|
||||
}
|
||||
callArgs = append(callArgs, a)
|
||||
} else {
|
||||
addr := s.constOffPtrSP(pt, argStart+f.Offset)
|
||||
ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(argStart + f.Offset)})
|
||||
if !canSSAType(f.Type) {
|
||||
s.move(f.Type, addr, argAddrVal)
|
||||
} else {
|
||||
@ -4307,18 +4360,37 @@ func (s *state) openDeferExit() {
|
||||
s.storeType(f.Type, addr, argVal, 0, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
var call *ssa.Value
|
||||
if r.closure != nil {
|
||||
v := s.load(r.closure.Type.Elem(), r.closure)
|
||||
s.maybeNilCheckClosure(v, callDefer)
|
||||
codeptr := s.rawLoad(types.Types[TUINTPTR], v)
|
||||
call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, ssa.ClosureAuxCall(ACArgs, ACResults), codeptr, v, s.mem())
|
||||
aux := ssa.ClosureAuxCall(ACArgs, ACResults)
|
||||
if testLateExpansion {
|
||||
callArgs = append(callArgs, s.mem())
|
||||
call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, v)
|
||||
call.AddArgs(callArgs...)
|
||||
} else {
|
||||
call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, aux, codeptr, v, s.mem())
|
||||
}
|
||||
} else {
|
||||
aux := ssa.StaticAuxCall(fn.Sym.Linksym(), ACArgs, ACResults)
|
||||
if testLateExpansion {
|
||||
callArgs = append(callArgs, s.mem())
|
||||
call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
|
||||
call.AddArgs(callArgs...)
|
||||
} else {
|
||||
// Do a static call if the original call was a static function or method
|
||||
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(fn.Sym.Linksym(), ACArgs, ACResults), s.mem())
|
||||
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
|
||||
}
|
||||
}
|
||||
call.AuxInt = stksize
|
||||
if testLateExpansion {
|
||||
s.vars[&memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
|
||||
} else {
|
||||
s.vars[&memVar] = call
|
||||
}
|
||||
// Make sure that the stack slots with pointers are kept live
|
||||
// through the call (which is a pre-emption point). Also, we will
|
||||
// use the first call of the last defer exit to compute liveness
|
||||
@ -4375,11 +4447,9 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
|
||||
|
||||
switch n.Op {
|
||||
case OCALLFUNC:
|
||||
testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
|
||||
if k == callNormal && fn.Op == ONAME && fn.Class() == PFUNC {
|
||||
sym = fn.Sym
|
||||
if !returnResultAddr && strings.Contains(sym.Name, "testLateExpansion") {
|
||||
testLateExpansion = true
|
||||
}
|
||||
break
|
||||
}
|
||||
closure = s.expr(fn)
|
||||
@ -4392,11 +4462,9 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
|
||||
if fn.Op != ODOTMETH {
|
||||
s.Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
|
||||
}
|
||||
testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
|
||||
if k == callNormal {
|
||||
sym = fn.Sym
|
||||
if !returnResultAddr && strings.Contains(sym.Name, "testLateExpansion") {
|
||||
testLateExpansion = true
|
||||
}
|
||||
break
|
||||
}
|
||||
closure = s.getMethodClosure(fn)
|
||||
@ -4406,6 +4474,7 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
|
||||
if fn.Op != ODOTINTER {
|
||||
s.Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
|
||||
}
|
||||
testLateExpansion = k != callDeferStack && ssa.LateCallExpansionEnabledWithin(s.f)
|
||||
var iclosure *ssa.Value
|
||||
iclosure, rcvr = s.getClosureAndRcvr(fn)
|
||||
if k == callNormal {
|
||||
@ -4424,6 +4493,7 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
|
||||
|
||||
var call *ssa.Value
|
||||
if k == callDeferStack {
|
||||
testLateExpansion = ssa.LateCallExpansionEnabledWithin(s.f)
|
||||
// Make a defer struct d on the stack.
|
||||
t := deferstruct(stksize)
|
||||
d := tempAt(n.Pos, s.curfn, t)
|
||||
@ -4474,10 +4544,17 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
|
||||
}
|
||||
|
||||
// Call runtime.deferprocStack with pointer to _defer record.
|
||||
ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(Ctxt.FixedFrameSize())})
|
||||
aux := ssa.StaticAuxCall(deferprocStack, ACArgs, ACResults)
|
||||
if testLateExpansion {
|
||||
callArgs = append(callArgs, addr, s.mem())
|
||||
call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
|
||||
call.AddArgs(callArgs...)
|
||||
} else {
|
||||
arg0 := s.constOffPtrSP(types.Types[TUINTPTR], Ctxt.FixedFrameSize())
|
||||
s.store(types.Types[TUINTPTR], arg0, addr)
|
||||
ACArgs = append(ACArgs, ssa.Param{Type: types.Types[TUINTPTR], Offset: int32(Ctxt.FixedFrameSize())})
|
||||
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(deferprocStack, ACArgs, ACResults), s.mem())
|
||||
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
|
||||
}
|
||||
if stksize < int64(Widthptr) {
|
||||
// We need room for both the call to deferprocStack and the call to
|
||||
// the deferred function.
|
||||
@ -4544,9 +4621,21 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
|
||||
// call target
|
||||
switch {
|
||||
case k == callDefer:
|
||||
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(deferproc, ACArgs, ACResults), s.mem())
|
||||
aux := ssa.StaticAuxCall(deferproc, ACArgs, ACResults)
|
||||
if testLateExpansion {
|
||||
call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
|
||||
call.AddArgs(callArgs...)
|
||||
} else {
|
||||
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
|
||||
}
|
||||
case k == callGo:
|
||||
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(newproc, ACArgs, ACResults), s.mem())
|
||||
aux := ssa.StaticAuxCall(newproc, ACArgs, ACResults)
|
||||
if testLateExpansion {
|
||||
call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
|
||||
call.AddArgs(callArgs...)
|
||||
} else {
|
||||
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
|
||||
}
|
||||
case closure != nil:
|
||||
// rawLoad because loading the code pointer from a
|
||||
// closure is always safe, but IsSanitizerSafeAddr
|
||||
@ -4554,18 +4643,25 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
|
||||
// critical that we not clobber any arguments already
|
||||
// stored onto the stack.
|
||||
codeptr = s.rawLoad(types.Types[TUINTPTR], closure)
|
||||
if testLateExpansion {
|
||||
aux := ssa.ClosureAuxCall(ACArgs, ACResults)
|
||||
call = s.newValue2A(ssa.OpClosureLECall, aux.LateExpansionResultType(), aux, codeptr, closure)
|
||||
call.AddArgs(callArgs...)
|
||||
} else {
|
||||
call = s.newValue3A(ssa.OpClosureCall, types.TypeMem, ssa.ClosureAuxCall(ACArgs, ACResults), codeptr, closure, s.mem())
|
||||
}
|
||||
case codeptr != nil:
|
||||
if testLateExpansion {
|
||||
aux := ssa.InterfaceAuxCall(ACArgs, ACResults)
|
||||
call = s.newValue1A(ssa.OpInterLECall, aux.LateExpansionResultType(), aux, codeptr)
|
||||
call.AddArgs(callArgs...)
|
||||
} else {
|
||||
call = s.newValue2A(ssa.OpInterCall, types.TypeMem, ssa.InterfaceAuxCall(ACArgs, ACResults), codeptr, s.mem())
|
||||
}
|
||||
case sym != nil:
|
||||
if testLateExpansion {
|
||||
var tys []*types.Type
|
||||
aux := ssa.StaticAuxCall(sym.Linksym(), ACArgs, ACResults)
|
||||
for i := int64(0); i < aux.NResults(); i++ {
|
||||
tys = append(tys, aux.TypeOfResult(i))
|
||||
}
|
||||
tys = append(tys, types.TypeMem)
|
||||
call = s.newValue0A(ssa.OpStaticLECall, types.NewResults(tys), aux)
|
||||
call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
|
||||
call.AddArgs(callArgs...)
|
||||
} else {
|
||||
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(sym.Linksym(), ACArgs, ACResults), s.mem())
|
||||
@ -4606,7 +4702,11 @@ func (s *state) call(n *Node, k callKind, returnResultAddr bool) *ssa.Value {
|
||||
}
|
||||
fp := res.Field(0)
|
||||
if returnResultAddr {
|
||||
return s.constOffPtrSP(types.NewPtr(fp.Type), fp.Offset+Ctxt.FixedFrameSize())
|
||||
pt := types.NewPtr(fp.Type)
|
||||
if testLateExpansion {
|
||||
return s.newValue1I(ssa.OpSelectNAddr, pt, 0, call)
|
||||
}
|
||||
return s.constOffPtrSP(pt, fp.Offset+Ctxt.FixedFrameSize())
|
||||
}
|
||||
|
||||
if testLateExpansion {
|
||||
@ -4649,7 +4749,7 @@ func (s *state) getClosureAndRcvr(fn *Node) (*ssa.Value, *ssa.Value) {
|
||||
s.nilCheck(itab)
|
||||
itabidx := fn.Xoffset + 2*int64(Widthptr) + 8 // offset of fun field in runtime.itab
|
||||
closure := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab)
|
||||
rcvr := s.newValue1(ssa.OpIData, types.Types[TUINTPTR], i)
|
||||
rcvr := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, i)
|
||||
return closure, rcvr
|
||||
}
|
||||
|
||||
@ -4710,7 +4810,7 @@ func (s *state) addr(n *Node) *ssa.Value {
|
||||
}
|
||||
case ORESULT:
|
||||
// load return from callee
|
||||
if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall {
|
||||
if s.prevCall == nil || s.prevCall.Op != ssa.OpStaticLECall && s.prevCall.Op != ssa.OpInterLECall && s.prevCall.Op != ssa.OpClosureLECall {
|
||||
return s.constOffPtrSP(t, n.Xoffset)
|
||||
}
|
||||
which := s.prevCall.Aux.(*ssa.AuxCall).ResultForOffset(n.Xoffset)
|
||||
@ -4770,7 +4870,7 @@ func (s *state) addr(n *Node) *ssa.Value {
|
||||
// canSSA reports whether n is SSA-able.
|
||||
// n must be an ONAME (or an ODOT sequence with an ONAME base).
|
||||
func (s *state) canSSA(n *Node) bool {
|
||||
if Debug['N'] != 0 {
|
||||
if Debug.N != 0 {
|
||||
return false
|
||||
}
|
||||
for n.Op == ODOT || (n.Op == OINDEX && n.Left.Type.IsArray()) {
|
||||
@ -4881,7 +4981,7 @@ func (s *state) nilCheck(ptr *ssa.Value) {
|
||||
func (s *state) boundsCheck(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
|
||||
idx = s.extendIndex(idx, len, kind, bounded)
|
||||
|
||||
if bounded || Debug['B'] != 0 {
|
||||
if bounded || Debug.B != 0 {
|
||||
// If bounded or bounds checking is flag-disabled, then no check necessary,
|
||||
// just return the extended index.
|
||||
//
|
||||
@ -5013,15 +5113,22 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args .
|
||||
s.prevCall = nil
|
||||
// Write args to the stack
|
||||
off := Ctxt.FixedFrameSize()
|
||||
testLateExpansion := ssa.LateCallExpansionEnabledWithin(s.f)
|
||||
var ACArgs []ssa.Param
|
||||
var ACResults []ssa.Param
|
||||
var callArgs []*ssa.Value
|
||||
|
||||
for _, arg := range args {
|
||||
t := arg.Type
|
||||
off = Rnd(off, t.Alignment())
|
||||
ptr := s.constOffPtrSP(t.PtrTo(), off)
|
||||
size := t.Size()
|
||||
ACArgs = append(ACArgs, ssa.Param{Type: t, Offset: int32(off)})
|
||||
if testLateExpansion {
|
||||
callArgs = append(callArgs, arg)
|
||||
} else {
|
||||
ptr := s.constOffPtrSP(t.PtrTo(), off)
|
||||
s.store(t, ptr, arg)
|
||||
}
|
||||
off += size
|
||||
}
|
||||
off = Rnd(off, int64(Widthreg))
|
||||
@ -5035,8 +5142,17 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args .
|
||||
}
|
||||
|
||||
// Issue call
|
||||
call := s.newValue1A(ssa.OpStaticCall, types.TypeMem, ssa.StaticAuxCall(fn, ACArgs, ACResults), s.mem())
|
||||
var call *ssa.Value
|
||||
aux := ssa.StaticAuxCall(fn, ACArgs, ACResults)
|
||||
if testLateExpansion {
|
||||
callArgs = append(callArgs, s.mem())
|
||||
call = s.newValue0A(ssa.OpStaticLECall, aux.LateExpansionResultType(), aux)
|
||||
call.AddArgs(callArgs...)
|
||||
s.vars[&memVar] = s.newValue1I(ssa.OpSelectN, types.TypeMem, int64(len(ACResults)), call)
|
||||
} else {
|
||||
call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, aux, s.mem())
|
||||
s.vars[&memVar] = call
|
||||
}
|
||||
|
||||
if !returns {
|
||||
// Finish block
|
||||
@ -5052,12 +5168,25 @@ func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args .
|
||||
|
||||
// Load results
|
||||
res := make([]*ssa.Value, len(results))
|
||||
if testLateExpansion {
|
||||
for i, t := range results {
|
||||
off = Rnd(off, t.Alignment())
|
||||
if canSSAType(t) {
|
||||
res[i] = s.newValue1I(ssa.OpSelectN, t, int64(i), call)
|
||||
} else {
|
||||
addr := s.newValue1I(ssa.OpSelectNAddr, types.NewPtr(t), int64(i), call)
|
||||
res[i] = s.rawLoad(t, addr)
|
||||
}
|
||||
off += t.Size()
|
||||
}
|
||||
} else {
|
||||
for i, t := range results {
|
||||
off = Rnd(off, t.Alignment())
|
||||
ptr := s.constOffPtrSP(types.NewPtr(t), off)
|
||||
res[i] = s.load(t, ptr)
|
||||
off += t.Size()
|
||||
}
|
||||
}
|
||||
off = Rnd(off, int64(Widthptr))
|
||||
|
||||
// Remember how much callee stack space we needed.
|
||||
@ -5093,7 +5222,10 @@ func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip ski
|
||||
case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
|
||||
s.store(t, left, right)
|
||||
case t.IsPtrShaped():
|
||||
// no scalar fields.
|
||||
if t.IsPtr() && t.Elem().NotInHeap() {
|
||||
s.store(t, left, right) // see issue 42032
|
||||
}
|
||||
// otherwise, no scalar fields.
|
||||
case t.IsString():
|
||||
if skip&skipLen != 0 {
|
||||
return
|
||||
@ -5137,6 +5269,9 @@ func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip ski
|
||||
func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) {
|
||||
switch {
|
||||
case t.IsPtrShaped():
|
||||
if t.IsPtr() && t.Elem().NotInHeap() {
|
||||
break // see issue 42032
|
||||
}
|
||||
s.store(t, left, right)
|
||||
case t.IsString():
|
||||
ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, right)
|
||||
@ -5913,9 +6048,7 @@ type SSAGenState struct {
|
||||
// bstart remembers where each block starts (indexed by block ID)
|
||||
bstart []*obj.Prog
|
||||
|
||||
// 387 port: maps from SSE registers (REG_X?) to 387 registers (REG_F?)
|
||||
SSEto387 map[int16]int16
|
||||
// Some architectures require a 64-bit temporary for FP-related register shuffling. Examples include x86-387, PPC, and Sparc V8.
|
||||
// Some architectures require a 64-bit temporary for FP-related register shuffling. Examples include PPC and Sparc V8.
|
||||
ScratchFpMem *Node
|
||||
|
||||
maxarg int64 // largest frame size for arguments to calls made by the function
|
||||
@ -6021,7 +6154,7 @@ func emitStackObjects(e *ssafn, pp *Progs) {
|
||||
|
||||
// Populate the stack object data.
|
||||
// Format must match runtime/stack.go:stackObjectRecord.
|
||||
x := e.curfn.Func.lsym.Func.StackObjects
|
||||
x := e.curfn.Func.lsym.Func().StackObjects
|
||||
off := 0
|
||||
off = duintptr(x, off, uint64(len(vars)))
|
||||
for _, v := range vars {
|
||||
@ -6058,7 +6191,7 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
s.livenessMap = liveness(e, f, pp)
|
||||
emitStackObjects(e, pp)
|
||||
|
||||
openDeferInfo := e.curfn.Func.lsym.Func.OpenCodedDeferInfo
|
||||
openDeferInfo := e.curfn.Func.lsym.Func().OpenCodedDeferInfo
|
||||
if openDeferInfo != nil {
|
||||
// This function uses open-coded defers -- write out the funcdata
|
||||
// info that we computed at the end of genssa.
|
||||
@ -6082,10 +6215,6 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
progToBlock[s.pp.next] = f.Blocks[0]
|
||||
}
|
||||
|
||||
if thearch.Use387 {
|
||||
s.SSEto387 = map[int16]int16{}
|
||||
}
|
||||
|
||||
s.ScratchFpMem = e.scratchFpMem
|
||||
|
||||
if Ctxt.Flag_locationlists {
|
||||
@ -6208,7 +6337,7 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
}
|
||||
// Emit control flow instructions for block
|
||||
var next *ssa.Block
|
||||
if i < len(f.Blocks)-1 && Debug['N'] == 0 {
|
||||
if i < len(f.Blocks)-1 && Debug.N == 0 {
|
||||
// If -N, leave next==nil so every block with successors
|
||||
// ends in a JMP (except call blocks - plive doesn't like
|
||||
// select{send,recv} followed by a JMP call). Helps keep
|
||||
@ -6267,7 +6396,7 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
// some of the inline marks.
|
||||
// Use this instruction instead.
|
||||
p.Pos = p.Pos.WithIsStmt() // promote position to a statement
|
||||
pp.curfn.Func.lsym.Func.AddInlMark(p, inlMarks[m])
|
||||
pp.curfn.Func.lsym.Func().AddInlMark(p, inlMarks[m])
|
||||
// Make the inline mark a real nop, so it doesn't generate any code.
|
||||
m.As = obj.ANOP
|
||||
m.Pos = src.NoXPos
|
||||
@ -6279,7 +6408,7 @@ func genssa(f *ssa.Func, pp *Progs) {
|
||||
// Any unmatched inline marks now need to be added to the inlining tree (and will generate a nop instruction).
|
||||
for _, p := range inlMarkList {
|
||||
if p.As != obj.ANOP {
|
||||
pp.curfn.Func.lsym.Func.AddInlMark(p, inlMarks[p])
|
||||
pp.curfn.Func.lsym.Func().AddInlMark(p, inlMarks[p])
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6516,7 +6645,7 @@ func (s *state) extendIndex(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bo
|
||||
} else {
|
||||
lo = s.newValue1(ssa.OpInt64Lo, types.Types[TUINT], idx)
|
||||
}
|
||||
if bounded || Debug['B'] != 0 {
|
||||
if bounded || Debug.B != 0 {
|
||||
return lo
|
||||
}
|
||||
bNext := s.f.NewBlock(ssa.BlockPlain)
|
||||
@ -6790,56 +6919,38 @@ func (e *ssafn) Auto(pos src.XPos, t *types.Type) ssa.GCNode {
|
||||
}
|
||||
|
||||
func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
||||
n := name.N.(*Node)
|
||||
ptrType := types.NewPtr(types.Types[TUINT8])
|
||||
lenType := types.Types[TINT]
|
||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
||||
// Split this string up into two separate variables.
|
||||
p := e.splitSlot(&name, ".ptr", 0, ptrType)
|
||||
l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
|
||||
p := e.SplitSlot(&name, ".ptr", 0, ptrType)
|
||||
l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
|
||||
return p, l
|
||||
}
|
||||
// Return the two parts of the larger variable.
|
||||
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)}
|
||||
}
|
||||
|
||||
func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
||||
n := name.N.(*Node)
|
||||
u := types.Types[TUINTPTR]
|
||||
t := types.NewPtr(types.Types[TUINT8])
|
||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
||||
// Split this interface up into two separate variables.
|
||||
f := ".itab"
|
||||
if n.Type.IsEmptyInterface() {
|
||||
f = ".type"
|
||||
}
|
||||
c := e.splitSlot(&name, f, 0, u) // see comment in plive.go:onebitwalktype1.
|
||||
d := e.splitSlot(&name, ".data", u.Size(), t)
|
||||
c := e.SplitSlot(&name, f, 0, u) // see comment in plive.go:onebitwalktype1.
|
||||
d := e.SplitSlot(&name, ".data", u.Size(), t)
|
||||
return c, d
|
||||
}
|
||||
// Return the two parts of the larger variable.
|
||||
return ssa.LocalSlot{N: n, Type: u, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)}
|
||||
}
|
||||
|
||||
func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
|
||||
n := name.N.(*Node)
|
||||
ptrType := types.NewPtr(name.Type.Elem())
|
||||
lenType := types.Types[TINT]
|
||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
||||
// Split this slice up into three separate variables.
|
||||
p := e.splitSlot(&name, ".ptr", 0, ptrType)
|
||||
l := e.splitSlot(&name, ".len", ptrType.Size(), lenType)
|
||||
c := e.splitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
|
||||
p := e.SplitSlot(&name, ".ptr", 0, ptrType)
|
||||
l := e.SplitSlot(&name, ".len", ptrType.Size(), lenType)
|
||||
c := e.SplitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType)
|
||||
return p, l, c
|
||||
}
|
||||
// Return the three parts of the larger variable.
|
||||
return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off},
|
||||
ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)},
|
||||
ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(2*Widthptr)}
|
||||
}
|
||||
|
||||
func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
||||
n := name.N.(*Node)
|
||||
s := name.Type.Size() / 2
|
||||
var t *types.Type
|
||||
if s == 8 {
|
||||
@ -6847,53 +6958,30 @@ func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot)
|
||||
} else {
|
||||
t = types.Types[TFLOAT32]
|
||||
}
|
||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
||||
// Split this complex up into two separate variables.
|
||||
r := e.splitSlot(&name, ".real", 0, t)
|
||||
i := e.splitSlot(&name, ".imag", t.Size(), t)
|
||||
r := e.SplitSlot(&name, ".real", 0, t)
|
||||
i := e.SplitSlot(&name, ".imag", t.Size(), t)
|
||||
return r, i
|
||||
}
|
||||
// Return the two parts of the larger variable.
|
||||
return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + s}
|
||||
}
|
||||
|
||||
func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
|
||||
n := name.N.(*Node)
|
||||
var t *types.Type
|
||||
if name.Type.IsSigned() {
|
||||
t = types.Types[TINT32]
|
||||
} else {
|
||||
t = types.Types[TUINT32]
|
||||
}
|
||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
||||
// Split this int64 up into two separate variables.
|
||||
if thearch.LinkArch.ByteOrder == binary.BigEndian {
|
||||
return e.splitSlot(&name, ".hi", 0, t), e.splitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
|
||||
return e.SplitSlot(&name, ".hi", 0, t), e.SplitSlot(&name, ".lo", t.Size(), types.Types[TUINT32])
|
||||
}
|
||||
return e.splitSlot(&name, ".hi", t.Size(), t), e.splitSlot(&name, ".lo", 0, types.Types[TUINT32])
|
||||
}
|
||||
// Return the two parts of the larger variable.
|
||||
if thearch.LinkArch.ByteOrder == binary.BigEndian {
|
||||
return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: types.Types[TUINT32], Off: name.Off + 4}
|
||||
}
|
||||
return ssa.LocalSlot{N: n, Type: t, Off: name.Off + 4}, ssa.LocalSlot{N: n, Type: types.Types[TUINT32], Off: name.Off}
|
||||
return e.SplitSlot(&name, ".hi", t.Size(), t), e.SplitSlot(&name, ".lo", 0, types.Types[TUINT32])
|
||||
}
|
||||
|
||||
func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
|
||||
n := name.N.(*Node)
|
||||
st := name.Type
|
||||
ft := st.FieldType(i)
|
||||
var offset int64
|
||||
for f := 0; f < i; f++ {
|
||||
offset += st.FieldType(f).Size()
|
||||
}
|
||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
||||
// Note: the _ field may appear several times. But
|
||||
// have no fear, identically-named but distinct Autos are
|
||||
// ok, albeit maybe confusing for a debugger.
|
||||
return e.splitSlot(&name, "."+st.FieldName(i), offset, ft)
|
||||
}
|
||||
return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)}
|
||||
return e.SplitSlot(&name, "."+st.FieldName(i), st.FieldOff(i), st.FieldType(i))
|
||||
}
|
||||
|
||||
func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
|
||||
@ -6903,19 +6991,23 @@ func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot {
|
||||
e.Fatalf(n.Pos, "bad array size")
|
||||
}
|
||||
et := at.Elem()
|
||||
if n.Class() == PAUTO && !n.Name.Addrtaken() {
|
||||
return e.splitSlot(&name, "[0]", 0, et)
|
||||
}
|
||||
return ssa.LocalSlot{N: n, Type: et, Off: name.Off}
|
||||
return e.SplitSlot(&name, "[0]", 0, et)
|
||||
}
|
||||
|
||||
func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym {
|
||||
return itabsym(it, offset)
|
||||
}
|
||||
|
||||
// splitSlot returns a slot representing the data of parent starting at offset.
|
||||
func (e *ssafn) splitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
|
||||
s := &types.Sym{Name: parent.N.(*Node).Sym.Name + suffix, Pkg: localpkg}
|
||||
// SplitSlot returns a slot representing the data of parent starting at offset.
|
||||
func (e *ssafn) SplitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot {
|
||||
node := parent.N.(*Node)
|
||||
|
||||
if node.Class() != PAUTO || node.Name.Addrtaken() {
|
||||
// addressed things and non-autos retain their parents (i.e., cannot truly be split)
|
||||
return ssa.LocalSlot{N: node, Type: t, Off: parent.Off + offset}
|
||||
}
|
||||
|
||||
s := &types.Sym{Name: node.Sym.Name + suffix, Pkg: localpkg}
|
||||
|
||||
n := &Node{
|
||||
Name: new(Name),
|
||||
|
@ -96,7 +96,7 @@ func flusherrors() {
|
||||
}
|
||||
|
||||
func hcrash() {
|
||||
if Debug['h'] != 0 {
|
||||
if Debug.h != 0 {
|
||||
flusherrors()
|
||||
if outfile != "" {
|
||||
os.Remove(outfile)
|
||||
@ -107,7 +107,7 @@ func hcrash() {
|
||||
}
|
||||
|
||||
func linestr(pos src.XPos) string {
|
||||
return Ctxt.OutermostPos(pos).Format(Debug['C'] == 0, Debug['L'] == 1)
|
||||
return Ctxt.OutermostPos(pos).Format(Debug.C == 0, Debug.L == 1)
|
||||
}
|
||||
|
||||
// lasterror keeps track of the most recently issued error.
|
||||
@ -153,7 +153,7 @@ func yyerrorl(pos src.XPos, format string, args ...interface{}) {
|
||||
|
||||
hcrash()
|
||||
nerrors++
|
||||
if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
|
||||
if nsavederrors+nerrors >= 10 && Debug.e == 0 {
|
||||
flusherrors()
|
||||
fmt.Printf("%v: too many errors\n", linestr(pos))
|
||||
errorexit()
|
||||
@ -175,7 +175,7 @@ func Warn(fmt_ string, args ...interface{}) {
|
||||
|
||||
func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
|
||||
adderr(line, fmt_, args...)
|
||||
if Debug['m'] != 0 {
|
||||
if Debug.m != 0 {
|
||||
flusherrors()
|
||||
}
|
||||
}
|
||||
@ -222,7 +222,7 @@ func hasUniquePos(n *Node) bool {
|
||||
}
|
||||
|
||||
if !n.Pos.IsKnown() {
|
||||
if Debug['K'] != 0 {
|
||||
if Debug.K != 0 {
|
||||
Warn("setlineno: unknown position (line 0)")
|
||||
}
|
||||
return false
|
||||
@ -348,7 +348,7 @@ func newname(s *types.Sym) *Node {
|
||||
return n
|
||||
}
|
||||
|
||||
// newname returns a new ONAME Node associated with symbol s at position pos.
|
||||
// newnamel returns a new ONAME Node associated with symbol s at position pos.
|
||||
// The caller is responsible for setting n.Name.Curfn.
|
||||
func newnamel(pos src.XPos, s *types.Sym) *Node {
|
||||
if s == nil {
|
||||
@ -546,22 +546,19 @@ func methtype(t *types.Type) *types.Type {
|
||||
|
||||
// Is type src assignment compatible to type dst?
|
||||
// If so, return op code to use in conversion.
|
||||
// If not, return OXXX.
|
||||
func assignop(src, dst *types.Type, why *string) Op {
|
||||
if why != nil {
|
||||
*why = ""
|
||||
}
|
||||
|
||||
// If not, return OXXX. In this case, the string return parameter may
|
||||
// hold a reason why. In all other cases, it'll be the empty string.
|
||||
func assignop(src, dst *types.Type) (Op, string) {
|
||||
if src == dst {
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
if src == nil || dst == nil || src.Etype == TFORW || dst.Etype == TFORW || src.Orig == nil || dst.Orig == nil {
|
||||
return OXXX
|
||||
return OXXX, ""
|
||||
}
|
||||
|
||||
// 1. src type is identical to dst.
|
||||
if types.Identical(src, dst) {
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
|
||||
// 2. src and dst have identical underlying types
|
||||
@ -575,13 +572,13 @@ func assignop(src, dst *types.Type, why *string) Op {
|
||||
if src.IsEmptyInterface() {
|
||||
// Conversion between two empty interfaces
|
||||
// requires no code.
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
if (src.Sym == nil || dst.Sym == nil) && !src.IsInterface() {
|
||||
// Conversion between two types, at least one unnamed,
|
||||
// needs no conversion. The exception is nonempty interfaces
|
||||
// which need to have their itab updated.
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
}
|
||||
|
||||
@ -590,49 +587,47 @@ func assignop(src, dst *types.Type, why *string) Op {
|
||||
var missing, have *types.Field
|
||||
var ptr int
|
||||
if implements(src, dst, &missing, &have, &ptr) {
|
||||
return OCONVIFACE
|
||||
return OCONVIFACE, ""
|
||||
}
|
||||
|
||||
// we'll have complained about this method anyway, suppress spurious messages.
|
||||
if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) {
|
||||
return OCONVIFACE
|
||||
return OCONVIFACE, ""
|
||||
}
|
||||
|
||||
if why != nil {
|
||||
var why string
|
||||
if isptrto(src, TINTER) {
|
||||
*why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
|
||||
why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
|
||||
} else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
|
||||
*why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
|
||||
why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
|
||||
} else if have != nil && have.Sym == missing.Sym {
|
||||
*why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
|
||||
why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
|
||||
"\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
|
||||
} else if ptr != 0 {
|
||||
*why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
|
||||
why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
|
||||
} else if have != nil {
|
||||
*why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
|
||||
why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
|
||||
"\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
|
||||
} else {
|
||||
*why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
|
||||
}
|
||||
why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
|
||||
}
|
||||
|
||||
return OXXX
|
||||
return OXXX, why
|
||||
}
|
||||
|
||||
if isptrto(dst, TINTER) {
|
||||
if why != nil {
|
||||
*why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
|
||||
}
|
||||
return OXXX
|
||||
why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
|
||||
return OXXX, why
|
||||
}
|
||||
|
||||
if src.IsInterface() && dst.Etype != TBLANK {
|
||||
var missing, have *types.Field
|
||||
var ptr int
|
||||
if why != nil && implements(dst, src, &missing, &have, &ptr) {
|
||||
*why = ": need type assertion"
|
||||
var why string
|
||||
if implements(dst, src, &missing, &have, &ptr) {
|
||||
why = ": need type assertion"
|
||||
}
|
||||
return OXXX
|
||||
return OXXX, why
|
||||
}
|
||||
|
||||
// 4. src is a bidirectional channel value, dst is a channel type,
|
||||
@ -640,7 +635,7 @@ func assignop(src, dst *types.Type, why *string) Op {
|
||||
// either src or dst is not a named type.
|
||||
if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
|
||||
if types.Identical(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) {
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
}
|
||||
|
||||
@ -653,7 +648,7 @@ func assignop(src, dst *types.Type, why *string) Op {
|
||||
TCHAN,
|
||||
TINTER,
|
||||
TSLICE:
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
}
|
||||
|
||||
@ -661,26 +656,23 @@ func assignop(src, dst *types.Type, why *string) Op {
|
||||
|
||||
// 7. Any typed value can be assigned to the blank identifier.
|
||||
if dst.Etype == TBLANK {
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
|
||||
return OXXX
|
||||
return OXXX, ""
|
||||
}
|
||||
|
||||
// Can we convert a value of type src to a value of type dst?
|
||||
// If so, return op code to use in conversion (maybe OCONVNOP).
|
||||
// If not, return OXXX.
|
||||
// If not, return OXXX. In this case, the string return parameter may
|
||||
// hold a reason why. In all other cases, it'll be the empty string.
|
||||
// srcConstant indicates whether the value of type src is a constant.
|
||||
func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
|
||||
if why != nil {
|
||||
*why = ""
|
||||
}
|
||||
|
||||
func convertop(srcConstant bool, src, dst *types.Type) (Op, string) {
|
||||
if src == dst {
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
if src == nil || dst == nil {
|
||||
return OXXX
|
||||
return OXXX, ""
|
||||
}
|
||||
|
||||
// Conversions from regular to go:notinheap are not allowed
|
||||
@ -688,23 +680,19 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
|
||||
// rules.
|
||||
// (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't.
|
||||
if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
|
||||
if why != nil {
|
||||
*why = fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
|
||||
}
|
||||
return OXXX
|
||||
why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
|
||||
return OXXX, why
|
||||
}
|
||||
// (b) Disallow string to []T where T is go:notinheap.
|
||||
if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Etype == types.Bytetype.Etype || dst.Elem().Etype == types.Runetype.Etype) {
|
||||
if why != nil {
|
||||
*why = fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
|
||||
}
|
||||
return OXXX
|
||||
why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
|
||||
return OXXX, why
|
||||
}
|
||||
|
||||
// 1. src can be assigned to dst.
|
||||
op := assignop(src, dst, why)
|
||||
op, why := assignop(src, dst)
|
||||
if op != OXXX {
|
||||
return op
|
||||
return op, why
|
||||
}
|
||||
|
||||
// The rules for interfaces are no different in conversions
|
||||
@ -712,60 +700,57 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
|
||||
// with the good message from assignop.
|
||||
// Otherwise clear the error.
|
||||
if src.IsInterface() || dst.IsInterface() {
|
||||
return OXXX
|
||||
}
|
||||
if why != nil {
|
||||
*why = ""
|
||||
return OXXX, why
|
||||
}
|
||||
|
||||
// 2. Ignoring struct tags, src and dst have identical underlying types.
|
||||
if types.IdenticalIgnoreTags(src.Orig, dst.Orig) {
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
|
||||
// 3. src and dst are unnamed pointer types and, ignoring struct tags,
|
||||
// their base types have identical underlying types.
|
||||
if src.IsPtr() && dst.IsPtr() && src.Sym == nil && dst.Sym == nil {
|
||||
if types.IdenticalIgnoreTags(src.Elem().Orig, dst.Elem().Orig) {
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
}
|
||||
|
||||
// 4. src and dst are both integer or floating point types.
|
||||
if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
|
||||
if simtype[src.Etype] == simtype[dst.Etype] {
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
return OCONV
|
||||
return OCONV, ""
|
||||
}
|
||||
|
||||
// 5. src and dst are both complex types.
|
||||
if src.IsComplex() && dst.IsComplex() {
|
||||
if simtype[src.Etype] == simtype[dst.Etype] {
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
return OCONV
|
||||
return OCONV, ""
|
||||
}
|
||||
|
||||
// Special case for constant conversions: any numeric
|
||||
// conversion is potentially okay. We'll validate further
|
||||
// within evconst. See #38117.
|
||||
if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) {
|
||||
return OCONV
|
||||
return OCONV, ""
|
||||
}
|
||||
|
||||
// 6. src is an integer or has type []byte or []rune
|
||||
// and dst is a string type.
|
||||
if src.IsInteger() && dst.IsString() {
|
||||
return ORUNESTR
|
||||
return ORUNESTR, ""
|
||||
}
|
||||
|
||||
if src.IsSlice() && dst.IsString() {
|
||||
if src.Elem().Etype == types.Bytetype.Etype {
|
||||
return OBYTES2STR
|
||||
return OBYTES2STR, ""
|
||||
}
|
||||
if src.Elem().Etype == types.Runetype.Etype {
|
||||
return ORUNES2STR
|
||||
return ORUNES2STR, ""
|
||||
}
|
||||
}
|
||||
|
||||
@ -773,21 +758,21 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
|
||||
// String to slice.
|
||||
if src.IsString() && dst.IsSlice() {
|
||||
if dst.Elem().Etype == types.Bytetype.Etype {
|
||||
return OSTR2BYTES
|
||||
return OSTR2BYTES, ""
|
||||
}
|
||||
if dst.Elem().Etype == types.Runetype.Etype {
|
||||
return OSTR2RUNES
|
||||
return OSTR2RUNES, ""
|
||||
}
|
||||
}
|
||||
|
||||
// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
|
||||
if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
|
||||
// 9. src is unsafe.Pointer and dst is a pointer or uintptr.
|
||||
if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
|
||||
// src is map and dst is a pointer to corresponding hmap.
|
||||
@ -795,10 +780,10 @@ func convertop(srcConstant bool, src, dst *types.Type, why *string) Op {
|
||||
// go gc maps are implemented as a pointer to a hmap struct.
|
||||
if src.Etype == TMAP && dst.IsPtr() &&
|
||||
src.MapType().Hmap == dst.Elem() {
|
||||
return OCONVNOP
|
||||
return OCONVNOP, ""
|
||||
}
|
||||
|
||||
return OXXX
|
||||
return OXXX, ""
|
||||
}
|
||||
|
||||
func assignconv(n *Node, t *types.Type, context string) *Node {
|
||||
@ -825,7 +810,7 @@ func assignconvfn(n *Node, t *types.Type, context func() string) *Node {
|
||||
|
||||
// Convert ideal bool from comparison to plain bool
|
||||
// if the next step is non-bool (like interface{}).
|
||||
if n.Type == types.Idealbool && !t.IsBoolean() {
|
||||
if n.Type == types.UntypedBool && !t.IsBoolean() {
|
||||
if n.Op == ONAME || n.Op == OLITERAL {
|
||||
r := nod(OCONVNOP, n, nil)
|
||||
r.Type = types.Types[TBOOL]
|
||||
@ -839,8 +824,7 @@ func assignconvfn(n *Node, t *types.Type, context func() string) *Node {
|
||||
return n
|
||||
}
|
||||
|
||||
var why string
|
||||
op := assignop(n.Type, t, &why)
|
||||
op, why := assignop(n.Type, t)
|
||||
if op == OXXX {
|
||||
yyerror("cannot use %L as type %v in %s%s", n, t, context(), why)
|
||||
op = OCONV
|
||||
@ -1040,25 +1024,24 @@ func calcHasCall(n *Node) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func badtype(op Op, tl *types.Type, tr *types.Type) {
|
||||
fmt_ := ""
|
||||
func badtype(op Op, tl, tr *types.Type) {
|
||||
var s string
|
||||
if tl != nil {
|
||||
fmt_ += fmt.Sprintf("\n\t%v", tl)
|
||||
s += fmt.Sprintf("\n\t%v", tl)
|
||||
}
|
||||
if tr != nil {
|
||||
fmt_ += fmt.Sprintf("\n\t%v", tr)
|
||||
s += fmt.Sprintf("\n\t%v", tr)
|
||||
}
|
||||
|
||||
// common mistake: *struct and *interface.
|
||||
if tl != nil && tr != nil && tl.IsPtr() && tr.IsPtr() {
|
||||
if tl.Elem().IsStruct() && tr.Elem().IsInterface() {
|
||||
fmt_ += "\n\t(*struct vs *interface)"
|
||||
s += "\n\t(*struct vs *interface)"
|
||||
} else if tl.Elem().IsInterface() && tr.Elem().IsStruct() {
|
||||
fmt_ += "\n\t(*interface vs *struct)"
|
||||
s += "\n\t(*interface vs *struct)"
|
||||
}
|
||||
}
|
||||
|
||||
s := fmt_
|
||||
yyerror("illegal types for operand: %v%s", op, s)
|
||||
}
|
||||
|
||||
@ -1523,7 +1506,7 @@ func structargs(tl *types.Type, mustname bool) []*Node {
|
||||
// method - M func (t T)(), a TFIELD type struct
|
||||
// newnam - the eventual mangled name of this function
|
||||
func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
||||
if false && Debug['r'] != 0 {
|
||||
if false && Debug.r != 0 {
|
||||
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
|
||||
}
|
||||
|
||||
@ -1596,7 +1579,7 @@ func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
||||
fn.Nbody.Append(call)
|
||||
}
|
||||
|
||||
if false && Debug['r'] != 0 {
|
||||
if false && Debug.r != 0 {
|
||||
dumplist("genwrapper body", fn.Nbody)
|
||||
}
|
||||
|
||||
@ -1737,7 +1720,7 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool
|
||||
// the method does not exist for value types.
|
||||
rcvr := tm.Type.Recv().Type
|
||||
if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) {
|
||||
if false && Debug['r'] != 0 {
|
||||
if false && Debug.r != 0 {
|
||||
yyerror("interface pointer mismatch")
|
||||
}
|
||||
|
||||
@ -1871,8 +1854,10 @@ func isdirectiface(t *types.Type) bool {
|
||||
}
|
||||
|
||||
switch t.Etype {
|
||||
case TPTR,
|
||||
TCHAN,
|
||||
case TPTR:
|
||||
// Pointers to notinheap types must be stored indirectly. See issue 42076.
|
||||
return !t.Elem().NotInHeap()
|
||||
case TCHAN,
|
||||
TMAP,
|
||||
TFUNC,
|
||||
TUNSAFEPTR:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user