[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:
Keith Randall 2015-05-28 13:49:20 -07:00
commit 067e8dfd82
618 changed files with 14079 additions and 7877 deletions

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 = "||" | "&amp;&amp;" | rel_op | add_op | mul_op .

39
misc/android/cleaner.go Normal file
View File

@ -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)
}
}

View File

@ -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) }

View File

@ -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);
}

View File

@ -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")
}
}

View File

@ -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}"

View File

@ -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, &note{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")
}

View File

@ -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
}

View File

@ -0,0 +1,11 @@
package dep2
import "dep"
var W int = 1
var hasProg dep.HasProg
func G() int {
return dep.F() + 1
}

View File

@ -0,0 +1,7 @@
package main
import "dep2"
func main() {
dep2.W = dep2.G() + 1
}

View File

@ -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

View File

@ -35,7 +35,7 @@ go src=..
gofmt_test.go
testdata
+
link
newlink
testdata
+
archive

View File

@ -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.

View File

@ -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

View File

@ -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]

View File

@ -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)
}

BIN
src/archive/tar/testdata/neg-size.tar vendored Normal file

Binary file not shown.

View File

@ -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

View File

@ -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)
}
}

View File

@ -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

View File

@ -1 +0,0 @@
package main

View File

@ -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]

View File

@ -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)
}
}

View File

@ -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)
}

View 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)
}
}

View File

@ -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)

View File

@ -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

View File

@ -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"
)

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

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

View File

@ -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"
)

View File

@ -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"
)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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
}

View File

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

View File

@ -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"
)

View File

@ -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

View File

@ -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"
)

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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 {

View File

@ -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"
)

View File

@ -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"
)

View File

@ -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 {

View File

@ -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{

View File

@ -5,9 +5,9 @@
package big_test
import (
"cmd/compile/internal/big"
"fmt"
"log"
"math/big"
)
func ExampleRat_SetString() {

View File

@ -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 {

View File

@ -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)
}
}
}

View File

@ -5,9 +5,9 @@
package big_test
import (
"cmd/compile/internal/big"
"fmt"
"math"
"math/big"
)
func ExampleFloat_Add() {

View File

@ -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)

View File

@ -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",

View File

@ -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 NewtonRaphson
// 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.

View File

@ -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

View File

@ -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 .

View File

@ -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

View File

@ -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)))
}

View File

@ -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
}

View File

@ -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

View File

@ -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")

View File

@ -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,

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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)

View File

@ -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);
}

View File

@ -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