Commit b4a78067 authored by Russ Cox's avatar Russ Cox

[dev.cc] all: merge master (5868ce35) into dev.cc

This time for sure!

Change-Id: I7e7ea24edb7c2f711489e162fb97237a87533089
parents d90bbf91 5868ce35
......@@ -10,7 +10,7 @@ visit https://golang.org/ or load doc/install-source.html
in your web browser.
Our canonical Git repository is located at https://go.googlesource.com/go.
(There is a mirror of the repository at https://github.com/golang/go.)
There is a mirror of the repository at https://github.com/golang/go.
Please report issues here: https://golang.org/issue/new
......@@ -43,4 +43,3 @@ put the following in your .profile:
export PATH=$PATH:$GOROOT/bin
See https://golang.org/doc/install or doc/install.html for more details.
......@@ -350,7 +350,11 @@ live pointers in its arguments, results, and local stack frame.
For an assembly function with no pointer results and
either no local stack frame or no function calls,
the only requirement is to define a Go prototype for the function
in a Go source file in the same package.
in a Go source file in the same package. The name of the assembly
function must not contain the package name component (for example,
function <code>Syscall</code> in package <code>syscall</code> should
use the name <code>·Syscall</code> instead of the equivalent name
<code>syscall·Syscall</code> in its <code>TEXT</code> directive).
For more complex situations, explicit annotation is needed.
These annotations use pseudo-instructions defined in the standard
<code>#include</code> file <code>funcdata.h</code>.
......
......@@ -26,6 +26,11 @@ go1.4.1 (released 2015/01/15) includes bug fixes to the linker and the <code>log
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.4.1">Go 1.4.1 milestone on our issue tracker</a> for details.
</p>
<p>
go1.4.2 (released 2015/02/17) includes bug fixes to the <code>go</code> command, the compiler and linker, and the <code>runtime</code>, <code>syscall</code>, <code>reflect</code>, and <code>math/big</code> packages.
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.4.2">Go 1.4.2 milestone on our issue tracker</a> for details.
</p>
<h2 id="go1.3">go1.3 (released 2014/06/18)</h2>
<p>
......
......@@ -14,7 +14,9 @@ crypto/tls: change default minimum version to TLS 1.0. (https://golang.org/cl/17
encoding/base64: add unpadded encodings (https://golang.org/cl/1511)
log: add SetOutput functions (https://golang.org/cl/2686, https://golang.org/cl/3023)
net/http: support for setting trailers from a server Handler (https://golang.org/cl/2157)
net/http/cgi: fix REMOTE_ADDR, REMOTE_HOST, add REMOTE_PORT (https://golang.org/cl/4933)
net/smtp: add TLSConnectionState accessor (https://golang.org/cl/2151)
os/signal: add Ignore and Reset (https://golang.org/cl/3580)
runtime, syscall: use SYSCALL instruction on FreeBSD (Go 1.5 now requires FreeBSD 8-STABLE+) (https://golang.org/cl/3020)
strings: add Compare(x, y string) int, for symmetry with bytes.Compare (https://golang.org/cl/2828)
testing/quick: support generation of arrays (https://golang.org/cl/3865)
......
......@@ -44,9 +44,9 @@ GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \
export ANDROID_PRODUCT_OUT=/tmp/androidtest-$$
FAKE_GOROOT=$ANDROID_PRODUCT_OUT/data/local/tmp/goroot
mkdir -p $FAKE_GOROOT
cp -R --preserve=all "${GOROOT}/src" "${FAKE_GOROOT}/"
cp -R --preserve=all "${GOROOT}/test" "${FAKE_GOROOT}/"
cp -R --preserve=all "${GOROOT}/lib" "${FAKE_GOROOT}/"
cp -a "${GOROOT}/src" "${FAKE_GOROOT}/"
cp -a "${GOROOT}/test" "${FAKE_GOROOT}/"
cp -a "${GOROOT}/lib" "${FAKE_GOROOT}/"
echo '# Syncing test files to android device'
time adb sync data &> /dev/null
echo ''
......
......@@ -297,6 +297,11 @@ func findgoversion() string {
return chomp(readfile(path))
}
// Show a nicer error message if this isn't a Git repo.
if !isGitRepo() {
fatal("FAILED: not a Git repo; must put a VERSION file in $GOROOT")
}
// Otherwise, use Git.
// What is the current branch?
branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD"))
......@@ -322,6 +327,22 @@ func findgoversion() string {
return tag
}
// isGitRepo reports whether the working directory is inside a Git repository.
func isGitRepo() bool {
p := ".git"
for {
fi, err := os.Stat(p)
if os.IsNotExist(err) {
p = filepath.Join("..", p)
continue
}
if err != nil || !fi.IsDir() {
return false
}
return true
}
}
/*
* Initial tree setup.
*/
......
......@@ -414,7 +414,7 @@ func main() {
if gohostarch == "" {
// Default Unix system.
out := run("", CheckExit, "uname", "-m", "-v")
out := run("", CheckExit, "uname", "-m")
switch {
case strings.Contains(out, "x86_64"), strings.Contains(out, "amd64"):
gohostarch = "amd64"
......@@ -427,7 +427,7 @@ func main() {
case strings.Contains(out, "ppc64"):
gohostarch = "ppc64"
case gohostos == "darwin":
if strings.Contains(out, "RELEASE_ARM_") {
if strings.Contains(run("", CheckExit, "uname", "-v"), "RELEASE_ARM_") {
gohostarch = "arm"
}
default:
......
......@@ -19,6 +19,7 @@ closurehdr(Node *ntype)
n = nod(OCLOSURE, N, N);
n->ntype = ntype;
n->funcdepth = funcdepth;
n->outerfunc = curfn;
funchdr(n);
......@@ -124,11 +125,55 @@ typecheckclosure(Node *func, int top)
xtop = list(xtop, makeclosure(func));
}
// closurename returns name for OCLOSURE n.
// It is not as simple as it ought to be, because we typecheck nested closures
// starting from the innermost one. So when we check the inner closure,
// we don't yet have name for the outer closure. This function uses recursion
// to generate names all the way up if necessary.
static Sym*
closurename(Node *n)
{
static int closgen;
char *outer, *prefix;
int gen;
if(n->sym != S)
return n->sym;
gen = 0;
outer = nil;
prefix = nil;
if(n->outerfunc == N) {
// Global closure.
outer = "glob";
prefix = "func";
gen = ++closgen;
} else if(n->outerfunc->op == ODCLFUNC) {
// The outermost closure inside of a named function.
outer = n->outerfunc->nname->sym->name;
prefix = "func";
// Yes, functions can be named _.
// Can't use function closgen in such case,
// because it would lead to name clashes.
if(!isblank(n->outerfunc->nname))
gen = ++n->outerfunc->closgen;
else
gen = ++closgen;
} else if(n->outerfunc->op == OCLOSURE) {
// Nested closure, recurse.
outer = closurename(n->outerfunc)->name;
prefix = "";
gen = ++n->outerfunc->closgen;
} else
fatal("closurename called for %hN", n);
snprint(namebuf, sizeof namebuf, "%s.%s%d", outer, prefix, gen);
n->sym = lookup(namebuf);
return n->sym;
}
static Node*
makeclosure(Node *func)
{
Node *xtype, *xfunc;
static int closgen;
/*
* wrap body in external function
......@@ -140,8 +185,7 @@ makeclosure(Node *func)
// create the function
xfunc = nod(ODCLFUNC, N, N);
snprint(namebuf, sizeof namebuf, "func·%.3d", ++closgen);
xfunc->nname = newname(lookup(namebuf));
xfunc->nname = newname(closurename(func));
xfunc->nname->sym->flags |= SymExported; // disable export
xfunc->nname->ntype = xtype;
xfunc->nname->defn = xfunc;
......@@ -158,7 +202,7 @@ makeclosure(Node *func)
xfunc->closure = func;
func->closure = xfunc;
func->nbody = nil;
func->list = nil;
func->rlist = nil;
......@@ -368,7 +412,7 @@ walkclosure(Node *func, NodeList **init)
// and has one float64 argument and no results,
// the generated code looks like:
//
// clos = &struct{F uintptr; A0 *int; A1 *string}{func·001, &i, &s}
// clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
//
// The use of the struct provides type information to the garbage
// collector so that it can walk the closure. We could use (in this case)
......@@ -378,7 +422,7 @@ walkclosure(Node *func, NodeList **init)
// same struct type can share the descriptor.
typ = nod(OTSTRUCT, N, N);
typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR])));
typ->list = list1(nod(ODCLFIELD, newname(lookup(".F")), typenod(types[TUINTPTR])));
for(l=func->cvars; l; l=l->next) {
v = l->n;
if(v->op == OXXX)
......@@ -447,12 +491,11 @@ makepartialcall(Node *fn, Type *t0, Node *meth)
static Pkg* gopkg;
int i, ddd;
// TODO: names are not right
rcvrtype = fn->left->type;
if(exportname(meth->sym->name))
p = smprint("%-hT.%s·fm", rcvrtype, meth->sym->name);
p = smprint("(%-hT).%s-fm", rcvrtype, meth->sym->name);
else
p = smprint("%-hT.(%-S)·fm", rcvrtype, meth->sym);
p = smprint("(%-hT).(%-S)-fm", rcvrtype, meth->sym);
basetype = rcvrtype;
if(isptr[rcvrtype->etype])
basetype = basetype->type;
......
......@@ -310,6 +310,8 @@ struct Node
NodeList* dcl; // autodcl for this func/closure
NodeList* inl; // copy of the body for use in inlining
NodeList* inldcl; // copy of dcl for use in inlining
int closgen;
Node* outerfunc;
// OLITERAL/OREGISTER
Val val;
......
......@@ -11,14 +11,14 @@
* it is called by the initialization before
* main is run. to make it unique within a
* package and also uncallable, the name,
* normally "pkg.init", is altered to "pkg.init·1".
* normally "pkg.init", is altered to "pkg.init.1".
*/
Sym*
renameinit(void)
{
static int initgen;
snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
snprint(namebuf, sizeof(namebuf), "init.%d", ++initgen);
return lookup(namebuf);
}
......@@ -35,7 +35,7 @@ renameinit(void)
* // over all matching imported symbols
* <pkg>.init() (7)
* { <init stmts> } (8)
* init·<n>() // if any (9)
* init.<n>() // if any (9)
* initdone· = 2; (10)
* return (11)
* }
......@@ -69,8 +69,7 @@ anyinit(NodeList *n)
return 1;
// is there an explicit init function
snprint(namebuf, sizeof(namebuf), "init·1");
s = lookup(namebuf);
s = lookup("init.1");
if(s->def != N)
return 1;
......@@ -167,7 +166,7 @@ fninit(NodeList *n)
// (9)
// could check that it is fn of no args/returns
for(i=1;; i++) {
snprint(namebuf, sizeof(namebuf), "init·%d", i);
snprint(namebuf, sizeof(namebuf), "init.%d", i);
s = lookup(namebuf);
if(s->def == N)
break;
......
......@@ -180,7 +180,7 @@ compile(Node *fn)
dowidth(curfn->type);
if(fn->nbody == nil) {
if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) {
if(pure_go || strncmp(fn->nname->sym->name, "init.", 5) == 0) {
yyerror("missing function body", fn);
goto ret;
}
......
......@@ -179,7 +179,8 @@ mapbucket(Type *t)
bucket->width += widthreg - widthptr;
// See comment on hmap.overflow in ../../runtime/hashmap.go.
if(!haspointers(t->type) && !haspointers(t->down))
if(!haspointers(t->type) && !haspointers(t->down) &&
t->type->width <= MAXKEYSIZE && t->down->width <= MAXVALSIZE)
bucket->haspointers = 1; // no pointers
t->bucket = bucket;
......
#!/bin/sh
x() {
echo '--- ' "$@"
"$@"
echo '---'
echo
}
x go help
x go help build
x go help clean
x go help install
x go help fix
x go help fmt
x go help get
x go help list
x go help test
x go help version
x go help vet
x go help gopath
x go help importpath
x go help remote
This diff is collapsed.
......@@ -50,6 +50,9 @@ func tool(toolName string) string {
if toolIsWindows {
toolPath += toolWindowsExtension
}
if len(buildToolExec) > 0 {
return toolPath
}
// Give a nice message if there is no tool with that name.
if _, err := os.Stat(toolPath); err != nil {
if isInGoToolsRepo(toolName) {
......
......@@ -122,32 +122,19 @@ var vcsGit = &vcsCmd{
}
func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error) {
outb, err := vcsGit.runOutput(rootDir, "remote -v")
cmd := "config remote.origin.url"
errParse := errors.New("unable to parse output of git " + cmd)
outb, err := vcsGit.runOutput(rootDir, cmd)
if err != nil {
return "", err
}
out := string(outb)
// Expect:
// origin https://github.com/rsc/pdf (fetch)
// origin https://github.com/rsc/pdf (push)
// use first line only.
if !strings.HasPrefix(out, "origin\t") {
return "", fmt.Errorf("unable to parse output of git remote -v")
}
out = strings.TrimPrefix(out, "origin\t")
i := strings.Index(out, "\n")
if i < 0 {
return "", fmt.Errorf("unable to parse output of git remote -v")
}
out = out[:i]
i = strings.LastIndex(out, " ")
if i < 0 {
return "", fmt.Errorf("unable to parse output of git remote -v")
repoUrl := strings.TrimSpace(string(outb))
for _, s := range vcsGit.scheme {
if strings.HasPrefix(repoUrl, s) {
return repoUrl, nil
}
}
out = out[:i]
return strings.TrimSpace(string(out)), nil
return "", errParse
}
// vcsBzr describes how to use Bazaar.
......
......@@ -1363,6 +1363,7 @@ asmbelf(vlong symo)
sh->type = SHT_REL;
sh->flags = SHF_ALLOC;
sh->entsize = ELF32RELSIZE;
sh->addralign = 4;
sh->link = elfshname(".dynsym")->shnum;
shsym(sh, linklookup(ctxt, ".rel.plt", 0));
......
......@@ -269,11 +269,13 @@ loadlib(void)
tlsg = linklookup(ctxt, "runtime.tlsg", 0);
// For most ports, runtime.tlsg is a placeholder symbol for TLS
// relocation. However, the Android and Darwin ports need it to
// be a real variable. Instead of hard-coding which platforms
// need it to be a real variable, we set the type to STLSBSS only
// when the runtime has not declared its type already.
if(tlsg->type == 0)
// relocation. However, the Android and Darwin arm ports need it
// to be a real variable.
//
// TODO(crawshaw): android should require leaving the tlsg->type
// alone (as the runtime-provided SNOPTRBSS) just like darwin/arm.
// But some other part of the linker is expecting STLSBSS.
if (!(strcmp(goos, "darwin") == 0 && thearch.thechar == '5'))
tlsg->type = STLSBSS;
tlsg->size = thearch.ptrsize;
tlsg->hide = 1;
......
......@@ -106,7 +106,9 @@ func PProf(flagset plugin.FlagSet, fetch plugin.Fetcher, sym plugin.Symbolizer,
return err
}
prof.RemoveUninteresting()
if !*f.flagRuntime {
prof.RemoveUninteresting()
}
if *f.flagInteractive {
return interactive(prof, obj, ui, f)
......@@ -445,6 +447,7 @@ type flags struct {
flagNodeFraction *float64 // Hide nodes below <f>*total
flagEdgeFraction *float64 // Hide edges below <f>*total
flagTrim *bool // Set to false to ignore NodeCount/*Fraction
flagRuntime *bool // Show runtime call frames in memory profiles
flagFocus *string // Restricts to paths going through a node matching regexp
flagIgnore *string // Skips paths going through any nodes matching regexp
flagHide *string // Skips sample locations matching regexp
......@@ -640,6 +643,7 @@ func getFlags(flag plugin.FlagSet, overrides commands.Commands, ui plugin.UI) (*
flagNodeFraction: flag.Float64("nodefraction", 0.005, "Hide nodes below <f>*total"),
flagEdgeFraction: flag.Float64("edgefraction", 0.001, "Hide edges below <f>*total"),
flagTrim: flag.Bool("trim", true, "Honor nodefraction/edgefraction/nodecount defaults"),
flagRuntime: flag.Bool("runtime", false, "Show runtime call frames in memory profiles"),
flagFocus: flag.String("focus", "", "Restricts to paths going through a node matching regexp"),
flagIgnore: flag.String("ignore", "", "Skips paths going through any nodes matching regexp"),
flagHide: flag.String("hide", "", "Skips nodes matching regexp"),
......@@ -877,6 +881,7 @@ var usageMsg = "Output file parameters (for file-based output formats):\n" +
" -contentions Display number of delays at each region\n" +
" -mean_delay Display mean delay at each region\n" +
"Filtering options:\n" +
" -runtime Show runtime call frames in memory profiles\n" +
" -focus=r Restricts to paths going through a node matching regexp\n" +
" -ignore=r Skips paths going through any nodes matching regexp\n" +
" -tagfocus=r Restrict to samples tagged with key:value matching regexp\n" +
......
......@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build cgo
// +build cgo,!arm
package x509
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:generate go run root_darwin_arm_gen.go -output root_darwin_arm.go
package x509
import "os/exec"
......
This diff is collapsed.
// 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.
// +build ignore
// Generates root_darwin_arm.go.
//
// As of iOS 8, there is no API for querying the system trusted X.509 root
// certificates. We could use SecTrustEvaluate to verify that a trust chain
// exists for a certificate, but the x509 API requires returning the entire
// chain.
//
// Apple publishes the list of trusted root certificates for iOS on
// support.apple.com. So we parse the list and extract the certificates from
// an OS X machine and embed them into the x509 package.
package main
import (
"bytes"
"crypto/x509"
"encoding/pem"
"flag"
"fmt"
"go/format"
"io/ioutil"
"log"
"math/big"
"net/http"
"os/exec"
"strings"
)
var output = flag.String("output", "root_darwin_arm.go", "file name to write")
func main() {
certs, err := selectCerts()
if err != nil {
log.Fatal(err)
}
buf := new(bytes.Buffer)
fmt.Fprintf(buf, "// Created by root_darwin_arm_gen --output %s; DO NOT EDIT\n", *output)
fmt.Fprintf(buf, "%s", header)
fmt.Fprintf(buf, "const systemRootsPEM = `\n")
for _, cert := range certs {
b := &pem.Block{
Type: "CERTIFICATE",
Bytes: cert.Raw,
}
if err := pem.Encode(buf, b); err != nil {
log.Fatal(err)
}
}
fmt.Fprintf(buf, "`")
source, err := format.Source(buf.Bytes())
if err != nil {
log.Fatal("source format error:", err)
}
if err := ioutil.WriteFile(*output, source, 0644); err != nil {
log.Fatal(err)
}
}
func selectCerts() ([]*x509.Certificate, error) {
ids, err := fetchCertIDs()
if err != nil {
return nil, err
}
scerts, err := sysCerts()
if err != nil {
return nil, err
}
var certs []*x509.Certificate
for _, id := range ids {
sn, ok := big.NewInt(0).SetString(id.serialNumber, 0) // 0x prefix selects hex
if !ok {
return nil, fmt.Errorf("invalid serial number: %q", id.serialNumber)
}
ski, ok := big.NewInt(0).SetString(id.subjectKeyID, 0)
if !ok {
return nil, fmt.Errorf("invalid Subject Key ID: %q", id.subjectKeyID)
}
for _, cert := range scerts {
if sn.Cmp(cert.SerialNumber) != 0 {
continue
}
cski := big.NewInt(0).SetBytes(cert.SubjectKeyId)
if ski.Cmp(cski) != 0 {
continue
}
certs = append(certs, cert)
break
}
}
return certs, nil
}
func sysCerts() (certs []*x509.Certificate, err error) {
cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
data, err := cmd.Output()
if err != nil {
return nil, err
}
for len(data) > 0 {
var block *pem.Block
block, data = pem.Decode(data)
if block == nil {
break
}
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
continue
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
continue
}
certs = append(certs, cert)
}
return certs, nil
}
type certID struct {
serialNumber string
subjectKeyID string
}
// fetchCertIDs fetches IDs of iOS X509 certificates from apple.com.
func fetchCertIDs() ([]certID, error) {
resp, err := http.Get("https://support.apple.com/en-us/HT204132")
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
text := string(body)
text = text[strings.Index(text, "<section id=trusted"):]
text = text[:strings.Index(text, "</section>")]
lines := strings.Split(text, "\n")
var ids []certID
var id certID
for i, ln := range lines {
if i == len(lines)-1 {
break
}
const sn = "Serial Number:"
if ln == sn {
id.serialNumber = "0x" + strings.Replace(strings.TrimSpace(lines[i+1]), ":", "", -1)
continue
}
if strings.HasPrefix(ln, sn) {
// extract hex value from parentheses.
id.serialNumber = ln[strings.Index(ln, "(")+1 : len(ln)-1]
continue
}
if strings.TrimSpace(ln) == "X509v3 Subject Key Identifier:" {
id.subjectKeyID = "0x" + strings.Replace(strings.TrimSpace(lines[i+1]), ":", "", -1)
ids = append(ids, id)
id = certID{}
}
}
return ids, nil
}
const header = `
// 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 x509
func initSystemRoots() {
systemRoots = NewCertPool()
systemRoots.AppendCertsFromPEM([]byte(systemRootsPEM))
}
`
......@@ -113,8 +113,8 @@ import (
// a JSON tag of "-".
//
// Map values encode as JSON objects.
// The map's key type must be string; the object keys are used directly
// as map keys.
// The map's key type must be string; the map keys are used as JSON object
// keys, subject to the UTF-8 coercion described for string values above.
//
// Pointer values encode as the value pointed to.
// A nil pointer encodes as the null JSON object.
......
......@@ -97,3 +97,58 @@ func yCbCrModel(c Color) Color {
y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
return YCbCr{y, u, v}
}
// RGBToCMYK converts an RGB triple to a CMYK quadruple.
func RGBToCMYK(r, g, b uint8) (uint8, uint8, uint8, uint8) {
rr := uint32(r)
gg := uint32(g)
bb := uint32(b)
w := rr
if w < gg {
w = gg
}
if w < bb {
w = bb
}
if w == 0 {
return 0, 0, 0, 255
}
c := (w - rr) * 255 / w
m := (w - gg) * 255 / w
y := (w - bb) * 255 / w
return uint8(c), uint8(m), uint8(y), uint8(255 - w)
}
// CMYKToRGB converts a CMYK quadruple to an RGB triple.
func CMYKToRGB(c, m, y, k uint8) (uint8, uint8, uint8) {
w := uint32(255 - k)
r := uint32(255-c) * w / 255
g := uint32(255-m) * w / 255
b := uint32(255-y) * w / 255
return uint8(r), uint8(g), uint8(b)
}
// CMYK represents a fully opaque CMYK color, having 8 bits for each of cyan,
// magenta, yellow and black.
//
// It is not associated with any particular color profile.
type CMYK struct {
C, M, Y, K uint8
}
func (c CMYK) RGBA() (uint32, uint32, uint32, uint32) {
r, g, b := CMYKToRGB(c.C, c.M, c.Y, c.K)
return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff
}
// CMYKModel is the Model for CMYK colors.
var CMYKModel Model = ModelFunc(cmykModel)
func cmykModel(c Color) Color {
if _, ok := c.(CMYK); ok {
return c
}
r, g, b, _ := c.RGBA()
cc, mm, yy, kk := RGBToCMYK(uint8(r>>8), uint8(g>>8), uint8(b>>8))
return CMYK{cc, mm, yy, kk}
}
......@@ -15,9 +15,9 @@ func delta(x, y uint8) uint8 {
return y - x
}
// Test that a subset of RGB space can be converted to YCbCr and back to within
// 1/256 tolerance.
func TestRoundtrip(t *testing.T) {
// TestYCbCrRoundtrip tests that a subset of RGB space can be converted to YCbCr
// and back to within 1/256 tolerance.
func TestYCbCrRoundtrip(t *testing.T) {
for r := 0; r < 255; r += 7 {
for g := 0; g < 255; g += 5 {
for b := 0; b < 255; b += 3 {
......@@ -31,3 +31,20 @@ func TestRoundtrip(t *testing.T) {
}
}
}
// TestCMYKRoundtrip tests that a subset of RGB space can be converted to CMYK
// and back to within 1/256 tolerance.
func TestCMYKRoundtrip(t *testing.T) {
for r := 0; r < 255; r += 7 {
for g := 0; g < 255; g += 5 {
for b := 0; b < 255; b += 3 {
r0, g0, b0 := uint8(r), uint8(g), uint8(b)
c, m, y, k := RGBToCMYK(r0, g0, b0)
r1, g1, b1 := CMYKToRGB(c, m, y, k)
if delta(r0, r1) > 1 || delta(g0, g1) > 1 || delta(b0, b1) > 1 {
t.Fatalf("r0, g0, b0 = %d, %d, %d r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1)
}
}
}
}
}
......@@ -32,6 +32,7 @@ var imageTests = []imageTest{
// JPEG is a lossy format and hence needs a non-zero tolerance.
{"testdata/video-001.png", "testdata/video-001.jpeg", 8 << 8},
{"testdata/video-001.png", "testdata/video-001.progressive.jpeg", 8 << 8},
{"testdata/video-001.cmyk.png", "testdata/video-001.cmyk.jpeg", 8 << 8},
// Grayscale images.
{"testdata/video-005.gray.png", "testdata/video-005.gray.jpeg", 8 << 8},
{"testdata/video-005.gray.png", "testdata/video-005.gray.png", 0},
......
......@@ -127,6 +127,9 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
if drawYCbCr(dst0, r, src0, sp) {
return
}
case *image.CMYK:
drawCMYK(dst0, r, src0, sp)
return
}
} else if mask0, ok := mask.(*image.Alpha); ok {
switch src0 := src.(type) {
......@@ -151,6 +154,9 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
if drawYCbCr(dst0, r, src0, sp) {
return
}
case *image.CMYK:
drawCMYK(dst0, r, src0, sp)
return
}
}
}
......@@ -392,6 +398,8 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
}
}
// TODO(nigeltao): this function is copy/pasted to image/jpeg/reader.go. We
// should un-copy/paste it.
func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) {
// An image.YCbCr is always fully opaque, and so if the mask is implicitly nil
// (i.e. fully opaque) then the op is effectively always Src.
......@@ -460,6 +468,28 @@ func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Po
return true
}
func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Point) {
// An image.CMYK is always fully opaque, and so if the mask is implicitly nil
// (i.e. fully opaque) then the op is effectively always Src.
i0 := (r.Min.X - dst.Rect.Min.X) * 4
i1 := (r.Max.X - dst.Rect.Min.X) * 4
si0 := (sp.X - src.Rect.Min.X) * 4
yMax := r.Max.Y - dst.Rect.Min.Y
y := r.Min.Y - dst.Rect.Min.Y
sy := sp.Y - src.Rect.Min.Y
for ; y != yMax; y, sy = y+1, sy+1 {
dpix := dst.Pix[y*dst.Stride:]
spix := src.Pix[sy*src.Stride:]
for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
dpix[i+0], dpix[i+1], dpix[i+2] =
color.CMYKToRGB(spix[si+0], spix[si+1], spix[si+2], spix[si+3])
dpix[i+3] = 255
}
}
}
func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
i0 := dst.PixOffset(r.Min.X, r.Min.Y)
i1 := i0 + r.Dx()*4
......
......@@ -74,6 +74,16 @@ func vgradCr() image.Image {
return m
}
func vgradMagenta() image.Image {
m := image.NewCMYK(image.Rect(0, 0, 16, 16))
for y := 0; y < 16; y++ {
for x := 0; x < 16; x++ {
m.Set(x, y, color.CMYK{0, uint8(y * 0x11), 0, 0x3f})
}
}
return m
}
func hgradRed(alpha int) Image {
m := image.NewRGBA(image.Rect(0, 0, 16, 16))
for y := 0; y < 16; y++ {
......@@ -147,6 +157,16 @@ var drawTests = []drawTest{
{"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, color.RGBA{8, 28, 0, 192}},
{"ycbcrNil", vgradCr(), nil, Over, color.RGBA{11, 38, 0, 255}},
{"ycbcrNilSrc", vgradCr(), nil, Src, color.RGBA{11, 38, 0, 255}},
// Uniform mask (100%, 75%, nil) and variable CMYK source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
// The source pixel is {0, 136, 0, 63} in CMYK-space, which is {192, 89, 192} in RGB-space.
{"cmyk", vgradMagenta(), fillAlpha(255), Over, color.RGBA{192, 89, 192, 255}},
{"cmykSrc", vgradMagenta(), fillAlpha(255), Src, color.RGBA{192, 89, 192, 255}},
{"cmykAlpha", vgradMagenta(), fillAlpha(192), Over, color.RGBA{178, 67, 145, 255}},
{"cmykAlphaSrc", vgradMagenta(), fillAlpha(192), Src, color.RGBA{145, 67, 145, 192}},
{"cmykNil", vgradMagenta(), nil, Over, color.RGBA{192, 89, 192, 255}},
{"cmykNilSrc", vgradMagenta(), nil, Src, color.RGBA{192, 89, 192, 255}},
// Variable mask and variable source.
// At (x, y) == (8, 8):
// The destination pixel is {136, 0, 0, 255}.
......
......@@ -62,7 +62,7 @@ func (p Point) Mod(r Rectangle) Point {
// Eq reports whether p and q are equal.
func (p Point) Eq(q Point) bool {
return p.X == q.X && p.Y == q.Y
return p == q
}
// ZP is the zero Point.
......@@ -164,6 +164,12 @@ func (r Rectangle) Intersect(s Rectangle) Rectangle {
// Union returns the smallest rectangle that contains both r and s.
func (r Rectangle) Union(s Rectangle) Rectangle {
if r.Empty() {
return s
}
if s.Empty() {
return r
}
if r.Min.X > s.Min.X {
r.Min.X = s.Min.X
}
......@@ -184,15 +190,16 @@ func (r Rectangle) Empty() bool {
return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
}
// Eq reports whether r and s are equal.
// Eq reports whether r and s contain the same set of points. All empty
// rectangles are considered equal.
func (r Rectangle) Eq(s Rectangle) bool {
return r.Min.X == s.Min.X && r.Min.Y == s.Min.Y &&
r.Max.X == s.Max.X && r.Max.Y == s.Max.Y
return r == s || r.Empty() && s.Empty()
}
// Overlaps reports whether r and s have a non-empty intersection.
func (r Rectangle) Overlaps(s Rectangle) bool {
return r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
return !r.Empty() && !s.Empty() &&
r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
}
......@@ -222,7 +229,9 @@ func (r Rectangle) Canon() Rectangle {
// ZR is the zero Rectangle.
var ZR Rectangle
// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}. The returned
// rectangle has minimum and maximum coordinates swapped if necessary so that
// it is well-formed.
func Rect(x0, y0, x1, y1 int) Rectangle {
if x0 > x1 {
x0, x1 = x1, x0
......
// 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 image
import (
"fmt"
"testing"
)
func TestRectangle(t *testing.T) {
// in checks that every point in f is in g.
in := func(f, g Rectangle) error {
if !f.In(g) {
return fmt.Errorf("f=%s, f.In(%s): got false, want true", f, g)
}
for y := f.Min.Y; y < f.Max.Y; y++ {
for x := f.Min.X; x < f.Max.X; x++ {
p := Point{x, y}
if !p.In(g) {
return fmt.Errorf("p=%s, p.In(%s): got false, want true", p, g)
}
}
}
return nil
}
rects := []Rectangle{
Rect(0, 0, 10, 10),
Rect(1, 2, 3, 4),
Rect(4, 6, 10, 10),
Rect(2, 3, 12, 5),
Rect(-1, -2, 0, 0),
Rect(-1, -2, 4, 6),
Rect(-10, -20, 30, 40),
Rect(8, 8, 8, 8),
Rect(88, 88, 88, 88),
Rect(6, 5, 4, 3),
}
// r.Eq(s) should be equivalent to every point in r being in s, and every
// point in s being in r.
for _, r := range rects {
for _, s := range rects {
got := r.Eq(s)
want := in(r, s) == nil && in(s, r) == nil
if got != want {
t.Errorf("Eq: r=%s, s=%s: got %t, want %t", r, s, got, want)
}
}
}
// The intersection should be the largest rectangle a such that every point
// in a is both in r and in s.
for _, r := range rects {
for _, s := range rects {
a := r.Intersect(s)
if err := in(a, r); err != nil {
t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in r: %v", r, s, a, err)
}
if err := in(a, s); err != nil {
t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in s: %v", r, s, a, err)
}
if a.Empty() == r.Overlaps(s) {
t.Errorf("Intersect: r=%s, s=%s, a=%s: empty=%t same as overlaps=%t",
r, s, a, a.Empty(), r.Overlaps(s))
}
largerThanA := [4]Rectangle{a, a, a, a}
largerThanA[0].Min.X--
largerThanA[1].Min.Y--
largerThanA[2].Max.X++
largerThanA[3].Max.Y++
for i, b := range largerThanA {
if b.Empty() {
// b isn't actually larger than a.
continue
}
if in(b, r) == nil && in(b, s) == nil {
t.Errorf("Intersect: r=%s, s=%s, a=%s, b=%s, i=%d: intersection could be larger",
r, s, a, b, i)
}
}
}
}
// The union should be the smallest rectangle a such that every point in r
// is in a and every point in s is in a.
for _, r := range rects {
for _, s := range rects {
a := r.Union(s)
if err := in(r, a); err != nil {
t.Errorf("Union: r=%s, s=%s, a=%s, r not in a: %v", r, s, a, err)
}
if err := in(s, a); err != nil {
t.Errorf("Union: r=%s, s=%s, a=%s, s not in a: %v", r, s, a, err)
}
if a.Empty() {
// You can't get any smaller than a.
continue
}
smallerThanA := [4]Rectangle{a, a, a, a}
smallerThanA[0].Min.X++
smallerThanA[1].Min.Y++
smallerThanA[2].Max.X--
smallerThanA[3].Max.Y--
for i, b := range smallerThanA {
if in(r, b) == nil && in(s, b) == nil {
t.Errorf("Union: r=%s, s=%s, a=%s, b=%s, i=%d: union could be smaller",
r, s, a, b, i)
}
}
}
}
}
......@@ -826,6 +826,92 @@ func NewGray16(r Rectangle) *Gray16 {
return &Gray16{pix, 2 * w, r}
}
// CMYK is an in-memory image whose At method returns color.CMYK values.
type CMYK struct {
// Pix holds the image's pixels, in C, M, Y, K order. The pixel at
// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
Pix []uint8
// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
Stride int
// Rect is the image's bounds.
Rect Rectangle
}
func (p *CMYK) ColorModel() color.Model { return color.CMYKModel }
func (p *CMYK) Bounds() Rectangle { return p.Rect }
func (p *CMYK) At(x, y int) color.Color {
return p.CMYKAt(x, y)
}
func (p *CMYK) CMYKAt(x, y int) color.CMYK {
if !(Point{x, y}.In(p.Rect)) {
return color.CMYK{}
}
i := p.PixOffset(x, y)
return color.CMYK{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
}
// PixOffset returns the index of the first element of Pix that corresponds to
// the pixel at (x, y).
func (p *CMYK) PixOffset(x, y int) int {
return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
}
func (p *CMYK) Set(x, y int, c color.Color) {
if !(Point{x, y}.In(p.Rect)) {
return
}
i := p.PixOffset(x, y)
c1 := color.CMYKModel.Convert(c).(color.CMYK)
p.Pix[i+0] = c1.C
p.Pix[i+1] = c1.M
p.Pix[i+2] = c1.Y
p.Pix[i+3] = c1.K
}
func (p *CMYK) SetCMYK(x, y int, c color.CMYK) {
if !(Point{x, y}.In(p.Rect)) {
return
}
i := p.PixOffset(x, y)
p.Pix[i+0] = c.C
p.Pix[i+1] = c.M
p.Pix[i+2] = c.Y
p.Pix[i+3] = c.K
}
// SubImage returns an image representing the portion of the image p visible
// through r. The returned value shares pixels with the original image.
func (p *CMYK) SubImage(r Rectangle) Image {
r = r.Intersect(p.Rect)
// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
// either r1 or r2 if the intersection is empty. Without explicitly checking for
// this, the Pix[i:] expression below can panic.
if r.Empty() {
return &CMYK{}
}
i := p.PixOffset(r.Min.X, r.Min.Y)
return &CMYK{
Pix: p.Pix[i:],
Stride: p.Stride,
Rect: r,
}
}
// Opaque scans the entire image and reports whether it is fully opaque.
func (p *CMYK) Opaque() bool {
return true
}
// NewCMYK returns a new CMYK with the given bounds.
func NewCMYK(r Rectangle) *CMYK {
w, h := r.Dx(), r.Dy()
buf := make([]uint8, 4*w*h)
return &CMYK{buf, 4 * w, r}
}
// Paletted is an in-memory image of uint8 indices into a given palette.
type Paletted struct {
// Pix holds the image's pixels, as palette indices. The pixel at
......
This diff is collapsed.
......@@ -10,11 +10,12 @@ import (
// makeImg allocates and initializes the destination image.
func (d *decoder) makeImg(h0, v0, mxx, myy int) {
if d.nComp == nGrayComponent {
if d.nComp == 1 {
m := image.NewGray(image.Rect(0, 0, 8*mxx, 8*myy))
d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray)
return
}
var subsampleRatio image.YCbCrSubsampleRatio
switch {
case h0 == 1 && v0 == 1:
......@@ -30,6 +31,12 @@ func (d *decoder) makeImg(h0, v0, mxx, myy int) {
}
m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio)
d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr)
if d.nComp == 4 {
h3, v3 := d.comp[3].h, d.comp[3].v
d.blackPix = make([]byte, 8*h3*mxx*8*v3*myy)
d.blackStride = 8 * h3 * mxx
}
}
// Specified in section B.2.3.
......@@ -47,7 +54,7 @@ func (d *decoder) processSOS(n int) error {
if n != 4+2*nComp {
return FormatError("SOS length inconsistent with number of components")
}
var scan [nColorComponent]struct {
var scan [maxComponents]struct {
compIndex uint8
td uint8 // DC table selector.
ta uint8 // AC table selector.
......@@ -128,7 +135,7 @@ func (d *decoder) processSOS(n int) error {
var (
// b is the decoded coefficients, in natural (not zig-zag) order.
b block
dc [nColorComponent]int32
dc [maxComponents]int32
// bx and by are the location of the current (in terms of 8x8 blocks).
// For example, with 4:2:0 chroma subsampling, the block whose top left
// pixel co-ordinates are (16, 8) is the third block in the first row:
......@@ -276,7 +283,7 @@ func (d *decoder) processSOS(n int) error {
}
idct(&b)
dst, stride := []byte(nil), 0
if d.nComp == nGrayComponent {
if d.nComp == 1 {
dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride
} else {
switch compIndex {
......@@ -286,6 +293,8 @@ func (d *decoder) processSOS(n int) error {
dst, stride = d.img3.Cb[8*(by*d.img3.CStride+bx):], d.img3.CStride
case 2:
dst, stride = d.img3.Cr[8*(by*d.img3.CStride+bx):], d.img3.CStride
case 3:
dst, stride = d.blackPix[8*(by*d.blackStride+bx):], d.blackStride
default:
return UnsupportedError("too many components")
}
......@@ -325,7 +334,7 @@ func (d *decoder) processSOS(n int) error {
// Reset the Huffman decoder.
d.bits = bits{}
// Reset the DC components, as per section F.2.1.3.1.
dc = [nColorComponent]int32{}
dc = [maxComponents]int32{}
// Reset the progressive decoder state, as per section G.1.2.2.
d.eobRun = 0
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -46,11 +46,12 @@ func (z *Float) SetString(s string) (*Float, bool) {
// digits = digit { digit } .
// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
//
// The base argument must be 0 or a value between 2 through MaxBase.
// The base argument must be 0, 2, 10, or 16. Providing an invalid base
// argument will lead to a run-time panic.
//
// For base 0, the number prefix determines the actual base: A prefix of
// ``0x'' or ``0X'' selects base 16, and a ``0b'' or ``0B'' prefix selects
// base 2; otherwise, the actual base is 10 and no prefix is permitted.
// base 2; otherwise, the actual base is 10 and no prefix is accepted.
// The octal prefix ``0'' is not supported.
//
// A "p" exponent indicates power of 2 for the exponent; for instance "1.2p3"
......@@ -75,7 +76,7 @@ func (z *Float) Scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
// exponent
var exp int64
var ebase int
exp, ebase, err = scanExponent(r)
exp, ebase, err = scanExponent(r, true)
if err != nil {
return
}
......@@ -151,13 +152,13 @@ func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
// ScanFloat is like f.Scan(r, base) with f set to the given precision
// and rounding mode.
func ScanFloat(r io.ByteScanner, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
return NewFloat(0, prec, mode).Scan(r, base)
return new(Float).SetPrec(prec).SetMode(mode).Scan(r, base)
}
// ParseFloat is like f.Parse(s, base) with f set to the given precision
// and rounding mode.
func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
return NewFloat(0, prec, mode).Parse(s, base)
return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base)
}
// Format converts the floating-point number x to a string according
......@@ -215,9 +216,9 @@ func (x *Float) Append(buf []byte, format byte, prec int) []byte {
return x.bigFtoa(buf, format, prec)
}
// BUG(gri): Currently, String uses the 'p' (rather than 'g') format.
// BUG(gri): Currently, String uses x.Format('g', 10) rather than x.Format('g', -1).
func (x *Float) String() string {
return x.Format('p', 0)
return x.Format('g', 10)
}
// bstring appends the string of x in the format ["-"] mantissa "p" exponent
......
......@@ -8,6 +8,7 @@ package big
import (
"errors"
"fmt"
"io"
"math"
"sync"
......@@ -50,7 +51,7 @@ func pow(x Word, n int) (p Word) {
// scan scans the number corresponding to the longest possible prefix
// from r representing an unsigned number in a given conversion base.
// It returns the corresponding natural number res, the actual base b,
// a digit count, and an error err, if any.
// a digit count, and a read or syntax error err, if any.
//
// number = [ prefix ] mantissa .
// prefix = "0" [ "x" | "X" | "b" | "B" ] .
......@@ -58,12 +59,15 @@ func pow(x Word, n int) (p Word) {
// digits = digit { digit } .
// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
//
// The base argument must be 0 or a value between 0 through MaxBase.
// Unless fracOk is set, the base argument must be 0 or a value between
// 2 through MaxBase. If fracOk is set, the base argument must be one of
// 0, 2, 10, or 16. Providing an invalid base argument leads to a run-
// time panic.
//
// For base 0, the number prefix determines the actual base: A prefix of
// ``0x'' or ``0X'' selects base 16; if fracOk is not set, the ``0'' prefix
// selects base 8, and a ``0b'' or ``0B'' prefix selects base 2. Otherwise
// the selected base is 10 and no prefix is permitted.
// the selected base is 10 and no prefix is accepted.
//
// If fracOk is set, an octal prefix is ignored (a leading ``0'' simply
// stands for a zero digit), and a period followed by a fractional part
......@@ -73,13 +77,15 @@ func pow(x Word, n int) (p Word) {
// A result digit count > 0 corresponds to the number of (non-prefix) digits
// parsed. A digit count <= 0 indicates the presence of a period (if fracOk
// is set, only), and -count is the number of fractional digits found.
// In this case, the value of the scanned number is res * 10**count.
// In this case, the actual value of the scanned number is res * b**count.
//
func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count int, err error) {
// reject illegal bases
if base != 0 && base < 2 || base > MaxBase {
err = errors.New("illegal number base")
return
baseOk := base == 0 ||
!fracOk && 2 <= base && base <= MaxBase ||
fracOk && (base == 2 || base == 10 || base == 16)
if !baseOk {
panic(fmt.Sprintf("illegal number base %d", base))
}
// one char look-ahead
......
......@@ -98,10 +98,6 @@ var natScanTests = []struct {
ok bool // expected success
next rune // next character (or 0, if at EOF)
}{
// error: illegal base
{base: -1},
{base: 37},
// error: no mantissa
{},
{s: "?"},
......@@ -114,7 +110,7 @@ var natScanTests = []struct {
// error: incorrect use of decimal point
{s: ".0"},
{s: ".0", base: 10},
{s: ".", base: 1},
{s: ".", base: 0},
{s: "0x.0"},
// no errors
......
......@@ -78,9 +78,8 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
// exponent
var exp int64
var ebase int
exp, ebase, err = scanExponent(r)
if ebase == 2 || err != nil {
exp, _, err = scanExponent(r, false)
if err != nil {
return nil, false
}
......@@ -115,7 +114,17 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
return z, true
}
func scanExponent(r io.ByteScanner) (exp int64, base int, err error) {
// scanExponent scans the longest possible prefix of r representing a decimal
// ('e', 'E') or binary ('p') exponent, if any. It returns the exponent, the
// exponent base (10 or 2), or a read or syntax error, if any.
//
// exponent = ( "E" | "e" | "p" ) [ sign ] digits .
// sign = "+" | "-" .
// digits = digit { digit } .
// digit = "0" ... "9" .
//
// A binary exponent is only permitted if binExpOk is set.
func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) {
base = 10
var ch byte
......@@ -130,7 +139,11 @@ func scanExponent(r io.ByteScanner) (exp int64, base int, err error) {
case 'e', 'E':
// ok
case 'p':
base = 2
if binExpOk {
base = 2
break // ok
}
fallthrough // binary exponent not permitted
default:
r.UnreadByte()
return // no exponent; same as e0
......
......@@ -29,9 +29,9 @@ func Nextafter32(x, y float32) (r float32) {
// Nextafter returns the next representable float64 value after x towards y.
//
// Special cases are:
// Nextafter64(x, x) = x
// Nextafter64(NaN, y) = NaN
// Nextafter64(x, NaN) = NaN
// Nextafter(x, x) = x
// Nextafter(NaN, y) = NaN
// Nextafter(x, NaN) = NaN
func Nextafter(x, y float64) (r float64) {
switch {
case IsNaN(x) || IsNaN(y): // special case
......
......@@ -19,6 +19,7 @@ import (
"fmt"
"io"
"log"
"net"
"net/http"
"os"
"os/exec"
......@@ -128,11 +129,16 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
"PATH_INFO=" + pathInfo,
"SCRIPT_NAME=" + root,
"SCRIPT_FILENAME=" + h.Path,
"REMOTE_ADDR=" + req.RemoteAddr,
"REMOTE_HOST=" + req.RemoteAddr,
"SERVER_PORT=" + port,
}
if remoteIP, remotePort, err := net.SplitHostPort(req.RemoteAddr); err == nil {
env = append(env, "REMOTE_ADDR="+remoteIP, "REMOTE_HOST="+remoteIP, "REMOTE_PORT="+remotePort)
} else {
// could not parse ip:port, let's use whole RemoteAddr and leave REMOTE_PORT undefined
env = append(env, "REMOTE_ADDR="+req.RemoteAddr, "REMOTE_HOST="+req.RemoteAddr)
}
if req.TLS != nil {
env = append(env, "HTTPS=on")
}
......
......@@ -29,7 +29,7 @@ func newRequest(httpreq string) *http.Request {
if err != nil {
panic("cgi: bogus http request in test: " + httpreq)
}
req.RemoteAddr = "1.2.3.4"
req.RemoteAddr = "1.2.3.4:1234"
return req
}
......@@ -37,7 +37,11 @@ func runCgiTest(t *testing.T, h *Handler, httpreq string, expectedMap map[string
rw := httptest.NewRecorder()
req := newRequest(httpreq)
h.ServeHTTP(rw, req)
runResponseChecks(t, rw, expectedMap)
return rw
}
func runResponseChecks(t *testing.T, rw *httptest.ResponseRecorder, expectedMap map[string]string) {
// Make a map to hold the test map that the CGI returns.
m := make(map[string]string)
m["_body"] = rw.Body.String()
......@@ -75,7 +79,6 @@ readlines:
t.Errorf("for key %q got %q; expected %q", key, got, expected)
}
}
return rw
}
var cgiTested, cgiWorks bool
......@@ -108,6 +111,7 @@ func TestCGIBasicGet(t *testing.T) {
"env-QUERY_STRING": "foo=bar&a=b",
"env-REMOTE_ADDR": "1.2.3.4",
"env-REMOTE_HOST": "1.2.3.4",
"env-REMOTE_PORT": "1234",
"env-REQUEST_METHOD": "GET",
"env-REQUEST_URI": "/test.cgi?foo=bar&a=b",
"env-SCRIPT_FILENAME": "testdata/test.cgi",
......@@ -126,6 +130,39 @@ func TestCGIBasicGet(t *testing.T) {
}
}
func TestCGIEnvIPv6(t *testing.T) {
check(t)
h := &Handler{
Path: "testdata/test.cgi",
Root: "/test.cgi",
}
expectedMap := map[string]string{
"test": "Hello CGI",
"param-a": "b",
"param-foo": "bar",
"env-GATEWAY_INTERFACE": "CGI/1.1",
"env-HTTP_HOST": "example.com",
"env-PATH_INFO": "",
"env-QUERY_STRING": "foo=bar&a=b",
"env-REMOTE_ADDR": "2000::3000",
"env-REMOTE_HOST": "2000::3000",
"env-REMOTE_PORT": "12345",
"env-REQUEST_METHOD": "GET",
"env-REQUEST_URI": "/test.cgi?foo=bar&a=b",
"env-SCRIPT_FILENAME": "testdata/test.cgi",
"env-SCRIPT_NAME": "/test.cgi",
"env-SERVER_NAME": "example.com",
"env-SERVER_PORT": "80",
"env-SERVER_SOFTWARE": "go",
}
rw := httptest.NewRecorder()
req := newRequest("GET /test.cgi?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n")
req.RemoteAddr = "[2000::3000]:12345"
h.ServeHTTP(rw, req)
runResponseChecks(t, rw, expectedMap)
}
func TestCGIBasicGetAbsPath(t *testing.T) {
check(t)
pwd, err := os.Getwd()
......@@ -289,7 +326,7 @@ func TestInternalRedirect(t *testing.T) {
}
expectedMap := map[string]string{
"basepath": "/foo",
"remoteaddr": "1.2.3.4",
"remoteaddr": "1.2.3.4:1234",
}
runCgiTest(t, h, "GET /test.cgi?loc=/foo HTTP/1.0\nHost: example.com\n\n", expectedMap)
}
......
......@@ -43,6 +43,7 @@ func TestHostingOurselves(t *testing.T) {
"env-QUERY_STRING": "foo=bar&a=b",
"env-REMOTE_ADDR": "1.2.3.4",
"env-REMOTE_HOST": "1.2.3.4",
"env-REMOTE_PORT": "1234",
"env-REQUEST_METHOD": "GET",
"env-REQUEST_URI": "/test.go?foo=bar&a=b",
"env-SCRIPT_FILENAME": os.Args[0],
......
......@@ -54,24 +54,22 @@ func newLink(m *syscall.InterfaceMessage) (*Interface, error) {
return nil, os.NewSyscallError("route sockaddr", err)
}
ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
for _, sa := range sas {
switch sa := sa.(type) {
case *syscall.SockaddrDatalink:
// NOTE: SockaddrDatalink.Data is minimum work area,
// can be larger.
m.Data = m.Data[unsafe.Offsetof(sa.Data):]
var name [syscall.IFNAMSIZ]byte
for i := 0; i < int(sa.Nlen); i++ {
name[i] = byte(m.Data[i])
}
ifi.Name = string(name[:sa.Nlen])
ifi.MTU = int(m.Header.Data.Mtu)
addr := make([]byte, sa.Alen)
for i := 0; i < int(sa.Alen); i++ {
addr[i] = byte(m.Data[int(sa.Nlen)+i])
}
ifi.HardwareAddr = addr[:sa.Alen]
sa, _ := sas[syscall.RTAX_IFP].(*syscall.SockaddrDatalink)
if sa != nil {
// NOTE: SockaddrDatalink.Data is minimum work area,
// can be larger.
m.Data = m.Data[unsafe.Offsetof(sa.Data):]
var name [syscall.IFNAMSIZ]byte
for i := 0; i < int(sa.Nlen); i++ {
name[i] = byte(m.Data[i])
}
ifi.Name = string(name[:sa.Nlen])
ifi.MTU = int(m.Header.Data.Mtu)
addr := make([]byte, sa.Alen)
for i := 0; i < int(sa.Alen); i++ {
addr[i] = byte(m.Data[int(sa.Nlen)+i])
}
ifi.HardwareAddr = addr[:sa.Alen]
}
return ifi, nil
}
......@@ -144,39 +142,34 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
return ifat, nil
}
func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (Addr, error) {
func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) {
sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil {
return nil, os.NewSyscallError("route sockaddr", err)
}
ifa := &IPNet{}
for i, sa := range sas {
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
switch i {
case 0:
ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
case 1:
ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
}
case *syscall.SockaddrInet6:
switch i {
case 0:
ifa.Mask = make(IPMask, IPv6len)
copy(ifa.Mask, sa.Addr[:])
case 1:
ifa.IP = make(IP, IPv6len)
copy(ifa.IP, sa.Addr[:])
// NOTE: KAME based IPv6 protcol stack usually embeds
// the interface index in the interface-local or link-
// local address as the kernel-internal form.
if ifa.IP.IsLinkLocalUnicast() {
ifa.IP[2], ifa.IP[3] = 0, 0
}
}
default: // Sockaddrs contain syscall.SockaddrDatalink on NetBSD
return nil, nil
switch sa := sas[syscall.RTAX_NETMASK].(type) {
case *syscall.SockaddrInet4:
ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
case *syscall.SockaddrInet6:
ifa.Mask = make(IPMask, IPv6len)
copy(ifa.Mask, sa.Addr[:])
}
switch sa := sas[syscall.RTAX_IFA].(type) {
case *syscall.SockaddrInet4:
ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
case *syscall.SockaddrInet6:
ifa.IP = make(IP, IPv6len)
copy(ifa.IP, sa.Addr[:])
// NOTE: KAME based IPv6 protcol stack usually embeds
// the interface index in the interface-local or
// link-local address as the kernel-internal form.
if ifa.IP.IsLinkLocalUnicast() {
ifa.IP[2], ifa.IP[3] = 0, 0
}
}
if ifa.IP == nil || ifa.Mask == nil {
return nil, nil // Sockaddrs contain syscall.SockaddrDatalink on NetBSD
}
return ifa, nil
}
......@@ -29,35 +29,34 @@ func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
if err != nil {
return nil, err
}
ifmat = append(ifmat, ifma...)
if ifma != nil {
ifmat = append(ifmat, ifma)
}
}
}
}
return ifmat, nil
}
func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil {
return nil, os.NewSyscallError("route sockaddr", err)
}
var ifmat []Addr
for _, sa := range sas {
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
ifma := &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}
ifmat = append(ifmat, ifma.toAddr())
case *syscall.SockaddrInet6:
ifma := &IPAddr{IP: make(IP, IPv6len)}
copy(ifma.IP, sa.Addr[:])
// NOTE: KAME based IPv6 protocol stack usually embeds
// the interface index in the interface-local or link-
// local address as the kernel-internal form.
if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
ifma.IP[2], ifma.IP[3] = 0, 0
}
ifmat = append(ifmat, ifma.toAddr())
switch sa := sas[syscall.RTAX_IFA].(type) {
case *syscall.SockaddrInet4:
return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil
case *syscall.SockaddrInet6:
ifma := IPAddr{IP: make(IP, IPv6len)}
copy(ifma.IP, sa.Addr[:])
// NOTE: KAME based IPv6 protcol stack usually embeds
// the interface index in the interface-local or
// link-local address as the kernel-internal form.
if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
ifma.IP[2], ifma.IP[3] = 0, 0
}
return &ifma, nil
default:
return nil, nil
}
return ifmat, nil
}
......@@ -29,35 +29,34 @@ func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
if err != nil {
return nil, err
}
ifmat = append(ifmat, ifma...)
if ifma != nil {
ifmat = append(ifmat, ifma)
}
}
}
}
return ifmat, nil
}
func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
sas, err := syscall.ParseRoutingSockaddr(m)
if err != nil {
return nil, os.NewSyscallError("route sockaddr", err)
}
var ifmat []Addr
for _, sa := range sas {
switch sa := sa.(type) {
case *syscall.SockaddrInet4:
ifma := &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}
ifmat = append(ifmat, ifma.toAddr())
case *syscall.SockaddrInet6:
ifma := &IPAddr{IP: make(IP, IPv6len)}
copy(ifma.IP, sa.Addr[:])
// NOTE: KAME based IPv6 protocol stack usually embeds
// the interface index in the interface-local or link-
// local address as the kernel-internal form.
if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
ifma.IP[2], ifma.IP[3] = 0, 0
}
ifmat = append(ifmat, ifma.toAddr())
switch sa := sas[syscall.RTAX_IFA].(type) {
case *syscall.SockaddrInet4:
return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil
case *syscall.SockaddrInet6:
ifma := IPAddr{IP: make(IP, IPv6len)}
copy(ifma.IP, sa.Addr[:])
// NOTE: KAME based IPv6 protcol stack usually embeds
// the interface index in the interface-local or
// link-local address as the kernel-internal form.
if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
ifma.IP[2], ifma.IP[3] = 0, 0
}
return &ifma, nil
default:
return nil, nil
}
return ifmat, nil
}
......@@ -132,7 +132,7 @@ func (ip IP) IsMulticast() bool {
return ip[0] == 0xff
}
// IsInterfaceLinkLocalMulticast returns true if ip is
// IsInterfaceLocalMulticast returns true if ip is
// an interface-local multicast address.
func (ip IP) IsInterfaceLocalMulticast() bool {
return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x01
......
......@@ -33,7 +33,7 @@ func ExpandEnv(s string) string {
return Expand(s, Getenv)
}
// isSpellSpecialVar reports whether the character identifies a special
// isShellSpecialVar reports whether the character identifies a special
// shell variable such as $*.
func isShellSpecialVar(c uint8) bool {
switch c {
......@@ -48,7 +48,7 @@ func isAlphaNum(c uint8) bool {
return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
}
// getName returns the name that begins the string and the number of bytes
// getShellName returns the name that begins the string and the number of bytes
// consumed to extract it. If the name is enclosed in {}, it's part of a ${}
// expansion and two more bytes are needed than the length of the name.
func getShellName(s string) (string, int) {
......
......@@ -24,6 +24,9 @@ TEXT ·signal_disable(SB),NOSPLIT,$0
TEXT ·signal_enable(SB),NOSPLIT,$0
JMP runtime·signal_enable(SB)
TEXT ·signal_ignore(SB),NOSPLIT,$0
JMP runtime·signal_ignore(SB)
TEXT ·signal_recv(SB),NOSPLIT,$0
JMP runtime·signal_recv(SB)
......@@ -28,9 +28,55 @@ func (h *handler) set(sig int) {
h.mask[sig/32] |= 1 << uint(sig&31)
}
func (h *handler) clear(sig int) {
h.mask[sig/32] &^= 1 << uint(sig&31)
}
// Stop relaying the signals, sigs, to any channels previously registered to
// receive them and either reset the signal handlers to their original values
// (action=disableSignal) or ignore the signals (action=ignoreSignal).
func cancel(sigs []os.Signal, action func(int)) {
handlers.Lock()
defer handlers.Unlock()
remove := func(n int) {
var zerohandler handler
for c, h := range handlers.m {
if h.want(n) {
handlers.ref[n]--
h.clear(n)
if h.mask == zerohandler.mask {
delete(handlers.m, c)
}
}
}
action(n)
}
if len(sigs) == 0 {
for n := 0; n < numSig; n++ {
remove(n)
}
} else {
for _, s := range sigs {
remove(signum(s))
}
}
}
// Ignore causes the provided signals to be ignored. If they are received by
// the program, nothing will happen. Ignore undoes the effect of any prior
// calls to Notify for the provided signals.
// If no signals are provided, all incoming signals will be ignored.
func Ignore(sig ...os.Signal) {
cancel(sig, ignoreSignal)
}
// Notify causes package signal to relay incoming signals to c.
// If no signals are listed, all incoming signals will be relayed to c.
// Otherwise, just the listed signals will.
// If no signals are provided, all incoming signals will be relayed to c.
// Otherwise, just the provided signals will.
//
// Package signal will not block sending to c: the caller must ensure
// that c has sufficient buffer space to keep up with the expected
......@@ -85,6 +131,13 @@ func Notify(c chan<- os.Signal, sig ...os.Signal) {
}
}
// Reset undoes the effect of any prior calls to Notify for the provided
// signals.
// If no signals are provided, all signal handlers will be reset.
func Reset(sig ...os.Signal) {
cancel(sig, disableSignal)
}
// Stop causes package signal to stop relaying incoming signals to c.
// It undoes the effect of all prior calls to Notify using c.
// When Stop returns, it is guaranteed that c will receive no more signals.
......
......@@ -14,6 +14,7 @@ var sigtab = make(map[os.Signal]int)
// In sig.s; jumps to runtime.
func signal_disable(uint32)
func signal_enable(uint32)
func signal_ignore(uint32)
func signal_recv() string
func init() {
......@@ -53,3 +54,7 @@ func enableSignal(sig int) {
func disableSignal(sig int) {
signal_disable(uint32(sig))
}
func ignoreSignal(sig int) {
signal_ignore(uint32(sig))
}
......@@ -109,6 +109,72 @@ func TestStress(t *testing.T) {
time.Sleep(10 * time.Millisecond)
}
func testCancel(t *testing.T, ignore bool) {
// Send SIGWINCH. By default this signal should be ignored.
syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
time.Sleep(100 * time.Millisecond)
// Ask to be notified on c1 when a SIGWINCH is received.
c1 := make(chan os.Signal, 1)
Notify(c1, syscall.SIGWINCH)
defer Stop(c1)
// Ask to be notified on c2 when a SIGHUP is received.
c2 := make(chan os.Signal, 1)
Notify(c2, syscall.SIGHUP)
defer Stop(c2)
// Send this process a SIGWINCH and wait for notification on c1.
syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
waitSig(t, c1, syscall.SIGWINCH)
// Send this process a SIGHUP and wait for notification on c2.
syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
waitSig(t, c2, syscall.SIGHUP)
// Ignore, or reset the signal handlers for, SIGWINCH and SIGHUP.
if ignore {
Ignore(syscall.SIGWINCH, syscall.SIGHUP)
} else {
Reset(syscall.SIGWINCH, syscall.SIGHUP)
}
// Send this process a SIGWINCH. It should be ignored.
syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
// If ignoring, Send this process a SIGHUP. It should be ignored.
if ignore {
syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
}
select {
case s := <-c1:
t.Fatalf("unexpected signal %v", s)
case <-time.After(100 * time.Millisecond):
// nothing to read - good
}
select {
case s := <-c2:
t.Fatalf("unexpected signal %v", s)
case <-time.After(100 * time.Millisecond):
// nothing to read - good
}
// Reset the signal handlers for all signals.
Reset()
}
// Test that Reset cancels registration for listed signals on all channels.
func TestReset(t *testing.T) {
testCancel(t, false)
}
// Test that Ignore cancels registration for listed signals on all channels.
func TestIgnore(t *testing.T) {
testCancel(t, true)
}
var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop")
// Test that Stop cancels the channel's registrations.
......
......@@ -14,6 +14,7 @@ import (
// In assembly.
func signal_disable(uint32)
func signal_enable(uint32)
func signal_ignore(uint32)
func signal_recv() uint32
func loop() {
......@@ -51,3 +52,7 @@ func enableSignal(sig int) {
func disableSignal(sig int) {
signal_disable(uint32(sig))
}
func ignoreSignal(sig int) {
signal_ignore(uint32(sig))
}
......@@ -37,3 +37,31 @@ func ExampleRel() {
// "/b/c": "../b/c" <nil>
// "./b/c": "" Rel: can't make b/c relative to /a
}
func ExampleSplit() {
paths := []string{
"/home/arnie/amelia.jpg",
"/mnt/photos/",
"rabbit.jpg",
"/usr/local//go",
}
fmt.Println("On Unix:")
for _, p := range paths {
dir, file := filepath.Split(p)
fmt.Printf("input: %q\n\tdir: %q\n\tfile: %q\n", p, dir, file)
}
// Output:
// On Unix:
// input: "/home/arnie/amelia.jpg"
// dir: "/home/arnie/"
// file: "amelia.jpg"
// input: "/mnt/photos/"
// dir: "/mnt/photos/"
// file: ""
// input: "rabbit.jpg"
// dir: ""
// file: "rabbit.jpg"
// input: "/usr/local//go"
// dir: "/usr/local//"
// file: "go"
}
......@@ -1659,7 +1659,8 @@ const (
func bucketOf(ktyp, etyp *rtype) *rtype {
// See comment on hmap.overflow in ../runtime/hashmap.go.
var kind uint8
if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 {
if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 &&
ktyp.size <= maxKeySize && etyp.size <= maxValSize {
kind = kindNoPointers
}
......
......@@ -114,7 +114,7 @@ type hmap struct {
oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated)
// If both key and value do not contain pointers, then we mark bucket
// If both key and value do not contain pointers and are inline, then we mark bucket
// type as containing no pointers. This avoids scanning such maps.
// However, bmap.overflow is a pointer. In order to keep overflow buckets
// alive, we store pointers to all overflow buckets in hmap.overflow.
......
......@@ -13,6 +13,24 @@ package runtime
import "unsafe"
//go:linkname runtime_debug_WriteHeapDump runtime/debug.WriteHeapDump
func runtime_debug_WriteHeapDump(fd uintptr) {
semacquire(&worldsema, false)
gp := getg()
gp.m.preemptoff = "write heap dump"
systemstack(stoptheworld)
systemstack(func() {
writeheapdump_m(fd)
})
gp.m.preemptoff = ""
gp.m.locks++
semrelease(&worldsema)
systemstack(starttheworld)
gp.m.locks--
}
const (
fieldKindEol = 0
fieldKindPtr = 1
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -515,6 +515,61 @@ func TestMapStringBytesLookup(t *testing.T) {
}
}
func TestMapLargeKeyNoPointer(t *testing.T) {
const (
I = 1000
N = 64
)
type T [N]int
m := make(map[T]int)
for i := 0; i < I; i++ {
var v T
for j := 0; j < N; j++ {
v[j] = i + j
}
m[v] = i
}
runtime.GC()
for i := 0; i < I; i++ {
var v T
for j := 0; j < N; j++ {
v[j] = i + j
}
if m[v] != i {
t.Fatalf("corrupted map: want %+v, got %+v", i, m[v])
}
}
}
func TestMapLargeValNoPointer(t *testing.T) {
const (
I = 1000
N = 64
)
type T [N]int
m := make(map[int]T)
for i := 0; i < I; i++ {
var v T
for j := 0; j < N; j++ {
v[j] = i + j
}
m[i] = v
}
runtime.GC()
for i := 0; i < I; i++ {
var v T
for j := 0; j < N; j++ {
v[j] = i + j
}
v1 := m[i]
for j := 0; j < N; j++ {
if v1[j] != v[j] {
t.Fatalf("corrupted map: want %+v, got %+v", v, v1)
}
}
}
}
func benchmarkMapPop(b *testing.B, n int) {
m := map[int]int{}
for i := 0; i < b.N; i++ {
......
......@@ -82,6 +82,12 @@ const (
typeShift = 2
)
// Information from the compiler about the layout of stack frames.
type bitvector struct {
n int32 // # of bits
bytedata *uint8
}
// addb returns the byte pointer p+n.
//go:nowritebarrier
func addb(p *byte, n uintptr) *byte {
......
......@@ -2,14 +2,63 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Per-P malloc cache for small objects.
//
// See malloc.h for an overview.
package runtime
import "unsafe"
// Per-thread (in Go, per-P) cache for small objects.
// No locking needed because it is per-thread (per-P).
type mcache struct {
// The following members are accessed on every malloc,
// so they are grouped here for better caching.
next_sample int32 // trigger heap sample after allocating this many bytes
local_cachealloc intptr // bytes allocated (or freed) from cache since last lock of heap
// Allocator cache for tiny objects w/o pointers.
// See "Tiny allocator" comment in malloc.go.
tiny unsafe.Pointer
tinyoffset uintptr
local_tinyallocs uintptr // number of tiny allocs not counted in other stats
// The rest is not accessed on every malloc.
alloc [_NumSizeClasses]*mspan // spans to allocate from
stackcache [_NumStackOrders]stackfreelist
sudogcache *sudog
// Local allocator stats, flushed during GC.
local_nlookup uintptr // number of pointer lookups
local_largefree uintptr // bytes freed for large objects (>maxsmallsize)
local_nlargefree uintptr // number of frees for large objects (>maxsmallsize)
local_nsmallfree [_NumSizeClasses]uintptr // number of frees for small objects (<=maxsmallsize)
}
// A gclink is a node in a linked list of blocks, like mlink,
// but it is opaque to the garbage collector.
// The GC does not trace the pointers during collection,
// and the compiler does not emit write barriers for assignments
// of gclinkptr values. Code should store references to gclinks
// as gclinkptr, not as *gclink.
type gclink struct {
next gclinkptr
}
// A gclinkptr is a pointer to a gclink, but it is opaque
// to the garbage collector.
type gclinkptr uintptr
// ptr returns the *gclink form of p.
// The result should be used for accessing fields, not stored
// in other data structures.
func (p gclinkptr) ptr() *gclink {
return (*gclink)(unsafe.Pointer(p))
}
type stackfreelist struct {
list gclinkptr // linked list of free stacks
size uintptr // total size of stacks in list
}
// dummy MSpan that contains no free objects.
var emptymspan mspan
......
......@@ -12,6 +12,14 @@
package runtime
// Central list of free objects of a given size.
type mcentral struct {
lock mutex
sizeclass int32
nonempty mspan // list of spans with a free object
empty mspan // list of spans with no free objects (or cached in an mcache)
}
// Initialize a single central free list.
func mCentral_Init(c *mcentral, sizeclass int32) {
c.sizeclass = sizeclass
......
......@@ -8,6 +8,14 @@ package runtime
import "unsafe"
type finblock struct {
alllink *finblock
next *finblock
cnt int32
_ int32
fin [(_FinBlockSize - 2*ptrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer
}
var finlock mutex // protects the following variables
var fing *g // goroutine that runs finalizers
var finq *finblock // list of finalizers that are to be executed
......@@ -17,6 +25,15 @@ var fingwait bool
var fingwake bool
var allfin *finblock // list of all blocks
// NOTE: Layout known to queuefinalizer.
type finalizer struct {
fn *funcval // function to call
arg unsafe.Pointer // ptr to object
nret uintptr // bytes of return values from fn
fint *_type // type of first argument of fn
ot *ptrtype // type of ptr to object
}
var finalizer1 = [...]byte{
// Each Finalizer is 5 words, ptr ptr uintptr ptr ptr.
// Each byte describes 4 words.
......
......@@ -10,6 +10,34 @@ package runtime
import "unsafe"
// FixAlloc is a simple free-list allocator for fixed size objects.
// Malloc uses a FixAlloc wrapped around sysAlloc to manages its
// MCache and MSpan objects.
//
// Memory returned by FixAlloc_Alloc is not zeroed.
// The caller is responsible for locking around FixAlloc calls.
// Callers can keep state in the object but the first word is
// smashed by freeing and reallocating.
type fixalloc struct {
size uintptr
first unsafe.Pointer // go func(unsafe.pointer, unsafe.pointer); f(arg, p) called first time p is returned
arg unsafe.Pointer
list *mlink
chunk *byte
nchunk uint32
inuse uintptr // in-use bytes now
stat *uint64
}
// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).)
// Since assignments to mlink.next will result in a write barrier being preformed
// this can not be used by some of the internal GC structures. For example when
// the sweeper is placing an unmarked object on the free list it does not want the
// write barrier to be called since that could result in the object being reachable.
type mlink struct {
next *mlink
}
// Initialize f to allocate objects of the given size,
// using the allocator to obtain chunks of memory.
func fixAlloc_Init(f *fixalloc, size uintptr, first func(unsafe.Pointer, unsafe.Pointer), arg unsafe.Pointer, stat *uint64) {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -27,8 +27,15 @@
package runtime
//var class_to_size [_NumSizeClasses]int32
//var class_to_allocnpages [_NumSizeClasses]int32
// Size classes. Computed and initialized by InitSizes.
//
// SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
// 1 <= sizeclass < NumSizeClasses, for n.
// Size class 0 is reserved to mean "not small".
//
// class_to_size[i] = largest size in class i
// class_to_allocnpages[i] = number of pages to allocate when
// making new objects in class i
// The SizeToClass lookup is implemented using two arrays,
// one mapping sizes <= 1024 to their class and one mapping
......@@ -38,8 +45,11 @@ package runtime
// are 128-aligned, so the second array is indexed by the
// size divided by 128 (rounded up). The arrays are filled in
// by InitSizes.
//var size_to_class8 [1024/8 + 1]int8
//var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8
var class_to_size [_NumSizeClasses]int32
var class_to_allocnpages [_NumSizeClasses]int32
var size_to_class8 [1024/8 + 1]int8
var size_to_class128 [(_MaxSmallSize-1024)/128 + 1]int8
func sizeToClass(size int32) int32 {
if size > _MaxSmallSize {
......
This diff is collapsed.
This diff is collapsed.
......@@ -118,3 +118,6 @@ func sigenable(sig uint32) {
func sigdisable(sig uint32) {
}
func sigignore(sig uint32) {
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment