mirror of https://github.com/golang/go.git
[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch
Semi-regular merge of tip to dev.ssa. Complicated a bit by the move of cmd/internal/* to cmd/compile/internal/*. Change-Id: I1c66d3c29bb95cce4a53c5a3476373aa5245303d
This commit is contained in:
commit
067e8dfd82
172
api/next.txt
172
api/next.txt
|
|
@ -1,6 +1,7 @@
|
|||
pkg archive/zip, method (*Writer) SetOffset(int64)
|
||||
pkg bufio, method (*Reader) Discard(int) (int, error)
|
||||
pkg bufio, method (ReadWriter) Discard(int) (int, error)
|
||||
pkg bytes, func LastIndexByte([]uint8, uint8) int
|
||||
pkg bytes, method (*Buffer) Cap() int
|
||||
pkg bytes, method (*Reader) Size() int64
|
||||
pkg crypto, type Decrypter interface { Decrypt, Public }
|
||||
|
|
@ -18,16 +19,56 @@ pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 49196
|
|||
pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16
|
||||
pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 49200
|
||||
pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16
|
||||
pkg crypto/tls, method (*Config) SetSessionTicketKeys([][32]uint8)
|
||||
pkg crypto/tls, type Certificate struct, SignedCertificateTimestamps [][]uint8
|
||||
pkg crypto/tls, type ConnectionState struct, OCSPResponse []uint8
|
||||
pkg crypto/tls, type ConnectionState struct, SignedCertificateTimestamps [][]uint8
|
||||
pkg crypto/x509, method (*CertificateRequest) CheckSignature() error
|
||||
pkg crypto/x509, type Certificate struct, UnhandledCriticalExtensions []asn1.ObjectIdentifier
|
||||
pkg crypto/x509/pkix, type Name struct, ExtraNames []AttributeTypeAndValue
|
||||
pkg database/sql, method (*DB) Stats() DBStats
|
||||
pkg database/sql, type DBStats struct
|
||||
pkg database/sql, type DBStats struct, OpenConnections int
|
||||
pkg debug/dwarf, const ClassAddress = 1
|
||||
pkg debug/dwarf, const ClassAddress Class
|
||||
pkg debug/dwarf, const ClassBlock = 2
|
||||
pkg debug/dwarf, const ClassBlock Class
|
||||
pkg debug/dwarf, const ClassConstant = 3
|
||||
pkg debug/dwarf, const ClassConstant Class
|
||||
pkg debug/dwarf, const ClassExprLoc = 4
|
||||
pkg debug/dwarf, const ClassExprLoc Class
|
||||
pkg debug/dwarf, const ClassFlag = 5
|
||||
pkg debug/dwarf, const ClassFlag Class
|
||||
pkg debug/dwarf, const ClassLinePtr = 6
|
||||
pkg debug/dwarf, const ClassLinePtr Class
|
||||
pkg debug/dwarf, const ClassLocListPtr = 7
|
||||
pkg debug/dwarf, const ClassLocListPtr Class
|
||||
pkg debug/dwarf, const ClassMacPtr = 8
|
||||
pkg debug/dwarf, const ClassMacPtr Class
|
||||
pkg debug/dwarf, const ClassRangeListPtr = 9
|
||||
pkg debug/dwarf, const ClassRangeListPtr Class
|
||||
pkg debug/dwarf, const ClassReference = 10
|
||||
pkg debug/dwarf, const ClassReference Class
|
||||
pkg debug/dwarf, const ClassReferenceAlt = 13
|
||||
pkg debug/dwarf, const ClassReferenceAlt Class
|
||||
pkg debug/dwarf, const ClassReferenceSig = 11
|
||||
pkg debug/dwarf, const ClassReferenceSig Class
|
||||
pkg debug/dwarf, const ClassString = 12
|
||||
pkg debug/dwarf, const ClassString Class
|
||||
pkg debug/dwarf, const ClassStringAlt = 14
|
||||
pkg debug/dwarf, const ClassStringAlt Class
|
||||
pkg debug/dwarf, method (*Data) LineReader(*Entry) (*LineReader, error)
|
||||
pkg debug/dwarf, method (*Entry) AttrField(Attr) *Field
|
||||
pkg debug/dwarf, method (*LineReader) Next(*LineEntry) error
|
||||
pkg debug/dwarf, method (*LineReader) Reset()
|
||||
pkg debug/dwarf, method (*LineReader) Seek(LineReaderPos)
|
||||
pkg debug/dwarf, method (*LineReader) SeekPC(uint64, *LineEntry) error
|
||||
pkg debug/dwarf, method (*LineReader) Tell() LineReaderPos
|
||||
pkg debug/dwarf, method (*Reader) AddressSize() int
|
||||
pkg debug/dwarf, method (Class) GoString() string
|
||||
pkg debug/dwarf, method (Class) String() string
|
||||
pkg debug/dwarf, type Class int
|
||||
pkg debug/dwarf, type Field struct, Class Class
|
||||
pkg debug/dwarf, type LineEntry struct
|
||||
pkg debug/dwarf, type LineEntry struct, Address uint64
|
||||
pkg debug/dwarf, type LineEntry struct, BasicBlock bool
|
||||
|
|
@ -227,48 +268,52 @@ pkg encoding/base64, var RawURLEncoding *Encoding
|
|||
pkg encoding/json, type UnmarshalTypeError struct, Offset int64
|
||||
pkg flag, func UnquoteUsage(*Flag) (string, string)
|
||||
pkg go/ast, type EmptyStmt struct, Implicit bool
|
||||
pkg go/exact, const Bool = 1
|
||||
pkg go/exact, const Bool Kind
|
||||
pkg go/exact, const Complex = 5
|
||||
pkg go/exact, const Complex Kind
|
||||
pkg go/exact, const Float = 4
|
||||
pkg go/exact, const Float Kind
|
||||
pkg go/exact, const Int = 3
|
||||
pkg go/exact, const Int Kind
|
||||
pkg go/exact, const String = 2
|
||||
pkg go/exact, const String Kind
|
||||
pkg go/exact, const Unknown = 0
|
||||
pkg go/exact, const Unknown Kind
|
||||
pkg go/exact, func BinaryOp(Value, token.Token, Value) Value
|
||||
pkg go/exact, func BitLen(Value) int
|
||||
pkg go/exact, func BoolVal(Value) bool
|
||||
pkg go/exact, func Bytes(Value) []uint8
|
||||
pkg go/exact, func Compare(Value, token.Token, Value) bool
|
||||
pkg go/exact, func Denom(Value) Value
|
||||
pkg go/exact, func Float32Val(Value) (float32, bool)
|
||||
pkg go/exact, func Float64Val(Value) (float64, bool)
|
||||
pkg go/exact, func Imag(Value) Value
|
||||
pkg go/exact, func Int64Val(Value) (int64, bool)
|
||||
pkg go/exact, func MakeBool(bool) Value
|
||||
pkg go/exact, func MakeFloat64(float64) Value
|
||||
pkg go/exact, func MakeFromBytes([]uint8) Value
|
||||
pkg go/exact, func MakeFromLiteral(string, token.Token) Value
|
||||
pkg go/exact, func MakeImag(Value) Value
|
||||
pkg go/exact, func MakeInt64(int64) Value
|
||||
pkg go/exact, func MakeString(string) Value
|
||||
pkg go/exact, func MakeUint64(uint64) Value
|
||||
pkg go/exact, func MakeUnknown() Value
|
||||
pkg go/exact, func Num(Value) Value
|
||||
pkg go/exact, func Real(Value) Value
|
||||
pkg go/exact, func Shift(Value, token.Token, uint) Value
|
||||
pkg go/exact, func Sign(Value) int
|
||||
pkg go/exact, func StringVal(Value) string
|
||||
pkg go/exact, func Uint64Val(Value) (uint64, bool)
|
||||
pkg go/exact, func UnaryOp(token.Token, Value, int) Value
|
||||
pkg go/exact, type Kind int
|
||||
pkg go/exact, type Value interface, Kind() Kind
|
||||
pkg go/exact, type Value interface, String() string
|
||||
pkg go/exact, type Value interface, unexported methods
|
||||
pkg go/build, type Package struct, PkgTargetRoot string
|
||||
pkg go/constant, const Bool = 1
|
||||
pkg go/constant, const Bool Kind
|
||||
pkg go/constant, const Complex = 5
|
||||
pkg go/constant, const Complex Kind
|
||||
pkg go/constant, const Float = 4
|
||||
pkg go/constant, const Float Kind
|
||||
pkg go/constant, const Int = 3
|
||||
pkg go/constant, const Int Kind
|
||||
pkg go/constant, const String = 2
|
||||
pkg go/constant, const String Kind
|
||||
pkg go/constant, const Unknown = 0
|
||||
pkg go/constant, const Unknown Kind
|
||||
pkg go/constant, func BinaryOp(Value, token.Token, Value) Value
|
||||
pkg go/constant, func BitLen(Value) int
|
||||
pkg go/constant, func BoolVal(Value) bool
|
||||
pkg go/constant, func Bytes(Value) []uint8
|
||||
pkg go/constant, func Compare(Value, token.Token, Value) bool
|
||||
pkg go/constant, func Denom(Value) Value
|
||||
pkg go/constant, func Float32Val(Value) (float32, bool)
|
||||
pkg go/constant, func Float64Val(Value) (float64, bool)
|
||||
pkg go/constant, func Imag(Value) Value
|
||||
pkg go/constant, func Int64Val(Value) (int64, bool)
|
||||
pkg go/constant, func MakeBool(bool) Value
|
||||
pkg go/constant, func MakeFloat64(float64) Value
|
||||
pkg go/constant, func MakeFromBytes([]uint8) Value
|
||||
pkg go/constant, func MakeFromLiteral(string, token.Token, uint) Value
|
||||
pkg go/constant, func MakeImag(Value) Value
|
||||
pkg go/constant, func MakeInt64(int64) Value
|
||||
pkg go/constant, func MakeString(string) Value
|
||||
pkg go/constant, func MakeUint64(uint64) Value
|
||||
pkg go/constant, func MakeUnknown() Value
|
||||
pkg go/constant, func Num(Value) Value
|
||||
pkg go/constant, func Real(Value) Value
|
||||
pkg go/constant, func Shift(Value, token.Token, uint) Value
|
||||
pkg go/constant, func Sign(Value) int
|
||||
pkg go/constant, func StringVal(Value) string
|
||||
pkg go/constant, func Uint64Val(Value) (uint64, bool)
|
||||
pkg go/constant, func UnaryOp(token.Token, Value, uint) Value
|
||||
pkg go/constant, type Kind int
|
||||
pkg go/constant, type Value interface, Kind() Kind
|
||||
pkg go/constant, type Value interface, String() string
|
||||
pkg go/constant, type Value interface, unexported methods
|
||||
pkg go/importer, func Default() types.Importer
|
||||
pkg go/importer, func For(string, Lookup) types.Importer
|
||||
pkg go/importer, type Lookup func(string) (io.ReadCloser, error)
|
||||
pkg go/types, const Bool = 1
|
||||
pkg go/types, const Bool BasicKind
|
||||
pkg go/types, const Byte = 8
|
||||
|
|
@ -376,6 +421,7 @@ pkg go/types, func New(string) Type
|
|||
pkg go/types, func NewArray(Type, int64) *Array
|
||||
pkg go/types, func NewChan(ChanDir, Type) *Chan
|
||||
pkg go/types, func NewChecker(*Config, *token.FileSet, *Package, *Info) *Checker
|
||||
pkg go/types, func NewConst(token.Pos, *Package, string, Type, constant.Value) *Const
|
||||
pkg go/types, func NewConst(token.Pos, *Package, string, Type, exact.Value) *Const
|
||||
pkg go/types, func NewField(token.Pos, *Package, string, Type, bool) *Var
|
||||
pkg go/types, func NewFunc(token.Pos, *Package, string, *Signature) *Func
|
||||
|
|
@ -432,6 +478,7 @@ pkg go/types, method (*Const) Pkg() *Package
|
|||
pkg go/types, method (*Const) Pos() token.Pos
|
||||
pkg go/types, method (*Const) String() string
|
||||
pkg go/types, method (*Const) Type() Type
|
||||
pkg go/types, method (*Const) Val() constant.Value
|
||||
pkg go/types, method (*Const) Val() exact.Value
|
||||
pkg go/types, method (*Func) Exported() bool
|
||||
pkg go/types, method (*Func) FullName() string
|
||||
|
|
@ -590,6 +637,7 @@ pkg go/types, type Config struct, Error func(error)
|
|||
pkg go/types, type Config struct, FakeImportC bool
|
||||
pkg go/types, type Config struct, IgnoreFuncBodies bool
|
||||
pkg go/types, type Config struct, Import Importer
|
||||
pkg go/types, type Config struct, Importer Importer
|
||||
pkg go/types, type Config struct, Packages map[string]*Package
|
||||
pkg go/types, type Config struct, Sizes Sizes
|
||||
pkg go/types, type Const struct
|
||||
|
|
@ -600,6 +648,8 @@ pkg go/types, type Error struct, Pos token.Pos
|
|||
pkg go/types, type Error struct, Soft bool
|
||||
pkg go/types, type Func struct
|
||||
pkg go/types, type Importer func(map[string]*Package, string) (*Package, error)
|
||||
pkg go/types, type Importer interface { Import }
|
||||
pkg go/types, type Importer interface, Import(string) (*Package, error)
|
||||
pkg go/types, type Info struct
|
||||
pkg go/types, type Info struct, Defs map[*ast.Ident]Object
|
||||
pkg go/types, type Info struct, Implicits map[ast.Node]Object
|
||||
|
|
@ -649,6 +699,7 @@ pkg go/types, type Type interface, String() string
|
|||
pkg go/types, type Type interface, Underlying() Type
|
||||
pkg go/types, type TypeAndValue struct
|
||||
pkg go/types, type TypeAndValue struct, Type Type
|
||||
pkg go/types, type TypeAndValue struct, Value constant.Value
|
||||
pkg go/types, type TypeAndValue struct, Value exact.Value
|
||||
pkg go/types, type TypeName struct
|
||||
pkg go/types, type Var struct
|
||||
|
|
@ -690,6 +741,18 @@ pkg image/color, type CMYK struct, K uint8
|
|||
pkg image/color, type CMYK struct, M uint8
|
||||
pkg image/color, type CMYK struct, Y uint8
|
||||
pkg image/color, var CMYKModel Model
|
||||
pkg image/gif, const DisposalBackground = 2
|
||||
pkg image/gif, const DisposalBackground ideal-int
|
||||
pkg image/gif, const DisposalNone = 1
|
||||
pkg image/gif, const DisposalNone ideal-int
|
||||
pkg image/gif, const DisposalPrevious = 3
|
||||
pkg image/gif, const DisposalPrevious ideal-int
|
||||
pkg image/gif, type GIF struct, BackgroundIndex uint8
|
||||
pkg image/gif, type GIF struct, Config image.Config
|
||||
pkg image/gif, type GIF struct, Disposal []uint8
|
||||
pkg io, func CopyBuffer(Writer, Reader, []uint8) (int64, error)
|
||||
pkg log, const LUTC = 32
|
||||
pkg log, const LUTC ideal-int
|
||||
pkg log, func Output(int, string) error
|
||||
pkg log, method (*Logger) SetOutput(io.Writer)
|
||||
pkg math/big, const Above = 1
|
||||
|
|
@ -716,6 +779,7 @@ pkg math/big, const ToPositiveInf = 5
|
|||
pkg math/big, const ToPositiveInf RoundingMode
|
||||
pkg math/big, const ToZero = 2
|
||||
pkg math/big, const ToZero RoundingMode
|
||||
pkg math/big, func Jacobi(*Int, *Int) int
|
||||
pkg math/big, func NewFloat(float64) *Float
|
||||
pkg math/big, func ParseFloat(string, int, uint, RoundingMode) (*Float, int, error)
|
||||
pkg math/big, func ScanFloat(io.ByteScanner, int, uint, RoundingMode) (*Float, int, error)
|
||||
|
|
@ -758,6 +822,7 @@ pkg math/big, method (*Float) Signbit() bool
|
|||
pkg math/big, method (*Float) String() string
|
||||
pkg math/big, method (*Float) Sub(*Float, *Float) *Float
|
||||
pkg math/big, method (*Float) Uint64() (uint64, Accuracy)
|
||||
pkg math/big, method (*Int) ModSqrt(*Int, *Int) *Int
|
||||
pkg math/big, method (Accuracy) String() string
|
||||
pkg math/big, method (ErrNaN) Error() string
|
||||
pkg math/big, method (RoundingMode) String() string
|
||||
|
|
@ -765,25 +830,48 @@ pkg math/big, type Accuracy int8
|
|||
pkg math/big, type ErrNaN struct
|
||||
pkg math/big, type Float struct
|
||||
pkg math/big, type RoundingMode uint8
|
||||
pkg mime, const BEncoding = 98
|
||||
pkg mime, const BEncoding WordEncoder
|
||||
pkg mime, const QEncoding = 113
|
||||
pkg mime, const QEncoding WordEncoder
|
||||
pkg mime, func ExtensionsByType(string) ([]string, error)
|
||||
pkg mime, method (*WordDecoder) Decode(string) (string, error)
|
||||
pkg mime, method (*WordDecoder) DecodeHeader(string) (string, error)
|
||||
pkg mime, method (WordEncoder) Encode(string, string) string
|
||||
pkg mime, type WordDecoder struct
|
||||
pkg mime, type WordDecoder struct, CharsetReader func(string, io.Reader) (io.Reader, error)
|
||||
pkg mime, type WordEncoder uint8
|
||||
pkg mime/quotedprintable, func NewReader(io.Reader) *Reader
|
||||
pkg mime/quotedprintable, func NewReader(io.Reader) io.Reader
|
||||
pkg mime/quotedprintable, func NewWriter(io.Writer) *Writer
|
||||
pkg mime/quotedprintable, method (*Reader) Read([]uint8) (int, error)
|
||||
pkg mime/quotedprintable, method (*Writer) Close() error
|
||||
pkg mime/quotedprintable, method (*Writer) Write([]uint8) (int, error)
|
||||
pkg mime/quotedprintable, type Reader struct
|
||||
pkg mime/quotedprintable, type Writer struct
|
||||
pkg mime/quotedprintable, type Writer struct, Binary bool
|
||||
pkg net, func SocketConn(*os.File, SocketAddr) (Conn, error)
|
||||
pkg net, func SocketPacketConn(*os.File, SocketAddr) (PacketConn, error)
|
||||
pkg net, type OpError struct, Source Addr
|
||||
pkg net, type SocketAddr interface { Addr, Raw }
|
||||
pkg net, type SocketAddr interface, Addr([]uint8) Addr
|
||||
pkg net, type SocketAddr interface, Raw(Addr) []uint8
|
||||
pkg net/http/fcgi, var ErrConnClosed error
|
||||
pkg net/http/fcgi, var ErrRequestAborted error
|
||||
pkg net/http/pprof, func Trace(http.ResponseWriter, *http.Request)
|
||||
pkg net/smtp, method (*Client) TLSConnectionState() (tls.ConnectionState, bool)
|
||||
pkg os, func LookupEnv(string) (string, bool)
|
||||
pkg os/signal, func Ignore(...os.Signal)
|
||||
pkg os/signal, func Reset(...os.Signal)
|
||||
pkg reflect, func ArrayOf(int, Type) Type
|
||||
pkg reflect, func FuncOf([]Type, []Type, bool) Type
|
||||
pkg runtime, func ReadTrace() []uint8
|
||||
pkg runtime, func StartTrace() error
|
||||
pkg runtime, func StopTrace()
|
||||
pkg runtime/pprof, func StartTrace(io.Writer) error
|
||||
pkg runtime/pprof, func StopTrace()
|
||||
pkg strings, func Compare(string, string) int
|
||||
pkg strings, func LastIndexByte(string, uint8) int
|
||||
pkg strings, method (*Reader) Size() int64
|
||||
pkg syscall (darwin-386), type SysProcAttr struct, Ctty int
|
||||
pkg syscall (darwin-386), type SysProcAttr struct, Foreground bool
|
||||
|
|
|
|||
|
|
@ -1382,7 +1382,7 @@ limit of how much data to read. Here is the signature of the
|
|||
<code>os</code>:
|
||||
</p>
|
||||
<pre>
|
||||
func (file *File) Read(buf []byte) (n int, err error)
|
||||
func (f *File) Read(buf []byte) (n int, err error)
|
||||
</pre>
|
||||
<p>
|
||||
The method returns the number of bytes read and an error value, if
|
||||
|
|
|
|||
|
|
@ -1,25 +1,29 @@
|
|||
Overall:
|
||||
toolchain in Go
|
||||
new GC
|
||||
- toolchain in Go
|
||||
- new GC
|
||||
- go tool asm, go tool compile, go tool link
|
||||
- default output files changed: now file.o and a.out
|
||||
|
||||
Language:
|
||||
permit omission of key type in map composite literals where key is a composite literal (https://golang.org/cl/2591)
|
||||
- permit omission of key type in map composite literals where key is a composite literal (https://golang.org/cl/2591)
|
||||
|
||||
Build:
|
||||
Go 1.4 required to build (https://golang.org/cl/2470, https://golang.org/cl/2993)
|
||||
- Go 1.4 required to build (https://golang.org/cl/2470, https://golang.org/cl/2993)
|
||||
|
||||
New Ports:
|
||||
darwin/arm, a.k.a iOS. (https://golang.org/cl/2118, 2119, 3273, 2121, 2122, ..., 2127)
|
||||
darwin/arm64
|
||||
linux/arm64 (cgo is supported, but only with external linking)
|
||||
openbsd/arm (no cgo or external linking)
|
||||
The port to Snow Leopard (OS X 10.6) is no longer actively maintained.
|
||||
|
||||
Runtime:
|
||||
goroutine scheduling order changed; never guaranteed by language, but can break tests that implicitly assume a specific execution order
|
||||
- darwin/arm, a.k.a iOS. (https://golang.org/cl/2118, 2119, 3273, 2121, 2122, ..., 2127)
|
||||
- darwin/arm64
|
||||
- linux/arm64 (cgo is supported, but only with external linking)
|
||||
- openbsd/arm (no cgo or external linking)
|
||||
|
||||
Removed Ports:
|
||||
dragonfly/386 (https://golang.org/cl/7543)
|
||||
- dragonfly/386 (https://golang.org/cl/7543)
|
||||
- The port to Snow Leopard (OS X 10.6) is no longer actively maintained.
|
||||
|
||||
Runtime:
|
||||
- goroutine scheduling order changed; never guaranteed by language,
|
||||
but can break tests that implicitly assume a specific execution
|
||||
order
|
||||
|
||||
API additions and behavior changes:
|
||||
|
||||
|
|
@ -53,9 +57,12 @@ mime: add ExtensionByType (https://golang.org/cl/7444)
|
|||
mime/quotedprintable: new package (https://golang.org/cl/5940 + others)
|
||||
net: add Source field to OpError (https://go-review.googlesource.com/9231)
|
||||
net: fix inconsistent errors (https://golang.org/cl/9236)
|
||||
net: add SocketConn, SocketPacketConn (https://golang.org/cl/9275)
|
||||
net: use Go's DNS resolver when system configuration permits (https://golang.org/cl/8945)
|
||||
net/http: support for setting trailers from a server Handler (https://golang.org/cl/2157)
|
||||
net/http: ignore the Unix epoch time in ServeContent (https://golang.org/cl/7915)
|
||||
net/http/cgi: fix REMOTE_ADDR, REMOTE_HOST, add REMOTE_PORT (https://golang.org/cl/4933)
|
||||
net/mail: adds AddressParser type (https://golang.org/cl/10392)
|
||||
net/smtp: add TLSConnectionState accessor (https://golang.org/cl/2151)
|
||||
os: add LookupEnv (https://golang.org/cl/9791)
|
||||
os/signal: add Ignore and Reset (https://golang.org/cl/3580)
|
||||
|
|
@ -63,6 +70,7 @@ reflect: add ArrayOf (https://golang.org/cl/4111)
|
|||
reflect: add FuncOf (https://golang.org/cl/1996)
|
||||
runtime, syscall: use SYSCALL instruction on FreeBSD (Go 1.5 now requires FreeBSD 8-STABLE+) (https://golang.org/cl/3020)
|
||||
runtime, syscall: use get_random_bytes syscall for NaCl (Go 1.5 now requires NaCl SDK pepper-39 or above) (https://golang.org/cl/1755)
|
||||
runtime/pprof: memory profiles include overall memory statistics by default (https://golang.org/cl/9491)
|
||||
strings: add Compare(x, y string) int, for symmetry with bytes.Compare (https://golang.org/cl/2828)
|
||||
syscall: Add Foreground and Pgid to SysProcAttr (https://golang.org/cl/5130)
|
||||
syscall: add missing Syscall9 for darwin/amd64 (https://golang.org/cl/6555)
|
||||
|
|
@ -106,6 +114,8 @@ cmd/gc: allocate backing storage for non-escaping interfaces on stack (https://g
|
|||
encoding/xml: avoid an allocation for tags without attributes (https://golang.org/cl/4160)
|
||||
image: many optimizations
|
||||
runtime: add ARM runtime.cmpstring and bytes.Compare (https://golang.org/cl/8010)
|
||||
runtime: do not scan maps when k/v do not contain pointers (https://golang.org/cl/3288)
|
||||
runtime: reduce thrashing of gs between ps (https://golang.org/cl/9872)
|
||||
sort: number of Sort performance optimizations (https://golang.org/cl/2100, https://golang.org/cl/2614, ...)
|
||||
strconv: optimize decimal to string conversion (https://golang.org/cl/2105)
|
||||
strconv: optimize float to string conversion (https://golang.org/cl/5600)
|
||||
|
|
|
|||
|
|
@ -1,24 +1,9 @@
|
|||
<!--{
|
||||
"Title": "The Go Programming Language Specification",
|
||||
"Subtitle": "Version of March 20, 2015",
|
||||
"Subtitle": "Version of May 26, 2015",
|
||||
"Path": "/ref/spec"
|
||||
}-->
|
||||
|
||||
<!--
|
||||
TODO
|
||||
[ ] need language about function/method calls and parameter passing rules
|
||||
[ ] last paragraph of #Assignments (constant promotion) should be elsewhere
|
||||
and mention assignment to empty interface.
|
||||
[ ] need to say something about "scope" of selectors?
|
||||
[ ] clarify what a field name is in struct declarations
|
||||
(struct{T} vs struct {T T} vs struct {t T})
|
||||
[ ] need explicit language about the result type of operations
|
||||
[ ] should probably write something about evaluation order of statements even
|
||||
though obvious
|
||||
[ ] in Selectors section, clarify what receiver value is passed in method invocations
|
||||
-->
|
||||
|
||||
|
||||
<h2 id="Introduction">Introduction</h2>
|
||||
|
||||
<p>
|
||||
|
|
@ -2605,7 +2590,7 @@ one may write:
|
|||
<pre>
|
||||
t.z // t.z
|
||||
t.y // t.T1.y
|
||||
t.x // (*t.TO).x
|
||||
t.x // (*t.T0).x
|
||||
|
||||
p.z // (*p).z
|
||||
p.y // (*p).T1.y
|
||||
|
|
@ -3305,7 +3290,7 @@ Operators combine operands into expressions.
|
|||
</p>
|
||||
|
||||
<pre class="ebnf">
|
||||
Expression = UnaryExpr | Expression binary_op UnaryExpr .
|
||||
Expression = UnaryExpr | Expression binary_op Expression .
|
||||
UnaryExpr = PrimaryExpr | unary_op UnaryExpr .
|
||||
|
||||
binary_op = "||" | "&&" | rel_op | add_op | mul_op .
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
// Cleaner removes anything from /data/local/tmp/goroot not on a builtin list.
|
||||
// Used by androidtest.bash.
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const goroot = "/data/local/tmp/goroot"
|
||||
expect := make(map[string]bool)
|
||||
for _, f := range strings.Split(files, "\n") {
|
||||
expect[filepath.Join(goroot, f)] = true
|
||||
}
|
||||
|
||||
err := filepath.Walk(goroot, func(path string, info os.FileInfo, err error) error {
|
||||
if expect[path] {
|
||||
return nil
|
||||
}
|
||||
log.Printf("removing %s", path)
|
||||
if err := os.RemoveAll(path); err != nil {
|
||||
return err
|
||||
}
|
||||
if info.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,8 @@ package cgotest
|
|||
|
||||
import "testing"
|
||||
|
||||
func TestSetgid(t *testing.T) { testSetgid(t) }
|
||||
func Test6997(t *testing.T) { test6997(t) }
|
||||
func TestBuildID(t *testing.T) { testBuildID(t) }
|
||||
func Test9400(t *testing.T) { test9400(t) }
|
||||
func TestSetgid(t *testing.T) { testSetgid(t) }
|
||||
func Test6997(t *testing.T) { test6997(t) }
|
||||
func TestBuildID(t *testing.T) { testBuildID(t) }
|
||||
func Test9400(t *testing.T) { test9400(t) }
|
||||
func TestSigProcMask(t *testing.T) { testSigProcMask(t) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright 2015 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.
|
||||
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
extern void IntoGoAndBack();
|
||||
|
||||
int CheckBlocked() {
|
||||
sigset_t mask;
|
||||
sigprocmask(SIG_BLOCK, NULL, &mask);
|
||||
return sigismember(&mask, SIGIO);
|
||||
}
|
||||
|
||||
static void* sigthreadfunc(void* unused) {
|
||||
sigset_t mask;
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, SIGIO);
|
||||
sigprocmask(SIG_BLOCK, &mask, NULL);
|
||||
IntoGoAndBack();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int RunSigThread() {
|
||||
pthread_t thread;
|
||||
int r;
|
||||
|
||||
r = pthread_create(&thread, NULL, &sigthreadfunc, NULL);
|
||||
if (r != 0)
|
||||
return r;
|
||||
return pthread_join(thread, NULL);
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2015 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
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -pthread
|
||||
#cgo LDFLAGS: -pthread
|
||||
extern int RunSigThread();
|
||||
extern int CheckBlocked();
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var blocked bool
|
||||
|
||||
//export IntoGoAndBack
|
||||
func IntoGoAndBack() {
|
||||
// Verify that SIGIO stays blocked on the C thread
|
||||
// even when unblocked for signal.Notify().
|
||||
signal.Notify(make(chan os.Signal), syscall.SIGIO)
|
||||
blocked = C.CheckBlocked() != 0
|
||||
}
|
||||
|
||||
func testSigProcMask(t *testing.T) {
|
||||
if r := C.RunSigThread(); r != 0 {
|
||||
t.Error("pthread_create/pthread_join failed")
|
||||
}
|
||||
if !blocked {
|
||||
t.Error("Go runtime unblocked SIGIO")
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,14 @@ if [ ! -f src/libgo/libgo.go ]; then
|
|||
fi
|
||||
|
||||
goos=$(go env GOOS)
|
||||
goarch=$(go env GOARCH)
|
||||
|
||||
# Directory where cgo headers and outputs will be installed.
|
||||
# The installation directory format varies depending on the platform.
|
||||
installdir=pkg/${goos}_${goarch}_testcshared_shared
|
||||
if [ "${goos}/${goarch}" == "android/arm" ]; then
|
||||
installdir=pkg/${goos}_${goarch}_testcshared
|
||||
fi
|
||||
|
||||
# Temporary directory on the android device.
|
||||
androidpath=/data/local/tmp/testcshared-$$
|
||||
|
|
@ -22,9 +30,9 @@ androidpath=/data/local/tmp/testcshared-$$
|
|||
function cleanup() {
|
||||
rm -rf libgo.so libgo2.so libgo.h testp testp2 testp3 pkg
|
||||
|
||||
rm -rf $(go env GOROOT)/pkg/$(go env GOOS)_$(go env GOARCH)_testcshared_shared
|
||||
rm -rf $(go env GOROOT)/${installdir}
|
||||
|
||||
if [ "$(go env GOOS)" == "android" ]; then
|
||||
if [ "$goos" == "android" ]; then
|
||||
adb shell rm -rf $androidpath
|
||||
fi
|
||||
}
|
||||
|
|
@ -38,11 +46,8 @@ function run() {
|
|||
case "$goos" in
|
||||
"android")
|
||||
local args=$@
|
||||
for ((i=0; i < ${#args}; i++)); do
|
||||
args[$i]=${args[$i]//.\//${androidpath}\/}
|
||||
args[$i]=${args[$i]//=./=${androidpath}}
|
||||
done
|
||||
output=$(adb shell ${args} | tr -d '\r')
|
||||
output=$(adb shell "cd ${androidpath}; $@")
|
||||
output=$(echo $output|tr -d '\r')
|
||||
case $output in
|
||||
*PASS) echo "PASS";;
|
||||
*) echo "$output";;
|
||||
|
|
@ -73,8 +78,9 @@ binpush libgo.so
|
|||
|
||||
# test0: exported symbols in shared lib are accessible.
|
||||
# TODO(iant): using _shared here shouldn't really be necessary.
|
||||
$(go env CC) $(go env GOGCCFLAGS) -I pkg/$(go env GOOS)_$(go env GOARCH)_testcshared_shared -o testp main0.c libgo.so
|
||||
$(go env CC) $(go env GOGCCFLAGS) -I ${installdir} -o testp main0.c libgo.so
|
||||
binpush testp
|
||||
|
||||
output=$(run LD_LIBRARY_PATH=. ./testp)
|
||||
if [ "$output" != "PASS" ]; then
|
||||
echo "FAIL test0 got ${output}"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,584 @@
|
|||
// Copyright 2015 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 shared_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
var gopathInstallDir, gorootInstallDir, suffix string
|
||||
|
||||
// This is the smallest set of packages we can link into a shared
|
||||
// library (runtime/cgo is built implicitly).
|
||||
var minpkgs = []string{"runtime", "sync/atomic"}
|
||||
var soname = "libruntime,sync-atomic.so"
|
||||
|
||||
// run runs a command and calls t.Errorf if it fails.
|
||||
func run(t *testing.T, msg string, args ...string) {
|
||||
c := exec.Command(args[0], args[1:]...)
|
||||
if output, err := c.CombinedOutput(); err != nil {
|
||||
t.Errorf("executing %s (%s) failed %s:\n%s", strings.Join(args, " "), msg, err, output)
|
||||
}
|
||||
}
|
||||
|
||||
// goCmd invokes the go tool with the installsuffix set up by TestMain. It calls
|
||||
// t.Errorf if the command fails.
|
||||
func goCmd(t *testing.T, args ...string) {
|
||||
newargs := []string{args[0], "-installsuffix=" + suffix}
|
||||
if testing.Verbose() {
|
||||
newargs = append(newargs, "-v")
|
||||
}
|
||||
newargs = append(newargs, args[1:]...)
|
||||
c := exec.Command("go", newargs...)
|
||||
var output []byte
|
||||
var err error
|
||||
if testing.Verbose() {
|
||||
fmt.Printf("+ go %s\n", strings.Join(newargs, " "))
|
||||
c.Stdout = os.Stdout
|
||||
c.Stderr = os.Stderr
|
||||
err = c.Run()
|
||||
} else {
|
||||
output, err = c.CombinedOutput()
|
||||
}
|
||||
if err != nil {
|
||||
if t != nil {
|
||||
t.Errorf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output)
|
||||
} else {
|
||||
log.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestMain calls testMain so that the latter can use defer (TestMain exits with os.Exit).
|
||||
func testMain(m *testing.M) (int, error) {
|
||||
// Because go install -buildmode=shared $standard_library_package always
|
||||
// installs into $GOROOT, here are some gymnastics to come up with a unique
|
||||
// installsuffix to use in this test that we can clean up afterwards.
|
||||
myContext := build.Default
|
||||
runtimeP, err := myContext.Import("runtime", ".", build.ImportComment)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("import failed: %v", err)
|
||||
}
|
||||
for i := 0; i < 10000; i++ {
|
||||
try := fmt.Sprintf("%s_%d_dynlink", runtimeP.PkgTargetRoot, rand.Int63())
|
||||
err = os.Mkdir(try, 0700)
|
||||
if os.IsExist(err) {
|
||||
continue
|
||||
}
|
||||
if err == nil {
|
||||
gorootInstallDir = try
|
||||
}
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("can't create temporary directory: %v", err)
|
||||
}
|
||||
if gorootInstallDir == "" {
|
||||
return 0, errors.New("could not create temporary directory after 10000 tries")
|
||||
}
|
||||
defer os.RemoveAll(gorootInstallDir)
|
||||
|
||||
// Some tests need to edit the source in GOPATH, so copy this directory to a
|
||||
// temporary directory and chdir to that.
|
||||
scratchDir, err := ioutil.TempDir("", "testshared")
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("TempDir failed: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(scratchDir)
|
||||
err = filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
||||
scratchPath := filepath.Join(scratchDir, path)
|
||||
if info.IsDir() {
|
||||
if path == "." {
|
||||
return nil
|
||||
}
|
||||
return os.Mkdir(scratchPath, info.Mode())
|
||||
} else {
|
||||
fromBytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(scratchPath, fromBytes, info.Mode())
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("walk failed: %v", err)
|
||||
}
|
||||
os.Setenv("GOPATH", scratchDir)
|
||||
myContext.GOPATH = scratchDir
|
||||
os.Chdir(scratchDir)
|
||||
|
||||
// All tests depend on runtime being built into a shared library. Because
|
||||
// that takes a few seconds, do it here and have all tests use the version
|
||||
// built here.
|
||||
suffix = strings.Split(filepath.Base(gorootInstallDir), "_")[2]
|
||||
goCmd(nil, append([]string{"install", "-buildmode=shared"}, minpkgs...)...)
|
||||
|
||||
myContext.InstallSuffix = suffix + "_dynlink"
|
||||
depP, err := myContext.Import("dep", ".", build.ImportComment)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("import failed: %v", err)
|
||||
}
|
||||
gopathInstallDir = depP.PkgTargetRoot
|
||||
return m.Run(), nil
|
||||
}
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
flag.Parse()
|
||||
exitCode, err := testMain(m)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
|
||||
// The shared library was built at the expected location.
|
||||
func TestSOBuilt(t *testing.T) {
|
||||
_, err := os.Stat(filepath.Join(gorootInstallDir, soname))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// The install command should have created a "shlibname" file for the
|
||||
// listed packages (and runtime/cgo) indicating the name of the shared
|
||||
// library containing it.
|
||||
func TestShlibnameFiles(t *testing.T) {
|
||||
pkgs := append([]string{}, minpkgs...)
|
||||
pkgs = append(pkgs, "runtime/cgo")
|
||||
for _, pkg := range pkgs {
|
||||
shlibnamefile := filepath.Join(gorootInstallDir, pkg+".shlibname")
|
||||
contentsb, err := ioutil.ReadFile(shlibnamefile)
|
||||
if err != nil {
|
||||
t.Errorf("error reading shlibnamefile for %s: %v", pkg, err)
|
||||
continue
|
||||
}
|
||||
contents := strings.TrimSpace(string(contentsb))
|
||||
if contents != soname {
|
||||
t.Errorf("shlibnamefile for %s has wrong contents: %q", pkg, contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is a given offset into the file contained in a loaded segment?
|
||||
func isOffsetLoaded(f *elf.File, offset uint64) bool {
|
||||
for _, prog := range f.Progs {
|
||||
if prog.Type == elf.PT_LOAD {
|
||||
if prog.Off <= offset && offset < prog.Off+prog.Filesz {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func rnd(v int32, r int32) int32 {
|
||||
if r <= 0 {
|
||||
return v
|
||||
}
|
||||
v += r - 1
|
||||
c := v % r
|
||||
if c < 0 {
|
||||
c += r
|
||||
}
|
||||
v -= c
|
||||
return v
|
||||
}
|
||||
|
||||
func readwithpad(r io.Reader, sz int32) ([]byte, error) {
|
||||
data := make([]byte, rnd(sz, 4))
|
||||
_, err := io.ReadFull(r, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data = data[:sz]
|
||||
return data, nil
|
||||
}
|
||||
|
||||
type note struct {
|
||||
name string
|
||||
tag int32
|
||||
desc string
|
||||
section *elf.Section
|
||||
}
|
||||
|
||||
// Read all notes from f. As ELF section names are not supposed to be special, one
|
||||
// looks for a particular note by scanning all SHT_NOTE sections looking for a note
|
||||
// with a particular "name" and "tag".
|
||||
func readNotes(f *elf.File) ([]*note, error) {
|
||||
var notes []*note
|
||||
for _, sect := range f.Sections {
|
||||
if sect.Type != elf.SHT_NOTE {
|
||||
continue
|
||||
}
|
||||
r := sect.Open()
|
||||
for {
|
||||
var namesize, descsize, tag int32
|
||||
err := binary.Read(r, f.ByteOrder, &namesize)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return nil, fmt.Errorf("read namesize failed:", err)
|
||||
}
|
||||
err = binary.Read(r, f.ByteOrder, &descsize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read descsize failed:", err)
|
||||
}
|
||||
err = binary.Read(r, f.ByteOrder, &tag)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read type failed:", err)
|
||||
}
|
||||
name, err := readwithpad(r, namesize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read name failed:", err)
|
||||
}
|
||||
desc, err := readwithpad(r, descsize)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read desc failed:", err)
|
||||
}
|
||||
notes = append(notes, ¬e{name: string(name), tag: tag, desc: string(desc), section: sect})
|
||||
}
|
||||
}
|
||||
return notes, nil
|
||||
}
|
||||
|
||||
func dynStrings(path string, flag elf.DynTag) []string {
|
||||
f, err := elf.Open(path)
|
||||
defer f.Close()
|
||||
if err != nil {
|
||||
log.Fatal("elf.Open failed: ", err)
|
||||
}
|
||||
dynstrings, err := f.DynString(flag)
|
||||
if err != nil {
|
||||
log.Fatal("dynstring failed: ", err)
|
||||
}
|
||||
return dynstrings
|
||||
}
|
||||
|
||||
func AssertIsLinkedTo(t *testing.T, path, lib string) {
|
||||
for _, dynstring := range dynStrings(path, elf.DT_NEEDED) {
|
||||
if dynstring == lib {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Errorf("%s is not linked to %s", path, lib)
|
||||
}
|
||||
|
||||
func AssertHasRPath(t *testing.T, path, dir string) {
|
||||
for _, tag := range []elf.DynTag{elf.DT_RPATH, elf.DT_RUNPATH} {
|
||||
for _, dynstring := range dynStrings(path, tag) {
|
||||
for _, rpath := range strings.Split(dynstring, ":") {
|
||||
if filepath.Clean(rpath) == filepath.Clean(dir) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
t.Errorf("%s does not have rpath %s", path, dir)
|
||||
}
|
||||
|
||||
// Build a trivial program that links against the shared runtime and check it runs.
|
||||
func TestTrivialExecutable(t *testing.T) {
|
||||
goCmd(t, "install", "-linkshared", "trivial")
|
||||
run(t, "trivial executable", "./bin/trivial")
|
||||
AssertIsLinkedTo(t, "./bin/trivial", soname)
|
||||
AssertHasRPath(t, "./bin/trivial", gorootInstallDir)
|
||||
}
|
||||
|
||||
// Build a GOPATH package into a shared library that links against the goroot runtime
|
||||
// and an executable that links against both.
|
||||
func TestGOPathShlib(t *testing.T) {
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
|
||||
AssertIsLinkedTo(t, filepath.Join(gopathInstallDir, "libdep.so"), soname)
|
||||
goCmd(t, "install", "-linkshared", "exe")
|
||||
AssertIsLinkedTo(t, "./bin/exe", soname)
|
||||
AssertIsLinkedTo(t, "./bin/exe", "libdep.so")
|
||||
AssertHasRPath(t, "./bin/exe", gorootInstallDir)
|
||||
AssertHasRPath(t, "./bin/exe", gopathInstallDir)
|
||||
// And check it runs.
|
||||
run(t, "executable linked to GOPATH library", "./bin/exe")
|
||||
}
|
||||
|
||||
// The shared library contains a note listing the packages it contains in a section
|
||||
// that is not mapped into memory.
|
||||
func testPkgListNote(t *testing.T, f *elf.File, note *note) {
|
||||
if note.section.Flags != 0 {
|
||||
t.Errorf("package list section has flags %v", note.section.Flags)
|
||||
}
|
||||
if isOffsetLoaded(f, note.section.Offset) {
|
||||
t.Errorf("package list section contained in PT_LOAD segment")
|
||||
}
|
||||
if note.desc != "dep\n" {
|
||||
t.Errorf("incorrect package list %q", note.desc)
|
||||
}
|
||||
}
|
||||
|
||||
// The shared library contains a note containing the ABI hash that is mapped into
|
||||
// memory and there is a local symbol called go.link.abihashbytes that points 16
|
||||
// bytes into it.
|
||||
func testABIHashNote(t *testing.T, f *elf.File, note *note) {
|
||||
if note.section.Flags != elf.SHF_ALLOC {
|
||||
t.Errorf("abi hash section has flags %v", note.section.Flags)
|
||||
}
|
||||
if !isOffsetLoaded(f, note.section.Offset) {
|
||||
t.Errorf("abihash section not contained in PT_LOAD segment")
|
||||
}
|
||||
var hashbytes elf.Symbol
|
||||
symbols, err := f.Symbols()
|
||||
if err != nil {
|
||||
t.Errorf("error reading symbols %v", err)
|
||||
return
|
||||
}
|
||||
for _, sym := range symbols {
|
||||
if sym.Name == "go.link.abihashbytes" {
|
||||
hashbytes = sym
|
||||
}
|
||||
}
|
||||
if hashbytes.Name == "" {
|
||||
t.Errorf("no symbol called go.link.abihashbytes")
|
||||
return
|
||||
}
|
||||
if elf.ST_BIND(hashbytes.Info) != elf.STB_LOCAL {
|
||||
t.Errorf("%s has incorrect binding %v", hashbytes.Name, elf.ST_BIND(hashbytes.Info))
|
||||
}
|
||||
if f.Sections[hashbytes.Section] != note.section {
|
||||
t.Errorf("%s has incorrect section %v", hashbytes.Name, f.Sections[hashbytes.Section].Name)
|
||||
}
|
||||
if hashbytes.Value-note.section.Addr != 16 {
|
||||
t.Errorf("%s has incorrect offset into section %d", hashbytes.Name, hashbytes.Value-note.section.Addr)
|
||||
}
|
||||
}
|
||||
|
||||
// A Go shared library contains a note indicating which other Go shared libraries it
|
||||
// was linked against in an unmapped section.
|
||||
func testDepsNote(t *testing.T, f *elf.File, note *note) {
|
||||
if note.section.Flags != 0 {
|
||||
t.Errorf("package list section has flags %v", note.section.Flags)
|
||||
}
|
||||
if isOffsetLoaded(f, note.section.Offset) {
|
||||
t.Errorf("package list section contained in PT_LOAD segment")
|
||||
}
|
||||
// libdep.so just links against the lib containing the runtime.
|
||||
if note.desc != soname {
|
||||
t.Errorf("incorrect dependency list %q", note.desc)
|
||||
}
|
||||
}
|
||||
|
||||
// The shared library contains notes with defined contents; see above.
|
||||
func TestNotes(t *testing.T) {
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
|
||||
f, err := elf.Open(filepath.Join(gopathInstallDir, "libdep.so"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
notes, err := readNotes(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
pkgListNoteFound := false
|
||||
abiHashNoteFound := false
|
||||
depsNoteFound := false
|
||||
for _, note := range notes {
|
||||
if note.name != "GO\x00\x00" {
|
||||
continue
|
||||
}
|
||||
switch note.tag {
|
||||
case 1: // ELF_NOTE_GOPKGLIST_TAG
|
||||
if pkgListNoteFound {
|
||||
t.Error("multiple package list notes")
|
||||
}
|
||||
testPkgListNote(t, f, note)
|
||||
pkgListNoteFound = true
|
||||
case 2: // ELF_NOTE_GOABIHASH_TAG
|
||||
if abiHashNoteFound {
|
||||
t.Error("multiple abi hash notes")
|
||||
}
|
||||
testABIHashNote(t, f, note)
|
||||
abiHashNoteFound = true
|
||||
case 3: // ELF_NOTE_GODEPS_TAG
|
||||
if depsNoteFound {
|
||||
t.Error("multiple abi hash notes")
|
||||
}
|
||||
testDepsNote(t, f, note)
|
||||
depsNoteFound = true
|
||||
}
|
||||
}
|
||||
if !pkgListNoteFound {
|
||||
t.Error("package list note not found")
|
||||
}
|
||||
if !abiHashNoteFound {
|
||||
t.Error("abi hash note not found")
|
||||
}
|
||||
if !depsNoteFound {
|
||||
t.Error("deps note not found")
|
||||
}
|
||||
}
|
||||
|
||||
// Build a GOPATH package (dep) into a shared library that links against the goroot
|
||||
// runtime, another package (dep2) that links against the first, and and an
|
||||
// executable that links against dep2.
|
||||
func TestTwoGOPathShlibs(t *testing.T) {
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep2")
|
||||
goCmd(t, "install", "-linkshared", "exe2")
|
||||
run(t, "executable linked to GOPATH library", "./bin/exe2")
|
||||
}
|
||||
|
||||
// Testing rebuilding of shared libraries when they are stale is a bit more
|
||||
// complicated that it seems like it should be. First, we make everything "old": but
|
||||
// only a few seconds old, or it might be older than 6g (or the runtime source) and
|
||||
// everything will get rebuilt. Then define a timestamp slightly newer than this
|
||||
// time, which is what we set the mtime to of a file to cause it to be seen as new,
|
||||
// and finally another slightly even newer one that we can compare files against to
|
||||
// see if they have been rebuilt.
|
||||
var oldTime = time.Now().Add(-9 * time.Second)
|
||||
var nearlyNew = time.Now().Add(-6 * time.Second)
|
||||
var stampTime = time.Now().Add(-3 * time.Second)
|
||||
|
||||
// resetFileStamps makes "everything" (bin, src, pkg from GOPATH and the
|
||||
// test-specific parts of GOROOT) appear old.
|
||||
func resetFileStamps() {
|
||||
chtime := func(path string, info os.FileInfo, err error) error {
|
||||
return os.Chtimes(path, oldTime, oldTime)
|
||||
}
|
||||
reset := func(path string) {
|
||||
if err := filepath.Walk(path, chtime); err != nil {
|
||||
log.Fatalf("resetFileStamps failed: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
reset("bin")
|
||||
reset("pkg")
|
||||
reset("src")
|
||||
reset(gorootInstallDir)
|
||||
}
|
||||
|
||||
// touch makes path newer than the "old" time stamp used by resetFileStamps.
|
||||
func touch(path string) {
|
||||
if err := os.Chtimes(path, nearlyNew, nearlyNew); err != nil {
|
||||
log.Fatalf("os.Chtimes failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// isNew returns if the path is newer than the time stamp used by touch.
|
||||
func isNew(path string) bool {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
log.Fatalf("os.Stat failed: %v", err)
|
||||
}
|
||||
return fi.ModTime().After(stampTime)
|
||||
}
|
||||
|
||||
// Fail unless path has been rebuilt (i.e. is newer than the time stamp used by
|
||||
// isNew)
|
||||
func AssertRebuilt(t *testing.T, msg, path string) {
|
||||
if !isNew(path) {
|
||||
t.Errorf("%s was not rebuilt (%s)", msg, path)
|
||||
}
|
||||
}
|
||||
|
||||
// Fail if path has been rebuilt (i.e. is newer than the time stamp used by isNew)
|
||||
func AssertNotRebuilt(t *testing.T, msg, path string) {
|
||||
if isNew(path) {
|
||||
t.Errorf("%s was rebuilt (%s)", msg, path)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRebuilding(t *testing.T) {
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
|
||||
goCmd(t, "install", "-linkshared", "exe")
|
||||
|
||||
// If the source is newer than both the .a file and the .so, both are rebuilt.
|
||||
resetFileStamps()
|
||||
touch("src/dep/dep.go")
|
||||
goCmd(t, "install", "-linkshared", "exe")
|
||||
AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "dep.a"))
|
||||
AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "libdep.so"))
|
||||
|
||||
// If the .a file is newer than the .so, the .so is rebuilt (but not the .a)
|
||||
resetFileStamps()
|
||||
touch(filepath.Join(gopathInstallDir, "dep.a"))
|
||||
goCmd(t, "install", "-linkshared", "exe")
|
||||
AssertNotRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "dep.a"))
|
||||
AssertRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "libdep.so"))
|
||||
}
|
||||
|
||||
func appendFile(path, content string) {
|
||||
f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0660)
|
||||
if err != nil {
|
||||
log.Fatalf("os.OpenFile failed: %v", err)
|
||||
}
|
||||
defer func() {
|
||||
err := f.Close()
|
||||
if err != nil {
|
||||
log.Fatalf("f.Close failed: %v", err)
|
||||
}
|
||||
}()
|
||||
_, err = f.WriteString(content)
|
||||
if err != nil {
|
||||
log.Fatalf("f.WriteString failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestABIChecking(t *testing.T) {
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
|
||||
goCmd(t, "install", "-linkshared", "exe")
|
||||
|
||||
// If we make an ABI-breaking change to dep and rebuild libp.so but not exe,
|
||||
// exe will abort with a complaint on startup.
|
||||
// This assumes adding an exported function breaks ABI, which is not true in
|
||||
// some senses but suffices for the narrow definition of ABI compatiblity the
|
||||
// toolchain uses today.
|
||||
appendFile("src/dep/dep.go", "func ABIBreak() {}\n")
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
|
||||
c := exec.Command("./bin/exe")
|
||||
output, err := c.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Fatal("executing exe did not fail after ABI break")
|
||||
}
|
||||
scanner := bufio.NewScanner(bytes.NewReader(output))
|
||||
foundMsg := false
|
||||
const wantLine = "abi mismatch detected between the executable and libdep.so"
|
||||
for scanner.Scan() {
|
||||
if scanner.Text() == wantLine {
|
||||
foundMsg = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if err = scanner.Err(); err != nil {
|
||||
t.Errorf("scanner encountered error: %v", err)
|
||||
}
|
||||
if !foundMsg {
|
||||
t.Fatalf("exe failed, but without line %q; got output:\n%s", wantLine, output)
|
||||
}
|
||||
|
||||
// Rebuilding exe makes it work again.
|
||||
goCmd(t, "install", "-linkshared", "exe")
|
||||
run(t, "rebuilt exe", "./bin/exe")
|
||||
|
||||
// If we make a change which does not break ABI (such as adding an unexported
|
||||
// function) and rebuild libdep.so, exe still works.
|
||||
appendFile("src/dep/dep.go", "func noABIBreak() {}\n")
|
||||
goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
|
||||
run(t, "after non-ABI breaking change", "./bin/exe")
|
||||
}
|
||||
|
|
@ -2,6 +2,12 @@ package dep
|
|||
|
||||
var V int = 1
|
||||
|
||||
var HasMask []string = []string{"hi"}
|
||||
|
||||
type HasProg struct {
|
||||
array [1024]*byte
|
||||
}
|
||||
|
||||
func F() int {
|
||||
return V
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package dep2
|
||||
|
||||
import "dep"
|
||||
|
||||
var W int = 1
|
||||
|
||||
var hasProg dep.HasProg
|
||||
|
||||
func G() int {
|
||||
return dep.F() + 1
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
import "dep2"
|
||||
|
||||
func main() {
|
||||
dep2.W = dep2.G() + 1
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
# Copyright 2015 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.
|
||||
|
||||
# Test that -buildmode=shared can produce a shared library and that
|
||||
# -linkshared can link against it to produce a working executable.
|
||||
|
||||
set -eu
|
||||
|
||||
export GOPATH="$(pwd)"
|
||||
|
||||
die () {
|
||||
echo $@
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Because go install -buildmode=shared $standard_library_package always
|
||||
# installs into $GOROOT, here are some gymnastics to come up with a
|
||||
# unique installsuffix to use in this test that we can clean up
|
||||
# afterwards.
|
||||
rootdir="$(dirname $(go list -f '{{.Target}}' runtime))"
|
||||
template="${rootdir}_XXXXXXXX_dynlink"
|
||||
std_install_dir=$(mktemp -d "$template")
|
||||
|
||||
cleanup () {
|
||||
rm -rf $std_install_dir ./bin/ ./pkg/
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
mysuffix=$(echo $std_install_dir | sed -e 's/.*_\([^_]*\)_dynlink/\1/')
|
||||
|
||||
# This is the smallest set of packages we can link into a shared
|
||||
# library (runtime/cgo is built implicitly). Check they are built into
|
||||
# a library with the expected name.
|
||||
minpkgs="runtime sync/atomic"
|
||||
soname=libruntime,sync-atomic.so
|
||||
|
||||
go install -installsuffix="$mysuffix" -buildmode=shared $minpkgs || die "install -buildmode=shared failed"
|
||||
|
||||
if [ ! -f "$std_install_dir/$soname" ]; then
|
||||
echo "$std_install_dir/$soname not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# The install command should have created a "shlibname" file for the
|
||||
# listed packages (and runtime/cgo) indicating the name of the shared
|
||||
# library containing it.
|
||||
for pkg in $minpkgs runtime/cgo; do
|
||||
if [ ! -f "$std_install_dir/$pkg.shlibname" ]; then
|
||||
die "no shlibname file for $pkg"
|
||||
fi
|
||||
if [ "$(cat "$std_install_dir/$pkg.shlibname")" != "$soname" ]; then
|
||||
die "shlibname file for $pkg has wrong contents"
|
||||
fi
|
||||
done
|
||||
|
||||
# Build a trivial program that links against the shared library we
|
||||
# just made and check it runs.
|
||||
go install -installsuffix="$mysuffix" -linkshared trivial || die "build -linkshared failed"
|
||||
./bin/trivial || die "./bin/trivial failed"
|
||||
|
||||
# And check that it is actually dynamically linked against the library
|
||||
# we hope it is linked against.
|
||||
|
||||
ensure_ldd () {
|
||||
a="$(ldd $1)" || die "ldd $1 failed: $a"
|
||||
{ echo "$a" | grep -q "$2"; } || die "$1 does not appear to be linked against $2"
|
||||
}
|
||||
|
||||
ensure_ldd ./bin/trivial $std_install_dir/$soname
|
||||
|
||||
# Build a GOPATH package into a shared library that links against the above one.
|
||||
rootdir="$(dirname $(go list -installsuffix="$mysuffix" -linkshared -f '{{.Target}}' dep))"
|
||||
go install -installsuffix="$mysuffix" -buildmode=shared -linkshared dep
|
||||
ensure_ldd $rootdir/libdep.so $std_install_dir/$soname
|
||||
|
||||
|
||||
# And exe that links against both
|
||||
go install -installsuffix="$mysuffix" -linkshared exe
|
||||
ensure_ldd ./bin/exe $rootdir/libdep.so
|
||||
ensure_ldd ./bin/exe $std_install_dir/$soname
|
||||
|
||||
# Now, test rebuilding of shared libraries when they are stale.
|
||||
|
||||
will_check_rebuilt () {
|
||||
for f in $@; do cp $f $f.bak; done
|
||||
}
|
||||
|
||||
assert_rebuilt () {
|
||||
find $1 -newer $1.bak | grep -q . || die "$1 was not rebuilt"
|
||||
}
|
||||
|
||||
assert_not_rebuilt () {
|
||||
find $1 -newer $1.bak | grep . && die "$1 was rebuilt" || true
|
||||
}
|
||||
|
||||
# If the source is newer than both the .a file and the .so, both are rebuilt.
|
||||
touch src/dep/dep.go
|
||||
will_check_rebuilt $rootdir/libdep.so $rootdir/dep.a
|
||||
go install -installsuffix="$mysuffix" -linkshared exe
|
||||
assert_rebuilt $rootdir/dep.a
|
||||
assert_rebuilt $rootdir/libdep.so
|
||||
|
||||
# If the .a file is newer than the .so, the .so is rebuilt (but not the .a)
|
||||
touch $rootdir/dep.a
|
||||
will_check_rebuilt $rootdir/libdep.so $rootdir/dep.a
|
||||
go install -installsuffix="$mysuffix" -linkshared exe
|
||||
assert_not_rebuilt $rootdir/dep.a
|
||||
assert_rebuilt $rootdir/libdep.so
|
||||
|
|
@ -35,7 +35,7 @@ go src=..
|
|||
gofmt_test.go
|
||||
testdata
|
||||
+
|
||||
link
|
||||
newlink
|
||||
testdata
|
||||
+
|
||||
archive
|
||||
|
|
|
|||
|
|
@ -1,6 +1,37 @@
|
|||
This directory contains helper file for trace viewer (go tool trace).
|
||||
This directory contains helper file for trace viewer (`go tool trace`).
|
||||
|
||||
trace_viewer_lean.html was generated following instructions in:
|
||||
https://github.com/google/trace-viewer/wiki/Embedding
|
||||
on revision 895aa74558d19d91906fb720df6458244ef160c6 using:
|
||||
`trace_viewer_lean.html` was generated by following
|
||||
[instructions](https://github.com/google/trace-viewer/wiki/Embedding)
|
||||
on revision `895aa74558d19d91906fb720df6458244ef160c6` using:
|
||||
```
|
||||
trace-viewer$ ./vulcanize_trace_viewer --config=lean
|
||||
```
|
||||
|
||||
The license for trace-viewer is as follows:
|
||||
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
|
|||
|
|
@ -24,10 +24,11 @@ if [ "$GOOS" != "android" ]; then
|
|||
fi
|
||||
|
||||
export CGO_ENABLED=1
|
||||
unset GOBIN
|
||||
|
||||
# Run the build for the host bootstrap, so we can build go_android_exec.
|
||||
# Do the build first, so we can build go_android_exec and cleaner.
|
||||
# Also lets us fail early before the (slow) adb push if the build is broken.
|
||||
./make.bash
|
||||
. ./make.bash --no-banner
|
||||
export GOROOT=$(dirname $(pwd))
|
||||
export PATH=$GOROOT/bin:$PATH
|
||||
GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \
|
||||
|
|
@ -50,9 +51,21 @@ cp -a "${GOROOT}/test" "${FAKE_GOROOT}/"
|
|||
cp -a "${GOROOT}/lib" "${FAKE_GOROOT}/"
|
||||
cp -a "${GOROOT}/pkg/android_$GOARCH" "${FAKE_GOROOT}/pkg/"
|
||||
echo '# Syncing test files to android device'
|
||||
adb shell mkdir -p /data/local/tmp/goroot
|
||||
time adb sync data &> /dev/null
|
||||
echo ''
|
||||
rm -rf "$ANDROID_PRODUCT_OUT"
|
||||
|
||||
# Run standard build and tests.
|
||||
./all.bash --no-clean
|
||||
export CLEANER=/tmp/androidcleaner-$$
|
||||
cp ../misc/android/cleaner.go $CLEANER.go
|
||||
echo 'var files = `' >> $CLEANER.go
|
||||
(cd $ANDROID_PRODUCT_OUT/data/local/tmp/goroot; find . >> $CLEANER.go)
|
||||
echo '`' >> $CLEANER.go
|
||||
go build -o $CLEANER $CLEANER.go
|
||||
adb push $CLEANER /data/local/tmp/cleaner
|
||||
rm $CLEANER $CLEANER.go
|
||||
adb shell /data/local/tmp/cleaner
|
||||
|
||||
rm -rf "$ANDROID_PRODUCT_OUT"
|
||||
echo ''
|
||||
|
||||
# Run standard tests.
|
||||
bash run.bash --no-rebuild
|
||||
|
|
|
|||
|
|
@ -463,6 +463,10 @@ func (tr *Reader) readHeader() *Header {
|
|||
hdr.Uid = int(tr.octal(s.next(8)))
|
||||
hdr.Gid = int(tr.octal(s.next(8)))
|
||||
hdr.Size = tr.octal(s.next(12))
|
||||
if hdr.Size < 0 {
|
||||
tr.err = ErrHeader
|
||||
return nil
|
||||
}
|
||||
hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
|
||||
s.next(8) // chksum
|
||||
hdr.Typeflag = s.next(1)[0]
|
||||
|
|
|
|||
|
|
@ -741,3 +741,19 @@ func TestUninitializedRead(t *testing.T) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
// Negative header size should not cause panic.
|
||||
// Issues 10959 and 10960.
|
||||
func TestNegativeHdrSize(t *testing.T) {
|
||||
f, err := os.Open("testdata/neg-size.tar")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
r := NewReader(f)
|
||||
_, err = r.Next()
|
||||
if err != ErrHeader {
|
||||
t.Error("want ErrHeader, got", err)
|
||||
}
|
||||
io.Copy(ioutil.Discard, r)
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -8,6 +8,7 @@ import (
|
|||
"bufio"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
|
|
@ -77,6 +78,9 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if end.directoryRecords > uint64(size)/fileHeaderLen {
|
||||
return fmt.Errorf("archive/zip: TOC declares impossible %d files in %d byte zip", end.directoryRecords, size)
|
||||
}
|
||||
z.r = r
|
||||
z.File = make([]*File, 0, end.directoryRecords)
|
||||
z.Comment = end.comment
|
||||
|
|
@ -146,16 +150,22 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
|
|||
if f.hasDataDescriptor() {
|
||||
desr = io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, dataDescriptorLen)
|
||||
}
|
||||
rc = &checksumReader{rc, crc32.NewIEEE(), f, desr, nil}
|
||||
rc = &checksumReader{
|
||||
rc: rc,
|
||||
hash: crc32.NewIEEE(),
|
||||
f: f,
|
||||
desr: desr,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type checksumReader struct {
|
||||
rc io.ReadCloser
|
||||
hash hash.Hash32
|
||||
f *File
|
||||
desr io.Reader // if non-nil, where to read the data descriptor
|
||||
err error // sticky error
|
||||
rc io.ReadCloser
|
||||
hash hash.Hash32
|
||||
nread uint64 // number of bytes read so far
|
||||
f *File
|
||||
desr io.Reader // if non-nil, where to read the data descriptor
|
||||
err error // sticky error
|
||||
}
|
||||
|
||||
func (r *checksumReader) Read(b []byte) (n int, err error) {
|
||||
|
|
@ -164,10 +174,14 @@ func (r *checksumReader) Read(b []byte) (n int, err error) {
|
|||
}
|
||||
n, err = r.rc.Read(b)
|
||||
r.hash.Write(b[:n])
|
||||
r.nread += uint64(n)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if err == io.EOF {
|
||||
if r.nread != r.f.UncompressedSize64 {
|
||||
return 0, io.ErrUnexpectedEOF
|
||||
}
|
||||
if r.desr != nil {
|
||||
if err1 := readDataDescriptor(r.desr, r.f); err1 != nil {
|
||||
err = err1
|
||||
|
|
|
|||
|
|
@ -531,3 +531,54 @@ func TestIssue8186(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verify we return ErrUnexpectedEOF when length is short.
|
||||
func TestIssue10957(t *testing.T) {
|
||||
data := []byte("PK\x03\x040000000PK\x01\x0200000" +
|
||||
"0000000000000000000\x00" +
|
||||
"\x00\x00\x00\x00\x00000000000000PK\x01" +
|
||||
"\x020000000000000000000" +
|
||||
"00000\v\x00\x00\x00\x00\x00000000000" +
|
||||
"00000000000000PK\x01\x0200" +
|
||||
"00000000000000000000" +
|
||||
"00\v\x00\x00\x00\x00\x00000000000000" +
|
||||
"00000000000PK\x01\x020000<" +
|
||||
"0\x00\x0000000000000000\v\x00\v" +
|
||||
"\x00\x00\x00\x00\x0000000000\x00\x00\x00\x00000" +
|
||||
"00000000PK\x01\x0200000000" +
|
||||
"0000000000000000\v\x00\x00\x00" +
|
||||
"\x00\x0000PK\x05\x06000000\x05\x000000" +
|
||||
"\v\x00\x00\x00\x00\x00")
|
||||
z, err := NewReader(bytes.NewReader(data), int64(len(data)))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for i, f := range z.File {
|
||||
r, err := f.Open()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if f.UncompressedSize64 < 1e6 {
|
||||
n, err := io.Copy(ioutil.Discard, r)
|
||||
if i == 3 && err != io.ErrUnexpectedEOF {
|
||||
t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err)
|
||||
}
|
||||
if err == nil && uint64(n) != f.UncompressedSize64 {
|
||||
t.Errorf("file %d: bad size: copied=%d; want=%d", i, n, f.UncompressedSize64)
|
||||
}
|
||||
}
|
||||
r.Close()
|
||||
}
|
||||
}
|
||||
|
||||
// Verify the number of files is sane.
|
||||
func TestIssue10956(t *testing.T) {
|
||||
data := []byte("PK\x06\x06PK\x06\a0000\x00\x00\x00\x00\x00\x00\x00\x00" +
|
||||
"0000PK\x05\x06000000000000" +
|
||||
"0000\v\x00000\x00\x00\x00\x00\x00\x00\x000")
|
||||
_, err := NewReader(bytes.NewReader(data), int64(len(data)))
|
||||
const want = "TOC declares impossible 3472328296227680304 files in 57 byte"
|
||||
if err == nil && !strings.Contains(err.Error(), want) {
|
||||
t.Errorf("error = %v; want %q", err, want)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ fi
|
|||
targets="$((ls runtime | sed -n 's/^rt0_\(.*\)_\(.*\)\.s/\1-\2/p'; echo linux-386-387 linux-arm-arm5) | sort | egrep -v android-arm | egrep "$pattern" | egrep 'linux|nacl')
|
||||
$(ls runtime | sed -n 's/^rt0_\(.*\)_\(.*\)\.s/\1-\2/p' | egrep -v 'android-arm|darwin-arm' | egrep "$pattern" | egrep -v 'linux|nacl')"
|
||||
|
||||
./make.bash
|
||||
./make.bash || exit 1
|
||||
GOROOT="$(cd .. && pwd)"
|
||||
|
||||
failed=false
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
package main
|
||||
|
|
@ -493,7 +493,10 @@ func (p *Parser) asmInstruction(op int, cond string, a []obj.Addr) {
|
|||
if arch.IsARM64STLXR(op) {
|
||||
prog.From = a[0]
|
||||
prog.To = a[1]
|
||||
prog.To2 = a[2]
|
||||
if a[2].Type != obj.TYPE_REG {
|
||||
p.errorf("invalid addressing modes for third operand to %s instruction, must be register", obj.Aconv(op))
|
||||
}
|
||||
prog.RegTo2 = a[2].Reg
|
||||
break
|
||||
}
|
||||
prog.From = a[0]
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ func Usage() {
|
|||
os.Exit(2)
|
||||
}
|
||||
|
||||
func Parse(theChar int) {
|
||||
func Parse() {
|
||||
flag.Usage = Usage
|
||||
flag.Parse()
|
||||
if flag.NArg() != 1 {
|
||||
|
|
@ -64,6 +64,6 @@ func Parse(theChar int) {
|
|||
if strings.HasSuffix(input, ".s") {
|
||||
input = input[:len(input)-2]
|
||||
}
|
||||
*OutputFile = fmt.Sprintf("%s.%c", input, theChar)
|
||||
*OutputFile = fmt.Sprintf("%s.o", input)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import (
|
|||
"text/scanner"
|
||||
|
||||
"cmd/asm/internal/flags"
|
||||
"cmd/internal/obj"
|
||||
)
|
||||
|
||||
// Input is the main input: a stack of readers and some macro definitions.
|
||||
|
|
@ -436,7 +435,7 @@ func (in *Input) line() {
|
|||
if tok != '\n' {
|
||||
in.Error("unexpected token at end of #line: ", tok)
|
||||
}
|
||||
obj.Linklinehist(linkCtxt, histLine, file, line)
|
||||
linkCtxt.LineHist.Update(histLine, file, line)
|
||||
in.Stack.SetPos(line, file)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ import (
|
|||
"strings"
|
||||
"text/scanner"
|
||||
"unicode"
|
||||
|
||||
"cmd/internal/obj"
|
||||
)
|
||||
|
||||
// A Tokenizer is a simple wrapping of text/scanner.Scanner, configured
|
||||
|
|
@ -40,7 +38,7 @@ func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer {
|
|||
s.Position.Filename = name
|
||||
s.IsIdentRune = isIdentRune
|
||||
if file != nil {
|
||||
obj.Linklinehist(linkCtxt, histLine, name, 0)
|
||||
linkCtxt.LineHist.Push(histLine, name)
|
||||
}
|
||||
return &Tokenizer{
|
||||
s: &s,
|
||||
|
|
@ -149,6 +147,6 @@ func (t *Tokenizer) Close() {
|
|||
if t.file != nil {
|
||||
t.file.Close()
|
||||
// It's an open file, so pop the line history.
|
||||
obj.Linklinehist(linkCtxt, histLine, "<pop>", 0)
|
||||
linkCtxt.LineHist.Pop(histLine)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ func main() {
|
|||
log.Fatalf("asm: unrecognized architecture %s", GOARCH)
|
||||
}
|
||||
|
||||
flags.Parse(architecture.Thechar)
|
||||
flags.Parse()
|
||||
|
||||
// Create object file, write header.
|
||||
fd, err := os.Create(*flags.OutputFile)
|
||||
|
|
|
|||
|
|
@ -846,6 +846,8 @@ func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||
fmt.Fprint(fgo2, "}\n")
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
|
||||
}
|
||||
|
||||
// Write out the C header allowing C code to call exported gccgo functions.
|
||||
|
|
@ -1009,6 +1011,8 @@ func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
|
|||
fmt.Fprint(fgo2, ")\n")
|
||||
fmt.Fprint(fgo2, "}\n")
|
||||
}
|
||||
|
||||
fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
|
||||
}
|
||||
|
||||
// writeExportHeader writes out the start of the _cgo_export.h file.
|
||||
|
|
@ -1374,6 +1378,17 @@ typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
|
|||
#endif
|
||||
|
||||
/* End of boilerplate cgo prologue. */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
`
|
||||
|
||||
// gccExportHeaderEpilog goes at the end of the generated header file.
|
||||
const gccExportHeaderEpilog = `
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
`
|
||||
|
||||
// gccgoExportFileProlog is written to the _cgo_export.c file when
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package amd64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/x86"
|
||||
)
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package amd64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/x86"
|
||||
)
|
||||
|
|
@ -65,7 +65,7 @@ func betypeinit() {
|
|||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
func Main() {
|
||||
if obj.Getgoos() == "nacl" {
|
||||
resvd = append(resvd, x86.REG_BP, x86.REG_R15)
|
||||
} else if obj.Framepointer_enabled != 0 {
|
||||
|
|
@ -101,6 +101,7 @@ func main() {
|
|||
gc.Thearch.Getg = getg
|
||||
gc.Thearch.Gins = gins
|
||||
gc.Thearch.Ginsboolval = ginsboolval
|
||||
gc.Thearch.Ginscmp = ginscmp
|
||||
gc.Thearch.Ginscon = ginscon
|
||||
gc.Thearch.Ginsnop = ginsnop
|
||||
gc.Thearch.Gmove = gmove
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package amd64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/x86"
|
||||
)
|
||||
|
|
@ -32,7 +32,7 @@ func defframe(ptxt *obj.Prog) {
|
|||
// iterate through declarations - they are sorted in decreasing xoffset order.
|
||||
for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
|
||||
n = l.N
|
||||
if !n.Needzero {
|
||||
if !n.Name.Needzero {
|
||||
continue
|
||||
}
|
||||
if n.Class != gc.PAUTO {
|
||||
|
|
@ -190,9 +190,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
|||
check := 0
|
||||
if gc.Issigned[t.Etype] {
|
||||
check = 1
|
||||
if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) {
|
||||
if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) {
|
||||
check = 0
|
||||
} else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 {
|
||||
} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
|
||||
check = 0
|
||||
}
|
||||
}
|
||||
|
|
@ -306,7 +306,7 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
|||
* known to be dead.
|
||||
*/
|
||||
func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) {
|
||||
r := int(reg[dr])
|
||||
r := reg[dr]
|
||||
|
||||
// save current ax and dx if they are live
|
||||
// and not the destination
|
||||
|
|
@ -318,7 +318,7 @@ func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) {
|
|||
x.Type = gc.Types[gc.TINT64]
|
||||
gmove(x, oldx)
|
||||
x.Type = t
|
||||
oldx.Ostk = int32(r) // squirrel away old r value
|
||||
oldx.Etype = r // squirrel away old r value
|
||||
reg[dr] = 1
|
||||
}
|
||||
}
|
||||
|
|
@ -326,7 +326,7 @@ func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) {
|
|||
func restx(x *gc.Node, oldx *gc.Node) {
|
||||
if oldx.Op != 0 {
|
||||
x.Type = gc.Types[gc.TINT64]
|
||||
reg[x.Reg] = uint8(oldx.Ostk)
|
||||
reg[x.Reg] = oldx.Etype
|
||||
gmove(oldx, x)
|
||||
gc.Regfree(oldx)
|
||||
}
|
||||
|
|
@ -381,7 +381,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
|||
var n1 gc.Node
|
||||
gc.Regalloc(&n1, nl.Type, res)
|
||||
gc.Cgen(nl, &n1)
|
||||
sc := uint64(gc.Mpgetfix(nr.Val.U.Xval))
|
||||
sc := uint64(nr.Int())
|
||||
if sc >= uint64(nl.Type.Width*8) {
|
||||
// large shift gets 2 shifts by width-1
|
||||
var n3 gc.Node
|
||||
|
|
@ -28,10 +28,11 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
package amd64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/big"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/x86"
|
||||
"fmt"
|
||||
|
|
@ -99,33 +100,67 @@ func ginscon(as int, c int64, n2 *gc.Node) {
|
|||
gins(as, &n1, n2)
|
||||
}
|
||||
|
||||
func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
|
||||
if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && gc.Smallintconst(n1) && n2.Op != gc.OLITERAL {
|
||||
// Reverse comparison to place constant last.
|
||||
op = gc.Brrev(op)
|
||||
n1, n2 = n2, n1
|
||||
}
|
||||
// General case.
|
||||
var r1, r2, g1, g2 gc.Node
|
||||
if n1.Op == gc.ONAME && n1.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG {
|
||||
r1 = *n1
|
||||
} else {
|
||||
gc.Regalloc(&r1, t, n1)
|
||||
gc.Regalloc(&g1, n1.Type, &r1)
|
||||
gc.Cgen(n1, &g1)
|
||||
gmove(&g1, &r1)
|
||||
}
|
||||
if n2.Op == gc.OLITERAL && gc.Isint[t.Etype] && gc.Smallintconst(n2) {
|
||||
r2 = *n2
|
||||
} else {
|
||||
gc.Regalloc(&r2, t, n2)
|
||||
gc.Regalloc(&g2, n1.Type, &r2)
|
||||
gc.Cgen(n2, &g2)
|
||||
gmove(&g2, &r2)
|
||||
}
|
||||
gins(optoas(gc.OCMP, t), &r1, &r2)
|
||||
if r1.Op == gc.OREGISTER {
|
||||
gc.Regfree(&g1)
|
||||
gc.Regfree(&r1)
|
||||
}
|
||||
if r2.Op == gc.OREGISTER {
|
||||
gc.Regfree(&g2)
|
||||
gc.Regfree(&r2)
|
||||
}
|
||||
return gc.Gbranch(optoas(op, t), nil, likely)
|
||||
}
|
||||
|
||||
func ginsboolval(a int, n *gc.Node) {
|
||||
gins(jmptoset(a), nil, n)
|
||||
}
|
||||
|
||||
/*
|
||||
* set up nodes representing 2^63
|
||||
*/
|
||||
var bigi gc.Node
|
||||
|
||||
var bigf gc.Node
|
||||
|
||||
var bignodes_did int
|
||||
// set up nodes representing 2^63
|
||||
var (
|
||||
bigi gc.Node
|
||||
bigf gc.Node
|
||||
bignodes_did bool
|
||||
)
|
||||
|
||||
func bignodes() {
|
||||
if bignodes_did != 0 {
|
||||
if bignodes_did {
|
||||
return
|
||||
}
|
||||
bignodes_did = 1
|
||||
bignodes_did = true
|
||||
|
||||
gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 1)
|
||||
gc.Mpshiftfix(bigi.Val.U.Xval, 63)
|
||||
var i big.Int
|
||||
i.SetInt64(1)
|
||||
i.Lsh(&i, 63)
|
||||
|
||||
bigf = bigi
|
||||
bigf.Type = gc.Types[gc.TFLOAT64]
|
||||
bigf.Val.Ctype = gc.CTFLT
|
||||
bigf.Val.U.Fval = new(gc.Mpflt)
|
||||
gc.Mpmovefixflt(bigf.Val.U.Fval, bigi.Val.U.Xval)
|
||||
gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
|
||||
bigi.SetBigInt(&i)
|
||||
|
||||
bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64])
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -156,7 +191,7 @@ func gmove(f *gc.Node, t *gc.Node) {
|
|||
// convert constant to desired type
|
||||
if f.Op == gc.OLITERAL {
|
||||
var con gc.Node
|
||||
gc.Convconst(&con, t.Type, &f.Val)
|
||||
f.Convconst(&con, t.Type)
|
||||
f = &con
|
||||
ft = tt // so big switch will choose a simple mov
|
||||
|
||||
|
|
@ -170,10 +205,7 @@ func gmove(f *gc.Node, t *gc.Node) {
|
|||
// 64-bit immediates are really 32-bit sign-extended
|
||||
// unless moving into a register.
|
||||
if gc.Isint[tt] {
|
||||
if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Minintval[gc.TINT32]) < 0 {
|
||||
goto hard
|
||||
}
|
||||
if gc.Mpcmpfixfix(con.Val.U.Xval, gc.Maxintval[gc.TINT32]) > 0 {
|
||||
if i := con.Int(); int64(int32(i)) != i {
|
||||
goto hard
|
||||
}
|
||||
}
|
||||
|
|
@ -1237,7 +1269,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
|
|||
if !gc.Isconst(n, gc.CTINT) {
|
||||
break
|
||||
}
|
||||
v := gc.Mpgetfix(n.Val.U.Xval)
|
||||
v := n.Int()
|
||||
if v >= 32000 || v <= -32000 {
|
||||
break
|
||||
}
|
||||
|
|
@ -28,10 +28,10 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
package amd64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/x86"
|
||||
"fmt"
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package amd64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/x86"
|
||||
)
|
||||
|
|
@ -28,10 +28,10 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
package amd64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/x86"
|
||||
)
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package arm
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm"
|
||||
)
|
||||
|
|
@ -53,28 +53,6 @@ func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
|
|||
return cgenindex(n, res, bounded)
|
||||
}
|
||||
|
||||
func gencmp0(n *gc.Node, t *gc.Type, o int, likely int, to *obj.Prog) {
|
||||
var n1 gc.Node
|
||||
|
||||
gc.Regalloc(&n1, t, nil)
|
||||
gc.Cgen(n, &n1)
|
||||
a := optoas(gc.OCMP, t)
|
||||
if a != arm.ACMP {
|
||||
var n2 gc.Node
|
||||
gc.Nodconst(&n2, t, 0)
|
||||
var n3 gc.Node
|
||||
gc.Regalloc(&n3, t, nil)
|
||||
gmove(&n2, &n3)
|
||||
gins(a, &n1, &n3)
|
||||
gc.Regfree(&n3)
|
||||
} else {
|
||||
gins(arm.ATST, &n1, nil)
|
||||
}
|
||||
a = optoas(o, t)
|
||||
gc.Patch(gc.Gbranch(a, t, likely), to)
|
||||
gc.Regfree(&n1)
|
||||
}
|
||||
|
||||
func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
|
||||
// determine alignment.
|
||||
// want to avoid unaligned access, so have to use
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package arm
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm"
|
||||
)
|
||||
|
|
@ -237,7 +237,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
|
|||
// shld hi:lo, c
|
||||
// shld lo:t, c
|
||||
case gc.OLROT:
|
||||
v := uint64(gc.Mpgetfix(r.Val.U.Xval))
|
||||
v := uint64(r.Int())
|
||||
|
||||
var bl gc.Node
|
||||
gc.Regalloc(&bl, lo1.Type, nil)
|
||||
|
|
@ -291,7 +291,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
|
|||
var p4 *obj.Prog
|
||||
var p5 *obj.Prog
|
||||
if r.Op == gc.OLITERAL {
|
||||
v := uint64(gc.Mpgetfix(r.Val.U.Xval))
|
||||
v := uint64(r.Int())
|
||||
if v >= 64 {
|
||||
// TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al)
|
||||
// here and below (verify it optimizes to EOR)
|
||||
|
|
@ -452,7 +452,7 @@ func cgen64(n *gc.Node, res *gc.Node) {
|
|||
var creg gc.Node
|
||||
var p3 *obj.Prog
|
||||
if r.Op == gc.OLITERAL {
|
||||
v := uint64(gc.Mpgetfix(r.Val.U.Xval))
|
||||
v := uint64(r.Int())
|
||||
if v >= 64 {
|
||||
if bh.Type.Etype == gc.TINT32 {
|
||||
// MOVW bh->31, al
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package arm
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm"
|
||||
)
|
||||
|
|
@ -37,7 +37,7 @@ func betypeinit() {
|
|||
gc.Widthreg = 4
|
||||
}
|
||||
|
||||
func main() {
|
||||
func Main() {
|
||||
gc.Thearch.Thechar = thechar
|
||||
gc.Thearch.Thestring = thestring
|
||||
gc.Thearch.Thelinkarch = thelinkarch
|
||||
|
|
@ -65,6 +65,7 @@ func main() {
|
|||
gc.Thearch.Expandchecks = expandchecks
|
||||
gc.Thearch.Getg = getg
|
||||
gc.Thearch.Gins = gins
|
||||
gc.Thearch.Ginscmp = ginscmp
|
||||
gc.Thearch.Ginscon = ginscon
|
||||
gc.Thearch.Ginsnop = ginsnop
|
||||
gc.Thearch.Gmove = gmove
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package arm
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm"
|
||||
)
|
||||
|
|
@ -30,7 +30,7 @@ func defframe(ptxt *obj.Prog) {
|
|||
r0 := uint32(0)
|
||||
for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
|
||||
n = l.N
|
||||
if !n.Needzero {
|
||||
if !n.Name.Needzero {
|
||||
continue
|
||||
}
|
||||
if n.Class != gc.PAUTO {
|
||||
|
|
@ -183,7 +183,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
|||
w := int(nl.Type.Width * 8)
|
||||
|
||||
if op == gc.OLROT {
|
||||
v := int(gc.Mpgetfix(nr.Val.U.Xval))
|
||||
v := nr.Int()
|
||||
var n1 gc.Node
|
||||
gc.Regalloc(&n1, nl.Type, res)
|
||||
if w == 32 {
|
||||
|
|
@ -210,7 +210,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
|||
var n1 gc.Node
|
||||
gc.Regalloc(&n1, nl.Type, res)
|
||||
gc.Cgen(nl, &n1)
|
||||
sc := uint64(gc.Mpgetfix(nr.Val.U.Xval))
|
||||
sc := uint64(nr.Int())
|
||||
if sc == 0 {
|
||||
} else // nothing to do
|
||||
if sc >= uint64(nl.Type.Width*8) {
|
||||
|
|
@ -479,6 +479,32 @@ func ginscon(as int, c int64, n *gc.Node) {
|
|||
gc.Regfree(&n2)
|
||||
}
|
||||
|
||||
func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
|
||||
if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n1.Int() == 0 && n2.Op != gc.OLITERAL {
|
||||
op = gc.Brrev(op)
|
||||
n1, n2 = n2, n1
|
||||
}
|
||||
var r1, r2, g1, g2 gc.Node
|
||||
gc.Regalloc(&r1, t, n1)
|
||||
gc.Regalloc(&g1, n1.Type, &r1)
|
||||
gc.Cgen(n1, &g1)
|
||||
gmove(&g1, &r1)
|
||||
if gc.Isint[t.Etype] && n2.Op == gc.OLITERAL && n2.Int() == 0 {
|
||||
gins(arm.ACMP, &r1, n2)
|
||||
} else {
|
||||
gc.Regalloc(&r2, t, n2)
|
||||
gc.Regalloc(&g2, n1.Type, &r2)
|
||||
gc.Cgen(n2, &g2)
|
||||
gmove(&g2, &r2)
|
||||
gins(optoas(gc.OCMP, t), &r1, &r2)
|
||||
gc.Regfree(&g2)
|
||||
gc.Regfree(&r2)
|
||||
}
|
||||
gc.Regfree(&g1)
|
||||
gc.Regfree(&r1)
|
||||
return gc.Gbranch(optoas(op, t), nil, likely)
|
||||
}
|
||||
|
||||
// addr += index*width if possible.
|
||||
func addindex(index *gc.Node, width int64, addr *gc.Node) bool {
|
||||
switch width {
|
||||
|
|
@ -28,10 +28,10 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
package arm
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm"
|
||||
"fmt"
|
||||
|
|
@ -53,7 +53,7 @@ func ncon(i uint32) *gc.Node {
|
|||
if ncon_n.Type == nil {
|
||||
gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0)
|
||||
}
|
||||
gc.Mpmovecfix(ncon_n.Val.U.Xval, int64(i))
|
||||
ncon_n.SetInt(int64(i))
|
||||
return &ncon_n
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +89,7 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
|
|||
case gc.ONAME:
|
||||
if n.Class == gc.PPARAMREF {
|
||||
var n1 gc.Node
|
||||
gc.Cgen(n.Heapaddr, &n1)
|
||||
gc.Cgen(n.Name.Heapaddr, &n1)
|
||||
sclean[nsclean-1] = n1
|
||||
n = &n1
|
||||
}
|
||||
|
|
@ -111,8 +111,8 @@ func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
|
|||
|
||||
case gc.OLITERAL:
|
||||
var n1 gc.Node
|
||||
gc.Convconst(&n1, n.Type, &n.Val)
|
||||
i := gc.Mpgetfix(n1.Val.U.Xval)
|
||||
n.Convconst(&n1, n.Type)
|
||||
i := n1.Int()
|
||||
gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i)))
|
||||
i >>= 32
|
||||
if n.Type.Etype == gc.TINT64 {
|
||||
|
|
@ -160,12 +160,12 @@ func gmove(f *gc.Node, t *gc.Node) {
|
|||
var con gc.Node
|
||||
switch tt {
|
||||
default:
|
||||
gc.Convconst(&con, t.Type, &f.Val)
|
||||
f.Convconst(&con, t.Type)
|
||||
|
||||
case gc.TINT16,
|
||||
gc.TINT8:
|
||||
var con gc.Node
|
||||
gc.Convconst(&con, gc.Types[gc.TINT32], &f.Val)
|
||||
f.Convconst(&con, gc.Types[gc.TINT32])
|
||||
var r1 gc.Node
|
||||
gc.Regalloc(&r1, con.Type, t)
|
||||
gins(arm.AMOVW, &con, &r1)
|
||||
|
|
@ -176,7 +176,7 @@ func gmove(f *gc.Node, t *gc.Node) {
|
|||
case gc.TUINT16,
|
||||
gc.TUINT8:
|
||||
var con gc.Node
|
||||
gc.Convconst(&con, gc.Types[gc.TUINT32], &f.Val)
|
||||
f.Convconst(&con, gc.Types[gc.TUINT32])
|
||||
var r1 gc.Node
|
||||
gc.Regalloc(&r1, con.Type, t)
|
||||
gins(arm.AMOVW, &con, &r1)
|
||||
|
|
@ -1118,7 +1118,7 @@ func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
|
|||
if !gc.Isconst(n, gc.CTINT) {
|
||||
break
|
||||
}
|
||||
v := gc.Mpgetfix(n.Val.U.Xval)
|
||||
v := n.Int()
|
||||
if v >= 32000 || v <= -32000 {
|
||||
break
|
||||
}
|
||||
|
|
@ -28,10 +28,10 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
package arm
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm"
|
||||
"fmt"
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package arm
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm"
|
||||
)
|
||||
|
|
@ -28,10 +28,10 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
package arm
|
||||
|
||||
import "cmd/internal/obj/arm"
|
||||
import "cmd/internal/gc"
|
||||
import "cmd/compile/internal/gc"
|
||||
|
||||
const (
|
||||
NREGVAR = 32
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package arm64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm64"
|
||||
)
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package arm64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm64"
|
||||
)
|
||||
|
|
@ -37,7 +37,7 @@ func betypeinit() {
|
|||
gc.Widthreg = 8
|
||||
}
|
||||
|
||||
func main() {
|
||||
func Main() {
|
||||
gc.Thearch.Thechar = thechar
|
||||
gc.Thearch.Thestring = thestring
|
||||
gc.Thearch.Thelinkarch = thelinkarch
|
||||
|
|
@ -65,6 +65,7 @@ func main() {
|
|||
gc.Thearch.Expandchecks = expandchecks
|
||||
gc.Thearch.Getg = getg
|
||||
gc.Thearch.Gins = gins
|
||||
gc.Thearch.Ginscmp = ginscmp
|
||||
gc.Thearch.Ginscon = ginscon
|
||||
gc.Thearch.Ginsnop = ginsnop
|
||||
gc.Thearch.Gmove = gmove
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package arm64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm64"
|
||||
"fmt"
|
||||
|
|
@ -32,7 +32,7 @@ func defframe(ptxt *obj.Prog) {
|
|||
// iterate through declarations - they are sorted in decreasing xoffset order.
|
||||
for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
|
||||
n = l.N
|
||||
if !n.Needzero {
|
||||
if !n.Name.Needzero {
|
||||
continue
|
||||
}
|
||||
if n.Class != gc.PAUTO {
|
||||
|
|
@ -147,9 +147,9 @@ func dodiv(op int, nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
|||
check := 0
|
||||
if gc.Issigned[t.Etype] {
|
||||
check = 1
|
||||
if gc.Isconst(nl, gc.CTINT) && gc.Mpgetfix(nl.Val.U.Xval) != -(1<<uint64(t.Width*8-1)) {
|
||||
if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) {
|
||||
check = 0
|
||||
} else if gc.Isconst(nr, gc.CTINT) && gc.Mpgetfix(nr.Val.U.Xval) != -1 {
|
||||
} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
|
||||
check = 0
|
||||
}
|
||||
}
|
||||
|
|
@ -312,7 +312,7 @@ func cgen_shift(op int, bounded bool, nl *gc.Node, nr *gc.Node, res *gc.Node) {
|
|||
var n1 gc.Node
|
||||
gc.Regalloc(&n1, nl.Type, res)
|
||||
gc.Cgen(nl, &n1)
|
||||
sc := uint64(uint64(gc.Mpgetfix(nr.Val.U.Xval)))
|
||||
sc := uint64(nr.Int())
|
||||
if sc >= uint64(nl.Type.Width*8) {
|
||||
// large shift gets 2 shifts by width-1
|
||||
var n3 gc.Node
|
||||
|
|
@ -28,10 +28,10 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
package arm64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm64"
|
||||
"fmt"
|
||||
|
|
@ -102,6 +102,34 @@ func ginscon2(as int, n2 *gc.Node, c int64) {
|
|||
gc.Regfree(&ntmp)
|
||||
}
|
||||
|
||||
func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
|
||||
if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL {
|
||||
// Reverse comparison to place constant last.
|
||||
op = gc.Brrev(op)
|
||||
n1, n2 = n2, n1
|
||||
}
|
||||
|
||||
var r1, r2, g1, g2 gc.Node
|
||||
gc.Regalloc(&r1, t, n1)
|
||||
gc.Regalloc(&g1, n1.Type, &r1)
|
||||
gc.Cgen(n1, &g1)
|
||||
gmove(&g1, &r1)
|
||||
if gc.Isint[t.Etype] && gc.Isconst(n2, gc.CTINT) {
|
||||
ginscon2(optoas(gc.OCMP, t), &r1, n2.Int())
|
||||
} else {
|
||||
gc.Regalloc(&r2, t, n2)
|
||||
gc.Regalloc(&g2, n1.Type, &r2)
|
||||
gc.Cgen(n2, &g2)
|
||||
gmove(&g2, &r2)
|
||||
gcmp(optoas(gc.OCMP, t), &r1, &r2)
|
||||
gc.Regfree(&g2)
|
||||
gc.Regfree(&r2)
|
||||
}
|
||||
gc.Regfree(&g1)
|
||||
gc.Regfree(&r1)
|
||||
return gc.Gbranch(optoas(op, t), nil, likely)
|
||||
}
|
||||
|
||||
/*
|
||||
* generate move:
|
||||
* t = f
|
||||
|
|
@ -133,13 +161,13 @@ func gmove(f *gc.Node, t *gc.Node) {
|
|||
var con gc.Node
|
||||
switch tt {
|
||||
default:
|
||||
gc.Convconst(&con, t.Type, &f.Val)
|
||||
f.Convconst(&con, t.Type)
|
||||
|
||||
case gc.TINT32,
|
||||
gc.TINT16,
|
||||
gc.TINT8:
|
||||
var con gc.Node
|
||||
gc.Convconst(&con, gc.Types[gc.TINT64], &f.Val)
|
||||
f.Convconst(&con, gc.Types[gc.TINT64])
|
||||
var r1 gc.Node
|
||||
gc.Regalloc(&r1, con.Type, t)
|
||||
gins(arm64.AMOVD, &con, &r1)
|
||||
|
|
@ -151,7 +179,7 @@ func gmove(f *gc.Node, t *gc.Node) {
|
|||
gc.TUINT16,
|
||||
gc.TUINT8:
|
||||
var con gc.Node
|
||||
gc.Convconst(&con, gc.Types[gc.TUINT64], &f.Val)
|
||||
f.Convconst(&con, gc.Types[gc.TUINT64])
|
||||
var r1 gc.Node
|
||||
gc.Regalloc(&r1, con.Type, t)
|
||||
gins(arm64.AMOVD, &con, &r1)
|
||||
|
|
@ -440,14 +468,13 @@ hard:
|
|||
}
|
||||
|
||||
func intLiteral(n *gc.Node) (x int64, ok bool) {
|
||||
if n == nil || n.Op != gc.OLITERAL {
|
||||
switch {
|
||||
case n == nil:
|
||||
return
|
||||
}
|
||||
switch n.Val.Ctype {
|
||||
case gc.CTINT, gc.CTRUNE:
|
||||
return gc.Mpgetfix(n.Val.U.Xval), true
|
||||
case gc.CTBOOL:
|
||||
return int64(obj.Bool2int(n.Val.U.Bval)), true
|
||||
case gc.Isconst(n, gc.CTINT):
|
||||
return n.Int(), true
|
||||
case gc.Isconst(n, gc.CTBOOL):
|
||||
return int64(obj.Bool2int(n.Bool())), true
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -28,10 +28,10 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
package arm64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm64"
|
||||
"fmt"
|
||||
|
|
@ -422,9 +422,9 @@ func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
|
|||
// 7g never generates a from3
|
||||
fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(&p.From3))
|
||||
}
|
||||
if p.To2.Type != obj.TYPE_NONE {
|
||||
if p.RegTo2 != obj.REG_NONE {
|
||||
// 7g never generates a to2
|
||||
fmt.Printf("copyu: to2 (%v) not implemented\n", gc.Ctxt.Dconv(&p.To2))
|
||||
fmt.Printf("copyu: RegTo2 (%v) not implemented\n", obj.Rconv(int(p.RegTo2)))
|
||||
}
|
||||
|
||||
switch p.As {
|
||||
|
|
@ -2,10 +2,10 @@
|
|||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
package arm64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm64"
|
||||
)
|
||||
|
|
@ -28,10 +28,10 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
package main
|
||||
package arm64
|
||||
|
||||
import (
|
||||
"cmd/internal/gc"
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/internal/obj/arm64"
|
||||
)
|
||||
|
||||
|
|
@ -196,7 +196,6 @@ func subVV_g(z, x, y []Word) (c Word) {
|
|||
return
|
||||
}
|
||||
|
||||
// Argument y must be either 0 or 1.
|
||||
// The resulting carry c is either 0 or 1.
|
||||
func addVW_g(z, x []Word, y Word) (c Word) {
|
||||
if use_addWW_g {
|
||||
|
|
@ -155,6 +155,7 @@ var sumVW = []argVW{
|
|||
{nat{1}, nat{1}, 0, 0},
|
||||
{nat{0}, nat{_M}, 1, 1},
|
||||
{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
|
||||
{nat{585}, nat{314}, 271, 0},
|
||||
}
|
||||
|
||||
var prodVW = []argVW{
|
||||
|
|
@ -5,9 +5,9 @@
|
|||
package big_test
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/big"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func ExampleRat_SetString() {
|
||||
|
|
@ -65,12 +65,16 @@ type Float struct {
|
|||
exp int32
|
||||
}
|
||||
|
||||
// Float operations that would lead to a NaN under IEEE-754 rules cause
|
||||
// a run-time panic of ErrNaN type.
|
||||
// An ErrNaN panic is raised by a Float operation that would lead to
|
||||
// a NaN under IEEE-754 rules. An ErrNaN implements the error interface.
|
||||
type ErrNaN struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
func (err ErrNaN) Error() string {
|
||||
return err.msg
|
||||
}
|
||||
|
||||
// NewFloat allocates and returns a new Float set to x,
|
||||
// with precision 53 and rounding mode ToNearestEven.
|
||||
// NewFloat panics with ErrNaN if x is a NaN.
|
||||
|
|
@ -849,9 +853,6 @@ func (x *Float) Int64() (int64, Accuracy) {
|
|||
panic("unreachable")
|
||||
}
|
||||
|
||||
// TODO(gri) Float32 and Float64 are very similar internally but for the
|
||||
// floatxx parameters and some conversions. Should factor out shared code.
|
||||
|
||||
// Float32 returns the float32 value nearest to x. If x is too small to be
|
||||
// represented by a float32 (|x| < math.SmallestNonzeroFloat32), the result
|
||||
// is (0, Below) or (-0, Above), respectively, depending on the sign of x.
|
||||
|
|
@ -876,64 +877,70 @@ func (x *Float) Float32() (float32, Accuracy) {
|
|||
emax = bias // 127 largest unbiased exponent (normal)
|
||||
)
|
||||
|
||||
// Float mantissae m have an explicit msb and are in the range 0.5 <= m < 1.0.
|
||||
// floatxx mantissae have an implicit msb and are in the range 1.0 <= m < 2.0.
|
||||
// For a given mantissa m, we need to add 1 to a floatxx exponent to get the
|
||||
// corresponding Float exponent.
|
||||
// (see also implementation of math.Ldexp for similar code)
|
||||
// Float mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa.
|
||||
e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0
|
||||
p := mbits + 1 // precision of normal float
|
||||
|
||||
if x.exp < dmin+1 {
|
||||
// underflow
|
||||
if x.neg {
|
||||
var z float32
|
||||
return -z, Above
|
||||
// If the exponent is too small, we may have a denormal number
|
||||
// in which case we have fewer mantissa bits available: reduce
|
||||
// precision accordingly.
|
||||
if e < emin {
|
||||
p -= emin - int(e)
|
||||
// Make sure we have at least 1 bit so that we don't
|
||||
// lose numbers rounded up to the smallest denormal.
|
||||
if p < 1 {
|
||||
p = 1
|
||||
}
|
||||
return 0.0, Below
|
||||
}
|
||||
// x.exp >= dmin+1
|
||||
|
||||
// round
|
||||
var r Float
|
||||
r.prec = mbits + 1 // +1 for implicit msb
|
||||
if x.exp < emin+1 {
|
||||
// denormal number - round to fewer bits
|
||||
r.prec = uint32(x.exp - dmin)
|
||||
}
|
||||
r.prec = uint32(p)
|
||||
r.Set(x)
|
||||
e = r.exp - 1
|
||||
|
||||
// Rounding may have caused r to overflow to ±Inf
|
||||
// (rounding never causes underflows to 0).
|
||||
if r.form == inf {
|
||||
r.exp = emax + 2 // cause overflow below
|
||||
e = emax + 1 // cause overflow below
|
||||
}
|
||||
|
||||
if r.exp > emax+1 {
|
||||
// If the exponent is too large, overflow to ±Inf.
|
||||
if e > emax {
|
||||
// overflow
|
||||
if x.neg {
|
||||
return float32(math.Inf(-1)), Below
|
||||
}
|
||||
return float32(math.Inf(+1)), Above
|
||||
}
|
||||
// dmin+1 <= r.exp <= emax+1
|
||||
|
||||
var s uint32
|
||||
if r.neg {
|
||||
s = 1 << (fbits - 1)
|
||||
// Determine sign, biased exponent, and mantissa.
|
||||
var sign, bexp, mant uint32
|
||||
if x.neg {
|
||||
sign = 1 << (fbits - 1)
|
||||
}
|
||||
|
||||
m := high32(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
|
||||
|
||||
// Rounding may have caused a denormal number to
|
||||
// become normal. Check again.
|
||||
c := float32(1.0)
|
||||
if r.exp < emin+1 {
|
||||
if e < emin {
|
||||
// denormal number
|
||||
r.exp += mbits
|
||||
c = 1.0 / (1 << mbits) // 2**-mbits
|
||||
if e < dmin {
|
||||
// underflow to ±0
|
||||
if x.neg {
|
||||
var z float32
|
||||
return -z, Above
|
||||
}
|
||||
return 0.0, Below
|
||||
}
|
||||
// bexp = 0
|
||||
mant = high32(r.mant) >> (fbits - r.prec)
|
||||
} else {
|
||||
// normal number: emin <= e <= emax
|
||||
bexp = uint32(e+bias) << mbits
|
||||
mant = high32(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
|
||||
}
|
||||
// emin+1 <= r.exp <= emax+1
|
||||
e := uint32(r.exp-emin) << mbits
|
||||
|
||||
return c * math.Float32frombits(s|e|m), r.acc
|
||||
return math.Float32frombits(sign | bexp | mant), r.acc
|
||||
|
||||
case zero:
|
||||
if x.neg {
|
||||
|
|
@ -976,64 +983,70 @@ func (x *Float) Float64() (float64, Accuracy) {
|
|||
emax = bias // 1023 largest unbiased exponent (normal)
|
||||
)
|
||||
|
||||
// Float mantissae m have an explicit msb and are in the range 0.5 <= m < 1.0.
|
||||
// floatxx mantissae have an implicit msb and are in the range 1.0 <= m < 2.0.
|
||||
// For a given mantissa m, we need to add 1 to a floatxx exponent to get the
|
||||
// corresponding Float exponent.
|
||||
// (see also implementation of math.Ldexp for similar code)
|
||||
// Float mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa.
|
||||
e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0
|
||||
p := mbits + 1 // precision of normal float
|
||||
|
||||
if x.exp < dmin+1 {
|
||||
// underflow
|
||||
if x.neg {
|
||||
var z float64
|
||||
return -z, Above
|
||||
// If the exponent is too small, we may have a denormal number
|
||||
// in which case we have fewer mantissa bits available: reduce
|
||||
// precision accordingly.
|
||||
if e < emin {
|
||||
p -= emin - int(e)
|
||||
// Make sure we have at least 1 bit so that we don't
|
||||
// lose numbers rounded up to the smallest denormal.
|
||||
if p < 1 {
|
||||
p = 1
|
||||
}
|
||||
return 0.0, Below
|
||||
}
|
||||
// x.exp >= dmin+1
|
||||
|
||||
// round
|
||||
var r Float
|
||||
r.prec = mbits + 1 // +1 for implicit msb
|
||||
if x.exp < emin+1 {
|
||||
// denormal number - round to fewer bits
|
||||
r.prec = uint32(x.exp - dmin)
|
||||
}
|
||||
r.prec = uint32(p)
|
||||
r.Set(x)
|
||||
e = r.exp - 1
|
||||
|
||||
// Rounding may have caused r to overflow to ±Inf
|
||||
// (rounding never causes underflows to 0).
|
||||
if r.form == inf {
|
||||
r.exp = emax + 2 // cause overflow below
|
||||
e = emax + 1 // cause overflow below
|
||||
}
|
||||
|
||||
if r.exp > emax+1 {
|
||||
// If the exponent is too large, overflow to ±Inf.
|
||||
if e > emax {
|
||||
// overflow
|
||||
if x.neg {
|
||||
return math.Inf(-1), Below
|
||||
}
|
||||
return math.Inf(+1), Above
|
||||
}
|
||||
// dmin+1 <= r.exp <= emax+1
|
||||
|
||||
var s uint64
|
||||
if r.neg {
|
||||
s = 1 << (fbits - 1)
|
||||
// Determine sign, biased exponent, and mantissa.
|
||||
var sign, bexp, mant uint64
|
||||
if x.neg {
|
||||
sign = 1 << (fbits - 1)
|
||||
}
|
||||
|
||||
m := high64(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
|
||||
|
||||
// Rounding may have caused a denormal number to
|
||||
// become normal. Check again.
|
||||
c := 1.0
|
||||
if r.exp < emin+1 {
|
||||
if e < emin {
|
||||
// denormal number
|
||||
r.exp += mbits
|
||||
c = 1.0 / (1 << mbits) // 2**-mbits
|
||||
if e < dmin {
|
||||
// underflow to ±0
|
||||
if x.neg {
|
||||
var z float64
|
||||
return -z, Above
|
||||
}
|
||||
return 0.0, Below
|
||||
}
|
||||
// bexp = 0
|
||||
mant = high64(r.mant) >> (fbits - r.prec)
|
||||
} else {
|
||||
// normal number: emin <= e <= emax
|
||||
bexp = uint64(e+bias) << mbits
|
||||
mant = high64(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
|
||||
}
|
||||
// emin+1 <= r.exp <= emax+1
|
||||
e := uint64(r.exp-emin) << mbits
|
||||
|
||||
return c * math.Float64frombits(s|e|m), r.acc
|
||||
return math.Float64frombits(sign | bexp | mant), r.acc
|
||||
|
||||
case zero:
|
||||
if x.neg {
|
||||
|
|
@ -12,6 +12,9 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
// Verify that ErrNaN implements the error interface.
|
||||
var _ error = ErrNaN{}
|
||||
|
||||
func (x *Float) uint64() uint64 {
|
||||
u, acc := x.Uint64()
|
||||
if acc != Exact {
|
||||
|
|
@ -200,6 +203,18 @@ func alike(x, y *Float) bool {
|
|||
return x.Cmp(y) == 0 && x.Signbit() == y.Signbit()
|
||||
}
|
||||
|
||||
func alike32(x, y float32) bool {
|
||||
// we can ignore NaNs
|
||||
return x == y && math.Signbit(float64(x)) == math.Signbit(float64(y))
|
||||
|
||||
}
|
||||
|
||||
func alike64(x, y float64) bool {
|
||||
// we can ignore NaNs
|
||||
return x == y && math.Signbit(x) == math.Signbit(y)
|
||||
|
||||
}
|
||||
|
||||
func TestFloatMantExp(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
x string
|
||||
|
|
@ -825,52 +840,69 @@ func TestFloatFloat32(t *testing.T) {
|
|||
out float32
|
||||
acc Accuracy
|
||||
}{
|
||||
{"-Inf", float32(math.Inf(-1)), Exact},
|
||||
{"-0x1.ffffff0p2147483646", float32(-math.Inf(+1)), Below}, // overflow in rounding
|
||||
{"-1e10000", float32(math.Inf(-1)), Below}, // overflow
|
||||
{"-0x1p128", float32(math.Inf(-1)), Below}, // overflow
|
||||
{"-0x1.ffffff0p127", float32(-math.Inf(+1)), Below}, // overflow
|
||||
{"-0x1.fffffe8p127", -math.MaxFloat32, Above},
|
||||
{"-0x1.fffffe0p127", -math.MaxFloat32, Exact},
|
||||
{"-12345.000000000000000000001", -12345, Above},
|
||||
{"-12345.0", -12345, Exact},
|
||||
{"-1.000000000000000000001", -1, Above},
|
||||
{"-1", -1, Exact},
|
||||
{"-0x0.000002p-126", -math.SmallestNonzeroFloat32, Exact},
|
||||
{"-0x0.000002p-127", -0, Above}, // underflow
|
||||
{"-1e-1000", -0, Above}, // underflow
|
||||
{"0", 0, Exact},
|
||||
{"1e-1000", 0, Below}, // underflow
|
||||
{"0x0.000002p-127", 0, Below}, // underflow
|
||||
{"0x0.000002p-126", math.SmallestNonzeroFloat32, Exact},
|
||||
|
||||
// underflow
|
||||
{"1e-1000", 0, Below},
|
||||
{"0x0.000002p-127", 0, Below},
|
||||
{"0x.0000010p-126", 0, Below},
|
||||
|
||||
// denormals
|
||||
{"1.401298464e-45", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
|
||||
{"0x.ffffff8p-149", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
|
||||
{"0x.0000018p-126", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
|
||||
{"0x.0000020p-126", math.SmallestNonzeroFloat32, Exact},
|
||||
{"0x.8p-148", math.SmallestNonzeroFloat32, Exact},
|
||||
{"1p-149", math.SmallestNonzeroFloat32, Exact},
|
||||
{"0x.fffffep-126", math.Float32frombits(0x7fffff), Exact}, // largest denormal
|
||||
|
||||
// normals
|
||||
{"0x.ffffffp-126", math.Float32frombits(0x00800000), Above}, // rounded up to smallest normal
|
||||
{"1p-126", math.Float32frombits(0x00800000), Exact}, // smallest normal
|
||||
{"0x1.fffffep-126", math.Float32frombits(0x00ffffff), Exact},
|
||||
{"0x1.ffffffp-126", math.Float32frombits(0x01000000), Above}, // rounded up
|
||||
{"1", 1, Exact},
|
||||
{"1.000000000000000000001", 1, Below},
|
||||
{"12345.0", 12345, Exact},
|
||||
{"12345.000000000000000000001", 12345, Below},
|
||||
{"0x1.fffffe0p127", math.MaxFloat32, Exact},
|
||||
{"0x1.fffffe8p127", math.MaxFloat32, Below},
|
||||
{"0x1.ffffff0p127", float32(math.Inf(+1)), Above}, // overflow
|
||||
{"0x1p128", float32(math.Inf(+1)), Above}, // overflow
|
||||
{"1e10000", float32(math.Inf(+1)), Above}, // overflow
|
||||
|
||||
// overflow
|
||||
{"0x1.ffffff0p127", float32(math.Inf(+1)), Above},
|
||||
{"0x1p128", float32(math.Inf(+1)), Above},
|
||||
{"1e10000", float32(math.Inf(+1)), Above},
|
||||
{"0x1.ffffff0p2147483646", float32(math.Inf(+1)), Above}, // overflow in rounding
|
||||
{"+Inf", float32(math.Inf(+1)), Exact},
|
||||
|
||||
// inf
|
||||
{"Inf", float32(math.Inf(+1)), Exact},
|
||||
} {
|
||||
// conversion should match strconv where syntax is agreeable
|
||||
if f, err := strconv.ParseFloat(test.x, 32); err == nil && float32(f) != test.out {
|
||||
t.Errorf("%s: got %g; want %g (incorrect test data)", test.x, f, test.out)
|
||||
}
|
||||
for i := 0; i < 2; i++ {
|
||||
// test both signs
|
||||
tx, tout, tacc := test.x, test.out, test.acc
|
||||
if i != 0 {
|
||||
tx = "-" + tx
|
||||
tout = -tout
|
||||
tacc = -tacc
|
||||
}
|
||||
|
||||
x := makeFloat(test.x)
|
||||
out, acc := x.Float32()
|
||||
if out != test.out || acc != test.acc {
|
||||
t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", test.x, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), test.acc)
|
||||
}
|
||||
// conversion should match strconv where syntax is agreeable
|
||||
if f, err := strconv.ParseFloat(tx, 32); err == nil && !alike32(float32(f), tout) {
|
||||
t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout)
|
||||
}
|
||||
|
||||
// test that x.SetFloat64(float64(f)).Float32() == f
|
||||
var x2 Float
|
||||
out2, acc2 := x2.SetFloat64(float64(out)).Float32()
|
||||
if out2 != out || acc2 != Exact {
|
||||
t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
|
||||
x := makeFloat(tx)
|
||||
out, acc := x.Float32()
|
||||
if !alike32(out, tout) || acc != tacc {
|
||||
t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc)
|
||||
}
|
||||
|
||||
// test that x.SetFloat64(float64(f)).Float32() == f
|
||||
var x2 Float
|
||||
out2, acc2 := x2.SetFloat64(float64(out)).Float32()
|
||||
if !alike32(out2, out) || acc2 != Exact {
|
||||
t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -882,35 +914,36 @@ func TestFloatFloat64(t *testing.T) {
|
|||
out float64
|
||||
acc Accuracy
|
||||
}{
|
||||
{"-Inf", math.Inf(-1), Exact},
|
||||
{"-0x1.fffffffffffff8p2147483646", -math.Inf(+1), Below}, // overflow in rounding
|
||||
{"-1e10000", math.Inf(-1), Below}, // overflow
|
||||
{"-0x1p1024", math.Inf(-1), Below}, // overflow
|
||||
{"-0x1.fffffffffffff8p1023", -math.Inf(+1), Below}, // overflow
|
||||
{"-0x1.fffffffffffff4p1023", -math.MaxFloat64, Above},
|
||||
{"-0x1.fffffffffffff0p1023", -math.MaxFloat64, Exact},
|
||||
{"-12345.000000000000000000001", -12345, Above},
|
||||
{"-12345.0", -12345, Exact},
|
||||
{"-1.000000000000000000001", -1, Above},
|
||||
{"-1", -1, Exact},
|
||||
{"-0x0.0000000000001p-1022", -math.SmallestNonzeroFloat64, Exact},
|
||||
{"-0x0.0000000000001p-1023", -0, Above}, // underflow
|
||||
{"-1e-1000", -0, Above}, // underflow
|
||||
{"0", 0, Exact},
|
||||
{"1e-1000", 0, Below}, // underflow
|
||||
{"0x0.0000000000001p-1023", 0, Below}, // underflow
|
||||
{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact},
|
||||
|
||||
// underflow
|
||||
{"1e-1000", 0, Below},
|
||||
{"0x0.0000000000001p-1023", 0, Below},
|
||||
{"0x0.00000000000008p-1022", 0, Below},
|
||||
|
||||
// denormals
|
||||
{"0x0.0000000000000cp-1022", math.SmallestNonzeroFloat64, Above}, // rounded up to smallest denormal
|
||||
{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact}, // smallest denormal
|
||||
{"0x.8p-1073", math.SmallestNonzeroFloat64, Exact},
|
||||
{"1p-1074", math.SmallestNonzeroFloat64, Exact},
|
||||
{"0x.fffffffffffffp-1022", math.Float64frombits(0x000fffffffffffff), Exact}, // largest denormal
|
||||
|
||||
// normals
|
||||
{"0x.fffffffffffff8p-1022", math.Float64frombits(0x0010000000000000), Above}, // rounded up to smallest normal
|
||||
{"1p-1022", math.Float64frombits(0x0010000000000000), Exact}, // smallest normal
|
||||
{"1", 1, Exact},
|
||||
{"1.000000000000000000001", 1, Below},
|
||||
{"12345.0", 12345, Exact},
|
||||
{"12345.000000000000000000001", 12345, Below},
|
||||
{"0x1.fffffffffffff0p1023", math.MaxFloat64, Exact},
|
||||
{"0x1.fffffffffffff4p1023", math.MaxFloat64, Below},
|
||||
{"0x1.fffffffffffff8p1023", math.Inf(+1), Above}, // overflow
|
||||
{"0x1p1024", math.Inf(+1), Above}, // overflow
|
||||
{"1e10000", math.Inf(+1), Above}, // overflow
|
||||
|
||||
// overflow
|
||||
{"0x1.fffffffffffff8p1023", math.Inf(+1), Above},
|
||||
{"0x1p1024", math.Inf(+1), Above},
|
||||
{"1e10000", math.Inf(+1), Above},
|
||||
{"0x1.fffffffffffff8p2147483646", math.Inf(+1), Above}, // overflow in rounding
|
||||
{"+Inf", math.Inf(+1), Exact},
|
||||
{"Inf", math.Inf(+1), Exact},
|
||||
|
||||
// selected denormalized values that were handled incorrectly in the past
|
||||
{"0x.fffffffffffffp-1022", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact},
|
||||
|
|
@ -921,22 +954,32 @@ func TestFloatFloat64(t *testing.T) {
|
|||
// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
|
||||
{"2.2250738585072012e-308", 2.2250738585072014e-308, Above},
|
||||
} {
|
||||
// conversion should match strconv where syntax is agreeable
|
||||
if f, err := strconv.ParseFloat(test.x, 64); err == nil && f != test.out {
|
||||
t.Errorf("%s: got %g; want %g (incorrect test data)", test.x, f, test.out)
|
||||
}
|
||||
for i := 0; i < 2; i++ {
|
||||
// test both signs
|
||||
tx, tout, tacc := test.x, test.out, test.acc
|
||||
if i != 0 {
|
||||
tx = "-" + tx
|
||||
tout = -tout
|
||||
tacc = -tacc
|
||||
}
|
||||
|
||||
x := makeFloat(test.x)
|
||||
out, acc := x.Float64()
|
||||
if out != test.out || acc != test.acc {
|
||||
t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", test.x, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), test.acc)
|
||||
}
|
||||
// conversion should match strconv where syntax is agreeable
|
||||
if f, err := strconv.ParseFloat(tx, 64); err == nil && !alike64(f, tout) {
|
||||
t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout)
|
||||
}
|
||||
|
||||
// test that x.SetFloat64(f).Float64() == f
|
||||
var x2 Float
|
||||
out2, acc2 := x2.SetFloat64(out).Float64()
|
||||
if out2 != out || acc2 != Exact {
|
||||
t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
|
||||
x := makeFloat(tx)
|
||||
out, acc := x.Float64()
|
||||
if !alike64(out, tout) || acc != tacc {
|
||||
t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc)
|
||||
}
|
||||
|
||||
// test that x.SetFloat64(f).Float64() == f
|
||||
var x2 Float
|
||||
out2, acc2 := x2.SetFloat64(out).Float64()
|
||||
if !alike64(out2, out) || acc2 != Exact {
|
||||
t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1656,7 +1699,7 @@ func TestFloatCmpSpecialValues(t *testing.T) {
|
|||
want = +1
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("(%g).Cmp(%g) = %s; want %s", x, y, got, want)
|
||||
t.Errorf("(%g).Cmp(%g) = %v; want %v", x, y, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,9 +5,9 @@
|
|||
package big_test
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/big"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
)
|
||||
|
||||
func ExampleFloat_Add() {
|
||||
|
|
@ -583,6 +583,124 @@ func (z *Int) ModInverse(g, n *Int) *Int {
|
|||
return z
|
||||
}
|
||||
|
||||
// Jacobi returns the Jacobi symbol (x/y), either +1, -1, or 0.
|
||||
// The y argument must be an odd integer.
|
||||
func Jacobi(x, y *Int) int {
|
||||
if len(y.abs) == 0 || y.abs[0]&1 == 0 {
|
||||
panic(fmt.Sprintf("big: invalid 2nd argument to Int.Jacobi: need odd integer but got %s", y))
|
||||
}
|
||||
|
||||
// We use the formulation described in chapter 2, section 2.4,
|
||||
// "The Yacas Book of Algorithms":
|
||||
// http://yacas.sourceforge.net/Algo.book.pdf
|
||||
|
||||
var a, b, c Int
|
||||
a.Set(x)
|
||||
b.Set(y)
|
||||
j := 1
|
||||
|
||||
if b.neg {
|
||||
if a.neg {
|
||||
j = -1
|
||||
}
|
||||
b.neg = false
|
||||
}
|
||||
|
||||
for {
|
||||
if b.Cmp(intOne) == 0 {
|
||||
return j
|
||||
}
|
||||
if len(a.abs) == 0 {
|
||||
return 0
|
||||
}
|
||||
a.Mod(&a, &b)
|
||||
if len(a.abs) == 0 {
|
||||
return 0
|
||||
}
|
||||
// a > 0
|
||||
|
||||
// handle factors of 2 in 'a'
|
||||
s := a.abs.trailingZeroBits()
|
||||
if s&1 != 0 {
|
||||
bmod8 := b.abs[0] & 7
|
||||
if bmod8 == 3 || bmod8 == 5 {
|
||||
j = -j
|
||||
}
|
||||
}
|
||||
c.Rsh(&a, s) // a = 2^s*c
|
||||
|
||||
// swap numerator and denominator
|
||||
if b.abs[0]&3 == 3 && c.abs[0]&3 == 3 {
|
||||
j = -j
|
||||
}
|
||||
a.Set(&b)
|
||||
b.Set(&c)
|
||||
}
|
||||
}
|
||||
|
||||
// ModSqrt sets z to a square root of x mod p if such a square root exists, and
|
||||
// returns z. The modulus p must be an odd prime. If x is not a square mod p,
|
||||
// ModSqrt leaves z unchanged and returns nil. This function panics if p is
|
||||
// not an odd integer.
|
||||
func (z *Int) ModSqrt(x, p *Int) *Int {
|
||||
switch Jacobi(x, p) {
|
||||
case -1:
|
||||
return nil // x is not a square mod p
|
||||
case 0:
|
||||
return z.SetInt64(0) // sqrt(0) mod p = 0
|
||||
case 1:
|
||||
break
|
||||
}
|
||||
if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
|
||||
x = new(Int).Mod(x, p)
|
||||
}
|
||||
|
||||
// Break p-1 into s*2^e such that s is odd.
|
||||
var s Int
|
||||
s.Sub(p, intOne)
|
||||
e := s.abs.trailingZeroBits()
|
||||
s.Rsh(&s, e)
|
||||
|
||||
// find some non-square n
|
||||
var n Int
|
||||
n.SetInt64(2)
|
||||
for Jacobi(&n, p) != -1 {
|
||||
n.Add(&n, intOne)
|
||||
}
|
||||
|
||||
// Core of the Tonelli-Shanks algorithm. Follows the description in
|
||||
// section 6 of "Square roots from 1; 24, 51, 10 to Dan Shanks" by Ezra
|
||||
// Brown:
|
||||
// https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf
|
||||
var y, b, g, t Int
|
||||
y.Add(&s, intOne)
|
||||
y.Rsh(&y, 1)
|
||||
y.Exp(x, &y, p) // y = x^((s+1)/2)
|
||||
b.Exp(x, &s, p) // b = x^s
|
||||
g.Exp(&n, &s, p) // g = n^s
|
||||
r := e
|
||||
for {
|
||||
// find the least m such that ord_p(b) = 2^m
|
||||
var m uint
|
||||
t.Set(&b)
|
||||
for t.Cmp(intOne) != 0 {
|
||||
t.Mul(&t, &t).Mod(&t, p)
|
||||
m++
|
||||
}
|
||||
|
||||
if m == 0 {
|
||||
return z.Set(&y)
|
||||
}
|
||||
|
||||
t.SetInt64(0).SetBit(&t, int(r-m-1), 1).Exp(&g, &t, p)
|
||||
// t = g^(2^(r-m-1)) mod p
|
||||
g.Mul(&t, &t).Mod(&g, p) // g = g^(2^(r-m)) mod p
|
||||
y.Mul(&y, &t).Mod(&y, p)
|
||||
b.Mul(&b, &g).Mod(&b, p)
|
||||
r = m
|
||||
}
|
||||
}
|
||||
|
||||
// Lsh sets z = x << n and returns z.
|
||||
func (z *Int) Lsh(x *Int, n uint) *Int {
|
||||
z.abs = z.abs.shl(x.abs, n)
|
||||
|
|
@ -525,6 +525,7 @@ var expTests = []struct {
|
|||
{"1234", "-1", "1", "0"},
|
||||
|
||||
// misc
|
||||
{"5", "1", "3", "2"},
|
||||
{"5", "-7", "", "1"},
|
||||
{"-5", "-7", "", "1"},
|
||||
{"5", "0", "", "1"},
|
||||
|
|
@ -703,6 +704,13 @@ var primes = []string{
|
|||
"230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
|
||||
"5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
|
||||
"203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
|
||||
|
||||
// ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02
|
||||
"3618502788666131106986593281521497120414687020801267626233049500247285301239", // Curve1174: 2^251-9
|
||||
"57896044618658097711785492504343953926634992332820282019728792003956564819949", // Curve25519: 2^255-19
|
||||
"9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599", // E-382: 2^382-105
|
||||
"42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367", // Curve41417: 2^414-17
|
||||
"6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
|
||||
}
|
||||
|
||||
var composites = []string{
|
||||
|
|
@ -1248,6 +1256,136 @@ func TestModInverse(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// testModSqrt is a helper for TestModSqrt,
|
||||
// which checks that ModSqrt can compute a square-root of elt^2.
|
||||
func testModSqrt(t *testing.T, elt, mod, sq, sqrt *Int) bool {
|
||||
var sqChk, sqrtChk, sqrtsq Int
|
||||
sq.Mul(elt, elt)
|
||||
sq.Mod(sq, mod)
|
||||
z := sqrt.ModSqrt(sq, mod)
|
||||
if z != sqrt {
|
||||
t.Errorf("ModSqrt returned wrong value %s", z)
|
||||
}
|
||||
|
||||
// test ModSqrt arguments outside the range [0,mod)
|
||||
sqChk.Add(sq, mod)
|
||||
z = sqrtChk.ModSqrt(&sqChk, mod)
|
||||
if z != &sqrtChk || z.Cmp(sqrt) != 0 {
|
||||
t.Errorf("ModSqrt returned inconsistent value %s", z)
|
||||
}
|
||||
sqChk.Sub(sq, mod)
|
||||
z = sqrtChk.ModSqrt(&sqChk, mod)
|
||||
if z != &sqrtChk || z.Cmp(sqrt) != 0 {
|
||||
t.Errorf("ModSqrt returned inconsistent value %s", z)
|
||||
}
|
||||
|
||||
// make sure we actually got a square root
|
||||
if sqrt.Cmp(elt) == 0 {
|
||||
return true // we found the "desired" square root
|
||||
}
|
||||
sqrtsq.Mul(sqrt, sqrt) // make sure we found the "other" one
|
||||
sqrtsq.Mod(&sqrtsq, mod)
|
||||
return sq.Cmp(&sqrtsq) == 0
|
||||
}
|
||||
|
||||
func TestModSqrt(t *testing.T) {
|
||||
var elt, mod, modx4, sq, sqrt Int
|
||||
r := rand.New(rand.NewSource(9))
|
||||
for i, s := range primes[1:] { // skip 2, use only odd primes
|
||||
mod.SetString(s, 10)
|
||||
modx4.Lsh(&mod, 2)
|
||||
|
||||
// test a few random elements per prime
|
||||
for x := 1; x < 5; x++ {
|
||||
elt.Rand(r, &modx4)
|
||||
elt.Sub(&elt, &mod) // test range [-mod, 3*mod)
|
||||
if !testModSqrt(t, &elt, &mod, &sq, &sqrt) {
|
||||
t.Errorf("#%d: failed (sqrt(e) = %s)", i, &sqrt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// exhaustive test for small values
|
||||
for n := 3; n < 100; n++ {
|
||||
mod.SetInt64(int64(n))
|
||||
if !mod.ProbablyPrime(10) {
|
||||
continue
|
||||
}
|
||||
isSquare := make([]bool, n)
|
||||
|
||||
// test all the squares
|
||||
for x := 1; x < n; x++ {
|
||||
elt.SetInt64(int64(x))
|
||||
if !testModSqrt(t, &elt, &mod, &sq, &sqrt) {
|
||||
t.Errorf("#%d: failed (sqrt(%d,%d) = %s)", x, &elt, &mod, &sqrt)
|
||||
}
|
||||
isSquare[sq.Uint64()] = true
|
||||
}
|
||||
|
||||
// test all non-squares
|
||||
for x := 1; x < n; x++ {
|
||||
sq.SetInt64(int64(x))
|
||||
z := sqrt.ModSqrt(&sq, &mod)
|
||||
if !isSquare[x] && z != nil {
|
||||
t.Errorf("#%d: failed (sqrt(%d,%d) = nil)", x, &sqrt, &mod)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJacobi(t *testing.T) {
|
||||
testCases := []struct {
|
||||
x, y int64
|
||||
result int
|
||||
}{
|
||||
{0, 1, 1},
|
||||
{0, -1, 1},
|
||||
{1, 1, 1},
|
||||
{1, -1, 1},
|
||||
{0, 5, 0},
|
||||
{1, 5, 1},
|
||||
{2, 5, -1},
|
||||
{-2, 5, -1},
|
||||
{2, -5, -1},
|
||||
{-2, -5, 1},
|
||||
{3, 5, -1},
|
||||
{5, 5, 0},
|
||||
{-5, 5, 0},
|
||||
{6, 5, 1},
|
||||
{6, -5, 1},
|
||||
{-6, 5, 1},
|
||||
{-6, -5, -1},
|
||||
}
|
||||
|
||||
var x, y Int
|
||||
|
||||
for i, test := range testCases {
|
||||
x.SetInt64(test.x)
|
||||
y.SetInt64(test.y)
|
||||
expected := test.result
|
||||
actual := Jacobi(&x, &y)
|
||||
if actual != expected {
|
||||
t.Errorf("#%d: Jacobi(%d, %d) = %d, but expected %d", i, test.x, test.y, actual, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestJacobiPanic(t *testing.T) {
|
||||
const failureMsg = "test failure"
|
||||
defer func() {
|
||||
msg := recover()
|
||||
if msg == nil || msg == failureMsg {
|
||||
panic(msg)
|
||||
}
|
||||
t.Log(msg)
|
||||
}()
|
||||
x := NewInt(1)
|
||||
y := NewInt(2)
|
||||
// Jacobi should panic when the second argument is even.
|
||||
Jacobi(x, y)
|
||||
panic(failureMsg)
|
||||
}
|
||||
|
||||
var encodingTests = []string{
|
||||
"-539345864568634858364538753846587364875430589374589",
|
||||
"-678645873",
|
||||
|
|
@ -216,6 +216,34 @@ func basicMul(z, x, y nat) {
|
|||
}
|
||||
}
|
||||
|
||||
// montgomery computes x*y*2^(-n*_W) mod m,
|
||||
// assuming k = -1/m mod 2^_W.
|
||||
// z is used for storing the result which is returned;
|
||||
// z must not alias x, y or m.
|
||||
func (z nat) montgomery(x, y, m nat, k Word, n int) nat {
|
||||
var c1, c2 Word
|
||||
z = z.make(n)
|
||||
z.clear()
|
||||
for i := 0; i < n; i++ {
|
||||
d := y[i]
|
||||
c1 += addMulVVW(z, x, d)
|
||||
t := z[0] * k
|
||||
c2 = addMulVVW(z, m, t)
|
||||
|
||||
copy(z, z[1:])
|
||||
z[n-1] = c1 + c2
|
||||
if z[n-1] < c1 {
|
||||
c1 = 1
|
||||
} else {
|
||||
c1 = 0
|
||||
}
|
||||
}
|
||||
if c1 != 0 {
|
||||
subVV(z, z, m)
|
||||
}
|
||||
return z
|
||||
}
|
||||
|
||||
// Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks.
|
||||
// Factored out for readability - do not use outside karatsuba.
|
||||
func karatsubaAdd(z, x nat, n int) {
|
||||
|
|
@ -888,6 +916,13 @@ func (z nat) expNN(x, y, m nat) nat {
|
|||
}
|
||||
// y > 0
|
||||
|
||||
// x**1 mod m == x mod m
|
||||
if len(y) == 1 && y[0] == 1 && len(m) != 0 {
|
||||
_, z = z.div(z, x, m)
|
||||
return z
|
||||
}
|
||||
// y > 1
|
||||
|
||||
if len(m) != 0 {
|
||||
// We likely end up being as long as the modulus.
|
||||
z = z.make(len(m))
|
||||
|
|
@ -898,8 +933,11 @@ func (z nat) expNN(x, y, m nat) nat {
|
|||
// 4-bit, windowed exponentiation. This involves precomputing 14 values
|
||||
// (x^2...x^15) but then reduces the number of multiply-reduces by a
|
||||
// third. Even for a 32-bit exponent, this reduces the number of
|
||||
// operations.
|
||||
// operations. Uses Montgomery method for odd moduli.
|
||||
if len(x) > 1 && len(y) > 1 && len(m) > 0 {
|
||||
if m[0]&1 == 1 {
|
||||
return z.expNNMontgomery(x, y, m)
|
||||
}
|
||||
return z.expNNWindowed(x, y, m)
|
||||
}
|
||||
|
||||
|
|
@ -1022,6 +1060,87 @@ func (z nat) expNNWindowed(x, y, m nat) nat {
|
|||
return z.norm()
|
||||
}
|
||||
|
||||
// expNNMontgomery calculates x**y mod m using a fixed, 4-bit window.
|
||||
// Uses Montgomery representation.
|
||||
func (z nat) expNNMontgomery(x, y, m nat) nat {
|
||||
var zz, one, rr, RR nat
|
||||
|
||||
numWords := len(m)
|
||||
|
||||
// We want the lengths of x and m to be equal.
|
||||
if len(x) > numWords {
|
||||
_, rr = rr.div(rr, x, m)
|
||||
} else if len(x) < numWords {
|
||||
rr = rr.make(numWords)
|
||||
rr.clear()
|
||||
for i := range x {
|
||||
rr[i] = x[i]
|
||||
}
|
||||
} else {
|
||||
rr = x
|
||||
}
|
||||
x = rr
|
||||
|
||||
// Ideally the precomputations would be performed outside, and reused
|
||||
// k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
|
||||
// Iteration for Multiplicative Inverses Modulo Prime Powers".
|
||||
k0 := 2 - m[0]
|
||||
t := m[0] - 1
|
||||
for i := 1; i < _W; i <<= 1 {
|
||||
t *= t
|
||||
k0 *= (t + 1)
|
||||
}
|
||||
k0 = -k0
|
||||
|
||||
// RR = 2ˆ(2*_W*len(m)) mod m
|
||||
RR = RR.setWord(1)
|
||||
zz = zz.shl(RR, uint(2*numWords*_W))
|
||||
_, RR = RR.div(RR, zz, m)
|
||||
if len(RR) < numWords {
|
||||
zz = zz.make(numWords)
|
||||
copy(zz, RR)
|
||||
RR = zz
|
||||
}
|
||||
// one = 1, with equal length to that of m
|
||||
one = one.make(numWords)
|
||||
one.clear()
|
||||
one[0] = 1
|
||||
|
||||
const n = 4
|
||||
// powers[i] contains x^i
|
||||
var powers [1 << n]nat
|
||||
powers[0] = powers[0].montgomery(one, RR, m, k0, numWords)
|
||||
powers[1] = powers[1].montgomery(x, RR, m, k0, numWords)
|
||||
for i := 2; i < 1<<n; i++ {
|
||||
powers[i] = powers[i].montgomery(powers[i-1], powers[1], m, k0, numWords)
|
||||
}
|
||||
|
||||
// initialize z = 1 (Montgomery 1)
|
||||
z = z.make(numWords)
|
||||
copy(z, powers[0])
|
||||
|
||||
zz = zz.make(numWords)
|
||||
|
||||
// same windowed exponent, but with Montgomery multiplications
|
||||
for i := len(y) - 1; i >= 0; i-- {
|
||||
yi := y[i]
|
||||
for j := 0; j < _W; j += n {
|
||||
if i != len(y)-1 || j != 0 {
|
||||
zz = zz.montgomery(z, z, m, k0, numWords)
|
||||
z = z.montgomery(zz, zz, m, k0, numWords)
|
||||
zz = zz.montgomery(z, z, m, k0, numWords)
|
||||
z = z.montgomery(zz, zz, m, k0, numWords)
|
||||
}
|
||||
zz = zz.montgomery(z, powers[yi>>(_W-n)], m, k0, numWords)
|
||||
z, zz = zz, z
|
||||
yi <<= n
|
||||
}
|
||||
}
|
||||
// convert to regular number
|
||||
zz = zz.montgomery(z, one, m, k0, numWords)
|
||||
return zz.norm()
|
||||
}
|
||||
|
||||
// probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
|
||||
// If it returns true, n is prime with probability 1 - 1/4^reps.
|
||||
// If it returns false, n is not prime.
|
||||
|
|
@ -332,6 +332,67 @@ func TestTrailingZeroBits(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
var montgomeryTests = []struct {
|
||||
x, y, m string
|
||||
k0 uint64
|
||||
out32, out64 string
|
||||
}{
|
||||
{
|
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
|
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
|
||||
"0xfffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
0x0000000000000000,
|
||||
"0xffffffffffffffffffffffffffffffffffffffffff",
|
||||
"0xffffffffffffffffffffffffffffffffff",
|
||||
},
|
||||
{
|
||||
"0x0000000080000000",
|
||||
"0x00000000ffffffff",
|
||||
"0x0000000010000001",
|
||||
0xff0000000fffffff,
|
||||
"0x0000000088000000",
|
||||
"0x0000000007800001",
|
||||
},
|
||||
{
|
||||
"0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
|
||||
"0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
|
||||
"0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
|
||||
0xdecc8f1249812adf,
|
||||
"0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79",
|
||||
"0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd",
|
||||
},
|
||||
{
|
||||
"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
|
||||
"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
|
||||
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
|
||||
0xdecc8f1249812adf,
|
||||
"0x5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d7a11c7772cba02c22f9711078d51a3797eb18e691295293284d988e349fa6deba46b25a4ecd9f715",
|
||||
"0x92fcad4b5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d799c32fe2f3cc5422f9711078d51a3797eb18e691295293284d8f5e69caf6decddfe1df6",
|
||||
},
|
||||
}
|
||||
|
||||
func TestMontgomery(t *testing.T) {
|
||||
for i, test := range montgomeryTests {
|
||||
x := natFromString(test.x)
|
||||
y := natFromString(test.y)
|
||||
m := natFromString(test.m)
|
||||
|
||||
var out nat
|
||||
if _W == 32 {
|
||||
out = natFromString(test.out32)
|
||||
} else {
|
||||
out = natFromString(test.out64)
|
||||
}
|
||||
|
||||
k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems.
|
||||
z := nat(nil).montgomery(x, y, m, k0, len(m))
|
||||
z = z.norm()
|
||||
if z.cmp(out) != 0 {
|
||||
t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var expNNTests = []struct {
|
||||
x, y, m string
|
||||
out string
|
||||
|
|
@ -15,9 +15,15 @@ rm *.go
|
|||
cp $BIGDIR/*.go .
|
||||
|
||||
# Use pure Go arith ops w/o build tag.
|
||||
sed 's/^\/\/ \+build math_big_pure_go$//' arith_decl_pure.go > arith_decl.go
|
||||
sed 's|^// \+build math_big_pure_go$||' arith_decl_pure.go > arith_decl.go
|
||||
rm arith_decl_pure.go
|
||||
|
||||
# Import vendored math/big in external tests (e.g., floatexample_test.go).
|
||||
for f in *_test.go; do
|
||||
sed 's|"math/big"|"cmd/compile/internal/big"|' $f > foo.go
|
||||
mv foo.go $f
|
||||
done
|
||||
|
||||
# gofmt to clean up after sed
|
||||
gofmt -w .
|
||||
|
||||
|
|
@ -71,8 +71,8 @@ func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
|
|||
// in typecheck.c. usually addrescapes runs after
|
||||
// widstruct, in which case we could drop this,
|
||||
// but function closure functions are the exception.
|
||||
if f.Nname.Stackparam != nil {
|
||||
f.Nname.Stackparam.Xoffset = o
|
||||
if f.Nname.Param.Stackparam != nil {
|
||||
f.Nname.Param.Stackparam.Xoffset = o
|
||||
f.Nname.Xoffset = 0
|
||||
} else {
|
||||
f.Nname.Xoffset = o
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -17,7 +17,7 @@ func closurehdr(ntype *Node) {
|
|||
var a *Node
|
||||
|
||||
n := Nod(OCLOSURE, nil, nil)
|
||||
n.Ntype = ntype
|
||||
n.Param.Ntype = ntype
|
||||
n.Funcdepth = Funcdepth
|
||||
n.Func.Outerfunc = Curfn
|
||||
|
||||
|
|
@ -72,8 +72,8 @@ func closurebody(body *NodeList) *Node {
|
|||
var v *Node
|
||||
for l := func_.Func.Cvars; l != nil; l = l.Next {
|
||||
v = l.N
|
||||
v.Closure.Closure = v.Outer
|
||||
v.Outerexpr = oldname(v.Sym)
|
||||
v.Param.Closure.Param.Closure = v.Param.Outer
|
||||
v.Param.Outerexpr = oldname(v.Sym)
|
||||
}
|
||||
|
||||
return func_
|
||||
|
|
@ -83,16 +83,16 @@ func typecheckclosure(func_ *Node, top int) {
|
|||
var n *Node
|
||||
|
||||
for l := func_.Func.Cvars; l != nil; l = l.Next {
|
||||
n = l.N.Closure
|
||||
if !n.Captured {
|
||||
n.Captured = true
|
||||
if n.Decldepth == 0 {
|
||||
n = l.N.Param.Closure
|
||||
if !n.Name.Captured {
|
||||
n.Name.Captured = true
|
||||
if n.Name.Decldepth == 0 {
|
||||
Fatal("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, obj.FmtShort))
|
||||
}
|
||||
|
||||
// Ignore assignments to the variable in straightline code
|
||||
// preceding the first capturing by a closure.
|
||||
if n.Decldepth == decldepth {
|
||||
if n.Name.Decldepth == decldepth {
|
||||
n.Assigned = false
|
||||
}
|
||||
}
|
||||
|
|
@ -100,14 +100,14 @@ func typecheckclosure(func_ *Node, top int) {
|
|||
|
||||
for l := func_.Func.Dcl; l != nil; l = l.Next {
|
||||
if l.N.Op == ONAME && (l.N.Class == PPARAM || l.N.Class == PPARAMOUT) {
|
||||
l.N.Decldepth = 1
|
||||
l.N.Name.Decldepth = 1
|
||||
}
|
||||
}
|
||||
|
||||
oldfn := Curfn
|
||||
typecheck(&func_.Ntype, Etype)
|
||||
func_.Type = func_.Ntype.Type
|
||||
func_.Top = top
|
||||
typecheck(&func_.Param.Ntype, Etype)
|
||||
func_.Type = func_.Param.Ntype.Type
|
||||
func_.Param.Top = top
|
||||
|
||||
// Type check the body now, but only if we're inside a function.
|
||||
// At top level (in a variable initialization: curfn==nil) we're not
|
||||
|
|
@ -193,7 +193,7 @@ func makeclosure(func_ *Node) *Node {
|
|||
|
||||
xfunc.Nname = newfuncname(closurename(func_))
|
||||
xfunc.Nname.Sym.Flags |= SymExported // disable export
|
||||
xfunc.Nname.Ntype = xtype
|
||||
xfunc.Nname.Param.Ntype = xtype
|
||||
xfunc.Nname.Defn = xfunc
|
||||
declare(xfunc.Nname, PFUNC)
|
||||
xfunc.Nname.Funcdepth = func_.Funcdepth
|
||||
|
|
@ -207,8 +207,8 @@ func makeclosure(func_ *Node) *Node {
|
|||
}
|
||||
typecheck(&xfunc, Etop)
|
||||
|
||||
xfunc.Closure = func_
|
||||
func_.Closure = xfunc
|
||||
xfunc.Param.Closure = func_
|
||||
func_.Param.Closure = xfunc
|
||||
|
||||
func_.Nbody = nil
|
||||
func_.List = nil
|
||||
|
|
@ -229,7 +229,7 @@ func capturevars(xfunc *Node) {
|
|||
lno := int(lineno)
|
||||
lineno = xfunc.Lineno
|
||||
|
||||
func_ := xfunc.Closure
|
||||
func_ := xfunc.Param.Closure
|
||||
func_.Func.Enter = nil
|
||||
for l := func_.Func.Cvars; l != nil; l = l.Next {
|
||||
v = l.N
|
||||
|
|
@ -249,14 +249,14 @@ func capturevars(xfunc *Node) {
|
|||
// so that the outer frame also grabs them and knows they escape.
|
||||
dowidth(v.Type)
|
||||
|
||||
outer = v.Outerexpr
|
||||
v.Outerexpr = nil
|
||||
outer = v.Param.Outerexpr
|
||||
v.Param.Outerexpr = nil
|
||||
|
||||
// out parameters will be assigned to implicitly upon return.
|
||||
if outer.Class != PPARAMOUT && !v.Closure.Addrtaken && !v.Closure.Assigned && v.Type.Width <= 128 {
|
||||
v.Byval = true
|
||||
if outer.Class != PPARAMOUT && !v.Param.Closure.Addrtaken && !v.Param.Closure.Assigned && v.Type.Width <= 128 {
|
||||
v.Name.Byval = true
|
||||
} else {
|
||||
v.Closure.Addrtaken = true
|
||||
v.Param.Closure.Addrtaken = true
|
||||
outer = Nod(OADDR, outer, nil)
|
||||
}
|
||||
|
||||
|
|
@ -266,10 +266,10 @@ func capturevars(xfunc *Node) {
|
|||
name = v.Curfn.Nname.Sym
|
||||
}
|
||||
how := "ref"
|
||||
if v.Byval {
|
||||
if v.Name.Byval {
|
||||
how = "value"
|
||||
}
|
||||
Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, v.Closure.Addrtaken, v.Closure.Assigned, int32(v.Type.Width))
|
||||
Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, v.Param.Closure.Addrtaken, v.Param.Closure.Assigned, int32(v.Type.Width))
|
||||
}
|
||||
|
||||
typecheck(&outer, Erv)
|
||||
|
|
@ -284,9 +284,9 @@ func capturevars(xfunc *Node) {
|
|||
func transformclosure(xfunc *Node) {
|
||||
lno := int(lineno)
|
||||
lineno = xfunc.Lineno
|
||||
func_ := xfunc.Closure
|
||||
func_ := xfunc.Param.Closure
|
||||
|
||||
if func_.Top&Ecall != 0 {
|
||||
if func_.Param.Top&Ecall != 0 {
|
||||
// If the closure is directly called, we transform it to a plain function call
|
||||
// with variables passed as args. This avoids allocation of a closure object.
|
||||
// Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
|
||||
|
|
@ -321,7 +321,7 @@ func transformclosure(xfunc *Node) {
|
|||
}
|
||||
fld = typ(TFIELD)
|
||||
fld.Funarg = 1
|
||||
if v.Byval {
|
||||
if v.Name.Byval {
|
||||
// If v is captured by value, we merely downgrade it to PPARAM.
|
||||
v.Class = PPARAM
|
||||
|
||||
|
|
@ -335,7 +335,7 @@ func transformclosure(xfunc *Node) {
|
|||
addr = newname(Lookupf("&%s", v.Sym.Name))
|
||||
addr.Type = Ptrto(v.Type)
|
||||
addr.Class = PPARAM
|
||||
v.Heapaddr = addr
|
||||
v.Name.Heapaddr = addr
|
||||
fld.Nname = addr
|
||||
}
|
||||
|
||||
|
|
@ -375,14 +375,14 @@ func transformclosure(xfunc *Node) {
|
|||
cv = Nod(OCLOSUREVAR, nil, nil)
|
||||
|
||||
cv.Type = v.Type
|
||||
if !v.Byval {
|
||||
if !v.Name.Byval {
|
||||
cv.Type = Ptrto(v.Type)
|
||||
}
|
||||
offset = Rnd(offset, int64(cv.Type.Align))
|
||||
cv.Xoffset = offset
|
||||
offset += cv.Type.Width
|
||||
|
||||
if v.Byval && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' {
|
||||
if v.Name.Byval && v.Type.Width <= int64(2*Widthptr) && Thearch.Thechar == '6' {
|
||||
// If it is a small variable captured by value, downgrade it to PAUTO.
|
||||
// This optimization is currently enabled only for amd64, see:
|
||||
// https://github.com/golang/go/issues/9865
|
||||
|
|
@ -395,13 +395,13 @@ func transformclosure(xfunc *Node) {
|
|||
// Declare variable holding addresses taken from closure
|
||||
// and initialize in entry prologue.
|
||||
addr = newname(Lookupf("&%s", v.Sym.Name))
|
||||
addr.Ntype = Nod(OIND, typenod(v.Type), nil)
|
||||
addr.Param.Ntype = Nod(OIND, typenod(v.Type), nil)
|
||||
addr.Class = PAUTO
|
||||
addr.Used = true
|
||||
addr.Curfn = xfunc
|
||||
xfunc.Func.Dcl = list(xfunc.Func.Dcl, addr)
|
||||
v.Heapaddr = addr
|
||||
if v.Byval {
|
||||
v.Name.Heapaddr = addr
|
||||
if v.Name.Byval {
|
||||
cv = Nod(OADDR, cv, nil)
|
||||
}
|
||||
body = list(body, Nod(OAS, addr, cv))
|
||||
|
|
@ -420,7 +420,7 @@ func transformclosure(xfunc *Node) {
|
|||
func walkclosure(func_ *Node, init **NodeList) *Node {
|
||||
// If no closure vars, don't bother wrapping.
|
||||
if func_.Func.Cvars == nil {
|
||||
return func_.Closure.Nname
|
||||
return func_.Param.Closure.Nname
|
||||
}
|
||||
|
||||
// Create closure in the form of a composite literal.
|
||||
|
|
@ -448,7 +448,7 @@ func walkclosure(func_ *Node, init **NodeList) *Node {
|
|||
continue
|
||||
}
|
||||
typ1 = typenod(v.Type)
|
||||
if !v.Byval {
|
||||
if !v.Name.Byval {
|
||||
typ1 = Nod(OIND, typ1, nil)
|
||||
}
|
||||
typ.List = list(typ.List, Nod(ODCLFIELD, newname(v.Sym), typ1))
|
||||
|
|
@ -457,7 +457,7 @@ func walkclosure(func_ *Node, init **NodeList) *Node {
|
|||
clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
|
||||
clos.Esc = func_.Esc
|
||||
clos.Right.Implicit = true
|
||||
clos.List = concat(list1(Nod(OCFUNC, func_.Closure.Nname, nil)), func_.Func.Enter)
|
||||
clos.List = concat(list1(Nod(OCFUNC, func_.Param.Closure.Nname, nil)), func_.Func.Enter)
|
||||
|
||||
// Force type conversion from *struct to the func type.
|
||||
clos = Nod(OCONVNOP, clos, nil)
|
||||
|
|
@ -583,7 +583,7 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
|
|||
xfunc.Func.Dupok = true
|
||||
xfunc.Nname = newfuncname(sym)
|
||||
xfunc.Nname.Sym.Flags |= SymExported // disable export
|
||||
xfunc.Nname.Ntype = xtype
|
||||
xfunc.Nname.Param.Ntype = xtype
|
||||
xfunc.Nname.Defn = xfunc
|
||||
declare(xfunc.Nname, PFUNC)
|
||||
|
||||
|
|
@ -606,10 +606,10 @@ func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
|
|||
xfunc.Func.Dcl = list(xfunc.Func.Dcl, ptr)
|
||||
var body *NodeList
|
||||
if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) {
|
||||
ptr.Ntype = typenod(rcvrtype)
|
||||
ptr.Param.Ntype = typenod(rcvrtype)
|
||||
body = list(body, Nod(OAS, ptr, cv))
|
||||
} else {
|
||||
ptr.Ntype = typenod(Ptrto(rcvrtype))
|
||||
ptr.Param.Ntype = typenod(Ptrto(rcvrtype))
|
||||
body = list(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
|
||||
}
|
||||
|
||||
|
|
@ -5,10 +5,47 @@
|
|||
package gc
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/big"
|
||||
"cmd/internal/obj"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Int returns n as an int.
|
||||
// n must be an integer constant.
|
||||
func (n *Node) Int() int64 {
|
||||
if !Isconst(n, CTINT) {
|
||||
Fatal("Int(%v)", n)
|
||||
}
|
||||
return Mpgetfix(n.Val.U.(*Mpint))
|
||||
}
|
||||
|
||||
// SetInt sets n's value to i.
|
||||
// n must be an integer constant.
|
||||
func (n *Node) SetInt(i int64) {
|
||||
if !Isconst(n, CTINT) {
|
||||
Fatal("SetInt(%v)", n)
|
||||
}
|
||||
Mpmovecfix(n.Val.U.(*Mpint), i)
|
||||
}
|
||||
|
||||
// SetBigInt sets n's value to x.
|
||||
// n must be an integer constant.
|
||||
func (n *Node) SetBigInt(x *big.Int) {
|
||||
if !Isconst(n, CTINT) {
|
||||
Fatal("SetBigInt(%v)", n)
|
||||
}
|
||||
n.Val.U.(*Mpint).Val.Set(x)
|
||||
}
|
||||
|
||||
// Bool returns n as an bool.
|
||||
// n must be an boolean constant.
|
||||
func (n *Node) Bool() bool {
|
||||
if !Isconst(n, CTBOOL) {
|
||||
Fatal("Int(%v)", n)
|
||||
}
|
||||
return n.Val.U.(bool)
|
||||
}
|
||||
|
||||
/*
|
||||
* truncate float literal fv to 32-bit or 64-bit precision
|
||||
* according to type; return truncated value.
|
||||
|
|
@ -20,7 +57,7 @@ func truncfltlit(oldv *Mpflt, t *Type) *Mpflt {
|
|||
|
||||
var v Val
|
||||
v.Ctype = CTFLT
|
||||
v.U.Fval = oldv
|
||||
v.U = oldv
|
||||
overflow(v, t)
|
||||
|
||||
fv := newMpflt()
|
||||
|
|
@ -190,8 +227,8 @@ func convlit1(np **Node, t *Type, explicit bool) {
|
|||
// if it is an unsafe.Pointer
|
||||
case TUINTPTR:
|
||||
if n.Type.Etype == TUNSAFEPTR {
|
||||
n.Val.U.Xval = new(Mpint)
|
||||
Mpmovecfix(n.Val.U.Xval, 0)
|
||||
n.Val.U = new(Mpint)
|
||||
Mpmovecfix(n.Val.U.(*Mpint), 0)
|
||||
n.Val.Ctype = CTINT
|
||||
} else {
|
||||
goto bad
|
||||
|
|
@ -204,6 +241,9 @@ func convlit1(np **Node, t *Type, explicit bool) {
|
|||
}
|
||||
|
||||
case CTINT, CTRUNE, CTFLT, CTCPLX:
|
||||
if n.Type.Etype == TUNSAFEPTR && t.Etype != TUINTPTR {
|
||||
goto bad
|
||||
}
|
||||
ct := int(n.Val.Ctype)
|
||||
if Isint[et] {
|
||||
switch ct {
|
||||
|
|
@ -229,7 +269,7 @@ func convlit1(np **Node, t *Type, explicit bool) {
|
|||
|
||||
// flowthrough
|
||||
case CTFLT:
|
||||
n.Val.U.Fval = truncfltlit(n.Val.U.Fval, t)
|
||||
n.Val.U = truncfltlit(n.Val.U.(*Mpflt), t)
|
||||
}
|
||||
} else if Iscomplex[et] {
|
||||
switch ct {
|
||||
|
|
@ -264,27 +304,25 @@ bad:
|
|||
defaultlit(&n, nil)
|
||||
*np = n
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func copyval(v Val) Val {
|
||||
switch v.Ctype {
|
||||
case CTINT, CTRUNE:
|
||||
i := new(Mpint)
|
||||
mpmovefixfix(i, v.U.Xval)
|
||||
v.U.Xval = i
|
||||
mpmovefixfix(i, v.U.(*Mpint))
|
||||
v.U = i
|
||||
|
||||
case CTFLT:
|
||||
f := newMpflt()
|
||||
mpmovefltflt(f, v.U.Fval)
|
||||
v.U.Fval = f
|
||||
mpmovefltflt(f, v.U.(*Mpflt))
|
||||
v.U = f
|
||||
|
||||
case CTCPLX:
|
||||
c := new(Mpcplx)
|
||||
mpmovefltflt(&c.Real, &v.U.Cval.Real)
|
||||
mpmovefltflt(&c.Imag, &v.U.Cval.Imag)
|
||||
v.U.Cval = c
|
||||
mpmovefltflt(&c.Real, &v.U.(*Mpcplx).Real)
|
||||
mpmovefltflt(&c.Imag, &v.U.(*Mpcplx).Imag)
|
||||
v.U = c
|
||||
}
|
||||
|
||||
return v
|
||||
|
|
@ -294,17 +332,17 @@ func tocplx(v Val) Val {
|
|||
switch v.Ctype {
|
||||
case CTINT, CTRUNE:
|
||||
c := new(Mpcplx)
|
||||
Mpmovefixflt(&c.Real, v.U.Xval)
|
||||
Mpmovefixflt(&c.Real, v.U.(*Mpint))
|
||||
Mpmovecflt(&c.Imag, 0.0)
|
||||
v.Ctype = CTCPLX
|
||||
v.U.Cval = c
|
||||
v.U = c
|
||||
|
||||
case CTFLT:
|
||||
c := new(Mpcplx)
|
||||
mpmovefltflt(&c.Real, v.U.Fval)
|
||||
mpmovefltflt(&c.Real, v.U.(*Mpflt))
|
||||
Mpmovecflt(&c.Imag, 0.0)
|
||||
v.Ctype = CTCPLX
|
||||
v.U.Cval = c
|
||||
v.U = c
|
||||
}
|
||||
|
||||
return v
|
||||
|
|
@ -314,18 +352,18 @@ func toflt(v Val) Val {
|
|||
switch v.Ctype {
|
||||
case CTINT, CTRUNE:
|
||||
f := newMpflt()
|
||||
Mpmovefixflt(f, v.U.Xval)
|
||||
Mpmovefixflt(f, v.U.(*Mpint))
|
||||
v.Ctype = CTFLT
|
||||
v.U.Fval = f
|
||||
v.U = f
|
||||
|
||||
case CTCPLX:
|
||||
f := newMpflt()
|
||||
mpmovefltflt(f, &v.U.Cval.Real)
|
||||
if mpcmpfltc(&v.U.Cval.Imag, 0) != 0 {
|
||||
Yyerror("constant %v%vi truncated to real", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign))
|
||||
mpmovefltflt(f, &v.U.(*Mpcplx).Real)
|
||||
if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 {
|
||||
Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign))
|
||||
}
|
||||
v.Ctype = CTFLT
|
||||
v.U.Fval = f
|
||||
v.U = f
|
||||
}
|
||||
|
||||
return v
|
||||
|
|
@ -338,22 +376,22 @@ func toint(v Val) Val {
|
|||
|
||||
case CTFLT:
|
||||
i := new(Mpint)
|
||||
if mpmovefltfix(i, v.U.Fval) < 0 {
|
||||
Yyerror("constant %v truncated to integer", Fconv(v.U.Fval, obj.FmtSharp))
|
||||
if mpmovefltfix(i, v.U.(*Mpflt)) < 0 {
|
||||
Yyerror("constant %v truncated to integer", Fconv(v.U.(*Mpflt), obj.FmtSharp))
|
||||
}
|
||||
v.Ctype = CTINT
|
||||
v.U.Xval = i
|
||||
v.U = i
|
||||
|
||||
case CTCPLX:
|
||||
i := new(Mpint)
|
||||
if mpmovefltfix(i, &v.U.Cval.Real) < 0 {
|
||||
Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign))
|
||||
if mpmovefltfix(i, &v.U.(*Mpcplx).Real) < 0 {
|
||||
Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign))
|
||||
}
|
||||
if mpcmpfltc(&v.U.Cval.Imag, 0) != 0 {
|
||||
Yyerror("constant %v%vi truncated to real", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp|obj.FmtSign))
|
||||
if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 {
|
||||
Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign))
|
||||
}
|
||||
v.Ctype = CTINT
|
||||
v.U.Xval = i
|
||||
v.U = i
|
||||
}
|
||||
|
||||
return v
|
||||
|
|
@ -365,7 +403,7 @@ func doesoverflow(v Val, t *Type) bool {
|
|||
if !Isint[t.Etype] {
|
||||
Fatal("overflow: %v integer constant", t)
|
||||
}
|
||||
if Mpcmpfixfix(v.U.Xval, Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[t.Etype]) > 0 {
|
||||
if Mpcmpfixfix(v.U.(*Mpint), Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[t.Etype]) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -373,7 +411,7 @@ func doesoverflow(v Val, t *Type) bool {
|
|||
if !Isfloat[t.Etype] {
|
||||
Fatal("overflow: %v floating-point constant", t)
|
||||
}
|
||||
if mpcmpfltflt(v.U.Fval, minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.Fval, maxfltval[t.Etype]) >= 0 {
|
||||
if mpcmpfltflt(v.U.(*Mpflt), minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.(*Mpflt), maxfltval[t.Etype]) >= 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -381,7 +419,7 @@ func doesoverflow(v Val, t *Type) bool {
|
|||
if !Iscomplex[t.Etype] {
|
||||
Fatal("overflow: %v complex constant", t)
|
||||
}
|
||||
if mpcmpfltflt(&v.U.Cval.Real, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.Cval.Real, maxfltval[t.Etype]) >= 0 || mpcmpfltflt(&v.U.Cval.Imag, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.Cval.Imag, maxfltval[t.Etype]) >= 0 {
|
||||
if mpcmpfltflt(&v.U.(*Mpcplx).Real, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Real, maxfltval[t.Etype]) >= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, maxfltval[t.Etype]) >= 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -396,32 +434,37 @@ func overflow(v Val, t *Type) {
|
|||
return
|
||||
}
|
||||
|
||||
// Only uintptrs may be converted to unsafe.Pointer, which cannot overflow.
|
||||
if t.Etype == TUNSAFEPTR {
|
||||
return
|
||||
}
|
||||
|
||||
if !doesoverflow(v, t) {
|
||||
return
|
||||
}
|
||||
|
||||
switch v.Ctype {
|
||||
case CTINT, CTRUNE:
|
||||
Yyerror("constant %v overflows %v", v.U.Xval, t)
|
||||
Yyerror("constant %v overflows %v", v.U.(*Mpint), t)
|
||||
|
||||
case CTFLT:
|
||||
Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), t)
|
||||
Yyerror("constant %v overflows %v", Fconv(v.U.(*Mpflt), obj.FmtSharp), t)
|
||||
|
||||
case CTCPLX:
|
||||
Yyerror("constant %v overflows %v", Fconv(v.U.Fval, obj.FmtSharp), t)
|
||||
Yyerror("constant %v overflows %v", Fconv(v.U.(*Mpflt), obj.FmtSharp), t)
|
||||
}
|
||||
}
|
||||
|
||||
func tostr(v Val) Val {
|
||||
switch v.Ctype {
|
||||
case CTINT, CTRUNE:
|
||||
if Mpcmpfixfix(v.U.Xval, Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.Xval, Maxintval[TINT]) > 0 {
|
||||
if Mpcmpfixfix(v.U.(*Mpint), Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[TINT]) > 0 {
|
||||
Yyerror("overflow in int -> string")
|
||||
}
|
||||
r := uint(Mpgetfix(v.U.Xval))
|
||||
r := uint(Mpgetfix(v.U.(*Mpint)))
|
||||
v = Val{}
|
||||
v.Ctype = CTSTR
|
||||
v.U.Sval = string(r)
|
||||
v.U = string(r)
|
||||
|
||||
case CTFLT:
|
||||
Yyerror("no float -> string")
|
||||
|
|
@ -430,7 +473,7 @@ func tostr(v Val) Val {
|
|||
case CTNIL:
|
||||
v = Val{}
|
||||
v.Ctype = CTSTR
|
||||
v.U.Sval = ""
|
||||
v.U = ""
|
||||
}
|
||||
|
||||
return v
|
||||
|
|
@ -519,7 +562,7 @@ func evconst(n *Node) {
|
|||
l2 = l1
|
||||
for l2 != nil && Isconst(l2.N, CTSTR) {
|
||||
nr = l2.N
|
||||
strs = append(strs, nr.Val.U.Sval)
|
||||
strs = append(strs, nr.Val.U.(string))
|
||||
l2 = l2.Next
|
||||
}
|
||||
|
||||
|
|
@ -527,7 +570,7 @@ func evconst(n *Node) {
|
|||
*nl = *l1.N
|
||||
nl.Orig = nl
|
||||
nl.Val.Ctype = CTSTR
|
||||
nl.Val.U.Sval = strings.Join(strs, "")
|
||||
nl.Val.U = strings.Join(strs, "")
|
||||
l1.N = nl
|
||||
l1.Next = l2
|
||||
}
|
||||
|
|
@ -607,7 +650,7 @@ func evconst(n *Node) {
|
|||
|
||||
case OMINUS<<16 | CTINT,
|
||||
OMINUS<<16 | CTRUNE:
|
||||
mpnegfix(v.U.Xval)
|
||||
mpnegfix(v.U.(*Mpint))
|
||||
|
||||
case OCOM<<16 | CTINT,
|
||||
OCOM<<16 | CTRUNE:
|
||||
|
|
@ -634,23 +677,23 @@ func evconst(n *Node) {
|
|||
mpmovefixfix(&b, Maxintval[et])
|
||||
}
|
||||
|
||||
mpxorfixfix(v.U.Xval, &b)
|
||||
mpxorfixfix(v.U.(*Mpint), &b)
|
||||
|
||||
case OPLUS<<16 | CTFLT:
|
||||
break
|
||||
|
||||
case OMINUS<<16 | CTFLT:
|
||||
mpnegflt(v.U.Fval)
|
||||
mpnegflt(v.U.(*Mpflt))
|
||||
|
||||
case OPLUS<<16 | CTCPLX:
|
||||
break
|
||||
|
||||
case OMINUS<<16 | CTCPLX:
|
||||
mpnegflt(&v.U.Cval.Real)
|
||||
mpnegflt(&v.U.Cval.Imag)
|
||||
mpnegflt(&v.U.(*Mpcplx).Real)
|
||||
mpnegflt(&v.U.(*Mpcplx).Imag)
|
||||
|
||||
case ONOT<<16 | CTBOOL:
|
||||
if !v.U.Bval {
|
||||
if !v.U.(bool) {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
|
@ -754,77 +797,77 @@ func evconst(n *Node) {
|
|||
|
||||
case OADD<<16 | CTINT,
|
||||
OADD<<16 | CTRUNE:
|
||||
mpaddfixfix(v.U.Xval, rv.U.Xval, 0)
|
||||
mpaddfixfix(v.U.(*Mpint), rv.U.(*Mpint), 0)
|
||||
|
||||
case OSUB<<16 | CTINT,
|
||||
OSUB<<16 | CTRUNE:
|
||||
mpsubfixfix(v.U.Xval, rv.U.Xval)
|
||||
mpsubfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
||||
|
||||
case OMUL<<16 | CTINT,
|
||||
OMUL<<16 | CTRUNE:
|
||||
mpmulfixfix(v.U.Xval, rv.U.Xval)
|
||||
mpmulfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
||||
|
||||
case ODIV<<16 | CTINT,
|
||||
ODIV<<16 | CTRUNE:
|
||||
if mpcmpfixc(rv.U.Xval, 0) == 0 {
|
||||
if mpcmpfixc(rv.U.(*Mpint), 0) == 0 {
|
||||
Yyerror("division by zero")
|
||||
Mpmovecfix(v.U.Xval, 1)
|
||||
mpsetovf(v.U.(*Mpint))
|
||||
break
|
||||
}
|
||||
|
||||
mpdivfixfix(v.U.Xval, rv.U.Xval)
|
||||
mpdivfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
||||
|
||||
case OMOD<<16 | CTINT,
|
||||
OMOD<<16 | CTRUNE:
|
||||
if mpcmpfixc(rv.U.Xval, 0) == 0 {
|
||||
if mpcmpfixc(rv.U.(*Mpint), 0) == 0 {
|
||||
Yyerror("division by zero")
|
||||
Mpmovecfix(v.U.Xval, 1)
|
||||
mpsetovf(v.U.(*Mpint))
|
||||
break
|
||||
}
|
||||
|
||||
mpmodfixfix(v.U.Xval, rv.U.Xval)
|
||||
mpmodfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
||||
|
||||
case OLSH<<16 | CTINT,
|
||||
OLSH<<16 | CTRUNE:
|
||||
mplshfixfix(v.U.Xval, rv.U.Xval)
|
||||
mplshfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
||||
|
||||
case ORSH<<16 | CTINT,
|
||||
ORSH<<16 | CTRUNE:
|
||||
mprshfixfix(v.U.Xval, rv.U.Xval)
|
||||
mprshfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
||||
|
||||
case OOR<<16 | CTINT,
|
||||
OOR<<16 | CTRUNE:
|
||||
mporfixfix(v.U.Xval, rv.U.Xval)
|
||||
mporfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
||||
|
||||
case OAND<<16 | CTINT,
|
||||
OAND<<16 | CTRUNE:
|
||||
mpandfixfix(v.U.Xval, rv.U.Xval)
|
||||
mpandfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
||||
|
||||
case OANDNOT<<16 | CTINT,
|
||||
OANDNOT<<16 | CTRUNE:
|
||||
mpandnotfixfix(v.U.Xval, rv.U.Xval)
|
||||
mpandnotfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
||||
|
||||
case OXOR<<16 | CTINT,
|
||||
OXOR<<16 | CTRUNE:
|
||||
mpxorfixfix(v.U.Xval, rv.U.Xval)
|
||||
mpxorfixfix(v.U.(*Mpint), rv.U.(*Mpint))
|
||||
|
||||
case OADD<<16 | CTFLT:
|
||||
mpaddfltflt(v.U.Fval, rv.U.Fval)
|
||||
mpaddfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
|
||||
|
||||
case OSUB<<16 | CTFLT:
|
||||
mpsubfltflt(v.U.Fval, rv.U.Fval)
|
||||
mpsubfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
|
||||
|
||||
case OMUL<<16 | CTFLT:
|
||||
mpmulfltflt(v.U.Fval, rv.U.Fval)
|
||||
mpmulfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
|
||||
|
||||
case ODIV<<16 | CTFLT:
|
||||
if mpcmpfltc(rv.U.Fval, 0) == 0 {
|
||||
if mpcmpfltc(rv.U.(*Mpflt), 0) == 0 {
|
||||
Yyerror("division by zero")
|
||||
Mpmovecflt(v.U.Fval, 1.0)
|
||||
Mpmovecflt(v.U.(*Mpflt), 1.0)
|
||||
break
|
||||
}
|
||||
|
||||
mpdivfltflt(v.U.Fval, rv.U.Fval)
|
||||
mpdivfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
|
||||
|
||||
// The default case above would print 'ideal % ideal',
|
||||
// which is not quite an ideal error.
|
||||
|
|
@ -837,25 +880,25 @@ func evconst(n *Node) {
|
|||
return
|
||||
|
||||
case OADD<<16 | CTCPLX:
|
||||
mpaddfltflt(&v.U.Cval.Real, &rv.U.Cval.Real)
|
||||
mpaddfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag)
|
||||
mpaddfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real)
|
||||
mpaddfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag)
|
||||
|
||||
case OSUB<<16 | CTCPLX:
|
||||
mpsubfltflt(&v.U.Cval.Real, &rv.U.Cval.Real)
|
||||
mpsubfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag)
|
||||
mpsubfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real)
|
||||
mpsubfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag)
|
||||
|
||||
case OMUL<<16 | CTCPLX:
|
||||
cmplxmpy(v.U.Cval, rv.U.Cval)
|
||||
cmplxmpy(v.U.(*Mpcplx), rv.U.(*Mpcplx))
|
||||
|
||||
case ODIV<<16 | CTCPLX:
|
||||
if mpcmpfltc(&rv.U.Cval.Real, 0) == 0 && mpcmpfltc(&rv.U.Cval.Imag, 0) == 0 {
|
||||
if mpcmpfltc(&rv.U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&rv.U.(*Mpcplx).Imag, 0) == 0 {
|
||||
Yyerror("complex division by zero")
|
||||
Mpmovecflt(&rv.U.Cval.Real, 1.0)
|
||||
Mpmovecflt(&rv.U.Cval.Imag, 0.0)
|
||||
Mpmovecflt(&rv.U.(*Mpcplx).Real, 1.0)
|
||||
Mpmovecflt(&rv.U.(*Mpcplx).Imag, 0.0)
|
||||
break
|
||||
}
|
||||
|
||||
cmplxdiv(v.U.Cval, rv.U.Cval)
|
||||
cmplxdiv(v.U.(*Mpcplx), rv.U.(*Mpcplx))
|
||||
|
||||
case OEQ<<16 | CTNIL:
|
||||
goto settrue
|
||||
|
|
@ -865,90 +908,90 @@ func evconst(n *Node) {
|
|||
|
||||
case OEQ<<16 | CTINT,
|
||||
OEQ<<16 | CTRUNE:
|
||||
if Mpcmpfixfix(v.U.Xval, rv.U.Xval) == 0 {
|
||||
if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) == 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case ONE<<16 | CTINT,
|
||||
ONE<<16 | CTRUNE:
|
||||
if Mpcmpfixfix(v.U.Xval, rv.U.Xval) != 0 {
|
||||
if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) != 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case OLT<<16 | CTINT,
|
||||
OLT<<16 | CTRUNE:
|
||||
if Mpcmpfixfix(v.U.Xval, rv.U.Xval) < 0 {
|
||||
if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) < 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case OLE<<16 | CTINT,
|
||||
OLE<<16 | CTRUNE:
|
||||
if Mpcmpfixfix(v.U.Xval, rv.U.Xval) <= 0 {
|
||||
if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) <= 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case OGE<<16 | CTINT,
|
||||
OGE<<16 | CTRUNE:
|
||||
if Mpcmpfixfix(v.U.Xval, rv.U.Xval) >= 0 {
|
||||
if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) >= 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case OGT<<16 | CTINT,
|
||||
OGT<<16 | CTRUNE:
|
||||
if Mpcmpfixfix(v.U.Xval, rv.U.Xval) > 0 {
|
||||
if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) > 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case OEQ<<16 | CTFLT:
|
||||
if mpcmpfltflt(v.U.Fval, rv.U.Fval) == 0 {
|
||||
if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) == 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case ONE<<16 | CTFLT:
|
||||
if mpcmpfltflt(v.U.Fval, rv.U.Fval) != 0 {
|
||||
if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) != 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case OLT<<16 | CTFLT:
|
||||
if mpcmpfltflt(v.U.Fval, rv.U.Fval) < 0 {
|
||||
if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) < 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case OLE<<16 | CTFLT:
|
||||
if mpcmpfltflt(v.U.Fval, rv.U.Fval) <= 0 {
|
||||
if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) <= 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case OGE<<16 | CTFLT:
|
||||
if mpcmpfltflt(v.U.Fval, rv.U.Fval) >= 0 {
|
||||
if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) >= 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case OGT<<16 | CTFLT:
|
||||
if mpcmpfltflt(v.U.Fval, rv.U.Fval) > 0 {
|
||||
if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) > 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case OEQ<<16 | CTCPLX:
|
||||
if mpcmpfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) == 0 && mpcmpfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) == 0 {
|
||||
if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) == 0 && mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) == 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case ONE<<16 | CTCPLX:
|
||||
if mpcmpfltflt(&v.U.Cval.Real, &rv.U.Cval.Real) != 0 || mpcmpfltflt(&v.U.Cval.Imag, &rv.U.Cval.Imag) != 0 {
|
||||
if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) != 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) != 0 {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
|
@ -990,25 +1033,25 @@ func evconst(n *Node) {
|
|||
goto setfalse
|
||||
|
||||
case OOROR<<16 | CTBOOL:
|
||||
if v.U.Bval || rv.U.Bval {
|
||||
if v.U.(bool) || rv.U.(bool) {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case OANDAND<<16 | CTBOOL:
|
||||
if v.U.Bval && rv.U.Bval {
|
||||
if v.U.(bool) && rv.U.(bool) {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case OEQ<<16 | CTBOOL:
|
||||
if v.U.Bval == rv.U.Bval {
|
||||
if v.U.(bool) == rv.U.(bool) {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
||||
case ONE<<16 | CTBOOL:
|
||||
if v.U.Bval != rv.U.Bval {
|
||||
if v.U.(bool) != rv.U.(bool) {
|
||||
goto settrue
|
||||
}
|
||||
goto setfalse
|
||||
|
|
@ -1033,7 +1076,7 @@ ret:
|
|||
|
||||
// truncate precision for non-ideal float.
|
||||
if v.Ctype == CTFLT && n.Type.Etype != TIDEAL {
|
||||
n.Val.U.Fval = truncfltlit(v.U.Fval, n.Type)
|
||||
n.Val.U = truncfltlit(v.U.(*Mpflt), n.Type)
|
||||
}
|
||||
return
|
||||
|
||||
|
|
@ -1088,15 +1131,15 @@ func nodcplxlit(r Val, i Val) *Node {
|
|||
c := new(Mpcplx)
|
||||
n := Nod(OLITERAL, nil, nil)
|
||||
n.Type = Types[TIDEAL]
|
||||
n.Val.U.Cval = c
|
||||
n.Val.U = c
|
||||
n.Val.Ctype = CTCPLX
|
||||
|
||||
if r.Ctype != CTFLT || i.Ctype != CTFLT {
|
||||
Fatal("nodcplxlit ctype %d/%d", r.Ctype, i.Ctype)
|
||||
}
|
||||
|
||||
mpmovefltflt(&c.Real, r.U.Fval)
|
||||
mpmovefltflt(&c.Imag, i.U.Fval)
|
||||
mpmovefltflt(&c.Real, r.U.(*Mpflt))
|
||||
mpmovefltflt(&c.Imag, i.U.(*Mpflt))
|
||||
return n
|
||||
}
|
||||
|
||||
|
|
@ -1311,7 +1354,7 @@ func defaultlit2(lp **Node, rp **Node, force int) {
|
|||
}
|
||||
|
||||
func cmpslit(l, r *Node) int {
|
||||
return stringsCompare(l.Val.U.Sval, r.Val.U.Sval)
|
||||
return stringsCompare(l.Val.U.(string), r.Val.U.(string))
|
||||
}
|
||||
|
||||
func Smallintconst(n *Node) bool {
|
||||
|
|
@ -1328,7 +1371,7 @@ func Smallintconst(n *Node) bool {
|
|||
return true
|
||||
|
||||
case TIDEAL, TINT64, TUINT64, TPTR64:
|
||||
if Mpcmpfixfix(n.Val.U.Xval, Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT32]) > 0 {
|
||||
if Mpcmpfixfix(n.Val.U.(*Mpint), Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val.U.(*Mpint), Maxintval[TINT32]) > 0 {
|
||||
break
|
||||
}
|
||||
return true
|
||||
|
|
@ -1351,10 +1394,10 @@ func nonnegconst(n *Node) int {
|
|||
TINT64,
|
||||
TUINT64,
|
||||
TIDEAL:
|
||||
if Mpcmpfixfix(n.Val.U.Xval, Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val.U.Xval, Maxintval[TINT32]) > 0 {
|
||||
if Mpcmpfixfix(n.Val.U.(*Mpint), Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val.U.(*Mpint), Maxintval[TINT32]) > 0 {
|
||||
break
|
||||
}
|
||||
return int(Mpgetfix(n.Val.U.Xval))
|
||||
return int(Mpgetfix(n.Val.U.(*Mpint)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1392,39 +1435,37 @@ func iconv(x int64, et int) int64 {
|
|||
return x
|
||||
}
|
||||
|
||||
/*
|
||||
* convert constant val to type t; leave in con.
|
||||
* for back end.
|
||||
*/
|
||||
func Convconst(con *Node, t *Type, val *Val) {
|
||||
// Convconst converts constant node n to type t and
|
||||
// places the result in con.
|
||||
func (n *Node) Convconst(con *Node, t *Type) {
|
||||
tt := Simsimtype(t)
|
||||
|
||||
// copy the constant for conversion
|
||||
Nodconst(con, Types[TINT8], 0)
|
||||
|
||||
con.Type = t
|
||||
con.Val = *val
|
||||
con.Val = n.Val
|
||||
|
||||
if Isint[tt] {
|
||||
con.Val.Ctype = CTINT
|
||||
con.Val.U.Xval = new(Mpint)
|
||||
con.Val.U = new(Mpint)
|
||||
var i int64
|
||||
switch val.Ctype {
|
||||
switch n.Val.Ctype {
|
||||
default:
|
||||
Fatal("convconst ctype=%d %v", val.Ctype, Tconv(t, obj.FmtLong))
|
||||
Fatal("convconst ctype=%d %v", n.Val.Ctype, Tconv(t, obj.FmtLong))
|
||||
|
||||
case CTINT, CTRUNE:
|
||||
i = Mpgetfix(val.U.Xval)
|
||||
i = Mpgetfix(n.Val.U.(*Mpint))
|
||||
|
||||
case CTBOOL:
|
||||
i = int64(obj.Bool2int(val.U.Bval))
|
||||
i = int64(obj.Bool2int(n.Val.U.(bool)))
|
||||
|
||||
case CTNIL:
|
||||
i = 0
|
||||
}
|
||||
|
||||
i = iconv(i, tt)
|
||||
Mpmovecfix(con.Val.U.Xval, i)
|
||||
Mpmovecfix(con.Val.U.(*Mpint), i)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -1434,7 +1475,7 @@ func Convconst(con *Node, t *Type, val *Val) {
|
|||
Fatal("convconst ctype=%d %v", con.Val.Ctype, t)
|
||||
}
|
||||
if tt == TFLOAT32 {
|
||||
con.Val.U.Fval = truncfltlit(con.Val.U.Fval, t)
|
||||
con.Val.U = truncfltlit(con.Val.U.(*Mpflt), t)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
@ -1442,10 +1483,9 @@ func Convconst(con *Node, t *Type, val *Val) {
|
|||
if Iscomplex[tt] {
|
||||
con.Val = tocplx(con.Val)
|
||||
if tt == TCOMPLEX64 {
|
||||
con.Val.U.Cval.Real = *truncfltlit(&con.Val.U.Cval.Real, Types[TFLOAT32])
|
||||
con.Val.U.Cval.Imag = *truncfltlit(&con.Val.U.Cval.Imag, Types[TFLOAT32])
|
||||
con.Val.U.(*Mpcplx).Real = *truncfltlit(&con.Val.U.(*Mpcplx).Real, Types[TFLOAT32])
|
||||
con.Val.U.(*Mpcplx).Imag = *truncfltlit(&con.Val.U.(*Mpcplx).Imag, Types[TFLOAT32])
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -89,8 +89,8 @@ func subnode(nr *Node, ni *Node, nc *Node) {
|
|||
t := Types[tc]
|
||||
|
||||
if nc.Op == OLITERAL {
|
||||
nodfconst(nr, t, &nc.Val.U.Cval.Real)
|
||||
nodfconst(ni, t, &nc.Val.U.Cval.Imag)
|
||||
nodfconst(nr, t, &nc.Val.U.(*Mpcplx).Real)
|
||||
nodfconst(ni, t, &nc.Val.U.(*Mpcplx).Imag)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -226,7 +226,7 @@ func nodfconst(n *Node, t *Type, fval *Mpflt) {
|
|||
n.Op = OLITERAL
|
||||
n.Addable = true
|
||||
ullmancalc(n)
|
||||
n.Val.U.Fval = fval
|
||||
n.Val.U = fval
|
||||
n.Val.Ctype = CTFLT
|
||||
n.Type = t
|
||||
|
||||
|
|
@ -183,7 +183,7 @@ func declare(n *Node, ctxt uint8) {
|
|||
}
|
||||
|
||||
if ctxt == PEXTERN && s.Name == "init" {
|
||||
Yyerror("cannot declare init - must be func", s)
|
||||
Yyerror("cannot declare init - must be func")
|
||||
}
|
||||
|
||||
gen := 0
|
||||
|
|
@ -260,7 +260,7 @@ func variter(vl *NodeList, t *Node, el *NodeList) *NodeList {
|
|||
v = vl.N
|
||||
v.Op = ONAME
|
||||
declare(v, dclcontext)
|
||||
v.Ntype = t
|
||||
v.Param.Ntype = t
|
||||
v.Defn = as2
|
||||
if Funcdepth > 0 {
|
||||
init = list(init, Nod(ODCL, v, nil))
|
||||
|
|
@ -288,7 +288,7 @@ func variter(vl *NodeList, t *Node, el *NodeList) *NodeList {
|
|||
v = vl.N
|
||||
v.Op = ONAME
|
||||
declare(v, dclcontext)
|
||||
v.Ntype = t
|
||||
v.Param.Ntype = t
|
||||
|
||||
if e != nil || Funcdepth > 0 || isblank(v) {
|
||||
if Funcdepth > 0 {
|
||||
|
|
@ -313,18 +313,19 @@ func variter(vl *NodeList, t *Node, el *NodeList) *NodeList {
|
|||
* new_name_list [[type] = expr_list]
|
||||
*/
|
||||
func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList {
|
||||
lno := int32(0) // default is to leave line number alone in listtreecopy
|
||||
if cl == nil {
|
||||
if t != nil {
|
||||
Yyerror("const declaration cannot have type without expression")
|
||||
}
|
||||
cl = lastconst
|
||||
t = lasttype
|
||||
lno = vl.N.Lineno
|
||||
} else {
|
||||
lastconst = cl
|
||||
lasttype = t
|
||||
}
|
||||
|
||||
cl = listtreecopy(cl)
|
||||
cl = listtreecopy(cl, lno)
|
||||
|
||||
var v *Node
|
||||
var c *Node
|
||||
|
|
@ -342,7 +343,7 @@ func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList {
|
|||
v.Op = OLITERAL
|
||||
declare(v, dclcontext)
|
||||
|
||||
v.Ntype = t
|
||||
v.Param.Ntype = t
|
||||
v.Defn = c
|
||||
|
||||
vv = list(vv, Nod(ODCLCONST, v, nil))
|
||||
|
|
@ -430,7 +431,7 @@ func oldname(s *Sym) *Node {
|
|||
// are parsing x := 5 inside the closure, until we get to
|
||||
// the := it looks like a reference to the outer x so we'll
|
||||
// make x a closure variable unnecessarily.
|
||||
if n.Closure == nil || n.Closure.Funcdepth != Funcdepth {
|
||||
if n.Param.Closure == nil || n.Param.Closure.Funcdepth != Funcdepth {
|
||||
// create new closure var.
|
||||
c := Nod(ONAME, nil, nil)
|
||||
|
||||
|
|
@ -441,15 +442,15 @@ func oldname(s *Sym) *Node {
|
|||
c.Addable = false
|
||||
c.Ullman = 2
|
||||
c.Funcdepth = Funcdepth
|
||||
c.Outer = n.Closure
|
||||
n.Closure = c
|
||||
c.Closure = n
|
||||
c.Param.Outer = n.Param.Closure
|
||||
n.Param.Closure = c
|
||||
c.Param.Closure = n
|
||||
c.Xoffset = 0
|
||||
Curfn.Func.Cvars = list(Curfn.Func.Cvars, c)
|
||||
}
|
||||
|
||||
// return ref to closure var, not original
|
||||
return n.Closure
|
||||
return n.Param.Closure
|
||||
}
|
||||
|
||||
return n
|
||||
|
|
@ -554,7 +555,7 @@ func ifacedcl(n *Node) {
|
|||
dclcontext = PPARAM
|
||||
markdcl()
|
||||
Funcdepth++
|
||||
n.Outer = Curfn
|
||||
n.Param.Outer = Curfn
|
||||
Curfn = n
|
||||
funcargs(n.Right)
|
||||
|
||||
|
|
@ -583,13 +584,13 @@ func funchdr(n *Node) {
|
|||
markdcl()
|
||||
Funcdepth++
|
||||
|
||||
n.Outer = Curfn
|
||||
n.Param.Outer = Curfn
|
||||
Curfn = n
|
||||
|
||||
if n.Nname != nil {
|
||||
funcargs(n.Nname.Ntype)
|
||||
} else if n.Ntype != nil {
|
||||
funcargs(n.Ntype)
|
||||
funcargs(n.Nname.Param.Ntype)
|
||||
} else if n.Param.Ntype != nil {
|
||||
funcargs(n.Param.Ntype)
|
||||
} else {
|
||||
funcargs2(n.Type)
|
||||
}
|
||||
|
|
@ -615,7 +616,7 @@ func funcargs(nt *Node) {
|
|||
}
|
||||
if n.Left != nil {
|
||||
n.Left.Op = ONAME
|
||||
n.Left.Ntype = n.Right
|
||||
n.Left.Param.Ntype = n.Right
|
||||
declare(n.Left, PPARAM)
|
||||
if dclcontext == PAUTO {
|
||||
vargen++
|
||||
|
|
@ -632,7 +633,7 @@ func funcargs(nt *Node) {
|
|||
}
|
||||
if n.Left != nil {
|
||||
n.Left.Op = ONAME
|
||||
n.Left.Ntype = n.Right
|
||||
n.Left.Param.Ntype = n.Right
|
||||
declare(n.Left, PPARAM)
|
||||
if dclcontext == PAUTO {
|
||||
vargen++
|
||||
|
|
@ -679,7 +680,7 @@ func funcargs(nt *Node) {
|
|||
n.Left = nn
|
||||
}
|
||||
|
||||
n.Left.Ntype = n.Right
|
||||
n.Left.Param.Ntype = n.Right
|
||||
declare(n.Left, PPARAMOUT)
|
||||
if dclcontext == PAUTO {
|
||||
i++
|
||||
|
|
@ -747,8 +748,8 @@ func funcbody(n *Node) {
|
|||
}
|
||||
popdcl()
|
||||
Funcdepth--
|
||||
Curfn = n.Outer
|
||||
n.Outer = nil
|
||||
Curfn = n.Param.Outer
|
||||
n.Param.Outer = nil
|
||||
if Funcdepth == 0 {
|
||||
dclcontext = PEXTERN
|
||||
}
|
||||
|
|
@ -770,7 +771,7 @@ func typedcl0(s *Sym) *Node {
|
|||
* return the ODCLTYPE node to use.
|
||||
*/
|
||||
func typedcl1(n *Node, t *Node, local bool) *Node {
|
||||
n.Ntype = t
|
||||
n.Param.Ntype = t
|
||||
n.Local = local
|
||||
return Nod(ODCLTYPE, n, nil)
|
||||
}
|
||||
|
|
@ -830,7 +831,7 @@ func structfield(n *Node) *Type {
|
|||
switch n.Val.Ctype {
|
||||
case CTSTR:
|
||||
f.Note = new(string)
|
||||
*f.Note = n.Val.U.Sval
|
||||
*f.Note = n.Val.U.(string)
|
||||
|
||||
default:
|
||||
Yyerror("field annotation must be string")
|
||||
|
|
@ -154,7 +154,7 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
|
|||
}
|
||||
|
||||
if n.Op == OCLOSURE {
|
||||
m := v.visit(n.Closure)
|
||||
m := v.visit(n.Param.Closure)
|
||||
if m < min {
|
||||
min = m
|
||||
}
|
||||
|
|
@ -379,7 +379,7 @@ type EscState struct {
|
|||
theSink Node
|
||||
|
||||
dsts *NodeList // all dst nodes
|
||||
loopdepth int // for detecting nested loop scopes
|
||||
loopdepth int32 // for detecting nested loop scopes
|
||||
pdepth int // for debug printing in recursions.
|
||||
dstcount int // diagnostic
|
||||
edgecount int // diagnostic
|
||||
|
|
@ -387,6 +387,19 @@ type EscState struct {
|
|||
recursive bool // recursive function or group of mutually recursive functions.
|
||||
}
|
||||
|
||||
// funcSym returns n.Nname.Sym if no nils are encountered along the way.
|
||||
func funcSym(n *Node) *Sym {
|
||||
if n == nil || n.Nname == nil {
|
||||
return nil
|
||||
}
|
||||
return n.Nname.Sym
|
||||
}
|
||||
|
||||
// curfnSym returns n.Curfn.Nname.Sym if no nils are encountered along the way.
|
||||
func curfnSym(n *Node) *Sym {
|
||||
return funcSym(n.Curfn)
|
||||
}
|
||||
|
||||
func escAnalyze(all *NodeList, recursive bool) {
|
||||
var es EscState
|
||||
e := &es
|
||||
|
|
@ -428,13 +441,7 @@ func escAnalyze(all *NodeList, recursive bool) {
|
|||
if Debug['m'] != 0 {
|
||||
for l := e.noesc; l != nil; l = l.Next {
|
||||
if l.N.Esc == EscNone {
|
||||
var tmp *Sym
|
||||
if l.N.Curfn != nil && l.N.Curfn.Nname != nil {
|
||||
tmp = l.N.Curfn.Nname.Sym
|
||||
} else {
|
||||
tmp = nil
|
||||
}
|
||||
Warnl(int(l.N.Lineno), "%v %v does not escape", tmp, Nconv(l.N, obj.FmtShort))
|
||||
Warnl(int(l.N.Lineno), "%v %v does not escape", curfnSym(l.N), Nconv(l.N, obj.FmtShort))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -579,6 +586,19 @@ func esc(e *EscState, n *Node, up *Node) {
|
|||
}
|
||||
}
|
||||
|
||||
// Big stuff escapes unconditionally
|
||||
// "Big" conditions that were scattered around in walk have been gathered here
|
||||
if n.Esc != EscHeap && n.Type != nil && (n.Type.Width > MaxStackVarSize ||
|
||||
n.Op == ONEW && n.Type.Type.Width >= 1<<16 ||
|
||||
n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
|
||||
if Debug['m'] > 1 {
|
||||
Warnl(int(n.Lineno), "%v is too large for stack", n)
|
||||
}
|
||||
n.Esc = EscHeap
|
||||
addrescapes(n)
|
||||
escassign(e, &e.theSink, n)
|
||||
}
|
||||
|
||||
esc(e, n.Left, n)
|
||||
esc(e, n.Right, n)
|
||||
esc(e, n.Ntest, n)
|
||||
|
|
@ -593,13 +613,7 @@ func esc(e *EscState, n *Node, up *Node) {
|
|||
}
|
||||
|
||||
if Debug['m'] > 1 {
|
||||
var tmp *Sym
|
||||
if Curfn != nil && Curfn.Nname != nil {
|
||||
tmp = Curfn.Nname.Sym
|
||||
} else {
|
||||
tmp = nil
|
||||
}
|
||||
fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, tmp, n)
|
||||
fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), n)
|
||||
}
|
||||
|
||||
switch n.Op {
|
||||
|
|
@ -629,8 +643,12 @@ func esc(e *EscState, n *Node, up *Node) {
|
|||
|
||||
// Everything but fixed array is a dereference.
|
||||
case ORANGE:
|
||||
if Isfixedarray(n.Type) && n.List != nil && n.List.Next != nil {
|
||||
escassign(e, n.List.Next.N, n.Right)
|
||||
if n.List != nil && n.List.Next != nil {
|
||||
if Isfixedarray(n.Type) {
|
||||
escassign(e, n.List.Next.N, n.Right)
|
||||
} else {
|
||||
escassign(e, n.List.Next.N, addDereference(n.Right))
|
||||
}
|
||||
}
|
||||
|
||||
case OSWITCH:
|
||||
|
|
@ -670,13 +688,7 @@ func esc(e *EscState, n *Node, up *Node) {
|
|||
// b escapes as well. If we ignore such OSLICEARR, we will conclude
|
||||
// that b does not escape when b contents do.
|
||||
if Debug['m'] != 0 {
|
||||
var tmp *Sym
|
||||
if n.Curfn != nil && n.Curfn.Nname != nil {
|
||||
tmp = n.Curfn.Nname.Sym
|
||||
} else {
|
||||
tmp = nil
|
||||
}
|
||||
Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", tmp, Nconv(n.Left, obj.FmtShort))
|
||||
Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", curfnSym(n), Nconv(n.Left, obj.FmtShort))
|
||||
}
|
||||
|
||||
break
|
||||
|
|
@ -763,7 +775,15 @@ func esc(e *EscState, n *Node, up *Node) {
|
|||
for ll := n.List.Next; ll != nil; ll = ll.Next {
|
||||
escassign(e, &e.theSink, ll.N) // lose track of assign to dereference
|
||||
}
|
||||
} else {
|
||||
// append(slice1, slice2...) -- slice2 itself does not escape, but contents do.
|
||||
slice2 := n.List.Next.N
|
||||
escassign(e, &e.theSink, addDereference(slice2)) // lose track of assign of dereference
|
||||
if Debug['m'] > 2 {
|
||||
Warnl(int(n.Lineno), "%v special treatment of append(slice1, slice2...) %v", curfnSym(n), Nconv(n, obj.FmtShort))
|
||||
}
|
||||
}
|
||||
escassign(e, &e.theSink, addDereference(n.List.N)) // The original elements are now leaked, too
|
||||
|
||||
case OCONV, OCONVNOP:
|
||||
escassign(e, n, n.Left)
|
||||
|
|
@ -776,19 +796,15 @@ func esc(e *EscState, n *Node, up *Node) {
|
|||
|
||||
case OARRAYLIT:
|
||||
if Isslice(n.Type) {
|
||||
n.Esc = EscNone // until proven otherwise
|
||||
// Slice itself is not leaked until proven otherwise
|
||||
n.Esc = EscNone
|
||||
e.noesc = list(e.noesc, n)
|
||||
n.Escloopdepth = e.loopdepth
|
||||
}
|
||||
|
||||
// Values make it to memory, lose track.
|
||||
for ll := n.List; ll != nil; ll = ll.Next {
|
||||
escassign(e, &e.theSink, ll.N.Right)
|
||||
}
|
||||
} else {
|
||||
// Link values to array.
|
||||
for ll := n.List; ll != nil; ll = ll.Next {
|
||||
escassign(e, n, ll.N.Right)
|
||||
}
|
||||
// Link values to array/slice
|
||||
for ll := n.List; ll != nil; ll = ll.Next {
|
||||
escassign(e, n, ll.N.Right)
|
||||
}
|
||||
|
||||
// Link values to struct.
|
||||
|
|
@ -833,8 +849,8 @@ func esc(e *EscState, n *Node, up *Node) {
|
|||
if v.Op == OXXX { // unnamed out argument; see dcl.c:/^funcargs
|
||||
continue
|
||||
}
|
||||
a = v.Closure
|
||||
if !v.Byval {
|
||||
a = v.Param.Closure
|
||||
if !v.Name.Byval {
|
||||
a = Nod(OADDR, a, nil)
|
||||
a.Lineno = v.Lineno
|
||||
a.Escloopdepth = e.loopdepth
|
||||
|
|
@ -909,14 +925,8 @@ func escassign(e *EscState, dst *Node, src *Node) {
|
|||
}
|
||||
|
||||
if Debug['m'] > 1 {
|
||||
var tmp *Sym
|
||||
if Curfn != nil && Curfn.Nname != nil {
|
||||
tmp = Curfn.Nname.Sym
|
||||
} else {
|
||||
tmp = nil
|
||||
}
|
||||
fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n",
|
||||
Ctxt.Line(int(lineno)), e.loopdepth, tmp,
|
||||
Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn),
|
||||
Nconv(dst, obj.FmtShort), Jconv(dst, obj.FmtShort), Oconv(int(dst.Op), 0),
|
||||
Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), Oconv(int(src.Op), 0))
|
||||
}
|
||||
|
|
@ -1038,12 +1048,15 @@ func escassign(e *EscState, dst *Node, src *Node) {
|
|||
|
||||
case OAPPEND:
|
||||
// Append returns first argument.
|
||||
// Subsequent arguments are already leaked because they are operands to append.
|
||||
escassign(e, dst, src.List.N)
|
||||
|
||||
case OINDEX:
|
||||
// Index of array preserves input value.
|
||||
if Isfixedarray(src.Left.Type) {
|
||||
escassign(e, dst, src.Left)
|
||||
} else {
|
||||
escflows(e, dst, src)
|
||||
}
|
||||
|
||||
// Might be pointer arithmetic, in which case
|
||||
|
|
@ -1269,6 +1282,24 @@ func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 {
|
|||
return (e &^ (bitsMaskForTag << shift)) | encodedFlow
|
||||
}
|
||||
|
||||
func initEscretval(e *EscState, n *Node, fntype *Type) {
|
||||
i := 0
|
||||
n.Escretval = nil // Suspect this is not nil for indirect calls.
|
||||
for t := getoutargx(fntype).Type; t != nil; t = t.Down {
|
||||
src := Nod(ONAME, nil, nil)
|
||||
buf := fmt.Sprintf(".out%d", i)
|
||||
i++
|
||||
src.Sym = Lookup(buf)
|
||||
src.Type = t.Type
|
||||
src.Class = PAUTO
|
||||
src.Curfn = Curfn
|
||||
src.Escloopdepth = e.loopdepth
|
||||
src.Used = true
|
||||
src.Lineno = n.Lineno
|
||||
n.Escretval = list(n.Escretval, src)
|
||||
}
|
||||
}
|
||||
|
||||
// This is a bit messier than fortunate, pulled out of esc's big
|
||||
// switch for clarity. We either have the paramnodes, which may be
|
||||
// connected to other things through flows or we have the parameter type
|
||||
|
|
@ -1277,7 +1308,7 @@ func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 {
|
|||
// this-package
|
||||
func esccall(e *EscState, n *Node, up *Node) {
|
||||
var fntype *Type
|
||||
|
||||
var indirect bool
|
||||
var fn *Node
|
||||
switch n.Op {
|
||||
default:
|
||||
|
|
@ -1286,6 +1317,7 @@ func esccall(e *EscState, n *Node, up *Node) {
|
|||
case OCALLFUNC:
|
||||
fn = n.Left
|
||||
fntype = fn.Type
|
||||
indirect = fn.Op != ONAME || fn.Class != PFUNC
|
||||
|
||||
case OCALLMETH:
|
||||
fn = n.Left.Right.Sym.Def
|
||||
|
|
@ -1297,6 +1329,7 @@ func esccall(e *EscState, n *Node, up *Node) {
|
|||
|
||||
case OCALLINTER:
|
||||
fntype = n.Left.Type
|
||||
indirect = true
|
||||
}
|
||||
|
||||
ll := n.List
|
||||
|
|
@ -1307,8 +1340,30 @@ func esccall(e *EscState, n *Node, up *Node) {
|
|||
}
|
||||
}
|
||||
|
||||
if indirect {
|
||||
// We know nothing!
|
||||
// Leak all the parameters
|
||||
for ; ll != nil; ll = ll.Next {
|
||||
escassign(e, &e.theSink, ll.N)
|
||||
if Debug['m'] > 2 {
|
||||
fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
|
||||
}
|
||||
}
|
||||
// Set up bogus outputs
|
||||
initEscretval(e, n, fntype)
|
||||
// If there is a receiver, it also leaks to heap.
|
||||
if n.Op != OCALLFUNC {
|
||||
t := getthisx(fntype).Type
|
||||
src := n.Left.Left
|
||||
if haspointers(t.Type) {
|
||||
escassign(e, &e.theSink, src)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if fn != nil && fn.Op == ONAME && fn.Class == PFUNC &&
|
||||
fn.Defn != nil && fn.Defn.Nbody != nil && fn.Ntype != nil && fn.Defn.Esc < EscFuncTagged {
|
||||
fn.Defn != nil && fn.Defn.Nbody != nil && fn.Param.Ntype != nil && fn.Defn.Esc < EscFuncTagged {
|
||||
if Debug['m'] > 2 {
|
||||
fmt.Printf("%v::esccall:: %v in recursive group\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort))
|
||||
}
|
||||
|
|
@ -1320,17 +1375,17 @@ func esccall(e *EscState, n *Node, up *Node) {
|
|||
}
|
||||
|
||||
// set up out list on this call node
|
||||
for lr := fn.Ntype.Rlist; lr != nil; lr = lr.Next {
|
||||
for lr := fn.Param.Ntype.Rlist; lr != nil; lr = lr.Next {
|
||||
n.Escretval = list(n.Escretval, lr.N.Left) // type.rlist -> dclfield -> ONAME (PPARAMOUT)
|
||||
}
|
||||
|
||||
// Receiver.
|
||||
if n.Op != OCALLFUNC {
|
||||
escassign(e, fn.Ntype.Left.Left, n.Left.Left)
|
||||
escassign(e, fn.Param.Ntype.Left.Left, n.Left.Left)
|
||||
}
|
||||
|
||||
var src *Node
|
||||
for lr := fn.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
|
||||
for lr := fn.Param.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
|
||||
src = ll.N
|
||||
if lr.N.Isddd && !n.Isddd {
|
||||
// Introduce ODDDARG node to represent ... allocation.
|
||||
|
|
@ -1376,23 +1431,7 @@ func esccall(e *EscState, n *Node, up *Node) {
|
|||
}
|
||||
|
||||
// set up out list on this call node with dummy auto ONAMES in the current (calling) function.
|
||||
i := 0
|
||||
|
||||
var src *Node
|
||||
var buf string
|
||||
for t := getoutargx(fntype).Type; t != nil; t = t.Down {
|
||||
src = Nod(ONAME, nil, nil)
|
||||
buf = fmt.Sprintf(".out%d", i)
|
||||
i++
|
||||
src.Sym = Lookup(buf)
|
||||
src.Type = t.Type
|
||||
src.Class = PAUTO
|
||||
src.Curfn = Curfn
|
||||
src.Escloopdepth = e.loopdepth
|
||||
src.Used = true
|
||||
src.Lineno = n.Lineno
|
||||
n.Escretval = list(n.Escretval, src)
|
||||
}
|
||||
initEscretval(e, n, fntype)
|
||||
|
||||
// print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
|
||||
|
||||
|
|
@ -1405,9 +1444,8 @@ func esccall(e *EscState, n *Node, up *Node) {
|
|||
}
|
||||
}
|
||||
|
||||
var a *Node
|
||||
for t := getinargx(fntype).Type; ll != nil; ll = ll.Next {
|
||||
src = ll.N
|
||||
src := ll.N
|
||||
if t.Isddd && !n.Isddd {
|
||||
// Introduce ODDDARG node to represent ... allocation.
|
||||
src = Nod(ODDDARG, nil, nil)
|
||||
|
|
@ -1425,7 +1463,7 @@ func esccall(e *EscState, n *Node, up *Node) {
|
|||
|
||||
if haspointers(t.Type) {
|
||||
if escassignfromtag(e, t.Note, n.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC {
|
||||
a = src
|
||||
a := src
|
||||
for a.Op == OCONVNOP {
|
||||
a = a.Left
|
||||
}
|
||||
|
|
@ -1510,13 +1548,7 @@ func escflood(e *EscState, dst *Node) {
|
|||
}
|
||||
|
||||
if Debug['m'] > 1 {
|
||||
var tmp *Sym
|
||||
if dst.Curfn != nil && dst.Curfn.Nname != nil {
|
||||
tmp = dst.Curfn.Nname.Sym
|
||||
} else {
|
||||
tmp = nil
|
||||
}
|
||||
fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", walkgen, Nconv(dst, obj.FmtShort), tmp, dst.Escloopdepth)
|
||||
fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", walkgen, Nconv(dst, obj.FmtShort), curfnSym(dst), dst.Escloopdepth)
|
||||
}
|
||||
|
||||
for l := dst.Escflowsrc; l != nil; l = l.Next {
|
||||
|
|
@ -1548,14 +1580,8 @@ func escwalk(e *EscState, level Level, dst *Node, src *Node) {
|
|||
src.Esclevel = level
|
||||
|
||||
if Debug['m'] > 1 {
|
||||
var tmp *Sym
|
||||
if src.Curfn != nil && src.Curfn.Nname != nil {
|
||||
tmp = src.Curfn.Nname.Sym
|
||||
} else {
|
||||
tmp = nil
|
||||
}
|
||||
fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d]\n",
|
||||
level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), tmp, src.Escloopdepth)
|
||||
level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), curfnSym(src), src.Escloopdepth)
|
||||
}
|
||||
|
||||
e.pdepth++
|
||||
|
|
@ -1627,7 +1653,7 @@ func escwalk(e *EscState, level Level, dst *Node, src *Node) {
|
|||
if leaks && Debug['m'] != 0 {
|
||||
Warnl(int(src.Lineno), "leaking closure reference %v", Nconv(src, obj.FmtShort))
|
||||
}
|
||||
escwalk(e, level, dst, src.Closure)
|
||||
escwalk(e, level, dst, src.Param.Closure)
|
||||
}
|
||||
|
||||
case OPTRLIT, OADDR:
|
||||
|
|
@ -1657,6 +1683,10 @@ func escwalk(e *EscState, level Level, dst *Node, src *Node) {
|
|||
if Isfixedarray(src.Type) {
|
||||
break
|
||||
}
|
||||
for ll := src.List; ll != nil; ll = ll.Next {
|
||||
escwalk(e, level.dec(), dst, ll.N.Right)
|
||||
}
|
||||
|
||||
fallthrough
|
||||
|
||||
case ODDDARG,
|
||||
|
|
@ -64,7 +64,7 @@ func autoexport(n *Node, ctxt uint8) {
|
|||
if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
|
||||
return
|
||||
}
|
||||
if n.Ntype != nil && n.Ntype.Op == OTFUNC && n.Ntype.Left != nil { // method
|
||||
if n.Param != nil && n.Param.Ntype != nil && n.Param.Ntype.Op == OTFUNC && n.Param.Ntype.Left != nil { // method
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -302,12 +302,12 @@ func Vconv(v *Val, flag int) string {
|
|||
switch v.Ctype {
|
||||
case CTINT:
|
||||
if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
|
||||
return Bconv(v.U.Xval, obj.FmtSharp)
|
||||
return Bconv(v.U.(*Mpint), obj.FmtSharp)
|
||||
}
|
||||
return Bconv(v.U.Xval, 0)
|
||||
return Bconv(v.U.(*Mpint), 0)
|
||||
|
||||
case CTRUNE:
|
||||
x := Mpgetfix(v.U.Xval)
|
||||
x := Mpgetfix(v.U.(*Mpint))
|
||||
if ' ' <= x && x < 0x80 && x != '\\' && x != '\'' {
|
||||
return fmt.Sprintf("'%c'", int(x))
|
||||
}
|
||||
|
|
@ -317,34 +317,34 @@ func Vconv(v *Val, flag int) string {
|
|||
if 0 <= x && x <= utf8.MaxRune {
|
||||
return fmt.Sprintf("'\\U%08x'", uint64(x))
|
||||
}
|
||||
return fmt.Sprintf("('\\x00' + %v)", v.U.Xval)
|
||||
return fmt.Sprintf("('\\x00' + %v)", v.U.(*Mpint))
|
||||
|
||||
case CTFLT:
|
||||
if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
|
||||
return Fconv(v.U.Fval, 0)
|
||||
return Fconv(v.U.(*Mpflt), 0)
|
||||
}
|
||||
return Fconv(v.U.Fval, obj.FmtSharp)
|
||||
return Fconv(v.U.(*Mpflt), obj.FmtSharp)
|
||||
|
||||
case CTCPLX:
|
||||
if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
|
||||
return fmt.Sprintf("(%v+%vi)", &v.U.Cval.Real, &v.U.Cval.Imag)
|
||||
return fmt.Sprintf("(%v+%vi)", &v.U.(*Mpcplx).Real, &v.U.(*Mpcplx).Imag)
|
||||
}
|
||||
if mpcmpfltc(&v.U.Cval.Real, 0) == 0 {
|
||||
return fmt.Sprintf("%vi", Fconv(&v.U.Cval.Imag, obj.FmtSharp))
|
||||
if mpcmpfltc(&v.U.(*Mpcplx).Real, 0) == 0 {
|
||||
return fmt.Sprintf("%vi", Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
|
||||
}
|
||||
if mpcmpfltc(&v.U.Cval.Imag, 0) == 0 {
|
||||
return Fconv(&v.U.Cval.Real, obj.FmtSharp)
|
||||
if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) == 0 {
|
||||
return Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp)
|
||||
}
|
||||
if mpcmpfltc(&v.U.Cval.Imag, 0) < 0 {
|
||||
return fmt.Sprintf("(%v%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp))
|
||||
if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) < 0 {
|
||||
return fmt.Sprintf("(%v%vi)", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
|
||||
}
|
||||
return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.Cval.Real, obj.FmtSharp), Fconv(&v.U.Cval.Imag, obj.FmtSharp))
|
||||
return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
|
||||
|
||||
case CTSTR:
|
||||
return strconv.Quote(v.U.Sval)
|
||||
return strconv.Quote(v.U.(string))
|
||||
|
||||
case CTBOOL:
|
||||
if v.U.Bval {
|
||||
if v.U.(bool) {
|
||||
return "true"
|
||||
}
|
||||
return "false"
|
||||
|
|
@ -1127,7 +1127,7 @@ func exprfmt(n *Node, prec int) string {
|
|||
// Special case: name used as local variable in export.
|
||||
// _ becomes ~b%d internally; print as _ for export
|
||||
case ONAME:
|
||||
if fmtmode == FExp && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
|
||||
if (fmtmode == FExp || fmtmode == FErr) && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
|
||||
return "_"
|
||||
}
|
||||
if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Vargen > 0 {
|
||||
|
|
@ -1199,7 +1199,7 @@ func exprfmt(n *Node, prec int) string {
|
|||
if n.Nbody != nil {
|
||||
return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
|
||||
}
|
||||
return fmt.Sprintf("%v { %v }", n.Type, n.Closure.Nbody)
|
||||
return fmt.Sprintf("%v { %v }", n.Type, n.Param.Closure.Nbody)
|
||||
|
||||
case OCOMPLIT:
|
||||
ptrlit := n.Right != nil && n.Right.Implicit && n.Right.Type != nil && Isptr[n.Right.Type.Etype]
|
||||
|
|
@ -1521,9 +1521,9 @@ func nodedump(n *Node, flag int) string {
|
|||
} else {
|
||||
fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
|
||||
}
|
||||
if recur && n.Type == nil && n.Ntype != nil {
|
||||
if recur && n.Type == nil && n.Param.Ntype != nil {
|
||||
indent(&buf)
|
||||
fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Ntype)
|
||||
fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Param.Ntype)
|
||||
}
|
||||
|
||||
case OASOP:
|
||||
|
|
@ -1531,9 +1531,9 @@ func nodedump(n *Node, flag int) string {
|
|||
|
||||
case OTYPE:
|
||||
fmt.Fprintf(&buf, "%v %v%v type=%v", Oconv(int(n.Op), 0), n.Sym, Jconv(n, 0), n.Type)
|
||||
if recur && n.Type == nil && n.Ntype != nil {
|
||||
if recur && n.Type == nil && n.Param.Ntype != nil {
|
||||
indent(&buf)
|
||||
fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Ntype)
|
||||
fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Param.Ntype)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -57,14 +57,14 @@ func addrescapes(n *Node) {
|
|||
|
||||
// expression to refer to stack copy
|
||||
case PPARAM, PPARAMOUT:
|
||||
n.Stackparam = Nod(OPARAM, n, nil)
|
||||
n.Param.Stackparam = Nod(OPARAM, n, nil)
|
||||
|
||||
n.Stackparam.Type = n.Type
|
||||
n.Stackparam.Addable = true
|
||||
n.Param.Stackparam.Type = n.Type
|
||||
n.Param.Stackparam.Addable = true
|
||||
if n.Xoffset == BADWIDTH {
|
||||
Fatal("addrescapes before param assignment")
|
||||
}
|
||||
n.Stackparam.Xoffset = n.Xoffset
|
||||
n.Param.Stackparam.Xoffset = n.Xoffset
|
||||
fallthrough
|
||||
|
||||
case PAUTO:
|
||||
|
|
@ -78,10 +78,10 @@ func addrescapes(n *Node) {
|
|||
oldfn := Curfn
|
||||
|
||||
Curfn = n.Curfn
|
||||
n.Heapaddr = temp(Ptrto(n.Type))
|
||||
n.Name.Heapaddr = temp(Ptrto(n.Type))
|
||||
buf := fmt.Sprintf("&%v", n.Sym)
|
||||
n.Heapaddr.Sym = Lookup(buf)
|
||||
n.Heapaddr.Orig.Sym = n.Heapaddr.Sym
|
||||
n.Name.Heapaddr.Sym = Lookup(buf)
|
||||
n.Name.Heapaddr.Orig.Sym = n.Name.Heapaddr.Sym
|
||||
n.Esc = EscHeap
|
||||
if Debug['m'] != 0 {
|
||||
fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
|
||||
|
|
@ -262,7 +262,7 @@ func cgen_dcl(n *Node) {
|
|||
if n.Alloc == nil {
|
||||
n.Alloc = callnew(n.Type)
|
||||
}
|
||||
Cgen_as(n.Heapaddr, n.Alloc)
|
||||
Cgen_as(n.Name.Heapaddr, n.Alloc)
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -333,21 +333,22 @@ func Clearslim(n *Node) {
|
|||
|
||||
switch Simtype[n.Type.Etype] {
|
||||
case TCOMPLEX64, TCOMPLEX128:
|
||||
z.Val.U.Cval = new(Mpcplx)
|
||||
Mpmovecflt(&z.Val.U.Cval.Real, 0.0)
|
||||
Mpmovecflt(&z.Val.U.Cval.Imag, 0.0)
|
||||
z.Val.U = new(Mpcplx)
|
||||
Mpmovecflt(&z.Val.U.(*Mpcplx).Real, 0.0)
|
||||
Mpmovecflt(&z.Val.U.(*Mpcplx).Imag, 0.0)
|
||||
|
||||
case TFLOAT32, TFLOAT64:
|
||||
var zero Mpflt
|
||||
Mpmovecflt(&zero, 0.0)
|
||||
z.Val.Ctype = CTFLT
|
||||
z.Val.U.Fval = &zero
|
||||
z.Val.U = &zero
|
||||
|
||||
case TPTR32, TPTR64, TCHAN, TMAP:
|
||||
z.Val.Ctype = CTNIL
|
||||
|
||||
case TBOOL:
|
||||
z.Val.Ctype = CTBOOL
|
||||
z.Val.U = false
|
||||
|
||||
case TINT8,
|
||||
TINT16,
|
||||
|
|
@ -358,8 +359,8 @@ func Clearslim(n *Node) {
|
|||
TUINT32,
|
||||
TUINT64:
|
||||
z.Val.Ctype = CTINT
|
||||
z.Val.U.Xval = new(Mpint)
|
||||
Mpmovecfix(z.Val.U.Xval, 0)
|
||||
z.Val.U = new(Mpint)
|
||||
Mpmovecfix(z.Val.U.(*Mpint), 0)
|
||||
|
||||
default:
|
||||
Fatal("clearslim called on type %v", n.Type)
|
||||
|
|
@ -428,8 +429,7 @@ func cgen_dottype(n *Node, res, resok *Node, wb bool) {
|
|||
Cgen(&iface, &r1)
|
||||
if !isnilinter(n.Left.Type) {
|
||||
// Holding itab, want concrete type in second word.
|
||||
Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, Nodintconst(0))
|
||||
p := Gbranch(Thearch.Optoas(OEQ, byteptr), nil, -1)
|
||||
p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1)
|
||||
r2 = r1
|
||||
r2.Op = OINDREG
|
||||
r2.Xoffset = int64(Widthptr)
|
||||
|
|
@ -438,8 +438,7 @@ func cgen_dottype(n *Node, res, resok *Node, wb bool) {
|
|||
}
|
||||
Regalloc(&r2, byteptr, nil)
|
||||
Cgen(typename(n.Type), &r2)
|
||||
Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, &r2)
|
||||
p := Gbranch(Thearch.Optoas(ONE, byteptr), nil, -1)
|
||||
p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1)
|
||||
Regfree(&r2) // not needed for success path; reclaimed on one failure path
|
||||
iface.Xoffset += int64(Widthptr)
|
||||
Cgen(&iface, &r1)
|
||||
|
|
@ -521,8 +520,7 @@ func Cgen_As2dottype(n, res, resok *Node) {
|
|||
Cgen(&iface, &r1)
|
||||
if !isnilinter(n.Left.Type) {
|
||||
// Holding itab, want concrete type in second word.
|
||||
Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, Nodintconst(0))
|
||||
p := Gbranch(Thearch.Optoas(OEQ, byteptr), nil, -1)
|
||||
p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -1)
|
||||
r2 = r1
|
||||
r2.Op = OINDREG
|
||||
r2.Xoffset = int64(Widthptr)
|
||||
|
|
@ -531,8 +529,7 @@ func Cgen_As2dottype(n, res, resok *Node) {
|
|||
}
|
||||
Regalloc(&r2, byteptr, nil)
|
||||
Cgen(typename(n.Type), &r2)
|
||||
Thearch.Gins(Thearch.Optoas(OCMP, byteptr), &r1, &r2)
|
||||
p := Gbranch(Thearch.Optoas(ONE, byteptr), nil, -1)
|
||||
p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1)
|
||||
iface.Type = n.Type
|
||||
iface.Xoffset += int64(Widthptr)
|
||||
Cgen(&iface, &r1)
|
||||
|
|
@ -555,122 +552,6 @@ func Cgen_As2dottype(n, res, resok *Node) {
|
|||
Patch(q, Pc)
|
||||
}
|
||||
|
||||
/*
|
||||
* generate:
|
||||
* res = s[lo, hi];
|
||||
* n->left is s
|
||||
* n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)])
|
||||
* caller (cgen) guarantees res is an addable ONAME.
|
||||
*
|
||||
* called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR.
|
||||
*/
|
||||
func Cgen_slice(n *Node, res *Node) {
|
||||
cap := n.List.N
|
||||
len := n.List.Next.N
|
||||
var offs *Node
|
||||
if n.List.Next.Next != nil {
|
||||
offs = n.List.Next.Next.N
|
||||
}
|
||||
|
||||
// evaluate base pointer first, because it is the only
|
||||
// possibly complex expression. once that is evaluated
|
||||
// and stored, updating the len and cap can be done
|
||||
// without making any calls, so without doing anything that
|
||||
// might cause preemption or garbage collection.
|
||||
// this makes the whole slice update atomic as far as the
|
||||
// garbage collector can see.
|
||||
base := temp(Types[TUINTPTR])
|
||||
|
||||
tmplen := temp(Types[TINT])
|
||||
var tmpcap *Node
|
||||
if n.Op != OSLICESTR {
|
||||
tmpcap = temp(Types[TINT])
|
||||
} else {
|
||||
tmpcap = tmplen
|
||||
}
|
||||
|
||||
var src Node
|
||||
if isnil(n.Left) {
|
||||
Tempname(&src, n.Left.Type)
|
||||
Cgen(n.Left, &src)
|
||||
} else {
|
||||
src = *n.Left
|
||||
}
|
||||
if n.Op == OSLICE || n.Op == OSLICE3 || n.Op == OSLICESTR {
|
||||
src.Xoffset += int64(Array_array)
|
||||
}
|
||||
|
||||
if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
|
||||
if !Isptr[n.Left.Type.Etype] {
|
||||
Fatal("slicearr is supposed to work on pointer: %v\n", Nconv(n, obj.FmtSign))
|
||||
}
|
||||
Cgen(&src, base)
|
||||
Cgen_checknil(base)
|
||||
} else {
|
||||
src.Type = Types[Tptr]
|
||||
Cgen(&src, base)
|
||||
}
|
||||
|
||||
// committed to the update
|
||||
Gvardef(res)
|
||||
|
||||
// compute len and cap.
|
||||
// len = n-i, cap = m-i, and offs = i*width.
|
||||
// computing offs last lets the multiply overwrite i.
|
||||
Cgen((*Node)(len), tmplen)
|
||||
|
||||
if n.Op != OSLICESTR {
|
||||
Cgen(cap, tmpcap)
|
||||
}
|
||||
|
||||
// if new cap != 0 { base += add }
|
||||
// This avoids advancing base past the end of the underlying array/string,
|
||||
// so that it cannot point at the next object in memory.
|
||||
// If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero.
|
||||
// In essence we are replacing x[i:j:k] where i == j == k
|
||||
// or x[i:j] where i == j == cap(x) with x[0:0:0].
|
||||
if offs != nil {
|
||||
p1 := gjmp(nil)
|
||||
p2 := gjmp(nil)
|
||||
Patch(p1, Pc)
|
||||
|
||||
var con Node
|
||||
Nodconst(&con, tmpcap.Type, 0)
|
||||
cmp := Nod(OEQ, tmpcap, &con)
|
||||
typecheck(&cmp, Erv)
|
||||
Bgen(cmp, true, -1, p2)
|
||||
|
||||
add := Nod(OADD, base, offs)
|
||||
typecheck(&add, Erv)
|
||||
Cgen(add, base)
|
||||
|
||||
Patch(p2, Pc)
|
||||
}
|
||||
|
||||
// dst.array = src.array [ + lo *width ]
|
||||
dst := *res
|
||||
|
||||
dst.Xoffset += int64(Array_array)
|
||||
dst.Type = Types[Tptr]
|
||||
Cgen(base, &dst)
|
||||
|
||||
// dst.len = hi [ - lo ]
|
||||
dst = *res
|
||||
|
||||
dst.Xoffset += int64(Array_nel)
|
||||
dst.Type = Types[Simtype[TUINT]]
|
||||
Cgen(tmplen, &dst)
|
||||
|
||||
if n.Op != OSLICESTR {
|
||||
// dst.cap = cap [ - lo ]
|
||||
dst = *res
|
||||
|
||||
dst.Xoffset += int64(Array_cap)
|
||||
dst.Type = Types[Simtype[TUINT]]
|
||||
Cgen(tmpcap, &dst)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* gather series of offsets
|
||||
* >=0 is direct addressed field
|
||||
|
|
@ -1085,7 +966,7 @@ func cgen_callmeth(n *Node, proc int) {
|
|||
l := n.Left
|
||||
|
||||
if l.Op != ODOTMETH {
|
||||
Fatal("cgen_callmeth: not dotmethod: %v")
|
||||
Fatal("cgen_callmeth: not dotmethod: %v", l)
|
||||
}
|
||||
|
||||
n2 := *n
|
||||
|
|
@ -1241,7 +1122,7 @@ func componentgen_wb(nr, nl *Node, wb bool) bool {
|
|||
nodl.Type = Ptrto(Types[TUINT8])
|
||||
Regalloc(&nodr, Types[Tptr], nil)
|
||||
p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr)
|
||||
Datastring(nr.Val.U.Sval, &p.From)
|
||||
Datastring(nr.Val.U.(string), &p.From)
|
||||
p.From.Type = obj.TYPE_ADDR
|
||||
Thearch.Gmove(&nodr, &nodl)
|
||||
Regfree(&nodr)
|
||||
|
|
@ -1249,7 +1130,7 @@ func componentgen_wb(nr, nl *Node, wb bool) bool {
|
|||
// length
|
||||
nodl.Type = Types[Simtype[TUINT]]
|
||||
nodl.Xoffset += int64(Array_nel) - int64(Array_array)
|
||||
Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.Sval)))
|
||||
Nodconst(&nodr, nodl.Type, int64(len(nr.Val.U.(string))))
|
||||
Thearch.Gmove(&nodr, &nodl)
|
||||
return true
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ package gc
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"cmd/internal/gc/big"
|
||||
"cmd/compile/internal/big"
|
||||
"cmd/internal/obj"
|
||||
)
|
||||
|
||||
|
|
@ -83,13 +83,13 @@ type Mpcplx struct {
|
|||
|
||||
type Val struct {
|
||||
Ctype int16
|
||||
U struct {
|
||||
Bval bool // bool value CTBOOL
|
||||
Xval *Mpint // int CTINT, rune CTRUNE
|
||||
Fval *Mpflt // float CTFLT
|
||||
Cval *Mpcplx // float CTCPLX
|
||||
Sval string // string CTSTR
|
||||
}
|
||||
// U contains one of:
|
||||
// bool bool when Ctype == CTBOOL
|
||||
// *Mpint int when Ctype == CTINT, rune when Ctype == CTRUNE
|
||||
// *Mpflt float when Ctype == CTFLT
|
||||
// *Mpcplx pair of floats when Ctype == CTCPLX
|
||||
// string string when Ctype == CTSTR
|
||||
U interface{}
|
||||
}
|
||||
|
||||
type Pkg struct {
|
||||
|
|
@ -448,7 +448,7 @@ var nsavederrors int
|
|||
|
||||
var nsyntaxerrors int
|
||||
|
||||
var decldepth int
|
||||
var decldepth int32
|
||||
|
||||
var safemode int
|
||||
|
||||
|
|
@ -778,13 +778,27 @@ type Arch struct {
|
|||
Expandchecks func(*obj.Prog)
|
||||
Getg func(*Node)
|
||||
Gins func(int, *Node, *Node) *obj.Prog
|
||||
|
||||
// Ginscmp generates code comparing n1 to n2 and jumping away if op is satisfied.
|
||||
// The returned prog should be Patch'ed with the jump target.
|
||||
// If op is not satisfied, code falls through to the next emitted instruction.
|
||||
// Likely is the branch prediction hint: +1 for likely, -1 for unlikely, 0 for no opinion.
|
||||
//
|
||||
// Ginscmp must be able to handle all kinds of arguments for n1 and n2,
|
||||
// not just simple registers, although it can assume that there are no
|
||||
// function calls needed during the evaluation, and on 32-bit systems
|
||||
// the values are guaranteed not to be 64-bit values, so no in-memory
|
||||
// temporaries are necessary.
|
||||
Ginscmp func(op int, t *Type, n1, n2 *Node, likely int) *obj.Prog
|
||||
|
||||
// Ginsboolval inserts instructions to convert the result
|
||||
// of a just-completed comparison to a boolean value.
|
||||
// The first argument is the conditional jump instruction
|
||||
// corresponding to the desired value.
|
||||
// The second argument is the destination.
|
||||
// If not present, Ginsboolval will be emulated with jumps.
|
||||
Ginsboolval func(int, *Node)
|
||||
Ginsboolval func(int, *Node)
|
||||
|
||||
Ginscon func(int, int64, *Node)
|
||||
Ginsnop func()
|
||||
Gmove func(*Node, *Node)
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
package gc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
%}
|
||||
|
|
@ -116,7 +117,68 @@ import (
|
|||
%left ')'
|
||||
%left PreferToRightParen
|
||||
|
||||
// TODO(rsc): Add %error-verbose
|
||||
%error loadsys package LIMPORT '(' LLITERAL import_package import_there ',':
|
||||
"unexpected comma during import block"
|
||||
|
||||
%error loadsys package LIMPORT LNAME ';':
|
||||
"missing import path; require quoted string"
|
||||
|
||||
%error loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';':
|
||||
"missing { after if clause"
|
||||
|
||||
%error loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';':
|
||||
"missing { after switch clause"
|
||||
|
||||
%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';':
|
||||
"missing { after for clause"
|
||||
|
||||
%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY:
|
||||
"missing { after for clause"
|
||||
|
||||
%error loadsys package imports LFUNC LNAME '(' ')' ';' '{':
|
||||
"unexpected semicolon or newline before {"
|
||||
|
||||
%error loadsys package imports LTYPE LNAME ';':
|
||||
"unexpected semicolon or newline in type declaration"
|
||||
|
||||
%error loadsys package imports LCHAN '}':
|
||||
"unexpected } in channel type"
|
||||
|
||||
%error loadsys package imports LCHAN ')':
|
||||
"unexpected ) in channel type"
|
||||
|
||||
%error loadsys package imports LCHAN ',':
|
||||
"unexpected comma in channel type"
|
||||
|
||||
%error loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE:
|
||||
"unexpected semicolon or newline before else"
|
||||
|
||||
%error loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME:
|
||||
"name list not allowed in interface type"
|
||||
|
||||
%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME:
|
||||
"var declaration not allowed in for initializer"
|
||||
|
||||
%error loadsys package imports LVAR LNAME '[' ']' LNAME '{':
|
||||
"unexpected { at end of statement"
|
||||
|
||||
%error loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{':
|
||||
"unexpected { at end of statement"
|
||||
|
||||
%error loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';':
|
||||
"argument to go/defer must be function call"
|
||||
|
||||
%error loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';':
|
||||
"need trailing comma before newline in composite literal"
|
||||
|
||||
%error loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';':
|
||||
"need trailing comma before newline in composite literal"
|
||||
|
||||
%error loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME:
|
||||
"nested func not allowed"
|
||||
|
||||
%error loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';':
|
||||
"else must be followed by if or statement block"
|
||||
|
||||
%%
|
||||
file:
|
||||
|
|
@ -1130,13 +1192,13 @@ hidden_importsym:
|
|||
{
|
||||
var p *Pkg
|
||||
|
||||
if $2.U.Sval == "" {
|
||||
if $2.U.(string) == "" {
|
||||
p = importpkg;
|
||||
} else {
|
||||
if isbadimport($2.U.Sval) {
|
||||
if isbadimport($2.U.(string)) {
|
||||
errorexit();
|
||||
}
|
||||
p = mkpkg($2.U.Sval);
|
||||
p = mkpkg($2.U.(string));
|
||||
}
|
||||
$$ = Pkglookup($4.Name, p);
|
||||
}
|
||||
|
|
@ -1144,13 +1206,13 @@ hidden_importsym:
|
|||
{
|
||||
var p *Pkg
|
||||
|
||||
if $2.U.Sval == "" {
|
||||
if $2.U.(string) == "" {
|
||||
p = importpkg;
|
||||
} else {
|
||||
if isbadimport($2.U.Sval) {
|
||||
if isbadimport($2.U.(string)) {
|
||||
errorexit();
|
||||
}
|
||||
p = mkpkg($2.U.Sval);
|
||||
p = mkpkg($2.U.(string));
|
||||
}
|
||||
$$ = Pkglookup("?", p);
|
||||
}
|
||||
|
|
@ -1360,7 +1422,7 @@ fndcl:
|
|||
$$ = Nod(ODCLFUNC, nil, nil);
|
||||
$$.Nname = newfuncname($1);
|
||||
$$.Nname.Defn = $$;
|
||||
$$.Nname.Ntype = t; // TODO: check if nname already has an ntype
|
||||
$$.Nname.Param.Ntype = t; // TODO: check if nname already has an ntype
|
||||
declare($$.Nname, PFUNC);
|
||||
|
||||
funchdr($$);
|
||||
|
|
@ -1395,7 +1457,7 @@ fndcl:
|
|||
$$.Func.Shortname = newfuncname($4);
|
||||
$$.Nname = methodname1($$.Func.Shortname, rcvr.Right);
|
||||
$$.Nname.Defn = $$;
|
||||
$$.Nname.Ntype = t;
|
||||
$$.Nname.Param.Ntype = t;
|
||||
$$.Nname.Nointerface = nointerface;
|
||||
declare($$.Nname, PFUNC);
|
||||
|
||||
|
|
@ -1944,7 +2006,7 @@ oliteral:
|
|||
hidden_import:
|
||||
LIMPORT LNAME LLITERAL ';'
|
||||
{
|
||||
importimport($2, $3.U.Sval);
|
||||
importimport($2, $3.U.(string));
|
||||
}
|
||||
| LVAR hidden_pkg_importsym hidden_type ';'
|
||||
{
|
||||
|
|
@ -1975,9 +2037,9 @@ hidden_import:
|
|||
importlist = list(importlist, $2);
|
||||
|
||||
if Debug['E'] > 0 {
|
||||
print("import [%q] func %lN \n", importpkg.Path, $2);
|
||||
fmt.Printf("import [%q] func %v \n", importpkg.Path, $2)
|
||||
if Debug['m'] > 2 && $2.Func.Inl != nil {
|
||||
print("inl body:%+H\n", $2.Func.Inl);
|
||||
fmt.Printf("inl body:%v\n", $2.Func.Inl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2171,14 +2233,14 @@ hidden_literal:
|
|||
$$ = nodlit($2);
|
||||
switch($$.Val.Ctype){
|
||||
case CTINT, CTRUNE:
|
||||
mpnegfix($$.Val.U.Xval);
|
||||
mpnegfix($$.Val.U.(*Mpint));
|
||||
break;
|
||||
case CTFLT:
|
||||
mpnegflt($$.Val.U.Fval);
|
||||
mpnegflt($$.Val.U.(*Mpflt));
|
||||
break;
|
||||
case CTCPLX:
|
||||
mpnegflt(&$$.Val.U.Cval.Real);
|
||||
mpnegflt(&$$.Val.U.Cval.Imag);
|
||||
mpnegflt(&$$.Val.U.(*Mpcplx).Real);
|
||||
mpnegflt(&$$.Val.U.(*Mpcplx).Imag);
|
||||
break;
|
||||
default:
|
||||
Yyerror("bad negated constant");
|
||||
|
|
@ -2198,11 +2260,11 @@ hidden_constant:
|
|||
{
|
||||
if $2.Val.Ctype == CTRUNE && $4.Val.Ctype == CTINT {
|
||||
$$ = $2;
|
||||
mpaddfixfix($2.Val.U.Xval, $4.Val.U.Xval, 0);
|
||||
mpaddfixfix($2.Val.U.(*Mpint), $4.Val.U.(*Mpint), 0);
|
||||
break;
|
||||
}
|
||||
$4.Val.U.Cval.Real = $4.Val.U.Cval.Imag;
|
||||
Mpmovecflt(&$4.Val.U.Cval.Imag, 0.0);
|
||||
$4.Val.U.(*Mpcplx).Real = $4.Val.U.(*Mpcplx).Imag;
|
||||
Mpmovecflt(&$4.Val.U.(*Mpcplx).Imag, 0.0);
|
||||
$$ = nodcplxlit($2.Val, $4.Val);
|
||||
}
|
||||
|
||||
|
|
@ -90,6 +90,10 @@ func Gbranch(as int, t *Type, likely int) *obj.Prog {
|
|||
p.From.Offset = int64(obj.Bool2int(likely > 0))
|
||||
}
|
||||
|
||||
if Debug['g'] != 0 {
|
||||
fmt.Printf("%v\n", p)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
|
|
@ -210,7 +214,7 @@ func ggloblnod(nam *Node) {
|
|||
p.To.Sym = nil
|
||||
p.To.Type = obj.TYPE_CONST
|
||||
p.To.Offset = nam.Type.Width
|
||||
if nam.Readonly {
|
||||
if nam.Name.Readonly {
|
||||
p.From3.Offset = obj.RODATA
|
||||
}
|
||||
if nam.Type != nil && !haspointers(nam.Type) {
|
||||
|
|
@ -365,7 +369,7 @@ func Naddr(a *obj.Addr, n *Node) {
|
|||
if s == nil {
|
||||
s = Lookup(".noname")
|
||||
}
|
||||
if n.Method {
|
||||
if n.Name.Method {
|
||||
if n.Type != nil {
|
||||
if n.Type.Sym != nil {
|
||||
if n.Type.Sym.Pkg != nil {
|
||||
|
|
@ -408,20 +412,20 @@ func Naddr(a *obj.Addr, n *Node) {
|
|||
|
||||
case CTFLT:
|
||||
a.Type = obj.TYPE_FCONST
|
||||
a.Val = mpgetflt(n.Val.U.Fval)
|
||||
a.Val = mpgetflt(n.Val.U.(*Mpflt))
|
||||
|
||||
case CTINT, CTRUNE:
|
||||
a.Sym = nil
|
||||
a.Type = obj.TYPE_CONST
|
||||
a.Offset = Mpgetfix(n.Val.U.Xval)
|
||||
a.Offset = Mpgetfix(n.Val.U.(*Mpint))
|
||||
|
||||
case CTSTR:
|
||||
datagostring(n.Val.U.Sval, a)
|
||||
datagostring(n.Val.U.(string), a)
|
||||
|
||||
case CTBOOL:
|
||||
a.Sym = nil
|
||||
a.Type = obj.TYPE_CONST
|
||||
a.Offset = int64(obj.Bool2int(n.Val.U.Bval))
|
||||
a.Offset = int64(obj.Bool2int(n.Val.U.(bool)))
|
||||
|
||||
case CTNIL:
|
||||
a.Sym = nil
|
||||
|
|
@ -621,20 +625,20 @@ func gclean() {
|
|||
for r := Thearch.REGMIN; r <= Thearch.REGMAX; r++ {
|
||||
n := reg[r-Thearch.REGMIN]
|
||||
if n != 0 {
|
||||
Yyerror("reg %v left allocated", obj.Rconv(r))
|
||||
if Debug['v'] != 0 {
|
||||
Regdump()
|
||||
}
|
||||
Yyerror("reg %v left allocated", obj.Rconv(r))
|
||||
}
|
||||
}
|
||||
|
||||
for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
|
||||
n := reg[r-Thearch.REGMIN]
|
||||
if n != 0 {
|
||||
Yyerror("reg %v left allocated", obj.Rconv(r))
|
||||
if Debug['v'] != 0 {
|
||||
Regdump()
|
||||
}
|
||||
Yyerror("reg %v left allocated", obj.Rconv(r))
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue