[dev.typeparams] merge master into dev.typeparams

On top of the merge, the following fixes were applied:
 + Debug["G"] changed to Debug.G, following golang.org/cl/263539.
 + issue42058a.go and issue42058b.go were skipped in
   types2/stdlib_test.go. go/types does not produce errors related to
   channel element size.

Change-Id: I59fc84e12a2d728ef789fdc616f7afe80e451283
This commit is contained in:
Rob Findley 2020-10-23 09:25:24 -04:00
commit 5bfd2964a6
636 changed files with 20765 additions and 19446 deletions

View file

@ -2,12 +2,56 @@ pkg encoding/json, method (*RawMessage) MarshalJSON() ([]uint8, error)
pkg math/big, const MaxBase = 36 pkg math/big, const MaxBase = 36
pkg math/big, type Word uintptr pkg math/big, type Word uintptr
pkg net, func ListenUnixgram(string, *UnixAddr) (*UDPConn, error) 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 = 2399141888
pkg os, const ModeType = 2399666176 pkg os, const ModeType = 2399666176
pkg os (linux-arm), const O_SYNC = 4096 pkg os, const ModeType FileMode
pkg os (linux-arm-cgo), const O_SYNC = 4096 pkg os, func Chmod(string, FileMode) error
pkg os (linux-arm), const O_SYNC = 1052672 pkg os, func Lstat(string) (FileInfo, error)
pkg os (linux-arm-cgo), const O_SYNC = 1052672 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), const ImplementsGetwd = false
pkg syscall (darwin-amd64), func Fchflags(string, int) error pkg syscall (darwin-amd64), func Fchflags(string, int) error
pkg syscall (darwin-amd64-cgo), const ImplementsGetwd = false 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 ImplementsGetwd = false
pkg syscall (freebsd-386), const O_CLOEXEC = 0 pkg syscall (freebsd-386), const O_CLOEXEC = 0
pkg syscall (freebsd-386), func Fchflags(string, int) error 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 AF_MAX = 38
pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242 pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242
pkg syscall (freebsd-386-cgo), const ELAST = 94 pkg syscall (freebsd-386-cgo), const ELAST = 94
pkg syscall (freebsd-386-cgo), const ImplementsGetwd = false pkg syscall (freebsd-386-cgo), const ImplementsGetwd = false
pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 0 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 AF_MAX = 38
pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242 pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242
pkg syscall (freebsd-amd64), const ELAST = 94 pkg syscall (freebsd-amd64), const ELAST = 94
pkg syscall (freebsd-amd64), const ImplementsGetwd = false pkg syscall (freebsd-amd64), const ImplementsGetwd = false
pkg syscall (freebsd-amd64), const O_CLOEXEC = 0 pkg syscall (freebsd-amd64), const O_CLOEXEC = 0
pkg syscall (freebsd-amd64), func Fchflags(string, int) error 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 AF_MAX = 38
pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242 pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242
pkg syscall (freebsd-amd64-cgo), const ELAST = 94 pkg syscall (freebsd-amd64-cgo), const ELAST = 94
pkg syscall (freebsd-amd64-cgo), const ImplementsGetwd = false pkg syscall (freebsd-amd64-cgo), const ImplementsGetwd = false
pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 0 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 AF_MAX = 38
pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262 pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262
pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148287085 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 SizeofSockaddrUnix = 108
pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041 pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041
pkg syscall (freebsd-arm), func Fchflags(string, int) error 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 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 RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8
pkg syscall (freebsd-arm), type RawSockaddrUnix 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, 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 AF_MAX = 38
pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262 pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262
pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148287085 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 SizeofSockaddrUnix = 108
pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041 pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041
pkg syscall (freebsd-arm-cgo), func Fchflags(string, int) error 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 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 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 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, 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), type Cmsghdr struct, X__cmsg_data [0]uint8
pkg syscall (linux-386-cgo), 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 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), const ImplementsGetwd = false
pkg syscall (netbsd-amd64-cgo), const ImplementsGetwd = false pkg syscall (netbsd-amd64-cgo), const ImplementsGetwd = false
pkg syscall (netbsd-arm), 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), const SizeofIfData = 132
pkg syscall (netbsd-arm), func Fchflags(string, int) error 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), 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), const SizeofIfData = 132
pkg syscall (netbsd-arm-cgo), func Fchflags(string, int) error pkg syscall (netbsd-arm-cgo), func Fchflags(string, int) error
pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8 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_GETRUSAGE = 117
pkg syscall (openbsd-386), const SYS_GETTIMEOFDAY = 116 pkg syscall (openbsd-386), const SYS_GETTIMEOFDAY = 116
pkg syscall (openbsd-386), const SYS_KEVENT = 270 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_LSTAT = 293
pkg syscall (openbsd-386), const SYS_NANOSLEEP = 240 pkg syscall (openbsd-386), const SYS_NANOSLEEP = 240
pkg syscall (openbsd-386), const SYS_SELECT = 93 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_GETRUSAGE = 117
pkg syscall (openbsd-386-cgo), const SYS_GETTIMEOFDAY = 116 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_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_LSTAT = 293
pkg syscall (openbsd-386-cgo), const SYS_NANOSLEEP = 240 pkg syscall (openbsd-386-cgo), const SYS_NANOSLEEP = 240
pkg syscall (openbsd-386-cgo), const SYS_SELECT = 93 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_GETRUSAGE = 117
pkg syscall (openbsd-amd64), const SYS_GETTIMEOFDAY = 116 pkg syscall (openbsd-amd64), const SYS_GETTIMEOFDAY = 116
pkg syscall (openbsd-amd64), const SYS_KEVENT = 270 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_LSTAT = 293
pkg syscall (openbsd-amd64), const SYS_NANOSLEEP = 240 pkg syscall (openbsd-amd64), const SYS_NANOSLEEP = 240
pkg syscall (openbsd-amd64), const SYS_SELECT = 93 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_GETRUSAGE = 117
pkg syscall (openbsd-amd64-cgo), const SYS_GETTIMEOFDAY = 116 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_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_LSTAT = 293
pkg syscall (openbsd-amd64-cgo), const SYS_NANOSLEEP = 240 pkg syscall (openbsd-amd64-cgo), const SYS_NANOSLEEP = 240
pkg syscall (openbsd-amd64-cgo), const SYS_SELECT = 93 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 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, Pad_cgo_0 [4]uint8
pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int32 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), const TOKEN_ALL_ACCESS = 983295
pkg syscall (windows-386), type AddrinfoW struct, Addr uintptr pkg syscall (windows-386), type AddrinfoW struct, Addr uintptr
pkg syscall (windows-386), type CertChainPolicyPara struct, ExtraPolicyPara 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 CertRevocationInfo struct, OidSpecificInfo uintptr
pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr
pkg syscall (windows-amd64), type RawSockaddrAny struct, Pad [96]int8 pkg syscall (windows-amd64), type RawSockaddrAny struct, Pad [96]int8
pkg syscall (freebsd-386), func Mknod(string, uint32, int) error pkg testing, func MainStart(func(string, string) (bool, error), []InternalTest, []InternalBenchmark, []InternalExample) *M
pkg syscall (freebsd-386), type Dirent struct, Fileno uint32 pkg testing, func RegisterCover(Cover)
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 text/scanner, const GoTokens = 1012 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 = "10.0.0"
pkg unicode, const Version = "11.0.0" pkg unicode, const Version = "11.0.0"
pkg unicode, const Version = "12.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"

View file

@ -1,8 +1,321 @@
pkg unicode, const Version = "13.0.0" pkg debug/elf, const DT_ADDRRNGHI = 1879047935
pkg unicode, var Chorasmian *RangeTable pkg debug/elf, const DT_ADDRRNGHI DynTag
pkg unicode, var Dives_Akuru *RangeTable pkg debug/elf, const DT_ADDRRNGLO = 1879047680
pkg unicode, var Khitan_Small_Script *RangeTable pkg debug/elf, const DT_ADDRRNGLO DynTag
pkg unicode, var Yezidi *RangeTable 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 = 20
pkg text/template/parse, const NodeComment NodeType pkg text/template/parse, const NodeComment NodeType
pkg text/template/parse, const ParseComments = 1 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 CommentNode struct, embedded Pos
pkg text/template/parse, type Mode uint pkg text/template/parse, type Mode uint
pkg text/template/parse, type Tree struct, Mode Mode 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

View file

@ -454,6 +454,8 @@ environmental variable is set accordingly.</p>
<li>GODEBUG=gctrace=1 prints garbage collector events at <li>GODEBUG=gctrace=1 prints garbage collector events at
each collection, summarizing the amount of memory collected each collection, summarizing the amount of memory collected
and the length of the pause.</li> 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> <li>GODEBUG=schedtrace=X prints scheduling events every X milliseconds.</li>
</ul> </ul>

View file

@ -122,6 +122,15 @@ 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. by <code>go</code> <code>mod</code> <code>vendor</code> since Go 1.11.
</p> </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>
<h3 id="cgo">Cgo</h3> <h3 id="cgo">Cgo</h3>
<p> <!-- CL 252378 --> <p> <!-- CL 252378 -->
@ -181,6 +190,14 @@ Do not send CLs removing the interior tags from such phrases.
TODO TODO
</p> </p>
<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> <h3 id="crypto/tls"><a href="/pkg/crypto/tls">crypto/tls</a></h3>
<p><!-- CL 256897 --> <p><!-- CL 256897 -->
@ -201,6 +218,21 @@ Do not send CLs removing the interior tags from such phrases.
contain strings with characters within the ASCII range. contain strings with characters within the ASCII range.
</p> </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> <h3 id="net"><a href="/pkg/net/">net</a></h3>
<p><!-- CL 250357 --> <p><!-- CL 250357 -->
@ -213,6 +245,12 @@ Do not send CLs removing the interior tags from such phrases.
with <code>"use of closed network connection"</code>. with <code>"use of closed network connection"</code>.
</p> </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> <h3 id="reflect"><a href="/pkg/reflect/">reflect</a></h3>
<p><!-- CL 259237, golang.org/issue/22075 --> <p><!-- CL 259237, golang.org/issue/22075 -->
@ -273,6 +311,20 @@ Do not send CLs removing the interior tags from such phrases.
</dd> </dd>
</dl><!-- crypto/x509 --> </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> <dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
<dd> <dd>
<p><!-- CL 233637 --> <p><!-- CL 233637 -->
@ -309,3 +361,16 @@ Do not send CLs removing the interior tags from such phrases.
</p> </p>
</dd> </dd>
</dl><!-- runtime/debug --> </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 -->

View file

@ -8,8 +8,8 @@
# Consult https://www.iana.org/time-zones for the latest versions. # Consult https://www.iana.org/time-zones for the latest versions.
# Versions to use. # Versions to use.
CODE=2020a CODE=2020b
DATA=2020a DATA=2020b
set -e set -e
rm -rf work rm -rf work

Binary file not shown.

View file

@ -3,6 +3,7 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !windows,!static // +build !windows,!static
// +build !darwin !internal_pie,!arm64
#include <stdint.h> #include <stdint.h>
#include <dlfcn.h> #include <dlfcn.h>

View file

@ -3,6 +3,11 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !windows,!static // +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 package cgotest

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build windows static // +build windows static darwin,internal_pie darwin,arm64
package cgotest package cgotest

View file

@ -102,7 +102,7 @@
} }
} }
if (!global.crypto) { if (!global.crypto && global.require) {
const nodeCrypto = require("crypto"); const nodeCrypto = require("crypto");
global.crypto = { global.crypto = {
getRandomValues(b) { getRandomValues(b) {
@ -110,6 +110,9 @@
}, },
}; };
} }
if (!global.crypto) {
throw new Error("global.crypto is not available, polyfill required (getRandomValues only)");
}
if (!global.performance) { if (!global.performance) {
global.performance = { global.performance = {
@ -120,13 +123,19 @@
}; };
} }
if (!global.TextEncoder) { if (!global.TextEncoder && global.require) {
global.TextEncoder = require("util").TextEncoder; 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; global.TextDecoder = require("util").TextDecoder;
} }
if (!global.TextDecoder) {
throw new Error("global.TextDecoder is not available, polyfill required");
}
// End of polyfills for common API. // End of polyfills for common API.
@ -255,6 +264,7 @@
// func wasmExit(code int32) // func wasmExit(code int32)
"runtime.wasmExit": (sp) => { "runtime.wasmExit": (sp) => {
sp >>>= 0;
const code = this.mem.getInt32(sp + 8, true); const code = this.mem.getInt32(sp + 8, true);
this.exited = true; this.exited = true;
delete this._inst; delete this._inst;
@ -267,6 +277,7 @@
// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32) // func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
"runtime.wasmWrite": (sp) => { "runtime.wasmWrite": (sp) => {
sp >>>= 0;
const fd = getInt64(sp + 8); const fd = getInt64(sp + 8);
const p = getInt64(sp + 16); const p = getInt64(sp + 16);
const n = this.mem.getInt32(sp + 24, true); const n = this.mem.getInt32(sp + 24, true);
@ -275,16 +286,19 @@
// func resetMemoryDataView() // func resetMemoryDataView()
"runtime.resetMemoryDataView": (sp) => { "runtime.resetMemoryDataView": (sp) => {
sp >>>= 0;
this.mem = new DataView(this._inst.exports.mem.buffer); this.mem = new DataView(this._inst.exports.mem.buffer);
}, },
// func nanotime1() int64 // func nanotime1() int64
"runtime.nanotime1": (sp) => { "runtime.nanotime1": (sp) => {
sp >>>= 0;
setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000); setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
}, },
// func walltime1() (sec int64, nsec int32) // func walltime1() (sec int64, nsec int32)
"runtime.walltime1": (sp) => { "runtime.walltime1": (sp) => {
sp >>>= 0;
const msec = (new Date).getTime(); const msec = (new Date).getTime();
setInt64(sp + 8, msec / 1000); setInt64(sp + 8, msec / 1000);
this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true); this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
@ -292,6 +306,7 @@
// func scheduleTimeoutEvent(delay int64) int32 // func scheduleTimeoutEvent(delay int64) int32
"runtime.scheduleTimeoutEvent": (sp) => { "runtime.scheduleTimeoutEvent": (sp) => {
sp >>>= 0;
const id = this._nextCallbackTimeoutID; const id = this._nextCallbackTimeoutID;
this._nextCallbackTimeoutID++; this._nextCallbackTimeoutID++;
this._scheduledTimeouts.set(id, setTimeout( this._scheduledTimeouts.set(id, setTimeout(
@ -311,6 +326,7 @@
// func clearTimeoutEvent(id int32) // func clearTimeoutEvent(id int32)
"runtime.clearTimeoutEvent": (sp) => { "runtime.clearTimeoutEvent": (sp) => {
sp >>>= 0;
const id = this.mem.getInt32(sp + 8, true); const id = this.mem.getInt32(sp + 8, true);
clearTimeout(this._scheduledTimeouts.get(id)); clearTimeout(this._scheduledTimeouts.get(id));
this._scheduledTimeouts.delete(id); this._scheduledTimeouts.delete(id);
@ -318,11 +334,13 @@
// func getRandomData(r []byte) // func getRandomData(r []byte)
"runtime.getRandomData": (sp) => { "runtime.getRandomData": (sp) => {
sp >>>= 0;
crypto.getRandomValues(loadSlice(sp + 8)); crypto.getRandomValues(loadSlice(sp + 8));
}, },
// func finalizeRef(v ref) // func finalizeRef(v ref)
"syscall/js.finalizeRef": (sp) => { "syscall/js.finalizeRef": (sp) => {
sp >>>= 0;
const id = this.mem.getUint32(sp + 8, true); const id = this.mem.getUint32(sp + 8, true);
this._goRefCounts[id]--; this._goRefCounts[id]--;
if (this._goRefCounts[id] === 0) { if (this._goRefCounts[id] === 0) {
@ -335,44 +353,51 @@
// func stringVal(value string) ref // func stringVal(value string) ref
"syscall/js.stringVal": (sp) => { "syscall/js.stringVal": (sp) => {
sp >>>= 0;
storeValue(sp + 24, loadString(sp + 8)); storeValue(sp + 24, loadString(sp + 8));
}, },
// func valueGet(v ref, p string) ref // func valueGet(v ref, p string) ref
"syscall/js.valueGet": (sp) => { "syscall/js.valueGet": (sp) => {
sp >>>= 0;
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16)); 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); storeValue(sp + 32, result);
}, },
// func valueSet(v ref, p string, x ref) // func valueSet(v ref, p string, x ref)
"syscall/js.valueSet": (sp) => { "syscall/js.valueSet": (sp) => {
sp >>>= 0;
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32)); Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
}, },
// func valueDelete(v ref, p string) // func valueDelete(v ref, p string)
"syscall/js.valueDelete": (sp) => { "syscall/js.valueDelete": (sp) => {
sp >>>= 0;
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16)); Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
}, },
// func valueIndex(v ref, i int) ref // func valueIndex(v ref, i int) ref
"syscall/js.valueIndex": (sp) => { "syscall/js.valueIndex": (sp) => {
sp >>>= 0;
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16))); storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
}, },
// valueSetIndex(v ref, i int, x ref) // valueSetIndex(v ref, i int, x ref)
"syscall/js.valueSetIndex": (sp) => { "syscall/js.valueSetIndex": (sp) => {
sp >>>= 0;
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24)); Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
}, },
// func valueCall(v ref, m string, args []ref) (ref, bool) // func valueCall(v ref, m string, args []ref) (ref, bool)
"syscall/js.valueCall": (sp) => { "syscall/js.valueCall": (sp) => {
sp >>>= 0;
try { try {
const v = loadValue(sp + 8); const v = loadValue(sp + 8);
const m = Reflect.get(v, loadString(sp + 16)); const m = Reflect.get(v, loadString(sp + 16));
const args = loadSliceOfValues(sp + 32); const args = loadSliceOfValues(sp + 32);
const result = Reflect.apply(m, v, args); 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); storeValue(sp + 56, result);
this.mem.setUint8(sp + 64, 1); this.mem.setUint8(sp + 64, 1);
} catch (err) { } catch (err) {
@ -383,11 +408,12 @@
// func valueInvoke(v ref, args []ref) (ref, bool) // func valueInvoke(v ref, args []ref) (ref, bool)
"syscall/js.valueInvoke": (sp) => { "syscall/js.valueInvoke": (sp) => {
sp >>>= 0;
try { try {
const v = loadValue(sp + 8); const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16); const args = loadSliceOfValues(sp + 16);
const result = Reflect.apply(v, undefined, args); 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); storeValue(sp + 40, result);
this.mem.setUint8(sp + 48, 1); this.mem.setUint8(sp + 48, 1);
} catch (err) { } catch (err) {
@ -398,11 +424,12 @@
// func valueNew(v ref, args []ref) (ref, bool) // func valueNew(v ref, args []ref) (ref, bool)
"syscall/js.valueNew": (sp) => { "syscall/js.valueNew": (sp) => {
sp >>>= 0;
try { try {
const v = loadValue(sp + 8); const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16); const args = loadSliceOfValues(sp + 16);
const result = Reflect.construct(v, args); 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); storeValue(sp + 40, result);
this.mem.setUint8(sp + 48, 1); this.mem.setUint8(sp + 48, 1);
} catch (err) { } catch (err) {
@ -413,11 +440,13 @@
// func valueLength(v ref) int // func valueLength(v ref) int
"syscall/js.valueLength": (sp) => { "syscall/js.valueLength": (sp) => {
sp >>>= 0;
setInt64(sp + 16, parseInt(loadValue(sp + 8).length)); setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
}, },
// valuePrepareString(v ref) (ref, int) // valuePrepareString(v ref) (ref, int)
"syscall/js.valuePrepareString": (sp) => { "syscall/js.valuePrepareString": (sp) => {
sp >>>= 0;
const str = encoder.encode(String(loadValue(sp + 8))); const str = encoder.encode(String(loadValue(sp + 8)));
storeValue(sp + 16, str); storeValue(sp + 16, str);
setInt64(sp + 24, str.length); setInt64(sp + 24, str.length);
@ -425,17 +454,20 @@
// valueLoadString(v ref, b []byte) // valueLoadString(v ref, b []byte)
"syscall/js.valueLoadString": (sp) => { "syscall/js.valueLoadString": (sp) => {
sp >>>= 0;
const str = loadValue(sp + 8); const str = loadValue(sp + 8);
loadSlice(sp + 16).set(str); loadSlice(sp + 16).set(str);
}, },
// func valueInstanceOf(v ref, t ref) bool // func valueInstanceOf(v ref, t ref) bool
"syscall/js.valueInstanceOf": (sp) => { "syscall/js.valueInstanceOf": (sp) => {
sp >>>= 0;
this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0); this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0);
}, },
// func copyBytesToGo(dst []byte, src ref) (int, bool) // func copyBytesToGo(dst []byte, src ref) (int, bool)
"syscall/js.copyBytesToGo": (sp) => { "syscall/js.copyBytesToGo": (sp) => {
sp >>>= 0;
const dst = loadSlice(sp + 8); const dst = loadSlice(sp + 8);
const src = loadValue(sp + 32); const src = loadValue(sp + 32);
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) { if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
@ -450,6 +482,7 @@
// func copyBytesToJS(dst ref, src []byte) (int, bool) // func copyBytesToJS(dst ref, src []byte) (int, bool)
"syscall/js.copyBytesToJS": (sp) => { "syscall/js.copyBytesToJS": (sp) => {
sp >>>= 0;
const dst = loadValue(sp + 8); const dst = loadValue(sp + 8);
const src = loadSlice(sp + 16); const src = loadSlice(sp + 16);
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) { if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {

View file

@ -13,8 +13,8 @@ package tar
import ( import (
"errors" "errors"
"fmt" "fmt"
"io/fs"
"math" "math"
"os"
"path" "path"
"reflect" "reflect"
"strconv" "strconv"
@ -525,12 +525,12 @@ func (h Header) allowedFormats() (format Format, paxHdrs map[string]string, err
return format, paxHdrs, err return format, paxHdrs, err
} }
// FileInfo returns an os.FileInfo for the Header. // FileInfo returns an fs.FileInfo for the Header.
func (h *Header) FileInfo() os.FileInfo { func (h *Header) FileInfo() fs.FileInfo {
return headerFileInfo{h} return headerFileInfo{h}
} }
// headerFileInfo implements os.FileInfo. // headerFileInfo implements fs.FileInfo.
type headerFileInfo struct { type headerFileInfo struct {
h *Header h *Header
} }
@ -549,57 +549,57 @@ func (fi headerFileInfo) Name() string {
} }
// Mode returns the permission and mode bits for the headerFileInfo. // 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. // Set file permission bits.
mode = os.FileMode(fi.h.Mode).Perm() mode = fs.FileMode(fi.h.Mode).Perm()
// Set setuid, setgid and sticky bits. // Set setuid, setgid and sticky bits.
if fi.h.Mode&c_ISUID != 0 { if fi.h.Mode&c_ISUID != 0 {
mode |= os.ModeSetuid mode |= fs.ModeSetuid
} }
if fi.h.Mode&c_ISGID != 0 { if fi.h.Mode&c_ISGID != 0 {
mode |= os.ModeSetgid mode |= fs.ModeSetgid
} }
if fi.h.Mode&c_ISVTX != 0 { if fi.h.Mode&c_ISVTX != 0 {
mode |= os.ModeSticky mode |= fs.ModeSticky
} }
// Set file mode bits; clear perm, setuid, setgid, and sticky bits. // 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: case c_ISDIR:
mode |= os.ModeDir mode |= fs.ModeDir
case c_ISFIFO: case c_ISFIFO:
mode |= os.ModeNamedPipe mode |= fs.ModeNamedPipe
case c_ISLNK: case c_ISLNK:
mode |= os.ModeSymlink mode |= fs.ModeSymlink
case c_ISBLK: case c_ISBLK:
mode |= os.ModeDevice mode |= fs.ModeDevice
case c_ISCHR: case c_ISCHR:
mode |= os.ModeDevice mode |= fs.ModeDevice
mode |= os.ModeCharDevice mode |= fs.ModeCharDevice
case c_ISSOCK: case c_ISSOCK:
mode |= os.ModeSocket mode |= fs.ModeSocket
} }
switch fi.h.Typeflag { switch fi.h.Typeflag {
case TypeSymlink: case TypeSymlink:
mode |= os.ModeSymlink mode |= fs.ModeSymlink
case TypeChar: case TypeChar:
mode |= os.ModeDevice mode |= fs.ModeDevice
mode |= os.ModeCharDevice mode |= fs.ModeCharDevice
case TypeBlock: case TypeBlock:
mode |= os.ModeDevice mode |= fs.ModeDevice
case TypeDir: case TypeDir:
mode |= os.ModeDir mode |= fs.ModeDir
case TypeFifo: case TypeFifo:
mode |= os.ModeNamedPipe mode |= fs.ModeNamedPipe
} }
return mode return mode
} }
// sysStat, if non-nil, populates h from system-dependent fields of fi. // 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 ( const (
// Mode constants from the USTAR spec: // 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 symlink, FileInfoHeader records link as the link target.
// If fi describes a directory, a slash is appended to the name. // 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 // the file it describes, it may be necessary to modify Header.Name
// to provide the full path name of the file. // 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 { if fi == nil {
return nil, errors.New("archive/tar: FileInfo is 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(): case fi.IsDir():
h.Typeflag = TypeDir h.Typeflag = TypeDir
h.Name += "/" h.Name += "/"
case fm&os.ModeSymlink != 0: case fm&fs.ModeSymlink != 0:
h.Typeflag = TypeSymlink h.Typeflag = TypeSymlink
h.Linkname = link h.Linkname = link
case fm&os.ModeDevice != 0: case fm&fs.ModeDevice != 0:
if fm&os.ModeCharDevice != 0 { if fm&fs.ModeCharDevice != 0 {
h.Typeflag = TypeChar h.Typeflag = TypeChar
} else { } else {
h.Typeflag = TypeBlock h.Typeflag = TypeBlock
} }
case fm&os.ModeNamedPipe != 0: case fm&fs.ModeNamedPipe != 0:
h.Typeflag = TypeFifo h.Typeflag = TypeFifo
case fm&os.ModeSocket != 0: case fm&fs.ModeSocket != 0:
return nil, fmt.Errorf("archive/tar: sockets not supported") return nil, fmt.Errorf("archive/tar: sockets not supported")
default: default:
return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm) 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 h.Mode |= c_ISUID
} }
if fm&os.ModeSetgid != 0 { if fm&fs.ModeSetgid != 0 {
h.Mode |= c_ISGID h.Mode |= c_ISGID
} }
if fm&os.ModeSticky != 0 { if fm&fs.ModeSticky != 0 {
h.Mode |= c_ISVTX h.Mode |= c_ISVTX
} }
// If possible, populate additional fields from OS-specific // If possible, populate additional fields from OS-specific

View file

@ -7,7 +7,6 @@ package tar
import ( import (
"bytes" "bytes"
"io" "io"
"io/ioutil"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -104,7 +103,7 @@ func (tr *Reader) next() (*Header, error) {
continue // This is a meta header affecting the next header continue // This is a meta header affecting the next header
case TypeGNULongName, TypeGNULongLink: case TypeGNULongName, TypeGNULongLink:
format.mayOnlyBe(FormatGNU) format.mayOnlyBe(FormatGNU)
realname, err := ioutil.ReadAll(tr) realname, err := io.ReadAll(tr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -294,7 +293,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) {
// parsePAX parses PAX headers. // parsePAX parses PAX headers.
// If an extended header (type 'x') is invalid, ErrHeader is returned // If an extended header (type 'x') is invalid, ErrHeader is returned
func parsePAX(r io.Reader) (map[string]string, error) { func parsePAX(r io.Reader) (map[string]string, error) {
buf, err := ioutil.ReadAll(r) buf, err := io.ReadAll(r)
if err != nil { if err != nil {
return nil, err 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 { if err == io.EOF && seekSkipped+copySkipped < n {
err = io.ErrUnexpectedEOF err = io.ErrUnexpectedEOF
} }

View file

@ -865,7 +865,7 @@ func TestReadTruncation(t *testing.T) {
} }
cnt++ cnt++
if s2 == "manual" { if s2 == "manual" {
if _, err = tr.writeTo(ioutil.Discard); err != nil { if _, err = tr.writeTo(io.Discard); err != nil {
break break
} }
} }

View file

@ -7,7 +7,7 @@
package tar package tar
import ( import (
"os" "io/fs"
"os/user" "os/user"
"runtime" "runtime"
"strconv" "strconv"
@ -23,7 +23,7 @@ func init() {
// The downside is that renaming uname or gname by the OS never takes effect. // The downside is that renaming uname or gname by the OS never takes effect.
var userMap, groupMap sync.Map // map[int]string 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) sys, ok := fi.Sys().(*syscall.Stat_t)
if !ok { if !ok {
return nil return nil

View file

@ -10,6 +10,7 @@ import (
"fmt" "fmt"
"internal/testenv" "internal/testenv"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"math" "math"
"os" "os"
@ -327,7 +328,7 @@ func TestRoundTrip(t *testing.T) {
if !reflect.DeepEqual(rHdr, hdr) { if !reflect.DeepEqual(rHdr, hdr) {
t.Errorf("Header mismatch.\n got %+v\nwant %+v", 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 { if err != nil {
t.Fatalf("Read: %v", err) t.Fatalf("Read: %v", err)
} }
@ -338,7 +339,7 @@ func TestRoundTrip(t *testing.T) {
type headerRoundTripTest struct { type headerRoundTripTest struct {
h *Header h *Header
fm os.FileMode fm fs.FileMode
} }
func TestHeaderRoundTrip(t *testing.T) { func TestHeaderRoundTrip(t *testing.T) {
@ -361,7 +362,7 @@ func TestHeaderRoundTrip(t *testing.T) {
ModTime: time.Unix(1360600852, 0), ModTime: time.Unix(1360600852, 0),
Typeflag: TypeSymlink, Typeflag: TypeSymlink,
}, },
fm: 0777 | os.ModeSymlink, fm: 0777 | fs.ModeSymlink,
}, { }, {
// character device node. // character device node.
h: &Header{ h: &Header{
@ -371,7 +372,7 @@ func TestHeaderRoundTrip(t *testing.T) {
ModTime: time.Unix(1360578951, 0), ModTime: time.Unix(1360578951, 0),
Typeflag: TypeChar, Typeflag: TypeChar,
}, },
fm: 0666 | os.ModeDevice | os.ModeCharDevice, fm: 0666 | fs.ModeDevice | fs.ModeCharDevice,
}, { }, {
// block device node. // block device node.
h: &Header{ h: &Header{
@ -381,7 +382,7 @@ func TestHeaderRoundTrip(t *testing.T) {
ModTime: time.Unix(1360578954, 0), ModTime: time.Unix(1360578954, 0),
Typeflag: TypeBlock, Typeflag: TypeBlock,
}, },
fm: 0660 | os.ModeDevice, fm: 0660 | fs.ModeDevice,
}, { }, {
// directory. // directory.
h: &Header{ h: &Header{
@ -391,7 +392,7 @@ func TestHeaderRoundTrip(t *testing.T) {
ModTime: time.Unix(1360601116, 0), ModTime: time.Unix(1360601116, 0),
Typeflag: TypeDir, Typeflag: TypeDir,
}, },
fm: 0755 | os.ModeDir, fm: 0755 | fs.ModeDir,
}, { }, {
// fifo node. // fifo node.
h: &Header{ h: &Header{
@ -401,7 +402,7 @@ func TestHeaderRoundTrip(t *testing.T) {
ModTime: time.Unix(1360578949, 0), ModTime: time.Unix(1360578949, 0),
Typeflag: TypeFifo, Typeflag: TypeFifo,
}, },
fm: 0600 | os.ModeNamedPipe, fm: 0600 | fs.ModeNamedPipe,
}, { }, {
// setuid. // setuid.
h: &Header{ h: &Header{
@ -411,7 +412,7 @@ func TestHeaderRoundTrip(t *testing.T) {
ModTime: time.Unix(1355405093, 0), ModTime: time.Unix(1355405093, 0),
Typeflag: TypeReg, Typeflag: TypeReg,
}, },
fm: 0755 | os.ModeSetuid, fm: 0755 | fs.ModeSetuid,
}, { }, {
// setguid. // setguid.
h: &Header{ h: &Header{
@ -421,7 +422,7 @@ func TestHeaderRoundTrip(t *testing.T) {
ModTime: time.Unix(1360602346, 0), ModTime: time.Unix(1360602346, 0),
Typeflag: TypeReg, Typeflag: TypeReg,
}, },
fm: 0750 | os.ModeSetgid, fm: 0750 | fs.ModeSetgid,
}, { }, {
// sticky. // sticky.
h: &Header{ h: &Header{
@ -431,7 +432,7 @@ func TestHeaderRoundTrip(t *testing.T) {
ModTime: time.Unix(1360602540, 0), ModTime: time.Unix(1360602540, 0),
Typeflag: TypeReg, Typeflag: TypeReg,
}, },
fm: 0600 | os.ModeSticky, fm: 0600 | fs.ModeSticky,
}, { }, {
// hard link. // hard link.
h: &Header{ h: &Header{
@ -804,9 +805,9 @@ func Benchmark(b *testing.B) {
b.Run(v.label, func(b *testing.B) { b.Run(v.label, func(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
for i := 0; i < b.N; i++ { 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. // 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 { for _, file := range v.files {
if err := tw.WriteHeader(file.hdr); err != nil { if err := tw.WriteHeader(file.hdr); err != nil {
b.Errorf("unexpected WriteHeader error: %v", err) b.Errorf("unexpected WriteHeader error: %v", err)
@ -844,7 +845,7 @@ func Benchmark(b *testing.B) {
if _, err := tr.Next(); err != nil { if _, err := tr.Next(); err != nil {
b.Errorf("unexpected Next error: %v", err) 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) b.Errorf("unexpected Copy error : %v", err)
} }
} }

View file

@ -11,7 +11,12 @@ import (
"hash" "hash"
"hash/crc32" "hash/crc32"
"io" "io"
"io/fs"
"os" "os"
"path"
"sort"
"strings"
"sync"
"time" "time"
) )
@ -21,18 +26,28 @@ var (
ErrChecksum = errors.New("zip: checksum error") ErrChecksum = errors.New("zip: checksum error")
) )
// A Reader serves content from a ZIP archive.
type Reader struct { type Reader struct {
r io.ReaderAt r io.ReaderAt
File []*File File []*File
Comment string Comment string
decompressors map[uint16]Decompressor 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 { type ReadCloser struct {
f *os.File f *os.File
Reader 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 { type File struct {
FileHeader FileHeader
zip *Reader zip *Reader
@ -187,6 +202,10 @@ type checksumReader struct {
err error // sticky error 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) { func (r *checksumReader) Read(b []byte) (n int, err error) {
if r.err != nil { if r.err != nil {
return 0, r.err return 0, r.err
@ -607,3 +626,173 @@ func (b *readBuf) sub(n int) readBuf {
*b = (*b)[n:] *b = (*b)[n:]
return b2 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
}

View file

@ -10,12 +10,14 @@ import (
"encoding/hex" "encoding/hex"
"internal/obscuretestdata" "internal/obscuretestdata"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strings" "strings"
"testing" "testing"
"testing/fstest"
"time" "time"
) )
@ -30,7 +32,7 @@ type ZipTest struct {
type ZipTestFile struct { type ZipTestFile struct {
Name string Name string
Mode os.FileMode Mode fs.FileMode
NonUTF8 bool NonUTF8 bool
ModTime time.Time ModTime time.Time
Modified time.Time Modified time.Time
@ -107,7 +109,7 @@ var tests = []ZipTest{
Name: "symlink", Name: "symlink",
Content: []byte("../target"), Content: []byte("../target"),
Modified: time.Date(2012, 2, 3, 19, 56, 48, 0, timeZone(-2*time.Hour)), 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/", Name: "dir/empty/",
Content: []byte{}, Content: []byte{},
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, time.UTC), Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, time.UTC),
Mode: os.ModeDir | 0777, Mode: fs.ModeDir | 0777,
}, },
{ {
Name: "readonly", Name: "readonly",
@ -179,7 +181,7 @@ var tests = []ZipTest{
Name: "dir/empty/", Name: "dir/empty/",
Content: []byte{}, Content: []byte{},
Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, timeZone(0)), Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, timeZone(0)),
Mode: os.ModeDir | 0777, Mode: fs.ModeDir | 0777,
}, },
{ {
Name: "readonly", 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() mode := f.Mode()
if want == 0 { if want == 0 {
t.Errorf("%s mode: got %v, want none", f.Name, mode) 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 { if err != nil {
panic(err) panic(err)
} }
b, err = ioutil.ReadAll(f) b, err = io.ReadAll(f)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -985,7 +987,7 @@ func TestIssue10957(t *testing.T) {
continue continue
} }
if f.UncompressedSize64 < 1e6 { if f.UncompressedSize64 < 1e6 {
n, err := io.Copy(ioutil.Discard, r) n, err := io.Copy(io.Discard, r)
if i == 3 && err != io.ErrUnexpectedEOF { if i == 3 && err != io.ErrUnexpectedEOF {
t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err) t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err)
} }
@ -1027,7 +1029,7 @@ func TestIssue11146(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
_, err = ioutil.ReadAll(r) _, err = io.ReadAll(r)
if err != io.ErrUnexpectedEOF { if err != io.ErrUnexpectedEOF {
t.Errorf("File[0] error = %v; want io.ErrUnexpectedEOF", err) 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) 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)
}
}

View file

@ -8,7 +8,6 @@ import (
"compress/flate" "compress/flate"
"errors" "errors"
"io" "io"
"io/ioutil"
"sync" "sync"
) )
@ -111,7 +110,7 @@ func init() {
compressors.Store(Store, Compressor(func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil })) 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 })) 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)) decompressors.Store(Deflate, Decompressor(newFlateReader))
} }

View file

@ -20,7 +20,7 @@ fields must be used instead.
package zip package zip
import ( import (
"os" "io/fs"
"path" "path"
"time" "time"
) )
@ -137,12 +137,12 @@ type FileHeader struct {
ExternalAttrs uint32 // Meaning depends on CreatorVersion ExternalAttrs uint32 // Meaning depends on CreatorVersion
} }
// FileInfo returns an os.FileInfo for the FileHeader. // FileInfo returns an fs.FileInfo for the FileHeader.
func (h *FileHeader) FileInfo() os.FileInfo { func (h *FileHeader) FileInfo() fs.FileInfo {
return headerFileInfo{h} return headerFileInfo{h}
} }
// headerFileInfo implements os.FileInfo. // headerFileInfo implements fs.FileInfo.
type headerFileInfo struct { type headerFileInfo struct {
fh *FileHeader fh *FileHeader
} }
@ -161,17 +161,20 @@ func (fi headerFileInfo) ModTime() time.Time {
} }
return fi.fh.Modified.UTC() 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) Sys() interface{} { return fi.fh }
func (fi headerFileInfo) Info() (fs.FileInfo, error) { return fi, nil }
// FileInfoHeader creates a partially-populated FileHeader from an // FileInfoHeader creates a partially-populated FileHeader from an
// os.FileInfo. // fs.FileInfo.
// Because os.FileInfo's Name method returns only the base name of // 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 // 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. // of the returned header to provide the full path name of the file.
// If compression is desired, callers should set the FileHeader.Method // If compression is desired, callers should set the FileHeader.Method
// field; it is unset by default. // field; it is unset by default.
func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) { func FileInfoHeader(fi fs.FileInfo) (*FileHeader, error) {
size := fi.Size() size := fi.Size()
fh := &FileHeader{ fh := &FileHeader{
Name: fi.Name(), Name: fi.Name(),
@ -280,7 +283,7 @@ const (
) )
// Mode returns the permission and mode bits for the FileHeader. // 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 { switch h.CreatorVersion >> 8 {
case creatorUnix, creatorMacOSX: case creatorUnix, creatorMacOSX:
mode = unixModeToFileMode(h.ExternalAttrs >> 16) mode = unixModeToFileMode(h.ExternalAttrs >> 16)
@ -288,18 +291,18 @@ func (h *FileHeader) Mode() (mode os.FileMode) {
mode = msdosModeToFileMode(h.ExternalAttrs) mode = msdosModeToFileMode(h.ExternalAttrs)
} }
if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' { if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' {
mode |= os.ModeDir mode |= fs.ModeDir
} }
return mode return mode
} }
// SetMode changes the permission and mode bits for the FileHeader. // 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.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
h.ExternalAttrs = fileModeToUnixMode(mode) << 16 h.ExternalAttrs = fileModeToUnixMode(mode) << 16
// set MSDOS attributes too, as the original zip does. // set MSDOS attributes too, as the original zip does.
if mode&os.ModeDir != 0 { if mode&fs.ModeDir != 0 {
h.ExternalAttrs |= msdosDir h.ExternalAttrs |= msdosDir
} }
if mode&0200 == 0 { if mode&0200 == 0 {
@ -312,9 +315,9 @@ func (h *FileHeader) isZip64() bool {
return h.CompressedSize64 >= uint32max || h.UncompressedSize64 >= uint32max 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 { if m&msdosDir != 0 {
mode = os.ModeDir | 0777 mode = fs.ModeDir | 0777
} else { } else {
mode = 0666 mode = 0666
} }
@ -324,64 +327,64 @@ func msdosModeToFileMode(m uint32) (mode os.FileMode) {
return mode return mode
} }
func fileModeToUnixMode(mode os.FileMode) uint32 { func fileModeToUnixMode(mode fs.FileMode) uint32 {
var m uint32 var m uint32
switch mode & os.ModeType { switch mode & fs.ModeType {
default: default:
m = s_IFREG m = s_IFREG
case os.ModeDir: case fs.ModeDir:
m = s_IFDIR m = s_IFDIR
case os.ModeSymlink: case fs.ModeSymlink:
m = s_IFLNK m = s_IFLNK
case os.ModeNamedPipe: case fs.ModeNamedPipe:
m = s_IFIFO m = s_IFIFO
case os.ModeSocket: case fs.ModeSocket:
m = s_IFSOCK m = s_IFSOCK
case os.ModeDevice: case fs.ModeDevice:
if mode&os.ModeCharDevice != 0 { if mode&fs.ModeCharDevice != 0 {
m = s_IFCHR m = s_IFCHR
} else { } else {
m = s_IFBLK m = s_IFBLK
} }
} }
if mode&os.ModeSetuid != 0 { if mode&fs.ModeSetuid != 0 {
m |= s_ISUID m |= s_ISUID
} }
if mode&os.ModeSetgid != 0 { if mode&fs.ModeSetgid != 0 {
m |= s_ISGID m |= s_ISGID
} }
if mode&os.ModeSticky != 0 { if mode&fs.ModeSticky != 0 {
m |= s_ISVTX m |= s_ISVTX
} }
return m | uint32(mode&0777) return m | uint32(mode&0777)
} }
func unixModeToFileMode(m uint32) os.FileMode { func unixModeToFileMode(m uint32) fs.FileMode {
mode := os.FileMode(m & 0777) mode := fs.FileMode(m & 0777)
switch m & s_IFMT { switch m & s_IFMT {
case s_IFBLK: case s_IFBLK:
mode |= os.ModeDevice mode |= fs.ModeDevice
case s_IFCHR: case s_IFCHR:
mode |= os.ModeDevice | os.ModeCharDevice mode |= fs.ModeDevice | fs.ModeCharDevice
case s_IFDIR: case s_IFDIR:
mode |= os.ModeDir mode |= fs.ModeDir
case s_IFIFO: case s_IFIFO:
mode |= os.ModeNamedPipe mode |= fs.ModeNamedPipe
case s_IFLNK: case s_IFLNK:
mode |= os.ModeSymlink mode |= fs.ModeSymlink
case s_IFREG: case s_IFREG:
// nothing to do // nothing to do
case s_IFSOCK: case s_IFSOCK:
mode |= os.ModeSocket mode |= fs.ModeSocket
} }
if m&s_ISGID != 0 { if m&s_ISGID != 0 {
mode |= os.ModeSetgid mode |= fs.ModeSetgid
} }
if m&s_ISUID != 0 { if m&s_ISUID != 0 {
mode |= os.ModeSetuid mode |= fs.ModeSetuid
} }
if m&s_ISVTX != 0 { if m&s_ISVTX != 0 {
mode |= os.ModeSticky mode |= fs.ModeSticky
} }
return mode return mode
} }

View file

@ -9,9 +9,9 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"math/rand" "math/rand"
"os"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -23,7 +23,7 @@ type WriteTest struct {
Name string Name string
Data []byte Data []byte
Method uint16 Method uint16
Mode os.FileMode Mode fs.FileMode
} }
var writeTests = []WriteTest{ var writeTests = []WriteTest{
@ -43,19 +43,19 @@ var writeTests = []WriteTest{
Name: "setuid", Name: "setuid",
Data: []byte("setuid file"), Data: []byte("setuid file"),
Method: Deflate, Method: Deflate,
Mode: 0755 | os.ModeSetuid, Mode: 0755 | fs.ModeSetuid,
}, },
{ {
Name: "setgid", Name: "setgid",
Data: []byte("setgid file"), Data: []byte("setgid file"),
Method: Deflate, Method: Deflate,
Mode: 0755 | os.ModeSetgid, Mode: 0755 | fs.ModeSetgid,
}, },
{ {
Name: "symlink", Name: "symlink",
Data: []byte("../link/target"), Data: []byte("../link/target"),
Method: Deflate, Method: Deflate,
Mode: 0755 | os.ModeSymlink, Mode: 0755 | fs.ModeSymlink,
}, },
} }
@ -301,7 +301,7 @@ func TestWriterFlush(t *testing.T) {
} }
func TestWriterDir(t *testing.T) { func TestWriterDir(t *testing.T) {
w := NewWriter(ioutil.Discard) w := NewWriter(io.Discard)
dw, err := w.Create("dir/") dw, err := w.Create("dir/")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
@ -380,7 +380,7 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) {
if err != nil { if err != nil {
t.Fatal("opening:", err) t.Fatal("opening:", err)
} }
b, err := ioutil.ReadAll(rc) b, err := io.ReadAll(rc)
if err != nil { if err != nil {
t.Fatal("reading:", err) t.Fatal("reading:", err)
} }

View file

@ -13,7 +13,6 @@ import (
"hash" "hash"
"internal/testenv" "internal/testenv"
"io" "io"
"io/ioutil"
"runtime" "runtime"
"sort" "sort"
"strings" "strings"
@ -620,7 +619,7 @@ func testZip64(t testing.TB, size int64) *rleBuffer {
t.Fatal("read:", err) t.Fatal("read:", err)
} }
} }
gotEnd, err := ioutil.ReadAll(rc) gotEnd, err := io.ReadAll(rc)
if err != nil { if err != nil {
t.Fatal("read end:", err) t.Fatal("read end:", err)
} }

View file

@ -10,7 +10,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"strings" "strings"
"testing" "testing"
"testing/iotest" "testing/iotest"
@ -886,7 +885,7 @@ func TestReadEmptyBuffer(t *testing.T) {
func TestLinesAfterRead(t *testing.T) { func TestLinesAfterRead(t *testing.T) {
l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize) l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize)
_, err := ioutil.ReadAll(l) _, err := io.ReadAll(l)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return 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. // Write is called on it.
type writeCountingDiscard int type writeCountingDiscard int
@ -1300,7 +1299,7 @@ func TestReaderReset(t *testing.T) {
t.Errorf("buf = %q; want foo", buf) t.Errorf("buf = %q; want foo", buf)
} }
r.Reset(strings.NewReader("bar bar")) r.Reset(strings.NewReader("bar bar"))
all, err := ioutil.ReadAll(r) all, err := io.ReadAll(r)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1645,13 +1644,13 @@ func BenchmarkReaderWriteToOptimal(b *testing.B) {
buf := make([]byte, bufSize) buf := make([]byte, bufSize)
r := bytes.NewReader(buf) r := bytes.NewReader(buf)
srcReader := NewReaderSize(onlyReader{r}, 1<<10) srcReader := NewReaderSize(onlyReader{r}, 1<<10)
if _, ok := ioutil.Discard.(io.ReaderFrom); !ok { if _, ok := io.Discard.(io.ReaderFrom); !ok {
b.Fatal("ioutil.Discard doesn't support ReaderFrom") b.Fatal("io.Discard doesn't support ReaderFrom")
} }
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
r.Seek(0, io.SeekStart) r.Seek(0, io.SeekStart)
srcReader.Reset(onlyReader{r}) srcReader.Reset(onlyReader{r})
n, err := srcReader.WriteTo(ioutil.Discard) n, err := srcReader.WriteTo(io.Discard)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -1722,7 +1721,7 @@ func BenchmarkReaderEmpty(b *testing.B) {
str := strings.Repeat("x", 16<<10) str := strings.Repeat("x", 16<<10)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
br := NewReader(strings.NewReader(str)) br := NewReader(strings.NewReader(str))
n, err := io.Copy(ioutil.Discard, br) n, err := io.Copy(io.Discard, br)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }
@ -1737,7 +1736,7 @@ func BenchmarkWriterEmpty(b *testing.B) {
str := strings.Repeat("x", 1<<10) str := strings.Repeat("x", 1<<10)
bs := []byte(str) bs := []byte(str)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
bw := NewWriter(ioutil.Discard) bw := NewWriter(io.Discard)
bw.Flush() bw.Flush()
bw.WriteByte('a') bw.WriteByte('a')
bw.Flush() bw.Flush()
@ -1752,7 +1751,7 @@ func BenchmarkWriterEmpty(b *testing.B) {
func BenchmarkWriterFlush(b *testing.B) { func BenchmarkWriterFlush(b *testing.B) {
b.ReportAllocs() b.ReportAllocs()
bw := NewWriter(ioutil.Discard) bw := NewWriter(io.Discard)
str := strings.Repeat("x", 50) str := strings.Repeat("x", 50)
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
bw.WriteString(str) bw.WriteString(str)

View file

@ -8,7 +8,6 @@ import (
. "bytes" . "bytes"
"fmt" "fmt"
"io" "io"
"io/ioutil"
"sync" "sync"
"testing" "testing"
) )
@ -235,7 +234,7 @@ func TestReaderCopyNothing(t *testing.T) {
type justWriter struct { type justWriter struct {
io.Writer io.Writer
} }
discard := justWriter{ioutil.Discard} // hide ReadFrom discard := justWriter{io.Discard} // hide ReadFrom
var with, withOut nErr var with, withOut nErr
with.n, with.err = io.Copy(discard, NewReader(nil)) 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. // tests that Len is affected by reads, but Size is not.
func TestReaderLenSize(t *testing.T) { func TestReaderLenSize(t *testing.T) {
r := NewReader([]byte("abc")) r := NewReader([]byte("abc"))
io.CopyN(ioutil.Discard, r, 1) io.CopyN(io.Discard, r, 1)
if r.Len() != 2 { if r.Len() != 2 {
t.Errorf("Len = %d; want 2", r.Len()) t.Errorf("Len = %d; want 2", r.Len())
} }
@ -268,7 +267,7 @@ func TestReaderReset(t *testing.T) {
if err := r.UnreadRune(); err == nil { if err := r.UnreadRune(); err == nil {
t.Errorf("UnreadRune: expected error, got nil") t.Errorf("UnreadRune: expected error, got nil")
} }
buf, err := ioutil.ReadAll(r) buf, err := io.ReadAll(r)
if err != nil { if err != nil {
t.Errorf("ReadAll: unexpected error: %v", err) t.Errorf("ReadAll: unexpected error: %v", err)
} }
@ -314,7 +313,7 @@ func TestReaderZero(t *testing.T) {
t.Errorf("UnreadRune: got nil, want error") 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) t.Errorf("WriteTo: got %d, %v; want 0, nil", n, err)
} }
} }

View file

@ -326,6 +326,18 @@ func compareAPI(w io.Writer, features, required, optional, exception []string, a
return 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 { func fileFeatures(filename string) []string {
if filename == "" { if filename == "" {
return nil return nil
@ -334,7 +346,9 @@ func fileFeatures(filename string) []string {
if err != nil { if err != nil {
log.Fatalf("Error reading file %s: %v", filename, err) 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 var nonblank []string
for _, line := range lines { for _, line := range lines {
line = strings.TrimSpace(line) line = strings.TrimSpace(line)
@ -856,6 +870,10 @@ func (w *Walker) emitObj(obj types.Object) {
func (w *Walker) emitType(obj *types.TypeName) { func (w *Walker) emitType(obj *types.TypeName) {
name := obj.Name() name := obj.Name()
typ := obj.Type() typ := obj.Type()
if obj.IsAlias() {
w.emitf("type %s = %s", name, w.typeString(typ))
return
}
switch typ := typ.Underlying().(type) { switch typ := typ.Underlying().(type) {
case *types.Struct: case *types.Struct:
w.emitStructType(name, typ) w.emitStructType(name, typ)

View file

@ -181,7 +181,7 @@ func (p *Parser) asmText(operands [][]lex.Token) {
// Argsize set below. // Argsize set below.
}, },
} }
nameAddr.Sym.Func.Text = prog nameAddr.Sym.Func().Text = prog
prog.To.Val = int32(argSize) prog.To.Val = int32(argSize)
p.append(prog, "", true) p.append(prog, "", true)
} }

View file

@ -31,7 +31,7 @@ func testEndToEnd(t *testing.T, goarch, file string) {
architecture, ctxt := setArch(goarch) architecture, ctxt := setArch(goarch)
architecture.Init(ctxt) architecture.Init(ctxt)
lexer := lex.NewLexer(input) lexer := lex.NewLexer(input)
parser := NewParser(ctxt, architecture, lexer) parser := NewParser(ctxt, architecture, lexer, false)
pList := new(obj.Plist) pList := new(obj.Plist)
var ok bool var ok bool
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer. testOut = new(bytes.Buffer) // The assembler writes test output to this buffer.
@ -257,11 +257,11 @@ func isHexes(s string) bool {
return true 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, // the standard file:line: prefix,
// but that's not where we are today. // 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. // 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 // Same as in test/run.go
var ( var (
@ -273,7 +273,7 @@ func testErrors(t *testing.T, goarch, file string) {
input := filepath.Join("testdata", file+".s") input := filepath.Join("testdata", file+".s")
architecture, ctxt := setArch(goarch) architecture, ctxt := setArch(goarch)
lexer := lex.NewLexer(input) lexer := lex.NewLexer(input)
parser := NewParser(ctxt, architecture, lexer) parser := NewParser(ctxt, architecture, lexer, false)
pList := new(obj.Plist) pList := new(obj.Plist)
var ok bool var ok bool
testOut = new(bytes.Buffer) // The assembler writes test output to this buffer. 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() defer ctxt.Bso.Flush()
failed := false failed := false
var errBuf bytes.Buffer var errBuf bytes.Buffer
parser.errorWriter = &errBuf
ctxt.DiagFunc = func(format string, args ...interface{}) { ctxt.DiagFunc = func(format string, args ...interface{}) {
failed = true failed = true
s := fmt.Sprintf(format, args...) s := fmt.Sprintf(format, args...)
@ -292,7 +293,7 @@ func testErrors(t *testing.T, goarch, file string) {
pList.Firstpc, ok = parser.Parse() pList.Firstpc, ok = parser.Parse()
obj.Flushplist(ctxt, pList, nil, "") obj.Flushplist(ctxt, pList, nil, "")
if ok && !failed { if ok && !failed {
t.Errorf("asm: %s had no errors", goarch) t.Errorf("asm: %s had no errors", file)
} }
errors := map[string]string{} errors := map[string]string{}
@ -368,6 +369,10 @@ func TestARMEndToEnd(t *testing.T) {
} }
} }
func TestGoBuildErrors(t *testing.T) {
testErrors(t, "amd64", "buildtagerror")
}
func TestARMErrors(t *testing.T) { func TestARMErrors(t *testing.T) {
testErrors(t, "arm", "armerror") testErrors(t, "arm", "armerror")
} }
@ -437,10 +442,6 @@ func TestPPC64EndToEnd(t *testing.T) {
testEndToEnd(t, "ppc64", "ppc64") testEndToEnd(t, "ppc64", "ppc64")
} }
func TestPPC64Encoder(t *testing.T) {
testEndToEnd(t, "ppc64", "ppc64enc")
}
func TestRISCVEncoder(t *testing.T) { func TestRISCVEncoder(t *testing.T) {
testEndToEnd(t, "riscv64", "riscvenc") testEndToEnd(t, "riscv64", "riscvenc")
} }

View file

@ -57,7 +57,7 @@ var exprTests = []exprTest{
} }
func TestExpr(t *testing.T) { 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 { for i, test := range exprTests {
p.start(lex.Tokenize(test.input)) p.start(lex.Tokenize(test.input))
result := int64(p.expr()) result := int64(p.expr())
@ -113,7 +113,7 @@ func TestBadExpr(t *testing.T) {
} }
func runBadTest(i int, test badExprTest, t *testing.T) (err error) { 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)) p.start(lex.Tokenize(test.input))
return tryParse(t, func() { return tryParse(t, func() {
p.expr() p.expr()

View file

@ -39,7 +39,7 @@ func testBadInstParser(t *testing.T, goarch string, tests []badInstTest) {
for i, test := range tests { for i, test := range tests {
arch, ctxt := setArch(goarch) arch, ctxt := setArch(goarch)
tokenizer := lex.NewTokenizer("", strings.NewReader(test.input+"\n"), nil) tokenizer := lex.NewTokenizer("", strings.NewReader(test.input+"\n"), nil)
parser := NewParser(ctxt, arch, tokenizer) parser := NewParser(ctxt, arch, tokenizer, false)
err := tryParse(t, func() { err := tryParse(t, func() {
parser.Parse() parser.Parse()

View file

@ -28,7 +28,7 @@ func setArch(goarch string) (*arch.Arch, *obj.Link) {
func newParser(goarch string) *Parser { func newParser(goarch string) *Parser {
architecture, ctxt := setArch(goarch) architecture, ctxt := setArch(goarch)
return NewParser(ctxt, architecture, nil) return NewParser(ctxt, architecture, nil, false)
} }
// tryParse executes parse func in panicOnError=true context. // 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)) parser.start(lex.Tokenize(test.input))
addr := obj.Addr{} addr := obj.Addr{}
parser.operand(&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 { if result != test.output {
t.Errorf("fail at %s: got %s; expected %s\n", test.input, 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") parser := newParser("amd64")
testOperandParser(t, parser, amd64OperandTests) testOperandParser(t, parser, amd64OperandTests)
testBadOperandParser(t, parser, amd64BadOperandTests) testBadOperandParser(t, parser, amd64BadOperandTests)
parser.compilingRuntime = true
testOperandParser(t, parser, amd64RuntimeOperandTests)
testBadOperandParser(t, parser, amd64BadOperandRuntimeTests)
} }
func Test386OperandParser(t *testing.T) { func Test386OperandParser(t *testing.T) {
@ -141,7 +149,7 @@ func TestFuncAddress(t *testing.T) {
parser := newParser(sub.arch) parser := newParser(sub.arch)
for _, test := range sub.tests { for _, test := range sub.tests {
parser.start(lex.Tokenize(test.input)) parser.start(lex.Tokenize(test.input))
name, ok := parser.funcAddress() name, _, ok := parser.funcAddress()
isFuncSym := strings.HasSuffix(test.input, "(SB)") && isFuncSym := strings.HasSuffix(test.input, "(SB)") &&
// Ignore static symbols. // 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. {"[):[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{ var amd64BadOperandTests = []badOperandTest{
{"[", "register list: expected ']', found EOF"}, {"[", "register list: expected ']', found EOF"},
{"[4", "register list: bad low register in `[4`"}, {"[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-X1-X2]", "register list: expected ']' after `[X0-X1`, found '-'"},
{"[X0,X3]", "register list: expected '-' after `[X0`, found ','"}, {"[X0,X3]", "register list: expected '-' after `[X0`, found ','"},
{"[X0,X1,X2,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{ var x86OperandTests = []operandTest{

View file

@ -29,6 +29,7 @@ type Parser struct {
lineNum int // Line number in source file. lineNum int // Line number in source file.
errorLine int // Line number of last error. errorLine int // Line number of last error.
errorCount int // Number of errors. 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. pc int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA.
input []lex.Token input []lex.Token
inputPos int inputPos int
@ -42,6 +43,7 @@ type Parser struct {
lastProg *obj.Prog lastProg *obj.Prog
dataAddr map[string]int64 // Most recent address for DATA for this symbol. dataAddr map[string]int64 // Most recent address for DATA for this symbol.
isJump bool // Instruction being assembled is a jump. isJump bool // Instruction being assembled is a jump.
compilingRuntime bool
errorWriter io.Writer errorWriter io.Writer
} }
@ -50,7 +52,7 @@ type Patch struct {
label string 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{ return &Parser{
ctxt: ctxt, ctxt: ctxt,
arch: ar, arch: ar,
@ -58,6 +60,7 @@ func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser {
labels: make(map[string]*obj.Prog), labels: make(map[string]*obj.Prog),
dataAddr: make(map[string]int64), dataAddr: make(map[string]int64),
errorWriter: os.Stderr, errorWriter: os.Stderr,
compilingRuntime: compilingRuntime,
} }
} }
@ -132,6 +135,30 @@ func (p *Parser) ParseSymABIs(w io.Writer) bool {
return p.errorCount == 0 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 // line consumes a single assembly line from p.lex of the form
// //
// {label:} WORD[.cond] [ arg {, arg} ] (';' | '\n') // {label:} WORD[.cond] [ arg {, arg} ] (';' | '\n')
@ -146,7 +173,7 @@ next:
// Skip newlines. // Skip newlines.
var tok lex.ScanToken var tok lex.ScanToken
for { for {
tok = p.lex.Next() tok = p.nextToken()
// We save the line number here so error messages from this instruction // We save the line number here so error messages from this instruction
// are labeled with this line. Otherwise we complain after we've absorbed // 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. // the terminating newline and the line numbers are off by one in errors.
@ -179,11 +206,11 @@ next:
items = make([]lex.Token, 0, 3) items = make([]lex.Token, 0, 3)
} }
for { for {
tok = p.lex.Next() tok = p.nextToken()
if len(operands) == 0 && len(items) == 0 { if len(operands) == 0 && len(items) == 0 {
if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386) && tok == '.' { if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386) && tok == '.' {
// Suffixes: ARM conditionals or x86 modifiers. // Suffixes: ARM conditionals or x86 modifiers.
tok = p.lex.Next() tok = p.nextToken()
str := p.lex.Text() str := p.lex.Text()
if tok != scanner.Ident { if tok != scanner.Ident {
p.errorf("instruction suffix expected identifier, found %s", str) 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]. // Defines text symbol in operands[0].
if len(operands) > 0 { if len(operands) > 0 {
p.start(operands[0]) p.start(operands[0])
if name, ok := p.funcAddress(); ok { if name, abi, ok := p.funcAddress(); ok {
fmt.Fprintf(w, "def %s ABI0\n", name) fmt.Fprintf(w, "def %s %s\n", name, abi)
} }
} }
return return
@ -304,8 +331,8 @@ func (p *Parser) symDefRef(w io.Writer, word string, operands [][]lex.Token) {
// Search for symbol references. // Search for symbol references.
for _, op := range operands { for _, op := range operands {
p.start(op) p.start(op)
if name, ok := p.funcAddress(); ok { if name, abi, ok := p.funcAddress(); ok {
fmt.Fprintf(w, "ref %s ABI0\n", name) 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 '*': case '*':
a.Type = obj.TYPE_INDIR a.Type = obj.TYPE_INDIR
} }
// Weirdness with statics: Might now have "<>".
isStatic := false // Parse optional <> (indicates a static symbol) or
if p.peek() == '<' { // <ABIxxx> (selecting text symbol with specific ABI).
isStatic = true doIssueError := true
p.next() isStatic, abi := p.symRefAttrs(name, doIssueError)
p.get('>')
}
if p.peek() == '+' || p.peek() == '-' { if p.peek() == '+' || p.peek() == '-' {
a.Offset = int64(p.expr()) a.Offset = int64(p.expr())
} }
if isStatic { if isStatic {
a.Sym = p.ctxt.LookupStatic(name) a.Sym = p.ctxt.LookupStatic(name)
} else { } else {
a.Sym = p.ctxt.Lookup(name) a.Sym = p.ctxt.LookupABI(name, abi)
} }
if p.peek() == scanner.EOF { if p.peek() == scanner.EOF {
if prefix == 0 && p.isJump { 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 // funcAddress parses an external function address. This is a
// constrained form of the operand syntax that's always SB-based, // constrained form of the operand syntax that's always SB-based,
// non-static, and has at most a simple integer offset: // non-static, and has at most a simple integer offset:
// //
// [$|*]sym[+Int](SB) // [$|*]sym[<abi>][+Int](SB)
func (p *Parser) funcAddress() (string, bool) { func (p *Parser) funcAddress() (string, obj.ABI, bool) {
switch p.peek() { switch p.peek() {
case '$', '*': case '$', '*':
// Skip prefix. // Skip prefix.
@ -813,25 +887,32 @@ func (p *Parser) funcAddress() (string, bool) {
tok := p.next() tok := p.next()
name := tok.String() name := tok.String()
if tok.ScanToken != scanner.Ident || p.atStartOfRegister(name) { 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() tok = p.next()
if tok.ScanToken == '+' { if tok.ScanToken == '+' {
if p.next().ScanToken != scanner.Int { if p.next().ScanToken != scanner.Int {
return "", false return "", obj.ABI0, false
} }
tok = p.next() tok = p.next()
} }
if tok.ScanToken != '(' { if tok.ScanToken != '(' {
return "", false return "", obj.ABI0, false
} }
if reg := p.next(); reg.ScanToken != scanner.Ident || reg.String() != "SB" { 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 { 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. // registerIndirect parses the general form of a register indirection.

View file

@ -37,6 +37,7 @@ func TestErroneous(t *testing.T) {
{"TEXT", "$0É:0, 0, $1", "expected end of operand, found É"}, // Issue #12467. {"TEXT", "$0É:0, 0, $1", "expected end of operand, found É"}, // Issue #12467.
{"TEXT", "$:0:(SB, 0, $1", "expected '(', found 0"}, // Issue 12468. {"TEXT", "$:0:(SB, 0, $1", "expected '(', found 0"}, // Issue 12468.
{"TEXT", "@B(SB),0,$0", "expected '(', found B"}, // Issue 23580. {"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", "", "expect two operands for FUNCDATA"},
{"FUNCDATA", "(SB ", "expect two operands for FUNCDATA"}, {"FUNCDATA", "(SB ", "expect two operands for FUNCDATA"},
{"DATA", "", "expect two operands for DATA"}, {"DATA", "", "expect two operands for DATA"},

View 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"

File diff suppressed because it is too large Load diff

View file

@ -1,642 +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
MULLW $10, R3 // 1c63000a
MULLW $10000000, R3 // 641f009863ff96807c7f19d6
MULLWCC R3, R4, R5 // 7ca419d7
MULHW R3, R4, R5 // 7ca41896
MULHWU R3, R4, R5 // 7ca41816
MULLD R3, R4 // 7c8419d2
MULLD R4, R4, R5 // 7ca421d2
MULLD $20, R4 // 1c840014
MULLD $200000000, R4 // 641f0beb63ffc2007c9f21d2
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 $8, R5, $6, R4 // 54a430b2
CLRLSLDI $24, R4, $4, R3 // 78832508
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

View file

@ -24,6 +24,7 @@ var (
SymABIs = flag.Bool("gensymabis", false, "write symbol ABI information to output file, don't assemble") 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") Importpath = flag.String("p", "", "set expected package import to path")
Spectre = flag.String("spectre", "", "enable spectre mitigations in `list` (all, ret)") 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 ( var (

View file

@ -109,6 +109,9 @@ func (in *Input) Next() ScanToken {
in.Error("'#' must be first item on line") in.Error("'#' must be first item on line")
} }
in.beginningOfLine = in.hash() in.beginningOfLine = in.hash()
in.text = "#"
return '#'
case scanner.Ident: case scanner.Ident:
// Is it a macro name? // Is it a macro name?
name := in.Stack.Text() name := in.Stack.Text()

View file

@ -26,6 +26,8 @@ const (
RSH // >> Logical right shift. RSH // >> Logical right shift.
ARR // -> Used on ARM for shift type 3, arithmetic right shift. ARR // -> Used on ARM for shift type 3, arithmetic right shift.
ROT // @> Used on ARM for shift type 4, rotate right. 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 macroName // name of macro that should not be expanded
) )

View file

@ -281,6 +281,9 @@ func drain(input *Input) string {
if tok == scanner.EOF { if tok == scanner.EOF {
return buf.String() return buf.String()
} }
if tok == '#' {
continue
}
if buf.Len() > 0 { if buf.Len() > 0 {
buf.WriteByte('.') buf.WriteByte('.')
} }

View file

@ -107,10 +107,13 @@ func (t *Tokenizer) Next() ScanToken {
if t.tok != scanner.Comment { if t.tok != scanner.Comment {
break break
} }
length := strings.Count(s.TokenText(), "\n") text := s.TokenText()
t.line += length t.line += strings.Count(text, "\n")
// TODO: If we ever have //go: comments in assembly, will need to keep them here. // TODO: Use constraint.IsGoBuild once it exists.
// For now, just discard all comments. if strings.HasPrefix(text, "//go:build") {
t.tok = BuildComment
break
}
} }
switch t.tok { switch t.tok {
case '\n': case '\n':

View file

@ -74,7 +74,8 @@ func main() {
var failedFile string var failedFile string
for _, f := range flag.Args() { for _, f := range flag.Args() {
lexer := lex.NewLexer(f) 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{}) { ctxt.DiagFunc = func(format string, args ...interface{}) {
diag = true diag = true
log.Printf(format, args...) log.Printf(format, args...)

View file

@ -282,7 +282,7 @@ func genhash(t *types.Type) *obj.LSym {
} }
sym := typesymprefix(".hash", t) sym := typesymprefix(".hash", t)
if Debug['r'] != 0 { if Debug.r != 0 {
fmt.Printf("genhash %v %v %v\n", closure, sym, t) 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) r.List.Append(nh)
fn.Nbody.Append(r) fn.Nbody.Append(r)
if Debug['r'] != 0 { if Debug.r != 0 {
dumplist("genhash body", fn.Nbody) dumplist("genhash body", fn.Nbody)
} }
@ -509,7 +509,7 @@ func geneq(t *types.Type) *obj.LSym {
return closure return closure
} }
sym := typesymprefix(".eq", t) sym := typesymprefix(".eq", t)
if Debug['r'] != 0 { if Debug.r != 0 {
fmt.Printf("geneq %v\n", t) fmt.Printf("geneq %v\n", t)
} }
@ -732,7 +732,7 @@ func geneq(t *types.Type) *obj.LSym {
fn.Nbody.Append(ret) fn.Nbody.Append(ret)
} }
if Debug['r'] != 0 { if Debug.r != 0 {
dumplist("geneq body", fn.Nbody) dumplist("geneq body", fn.Nbody)
} }

View file

@ -86,7 +86,7 @@ func expandiface(t *types.Type) {
sort.Sort(methcmp(methods)) sort.Sort(methcmp(methods))
if int64(len(methods)) >= thearch.MAXWIDTH/int64(Widthptr) { if int64(len(methods)) >= thearch.MAXWIDTH/int64(Widthptr) {
yyerror("interface too large") yyerrorl(typePos(t), "interface too large")
} }
for i, m := range methods { for i, m := range methods {
m.Offset = int64(i) * int64(Widthptr) 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 maxwidth = 1<<31 - 1
} }
if o >= maxwidth { if o >= maxwidth {
yyerror("type %L too large", errtype) yyerrorl(typePos(errtype), "type %L too large", errtype)
o = 8 // small but nonzero o = 8 // small but nonzero
} }
} }
@ -199,7 +199,7 @@ func findTypeLoop(t *types.Type, path *[]*types.Type) bool {
} }
*path = append(*path, t) *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 return true
} }
*path = (*path)[:len(*path)-1] *path = (*path)[:len(*path)-1]
@ -381,7 +381,7 @@ func dowidth(t *types.Type) {
t1 := t.ChanArgs() t1 := t.ChanArgs()
dowidth(t1) // just in case dowidth(t1) // just in case
if t1.Elem().Width >= 1<<16 { 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 w = 1 // anything will do
@ -414,7 +414,7 @@ func dowidth(t *types.Type) {
if t.Elem().Width != 0 { if t.Elem().Width != 0 {
cap := (uint64(thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width) cap := (uint64(thearch.MAXWIDTH) - 1) / uint64(t.Elem().Width)
if uint64(t.NumElem()) > cap { 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 w = t.NumElem() * t.Elem().Width
@ -456,7 +456,7 @@ func dowidth(t *types.Type) {
} }
if Widthptr == 4 && w != int64(int32(w)) { if Widthptr == 4 && w != int64(int32(w)) {
yyerror("type %v too large", t) yyerrorl(typePos(t), "type %v too large", t)
} }
t.Width = w t.Width = w

View file

@ -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 // Export format

View file

@ -198,7 +198,7 @@ func capturevars(xfunc *Node) {
outer = nod(OADDR, outer, nil) outer = nod(OADDR, outer, nil)
} }
if Debug['m'] > 1 { if Debug.m > 1 {
var name *types.Sym var name *types.Sym
if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil { if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil {
name = v.Name.Curfn.Func.Nname.Sym name = v.Name.Curfn.Func.Nname.Sym
@ -434,6 +434,8 @@ func typecheckpartialcall(fn *Node, sym *types.Sym) {
fn.Type = xfunc.Type 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 { func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
rcvrtype := fn.Left.Type rcvrtype := fn.Left.Type
sym := methodSymSuffix(rcvrtype, meth, "-fm") sym := methodSymSuffix(rcvrtype, meth, "-fm")
@ -500,6 +502,10 @@ func makepartialcall(fn *Node, t0 *types.Type, meth *types.Sym) *Node {
funcbody() funcbody()
xfunc = typecheck(xfunc, ctxStmt) 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) sym.Def = asTypesNode(xfunc)
xtop = append(xtop, xfunc) xtop = append(xtop, xfunc)
Curfn = savecurfn Curfn = savecurfn

View file

@ -114,16 +114,16 @@ func (v Val) Interface() interface{} {
type NilVal struct{} type NilVal struct{}
// Int64 returns n as an int64. // Int64Val returns n as an int64.
// n must be an integer or rune constant. // n must be an integer or rune constant.
func (n *Node) Int64() int64 { func (n *Node) Int64Val() int64 {
if !Isconst(n, CTINT) { if !Isconst(n, CTINT) {
Fatalf("Int64(%v)", n) Fatalf("Int64Val(%v)", n)
} }
return n.Val().U.(*Mpint).Int64() 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 { func (n *Node) CanInt64() bool {
if !Isconst(n, CTINT) { if !Isconst(n, CTINT) {
return false return false
@ -131,18 +131,27 @@ func (n *Node) CanInt64() bool {
// if the value inside n cannot be represented as an int64, the // if the value inside n cannot be represented as an int64, the
// return value of Int64 is undefined // 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. // n must be a boolean constant.
func (n *Node) Bool() bool { func (n *Node) BoolVal() bool {
if !Isconst(n, CTBOOL) { if !Isconst(n, CTBOOL) {
Fatalf("Bool(%v)", n) Fatalf("BoolVal(%v)", n)
} }
return n.Val().U.(bool) 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 // truncate float literal fv to 32-bit or 64-bit precision
// according to type; return truncated value. // according to type; return truncated value.
func truncfltlit(oldv *Mpflt, t *types.Type) *Mpflt { func truncfltlit(oldv *Mpflt, t *types.Type) *Mpflt {
@ -612,7 +621,7 @@ func evconst(n *Node) {
var strs []string var strs []string
i2 := i1 i2 := i1
for i2 < len(s) && Isconst(s[i2], CTSTR) { for i2 < len(s) && Isconst(s[i2], CTSTR) {
strs = append(strs, strlit(s[i2])) strs = append(strs, s[i2].StringVal())
i2++ i2++
} }
@ -635,7 +644,7 @@ func evconst(n *Node) {
switch nl.Type.Etype { switch nl.Type.Etype {
case TSTRING: case TSTRING:
if Isconst(nl, CTSTR) { if Isconst(nl, CTSTR) {
setintconst(n, int64(len(strlit(nl)))) setintconst(n, int64(len(nl.StringVal())))
} }
case TARRAY: case TARRAY:
if !hascallchan(nl) { if !hascallchan(nl) {
@ -1129,11 +1138,6 @@ func defaultType(t *types.Type) *types.Type {
return nil return nil
} }
// strlit returns the value of a literal string Node as a string.
func strlit(n *Node) string {
return n.Val().U.(string)
}
func smallintconst(n *Node) bool { func smallintconst(n *Node) bool {
if n.Op == OLITERAL && Isconst(n, CTINT) && n.Type != nil { if n.Op == OLITERAL && Isconst(n, CTINT) && n.Type != nil {
switch simtype[n.Type.Etype] { switch simtype[n.Type.Etype] {

View file

@ -283,7 +283,7 @@ func oldname(s *types.Sym) *Node {
c.Name.Defn = n c.Name.Defn = n
// Link into list of active closure variables. // 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 c.Name.Param.Outer = n.Name.Param.Innermost
n.Name.Param.Innermost = c n.Name.Param.Innermost = c

View file

@ -34,7 +34,7 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
// Walk progs to build up the InlCalls data structure // Walk progs to build up the InlCalls data structure
var prevpos src.XPos 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 { if p.Pos == prevpos {
continue continue
} }
@ -150,7 +150,7 @@ func assembleInlines(fnsym *obj.LSym, dwVars []*dwarf.Var) dwarf.InlCalls {
start := int64(-1) start := int64(-1)
curii := -1 curii := -1
var prevp *obj.Prog 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 { if prevp != nil && p.Pos == prevp.Pos {
continue continue
} }

View file

@ -204,7 +204,7 @@ func heapAllocReason(n *Node) string {
if !smallintconst(r) { if !smallintconst(r) {
return "non-constant size" return "non-constant size"
} }
if t := n.Type; t.Elem().Width != 0 && r.Int64() >= maxImplicitStackVarSize/t.Elem().Width { if t := n.Type; t.Elem().Width != 0 && r.Int64Val() >= maxImplicitStackVarSize/t.Elem().Width {
return "too large for stack" return "too large for stack"
} }
} }
@ -282,7 +282,7 @@ func addrescapes(n *Node) {
// moveToHeap records the parameter or local variable n as moved to the heap. // moveToHeap records the parameter or local variable n as moved to the heap.
func moveToHeap(n *Node) { func moveToHeap(n *Node) {
if Debug['r'] != 0 { if Debug.r != 0 {
Dump("MOVE", n) Dump("MOVE", n)
} }
if compiling_runtime { if compiling_runtime {
@ -359,7 +359,7 @@ func moveToHeap(n *Node) {
n.Xoffset = 0 n.Xoffset = 0
n.Name.Param.Heapaddr = heapaddr n.Name.Param.Heapaddr = heapaddr
n.Esc = EscHeap n.Esc = EscHeap
if Debug['m'] != 0 { if Debug.m != 0 {
Warnl(n.Pos, "moved to heap: %v", n) Warnl(n.Pos, "moved to heap: %v", n)
} }
} }
@ -389,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 // but we are reusing the ability to annotate an individual function
// argument and pass those annotations along to importing code. // argument and pass those annotations along to importing code.
if f.Type.IsUintptr() { if f.Type.IsUintptr() {
if Debug['m'] != 0 { if Debug.m != 0 {
Warnl(f.Pos, "assuming %v is unsafe uintptr", name()) Warnl(f.Pos, "assuming %v is unsafe uintptr", name())
} }
return unsafeUintptrTag return unsafeUintptrTag
@ -404,11 +404,11 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
// External functions are assumed unsafe, unless // External functions are assumed unsafe, unless
// //go:noescape is given before the declaration. // //go:noescape is given before the declaration.
if fn.Func.Pragma&Noescape != 0 { 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()) Warnl(f.Pos, "%v does not escape", name())
} }
} else { } else {
if Debug['m'] != 0 && f.Sym != nil { if Debug.m != 0 && f.Sym != nil {
Warnl(f.Pos, "leaking param: %v", name()) Warnl(f.Pos, "leaking param: %v", name())
} }
esc.AddHeap(0) esc.AddHeap(0)
@ -419,14 +419,14 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
if fn.Func.Pragma&UintptrEscapes != 0 { if fn.Func.Pragma&UintptrEscapes != 0 {
if f.Type.IsUintptr() { if f.Type.IsUintptr() {
if Debug['m'] != 0 { if Debug.m != 0 {
Warnl(f.Pos, "marking %v as escaping uintptr", name()) Warnl(f.Pos, "marking %v as escaping uintptr", name())
} }
return uintptrEscapesTag return uintptrEscapesTag
} }
if f.IsDDD() && f.Type.Elem().IsUintptr() { if f.IsDDD() && f.Type.Elem().IsUintptr() {
// final argument is ...uintptr. // final argument is ...uintptr.
if Debug['m'] != 0 { if Debug.m != 0 {
Warnl(f.Pos, "marking %v as escaping ...uintptr", name()) Warnl(f.Pos, "marking %v as escaping ...uintptr", name())
} }
return uintptrEscapesTag return uintptrEscapesTag
@ -448,7 +448,7 @@ func (e *Escape) paramTag(fn *Node, narg int, f *types.Field) string {
esc := loc.paramEsc esc := loc.paramEsc
esc.Optimize() esc.Optimize()
if Debug['m'] != 0 && !loc.escapes { if Debug.m != 0 && !loc.escapes {
if esc.Empty() { if esc.Empty() {
Warnl(f.Pos, "%v does not escape", name()) Warnl(f.Pos, "%v does not escape", name())
} }

View file

@ -170,7 +170,7 @@ func (e *Escape) initFunc(fn *Node) {
Fatalf("unexpected node: %v", fn) Fatalf("unexpected node: %v", fn)
} }
fn.Esc = EscFuncPlanned fn.Esc = EscFuncPlanned
if Debug['m'] > 3 { if Debug.m > 3 {
Dump("escAnalyze", fn) Dump("escAnalyze", fn)
} }
@ -247,7 +247,7 @@ func (e *Escape) stmt(n *Node) {
lineno = lno 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) 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: case OLABEL:
switch asNode(n.Sym.Label) { switch asNode(n.Sym.Label) {
case &nonlooping: case &nonlooping:
if Debug['m'] > 2 { if Debug.m > 2 {
fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n) fmt.Printf("%v:%v non-looping label\n", linestr(lineno), n)
} }
case &looping: case &looping:
if Debug['m'] > 2 { if Debug.m > 2 {
fmt.Printf("%v: %v looping label\n", linestr(lineno), n) fmt.Printf("%v: %v looping label\n", linestr(lineno), n)
} }
e.loopDepth++ e.loopDepth++
@ -717,7 +717,7 @@ func (e *Escape) addrs(l Nodes) []EscHole {
func (e *Escape) assign(dst, src *Node, why string, where *Node) { func (e *Escape) assign(dst, src *Node, why string, where *Node) {
// Filter out some no-op assignments for escape analysis. // Filter out some no-op assignments for escape analysis.
ignore := dst != nil && src != nil && isSelfAssign(dst, src) 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) 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 var fn *Node
switch call.Op { switch call.Op {
case OCALLFUNC: case OCALLFUNC:
if call.Left.Op == ONAME && call.Left.Class() == PFUNC { switch v := staticValue(call.Left); {
fn = call.Left case v.Op == ONAME && v.Class() == PFUNC:
} else if call.Left.Op == OCLOSURE { fn = v
fn = call.Left.Func.Closure.Func.Nname case v.Op == OCLOSURE:
fn = v.Func.Closure.Func.Nname
} }
case OCALLMETH: case OCALLMETH:
fn = asNode(call.Left.Type.FuncType().Nname) fn = asNode(call.Left.Type.FuncType().Nname)
@ -930,7 +931,7 @@ func (k EscHole) note(where *Node, why string) EscHole {
if where == nil || why == "" { if where == nil || why == "" {
Fatalf("note: missing where/why") Fatalf("note: missing where/why")
} }
if Debug['m'] >= 2 || logopt.Enabled() { if Debug.m >= 2 || logopt.Enabled() {
k.notes = &EscNote{ k.notes = &EscNote{
next: k.notes, next: k.notes,
where: where, where: where,
@ -1076,9 +1077,9 @@ func (e *Escape) flow(k EscHole, src *EscLocation) {
return return
} }
if dst.escapes && k.derefs < 0 { // dst = &src 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) pos := linestr(src.n.Pos)
if Debug['m'] >= 2 { if Debug.m >= 2 {
fmt.Printf("%s: %v escapes to heap:\n", pos, src.n) fmt.Printf("%s: %v escapes to heap:\n", pos, src.n)
} }
explanation := e.explainFlow(pos, dst, src, k.derefs, k.notes, []*logopt.LoggedOpt{}) explanation := e.explainFlow(pos, dst, src, k.derefs, k.notes, []*logopt.LoggedOpt{})
@ -1178,8 +1179,8 @@ func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLoc
// that value flow for tagging the function // that value flow for tagging the function
// later. // later.
if l.isName(PPARAM) { if l.isName(PPARAM) {
if (logopt.Enabled() || Debug['m'] >= 2) && !l.escapes { if (logopt.Enabled() || Debug.m >= 2) && !l.escapes {
if Debug['m'] >= 2 { 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) 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) explanation := e.explainPath(root, l)
@ -1195,8 +1196,8 @@ func (e *Escape) walkOne(root *EscLocation, walkgen uint32, enqueue func(*EscLoc
// outlives it, then l needs to be heap // outlives it, then l needs to be heap
// allocated. // allocated.
if addressOf && !l.escapes { if addressOf && !l.escapes {
if logopt.Enabled() || Debug['m'] >= 2 { if logopt.Enabled() || Debug.m >= 2 {
if Debug['m'] >= 2 { if Debug.m >= 2 {
fmt.Printf("%s: %v escapes to heap:\n", linestr(l.n.Pos), l.n) fmt.Printf("%s: %v escapes to heap:\n", linestr(l.n.Pos), l.n)
} }
explanation := e.explainPath(root, l) explanation := e.explainPath(root, l)
@ -1234,7 +1235,7 @@ func (e *Escape) explainPath(root, src *EscLocation) []*logopt.LoggedOpt {
for { for {
// Prevent infinite loop. // Prevent infinite loop.
if visited[src] { 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) fmt.Printf("%s: warning: truncated explanation due to assignment cycle; see golang.org/issue/35518\n", pos)
} }
break break
@ -1262,7 +1263,7 @@ func (e *Escape) explainFlow(pos string, dst, srcloc *EscLocation, derefs int, n
if derefs >= 0 { if derefs >= 0 {
ops = strings.Repeat("*", derefs) 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)) flow := fmt.Sprintf(" flow: %s = %s%v:", e.explainLoc(dst), ops, e.explainLoc(srcloc))
if print { if print {
@ -1416,7 +1417,7 @@ func (e *Escape) finish(fns []*Node) {
if loc.escapes { if loc.escapes {
if n.Op != ONAME { if n.Op != ONAME {
if Debug['m'] != 0 { if Debug.m != 0 {
Warnl(n.Pos, "%S escapes to heap", n) Warnl(n.Pos, "%S escapes to heap", n)
} }
if logopt.Enabled() { if logopt.Enabled() {
@ -1426,7 +1427,7 @@ func (e *Escape) finish(fns []*Node) {
n.Esc = EscHeap n.Esc = EscHeap
addrescapes(n) addrescapes(n)
} else { } else {
if Debug['m'] != 0 && n.Op != ONAME { if Debug.m != 0 && n.Op != ONAME {
Warnl(n.Pos, "%S does not escape", n) Warnl(n.Pos, "%S does not escape", n)
} }
n.Esc = EscNone n.Esc = EscNone

View file

@ -31,7 +31,7 @@ func exportsym(n *Node) {
} }
n.Sym.SetOnExportList(true) n.Sym.SetOnExportList(true)
if Debug['E'] != 0 { if Debug.E != 0 {
fmt.Printf("export symbol %v\n", n.Sym) fmt.Printf("export symbol %v\n", n.Sym)
} }
@ -150,7 +150,7 @@ func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val
n.SetVal(val) n.SetVal(val)
if Debug['E'] != 0 { if Debug.E != 0 {
fmt.Printf("import const %v %L = %v\n", s, t, val) 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) n.Func = new(Func)
t.SetNname(asTypesNode(n)) t.SetNname(asTypesNode(n))
if Debug['E'] != 0 { if Debug.E != 0 {
fmt.Printf("import func %v%S\n", s, t) 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 return
} }
if Debug['E'] != 0 { if Debug.E != 0 {
fmt.Printf("import var %v %L\n", s, t) 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 return
} }
if Debug['E'] != 0 { if Debug.E != 0 {
fmt.Printf("import type %v = %L\n", s, t) fmt.Printf("import type %v = %L\n", s, t)
} }
} }

View file

@ -792,6 +792,13 @@ func tconv2(b *bytes.Buffer, t *types.Type, flag FmtFlag, mode fmtMode, visited
return 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 // 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. // 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 // 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() visited[t] = b.Len()
defer delete(visited, t) defer delete(visited, t)
if mode == FDbg {
b.WriteString(t.Etype.String())
b.WriteByte('-')
tconv2(b, t, flag, FErr, visited)
return
}
switch t.Etype { switch t.Etype {
case TPTR: case TPTR:
b.WriteByte('*') b.WriteByte('*')
@ -1333,7 +1334,7 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
n.Orig.exprfmt(s, prec, mode) n.Orig.exprfmt(s, prec, mode)
return return
} }
if n.Type != nil && n.Type.Etype != TIDEAL && n.Type.Etype != TNIL && n.Type != types.UntypedBool && n.Type != types.UntypedString { if n.Type != nil && !n.Type.IsUntyped() {
// Need parens when type begins with what might // Need parens when type begins with what might
// be misinterpreted as a unary operator: * or <-. // be misinterpreted as a unary operator: * or <-.
if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == types.Crecv) { if n.Type.IsPtr() || (n.Type.IsChan() && n.Type.ChanDir() == types.Crecv) {

View file

@ -61,12 +61,12 @@ type Class uint8
//go:generate stringer -type=Class //go:generate stringer -type=Class
const ( const (
Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables Pxxx Class = iota // no class; used during ssa conversion to indicate pseudo-variables
PEXTERN // global variable PEXTERN // global variables
PAUTO // local variables PAUTO // local variables
PAUTOHEAP // local variable or parameter moved to heap PAUTOHEAP // local variables or parameters moved to heap
PPARAM // input arguments PPARAM // input arguments
PPARAMOUT // output results PPARAMOUT // output results
PFUNC // global function PFUNC // global functions
// Careful: Class is stored in three bits in Node.flags. // Careful: Class is stored in three bits in Node.flags.
_ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3) _ = uint((1 << 3) - iota) // static assert for iota <= (1 << 3)
@ -116,7 +116,15 @@ var decldepth int32
var nolocalimports bool var nolocalimports bool
var Debug [256]int // gc debug flags
type DebugFlags struct {
P, B, C, E, G,
K, L, N, S,
W, e, h, j,
l, m, r, w int
}
var Debug DebugFlags
var debugstr string var debugstr string

View file

@ -153,7 +153,7 @@ func (pp *Progs) Prog(as obj.As) *obj.Prog {
pp.clearp(pp.next) pp.clearp(pp.next)
p.Link = 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)") Warn("prog: unknown position (line 0)")
} }
@ -199,7 +199,7 @@ func (pp *Progs) settext(fn *Node) {
ptxt := pp.Prog(obj.ATEXT) ptxt := pp.Prog(obj.ATEXT)
pp.Text = ptxt pp.Text = ptxt
fn.Func.lsym.Func.Text = ptxt fn.Func.lsym.Func().Text = ptxt
ptxt.From.Type = obj.TYPE_MEM ptxt.From.Type = obj.TYPE_MEM
ptxt.From.Name = obj.NAME_EXTERN ptxt.From.Name = obj.NAME_EXTERN
ptxt.From.Sym = fn.Func.lsym ptxt.From.Sym = fn.Func.lsym

View file

@ -1266,8 +1266,13 @@ func (w *exportWriter) expr(n *Node) {
// case OSTRUCTKEY: // case OSTRUCTKEY:
// unreachable - handled in case OSTRUCTLIT by elemList // unreachable - handled in case OSTRUCTLIT by elemList
// case OCALLPART: case OCALLPART:
// unimplemented - handled by default case // 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: case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
w.op(OXDOT) w.op(OXDOT)

View file

@ -742,8 +742,8 @@ func (r *importReader) doInline(n *Node) {
importlist = append(importlist, n) importlist = append(importlist, n)
if Debug['E'] > 0 && Debug['m'] > 2 { if Debug.E > 0 && Debug.m > 2 {
if Debug['m'] > 3 { if Debug.m > 3 {
fmt.Printf("inl body for %v %#v: %+v\n", n, n.Type, asNodes(n.Func.Inl.Body)) fmt.Printf("inl body for %v %#v: %+v\n", n, n.Type, asNodes(n.Func.Inl.Body))
} else { } else {
fmt.Printf("inl body for %v %#v: %v\n", n, n.Type, asNodes(n.Func.Inl.Body)) 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 // unreachable - handled in case OSTRUCTLIT by elemList
// case OCALLPART: // case OCALLPART:
// unimplemented // unreachable - mapped to case OXDOT below by exporter
// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: // case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
// unreachable - mapped to case OXDOT below by exporter // unreachable - mapped to case OXDOT below by exporter

View file

@ -7,7 +7,7 @@
// saves a copy of the body. Then inlcalls walks each function body to // saves a copy of the body. Then inlcalls walks each function body to
// expand calls to inlinable functions. // 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 // making 1 the default and -l disable. Additional levels (beyond -l) may be buggy and
// are not supported. // are not supported.
// 0: disabled // 0: disabled
@ -21,7 +21,7 @@
// The -d typcheckinl flag enables early typechecking of all imported bodies, // The -d typcheckinl flag enables early typechecking of all imported bodies,
// which is useful to flush out bugs. // 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. // which calls get inlined or not, more is for debugging, and may go away at any point.
package gc package gc
@ -85,7 +85,7 @@ func typecheckinl(fn *Node) {
return // typecheckinl on local function 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)) 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 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() { defer func() {
if reason != "" { if reason != "" {
if Debug['m'] > 1 { if Debug.m > 1 {
fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason) fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
} }
if logopt.Enabled() { if logopt.Enabled() {
@ -187,7 +187,7 @@ func caninl(fn *Node) {
defer n.Func.SetInlinabilityChecked(true) defer n.Func.SetInlinabilityChecked(true)
cc := int32(inlineExtraCallCost) cc := int32(inlineExtraCallCost)
if Debug['l'] == 4 { if Debug.l == 4 {
cc = 1 // this appears to yield better performance than 0. 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 // this is so export can find the body of a method
fn.Type.FuncType().Nname = asTypesNode(n) 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)) 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) fmt.Printf("%v: can inline %v\n", fn.Line(), n)
} }
if logopt.Enabled() { if logopt.Enabled() {
@ -325,18 +325,10 @@ func (v *hairyVisitor) visit(n *Node) bool {
break break
} }
if fn := n.Left.Func; fn != nil && fn.Inl != nil { if fn := inlCallee(n.Left); fn != nil && fn.Func.Inl != nil {
v.budget -= fn.Inl.Cost v.budget -= fn.Func.Inl.Cost
break 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. // Call cost for non-leaf inlining.
v.budget -= v.extraCallCost v.budget -= v.extraCallCost
@ -382,17 +374,16 @@ func (v *hairyVisitor) visit(n *Node) bool {
v.reason = "call to recover" v.reason = "call to recover"
return true return true
case OCALLPART:
// OCALLPART is inlineable, but no extra cost to the budget
case OCLOSURE, case OCLOSURE,
OCALLPART,
ORANGE, ORANGE,
OFOR,
OFORUNTIL,
OSELECT, OSELECT,
OTYPESW, OTYPESW,
OGO, OGO,
ODEFER, ODEFER,
ODCLTYPE, // can't print yet ODCLTYPE, // can't print yet
OBREAK,
ORETJMP: ORETJMP:
v.reason = "unhandled op " + n.Op.String() v.reason = "unhandled op " + n.Op.String()
return true return true
@ -400,10 +391,23 @@ func (v *hairyVisitor) visit(n *Node) bool {
case OAPPEND: case OAPPEND:
v.budget -= inlineExtraAppendCost v.budget -= inlineExtraAppendCost
case ODCLCONST, OEMPTY, OFALL, OLABEL: case ODCLCONST, OEMPTY, OFALL:
// These nodes don't produce code; omit from inlining budget. // These nodes don't produce code; omit from inlining budget.
return false 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: case OIF:
if Isconst(n.Left, CTBOOL) { if Isconst(n.Left, CTBOOL) {
// This if and the condition cost nothing. // This if and the condition cost nothing.
@ -421,7 +425,7 @@ func (v *hairyVisitor) visit(n *Node) bool {
v.budget-- v.budget--
// When debugging, don't stop early, to get full cost of inlining this function // 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 return true
} }
@ -452,7 +456,7 @@ func inlcopy(n *Node) *Node {
} }
m := n.copy() m := n.copy()
if m.Func != nil { if n.Op != OCALLPART && m.Func != nil {
Fatalf("unexpected Func: %v", m) Fatalf("unexpected Func: %v", m)
} }
m.Left = inlcopy(n.Left) m.Left = inlcopy(n.Left)
@ -666,60 +670,18 @@ func inlnode(n *Node, maxCost int32, inlMap map[*Node]bool) *Node {
switch n.Op { switch n.Op {
case OCALLFUNC: case OCALLFUNC:
if Debug['m'] > 3 { if Debug.m > 3 {
fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left) 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 if isIntrinsicCall(n) {
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))
}
break break
} }
if fn := inlCallee(n.Left); fn != nil && fn.Func.Inl != nil {
// ensure the variable is never re-assigned n = mkinlcall(n, fn, maxCost, inlMap)
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)
}
}
} }
case OCALLMETH: case OCALLMETH:
if Debug['m'] > 3 { if Debug.m > 3 {
fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right) 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 return n
} }
// inlinableClosure takes an OCLOSURE node and follows linkage to the matching ONAME with // inlCallee takes a function-typed expression and returns the underlying function ONAME
// the inlinable body. Returns nil if the function is not inlinable. // that it refers to if statically known. Otherwise, it returns nil.
func inlinableClosure(n *Node) *Node { func inlCallee(fn *Node) *Node {
c := n.Func.Closure 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) caninl(c)
f := c.Func.Nname return c.Func.Nname
if f == nil || f.Func.Inl == nil { }
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 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 // 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 return nil
} }
func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node { func inlParam(t *types.Field, as *Node, inlvars map[*Node]*Node) *Node {
if n := asNode(t.Nname); n != nil && !n.isBlank() { n := asNode(t.Nname)
inlvar := inlvars[n] if n == nil || n.isBlank() {
if inlvar == nil { return nblank
Fatalf("missing inlvar for %v\n", n)
}
return inlvar
} }
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 var inlgen int
@ -889,7 +911,7 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
} }
if inlMap[fn] { 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()) fmt.Printf("%v: cannot inline %v into %v: repeated recursive cycle\n", n.Line(), fn, Curfn.funcname())
} }
return n 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. // 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)) 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) 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) 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 continue
} }
if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
continue // TODO(mdempsky): Remove once I'm confident
} // this never actually happens. We currently
inlvars[ln] = typecheck(inlvar(ln), ctxExpr) // perform inlining before escape analysis, so
if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM { // nothing should have moved to the heap yet.
ninit.Append(nod(ODCL, inlvars[ln], nil)) Fatalf("impossible: %v", ln)
} }
inlf := typecheck(inlvar(ln), ctxExpr)
inlvars[ln] = inlf
if genDwarfInline > 0 { if genDwarfInline > 0 {
inlf := inlvars[ln]
if ln.Class() == PPARAM { if ln.Class() == PPARAM {
inlf.Name.SetInlFormal(true) inlf.Name.SetInlFormal(true)
} else { } else {
@ -1019,56 +1042,42 @@ func mkinlcall(n, fn *Node, maxCost int32, inlMap map[*Node]bool) *Node {
// Assign arguments to the parameters' temp names. // Assign arguments to the parameters' temp names.
as := nod(OAS2, nil, nil) 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 // For non-dotted calls to variadic functions, we assign the
// variadic parameter's temp name separately. // variadic parameter's temp name separately.
var vas *Node var vas *Node
if fn.IsMethod() { if recv := fn.Type.Recv(); recv != nil {
rcv := fn.Type.Recv() as.List.Append(inlParam(recv, as, inlvars))
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)
} }
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 _, param := range fn.Type.Params().Fields().Slice() {
// For ordinary parameters or variadic parameters in // For ordinary parameters or variadic parameters in
// dotted calls, just add the variable to the // dotted calls, just add the variable to the
// assignment list, and we're done. // assignment list, and we're done.
if !param.IsDDD() || n.IsDDD() { if !param.IsDDD() || n.IsDDD() {
as.List.Append(tinlvar(param, inlvars)) as.List.Append(inlParam(param, as, inlvars))
continue continue
} }
// Otherwise, we need to collect the remaining values // Otherwise, we need to collect the remaining values
// to pass as a slice. // to pass as a slice.
numvals := n.List.Len()
x := as.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())) as.List.Append(argvar(param.Type, as.List.Len()))
} }
varargs := as.List.Slice()[x:] 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 { if len(varargs) == 0 {
vas.Right = nodnil() vas.Right = nodnil()
vas.Right.Type = param.Type 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) 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 // PAUTO's in the calling functions, and link them off of the
// PPARAM's, PAUTOS and PPARAMOUTs of the called function. // PPARAM's, PAUTOS and PPARAMOUTs of the called function.
func inlvar(var_ *Node) *Node { func inlvar(var_ *Node) *Node {
if Debug['m'] > 3 { if Debug.m > 3 {
fmt.Printf("inlvar %+v\n", var_) fmt.Printf("inlvar %+v\n", var_)
} }
@ -1255,13 +1264,13 @@ func (subst *inlsubst) node(n *Node) *Node {
switch n.Op { switch n.Op {
case ONAME: case ONAME:
if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode 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) fmt.Printf("substituting name %+v -> %+v\n", n, inlvar)
} }
return inlvar return inlvar
} }
if Debug['m'] > 2 { if Debug.m > 2 {
fmt.Printf("not substituting name %+v\n", n) fmt.Printf("not substituting name %+v\n", n)
} }
return n return n

View file

@ -83,7 +83,7 @@ func TestIntendedInlining(t *testing.T) {
"puintptr.ptr", "puintptr.ptr",
"spanOf", "spanOf",
"spanOfUnchecked", "spanOfUnchecked",
//"(*gcWork).putFast", // TODO(austin): For debugging #27993 "(*gcWork).putFast",
"(*gcWork).tryGetFast", "(*gcWork).tryGetFast",
"(*guintptr).set", "(*guintptr).set",
"(*markBits).advance", "(*markBits).advance",
@ -115,6 +115,7 @@ func TestIntendedInlining(t *testing.T) {
"byLiteral.Len", "byLiteral.Len",
"byLiteral.Less", "byLiteral.Less",
"byLiteral.Swap", "byLiteral.Swap",
"(*dictDecoder).tryWriteCopy",
}, },
"encoding/base64": { "encoding/base64": {
"assemble32", "assemble32",

View file

@ -50,6 +50,9 @@ const (
// Runtime and cgo type pragmas // Runtime and cgo type pragmas
NotInHeap // values of this type must not be heap allocated NotInHeap // values of this type must not be heap allocated
// Go command pragmas
GoBuildPragma
) )
const ( const (
@ -71,6 +74,8 @@ const (
func pragmaFlag(verb string) PragmaFlag { func pragmaFlag(verb string) PragmaFlag {
switch verb { switch verb {
case "go:build":
return GoBuildPragma
case "go:nointerface": case "go:nointerface":
if objabi.Fieldtrack_enabled != 0 { if objabi.Fieldtrack_enabled != 0 {
return Nointerface return Nointerface

View file

@ -211,19 +211,28 @@ func Main(archInit func(*Arch)) {
flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime") flag.BoolVar(&compiling_runtime, "+", false, "compiling runtime")
flag.BoolVar(&compiling_std, "std", false, "compiling standard library") 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") flag.StringVar(&localimport, "D", "", "set relative `path` for local imports")
objabi.Flagcount("E", "debug symbol export", &Debug['E'])
objabi.Flagcount("G", "accept generic code", &Debug['G']) 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("G", "accept generic code", &Debug.G)
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.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.AddVersionFlag() // -V
objabi.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`") flag.StringVar(&asmhdr, "asmhdr", "", "write assembly header to `file`")
flag.StringVar(&buildid, "buildid", "", "record `id` as the build id in the export metadata") 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") flag.IntVar(&nBackendWorkers, "c", 1, "concurrency during compilation, 1 means no concurrency")
@ -232,17 +241,12 @@ func Main(archInit func(*Arch)) {
flag.BoolVar(&flagDWARF, "dwarf", !Wasm, "generate DWARF symbols") flag.BoolVar(&flagDWARF, "dwarf", !Wasm, "generate DWARF symbols")
flag.BoolVar(&Ctxt.Flag_locationlists, "dwarflocationlists", true, "add location lists to DWARF in optimized mode") 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") 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("importmap", "add `definition` of the form source=actual to import map", addImportMap) objabi.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg) objabi.Flagfn1("importcfg", "read import configuration from `file`", readImportCfg)
flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`") 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(&flag_lang, "lang", "", "release to compile for")
flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`") flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
objabi.Flagcount("live", "debug liveness analysis", &debuglive) objabi.Flagcount("live", "debug liveness analysis", &debuglive)
objabi.Flagcount("m", "print optimization decisions", &Debug['m'])
if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) { if sys.MSanSupported(objabi.GOOS, objabi.GOARCH) {
flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer") flag.BoolVar(&flag_msan, "msan", false, "build code compatible with C/C++ memory sanitizer")
} }
@ -250,7 +254,6 @@ func Main(archInit func(*Arch)) {
flag.StringVar(&outfile, "o", "", "write output to `file`") flag.StringVar(&outfile, "o", "", "write output to `file`")
flag.StringVar(&myimportpath, "p", "", "set expected package import `path`") flag.StringVar(&myimportpath, "p", "", "set expected package import `path`")
flag.BoolVar(&writearchive, "pack", false, "write to file.a instead of file.o") 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) { if sys.RaceDetectorSupported(objabi.GOOS, objabi.GOARCH) {
flag.BoolVar(&flag_race, "race", false, "enable race detector") flag.BoolVar(&flag_race, "race", false, "enable race detector")
} }
@ -260,7 +263,6 @@ func Main(archInit func(*Arch)) {
} }
flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths") flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity") 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") flag.BoolVar(&use_writebarrier, "wb", true, "enable write barrier")
var flag_shared bool var flag_shared bool
var flag_dynlink bool var flag_dynlink bool
@ -326,9 +328,9 @@ func Main(archInit func(*Arch)) {
Ctxt.Flag_shared = flag_dynlink || flag_shared Ctxt.Flag_shared = flag_dynlink || flag_shared
Ctxt.Flag_dynlink = flag_dynlink 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 Ctxt.Debugvlog = Debug_vlog
if flagDWARF { if flagDWARF {
Ctxt.DebugInfo = debuginfo Ctxt.DebugInfo = debuginfo
@ -400,7 +402,7 @@ func Main(archInit func(*Arch)) {
instrumenting = true instrumenting = true
} }
if compiling_runtime && Debug['N'] != 0 { if compiling_runtime && Debug.N != 0 {
log.Fatal("cannot disable optimizations while compiling runtime") log.Fatal("cannot disable optimizations while compiling runtime")
} }
if nBackendWorkers < 1 { if nBackendWorkers < 1 {
@ -505,11 +507,11 @@ func Main(archInit func(*Arch)) {
} }
// enable inlining. for now: // enable inlining. for now:
// default: inlining on. (debug['l'] == 1) // default: inlining on. (Debug.l == 1)
// -l: inlining off (debug['l'] == 0) // -l: inlining off (Debug.l == 0)
// -l=2, -l=3: inlining on again, with extra debugging (debug['l'] > 1) // -l=2, -l=3: inlining on again, with extra debugging (Debug.l > 1)
if Debug['l'] <= 1 { if Debug.l <= 1 {
Debug['l'] = 1 - Debug['l'] Debug.l = 1 - Debug.l
} }
if jsonLogOpt != "" { // parse version,destination from json logging optimization. if jsonLogOpt != "" { // parse version,destination from json logging optimization.
@ -572,10 +574,10 @@ func Main(archInit func(*Arch)) {
loadsys() loadsys()
timings.Start("fe", "parse") timings.Start("fe", "parse")
lines := parseFiles(flag.Args(), Debug['G'] != 0) lines := parseFiles(flag.Args(), Debug.G != 0)
timings.Stop() timings.Stop()
timings.AddEvent(int64(lines), "lines") timings.AddEvent(int64(lines), "lines")
if Debug['G'] != 0 { if Debug.G != 0 {
// can only parse generic code for now // can only parse generic code for now
if nerrors+nsavederrors != 0 { if nerrors+nsavederrors != 0 {
errorexit() errorexit()
@ -674,7 +676,7 @@ func Main(archInit func(*Arch)) {
// Phase 5: Inlining // Phase 5: Inlining
timings.Start("fe", "inlining") timings.Start("fe", "inlining")
if Debug_typecheckinl != 0 { 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. // otherwise lazily when used or re-exported.
for _, n := range importlist { for _, n := range importlist {
if n.Func.Inl != nil { if n.Func.Inl != nil {
@ -688,7 +690,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. // Find functions that can be inlined and clone them before walk expands them.
visitBottomUp(xtop, func(list []*Node, recursive bool) { visitBottomUp(xtop, func(list []*Node, recursive bool) {
numfns := numNonClosures(list) numfns := numNonClosures(list)
@ -699,7 +701,7 @@ func Main(archInit func(*Arch)) {
// across more than one function. // across more than one function.
caninl(n) caninl(n)
} else { } else {
if Debug['m'] > 1 { if Debug.m > 1 {
fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname) fmt.Printf("%v: cannot inline %v: recursive\n", n.Line(), n.Func.Nname)
} }
} }
@ -976,9 +978,10 @@ func readSymABIs(file, myimportpath string) {
if len(parts) != 3 { if len(parts) != 3 {
log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0]) log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
} }
sym, abi := parts[1], parts[2] sym, abistr := parts[1], parts[2]
if abi != "ABI0" { // Only supported external ABI right now abi, valid := obj.ParseABI(abistr)
log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abi) if !valid {
log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abistr)
} }
// If the symbol is already prefixed with // If the symbol is already prefixed with
@ -991,9 +994,9 @@ func readSymABIs(file, myimportpath string) {
// Record for later. // Record for later.
if parts[0] == "def" { if parts[0] == "def" {
symabiDefs[sym] = obj.ABI0 symabiDefs[sym] = abi
} else { } else {
symabiRefs[sym] = obj.ABI0 symabiRefs[sym] = abi
} }
default: default:
log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0]) log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
@ -1415,29 +1418,34 @@ func IsAlias(sym *types.Sym) bool {
return sym.Def != nil && asNode(sym.Def).Sym != sym return sym.Def != nil && asNode(sym.Def).Sym != sym
} }
// By default, assume any debug flags are incompatible with concurrent compilation. // By default, assume any debug flags are incompatible with concurrent
// A few are safe and potentially in common use for normal compiles, though; mark them as such here. // compilation. A few are safe and potentially in common use for
var concurrentFlagOK = [256]bool{ // normal compiles, though; return true for those.
'B': true, // disabled bounds checking func concurrentFlagOk() bool {
'C': true, // disable printing of columns in error messages // Report whether any debug flag that would prevent concurrent
'e': true, // no limit on errors; errors all come from non-concurrent code // compilation is set, by zeroing out the allowed ones and then
'I': true, // add `directory` to import search path // checking if the resulting struct is zero.
'N': true, // disable optimizations d := Debug
'l': true, // disable inlining d.B = 0 // disable bounds checking
'w': true, // all printing happens before compilation d.C = 0 // disable printing of columns in error messages
'W': true, // all printing happens before compilation d.e = 0 // no limit on errors; errors all come from non-concurrent code
'S': true, // printing disassembly happens at the end (but see concurrentBackendAllowed below) 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 { func concurrentBackendAllowed() bool {
for i, x := range &Debug { if !concurrentFlagOk() {
if x != 0 && !concurrentFlagOK[i] {
return false 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. // 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. // while flushing the plist, which happens concurrently.
if Debug_vlog || debugstr != "" || debuglive > 0 { if Debug_vlog || debugstr != "" || debuglive > 0 {
return false return false

View file

@ -249,6 +249,7 @@ func (p *noder) node() {
mkpackage(p.file.PkgName.Value) mkpackage(p.file.PkgName.Value)
if pragma, ok := p.file.Pragma.(*Pragma); ok { if pragma, ok := p.file.Pragma.(*Pragma); ok {
pragma.Flag &^= GoBuildPragma
p.checkUnused(pragma) p.checkUnused(pragma)
} }
@ -780,7 +781,7 @@ func (p *noder) sum(x syntax.Expr) *Node {
n := p.expr(x) n := p.expr(x)
if Isconst(n, CTSTR) && n.Sym == nil { if Isconst(n, CTSTR) && n.Sym == nil {
nstr = n nstr = n
chunks = append(chunks, strlit(nstr)) chunks = append(chunks, nstr.StringVal())
} }
for i := len(adds) - 1; i >= 0; i-- { for i := len(adds) - 1; i >= 0; i-- {
@ -790,12 +791,12 @@ func (p *noder) sum(x syntax.Expr) *Node {
if Isconst(r, CTSTR) && r.Sym == nil { if Isconst(r, CTSTR) && r.Sym == nil {
if nstr != nil { if nstr != nil {
// Collapse r into nstr instead of adding to n. // Collapse r into nstr instead of adding to n.
chunks = append(chunks, strlit(r)) chunks = append(chunks, r.StringVal())
continue continue
} }
nstr = r nstr = r
chunks = append(chunks, strlit(nstr)) chunks = append(chunks, nstr.StringVal())
} else { } else {
if len(chunks) > 1 { if len(chunks) > 1 {
nstr.SetVal(Val{U: strings.Join(chunks, "")}) nstr.SetVal(Val{U: strings.Join(chunks, "")})
@ -1444,11 +1445,6 @@ func (p *noder) mkname(name *syntax.Name) *Node {
return mkname(p.name(name)) 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 { func (p *noder) wrapname(n syntax.Node, x *Node) *Node {
// These nodes do not carry line numbers. // These nodes do not carry line numbers.
// Introduce a wrapper node to give them the correct line. // Introduce a wrapper node to give them the correct line.

View file

@ -272,7 +272,7 @@ func dumpGlobalConst(n *Node) {
default: default:
return return
} }
Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), n.Int64()) Ctxt.DwarfIntConst(myimportpath, n.Sym.Name, typesymname(t), n.Int64Val())
} }
func dumpglobls() { func dumpglobls() {
@ -305,20 +305,21 @@ func dumpglobls() {
// global symbols can't be declared during parallel compilation. // global symbols can't be declared during parallel compilation.
func addGCLocals() { func addGCLocals() {
for _, s := range Ctxt.Text { for _, s := range Ctxt.Text {
if s.Func == nil { fn := s.Func()
if fn == nil {
continue 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() { if gcsym != nil && !gcsym.OnList() {
ggloblsym(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK) 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) attr := int16(obj.RODATA)
ggloblsym(x, int32(len(x.P)), attr) ggloblsym(x, int32(len(x.P)), attr)
x.Set(obj.AttrStatic, true) 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) ggloblsym(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
} }
} }

View file

@ -50,7 +50,7 @@ type Order struct {
// Order rewrites fn.Nbody to apply the ordering constraints // Order rewrites fn.Nbody to apply the ordering constraints
// described in the comment at the top of the file. // described in the comment at the top of the file.
func order(fn *Node) { func order(fn *Node) {
if Debug['W'] > 1 { if Debug.W > 1 {
s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym) s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym)
dumplist(s, fn.Nbody) dumplist(s, fn.Nbody)
} }
@ -323,12 +323,7 @@ func (o *Order) stmtList(l Nodes) {
// and rewrites it to: // and rewrites it to:
// m = OMAKESLICECOPY([]T, x, s); nil // m = OMAKESLICECOPY([]T, x, s); nil
func orderMakeSliceCopy(s []*Node) { func orderMakeSliceCopy(s []*Node) {
const go115makeslicecopy = true if Debug.N != 0 || instrumenting {
if !go115makeslicecopy {
return
}
if Debug['N'] != 0 || instrumenting {
return return
} }
@ -1102,7 +1097,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
haslit := false haslit := false
for _, n1 := range n.List.Slice() { for _, n1 := range n.List.Slice() {
hasbyte = hasbyte || n1.Op == OBYTES2STR 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 { if haslit && hasbyte {
@ -1274,7 +1269,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
var t *types.Type var t *types.Type
switch n.Op { switch n.Op {
case OSLICELIT: case OSLICELIT:
t = types.NewArray(n.Type.Elem(), n.Right.Int64()) t = types.NewArray(n.Type.Elem(), n.Right.Int64Val())
case OCALLPART: case OCALLPART:
t = partialCallType(n) t = partialCallType(n)
} }

View file

@ -266,8 +266,8 @@ func compile(fn *Node) {
dtypesym(n.Type) dtypesym(n.Type)
// Also make sure we allocate a linker symbol // Also make sure we allocate a linker symbol
// for the stack object data, for the same reason. // for the stack object data, for the same reason.
if fn.Func.lsym.Func.StackObjects == nil { if fn.Func.lsym.Func().StackObjects == nil {
fn.Func.lsym.Func.StackObjects = Ctxt.Lookup(fn.Func.lsym.Name + ".stkobj") 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: case PAUTO:
if !n.Name.Used() { if !n.Name.Used() {
// Text == nil -> generating abstract function // 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)") Fatalf("debuginfo unused node (AllocFrame should truncate fn.Func.Dcl)")
} }
continue continue
@ -425,7 +425,7 @@ func debuginfo(fnsym *obj.LSym, infosym *obj.LSym, curfn interface{}) ([]dwarf.S
continue continue
} }
apdecls = append(apdecls, n) apdecls = append(apdecls, n)
fnsym.Func.RecordAutoType(ngotype(n).Linksym()) fnsym.Func().RecordAutoType(ngotype(n).Linksym())
} }
decls, dwarfVars := createDwarfVars(fnsym, fn.Func, apdecls) 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 // the function symbol to insure that the type included in DWARF
// processing during linking. // processing during linking.
typesyms := []*obj.LSym{} typesyms := []*obj.LSym{}
for t, _ := range fnsym.Func.Autot { for t, _ := range fnsym.Func().Autot {
typesyms = append(typesyms, t) typesyms = append(typesyms, t)
} }
sort.Sort(obj.BySymName(typesyms)) 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.Sym = sym
r.Type = objabi.R_USETYPE r.Type = objabi.R_USETYPE
} }
fnsym.Func.Autot = nil fnsym.Func().Autot = nil
var varScopes []ScopeID var varScopes []ScopeID
for _, decl := range decls { for _, decl := range decls {
@ -522,7 +522,7 @@ func createSimpleVar(fnsym *obj.LSym, n *Node) *dwarf.Var {
} }
typename := dwarf.InfoPrefix + typesymname(n.Type) typename := dwarf.InfoPrefix + typesymname(n.Type)
delete(fnsym.Func.Autot, ngotype(n).Linksym()) delete(fnsym.Func().Autot, ngotype(n).Linksym())
inlIndex := 0 inlIndex := 0
if genDwarfInline > 1 { if genDwarfInline > 1 {
if n.Name.InlFormal() || n.Name.InlLocal() { if n.Name.InlFormal() || n.Name.InlLocal() {
@ -667,7 +667,7 @@ func createDwarfVars(fnsym *obj.LSym, fn *Func, apDecls []*Node) ([]*Node, []*dw
ChildIndex: -1, ChildIndex: -1,
}) })
// Record go type of to insure that it gets emitted by the linker. // 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 return decls, vars
@ -731,7 +731,7 @@ func createComplexVar(fnsym *obj.LSym, fn *Func, varID ssa.VarID) *dwarf.Var {
} }
gotype := ngotype(n).Linksym() gotype := ngotype(n).Linksym()
delete(fnsym.Func.Autot, gotype) delete(fnsym.Func().Autot, gotype)
typename := dwarf.InfoPrefix + gotype.Name[len("type."):] typename := dwarf.InfoPrefix + gotype.Name[len("type."):]
inlIndex := 0 inlIndex := 0
if genDwarfInline > 1 { if genDwarfInline > 1 {

View file

@ -1552,26 +1552,27 @@ func liveness(e *ssafn, f *ssa.Func, pp *Progs) LivenessMap {
// Emit the live pointer map data structures // Emit the live pointer map data structures
ls := e.curfn.Func.lsym 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) p := pp.Prog(obj.AFUNCDATA)
Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps) Addrconst(&p.From, objabi.FUNCDATA_ArgsPointerMaps)
p.To.Type = obj.TYPE_MEM p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN p.To.Name = obj.NAME_EXTERN
p.To.Sym = ls.Func.GCArgs p.To.Sym = fninfo.GCArgs
p = pp.Prog(obj.AFUNCDATA) p = pp.Prog(obj.AFUNCDATA)
Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps) Addrconst(&p.From, objabi.FUNCDATA_LocalsPointerMaps)
p.To.Type = obj.TYPE_MEM p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN p.To.Name = obj.NAME_EXTERN
p.To.Sym = ls.Func.GCLocals p.To.Sym = fninfo.GCLocals
if !go115ReduceLiveness { if !go115ReduceLiveness {
p = pp.Prog(obj.AFUNCDATA) p = pp.Prog(obj.AFUNCDATA)
Addrconst(&p.From, objabi.FUNCDATA_RegPointerMaps) Addrconst(&p.From, objabi.FUNCDATA_RegPointerMaps)
p.To.Type = obj.TYPE_MEM p.To.Type = obj.TYPE_MEM
p.To.Name = obj.NAME_EXTERN p.To.Name = obj.NAME_EXTERN
p.To.Sym = ls.Func.GCRegs p.To.Sym = fninfo.GCRegs
} }
return lv.livenessMap return lv.livenessMap

View file

@ -112,22 +112,25 @@ func typecheckrangeExpr(n *Node) {
v2 = nil v2 = nil
} }
var why string
if v1 != nil { if v1 != nil {
if v1.Name != nil && v1.Name.Defn == n { if v1.Name != nil && v1.Name.Defn == n {
v1.Type = t1 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) yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t1, v1, why)
} }
}
checkassign(n, v1) checkassign(n, v1)
} }
if v2 != nil { if v2 != nil {
if v2.Name != nil && v2.Name.Defn == n { if v2.Name != nil && v2.Name.Defn == n {
v2.Type = t2 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) yyerrorl(n.Pos, "cannot assign type %v to %L in range%s", t2, v2, why)
} }
}
checkassign(n, v2) checkassign(n, v2)
} }
} }
@ -463,7 +466,7 @@ func walkrange(n *Node) *Node {
// //
// where == for keys of map m is reflexive. // where == for keys of map m is reflexive.
func isMapClear(n *Node) bool { func isMapClear(n *Node) bool {
if Debug['N'] != 0 || instrumenting { if Debug.N != 0 || instrumenting {
return false return false
} }
@ -530,7 +533,7 @@ func mapClear(m *Node) *Node {
// //
// Parameters are as in walkrange: "for v1, v2 = range a". // Parameters are as in walkrange: "for v1, v2 = range a".
func arrayClear(n, v1, v2, a *Node) bool { func arrayClear(n, v1, v2, a *Node) bool {
if Debug['N'] != 0 || instrumenting { if Debug.N != 0 || instrumenting {
return false return false
} }

View file

@ -62,9 +62,9 @@ func scopePCs(fnsym *obj.LSym, marks []Mark, dwarfScopes []dwarf.Scope) {
if len(marks) == 0 { if len(marks) == 0 {
return return
} }
p0 := fnsym.Func.Text p0 := fnsym.Func().Text
scope := findScope(marks, p0.Pos) 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 { if p.Pos == p0.Pos {
continue continue
} }

View file

@ -39,7 +39,7 @@ func (s *InitSchedule) append(n *Node) {
// staticInit adds an initialization statement n to the schedule. // staticInit adds an initialization statement n to the schedule.
func (s *InitSchedule) staticInit(n *Node) { func (s *InitSchedule) staticInit(n *Node) {
if !s.tryStaticInit(n) { if !s.tryStaticInit(n) {
if Debug['%'] != 0 { if Debug.P != 0 {
Dump("nonstatic", n) Dump("nonstatic", n)
} }
s.append(n) s.append(n)
@ -128,7 +128,7 @@ func (s *InitSchedule) staticcopy(l *Node, r *Node) bool {
case OSLICELIT: case OSLICELIT:
// copy slice // copy slice
a := s.inittemps[r] a := s.inittemps[r]
slicesym(l, a, r.Right.Int64()) slicesym(l, a, r.Right.Int64Val())
return true return true
case OARRAYLIT, OSTRUCTLIT: case OARRAYLIT, OSTRUCTLIT:
@ -205,7 +205,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
case OSTR2BYTES: case OSTR2BYTES:
if l.Class() == PEXTERN && r.Left.Op == OLITERAL { if l.Class() == PEXTERN && r.Left.Op == OLITERAL {
sval := strlit(r.Left) sval := r.Left.StringVal()
slicebytes(l, sval) slicebytes(l, sval)
return true return true
} }
@ -213,7 +213,7 @@ func (s *InitSchedule) staticassign(l *Node, r *Node) bool {
case OSLICELIT: case OSLICELIT:
s.initplan(r) s.initplan(r)
// Init slice. // Init slice.
bound := r.Right.Int64() bound := r.Right.Int64Val()
ta := types.NewArray(r.Type.Elem(), bound) ta := types.NewArray(r.Type.Elem(), bound)
ta.SetNoalg(true) ta.SetNoalg(true)
a := staticname(ta) a := staticname(ta)
@ -413,7 +413,7 @@ func getdyn(n *Node, top bool) initGenType {
if !top { if !top {
return initDynamic 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. // <25% of entries have explicit values.
// Very rough estimation, it takes 4 bytes of instructions // Very rough estimation, it takes 4 bytes of instructions
// to initialize 1 byte of result. So don't use a static // to initialize 1 byte of result. So don't use a static
@ -589,12 +589,12 @@ func isSmallSliceLit(n *Node) bool {
r := n.Right 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) { func slicelit(ctxt initContext, n *Node, var_ *Node, init *Nodes) {
// make an array type corresponding the number of elements we have // 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) dowidth(t)
if ctxt == inNonInitFunction { if ctxt == inNonInitFunction {
@ -993,7 +993,7 @@ func oaslit(n *Node, init *Nodes) bool {
func getlit(lit *Node) int { func getlit(lit *Node) int {
if smallintconst(lit) { if smallintconst(lit) {
return int(lit.Int64()) return int(lit.Int64Val())
} }
return -1 return -1
} }

View file

@ -59,7 +59,7 @@ func initssaconfig() {
_ = types.NewPtr(types.Types[TINT64]) // *int64 _ = types.NewPtr(types.Types[TINT64]) // *int64
_ = types.NewPtr(types.Errortype) // *error _ = types.NewPtr(types.Errortype) // *error
types.NewPtrCacheEnabled = false types.NewPtrCacheEnabled = false
ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, *types_, Ctxt, Debug['N'] == 0) ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, *types_, Ctxt, Debug.N == 0)
ssaConfig.SoftFloat = thearch.SoftFloat ssaConfig.SoftFloat = thearch.SoftFloat
ssaConfig.Race = flag_race ssaConfig.Race = flag_race
ssaCaches = make([]ssa.Cache, nBackendWorkers) ssaCaches = make([]ssa.Cache, nBackendWorkers)
@ -240,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 // - Offset of where argument should be placed in the args frame when making call
func (s *state) emitOpenDeferInfo() { func (s *state) emitOpenDeferInfo() {
x := Ctxt.Lookup(s.curfn.Func.lsym.Name + ".opendefer") 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 off := 0
// Compute maxargsize (max size of arguments for all defers) // Compute maxargsize (max size of arguments for all defers)
@ -357,7 +357,7 @@ func buildssa(fn *Node, worker int) *ssa.Func {
s.fwdVars = map[*Node]*ssa.Value{} s.fwdVars = map[*Node]*ssa.Value{}
s.startmem = s.entryNewValue0(ssa.OpInitMem, types.TypeMem) 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 { switch {
case s.hasOpenDefers && (Ctxt.Flag_shared || Ctxt.Flag_dynlink) && thearch.LinkArch.Name == "386": 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 // Don't support open-coded defers for 386 ONLY when using shared
@ -741,7 +741,7 @@ func (s *state) pushLine(line src.XPos) {
// the frontend may emit node with line number missing, // the frontend may emit node with line number missing,
// use the parent line number in this case. // use the parent line number in this case.
line = s.peekPos() line = s.peekPos()
if Debug['K'] != 0 { if Debug.K != 0 {
Warn("buildssa: unknown position (line 0)") Warn("buildssa: unknown position (line 0)")
} }
} else { } else {
@ -1214,7 +1214,7 @@ func (s *state) stmt(n *Node) {
// Check whether we're writing the result of an append back to the same slice. // 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 // If so, we handle it specially to avoid write barriers on the fast
// (non-growth) path. // (non-growth) path.
if !samesafeexpr(n.Left, rhs.List.First()) || Debug['N'] != 0 { if !samesafeexpr(n.Left, rhs.List.First()) || Debug.N != 0 {
break break
} }
// If the slice can be SSA'd, it'll be on the stack, // If the slice can be SSA'd, it'll be on the stack,
@ -1271,7 +1271,7 @@ func (s *state) stmt(n *Node) {
// We're assigning a slicing operation back to its source. // We're assigning a slicing operation back to its source.
// Don't write back fields we aren't changing. See issue #14855. // Don't write back fields we aren't changing. See issue #14855.
i, j, k := rhs.SliceBounds() 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 [:...] // [0:...] is the same as [:...]
i = nil i = nil
} }
@ -1301,7 +1301,7 @@ func (s *state) stmt(n *Node) {
case OIF: case OIF:
if Isconst(n.Left, CTBOOL) { if Isconst(n.Left, CTBOOL) {
s.stmtList(n.Left.Ninit) s.stmtList(n.Left.Ninit)
if n.Left.Bool() { if n.Left.BoolVal() {
s.stmtList(n.Nbody) s.stmtList(n.Nbody)
} else { } else {
s.stmtList(n.Rlist) s.stmtList(n.Rlist)
@ -2610,7 +2610,7 @@ func (s *state) expr(n *Node) *ssa.Value {
// Replace "abc"[1] with 'b'. // Replace "abc"[1] with 'b'.
// Delayed until now because "abc"[1] is not an ideal constant. // Delayed until now because "abc"[1] is not an ideal constant.
// See test/fixedbugs/issue11370.go. // 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) a := s.expr(n.Left)
i := s.expr(n.Right) i := s.expr(n.Right)
@ -2619,7 +2619,7 @@ func (s *state) expr(n *Node) *ssa.Value {
ptrtyp := s.f.Config.Types.BytePtr ptrtyp := s.f.Config.Types.BytePtr
ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a) ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
if Isconst(n.Right, CTINT) { 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 { } else {
ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i) ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
} }
@ -3389,6 +3389,13 @@ func init() {
return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v) return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
}, },
sys.PPC64, sys.S390X) 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", addF("runtime/internal/atomic", "Loadp",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 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()) v := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(s.f.Config.Types.BytePtr, types.TypeMem), args[0], s.mem())
@ -3427,6 +3434,12 @@ func init() {
return nil return nil
}, },
sys.PPC64, sys.S390X) 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", addF("runtime/internal/atomic", "Xchg",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value { func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
@ -3542,9 +3555,15 @@ func init() {
alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load", p4...) alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load", p4...)
alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load64", p8...) alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load64", p8...)
alias("runtime/internal/atomic", "LoadAcq", "runtime/internal/atomic", "Load", lwatomics...) 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("runtime/internal/atomic", "LoadAcquintptr", "runtime/internal/atomic", "LoadAcq64", p8...)
alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store", p4...) alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store", p4...)
alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store64", p8...) alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store64", p8...)
alias("runtime/internal/atomic", "StoreRel", "runtime/internal/atomic", "Store", lwatomics...) 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("runtime/internal/atomic", "StoreReluintptr", "runtime/internal/atomic", "StoreRel64", p8...)
alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg", p4...) alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg", p4...)
alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg64", p8...) alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg64", p8...)
alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd", p4...) alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd", p4...)
@ -4830,7 +4849,7 @@ func (s *state) addr(n *Node) *ssa.Value {
// canSSA reports whether n is SSA-able. // canSSA reports whether n is SSA-able.
// n must be an ONAME (or an ODOT sequence with an ONAME base). // n must be an ONAME (or an ODOT sequence with an ONAME base).
func (s *state) canSSA(n *Node) bool { func (s *state) canSSA(n *Node) bool {
if Debug['N'] != 0 { if Debug.N != 0 {
return false return false
} }
for n.Op == ODOT || (n.Op == OINDEX && n.Left.Type.IsArray()) { for n.Op == ODOT || (n.Op == OINDEX && n.Left.Type.IsArray()) {
@ -4941,7 +4960,7 @@ func (s *state) nilCheck(ptr *ssa.Value) {
func (s *state) boundsCheck(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value { func (s *state) boundsCheck(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bool) *ssa.Value {
idx = s.extendIndex(idx, len, kind, bounded) 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, // If bounded or bounds checking is flag-disabled, then no check necessary,
// just return the extended index. // just return the extended index.
// //
@ -6108,7 +6127,7 @@ func emitStackObjects(e *ssafn, pp *Progs) {
// Populate the stack object data. // Populate the stack object data.
// Format must match runtime/stack.go:stackObjectRecord. // Format must match runtime/stack.go:stackObjectRecord.
x := e.curfn.Func.lsym.Func.StackObjects x := e.curfn.Func.lsym.Func().StackObjects
off := 0 off := 0
off = duintptr(x, off, uint64(len(vars))) off = duintptr(x, off, uint64(len(vars)))
for _, v := range vars { for _, v := range vars {
@ -6145,7 +6164,7 @@ func genssa(f *ssa.Func, pp *Progs) {
s.livenessMap = liveness(e, f, pp) s.livenessMap = liveness(e, f, pp)
emitStackObjects(e, pp) emitStackObjects(e, pp)
openDeferInfo := e.curfn.Func.lsym.Func.OpenCodedDeferInfo openDeferInfo := e.curfn.Func.lsym.Func().OpenCodedDeferInfo
if openDeferInfo != nil { if openDeferInfo != nil {
// This function uses open-coded defers -- write out the funcdata // This function uses open-coded defers -- write out the funcdata
// info that we computed at the end of genssa. // info that we computed at the end of genssa.
@ -6291,7 +6310,7 @@ func genssa(f *ssa.Func, pp *Progs) {
} }
// Emit control flow instructions for block // Emit control flow instructions for block
var next *ssa.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 // If -N, leave next==nil so every block with successors
// ends in a JMP (except call blocks - plive doesn't like // ends in a JMP (except call blocks - plive doesn't like
// select{send,recv} followed by a JMP call). Helps keep // select{send,recv} followed by a JMP call). Helps keep
@ -6350,7 +6369,7 @@ func genssa(f *ssa.Func, pp *Progs) {
// some of the inline marks. // some of the inline marks.
// Use this instruction instead. // Use this instruction instead.
p.Pos = p.Pos.WithIsStmt() // promote position to a statement 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. // Make the inline mark a real nop, so it doesn't generate any code.
m.As = obj.ANOP m.As = obj.ANOP
m.Pos = src.NoXPos m.Pos = src.NoXPos
@ -6362,7 +6381,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). // Any unmatched inline marks now need to be added to the inlining tree (and will generate a nop instruction).
for _, p := range inlMarkList { for _, p := range inlMarkList {
if p.As != obj.ANOP { if p.As != obj.ANOP {
pp.curfn.Func.lsym.Func.AddInlMark(p, inlMarks[p]) pp.curfn.Func.lsym.Func().AddInlMark(p, inlMarks[p])
} }
} }
} }
@ -6599,7 +6618,7 @@ func (s *state) extendIndex(idx, len *ssa.Value, kind ssa.BoundsKind, bounded bo
} else { } else {
lo = s.newValue1(ssa.OpInt64Lo, types.Types[TUINT], idx) lo = s.newValue1(ssa.OpInt64Lo, types.Types[TUINT], idx)
} }
if bounded || Debug['B'] != 0 { if bounded || Debug.B != 0 {
return lo return lo
} }
bNext := s.f.NewBlock(ssa.BlockPlain) bNext := s.f.NewBlock(ssa.BlockPlain)

View file

@ -96,7 +96,7 @@ func flusherrors() {
} }
func hcrash() { func hcrash() {
if Debug['h'] != 0 { if Debug.h != 0 {
flusherrors() flusherrors()
if outfile != "" { if outfile != "" {
os.Remove(outfile) os.Remove(outfile)
@ -107,7 +107,7 @@ func hcrash() {
} }
func linestr(pos src.XPos) string { 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. // lasterror keeps track of the most recently issued error.
@ -153,7 +153,7 @@ func yyerrorl(pos src.XPos, format string, args ...interface{}) {
hcrash() hcrash()
nerrors++ nerrors++
if nsavederrors+nerrors >= 10 && Debug['e'] == 0 { if nsavederrors+nerrors >= 10 && Debug.e == 0 {
flusherrors() flusherrors()
fmt.Printf("%v: too many errors\n", linestr(pos)) fmt.Printf("%v: too many errors\n", linestr(pos))
errorexit() errorexit()
@ -175,7 +175,7 @@ func Warn(fmt_ string, args ...interface{}) {
func Warnl(line src.XPos, fmt_ string, args ...interface{}) { func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
adderr(line, fmt_, args...) adderr(line, fmt_, args...)
if Debug['m'] != 0 { if Debug.m != 0 {
flusherrors() flusherrors()
} }
} }
@ -222,7 +222,7 @@ func hasUniquePos(n *Node) bool {
} }
if !n.Pos.IsKnown() { if !n.Pos.IsKnown() {
if Debug['K'] != 0 { if Debug.K != 0 {
Warn("setlineno: unknown position (line 0)") Warn("setlineno: unknown position (line 0)")
} }
return false return false
@ -348,7 +348,7 @@ func newname(s *types.Sym) *Node {
return n 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. // The caller is responsible for setting n.Name.Curfn.
func newnamel(pos src.XPos, s *types.Sym) *Node { func newnamel(pos src.XPos, s *types.Sym) *Node {
if s == nil { if s == nil {
@ -546,22 +546,19 @@ func methtype(t *types.Type) *types.Type {
// Is type src assignment compatible to type dst? // Is type src assignment compatible to type dst?
// If so, return op code to use in conversion. // If so, return op code to use in conversion.
// If not, return OXXX. // If not, return OXXX. In this case, the string return parameter may
func assignop(src, dst *types.Type, why *string) Op { // hold a reason why. In all other cases, it'll be the empty string.
if why != nil { func assignop(src, dst *types.Type) (Op, string) {
*why = ""
}
if src == dst { if src == dst {
return OCONVNOP return OCONVNOP, ""
} }
if src == nil || dst == nil || src.Etype == TFORW || dst.Etype == TFORW || src.Orig == nil || dst.Orig == nil { 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. // 1. src type is identical to dst.
if types.Identical(src, dst) { if types.Identical(src, dst) {
return OCONVNOP return OCONVNOP, ""
} }
// 2. src and dst have identical underlying types // 2. src and dst have identical underlying types
@ -575,13 +572,13 @@ func assignop(src, dst *types.Type, why *string) Op {
if src.IsEmptyInterface() { if src.IsEmptyInterface() {
// Conversion between two empty interfaces // Conversion between two empty interfaces
// requires no code. // requires no code.
return OCONVNOP return OCONVNOP, ""
} }
if (src.Sym == nil || dst.Sym == nil) && !src.IsInterface() { if (src.Sym == nil || dst.Sym == nil) && !src.IsInterface() {
// Conversion between two types, at least one unnamed, // Conversion between two types, at least one unnamed,
// needs no conversion. The exception is nonempty interfaces // needs no conversion. The exception is nonempty interfaces
// which need to have their itab updated. // 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 missing, have *types.Field
var ptr int var ptr int
if implements(src, dst, &missing, &have, &ptr) { if implements(src, dst, &missing, &have, &ptr) {
return OCONVIFACE return OCONVIFACE, ""
} }
// we'll have complained about this method anyway, suppress spurious messages. // we'll have complained about this method anyway, suppress spurious messages.
if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) { 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) { 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() { } 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 { } 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) "\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 { } 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 { } 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) "\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
} else { } 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 isptrto(dst, TINTER) {
if why != nil { why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
*why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst) return OXXX, why
}
return OXXX
} }
if src.IsInterface() && dst.Etype != TBLANK { if src.IsInterface() && dst.Etype != TBLANK {
var missing, have *types.Field var missing, have *types.Field
var ptr int var ptr int
if why != nil && implements(dst, src, &missing, &have, &ptr) { var why string
*why = ": need type assertion" 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, // 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. // either src or dst is not a named type.
if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() { if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
if types.Identical(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) { 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, TCHAN,
TINTER, TINTER,
TSLICE: 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. // 7. Any typed value can be assigned to the blank identifier.
if dst.Etype == TBLANK { 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? // 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 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. // srcConstant indicates whether the value of type src is a constant.
func convertop(srcConstant bool, src, dst *types.Type, why *string) Op { func convertop(srcConstant bool, src, dst *types.Type) (Op, string) {
if why != nil {
*why = ""
}
if src == dst { if src == dst {
return OCONVNOP return OCONVNOP, ""
} }
if src == nil || dst == nil { if src == nil || dst == nil {
return OXXX return OXXX, ""
} }
// Conversions from regular to go:notinheap are not allowed // 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. // rules.
// (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't. // (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 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())
*why = fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem()) return OXXX, why
}
return OXXX
} }
// (b) Disallow string to []T where T is go:notinheap. // (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 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())
*why = fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem()) return OXXX, why
}
return OXXX
} }
// 1. src can be assigned to dst. // 1. src can be assigned to dst.
op := assignop(src, dst, why) op, why := assignop(src, dst)
if op != OXXX { if op != OXXX {
return op return op, why
} }
// The rules for interfaces are no different in conversions // 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. // with the good message from assignop.
// Otherwise clear the error. // Otherwise clear the error.
if src.IsInterface() || dst.IsInterface() { if src.IsInterface() || dst.IsInterface() {
return OXXX return OXXX, why
}
if why != nil {
*why = ""
} }
// 2. Ignoring struct tags, src and dst have identical underlying types. // 2. Ignoring struct tags, src and dst have identical underlying types.
if types.IdenticalIgnoreTags(src.Orig, dst.Orig) { if types.IdenticalIgnoreTags(src.Orig, dst.Orig) {
return OCONVNOP return OCONVNOP, ""
} }
// 3. src and dst are unnamed pointer types and, ignoring struct tags, // 3. src and dst are unnamed pointer types and, ignoring struct tags,
// their base types have identical underlying types. // their base types have identical underlying types.
if src.IsPtr() && dst.IsPtr() && src.Sym == nil && dst.Sym == nil { if src.IsPtr() && dst.IsPtr() && src.Sym == nil && dst.Sym == nil {
if types.IdenticalIgnoreTags(src.Elem().Orig, dst.Elem().Orig) { if types.IdenticalIgnoreTags(src.Elem().Orig, dst.Elem().Orig) {
return OCONVNOP return OCONVNOP, ""
} }
} }
// 4. src and dst are both integer or floating point types. // 4. src and dst are both integer or floating point types.
if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) { if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
if simtype[src.Etype] == simtype[dst.Etype] { if simtype[src.Etype] == simtype[dst.Etype] {
return OCONVNOP return OCONVNOP, ""
} }
return OCONV return OCONV, ""
} }
// 5. src and dst are both complex types. // 5. src and dst are both complex types.
if src.IsComplex() && dst.IsComplex() { if src.IsComplex() && dst.IsComplex() {
if simtype[src.Etype] == simtype[dst.Etype] { if simtype[src.Etype] == simtype[dst.Etype] {
return OCONVNOP return OCONVNOP, ""
} }
return OCONV return OCONV, ""
} }
// Special case for constant conversions: any numeric // Special case for constant conversions: any numeric
// conversion is potentially okay. We'll validate further // conversion is potentially okay. We'll validate further
// within evconst. See #38117. // within evconst. See #38117.
if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) { 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 // 6. src is an integer or has type []byte or []rune
// and dst is a string type. // and dst is a string type.
if src.IsInteger() && dst.IsString() { if src.IsInteger() && dst.IsString() {
return ORUNESTR return ORUNESTR, ""
} }
if src.IsSlice() && dst.IsString() { if src.IsSlice() && dst.IsString() {
if src.Elem().Etype == types.Bytetype.Etype { if src.Elem().Etype == types.Bytetype.Etype {
return OBYTES2STR return OBYTES2STR, ""
} }
if src.Elem().Etype == types.Runetype.Etype { 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. // String to slice.
if src.IsString() && dst.IsSlice() { if src.IsString() && dst.IsSlice() {
if dst.Elem().Etype == types.Bytetype.Etype { if dst.Elem().Etype == types.Bytetype.Etype {
return OSTR2BYTES return OSTR2BYTES, ""
} }
if dst.Elem().Etype == types.Runetype.Etype { if dst.Elem().Etype == types.Runetype.Etype {
return OSTR2RUNES return OSTR2RUNES, ""
} }
} }
// 8. src is a pointer or uintptr and dst is unsafe.Pointer. // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() { if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
return OCONVNOP return OCONVNOP, ""
} }
// 9. src is unsafe.Pointer and dst is a pointer or uintptr. // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) { if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
return OCONVNOP return OCONVNOP, ""
} }
// src is map and dst is a pointer to corresponding hmap. // 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. // go gc maps are implemented as a pointer to a hmap struct.
if src.Etype == TMAP && dst.IsPtr() && if src.Etype == TMAP && dst.IsPtr() &&
src.MapType().Hmap == dst.Elem() { src.MapType().Hmap == dst.Elem() {
return OCONVNOP return OCONVNOP, ""
} }
return OXXX return OXXX, ""
} }
func assignconv(n *Node, t *types.Type, context string) *Node { func assignconv(n *Node, t *types.Type, context string) *Node {
@ -839,8 +824,7 @@ func assignconvfn(n *Node, t *types.Type, context func() string) *Node {
return n return n
} }
var why string op, why := assignop(n.Type, t)
op := assignop(n.Type, t, &why)
if op == OXXX { if op == OXXX {
yyerror("cannot use %L as type %v in %s%s", n, t, context(), why) yyerror("cannot use %L as type %v in %s%s", n, t, context(), why)
op = OCONV op = OCONV
@ -1040,25 +1024,24 @@ func calcHasCall(n *Node) bool {
return false return false
} }
func badtype(op Op, tl *types.Type, tr *types.Type) { func badtype(op Op, tl, tr *types.Type) {
fmt_ := "" var s string
if tl != nil { if tl != nil {
fmt_ += fmt.Sprintf("\n\t%v", tl) s += fmt.Sprintf("\n\t%v", tl)
} }
if tr != nil { if tr != nil {
fmt_ += fmt.Sprintf("\n\t%v", tr) s += fmt.Sprintf("\n\t%v", tr)
} }
// common mistake: *struct and *interface. // common mistake: *struct and *interface.
if tl != nil && tr != nil && tl.IsPtr() && tr.IsPtr() { if tl != nil && tr != nil && tl.IsPtr() && tr.IsPtr() {
if tl.Elem().IsStruct() && tr.Elem().IsInterface() { 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() { } 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) 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 // method - M func (t T)(), a TFIELD type struct
// newnam - the eventual mangled name of this function // newnam - the eventual mangled name of this function
func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) { 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) 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) fn.Nbody.Append(call)
} }
if false && Debug['r'] != 0 { if false && Debug.r != 0 {
dumplist("genwrapper body", fn.Nbody) 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. // the method does not exist for value types.
rcvr := tm.Type.Recv().Type rcvr := tm.Type.Recv().Type
if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) { if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) {
if false && Debug['r'] != 0 { if false && Debug.r != 0 {
yyerror("interface pointer mismatch") yyerror("interface pointer mismatch")
} }

View file

@ -189,18 +189,21 @@ func typecheckExprSwitch(n *Node) {
continue continue
} }
switch { if nilonly != "" && !n1.isNil() {
case nilonly != "" && !n1.isNil():
yyerrorl(ncase.Pos, "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left) yyerrorl(ncase.Pos, "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Left)
case t.IsInterface() && !n1.Type.IsInterface() && !IsComparable(n1.Type): } else if t.IsInterface() && !n1.Type.IsInterface() && !IsComparable(n1.Type) {
yyerrorl(ncase.Pos, "invalid case %L in switch (incomparable type)", n1) yyerrorl(ncase.Pos, "invalid case %L in switch (incomparable type)", n1)
case assignop(n1.Type, t, nil) == 0 && assignop(t, n1.Type, nil) == 0: } else {
op1, _ := assignop(n1.Type, t)
op2, _ := assignop(t, n1.Type)
if op1 == OXXX && op2 == OXXX {
if n.Left != nil { if n.Left != nil {
yyerrorl(ncase.Pos, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t) yyerrorl(ncase.Pos, "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Left, n1.Type, t)
} else { } else {
yyerrorl(ncase.Pos, "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type) yyerrorl(ncase.Pos, "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type)
} }
} }
}
// Don't check for duplicate bools. Although the spec allows it, // Don't check for duplicate bools. Although the spec allows it,
// (1) the compiler hasn't checked it in the past, so compatibility mandates it, and // (1) the compiler hasn't checked it in the past, so compatibility mandates it, and
@ -358,8 +361,8 @@ func (s *exprSwitch) flush() {
// all we need here is consistency. We respect this // all we need here is consistency. We respect this
// sorting below. // sorting below.
sort.Slice(cc, func(i, j int) bool { sort.Slice(cc, func(i, j int) bool {
si := strlit(cc[i].lo) si := cc[i].lo.StringVal()
sj := strlit(cc[j].lo) sj := cc[j].lo.StringVal()
if len(si) != len(sj) { if len(si) != len(sj) {
return len(si) < len(sj) return len(si) < len(sj)
} }
@ -368,7 +371,7 @@ func (s *exprSwitch) flush() {
// runLen returns the string length associated with a // runLen returns the string length associated with a
// particular run of exprClauses. // particular run of exprClauses.
runLen := func(run []exprClause) int64 { return int64(len(strlit(run[0].lo))) } runLen := func(run []exprClause) int64 { return int64(len(run[0].lo.StringVal())) }
// Collapse runs of consecutive strings with the same length. // Collapse runs of consecutive strings with the same length.
var runs [][]exprClause var runs [][]exprClause
@ -405,7 +408,7 @@ func (s *exprSwitch) flush() {
merged := cc[:1] merged := cc[:1]
for _, c := range cc[1:] { for _, c := range cc[1:] {
last := &merged[len(merged)-1] last := &merged[len(merged)-1]
if last.jmp == c.jmp && last.hi.Int64()+1 == c.lo.Int64() { if last.jmp == c.jmp && last.hi.Int64Val()+1 == c.lo.Int64Val() {
last.hi = c.lo last.hi = c.lo
} else { } else {
merged = append(merged, c) merged = append(merged, c)
@ -440,7 +443,7 @@ func (c *exprClause) test(exprname *Node) *Node {
// Optimize "switch true { ...}" and "switch false { ... }". // Optimize "switch true { ...}" and "switch false { ... }".
if Isconst(exprname, CTBOOL) && !c.lo.Type.IsInterface() { if Isconst(exprname, CTBOOL) && !c.lo.Type.IsInterface() {
if exprname.Bool() { if exprname.BoolVal() {
return c.lo return c.lo
} else { } else {
return nodl(c.pos, ONOT, c.lo, nil) return nodl(c.pos, ONOT, c.lo, nil)

View file

@ -247,7 +247,7 @@ func (n *Node) Val() Val {
// SetVal sets the Val for the node, which must not have been used with SetOpt. // SetVal sets the Val for the node, which must not have been used with SetOpt.
func (n *Node) SetVal(v Val) { func (n *Node) SetVal(v Val) {
if n.HasOpt() { if n.HasOpt() {
Debug['h'] = 1 Debug.h = 1
Dump("have Opt", n) Dump("have Opt", n)
Fatalf("have Opt") Fatalf("have Opt")
} }
@ -270,7 +270,7 @@ func (n *Node) SetOpt(x interface{}) {
return return
} }
if n.HasVal() { if n.HasVal() {
Debug['h'] = 1 Debug.h = 1
Dump("have Val", n) Dump("have Val", n)
Fatalf("have Val") Fatalf("have Val")
} }
@ -460,14 +460,14 @@ type Param struct {
// x1 := xN.Defn // x1 := xN.Defn
// x1.Innermost = xN.Outer // x1.Innermost = xN.Outer
// //
// We leave xN.Innermost set so that we can still get to the original // We leave x1.Innermost set so that we can still get to the original
// variable quickly. Not shown here, but once we're // variable quickly. Not shown here, but once we're
// done parsing a function and no longer need xN.Outer for the // done parsing a function and no longer need xN.Outer for the
// lexical x reference links as described above, closurebody // lexical x reference links as described above, funcLit
// recomputes xN.Outer as the semantic x reference link tree, // recomputes xN.Outer as the semantic x reference link tree,
// even filling in x in intermediate closures that might not // even filling in x in intermediate closures that might not
// have mentioned it along the way to inner closures that did. // have mentioned it along the way to inner closures that did.
// See closurebody for details. // See funcLit for details.
// //
// During the eventual compilation, then, for closure variables we have: // During the eventual compilation, then, for closure variables we have:
// //

View file

@ -674,8 +674,8 @@ func typecheck1(n *Node, top int) (res *Node) {
// The conversion allocates, so only do it if the concrete type is huge. // The conversion allocates, so only do it if the concrete type is huge.
converted := false converted := false
if r.Type.Etype != TBLANK { if r.Type.Etype != TBLANK {
aop = assignop(l.Type, r.Type, nil) aop, _ = assignop(l.Type, r.Type)
if aop != 0 { if aop != OXXX {
if r.Type.IsInterface() && !l.Type.IsInterface() && !IsComparable(l.Type) { if r.Type.IsInterface() && !l.Type.IsInterface() && !IsComparable(l.Type) {
yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type)) yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type))
n.Type = nil n.Type = nil
@ -696,8 +696,8 @@ func typecheck1(n *Node, top int) (res *Node) {
} }
if !converted && l.Type.Etype != TBLANK { if !converted && l.Type.Etype != TBLANK {
aop = assignop(r.Type, l.Type, nil) aop, _ = assignop(r.Type, l.Type)
if aop != 0 { if aop != OXXX {
if l.Type.IsInterface() && !r.Type.IsInterface() && !IsComparable(r.Type) { if l.Type.IsInterface() && !r.Type.IsInterface() && !IsComparable(r.Type) {
yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type)) yyerror("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type))
n.Type = nil n.Type = nil
@ -1046,13 +1046,13 @@ func typecheck1(n *Node, top int) (res *Node) {
} }
if !n.Bounded() && Isconst(n.Right, CTINT) { if !n.Bounded() && Isconst(n.Right, CTINT) {
x := n.Right.Int64() x := n.Right.Int64Val()
if x < 0 { if x < 0 {
yyerror("invalid %s index %v (index must be non-negative)", why, n.Right) yyerror("invalid %s index %v (index must be non-negative)", why, n.Right)
} else if t.IsArray() && x >= t.NumElem() { } else if t.IsArray() && x >= t.NumElem() {
yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.NumElem()) yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.NumElem())
} else if Isconst(n.Left, CTSTR) && x >= int64(len(strlit(n.Left))) { } else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.StringVal())) {
yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(strlit(n.Left))) yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.StringVal()))
} else if n.Right.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 { } else if n.Right.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
yyerror("invalid %s index %v (index too large)", why, n.Right) yyerror("invalid %s index %v (index too large)", why, n.Right)
} }
@ -1148,11 +1148,11 @@ func typecheck1(n *Node, top int) (res *Node) {
l = defaultlit(l, types.Types[TINT]) l = defaultlit(l, types.Types[TINT])
c = defaultlit(c, types.Types[TINT]) c = defaultlit(c, types.Types[TINT])
if Isconst(l, CTINT) && l.Int64() < 0 { if Isconst(l, CTINT) && l.Int64Val() < 0 {
Fatalf("len for OSLICEHEADER must be non-negative") Fatalf("len for OSLICEHEADER must be non-negative")
} }
if Isconst(c, CTINT) && c.Int64() < 0 { if Isconst(c, CTINT) && c.Int64Val() < 0 {
Fatalf("cap for OSLICEHEADER must be non-negative") Fatalf("cap for OSLICEHEADER must be non-negative")
} }
@ -1201,7 +1201,7 @@ func typecheck1(n *Node, top int) (res *Node) {
if n.Left.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 { if n.Left.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
Fatalf("len for OMAKESLICECOPY too large") Fatalf("len for OMAKESLICECOPY too large")
} }
if n.Left.Int64() < 0 { if n.Left.Int64Val() < 0 {
Fatalf("len for OMAKESLICECOPY must be non-negative") Fatalf("len for OMAKESLICECOPY must be non-negative")
} }
} }
@ -1691,7 +1691,7 @@ func typecheck1(n *Node, top int) (res *Node) {
return n return n
} }
var why string var why string
n.Op = convertop(n.Left.Op == OLITERAL, t, n.Type, &why) n.Op, why = convertop(n.Left.Op == OLITERAL, t, n.Type)
if n.Op == OXXX { if n.Op == OXXX {
if !n.Diag() && !n.Type.Broke() && !n.Left.Diag() { if !n.Diag() && !n.Type.Broke() && !n.Left.Diag() {
yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why) yyerror("cannot convert %L to type %v%s", n.Left, n.Type, why)
@ -2187,14 +2187,14 @@ func checksliceindex(l *Node, r *Node, tp *types.Type) bool {
} }
if r.Op == OLITERAL { if r.Op == OLITERAL {
if r.Int64() < 0 { if r.Int64Val() < 0 {
yyerror("invalid slice index %v (index must be non-negative)", r) yyerror("invalid slice index %v (index must be non-negative)", r)
return false return false
} else if tp != nil && tp.NumElem() >= 0 && r.Int64() > tp.NumElem() { } else if tp != nil && tp.NumElem() >= 0 && r.Int64Val() > tp.NumElem() {
yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.NumElem()) yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.NumElem())
return false return false
} else if Isconst(l, CTSTR) && r.Int64() > int64(len(strlit(l))) { } else if Isconst(l, CTSTR) && r.Int64Val() > int64(len(l.StringVal())) {
yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(strlit(l))) yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.StringVal()))
return false return false
} else if r.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 { } else if r.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
yyerror("invalid slice index %v (index too large)", r) yyerror("invalid slice index %v (index too large)", r)
@ -3267,9 +3267,7 @@ func typecheckas(n *Node) {
} }
func checkassignto(src *types.Type, dst *Node) { func checkassignto(src *types.Type, dst *Node) {
var why string if op, why := assignop(src, dst.Type); op == OXXX {
if assignop(src, dst.Type, &why) == 0 {
yyerror("cannot assign %v to %L in multiple assignment%s", src, dst, why) yyerror("cannot assign %v to %L in multiple assignment%s", src, dst, why)
return return
} }
@ -3450,9 +3448,8 @@ func stringtoruneslit(n *Node) *Node {
} }
var l []*Node var l []*Node
s := strlit(n.Left)
i := 0 i := 0
for _, r := range s { for _, r := range n.Left.StringVal() {
l = append(l, nod(OKEY, nodintconst(int64(i)), nodintconst(int64(r)))) l = append(l, nod(OKEY, nodintconst(int64(i)), nodintconst(int64(r))))
i++ i++
} }
@ -3904,7 +3901,7 @@ func deadcodefn(fn *Node) {
return return
} }
case OFOR: case OFOR:
if !Isconst(n.Left, CTBOOL) || n.Left.Bool() { if !Isconst(n.Left, CTBOOL) || n.Left.BoolVal() {
return return
} }
default: default:
@ -3934,7 +3931,7 @@ func deadcodeslice(nn Nodes) {
n.Left = deadcodeexpr(n.Left) n.Left = deadcodeexpr(n.Left)
if Isconst(n.Left, CTBOOL) { if Isconst(n.Left, CTBOOL) {
var body Nodes var body Nodes
if n.Left.Bool() { if n.Left.BoolVal() {
n.Rlist = Nodes{} n.Rlist = Nodes{}
body = n.Nbody body = n.Nbody
} else { } else {
@ -3977,7 +3974,7 @@ func deadcodeexpr(n *Node) *Node {
n.Left = deadcodeexpr(n.Left) n.Left = deadcodeexpr(n.Left)
n.Right = deadcodeexpr(n.Right) n.Right = deadcodeexpr(n.Right)
if Isconst(n.Left, CTBOOL) { if Isconst(n.Left, CTBOOL) {
if n.Left.Bool() { if n.Left.BoolVal() {
return n.Right // true && x => x return n.Right // true && x => x
} else { } else {
return n.Left // false && x => false return n.Left // false && x => false
@ -3987,7 +3984,7 @@ func deadcodeexpr(n *Node) *Node {
n.Left = deadcodeexpr(n.Left) n.Left = deadcodeexpr(n.Left)
n.Right = deadcodeexpr(n.Right) n.Right = deadcodeexpr(n.Right)
if Isconst(n.Left, CTBOOL) { if Isconst(n.Left, CTBOOL) {
if n.Left.Bool() { if n.Left.BoolVal() {
return n.Left // true || x => true return n.Left // true || x => true
} else { } else {
return n.Right // false || x => x return n.Right // false || x => x

View file

@ -21,7 +21,7 @@ const zeroValSize = 1024 // must match value of runtime/map.go:maxZero
func walk(fn *Node) { func walk(fn *Node) {
Curfn = fn Curfn = fn
if Debug['W'] != 0 { if Debug.W != 0 {
s := fmt.Sprintf("\nbefore walk %v", Curfn.Func.Nname.Sym) s := fmt.Sprintf("\nbefore walk %v", Curfn.Func.Nname.Sym)
dumplist(s, Curfn.Nbody) dumplist(s, Curfn.Nbody)
} }
@ -63,14 +63,14 @@ func walk(fn *Node) {
return return
} }
walkstmtlist(Curfn.Nbody.Slice()) walkstmtlist(Curfn.Nbody.Slice())
if Debug['W'] != 0 { if Debug.W != 0 {
s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym) s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
dumplist(s, Curfn.Nbody) dumplist(s, Curfn.Nbody)
} }
zeroResults() zeroResults()
heapmoves() heapmoves()
if Debug['W'] != 0 && Curfn.Func.Enter.Len() > 0 { if Debug.W != 0 && Curfn.Func.Enter.Len() > 0 {
s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym) s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
dumplist(s, Curfn.Func.Enter) dumplist(s, Curfn.Func.Enter)
} }
@ -436,7 +436,7 @@ func walkexpr(n *Node, init *Nodes) *Node {
lno := setlineno(n) lno := setlineno(n)
if Debug['w'] > 1 { if Debug.w > 1 {
Dump("before walk expr", n) Dump("before walk expr", n)
} }
@ -1001,7 +1001,7 @@ opswitch:
// The SSA backend will handle those. // The SSA backend will handle those.
switch et { switch et {
case TINT64: case TINT64:
c := n.Right.Int64() c := n.Right.Int64Val()
if c < 0 { if c < 0 {
c = -c c = -c
} }
@ -1009,7 +1009,7 @@ opswitch:
break opswitch break opswitch
} }
case TUINT64: case TUINT64:
c := uint64(n.Right.Int64()) c := uint64(n.Right.Int64Val())
if c != 0 && c&(c-1) == 0 { if c != 0 && c&(c-1) == 0 {
break opswitch break opswitch
} }
@ -1049,15 +1049,15 @@ opswitch:
} }
if t.IsArray() { if t.IsArray() {
n.SetBounded(bounded(r, t.NumElem())) n.SetBounded(bounded(r, t.NumElem()))
if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) { if Debug.m != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
Warn("index bounds check elided") Warn("index bounds check elided")
} }
if smallintconst(n.Right) && !n.Bounded() { if smallintconst(n.Right) && !n.Bounded() {
yyerror("index out of bounds") yyerror("index out of bounds")
} }
} else if Isconst(n.Left, CTSTR) { } else if Isconst(n.Left, CTSTR) {
n.SetBounded(bounded(r, int64(len(strlit(n.Left))))) n.SetBounded(bounded(r, int64(len(n.Left.StringVal()))))
if Debug['m'] != 0 && n.Bounded() && !Isconst(n.Right, CTINT) { if Debug.m != 0 && n.Bounded() && !Isconst(n.Right, CTINT) {
Warn("index bounds check elided") Warn("index bounds check elided")
} }
if smallintconst(n.Right) && !n.Bounded() { if smallintconst(n.Right) && !n.Bounded() {
@ -1491,7 +1491,7 @@ opswitch:
case OSTR2BYTES: case OSTR2BYTES:
s := n.Left s := n.Left
if Isconst(s, CTSTR) { if Isconst(s, CTSTR) {
sc := strlit(s) sc := s.StringVal()
// Allocate a [n]byte of the right size. // Allocate a [n]byte of the right size.
t := types.NewArray(types.Types[TUINT8], int64(len(sc))) t := types.NewArray(types.Types[TUINT8], int64(len(sc)))
@ -1599,7 +1599,7 @@ opswitch:
updateHasCall(n) updateHasCall(n)
if Debug['w'] != 0 && n != nil { if Debug.w != 0 && n != nil {
Dump("after walk expr", n) Dump("after walk expr", n)
} }
@ -1919,7 +1919,7 @@ func walkprint(nn *Node, init *Nodes) *Node {
for i := 0; i < len(s); { for i := 0; i < len(s); {
var strs []string var strs []string
for i < len(s) && Isconst(s[i], CTSTR) { for i < len(s) && Isconst(s[i], CTSTR) {
strs = append(strs, strlit(s[i])) strs = append(strs, s[i].StringVal())
i++ i++
} }
if len(strs) > 0 { if len(strs) > 0 {
@ -1988,7 +1988,7 @@ func walkprint(nn *Node, init *Nodes) *Node {
case TSTRING: case TSTRING:
cs := "" cs := ""
if Isconst(n, CTSTR) { if Isconst(n, CTSTR) {
cs = strlit(n) cs = n.StringVal()
} }
switch cs { switch cs {
case " ": case " ":
@ -2157,7 +2157,7 @@ func reorder3(all []*Node) []*Node {
// The result of reorder3save MUST be assigned back to n, e.g. // The result of reorder3save MUST be assigned back to n, e.g.
// n.Left = reorder3save(n.Left, all, i, early) // n.Left = reorder3save(n.Left, all, i, early)
func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node { func reorder3save(n *Node, all []*Node, i int, early *[]*Node) *Node {
if !aliased(n, all, i) { if !aliased(n, all[:i]) {
return n return n
} }
@ -2189,73 +2189,75 @@ func outervalue(n *Node) *Node {
} }
} }
// Is it possible that the computation of n might be // Is it possible that the computation of r might be
// affected by writes in as up to but not including the ith element? // affected by assignments in all?
func aliased(n *Node, all []*Node, i int) bool { func aliased(r *Node, all []*Node) bool {
if n == nil { if r == nil {
return false return false
} }
// Treat all fields of a struct as referring to the whole struct. // Treat all fields of a struct as referring to the whole struct.
// We could do better but we would have to keep track of the fields. // We could do better but we would have to keep track of the fields.
for n.Op == ODOT { for r.Op == ODOT {
n = n.Left r = r.Left
} }
// Look for obvious aliasing: a variable being assigned // Look for obvious aliasing: a variable being assigned
// during the all list and appearing in n. // during the all list and appearing in n.
// Also record whether there are any writes to main memory. // Also record whether there are any writes to addressable
// Also record whether there are any writes to variables // memory (either main memory or variables whose addresses
// whose addresses have been taken. // have been taken).
memwrite := false memwrite := false
varwrite := false for _, as := range all {
for _, an := range all[:i] { // We can ignore assignments to blank.
a := outervalue(an.Left) if as.Left.isBlank() {
continue
for a.Op == ODOT {
a = a.Left
} }
if a.Op != ONAME { l := outervalue(as.Left)
if l.Op != ONAME {
memwrite = true memwrite = true
continue continue
} }
switch n.Class() { switch l.Class() {
default: default:
varwrite = true Fatalf("unexpected class: %v, %v", l, l.Class())
case PAUTOHEAP, PEXTERN:
memwrite = true
continue continue
case PAUTO, PPARAM, PPARAMOUT: case PAUTO, PPARAM, PPARAMOUT:
if n.Name.Addrtaken() { if l.Name.Addrtaken() {
varwrite = true memwrite = true
continue continue
} }
if vmatch2(a, n) { if vmatch2(l, r) {
// Direct hit. // Direct hit: l appears in r.
return true return true
} }
} }
} }
// The variables being written do not appear in n. // The variables being written do not appear in r.
// However, n might refer to computed addresses // However, r might refer to computed addresses
// that are being written. // that are being written.
// If no computed addresses are affected by the writes, no aliasing. // If no computed addresses are affected by the writes, no aliasing.
if !memwrite && !varwrite { if !memwrite {
return false return false
} }
// If n does not refer to computed addresses // If r does not refer to computed addresses
// (that is, if n only refers to variables whose addresses // (that is, if r only refers to variables whose addresses
// have not been taken), no aliasing. // have not been taken), no aliasing.
if varexpr(n) { if varexpr(r) {
return false return false
} }
// Otherwise, both the writes and n refer to computed memory addresses. // Otherwise, both the writes and r refer to computed memory addresses.
// Assume that they might conflict. // Assume that they might conflict.
return true return true
} }
@ -2643,7 +2645,7 @@ func addstr(n *Node, init *Nodes) *Node {
sz := int64(0) sz := int64(0)
for _, n1 := range n.List.Slice() { for _, n1 := range n.List.Slice() {
if n1.Op == OLITERAL { if n1.Op == OLITERAL {
sz += int64(len(strlit(n1))) sz += int64(len(n1.StringVal()))
} }
} }
@ -2817,7 +2819,7 @@ func appendslice(n *Node, init *Nodes) *Node {
// isAppendOfMake reports whether n is of the form append(x , make([]T, y)...). // isAppendOfMake reports whether n is of the form append(x , make([]T, y)...).
// isAppendOfMake assumes n has already been typechecked. // isAppendOfMake assumes n has already been typechecked.
func isAppendOfMake(n *Node) bool { func isAppendOfMake(n *Node) bool {
if Debug['N'] != 0 || instrumenting { if Debug.N != 0 || instrumenting {
return false return false
} }
@ -3437,7 +3439,7 @@ func walkcompare(n *Node, init *Nodes) *Node {
func tracecmpArg(n *Node, t *types.Type, init *Nodes) *Node { func tracecmpArg(n *Node, t *types.Type, init *Nodes) *Node {
// Ugly hack to avoid "constant -1 overflows uintptr" errors, etc. // Ugly hack to avoid "constant -1 overflows uintptr" errors, etc.
if n.Op == OLITERAL && n.Type.IsSigned() && n.Int64() < 0 { if n.Op == OLITERAL && n.Type.IsSigned() && n.Int64Val() < 0 {
n = copyexpr(n, n.Type, init) n = copyexpr(n, n.Type, init)
} }
@ -3507,7 +3509,7 @@ func walkcompareString(n *Node, init *Nodes) *Node {
// Length-only checks are ok, though. // Length-only checks are ok, though.
maxRewriteLen = 0 maxRewriteLen = 0
} }
if s := strlit(cs); len(s) <= maxRewriteLen { if s := cs.StringVal(); len(s) <= maxRewriteLen {
if len(s) > 0 { if len(s) > 0 {
ncs = safeexpr(ncs, init) ncs = safeexpr(ncs, init)
} }
@ -3602,7 +3604,7 @@ func bounded(n *Node, max int64) bool {
bits := int32(8 * n.Type.Width) bits := int32(8 * n.Type.Width)
if smallintconst(n) { if smallintconst(n) {
v := n.Int64() v := n.Int64Val()
return 0 <= v && v < max return 0 <= v && v < max
} }
@ -3610,9 +3612,9 @@ func bounded(n *Node, max int64) bool {
case OAND: case OAND:
v := int64(-1) v := int64(-1)
if smallintconst(n.Left) { if smallintconst(n.Left) {
v = n.Left.Int64() v = n.Left.Int64Val()
} else if smallintconst(n.Right) { } else if smallintconst(n.Right) {
v = n.Right.Int64() v = n.Right.Int64Val()
} }
if 0 <= v && v < max { if 0 <= v && v < max {
@ -3621,7 +3623,7 @@ func bounded(n *Node, max int64) bool {
case OMOD: case OMOD:
if !sign && smallintconst(n.Right) { if !sign && smallintconst(n.Right) {
v := n.Right.Int64() v := n.Right.Int64Val()
if 0 <= v && v <= max { if 0 <= v && v <= max {
return true return true
} }
@ -3629,7 +3631,7 @@ func bounded(n *Node, max int64) bool {
case ODIV: case ODIV:
if !sign && smallintconst(n.Right) { if !sign && smallintconst(n.Right) {
v := n.Right.Int64() v := n.Right.Int64Val()
for bits > 0 && v >= 2 { for bits > 0 && v >= 2 {
bits-- bits--
v >>= 1 v >>= 1
@ -3638,7 +3640,7 @@ func bounded(n *Node, max int64) bool {
case ORSH: case ORSH:
if !sign && smallintconst(n.Right) { if !sign && smallintconst(n.Right) {
v := n.Right.Int64() v := n.Right.Int64Val()
if v > int64(bits) { if v > int64(bits) {
return true return true
} }
@ -3879,6 +3881,16 @@ func wrapCall(n *Node, init *Nodes) *Node {
} }
isBuiltinCall := n.Op != OCALLFUNC && n.Op != OCALLMETH && n.Op != OCALLINTER isBuiltinCall := n.Op != OCALLFUNC && n.Op != OCALLMETH && n.Op != OCALLINTER
// Turn f(a, b, []T{c, d, e}...) back into f(a, b, c, d, e).
if !isBuiltinCall && n.IsDDD() {
last := n.List.Len() - 1
if va := n.List.Index(last); va.Op == OSLICELIT {
n.List.Set(append(n.List.Slice()[:last], va.List.Slice()...))
n.SetIsDDD(false)
}
}
// origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion. // origArgs keeps track of what argument is uintptr-unsafe/unsafe-uintptr conversion.
origArgs := make([]*Node, n.List.Len()) origArgs := make([]*Node, n.List.Len())
t := nod(OTFUNC, nil, nil) t := nod(OTFUNC, nil, nil)
@ -3964,7 +3976,7 @@ func canMergeLoads() bool {
// isRuneCount reports whether n is of the form len([]rune(string)). // isRuneCount reports whether n is of the form len([]rune(string)).
// These are optimized into a call to runtime.countrunes. // These are optimized into a call to runtime.countrunes.
func isRuneCount(n *Node) bool { func isRuneCount(n *Node) bool {
return Debug['N'] == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTR2RUNES return Debug.N == 0 && !instrumenting && n.Op == OLEN && n.Left.Op == OSTR2RUNES
} }
func walkCheckPtrAlignment(n *Node, init *Nodes, count *Node) *Node { func walkCheckPtrAlignment(n *Node, init *Nodes, count *Node) *Node {

View file

@ -208,12 +208,11 @@ func s15a8(x *[15]int64) [15]int64 {
`"relatedInformation":[{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"}]}`) `"relatedInformation":[{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"}]}`)
want(t, slogged, `{"range":{"start":{"line":11,"character":6},"end":{"line":11,"character":6}},"severity":3,"code":"isInBounds","source":"go compiler","message":""}`) want(t, slogged, `{"range":{"start":{"line":11,"character":6},"end":{"line":11,"character":6}},"severity":3,"code":"isInBounds","source":"go compiler","message":""}`)
want(t, slogged, `{"range":{"start":{"line":7,"character":6},"end":{"line":7,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 35"}`) want(t, slogged, `{"range":{"start":{"line":7,"character":6},"end":{"line":7,"character":6}},"severity":3,"code":"canInlineFunction","source":"go compiler","message":"cost: 35"}`)
want(t, slogged, `{"range":{"start":{"line":21,"character":21},"end":{"line":21,"character":21}},"severity":3,"code":"cannotInlineCall","source":"go compiler","message":"foo cannot be inlined (escaping closure variable)"}`)
// escape analysis explanation // escape analysis explanation
want(t, slogged, `{"range":{"start":{"line":7,"character":13},"end":{"line":7,"character":13}},"severity":3,"code":"leak","source":"go compiler","message":"parameter z leaks to ~r2 with derefs=0",`+ want(t, slogged, `{"range":{"start":{"line":7,"character":13},"end":{"line":7,"character":13}},"severity":3,"code":"leak","source":"go compiler","message":"parameter z leaks to ~r2 with derefs=0",`+
`"relatedInformation":[`+ `"relatedInformation":[`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: y = z:"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y = \u003cN\u003e (assign-pair)"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y := z (assign-pair)"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~r1 = y:"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: flow: ~r1 = y:"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":4,"character":11},"end":{"line":4,"character":11}}},"message":"inlineLoc"},`+
`{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y.b (dot of pointer)"},`+ `{"location":{"uri":"file://tmpdir/file.go","range":{"start":{"line":9,"character":13},"end":{"line":9,"character":13}}},"message":"escflow: from y.b (dot of pointer)"},`+

View file

@ -35,7 +35,7 @@ func branchelim(f *Func) {
for _, b := range f.Blocks { for _, b := range f.Blocks {
for _, v := range b.Values { for _, v := range b.Values {
switch v.Op { switch v.Op {
case OpLoad, OpAtomicLoad8, OpAtomicLoad32, OpAtomicLoad64, OpAtomicLoadPtr, OpAtomicLoadAcq32: case OpLoad, OpAtomicLoad8, OpAtomicLoad32, OpAtomicLoad64, OpAtomicLoadPtr, OpAtomicLoadAcq32, OpAtomicLoadAcq64:
loadAddr.add(v.Args[0].ID) loadAddr.add(v.Args[0].ID)
case OpMove: case OpMove:
loadAddr.add(v.Args[1].ID) loadAddr.add(v.Args[1].ID)

View file

@ -191,11 +191,6 @@ func flagalloc(f *Func) {
b.FlagsLiveAtEnd = end[b.ID] != nil b.FlagsLiveAtEnd = end[b.ID] != nil
} }
const go115flagallocdeadcode = true
if !go115flagallocdeadcode {
return
}
// Remove any now-dead values. // Remove any now-dead values.
// The number of values to remove is likely small, // The number of values to remove is likely small,
// and removing them requires processing all values in a block, // and removing them requires processing all values in a block,

View file

@ -1052,8 +1052,8 @@
(BICshiftRL x (MOVWconst [c]) [d]) => (BICconst x [int32(uint32(c)>>uint64(d))]) (BICshiftRL x (MOVWconst [c]) [d]) => (BICconst x [int32(uint32(c)>>uint64(d))])
(BICshiftRA x (MOVWconst [c]) [d]) => (BICconst x [c>>uint64(d)]) (BICshiftRA x (MOVWconst [c]) [d]) => (BICconst x [c>>uint64(d)])
(MVNshiftLL (MOVWconst [c]) [d]) => (MOVWconst [^(c<<uint64(d))]) (MVNshiftLL (MOVWconst [c]) [d]) => (MOVWconst [^(c<<uint64(d))])
(MVNshiftRL (MOVWconst [c]) [d]) -> (MOVWconst [^int64(uint32(c)>>uint64(d))]) (MVNshiftRL (MOVWconst [c]) [d]) => (MOVWconst [^int32(uint32(c)>>uint64(d))])
(MVNshiftRA (MOVWconst [c]) [d]) -> (MOVWconst [^int64(int32(c)>>uint64(d))]) (MVNshiftRA (MOVWconst [c]) [d]) => (MOVWconst [int32(c)>>uint64(d)])
(CMPshiftLL x (MOVWconst [c]) [d]) => (CMPconst x [c<<uint64(d)]) (CMPshiftLL x (MOVWconst [c]) [d]) => (CMPconst x [c<<uint64(d)])
(CMPshiftRL x (MOVWconst [c]) [d]) => (CMPconst x [int32(uint32(c)>>uint64(d))]) (CMPshiftRL x (MOVWconst [c]) [d]) => (CMPconst x [int32(uint32(c)>>uint64(d))])
(CMPshiftRA x (MOVWconst [c]) [d]) => (CMPconst x [c>>uint64(d)]) (CMPshiftRA x (MOVWconst [c]) [d]) => (CMPconst x [c>>uint64(d)])
@ -1190,12 +1190,12 @@
(MOVWstoreidx ptr (SRAconst idx [c]) val mem) => (MOVWstoreshiftRA ptr idx [c] val mem) (MOVWstoreidx ptr (SRAconst idx [c]) val mem) => (MOVWstoreshiftRA ptr idx [c] val mem)
(MOVWstoreidx (SRAconst idx [c]) ptr val mem) => (MOVWstoreshiftRA ptr idx [c] val mem) (MOVWstoreidx (SRAconst idx [c]) ptr val mem) => (MOVWstoreshiftRA ptr idx [c] val mem)
(MOVWloadshiftLL ptr (MOVWconst [c]) [d] mem) -> (MOVWload [int64(uint32(c)<<uint64(d))] ptr mem) (MOVWloadshiftLL ptr (MOVWconst [c]) [d] mem) => (MOVWload [int32(uint32(c)<<uint64(d))] ptr mem)
(MOVWloadshiftRL ptr (MOVWconst [c]) [d] mem) -> (MOVWload [int64(uint32(c)>>uint64(d))] ptr mem) (MOVWloadshiftRL ptr (MOVWconst [c]) [d] mem) => (MOVWload [int32(uint32(c)>>uint64(d))] ptr mem)
(MOVWloadshiftRA ptr (MOVWconst [c]) [d] mem) => (MOVWload [c>>uint64(d)] ptr mem) (MOVWloadshiftRA ptr (MOVWconst [c]) [d] mem) => (MOVWload [c>>uint64(d)] ptr mem)
(MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem) -> (MOVWstore [int64(uint32(c)<<uint64(d))] ptr val mem) (MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem) => (MOVWstore [int32(uint32(c)<<uint64(d))] ptr val mem)
(MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem) -> (MOVWstore [int64(uint32(c)>>uint64(d))] ptr val mem) (MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem) => (MOVWstore [int32(uint32(c)>>uint64(d))] ptr val mem)
(MOVWstoreshiftRA ptr (MOVWconst [c]) [d] val mem) => (MOVWstore [c>>uint64(d)] ptr val mem) (MOVWstoreshiftRA ptr (MOVWconst [c]) [d] val mem) => (MOVWstore [c>>uint64(d)] ptr val mem)
// generic simplifications // generic simplifications

View file

@ -967,10 +967,10 @@
// atomic intrinsics // atomic intrinsics
(AtomicLoad(8|32|64|Ptr) ptr mem) => (LoweredAtomicLoad(8|32|64|Ptr) [1] ptr mem) (AtomicLoad(8|32|64|Ptr) ptr mem) => (LoweredAtomicLoad(8|32|64|Ptr) [1] ptr mem)
(AtomicLoadAcq32 ptr mem) => (LoweredAtomicLoad32 [0] ptr mem) (AtomicLoadAcq(32|64) ptr mem) => (LoweredAtomicLoad(32|64) [0] ptr mem)
(AtomicStore(8|32|64) ptr val mem) => (LoweredAtomicStore(8|32|64) [1] ptr val mem) (AtomicStore(8|32|64) ptr val mem) => (LoweredAtomicStore(8|32|64) [1] ptr val mem)
(AtomicStoreRel32 ptr val mem) => (LoweredAtomicStore32 [0] ptr val mem) (AtomicStoreRel(32|64) ptr val mem) => (LoweredAtomicStore(32|64) [0] ptr val mem)
//(AtomicStorePtrNoWB ptr val mem) => (STLR ptr val mem) //(AtomicStorePtrNoWB ptr val mem) => (STLR ptr val mem)
(AtomicExchange(32|64) ...) => (LoweredAtomicExchange(32|64) ...) (AtomicExchange(32|64) ...) => (LoweredAtomicExchange(32|64) ...)

View file

@ -24,10 +24,11 @@ import (
// L = 64 bit int, used when the opcode starts with F // L = 64 bit int, used when the opcode starts with F
const ( const (
riscv64REG_G = 4 riscv64REG_G = 27
riscv64REG_CTXT = 20 riscv64REG_CTXT = 20
riscv64REG_LR = 1 riscv64REG_LR = 1
riscv64REG_SP = 2 riscv64REG_SP = 2
riscv64REG_TP = 4
riscv64REG_TMP = 31 riscv64REG_TMP = 31
riscv64REG_ZERO = 0 riscv64REG_ZERO = 0
) )
@ -78,8 +79,8 @@ func init() {
// Add general purpose registers to gpMask. // Add general purpose registers to gpMask.
switch r { switch r {
// ZERO, and TMP are not in any gp mask. // ZERO, TP and TMP are not in any gp mask.
case riscv64REG_ZERO, riscv64REG_TMP: case riscv64REG_ZERO, riscv64REG_TP, riscv64REG_TMP:
case riscv64REG_G: case riscv64REG_G:
gpgMask |= mask gpgMask |= mask
gpspsbgMask |= mask gpspsbgMask |= mask

View file

@ -1961,6 +1961,31 @@
&& warnRule(fe.Debug_checknil(), v, "removed nil check") && warnRule(fe.Debug_checknil(), v, "removed nil check")
=> (Invalid) => (Invalid)
// for late-expanded calls
(Zero (SelectN [0] call:(StaticLECall _ _)) mem:(SelectN [1] call))
&& isSameCall(call.Aux, "runtime.newobject")
=> mem
(Store (SelectN [0] call:(StaticLECall _ _)) x mem:(SelectN [1] call))
&& isConstZero(x)
&& isSameCall(call.Aux, "runtime.newobject")
=> mem
(Store (OffPtr (SelectN [0] call:(StaticLECall _ _))) x mem:(SelectN [1] call))
&& isConstZero(x)
&& isSameCall(call.Aux, "runtime.newobject")
=> mem
(NilCheck (SelectN [0] call:(StaticLECall _ _)) (SelectN [1] call))
&& isSameCall(call.Aux, "runtime.newobject")
&& warnRule(fe.Debug_checknil(), v, "removed nil check")
=> (Invalid)
(NilCheck (OffPtr (SelectN [0] call:(StaticLECall _ _))) (SelectN [1] call))
&& isSameCall(call.Aux, "runtime.newobject")
&& warnRule(fe.Debug_checknil(), v, "removed nil check")
=> (Invalid)
// Evaluate constant address comparisons. // Evaluate constant address comparisons.
(EqPtr x x) => (ConstBool [true]) (EqPtr x x) => (ConstBool [true])
(NeqPtr x x) => (ConstBool [false]) (NeqPtr x x) => (ConstBool [false])
@ -2017,6 +2042,17 @@
&& clobber(s1, s2, s3) && clobber(s1, s2, s3)
=> (Move {t.Elem()} [int64(sz)] dst src mem) => (Move {t.Elem()} [int64(sz)] dst src mem)
// Inline small or disjoint runtime.memmove calls with constant length.
// See the comment in op Move in genericOps.go for discussion of the type.
(SelectN [0] call:(StaticLECall {sym} dst src (Const(64|32) [sz]) mem))
&& sz >= 0
&& call.Uses == 1 // this will exclude all calls with results
&& isSameCall(sym, "runtime.memmove")
&& dst.Type.IsPtr() // avoids TUINTPTR, see issue 30061
&& isInlinableMemmove(dst, src, int64(sz), config)
&& clobber(call)
=> (Move {dst.Type.Elem()} [int64(sz)] dst src mem)
// De-virtualize interface calls into static calls. // De-virtualize interface calls into static calls.
// Note that (ITab (IMake)) doesn't get // Note that (ITab (IMake)) doesn't get
// rewritten until after the first opt pass, // rewritten until after the first opt pass,
@ -2411,6 +2447,7 @@
(Store {t5} (OffPtr <tt5> [o5] dst) d4 (Store {t5} (OffPtr <tt5> [o5] dst) d4
(Zero {t1} [n] dst mem))))) (Zero {t1} [n] dst mem)))))
// TODO this does not fire before call expansion; is that acceptable?
(StaticCall {sym} x) && needRaceCleanup(sym, v) => x (StaticCall {sym} x) && needRaceCleanup(sym, v) => x
// Collapse moving A -> B -> C into just A -> C. // Collapse moving A -> B -> C into just A -> C.

View file

@ -550,11 +550,13 @@ var genericOps = []opData{
{name: "AtomicLoad64", argLength: 2, typ: "(UInt64,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory. {name: "AtomicLoad64", argLength: 2, typ: "(UInt64,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
{name: "AtomicLoadPtr", argLength: 2, typ: "(BytePtr,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory. {name: "AtomicLoadPtr", argLength: 2, typ: "(BytePtr,Mem)"}, // Load from arg0. arg1=memory. Returns loaded value and new memory.
{name: "AtomicLoadAcq32", argLength: 2, typ: "(UInt32,Mem)"}, // Load from arg0. arg1=memory. Lock acquisition, returns loaded value and new memory. {name: "AtomicLoadAcq32", argLength: 2, typ: "(UInt32,Mem)"}, // Load from arg0. arg1=memory. Lock acquisition, returns loaded value and new memory.
{name: "AtomicLoadAcq64", argLength: 2, typ: "(UInt64,Mem)"}, // Load from arg0. arg1=memory. Lock acquisition, returns loaded value and new memory.
{name: "AtomicStore8", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory. {name: "AtomicStore8", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
{name: "AtomicStore32", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory. {name: "AtomicStore32", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
{name: "AtomicStore64", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory. {name: "AtomicStore64", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
{name: "AtomicStorePtrNoWB", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory. {name: "AtomicStorePtrNoWB", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns memory.
{name: "AtomicStoreRel32", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Lock release, returns memory. {name: "AtomicStoreRel32", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Lock release, returns memory.
{name: "AtomicStoreRel64", argLength: 3, typ: "Mem", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Lock release, returns memory.
{name: "AtomicExchange32", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory. {name: "AtomicExchange32", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
{name: "AtomicExchange64", argLength: 3, typ: "(UInt64,Mem)", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory. {name: "AtomicExchange64", argLength: 3, typ: "(UInt64,Mem)", hasSideEffects: true}, // Store arg1 to *arg0. arg2=memory. Returns old contents of *arg0 and new memory.
{name: "AtomicAdd32", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory. {name: "AtomicAdd32", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.

File diff suppressed because it is too large Load diff

View file

@ -1012,8 +1012,8 @@ func (s *regAllocState) regalloc(f *Func) {
// Copy phi ops into new schedule. // Copy phi ops into new schedule.
b.Values = append(b.Values, phis...) b.Values = append(b.Values, phis...)
// Third pass - pick registers for phis whose inputs // Third pass - pick registers for phis whose input
// were not in a register. // was not in a register in the primary predecessor.
for i, v := range phis { for i, v := range phis {
if !s.values[v.ID].needReg { if !s.values[v.ID].needReg {
continue continue
@ -1022,6 +1022,24 @@ func (s *regAllocState) regalloc(f *Func) {
continue continue
} }
m := s.compatRegs(v.Type) &^ phiUsed &^ s.used m := s.compatRegs(v.Type) &^ phiUsed &^ s.used
// If one of the other inputs of v is in a register, and the register is available,
// select this register, which can save some unnecessary copies.
for i, pe := range b.Preds {
if int32(i) == idx {
continue
}
ri := noRegister
for _, er := range s.endRegs[pe.b.ID] {
if er.v == s.orig[v.Args[i].ID] {
ri = er.r
break
}
}
if ri != noRegister && m>>ri&1 != 0 {
m = regMask(1) << ri
break
}
}
if m != 0 { if m != 0 {
r := pickReg(m) r := pickReg(m)
phiRegs[i] = r phiRegs[i] = r
@ -1118,9 +1136,21 @@ func (s *regAllocState) regalloc(f *Func) {
continue continue
} }
rp, ok := s.f.getHome(v.ID).(*Register) rp, ok := s.f.getHome(v.ID).(*Register)
if !ok {
// If v is not assigned a register, pick a register assigned to one of v's inputs.
// Hopefully v will get assigned that register later.
// If the inputs have allocated register information, add it to desired,
// which may reduce spill or copy operations when the register is available.
for _, a := range v.Args {
rp, ok = s.f.getHome(a.ID).(*Register)
if ok {
break
}
}
if !ok { if !ok {
continue continue
} }
}
desired.add(v.Args[pidx].ID, register(rp.num)) desired.add(v.Args[pidx].ID, register(rp.num))
} }
} }
@ -1552,6 +1582,19 @@ func (s *regAllocState) regalloc(f *Func) {
} }
v := s.orig[vid] v := s.orig[vid]
m := s.compatRegs(v.Type) &^ s.used m := s.compatRegs(v.Type) &^ s.used
// Used desired register if available.
outerloop:
for _, e := range desired.entries {
if e.ID != v.ID {
continue
}
for _, r := range e.regs {
if r != noRegister && m>>r&1 != 0 {
m = regMask(1) << r
break outerloop
}
}
}
if m&^desired.avoid != 0 { if m&^desired.avoid != 0 {
m &^= desired.avoid m &^= desired.avoid
} }
@ -1613,7 +1656,9 @@ func (s *regAllocState) regalloc(f *Func) {
// we'll rematerialize during the merge. // we'll rematerialize during the merge.
continue continue
} }
//fmt.Printf("live-at-end spill for %s at %s\n", s.orig[e.ID], b) if s.f.pass.debug > regDebug {
fmt.Printf("live-at-end spill for %s at %s\n", s.orig[e.ID], b)
}
spill := s.makeSpill(s.orig[e.ID], b) spill := s.makeSpill(s.orig[e.ID], b)
s.spillLive[b.ID] = append(s.spillLive[b.ID], spill.ID) s.spillLive[b.ID] = append(s.spillLive[b.ID], spill.ID)
} }
@ -2484,7 +2529,7 @@ func (s *regAllocState) computeLive() {
for _, b := range f.Blocks { for _, b := range f.Blocks {
fmt.Printf(" %s:", b) fmt.Printf(" %s:", b)
for _, x := range s.live[b.ID] { for _, x := range s.live[b.ID] {
fmt.Printf(" v%d", x.ID) fmt.Printf(" v%d(%d)", x.ID, x.dist)
for _, e := range s.desired[b.ID].entries { for _, e := range s.desired[b.ID].entries {
if e.ID != x.ID { if e.ID != x.ID {
continue continue

View file

@ -395,7 +395,8 @@ func canMergeLoad(target, load *Value) bool {
// isSameCall reports whether sym is the same as the given named symbol // isSameCall reports whether sym is the same as the given named symbol
func isSameCall(sym interface{}, name string) bool { func isSameCall(sym interface{}, name string) bool {
return sym.(*AuxCall).Fn.String() == name fn := sym.(*AuxCall).Fn
return fn != nil && fn.String() == name
} }
// nlz returns the number of leading zeros. // nlz returns the number of leading zeros.

View file

@ -6412,17 +6412,17 @@ func rewriteValueARM_OpARMMOVWloadshiftLL(v *Value) bool {
return true return true
} }
// match: (MOVWloadshiftLL ptr (MOVWconst [c]) [d] mem) // match: (MOVWloadshiftLL ptr (MOVWconst [c]) [d] mem)
// result: (MOVWload [int64(uint32(c)<<uint64(d))] ptr mem) // result: (MOVWload [int32(uint32(c)<<uint64(d))] ptr mem)
for { for {
d := v.AuxInt d := auxIntToInt32(v.AuxInt)
ptr := v_0 ptr := v_0
if v_1.Op != OpARMMOVWconst { if v_1.Op != OpARMMOVWconst {
break break
} }
c := v_1.AuxInt c := auxIntToInt32(v_1.AuxInt)
mem := v_2 mem := v_2
v.reset(OpARMMOVWload) v.reset(OpARMMOVWload)
v.AuxInt = int64(uint32(c) << uint64(d)) v.AuxInt = int32ToAuxInt(int32(uint32(c) << uint64(d)))
v.AddArg2(ptr, mem) v.AddArg2(ptr, mem)
return true return true
} }
@ -6492,17 +6492,17 @@ func rewriteValueARM_OpARMMOVWloadshiftRL(v *Value) bool {
return true return true
} }
// match: (MOVWloadshiftRL ptr (MOVWconst [c]) [d] mem) // match: (MOVWloadshiftRL ptr (MOVWconst [c]) [d] mem)
// result: (MOVWload [int64(uint32(c)>>uint64(d))] ptr mem) // result: (MOVWload [int32(uint32(c)>>uint64(d))] ptr mem)
for { for {
d := v.AuxInt d := auxIntToInt32(v.AuxInt)
ptr := v_0 ptr := v_0
if v_1.Op != OpARMMOVWconst { if v_1.Op != OpARMMOVWconst {
break break
} }
c := v_1.AuxInt c := auxIntToInt32(v_1.AuxInt)
mem := v_2 mem := v_2
v.reset(OpARMMOVWload) v.reset(OpARMMOVWload)
v.AuxInt = int64(uint32(c) >> uint64(d)) v.AuxInt = int32ToAuxInt(int32(uint32(c) >> uint64(d)))
v.AddArg2(ptr, mem) v.AddArg2(ptr, mem)
return true return true
} }
@ -6833,18 +6833,18 @@ func rewriteValueARM_OpARMMOVWstoreshiftLL(v *Value) bool {
v_1 := v.Args[1] v_1 := v.Args[1]
v_0 := v.Args[0] v_0 := v.Args[0]
// match: (MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem) // match: (MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem)
// result: (MOVWstore [int64(uint32(c)<<uint64(d))] ptr val mem) // result: (MOVWstore [int32(uint32(c)<<uint64(d))] ptr val mem)
for { for {
d := v.AuxInt d := auxIntToInt32(v.AuxInt)
ptr := v_0 ptr := v_0
if v_1.Op != OpARMMOVWconst { if v_1.Op != OpARMMOVWconst {
break break
} }
c := v_1.AuxInt c := auxIntToInt32(v_1.AuxInt)
val := v_2 val := v_2
mem := v_3 mem := v_3
v.reset(OpARMMOVWstore) v.reset(OpARMMOVWstore)
v.AuxInt = int64(uint32(c) << uint64(d)) v.AuxInt = int32ToAuxInt(int32(uint32(c) << uint64(d)))
v.AddArg3(ptr, val, mem) v.AddArg3(ptr, val, mem)
return true return true
} }
@ -6879,18 +6879,18 @@ func rewriteValueARM_OpARMMOVWstoreshiftRL(v *Value) bool {
v_1 := v.Args[1] v_1 := v.Args[1]
v_0 := v.Args[0] v_0 := v.Args[0]
// match: (MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem) // match: (MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem)
// result: (MOVWstore [int64(uint32(c)>>uint64(d))] ptr val mem) // result: (MOVWstore [int32(uint32(c)>>uint64(d))] ptr val mem)
for { for {
d := v.AuxInt d := auxIntToInt32(v.AuxInt)
ptr := v_0 ptr := v_0
if v_1.Op != OpARMMOVWconst { if v_1.Op != OpARMMOVWconst {
break break
} }
c := v_1.AuxInt c := auxIntToInt32(v_1.AuxInt)
val := v_2 val := v_2
mem := v_3 mem := v_3
v.reset(OpARMMOVWstore) v.reset(OpARMMOVWstore)
v.AuxInt = int64(uint32(c) >> uint64(d)) v.AuxInt = int32ToAuxInt(int32(uint32(c) >> uint64(d)))
v.AddArg3(ptr, val, mem) v.AddArg3(ptr, val, mem)
return true return true
} }
@ -8105,15 +8105,15 @@ func rewriteValueARM_OpARMMVNshiftLLreg(v *Value) bool {
func rewriteValueARM_OpARMMVNshiftRA(v *Value) bool { func rewriteValueARM_OpARMMVNshiftRA(v *Value) bool {
v_0 := v.Args[0] v_0 := v.Args[0]
// match: (MVNshiftRA (MOVWconst [c]) [d]) // match: (MVNshiftRA (MOVWconst [c]) [d])
// result: (MOVWconst [^int64(int32(c)>>uint64(d))]) // result: (MOVWconst [int32(c)>>uint64(d)])
for { for {
d := v.AuxInt d := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARMMOVWconst { if v_0.Op != OpARMMOVWconst {
break break
} }
c := v_0.AuxInt c := auxIntToInt32(v_0.AuxInt)
v.reset(OpARMMOVWconst) v.reset(OpARMMOVWconst)
v.AuxInt = ^int64(int32(c) >> uint64(d)) v.AuxInt = int32ToAuxInt(int32(c) >> uint64(d))
return true return true
} }
return false return false
@ -8139,15 +8139,15 @@ func rewriteValueARM_OpARMMVNshiftRAreg(v *Value) bool {
func rewriteValueARM_OpARMMVNshiftRL(v *Value) bool { func rewriteValueARM_OpARMMVNshiftRL(v *Value) bool {
v_0 := v.Args[0] v_0 := v.Args[0]
// match: (MVNshiftRL (MOVWconst [c]) [d]) // match: (MVNshiftRL (MOVWconst [c]) [d])
// result: (MOVWconst [^int64(uint32(c)>>uint64(d))]) // result: (MOVWconst [^int32(uint32(c)>>uint64(d))])
for { for {
d := v.AuxInt d := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARMMOVWconst { if v_0.Op != OpARMMOVWconst {
break break
} }
c := v_0.AuxInt c := auxIntToInt32(v_0.AuxInt)
v.reset(OpARMMOVWconst) v.reset(OpARMMOVWconst)
v.AuxInt = ^int64(uint32(c) >> uint64(d)) v.AuxInt = int32ToAuxInt(^int32(uint32(c) >> uint64(d)))
return true return true
} }
return false return false

View file

@ -82,6 +82,8 @@ func rewriteValuePPC64(v *Value) bool {
return rewriteValuePPC64_OpAtomicLoad8(v) return rewriteValuePPC64_OpAtomicLoad8(v)
case OpAtomicLoadAcq32: case OpAtomicLoadAcq32:
return rewriteValuePPC64_OpAtomicLoadAcq32(v) return rewriteValuePPC64_OpAtomicLoadAcq32(v)
case OpAtomicLoadAcq64:
return rewriteValuePPC64_OpAtomicLoadAcq64(v)
case OpAtomicLoadPtr: case OpAtomicLoadPtr:
return rewriteValuePPC64_OpAtomicLoadPtr(v) return rewriteValuePPC64_OpAtomicLoadPtr(v)
case OpAtomicOr8: case OpAtomicOr8:
@ -95,6 +97,8 @@ func rewriteValuePPC64(v *Value) bool {
return rewriteValuePPC64_OpAtomicStore8(v) return rewriteValuePPC64_OpAtomicStore8(v)
case OpAtomicStoreRel32: case OpAtomicStoreRel32:
return rewriteValuePPC64_OpAtomicStoreRel32(v) return rewriteValuePPC64_OpAtomicStoreRel32(v)
case OpAtomicStoreRel64:
return rewriteValuePPC64_OpAtomicStoreRel64(v)
case OpAvg64u: case OpAvg64u:
return rewriteValuePPC64_OpAvg64u(v) return rewriteValuePPC64_OpAvg64u(v)
case OpBitLen32: case OpBitLen32:
@ -930,6 +934,20 @@ func rewriteValuePPC64_OpAtomicLoadAcq32(v *Value) bool {
return true return true
} }
} }
func rewriteValuePPC64_OpAtomicLoadAcq64(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (AtomicLoadAcq64 ptr mem)
// result: (LoweredAtomicLoad64 [0] ptr mem)
for {
ptr := v_0
mem := v_1
v.reset(OpPPC64LoweredAtomicLoad64)
v.AuxInt = int64ToAuxInt(0)
v.AddArg2(ptr, mem)
return true
}
}
func rewriteValuePPC64_OpAtomicLoadPtr(v *Value) bool { func rewriteValuePPC64_OpAtomicLoadPtr(v *Value) bool {
v_1 := v.Args[1] v_1 := v.Args[1]
v_0 := v.Args[0] v_0 := v.Args[0]
@ -1008,6 +1026,22 @@ func rewriteValuePPC64_OpAtomicStoreRel32(v *Value) bool {
return true return true
} }
} }
func rewriteValuePPC64_OpAtomicStoreRel64(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (AtomicStoreRel64 ptr val mem)
// result: (LoweredAtomicStore64 [0] ptr val mem)
for {
ptr := v_0
val := v_1
mem := v_2
v.reset(OpPPC64LoweredAtomicStore64)
v.AuxInt = int64ToAuxInt(0)
v.AddArg3(ptr, val, mem)
return true
}
}
func rewriteValuePPC64_OpAvg64u(v *Value) bool { func rewriteValuePPC64_OpAvg64u(v *Value) bool {
v_1 := v.Args[1] v_1 := v.Args[1]
v_0 := v.Args[0] v_0 := v.Args[0]

View file

@ -368,6 +368,8 @@ func rewriteValuegeneric(v *Value) bool {
return rewriteValuegeneric_OpSelect0(v) return rewriteValuegeneric_OpSelect0(v)
case OpSelect1: case OpSelect1:
return rewriteValuegeneric_OpSelect1(v) return rewriteValuegeneric_OpSelect1(v)
case OpSelectN:
return rewriteValuegeneric_OpSelectN(v)
case OpSignExt16to32: case OpSignExt16to32:
return rewriteValuegeneric_OpSignExt16to32(v) return rewriteValuegeneric_OpSignExt16to32(v)
case OpSignExt16to64: case OpSignExt16to64:
@ -16124,6 +16126,38 @@ func rewriteValuegeneric_OpNilCheck(v *Value) bool {
v.reset(OpInvalid) v.reset(OpInvalid)
return true return true
} }
// match: (NilCheck (SelectN [0] call:(StaticLECall _ _)) (SelectN [1] call))
// cond: isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")
// result: (Invalid)
for {
if v_0.Op != OpSelectN || auxIntToInt64(v_0.AuxInt) != 0 {
break
}
call := v_0.Args[0]
if call.Op != OpStaticLECall || len(call.Args) != 2 || v_1.Op != OpSelectN || auxIntToInt64(v_1.AuxInt) != 1 || call != v_1.Args[0] || !(isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")) {
break
}
v.reset(OpInvalid)
return true
}
// match: (NilCheck (OffPtr (SelectN [0] call:(StaticLECall _ _))) (SelectN [1] call))
// cond: isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")
// result: (Invalid)
for {
if v_0.Op != OpOffPtr {
break
}
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpSelectN || auxIntToInt64(v_0_0.AuxInt) != 0 {
break
}
call := v_0_0.Args[0]
if call.Op != OpStaticLECall || len(call.Args) != 2 || v_1.Op != OpSelectN || auxIntToInt64(v_1.AuxInt) != 1 || call != v_1.Args[0] || !(isSameCall(call.Aux, "runtime.newobject") && warnRule(fe.Debug_checknil(), v, "removed nil check")) {
break
}
v.reset(OpInvalid)
return true
}
return false return false
} }
func rewriteValuegeneric_OpNot(v *Value) bool { func rewriteValuegeneric_OpNot(v *Value) bool {
@ -20669,6 +20703,70 @@ func rewriteValuegeneric_OpSelect1(v *Value) bool {
} }
return false return false
} }
func rewriteValuegeneric_OpSelectN(v *Value) bool {
v_0 := v.Args[0]
b := v.Block
config := b.Func.Config
// match: (SelectN [0] call:(StaticLECall {sym} dst src (Const64 [sz]) mem))
// cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)
// result: (Move {dst.Type.Elem()} [int64(sz)] dst src mem)
for {
if auxIntToInt64(v.AuxInt) != 0 {
break
}
call := v_0
if call.Op != OpStaticLECall || len(call.Args) != 4 {
break
}
sym := auxToCall(call.Aux)
mem := call.Args[3]
dst := call.Args[0]
src := call.Args[1]
call_2 := call.Args[2]
if call_2.Op != OpConst64 {
break
}
sz := auxIntToInt64(call_2.AuxInt)
if !(sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)) {
break
}
v.reset(OpMove)
v.AuxInt = int64ToAuxInt(int64(sz))
v.Aux = typeToAux(dst.Type.Elem())
v.AddArg3(dst, src, mem)
return true
}
// match: (SelectN [0] call:(StaticLECall {sym} dst src (Const32 [sz]) mem))
// cond: sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)
// result: (Move {dst.Type.Elem()} [int64(sz)] dst src mem)
for {
if auxIntToInt64(v.AuxInt) != 0 {
break
}
call := v_0
if call.Op != OpStaticLECall || len(call.Args) != 4 {
break
}
sym := auxToCall(call.Aux)
mem := call.Args[3]
dst := call.Args[0]
src := call.Args[1]
call_2 := call.Args[2]
if call_2.Op != OpConst32 {
break
}
sz := auxIntToInt32(call_2.AuxInt)
if !(sz >= 0 && call.Uses == 1 && isSameCall(sym, "runtime.memmove") && dst.Type.IsPtr() && isInlinableMemmove(dst, src, int64(sz), config) && clobber(call)) {
break
}
v.reset(OpMove)
v.AuxInt = int64ToAuxInt(int64(sz))
v.Aux = typeToAux(dst.Type.Elem())
v.AddArg3(dst, src, mem)
return true
}
return false
}
func rewriteValuegeneric_OpSignExt16to32(v *Value) bool { func rewriteValuegeneric_OpSignExt16to32(v *Value) bool {
v_0 := v.Args[0] v_0 := v.Args[0]
// match: (SignExt16to32 (Const16 [c])) // match: (SignExt16to32 (Const16 [c]))
@ -21714,6 +21812,48 @@ func rewriteValuegeneric_OpStore(v *Value) bool {
v.copyOf(mem) v.copyOf(mem)
return true return true
} }
// match: (Store (SelectN [0] call:(StaticLECall _ _)) x mem:(SelectN [1] call))
// cond: isConstZero(x) && isSameCall(call.Aux, "runtime.newobject")
// result: mem
for {
if v_0.Op != OpSelectN || auxIntToInt64(v_0.AuxInt) != 0 {
break
}
call := v_0.Args[0]
if call.Op != OpStaticLECall || len(call.Args) != 2 {
break
}
x := v_1
mem := v_2
if mem.Op != OpSelectN || auxIntToInt64(mem.AuxInt) != 1 || call != mem.Args[0] || !(isConstZero(x) && isSameCall(call.Aux, "runtime.newobject")) {
break
}
v.copyOf(mem)
return true
}
// match: (Store (OffPtr (SelectN [0] call:(StaticLECall _ _))) x mem:(SelectN [1] call))
// cond: isConstZero(x) && isSameCall(call.Aux, "runtime.newobject")
// result: mem
for {
if v_0.Op != OpOffPtr {
break
}
v_0_0 := v_0.Args[0]
if v_0_0.Op != OpSelectN || auxIntToInt64(v_0_0.AuxInt) != 0 {
break
}
call := v_0_0.Args[0]
if call.Op != OpStaticLECall || len(call.Args) != 2 {
break
}
x := v_1
mem := v_2
if mem.Op != OpSelectN || auxIntToInt64(mem.AuxInt) != 1 || call != mem.Args[0] || !(isConstZero(x) && isSameCall(call.Aux, "runtime.newobject")) {
break
}
v.copyOf(mem)
return true
}
// match: (Store {t1} op1:(OffPtr [o1] p1) d1 m2:(Store {t2} op2:(OffPtr [0] p2) d2 m3:(Move [n] p3 _ mem))) // match: (Store {t1} op1:(OffPtr [o1] p1) d1 m2:(Store {t2} op2:(OffPtr [0] p2) d2 m3:(Move [n] p3 _ mem)))
// cond: m2.Uses == 1 && m3.Uses == 1 && o1 == t2.Size() && n == t2.Size() + t1.Size() && isSamePtr(p1, p2) && isSamePtr(p2, p3) && clobber(m2, m3) // cond: m2.Uses == 1 && m3.Uses == 1 && o1 == t2.Size() && n == t2.Size() + t1.Size() && isSamePtr(p1, p2) && isSamePtr(p2, p3) && clobber(m2, m3)
// result: (Store {t1} op1 d1 (Store {t2} op2 d2 mem)) // result: (Store {t1} op1 d1 (Store {t2} op2 d2 mem))
@ -24411,6 +24551,24 @@ func rewriteValuegeneric_OpZero(v *Value) bool {
v.copyOf(mem) v.copyOf(mem)
return true return true
} }
// match: (Zero (SelectN [0] call:(StaticLECall _ _)) mem:(SelectN [1] call))
// cond: isSameCall(call.Aux, "runtime.newobject")
// result: mem
for {
if v_0.Op != OpSelectN || auxIntToInt64(v_0.AuxInt) != 0 {
break
}
call := v_0.Args[0]
if call.Op != OpStaticLECall || len(call.Args) != 2 {
break
}
mem := v_1
if mem.Op != OpSelectN || auxIntToInt64(mem.AuxInt) != 1 || call != mem.Args[0] || !(isSameCall(call.Aux, "runtime.newobject")) {
break
}
v.copyOf(mem)
return true
}
// match: (Zero {t1} [n] p1 store:(Store {t2} (OffPtr [o2] p2) _ mem)) // match: (Zero {t1} [n] p1 store:(Store {t2} (OffPtr [o2] p2) _ mem))
// cond: isSamePtr(p1, p2) && store.Uses == 1 && n >= o2 + t2.Size() && clobber(store) // cond: isSamePtr(p1, p2) && store.Uses == 1 && n >= o2 + t2.Size() && clobber(store)
// result: (Zero {t1} [n] p1 mem) // result: (Zero {t1} [n] p1 mem)

View file

@ -261,11 +261,6 @@ func shortcircuitBlock(b *Block) bool {
// and the CFG modifications must not proceed. // and the CFG modifications must not proceed.
// The returned function assumes that shortcircuitBlock has completed its CFG modifications. // The returned function assumes that shortcircuitBlock has completed its CFG modifications.
func shortcircuitPhiPlan(b *Block, ctl *Value, cidx int, ti int64) func(*Value, int) { func shortcircuitPhiPlan(b *Block, ctl *Value, cidx int, ti int64) func(*Value, int) {
const go115shortcircuitPhis = true
if !go115shortcircuitPhis {
return nil
}
// t is the "taken" branch: the successor we always go to when coming in from p. // t is the "taken" branch: the successor we always go to when coming in from p.
t := b.Succs[ti].b t := b.Succs[ti].b
// u is the "untaken" branch: the successor we never go to when coming in from p. // u is the "untaken" branch: the successor we never go to when coming in from p.

View file

@ -188,6 +188,8 @@ func TestStdFixed(t *testing.T) {
"issue20780.go", // go/types does not have constraints on stack size "issue20780.go", // go/types does not have constraints on stack size
"issue31747.go", // go/types does not have constraints on language level (-lang=go1.12) (see #31793) "issue31747.go", // go/types does not have constraints on language level (-lang=go1.12) (see #31793)
"issue34329.go", // go/types does not have constraints on language level (-lang=go1.13) (see #31793) "issue34329.go", // go/types does not have constraints on language level (-lang=go1.13) (see #31793)
"issue42058a.go", // go/types does not have constraints on channel element size
"issue42058b.go", // go/types does not have constraints on channel element size
"bug251.go", // issue #34333 which was exposed with fix for #34151 "bug251.go", // issue #34333 which was exposed with fix for #34151
) )
} }

40
src/cmd/dist/build.go vendored
View file

@ -832,6 +832,21 @@ func runInstall(pkg string, ch chan struct{}) {
asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64) asmArgs = append(asmArgs, "-D", "GOMIPS64_"+gomips64)
} }
goasmh := pathf("%s/go_asm.h", workdir) goasmh := pathf("%s/go_asm.h", workdir)
if IsRuntimePackagePath(pkg) {
asmArgs = append(asmArgs, "-compiling-runtime")
if os.Getenv("GOEXPERIMENT") == "regabi" {
// In order to make it easier to port runtime assembly
// to the register ABI, we introduce a macro
// indicating the experiment is enabled.
//
// Note: a similar change also appears in
// cmd/go/internal/work/gc.go.
//
// TODO(austin): Remove this once we commit to the
// register ABI (#40724).
asmArgs = append(asmArgs, "-D=GOEXPERIMENT_REGABI=1")
}
}
// Collect symabis from assembly code. // Collect symabis from assembly code.
var symabis string var symabis string
@ -1462,8 +1477,8 @@ func wrapperPathFor(goos, goarch string) string {
if gohostos != "android" { if gohostos != "android" {
return pathf("%s/misc/android/go_android_exec.go", goroot) return pathf("%s/misc/android/go_android_exec.go", goroot)
} }
case (goos == "darwin" || goos == "ios") && goarch == "arm64": case goos == "ios":
if gohostos != "darwin" || gohostarch != "arm64" { if gohostos != "ios" {
return pathf("%s/misc/ios/go_ios_exec.go", goroot) return pathf("%s/misc/ios/go_ios_exec.go", goroot)
} }
} }
@ -1542,6 +1557,7 @@ var cgoEnabled = map[string]bool{
"android/arm": true, "android/arm": true,
"android/arm64": true, "android/arm64": true,
"ios/arm64": true, "ios/arm64": true,
"ios/amd64": true,
"js/wasm": false, "js/wasm": false,
"netbsd/386": true, "netbsd/386": true,
"netbsd/amd64": true, "netbsd/amd64": true,
@ -1733,3 +1749,23 @@ func cmdlist() {
fatalf("write failed: %v", err) fatalf("write failed: %v", err)
} }
} }
// IsRuntimePackagePath examines 'pkgpath' and returns TRUE if it
// belongs to the collection of "runtime-related" packages, including
// "runtime" itself, "reflect", "syscall", and the
// "runtime/internal/*" packages. See also the function of the same
// name in cmd/internal/objabi/path.go.
func IsRuntimePackagePath(pkgpath string) bool {
rval := false
switch pkgpath {
case "runtime":
rval = true
case "reflect":
rval = true
case "syscall":
rval = true
default:
rval = strings.HasPrefix(pkgpath, "runtime/internal")
}
return rval
}

View file

@ -133,6 +133,10 @@ func main() {
if strings.Contains(run("", CheckExit, "uname", "-v"), "RELEASE_ARM64_") { if strings.Contains(run("", CheckExit, "uname", "-v"), "RELEASE_ARM64_") {
gohostarch = "arm64" gohostarch = "arm64"
} }
case gohostos == "openbsd":
if strings.Contains(run("", CheckExit, "uname", "-p"), "mips64") {
gohostarch = "mips64"
}
default: default:
fatalf("unknown architecture: %s", out) fatalf("unknown architecture: %s", out)
} }

24
src/cmd/dist/test.go vendored
View file

@ -921,7 +921,7 @@ func (t *tester) extLink() bool {
"darwin-amd64", "darwin-arm64", "darwin-amd64", "darwin-arm64",
"dragonfly-amd64", "dragonfly-amd64",
"freebsd-386", "freebsd-amd64", "freebsd-arm", "freebsd-386", "freebsd-amd64", "freebsd-arm",
"linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-s390x", "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-riscv64", "linux-s390x",
"netbsd-386", "netbsd-amd64", "netbsd-386", "netbsd-amd64",
"openbsd-386", "openbsd-amd64", "openbsd-386", "openbsd-amd64",
"windows-386", "windows-amd64": "windows-386", "windows-amd64":
@ -946,9 +946,6 @@ func (t *tester) internalLink() bool {
if goos == "ios" { if goos == "ios" {
return false return false
} }
if goos == "darwin" && goarch == "arm64" {
return false
}
// Internally linking cgo is incomplete on some architectures. // Internally linking cgo is incomplete on some architectures.
// https://golang.org/issue/10373 // https://golang.org/issue/10373
// https://golang.org/issue/14449 // https://golang.org/issue/14449
@ -964,10 +961,10 @@ func (t *tester) internalLink() bool {
func (t *tester) internalLinkPIE() bool { func (t *tester) internalLinkPIE() bool {
switch goos + "-" + goarch { switch goos + "-" + goarch {
case "linux-amd64", "linux-arm64", case "darwin-amd64", "darwin-arm64",
"android-arm64": "linux-amd64", "linux-arm64",
return true "android-arm64",
case "windows-amd64", "windows-386", "windows-arm": "windows-amd64", "windows-386", "windows-arm":
return true return true
} }
return false return false
@ -1088,7 +1085,7 @@ func (t *tester) cgoTest(dt *distTest) error {
pair := gohostos + "-" + goarch pair := gohostos + "-" + goarch
switch pair { switch pair {
case "darwin-amd64", case "darwin-amd64", "darwin-arm64",
"openbsd-386", "openbsd-amd64", "openbsd-386", "openbsd-amd64",
"windows-386", "windows-amd64": "windows-386", "windows-amd64":
// test linkmode=external, but __thread not supported, so skip testtls. // test linkmode=external, but __thread not supported, so skip testtls.
@ -1100,6 +1097,13 @@ func (t *tester) cgoTest(dt *distTest) error {
cmd = t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s") cmd = t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s")
if t.supportedBuildmode("pie") {
t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie")
if t.internalLink() && t.internalLinkPIE() {
t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie")
}
}
case "aix-ppc64", case "aix-ppc64",
"android-arm", "android-arm64", "android-arm", "android-arm64",
"dragonfly-amd64", "dragonfly-amd64",
@ -1151,7 +1155,7 @@ func (t *tester) cgoTest(dt *distTest) error {
if t.supportedBuildmode("pie") { if t.supportedBuildmode("pie") {
t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie") t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie")
if t.internalLink() && t.internalLinkPIE() { if t.internalLink() && t.internalLinkPIE() {
t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal") t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie")
} }
t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-buildmode=pie") t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-buildmode=pie")
t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-buildmode=pie") t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-buildmode=pie")

View file

@ -16,8 +16,8 @@ import (
"go/printer" "go/printer"
"go/token" "go/token"
"io" "io"
"io/fs"
"log" "log"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"unicode" "unicode"
@ -129,11 +129,10 @@ func (pkg *Package) Fatalf(format string, args ...interface{}) {
// parsePackage turns the build package we found into a parsed package // parsePackage turns the build package we found into a parsed package
// we can then use to generate documentation. // we can then use to generate documentation.
func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Package { func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Package {
fs := token.NewFileSet()
// include tells parser.ParseDir which files to include. // include tells parser.ParseDir which files to include.
// That means the file must be in the build package's GoFiles or CgoFiles // That means the file must be in the build package's GoFiles or CgoFiles
// list only (no tag-ignored files, tests, swig or other non-Go files). // list only (no tag-ignored files, tests, swig or other non-Go files).
include := func(info os.FileInfo) bool { include := func(info fs.FileInfo) bool {
for _, name := range pkg.GoFiles { for _, name := range pkg.GoFiles {
if name == info.Name() { if name == info.Name() {
return true return true
@ -146,7 +145,8 @@ func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Packag
} }
return false return false
} }
pkgs, err := parser.ParseDir(fs, pkg.Dir, include, parser.ParseComments) fset := token.NewFileSet()
pkgs, err := parser.ParseDir(fset, pkg.Dir, include, parser.ParseComments)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
@ -203,7 +203,7 @@ func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Packag
typedValue: typedValue, typedValue: typedValue,
constructor: constructor, constructor: constructor,
build: pkg, build: pkg,
fs: fs, fs: fset,
} }
p.buf.pkg = p p.buf.pkg = p
return p return p

View file

@ -13,6 +13,8 @@ import (
"go/parser" "go/parser"
"go/scanner" "go/scanner"
"go/token" "go/token"
"io"
"io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -127,7 +129,7 @@ func processFile(filename string, useStdin bool) error {
defer f.Close() defer f.Close()
} }
src, err := ioutil.ReadAll(f) src, err := io.ReadAll(f)
if err != nil { if err != nil {
return err return err
} }
@ -235,7 +237,7 @@ func walkDir(path string) {
filepath.Walk(path, visitFile) filepath.Walk(path, visitFile)
} }
func visitFile(path string, f os.FileInfo, err error) error { func visitFile(path string, f fs.FileInfo, err error) error {
if err == nil && isGoFile(f) { if err == nil && isGoFile(f) {
err = processFile(path, false) err = processFile(path, false)
} }
@ -245,7 +247,7 @@ func visitFile(path string, f os.FileInfo, err error) error {
return nil return nil
} }
func isGoFile(f os.FileInfo) bool { func isGoFile(f fs.FileInfo) bool {
// ignore non-Go files // ignore non-Go files
name := f.Name() name := f.Name()
return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")

View file

@ -5,9 +5,9 @@ go 1.16
require ( require (
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99 github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
golang.org/x/arch v0.0.0-20200826200359-b19915210f00 golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449 golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d // indirect golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d // indirect
golang.org/x/tools v0.0.0-20200918232735-d647fc253266 golang.org/x/tools v0.0.0-20201014170642-d1624618ad65
) )

View file

@ -7,8 +7,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 h1:S1+yTUaFPXuDZnPDbO+TrDFIjPzQraYH8/CwSlu9Fac= github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 h1:S1+yTUaFPXuDZnPDbO+TrDFIjPzQraYH8/CwSlu9Fac=
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/arch v0.0.0-20200826200359-b19915210f00 h1:cfd5G6xu8iZTFmjBYVemyBmE/sTf0A3vpE3BmoOuLCI= golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff h1:XmKBi9R6duxOB3lfc72wyrwiOY7X2Jl1wuI+RFOyMDE=
golang.org/x/arch v0.0.0-20200826200359-b19915210f00/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4= golang.org/x/arch v0.0.0-20201008161808-52c3e6f60cff/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -30,8 +30,8 @@ golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d h1:L/IKR6COd7ubZrs2oTnTi73Ih
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200918232735-d647fc253266 h1:k7tVuG0g1JwmD3Jh8oAl1vQ1C3jb4Hi/dUl1wWDBJpQ= golang.org/x/tools v0.0.0-20201014170642-d1624618ad65 h1:q80OtYaeeySe8Kqg0vjXehHwj5fUTqe3xOvnbi5w3Gg=
golang.org/x/tools v0.0.0-20200918232735-d647fc253266/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20201014170642-d1624618ad65/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=

View file

@ -796,6 +796,7 @@
// BinaryOnly bool // binary-only package (no longer supported) // BinaryOnly bool // binary-only package (no longer supported)
// ForTest string // package is only for use in named test // ForTest string // package is only for use in named test
// Export string // file containing export data (when using -export) // Export string // file containing export data (when using -export)
// BuildID string // build ID of the export data (when using -export)
// Module *Module // info about package's containing module, if any (can be nil) // Module *Module // info about package's containing module, if any (can be nil)
// Match []string // command-line patterns matching this package // Match []string // command-line patterns matching this package
// DepOnly bool // package is only a dependency, not explicitly listed // DepOnly bool // package is only a dependency, not explicitly listed
@ -805,6 +806,7 @@
// CgoFiles []string // .go source files that import "C" // CgoFiles []string // .go source files that import "C"
// CompiledGoFiles []string // .go files presented to compiler (when using -compiled) // CompiledGoFiles []string // .go files presented to compiler (when using -compiled)
// IgnoredGoFiles []string // .go source files ignored due to build constraints // IgnoredGoFiles []string // .go source files ignored due to build constraints
// IgnoredOtherFiles []string // non-.go source files ignored due to build constraints
// CFiles []string // .c source files // CFiles []string // .c source files
// CXXFiles []string // .cc, .cxx and .cpp source files // CXXFiles []string // .cc, .cxx and .cpp source files
// MFiles []string // .m source files // MFiles []string // .m source files

View file

@ -15,6 +15,7 @@ import (
"internal/race" "internal/race"
"internal/testenv" "internal/testenv"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
@ -813,7 +814,7 @@ func (tg *testgoData) cleanup() {
func removeAll(dir string) error { func removeAll(dir string) error {
// module cache has 0444 directories; // module cache has 0444 directories;
// make them writable in order to remove content. // make them writable in order to remove content.
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error {
// chmod not only directories, but also things that we couldn't even stat // chmod not only directories, but also things that we couldn't even stat
// due to permission errors: they may also be unreadable directories. // due to permission errors: they may also be unreadable directories.
if err != nil || info.IsDir() { if err != nil || info.IsDir() {
@ -860,7 +861,7 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) {
srcdir := filepath.Join(testGOROOT, copydir) srcdir := filepath.Join(testGOROOT, copydir)
tg.tempDir(filepath.Join("goroot", copydir)) tg.tempDir(filepath.Join("goroot", copydir))
err := filepath.Walk(srcdir, err := filepath.Walk(srcdir,
func(path string, info os.FileInfo, err error) error { func(path string, info fs.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
@ -1236,6 +1237,18 @@ func TestGoListExport(t *testing.T) {
if _, err := os.Stat(file); err != nil { if _, err := os.Stat(file); err != nil {
t.Fatalf("cannot find .Export result %s: %v", file, err) t.Fatalf("cannot find .Export result %s: %v", file, err)
} }
tg.run("list", "-export", "-f", "{{.BuildID}}", "strings")
buildID := strings.TrimSpace(tg.stdout.String())
if buildID == "" {
t.Fatalf(".BuildID with -export was empty")
}
tg.run("tool", "buildid", file)
toolBuildID := strings.TrimSpace(tg.stdout.String())
if buildID != toolBuildID {
t.Fatalf(".BuildID with -export %q disagrees with 'go tool buildid' %q", buildID, toolBuildID)
}
} }
// Issue 4096. Validate the output of unsuccessful go install foo/quxx. // Issue 4096. Validate the output of unsuccessful go install foo/quxx.
@ -2018,7 +2031,7 @@ func main() {
tg.run("build", "-o", exe, "p") tg.run("build", "-o", exe, "p")
} }
func copyFile(src, dst string, perm os.FileMode) error { func copyFile(src, dst string, perm fs.FileMode) error {
sf, err := os.Open(src) sf, err := os.Open(src)
if err != nil { if err != nil {
return err return err

View file

@ -92,7 +92,11 @@ func SetFromGOFLAGS(flags *flag.FlagSet) {
} }
for _, goflag := range goflags { for _, goflag := range goflags {
name, value, hasValue := goflag, "", false name, value, hasValue := goflag, "", false
if i := strings.Index(goflag, "="); i >= 0 { // Ignore invalid flags like '=' or '=value'.
// If it is not reported in InitGOFlags it means we don't want to report it.
if i := strings.Index(goflag, "="); i == 0 {
continue
} else if i > 0 {
name, value, hasValue = goflag[:i], goflag[i+1:], true name, value, hasValue = goflag[:i], goflag[i+1:], true
} }
if strings.HasPrefix(name, "--") { if strings.HasPrefix(name, "--") {

View file

@ -12,6 +12,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/fs"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
@ -54,7 +55,7 @@ func Open(dir string) (*Cache, error) {
return nil, err return nil, err
} }
if !info.IsDir() { if !info.IsDir() {
return nil, &os.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")} return nil, &fs.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")}
} }
for i := 0; i < 256; i++ { for i := 0; i < 256; i++ {
name := filepath.Join(dir, fmt.Sprintf("%02x", i)) name := filepath.Join(dir, fmt.Sprintf("%02x", i))

Some files were not shown because too many files have changed in this diff Show more