mirror of https://github.com/golang/go.git
[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch
Change-Id: Idd150294aaeced0176b53d6b95852f5d21ff4fdc
This commit is contained in:
commit
0393ed8201
2
LICENSE
2
LICENSE
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
|
|
|
|||
|
|
@ -0,0 +1,276 @@
|
|||
pkg bytes, func ContainsAny([]uint8, string) bool
|
||||
pkg bytes, func ContainsRune([]uint8, int32) bool
|
||||
pkg bytes, method (*Reader) Reset([]uint8)
|
||||
pkg compress/flate, const HuffmanOnly = -2
|
||||
pkg compress/flate, const HuffmanOnly ideal-int
|
||||
pkg context, func Background() Context
|
||||
pkg context, func TODO() Context
|
||||
pkg context, func WithCancel(Context) (Context, CancelFunc)
|
||||
pkg context, func WithDeadline(Context, time.Time) (Context, CancelFunc)
|
||||
pkg context, func WithTimeout(Context, time.Duration) (Context, CancelFunc)
|
||||
pkg context, func WithValue(Context, interface{}, interface{}) Context
|
||||
pkg context, type CancelFunc func()
|
||||
pkg context, type Context interface { Deadline, Done, Err, Value }
|
||||
pkg context, type Context interface, Deadline() (time.Time, bool)
|
||||
pkg context, type Context interface, Done() <-chan struct
|
||||
pkg context, type Context interface, Err() error
|
||||
pkg context, type Context interface, Value(interface{}) interface{}
|
||||
pkg context, var Canceled error
|
||||
pkg context, var DeadlineExceeded error
|
||||
pkg crypto/tls, const RenegotiateFreelyAsClient = 2
|
||||
pkg crypto/tls, const RenegotiateFreelyAsClient RenegotiationSupport
|
||||
pkg crypto/tls, const RenegotiateNever = 0
|
||||
pkg crypto/tls, const RenegotiateNever RenegotiationSupport
|
||||
pkg crypto/tls, const RenegotiateOnceAsClient = 1
|
||||
pkg crypto/tls, const RenegotiateOnceAsClient RenegotiationSupport
|
||||
pkg crypto/tls, type Config struct, DynamicRecordSizingDisabled bool
|
||||
pkg crypto/tls, type Config struct, Renegotiation RenegotiationSupport
|
||||
pkg crypto/tls, type RenegotiationSupport int
|
||||
pkg crypto/x509, func SystemCertPool() (*CertPool, error)
|
||||
pkg crypto/x509, type SystemRootsError struct, Err error
|
||||
pkg debug/dwarf, method (*Data) Ranges(*Entry) ([][2]uint64, error)
|
||||
pkg debug/dwarf, method (*Reader) SeekPC(uint64) (*Entry, error)
|
||||
pkg debug/elf, const R_390_12 = 2
|
||||
pkg debug/elf, const R_390_12 R_390
|
||||
pkg debug/elf, const R_390_16 = 3
|
||||
pkg debug/elf, const R_390_16 R_390
|
||||
pkg debug/elf, const R_390_20 = 57
|
||||
pkg debug/elf, const R_390_20 R_390
|
||||
pkg debug/elf, const R_390_32 = 4
|
||||
pkg debug/elf, const R_390_32 R_390
|
||||
pkg debug/elf, const R_390_64 = 22
|
||||
pkg debug/elf, const R_390_64 R_390
|
||||
pkg debug/elf, const R_390_8 = 1
|
||||
pkg debug/elf, const R_390_8 R_390
|
||||
pkg debug/elf, const R_390_COPY = 9
|
||||
pkg debug/elf, const R_390_COPY R_390
|
||||
pkg debug/elf, const R_390_GLOB_DAT = 10
|
||||
pkg debug/elf, const R_390_GLOB_DAT R_390
|
||||
pkg debug/elf, const R_390_GOT12 = 6
|
||||
pkg debug/elf, const R_390_GOT12 R_390
|
||||
pkg debug/elf, const R_390_GOT16 = 15
|
||||
pkg debug/elf, const R_390_GOT16 R_390
|
||||
pkg debug/elf, const R_390_GOT20 = 58
|
||||
pkg debug/elf, const R_390_GOT20 R_390
|
||||
pkg debug/elf, const R_390_GOT32 = 7
|
||||
pkg debug/elf, const R_390_GOT32 R_390
|
||||
pkg debug/elf, const R_390_GOT64 = 24
|
||||
pkg debug/elf, const R_390_GOT64 R_390
|
||||
pkg debug/elf, const R_390_GOTENT = 26
|
||||
pkg debug/elf, const R_390_GOTENT R_390
|
||||
pkg debug/elf, const R_390_GOTOFF = 13
|
||||
pkg debug/elf, const R_390_GOTOFF R_390
|
||||
pkg debug/elf, const R_390_GOTOFF16 = 27
|
||||
pkg debug/elf, const R_390_GOTOFF16 R_390
|
||||
pkg debug/elf, const R_390_GOTOFF64 = 28
|
||||
pkg debug/elf, const R_390_GOTOFF64 R_390
|
||||
pkg debug/elf, const R_390_GOTPC = 14
|
||||
pkg debug/elf, const R_390_GOTPC R_390
|
||||
pkg debug/elf, const R_390_GOTPCDBL = 21
|
||||
pkg debug/elf, const R_390_GOTPCDBL R_390
|
||||
pkg debug/elf, const R_390_GOTPLT12 = 29
|
||||
pkg debug/elf, const R_390_GOTPLT12 R_390
|
||||
pkg debug/elf, const R_390_GOTPLT16 = 30
|
||||
pkg debug/elf, const R_390_GOTPLT16 R_390
|
||||
pkg debug/elf, const R_390_GOTPLT20 = 59
|
||||
pkg debug/elf, const R_390_GOTPLT20 R_390
|
||||
pkg debug/elf, const R_390_GOTPLT32 = 31
|
||||
pkg debug/elf, const R_390_GOTPLT32 R_390
|
||||
pkg debug/elf, const R_390_GOTPLT64 = 32
|
||||
pkg debug/elf, const R_390_GOTPLT64 R_390
|
||||
pkg debug/elf, const R_390_GOTPLTENT = 33
|
||||
pkg debug/elf, const R_390_GOTPLTENT R_390
|
||||
pkg debug/elf, const R_390_GOTPLTOFF16 = 34
|
||||
pkg debug/elf, const R_390_GOTPLTOFF16 R_390
|
||||
pkg debug/elf, const R_390_GOTPLTOFF32 = 35
|
||||
pkg debug/elf, const R_390_GOTPLTOFF32 R_390
|
||||
pkg debug/elf, const R_390_GOTPLTOFF64 = 36
|
||||
pkg debug/elf, const R_390_GOTPLTOFF64 R_390
|
||||
pkg debug/elf, const R_390_JMP_SLOT = 11
|
||||
pkg debug/elf, const R_390_JMP_SLOT R_390
|
||||
pkg debug/elf, const R_390_NONE = 0
|
||||
pkg debug/elf, const R_390_NONE R_390
|
||||
pkg debug/elf, const R_390_PC16 = 16
|
||||
pkg debug/elf, const R_390_PC16 R_390
|
||||
pkg debug/elf, const R_390_PC16DBL = 17
|
||||
pkg debug/elf, const R_390_PC16DBL R_390
|
||||
pkg debug/elf, const R_390_PC32 = 5
|
||||
pkg debug/elf, const R_390_PC32 R_390
|
||||
pkg debug/elf, const R_390_PC32DBL = 19
|
||||
pkg debug/elf, const R_390_PC32DBL R_390
|
||||
pkg debug/elf, const R_390_PC64 = 23
|
||||
pkg debug/elf, const R_390_PC64 R_390
|
||||
pkg debug/elf, const R_390_PLT16DBL = 18
|
||||
pkg debug/elf, const R_390_PLT16DBL R_390
|
||||
pkg debug/elf, const R_390_PLT32 = 8
|
||||
pkg debug/elf, const R_390_PLT32 R_390
|
||||
pkg debug/elf, const R_390_PLT32DBL = 20
|
||||
pkg debug/elf, const R_390_PLT32DBL R_390
|
||||
pkg debug/elf, const R_390_PLT64 = 25
|
||||
pkg debug/elf, const R_390_PLT64 R_390
|
||||
pkg debug/elf, const R_390_RELATIVE = 12
|
||||
pkg debug/elf, const R_390_RELATIVE R_390
|
||||
pkg debug/elf, const R_390_TLS_DTPMOD = 54
|
||||
pkg debug/elf, const R_390_TLS_DTPMOD R_390
|
||||
pkg debug/elf, const R_390_TLS_DTPOFF = 55
|
||||
pkg debug/elf, const R_390_TLS_DTPOFF R_390
|
||||
pkg debug/elf, const R_390_TLS_GD32 = 40
|
||||
pkg debug/elf, const R_390_TLS_GD32 R_390
|
||||
pkg debug/elf, const R_390_TLS_GD64 = 41
|
||||
pkg debug/elf, const R_390_TLS_GD64 R_390
|
||||
pkg debug/elf, const R_390_TLS_GDCALL = 38
|
||||
pkg debug/elf, const R_390_TLS_GDCALL R_390
|
||||
pkg debug/elf, const R_390_TLS_GOTIE12 = 42
|
||||
pkg debug/elf, const R_390_TLS_GOTIE12 R_390
|
||||
pkg debug/elf, const R_390_TLS_GOTIE20 = 60
|
||||
pkg debug/elf, const R_390_TLS_GOTIE20 R_390
|
||||
pkg debug/elf, const R_390_TLS_GOTIE32 = 43
|
||||
pkg debug/elf, const R_390_TLS_GOTIE32 R_390
|
||||
pkg debug/elf, const R_390_TLS_GOTIE64 = 44
|
||||
pkg debug/elf, const R_390_TLS_GOTIE64 R_390
|
||||
pkg debug/elf, const R_390_TLS_IE32 = 47
|
||||
pkg debug/elf, const R_390_TLS_IE32 R_390
|
||||
pkg debug/elf, const R_390_TLS_IE64 = 48
|
||||
pkg debug/elf, const R_390_TLS_IE64 R_390
|
||||
pkg debug/elf, const R_390_TLS_IEENT = 49
|
||||
pkg debug/elf, const R_390_TLS_IEENT R_390
|
||||
pkg debug/elf, const R_390_TLS_LDCALL = 39
|
||||
pkg debug/elf, const R_390_TLS_LDCALL R_390
|
||||
pkg debug/elf, const R_390_TLS_LDM32 = 45
|
||||
pkg debug/elf, const R_390_TLS_LDM32 R_390
|
||||
pkg debug/elf, const R_390_TLS_LDM64 = 46
|
||||
pkg debug/elf, const R_390_TLS_LDM64 R_390
|
||||
pkg debug/elf, const R_390_TLS_LDO32 = 52
|
||||
pkg debug/elf, const R_390_TLS_LDO32 R_390
|
||||
pkg debug/elf, const R_390_TLS_LDO64 = 53
|
||||
pkg debug/elf, const R_390_TLS_LDO64 R_390
|
||||
pkg debug/elf, const R_390_TLS_LE32 = 50
|
||||
pkg debug/elf, const R_390_TLS_LE32 R_390
|
||||
pkg debug/elf, const R_390_TLS_LE64 = 51
|
||||
pkg debug/elf, const R_390_TLS_LE64 R_390
|
||||
pkg debug/elf, const R_390_TLS_LOAD = 37
|
||||
pkg debug/elf, const R_390_TLS_LOAD R_390
|
||||
pkg debug/elf, const R_390_TLS_TPOFF = 56
|
||||
pkg debug/elf, const R_390_TLS_TPOFF R_390
|
||||
pkg debug/elf, method (R_390) GoString() string
|
||||
pkg debug/elf, method (R_390) String() string
|
||||
pkg debug/elf, type R_390 int
|
||||
pkg encoding/json, method (*Encoder) SetEscapeHTML(bool)
|
||||
pkg encoding/json, method (*Encoder) SetIndent(string, string)
|
||||
pkg go/build, type Package struct, BinaryOnly bool
|
||||
pkg go/build, type Package struct, CgoFFLAGS []string
|
||||
pkg go/build, type Package struct, FFiles []string
|
||||
pkg go/doc, type Example struct, Unordered bool
|
||||
pkg io, const SeekCurrent = 1
|
||||
pkg io, const SeekCurrent ideal-int
|
||||
pkg io, const SeekEnd = 2
|
||||
pkg io, const SeekEnd ideal-int
|
||||
pkg io, const SeekStart = 0
|
||||
pkg io, const SeekStart ideal-int
|
||||
pkg math/big, method (*Float) GobDecode([]uint8) error
|
||||
pkg math/big, method (*Float) GobEncode() ([]uint8, error)
|
||||
pkg net, method (*Dialer) DialContext(context.Context, string, string) (Conn, error)
|
||||
pkg net/http, const StatusAlreadyReported = 208
|
||||
pkg net/http, const StatusAlreadyReported ideal-int
|
||||
pkg net/http, const StatusFailedDependency = 424
|
||||
pkg net/http, const StatusFailedDependency ideal-int
|
||||
pkg net/http, const StatusIMUsed = 226
|
||||
pkg net/http, const StatusIMUsed ideal-int
|
||||
pkg net/http, const StatusInsufficientStorage = 507
|
||||
pkg net/http, const StatusInsufficientStorage ideal-int
|
||||
pkg net/http, const StatusLocked = 423
|
||||
pkg net/http, const StatusLocked ideal-int
|
||||
pkg net/http, const StatusLoopDetected = 508
|
||||
pkg net/http, const StatusLoopDetected ideal-int
|
||||
pkg net/http, const StatusMultiStatus = 207
|
||||
pkg net/http, const StatusMultiStatus ideal-int
|
||||
pkg net/http, const StatusNotExtended = 510
|
||||
pkg net/http, const StatusNotExtended ideal-int
|
||||
pkg net/http, const StatusPermanentRedirect = 308
|
||||
pkg net/http, const StatusPermanentRedirect ideal-int
|
||||
pkg net/http, const StatusProcessing = 102
|
||||
pkg net/http, const StatusProcessing ideal-int
|
||||
pkg net/http, const StatusUnprocessableEntity = 422
|
||||
pkg net/http, const StatusUnprocessableEntity ideal-int
|
||||
pkg net/http, const StatusUpgradeRequired = 426
|
||||
pkg net/http, const StatusUpgradeRequired ideal-int
|
||||
pkg net/http, const StatusVariantAlsoNegotiates = 506
|
||||
pkg net/http, const StatusVariantAlsoNegotiates ideal-int
|
||||
pkg net/http, method (*Request) Context() context.Context
|
||||
pkg net/http, method (*Request) WithContext(context.Context) *Request
|
||||
pkg net/http, type Request struct, Response *Response
|
||||
pkg net/http, type Response struct, Uncompressed bool
|
||||
pkg net/http, type Transport struct, DialContext func(context.Context, string, string) (net.Conn, error)
|
||||
pkg net/http, type Transport struct, IdleConnTimeout time.Duration
|
||||
pkg net/http, type Transport struct, MaxIdleConns int
|
||||
pkg net/http, type Transport struct, MaxResponseHeaderBytes int64
|
||||
pkg net/http, var ErrUseLastResponse error
|
||||
pkg net/http, var LocalAddrContextKey *contextKey
|
||||
pkg net/http, var ServerContextKey *contextKey
|
||||
pkg net/http/cgi, type Handler struct, Stderr io.Writer
|
||||
pkg net/http/httptest, func NewRequest(string, string, io.Reader) *http.Request
|
||||
pkg net/http/httptest, method (*ResponseRecorder) Result() *http.Response
|
||||
pkg net/http/httptrace, func ContextClientTrace(context.Context) *ClientTrace
|
||||
pkg net/http/httptrace, func WithClientTrace(context.Context, *ClientTrace) context.Context
|
||||
pkg net/http/httptrace, type ClientTrace struct
|
||||
pkg net/http/httptrace, type ClientTrace struct, ConnectDone func(string, string, error)
|
||||
pkg net/http/httptrace, type ClientTrace struct, ConnectStart func(string, string)
|
||||
pkg net/http/httptrace, type ClientTrace struct, DNSDone func(DNSDoneInfo)
|
||||
pkg net/http/httptrace, type ClientTrace struct, DNSStart func(DNSStartInfo)
|
||||
pkg net/http/httptrace, type ClientTrace struct, GetConn func(string)
|
||||
pkg net/http/httptrace, type ClientTrace struct, Got100Continue func()
|
||||
pkg net/http/httptrace, type ClientTrace struct, GotConn func(GotConnInfo)
|
||||
pkg net/http/httptrace, type ClientTrace struct, GotFirstResponseByte func()
|
||||
pkg net/http/httptrace, type ClientTrace struct, PutIdleConn func(error)
|
||||
pkg net/http/httptrace, type ClientTrace struct, Wait100Continue func()
|
||||
pkg net/http/httptrace, type ClientTrace struct, WroteHeaders func()
|
||||
pkg net/http/httptrace, type ClientTrace struct, WroteRequest func(WroteRequestInfo)
|
||||
pkg net/http/httptrace, type DNSDoneInfo struct
|
||||
pkg net/http/httptrace, type DNSDoneInfo struct, Addrs []net.IPAddr
|
||||
pkg net/http/httptrace, type DNSDoneInfo struct, Coalesced bool
|
||||
pkg net/http/httptrace, type DNSDoneInfo struct, Err error
|
||||
pkg net/http/httptrace, type DNSStartInfo struct
|
||||
pkg net/http/httptrace, type DNSStartInfo struct, Host string
|
||||
pkg net/http/httptrace, type GotConnInfo struct
|
||||
pkg net/http/httptrace, type GotConnInfo struct, Conn net.Conn
|
||||
pkg net/http/httptrace, type GotConnInfo struct, IdleTime time.Duration
|
||||
pkg net/http/httptrace, type GotConnInfo struct, Reused bool
|
||||
pkg net/http/httptrace, type GotConnInfo struct, WasIdle bool
|
||||
pkg net/http/httptrace, type WroteRequestInfo struct
|
||||
pkg net/http/httptrace, type WroteRequestInfo struct, Err error
|
||||
pkg net/url, type URL struct, ForceQuery bool
|
||||
pkg os/exec, func CommandContext(context.Context, string, ...string) *Cmd
|
||||
pkg os/user, func LookupGroup(string) (*Group, error)
|
||||
pkg os/user, func LookupGroupId(string) (*Group, error)
|
||||
pkg os/user, method (*User) GroupIds() ([]string, error)
|
||||
pkg os/user, method (UnknownGroupError) Error() string
|
||||
pkg os/user, method (UnknownGroupIdError) Error() string
|
||||
pkg os/user, type Group struct
|
||||
pkg os/user, type Group struct, Gid string
|
||||
pkg os/user, type Group struct, Name string
|
||||
pkg os/user, type UnknownGroupError string
|
||||
pkg os/user, type UnknownGroupIdError string
|
||||
pkg reflect, func StructOf([]StructField) Type
|
||||
pkg reflect, method (StructTag) Lookup(string) (string, bool)
|
||||
pkg runtime, func CallersFrames([]uintptr) *Frames
|
||||
pkg runtime, func KeepAlive(interface{})
|
||||
pkg runtime, func SetCgoTraceback(int, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer)
|
||||
pkg runtime, method (*Frames) Next() (Frame, bool)
|
||||
pkg runtime, type Frame struct
|
||||
pkg runtime, type Frame struct, Entry uintptr
|
||||
pkg runtime, type Frame struct, File string
|
||||
pkg runtime, type Frame struct, Func *Func
|
||||
pkg runtime, type Frame struct, Function string
|
||||
pkg runtime, type Frame struct, Line int
|
||||
pkg runtime, type Frame struct, PC uintptr
|
||||
pkg runtime, type Frames struct
|
||||
pkg strings, method (*Reader) Reset(string)
|
||||
pkg syscall (linux-386), type SysProcAttr struct, Unshareflags uintptr
|
||||
pkg syscall (linux-386-cgo), type SysProcAttr struct, Unshareflags uintptr
|
||||
pkg syscall (linux-amd64), type SysProcAttr struct, Unshareflags uintptr
|
||||
pkg syscall (linux-amd64-cgo), type SysProcAttr struct, Unshareflags uintptr
|
||||
pkg syscall (linux-arm), type SysProcAttr struct, Unshareflags uintptr
|
||||
pkg syscall (linux-arm-cgo), type SysProcAttr struct, Unshareflags uintptr
|
||||
pkg testing, method (*B) Run(string, func(*B)) bool
|
||||
pkg testing, method (*T) Run(string, func(*T)) bool
|
||||
pkg testing, type InternalExample struct, Unordered bool
|
||||
251
api/next.txt
251
api/next.txt
|
|
@ -1,251 +0,0 @@
|
|||
pkg bytes, func ContainsAny([]uint8, string) bool
|
||||
pkg bytes, func ContainsRune([]uint8, int32) bool
|
||||
pkg bytes, method (*Reader) Reset([]uint8)
|
||||
pkg compress/flate, const HuffmanOnly = -2
|
||||
pkg compress/flate, const HuffmanOnly ideal-int
|
||||
pkg context, func Background() Context
|
||||
pkg context, func TODO() Context
|
||||
pkg context, func WithCancel(Context) (Context, CancelFunc)
|
||||
pkg context, func WithDeadline(Context, time.Time) (Context, CancelFunc)
|
||||
pkg context, func WithTimeout(Context, time.Duration) (Context, CancelFunc)
|
||||
pkg context, func WithValue(Context, interface{}, interface{}) Context
|
||||
pkg context, type CancelFunc func()
|
||||
pkg context, type Context interface { Deadline, Done, Err, Value }
|
||||
pkg context, type Context interface, Deadline() (time.Time, bool)
|
||||
pkg context, type Context interface, Done() <-chan struct
|
||||
pkg context, type Context interface, Err() error
|
||||
pkg context, type Context interface, Value(interface{}) interface{}
|
||||
pkg context, var Canceled error
|
||||
pkg context, var DeadlineExceeded error
|
||||
pkg crypto/tls, const RenegotiateFreelyAsClient = 2
|
||||
pkg crypto/tls, const RenegotiateFreelyAsClient RenegotiationSupport
|
||||
pkg crypto/tls, const RenegotiateNever = 0
|
||||
pkg crypto/tls, const RenegotiateNever RenegotiationSupport
|
||||
pkg crypto/tls, const RenegotiateOnceAsClient = 1
|
||||
pkg crypto/tls, const RenegotiateOnceAsClient RenegotiationSupport
|
||||
pkg crypto/tls, type Config struct, DynamicRecordSizingDisabled bool
|
||||
pkg crypto/tls, type Config struct, Renegotiation RenegotiationSupport
|
||||
pkg crypto/tls, type RenegotiationSupport int
|
||||
pkg crypto/x509, func SystemCertPool() (*CertPool, error)
|
||||
pkg crypto/x509, type SystemRootsError struct, Err error
|
||||
pkg debug/dwarf, method (*Data) Ranges(*Entry) ([][2]uint64, error)
|
||||
pkg debug/dwarf, method (*Reader) SeekPC(uint64) (*Entry, error)
|
||||
pkg debug/elf, const R_390_12 = 2
|
||||
pkg debug/elf, const R_390_12 R_390
|
||||
pkg debug/elf, const R_390_16 = 3
|
||||
pkg debug/elf, const R_390_16 R_390
|
||||
pkg debug/elf, const R_390_20 = 57
|
||||
pkg debug/elf, const R_390_20 R_390
|
||||
pkg debug/elf, const R_390_32 = 4
|
||||
pkg debug/elf, const R_390_32 R_390
|
||||
pkg debug/elf, const R_390_64 = 22
|
||||
pkg debug/elf, const R_390_64 R_390
|
||||
pkg debug/elf, const R_390_8 = 1
|
||||
pkg debug/elf, const R_390_8 R_390
|
||||
pkg debug/elf, const R_390_COPY = 9
|
||||
pkg debug/elf, const R_390_COPY R_390
|
||||
pkg debug/elf, const R_390_GLOB_DAT = 10
|
||||
pkg debug/elf, const R_390_GLOB_DAT R_390
|
||||
pkg debug/elf, const R_390_GOT12 = 6
|
||||
pkg debug/elf, const R_390_GOT12 R_390
|
||||
pkg debug/elf, const R_390_GOT16 = 15
|
||||
pkg debug/elf, const R_390_GOT16 R_390
|
||||
pkg debug/elf, const R_390_GOT20 = 58
|
||||
pkg debug/elf, const R_390_GOT20 R_390
|
||||
pkg debug/elf, const R_390_GOT32 = 7
|
||||
pkg debug/elf, const R_390_GOT32 R_390
|
||||
pkg debug/elf, const R_390_GOT64 = 24
|
||||
pkg debug/elf, const R_390_GOT64 R_390
|
||||
pkg debug/elf, const R_390_GOTENT = 26
|
||||
pkg debug/elf, const R_390_GOTENT R_390
|
||||
pkg debug/elf, const R_390_GOTOFF = 13
|
||||
pkg debug/elf, const R_390_GOTOFF R_390
|
||||
pkg debug/elf, const R_390_GOTOFF16 = 27
|
||||
pkg debug/elf, const R_390_GOTOFF16 R_390
|
||||
pkg debug/elf, const R_390_GOTOFF64 = 28
|
||||
pkg debug/elf, const R_390_GOTOFF64 R_390
|
||||
pkg debug/elf, const R_390_GOTPC = 14
|
||||
pkg debug/elf, const R_390_GOTPC R_390
|
||||
pkg debug/elf, const R_390_GOTPCDBL = 21
|
||||
pkg debug/elf, const R_390_GOTPCDBL R_390
|
||||
pkg debug/elf, const R_390_GOTPLT12 = 29
|
||||
pkg debug/elf, const R_390_GOTPLT12 R_390
|
||||
pkg debug/elf, const R_390_GOTPLT16 = 30
|
||||
pkg debug/elf, const R_390_GOTPLT16 R_390
|
||||
pkg debug/elf, const R_390_GOTPLT20 = 59
|
||||
pkg debug/elf, const R_390_GOTPLT20 R_390
|
||||
pkg debug/elf, const R_390_GOTPLT32 = 31
|
||||
pkg debug/elf, const R_390_GOTPLT32 R_390
|
||||
pkg debug/elf, const R_390_GOTPLT64 = 32
|
||||
pkg debug/elf, const R_390_GOTPLT64 R_390
|
||||
pkg debug/elf, const R_390_GOTPLTENT = 33
|
||||
pkg debug/elf, const R_390_GOTPLTENT R_390
|
||||
pkg debug/elf, const R_390_GOTPLTOFF16 = 34
|
||||
pkg debug/elf, const R_390_GOTPLTOFF16 R_390
|
||||
pkg debug/elf, const R_390_GOTPLTOFF32 = 35
|
||||
pkg debug/elf, const R_390_GOTPLTOFF32 R_390
|
||||
pkg debug/elf, const R_390_GOTPLTOFF64 = 36
|
||||
pkg debug/elf, const R_390_GOTPLTOFF64 R_390
|
||||
pkg debug/elf, const R_390_JMP_SLOT = 11
|
||||
pkg debug/elf, const R_390_JMP_SLOT R_390
|
||||
pkg debug/elf, const R_390_NONE = 0
|
||||
pkg debug/elf, const R_390_NONE R_390
|
||||
pkg debug/elf, const R_390_PC16 = 16
|
||||
pkg debug/elf, const R_390_PC16 R_390
|
||||
pkg debug/elf, const R_390_PC16DBL = 17
|
||||
pkg debug/elf, const R_390_PC16DBL R_390
|
||||
pkg debug/elf, const R_390_PC32 = 5
|
||||
pkg debug/elf, const R_390_PC32 R_390
|
||||
pkg debug/elf, const R_390_PC32DBL = 19
|
||||
pkg debug/elf, const R_390_PC32DBL R_390
|
||||
pkg debug/elf, const R_390_PC64 = 23
|
||||
pkg debug/elf, const R_390_PC64 R_390
|
||||
pkg debug/elf, const R_390_PLT16DBL = 18
|
||||
pkg debug/elf, const R_390_PLT16DBL R_390
|
||||
pkg debug/elf, const R_390_PLT32 = 8
|
||||
pkg debug/elf, const R_390_PLT32 R_390
|
||||
pkg debug/elf, const R_390_PLT32DBL = 20
|
||||
pkg debug/elf, const R_390_PLT32DBL R_390
|
||||
pkg debug/elf, const R_390_PLT64 = 25
|
||||
pkg debug/elf, const R_390_PLT64 R_390
|
||||
pkg debug/elf, const R_390_RELATIVE = 12
|
||||
pkg debug/elf, const R_390_RELATIVE R_390
|
||||
pkg debug/elf, const R_390_TLS_DTPMOD = 54
|
||||
pkg debug/elf, const R_390_TLS_DTPMOD R_390
|
||||
pkg debug/elf, const R_390_TLS_DTPOFF = 55
|
||||
pkg debug/elf, const R_390_TLS_DTPOFF R_390
|
||||
pkg debug/elf, const R_390_TLS_GD32 = 40
|
||||
pkg debug/elf, const R_390_TLS_GD32 R_390
|
||||
pkg debug/elf, const R_390_TLS_GD64 = 41
|
||||
pkg debug/elf, const R_390_TLS_GD64 R_390
|
||||
pkg debug/elf, const R_390_TLS_GDCALL = 38
|
||||
pkg debug/elf, const R_390_TLS_GDCALL R_390
|
||||
pkg debug/elf, const R_390_TLS_GOTIE12 = 42
|
||||
pkg debug/elf, const R_390_TLS_GOTIE12 R_390
|
||||
pkg debug/elf, const R_390_TLS_GOTIE20 = 60
|
||||
pkg debug/elf, const R_390_TLS_GOTIE20 R_390
|
||||
pkg debug/elf, const R_390_TLS_GOTIE32 = 43
|
||||
pkg debug/elf, const R_390_TLS_GOTIE32 R_390
|
||||
pkg debug/elf, const R_390_TLS_GOTIE64 = 44
|
||||
pkg debug/elf, const R_390_TLS_GOTIE64 R_390
|
||||
pkg debug/elf, const R_390_TLS_IE32 = 47
|
||||
pkg debug/elf, const R_390_TLS_IE32 R_390
|
||||
pkg debug/elf, const R_390_TLS_IE64 = 48
|
||||
pkg debug/elf, const R_390_TLS_IE64 R_390
|
||||
pkg debug/elf, const R_390_TLS_IEENT = 49
|
||||
pkg debug/elf, const R_390_TLS_IEENT R_390
|
||||
pkg debug/elf, const R_390_TLS_LDCALL = 39
|
||||
pkg debug/elf, const R_390_TLS_LDCALL R_390
|
||||
pkg debug/elf, const R_390_TLS_LDM32 = 45
|
||||
pkg debug/elf, const R_390_TLS_LDM32 R_390
|
||||
pkg debug/elf, const R_390_TLS_LDM64 = 46
|
||||
pkg debug/elf, const R_390_TLS_LDM64 R_390
|
||||
pkg debug/elf, const R_390_TLS_LDO32 = 52
|
||||
pkg debug/elf, const R_390_TLS_LDO32 R_390
|
||||
pkg debug/elf, const R_390_TLS_LDO64 = 53
|
||||
pkg debug/elf, const R_390_TLS_LDO64 R_390
|
||||
pkg debug/elf, const R_390_TLS_LE32 = 50
|
||||
pkg debug/elf, const R_390_TLS_LE32 R_390
|
||||
pkg debug/elf, const R_390_TLS_LE64 = 51
|
||||
pkg debug/elf, const R_390_TLS_LE64 R_390
|
||||
pkg debug/elf, const R_390_TLS_LOAD = 37
|
||||
pkg debug/elf, const R_390_TLS_LOAD R_390
|
||||
pkg debug/elf, const R_390_TLS_TPOFF = 56
|
||||
pkg debug/elf, const R_390_TLS_TPOFF R_390
|
||||
pkg debug/elf, method (R_390) GoString() string
|
||||
pkg debug/elf, method (R_390) String() string
|
||||
pkg debug/elf, type R_390 int
|
||||
pkg encoding/json, method (*Encoder) SetEscapeHTML(bool)
|
||||
pkg encoding/json, method (*Encoder) SetIndent(string, string)
|
||||
pkg go/build, type Package struct, BinaryOnly bool
|
||||
pkg go/build, type Package struct, CgoFFLAGS []string
|
||||
pkg go/build, type Package struct, FFiles []string
|
||||
pkg go/doc, type Example struct, Unordered bool
|
||||
pkg io, const SeekCurrent = 1
|
||||
pkg io, const SeekCurrent ideal-int
|
||||
pkg io, const SeekEnd = 2
|
||||
pkg io, const SeekEnd ideal-int
|
||||
pkg io, const SeekStart = 0
|
||||
pkg io, const SeekStart ideal-int
|
||||
pkg math/big, method (*Float) GobDecode([]uint8) error
|
||||
pkg math/big, method (*Float) GobEncode() ([]uint8, error)
|
||||
pkg net, method (*Dialer) DialContext(context.Context, string, string) (Conn, error)
|
||||
pkg net/http, method (*Request) Context() context.Context
|
||||
pkg net/http, method (*Request) WithContext(context.Context) *Request
|
||||
pkg net/http, type Request struct, Response *Response
|
||||
pkg net/http, type Response struct, Uncompressed bool
|
||||
pkg net/http, type Transport struct, Dialer *net.Dialer
|
||||
pkg net/http, type Transport struct, IdleConnTimeout time.Duration
|
||||
pkg net/http, type Transport struct, MaxIdleConns int
|
||||
pkg net/http, type Transport struct, MaxResponseHeaderBytes int64
|
||||
pkg net/http, var ErrUseLastResponse error
|
||||
pkg net/http, var LocalAddrContextKey *contextKey
|
||||
pkg net/http, var ServerContextKey *contextKey
|
||||
pkg net/http/cgi, type Handler struct, Stderr io.Writer
|
||||
pkg net/http/httptest, func NewRequest(string, string, io.Reader) *http.Request
|
||||
pkg net/http/httptest, method (*ResponseRecorder) Result() *http.Response
|
||||
pkg net/http/httptrace, func ContextClientTrace(context.Context) *ClientTrace
|
||||
pkg net/http/httptrace, func WithClientTrace(context.Context, *ClientTrace) context.Context
|
||||
pkg net/http/httptrace, type ClientTrace struct
|
||||
pkg net/http/httptrace, type ClientTrace struct, ConnectDone func(string, string, error)
|
||||
pkg net/http/httptrace, type ClientTrace struct, ConnectStart func(string, string)
|
||||
pkg net/http/httptrace, type ClientTrace struct, DNSDone func(DNSDoneInfo)
|
||||
pkg net/http/httptrace, type ClientTrace struct, DNSStart func(DNSStartInfo)
|
||||
pkg net/http/httptrace, type ClientTrace struct, GetConn func(string)
|
||||
pkg net/http/httptrace, type ClientTrace struct, Got100Continue func()
|
||||
pkg net/http/httptrace, type ClientTrace struct, GotConn func(GotConnInfo)
|
||||
pkg net/http/httptrace, type ClientTrace struct, GotFirstResponseByte func()
|
||||
pkg net/http/httptrace, type ClientTrace struct, PutIdleConn func(error)
|
||||
pkg net/http/httptrace, type ClientTrace struct, Wait100Continue func()
|
||||
pkg net/http/httptrace, type ClientTrace struct, WroteHeaders func()
|
||||
pkg net/http/httptrace, type ClientTrace struct, WroteRequest func(WroteRequestInfo)
|
||||
pkg net/http/httptrace, type DNSDoneInfo struct
|
||||
pkg net/http/httptrace, type DNSDoneInfo struct, Addrs []net.IPAddr
|
||||
pkg net/http/httptrace, type DNSDoneInfo struct, Coalesced bool
|
||||
pkg net/http/httptrace, type DNSDoneInfo struct, Err error
|
||||
pkg net/http/httptrace, type DNSStartInfo struct
|
||||
pkg net/http/httptrace, type DNSStartInfo struct, Host string
|
||||
pkg net/http/httptrace, type GotConnInfo struct
|
||||
pkg net/http/httptrace, type GotConnInfo struct, Conn net.Conn
|
||||
pkg net/http/httptrace, type GotConnInfo struct, IdleTime time.Duration
|
||||
pkg net/http/httptrace, type GotConnInfo struct, Reused bool
|
||||
pkg net/http/httptrace, type GotConnInfo struct, WasIdle bool
|
||||
pkg net/http/httptrace, type WroteRequestInfo struct
|
||||
pkg net/http/httptrace, type WroteRequestInfo struct, Err error
|
||||
pkg net/url, type URL struct, ForceQuery bool
|
||||
pkg os, method (*File) Size() (int64, error)
|
||||
pkg os/exec, func CommandContext(context.Context, string, ...string) *Cmd
|
||||
pkg os/user, func LookupGroup(string) (*Group, error)
|
||||
pkg os/user, func LookupGroupId(string) (*Group, error)
|
||||
pkg os/user, method (*User) GroupIds() ([]string, error)
|
||||
pkg os/user, method (UnknownGroupError) Error() string
|
||||
pkg os/user, method (UnknownGroupIdError) Error() string
|
||||
pkg os/user, type Group struct
|
||||
pkg os/user, type Group struct, Gid string
|
||||
pkg os/user, type Group struct, Name string
|
||||
pkg os/user, type UnknownGroupError string
|
||||
pkg os/user, type UnknownGroupIdError string
|
||||
pkg reflect, func StructOf([]StructField) Type
|
||||
pkg reflect, method (StructTag) Lookup(string) (string, bool)
|
||||
pkg runtime, func CallersFrames([]uintptr) *Frames
|
||||
pkg runtime, func KeepAlive(interface{})
|
||||
pkg runtime, func SetCgoTraceback(int, unsafe.Pointer, unsafe.Pointer, unsafe.Pointer)
|
||||
pkg runtime, method (*Frames) Next() (Frame, bool)
|
||||
pkg runtime, type Frame struct
|
||||
pkg runtime, type Frame struct, Entry uintptr
|
||||
pkg runtime, type Frame struct, File string
|
||||
pkg runtime, type Frame struct, Func *Func
|
||||
pkg runtime, type Frame struct, Function string
|
||||
pkg runtime, type Frame struct, Line int
|
||||
pkg runtime, type Frame struct, PC uintptr
|
||||
pkg runtime, type Frames struct
|
||||
pkg strings, method (*Reader) Reset(string)
|
||||
pkg syscall (linux-386), type SysProcAttr struct, Unshare uintptr
|
||||
pkg syscall (linux-386-cgo), type SysProcAttr struct, Unshare uintptr
|
||||
pkg syscall (linux-amd64), type SysProcAttr struct, Unshare uintptr
|
||||
pkg syscall (linux-amd64-cgo), type SysProcAttr struct, Unshare uintptr
|
||||
pkg syscall (linux-arm), type SysProcAttr struct, Unshare uintptr
|
||||
pkg syscall (linux-arm-cgo), type SysProcAttr struct, Unshare uintptr
|
||||
pkg testing, method (*B) Run(string, func(*B)) bool
|
||||
pkg testing, method (*T) Run(string, func(*T)) bool
|
||||
pkg testing, type InternalExample struct, Unordered bool
|
||||
194
doc/go1.7.html
194
doc/go1.7.html
|
|
@ -33,7 +33,7 @@ Go 1.7 has NOT yet been released.
|
|||
By our regular schedule, it is expected some time in August 2016.
|
||||
</i>
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="introduction">Introduction to Go 1.7</h2>
|
||||
|
||||
<p>
|
||||
|
|
@ -95,7 +95,7 @@ The OpenBSD port now requires OpenBSD 5.6 or later, for access to the <a href="h
|
|||
|
||||
<h2 id="tools">Tools</h2>
|
||||
|
||||
<h3 id="cmd/asm">Assembler</h3>
|
||||
<h3 id="cmd_asm">Assembler</h3>
|
||||
|
||||
<p>
|
||||
For 64-bit ARM systems, the vector register names have been
|
||||
|
|
@ -185,7 +185,18 @@ built with Go 1.6,
|
|||
sometimes by as much as 20-30%.
|
||||
</p>
|
||||
|
||||
<h3 id="cmd/cgo">Cgo</h3>
|
||||
<p>
|
||||
On x86-64 systems, Go programs now maintain stack frame pointers
|
||||
as expected by profiling tools like Linux's perf and Intel's VTune,
|
||||
making it easier to analyze and optimize Go programs using these tools.
|
||||
The frame pointer maintenance has a small run-time overhead that varies
|
||||
but averages around 2%. We hope to reduce this cost in future releases.
|
||||
To build a toolchain that does not use frame pointers, set
|
||||
<code>GOEXPERIMENT=noframepointer</code> when running
|
||||
<code>make.bash</code>, <code>make.bat</code>, or <code>make.rc</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="cmd_cgo">Cgo</h3>
|
||||
|
||||
<p>
|
||||
Packages using <a href="/cmd/cgo/">cgo</a> may now include
|
||||
|
|
@ -219,7 +230,7 @@ GCC release 6 contains the Go 1.6.1 version of gccgo.
|
|||
The next release, GCC 7, will likely have the Go 1.8 version of gccgo.
|
||||
</p>
|
||||
|
||||
<h3 id="cmd/go">Go command</h3>
|
||||
<h3 id="cmd_go">Go command</h3>
|
||||
|
||||
<p>
|
||||
The <a href="/cmd/go/"><code>go</code></a> command's basic operation
|
||||
|
|
@ -259,7 +270,7 @@ will not work with such packages, and there are no plans to support
|
|||
such packages in the “<code>go</code> <code>get</code>” command.
|
||||
</p>
|
||||
|
||||
<h3 id="cmd/doc">Go doc</h3>
|
||||
<h3 id="cmd_doc">Go doc</h3>
|
||||
|
||||
<p>
|
||||
The “<code>go</code> <code>doc</code>” command
|
||||
|
|
@ -267,7 +278,7 @@ now groups constructors with the type they construct,
|
|||
following <a href="/cmd/godoc/"><code>godoc</code></a>.
|
||||
</p>
|
||||
|
||||
<h3 id="cmd/vet">Go vet</h3>
|
||||
<h3 id="cmd_vet">Go vet</h3>
|
||||
|
||||
<p>
|
||||
The “<code>go</code> <code>vet</code>” command
|
||||
|
|
@ -277,14 +288,14 @@ To avoid confusion with the new <code>-tests</code> check, the old, unadvertised
|
|||
<code>-test</code> option has been removed; it was equivalent to <code>-all</code> <code>-shadow</code>.
|
||||
</p>
|
||||
|
||||
<h3 id="cmd/dist">Go tool dist</h3>
|
||||
<h3 id="cmd_dist">Go tool dist</h3>
|
||||
|
||||
<p>
|
||||
The new subcommand “<code>go</code> <code>tool</code> <code>dist</code> <code>list</code>”
|
||||
prints all supported operating system/architecture pairs.
|
||||
</p>
|
||||
|
||||
<h3 id="cmd/trace">Go tool trace</h3>
|
||||
<h3 id="cmd_trace">Go tool trace</h3>
|
||||
|
||||
<p>
|
||||
The “<code>go</code> <code>tool</code> <code>trace</code>” command,
|
||||
|
|
@ -324,7 +335,7 @@ the code generation changes alone typically reduce program CPU time by 5-35%.
|
|||
</p>
|
||||
|
||||
<p>
|
||||
<!-- git log --grep '-[0-9][0-9]\.[0-9][0-9]%' go1.6.. -->
|
||||
<!-- git log --grep '-[0-9][0-9]\.[0-9][0-9]%' go1.6.. -->
|
||||
There have been significant optimizations bringing more than 10% improvements
|
||||
to implementations in the
|
||||
<a href="/pkg/crypto/sha1/"><code>crypto/sha1</code></a>,
|
||||
|
|
@ -351,7 +362,7 @@ packages.
|
|||
<p>
|
||||
Go 1.7 moves the <code>golang.org/x/net/context</code> package
|
||||
into the standard library as <a href="/pkg/context/"><code>context</code></a>.
|
||||
This allows the use of contexts for cancellation, timeouts, and passing
|
||||
This allows the use of contexts for cancelation, timeouts, and passing
|
||||
request-scoped data in other standard library packages,
|
||||
including
|
||||
<a href="#net">net</a>,
|
||||
|
|
@ -368,6 +379,13 @@ and the Go blog post
|
|||
“<a href="https://blog.golang.org/context">Go Concurrent Patterns: Context</a>.”
|
||||
</p>
|
||||
|
||||
<h3 id="httptrace">HTTP Tracing</h3>
|
||||
|
||||
<p>
|
||||
Go 1.7 introduces <a href="/pkg/net/http/httptrace/"><code>net/http/httptrace</code></a>,
|
||||
a package that provides mechanisms for tracing events within HTTP requests.
|
||||
</p>
|
||||
|
||||
<h3 id="testing">Testing</h3>
|
||||
|
||||
<p>
|
||||
|
|
@ -383,7 +401,8 @@ See the <a href="/pkg/testing/#hdr-Subtests_and_Sub_benchmarks">package document
|
|||
|
||||
<p>
|
||||
All panics started by the runtime now use panic values
|
||||
that implement both the builtin <a href="/ref/spec#Errors">error</code>,
|
||||
that implement both the
|
||||
builtin <a href="/ref/spec#Errors"><code>error</code></a>,
|
||||
and
|
||||
<a href="/pkg/runtime/#Error"><code>runtime.Error</code></a>,
|
||||
as
|
||||
|
|
@ -451,7 +470,7 @@ made with the Go 1 <a href="/doc/go1compat">promise of compatibility</a>
|
|||
in mind.
|
||||
</p>
|
||||
|
||||
<dl id="bufio"><a href="/pkg/bufio/">bufio</a></dl>
|
||||
<dl id="bufio"><dt><a href="/pkg/bufio/">bufio</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -463,8 +482,9 @@ it would return an empty slice and the error <code>ErrBufferFull</code>.
|
|||
Now it returns the entire underlying buffer, still accompanied by the error <code>ErrBufferFull</code>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="bytes"><a href="/pkg/bytes/">bytes</a></dl>
|
||||
<dl id="bytes"><dt><a href="/pkg/bytes/">bytes</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -482,7 +502,7 @@ In previous releases of Go, if
|
|||
were asked for zero bytes with no data remaining, it would
|
||||
return a count of 0 and no error.
|
||||
Now it returns a count of 0 and the error
|
||||
<a href="/pkg/io/#EOF"><code>io.EOF</code></a> .
|
||||
<a href="/pkg/io/#EOF"><code>io.EOF</code></a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
@ -491,8 +511,9 @@ The
|
|||
<a href="/pkg/bytes/#Reader.Reset"><code>Reset</code></a> to allow reuse of a <code>Reader</code>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="compress/flate"><a href="/pkg/compress/flate/">compress/flate</a></dl>
|
||||
<dl id="compress_flate"><dt><a href="/pkg/compress/flate/">compress/flate</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -521,9 +542,26 @@ that applies Huffman but not Lempel-Ziv encoding.
|
|||
but at the cost of producing compressed outputs that are 20-40% larger than those
|
||||
generated by the new <code>BestSpeed</code>.
|
||||
</p>
|
||||
</dd>
|
||||
|
||||
<dl id="crypto/tls"><a href="/pkg/crypto/tls/">crypto/tls</a></dl>
|
||||
<p>
|
||||
It is important to note that both
|
||||
<code>BestSpeed</code> and <code>HuffmanOnly</code> produce a compressed output that is
|
||||
<a href="https://tools.ietf.org/html/rfc1951">RFC 1951</a> compliant.
|
||||
In other words, any valid DEFLATE decompressor will continue to be able to decompress these outputs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Lastly, there is a minor change to the decompressor's implementation of
|
||||
<a href="/pkg/io/#Reader"><code>io.Reader</code></a>. In previous versions,
|
||||
the decompressor deferred reporting
|
||||
<a href="/pkg/io/#EOF"><code>io.EOF</code></a> until exactly no more bytes could be read.
|
||||
Now, it reports
|
||||
<a href="/pkg/io/#EOF"><code>io.EOF</code></a> more eagerly when reading the last set of bytes.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="crypto_tls"><dt><a href="/pkg/crypto/tls/">crypto/tls</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -559,8 +597,9 @@ When generating self-signed certificates, the package no longer sets the
|
|||
“Authority Key Identifier” field by default.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="crypto/x509"><a href="/pkg/crypto/x509/">crypto/x509</a></dl>
|
||||
<dl id="crypto_x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -571,8 +610,9 @@ There is also a new associated error type
|
|||
<a href="/pkg/crypto/x509/#SystemRootsError"><code>SystemRootsError</code></a>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="debug/dwarf"><a href="/pkg/debug/dwarf/">debug/dwarf</a></dl>
|
||||
<dl id="debug_dwarf"><dt><a href="/pkg/debug/dwarf/">debug/dwarf</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -586,8 +626,9 @@ help to find the compilation unit to pass to a
|
|||
and to identify the specific function for a given program counter.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="debug/elf"><a href="/pkg/debug/elf/">debug/elf</a></dl>
|
||||
<dl id="debug_elf"><dt><a href="/pkg/debug/elf/">debug/elf</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -597,8 +638,9 @@ and its many predefined constants
|
|||
support the S390 port.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="encoding/asn1"><a href="/pkg/encoding/asn1/">encoding/asn1</a></dl>
|
||||
<dl id="encoding_asn1"><dt><a href="/pkg/encoding/asn1/">encoding/asn1</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -606,8 +648,9 @@ The ASN.1 decoder now rejects non-minimal integer encodings.
|
|||
This may cause the package to reject some invalid but formerly accepted ASN.1 data.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="encoding/json"><a href="/pkg/encoding/json/">encoding/json</a></dl>
|
||||
<dl id="encoding_json"><dt><a href="/pkg/encoding/json/">encoding/json</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -638,23 +681,15 @@ maps using keys with string types.
|
|||
Go 1.7 adds support for maps using keys with integer types:
|
||||
the encoding uses a quoted decimal representation as the JSON key.
|
||||
Go 1.7 also adds support for encoding maps using non-string keys that implement
|
||||
<code>MarshalJSON</code>
|
||||
(see
|
||||
<a href="/pkg/encoding/json/#Marshaler"><code>Marshaler</code></a>)
|
||||
or
|
||||
<code>MarshalText</code>
|
||||
the <code>MarshalText</code>
|
||||
(see
|
||||
<a href="/pkg/encoding/#TextMarshaler"><code>encoding.TextMarshaler</code></a>)
|
||||
methods,
|
||||
method,
|
||||
as well as support for decoding maps using non-string keys that implement
|
||||
<code>UnmarshalJSON</code>
|
||||
(see
|
||||
<a href="/pkg/encoding/json/#Unmarshaler"><code>Unmarshaler</code></a>)
|
||||
or
|
||||
<code>UnmarshalText</code>
|
||||
the <code>UnmarshalText</code>
|
||||
(see
|
||||
<a href="/pkg/encoding/#TextUnmarshaler"><code>encoding.TextUnmarshaler</code></a>)
|
||||
methods.
|
||||
method.
|
||||
These methods are ignored for keys with string types in order to preserve
|
||||
the encoding and decoding used in earlier versions of Go.
|
||||
</p>
|
||||
|
|
@ -679,8 +714,9 @@ so this change should be semantically backwards compatible with earlier versions
|
|||
even though it does change the chosen encoding.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="go/build"><a href="/pkg/go/build/">go/build</a></dl>
|
||||
<dl id="go_build"><dt><a href="/pkg/go/build/">go/build</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -691,8 +727,9 @@ the
|
|||
adds new fields <code>BinaryOnly</code>, <code>CgoFFLAGS</code>, and <code>FFiles</code>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="go/doc"><a href="/pkg/go/doc/">go/doc</a></dl>
|
||||
<dl id="go_doc"><dt><a href="/pkg/go/doc/">go/doc</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -701,8 +738,9 @@ To support the corresponding change in <code>go</code> <code>test</code> describ
|
|||
indicating whether the example may generate its output lines in any order.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="io"><a href="/pkg/io/">io</a></dl>
|
||||
<dl id="io"><dt><a href="/pkg/io/">io</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -715,8 +753,9 @@ These constants are preferred over <code>os.SEEK_SET</code>, <code>os.SEEK_CUR</
|
|||
but the latter will be preserved for compatibility.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="math/big"><a href="/pkg/math/big/">math/big</a></dl>
|
||||
<dl id="math_big"><dt><a href="/pkg/math/big/">math/big</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -729,8 +768,9 @@ so that values of type <code>Float</code> can now be encoded and decoded using t
|
|||
package.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="mime/multipart"><a href="/pkg/mime/multipart/">mime/multipart</a></dl>
|
||||
<dl id="mime_multipart"><dt><a href="/pkg/mime/multipart/">mime/multipart</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -741,8 +781,9 @@ Previously, iteration over a map caused the section header to use a
|
|||
non-deterministic order.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="net"><a href="/pkg/net/">net</a></dl>
|
||||
<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -769,13 +810,14 @@ Go 1.7 adds the hexadecimal encoding of the bytes, as in <code>"?12ab"</code>.
|
|||
|
||||
<p>
|
||||
The pure Go <a href="/pkg/net/#hdr-Name_Resolution">name resolution</a>
|
||||
implementation now respects <code>nsswtch.conf</code>'s
|
||||
implementation now respects <code>nsswitch.conf</code>'s
|
||||
stated preference for the priority of DNS lookups compared to
|
||||
local file (that is, <code>/etc/hosts</code>) lookups.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="net/http"><a href="/pkg/net/http/">net/http</a></dl>
|
||||
<dl id="net_http"><dt><a href="/pkg/net/http/">net/http</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -847,13 +889,13 @@ as <code>req.Response</code>.
|
|||
Since Go 1, the default behavior of the HTTP client is
|
||||
to request server-side compression
|
||||
using the <code>Accept-Encoding</code> request header
|
||||
and then to uncompress the response body transparently,
|
||||
and then to decompress the response body transparently,
|
||||
and this behavior is adjustable using the
|
||||
<a href="/pkg/net/http/#Transport"><code>Transport</code></a>'s <code>DisableCompression</code> field.
|
||||
In Go 1.7, to aid the implementation of HTTP proxies, the
|
||||
<a href="/pkg/net/http/#Response"><code>Response</code></a>'s new
|
||||
<code>Uncompressed</code> field reports whether
|
||||
this transparent uncompression took place.
|
||||
this transparent decompression took place.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
@ -861,8 +903,9 @@ this transparent uncompression took place.
|
|||
adds support for a few new audio and video content types.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="net/http/cgi"><a href="/pkg/net/http/cgi/">net/http/cgi</a></dl>
|
||||
<dl id="net_http_cgi"><dt><a href="/pkg/net/http/cgi/">net/http/cgi</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -875,8 +918,9 @@ standard error away from the host process's
|
|||
standard error.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="net/http/httptest"><a href="/pkg/net/http/httptest/">net/http/httptest</a></dl>
|
||||
<dl id="net_http_httptest"><dt><a href="/pkg/net/http/httptest/">net/http/httptest</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -900,8 +944,9 @@ instead of accessing
|
|||
<code>ResponseRecorder</code>'s <code>HeaderMap</code> directly.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="net/http/httputil"><a href="/pkg/net/http/httputil/">net/http/httputil</a></dl>
|
||||
<dl id="net_http_httputil"><dt><a href="/pkg/net/http/httputil/">net/http/httputil</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -924,8 +969,9 @@ and
|
|||
instead.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="net/http/pprof"><a href="/pkg/net/http/pprof/">net/http/pprof</a></dl>
|
||||
<dl id="net_http_pprof"><dt><a href="/pkg/net/http/pprof/">net/http/pprof</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -935,8 +981,9 @@ allowing collection of traces for intervals smaller than one second.
|
|||
This is especially useful on busy servers.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl><a href="/pkg/net/mail/">net/mail</a></dl>
|
||||
<dl><dt><a href="/pkg/net/mail/">net/mail</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -947,11 +994,21 @@ For compatibility with older mail parsers,
|
|||
the address encoder, namely
|
||||
<a href="/pkg/net/mail/#Address"><code>Address</code></a>'s
|
||||
<a href="/pkg/net/mail/#Address.String"><code>String</code></a> method,
|
||||
continues to escape all UTF-8 text following <a href="https://tools.ietf.org/html/rfc5322">RFC 5322</a>,
|
||||
continues to escape all UTF-8 text following <a href="https://tools.ietf.org/html/rfc5322">RFC 5322</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The <a href="/pkg/net/mail/#ParseAddress"><code>ParseAddress</code></a>
|
||||
function and
|
||||
the <a href="/pkg/net/mail/#AddressParser.Parse"><code>AddressParser.Parse</code></a>
|
||||
method are stricter.
|
||||
They used to ignore any characters following an e-mail address, but
|
||||
will now return an error for anything other than whitespace.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="net/url"><a href="/pkg/net/url/">net/url</a></dl>
|
||||
<dl id="net_url"><dt><a href="/pkg/net/url/">net/url</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -963,19 +1020,11 @@ in order to distinguish URLs without query strings (like <code>/search</code>)
|
|||
from URLs with empty query strings (like <code>/search?</code>).
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="os"><a href="/pkg/os/">os</a></dl>
|
||||
<dl id="os"><dt><a href="/pkg/os/">os</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
The
|
||||
<a href="/pkg/os/#File"><code>File</code></a>
|
||||
type adds a new
|
||||
<a href="/pkg/os/#File.Size"><code>Size</code></a>
|
||||
method, so that <code>File</code> implements the new
|
||||
<a href="/pkg/io/#SizedReaderAt"><code>SizedReaderAt</code></a> method.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/os/#IsExists"><code>IsExists</code></a> now returns true for <code>syscall.ENOTEMPTY</code>,
|
||||
on systems where that error exists.
|
||||
|
|
@ -988,8 +1037,9 @@ making the implementation behave as on
|
|||
non-Windows systems.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="os/exec"><a href="/pkg/os/exec/">os/exec</a></dl>
|
||||
<dl id="os_exec"><dt><a href="/pkg/os/exec/">os/exec</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -1000,8 +1050,9 @@ is like
|
|||
<a href="/pkg/os/exec/#Command"><code>Command</code></a> but includes a context that can be used to cancel the command execution.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="os/user"><a href="/pkg/os/user/">os/user</a></dl>
|
||||
<dl id="os_user"><dt><a href="/pkg/os/user/">os/user</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -1020,8 +1071,9 @@ and the new field <code>GroupIds</code> in the <code>User</code> struct,
|
|||
provides access to system-specific user group information.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="reflect"><a href="/pkg/reflect/">reflect</a></dl>
|
||||
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -1068,8 +1120,9 @@ methods of
|
|||
no longer return or count unexported methods.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="strings"><a href="/pkg/strings/">strings</a></dl>
|
||||
<dl id="strings"><dt><a href="/pkg/strings/">strings</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -1079,7 +1132,7 @@ In previous releases of Go, if
|
|||
were asked for zero bytes with no data remaining, it would
|
||||
return a count of 0 and no error.
|
||||
Now it returns a count of 0 and the error
|
||||
<a href="/pkg/io/#EOF"><code>io.EOF</code></a> .
|
||||
<a href="/pkg/io/#EOF"><code>io.EOF</code></a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
@ -1088,8 +1141,9 @@ The
|
|||
<a href="/pkg/strings/#Reader.Reset"><code>Reset</code></a> to allow reuse of a <code>Reader</code>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="time"><a href="/pkg/time/">time</a></dl>
|
||||
<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -1112,8 +1166,9 @@ cannot be found, for example on Windows.
|
|||
The Windows time zone abbreviation list has also been updated.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="syscall"><a href="/pkg/syscall/">syscall</a></dl>
|
||||
<dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
|
|
@ -1121,7 +1176,7 @@ On Linux, the
|
|||
<a href="/pkg/syscall/#SysProcAttr"><code>SysProcAttr</code></a> struct
|
||||
(as used in
|
||||
<a href="/pkg/os/exec/#Cmd"><code>os/exec.Cmd</code></a>'s <code>SysProcAttr</code> field)
|
||||
has a new <code>Unshare</code> field.
|
||||
has a new <code>Unshareflags</code> field.
|
||||
If the field is nonzero, the child process created by
|
||||
<a href="/pkg/syscall/#ForkExec"><code>ForkExec</code></a>
|
||||
(as used in <code>exec.Cmd</code>'s <code>Run</code> method)
|
||||
|
|
@ -1130,3 +1185,4 @@ will call the
|
|||
system call before executing the new program.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of April 25, 2016",
|
||||
"Subtitle": "Version of May 31, 2016",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
|
|
@ -4672,6 +4672,8 @@ Cases then match actual types <code>T</code> against the dynamic type of the
|
|||
expression <code>x</code>. As with type assertions, <code>x</code> must be of
|
||||
<a href="#Interface_types">interface type</a>, and each non-interface type
|
||||
<code>T</code> listed in a case must implement the type of <code>x</code>.
|
||||
The types listed in the cases of a type switch must all be
|
||||
<a href="#Type_identity">different</a>.
|
||||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
|
|
@ -4696,6 +4698,7 @@ in the TypeSwitchGuard.
|
|||
The type in a case may be <a href="#Predeclared_identifiers"><code>nil</code></a>;
|
||||
that case is used when the expression in the TypeSwitchGuard
|
||||
is a <code>nil</code> interface value.
|
||||
There may be at most one <code>nil</code> case.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
|
|
|||
|
|
@ -91,11 +91,11 @@ func main() {
|
|||
|
||||
run("shell", "rm", "-rf", deviceGotmp) // Clean up.
|
||||
|
||||
output = output[strings.LastIndex(output, "\n")+1:]
|
||||
if !strings.HasPrefix(output, exitstr) {
|
||||
exitIdx := strings.LastIndex(output, exitstr)
|
||||
if exitIdx == -1 {
|
||||
log.Fatalf("no exit code: %q", output)
|
||||
}
|
||||
code, err := strconv.Atoi(output[len(exitstr):])
|
||||
code, err := strconv.Atoi(output[exitIdx+len(exitstr):])
|
||||
if err != nil {
|
||||
log.Fatalf("bad exit code: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
// Copyright 2016 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.
|
||||
|
||||
// cgo converts C void* to Go unsafe.Pointer, so despite appearances C
|
||||
// void** is Go *unsafe.Pointer. This test verifies that we detect the
|
||||
// problem at build time.
|
||||
|
||||
package main
|
||||
|
||||
// typedef void v;
|
||||
// void F(v** p) {}
|
||||
import "C"
|
||||
|
||||
import "unsafe"
|
||||
|
||||
type v [0]byte
|
||||
|
||||
func f(p **v) {
|
||||
C.F((**C.v)(unsafe.Pointer(p))) // ERROR HERE
|
||||
}
|
||||
|
||||
func main() {
|
||||
var p *v
|
||||
f(&p)
|
||||
}
|
||||
|
|
@ -314,6 +314,14 @@ var ptrTests = []ptrTest{
|
|||
body: `i := 0; p := S{u:uintptr(unsafe.Pointer(&i))}; q := (*S)(C.malloc(C.size_t(unsafe.Sizeof(p)))); *q = p; C.f(unsafe.Pointer(q))`,
|
||||
fail: false,
|
||||
},
|
||||
{
|
||||
// Check deferred pointers when they are used, not
|
||||
// when the defer statement is run.
|
||||
name: "defer",
|
||||
c: `typedef struct s { int *p; } s; void f(s *ps) {}`,
|
||||
body: `p := &C.s{}; defer C.f(p); p.p = new(C.int)`,
|
||||
fail: true,
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
|
|||
|
|
@ -18,16 +18,16 @@ expect() {
|
|||
file=$1
|
||||
shift
|
||||
if go build $file >errs 2>&1; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail but it succeeded
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected cgo to fail on $file but it succeeded
|
||||
exit 1
|
||||
fi
|
||||
if ! test -s errs; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output but saw none
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output for $file but saw none
|
||||
exit 1
|
||||
fi
|
||||
for error; do
|
||||
if ! fgrep $error errs >/dev/null 2>&1; then
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output to contain \"$error\" but saw:
|
||||
echo 1>&2 misc/cgo/errors/test.bash: BUG: expected error output for $file to contain \"$error\" but saw:
|
||||
cat 1>&2 errs
|
||||
exit 1
|
||||
fi
|
||||
|
|
@ -44,6 +44,7 @@ check issue11097b.go
|
|||
expect issue13129.go C.ushort
|
||||
check issue13423.go
|
||||
expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble
|
||||
check issue13830.go
|
||||
|
||||
if ! go build issue14669.go; then
|
||||
exit 1
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cgotest
|
||||
|
||||
import "testing"
|
||||
|
||||
// Stubs for tests that fails to build on Android
|
||||
func test6997(t *testing.T) {}
|
||||
func test3775(t *testing.T) {}
|
||||
func test8694(t *testing.T) {}
|
||||
func testSigaltstack(t *testing.T) {}
|
||||
|
|
@ -8,6 +8,7 @@ package cgotest
|
|||
import "C"
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
|
@ -30,6 +31,9 @@ func Add(x int) {
|
|||
}
|
||||
|
||||
func testCthread(t *testing.T) {
|
||||
if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
|
||||
t.Skip("the iOS exec wrapper is unable to properly handle the panic from Add")
|
||||
}
|
||||
sum.i = 0
|
||||
C.doAdd(10, 6)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// +build !android
|
||||
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !android
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !android
|
||||
|
||||
// Test that pthread_cancel works as expected
|
||||
// (NPTL uses SIGRTMIN to implement thread cancelation)
|
||||
// See https://golang.org/issue/6997
|
||||
|
|
|
|||
|
|
@ -103,6 +103,9 @@ func test7978(t *testing.T) {
|
|||
if C.HAS_SYNC_FETCH_AND_ADD == 0 {
|
||||
t.Skip("clang required for __sync_fetch_and_add support on darwin/arm")
|
||||
}
|
||||
if runtime.GOOS == "android" || runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
|
||||
t.Skip("GOTRACEBACK is not passed on to the exec wrapper")
|
||||
}
|
||||
if os.Getenv("GOTRACEBACK") != "2" {
|
||||
t.Fatalf("GOTRACEBACK must be 2")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !android
|
||||
|
||||
package cgotest
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -7,17 +7,18 @@
|
|||
#include "textflag.h"
|
||||
|
||||
TEXT ·RewindAndSetgid(SB),NOSPLIT,$0-0
|
||||
MOVL $·Baton(SB), BX
|
||||
// Rewind stack pointer so anything that happens on the stack
|
||||
// will clobber the test pattern created by the caller
|
||||
ADDL $(1024 * 8), SP
|
||||
|
||||
// Ask signaller to setgid
|
||||
MOVL $1, ·Baton(SB)
|
||||
MOVL $1, (BX)
|
||||
|
||||
// Wait for setgid completion
|
||||
loop:
|
||||
PAUSE
|
||||
MOVL ·Baton(SB), AX
|
||||
MOVL (BX), AX
|
||||
CMPL AX, $0
|
||||
JNE loop
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !windows
|
||||
// +build !windows,!android
|
||||
|
||||
// Test that the Go runtime still works if C code changes the signal stack.
|
||||
|
||||
|
|
|
|||
|
|
@ -111,50 +111,52 @@ if test "$tsan" = "yes"; then
|
|||
rm -f ${TMPDIR}/testsanitizers$$*
|
||||
fi
|
||||
|
||||
if test "$tsan" = "yes"; then
|
||||
# Run a TSAN test.
|
||||
# $1 test name
|
||||
# $2 environment variables
|
||||
# $3 go run args
|
||||
testtsan() {
|
||||
err=${TMPDIR}/tsanerr$$.out
|
||||
|
||||
if ! go run tsan.go 2>$err; then
|
||||
if ! env $2 go run $3 $1 2>$err; then
|
||||
cat $err
|
||||
echo "FAIL: tsan"
|
||||
echo "FAIL: $1"
|
||||
status=1
|
||||
elif grep -i warning $err >/dev/null 2>&1; then
|
||||
cat $err
|
||||
echo "FAIL: tsan"
|
||||
echo "FAIL: $1"
|
||||
status=1
|
||||
fi
|
||||
|
||||
if ! go run tsan2.go 2>$err; then
|
||||
cat $err
|
||||
echo "FAIL: tsan2"
|
||||
status=1
|
||||
elif grep -i warning $err >/dev/null 2>&1; then
|
||||
cat $err
|
||||
echo "FAIL: tsan2"
|
||||
status=1
|
||||
fi
|
||||
|
||||
if ! go run tsan3.go 2>$err; then
|
||||
cat $err
|
||||
echo "FAIL: tsan3"
|
||||
status=1
|
||||
elif grep -i warning $err >/dev/null 2>&1; then
|
||||
cat $err
|
||||
echo "FAIL: tsan3"
|
||||
status=1
|
||||
fi
|
||||
|
||||
if ! go run tsan4.go 2>$err; then
|
||||
cat $err
|
||||
echo "FAIL: tsan4"
|
||||
status=1
|
||||
elif grep -i warning $err >/dev/null 2>&1; then
|
||||
cat $err
|
||||
echo "FAIL: tsan4"
|
||||
status=1
|
||||
fi
|
||||
|
||||
rm -f $err
|
||||
}
|
||||
|
||||
if test "$tsan" = "yes"; then
|
||||
testtsan tsan.go
|
||||
testtsan tsan2.go
|
||||
testtsan tsan3.go
|
||||
testtsan tsan4.go
|
||||
|
||||
# These tests are only reliable using clang or GCC version 7 or later.
|
||||
# Otherwise runtime/cgo/libcgo.h can't tell whether TSAN is in use.
|
||||
ok=false
|
||||
if ${CC} --version | grep clang >/dev/null 2>&1; then
|
||||
ok=true
|
||||
else
|
||||
ver=$($CC -dumpversion)
|
||||
major=$(echo $ver | sed -e 's/\([0-9]*\).*/\1/')
|
||||
if test "$major" -lt 7; then
|
||||
echo "skipping remaining TSAN tests: GCC version $major (older than 7)"
|
||||
else
|
||||
ok=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if test "$ok" = "true"; then
|
||||
# This test requires rebuilding os/user with -fsanitize=thread.
|
||||
testtsan tsan5.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
|
||||
# This test requires rebuilding runtime/cgo with -fsanitize=thread.
|
||||
testtsan tsan6.go "CGO_CFLAGS=-fsanitize=thread CGO_LDFLAGS=-fsanitize=thread" "-installsuffix=tsan"
|
||||
fi
|
||||
fi
|
||||
|
||||
exit $status
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
// Check that calls to C.malloc/C.free do not collide with the calls
|
||||
// made by the os/user package.
|
||||
|
||||
// #cgo CFLAGS: -fsanitize=thread
|
||||
// #cgo LDFLAGS: -fsanitize=thread
|
||||
// #include <stdlib.h>
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
// Let the test pass.
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 20; i++ {
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for i := 0; i < 1000; i++ {
|
||||
user.Lookup(u.Username)
|
||||
runtime.Gosched()
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for i := 0; i < 1000; i++ {
|
||||
p := C.malloc(C.size_t(len(u.Username) + 1))
|
||||
runtime.Gosched()
|
||||
C.free(p)
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
// Check that writes to Go allocated memory, with Go synchronization,
|
||||
// do not look like a race.
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -fsanitize=thread
|
||||
#cgo LDFLAGS: -fsanitize=thread
|
||||
|
||||
void f(char *p) {
|
||||
*p = 1;
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var wg sync.WaitGroup
|
||||
var mu sync.Mutex
|
||||
c := make(chan []C.char, 100)
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(2)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for i := 0; i < 100; i++ {
|
||||
c <- make([]C.char, 4096)
|
||||
runtime.Gosched()
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for i := 0; i < 100; i++ {
|
||||
p := &(<-c)[0]
|
||||
mu.Lock()
|
||||
C.f(p)
|
||||
mu.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
|
@ -12,6 +12,11 @@ type Dep struct {
|
|||
X int
|
||||
}
|
||||
|
||||
func (d *Dep) Method() int {
|
||||
return 10
|
||||
}
|
||||
|
||||
func F() int {
|
||||
defer func() {}()
|
||||
return V
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,5 +3,6 @@ package main
|
|||
import "dep2"
|
||||
|
||||
func main() {
|
||||
dep2.W = dep2.G() + 1
|
||||
d := &dep2.Dep2{}
|
||||
dep2.W = dep2.G() + 1 + d.Method()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package bytes_test
|
|||
|
||||
import (
|
||||
. "bytes"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
|
@ -357,167 +358,152 @@ func TestIndexRune(t *testing.T) {
|
|||
|
||||
var bmbuf []byte
|
||||
|
||||
func BenchmarkIndexByte10(b *testing.B) { bmIndexByte(b, IndexByte, 10) }
|
||||
func BenchmarkIndexByte32(b *testing.B) { bmIndexByte(b, IndexByte, 32) }
|
||||
func BenchmarkIndexByte4K(b *testing.B) { bmIndexByte(b, IndexByte, 4<<10) }
|
||||
func BenchmarkIndexByte4M(b *testing.B) { bmIndexByte(b, IndexByte, 4<<20) }
|
||||
func BenchmarkIndexByte64M(b *testing.B) { bmIndexByte(b, IndexByte, 64<<20) }
|
||||
func BenchmarkIndexBytePortable10(b *testing.B) { bmIndexByte(b, IndexBytePortable, 10) }
|
||||
func BenchmarkIndexBytePortable32(b *testing.B) { bmIndexByte(b, IndexBytePortable, 32) }
|
||||
func BenchmarkIndexBytePortable4K(b *testing.B) { bmIndexByte(b, IndexBytePortable, 4<<10) }
|
||||
func BenchmarkIndexBytePortable4M(b *testing.B) { bmIndexByte(b, IndexBytePortable, 4<<20) }
|
||||
func BenchmarkIndexBytePortable64M(b *testing.B) { bmIndexByte(b, IndexBytePortable, 64<<20) }
|
||||
|
||||
func bmIndexByte(b *testing.B, index func([]byte, byte) int, n int) {
|
||||
if len(bmbuf) < n {
|
||||
bmbuf = make([]byte, n)
|
||||
func valName(x int) string {
|
||||
if s := x >> 20; s<<20 == x {
|
||||
return fmt.Sprintf("%dM", s)
|
||||
}
|
||||
b.SetBytes(int64(n))
|
||||
buf := bmbuf[0:n]
|
||||
buf[n-1] = 'x'
|
||||
for i := 0; i < b.N; i++ {
|
||||
j := index(buf, 'x')
|
||||
if j != n-1 {
|
||||
b.Fatal("bad index", j)
|
||||
}
|
||||
if s := x >> 10; s<<10 == x {
|
||||
return fmt.Sprintf("%dK", s)
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
return fmt.Sprint(x)
|
||||
}
|
||||
|
||||
func BenchmarkEqual0(b *testing.B) {
|
||||
var buf [4]byte
|
||||
buf1 := buf[0:0]
|
||||
buf2 := buf[1:1]
|
||||
for i := 0; i < b.N; i++ {
|
||||
eq := Equal(buf1, buf2)
|
||||
if !eq {
|
||||
b.Fatal("bad equal")
|
||||
}
|
||||
func benchBytes(b *testing.B, sizes []int, f func(b *testing.B, n int)) {
|
||||
for _, n := range sizes {
|
||||
b.Run(valName(n), func(b *testing.B) {
|
||||
if len(bmbuf) < n {
|
||||
bmbuf = make([]byte, n)
|
||||
}
|
||||
b.SetBytes(int64(n))
|
||||
f(b, n)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEqual1(b *testing.B) { bmEqual(b, Equal, 1) }
|
||||
func BenchmarkEqual6(b *testing.B) { bmEqual(b, Equal, 6) }
|
||||
func BenchmarkEqual9(b *testing.B) { bmEqual(b, Equal, 9) }
|
||||
func BenchmarkEqual15(b *testing.B) { bmEqual(b, Equal, 15) }
|
||||
func BenchmarkEqual16(b *testing.B) { bmEqual(b, Equal, 16) }
|
||||
func BenchmarkEqual20(b *testing.B) { bmEqual(b, Equal, 20) }
|
||||
func BenchmarkEqual32(b *testing.B) { bmEqual(b, Equal, 32) }
|
||||
func BenchmarkEqual4K(b *testing.B) { bmEqual(b, Equal, 4<<10) }
|
||||
func BenchmarkEqual4M(b *testing.B) { bmEqual(b, Equal, 4<<20) }
|
||||
func BenchmarkEqual64M(b *testing.B) { bmEqual(b, Equal, 64<<20) }
|
||||
func BenchmarkEqualPort1(b *testing.B) { bmEqual(b, EqualPortable, 1) }
|
||||
func BenchmarkEqualPort6(b *testing.B) { bmEqual(b, EqualPortable, 6) }
|
||||
func BenchmarkEqualPort32(b *testing.B) { bmEqual(b, EqualPortable, 32) }
|
||||
func BenchmarkEqualPort4K(b *testing.B) { bmEqual(b, EqualPortable, 4<<10) }
|
||||
func BenchmarkEqualPortable4M(b *testing.B) { bmEqual(b, EqualPortable, 4<<20) }
|
||||
func BenchmarkEqualPortable64M(b *testing.B) { bmEqual(b, EqualPortable, 64<<20) }
|
||||
var indexSizes = []int{10, 32, 4 << 10, 4 << 20, 64 << 20}
|
||||
|
||||
func bmEqual(b *testing.B, equal func([]byte, []byte) bool, n int) {
|
||||
if len(bmbuf) < 2*n {
|
||||
bmbuf = make([]byte, 2*n)
|
||||
}
|
||||
b.SetBytes(int64(n))
|
||||
buf1 := bmbuf[0:n]
|
||||
buf2 := bmbuf[n : 2*n]
|
||||
buf1[n-1] = 'x'
|
||||
buf2[n-1] = 'x'
|
||||
for i := 0; i < b.N; i++ {
|
||||
eq := equal(buf1, buf2)
|
||||
if !eq {
|
||||
b.Fatal("bad equal")
|
||||
}
|
||||
}
|
||||
buf1[n-1] = '\x00'
|
||||
buf2[n-1] = '\x00'
|
||||
func BenchmarkIndexByte(b *testing.B) {
|
||||
benchBytes(b, indexSizes, bmIndexByte(IndexByte))
|
||||
}
|
||||
|
||||
func BenchmarkIndex32(b *testing.B) { bmIndex(b, Index, 32) }
|
||||
func BenchmarkIndex4K(b *testing.B) { bmIndex(b, Index, 4<<10) }
|
||||
func BenchmarkIndex4M(b *testing.B) { bmIndex(b, Index, 4<<20) }
|
||||
func BenchmarkIndex64M(b *testing.B) { bmIndex(b, Index, 64<<20) }
|
||||
|
||||
func bmIndex(b *testing.B, index func([]byte, []byte) int, n int) {
|
||||
if len(bmbuf) < n {
|
||||
bmbuf = make([]byte, n)
|
||||
}
|
||||
b.SetBytes(int64(n))
|
||||
buf := bmbuf[0:n]
|
||||
buf[n-1] = 'x'
|
||||
for i := 0; i < b.N; i++ {
|
||||
j := index(buf, buf[n-7:])
|
||||
if j != n-7 {
|
||||
b.Fatal("bad index", j)
|
||||
}
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
func BenchmarkIndexBytePortable(b *testing.B) {
|
||||
benchBytes(b, indexSizes, bmIndexByte(IndexBytePortable))
|
||||
}
|
||||
|
||||
func BenchmarkIndexEasy32(b *testing.B) { bmIndexEasy(b, Index, 32) }
|
||||
func BenchmarkIndexEasy4K(b *testing.B) { bmIndexEasy(b, Index, 4<<10) }
|
||||
func BenchmarkIndexEasy4M(b *testing.B) { bmIndexEasy(b, Index, 4<<20) }
|
||||
func BenchmarkIndexEasy64M(b *testing.B) { bmIndexEasy(b, Index, 64<<20) }
|
||||
|
||||
func bmIndexEasy(b *testing.B, index func([]byte, []byte) int, n int) {
|
||||
if len(bmbuf) < n {
|
||||
bmbuf = make([]byte, n)
|
||||
}
|
||||
b.SetBytes(int64(n))
|
||||
buf := bmbuf[0:n]
|
||||
buf[n-1] = 'x'
|
||||
buf[n-7] = 'x'
|
||||
for i := 0; i < b.N; i++ {
|
||||
j := index(buf, buf[n-7:])
|
||||
if j != n-7 {
|
||||
b.Fatal("bad index", j)
|
||||
func bmIndexByte(index func([]byte, byte) int) func(b *testing.B, n int) {
|
||||
return func(b *testing.B, n int) {
|
||||
buf := bmbuf[0:n]
|
||||
buf[n-1] = 'x'
|
||||
for i := 0; i < b.N; i++ {
|
||||
j := index(buf, 'x')
|
||||
if j != n-1 {
|
||||
b.Fatal("bad index", j)
|
||||
}
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
buf[n-7] = '\x00'
|
||||
}
|
||||
|
||||
func BenchmarkCount32(b *testing.B) { bmCount(b, Count, 32) }
|
||||
func BenchmarkCount4K(b *testing.B) { bmCount(b, Count, 4<<10) }
|
||||
func BenchmarkCount4M(b *testing.B) { bmCount(b, Count, 4<<20) }
|
||||
func BenchmarkCount64M(b *testing.B) { bmCount(b, Count, 64<<20) }
|
||||
|
||||
func bmCount(b *testing.B, count func([]byte, []byte) int, n int) {
|
||||
if len(bmbuf) < n {
|
||||
bmbuf = make([]byte, n)
|
||||
}
|
||||
b.SetBytes(int64(n))
|
||||
buf := bmbuf[0:n]
|
||||
buf[n-1] = 'x'
|
||||
for i := 0; i < b.N; i++ {
|
||||
j := count(buf, buf[n-7:])
|
||||
if j != 1 {
|
||||
b.Fatal("bad count", j)
|
||||
func BenchmarkEqual(b *testing.B) {
|
||||
b.Run("0", func(b *testing.B) {
|
||||
var buf [4]byte
|
||||
buf1 := buf[0:0]
|
||||
buf2 := buf[1:1]
|
||||
for i := 0; i < b.N; i++ {
|
||||
eq := Equal(buf1, buf2)
|
||||
if !eq {
|
||||
b.Fatal("bad equal")
|
||||
}
|
||||
}
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
})
|
||||
|
||||
sizes := []int{1, 6, 9, 15, 16, 20, 32, 4 << 10, 4 << 20, 64 << 20}
|
||||
benchBytes(b, sizes, bmEqual(Equal))
|
||||
}
|
||||
|
||||
func BenchmarkCountEasy32(b *testing.B) { bmCountEasy(b, Count, 32) }
|
||||
func BenchmarkCountEasy4K(b *testing.B) { bmCountEasy(b, Count, 4<<10) }
|
||||
func BenchmarkCountEasy4M(b *testing.B) { bmCountEasy(b, Count, 4<<20) }
|
||||
func BenchmarkCountEasy64M(b *testing.B) { bmCountEasy(b, Count, 64<<20) }
|
||||
func BenchmarkEqualPort(b *testing.B) {
|
||||
sizes := []int{1, 6, 32, 4 << 10, 4 << 20, 64 << 20}
|
||||
benchBytes(b, sizes, bmEqual(EqualPortable))
|
||||
}
|
||||
|
||||
func bmCountEasy(b *testing.B, count func([]byte, []byte) int, n int) {
|
||||
if len(bmbuf) < n {
|
||||
bmbuf = make([]byte, n)
|
||||
}
|
||||
b.SetBytes(int64(n))
|
||||
buf := bmbuf[0:n]
|
||||
buf[n-1] = 'x'
|
||||
buf[n-7] = 'x'
|
||||
for i := 0; i < b.N; i++ {
|
||||
j := count(buf, buf[n-7:])
|
||||
if j != 1 {
|
||||
b.Fatal("bad count", j)
|
||||
func bmEqual(equal func([]byte, []byte) bool) func(b *testing.B, n int) {
|
||||
return func(b *testing.B, n int) {
|
||||
if len(bmbuf) < 2*n {
|
||||
bmbuf = make([]byte, 2*n)
|
||||
}
|
||||
buf1 := bmbuf[0:n]
|
||||
buf2 := bmbuf[n : 2*n]
|
||||
buf1[n-1] = 'x'
|
||||
buf2[n-1] = 'x'
|
||||
for i := 0; i < b.N; i++ {
|
||||
eq := equal(buf1, buf2)
|
||||
if !eq {
|
||||
b.Fatal("bad equal")
|
||||
}
|
||||
}
|
||||
buf1[n-1] = '\x00'
|
||||
buf2[n-1] = '\x00'
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
buf[n-7] = '\x00'
|
||||
}
|
||||
|
||||
func BenchmarkIndex(b *testing.B) {
|
||||
benchBytes(b, indexSizes, func(b *testing.B, n int) {
|
||||
buf := bmbuf[0:n]
|
||||
buf[n-1] = 'x'
|
||||
for i := 0; i < b.N; i++ {
|
||||
j := Index(buf, buf[n-7:])
|
||||
if j != n-7 {
|
||||
b.Fatal("bad index", j)
|
||||
}
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkIndexEasy(b *testing.B) {
|
||||
benchBytes(b, indexSizes, func(b *testing.B, n int) {
|
||||
buf := bmbuf[0:n]
|
||||
buf[n-1] = 'x'
|
||||
buf[n-7] = 'x'
|
||||
for i := 0; i < b.N; i++ {
|
||||
j := Index(buf, buf[n-7:])
|
||||
if j != n-7 {
|
||||
b.Fatal("bad index", j)
|
||||
}
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
buf[n-7] = '\x00'
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkCount(b *testing.B) {
|
||||
benchBytes(b, indexSizes, func(b *testing.B, n int) {
|
||||
buf := bmbuf[0:n]
|
||||
buf[n-1] = 'x'
|
||||
for i := 0; i < b.N; i++ {
|
||||
j := Count(buf, buf[n-7:])
|
||||
if j != 1 {
|
||||
b.Fatal("bad count", j)
|
||||
}
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkCountEasy(b *testing.B) {
|
||||
benchBytes(b, indexSizes, func(b *testing.B, n int) {
|
||||
buf := bmbuf[0:n]
|
||||
buf[n-1] = 'x'
|
||||
buf[n-7] = 'x'
|
||||
for i := 0; i < b.N; i++ {
|
||||
j := Count(buf, buf[n-7:])
|
||||
if j != 1 {
|
||||
b.Fatal("bad count", j)
|
||||
}
|
||||
}
|
||||
buf[n-1] = '\x00'
|
||||
buf[n-7] = '\x00'
|
||||
})
|
||||
}
|
||||
|
||||
type ExplodeTest struct {
|
||||
|
|
@ -1318,33 +1304,24 @@ func BenchmarkRepeat(b *testing.B) {
|
|||
}
|
||||
}
|
||||
|
||||
func benchmarkBytesCompare(b *testing.B, n int) {
|
||||
var x = make([]byte, n)
|
||||
var y = make([]byte, n)
|
||||
func BenchmarkBytesCompare(b *testing.B) {
|
||||
for n := 1; n <= 2048; n <<= 1 {
|
||||
b.Run(fmt.Sprint(n), func(b *testing.B) {
|
||||
var x = make([]byte, n)
|
||||
var y = make([]byte, n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
x[i] = 'a'
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
x[i] = 'a'
|
||||
}
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
y[i] = 'a'
|
||||
}
|
||||
for i := 0; i < n; i++ {
|
||||
y[i] = 'a'
|
||||
}
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Compare(x, y)
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Compare(x, y)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBytesCompare1(b *testing.B) { benchmarkBytesCompare(b, 1) }
|
||||
func BenchmarkBytesCompare2(b *testing.B) { benchmarkBytesCompare(b, 2) }
|
||||
func BenchmarkBytesCompare4(b *testing.B) { benchmarkBytesCompare(b, 4) }
|
||||
func BenchmarkBytesCompare8(b *testing.B) { benchmarkBytesCompare(b, 8) }
|
||||
func BenchmarkBytesCompare16(b *testing.B) { benchmarkBytesCompare(b, 16) }
|
||||
func BenchmarkBytesCompare32(b *testing.B) { benchmarkBytesCompare(b, 32) }
|
||||
func BenchmarkBytesCompare64(b *testing.B) { benchmarkBytesCompare(b, 64) }
|
||||
func BenchmarkBytesCompare128(b *testing.B) { benchmarkBytesCompare(b, 128) }
|
||||
func BenchmarkBytesCompare256(b *testing.B) { benchmarkBytesCompare(b, 256) }
|
||||
func BenchmarkBytesCompare512(b *testing.B) { benchmarkBytesCompare(b, 512) }
|
||||
func BenchmarkBytesCompare1024(b *testing.B) { benchmarkBytesCompare(b, 1024) }
|
||||
func BenchmarkBytesCompare2048(b *testing.B) { benchmarkBytesCompare(b, 2048) }
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ func main() {
|
|||
}
|
||||
|
||||
out, err := exec.Command("go", "tool", "api",
|
||||
"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6"),
|
||||
"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5", "go1.6", "go1.7"),
|
||||
"-next", file("next"),
|
||||
"-except", file("except")).CombinedOutput()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ func (f *File) saveExprs(x interface{}, context string) {
|
|||
f.saveRef(x, context)
|
||||
}
|
||||
case *ast.CallExpr:
|
||||
f.saveCall(x)
|
||||
f.saveCall(x, context)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -220,7 +220,7 @@ func (f *File) saveRef(n *ast.Expr, context string) {
|
|||
}
|
||||
|
||||
// Save calls to C.xxx for later processing.
|
||||
func (f *File) saveCall(call *ast.CallExpr) {
|
||||
func (f *File) saveCall(call *ast.CallExpr, context string) {
|
||||
sel, ok := call.Fun.(*ast.SelectorExpr)
|
||||
if !ok {
|
||||
return
|
||||
|
|
@ -228,7 +228,8 @@ func (f *File) saveCall(call *ast.CallExpr) {
|
|||
if l, ok := sel.X.(*ast.Ident); !ok || l.Name != "C" {
|
||||
return
|
||||
}
|
||||
f.Calls = append(f.Calls, call)
|
||||
c := &Call{Call: call, Deferred: context == "defer"}
|
||||
f.Calls = append(f.Calls, c)
|
||||
}
|
||||
|
||||
// If a function should be exported add it to ExpFunc.
|
||||
|
|
@ -401,7 +402,7 @@ func (f *File) walk(x interface{}, context string, visit func(*File, interface{}
|
|||
case *ast.GoStmt:
|
||||
f.walk(n.Call, "expr", visit)
|
||||
case *ast.DeferStmt:
|
||||
f.walk(n.Call, "expr", visit)
|
||||
f.walk(n.Call, "defer", visit)
|
||||
case *ast.ReturnStmt:
|
||||
f.walk(n.Results, "expr", visit)
|
||||
case *ast.BranchStmt:
|
||||
|
|
|
|||
|
|
@ -581,7 +581,7 @@ func (p *Package) mangleName(n *Name) {
|
|||
func (p *Package) rewriteCalls(f *File) {
|
||||
for _, call := range f.Calls {
|
||||
// This is a call to C.xxx; set goname to "xxx".
|
||||
goname := call.Fun.(*ast.SelectorExpr).Sel.Name
|
||||
goname := call.Call.Fun.(*ast.SelectorExpr).Sel.Name
|
||||
if goname == "malloc" {
|
||||
continue
|
||||
}
|
||||
|
|
@ -596,37 +596,58 @@ func (p *Package) rewriteCalls(f *File) {
|
|||
|
||||
// rewriteCall rewrites one call to add pointer checks. We replace
|
||||
// each pointer argument x with _cgoCheckPointer(x).(T).
|
||||
func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
|
||||
func (p *Package) rewriteCall(f *File, call *Call, name *Name) {
|
||||
any := false
|
||||
for i, param := range name.FuncType.Params {
|
||||
if len(call.Args) <= i {
|
||||
if len(call.Call.Args) <= i {
|
||||
// Avoid a crash; this will be caught when the
|
||||
// generated file is compiled.
|
||||
return
|
||||
}
|
||||
if p.needsPointerCheck(f, param.Go, call.Call.Args[i]) {
|
||||
any = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !any {
|
||||
return
|
||||
}
|
||||
|
||||
// An untyped nil does not need a pointer check, and
|
||||
// when _cgoCheckPointer returns the untyped nil the
|
||||
// type assertion we are going to insert will fail.
|
||||
// Easier to just skip nil arguments.
|
||||
// TODO: Note that this fails if nil is shadowed.
|
||||
if id, ok := call.Args[i].(*ast.Ident); ok && id.Name == "nil" {
|
||||
continue
|
||||
// We need to rewrite this call.
|
||||
//
|
||||
// We are going to rewrite C.f(p) to C.f(_cgoCheckPointer(p)).
|
||||
// If the call to C.f is deferred, that will check p at the
|
||||
// point of the defer statement, not when the function is called, so
|
||||
// rewrite to func(_cgo0 ptype) { C.f(_cgoCheckPointer(_cgo0)) }(p)
|
||||
|
||||
var dargs []ast.Expr
|
||||
if call.Deferred {
|
||||
dargs = make([]ast.Expr, len(name.FuncType.Params))
|
||||
}
|
||||
for i, param := range name.FuncType.Params {
|
||||
origArg := call.Call.Args[i]
|
||||
darg := origArg
|
||||
|
||||
if call.Deferred {
|
||||
dargs[i] = darg
|
||||
darg = ast.NewIdent(fmt.Sprintf("_cgo%d", i))
|
||||
call.Call.Args[i] = darg
|
||||
}
|
||||
|
||||
if !p.needsPointerCheck(f, param.Go) {
|
||||
if !p.needsPointerCheck(f, param.Go, origArg) {
|
||||
continue
|
||||
}
|
||||
|
||||
c := &ast.CallExpr{
|
||||
Fun: ast.NewIdent("_cgoCheckPointer"),
|
||||
Args: []ast.Expr{
|
||||
call.Args[i],
|
||||
darg,
|
||||
},
|
||||
}
|
||||
|
||||
// Add optional additional arguments for an address
|
||||
// expression.
|
||||
c.Args = p.checkAddrArgs(f, c.Args, call.Args[i])
|
||||
c.Args = p.checkAddrArgs(f, c.Args, origArg)
|
||||
|
||||
// _cgoCheckPointer returns interface{}.
|
||||
// We need to type assert that to the type we want.
|
||||
|
|
@ -636,7 +657,7 @@ func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
|
|||
// Instead we use a local variant of _cgoCheckPointer.
|
||||
|
||||
var arg ast.Expr
|
||||
if n := p.unsafeCheckPointerName(param.Go); n != "" {
|
||||
if n := p.unsafeCheckPointerName(param.Go, call.Deferred); n != "" {
|
||||
c.Fun = ast.NewIdent(n)
|
||||
arg = c
|
||||
} else {
|
||||
|
|
@ -664,14 +685,73 @@ func (p *Package) rewriteCall(f *File, call *ast.CallExpr, name *Name) {
|
|||
}
|
||||
}
|
||||
|
||||
call.Args[i] = arg
|
||||
call.Call.Args[i] = arg
|
||||
}
|
||||
|
||||
if call.Deferred {
|
||||
params := make([]*ast.Field, len(name.FuncType.Params))
|
||||
for i, param := range name.FuncType.Params {
|
||||
ptype := param.Go
|
||||
if p.hasUnsafePointer(ptype) {
|
||||
// Avoid generating unsafe.Pointer by using
|
||||
// interface{}. This works because we are
|
||||
// going to call a _cgoCheckPointer function
|
||||
// anyhow.
|
||||
ptype = &ast.InterfaceType{
|
||||
Methods: &ast.FieldList{},
|
||||
}
|
||||
}
|
||||
params[i] = &ast.Field{
|
||||
Names: []*ast.Ident{
|
||||
ast.NewIdent(fmt.Sprintf("_cgo%d", i)),
|
||||
},
|
||||
Type: ptype,
|
||||
}
|
||||
}
|
||||
|
||||
dbody := &ast.CallExpr{
|
||||
Fun: call.Call.Fun,
|
||||
Args: call.Call.Args,
|
||||
}
|
||||
call.Call.Fun = &ast.FuncLit{
|
||||
Type: &ast.FuncType{
|
||||
Params: &ast.FieldList{
|
||||
List: params,
|
||||
},
|
||||
},
|
||||
Body: &ast.BlockStmt{
|
||||
List: []ast.Stmt{
|
||||
&ast.ExprStmt{
|
||||
X: dbody,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
call.Call.Args = dargs
|
||||
call.Call.Lparen = token.NoPos
|
||||
call.Call.Rparen = token.NoPos
|
||||
|
||||
// There is a Ref pointing to the old call.Call.Fun.
|
||||
for _, ref := range f.Ref {
|
||||
if ref.Expr == &call.Call.Fun {
|
||||
ref.Expr = &dbody.Fun
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// needsPointerCheck returns whether the type t needs a pointer check.
|
||||
// This is true if t is a pointer and if the value to which it points
|
||||
// might contain a pointer.
|
||||
func (p *Package) needsPointerCheck(f *File, t ast.Expr) bool {
|
||||
func (p *Package) needsPointerCheck(f *File, t ast.Expr, arg ast.Expr) bool {
|
||||
// An untyped nil does not need a pointer check, and when
|
||||
// _cgoCheckPointer returns the untyped nil the type assertion we
|
||||
// are going to insert will fail. Easier to just skip nil arguments.
|
||||
// TODO: Note that this fails if nil is shadowed.
|
||||
if id, ok := arg.(*ast.Ident); ok && id.Name == "nil" {
|
||||
return false
|
||||
}
|
||||
|
||||
return p.hasPointer(f, t, true)
|
||||
}
|
||||
|
||||
|
|
@ -859,20 +939,31 @@ func (p *Package) isType(t ast.Expr) bool {
|
|||
// assertion to unsafe.Pointer in our copy of user code. We return
|
||||
// the name of the _cgoCheckPointer function we are going to build, or
|
||||
// the empty string if the type does not use unsafe.Pointer.
|
||||
func (p *Package) unsafeCheckPointerName(t ast.Expr) string {
|
||||
//
|
||||
// The deferred parameter is true if this check is for the argument of
|
||||
// a deferred function. In that case we need to use an empty interface
|
||||
// as the argument type, because the deferred function we introduce in
|
||||
// rewriteCall will use an empty interface type, and we can't add a
|
||||
// type assertion. This is handled by keeping a separate list, and
|
||||
// writing out the lists separately in writeDefs.
|
||||
func (p *Package) unsafeCheckPointerName(t ast.Expr, deferred bool) string {
|
||||
if !p.hasUnsafePointer(t) {
|
||||
return ""
|
||||
}
|
||||
var buf bytes.Buffer
|
||||
conf.Fprint(&buf, fset, t)
|
||||
s := buf.String()
|
||||
for i, t := range p.CgoChecks {
|
||||
checks := &p.CgoChecks
|
||||
if deferred {
|
||||
checks = &p.DeferredCgoChecks
|
||||
}
|
||||
for i, t := range *checks {
|
||||
if s == t {
|
||||
return p.unsafeCheckPointerNameIndex(i)
|
||||
return p.unsafeCheckPointerNameIndex(i, deferred)
|
||||
}
|
||||
}
|
||||
p.CgoChecks = append(p.CgoChecks, s)
|
||||
return p.unsafeCheckPointerNameIndex(len(p.CgoChecks) - 1)
|
||||
*checks = append(*checks, s)
|
||||
return p.unsafeCheckPointerNameIndex(len(*checks)-1, deferred)
|
||||
}
|
||||
|
||||
// hasUnsafePointer returns whether the Go type t uses unsafe.Pointer.
|
||||
|
|
@ -900,7 +991,10 @@ func (p *Package) hasUnsafePointer(t ast.Expr) bool {
|
|||
|
||||
// unsafeCheckPointerNameIndex returns the name to use for a
|
||||
// _cgoCheckPointer variant based on the index in the CgoChecks slice.
|
||||
func (p *Package) unsafeCheckPointerNameIndex(i int) string {
|
||||
func (p *Package) unsafeCheckPointerNameIndex(i int, deferred bool) string {
|
||||
if deferred {
|
||||
return fmt.Sprintf("_cgoCheckPointerInDefer%d", i)
|
||||
}
|
||||
return fmt.Sprintf("_cgoCheckPointer%d", i)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,10 @@ type Package struct {
|
|||
GoFiles []string // list of Go files
|
||||
GccFiles []string // list of gcc output files
|
||||
Preamble string // collected preamble for _cgo_export.h
|
||||
CgoChecks []string // see unsafeCheckPointerName
|
||||
|
||||
// See unsafeCheckPointerName.
|
||||
CgoChecks []string
|
||||
DeferredCgoChecks []string
|
||||
}
|
||||
|
||||
// A File collects information about a single Go input file.
|
||||
|
|
@ -52,7 +55,7 @@ type File struct {
|
|||
Package string // Package name
|
||||
Preamble string // C preamble (doc comment on import "C")
|
||||
Ref []*Ref // all references to C.xxx in AST
|
||||
Calls []*ast.CallExpr // all calls to C.xxx in AST
|
||||
Calls []*Call // all calls to C.xxx in AST
|
||||
ExpFunc []*ExpFunc // exported functions for this file
|
||||
Name map[string]*Name // map from Go name to Name
|
||||
}
|
||||
|
|
@ -66,6 +69,12 @@ func nameKeys(m map[string]*Name) []string {
|
|||
return ks
|
||||
}
|
||||
|
||||
// A Call refers to a call of a C.xxx function in the AST.
|
||||
type Call struct {
|
||||
Call *ast.CallExpr
|
||||
Deferred bool
|
||||
}
|
||||
|
||||
// A Ref refers to an expression of the form C.xxx in the AST.
|
||||
type Ref struct {
|
||||
Name *Name
|
||||
|
|
|
|||
|
|
@ -112,7 +112,13 @@ func (p *Package) writeDefs() {
|
|||
}
|
||||
|
||||
for i, t := range p.CgoChecks {
|
||||
n := p.unsafeCheckPointerNameIndex(i)
|
||||
n := p.unsafeCheckPointerNameIndex(i, false)
|
||||
fmt.Fprintf(fgo2, "\nfunc %s(p %s, args ...interface{}) %s {\n", n, t, t)
|
||||
fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
|
||||
fmt.Fprintf(fgo2, "}\n")
|
||||
}
|
||||
for i, t := range p.DeferredCgoChecks {
|
||||
n := p.unsafeCheckPointerNameIndex(i, true)
|
||||
fmt.Fprintf(fgo2, "\nfunc %s(p interface{}, args ...interface{}) %s {\n", n, t)
|
||||
fmt.Fprintf(fgo2, "\treturn _cgoCheckPointer(p, args...).(%s)\n", t)
|
||||
fmt.Fprintf(fgo2, "}\n")
|
||||
|
|
@ -1324,6 +1330,7 @@ const noTsanProlog = `
|
|||
#define _cgo_tsan_release()
|
||||
`
|
||||
|
||||
// This must match the TSAN code in runtime/cgo/libcgo.h.
|
||||
const yesTsanProlog = `
|
||||
#define CGO_NO_SANITIZE_THREAD __attribute__ ((no_sanitize_thread))
|
||||
|
||||
|
|
@ -1332,10 +1339,12 @@ long long _cgo_sync __attribute__ ((common));
|
|||
extern void __tsan_acquire(void*);
|
||||
extern void __tsan_release(void*);
|
||||
|
||||
__attribute__ ((unused))
|
||||
static void _cgo_tsan_acquire() {
|
||||
__tsan_acquire(&_cgo_sync);
|
||||
}
|
||||
|
||||
__attribute__ ((unused))
|
||||
static void _cgo_tsan_release() {
|
||||
__tsan_release(&_cgo_sync);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -341,6 +341,11 @@ func clearfat(nl *gc.Node) {
|
|||
c := w % 4 // bytes
|
||||
q := w / 4 // quads
|
||||
|
||||
if nl.Type.Align < 4 {
|
||||
q = 0
|
||||
c = w
|
||||
}
|
||||
|
||||
var r0 gc.Node
|
||||
r0.Op = gc.OREGISTER
|
||||
|
||||
|
|
@ -395,6 +400,27 @@ func clearfat(nl *gc.Node) {
|
|||
}
|
||||
}
|
||||
|
||||
if c > 4 {
|
||||
// Loop to zero unaligned memory.
|
||||
var end gc.Node
|
||||
gc.Regalloc(&end, gc.Types[gc.Tptr], nil)
|
||||
p := gins(arm.AMOVW, &dst, &end)
|
||||
p.From.Type = obj.TYPE_ADDR
|
||||
p.From.Offset = int64(c)
|
||||
|
||||
p = gins(arm.AMOVB, &nz, &dst)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Offset = 1
|
||||
p.Scond |= arm.C_PBIT
|
||||
pl := p
|
||||
|
||||
p = gins(arm.ACMP, &dst, nil)
|
||||
raddr(&end, p)
|
||||
gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), pl)
|
||||
|
||||
gc.Regfree(&end)
|
||||
c = 0
|
||||
}
|
||||
var p *obj.Prog
|
||||
for c > 0 {
|
||||
p = gins(arm.AMOVB, &nz, &dst)
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ func compileToAsm(dir, arch, pkg string) string {
|
|||
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd := exec.Command("go", "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src)
|
||||
cmd.Env = append(cmd.Env, "GOARCH="+arch)
|
||||
cmd.Env = mergeEnvLists([]string{"GOARCH=" + arch}, os.Environ())
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
|
|
@ -103,3 +103,22 @@ func f(x int) int {
|
|||
[]string{"\tSHLQ\t\\$5,", "\tLEAQ\t\\(.*\\)\\(.*\\*2\\),"},
|
||||
},
|
||||
}
|
||||
|
||||
// mergeEnvLists merges the two environment lists such that
|
||||
// variables with the same name in "in" replace those in "out".
|
||||
// This always returns a newly allocated slice.
|
||||
func mergeEnvLists(in, out []string) []string {
|
||||
out = append([]string(nil), out...)
|
||||
NextVar:
|
||||
for _, inkv := range in {
|
||||
k := strings.SplitAfterN(inkv, "=", 2)[0]
|
||||
for i, outkv := range out {
|
||||
if strings.HasPrefix(outkv, k) {
|
||||
out[i] = inkv
|
||||
continue NextVar
|
||||
}
|
||||
}
|
||||
out = append(out, inkv)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
|
|
|||
|
|
@ -622,6 +622,8 @@ func isInlineable(n *Node) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
var errorInterface *Type // lazily initialized
|
||||
|
||||
func (p *exporter) typ(t *Type) {
|
||||
if t == nil {
|
||||
Fatalf("exporter: nil type")
|
||||
|
|
@ -673,7 +675,19 @@ func (p *exporter) typ(t *Type) {
|
|||
p.qualifiedName(tsym)
|
||||
|
||||
// write underlying type
|
||||
p.typ(t.Orig)
|
||||
orig := t.Orig
|
||||
if orig == errortype {
|
||||
// The error type is the only predeclared type which has
|
||||
// a composite underlying type. When we encode that type,
|
||||
// make sure to encode the underlying interface rather than
|
||||
// the named type again. See also the comment in universe.go
|
||||
// regarding the errortype and issue #15920.
|
||||
if errorInterface == nil {
|
||||
errorInterface = makeErrorInterface()
|
||||
}
|
||||
orig = errorInterface
|
||||
}
|
||||
p.typ(orig)
|
||||
|
||||
// interfaces don't have associated methods
|
||||
if t.Orig.IsInterface() {
|
||||
|
|
|
|||
|
|
@ -2855,11 +2855,6 @@ func cgen_append(n, res *Node) {
|
|||
Dump("cgen_append-n", n)
|
||||
Dump("cgen_append-res", res)
|
||||
}
|
||||
if res.Op != ONAME && !samesafeexpr(res, n.List.First()) {
|
||||
Dump("cgen_append-n", n)
|
||||
Dump("cgen_append-res", res)
|
||||
Fatalf("append not lowered")
|
||||
}
|
||||
for _, n1 := range n.List.Slice() {
|
||||
if n1.Ullman >= UINF {
|
||||
Fatalf("append with function call arguments")
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package gc
|
||||
|
||||
import "testing"
|
||||
|
||||
type T struct {
|
||||
x [2]int64 // field that will be clobbered. Also makes type not SSAable.
|
||||
p *byte // has a pointer
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func makeT() T {
|
||||
return T{}
|
||||
}
|
||||
|
||||
var g T
|
||||
|
||||
var sink []byte
|
||||
|
||||
func TestIssue15854(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
if g.x[0] != 0 {
|
||||
t.Fatalf("g.x[0] clobbered with %x\n", g.x[0])
|
||||
}
|
||||
// The bug was in the following assignment. The return
|
||||
// value of makeT() is not copied out of the args area of
|
||||
// stack frame in a timely fashion. So when write barriers
|
||||
// are enabled, the marshaling of the args for the write
|
||||
// barrier call clobbers the result of makeT() before it is
|
||||
// read by the write barrier code.
|
||||
g = makeT()
|
||||
sink = make([]byte, 1000) // force write barriers to eventually happen
|
||||
}
|
||||
}
|
||||
func TestIssue15854b(t *testing.T) {
|
||||
const N = 10000
|
||||
a := make([]T, N)
|
||||
for i := 0; i < N; i++ {
|
||||
a = append(a, makeT())
|
||||
sink = make([]byte, 1000) // force write barriers to eventually happen
|
||||
}
|
||||
for i, v := range a {
|
||||
if v.x[0] != 0 {
|
||||
t.Fatalf("a[%d].x[0] clobbered with %x\n", i, v.x[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -156,6 +156,8 @@ var Debug_typeassert int
|
|||
|
||||
var localpkg *Pkg // package being compiled
|
||||
|
||||
var autopkg *Pkg // fake package for allocating auto variables
|
||||
|
||||
var importpkg *Pkg // package being imported
|
||||
|
||||
var itabpkg *Pkg // fake pkg for itab entries
|
||||
|
|
|
|||
|
|
@ -108,6 +108,8 @@ func Main() {
|
|||
|
||||
localpkg = mkpkg("")
|
||||
localpkg.Prefix = "\"\""
|
||||
autopkg = mkpkg("")
|
||||
autopkg.Prefix = "\"\""
|
||||
|
||||
// pseudo-package, for scoping
|
||||
builtinpkg = mkpkg("go.builtin")
|
||||
|
|
|
|||
|
|
@ -577,6 +577,15 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini
|
|||
|
||||
return
|
||||
}
|
||||
if prog.As == obj.AJMP && prog.To.Type == obj.TYPE_MEM && prog.To.Name == obj.NAME_EXTERN {
|
||||
// This is a tail call. Ensure the arguments are still alive.
|
||||
// See issue 16016.
|
||||
for i, node := range vars {
|
||||
if node.Class == PPARAM {
|
||||
bvset(uevar, int32(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if prog.As == obj.ATEXT {
|
||||
// A text instruction marks the entry point to a function and
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ func instrumentnode(np **Node, init *Nodes, wr int, skip int) {
|
|||
var outn Nodes
|
||||
outn.Set(out)
|
||||
instrumentnode(&ls[i], &outn, 0, 0)
|
||||
if ls[i].Op != OAS || ls[i].Ninit.Len() == 0 {
|
||||
if ls[i].Op != OAS && ls[i].Op != OASWB && ls[i].Op != OAS2FUNC || ls[i].Ninit.Len() == 0 {
|
||||
out = append(outn.Slice(), ls[i])
|
||||
} else {
|
||||
// Splice outn onto end of ls[i].Ninit
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -580,8 +580,8 @@ func (s *state) stmt(n *Node) {
|
|||
|
||||
case OAS2DOTTYPE:
|
||||
res, resok := s.dottype(n.Rlist.First(), true)
|
||||
s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), false, n.Lineno, 0)
|
||||
s.assign(n.List.Second(), resok, false, false, n.Lineno, 0)
|
||||
s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), false, n.Lineno, 0, false)
|
||||
s.assign(n.List.Second(), resok, false, false, n.Lineno, 0, false)
|
||||
return
|
||||
|
||||
case ODCL:
|
||||
|
|
@ -700,13 +700,14 @@ func (s *state) stmt(n *Node) {
|
|||
}
|
||||
}
|
||||
var r *ssa.Value
|
||||
var isVolatile bool
|
||||
needwb := n.Op == OASWB && rhs != nil
|
||||
deref := !canSSAType(t)
|
||||
if deref {
|
||||
if rhs == nil {
|
||||
r = nil // Signal assign to use OpZero.
|
||||
} else {
|
||||
r = s.addr(rhs, false)
|
||||
r, isVolatile = s.addr(rhs, false)
|
||||
}
|
||||
} else {
|
||||
if rhs == nil {
|
||||
|
|
@ -755,7 +756,7 @@ func (s *state) stmt(n *Node) {
|
|||
}
|
||||
}
|
||||
|
||||
s.assign(n.Left, r, needwb, deref, n.Lineno, skip)
|
||||
s.assign(n.Left, r, needwb, deref, n.Lineno, skip, isVolatile)
|
||||
|
||||
case OIF:
|
||||
bThen := s.f.NewBlock(ssa.BlockPlain)
|
||||
|
|
@ -1449,10 +1450,10 @@ func (s *state) expr(n *Node) *ssa.Value {
|
|||
if s.canSSA(n) {
|
||||
return s.variable(n, n.Type)
|
||||
}
|
||||
addr := s.addr(n, false)
|
||||
addr, _ := s.addr(n, false)
|
||||
return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
|
||||
case OCLOSUREVAR:
|
||||
addr := s.addr(n, false)
|
||||
addr, _ := s.addr(n, false)
|
||||
return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
|
||||
case OLITERAL:
|
||||
switch u := n.Val().U.(type) {
|
||||
|
|
@ -1926,7 +1927,9 @@ func (s *state) expr(n *Node) *ssa.Value {
|
|||
return s.expr(n.Left)
|
||||
|
||||
case OADDR:
|
||||
return s.addr(n.Left, n.Bounded)
|
||||
a, _ := s.addr(n.Left, n.Bounded)
|
||||
// Note we know the volatile result is false because you can't write &f() in Go.
|
||||
return a
|
||||
|
||||
case OINDREG:
|
||||
if int(n.Reg) != Thearch.REGSP {
|
||||
|
|
@ -1946,7 +1949,7 @@ func (s *state) expr(n *Node) *ssa.Value {
|
|||
v := s.expr(n.Left)
|
||||
return s.newValue1I(ssa.OpStructSelect, n.Type, int64(fieldIdx(n)), v)
|
||||
}
|
||||
p := s.addr(n, false)
|
||||
p, _ := s.addr(n, false)
|
||||
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
|
||||
|
||||
case ODOTPTR:
|
||||
|
|
@ -1973,11 +1976,11 @@ func (s *state) expr(n *Node) *ssa.Value {
|
|||
}
|
||||
return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
|
||||
case n.Left.Type.IsSlice():
|
||||
p := s.addr(n, false)
|
||||
p, _ := s.addr(n, false)
|
||||
return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
|
||||
case n.Left.Type.IsArray():
|
||||
// TODO: fix when we can SSA arrays of length 1.
|
||||
p := s.addr(n, false)
|
||||
p, _ := s.addr(n, false)
|
||||
return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
|
||||
default:
|
||||
s.Fatalf("bad type for index %v", n.Left.Type)
|
||||
|
|
@ -2142,7 +2145,7 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
|
|||
|
||||
var slice, addr *ssa.Value
|
||||
if inplace {
|
||||
addr = s.addr(sn, false)
|
||||
addr, _ = s.addr(sn, false)
|
||||
slice = s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
|
||||
} else {
|
||||
slice = s.expr(sn)
|
||||
|
|
@ -2213,15 +2216,21 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
|
|||
}
|
||||
|
||||
// Evaluate args
|
||||
args := make([]*ssa.Value, 0, nargs)
|
||||
store := make([]bool, 0, nargs)
|
||||
type argRec struct {
|
||||
// if store is true, we're appending the value v. If false, we're appending the
|
||||
// value at *v. If store==false, isVolatile reports whether the source
|
||||
// is in the outargs section of the stack frame.
|
||||
v *ssa.Value
|
||||
store bool
|
||||
isVolatile bool
|
||||
}
|
||||
args := make([]argRec, 0, nargs)
|
||||
for _, n := range n.List.Slice()[1:] {
|
||||
if canSSAType(n.Type) {
|
||||
args = append(args, s.expr(n))
|
||||
store = append(store, true)
|
||||
args = append(args, argRec{v: s.expr(n), store: true})
|
||||
} else {
|
||||
args = append(args, s.addr(n, false))
|
||||
store = append(store, false)
|
||||
v, isVolatile := s.addr(n, false)
|
||||
args = append(args, argRec{v: v, isVolatile: isVolatile})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2235,17 +2244,17 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
|
|||
// TODO: maybe just one writeBarrier.enabled check?
|
||||
for i, arg := range args {
|
||||
addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
|
||||
if store[i] {
|
||||
if arg.store {
|
||||
if haspointers(et) {
|
||||
s.insertWBstore(et, addr, arg, n.Lineno, 0)
|
||||
s.insertWBstore(et, addr, arg.v, n.Lineno, 0)
|
||||
} else {
|
||||
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
|
||||
s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg.v, s.mem())
|
||||
}
|
||||
} else {
|
||||
if haspointers(et) {
|
||||
s.insertWBmove(et, addr, arg, n.Lineno)
|
||||
s.insertWBmove(et, addr, arg.v, n.Lineno, arg.isVolatile)
|
||||
} else {
|
||||
s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
|
||||
s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg.v, s.mem())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2317,9 +2326,10 @@ const (
|
|||
// Right has already been evaluated to ssa, left has not.
|
||||
// If deref is true, then we do left = *right instead (and right has already been nil-checked).
|
||||
// If deref is true and right == nil, just do left = 0.
|
||||
// If deref is true, rightIsVolatile reports whether right points to volatile (clobbered by a call) storage.
|
||||
// Include a write barrier if wb is true.
|
||||
// skip indicates assignments (at the top level) that can be avoided.
|
||||
func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, skip skipMask) {
|
||||
func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, skip skipMask, rightIsVolatile bool) {
|
||||
if left.Op == ONAME && isblank(left) {
|
||||
return
|
||||
}
|
||||
|
|
@ -2360,7 +2370,7 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32,
|
|||
}
|
||||
|
||||
// Recursively assign the new value we've made to the base of the dot op.
|
||||
s.assign(left.Left, new, false, false, line, 0)
|
||||
s.assign(left.Left, new, false, false, line, 0, rightIsVolatile)
|
||||
// TODO: do we need to update named values here?
|
||||
return
|
||||
}
|
||||
|
|
@ -2370,7 +2380,7 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32,
|
|||
return
|
||||
}
|
||||
// Left is not ssa-able. Compute its address.
|
||||
addr := s.addr(left, false)
|
||||
addr, _ := s.addr(left, false)
|
||||
if left.Op == ONAME && skip == 0 {
|
||||
s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
|
||||
}
|
||||
|
|
@ -2381,7 +2391,7 @@ func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32,
|
|||
return
|
||||
}
|
||||
if wb {
|
||||
s.insertWBmove(t, addr, right, line)
|
||||
s.insertWBmove(t, addr, right, line, rightIsVolatile)
|
||||
return
|
||||
}
|
||||
s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), addr, right, s.mem())
|
||||
|
|
@ -2579,6 +2589,9 @@ func (s *state) call(n *Node, k callKind) *ssa.Value {
|
|||
}
|
||||
i := s.expr(fn.Left)
|
||||
itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
|
||||
if k != callNormal {
|
||||
s.nilCheck(itab)
|
||||
}
|
||||
itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
|
||||
itab = s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), itabidx, itab)
|
||||
if k == callNormal {
|
||||
|
|
@ -2702,10 +2715,12 @@ func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
|
|||
}
|
||||
|
||||
// addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
|
||||
// Also returns a bool reporting whether the returned value is "volatile", that is it
|
||||
// points to the outargs section and thus the referent will be clobbered by any call.
|
||||
// The value that the returned Value represents is guaranteed to be non-nil.
|
||||
// If bounded is true then this address does not require a nil check for its operand
|
||||
// even if that would otherwise be implied.
|
||||
func (s *state) addr(n *Node, bounded bool) *ssa.Value {
|
||||
func (s *state) addr(n *Node, bounded bool) (*ssa.Value, bool) {
|
||||
t := Ptrto(n.Type)
|
||||
switch n.Op {
|
||||
case ONAME:
|
||||
|
|
@ -2718,41 +2733,41 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value {
|
|||
if n.Xoffset != 0 {
|
||||
v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
|
||||
}
|
||||
return v
|
||||
return v, false
|
||||
case PPARAM:
|
||||
// parameter slot
|
||||
v := s.decladdrs[n]
|
||||
if v != nil {
|
||||
return v
|
||||
return v, false
|
||||
}
|
||||
if n.String() == ".fp" {
|
||||
// Special arg that points to the frame pointer.
|
||||
// (Used by the race detector, others?)
|
||||
aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
|
||||
return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
|
||||
return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp), false
|
||||
}
|
||||
s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
|
||||
return nil
|
||||
return nil, false
|
||||
case PAUTO:
|
||||
aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
|
||||
return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
|
||||
return s.newValue1A(ssa.OpAddr, t, aux, s.sp), false
|
||||
case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
|
||||
// ensure that we reuse symbols for out parameters so
|
||||
// that cse works on their addresses
|
||||
aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
|
||||
return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
|
||||
return s.newValue1A(ssa.OpAddr, t, aux, s.sp), false
|
||||
default:
|
||||
s.Unimplementedf("variable address class %v not implemented", classnames[n.Class])
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
case OINDREG:
|
||||
// indirect off a register
|
||||
// used for storing/loading arguments/returns to/from callees
|
||||
if int(n.Reg) != Thearch.REGSP {
|
||||
s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp)
|
||||
return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp), true
|
||||
case OINDEX:
|
||||
if n.Left.Type.IsSlice() {
|
||||
a := s.expr(n.Left)
|
||||
|
|
@ -2763,37 +2778,37 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value {
|
|||
s.boundsCheck(i, len)
|
||||
}
|
||||
p := s.newValue1(ssa.OpSlicePtr, t, a)
|
||||
return s.newValue2(ssa.OpPtrIndex, t, p, i)
|
||||
return s.newValue2(ssa.OpPtrIndex, t, p, i), false
|
||||
} else { // array
|
||||
a := s.addr(n.Left, bounded)
|
||||
a, isVolatile := s.addr(n.Left, bounded)
|
||||
i := s.expr(n.Right)
|
||||
i = s.extendIndex(i, Panicindex)
|
||||
len := s.constInt(Types[TINT], n.Left.Type.NumElem())
|
||||
if !n.Bounded {
|
||||
s.boundsCheck(i, len)
|
||||
}
|
||||
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i)
|
||||
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i), isVolatile
|
||||
}
|
||||
case OIND:
|
||||
return s.exprPtr(n.Left, bounded, n.Lineno)
|
||||
return s.exprPtr(n.Left, bounded, n.Lineno), false
|
||||
case ODOT:
|
||||
p := s.addr(n.Left, bounded)
|
||||
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
|
||||
p, isVolatile := s.addr(n.Left, bounded)
|
||||
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), isVolatile
|
||||
case ODOTPTR:
|
||||
p := s.exprPtr(n.Left, bounded, n.Lineno)
|
||||
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
|
||||
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p), false
|
||||
case OCLOSUREVAR:
|
||||
return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
|
||||
s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])))
|
||||
s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8]))), false
|
||||
case OCONVNOP:
|
||||
addr := s.addr(n.Left, bounded)
|
||||
return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
|
||||
addr, isVolatile := s.addr(n.Left, bounded)
|
||||
return s.newValue1(ssa.OpCopy, t, addr), isVolatile // ensure that addr has the right type
|
||||
case OCALLFUNC, OCALLINTER, OCALLMETH:
|
||||
return s.call(n, callNormal)
|
||||
return s.call(n, callNormal), true
|
||||
|
||||
default:
|
||||
s.Unimplementedf("unhandled addr %v", n.Op)
|
||||
return nil
|
||||
return nil, false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3023,7 +3038,7 @@ func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Val
|
|||
|
||||
// insertWBmove inserts the assignment *left = *right including a write barrier.
|
||||
// t is the type being assigned.
|
||||
func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32) {
|
||||
func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32, rightIsVolatile bool) {
|
||||
// if writeBarrier.enabled {
|
||||
// typedmemmove(&t, left, right)
|
||||
// } else {
|
||||
|
|
@ -3053,8 +3068,25 @@ func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32) {
|
|||
b.AddEdgeTo(bElse)
|
||||
|
||||
s.startBlock(bThen)
|
||||
taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}, s.sb)
|
||||
s.rtcall(typedmemmove, true, nil, taddr, left, right)
|
||||
|
||||
if !rightIsVolatile {
|
||||
// Issue typedmemmove call.
|
||||
taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}, s.sb)
|
||||
s.rtcall(typedmemmove, true, nil, taddr, left, right)
|
||||
} else {
|
||||
// Copy to temp location if the source is volatile (will be clobbered by
|
||||
// a function call). Marshaling the args to typedmemmove might clobber the
|
||||
// value we're trying to move.
|
||||
tmp := temp(t)
|
||||
s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, tmp, s.mem())
|
||||
tmpaddr, _ := s.addr(tmp, true)
|
||||
s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), tmpaddr, right, s.mem())
|
||||
// Issue typedmemmove call.
|
||||
taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}, s.sb)
|
||||
s.rtcall(typedmemmove, true, nil, taddr, left, tmpaddr)
|
||||
// Mark temp as dead.
|
||||
s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, tmp, s.mem())
|
||||
}
|
||||
s.endBlock().AddEdgeTo(bEnd)
|
||||
|
||||
s.startBlock(bElse)
|
||||
|
|
@ -4387,7 +4419,7 @@ func (e *ssaExport) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
|
|||
// namedAuto returns a new AUTO variable with the given name and type.
|
||||
func (e *ssaExport) namedAuto(name string, typ ssa.Type) ssa.GCNode {
|
||||
t := typ.(*Type)
|
||||
s := Lookup(name)
|
||||
s := &Sym{Name: name, Pkg: autopkg}
|
||||
n := Nod(ONAME, nil, nil)
|
||||
s.Def = n
|
||||
s.Def.Used = true
|
||||
|
|
|
|||
|
|
@ -1860,7 +1860,13 @@ func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
|
|||
dot := adddot(NodSym(OXDOT, this.Left, method.Sym))
|
||||
|
||||
// generate call
|
||||
if !instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !isifacemethod(method.Type) {
|
||||
// It's not possible to use a tail call when dynamic linking on ppc64le. The
|
||||
// bad scenario is when a local call is made to the wrapper: the wrapper will
|
||||
// call the implementation, which might be in a different module and so set
|
||||
// the TOC to the appropriate value for that module. But if it returns
|
||||
// directly to the wrapper's caller, nothing will reset it to the correct
|
||||
// value for that function.
|
||||
if !instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !isifacemethod(method.Type) && !(Thearch.LinkArch.Name == "ppc64le" && Ctxt.Flag_dynlink) {
|
||||
// generate tail call: adjust pointer receiver and jump to embedded method.
|
||||
dot = dot.Left // skip final .M
|
||||
// TODO(mdempsky): Remove dependency on dotlist.
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ func typecheckswitch(n *Node) {
|
|||
|
||||
n.Type = t
|
||||
|
||||
var def *Node
|
||||
var def, niltype *Node
|
||||
for _, ncase := range n.List.Slice() {
|
||||
setlineno(n)
|
||||
if ncase.List.Len() == 0 {
|
||||
|
|
@ -150,6 +150,12 @@ func typecheckswitch(n *Node) {
|
|||
var ptr int
|
||||
switch {
|
||||
case n1.Op == OLITERAL && n1.Type.IsKind(TNIL):
|
||||
// case nil:
|
||||
if niltype != nil {
|
||||
Yyerror("multiple nil cases in type switch (first at %v)", niltype.Line())
|
||||
} else {
|
||||
niltype = ncase
|
||||
}
|
||||
case n1.Op != OTYPE && n1.Type != nil: // should this be ||?
|
||||
Yyerror("%v is not a type", Nconv(n1, FmtLong))
|
||||
// reset to original type
|
||||
|
|
|
|||
|
|
@ -208,6 +208,89 @@ func main() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Constant folding for comparisons
|
||||
for _, s := range szs {
|
||||
fmt.Fprintf(w, "func TestConstFoldCompare%s(t *testing.T) {\n", s.name)
|
||||
for _, x := range s.i {
|
||||
for _, y := range s.i {
|
||||
fmt.Fprintf(w, "\t{\n")
|
||||
fmt.Fprintf(w, "\t\tvar x %s = %d\n", s.name, x)
|
||||
fmt.Fprintf(w, "\t\tvar y %s = %d\n", s.name, y)
|
||||
if x == y {
|
||||
fmt.Fprintf(w, "\t\tif !(x == y) { t.Errorf(\"!(%%d == %%d)\", x, y) }\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t\tif x == y { t.Errorf(\"%%d == %%d\", x, y) }\n")
|
||||
}
|
||||
if x != y {
|
||||
fmt.Fprintf(w, "\t\tif !(x != y) { t.Errorf(\"!(%%d != %%d)\", x, y) }\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t\tif x != y { t.Errorf(\"%%d != %%d\", x, y) }\n")
|
||||
}
|
||||
if x < y {
|
||||
fmt.Fprintf(w, "\t\tif !(x < y) { t.Errorf(\"!(%%d < %%d)\", x, y) }\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t\tif x < y { t.Errorf(\"%%d < %%d\", x, y) }\n")
|
||||
}
|
||||
if x > y {
|
||||
fmt.Fprintf(w, "\t\tif !(x > y) { t.Errorf(\"!(%%d > %%d)\", x, y) }\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t\tif x > y { t.Errorf(\"%%d > %%d\", x, y) }\n")
|
||||
}
|
||||
if x <= y {
|
||||
fmt.Fprintf(w, "\t\tif !(x <= y) { t.Errorf(\"!(%%d <= %%d)\", x, y) }\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t\tif x <= y { t.Errorf(\"%%d <= %%d\", x, y) }\n")
|
||||
}
|
||||
if x >= y {
|
||||
fmt.Fprintf(w, "\t\tif !(x >= y) { t.Errorf(\"!(%%d >= %%d)\", x, y) }\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t\tif x >= y { t.Errorf(\"%%d >= %%d\", x, y) }\n")
|
||||
}
|
||||
fmt.Fprintf(w, "\t}\n")
|
||||
}
|
||||
}
|
||||
for _, x := range s.u {
|
||||
for _, y := range s.u {
|
||||
fmt.Fprintf(w, "\t{\n")
|
||||
fmt.Fprintf(w, "\t\tvar x %s = %d\n", s.name, x)
|
||||
fmt.Fprintf(w, "\t\tvar y %s = %d\n", s.name, y)
|
||||
if x == y {
|
||||
fmt.Fprintf(w, "\t\tif !(x == y) { t.Errorf(\"!(%%d == %%d)\", x, y) }\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t\tif x == y { t.Errorf(\"%%d == %%d\", x, y) }\n")
|
||||
}
|
||||
if x != y {
|
||||
fmt.Fprintf(w, "\t\tif !(x != y) { t.Errorf(\"!(%%d != %%d)\", x, y) }\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t\tif x != y { t.Errorf(\"%%d != %%d\", x, y) }\n")
|
||||
}
|
||||
if x < y {
|
||||
fmt.Fprintf(w, "\t\tif !(x < y) { t.Errorf(\"!(%%d < %%d)\", x, y) }\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t\tif x < y { t.Errorf(\"%%d < %%d\", x, y) }\n")
|
||||
}
|
||||
if x > y {
|
||||
fmt.Fprintf(w, "\t\tif !(x > y) { t.Errorf(\"!(%%d > %%d)\", x, y) }\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t\tif x > y { t.Errorf(\"%%d > %%d\", x, y) }\n")
|
||||
}
|
||||
if x <= y {
|
||||
fmt.Fprintf(w, "\t\tif !(x <= y) { t.Errorf(\"!(%%d <= %%d)\", x, y) }\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t\tif x <= y { t.Errorf(\"%%d <= %%d\", x, y) }\n")
|
||||
}
|
||||
if x >= y {
|
||||
fmt.Fprintf(w, "\t\tif !(x >= y) { t.Errorf(\"!(%%d >= %%d)\", x, y) }\n")
|
||||
} else {
|
||||
fmt.Fprintf(w, "\t\tif x >= y { t.Errorf(\"%%d >= %%d\", x, y) }\n")
|
||||
}
|
||||
fmt.Fprintf(w, "\t}\n")
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(w, "}\n")
|
||||
}
|
||||
|
||||
// gofmt result
|
||||
b := w.Bytes()
|
||||
src, err := format.Source(b)
|
||||
|
|
|
|||
|
|
@ -358,9 +358,7 @@ func typeinit() {
|
|||
itable = typPtr(Types[TUINT8])
|
||||
}
|
||||
|
||||
func lexinit1() {
|
||||
// t = interface { Error() string }
|
||||
|
||||
func makeErrorInterface() *Type {
|
||||
rcvr := typ(TSTRUCT)
|
||||
rcvr.StructType().Funarg = FunargRcvr
|
||||
field := newField()
|
||||
|
|
@ -387,10 +385,18 @@ func lexinit1() {
|
|||
field.Type = f
|
||||
t.SetFields([]*Field{field})
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
func lexinit1() {
|
||||
// error type
|
||||
s := Pkglookup("error", builtinpkg)
|
||||
errortype = t
|
||||
errortype = makeErrorInterface()
|
||||
errortype.Sym = s
|
||||
// TODO: If we can prove that it's safe to set errortype.Orig here
|
||||
// than we don't need the special errortype/errorInterface case in
|
||||
// bexport.go. See also issue #15920.
|
||||
// errortype.Orig = makeErrorInterface()
|
||||
s.Def = typenod(errortype)
|
||||
|
||||
// byte alias
|
||||
|
|
|
|||
|
|
@ -246,17 +246,53 @@
|
|||
|
||||
// zero shifted.
|
||||
(Lsh64x64 (Const64 [0]) _) -> (Const64 [0])
|
||||
(Lsh64x32 (Const64 [0]) _) -> (Const64 [0])
|
||||
(Lsh64x16 (Const64 [0]) _) -> (Const64 [0])
|
||||
(Lsh64x8 (Const64 [0]) _) -> (Const64 [0])
|
||||
(Rsh64x64 (Const64 [0]) _) -> (Const64 [0])
|
||||
(Rsh64x32 (Const64 [0]) _) -> (Const64 [0])
|
||||
(Rsh64x16 (Const64 [0]) _) -> (Const64 [0])
|
||||
(Rsh64x8 (Const64 [0]) _) -> (Const64 [0])
|
||||
(Rsh64Ux64 (Const64 [0]) _) -> (Const64 [0])
|
||||
(Lsh32x64 (Const64 [0]) _) -> (Const32 [0])
|
||||
(Rsh32x64 (Const64 [0]) _) -> (Const32 [0])
|
||||
(Rsh32Ux64 (Const64 [0]) _) -> (Const32 [0])
|
||||
(Lsh16x64 (Const64 [0]) _) -> (Const16 [0])
|
||||
(Rsh16x64 (Const64 [0]) _) -> (Const16 [0])
|
||||
(Rsh16Ux64 (Const64 [0]) _) -> (Const16 [0])
|
||||
(Lsh8x64 (Const64 [0]) _) -> (Const8 [0])
|
||||
(Rsh8x64 (Const64 [0]) _) -> (Const8 [0])
|
||||
(Rsh8Ux64 (Const64 [0]) _) -> (Const8 [0])
|
||||
(Rsh64Ux32 (Const64 [0]) _) -> (Const64 [0])
|
||||
(Rsh64Ux16 (Const64 [0]) _) -> (Const64 [0])
|
||||
(Rsh64Ux8 (Const64 [0]) _) -> (Const64 [0])
|
||||
(Lsh32x64 (Const32 [0]) _) -> (Const32 [0])
|
||||
(Lsh32x32 (Const32 [0]) _) -> (Const32 [0])
|
||||
(Lsh32x16 (Const32 [0]) _) -> (Const32 [0])
|
||||
(Lsh32x8 (Const32 [0]) _) -> (Const32 [0])
|
||||
(Rsh32x64 (Const32 [0]) _) -> (Const32 [0])
|
||||
(Rsh32x32 (Const32 [0]) _) -> (Const32 [0])
|
||||
(Rsh32x16 (Const32 [0]) _) -> (Const32 [0])
|
||||
(Rsh32x8 (Const32 [0]) _) -> (Const32 [0])
|
||||
(Rsh32Ux64 (Const32 [0]) _) -> (Const32 [0])
|
||||
(Rsh32Ux32 (Const32 [0]) _) -> (Const32 [0])
|
||||
(Rsh32Ux16 (Const32 [0]) _) -> (Const32 [0])
|
||||
(Rsh32Ux8 (Const32 [0]) _) -> (Const32 [0])
|
||||
(Lsh16x64 (Const16 [0]) _) -> (Const16 [0])
|
||||
(Lsh16x32 (Const16 [0]) _) -> (Const16 [0])
|
||||
(Lsh16x16 (Const16 [0]) _) -> (Const16 [0])
|
||||
(Lsh16x8 (Const16 [0]) _) -> (Const16 [0])
|
||||
(Rsh16x64 (Const16 [0]) _) -> (Const16 [0])
|
||||
(Rsh16x32 (Const16 [0]) _) -> (Const16 [0])
|
||||
(Rsh16x16 (Const16 [0]) _) -> (Const16 [0])
|
||||
(Rsh16x8 (Const16 [0]) _) -> (Const16 [0])
|
||||
(Rsh16Ux64 (Const16 [0]) _) -> (Const16 [0])
|
||||
(Rsh16Ux32 (Const16 [0]) _) -> (Const16 [0])
|
||||
(Rsh16Ux16 (Const16 [0]) _) -> (Const16 [0])
|
||||
(Rsh16Ux8 (Const16 [0]) _) -> (Const16 [0])
|
||||
(Lsh8x64 (Const8 [0]) _) -> (Const8 [0])
|
||||
(Lsh8x32 (Const8 [0]) _) -> (Const8 [0])
|
||||
(Lsh8x16 (Const8 [0]) _) -> (Const8 [0])
|
||||
(Lsh8x8 (Const8 [0]) _) -> (Const8 [0])
|
||||
(Rsh8x64 (Const8 [0]) _) -> (Const8 [0])
|
||||
(Rsh8x32 (Const8 [0]) _) -> (Const8 [0])
|
||||
(Rsh8x16 (Const8 [0]) _) -> (Const8 [0])
|
||||
(Rsh8x8 (Const8 [0]) _) -> (Const8 [0])
|
||||
(Rsh8Ux64 (Const8 [0]) _) -> (Const8 [0])
|
||||
(Rsh8Ux32 (Const8 [0]) _) -> (Const8 [0])
|
||||
(Rsh8Ux16 (Const8 [0]) _) -> (Const8 [0])
|
||||
(Rsh8Ux8 (Const8 [0]) _) -> (Const8 [0])
|
||||
|
||||
// large left shifts of all values, and right shifts of unsigned values
|
||||
(Lsh64x64 _ (Const64 [c])) && uint64(c) >= 64 -> (Const64 [0])
|
||||
|
|
@ -286,31 +322,31 @@
|
|||
|
||||
// ((x >> c1) << c2) >> c3
|
||||
(Rsh64Ux64 (Lsh64x64 (Rsh64Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
||||
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2)
|
||||
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
||||
-> (Rsh64Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
||||
(Rsh32Ux64 (Lsh32x64 (Rsh32Ux64 x (Const32 [c1])) (Const32 [c2])) (Const32 [c3]))
|
||||
&& uint32(c1) >= uint32(c2) && uint32(c3) >= uint32(c2)
|
||||
-> (Rsh32Ux64 x (Const32 <config.fe.TypeUInt32()> [int64(int32(c1-c2+c3))]))
|
||||
(Rsh16Ux64 (Lsh16x64 (Rsh16Ux64 x (Const16 [c1])) (Const16 [c2])) (Const16 [c3]))
|
||||
&& uint16(c1) >= uint16(c2) && uint16(c3) >= uint16(c2)
|
||||
-> (Rsh16Ux64 x (Const16 <config.fe.TypeUInt16()> [int64(int16(c1-c2+c3))]))
|
||||
(Rsh8Ux64 (Lsh8x64 (Rsh8Ux64 x (Const8 [c1])) (Const8 [c2])) (Const8 [c3]))
|
||||
&& uint8(c1) >= uint8(c2) && uint8(c3) >= uint8(c2)
|
||||
-> (Rsh8Ux64 x (Const8 <config.fe.TypeUInt8()> [int64(int8(c1-c2+c3))]))
|
||||
(Rsh32Ux64 (Lsh32x64 (Rsh32Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
||||
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
||||
-> (Rsh32Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
||||
(Rsh16Ux64 (Lsh16x64 (Rsh16Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
||||
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
||||
-> (Rsh16Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
||||
(Rsh8Ux64 (Lsh8x64 (Rsh8Ux64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
||||
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
||||
-> (Rsh8Ux64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
||||
|
||||
// ((x << c1) >> c2) << c3
|
||||
(Lsh64x64 (Rsh64Ux64 (Lsh64x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
||||
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2)
|
||||
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
||||
-> (Lsh64x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
||||
(Lsh32x64 (Rsh32Ux64 (Lsh32x64 x (Const32 [c1])) (Const32 [c2])) (Const32 [c3]))
|
||||
&& uint32(c1) >= uint32(c2) && uint32(c3) >= uint32(c2)
|
||||
-> (Lsh32x64 x (Const32 <config.fe.TypeUInt32()> [int64(int32(c1-c2+c3))]))
|
||||
(Lsh16x64 (Rsh16Ux64 (Lsh16x64 x (Const16 [c1])) (Const16 [c2])) (Const16 [c3]))
|
||||
&& uint16(c1) >= uint16(c2) && uint16(c3) >= uint16(c2)
|
||||
-> (Lsh16x64 x (Const16 <config.fe.TypeUInt16()> [int64(int16(c1-c2+c3))]))
|
||||
(Lsh8x64 (Rsh8Ux64 (Lsh8x64 x (Const8 [c1])) (Const8 [c2])) (Const8 [c3]))
|
||||
&& uint8(c1) >= uint8(c2) && uint8(c3) >= uint8(c2)
|
||||
-> (Lsh8x64 x (Const8 <config.fe.TypeUInt8()> [int64(int8(c1-c2+c3))]))
|
||||
(Lsh32x64 (Rsh32Ux64 (Lsh32x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
||||
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
||||
-> (Lsh32x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
||||
(Lsh16x64 (Rsh16Ux64 (Lsh16x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
||||
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
||||
-> (Lsh16x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
||||
(Lsh8x64 (Rsh8Ux64 (Lsh8x64 x (Const64 [c1])) (Const64 [c2])) (Const64 [c3]))
|
||||
&& uint64(c1) >= uint64(c2) && uint64(c3) >= uint64(c2) && !uaddOvf(c1-c2, c3)
|
||||
-> (Lsh8x64 x (Const64 <config.fe.TypeUInt64()> [c1-c2+c3]))
|
||||
|
||||
// constant comparisons
|
||||
(Eq64 (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(c == d)])
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1143,8 +1143,8 @@ func checkCC() {
|
|||
}
|
||||
fatal("cannot invoke C compiler %q: %v\n\n"+
|
||||
"Go needs a system C compiler for use with cgo.\n"+
|
||||
"To set a C compiler, export CC=the-compiler.\n"+
|
||||
"To disable cgo, export CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output)
|
||||
"To set a C compiler, set CC=the-compiler.\n"+
|
||||
"To disable cgo, set CGO_ENABLED=0.\n%s%s", defaultcc, err, outputHdr, output)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -432,8 +432,8 @@ func (t *tester) registerTests() {
|
|||
},
|
||||
})
|
||||
|
||||
if t.cgoEnabled && t.goos != "android" && !t.iOS() {
|
||||
// Disabled on android and iOS. golang.org/issue/8345
|
||||
if t.cgoEnabled && !t.iOS() {
|
||||
// Disabled on iOS. golang.org/issue/15919
|
||||
t.tests = append(t.tests, distTest{
|
||||
name: "cgo_stdio",
|
||||
heading: "../misc/cgo/stdio",
|
||||
|
|
@ -465,11 +465,7 @@ func (t *tester) registerTests() {
|
|||
})
|
||||
}
|
||||
}
|
||||
if t.cgoEnabled && t.goos != "android" && !t.iOS() {
|
||||
// TODO(crawshaw): reenable on android and iOS
|
||||
// golang.org/issue/8345
|
||||
//
|
||||
// These tests are not designed to run off the host.
|
||||
if t.cgoEnabled {
|
||||
t.tests = append(t.tests, distTest{
|
||||
name: "cgo_test",
|
||||
heading: "../misc/cgo/test",
|
||||
|
|
@ -729,16 +725,10 @@ func (t *tester) runHostTest(dirBanner, pkg string) error {
|
|||
func (t *tester) cgoTest(dt *distTest) error {
|
||||
env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ())
|
||||
|
||||
if t.goos == "android" || t.iOS() {
|
||||
cmd := t.dirCmd("misc/cgo/test", "go", "test", t.tags())
|
||||
cmd.Env = env
|
||||
return cmd.Run()
|
||||
}
|
||||
|
||||
cmd := t.addCmd(dt, "misc/cgo/test", "go", "test", t.tags(), "-ldflags", "-linkmode=auto", t.runFlag(""))
|
||||
cmd.Env = env
|
||||
|
||||
if t.gohostos != "dragonfly" && t.gohostarch != "ppc64le" {
|
||||
if t.gohostos != "dragonfly" && t.gohostarch != "ppc64le" && t.goos != "android" && (t.goos != "darwin" || t.goarch != "arm") {
|
||||
// linkmode=internal fails on dragonfly since errno is a TLS relocation.
|
||||
// linkmode=internal fails on ppc64le because cmd/link doesn't
|
||||
// handle the TOC correctly (issue 15409).
|
||||
|
|
@ -792,8 +782,10 @@ func (t *tester) cgoTest(dt *distTest) error {
|
|||
if err := cmd.Run(); err != nil {
|
||||
fmt.Println("No support for static linking found (lacks libc.a?), skip cgo static linking test.")
|
||||
} else {
|
||||
cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
|
||||
cmd.Env = env
|
||||
if t.goos != "android" {
|
||||
cmd = t.addCmd(dt, "misc/cgo/testtls", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
|
||||
cmd.Env = env
|
||||
}
|
||||
|
||||
cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test")
|
||||
cmd.Env = env
|
||||
|
|
@ -801,8 +793,10 @@ func (t *tester) cgoTest(dt *distTest) error {
|
|||
cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external`)
|
||||
cmd.Env = env
|
||||
|
||||
cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
|
||||
cmd.Env = env
|
||||
if t.goos != "android" {
|
||||
cmd = t.addCmd(dt, "misc/cgo/nocgo", "go", "test", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`)
|
||||
cmd.Env = env
|
||||
}
|
||||
}
|
||||
|
||||
if pair != "freebsd-amd64" { // clang -pie fails to link misc/cgo/test
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -2182,7 +2182,6 @@ func mkAbs(dir, f string) string {
|
|||
type toolchain interface {
|
||||
// gc runs the compiler in a specific directory on a set of files
|
||||
// and returns the name of the generated output file.
|
||||
// The compiler runs in the directory dir.
|
||||
gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
|
||||
// cc runs the toolchain's C compiler in a directory on a C file
|
||||
// to produce an output file.
|
||||
|
|
@ -2328,7 +2327,15 @@ func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error {
|
|||
// Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files.
|
||||
inc := filepath.Join(goroot, "pkg", "include")
|
||||
sfile = mkAbs(p.Dir, sfile)
|
||||
args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags, sfile}
|
||||
args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags}
|
||||
if p.ImportPath == "runtime" && goarch == "386" {
|
||||
for _, arg := range buildAsmflags {
|
||||
if arg == "-dynlink" {
|
||||
args = append(args, "-D=GOBUILDMODE_shared=1")
|
||||
}
|
||||
}
|
||||
}
|
||||
args = append(args, sfile)
|
||||
if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -2625,7 +2632,7 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
|
|||
return b.run(p.Dir, p.ImportPath, nil, "ar", "rc", mkAbs(objDir, afile), absOfiles)
|
||||
}
|
||||
|
||||
func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
|
||||
func (tools gccgoToolchain) link(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string, buildmode, desc string) error {
|
||||
// gccgo needs explicit linking with all package dependencies,
|
||||
// and all LDFLAGS from cgo dependencies.
|
||||
apackagePathsSeen := make(map[string]bool)
|
||||
|
|
@ -2634,9 +2641,14 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
|
|||
ldflags := b.gccArchArgs()
|
||||
cgoldflags := []string{}
|
||||
usesCgo := false
|
||||
cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
|
||||
objc := len(root.p.MFiles) > 0
|
||||
fortran := len(root.p.FFiles) > 0
|
||||
cxx := false
|
||||
objc := false
|
||||
fortran := false
|
||||
if root.p != nil {
|
||||
cxx = len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
|
||||
objc = len(root.p.MFiles) > 0
|
||||
fortran = len(root.p.FFiles) > 0
|
||||
}
|
||||
|
||||
readCgoFlags := func(flagsFile string) error {
|
||||
flags, err := ioutil.ReadFile(flagsFile)
|
||||
|
|
@ -2683,11 +2695,11 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
|
|||
}
|
||||
|
||||
newarchive := newa.Name()
|
||||
err = b.run(b.work, root.p.ImportPath, nil, "ar", "x", newarchive, "_cgo_flags")
|
||||
err = b.run(b.work, desc, nil, "ar", "x", newarchive, "_cgo_flags")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = b.run(".", root.p.ImportPath, nil, "ar", "d", newarchive, "_cgo_flags")
|
||||
err = b.run(".", desc, nil, "ar", "d", newarchive, "_cgo_flags")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -2793,7 +2805,9 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
|
|||
|
||||
ldflags = append(ldflags, cgoldflags...)
|
||||
ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
|
||||
ldflags = append(ldflags, root.p.CgoLDFLAGS...)
|
||||
if root.p != nil {
|
||||
ldflags = append(ldflags, root.p.CgoLDFLAGS...)
|
||||
}
|
||||
|
||||
ldflags = stringList("-Wl,-(", ldflags, "-Wl,-)")
|
||||
|
||||
|
|
@ -2808,7 +2822,7 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
|
|||
}
|
||||
|
||||
var realOut string
|
||||
switch ldBuildmode {
|
||||
switch buildmode {
|
||||
case "exe":
|
||||
if usesCgo && goos == "linux" {
|
||||
ldflags = append(ldflags, "-Wl,-E")
|
||||
|
|
@ -2843,12 +2857,14 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
|
|||
|
||||
case "c-shared":
|
||||
ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc", "-lc", "-lgcc")
|
||||
case "shared":
|
||||
ldflags = append(ldflags, "-zdefs", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
|
||||
|
||||
default:
|
||||
fatalf("-buildmode=%s not supported for gccgo", ldBuildmode)
|
||||
fatalf("-buildmode=%s not supported for gccgo", buildmode)
|
||||
}
|
||||
|
||||
switch ldBuildmode {
|
||||
switch buildmode {
|
||||
case "exe", "c-shared":
|
||||
if cxx {
|
||||
ldflags = append(ldflags, "-lstdc++")
|
||||
|
|
@ -2869,41 +2885,27 @@ func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions
|
|||
}
|
||||
}
|
||||
|
||||
if err := b.run(".", root.p.ImportPath, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
|
||||
if err := b.run(".", desc, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch ldBuildmode {
|
||||
switch buildmode {
|
||||
case "c-archive":
|
||||
if err := b.run(".", root.p.ImportPath, nil, "ar", "rc", realOut, out); err != nil {
|
||||
if err := b.run(".", desc, nil, "ar", "rc", realOut, out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tools gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
|
||||
return tools.link(b, root, out, allactions, mainpkg, ofiles, ldBuildmode, root.p.ImportPath)
|
||||
}
|
||||
|
||||
func (tools gccgoToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
|
||||
args := []string{"-o", out, "-shared", "-nostdlib", "-zdefs", "-Wl,--whole-archive"}
|
||||
for _, a := range toplevelactions {
|
||||
args = append(args, a.target)
|
||||
}
|
||||
args = append(args, "-Wl,--no-whole-archive", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
|
||||
shlibs := []string{}
|
||||
for _, a := range allactions {
|
||||
if strings.HasSuffix(a.target, ".so") {
|
||||
shlibs = append(shlibs, a.target)
|
||||
}
|
||||
}
|
||||
for _, shlib := range shlibs {
|
||||
args = append(
|
||||
args,
|
||||
"-L"+filepath.Dir(shlib),
|
||||
"-Wl,-rpath="+filepath.Dir(shlib),
|
||||
"-l"+strings.TrimSuffix(
|
||||
strings.TrimPrefix(filepath.Base(shlib), "lib"),
|
||||
".so"))
|
||||
}
|
||||
return b.run(".", out, nil, tools.linker(), args, buildGccgoflags)
|
||||
fakeRoot := &action{}
|
||||
fakeRoot.deps = toplevelactions
|
||||
return tools.link(b, fakeRoot, out, allactions, "", nil, "shared", out)
|
||||
}
|
||||
|
||||
func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
|
||||
|
|
@ -3088,7 +3090,7 @@ func (b *builder) gccSupportsFlag(flag string) bool {
|
|||
}
|
||||
cmd := exec.Command(cmdArgs[0], cmdArgs[1:]...)
|
||||
cmd.Dir = b.work
|
||||
cmd.Env = envForDir(cmd.Dir, os.Environ())
|
||||
cmd.Env = mergeEnvLists([]string{"LC_ALL=C"}, envForDir(cmd.Dir, os.Environ()))
|
||||
out, err := cmd.CombinedOutput()
|
||||
supported := err == nil && !bytes.Contains(out, []byte("unrecognized"))
|
||||
b.flagCache[flag] = supported
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ var cmdGet = &Command{
|
|||
UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]",
|
||||
Short: "download and install packages and dependencies",
|
||||
Long: `
|
||||
Get downloads and installs the packages named by the import paths,
|
||||
along with their dependencies.
|
||||
Get downloads the packages named by the import paths, along with their
|
||||
dependencies. It then installs the named packages, like 'go install'.
|
||||
|
||||
The -d flag instructs get to stop after downloading the packages; that is,
|
||||
it instructs get not to install the packages.
|
||||
|
|
|
|||
|
|
@ -1332,15 +1332,31 @@ func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) {
|
|||
tg.run("test", "main_test")
|
||||
}
|
||||
|
||||
// The runtime version string takes one of two forms:
|
||||
// "go1.X[.Y]" for Go releases, and "devel +hash" at tip.
|
||||
// Determine whether we are in a released copy by
|
||||
// inspecting the version.
|
||||
var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
|
||||
|
||||
// Issue 12690
|
||||
func TestPackageNotStaleWithTrailingSlash(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
|
||||
// Make sure the packages below are not stale.
|
||||
tg.run("install", "runtime", "os", "io")
|
||||
|
||||
goroot := runtime.GOROOT()
|
||||
tg.setenv("GOROOT", goroot+"/")
|
||||
tg.wantNotStale("runtime", "", "with trailing slash in GOROOT, runtime listed as stale")
|
||||
tg.wantNotStale("os", "", "with trailing slash in GOROOT, os listed as stale")
|
||||
tg.wantNotStale("io", "", "with trailing slash in GOROOT, io listed as stale")
|
||||
|
||||
want := ""
|
||||
if isGoRelease {
|
||||
want = "standard package in Go release distribution"
|
||||
}
|
||||
|
||||
tg.wantNotStale("runtime", want, "with trailing slash in GOROOT, runtime listed as stale")
|
||||
tg.wantNotStale("os", want, "with trailing slash in GOROOT, os listed as stale")
|
||||
tg.wantNotStale("io", want, "with trailing slash in GOROOT, io listed as stale")
|
||||
}
|
||||
|
||||
// With $GOBIN set, binaries get installed to $GOBIN.
|
||||
|
|
@ -2342,6 +2358,11 @@ func TestGoGetRscIoToolstash(t *testing.T) {
|
|||
// Issue 13037: Was not parsing <meta> tags in 404 served over HTTPS
|
||||
func TestGoGetHTTPS404(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
switch runtime.GOOS {
|
||||
case "darwin", "linux", "freebsd":
|
||||
default:
|
||||
t.Skipf("test case does not work on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
|
|
@ -2877,3 +2898,25 @@ func TestBinaryOnlyPackages(t *testing.T) {
|
|||
tg.run("run", tg.path("src/p3/p3.go"))
|
||||
tg.grepStdout("hello from p1", "did not see message from p1")
|
||||
}
|
||||
|
||||
// Issue 16050.
|
||||
func TestAlwaysLinkSysoFiles(t *testing.T) {
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempDir("src/syso")
|
||||
tg.tempFile("src/syso/a.syso", ``)
|
||||
tg.tempFile("src/syso/b.go", `package syso`)
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
|
||||
// We should see the .syso file regardless of the setting of
|
||||
// CGO_ENABLED.
|
||||
|
||||
tg.setenv("CGO_ENABLED", "1")
|
||||
tg.run("list", "-f", "{{.SysoFiles}}", "syso")
|
||||
tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=1")
|
||||
|
||||
tg.setenv("CGO_ENABLED", "0")
|
||||
tg.run("list", "-f", "{{.SysoFiles}}", "syso")
|
||||
tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=0")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,15 +214,7 @@ var helpTemplate = `{{if .Runnable}}usage: go {{.UsageLine}}
|
|||
{{end}}{{.Long | trim}}
|
||||
`
|
||||
|
||||
var documentationTemplate = `// Copyright 2011 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.
|
||||
|
||||
// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.
|
||||
// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.
|
||||
|
||||
/*
|
||||
{{range .}}{{if .Short}}{{.Short | capitalize}}
|
||||
var documentationTemplate = `{{range .}}{{if .Short}}{{.Short | capitalize}}
|
||||
|
||||
{{end}}{{if .Runnable}}Usage:
|
||||
|
||||
|
|
@ -231,9 +223,39 @@ var documentationTemplate = `// Copyright 2011 The Go Authors. All rights reserv
|
|||
{{end}}{{.Long | trim}}
|
||||
|
||||
|
||||
{{end}}*/
|
||||
package main
|
||||
`
|
||||
{{end}}`
|
||||
|
||||
// commentWriter writes a Go comment to the underlying io.Writer,
|
||||
// using line comment form (//).
|
||||
type commentWriter struct {
|
||||
W io.Writer
|
||||
wroteSlashes bool // Wrote "//" at the beginning of the current line.
|
||||
}
|
||||
|
||||
func (c *commentWriter) Write(p []byte) (int, error) {
|
||||
var n int
|
||||
for i, b := range p {
|
||||
if !c.wroteSlashes {
|
||||
s := "//"
|
||||
if b != '\n' {
|
||||
s = "// "
|
||||
}
|
||||
if _, err := io.WriteString(c.W, s); err != nil {
|
||||
return n, err
|
||||
}
|
||||
c.wroteSlashes = true
|
||||
}
|
||||
n0, err := c.W.Write(p[i : i+1])
|
||||
n += n0
|
||||
if err != nil {
|
||||
return n, err
|
||||
}
|
||||
if b == '\n' {
|
||||
c.wroteSlashes = false
|
||||
}
|
||||
}
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// An errWriter wraps a writer, recording whether a write error occurred.
|
||||
type errWriter struct {
|
||||
|
|
@ -310,10 +332,18 @@ func help(args []string) {
|
|||
|
||||
// 'go help documentation' generates doc.go.
|
||||
if arg == "documentation" {
|
||||
fmt.Println("// Copyright 2011 The Go Authors. All rights reserved.")
|
||||
fmt.Println("// Use of this source code is governed by a BSD-style")
|
||||
fmt.Println("// license that can be found in the LICENSE file.")
|
||||
fmt.Println()
|
||||
fmt.Println("// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.")
|
||||
fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.")
|
||||
fmt.Println()
|
||||
buf := new(bytes.Buffer)
|
||||
printUsage(buf)
|
||||
usage := &Command{Long: buf.String()}
|
||||
tmpl(os.Stdout, documentationTemplate, append([]*Command{usage}, commands...))
|
||||
tmpl(&commentWriter{W: os.Stdout}, documentationTemplate, append([]*Command{usage}, commands...))
|
||||
fmt.Println("package main")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
set -e
|
||||
|
||||
go build -o go.latest
|
||||
./go.latest help documentation | sed 's; \*/; * /;' >alldocs.go
|
||||
./go.latest help documentation >alldocs.go
|
||||
gofmt -w alldocs.go
|
||||
rm go.latest
|
||||
|
||||
|
|
|
|||
|
|
@ -1022,9 +1022,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
|
|||
p.MFiles = nil
|
||||
p.SwigFiles = nil
|
||||
p.SwigCXXFiles = nil
|
||||
p.SysoFiles = nil
|
||||
// Note that SFiles are okay (they go to the Go assembler)
|
||||
// and HFiles are okay (they might be used by the SFiles).
|
||||
// Also Sysofiles are okay (they might not contain object
|
||||
// code; see issue #16050).
|
||||
}
|
||||
|
||||
// The gc toolchain only permits C source files with cgo.
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ control the execution of any test:
|
|||
const testFlag2 = `
|
||||
-bench regexp
|
||||
Run (sub)benchmarks matching a regular expression.
|
||||
The given regular expression is split into smaller ones by
|
||||
The given regular expression is split into smaller ones by
|
||||
top-level '/', where each must match the corresponding part of a
|
||||
benchmark's identifier.
|
||||
By default, no benchmarks run. To run all benchmarks,
|
||||
|
|
@ -221,7 +221,7 @@ const testFlag2 = `
|
|||
-run regexp
|
||||
Run only those tests and examples matching the regular expression.
|
||||
For tests the regular expression is split into smaller ones by
|
||||
top-level '/', where each must match the corresponding part of a
|
||||
top-level '/', where each must match the corresponding part of a
|
||||
test's identifier.
|
||||
|
||||
-short
|
||||
|
|
@ -263,7 +263,7 @@ execution, not to the test itself.)
|
|||
The test flags that generate profiles (other than for coverage) also
|
||||
leave the test binary in pkg.test for use when analyzing the profiles.
|
||||
|
||||
When 'go test' runs a test binary, it does so from within the
|
||||
When 'go test' runs a test binary, it does so from within the
|
||||
corresponding package's source code directory. Depending on the test,
|
||||
it may be necessary to do the same when invoking a generated test
|
||||
binary directly.
|
||||
|
|
|
|||
|
|
@ -779,15 +779,31 @@ type metaImport struct {
|
|||
// errNoMatch is returned from matchGoImport when there's no applicable match.
|
||||
var errNoMatch = errors.New("no import match")
|
||||
|
||||
func splitPathHasPrefix(path, prefix []string) bool {
|
||||
if len(path) < len(prefix) {
|
||||
return false
|
||||
}
|
||||
for i, p := range prefix {
|
||||
if path[i] != p {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// matchGoImport returns the metaImport from imports matching importPath.
|
||||
// An error is returned if there are multiple matches.
|
||||
// errNoMatch is returned if none match.
|
||||
func matchGoImport(imports []metaImport, importPath string) (_ metaImport, err error) {
|
||||
match := -1
|
||||
imp := strings.Split(importPath, "/")
|
||||
for i, im := range imports {
|
||||
if !strings.HasPrefix(importPath, im.Prefix) {
|
||||
pre := strings.Split(im.Prefix, "/")
|
||||
|
||||
if !splitPathHasPrefix(imp, pre) {
|
||||
continue
|
||||
}
|
||||
|
||||
if match != -1 {
|
||||
err = fmt.Errorf("multiple meta tags match import path %q", importPath)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"internal/testenv"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
|
@ -227,3 +228,96 @@ func TestIsSecure(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchGoImport(t *testing.T) {
|
||||
tests := []struct {
|
||||
imports []metaImport
|
||||
path string
|
||||
mi metaImport
|
||||
err error
|
||||
}{
|
||||
{
|
||||
imports: []metaImport{
|
||||
{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
path: "example.com/user/foo",
|
||||
mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
{
|
||||
imports: []metaImport{
|
||||
{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
path: "example.com/user/foo/",
|
||||
mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
{
|
||||
imports: []metaImport{
|
||||
{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
path: "example.com/user/foo",
|
||||
mi: metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
{
|
||||
imports: []metaImport{
|
||||
{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
path: "example.com/user/fooa",
|
||||
mi: metaImport{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
{
|
||||
imports: []metaImport{
|
||||
{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
path: "example.com/user/foo/bar",
|
||||
err: errors.New("should not be allowed to create nested repo"),
|
||||
},
|
||||
{
|
||||
imports: []metaImport{
|
||||
{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
path: "example.com/user/foo/bar/baz",
|
||||
err: errors.New("should not be allowed to create nested repo"),
|
||||
},
|
||||
{
|
||||
imports: []metaImport{
|
||||
{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
path: "example.com/user/foo/bar/baz/qux",
|
||||
err: errors.New("should not be allowed to create nested repo"),
|
||||
},
|
||||
{
|
||||
imports: []metaImport{
|
||||
{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
path: "example.com/user/foo/bar/baz/",
|
||||
err: errors.New("should not be allowed to create nested repo"),
|
||||
},
|
||||
{
|
||||
imports: []metaImport{
|
||||
{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
|
||||
},
|
||||
path: "example.com",
|
||||
err: errors.New("pathologically short path"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
mi, err := matchGoImport(test.imports, test.path)
|
||||
if mi != test.mi {
|
||||
t.Errorf("unexpected metaImport; got %v, want %v", mi, test.mi)
|
||||
}
|
||||
|
||||
got := err
|
||||
want := test.err
|
||||
if (got == nil) != (want == nil) {
|
||||
t.Errorf("unexpected error; got %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1986,16 +1986,6 @@ func span6(ctxt *obj.Link, s *obj.LSym) {
|
|||
c = naclpad(ctxt, s, c, -c&31)
|
||||
}
|
||||
|
||||
// Pad functions with trap instruction, to catch invalid jumps
|
||||
if c&(FuncAlign-1) != 0 {
|
||||
v := -c & (FuncAlign - 1)
|
||||
s.Grow(int64(c) + int64(v))
|
||||
for i := c; i < c+v; i++ {
|
||||
// 0xCC is INT $3 - breakpoint instruction
|
||||
s.P[i] = uint8(0xCC)
|
||||
}
|
||||
c += v
|
||||
}
|
||||
s.Size = int64(c)
|
||||
|
||||
if false { /* debug['a'] > 1 */
|
||||
|
|
|
|||
|
|
@ -1092,6 +1092,7 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
|
|||
call.Mode = ctxt.Cursym.Text.Mode
|
||||
call.As = obj.ACALL
|
||||
call.To.Type = obj.TYPE_BRANCH
|
||||
call.To.Name = obj.NAME_EXTERN
|
||||
morestack := "runtime.morestack"
|
||||
switch {
|
||||
case ctxt.Cursym.Cfunc:
|
||||
|
|
@ -1100,8 +1101,17 @@ func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *ob
|
|||
morestack = "runtime.morestack_noctxt"
|
||||
}
|
||||
call.To.Sym = obj.Linklookup(ctxt, morestack, 0)
|
||||
// When compiling 386 code for dynamic linking, the call needs to be adjusted
|
||||
// to follow PIC rules. This in turn can insert more instructions, so we need
|
||||
// to keep track of the start of the call (where the jump will be to) and the
|
||||
// end (which following instructions are appended to).
|
||||
callend := call
|
||||
progedit(ctxt, callend)
|
||||
for ; callend.Link != nil; callend = callend.Link {
|
||||
progedit(ctxt, callend.Link)
|
||||
}
|
||||
|
||||
jmp := obj.Appendp(ctxt, call)
|
||||
jmp := obj.Appendp(ctxt, callend)
|
||||
jmp.As = obj.AJMP
|
||||
jmp.To.Type = obj.TYPE_BRANCH
|
||||
jmp.Pcond = ctxt.Cursym.Text.Link
|
||||
|
|
|
|||
|
|
@ -106,6 +106,15 @@ func (f *elfFile) goarch() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (f *elfFile) loadAddress() (uint64, error) {
|
||||
for _, p := range f.elf.Progs {
|
||||
if p.Type == elf.PT_LOAD {
|
||||
return p.Vaddr, nil
|
||||
}
|
||||
}
|
||||
return 0, fmt.Errorf("unknown load address")
|
||||
}
|
||||
|
||||
func (f *elfFile) dwarf() (*dwarf.Data, error) {
|
||||
return f.elf.DWARF()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,6 +94,10 @@ func (f *goobjFile) goarch() string {
|
|||
return "GOARCH unimplemented for debug/goobj files"
|
||||
}
|
||||
|
||||
func (f *goobjFile) loadAddress() (uint64, error) {
|
||||
return 0, fmt.Errorf("unknown load address")
|
||||
}
|
||||
|
||||
func (f *goobjFile) dwarf() (*dwarf.Data, error) {
|
||||
return nil, errors.New("no DWARF data in go object file")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,6 +125,10 @@ func (x uint64s) Len() int { return len(x) }
|
|||
func (x uint64s) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||
func (x uint64s) Less(i, j int) bool { return x[i] < x[j] }
|
||||
|
||||
func (f *machoFile) loadAddress() (uint64, error) {
|
||||
return 0, fmt.Errorf("unknown load address")
|
||||
}
|
||||
|
||||
func (f *machoFile) dwarf() (*dwarf.Data, error) {
|
||||
return f.macho.DWARF()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ type rawFile interface {
|
|||
pcln() (textStart uint64, symtab, pclntab []byte, err error)
|
||||
text() (textStart uint64, text []byte, err error)
|
||||
goarch() string
|
||||
loadAddress() (uint64, error)
|
||||
dwarf() (*dwarf.Data, error)
|
||||
}
|
||||
|
||||
|
|
@ -95,6 +96,13 @@ func (f *File) GOARCH() string {
|
|||
return f.raw.goarch()
|
||||
}
|
||||
|
||||
// LoadAddress returns the expected load address of the file.
|
||||
// This differs from the actual load address for a position-independent
|
||||
// executable.
|
||||
func (f *File) LoadAddress() (uint64, error) {
|
||||
return f.raw.loadAddress()
|
||||
}
|
||||
|
||||
// DWARF returns DWARF debug data for the file, if any.
|
||||
// This is for cmd/pprof to locate cgo functions.
|
||||
func (f *File) DWARF() (*dwarf.Data, error) {
|
||||
|
|
|
|||
|
|
@ -199,6 +199,10 @@ func (f *peFile) goarch() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (f *peFile) loadAddress() (uint64, error) {
|
||||
return 0, fmt.Errorf("unknown load address")
|
||||
}
|
||||
|
||||
func (f *peFile) dwarf() (*dwarf.Data, error) {
|
||||
return f.pe.DWARF()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,6 +147,10 @@ func (f *plan9File) goarch() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (f *plan9File) loadAddress() (uint64, error) {
|
||||
return 0, fmt.Errorf("unknown load address")
|
||||
}
|
||||
|
||||
func (f *plan9File) dwarf() (*dwarf.Data, error) {
|
||||
return nil, errors.New("no DWARF data in Plan 9 file")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -615,7 +615,8 @@ func asmb() {
|
|||
|
||||
sect := ld.Segtext.Sect
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
// 0xCC is INT $3 - breakpoint instruction
|
||||
ld.CodeblkPad(int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
|
||||
for sect = sect.Next; sect != nil; sect = sect.Next {
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
|
|
|
|||
|
|
@ -790,11 +790,14 @@ func blk(start *LSym, addr int64, size int64) {
|
|||
}
|
||||
|
||||
func Codeblk(addr int64, size int64) {
|
||||
CodeblkPad(addr, size, zeros[:])
|
||||
}
|
||||
func CodeblkPad(addr int64, size int64, pad []byte) {
|
||||
if Debug['a'] != 0 {
|
||||
fmt.Fprintf(Bso, "codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
|
||||
}
|
||||
|
||||
blkSlice(Ctxt.Textp, addr, size)
|
||||
blkSlice(Ctxt.Textp, addr, size, pad)
|
||||
|
||||
/* again for printing */
|
||||
if Debug['a'] == 0 {
|
||||
|
|
@ -858,7 +861,7 @@ func Codeblk(addr int64, size int64) {
|
|||
// blkSlice is a variant of blk that processes slices.
|
||||
// After text symbols are converted from a linked list to a slice,
|
||||
// delete blk and give this function its name.
|
||||
func blkSlice(syms []*LSym, addr, size int64) {
|
||||
func blkSlice(syms []*LSym, addr, size int64, pad []byte) {
|
||||
for i, s := range syms {
|
||||
if s.Type&obj.SSUB == 0 && s.Value >= addr {
|
||||
syms = syms[i:]
|
||||
|
|
@ -880,13 +883,13 @@ func blkSlice(syms []*LSym, addr, size int64) {
|
|||
errorexit()
|
||||
}
|
||||
if addr < s.Value {
|
||||
strnput("", int(s.Value-addr))
|
||||
strnputPad("", int(s.Value-addr), pad)
|
||||
addr = s.Value
|
||||
}
|
||||
Cwrite(s.P)
|
||||
addr += int64(len(s.P))
|
||||
if addr < s.Value+s.Size {
|
||||
strnput("", int(s.Value+s.Size-addr))
|
||||
strnputPad("", int(s.Value+s.Size-addr), pad)
|
||||
addr = s.Value + s.Size
|
||||
}
|
||||
if addr != s.Value+s.Size {
|
||||
|
|
@ -899,7 +902,7 @@ func blkSlice(syms []*LSym, addr, size int64) {
|
|||
}
|
||||
|
||||
if addr < eaddr {
|
||||
strnput("", int(eaddr-addr))
|
||||
strnputPad("", int(eaddr-addr), pad)
|
||||
}
|
||||
Cflush()
|
||||
}
|
||||
|
|
@ -909,7 +912,7 @@ func Datblk(addr int64, size int64) {
|
|||
fmt.Fprintf(Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
|
||||
}
|
||||
|
||||
blkSlice(datap, addr, size)
|
||||
blkSlice(datap, addr, size, zeros[:])
|
||||
|
||||
/* again for printing */
|
||||
if Debug['a'] == 0 {
|
||||
|
|
@ -986,23 +989,27 @@ func Dwarfblk(addr int64, size int64) {
|
|||
var zeros [512]byte
|
||||
|
||||
// strnput writes the first n bytes of s.
|
||||
// If n is larger then len(s),
|
||||
// If n is larger than len(s),
|
||||
// it is padded with NUL bytes.
|
||||
func strnput(s string, n int) {
|
||||
strnputPad(s, n, zeros[:])
|
||||
}
|
||||
|
||||
// strnput writes the first n bytes of s.
|
||||
// If n is larger than len(s),
|
||||
// it is padded with the bytes in pad (repeated as needed).
|
||||
func strnputPad(s string, n int, pad []byte) {
|
||||
if len(s) >= n {
|
||||
Cwritestring(s[:n])
|
||||
} else {
|
||||
Cwritestring(s)
|
||||
n -= len(s)
|
||||
for n > 0 {
|
||||
if len(zeros) >= n {
|
||||
Cwrite(zeros[:n])
|
||||
return
|
||||
} else {
|
||||
Cwrite(zeros[:])
|
||||
n -= len(zeros)
|
||||
}
|
||||
for n > len(pad) {
|
||||
Cwrite(pad)
|
||||
n -= len(pad)
|
||||
|
||||
}
|
||||
Cwrite(pad[:n])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -529,7 +529,7 @@ func walktypedef(die *DWDie) *DWDie {
|
|||
}
|
||||
|
||||
func walksymtypedef(s *LSym) *LSym {
|
||||
if t := Linkrlookup(Ctxt, s.Name+".def", int(s.Version)); t != nil {
|
||||
if t := Linkrlookup(Ctxt, s.Name+"..def", int(s.Version)); t != nil {
|
||||
return t
|
||||
}
|
||||
return s
|
||||
|
|
@ -819,7 +819,7 @@ func dotypedef(parent *DWDie, name string, def *DWDie) {
|
|||
Diag("dwarf: bad def in dotypedef")
|
||||
}
|
||||
|
||||
def.sym = Linklookup(Ctxt, def.sym.Name+".def", 0)
|
||||
def.sym = Linklookup(Ctxt, def.sym.Name+"..def", 0)
|
||||
def.sym.Attr |= AttrHidden
|
||||
def.sym.Type = obj.SDWARFINFO
|
||||
|
||||
|
|
@ -1021,7 +1021,7 @@ func newtype(gotype *LSym) *DWDie {
|
|||
}
|
||||
|
||||
func nameFromDIESym(dwtype *LSym) string {
|
||||
return strings.TrimSuffix(dwtype.Name[len(infoprefix):], ".def")
|
||||
return strings.TrimSuffix(dwtype.Name[len(infoprefix):], "..def")
|
||||
}
|
||||
|
||||
// Find or construct *T given T.
|
||||
|
|
|
|||
|
|
@ -1222,19 +1222,28 @@ func hostlink() {
|
|||
}
|
||||
}
|
||||
|
||||
sanitizers := flag_race != 0
|
||||
|
||||
for _, flag := range ldflag {
|
||||
if strings.HasPrefix(flag, "-fsanitize=") {
|
||||
sanitizers = true
|
||||
}
|
||||
}
|
||||
|
||||
argv = append(argv, ldflag...)
|
||||
|
||||
if flag_race != 0 {
|
||||
if sanitizers {
|
||||
// On a system where the toolchain creates position independent
|
||||
// executables by default, tsan initialization can fail. So we pass
|
||||
// -no-pie here, but support for that flag is quite new and we test
|
||||
// for its support first.
|
||||
// executables by default, tsan/msan/asan/etc initialization can
|
||||
// fail. So we pass -no-pie here, but support for that flag is quite
|
||||
// new and we test for its support first.
|
||||
src := filepath.Join(tmpdir, "trivial.c")
|
||||
if err := ioutil.WriteFile(src, []byte{}, 0666); err != nil {
|
||||
Ctxt.Diag("WriteFile trivial.c failed: %v", err)
|
||||
}
|
||||
cmd := exec.Command(argv[0], "-c", "-no-pie", "trivial.c")
|
||||
cmd.Dir = tmpdir
|
||||
cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
|
||||
out, err := cmd.CombinedOutput()
|
||||
supported := err == nil && !bytes.Contains(out, []byte("unrecognized"))
|
||||
if supported {
|
||||
|
|
|
|||
|
|
@ -609,7 +609,8 @@ func asmb() {
|
|||
|
||||
sect := ld.Segtext.Sect
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Codeblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
// 0xCC is INT $3 - breakpoint instruction
|
||||
ld.CodeblkPad(int64(sect.Vaddr), int64(sect.Length), []byte{0xCC})
|
||||
for sect = sect.Next; sect != nil; sect = sect.Next {
|
||||
ld.Cseek(int64(sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff))
|
||||
ld.Datblk(int64(sect.Vaddr), int64(sect.Length))
|
||||
|
|
|
|||
|
|
@ -117,6 +117,9 @@ func (*objTool) Open(name string, start uint64) (plugin.ObjFile, error) {
|
|||
name: name,
|
||||
file: of,
|
||||
}
|
||||
if load, err := of.LoadAddress(); err == nil {
|
||||
f.offset = start - load
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
|
|
@ -169,10 +172,11 @@ func (*objTool) SetConfig(config string) {
|
|||
// (instead of invoking GNU binutils).
|
||||
// A file represents a single executable being analyzed.
|
||||
type file struct {
|
||||
name string
|
||||
sym []objfile.Sym
|
||||
file *objfile.File
|
||||
pcln *gosym.Table
|
||||
name string
|
||||
offset uint64
|
||||
sym []objfile.Sym
|
||||
file *objfile.File
|
||||
pcln *gosym.Table
|
||||
|
||||
triedDwarf bool
|
||||
dwarf *dwarf.Data
|
||||
|
|
@ -200,6 +204,7 @@ func (f *file) SourceLine(addr uint64) ([]plugin.Frame, error) {
|
|||
}
|
||||
f.pcln = pcln
|
||||
}
|
||||
addr -= f.offset
|
||||
file, line, fn := f.pcln.PCToLine(addr)
|
||||
if fn != nil {
|
||||
frame := []plugin.Frame{
|
||||
|
|
|
|||
|
|
@ -16,9 +16,12 @@ const (
|
|||
BestCompression = 9
|
||||
DefaultCompression = -1
|
||||
HuffmanOnly = -2 // Disables match search and only does Huffman entropy reduction.
|
||||
logWindowSize = 15
|
||||
windowSize = 1 << logWindowSize
|
||||
windowMask = windowSize - 1
|
||||
)
|
||||
|
||||
const (
|
||||
logWindowSize = 15
|
||||
windowSize = 1 << logWindowSize
|
||||
windowMask = windowSize - 1
|
||||
|
||||
// The LZ77 step produces a sequence of literal tokens and <length, offset>
|
||||
// pair tokens. The offset is also known as distance. The underlying wire
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ type Context interface {
|
|||
// collisions.
|
||||
//
|
||||
// Packages that define a Context key should provide type-safe accessors
|
||||
// for the values stores using that key:
|
||||
// for the values stored using that key:
|
||||
//
|
||||
// // Package user defines a User type that's stored in Contexts.
|
||||
// package user
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
// code but require careful thought to use correctly.
|
||||
package subtle
|
||||
|
||||
// ConstantTimeCompare returns 1 iff the two slices, x
|
||||
// ConstantTimeCompare returns 1 if and only if the two slices, x
|
||||
// and y, have equal contents. The time taken is a function of the length of
|
||||
// the slices and is independent of the contents.
|
||||
func ConstantTimeCompare(x, y []byte) int {
|
||||
|
|
|
|||
|
|
@ -71,10 +71,12 @@ type Conn struct {
|
|||
clientProtocolFallback bool
|
||||
|
||||
// input/output
|
||||
in, out halfConn // in.Mutex < out.Mutex
|
||||
rawInput *block // raw input, right off the wire
|
||||
input *block // application data waiting to be read
|
||||
hand bytes.Buffer // handshake data waiting to be read
|
||||
in, out halfConn // in.Mutex < out.Mutex
|
||||
rawInput *block // raw input, right off the wire
|
||||
input *block // application data waiting to be read
|
||||
hand bytes.Buffer // handshake data waiting to be read
|
||||
buffering bool // whether records are buffered in sendBuf
|
||||
sendBuf []byte // a buffer of records waiting to be sent
|
||||
|
||||
// bytesSent counts the bytes of application data sent.
|
||||
// packetsSent counts packets.
|
||||
|
|
@ -803,6 +805,30 @@ func (c *Conn) maxPayloadSizeForWrite(typ recordType, explicitIVLen int) int {
|
|||
return n
|
||||
}
|
||||
|
||||
// c.out.Mutex <= L.
|
||||
func (c *Conn) write(data []byte) (int, error) {
|
||||
if c.buffering {
|
||||
c.sendBuf = append(c.sendBuf, data...)
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
n, err := c.conn.Write(data)
|
||||
c.bytesSent += int64(n)
|
||||
return n, err
|
||||
}
|
||||
|
||||
func (c *Conn) flush() (int, error) {
|
||||
if len(c.sendBuf) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
n, err := c.conn.Write(c.sendBuf)
|
||||
c.bytesSent += int64(n)
|
||||
c.sendBuf = nil
|
||||
c.buffering = false
|
||||
return n, err
|
||||
}
|
||||
|
||||
// writeRecordLocked writes a TLS record with the given type and payload to the
|
||||
// connection and updates the record layer state.
|
||||
// c.out.Mutex <= L.
|
||||
|
|
@ -862,10 +888,9 @@ func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
|
|||
}
|
||||
copy(b.data[recordHeaderLen+explicitIVLen:], data)
|
||||
c.out.encrypt(b, explicitIVLen)
|
||||
if _, err := c.conn.Write(b.data); err != nil {
|
||||
if _, err := c.write(b.data); err != nil {
|
||||
return n, err
|
||||
}
|
||||
c.bytesSent += int64(m)
|
||||
n += m
|
||||
data = data[m:]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,6 +206,7 @@ NextCipherSuite:
|
|||
hs.finishedHash.Write(hs.hello.marshal())
|
||||
hs.finishedHash.Write(hs.serverHello.marshal())
|
||||
|
||||
c.buffering = true
|
||||
if isResume {
|
||||
if err := hs.establishKeys(); err != nil {
|
||||
return err
|
||||
|
|
@ -220,6 +221,9 @@ NextCipherSuite:
|
|||
if err := hs.sendFinished(c.clientFinished[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := c.flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := hs.doFullHandshake(); err != nil {
|
||||
return err
|
||||
|
|
@ -230,6 +234,9 @@ NextCipherSuite:
|
|||
if err := hs.sendFinished(c.clientFinished[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := c.flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.clientFinishedIsFirst = true
|
||||
if err := hs.readSessionTicket(); err != nil {
|
||||
return err
|
||||
|
|
|
|||
|
|
@ -983,7 +983,7 @@ func (b *brokenConn) Write(data []byte) (int, error) {
|
|||
|
||||
func TestFailedWrite(t *testing.T) {
|
||||
// Test that a write error during the handshake is returned.
|
||||
for _, breakAfter := range []int{0, 1, 2, 3} {
|
||||
for _, breakAfter := range []int{0, 1} {
|
||||
c, s := net.Pipe()
|
||||
done := make(chan bool)
|
||||
|
||||
|
|
@ -1003,3 +1003,45 @@ func TestFailedWrite(t *testing.T) {
|
|||
<-done
|
||||
}
|
||||
}
|
||||
|
||||
// writeCountingConn wraps a net.Conn and counts the number of Write calls.
|
||||
type writeCountingConn struct {
|
||||
net.Conn
|
||||
|
||||
// numWrites is the number of writes that have been done.
|
||||
numWrites int
|
||||
}
|
||||
|
||||
func (wcc *writeCountingConn) Write(data []byte) (int, error) {
|
||||
wcc.numWrites++
|
||||
return wcc.Conn.Write(data)
|
||||
}
|
||||
|
||||
func TestBuffering(t *testing.T) {
|
||||
c, s := net.Pipe()
|
||||
done := make(chan bool)
|
||||
|
||||
clientWCC := &writeCountingConn{Conn: c}
|
||||
serverWCC := &writeCountingConn{Conn: s}
|
||||
|
||||
go func() {
|
||||
Server(serverWCC, testConfig).Handshake()
|
||||
serverWCC.Close()
|
||||
done <- true
|
||||
}()
|
||||
|
||||
err := Client(clientWCC, testConfig).Handshake()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
clientWCC.Close()
|
||||
<-done
|
||||
|
||||
if n := clientWCC.numWrites; n != 2 {
|
||||
t.Errorf("expected client handshake to complete with only two writes, but saw %d", n)
|
||||
}
|
||||
|
||||
if n := serverWCC.numWrites; n != 2 {
|
||||
t.Errorf("expected server handshake to complete with only two writes, but saw %d", n)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ func (c *Conn) serverHandshake() error {
|
|||
}
|
||||
|
||||
// For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3
|
||||
c.buffering = true
|
||||
if isResume {
|
||||
// The client has included a session ticket and so we do an abbreviated handshake.
|
||||
if err := hs.doResumeHandshake(); err != nil {
|
||||
|
|
@ -71,6 +72,9 @@ func (c *Conn) serverHandshake() error {
|
|||
if err := hs.sendFinished(c.serverFinished[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := c.flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.clientFinishedIsFirst = false
|
||||
if err := hs.readFinished(nil); err != nil {
|
||||
return err
|
||||
|
|
@ -89,12 +93,16 @@ func (c *Conn) serverHandshake() error {
|
|||
return err
|
||||
}
|
||||
c.clientFinishedIsFirst = true
|
||||
c.buffering = true
|
||||
if err := hs.sendSessionTicket(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := hs.sendFinished(nil); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := c.flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
c.handshakeComplete = true
|
||||
|
||||
|
|
@ -430,6 +438,10 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if _, err := c.flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pub crypto.PublicKey // public key for client auth, if any
|
||||
|
||||
msg, err := c.readHandshake()
|
||||
|
|
|
|||
|
|
@ -481,20 +481,19 @@ func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool
|
|||
|
||||
N := b.N
|
||||
|
||||
var serr error
|
||||
go func() {
|
||||
for i := 0; i < N; i++ {
|
||||
sconn, err := ln.Accept()
|
||||
if err != nil {
|
||||
serr = err
|
||||
return
|
||||
// panic rather than synchronize to avoid benchmark overhead
|
||||
// (cannot call b.Fatal in goroutine)
|
||||
panic(fmt.Errorf("accept: %v", err))
|
||||
}
|
||||
serverConfig := *testConfig
|
||||
serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
|
||||
srv := Server(sconn, &serverConfig)
|
||||
if err := srv.Handshake(); err != nil {
|
||||
serr = fmt.Errorf("handshake: %v", err)
|
||||
return
|
||||
panic(fmt.Errorf("handshake: %v", err))
|
||||
}
|
||||
io.Copy(srv, srv)
|
||||
}
|
||||
|
|
@ -504,7 +503,7 @@ func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool
|
|||
clientConfig := *testConfig
|
||||
clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
|
||||
|
||||
buf := make([]byte, 1<<16)
|
||||
buf := make([]byte, 1<<14)
|
||||
chunks := int(math.Ceil(float64(totalBytes) / float64(len(buf))))
|
||||
for i := 0; i < N; i++ {
|
||||
conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
|
||||
|
|
@ -570,20 +569,19 @@ func latency(b *testing.B, bps int, dynamicRecordSizingDisabled bool) {
|
|||
|
||||
N := b.N
|
||||
|
||||
var serr error
|
||||
go func() {
|
||||
for i := 0; i < N; i++ {
|
||||
sconn, err := ln.Accept()
|
||||
if err != nil {
|
||||
serr = err
|
||||
return
|
||||
// panic rather than synchronize to avoid benchmark overhead
|
||||
// (cannot call b.Fatal in goroutine)
|
||||
panic(fmt.Errorf("accept: %v", err))
|
||||
}
|
||||
serverConfig := *testConfig
|
||||
serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
|
||||
srv := Server(&slowConn{sconn, bps}, &serverConfig)
|
||||
if err := srv.Handshake(); err != nil {
|
||||
serr = fmt.Errorf("handshake: %v", err)
|
||||
return
|
||||
panic(fmt.Errorf("handshake: %v", err))
|
||||
}
|
||||
io.Copy(srv, srv)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1796,6 +1796,9 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
|
|||
func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) {
|
||||
var rawAttributes []asn1.RawValue
|
||||
b, err := asn1.Marshal(attributes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rest, err := asn1.Unmarshal(b, &rawAttributes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -86,34 +86,35 @@ var (
|
|||
// The exported fields can be changed to customize the details before the
|
||||
// first call to Read or ReadAll.
|
||||
//
|
||||
// Comma is the field delimiter. It defaults to ','.
|
||||
//
|
||||
// Comment, if not 0, is the comment character. Lines beginning with the
|
||||
// Comment character are ignored.
|
||||
//
|
||||
// If FieldsPerRecord is positive, Read requires each record to
|
||||
// have the given number of fields. If FieldsPerRecord is 0, Read sets it to
|
||||
// the number of fields in the first record, so that future records must
|
||||
// have the same field count. If FieldsPerRecord is negative, no check is
|
||||
// made and records may have a variable number of fields.
|
||||
//
|
||||
// If LazyQuotes is true, a quote may appear in an unquoted field and a
|
||||
// non-doubled quote may appear in a quoted field.
|
||||
//
|
||||
// If TrimLeadingSpace is true, leading white space in a field is ignored.
|
||||
// If the field delimiter is white space, TrimLeadingSpace will trim the
|
||||
// delimiter.
|
||||
type Reader struct {
|
||||
Comma rune // field delimiter (set to ',' by NewReader)
|
||||
Comment rune // comment character for start of line
|
||||
FieldsPerRecord int // number of expected fields per record
|
||||
LazyQuotes bool // allow lazy quotes
|
||||
TrailingComma bool // ignored; here for backwards compatibility
|
||||
TrimLeadingSpace bool // trim leading space
|
||||
line int
|
||||
column int
|
||||
r *bufio.Reader
|
||||
field bytes.Buffer
|
||||
// Comma is the field delimiter.
|
||||
// It is set to comma (',') by NewReader.
|
||||
Comma rune
|
||||
// Comment, if not 0, is the comment character. Lines beginning with the
|
||||
// Comment character without preceding whitespace are ignored.
|
||||
// With leading whitespace the Comment character becomes part of the
|
||||
// field, even if TrimLeadingSpace is true.
|
||||
Comment rune
|
||||
// FieldsPerRecord is the number of expected fields per record.
|
||||
// If FieldsPerRecord is positive, Read requires each record to
|
||||
// have the given number of fields. If FieldsPerRecord is 0, Read sets it to
|
||||
// the number of fields in the first record, so that future records must
|
||||
// have the same field count. If FieldsPerRecord is negative, no check is
|
||||
// made and records may have a variable number of fields.
|
||||
FieldsPerRecord int
|
||||
// If LazyQuotes is true, a quote may appear in an unquoted field and a
|
||||
// non-doubled quote may appear in a quoted field.
|
||||
LazyQuotes bool
|
||||
TrailingComma bool // ignored; here for backwards compatibility
|
||||
// If TrimLeadingSpace is true, leading white space in a field is ignored.
|
||||
// This is done even if the field delimiter, Comma, is white space.
|
||||
TrimLeadingSpace bool
|
||||
|
||||
line int
|
||||
column int
|
||||
r *bufio.Reader
|
||||
field bytes.Buffer
|
||||
}
|
||||
|
||||
// NewReader returns a new Reader that reads from r.
|
||||
|
|
|
|||
|
|
@ -90,8 +90,8 @@ import (
|
|||
// Int64String int64 `json:",string"`
|
||||
//
|
||||
// The key name will be used if it's a non-empty string consisting of
|
||||
// only Unicode letters, digits, dollar signs, percent signs, hyphens,
|
||||
// underscores and slashes.
|
||||
// only Unicode letters, digits, and ASCII punctuation except quotation
|
||||
// marks, backslash, and comma.
|
||||
//
|
||||
// Anonymous struct fields are usually marshaled as if their inner exported fields
|
||||
// were fields in the outer struct, subject to the usual Go visibility rules amended
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strconv"
|
||||
"time"
|
||||
|
|
@ -378,7 +379,21 @@ func Set(name, value string) error {
|
|||
|
||||
// isZeroValue guesses whether the string represents the zero
|
||||
// value for a flag. It is not accurate but in practice works OK.
|
||||
func isZeroValue(value string) bool {
|
||||
func isZeroValue(flag *Flag, value string) bool {
|
||||
// Build a zero value of the flag's Value type, and see if the
|
||||
// result of calling its String method equals the value passed in.
|
||||
// This works unless the Value type is itself an interface type.
|
||||
typ := reflect.TypeOf(flag.Value)
|
||||
var z reflect.Value
|
||||
if typ.Kind() == reflect.Ptr {
|
||||
z = reflect.New(typ.Elem())
|
||||
} else {
|
||||
z = reflect.Zero(typ)
|
||||
}
|
||||
if value == z.Interface().(Value).String() {
|
||||
return true
|
||||
}
|
||||
|
||||
switch value {
|
||||
case "false":
|
||||
return true
|
||||
|
|
@ -449,7 +464,7 @@ func (f *FlagSet) PrintDefaults() {
|
|||
s += "\n \t"
|
||||
}
|
||||
s += usage
|
||||
if !isZeroValue(flag.DefValue) {
|
||||
if !isZeroValue(flag, flag.DefValue) {
|
||||
if _, ok := flag.Value.(*stringValue); ok {
|
||||
// put quotes on the value
|
||||
s += fmt.Sprintf(" (default %q)", flag.DefValue)
|
||||
|
|
|
|||
|
|
@ -393,7 +393,7 @@ const defaultOutput = ` -A for bootstrapping, allow 'any' type
|
|||
-Z int
|
||||
an int that defaults to zero
|
||||
-maxT timeout
|
||||
set timeout for dial (default 0s)
|
||||
set timeout for dial
|
||||
`
|
||||
|
||||
func TestPrintDefaults(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ var pkgDeps = map[string][]string{
|
|||
"regexp": {"L2", "regexp/syntax"},
|
||||
"regexp/syntax": {"L2"},
|
||||
"runtime/debug": {"L2", "fmt", "io/ioutil", "os", "time"},
|
||||
"runtime/pprof": {"L2", "fmt", "text/tabwriter"},
|
||||
"runtime/pprof": {"L2", "fmt", "os", "text/tabwriter"},
|
||||
"runtime/trace": {"L0"},
|
||||
"text/tabwriter": {"L2"},
|
||||
|
||||
|
|
|
|||
|
|
@ -400,3 +400,28 @@ func TestIssue15517(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue15920(t *testing.T) {
|
||||
skipSpecialPlatforms(t)
|
||||
|
||||
// This package only handles gc export data.
|
||||
if runtime.Compiler != "gc" {
|
||||
t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
|
||||
return
|
||||
}
|
||||
|
||||
// On windows, we have to set the -D option for the compiler to avoid having a drive
|
||||
// letter and an illegal ':' in the import path - just skip it (see also issue #3483).
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("avoid dealing with relative paths/drive letters on windows")
|
||||
}
|
||||
|
||||
if f := compile(t, "testdata", "issue15920.go"); f != "" {
|
||||
defer os.Remove(f)
|
||||
}
|
||||
|
||||
imports := make(map[string]*types.Package)
|
||||
if _, err := Import(imports, "./testdata/issue15920", "."); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package p
|
||||
|
||||
// The underlying type of Error is the underlying type of error.
|
||||
// Make sure we can import this again without problems.
|
||||
type Error error
|
||||
|
||||
func F() Error { return nil }
|
||||
|
|
@ -73,7 +73,7 @@ const (
|
|||
//
|
||||
// The mode parameter controls the amount of source text parsed and other
|
||||
// optional parser functionality. Position information is recorded in the
|
||||
// file set fset.
|
||||
// file set fset, which must not be nil.
|
||||
//
|
||||
// If the source couldn't be read, the returned AST is nil and the error
|
||||
// indicates the specific failure. If the source was read but syntax
|
||||
|
|
@ -82,6 +82,10 @@ const (
|
|||
// are returned via a scanner.ErrorList which is sorted by file position.
|
||||
//
|
||||
func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) (f *ast.File, err error) {
|
||||
if fset == nil {
|
||||
panic("parser.ParseFile: no token.FileSet provided (fset == nil)")
|
||||
}
|
||||
|
||||
// get source
|
||||
text, err := readSource(filename, src)
|
||||
if err != nil {
|
||||
|
|
@ -125,7 +129,8 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode)
|
|||
//
|
||||
// If filter != nil, only the files with os.FileInfo entries passing through
|
||||
// the filter (and ending in ".go") are considered. The mode bits are passed
|
||||
// to ParseFile unchanged. Position information is recorded in fset.
|
||||
// to ParseFile unchanged. Position information is recorded in fset, which
|
||||
// must not be nil.
|
||||
//
|
||||
// If the directory couldn't be read, a nil map and the respective error are
|
||||
// returned. If a parse error occurred, a non-nil but incomplete map and the
|
||||
|
|
@ -169,9 +174,14 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m
|
|||
|
||||
// ParseExprFrom is a convenience function for parsing an expression.
|
||||
// The arguments have the same meaning as for Parse, but the source must
|
||||
// be a valid Go (type or value) expression.
|
||||
// be a valid Go (type or value) expression. Specifically, fset must not
|
||||
// be nil.
|
||||
//
|
||||
func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode Mode) (ast.Expr, error) {
|
||||
if fset == nil {
|
||||
panic("parser.ParseExprFrom: no token.FileSet provided (fset == nil)")
|
||||
}
|
||||
|
||||
// get source
|
||||
text, err := readSource(filename, src)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -572,6 +572,47 @@ func TestInitOrderInfo(t *testing.T) {
|
|||
`, []string{
|
||||
"a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
|
||||
}},
|
||||
// test case for issue 10709
|
||||
// TODO(gri) enable once the issue is fixed
|
||||
// {`package p13
|
||||
|
||||
// var (
|
||||
// v = t.m()
|
||||
// t = makeT(0)
|
||||
// )
|
||||
|
||||
// type T struct{}
|
||||
|
||||
// func (T) m() int { return 0 }
|
||||
|
||||
// func makeT(n int) T {
|
||||
// if n > 0 {
|
||||
// return makeT(n-1)
|
||||
// }
|
||||
// return T{}
|
||||
// }`, []string{
|
||||
// "t = makeT(0)", "v = t.m()",
|
||||
// }},
|
||||
// test case for issue 10709: same as test before, but variable decls swapped
|
||||
{`package p14
|
||||
|
||||
var (
|
||||
t = makeT(0)
|
||||
v = t.m()
|
||||
)
|
||||
|
||||
type T struct{}
|
||||
|
||||
func (T) m() int { return 0 }
|
||||
|
||||
func makeT(n int) T {
|
||||
if n > 0 {
|
||||
return makeT(n-1)
|
||||
}
|
||||
return T{}
|
||||
}`, []string{
|
||||
"t = makeT(0)", "v = t.m()",
|
||||
}},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
|
|
|||
|
|
@ -15,25 +15,40 @@ func (check *Checker) initOrder() {
|
|||
// built from several calls to (*Checker).Files. Clear it.
|
||||
check.Info.InitOrder = check.Info.InitOrder[:0]
|
||||
|
||||
// compute the object dependency graph and
|
||||
// initialize a priority queue with the list
|
||||
// of graph nodes
|
||||
// Compute the transposed object dependency graph and initialize
|
||||
// a priority queue with the list of graph nodes.
|
||||
pq := nodeQueue(dependencyGraph(check.objMap))
|
||||
heap.Init(&pq)
|
||||
|
||||
const debug = false
|
||||
if debug {
|
||||
fmt.Printf("package %s: object dependency graph\n", check.pkg.Name())
|
||||
for _, n := range pq {
|
||||
for _, o := range n.out {
|
||||
fmt.Printf("\t%s -> %s\n", n.obj.Name(), o.obj.Name())
|
||||
fmt.Printf("Computing initialization order for %s\n\n", check.pkg)
|
||||
fmt.Println("Object dependency graph:")
|
||||
for obj, d := range check.objMap {
|
||||
if len(d.deps) > 0 {
|
||||
fmt.Printf("\t%s depends on\n", obj.Name())
|
||||
for dep := range d.deps {
|
||||
fmt.Printf("\t\t%s\n", dep.Name())
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("\t%s has no dependencies\n", obj.Name())
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Printf("package %s: initialization order\n", check.pkg.Name())
|
||||
|
||||
fmt.Println("Transposed object dependency graph:")
|
||||
for _, n := range pq {
|
||||
fmt.Printf("\t%s depends on %d nodes\n", n.obj.Name(), n.in)
|
||||
for _, out := range n.out {
|
||||
fmt.Printf("\t\t%s is dependent\n", out.obj.Name())
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
fmt.Println("Processing nodes:")
|
||||
}
|
||||
|
||||
// determine initialization order by removing the highest priority node
|
||||
// Determine initialization order by removing the highest priority node
|
||||
// (the one with the fewest dependencies) and its edges from the graph,
|
||||
// repeatedly, until there are no nodes left.
|
||||
// In a valid Go program, those nodes always have zero dependencies (after
|
||||
|
|
@ -45,6 +60,11 @@ func (check *Checker) initOrder() {
|
|||
// get the next node
|
||||
n := heap.Pop(&pq).(*objNode)
|
||||
|
||||
if debug {
|
||||
fmt.Printf("\t%s (src pos %d) depends on %d nodes now\n",
|
||||
n.obj.Name(), n.obj.order(), n.in)
|
||||
}
|
||||
|
||||
// if n still depends on other nodes, we have a cycle
|
||||
if n.in > 0 {
|
||||
mark++ // mark nodes using a different value each time
|
||||
|
|
@ -86,14 +106,15 @@ func (check *Checker) initOrder() {
|
|||
}
|
||||
init := &Initializer{infoLhs, info.init}
|
||||
check.Info.InitOrder = append(check.Info.InitOrder, init)
|
||||
|
||||
if debug {
|
||||
fmt.Printf("\t%s\n", init)
|
||||
}
|
||||
}
|
||||
|
||||
if debug {
|
||||
fmt.Println()
|
||||
fmt.Println("Initialization order:")
|
||||
for _, init := range check.Info.InitOrder {
|
||||
fmt.Printf("\t%s\n", init)
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func (d *declInfo) hasInitializer() bool {
|
|||
return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil
|
||||
}
|
||||
|
||||
// addDep adds obj as a dependency to d.
|
||||
// addDep adds obj to the set of objects d's init expression depends on.
|
||||
func (d *declInfo) addDep(obj Object) {
|
||||
m := d.deps
|
||||
if m == nil {
|
||||
|
|
|
|||
10
src/io/io.go
10
src/io/io.go
|
|
@ -102,10 +102,12 @@ type Closer interface {
|
|||
// Seeker is the interface that wraps the basic Seek method.
|
||||
//
|
||||
// Seek sets the offset for the next Read or Write to offset,
|
||||
// interpreted according to whence: 0 means relative to the start of
|
||||
// the file, 1 means relative to the current offset, and 2 means
|
||||
// relative to the end. Seek returns the new offset relative to the
|
||||
// start of the file and an error, if any.
|
||||
// interpreted according to whence:
|
||||
// SeekStart means relative to the start of the file,
|
||||
// SeekCurrent means relative to the current offset, and
|
||||
// SeekEnd means relative to the end.
|
||||
// Seek returns the new offset relative to the start of the
|
||||
// file and an error, if any.
|
||||
//
|
||||
// Seeking to an offset before the start of the file is an error.
|
||||
// Seeking to any positive offset is legal, but the behavior of subsequent
|
||||
|
|
|
|||
|
|
@ -290,6 +290,11 @@ func TestFloat64Text(t *testing.T) {
|
|||
// Issue 2625.
|
||||
{383260575764816448, 'f', 0, "383260575764816448"},
|
||||
{383260575764816448, 'g', -1, "3.8326057576481645e+17"},
|
||||
|
||||
// Issue 15918.
|
||||
{1, 'f', -10, "1"},
|
||||
{1, 'f', -11, "1"},
|
||||
{1, 'f', -12, "1"},
|
||||
} {
|
||||
// The test cases are from the strconv package which tests float64 values.
|
||||
// When formatting values with prec = -1 (shortest representation),
|
||||
|
|
|
|||
|
|
@ -41,8 +41,11 @@ import (
|
|||
// x.Prec() mantissa bits.
|
||||
// The prec value is ignored for the 'b' or 'p' format.
|
||||
func (x *Float) Text(format byte, prec int) string {
|
||||
const extra = 10 // TODO(gri) determine a good/better value here
|
||||
return string(x.Append(make([]byte, 0, prec+extra), format, prec))
|
||||
cap := 10 // TODO(gri) determine a good/better value here
|
||||
if prec > 0 {
|
||||
cap += prec
|
||||
}
|
||||
return string(x.Append(make([]byte, 0, cap), format, prec))
|
||||
}
|
||||
|
||||
// String formats x like x.Text('g', 10).
|
||||
|
|
|
|||
|
|
@ -87,17 +87,14 @@ func TestDialTimeoutFDLeak(t *testing.T) {
|
|||
// socktest.Switch.
|
||||
// It may happen when the Dial call bumps against TCP
|
||||
// simultaneous open. See selfConnect in tcpsock_posix.go.
|
||||
defer func() {
|
||||
sw.Set(socktest.FilterClose, nil)
|
||||
forceCloseSockets()
|
||||
}()
|
||||
defer func() { sw.Set(socktest.FilterClose, nil) }()
|
||||
var mu sync.Mutex
|
||||
var attempts int
|
||||
sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) {
|
||||
mu.Lock()
|
||||
attempts++
|
||||
mu.Unlock()
|
||||
return nil, errTimedout
|
||||
return nil, nil
|
||||
})
|
||||
|
||||
const N = 100
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ import (
|
|||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"golang.org/x/net/lex/httplex"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
|
|
@ -42,6 +40,9 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/http2/hpack"
|
||||
"golang.org/x/net/lex/httplex"
|
||||
)
|
||||
|
||||
// ClientConnPool manages a pool of HTTP/2 client connections.
|
||||
|
|
@ -291,7 +292,7 @@ func http2configureTransport(t1 *Transport) (*http2Transport, error) {
|
|||
t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
|
||||
}
|
||||
upgradeFn := func(authority string, c *tls.Conn) RoundTripper {
|
||||
addr := http2authorityAddr(authority)
|
||||
addr := http2authorityAddr("https", authority)
|
||||
if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
|
||||
go c.Close()
|
||||
return http2erringRoundTripper{err}
|
||||
|
|
@ -2630,6 +2631,12 @@ type http2pipeBuffer interface {
|
|||
io.Reader
|
||||
}
|
||||
|
||||
func (p *http2pipe) Len() int {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
return p.b.Len()
|
||||
}
|
||||
|
||||
// Read waits until data is available and copies bytes
|
||||
// from the buffer into p.
|
||||
func (p *http2pipe) Read(d []byte) (n int, err error) {
|
||||
|
|
@ -4848,6 +4855,10 @@ type http2Transport struct {
|
|||
// uncompressed.
|
||||
DisableCompression bool
|
||||
|
||||
// AllowHTTP, if true, permits HTTP/2 requests using the insecure,
|
||||
// plain-text "http" scheme. Note that this does not enable h2c support.
|
||||
AllowHTTP bool
|
||||
|
||||
// MaxHeaderListSize is the http2 SETTINGS_MAX_HEADER_LIST_SIZE to
|
||||
// send in the initial settings frame. It is how many bytes
|
||||
// of response headers are allow. Unlike the http2 spec, zero here
|
||||
|
|
@ -4963,6 +4974,7 @@ type http2clientStream struct {
|
|||
done chan struct{} // closed when stream remove from cc.streams map; close calls guarded by cc.mu
|
||||
|
||||
// owned by clientConnReadLoop:
|
||||
firstByte bool // got the first response byte
|
||||
pastHeaders bool // got first MetaHeadersFrame (actual headers)
|
||||
pastTrailers bool // got optional second MetaHeadersFrame (trailers)
|
||||
|
||||
|
|
@ -5046,20 +5058,24 @@ func (t *http2Transport) RoundTrip(req *Request) (*Response, error) {
|
|||
|
||||
// authorityAddr returns a given authority (a host/IP, or host:port / ip:port)
|
||||
// and returns a host:port. The port 443 is added if needed.
|
||||
func http2authorityAddr(authority string) (addr string) {
|
||||
func http2authorityAddr(scheme string, authority string) (addr string) {
|
||||
if _, _, err := net.SplitHostPort(authority); err == nil {
|
||||
return authority
|
||||
}
|
||||
return net.JoinHostPort(authority, "443")
|
||||
port := "443"
|
||||
if scheme == "http" {
|
||||
port = "80"
|
||||
}
|
||||
return net.JoinHostPort(authority, port)
|
||||
}
|
||||
|
||||
// RoundTripOpt is like RoundTrip, but takes options.
|
||||
func (t *http2Transport) RoundTripOpt(req *Request, opt http2RoundTripOpt) (*Response, error) {
|
||||
if req.URL.Scheme != "https" {
|
||||
if !(req.URL.Scheme == "https" || (req.URL.Scheme == "http" && t.AllowHTTP)) {
|
||||
return nil, errors.New("http2: unsupported scheme")
|
||||
}
|
||||
|
||||
addr := http2authorityAddr(req.URL.Host)
|
||||
addr := http2authorityAddr(req.URL.Scheme, req.URL.Host)
|
||||
for {
|
||||
cc, err := t.connPool().GetClientConn(req, addr)
|
||||
if err != nil {
|
||||
|
|
@ -5944,15 +5960,18 @@ func (rl *http2clientConnReadLoop) processHeaders(f *http2MetaHeadersFrame) erro
|
|||
|
||||
return nil
|
||||
}
|
||||
if !cs.firstByte {
|
||||
if cs.trace != nil {
|
||||
|
||||
http2traceFirstResponseByte(cs.trace)
|
||||
}
|
||||
cs.firstByte = true
|
||||
}
|
||||
if !cs.pastHeaders {
|
||||
cs.pastHeaders = true
|
||||
} else {
|
||||
return rl.processTrailers(cs, f)
|
||||
}
|
||||
if cs.trace != nil {
|
||||
|
||||
http2traceFirstResponseByte(cs.trace)
|
||||
}
|
||||
|
||||
res, err := rl.handleResponse(cs, f)
|
||||
if err != nil {
|
||||
|
|
@ -6139,8 +6158,10 @@ func (b http2transportResponseBody) Read(p []byte) (n int, err error) {
|
|||
cc.inflow.add(connAdd)
|
||||
}
|
||||
if err == nil {
|
||||
if v := cs.inflow.available(); v < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh {
|
||||
streamAdd = http2transportDefaultStreamFlow - v
|
||||
|
||||
v := int(cs.inflow.available()) + cs.bufPipe.Len()
|
||||
if v < http2transportDefaultStreamFlow-http2transportDefaultStreamMinRefresh {
|
||||
streamAdd = int32(http2transportDefaultStreamFlow - v)
|
||||
cs.inflow.add(streamAdd)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ var (
|
|||
var errClosed = errors.New("i/o operation on closed connection")
|
||||
|
||||
// ServerConn is an artifact of Go's early HTTP implementation.
|
||||
// Is is low-level, old, and unused by Go's current HTTP stack.
|
||||
// It is low-level, old, and unused by Go's current HTTP stack.
|
||||
// We should have deleted it before Go 1.
|
||||
//
|
||||
// Deprecated: Use the Server in package net/http instead.
|
||||
|
|
@ -42,7 +42,7 @@ type ServerConn struct {
|
|||
}
|
||||
|
||||
// NewServerConn is an artifact of Go's early HTTP implementation.
|
||||
// Is is low-level, old, and unused by Go's current HTTP stack.
|
||||
// It is low-level, old, and unused by Go's current HTTP stack.
|
||||
// We should have deleted it before Go 1.
|
||||
//
|
||||
// Deprecated: Use the Server in package net/http instead.
|
||||
|
|
@ -218,7 +218,7 @@ func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
|
|||
}
|
||||
|
||||
// ClientConn is an artifact of Go's early HTTP implementation.
|
||||
// Is is low-level, old, and unused by Go's current HTTP stack.
|
||||
// It is low-level, old, and unused by Go's current HTTP stack.
|
||||
// We should have deleted it before Go 1.
|
||||
//
|
||||
// Deprecated: Use Client or Transport in package net/http instead.
|
||||
|
|
@ -236,7 +236,7 @@ type ClientConn struct {
|
|||
}
|
||||
|
||||
// NewClientConn is an artifact of Go's early HTTP implementation.
|
||||
// Is is low-level, old, and unused by Go's current HTTP stack.
|
||||
// It is low-level, old, and unused by Go's current HTTP stack.
|
||||
// We should have deleted it before Go 1.
|
||||
//
|
||||
// Deprecated: Use the Client or Transport in package net/http instead.
|
||||
|
|
@ -253,7 +253,7 @@ func NewClientConn(c net.Conn, r *bufio.Reader) *ClientConn {
|
|||
}
|
||||
|
||||
// NewProxyClientConn is an artifact of Go's early HTTP implementation.
|
||||
// Is is low-level, old, and unused by Go's current HTTP stack.
|
||||
// It is low-level, old, and unused by Go's current HTTP stack.
|
||||
// We should have deleted it before Go 1.
|
||||
//
|
||||
// Deprecated: Use the Client or Transport in package net/http instead.
|
||||
|
|
|
|||
|
|
@ -275,9 +275,9 @@ type Request struct {
|
|||
//
|
||||
// For outgoing client requests, the context controls cancelation.
|
||||
//
|
||||
// For incoming server requests, the context is canceled when either
|
||||
// the client's connection closes, or when the ServeHTTP method
|
||||
// returns.
|
||||
// For incoming server requests, the context is canceled when the
|
||||
// ServeHTTP method returns. For its associated values, see
|
||||
// ServerContextKey and LocalAddrContextKey.
|
||||
func (r *Request) Context() context.Context {
|
||||
if r.ctx != nil {
|
||||
return r.ctx
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue