]> Cypherpunks repositories - gostls13.git/commitdiff
all: merge NaCl branch (part 1)
authorDave Cheney <dave@cheney.net>
Tue, 25 Feb 2014 14:47:42 +0000 (09:47 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 25 Feb 2014 14:47:42 +0000 (09:47 -0500)
See golang.org/s/go13nacl for design overview.

This CL is the mostly mechanical changes from rsc's Go 1.2 based NaCl branch, specifically 39cb35750369 to 500771b477cf from https://code.google.com/r/rsc-go13nacl. This CL does not include working NaCl support, there are probably two or three more large merges to come.

CL 15750044 is not included as it involves more invasive changes to the linker which will need to be merged separately.

The exact change lists included are

15050047: syscall: support for Native Client
15360044: syscall: unzip implementation for Native Client
15370044: syscall: Native Client SRPC implementation
15400047: cmd/dist, cmd/go, go/build, test: support for Native Client
15410048: runtime: support for Native Client
15410049: syscall: file descriptor table for Native Client
15410050: syscall: in-memory file system for Native Client
15440048: all: update +build lines for Native Client port
15540045: cmd/6g, cmd/8g, cmd/gc: support for Native Client
15570045: os: support for Native Client
15680044: crypto/..., hash/crc32, reflect, sync/atomic: support for amd64p32
15690044: net: support for Native Client
15690048: runtime: support for fake time like on Go Playground
15690051: build: disable various tests on Native Client

LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/68150047

133 files changed:
src/cmd/5g/galign.c
src/cmd/6g/cgen.c
src/cmd/6g/galign.c
src/cmd/6g/gg.h
src/cmd/6g/ggen.c
src/cmd/6g/gsubr.c
src/cmd/6g/prog.c
src/cmd/6g/reg.c
src/cmd/8g/galign.c
src/cmd/8g/gg.h
src/cmd/8g/ggen.c
src/cmd/dist/build.c
src/cmd/gc/align.c
src/cmd/gc/builtin.c
src/cmd/gc/go.h
src/cmd/gc/lex.c
src/cmd/gc/obj.c
src/cmd/gc/pgen.c
src/cmd/gc/reflect.c
src/cmd/gc/runtime.go
src/cmd/gc/walk.c
src/cmd/go/build.go
src/cmd/go/run.go
src/cmd/go/signal_unix.go
src/cmd/go/test.go
src/cmd/go/testflag.go
src/pkg/crypto/md5/md5block_amd64p32.s [new file with mode: 0644]
src/pkg/crypto/md5/md5block_decl.go
src/pkg/crypto/rand/rand_unix.go
src/pkg/crypto/rc4/rc4_amd64p32.s [new file with mode: 0644]
src/pkg/crypto/rc4/rc4_asm.go
src/pkg/crypto/rc4/rc4_ref.go
src/pkg/crypto/sha1/sha1block_amd64p32.s [new file with mode: 0644]
src/pkg/crypto/sha1/sha1block_decl.go
src/pkg/crypto/x509/root_unix.go
src/pkg/go/build/build.go
src/pkg/go/build/deps_test.go
src/pkg/go/build/syslist.go
src/pkg/hash/crc32/crc32_amd64p32.s [new file with mode: 0644]
src/pkg/hash/crc32/crc32_amd64x.go [moved from src/pkg/hash/crc32/crc32_amd64.go with 96% similarity]
src/pkg/log/syslog/syslog.go
src/pkg/log/syslog/syslog_test.go
src/pkg/log/syslog/syslog_unix.go
src/pkg/mime/type_unix.go
src/pkg/net/conn_test.go
src/pkg/net/dnsclient_unix.go
src/pkg/net/dnsconfig_unix.go
src/pkg/net/fd_poll_nacl.go [new file with mode: 0644]
src/pkg/net/fd_unix.go
src/pkg/net/file_test.go
src/pkg/net/file_unix.go
src/pkg/net/interface_stub.go
src/pkg/net/ipraw_test.go
src/pkg/net/iprawsock_posix.go
src/pkg/net/ipsock_posix.go
src/pkg/net/lookup_unix.go
src/pkg/net/multicast_test.go
src/pkg/net/net_test.go
src/pkg/net/port_unix.go
src/pkg/net/sendfile_stub.go
src/pkg/net/sock_bsd.go
src/pkg/net/sock_posix.go
src/pkg/net/sockopt_bsd.go
src/pkg/net/sockopt_posix.go
src/pkg/net/sockoptip_bsd.go
src/pkg/net/sockoptip_posix.go
src/pkg/net/sys_cloexec.go
src/pkg/net/tcpsock_posix.go
src/pkg/net/tcpsockopt_posix.go
src/pkg/net/tcpsockopt_unix.go
src/pkg/net/udpsock_posix.go
src/pkg/net/unixsock_posix.go
src/pkg/os/dir_unix.go
src/pkg/os/error_unix.go
src/pkg/os/exec/lp_unix.go
src/pkg/os/exec_posix.go
src/pkg/os/exec_unix.go
src/pkg/os/file_posix.go
src/pkg/os/file_unix.go
src/pkg/os/path_unix.go
src/pkg/os/pipe_bsd.go
src/pkg/os/signal/sig.s
src/pkg/os/signal/signal_unix.go
src/pkg/os/stat_nacl.go [new file with mode: 0644]
src/pkg/os/sys_bsd.go
src/pkg/path/filepath/path_unix.go
src/pkg/reflect/asm_amd64p32.s [new file with mode: 0644]
src/pkg/reflect/type.go
src/pkg/runtime/arch_386.h
src/pkg/runtime/arch_amd64.h
src/pkg/runtime/arch_amd64p32.h [new file with mode: 0644]
src/pkg/runtime/arch_arm.h
src/pkg/runtime/mem_linux.c
src/pkg/runtime/mem_nacl.c [new file with mode: 0644]
src/pkg/runtime/mgc0.c
src/pkg/runtime/mheap.c
src/pkg/runtime/mknacl.sh [new file with mode: 0644]
src/pkg/runtime/netpoll.goc
src/pkg/runtime/netpoll_nacl.c [new file with mode: 0644]
src/pkg/runtime/os_nacl.c [new file with mode: 0644]
src/pkg/runtime/os_nacl.h [new file with mode: 0644]
src/pkg/runtime/runtime.h
src/pkg/runtime/signal_386.c
src/pkg/runtime/signal_nacl_386.h [new file with mode: 0644]
src/pkg/runtime/signal_nacl_amd64p32.h [new file with mode: 0644]
src/pkg/runtime/signals_nacl.h [new file with mode: 0644]
src/pkg/runtime/sys_x86.c
src/pkg/runtime/syscall_nacl.h [new file with mode: 0644]
src/pkg/runtime/traceback_x86.c
src/pkg/runtime/vlrt_386.c
src/pkg/runtime/vlrt_arm.c
src/pkg/sync/atomic/asm_amd64p32.s [new file with mode: 0644]
src/pkg/sync/atomic/atomic_test.go
src/pkg/syscall/asm_nacl_386.s [new file with mode: 0644]
src/pkg/syscall/asm_nacl_amd64p32.s [new file with mode: 0644]
src/pkg/syscall/env_unix.go
src/pkg/syscall/fd_nacl.go [new file with mode: 0644]
src/pkg/syscall/fs_nacl.go [new file with mode: 0644]
src/pkg/syscall/mkall.sh
src/pkg/syscall/mksyscall.pl
src/pkg/syscall/srpc_nacl.go [new file with mode: 0644]
src/pkg/syscall/syscall_nacl.go [new file with mode: 0644]
src/pkg/syscall/syscall_nacl_386.go [new file with mode: 0644]
src/pkg/syscall/syscall_nacl_amd64p32.go [new file with mode: 0644]
src/pkg/syscall/tables_nacl.go [new file with mode: 0644]
src/pkg/syscall/time_nacl_386.s [new file with mode: 0644]
src/pkg/syscall/time_nacl_amd64p32.s [new file with mode: 0644]
src/pkg/syscall/unzip_nacl.go [new file with mode: 0644]
src/pkg/syscall/zsyscall_nacl_386.go [new file with mode: 0644]
src/pkg/syscall/zsyscall_nacl_amd64p32.go [new file with mode: 0644]
src/pkg/time/sys_unix.go
src/pkg/time/zoneinfo_unix.go
test/run.go

index 62f435e0e35a4b80c06986b2b5f649e40b0826a4..14d323fa7eff2a92d92896d41c137e383625f6f3 100644 (file)
@@ -29,6 +29,7 @@ betypeinit(void)
 {
        widthptr = 4;
        widthint = 4;
+       widthreg = 4;
 
        zprog.link = P;
        zprog.as = AGOK;
index 5afa25e4032b62b2617b70c2304e17d857f88716..e1b5d1140ee8a5d57553b2ddf4ccfdccfa23b9fa 100644 (file)
@@ -1417,23 +1417,23 @@ sgen(Node *n, Node *ns, int64 w)
                // reverse direction
                gins(ASTD, N, N);               // set direction flag
                if(c > 0) {
-                       gconreg(AADDQ, w-1, D_SI);
-                       gconreg(AADDQ, w-1, D_DI);
+                       gconreg(addptr, w-1, D_SI);
+                       gconreg(addptr, w-1, D_DI);
 
-                       gconreg(AMOVQ, c, D_CX);
+                       gconreg(movptr, c, D_CX);
                        gins(AREP, N, N);       // repeat
                        gins(AMOVSB, N, N);     // MOVB *(SI)-,*(DI)-
                }
 
                if(q > 0) {
                        if(c > 0) {
-                               gconreg(AADDQ, -7, D_SI);
-                               gconreg(AADDQ, -7, D_DI);
+                               gconreg(addptr, -7, D_SI);
+                               gconreg(addptr, -7, D_DI);
                        } else {
-                               gconreg(AADDQ, w-8, D_SI);
-                               gconreg(AADDQ, w-8, D_DI);
+                               gconreg(addptr, w-8, D_SI);
+                               gconreg(addptr, w-8, D_DI);
                        }
-                       gconreg(AMOVQ, q, D_CX);
+                       gconreg(movptr, q, D_CX);
                        gins(AREP, N, N);       // repeat
                        gins(AMOVSQ, N, N);     // MOVQ *(SI)-,*(DI)-
                }
@@ -1442,7 +1442,7 @@ sgen(Node *n, Node *ns, int64 w)
        } else {
                // normal direction
                if(q >= 4) {
-                       gconreg(AMOVQ, q, D_CX);
+                       gconreg(movptr, q, D_CX);
                        gins(AREP, N, N);       // repeat
                        gins(AMOVSQ, N, N);     // MOVQ *(SI)+,*(DI)+
                } else
index 3ea57d761640cefb81861f64e001a866dfa5167f..ec37ceb23308f764997c70c9397db8d360279d3d 100644 (file)
@@ -12,6 +12,12 @@ LinkArch*    thelinkarch = &linkamd64;
 
 vlong MAXWIDTH = 1LL<<50;
 
+int    addptr = AADDQ;
+int    movptr = AMOVQ;
+int    leaptr = ALEAQ;
+int    stosptr = ASTOSQ;
+int    cmpptr = ACMPQ;
+
 /*
  * go declares several platform-specific type aliases:
  * int, uint, float, and uintptr
@@ -29,6 +35,20 @@ betypeinit(void)
 {
        widthptr = 8;
        widthint = 8;
+       widthreg = 8;
+       if(strcmp(getgoarch(), "amd64p32") == 0) {
+               widthptr = 4;
+               widthint = 4;
+               addptr = AADDL;
+               movptr = AMOVL;
+               leaptr = ALEAL;
+               stosptr = ASTOSL;
+               cmpptr = ACMPL;
+               typedefs[0].sameas = TINT32;
+               typedefs[1].sameas = TUINT32;
+               typedefs[2].sameas = TUINT32;
+               
+       }
 
        zprog.link = P;
        zprog.as = AGOK;
index a3c5faf6c42075ca29854bca7893e4e59ef9964c..0bc8885cf3ee6ce7d796b928dff5cb892910b685 100644 (file)
@@ -21,8 +21,14 @@ EXTERN       Node*   deferproc;
 EXTERN Node*   deferreturn;
 EXTERN Node*   panicindex;
 EXTERN Node*   panicslice;
+EXTERN Node*   panicdiv;
 EXTERN Node*   throwreturn;
 extern vlong   unmappedzero;
+extern int     addptr;
+extern int     cmpptr;
+extern int     movptr;
+extern int     leaptr;
+extern int     stosptr;
 
 /*
  * ggen.c
index b5c28bb089b1607346bd5384809804299a02f039..8b0c287400391fe976d4117d8ce756e272bb972a 100644 (file)
@@ -180,17 +180,21 @@ ginscall(Node *f, int proc)
 
        case 1: // call in new proc (go)
        case 2: // deferred call (defer)
-               nodreg(&reg, types[TINT64], D_CX);
-               if(flag_largemodel) {
-                       regalloc(&r1, f->type, f);
+               nodconst(&con, types[TINT64], argsize(f->type));
+               if(widthptr == 4) {
+                       nodreg(&r1, types[TINT32], D_CX);
                        gmove(f, &r1);
-                       gins(APUSHQ, &r1, N);
-                       regfree(&r1);
+                       nodreg(&reg, types[TINT64], D_CX);
+                       nodconst(&r1, types[TINT64], 32);
+                       gins(ASHLQ, &r1, &reg);
+                       gins(AORQ, &con, &reg);
+                       gins(APUSHQ, &reg, N);
                } else {
-                       gins(APUSHQ, f, N);
+                       nodreg(&reg, types[TINT64], D_CX);
+                       gmove(f, &reg);
+                       gins(APUSHQ, &reg, N);
+                       gins(APUSHQ, &con, N);
                }
-               nodconst(&con, types[TINT32], argsize(f->type));
-               gins(APUSHQ, &con, N);
                if(proc == 1)
                        ginscall(newproc, 0);
                else {
@@ -198,8 +202,10 @@ ginscall(Node *f, int proc)
                                fatal("hasdefer=0 but has defer");
                        ginscall(deferproc, 0);
                }
+               nodreg(&reg, types[TINT64], D_CX);
                gins(APOPQ, N, &reg);
-               gins(APOPQ, N, &reg);
+               if(widthptr == 8)
+                       gins(APOPQ, N, &reg);
                if(proc == 2) {
                        nodreg(&reg, types[TINT64], D_AX);
                        gins(ATESTQ, &reg, &reg);
@@ -387,11 +393,11 @@ cgen_aret(Node *n, Node *res)
 
        if(res->op != OREGISTER) {
                regalloc(&nod2, types[tptr], res);
-               gins(ALEAQ, &nod1, &nod2);
-               gins(AMOVQ, &nod2, res);
+               gins(leaptr, &nod1, &nod2);
+               gins(movptr, &nod2, res);
                regfree(&nod2);
        } else
-               gins(ALEAQ, &nod1, res);
+               gins(leaptr, &nod1, res);
 }
 
 /*
@@ -634,6 +640,18 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
        }
 
        p2 = P;
+       if(nacl) {
+               // Native Client does not relay the divide-by-zero trap
+               // to the executing program, so we must insert a check
+               // for ourselves.
+               nodconst(&n4, t, 0);
+               gins(optoas(OCMP, t), &n3, &n4);
+               p1 = gbranch(optoas(ONE, t), T, +1);
+               if(panicdiv == N)
+                       panicdiv = sysfunc("panicdivide");
+               ginscall(panicdiv, -1);
+               patch(p1, pc);
+       }
        if(check) {
                nodconst(&n4, t, -1);
                gins(optoas(OCMP, t), &n3, &n4);
@@ -1045,10 +1063,10 @@ clearfat(Node *nl)
        agen(nl, &n1);
 
        savex(D_AX, &ax, &oldax, N, types[tptr]);
-       gconreg(AMOVQ, 0, D_AX);
+       gconreg(AMOVL, 0, D_AX);
 
        if(q >= 4) {
-               gconreg(AMOVQ, q, D_CX);
+               gconreg(movptr, q, D_CX);
                gins(AREP, N, N);       // repeat
                gins(ASTOSQ, N, N);     // STOQ AL,*(DI)+
        } else
@@ -1111,7 +1129,7 @@ expandchecks(Prog *firstp)
                p2->lineno = p->lineno;
                p1->pc = 9999;
                p2->pc = 9999;
-               p->as = ACMPQ;
+               p->as = cmpptr;
                p->to.type = D_CONST;
                p->to.offset = 0;
                p1->as = AJNE;
index f4861ceecf0f141d0030c27121a820c6186d3536..e8a62fb8a61fc32cf72937474f2c7b6e5678a620 100644 (file)
@@ -296,6 +296,11 @@ ginit(void)
 
        for(i=0; i<nelem(resvd); i++)
                reg[resvd[i]]++;
+       
+       if(nacl) {
+               reg[D_BP]++;
+               reg[D_R15]++;
+       }
 }
 
 void
@@ -305,6 +310,11 @@ gclean(void)
 
        for(i=0; i<nelem(resvd); i++)
                reg[resvd[i]]--;
+       if(nacl) {
+               reg[D_BP]--;
+               reg[D_R15]--;
+       }
+
 
        for(i=D_AX; i<=D_R15; i++)
                if(reg[i])
@@ -520,7 +530,16 @@ gconreg(int as, vlong c, int reg)
 {
        Node nr;
 
-       nodreg(&nr, types[TINT64], reg);
+       switch(as) {
+       case AADDL:
+       case AMOVL:
+       case ALEAL:
+               nodreg(&nr, types[TINT32], reg);
+               break;
+       default:
+               nodreg(&nr, types[TINT64], reg);
+       }
+
        ginscon(as, c, &nr);
 }
 
@@ -533,10 +552,18 @@ ginscon(int as, vlong c, Node *n2)
 {
        Node n1, ntmp;
 
-       nodconst(&n1, types[TINT64], c);
+       switch(as) {
+       case AADDL:
+       case AMOVL:
+       case ALEAL:
+               nodconst(&n1, types[TINT32], c);
+               break;
+       default:
+               nodconst(&n1, types[TINT64], c);
+       }
 
        if(as != AMOVQ && (c < -(1LL<<31) || c >= 1LL<<31)) {
-               // cannot have 64-bit immediokate in ADD, etc.
+               // cannot have 64-bit immediate in ADD, etc.
                // instead, MOV into register first.
                regalloc(&ntmp, types[TINT64], N);
                gins(AMOVQ, &n1, &ntmp);
@@ -2040,7 +2067,7 @@ odot:
        for(i=1; i<o; i++) {
                if(oary[i] >= 0)
                        fatal("can't happen");
-               gins(AMOVQ, &n1, reg);
+               gins(movptr, &n1, reg);
                cgen_checknil(reg);
                n1.xoffset = -(oary[i]+1);
        }
@@ -2252,7 +2279,7 @@ oindex_const_sudo:
        if(reg->op == OEMPTY)
                regalloc(reg, types[tptr], N);
 
-       p1 = gins(AMOVQ, N, reg);
+       p1 = gins(movptr, N, reg);
        p1->from = *a;
 
        n2 = *reg;
index 76c9be14fc120e61e9ced78d8db6af7c59f02f0d..8fe759d79ab1a04bfe01dfc201b94024da8387c9 100644 (file)
@@ -143,6 +143,7 @@ static ProgInfo progtable[ALAST] = {
 
        [AJMP]=         {Jump | Break | KillCarry},
 
+       [ALEAL]=        {LeftAddr | RightWrite},
        [ALEAQ]=        {LeftAddr | RightWrite},
 
        [AMOVBLSX]=     {SizeL | LeftRead | RightWrite | Conv},
index 45bc4a2670cf5e3a3d29689561be2013477983e3..eadd1cadc25311e243210fd611b502f46f2260d3 100644 (file)
@@ -487,7 +487,7 @@ addmove(Reg *r, int bn, int rn, int f)
        // need to clean this up with wptr and
        // some of the defaults
        p1->as = AMOVL;
-       switch(v->etype) {
+       switch(simtype[(uchar)v->etype]) {
        default:
                fatal("unknown type %E", v->etype);
        case TINT8:
@@ -501,7 +501,6 @@ addmove(Reg *r, int bn, int rn, int f)
                break;
        case TINT64:
        case TUINT64:
-       case TUINTPTR:
        case TPTR64:
                p1->as = AMOVQ;
                break;
@@ -511,8 +510,6 @@ addmove(Reg *r, int bn, int rn, int f)
        case TFLOAT64:
                p1->as = AMOVSD;
                break;
-       case TINT:
-       case TUINT:
        case TINT32:
        case TUINT32:
        case TPTR32:
@@ -1088,6 +1085,8 @@ int
 BtoR(int32 b)
 {
        b &= 0xffffL;
+       if(nacl)
+               b &= ~((1<<(D_BP-D_AX)) | (1<<(D_R15-D_AX)));
        if(b == 0)
                return 0;
        return bitno(b) + D_AX;
index f8197c895ff85ec49519f67afd8d97431db81203..439e741553f60f847f684d2a4c479ad313e9cb36 100644 (file)
@@ -29,6 +29,7 @@ betypeinit(void)
 {
        widthptr = 4;
        widthint = 4;
+       widthreg = 4;
 
        zprog.link = P;
        zprog.as = AGOK;
index 3830f31d93a50cdc14c7b9bde5d271d7f7032309..8a2fcb67722f6675cfac2997a58084329bf43726 100644 (file)
@@ -29,6 +29,7 @@ EXTERN        Node*   deferproc;
 EXTERN Node*   deferreturn;
 EXTERN Node*   panicindex;
 EXTERN Node*   panicslice;
+EXTERN Node*   panicdiv;
 EXTERN Node*   throwreturn;
 EXTERN int     maxstksize;
 extern uint32  unmappedzero;
index b3e2665ca4e94fa7f87bdd7ecb585b548ee205ba..f761fa6b03e245ee13d9d290d9cd317761280d29 100644 (file)
@@ -664,6 +664,18 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
        gmove(&t2, &n1);
        gmove(&t1, ax);
        p2 = P;
+       if(nacl) {
+               // Native Client does not relay the divide-by-zero trap
+               // to the executing program, so we must insert a check
+               // for ourselves.
+               nodconst(&n4, t, 0);
+               gins(optoas(OCMP, t), &n1, &n4);
+               p1 = gbranch(optoas(ONE, t), T, +1);
+               if(panicdiv == N)
+                       panicdiv = sysfunc("panicdivide");
+               ginscall(panicdiv, -1);
+               patch(p1, pc);
+       }
        if(check) {
                nodconst(&n4, t, -1);
                gins(optoas(OCMP, t), &n1, &n4);
index dff0a6e11d4f5c6bb37700ac0cea6a7448c03a8c..e79b7188e0fa550cd649d89266c7844b75334197 100644 (file)
@@ -38,13 +38,14 @@ static void dopack(char*, char*, char**, int);
 static char *findgoversion(void);
 
 // The known architecture letters.
-static char *gochars = "568";
+static char *gochars = "5668";
 
 // The known architectures.
 static char *okgoarch[] = {
        // same order as gochars
        "arm",
        "amd64",
+       "amd64p32",
        "386",
 };
 
@@ -55,6 +56,7 @@ static char *okgoos[] = {
        "linux",
        "solaris",
        "freebsd",
+       "nacl",
        "netbsd",
        "openbsd",
        "plan9",
index 8e9677e75b6e73cc69647f6577411fd08bdb0c74..b809640e4227a71b610c4489039185a3e06f410b 100644 (file)
@@ -175,11 +175,11 @@ dowidth(Type *t)
        case TFLOAT64:
        case TCOMPLEX64:
                w = 8;
-               t->align = widthptr;
+               t->align = widthreg;
                break;
        case TCOMPLEX128:
                w = 16;
-               t->align = widthptr;
+               t->align = widthreg;
                break;
        case TPTR32:
                w = 4;
@@ -288,10 +288,10 @@ dowidth(Type *t)
                // compute their widths as side-effect.
                t1 = t->type;
                w = widstruct(t->type, *getthis(t1), 0, 0);
-               w = widstruct(t->type, *getinarg(t1), w, widthptr);
-               w = widstruct(t->type, *getoutarg(t1), w, widthptr);
+               w = widstruct(t->type, *getinarg(t1), w, widthreg);
+               w = widstruct(t->type, *getoutarg(t1), w, widthreg);
                t1->argwid = w;
-               if(w%widthptr)
+               if(w%widthreg)
                        warn("bad type %T %d\n", t1, w);
                t->align = 1;
                break;
index 4955231c20231a18e609b7078069754a0491bd46..1f4aed5baa404e856ac0c76f62a3f0d24f6896e4 100644 (file)
@@ -5,6 +5,7 @@ char *runtimeimport =
        "func @\"\".new (@\"\".typ·2 *byte) (? *any)\n"
        "func @\"\".panicindex ()\n"
        "func @\"\".panicslice ()\n"
+       "func @\"\".panicdivide ()\n"
        "func @\"\".throwreturn ()\n"
        "func @\"\".throwinit ()\n"
        "func @\"\".panicwrap (? string, ? string, ? string)\n"
index e5d12a83450f6c2ada2c2437ce01ce90d2eb936e..68ec37bee33d382b7f59427dc9811b12d06b3486 100644 (file)
@@ -950,6 +950,7 @@ EXTERN      Node*   curfn;
 
 EXTERN int     widthptr;
 EXTERN int     widthint;
+EXTERN int     widthreg;
 
 EXTERN Node*   typesw;
 EXTERN Node*   nblank;
@@ -982,6 +983,8 @@ EXTERN      int     writearchive;
 
 EXTERN Biobuf  bstdout;
 
+EXTERN int     nacl;
+
 /*
  *     y.tab.c
  */
index 2a817f3d9a5227fe9ff24b01d067bf738580518f..90def10b8205ee853af4b3d0aabdf921d91130a5 100644 (file)
@@ -258,8 +258,18 @@ main(int argc, char *argv[])
 
        goroot = getgoroot();
        goos = getgoos();
-       goarch = thestring;
+
+       // Allow GOARCH=thestring or GOARCH=thestringsuffix,
+       // but not other values.        
+       p = getgoarch();
+       if(strncmp(p, thestring, strlen(thestring)) != 0)
+               fatal("cannot use %cg with GOARCH=%s", thechar, p);
+       goarch = p;
        
+       nacl = strcmp(goos, "nacl") == 0;
+       if(nacl)
+               flag_largemodel = 1;
+
        setexp();
 
        outfile = nil;
@@ -779,7 +789,7 @@ importfile(Val *f, int line)
                        yyerror("import %s: not a go object file", file);
                        errorexit();
                }
-               q = smprint("%s %s %s %s", getgoos(), thestring, getgoversion(), expstring());
+               q = smprint("%s %s %s %s", getgoos(), getgoarch(), getgoversion(), expstring());
                if(strcmp(p+10, q) != 0) {
                        yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
                        errorexit();
index 635a30d4027e293c05f3e582d0e21c648afe48fd..c7315e0f76573392ac7cc443e03dce3ac5a32380 100644 (file)
@@ -47,7 +47,7 @@ dumpobj(void)
                Bwrite(bout, arhdr, sizeof arhdr);
                startobj = Boffset(bout);
        }
-       Bprint(bout, "go object %s %s %s %s\n", getgoos(), thestring, getgoversion(), expstring());
+       Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
        dumpexport();
        
        if(writearchive) {
index 62153cb52449ec5a3cf9c11448bdc873950a767f..1048a62cc8bb158f9f10b1d602e90aa90081dc3a 100644 (file)
@@ -426,7 +426,7 @@ allocauto(Prog* ptxt)
                }
                n->stkdelta = -stksize - n->xoffset;
        }
-       stksize = rnd(stksize, widthptr);
+       stksize = rnd(stksize, widthreg);
        stkptrsize = rnd(stkptrsize, widthptr);
        stkzerosize = rnd(stkzerosize, widthptr);
 
index 68b21772451c34dfed2b371fd6efd26173de2374..88ef57f409b3cff8f44fe29a4f036b49c2b0448f 100644 (file)
@@ -143,6 +143,11 @@ mapbucket(Type *t)
        overflowfield->sym = mal(sizeof(Sym)); // not important but needs to be set to give this type a name
        overflowfield->sym->name = "overflow";
        offset += widthptr;
+       
+       // The keys are padded to the native integer alignment.
+       // This is usually the same as widthptr; the exception (as usual) is nacl/amd64.
+       if(widthreg > widthptr)
+               offset += widthreg - widthptr;
 
        keysfield = typ(TFIELD);
        keysfield->type = typ(TARRAY);
index c65365f55ae05e9763df18f437679dcaa42915f3..9ea4a79fd3bbe11b906210d5d79c270c8ebec13b 100644 (file)
@@ -15,6 +15,7 @@ package PACKAGE
 func new(typ *byte) *any
 func panicindex()
 func panicslice()
+func panicdivide()
 func throwreturn()
 func throwinit()
 func panicwrap(string, string, string)
index 068e38cf3ba69f088a7fc8145abee533233674d4..717c771336c39bf847302377496c1ab659e05d4e 100644 (file)
@@ -1059,7 +1059,7 @@ walkexpr(Node **np, NodeList **init)
                switch(n->op) {
                case OMOD:
                case ODIV:
-                       if(widthptr > 4 || (et != TUINT64 && et != TINT64))
+                       if(widthreg >= 8 || (et != TUINT64 && et != TINT64))
                                goto ret;
                        if(et == TINT64)
                                strcpy(namebuf, "int64");
index dcc24d99c42979ca97afdeeef9c92571e93581b4..6c9b9f7e50369638f6daecbc1bbd9551ffa5a76b 100644 (file)
@@ -204,6 +204,9 @@ type stringsFlag []string
 func (v *stringsFlag) Set(s string) error {
        var err error
        *v, err = splitQuotedFields(s)
+       if *v == nil {
+               *v = []string{}
+       }
        return err
 }
 
index 8d42622b8660168c52f546d52a882f420f912013..b6449713dfa200deb8c38ac2fdddc9627051d553 100644 (file)
@@ -8,9 +8,27 @@ import (
        "fmt"
        "os"
        "os/exec"
+       "runtime"
        "strings"
 )
 
+var execCmd []string // -exec flag, for run and test
+
+func findExecCmd() []string {
+       if execCmd != nil {
+               return execCmd
+       }
+       execCmd = []string{} // avoid work the second time
+       if goos == runtime.GOOS && goarch == runtime.GOARCH {
+               return execCmd
+       }
+       path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
+       if err == nil {
+               execCmd = []string{path}
+       }
+       return execCmd
+}
+
 var cmdRun = &Command{
        UsageLine: "run [build flags] gofiles... [arguments...]",
        Short:     "compile and run Go program",
@@ -28,6 +46,7 @@ func init() {
        cmdRun.Run = runRun // break init loop
 
        addBuildFlags(cmdRun)
+       cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "")
 }
 
 func printStderr(args ...interface{}) (int, error) {
@@ -90,20 +109,20 @@ func runRun(cmd *Command, args []string) {
 // runProgram is the action for running a binary that has already
 // been compiled.  We ignore exit status.
 func (b *builder) runProgram(a *action) error {
+       cmdline := stringList(findExecCmd(), a.deps[0].target, a.args)
        if buildN || buildX {
-               b.showcmd("", "%s %s", a.deps[0].target, strings.Join(a.args, " "))
+               b.showcmd("", "%s", strings.Join(cmdline, " "))
                if buildN {
                        return nil
                }
        }
 
-       runStdin(a.deps[0].target, a.args)
+       runStdin(cmdline)
        return nil
 }
 
 // runStdin is like run, but connects Stdin.
-func runStdin(cmdargs ...interface{}) {
-       cmdline := stringList(cmdargs...)
+func runStdin(cmdline []string) {
        cmd := exec.Command(cmdline[0], cmdline[1:]...)
        cmd.Stdin = os.Stdin
        cmd.Stdout = os.Stdout
index 8faa7efa76e54723278354fe7cf939e8f9edf937..e86cd4652311ccdb851d7cfa72c596a6dbb2fdf9 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package main
 
index 26b7f87f48f5cb60a1d494e9b877be2d93a3597d..2da63ef04a2805405a1f6d1eaab75ba852a05391 100644 (file)
@@ -293,6 +293,8 @@ func runTest(cmd *Command, args []string) {
        var pkgArgs []string
        pkgArgs, testArgs = testFlags(args)
 
+       findExecCmd() // initialize cached result
+
        raceInit()
        pkgs := packagesForBuild(pkgArgs)
        if len(pkgs) == 0 {
@@ -835,7 +837,7 @@ func declareCoverVars(importPath string, files ...string) map[string]*CoverVar {
 
 // runTest is the action for running a test binary.
 func (b *builder) runTest(a *action) error {
-       args := stringList(a.deps[0].target, testArgs)
+       args := stringList(findExecCmd(), a.deps[0].target, testArgs)
        a.testOutput = new(bytes.Buffer)
 
        if buildN || buildX {
index aea81d8f83479c63606988fd0485fe0ba924c20c..69c33d39e66710b6e722b0bd0b5bc387da19d4b1 100644 (file)
@@ -77,6 +77,7 @@ var testFlagDefn = []*testFlagSpec{
        {name: "x", boolVar: &buildX},
        {name: "work", boolVar: &buildWork},
        {name: "gcflags"},
+       {name: "exec"},
        {name: "ldflags"},
        {name: "gccgoflags"},
        {name: "tags"},
@@ -154,6 +155,11 @@ func testFlags(args []string) (packageNames, passToTest []string) {
                        setBoolFlag(f.boolVar, value)
                case "p":
                        setIntFlag(&buildP, value)
+               case "exec":
+                       execCmd, err = splitQuotedFields(value)
+                       if err != nil {
+                               fatalf("invalid flag argument for -%s: %v", f.name, err)
+                       }
                case "gcflags":
                        buildGcflags, err = splitQuotedFields(value)
                        if err != nil {
diff --git a/src/pkg/crypto/md5/md5block_amd64p32.s b/src/pkg/crypto/md5/md5block_amd64p32.s
new file mode 100644 (file)
index 0000000..a78a3f6
--- /dev/null
@@ -0,0 +1,184 @@
+// Original source:
+//     http://www.zorinaq.com/papers/md5-amd64.html
+//     http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// Translated from Perl generating GNU assembly into
+// #defines generating 6a assembly by the Go Authors.
+//
+// Restrictions to make code safe for Native Client:
+// replace BP with R11, reloaded before use at return.
+// replace R15 with R11.
+
+#include "../../../cmd/ld/textflag.h"
+
+// MD5 optimized for AMD64.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+TEXT   Â·block(SB),NOSPLIT,$0-32
+       MOVL    dig+0(FP),      R11
+       MOVL    p+4(FP),        SI
+       MOVL    p_len+8(FP), DX
+       SHRQ    $6,             DX
+       SHLQ    $6,             DX
+
+       LEAQ    (SI)(DX*1),     DI
+       MOVL    (0*4)(R11),     AX
+       MOVL    (1*4)(R11),     BX
+       MOVL    (2*4)(R11),     CX
+       MOVL    (3*4)(R11),     DX
+
+       CMPQ    SI,             DI
+       JEQ     end
+
+loop:
+       MOVL    AX,             R12
+       MOVL    BX,             R13
+       MOVL    CX,             R14
+       MOVL    DX,             R11
+
+       MOVL    (0*4)(SI),      R8
+       MOVL    DX,             R9
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+       XORL    c, R9; \
+       LEAL    const(a)(R8*1), a; \
+       ANDL    b, R9; \
+       XORL d, R9; \
+       MOVL (index*4)(SI), R8; \
+       ADDL R9, a; \
+       ROLL $shift, a; \
+       MOVL c, R9; \
+       ADDL b, a
+
+       ROUND1(AX,BX,CX,DX, 1,0xd76aa478, 7);
+       ROUND1(DX,AX,BX,CX, 2,0xe8c7b756,12);
+       ROUND1(CX,DX,AX,BX, 3,0x242070db,17);
+       ROUND1(BX,CX,DX,AX, 4,0xc1bdceee,22);
+       ROUND1(AX,BX,CX,DX, 5,0xf57c0faf, 7);
+       ROUND1(DX,AX,BX,CX, 6,0x4787c62a,12);
+       ROUND1(CX,DX,AX,BX, 7,0xa8304613,17);
+       ROUND1(BX,CX,DX,AX, 8,0xfd469501,22);
+       ROUND1(AX,BX,CX,DX, 9,0x698098d8, 7);
+       ROUND1(DX,AX,BX,CX,10,0x8b44f7af,12);
+       ROUND1(CX,DX,AX,BX,11,0xffff5bb1,17);
+       ROUND1(BX,CX,DX,AX,12,0x895cd7be,22);
+       ROUND1(AX,BX,CX,DX,13,0x6b901122, 7);
+       ROUND1(DX,AX,BX,CX,14,0xfd987193,12);
+       ROUND1(CX,DX,AX,BX,15,0xa679438e,17);
+       ROUND1(BX,CX,DX,AX, 0,0x49b40821,22);
+
+       MOVL    (1*4)(SI),      R8
+       MOVL    DX,             R9
+       MOVL    DX,             R10
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+       NOTL    R9; \
+       LEAL    const(a)(R8*1),a; \
+       ANDL    b,              R10; \
+       ANDL    c,              R9; \
+       MOVL    (index*4)(SI),R8; \
+       ORL     R9,             R10; \
+       MOVL    c,              R9; \
+       ADDL    R10,            a; \
+       MOVL    c,              R10; \
+       ROLL    $shift, a; \
+       ADDL    b,              a
+
+       ROUND2(AX,BX,CX,DX, 6,0xf61e2562, 5);
+       ROUND2(DX,AX,BX,CX,11,0xc040b340, 9);
+       ROUND2(CX,DX,AX,BX, 0,0x265e5a51,14);
+       ROUND2(BX,CX,DX,AX, 5,0xe9b6c7aa,20);
+       ROUND2(AX,BX,CX,DX,10,0xd62f105d, 5);
+       ROUND2(DX,AX,BX,CX,15, 0x2441453, 9);
+       ROUND2(CX,DX,AX,BX, 4,0xd8a1e681,14);
+       ROUND2(BX,CX,DX,AX, 9,0xe7d3fbc8,20);
+       ROUND2(AX,BX,CX,DX,14,0x21e1cde6, 5);
+       ROUND2(DX,AX,BX,CX, 3,0xc33707d6, 9);
+       ROUND2(CX,DX,AX,BX, 8,0xf4d50d87,14);
+       ROUND2(BX,CX,DX,AX,13,0x455a14ed,20);
+       ROUND2(AX,BX,CX,DX, 2,0xa9e3e905, 5);
+       ROUND2(DX,AX,BX,CX, 7,0xfcefa3f8, 9);
+       ROUND2(CX,DX,AX,BX,12,0x676f02d9,14);
+       ROUND2(BX,CX,DX,AX, 0,0x8d2a4c8a,20);
+       MOVL    (5*4)(SI),      R8
+       MOVL    CX,             R9
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+       LEAL    const(a)(R8*1),a; \
+       MOVL    (index*4)(SI),R8; \
+       XORL    d,              R9; \
+       XORL    b,              R9; \
+       ADDL    R9,             a; \
+       ROLL    $shift,         a; \
+       MOVL    b,              R9; \
+       ADDL    b,              a
+
+       ROUND3(AX,BX,CX,DX, 8,0xfffa3942, 4);
+       ROUND3(DX,AX,BX,CX,11,0x8771f681,11);
+       ROUND3(CX,DX,AX,BX,14,0x6d9d6122,16);
+       ROUND3(BX,CX,DX,AX, 1,0xfde5380c,23);
+       ROUND3(AX,BX,CX,DX, 4,0xa4beea44, 4);
+       ROUND3(DX,AX,BX,CX, 7,0x4bdecfa9,11);
+       ROUND3(CX,DX,AX,BX,10,0xf6bb4b60,16);
+       ROUND3(BX,CX,DX,AX,13,0xbebfbc70,23);
+       ROUND3(AX,BX,CX,DX, 0,0x289b7ec6, 4);
+       ROUND3(DX,AX,BX,CX, 3,0xeaa127fa,11);
+       ROUND3(CX,DX,AX,BX, 6,0xd4ef3085,16);
+       ROUND3(BX,CX,DX,AX, 9, 0x4881d05,23);
+       ROUND3(AX,BX,CX,DX,12,0xd9d4d039, 4);
+       ROUND3(DX,AX,BX,CX,15,0xe6db99e5,11);
+       ROUND3(CX,DX,AX,BX, 2,0x1fa27cf8,16);
+       ROUND3(BX,CX,DX,AX, 0,0xc4ac5665,23);
+
+       MOVL    (0*4)(SI),      R8
+       MOVL    $0xffffffff,    R9
+       XORL    DX,             R9
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+       LEAL    const(a)(R8*1),a; \
+       ORL     b,              R9; \
+       XORL    c,              R9; \
+       ADDL    R9,             a; \
+       MOVL    (index*4)(SI),R8; \
+       MOVL    $0xffffffff,    R9; \
+       ROLL    $shift,         a; \
+       XORL    c,              R9; \
+       ADDL    b,              a
+       
+       ROUND4(AX,BX,CX,DX, 7,0xf4292244, 6);
+       ROUND4(DX,AX,BX,CX,14,0x432aff97,10);
+       ROUND4(CX,DX,AX,BX, 5,0xab9423a7,15);
+       ROUND4(BX,CX,DX,AX,12,0xfc93a039,21);
+       ROUND4(AX,BX,CX,DX, 3,0x655b59c3, 6);
+       ROUND4(DX,AX,BX,CX,10,0x8f0ccc92,10);
+       ROUND4(CX,DX,AX,BX, 1,0xffeff47d,15);
+       ROUND4(BX,CX,DX,AX, 8,0x85845dd1,21);
+       ROUND4(AX,BX,CX,DX,15,0x6fa87e4f, 6);
+       ROUND4(DX,AX,BX,CX, 6,0xfe2ce6e0,10);
+       ROUND4(CX,DX,AX,BX,13,0xa3014314,15);
+       ROUND4(BX,CX,DX,AX, 4,0x4e0811a1,21);
+       ROUND4(AX,BX,CX,DX,11,0xf7537e82, 6);
+       ROUND4(DX,AX,BX,CX, 2,0xbd3af235,10);
+       ROUND4(CX,DX,AX,BX, 9,0x2ad7d2bb,15);
+       ROUND4(BX,CX,DX,AX, 0,0xeb86d391,21);
+
+       ADDL    R12,    AX
+       ADDL    R13,    BX
+       ADDL    R14,    CX
+       ADDL    R11,    DX
+
+       ADDQ    $64,            SI
+       CMPQ    SI,             DI
+       JB      loop
+
+end:
+       MOVL    dig+0(FP),      R11
+       MOVL    AX,             (0*4)(R11)
+       MOVL    BX,             (1*4)(R11)
+       MOVL    CX,             (2*4)(R11)
+       MOVL    DX,             (3*4)(R11)
+       RET
index c4d6aaaf03a1e33b46feac4bfda30c3639ae69f1..d7956a6d203ee753bd3197650cc6a1aab9b0bde7 100644 (file)
@@ -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 amd64 386 arm
+// +build amd64 amd64p32 386 arm
 
 package md5
 
index 0fbd7eaf5794bab6492f4e84d894df833cf42bf6..1e741fda193b111eaa421f200291677538560439 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd plan9 solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris
 
 // Unix cryptographically secure pseudorandom number
 // generator.
diff --git a/src/pkg/crypto/rc4/rc4_amd64p32.s b/src/pkg/crypto/rc4/rc4_amd64p32.s
new file mode 100644 (file)
index 0000000..27d8495
--- /dev/null
@@ -0,0 +1,192 @@
+// Original source:
+//     http://www.zorinaq.com/papers/rc4-amd64.html
+//     http://www.zorinaq.com/papers/rc4-amd64.tar.bz2
+
+#include "../../../cmd/ld/textflag.h"
+
+// Local modifications:
+//
+// Transliterated from GNU to 6a assembly syntax by the Go authors.
+// The comments and spacing are from the original.
+//
+// The new EXTEND macros avoid a bad stall on some systems after 8-bit math.
+//
+// The original code accumulated 64 bits of key stream in an integer
+// register and then XOR'ed the key stream into the data 8 bytes at a time.
+// Modified to accumulate 128 bits of key stream into an XMM register
+// and then XOR the key stream into the data 16 bytes at a time.
+// Approximately doubles throughput.
+//
+// Converted to amd64p32.
+//
+// To make safe for Native Client, avoid use of BP, R15,
+// and two-register addressing modes.
+
+// NOTE: Changing EXTEND to a no-op makes the code run 1.2x faster on Core i5
+// but makes the code run 2.0x slower on Xeon.
+#define EXTEND(r) MOVBLZX r, r
+
+/*
+** RC4 implementation optimized for AMD64.
+**
+** Author: Marc Bevand <bevand_m (at) epita.fr>
+** Licence: I hereby disclaim the copyright on this code and place it
+** in the public domain.
+**
+** The code has been designed to be easily integrated into openssl:
+** the exported RC4() function can replace the actual implementations
+** openssl already contains. Please note that when linking with openssl,
+** it requires that sizeof(RC4_INT) == 8. So openssl must be compiled
+** with -DRC4_INT='unsigned long'.
+**
+** The throughput achieved by this code is about 320 MBytes/sec, on
+** a 1.8 GHz AMD Opteron (rev C0) processor.
+*/
+
+TEXT Â·xorKeyStream(SB),NOSPLIT,$0
+       MOVL    n+8(FP),        BX              // rbx = ARG(len)
+       MOVL    src+4(FP),      SI              // in = ARG(in)
+       MOVL    dst+0(FP),      DI              // out = ARG(out)
+       MOVL    state+12(FP),   R10             // d = ARG(data)
+       MOVL    i+16(FP),       AX
+       MOVBQZX 0(AX),          CX              // x = *xp
+       MOVL    j+20(FP),       AX
+       MOVBQZX 0(AX),          DX              // y = *yp
+
+       LEAQ    (SI)(BX*1),     R9              // limit = in+len
+
+l1:    CMPQ    SI,             R9              // cmp in with in+len
+       JGE     finished                        // jump if (in >= in+len)
+
+       INCB    CX
+       EXTEND(CX)
+       TESTL   $15,            CX
+       JZ      wordloop
+       LEAL    (R10)(CX*4), R12
+
+       MOVBLZX (R12),  AX
+
+       ADDB    AX,             DX              // y += tx
+       EXTEND(DX)
+       LEAL (R10)(DX*4), R11
+       MOVBLZX (R11),  BX              // ty = d[y]
+       MOVB    BX,             (R12)   // d[x] = ty
+       ADDB    AX,             BX              // val = ty+tx
+       EXTEND(BX)
+       LEAL (R10)(BX*4), R13
+       MOVB    AX,             (R11)   // d[y] = tx
+       MOVBLZX (R13),  R8              // val = d[val]
+       XORB    (SI),           R8              // xor 1 byte
+       MOVB    R8,             (DI)
+       INCQ    SI                              // in++
+       INCQ    DI                              // out++
+       JMP l1
+
+wordloop:
+       SUBQ    $16,            R9
+       CMPQ    SI,             R9
+       JGT     end
+
+start:
+       ADDQ    $16,            SI              // increment in
+       ADDQ    $16,            DI              // increment out
+
+       // Each KEYROUND generates one byte of key and
+       // inserts it into an XMM register at the given 16-bit index.
+       // The key state array is uint32 words only using the bottom
+       // byte of each word, so the 16-bit OR only copies 8 useful bits.
+       // We accumulate alternating bytes into X0 and X1, and then at
+       // the end we OR X1<<8 into X0 to produce the actual key.
+       //
+       // At the beginning of the loop, CX%16 == 0, so the 16 loads
+       // at state[CX], state[CX+1], ..., state[CX+15] can precompute
+       // (state+CX) as R12 and then become R12[0], R12[1], ... R12[15],
+       // without fear of the byte computation CX+15 wrapping around.
+       //
+       // The first round needs R12[0], the second needs R12[1], and so on.
+       // We can avoid memory stalls by starting the load for round n+1
+       // before the end of round n, using the LOAD macro.
+       LEAQ    (R10)(CX*4),    R12
+
+#define KEYROUND(xmm, load, off, r1, r2, index) \
+       LEAL (R10)(DX*4), R11; \
+       MOVBLZX (R11),  R8; \
+       MOVB    r1,             (R11); \
+       load((off+1), r2); \
+       MOVB    R8,             (off*4)(R12); \
+       ADDB    r1,             R8; \
+       EXTEND(R8); \
+       LEAL (R10)(R8*4), R14; \
+       PINSRW  $index, (R14), xmm
+
+#define LOAD(off, reg) \
+       MOVBLZX (off*4)(R12),   reg; \
+       ADDB    reg,            DX; \
+       EXTEND(DX)
+
+#define SKIP(off, reg)
+
+       LOAD(0, AX)
+       KEYROUND(X0, LOAD, 0, AX, BX, 0)
+       KEYROUND(X1, LOAD, 1, BX, AX, 0)
+       KEYROUND(X0, LOAD, 2, AX, BX, 1)
+       KEYROUND(X1, LOAD, 3, BX, AX, 1)
+       KEYROUND(X0, LOAD, 4, AX, BX, 2)
+       KEYROUND(X1, LOAD, 5, BX, AX, 2)
+       KEYROUND(X0, LOAD, 6, AX, BX, 3)
+       KEYROUND(X1, LOAD, 7, BX, AX, 3)
+       KEYROUND(X0, LOAD, 8, AX, BX, 4)
+       KEYROUND(X1, LOAD, 9, BX, AX, 4)
+       KEYROUND(X0, LOAD, 10, AX, BX, 5)
+       KEYROUND(X1, LOAD, 11, BX, AX, 5)
+       KEYROUND(X0, LOAD, 12, AX, BX, 6)
+       KEYROUND(X1, LOAD, 13, BX, AX, 6)
+       KEYROUND(X0, LOAD, 14, AX, BX, 7)
+       KEYROUND(X1, SKIP, 15, BX, AX, 7)
+       
+       ADDB    $16,            CX
+
+       PSLLQ   $8,             X1
+       PXOR    X1,             X0
+       MOVOU   -16(SI),        X2
+       PXOR    X0,             X2
+       MOVOU   X2,             -16(DI)
+
+       CMPQ    SI,             R9              // cmp in with in+len-16
+       JLE     start                           // jump if (in <= in+len-16)
+
+end:
+       DECB    CX
+       ADDQ    $16,            R9              // tmp = in+len
+
+       // handle the last bytes, one by one
+l2:    CMPQ    SI,             R9              // cmp in with in+len
+       JGE     finished                        // jump if (in >= in+len)
+
+       INCB    CX
+       EXTEND(CX)
+       LEAL (R10)(CX*4), R12
+       MOVBLZX (R12),  AX
+
+       ADDB    AX,             DX              // y += tx
+       EXTEND(DX)
+       LEAL (R10)(DX*4), R11
+       MOVBLZX (R11),  BX              // ty = d[y]
+       MOVB    BX,             (R12)   // d[x] = ty
+       ADDB    AX,             BX              // val = ty+tx
+       EXTEND(BX)
+       LEAL (R10)(BX*4), R13
+       MOVB    AX,             (R11)   // d[y] = tx
+       MOVBLZX (R13),  R8              // val = d[val]
+       XORB    (SI),           R8              // xor 1 byte
+       MOVB    R8,             (DI)
+       INCQ    SI                              // in++
+       INCQ    DI                              // out++
+       JMP l2
+
+finished:
+       MOVL    j+20(FP),       BX
+       MOVB    DX, 0(BX)
+       MOVL    i+16(FP),       AX
+       MOVB    CX, 0(AX)
+       RET
index c582a4488b85d98c09e3c5373fe2304659cbce6a..fc71b9a6fa2f50199eb95a4f3e361b500a82f009 100644 (file)
@@ -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 amd64 arm 386
+// +build amd64 amd64p32 arm 386
 
 package rc4
 
index bdf5e1db2ddf127801d7b182bacf0e08d726adf6..1ecce1a7fbcd457ed0a0be54bc39536937debebb 100644 (file)
@@ -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 !amd64,!arm,!386
+// +build !amd64,!amd64p32,!arm,!386
 
 package rc4
 
diff --git a/src/pkg/crypto/sha1/sha1block_amd64p32.s b/src/pkg/crypto/sha1/sha1block_amd64p32.s
new file mode 100644 (file)
index 0000000..3c589d9
--- /dev/null
@@ -0,0 +1,216 @@
+// Copyright 2013 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 "../../../cmd/ld/textflag.h"
+
+// SHA1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+//   - rounds 0-15 are type 1 and load data (ROUND1 macro).
+//   - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+//   - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+//   - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+//   - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+//
+// amd64p32 version.
+// To ensure safety for Native Client, avoids use of BP and R15
+// as well as two-register addressing modes.
+
+#define LOAD(index) \
+       MOVL    (index*4)(SI), R10; \
+       BSWAPL  R10; \
+       MOVL    R10, (index*4)(SP)
+
+#define SHUFFLE(index) \
+       MOVL    (((index)&0xf)*4)(SP), R10; \
+       XORL    (((index-3)&0xf)*4)(SP), R10; \
+       XORL    (((index-8)&0xf)*4)(SP), R10; \
+       XORL    (((index-14)&0xf)*4)(SP), R10; \
+       ROLL    $1, R10; \
+       MOVL    R10, (((index)&0xf)*4)(SP)
+
+#define FUNC1(a, b, c, d, e) \
+       MOVL    d, R9; \
+       XORL    c, R9; \
+       ANDL    b, R9; \
+       XORL    d, R9
+
+#define FUNC2(a, b, c, d, e) \
+       MOVL    b, R9; \
+       XORL    c, R9; \
+       XORL    d, R9
+
+#define FUNC3(a, b, c, d, e) \
+       MOVL    b, R8; \
+       ORL     c, R8; \
+       ANDL    d, R8; \
+       MOVL    b, R9; \
+       ANDL    c, R9; \
+       ORL     R8, R9
+       
+#define FUNC4 FUNC2
+
+#define MIX(a, b, c, d, e, const) \
+       ROLL    $30, b; \
+       ADDL    R9, e; \
+       MOVL    a, R8; \
+       ROLL    $5, R8; \
+       LEAL    const(e)(R10*1), e; \
+       ADDL    R8, e
+
+#define ROUND1(a, b, c, d, e, index) \
+       LOAD(index); \
+       FUNC1(a, b, c, d, e); \
+       MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND1x(a, b, c, d, e, index) \
+       SHUFFLE(index); \
+       FUNC1(a, b, c, d, e); \
+       MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND2(a, b, c, d, e, index) \
+       SHUFFLE(index); \
+       FUNC2(a, b, c, d, e); \
+       MIX(a, b, c, d, e, 0x6ED9EBA1)
+
+#define ROUND3(a, b, c, d, e, index) \
+       SHUFFLE(index); \
+       FUNC3(a, b, c, d, e); \
+       MIX(a, b, c, d, e, 0x8F1BBCDC)
+
+#define ROUND4(a, b, c, d, e, index) \
+       SHUFFLE(index); \
+       FUNC4(a, b, c, d, e); \
+       MIX(a, b, c, d, e, 0xCA62C1D6)
+
+TEXT Â·block(SB),NOSPLIT,$64-32
+       MOVL    dig+0(FP),      R14
+       MOVL    p_base+4(FP),   SI
+       MOVL    p_len+8(FP),    DX
+       SHRQ    $6,             DX
+       SHLQ    $6,             DX
+       
+       LEAQ    (SI)(DX*1),     DI
+       MOVL    (0*4)(R14),     AX
+       MOVL    (1*4)(R14),     BX
+       MOVL    (2*4)(R14),     CX
+       MOVL    (3*4)(R14),     DX
+       MOVL    (4*4)(R14),     R13
+
+       CMPQ    SI,             DI
+       JEQ     end
+
+loop:
+#define BP R13 /* keep diff from sha1block_amd64.s small */
+       ROUND1(AX, BX, CX, DX, BP, 0)
+       ROUND1(BP, AX, BX, CX, DX, 1)
+       ROUND1(DX, BP, AX, BX, CX, 2)
+       ROUND1(CX, DX, BP, AX, BX, 3)
+       ROUND1(BX, CX, DX, BP, AX, 4)
+       ROUND1(AX, BX, CX, DX, BP, 5)
+       ROUND1(BP, AX, BX, CX, DX, 6)
+       ROUND1(DX, BP, AX, BX, CX, 7)
+       ROUND1(CX, DX, BP, AX, BX, 8)
+       ROUND1(BX, CX, DX, BP, AX, 9)
+       ROUND1(AX, BX, CX, DX, BP, 10)
+       ROUND1(BP, AX, BX, CX, DX, 11)
+       ROUND1(DX, BP, AX, BX, CX, 12)
+       ROUND1(CX, DX, BP, AX, BX, 13)
+       ROUND1(BX, CX, DX, BP, AX, 14)
+       ROUND1(AX, BX, CX, DX, BP, 15)
+
+       ROUND1x(BP, AX, BX, CX, DX, 16)
+       ROUND1x(DX, BP, AX, BX, CX, 17)
+       ROUND1x(CX, DX, BP, AX, BX, 18)
+       ROUND1x(BX, CX, DX, BP, AX, 19)
+       
+       ROUND2(AX, BX, CX, DX, BP, 20)
+       ROUND2(BP, AX, BX, CX, DX, 21)
+       ROUND2(DX, BP, AX, BX, CX, 22)
+       ROUND2(CX, DX, BP, AX, BX, 23)
+       ROUND2(BX, CX, DX, BP, AX, 24)
+       ROUND2(AX, BX, CX, DX, BP, 25)
+       ROUND2(BP, AX, BX, CX, DX, 26)
+       ROUND2(DX, BP, AX, BX, CX, 27)
+       ROUND2(CX, DX, BP, AX, BX, 28)
+       ROUND2(BX, CX, DX, BP, AX, 29)
+       ROUND2(AX, BX, CX, DX, BP, 30)
+       ROUND2(BP, AX, BX, CX, DX, 31)
+       ROUND2(DX, BP, AX, BX, CX, 32)
+       ROUND2(CX, DX, BP, AX, BX, 33)
+       ROUND2(BX, CX, DX, BP, AX, 34)
+       ROUND2(AX, BX, CX, DX, BP, 35)
+       ROUND2(BP, AX, BX, CX, DX, 36)
+       ROUND2(DX, BP, AX, BX, CX, 37)
+       ROUND2(CX, DX, BP, AX, BX, 38)
+       ROUND2(BX, CX, DX, BP, AX, 39)
+       
+       ROUND3(AX, BX, CX, DX, BP, 40)
+       ROUND3(BP, AX, BX, CX, DX, 41)
+       ROUND3(DX, BP, AX, BX, CX, 42)
+       ROUND3(CX, DX, BP, AX, BX, 43)
+       ROUND3(BX, CX, DX, BP, AX, 44)
+       ROUND3(AX, BX, CX, DX, BP, 45)
+       ROUND3(BP, AX, BX, CX, DX, 46)
+       ROUND3(DX, BP, AX, BX, CX, 47)
+       ROUND3(CX, DX, BP, AX, BX, 48)
+       ROUND3(BX, CX, DX, BP, AX, 49)
+       ROUND3(AX, BX, CX, DX, BP, 50)
+       ROUND3(BP, AX, BX, CX, DX, 51)
+       ROUND3(DX, BP, AX, BX, CX, 52)
+       ROUND3(CX, DX, BP, AX, BX, 53)
+       ROUND3(BX, CX, DX, BP, AX, 54)
+       ROUND3(AX, BX, CX, DX, BP, 55)
+       ROUND3(BP, AX, BX, CX, DX, 56)
+       ROUND3(DX, BP, AX, BX, CX, 57)
+       ROUND3(CX, DX, BP, AX, BX, 58)
+       ROUND3(BX, CX, DX, BP, AX, 59)
+       
+       ROUND4(AX, BX, CX, DX, BP, 60)
+       ROUND4(BP, AX, BX, CX, DX, 61)
+       ROUND4(DX, BP, AX, BX, CX, 62)
+       ROUND4(CX, DX, BP, AX, BX, 63)
+       ROUND4(BX, CX, DX, BP, AX, 64)
+       ROUND4(AX, BX, CX, DX, BP, 65)
+       ROUND4(BP, AX, BX, CX, DX, 66)
+       ROUND4(DX, BP, AX, BX, CX, 67)
+       ROUND4(CX, DX, BP, AX, BX, 68)
+       ROUND4(BX, CX, DX, BP, AX, 69)
+       ROUND4(AX, BX, CX, DX, BP, 70)
+       ROUND4(BP, AX, BX, CX, DX, 71)
+       ROUND4(DX, BP, AX, BX, CX, 72)
+       ROUND4(CX, DX, BP, AX, BX, 73)
+       ROUND4(BX, CX, DX, BP, AX, 74)
+       ROUND4(AX, BX, CX, DX, BP, 75)
+       ROUND4(BP, AX, BX, CX, DX, 76)
+       ROUND4(DX, BP, AX, BX, CX, 77)
+       ROUND4(CX, DX, BP, AX, BX, 78)
+       ROUND4(BX, CX, DX, BP, AX, 79)
+#undef BP
+
+       ADDL    (0*4)(R14), AX
+       ADDL    (1*4)(R14), BX
+       ADDL    (2*4)(R14), CX
+       ADDL    (3*4)(R14), DX
+       ADDL    (4*4)(R14), R13
+
+       MOVL    AX, (0*4)(R14)
+       MOVL    BX, (1*4)(R14)
+       MOVL    CX, (2*4)(R14)
+       MOVL    DX, (3*4)(R14)
+       MOVL    R13, (4*4)(R14)
+
+       ADDQ    $64, SI
+       CMPQ    SI, DI
+       JB      loop
+
+end:
+       RET
index b2c68f0e8baaf2f1d65d18f278530e4ebe1afea4..2331deb3a99ec04146f4b843119fe9ecac14c8c3 100644 (file)
@@ -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 amd64 386 arm
+// +build amd64 amd64p32 386
 
 package sha1
 
index a5bd19e821695d6352a00f2ecf2d428b6f6a129b..11ad3c440d20468f8f6a9cba43fdde9f839a7809 100644 (file)
@@ -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 dragonfly freebsd linux openbsd netbsd solaris
+// +build dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package x509
 
index 98ec5ea5ed9a428fa728df4a1ef33be080eb2929..8a390762dc8a09623e2d802c60cc0b0d0dfea744 100644 (file)
@@ -1209,7 +1209,7 @@ func ArchChar(goarch string) (string, error) {
        switch goarch {
        case "386":
                return "8", nil
-       case "amd64":
+       case "amd64", "amd64p32":
                return "6", nil
        case "arm":
                return "5", nil
index 3e7ae22a82a8bcd42eb99c4c7487388c59874049..7421e144f15d3c32310149d576764c872c3bd361 100644 (file)
@@ -8,6 +8,7 @@
 package build
 
 import (
+       "runtime"
        "sort"
        "testing"
 )
@@ -359,7 +360,7 @@ func allowed(pkg string) map[string]bool {
 }
 
 var bools = []bool{false, true}
-var geese = []string{"darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "plan9", "solaris", "windows"}
+var geese = []string{"darwin", "dragonfly", "freebsd", "linux", "nacl", "netbsd", "openbsd", "plan9", "solaris", "windows"}
 var goarches = []string{"386", "amd64", "arm"}
 
 type osPkg struct {
@@ -374,6 +375,11 @@ var allowedErrors = map[osPkg]bool{
 }
 
 func TestDependencies(t *testing.T) {
+       if runtime.GOOS == "nacl" {
+               // NaCl tests run in a limited file system and we do not
+               // provide access to every source file.
+               t.Skip("skipping on NaCl")
+       }
        var all []string
 
        for k := range pkgDeps {
@@ -387,6 +393,9 @@ func TestDependencies(t *testing.T) {
                        if isMacro(pkg) {
                                continue
                        }
+                       if pkg == "runtime/cgo" && !ctxt.CgoEnabled {
+                               continue
+                       }
                        p, err := ctxt.Import(pkg, "", 0)
                        if err != nil {
                                if allowedErrors[osPkg{ctxt.GOOS, pkg}] {
index f4702d0dc401552d891b24e28db6fc40a82094ba..5c42b946b09434d060eb70565a22cd71a24880a8 100644 (file)
@@ -4,5 +4,5 @@
 
 package build
 
-const goosList = "darwin dragonfly freebsd linux netbsd openbsd plan9 solaris windows "
-const goarchList = "386 amd64 arm "
+const goosList = "darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows "
+const goarchList = "386 amd64 amd64p32 arm "
diff --git a/src/pkg/hash/crc32/crc32_amd64p32.s b/src/pkg/hash/crc32/crc32_amd64p32.s
new file mode 100644 (file)
index 0000000..e34f208
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../../cmd/ld/textflag.h"
+
+// func castagnoliSSE42(crc uint32, p []byte) uint32
+TEXT Â·castagnoliSSE42(SB),NOSPLIT,$0
+       MOVL crc+0(FP), AX  // CRC value
+       MOVL p+4(FP), SI  // data pointer
+       MOVL p_len+8(FP), CX  // len(p)
+
+       NOTL AX
+
+       /* If there's less than 8 bytes to process, we do it byte-by-byte. */
+       CMPQ CX, $8
+       JL cleanup
+
+       /* Process individual bytes until the input is 8-byte aligned. */
+startup:
+       MOVQ SI, BX
+       ANDQ $7, BX
+       JZ aligned
+
+       CRC32B (SI), AX
+       DECQ CX
+       INCQ SI
+       JMP startup
+
+aligned:
+       /* The input is now 8-byte aligned and we can process 8-byte chunks. */
+       CMPQ CX, $8
+       JL cleanup
+
+       CRC32Q (SI), AX
+       ADDQ $8, SI
+       SUBQ $8, CX
+       JMP aligned
+
+cleanup:
+       /* We may have some bytes left over that we process one at a time. */
+       CMPQ CX, $0
+       JE done
+
+       CRC32B (SI), AX
+       INCQ SI
+       DECQ CX
+       JMP cleanup
+
+done:
+       NOTL AX
+       MOVL AX, ret+16(FP)
+       RET
+
+// func haveSSE42() bool
+TEXT Â·haveSSE42(SB),NOSPLIT,$0
+       XORQ AX, AX
+       INCL AX
+       CPUID
+       SHRQ $20, CX
+       ANDQ $1, CX
+       MOVB CX, ret+0(FP)
+       RET
+
similarity index 96%
rename from src/pkg/hash/crc32/crc32_amd64.go
rename to src/pkg/hash/crc32/crc32_amd64x.go
index b5bc6d3cf07df50da42a27afc27c27e576aaa3db..b7e359930a4ca59e2f3445f01a68bcad2cc984c7 100644 (file)
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// +build amd64 amd64p32
+
 package crc32
 
 // This file contains the code to call the SSE 4.2 version of the Castagnoli
index 0cbfa9011b8e0fa0dd9648634797bec0816bd6c1..1c7588e3656842e4a468bfdc0da90fb8f0b1ebb8 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !windows,!plan9
+// +build !windows,!nacl,!plan9
 
 // Package syslog provides a simple interface to the system log
 // service. It can send messages to the syslog daemon using UNIX
index 760a5c7d1e99169e399db5da6af4c8a3732816be..24a460f6d9eaaa0b33348e4a1a1c51e946a9d09a 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !windows,!plan9
+// +build !windows,!nacl,!plan9
 
 package syslog
 
index 28a294af96387eb96a2546522b54df304f62723d..f6d2f1b7a399ef89a1958b985dd8be6d9fd1e38c 100644 (file)
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !windows,!plan9
+// +build !windows,!nacl,!plan9
 
 package syslog
 
index d949ba3f3e5ece6473337cdb51935a7bb32d39c6..1d394315a49b0cafd80d0177340a6f6c1d983e55 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package mime
 
index 7250dcb85ad766d9f8897d776041640bfe6bdb76..78aaa130df8acd43d756773b6fb8cf79908be8f3 100644 (file)
@@ -33,7 +33,7 @@ func TestConnAndListener(t *testing.T) {
                switch tt.net {
                case "unix", "unixpacket":
                        switch runtime.GOOS {
-                       case "plan9", "windows":
+                       case "plan9", "windows", "nacl":
                                continue
                        }
                        if tt.net == "unixpacket" && runtime.GOOS != "linux" {
index 7840d4eebbd680453775cd18da16be2e1ae1729d..2211e2190c7af304657fc8b9af880c54e5ce585a 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 // DNS client: see RFC 1035.
 // Has to be linked into package net for Dial.
index 656b270f180dbdaf3c9b3e0aca09bbbb868474c3..af288253e09bacea861f751c779ae823c98035b2 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 // Read system DNS config from /etc/resolv.conf
 
diff --git a/src/pkg/net/fd_poll_nacl.go b/src/pkg/net/fd_poll_nacl.go
new file mode 100644 (file)
index 0000000..a3701f8
--- /dev/null
@@ -0,0 +1,94 @@
+// Copyright 2013 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 net
+
+import (
+       "syscall"
+       "time"
+)
+
+type pollDesc struct {
+       fd      *netFD
+       closing bool
+}
+
+func (pd *pollDesc) Init(fd *netFD) error { pd.fd = fd; return nil }
+
+func (pd *pollDesc) Close() {}
+
+func (pd *pollDesc) Lock() {}
+
+func (pd *pollDesc) Unlock() {}
+
+func (pd *pollDesc) Wakeup() {}
+
+func (pd *pollDesc) Evict() bool {
+       pd.closing = true
+       if pd.fd != nil {
+               syscall.StopIO(pd.fd.sysfd)
+       }
+       return false
+}
+
+func (pd *pollDesc) Prepare(mode int) error {
+       if pd.closing {
+               return errClosing
+       }
+       return nil
+}
+
+func (pd *pollDesc) PrepareRead() error { return pd.Prepare('r') }
+
+func (pd *pollDesc) PrepareWrite() error { return pd.Prepare('w') }
+
+func (pd *pollDesc) Wait(mode int) error {
+       if pd.closing {
+               return errClosing
+       }
+       return errTimeout
+}
+
+func (pd *pollDesc) WaitRead() error { return pd.Wait('r') }
+
+func (pd *pollDesc) WaitWrite() error { return pd.Wait('w') }
+
+func (pd *pollDesc) WaitCanceled(mode int) {}
+
+func (pd *pollDesc) WaitCanceledRead() {}
+
+func (pd *pollDesc) WaitCanceledWrite() {}
+
+func (fd *netFD) setDeadline(t time.Time) error {
+       return setDeadlineImpl(fd, t, 'r'+'w')
+}
+
+func (fd *netFD) setReadDeadline(t time.Time) error {
+       return setDeadlineImpl(fd, t, 'r')
+}
+
+func (fd *netFD) setWriteDeadline(t time.Time) error {
+       return setDeadlineImpl(fd, t, 'w')
+}
+
+func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
+       d := t.UnixNano()
+       if t.IsZero() {
+               d = 0
+       }
+       if err := fd.incref(); err != nil {
+               return err
+       }
+       switch mode {
+       case 'r':
+               syscall.SetReadDeadline(fd.sysfd, d)
+       case 'w':
+               syscall.SetWriteDeadline(fd.sysfd, d)
+       case 'r' + 'w':
+               syscall.SetReadDeadline(fd.sysfd, d)
+               syscall.SetWriteDeadline(fd.sysfd, d)
+       }
+       fd.decref()
+       return nil
+}
index f96dbf975df65f7604341aa3010140f9a88bd3d3..54aeaeb1984999a2f2e9488b9edb708a5319e28c 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package net
 
index e4615b74fc376de976fe9d9e0e95e8348ac5cfb1..09d1f4dcc0ad82464d2e4ae14f3633ecc30f6d60 100644 (file)
@@ -181,7 +181,7 @@ var filePacketConnTests = []struct {
 
 func TestFilePacketConn(t *testing.T) {
        switch runtime.GOOS {
-       case "plan9", "windows":
+       case "plan9", "windows", "nacl":
                t.Skipf("skipping test on %q", runtime.GOOS)
        }
 
index 214a4196c8e3cfca5376ab380ef7912c07e7de97..c674b9b32013d827ef68728c7c52b305c997f954 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package net
 
@@ -24,6 +24,7 @@ func newFileFD(f *os.File) (*netFD, error) {
 
        sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
        if err != nil {
+               println("getsockopt failed", fd, err.Error())
                closesocket(fd)
                return nil, os.NewSyscallError("getsockopt", err)
        }
index 31f6ee3e1c495b001537903b961e15675c09b76e..c38fb7f7651d9f584de7e0a272dad1aeca79d98d 100644 (file)
@@ -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 plan9 solaris
+// +build nacl plan9 solaris
 
 package net
 
index 1408b065d3ce1f95d6e0cbea60c8c077b7c1c7e4..51a1b2c2fecd1a2127b52c2c50aa5e0ab71f049d 100644 (file)
@@ -247,7 +247,7 @@ var ipConnLocalNameTests = []struct {
 
 func TestIPConnLocalName(t *testing.T) {
        switch runtime.GOOS {
-       case "plan9", "windows":
+       case "plan9", "windows", "nacl":
                t.Skipf("skipping test on %q", runtime.GOOS)
        default:
                if os.Getuid() != 0 {
index 517bea21f3944405a16bfc3904111258aaac0ca2..ff6c768481185cc608acebddecb4d7062f28e240 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
index 486c3f2b9a1646a25040848b2061f9a1dd3d4000..d2f45060f9876a83f750c7487b0e442d46445498 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 // Internet protocol family sockets for POSIX
 
index a54578456d7c6ac49df2a0ae56460c90afaa3e0c..b1d2f8f31a9e6eea37a9659464e970e12699e6ff 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package net
 
index 0f313cc4cb8035598b478e119858223b41e2dc1b..63dbce88e9a5550b18e1bba1dacba3befac90fd0 100644 (file)
@@ -25,7 +25,7 @@ var ipv4MulticastListenerTests = []struct {
 // port.
 func TestIPv4MulticastListener(t *testing.T) {
        switch runtime.GOOS {
-       case "plan9":
+       case "nacl", "plan9":
                t.Skipf("skipping test on %q", runtime.GOOS)
        case "solaris":
                t.Skipf("skipping test on solaris, see issue 7399")
index c9fb433ec91b10edf57c3bbb8c3f265307ac5a71..93eb8659eac98f55ff66488c2b42e1d3aaa42308 100644 (file)
@@ -62,7 +62,7 @@ func TestShutdown(t *testing.T) {
 
 func TestShutdownUnix(t *testing.T) {
        switch runtime.GOOS {
-       case "windows", "plan9":
+       case "nacl", "plan9", "windows":
                t.Skipf("skipping test on %q", runtime.GOOS)
        }
        f, err := ioutil.TempFile("", "go_net_unixtest")
index a1beb840d595e82eb866c2b18f939331e30b8e76..5b803e610064aec9ad147586fc92118e91dd639a 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 // Read system port mappings from /etc/services
 
index d7401e274da37a7d95539528c911f7f3a80a5dfc..03426ef0df17897e9966d95b7c44b5cd08e3759d 100644 (file)
@@ -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 darwin netbsd openbsd solaris
+// +build darwin nacl netbsd openbsd solaris
 
 package net
 
index 6c37109f5e4b02d84924719372e957bfb357bb13..48fb7852757c23687f3445f96ce46248bb7a1eb7 100644 (file)
@@ -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 darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
 
 package net
 
index 290596247efbb8cd3ec8b801c193073e82fd0ff4..a6ef874c9fda0b3304dd503f2c1b836d2b5e200f 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
index ef6eb85053bc9487747c08ce369276156eaea2b8..c0255f1644798eb068a0f4509ae3dbb5ce1daae9 100644 (file)
@@ -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 darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
 
 package net
 
index 1654d1b85e46c6481e0b7ebb5c009b3e205faa0f..921918c37f543b42dbb17569d82c3e2b2fcc45b5 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
index 0fa74718a6a38ffe5ea6dc4f8f2b36e5fbf46e9e..c6b339fa5a44d5015ec296b0b363b8ecac9626ee 100644 (file)
@@ -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 darwin dragonfly freebsd netbsd openbsd solaris
+// +build darwin dragonfly freebsd nacl netbsd openbsd solaris
 
 package net
 
index f38bb4f04069f51f4765c2c855e90750e7d8c32f..2aea6830b1c7296e6ba2680f6377c94374821c92 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
index cdc669b6210314038a074e947ba5d3d48ac05f45..19ba0fc00ccca91c128d8c6ee67138094fc1fa8d 100644 (file)
@@ -5,7 +5,7 @@
 // This file implements sysSocket and accept for platforms that do not
 // provide a fast path for setting SetNonblock and CloseOnExec.
 
-// +build darwin dragonfly freebsd netbsd openbsd solaris
+// +build darwin dragonfly freebsd nacl netbsd openbsd solaris
 
 package net
 
index 3727e470e63452c175df667cc71395b5e349915a..cbae7f3c62179be941c6d202bd11ac5f1157a2dd 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
index 0abf3f97f6b4e028f5ddfa0c792b951140453d1a..6484bad4b45d6f3a4856095cd8a0f42e8cc1a2e4 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
index 89d9143b52e2bfb54ac301decf8112b86e163cda..15d4fd9651960dfd1173ce5b9c9052751cd06730 100644 (file)
@@ -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 dragonfly freebsd linux netbsd
+// +build dragonfly freebsd linux nacl netbsd
 
 package net
 
index 11f9621dc363c966355a2673176fcbf6a087fb72..d81c2535687f5cd19a33d9c5285d0e0779d52cf7 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
index 5f1503acab969619a497051199f1361811d9953b..83f7c3f979851787d0d0d8f095653a1415da5e48 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
index 67c390283c7336349d714bef3c36d13126088a97..d353e405e54178088608408609ede466248fcfbb 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package os
 
index f281495e6b8e09ecc4eb144022f1fd4346282e28..f2aabbb45c43b5282ce97d1225cd08d568c826fd 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package os
 
index 7b9dec7e8b50894c4d1a1b0ff9848465c59c7087..3f895d5b3bacbe9d1001e21d1bba1adf9dfb80cb 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package exec
 
index 8a4d019d2f748ee4d45a513370b5a59c5a20f628..fb9d291e66453a936beb1fe3c01273c74dd938c1 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package os
 
index 3c05b8f080625136d1692f5e4a35b245194afb47..848a5de8f98e56878e72f1880fe47a35b2fdfcd0 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package os
 
index 441ad5384d70a20d3e75a7566789c69ed3d82d61..b3466b15cc8446477bec4ff602df29dd96a53953 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package os
 
index cfe0c1c2f87b5fed84fdbd9825e77fba39c764a4..f6d76f289df4608972e22b4298d80839a2f10ea9 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package os
 
index bdf9fe642187b58548a85e414fc8807251faea75..0211107ddfc42d3bb8a7610b043d5edb2ad0ed36 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package os
 
index 0ea8e4b1f83cd531219e1085de4e41bf60e0dc6d..3b81ed20f1b72df2d0de968721a92909c187c3e0 100644 (file)
@@ -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 darwin dragonfly freebsd netbsd openbsd solaris
+// +build darwin dragonfly freebsd nacl netbsd openbsd solaris
 
 package os
 
index 888823cf453a6ab9074de5f5252a88f94a5a46c1..f860924aa0b697b28fc52cdedbc464883984bdfe 100644 (file)
@@ -4,7 +4,7 @@
 
 // Assembly to get into package runtime without using exported symbols.
 
-// +build amd64 arm 386
+// +build amd64 amd64p32 arm 386
 
 #include "../../../cmd/ld/textflag.h"
 
index 80dc4304aaa4d625586ecb0c8f35bca5cf21b0e4..94b8ab3ddbf455795b5d222dcc6f1ca71b175e88 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package signal
 
diff --git a/src/pkg/os/stat_nacl.go b/src/pkg/os/stat_nacl.go
new file mode 100644 (file)
index 0000000..a503b59
--- /dev/null
@@ -0,0 +1,62 @@
+// Copyright 2009 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 os
+
+import (
+       "syscall"
+       "time"
+)
+
+func sameFile(fs1, fs2 *fileStat) bool {
+       stat1 := fs1.sys.(*syscall.Stat_t)
+       stat2 := fs2.sys.(*syscall.Stat_t)
+       return stat1.Dev == stat2.Dev && stat1.Ino == stat2.Ino
+}
+
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+       fs := &fileStat{
+               name:    basename(name),
+               size:    int64(st.Size),
+               modTime: timespecToTime(st.Mtime, st.MtimeNsec),
+               sys:     st,
+       }
+       fs.mode = FileMode(st.Mode & 0777)
+       switch st.Mode & syscall.S_IFMT {
+       case syscall.S_IFBLK:
+               fs.mode |= ModeDevice
+       case syscall.S_IFCHR:
+               fs.mode |= ModeDevice | ModeCharDevice
+       case syscall.S_IFDIR:
+               fs.mode |= ModeDir
+       case syscall.S_IFIFO:
+               fs.mode |= ModeNamedPipe
+       case syscall.S_IFLNK:
+               fs.mode |= ModeSymlink
+       case syscall.S_IFREG:
+               // nothing to do
+       case syscall.S_IFSOCK:
+               fs.mode |= ModeSocket
+       }
+       if st.Mode&syscall.S_ISGID != 0 {
+               fs.mode |= ModeSetgid
+       }
+       if st.Mode&syscall.S_ISUID != 0 {
+               fs.mode |= ModeSetuid
+       }
+       if st.Mode&syscall.S_ISVTX != 0 {
+               fs.mode |= ModeSticky
+       }
+       return fs
+}
+
+func timespecToTime(sec, nsec int64) time.Time {
+       return time.Unix(sec, nsec)
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+       st := fi.Sys().(*syscall.Stat_t)
+       return timespecToTime(st.Atime, st.AtimeNsec)
+}
index 9ad2f8546b99f2242f4f01403a0afb96008a3121..8ad5e21837100c395e3cc4cadb6cd70f00291d3e 100644 (file)
@@ -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 darwin dragonfly freebsd netbsd openbsd
+// +build darwin dragonfly freebsd nacl netbsd openbsd
 
 // os code shared between *BSD systems including OS X (Darwin)
 // and FreeBSD.
index 2be675c3af1dc0b89765a5787507c67c7394903e..7aba0ab5b9bb2e09488612c8236a91859c0157ef 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package filepath
 
diff --git a/src/pkg/reflect/asm_amd64p32.s b/src/pkg/reflect/asm_amd64p32.s
new file mode 100644 (file)
index 0000000..75413c7
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2012 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../cmd/ld/textflag.h"
+
+// makeFuncStub is the code half of the function returned by MakeFunc.
+// See the comment on the declaration of makeFuncStub in makefunc.go
+// for more details.
+// No argsize here, gc generates argsize info at call site.
+TEXT Â·makeFuncStub(SB),(NOSPLIT|WRAPPER),$8
+       MOVL    DX, 0(SP)
+       LEAL    argframe+0(FP), CX
+       MOVL    CX, 4(SP)
+       CALL    Â·callReflect(SB)
+       RET
+
+// methodValueCall is the code half of the function returned by makeMethodValue.
+// See the comment on the declaration of methodValueCall in makefunc.go
+// for more details.
+// No argsize here, gc generates argsize info at call site.
+TEXT Â·methodValueCall(SB),(NOSPLIT|WRAPPER),$8
+       MOVL    DX, 0(SP)
+       LEAL    argframe+0(FP), CX
+       MOVL    CX, 4(SP)
+       CALL    Â·callMethod(SB)
+       RET
index 51fdc1ecad69b523a9b19db75852efdb0aa0dfe3..3b4fe2190e133d7870ab0a759111b7ade46fc65d 100644 (file)
@@ -16,6 +16,7 @@
 package reflect
 
 import (
+       "runtime"
        "strconv"
        "sync"
        "unsafe"
@@ -1572,6 +1573,10 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
        gc = append(gc, _GC_PTR, offset, 0 /*self pointer set below*/) // overflow
        offset += ptrsize
 
+       if runtime.GOARCH == "amd64p32" {
+               offset += 4
+       }
+
        // keys
        if ktyp.kind&kindNoPointers == 0 {
                gc = append(gc, _GC_ARRAY_START, offset, _BUCKETSIZE, ktyp.size)
index ebdb3ff4e27c85f11d3dcdf7560db3c95c9409c8..5c0a54f8c07b915dc59331bb65b63817df89e526 100644 (file)
@@ -7,5 +7,10 @@ enum {
        BigEndian = 0,
        CacheLineSize = 64,
        RuntimeGogoBytes = 64,
+#ifdef GOOS_nacl
+       PhysPageSize = 65536,
+#else
+       PhysPageSize = 4096,
+#endif
        PCQuantum = 1
 };
index 171839481bc00b42f4fa82c15e12866a882b073e..88b68cc6df58b7ebc500b5f0fbddbe537b8139ab 100644 (file)
@@ -10,6 +10,11 @@ enum {
        RuntimeGogoBytes = 80,
 #else
        RuntimeGogoBytes = 64,
+#endif
+#ifdef GOOS_nacl
+       PhysPageSize = 65536,
+#else
+       PhysPageSize = 4096,
 #endif
        PCQuantum = 1
 };
diff --git a/src/pkg/runtime/arch_amd64p32.h b/src/pkg/runtime/arch_amd64p32.h
new file mode 100644 (file)
index 0000000..88b68cc
--- /dev/null
@@ -0,0 +1,20 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+enum {
+       thechar = '6',
+       BigEndian = 0,
+       CacheLineSize = 64,
+#ifdef GOOS_solaris
+       RuntimeGogoBytes = 80,
+#else
+       RuntimeGogoBytes = 64,
+#endif
+#ifdef GOOS_nacl
+       PhysPageSize = 65536,
+#else
+       PhysPageSize = 4096,
+#endif
+       PCQuantum = 1
+};
index e5da01c6033be40ff5c1aa71c7b03d89a5b3cd13..b9711289f4fab26326ae7f77a1d723473e200153 100644 (file)
@@ -7,5 +7,6 @@ enum {
        BigEndian = 0,
        CacheLineSize = 32,
        RuntimeGogoBytes = 80,
+       PhysPageSize = 4096,
        PCQuantum = 4
 };
index b0f2956335453bdc31b1d1c6732177761264ad5a..2786ad70f6867bc43595491b77b5cc034f6f8fb3 100644 (file)
@@ -11,6 +11,7 @@
 enum
 {
        _PAGE_SIZE = 4096,
+       EACCES = 13,
 };
 
 static int32
diff --git a/src/pkg/runtime/mem_nacl.c b/src/pkg/runtime/mem_nacl.c
new file mode 100644 (file)
index 0000000..993d194
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright 2010 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 "runtime.h"
+#include "arch_GOARCH.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "malloc.h"
+
+enum
+{
+       Debug = 0,
+};
+
+void*
+runtime·SysAlloc(uintptr n, uint64 *stat)
+{
+       void *v;
+
+       v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+       if(v < (void*)4096) {
+               if(Debug)
+                       runtime·printf("SysAlloc(%p): %p\n", n, v);
+               return nil;
+       }
+       runtime·xadd64(stat, n);
+       if(Debug)
+               runtime·printf("SysAlloc(%p) = %p\n", n, v);
+       return v;
+}
+
+void
+runtime·SysUnused(void *v, uintptr n)
+{
+       if(Debug)
+               runtime·printf("SysUnused(%p, %p)\n", v, n);
+}
+
+void
+runtime·SysUsed(void *v, uintptr n)
+{
+       USED(v);
+       USED(n);
+}
+
+void
+runtime·SysFree(void *v, uintptr n, uint64 *stat)
+{
+       if(Debug)
+               runtime·printf("SysFree(%p, %p)\n", v, n);
+       runtime·xadd64(stat, -(uint64)n);
+       runtime·munmap(v, n);
+}
+
+void*
+runtime·SysReserve(void *v, uintptr n)
+{
+       void *p;
+
+       // On 64-bit, people with ulimit -v set complain if we reserve too
+       // much address space.  Instead, assume that the reservation is okay
+       // and check the assumption in SysMap.
+       if(NaCl || sizeof(void*) == 8)
+               return v;
+       
+       p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+       if(p < (void*)4096)
+               return nil;
+       return p;
+}
+
+void
+runtime·SysMap(void *v, uintptr n, uint64 *stat)
+{
+       void *p;
+       
+       runtime·xadd64(stat, n);
+
+       // On 64-bit, we don't actually have v reserved, so tread carefully.
+       if(sizeof(void*) == 8) {
+               p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
+               if(p == (void*)ENOMEM) {
+                       runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+                       runtime·throw("runtime: out of memory");
+               }
+               if(p != v) {
+                       runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+                       runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
+                       runtime·throw("runtime: address space conflict");
+               }
+               if(Debug)
+                       runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
+               return;
+       }
+
+       p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
+       if(p == (void*)ENOMEM) {
+               runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+               runtime·throw("runtime: out of memory");
+       }
+       if(p != v) {
+               runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
+               runtime·printf("mmap MAP_FIXED %p returned %p\n", v, p);
+               runtime·throw("runtime: cannot map pages in arena address space");
+       }
+       if(Debug)
+               runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
+}
index 95c3e831516f25ebce18c31457d93a0c5c917127..8d91a6db2e4cfa7f555d54dad662800d64d74481 100644 (file)
@@ -2771,6 +2771,7 @@ runtime·MHeap_MapBits(MHeap *h)
 
        n = (h->arena_used - h->arena_start) / wordsPerBitmapWord;
        n = ROUND(n, bitmapChunk);
+       n = ROUND(n, PhysPageSize);
        if(h->bitmap_mapped >= n)
                return;
 
index ba46b6404e6456afe425004bb63a2c684adc76e4..d89512d3f10f2231f7812f3107b4185e1b307ca0 100644 (file)
@@ -82,7 +82,7 @@ runtime·MHeap_MapSpans(MHeap *h)
        n = (uintptr)h->arena_used;
        n -= (uintptr)h->arena_start;
        n = n / PageSize * sizeof(h->spans[0]);
-       n = ROUND(n, PageSize);
+       n = ROUND(n, PhysPageSize);
        if(h->spans_mapped >= n)
                return;
        runtime·SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, &mstats.other_sys);
diff --git a/src/pkg/runtime/mknacl.sh b/src/pkg/runtime/mknacl.sh
new file mode 100644 (file)
index 0000000..47fb7bd
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+# Copyright 2013 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.
+
+cat /Users/rsc/pub/native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h |
+       awk '
+       BEGIN {
+               printf("// generated by mknacl.sh - do not edit\n")
+       }
+       NF==3 && $1=="#define" && $2~/^NACL_sys_/ {
+               name=$2
+               sub(/^NACL_sys_/, "SYS_", name)
+               printf("#define %s %s\n", name, $3)
+       }' >syscall_nacl.h
index 9cc5eb5a36b4614a26228eeeafb7d3201be0cdb2..77ddde9d60160e5c5d9d2977be5888ff2a0f087f 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
 
 package net
 
diff --git a/src/pkg/runtime/netpoll_nacl.c b/src/pkg/runtime/netpoll_nacl.c
new file mode 100644 (file)
index 0000000..b75753a
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright 2013 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 "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+
+// Fake network poller for NaCl.
+// Should never be used, because NaCl network connections do not honor "SetNonblock".
+
+void
+runtime·netpollinit(void)
+{
+}
+
+int32
+runtime·netpollopen(uintptr fd, PollDesc *pd)
+{
+       USED(fd);
+       USED(pd);
+       return 0;
+}
+
+int32
+runtime·netpollclose(uintptr fd)
+{
+       USED(fd);
+       return 0;
+}
+
+G*
+runtime·netpoll(bool block)
+{
+       USED(block);
+       return nil;
+}
diff --git a/src/pkg/runtime/os_nacl.c b/src/pkg/runtime/os_nacl.c
new file mode 100644 (file)
index 0000000..3c5e487
--- /dev/null
@@ -0,0 +1,275 @@
+// Copyright 2010 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 "runtime.h"
+#include "defs_GOOS_GOARCH.h"
+#include "os_GOOS.h"
+#include "arch_GOARCH.h"
+#include "../../cmd/ld/textflag.h"
+#include "stack.h"
+
+int8 *goos = "nacl";
+extern SigTab runtime·sigtab[];
+
+void runtime·sigtramp(void);
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+void
+runtime·mpreinit(M *mp)
+{
+       mp->gsignal = runtime·malg(32*1024);   // OS X wants >=8K, Linux >=2K
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+void
+runtime·minit(void)
+{
+       int32 ret;
+
+       // Initialize signal handling
+       ret = runtime·nacl_exception_stack((byte*)m->gsignal->stackguard - StackGuard, 32*1024);
+       if(ret < 0)
+               runtime·printf("runtime: nacl_exception_stack: error %d\n", -ret);
+
+       ret = runtime·nacl_exception_handler(runtime·sigtramp, nil);
+       if(ret < 0)
+               runtime·printf("runtime: nacl_exception_handler: error %d\n", -ret);
+}
+
+// Called from dropm to undo the effect of an minit.
+void
+runtime·unminit(void)
+{
+}
+
+int8 runtime·sigtrampf[] = "runtime: signal at PC=%X AX=%X CX=%X DX=%X BX=%X DI=%X R15=%X *SP=%X\n";
+int8 runtime·sigtrampp[] = "runtime: sigtramp";
+
+extern byte runtime·tls0[];
+
+void
+runtime·osinit(void)
+{
+       runtime·ncpu = 1;
+       m->procid = 2;
+//runtime·nacl_exception_handler(runtime·sigtramp, nil);
+}
+
+void
+runtime·crash(void)
+{
+       *(int32*)0 = 0;
+}
+
+void
+runtime·get_random_data(byte **rnd, int32 *rnd_len)
+{
+       *rnd = nil;
+       *rnd_len = 0;
+}
+
+void
+runtime·goenvs(void)
+{
+       runtime·goenvs_unix();
+}
+
+void
+runtime·initsig(void)
+{
+}
+
+#pragma textflag NOSPLIT
+void
+runtime·usleep(uint32 us)
+{
+       Timespec ts;
+       
+       ts.tv_sec = us/1000000;
+       ts.tv_nsec = (us%1000000)*1000;
+       runtime·nacl_nanosleep(&ts, nil);
+}
+
+void runtime·mstart_nacl(void);
+
+void
+runtime·newosproc(M *mp, void *stk)
+{
+       int32 ret;
+       void **tls;
+
+       tls = (void**)mp->tls;
+       tls[0] = mp->g0;
+       tls[1] = mp;
+       ret = runtime·nacl_thread_create(runtime·mstart_nacl, stk, tls+2, 0);
+       if(ret < 0) {
+               runtime·printf("nacl_thread_create: error %d\n", -ret);
+               runtime·throw("newosproc");
+       }
+}
+
+uintptr
+runtime·semacreate(void)
+{
+       int32 mu, cond;
+       
+       mu = runtime·nacl_mutex_create(0);
+       if(mu < 0) {
+               runtime·printf("nacl_mutex_create: error %d\n", -mu);
+               runtime·throw("semacreate");
+       }
+       cond = runtime·nacl_cond_create(0);
+       if(cond < 0) {
+               runtime·printf("nacl_cond_create: error %d\n", -cond);
+               runtime·throw("semacreate");
+       }
+       m->waitsemalock = mu;
+       return cond; // assigned to m->waitsema
+}
+
+#pragma textflag NOSPLIT
+int32
+runtime·semasleep(int64 ns)
+{
+       int32 ret;
+       
+       ret = runtime·nacl_mutex_lock(m->waitsemalock);
+       if(ret < 0) {
+               //runtime·printf("nacl_mutex_lock: error %d\n", -ret);
+               runtime·throw("semasleep");
+       }
+       if(m->waitsemacount > 0) {
+               m->waitsemacount = 0;
+               runtime·nacl_mutex_unlock(m->waitsemalock);
+               return 0;
+       }
+
+       while(m->waitsemacount == 0) {
+               if(ns < 0) {
+                       ret = runtime·nacl_cond_wait(m->waitsema, m->waitsemalock);
+                       if(ret < 0) {
+                               //runtime·printf("nacl_cond_wait: error %d\n", -ret);
+                               runtime·throw("semasleep");
+                       }
+               } else {
+                       Timespec ts;
+                       
+                       ns += runtime·nanotime();
+                       ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
+                       ret = runtime·nacl_cond_timed_wait_abs(m->waitsema, m->waitsemalock, &ts);
+                       if(ret == -ETIMEDOUT) {
+                               runtime·nacl_mutex_unlock(m->waitsemalock);
+                               return -1;
+                       }
+                       if(ret < 0) {
+                               //runtime·printf("nacl_cond_timed_wait_abs: error %d\n", -ret);
+                               runtime·throw("semasleep");
+                       }
+               }
+       }
+                       
+       m->waitsemacount = 0;
+       runtime·nacl_mutex_unlock(m->waitsemalock);
+       return 0;
+}
+
+void
+runtime·semawakeup(M *mp)
+{
+       int32 ret;
+       
+       ret = runtime·nacl_mutex_lock(mp->waitsemalock);
+       if(ret < 0) {
+               //runtime·printf("nacl_mutex_lock: error %d\n", -ret);
+               runtime·throw("semawakeup");
+       }
+       if(mp->waitsemacount != 0) {
+               //runtime·printf("semawakeup: double wakeup\n");
+               runtime·throw("semawakeup");
+       }
+       mp->waitsemacount = 1;
+       runtime·nacl_cond_signal(mp->waitsema);
+       runtime·nacl_mutex_unlock(mp->waitsemalock);
+}
+
+void
+os·sigpipe(void)
+{
+       runtime·throw("too many writes on closed pipe");
+}
+
+uintptr
+runtime·memlimit(void)
+{
+       runtime·printf("memlimit\n");
+       return 0;
+}
+
+#pragma dataflag NOPTR
+static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+#pragma textflag NOSPLIT
+void
+runtime·badsignal2(void)
+{
+       runtime·write(2, badsignal, sizeof badsignal - 1);
+       runtime·exit(2);
+}
+
+void   runtime·madvise(byte*, uintptr, int32) { }
+void runtime·munmap(byte*, uintptr) {}
+
+void
+runtime·resetcpuprofiler(int32 hz)
+{
+       USED(hz);
+}
+
+void
+runtime·sigdisable(uint32)
+{
+}
+
+void
+runtime·sigenable(uint32)
+{
+}
+
+void
+runtime·closeonexec(int32)
+{
+}
+
+void
+runtime·sigpanic(void)
+{
+       // Native Client only invokes the exception handler for memory faults.
+       g->sig = SIGSEGV;
+       if(g->sigpc == 0)
+               runtime·panicstring("call of nil func value");
+       runtime·panicstring("invalid memory address or nil pointer dereference");
+}
+
+uint32 runtime·writelock; // test-and-set spin lock for runtime.write
+
+/*
+An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
+
+void (*runtime·nacl_irt_query)(void);
+
+int8 runtime·nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
+void *runtime·nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
+int32 runtime·nacl_irt_basic_v0_1_size = sizeof(runtime·nacl_irt_basic_v0_1);
+
+int8 runtime·nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
+void *runtime·nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
+int32 runtime·nacl_irt_memory_v0_3_size = sizeof(runtime·nacl_irt_memory_v0_3);
+
+int8 runtime·nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
+void *runtime·nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
+int32 runtime·nacl_irt_thread_v0_1_size = sizeof(runtime·nacl_irt_thread_v0_1);
+*/
\ No newline at end of file
diff --git a/src/pkg/runtime/os_nacl.h b/src/pkg/runtime/os_nacl.h
new file mode 100644 (file)
index 0000000..7c9d9c2
--- /dev/null
@@ -0,0 +1,162 @@
+enum {
+       NSIG = 32,
+       SI_USER = 1,
+
+       // native_client/src/trusted/service_runtime/include/sys/errno.h
+       // The errors are mainly copied from Linux.
+       EPERM = 1,  /* Operation not permitted */
+       ENOENT = 2,  /* No such file or directory */
+       ESRCH = 3,  /* No such process */
+       EINTR = 4,  /* Interrupted system call */
+       EIO = 5,  /* I/O error */
+       ENXIO = 6,  /* No such device or address */
+       E2BIG = 7,  /* Argument list too long */
+       ENOEXEC = 8,  /* Exec format error */
+       EBADF = 9,  /* Bad file number */
+       ECHILD = 10,  /* No child processes */
+       EAGAIN = 11,  /* Try again */
+       ENOMEM = 12,  /* Out of memory */
+       EACCES = 13,  /* Permission denied */
+       EFAULT = 14,  /* Bad address */
+       EBUSY = 16,  /* Device or resource busy */
+       EEXIST = 17,  /* File exists */
+       EXDEV = 18,  /* Cross-device link */
+       ENODEV = 19,  /* No such device */
+       ENOTDIR = 20,  /* Not a directory */
+       EISDIR = 21,  /* Is a directory */
+       EINVAL = 22,  /* Invalid argument */
+       ENFILE = 23,  /* File table overflow */
+       EMFILE = 24,  /* Too many open files */
+       ENOTTY = 25,  /* Not a typewriter */
+       EFBIG = 27,  /* File too large */
+       ENOSPC = 28,  /* No space left on device */
+       ESPIPE = 29,  /* Illegal seek */
+       EROFS = 30,  /* Read-only file system */
+       EMLINK = 31,  /* Too many links */
+       EPIPE = 32,  /* Broken pipe */
+       ENAMETOOLONG = 36,  /* File name too long */
+       ENOSYS = 38,  /* Function not implemented */
+       EDQUOT = 122, /* Quota exceeded */
+       EDOM = 33,   /* Math arg out of domain of func */
+       ERANGE = 34, /* Math result not representable */
+       EDEADLK = 35,  /* Deadlock condition */
+       ENOLCK = 37, /* No record locks available */
+       ENOTEMPTY = 39,  /* Directory not empty */
+       ELOOP = 40,  /* Too many symbolic links */
+       ENOMSG = 42, /* No message of desired type */
+       EIDRM = 43,  /* Identifier removed */
+       ECHRNG = 44, /* Channel number out of range */
+       EL2NSYNC = 45, /* Level 2 not synchronized */
+       EL3HLT = 46, /* Level 3 halted */
+       EL3RST = 47, /* Level 3 reset */
+       ELNRNG = 48, /* Link number out of range */
+       EUNATCH = 49,  /* Protocol driver not attached */
+       ENOCSI = 50, /* No CSI structure available */
+       EL2HLT = 51, /* Level 2 halted */
+       EBADE = 52,  /* Invalid exchange */
+       EBADR = 53,  /* Invalid request descriptor */
+       EXFULL = 54, /* Exchange full */
+       ENOANO = 55, /* No anode */
+       EBADRQC = 56,  /* Invalid request code */
+       EBADSLT = 57,  /* Invalid slot */
+       EDEADLOCK = EDEADLK,  /* File locking deadlock error */
+       EBFONT = 59, /* Bad font file fmt */
+       ENOSTR = 60, /* Device not a stream */
+       ENODATA = 61,  /* No data (for no delay io) */
+       ETIME = 62,  /* Timer expired */
+       ENOSR = 63,  /* Out of streams resources */
+       ENONET = 64, /* Machine is not on the network */
+       ENOPKG = 65, /* Package not installed */
+       EREMOTE = 66,  /* The object is remote */
+       ENOLINK = 67,  /* The link has been severed */
+       EADV = 68,   /* Advertise error */
+       ESRMNT = 69, /* Srmount error */
+       ECOMM = 70,  /* Communication error on send */
+       EPROTO = 71, /* Protocol error */
+       EMULTIHOP = 72,  /* Multihop attempted */
+       EDOTDOT = 73,  /* Cross mount point (not really error) */
+       EBADMSG = 74,  /* Trying to read unreadable message */
+       EOVERFLOW = 75, /* Value too large for defined data type */
+       ENOTUNIQ = 76, /* Given log. name not unique */
+       EBADFD = 77, /* f.d. invalid for this operation */
+       EREMCHG = 78,  /* Remote address changed */
+       ELIBACC = 79,  /* Can't access a needed shared lib */
+       ELIBBAD = 80,  /* Accessing a corrupted shared lib */
+       ELIBSCN = 81,  /* .lib section in a.out corrupted */
+       ELIBMAX = 82,  /* Attempting to link in too many libs */
+       ELIBEXEC = 83, /* Attempting to exec a shared library */
+       EILSEQ = 84,
+       EUSERS = 87,
+       ENOTSOCK = 88,  /* Socket operation on non-socket */
+       EDESTADDRREQ = 89,  /* Destination address required */
+       EMSGSIZE = 90,    /* Message too long */
+       EPROTOTYPE = 91,  /* Protocol wrong type for socket */
+       ENOPROTOOPT = 92, /* Protocol not available */
+       EPROTONOSUPPORT = 93, /* Unknown protocol */
+       ESOCKTNOSUPPORT = 94, /* Socket type not supported */
+       EOPNOTSUPP = 95, /* Operation not supported on transport endpoint */
+       EPFNOSUPPORT = 96, /* Protocol family not supported */
+       EAFNOSUPPORT = 97, /* Address family not supported by protocol family */
+       EADDRINUSE = 98,    /* Address already in use */
+       EADDRNOTAVAIL = 99, /* Address not available */
+       ENETDOWN = 100,    /* Network interface is not configured */
+       ENETUNREACH = 101,   /* Network is unreachable */
+       ENETRESET = 102,
+       ECONNABORTED = 103,  /* Connection aborted */
+       ECONNRESET = 104,  /* Connection reset by peer */
+       ENOBUFS = 105, /* No buffer space available */
+       EISCONN = 106,   /* Socket is already connected */
+       ENOTCONN = 107,    /* Socket is not connected */
+       ESHUTDOWN = 108, /* Can't send after socket shutdown */
+       ETOOMANYREFS = 109,
+       ETIMEDOUT = 110,   /* Connection timed out */
+       ECONNREFUSED = 111,  /* Connection refused */
+       EHOSTDOWN = 112,   /* Host is down */
+       EHOSTUNREACH = 113,  /* Host is unreachable */
+       EALREADY = 114,    /* Socket already connected */
+       EINPROGRESS = 115,   /* Connection already in progress */
+       ESTALE = 116,
+       ENOTSUP = EOPNOTSUPP,   /* Not supported */
+       ENOMEDIUM = 123,   /* No medium (in tape drive) */
+       ECANCELED = 125, /* Operation canceled. */
+       ELBIN = 2048,  /* Inode is remote (not really error) */
+       EFTYPE = 2049,  /* Inappropriate file type or format */
+       ENMFILE = 2050,  /* No more files */
+       EPROCLIM = 2051,
+       ENOSHARE = 2052,  /* No such host or network path */
+       ECASECLASH = 2053,  /* Filename exists with different case */
+       EWOULDBLOCK = EAGAIN,      /* Operation would block */
+
+       // native_client/src/trusted/service_runtime/include/bits/mman.h.
+       // NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h.
+       // Those MAP_*values are different from these.
+       PROT_NONE       = 0x0,
+       PROT_READ       = 0x1,
+       PROT_WRITE      = 0x2,
+       PROT_EXEC       = 0x4,
+
+       MAP_SHARED      = 0x1,
+       MAP_PRIVATE     = 0x2,
+       MAP_FIXED       = 0x10,
+       MAP_ANON        = 0x20,
+};
+typedef byte* kevent_udata;
+
+int32  runtime·nacl_exception_stack(byte*, int32);
+int32  runtime·nacl_exception_handler(void*, void*);
+int32  runtime·nacl_sem_create(int32);
+int32  runtime·nacl_sem_wait(int32);
+int32  runtime·nacl_sem_post(int32);
+int32  runtime·nacl_mutex_create(int32);
+int32  runtime·nacl_mutex_lock(int32);
+int32  runtime·nacl_mutex_trylock(int32);
+int32  runtime·nacl_mutex_unlock(int32);
+int32  runtime·nacl_cond_create(int32);
+int32  runtime·nacl_cond_wait(int32, int32);
+int32  runtime·nacl_cond_signal(int32);
+int32  runtime·nacl_cond_broadcast(int32);
+int32  runtime·nacl_cond_timed_wait_abs(int32, int32, Timespec*);
+int32  runtime·nacl_thread_create(void*, void*, void*, void*);
+int32  runtime·nacl_nanosleep(Timespec*, Timespec*);
+
+void   runtime·sigpanic(void);
index c9887b66372ce328a22620c97512f59590353489..0069d5a774d71f8ae008f8c57d11849224d62bcf 100644 (file)
@@ -21,11 +21,19 @@ typedef     uint64          uintptr;
 typedef        int64           intptr;
 typedef        int64           intgo; // Go's int
 typedef        uint64          uintgo; // Go's uint
+typedef        uint64          uintreg;
 #else
 typedef        uint32          uintptr;
 typedef        int32           intptr;
 typedef        int32           intgo; // Go's int
 typedef        uint32          uintgo; // Go's uint
+typedef        uint32          uintreg;
+#endif
+
+#ifdef _64BITREG
+//typedef      uint64          uintreg;
+#else
+//typedef      uint32          uintreg;
 #endif
 
 /*
@@ -209,8 +217,8 @@ struct      Gobuf
        uintptr sp;
        uintptr pc;
        G*      g;
-       uintptr ret;
        void*   ctxt;
+       uintreg ret;
        uintptr lr;
 };
 struct GCStats
@@ -295,8 +303,8 @@ struct      M
 
        // Fields not known to debuggers.
        uint32  moreframesize;  // size arguments to morestack
-       uint32  moreargsize;
-       uintptr cret;           // return value from C
+       uint32  moreargsize;    // known by amd64 asm to follow moreframesize
+       uintreg cret;           // return value from C
        uint64  procid;         // for debuggers, but offset not hard-coded
        G*      gsignal;        // signal-handling G
        uintptr tls[4];         // thread-local storage (for x86 extern register)
@@ -479,6 +487,16 @@ struct     Itab
        void    (*fun[])(void);
 };
 
+#ifdef GOOS_nacl
+enum {
+   NaCl = 1,
+};
+#else
+enum {
+   NaCl = 0,
+};
+#endif
+
 #ifdef GOOS_windows
 enum {
    Windows = 1
@@ -512,6 +530,8 @@ struct      Timers
 
 // Package time knows the layout of this structure.
 // If this struct changes, adjust ../time/sleep.go:/runtimeTimer.
+// For GOOS=nacl, package syscall knows the layout of this structure.
+// If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer.
 struct Timer
 {
        int32   i;      // heap index
@@ -588,7 +608,7 @@ extern bool runtime·precisestack;
  * known to compiler
  */
 enum {
-       Structrnd = sizeof(uintptr)
+       Structrnd = sizeof(uintreg),
 };
 
 /*
@@ -762,6 +782,7 @@ void        runtime·dump(byte*, int32);
 int32  runtime·runetochar(byte*, int32);
 int32  runtime·charntorune(int32*, uint8*, int32);
 
+
 /*
  * This macro is used when writing C functions
  * called as if they were Go functions.
@@ -774,8 +795,6 @@ int32       runtime·charntorune(int32*, uint8*, int32);
  * first output value. Almost all code should write such
  * functions in .goc files, where goc2c (part of cmd/dist)
  * can arrange the correct alignment for the target system.
- * Goc2c also takes care of conveying to the garbage collector
- * which parts of the argument list are input vs outputs.
  *
  * Therefore, do NOT use this macro if at all possible.
  */ 
@@ -926,6 +945,7 @@ void        runtime·parsedebugvars(void);
 void   _rt0_go(void);
 void*  runtime·funcdata(Func*, int32);
 int32  runtime·setmaxthreads(int32);
+G*     runtime·timejump(void);
 
 #pragma        varargck        argpos  runtime·printf 1
 #pragma        varargck        type    "c"     int32
@@ -1016,13 +1036,6 @@ void     runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool w
 void   runtime·parfordo(ParFor *desc);
 void   runtime·parforiters(ParFor*, uintptr, uintptr*, uintptr*);
 
-/*
- * This is consistent across Linux and BSD.
- * If a new OS is added that is different, move this to
- * $GOOS/$GOARCH/defs.h.
- */
-#define EACCES         13
-
 /*
  * low level C-called
  */
@@ -1057,6 +1070,7 @@ void      reflect·call(FuncVal*, byte*, uint32);
 void   runtime·panic(Eface);
 void   runtime·panicindex(void);
 void   runtime·panicslice(void);
+void   runtime·panicdivide(void);
 
 /*
  * runtime c-called (but written in Go)
index 553ea87e49b38a8e718f1d1a099873ba26f1688c..9f3f52179c480a1bb9b7a0ef35ee941d06bf9269 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd
 
 #include "runtime.h"
 #include "defs_GOOS_GOARCH.h"
diff --git a/src/pkg/runtime/signal_nacl_386.h b/src/pkg/runtime/signal_nacl_386.h
new file mode 100644 (file)
index 0000000..c9481b5
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs)
+
+#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
+#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
+#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
+#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
+#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
+#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
+#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
+#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
+#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
+#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
+
+#define SIG_CS(info, ctxt) (~0)
+#define SIG_FS(info, ctxt) (~0)
+#define SIG_GS(info, ctxt) (~0)
+
+#define SIG_CODE0(info, ctxt) (~0)
+#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/pkg/runtime/signal_nacl_amd64p32.h b/src/pkg/runtime/signal_nacl_amd64p32.h
new file mode 100644 (file)
index 0000000..c58593a
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2013 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs64)
+
+#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
+#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
+#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
+#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
+#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
+#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
+#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
+#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
+#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
+#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
+#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
+#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
+#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
+#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
+#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
+#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
+#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
+#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags)
+
+#define SIG_CS(info, ctxt) (~0)
+#define SIG_FS(info, ctxt) (~0)
+#define SIG_GS(info, ctxt) (~0)
+
+#define SIG_CODE0(info, ctxt) (~0)
+#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/pkg/runtime/signals_nacl.h b/src/pkg/runtime/signals_nacl.h
new file mode 100644 (file)
index 0000000..229b585
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#define N SigNotify
+#define K SigKill
+#define T SigThrow
+#define P SigPanic
+#define D SigDefault
+
+SigTab runtime·sigtab[] = {
+       /* 0 */ 0, "SIGNONE: no trap",
+       /* 1 */ N+K, "SIGHUP: terminal line hangup",
+       /* 2 */ N+K, "SIGINT: interrupt",
+       /* 3 */ N+T, "SIGQUIT: quit",
+       /* 4 */ T, "SIGILL: illegal instruction",
+       /* 5 */ T, "SIGTRAP: trace trap",
+       /* 6 */ N+T, "SIGABRT: abort",
+       /* 7 */ T, "SIGEMT: emulate instruction executed",
+       /* 8 */ P, "SIGFPE: floating-point exception",
+       /* 9 */ 0, "SIGKILL: kill",
+       /* 10 */        P, "SIGBUS: bus error",
+       /* 11 */        P, "SIGSEGV: segmentation violation",
+       /* 12 */        T, "SIGSYS: bad system call",
+       /* 13 */        N, "SIGPIPE: write to broken pipe",
+       /* 14 */        N, "SIGALRM: alarm clock",
+       /* 15 */        N+K, "SIGTERM: termination",
+       /* 16 */        N, "SIGURG: urgent condition on socket",
+       /* 17 */        0, "SIGSTOP: stop",
+       /* 18 */        N+D, "SIGTSTP: keyboard stop",
+       /* 19 */        0, "SIGCONT: continue after stop",
+       /* 20 */        N, "SIGCHLD: child status has changed",
+       /* 21 */        N+D, "SIGTTIN: background read from tty",
+       /* 22 */        N+D, "SIGTTOU: background write to tty",
+       /* 23 */        N, "SIGIO: i/o now possible",
+       /* 24 */        N, "SIGXCPU: cpu limit exceeded",
+       /* 25 */        N, "SIGXFSZ: file size limit exceeded",
+       /* 26 */        N, "SIGVTALRM: virtual alarm clock",
+       /* 27 */        N, "SIGPROF: profiling alarm clock",
+       /* 28 */        N, "SIGWINCH: window size change",
+       /* 29 */        N, "SIGINFO: status request from keyboard",
+       /* 30 */        N, "SIGUSR1: user-defined signal 1",
+       /* 31 */        N, "SIGUSR2: user-defined signal 2",
+};
+
+#undef N
+#undef K
+#undef T
+#undef P
+#undef D
index f24337eac71240121c0eefea079613be34265c2e..a450b3e58443363280950ffcbda63cc537520d5d 100644 (file)
@@ -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 amd64 386
+// +build amd64 amd64p32 386
 
 #include "runtime.h"
 
@@ -14,6 +14,8 @@ runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt)
        uintptr *sp;
        
        sp = (uintptr*)gobuf->sp;
+       if(sizeof(uintreg) > sizeof(uintptr))
+               *--sp = 0;
        *--sp = (uintptr)gobuf->pc;
        gobuf->sp = (uintptr)sp;
        gobuf->pc = (uintptr)fn;
diff --git a/src/pkg/runtime/syscall_nacl.h b/src/pkg/runtime/syscall_nacl.h
new file mode 100644 (file)
index 0000000..b33852e
--- /dev/null
@@ -0,0 +1,71 @@
+// generated by mknacl.sh - do not edit
+#define SYS_null 1
+#define SYS_nameservice 2
+#define SYS_dup 8
+#define SYS_dup2 9
+#define SYS_open 10
+#define SYS_close 11
+#define SYS_read 12
+#define SYS_write 13
+#define SYS_lseek 14
+#define SYS_ioctl 15
+#define SYS_stat 16
+#define SYS_fstat 17
+#define SYS_chmod 18
+#define SYS_brk 20
+#define SYS_mmap 21
+#define SYS_munmap 22
+#define SYS_getdents 23
+#define SYS_mprotect 24
+#define SYS_list_mappings 25
+#define SYS_exit 30
+#define SYS_getpid 31
+#define SYS_sched_yield 32
+#define SYS_sysconf 33
+#define SYS_gettimeofday 40
+#define SYS_clock 41
+#define SYS_nanosleep 42
+#define SYS_clock_getres 43
+#define SYS_clock_gettime 44
+#define SYS_mkdir 45
+#define SYS_rmdir 46
+#define SYS_chdir 47
+#define SYS_getcwd 48
+#define SYS_unlink 49
+#define SYS_imc_makeboundsock 60
+#define SYS_imc_accept 61
+#define SYS_imc_connect 62
+#define SYS_imc_sendmsg 63
+#define SYS_imc_recvmsg 64
+#define SYS_imc_mem_obj_create 65
+#define SYS_imc_socketpair 66
+#define SYS_mutex_create 70
+#define SYS_mutex_lock 71
+#define SYS_mutex_trylock 72
+#define SYS_mutex_unlock 73
+#define SYS_cond_create 74
+#define SYS_cond_wait 75
+#define SYS_cond_signal 76
+#define SYS_cond_broadcast 77
+#define SYS_cond_timed_wait_abs 79
+#define SYS_thread_create 80
+#define SYS_thread_exit 81
+#define SYS_tls_init 82
+#define SYS_thread_nice 83
+#define SYS_tls_get 84
+#define SYS_second_tls_set 85
+#define SYS_second_tls_get 86
+#define SYS_exception_handler 87
+#define SYS_exception_stack 88
+#define SYS_exception_clear_flag 89
+#define SYS_sem_create 100
+#define SYS_sem_wait 101
+#define SYS_sem_post 102
+#define SYS_sem_get_value 103
+#define SYS_dyncode_create 104
+#define SYS_dyncode_modify 105
+#define SYS_dyncode_delete 106
+#define SYS_test_infoleak 109
+#define SYS_test_crash 110
+#define SYS_test_syscall_1 111
+#define SYS_test_syscall_2 112
index fa46d547a837222f2872ff5fb97c394aa92d0e02..bd431be2245dd209b7646f73db8731a70877cba8 100644 (file)
@@ -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 amd64 386
+// +build amd64 amd64p32 386
 
 #include "runtime.h"
 #include "arch_GOARCH.h"
@@ -52,7 +52,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
        // Start in the caller's frame.
        if(frame.pc == 0) {
                frame.pc = *(uintptr*)frame.sp;
-               frame.sp += sizeof(uintptr);
+               frame.sp += sizeof(uintreg);
        }
        
        f = runtime·findfunc(frame.pc);
@@ -101,14 +101,14 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                // Derive frame pointer and link register.
                if(frame.fp == 0) {
                        frame.fp = frame.sp + runtime·funcspdelta(f, frame.pc);
-                       frame.fp += sizeof(uintptr); // caller PC
+                       frame.fp += sizeof(uintreg); // caller PC
                }
                if(runtime·topofstack(f)) {
                        frame.lr = 0;
                        flr = nil;
                } else {
                        if(frame.lr == 0)
-                               frame.lr = ((uintptr*)frame.fp)[-1];
+                               frame.lr = ((uintreg*)frame.fp)[-1];
                        flr = runtime·findfunc(frame.lr);
                        if(flr == nil) {
                                runtime·printf("runtime: unexpected return pc for %s called from %p\n", runtime·funcname(f), frame.lr);
@@ -117,7 +117,7 @@ runtime·gentraceback(uintptr pc0, uintptr sp0, uintptr lr0, G *gp, int32 skip,
                        }
                }
                
-               frame.varp = (byte*)frame.fp - sizeof(uintptr);
+               frame.varp = (byte*)frame.fp - sizeof(uintreg);
 
                // Derive size of arguments.
                // Most functions have a fixed-size argument block,
index 8d965c086e4df1b5029fe3011d515a646bfacc55..ace1beb4cce7733549283bbb8ac8f17e0b683108 100644 (file)
@@ -32,6 +32,8 @@
  * to generate the code directly now.  Find and remove.
  */
 
+extern void runtime·panicdivide(void);
+
 typedef        unsigned long   ulong;
 typedef        unsigned int    uint;
 typedef        unsigned short  ushort;
@@ -240,6 +242,8 @@ dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
                }
        } else {
                if(num.hi >= den.lo){
+                       if(den.lo == 0)
+                               runtime·panicdivide();
                        q.hi = n = num.hi/den.lo;
                        num.hi -= den.lo*n;
                } else {
@@ -263,6 +267,8 @@ _divvu(Vlong *q, Vlong n, Vlong d)
 {
 
        if(n.hi == 0 && d.hi == 0) {
+               if(d.lo == 0)
+                       runtime·panicdivide();
                q->hi = 0;
                q->lo = n.lo / d.lo;
                return;
@@ -281,6 +287,8 @@ _modvu(Vlong *r, Vlong n, Vlong d)
 {
 
        if(n.hi == 0 && d.hi == 0) {
+               if(d.lo == 0)
+                       runtime·panicdivide();
                r->hi = 0;
                r->lo = n.lo % d.lo;
                return;
@@ -319,6 +327,8 @@ _divv(Vlong *q, Vlong n, Vlong d)
                        q->hi = 0;
                        return;
                }
+               if(d.lo == 0)
+                       runtime·panicdivide();
                q->lo = (long)n.lo / (long)d.lo;
                q->hi = ((long)q->lo) >> 31;
                return;
@@ -353,6 +363,8 @@ _modv(Vlong *r, Vlong n, Vlong d)
                        r->hi = 0;
                        return;
                }
+               if(d.lo == 0)
+                       runtime·panicdivide();
                r->lo = (long)n.lo % (long)d.lo;
                r->hi = ((long)r->lo) >> 31;
                return;
index 219163c60f7bc213b5e040a4e33cbe82db8d2102..9606e1607643d3ed3c7fba272c3d7c4529c9a432 100644 (file)
@@ -36,12 +36,6 @@ typedef signed char     schar;
 
 #define SIGN(n) (1UL<<(n-1))
 
-void
-runtime·panicdivide(void)
-{
-       runtime·panicstring("integer divide by zero");
-}
-
 typedef struct  Vlong   Vlong;
 struct  Vlong
 {
diff --git a/src/pkg/sync/atomic/asm_amd64p32.s b/src/pkg/sync/atomic/asm_amd64p32.s
new file mode 100644 (file)
index 0000000..4c602ab
--- /dev/null
@@ -0,0 +1,159 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "../../../cmd/ld/textflag.h"
+
+TEXT Â·SwapInt32(SB),NOSPLIT,$0-12
+       JMP     Â·SwapUint32(SB)
+
+TEXT Â·SwapUint32(SB),NOSPLIT,$0-12
+       MOVL    addr+0(FP), BX
+       MOVL    new+4(FP), AX
+       XCHGL   AX, 0(BX)
+       MOVL    AX, new+8(FP)
+       RET
+
+TEXT Â·SwapInt64(SB),NOSPLIT,$0-24
+       JMP     Â·SwapUint64(SB)
+
+TEXT Â·SwapUint64(SB),NOSPLIT,$0-24
+       MOVL    addr+0(FP), BX
+       TESTL   $7, BX
+       JZ      2(PC)
+       MOVL    0, BX // crash with nil ptr deref
+       MOVQ    new+8(FP), AX
+       XCHGQ   AX, 0(BX)
+       MOVQ    AX, new+16(FP)
+       RET
+
+TEXT Â·SwapUintptr(SB),NOSPLIT,$0-24
+       JMP     Â·SwapUint32(SB)
+
+TEXT Â·SwapPointer(SB),NOSPLIT,$0-24
+       JMP     Â·SwapUint32(SB)
+
+TEXT Â·CompareAndSwapInt32(SB),NOSPLIT,$0-17
+       JMP     Â·CompareAndSwapUint32(SB)
+
+TEXT Â·CompareAndSwapUint32(SB),NOSPLIT,$0-17
+       MOVL    addr+0(FP), BX
+       MOVL    old+4(FP), AX
+       MOVL    new+8(FP), CX
+       LOCK
+       CMPXCHGL        CX, 0(BX)
+       SETEQ   swapped+16(FP)
+       RET
+
+TEXT Â·CompareAndSwapUintptr(SB),NOSPLIT,$0-25
+       JMP     Â·CompareAndSwapUint32(SB)
+
+TEXT Â·CompareAndSwapPointer(SB),NOSPLIT,$0-25
+       JMP     Â·CompareAndSwapUint32(SB)
+
+TEXT Â·CompareAndSwapInt64(SB),NOSPLIT,$0-25
+       JMP     Â·CompareAndSwapUint64(SB)
+
+TEXT Â·CompareAndSwapUint64(SB),NOSPLIT,$0-25
+       MOVL    addr+0(FP), BX
+       TESTL   $7, BX
+       JZ      2(PC)
+       MOVL    0, BX // crash with nil ptr deref
+       MOVQ    old+8(FP), AX
+       MOVQ    new+16(FP), CX
+       LOCK
+       CMPXCHGQ        CX, 0(BX)
+       SETEQ   swapped+24(FP)
+       RET
+
+TEXT Â·AddInt32(SB),NOSPLIT,$0-12
+       JMP     Â·AddUint32(SB)
+
+TEXT Â·AddUint32(SB),NOSPLIT,$0-12
+       MOVL    addr+0(FP), BX
+       MOVL    delta+4(FP), AX
+       MOVL    AX, CX
+       LOCK
+       XADDL   AX, 0(BX)
+       ADDL    AX, CX
+       MOVL    CX, new+8(FP)
+       RET
+
+TEXT Â·AddUintptr(SB),NOSPLIT,$0-12
+       JMP     Â·AddUint32(SB)
+
+TEXT Â·AddInt64(SB),NOSPLIT,$0-12
+       JMP     Â·AddUint64(SB)
+
+TEXT Â·AddUint64(SB),NOSPLIT,$0-24
+       MOVL    addr+0(FP), BX
+       TESTL   $7, BX
+       JZ      2(PC)
+       MOVL    0, BX // crash with nil ptr deref
+       MOVQ    delta+8(FP), AX
+       MOVQ    AX, CX
+       LOCK
+       XADDQ   AX, 0(BX)
+       ADDQ    AX, CX
+       MOVQ    CX, new+16(FP)
+       RET
+
+TEXT Â·LoadInt32(SB),NOSPLIT,$0-12
+       JMP     Â·LoadUint32(SB)
+
+TEXT Â·LoadUint32(SB),NOSPLIT,$0-12
+       MOVL    addr+0(FP), AX
+       MOVL    0(AX), AX
+       MOVL    AX, val+8(FP)
+       RET
+
+TEXT Â·LoadInt64(SB),NOSPLIT,$0-16
+       JMP     Â·LoadUint64(SB)
+
+TEXT Â·LoadUint64(SB),NOSPLIT,$0-16
+       MOVL    addr+0(FP), AX
+       TESTL   $7, AX
+       JZ      2(PC)
+       MOVL    0, AX // crash with nil ptr deref
+       MOVQ    0(AX), AX
+       MOVQ    AX, val+8(FP)
+       RET
+
+TEXT Â·LoadUintptr(SB),NOSPLIT,$0-12
+       JMP     Â·LoadPointer(SB)
+
+TEXT Â·LoadPointer(SB),NOSPLIT,$0-12
+       MOVL    addr+0(FP), AX
+       MOVL    0(AX), AX
+       MOVL    AX, val+8(FP)
+       RET
+
+TEXT Â·StoreInt32(SB),NOSPLIT,$0-8
+       JMP     Â·StoreUint32(SB)
+
+TEXT Â·StoreUint32(SB),NOSPLIT,$0-8
+       MOVL    addr+0(FP), BX
+       MOVL    val+4(FP), AX
+       XCHGL   AX, 0(BX)
+       RET
+
+TEXT Â·StoreInt64(SB),NOSPLIT,$0-16
+       JMP     Â·StoreUint64(SB)
+
+TEXT Â·StoreUint64(SB),NOSPLIT,$0-16
+       MOVL    addr+0(FP), BX
+       TESTL   $7, BX
+       JZ      2(PC)
+       MOVL    0, BX // crash with nil ptr deref
+       MOVQ    val+8(FP), AX
+       XCHGQ   AX, 0(BX)
+       RET
+
+TEXT Â·StoreUintptr(SB),NOSPLIT,$0-8
+       JMP     Â·StorePointer(SB)
+
+TEXT Â·StorePointer(SB),NOSPLIT,$0-8
+       MOVL    addr+0(FP), BX
+       MOVL    val+4(FP), AX
+       XCHGL   AX, 0(BX)
+       RET
index e10effe7e6293c662ae03b9d5a943eb564ade696..c702158e8ccfba5bc5b770c0a36dfe1eb7bf510e 100644 (file)
@@ -813,7 +813,7 @@ func hammerSwapUintptr32(uaddr *uint32, count int) {
                new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16
                old := SwapUintptr(addr, new)
                if old>>16 != old<<16>>16 {
-                       panic(fmt.Sprintf("SwapUintptr is not atomic: %v", old))
+                       panic(fmt.Sprintf("SwapUintptr is not atomic: %#08x", old))
                }
        }
 }
@@ -827,7 +827,7 @@ func hammerSwapPointer32(uaddr *uint32, count int) {
                new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16
                old := uintptr(SwapPointer(addr, unsafe.Pointer(new)))
                if old>>16 != old<<16>>16 {
-                       panic(fmt.Sprintf("SwapPointer is not atomic: %v", old))
+                       panic(fmt.Sprintf("SwapPointer is not atomic: %#08x", old))
                }
        }
 }
diff --git a/src/pkg/syscall/asm_nacl_386.s b/src/pkg/syscall/asm_nacl_386.s
new file mode 100644 (file)
index 0000000..7f330d3
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2013 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 "../../cmd/ld/textflag.h"
+#include "../runtime/syscall_nacl.h"
+
+//
+// System call support for 386, Native Client
+//
+
+#define NACL_SYSCALL(code) \
+       MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+       MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT syscall·Syscall(SB),NOSPLIT,$12-32
+       CALL    runtime·entersyscall(SB)
+       MOVL    trap+0(FP), AX
+       MOVL    a1+4(FP), BX
+       MOVL    BX, 0(SP)
+       MOVL    a2+8(FP), BX
+       MOVL    BX, 4(SP)
+       MOVL    a3+12(FP), BX
+       MOVL    BX, 8(SP)
+       SHLL    $5, AX
+       ADDL    $0x10000, AX
+       CALL    AX
+       CMPL    AX, $0
+       JGE     ok
+       MOVL    $-1, r1+16(FP)
+       MOVL    $-1, r2+20(FP)
+       NEGL    AX
+       MOVL    AX, errno+24(FP)
+       CALL    runtime·exitsyscall(SB)
+       RET
+ok:
+       MOVL    AX, r1+16(FP)
+       MOVL    DX, r2+20(FP)
+       MOVL    $0, errno+24(FP)
+       CALL    runtime·exitsyscall(SB)
+       RET     
diff --git a/src/pkg/syscall/asm_nacl_amd64p32.s b/src/pkg/syscall/asm_nacl_amd64p32.s
new file mode 100644 (file)
index 0000000..0ff6ece
--- /dev/null
@@ -0,0 +1,41 @@
+// Copyright 2013 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 "../../cmd/ld/textflag.h"
+#include "../runtime/syscall_nacl.h"
+
+//
+// System call support for amd64, Native Client
+//
+
+#define NACL_SYSCALL(code) \
+       MOVL $(0x10000 + ((code)<<5)), AX; CALL AX
+
+#define NACL_SYSJMP(code) \
+       MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
+
+TEXT syscall·Syscall(SB),NOSPLIT,$0-32
+       CALL    runtime·entersyscall(SB)
+       MOVL    trap+0(FP), AX
+       MOVL    a1+4(FP), DI
+       MOVL    a2+8(FP), SI
+       MOVL    a3+12(FP), DX
+       // more args would use CX, R8, R9
+       SHLL    $5, AX
+       ADDL    $0x10000, AX
+       CALL    AX
+       CMPL    AX, $0
+       JGE     ok
+       MOVL    $-1, r1+16(FP)
+       MOVL    $-1, r2+20(FP)
+       NEGL    AX
+       MOVL    AX, errno+24(FP)
+       CALL    runtime·exitsyscall(SB)
+       RET
+ok:
+       MOVL    AX, r1+16(FP)
+       MOVL    DX, r2+20(FP)
+       MOVL    $0, errno+24(FP)
+       CALL    runtime·exitsyscall(SB)
+       RET     
index 76663c6c415e15ad930fbfd5b83e674ec3be22a2..ad354ed05785cfcdc5ee6230930667a16a26ea12 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 // Unix environment variables.
 
diff --git a/src/pkg/syscall/fd_nacl.go b/src/pkg/syscall/fd_nacl.go
new file mode 100644 (file)
index 0000000..cbc8315
--- /dev/null
@@ -0,0 +1,320 @@
+// Copyright 2013 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.
+
+// File descriptor support for Native Client.
+// We want to provide access to a broader range of (simulated) files than
+// Native Client allows, so we maintain our own file descriptor table exposed
+// to higher-level packages.
+
+package syscall
+
+import (
+       "sync"
+)
+
+// files is the table indexed by a file descriptor.
+var files struct {
+       sync.RWMutex
+       tab []*file
+}
+
+// A file is an open file, something with a file descriptor.
+// A particular *file may appear in files multiple times, due to use of Dup or Dup2.
+type file struct {
+       fdref int      // uses in files.tab
+       impl  fileImpl // underlying implementation
+}
+
+// A fileImpl is the implementation of something that can be a file.
+type fileImpl interface {
+       // Standard operations.
+       // These can be called concurrently from multiple goroutines.
+       stat(*Stat_t) error
+       read([]byte) (int, error)
+       write([]byte) (int, error)
+       seek(int64, int) (int64, error)
+       pread([]byte, int64) (int, error)
+       pwrite([]byte, int64) (int, error)
+
+       // Close is called when the last reference to a *file is removed
+       // from the file descriptor table. It may be called concurrently
+       // with active operations such as blocked read or write calls.
+       close() error
+}
+
+// newFD adds impl to the file descriptor table,
+// returning the new file descriptor.
+// Like Unix, it uses the lowest available descriptor.
+func newFD(impl fileImpl) int {
+       files.Lock()
+       defer files.Unlock()
+       f := &file{impl: impl, fdref: 1}
+       for fd, oldf := range files.tab {
+               if oldf == nil {
+                       files.tab[fd] = f
+                       return fd
+               }
+       }
+       fd := len(files.tab)
+       files.tab = append(files.tab, f)
+       return fd
+}
+
+// Install Native Client stdin, stdout, stderr.
+func init() {
+       newFD(&naclFile{naclFD: 0})
+       newFD(&naclFile{naclFD: 1})
+       newFD(&naclFile{naclFD: 2})
+}
+
+// fdToFile retrieves the *file corresponding to a file descriptor.
+func fdToFile(fd int) (*file, error) {
+       files.Lock()
+       defer files.Unlock()
+       if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+               return nil, EBADF
+       }
+       return files.tab[fd], nil
+}
+
+func Close(fd int) error {
+       files.Lock()
+       if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+               files.Unlock()
+               return EBADF
+       }
+       f := files.tab[fd]
+       files.tab[fd] = nil
+       f.fdref--
+       fdref := f.fdref
+       files.Unlock()
+       if fdref > 0 {
+               return nil
+       }
+       return f.impl.close()
+}
+
+func CloseOnExec(fd int) {
+       // nothing to do - no exec
+}
+
+func Dup(fd int) (int, error) {
+       files.Lock()
+       defer files.Unlock()
+       if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil {
+               return -1, EBADF
+       }
+       f := files.tab[fd]
+       f.fdref++
+       for newfd, oldf := range files.tab {
+               if oldf == nil {
+                       files.tab[newfd] = f
+                       return newfd, nil
+               }
+       }
+       newfd := len(files.tab)
+       files.tab = append(files.tab, f)
+       return newfd, nil
+}
+
+func Dup2(fd, newfd int) error {
+       files.Lock()
+       defer files.Unlock()
+       if fd < 0 || fd >= len(files.tab) || files.tab[fd] == nil || newfd < 0 || newfd >= len(files.tab)+100 {
+               files.Unlock()
+               return EBADF
+       }
+       f := files.tab[fd]
+       f.fdref++
+       for cap(files.tab) <= newfd {
+               files.tab = append(files.tab[:cap(files.tab)], nil)
+       }
+       oldf := files.tab[newfd]
+       var oldfdref int
+       if oldf != nil {
+               oldf.fdref--
+               oldfdref = oldf.fdref
+       }
+       files.tab[newfd] = f
+       files.Unlock()
+       if oldf != nil {
+               if oldfdref == 0 {
+                       oldf.impl.close()
+               }
+       }
+       return nil
+}
+
+func Fstat(fd int, st *Stat_t) error {
+       f, err := fdToFile(fd)
+       if err != nil {
+               return err
+       }
+       return f.impl.stat(st)
+}
+
+func Read(fd int, b []byte) (int, error) {
+       f, err := fdToFile(fd)
+       if err != nil {
+               return 0, err
+       }
+       return f.impl.read(b)
+}
+
+func Write(fd int, b []byte) (int, error) {
+       f, err := fdToFile(fd)
+       if err != nil {
+               return 0, err
+       }
+       return f.impl.write(b)
+}
+
+func Pread(fd int, b []byte, offset int64) (int, error) {
+       f, err := fdToFile(fd)
+       if err != nil {
+               return 0, err
+       }
+       return f.impl.pread(b, offset)
+}
+
+func Pwrite(fd int, b []byte, offset int64) (int, error) {
+       f, err := fdToFile(fd)
+       if err != nil {
+               return 0, err
+       }
+       return f.impl.pwrite(b, offset)
+}
+
+func Seek(fd int, offset int64, whence int) (int64, error) {
+       f, err := fdToFile(fd)
+       if err != nil {
+               return 0, err
+       }
+       return f.impl.seek(offset, whence)
+}
+
+// defaulFileImpl imlements fileImpl.
+// It can be embedded to complete a partial fileImpl implementation.
+type defaultFileImpl struct{}
+
+func (*defaultFileImpl) close() error                      { return nil }
+func (*defaultFileImpl) stat(*Stat_t) error                { return ENOSYS }
+func (*defaultFileImpl) read([]byte) (int, error)          { return 0, ENOSYS }
+func (*defaultFileImpl) write([]byte) (int, error)         { return 0, ENOSYS }
+func (*defaultFileImpl) seek(int64, int) (int64, error)    { return 0, ENOSYS }
+func (*defaultFileImpl) pread([]byte, int64) (int, error)  { return 0, ENOSYS }
+func (*defaultFileImpl) pwrite([]byte, int64) (int, error) { return 0, ENOSYS }
+
+// naclFile is the fileImpl implementation for a Native Client file descriptor.
+type naclFile struct {
+       defaultFileImpl
+       naclFD int
+}
+
+func (f *naclFile) stat(st *Stat_t) error {
+       return naclFstat(f.naclFD, st)
+}
+
+func (f *naclFile) read(b []byte) (int, error) {
+       n, err := naclRead(f.naclFD, b)
+       if err != nil {
+               n = 0
+       }
+       return n, err
+}
+
+// implemented in package runtime, to add time header on playground
+func naclWrite(fd int, b []byte) int
+
+func (f *naclFile) write(b []byte) (int, error) {
+       n := naclWrite(f.naclFD, b)
+       if n < 0 {
+               return 0, Errno(-n)
+       }
+       return n, nil
+}
+
+func (f *naclFile) seek(off int64, whence int) (int64, error) {
+       old := off
+       err := naclSeek(f.naclFD, &off, whence)
+       if err != nil {
+               return old, err
+       }
+       return off, nil
+}
+
+func (f *naclFile) prw(b []byte, offset int64, rw func([]byte) (int, error)) (int, error) {
+       // NaCl has no pread; simulate with seek and hope for no races.
+       old, err := f.seek(0, 1)
+       if err != nil {
+               return 0, err
+       }
+       if _, err := f.seek(offset, 0); err != nil {
+               return 0, err
+       }
+       n, err := rw(b)
+       f.seek(old, 0)
+       return n, err
+}
+
+func (f *naclFile) pread(b []byte, offset int64) (int, error) {
+       return f.prw(b, offset, f.read)
+}
+
+func (f *naclFile) pwrite(b []byte, offset int64) (int, error) {
+       return f.prw(b, offset, f.write)
+}
+
+func (f *naclFile) close() error {
+       err := naclClose(f.naclFD)
+       f.naclFD = -1
+       return err
+}
+
+// A pipeFile is an in-memory implementation of a pipe.
+// The byteq implementation is in net_nacl.go.
+type pipeFile struct {
+       defaultFileImpl
+       rd *byteq
+       wr *byteq
+}
+
+func (f *pipeFile) close() error {
+       if f.rd != nil {
+               f.rd.close()
+       }
+       if f.wr != nil {
+               f.wr.close()
+       }
+       return nil
+}
+
+func (f *pipeFile) read(b []byte) (int, error) {
+       if f.rd == nil {
+               return 0, EINVAL
+       }
+       n, err := f.rd.read(b, 0)
+       if err == EAGAIN {
+               err = nil
+       }
+       return n, err
+}
+
+func (f *pipeFile) write(b []byte) (int, error) {
+       if f.wr == nil {
+               return 0, EINVAL
+       }
+       n, err := f.wr.write(b, 0)
+       if err == EAGAIN {
+               err = EPIPE
+       }
+       return n, err
+}
+
+func Pipe(fd []int) error {
+       q := newByteq()
+       fd[0] = newFD(&pipeFile{rd: q})
+       fd[1] = newFD(&pipeFile{wr: q})
+       return nil
+}
diff --git a/src/pkg/syscall/fs_nacl.go b/src/pkg/syscall/fs_nacl.go
new file mode 100644 (file)
index 0000000..ac92394
--- /dev/null
@@ -0,0 +1,815 @@
+// Copyright 2013 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.
+
+// A simulated Unix-like file system for use within NaCl.
+//
+// The simulation is not particularly tied to NaCl other than the reuse
+// of NaCl's definition for the Stat_t structure.
+//
+// The file system need never be written to disk, so it is represented as
+// in-memory Go data structures, never in a serialized form.
+//
+// TODO: Perhaps support symlinks, although they muck everything up.
+
+package syscall
+
+import (
+       "sync"
+       "unsafe"
+)
+
+// Provided by package runtime.
+func now() (sec int64, nsec int32)
+
+// An fsys is a file system.
+// Since there is no I/O (everything is in memory),
+// the global lock mu protects the whole file system state,
+// and that's okay.
+type fsys struct {
+       mu   sync.Mutex
+       root *inode                    // root directory
+       cwd  *inode                    // process current directory
+       inum uint64                    // number of inodes created
+       dev  []func() (devFile, error) // table for opening devices
+}
+
+// A devFile is the implementation required of device files
+// like /dev/null or /dev/random.
+type devFile interface {
+       pread([]byte, int64) (int, error)
+       pwrite([]byte, int64) (int, error)
+}
+
+// An inode is a (possibly special) file in the file system.
+type inode struct {
+       Stat_t
+       data []byte
+       dir  []dirent
+}
+
+// A dirent describes a single directory entry.
+type dirent struct {
+       name  string
+       inode *inode
+}
+
+// An fsysFile is the fileImpl implementation backed by the file system.
+type fsysFile struct {
+       defaultFileImpl
+       fsys     *fsys
+       inode    *inode
+       openmode int
+       offset   int64
+       dev      devFile
+}
+
+// newFsys creates a new file system.
+func newFsys() *fsys {
+       fs := &fsys{}
+       fs.mu.Lock()
+       defer fs.mu.Unlock()
+       ip := fs.newInode()
+       ip.Mode = 0555 | S_IFDIR
+       fs.dirlink(ip, ".", ip)
+       fs.dirlink(ip, "..", ip)
+       fs.cwd = ip
+       fs.root = ip
+       return fs
+}
+
+var fs = newFsys()
+
+func init() {
+       Mkdir("/dev", 0555)
+       Mkdir("/tmp", 0777)
+       mkdev("/dev/null", 0666, openNull)
+       mkdev("/dev/random", 0444, openRandom)
+       mkdev("/dev/urandom", 0444, openRandom)
+       mkdev("/dev/zero", 0666, openZero)
+       chdirEnv()
+}
+
+func chdirEnv() {
+       pwd, ok := Getenv("NACLPWD")
+       if ok {
+               Chdir(pwd)
+       }
+}
+
+// Except where indicated otherwise, unexported methods on fsys
+// expect fs.mu to have been locked by the caller.
+
+// newInode creates a new inode.
+func (fs *fsys) newInode() *inode {
+       fs.inum++
+       ip := &inode{
+               Stat_t: Stat_t{
+                       Ino:     fs.inum,
+                       Blksize: 512,
+               },
+       }
+       return ip
+}
+
+// atime sets ip.Atime to the current time.
+func (fs *fsys) atime(ip *inode) {
+       sec, nsec := now()
+       ip.Atime, ip.AtimeNsec = sec, int64(nsec)
+}
+
+// mtime sets ip.Mtime to the current time.
+func (fs *fsys) mtime(ip *inode) {
+       sec, nsec := now()
+       ip.Mtime, ip.MtimeNsec = sec, int64(nsec)
+}
+
+// dirlookup looks for an entry in the directory dp with the given name.
+// It returns the directory entry and its index within the directory.
+func (fs *fsys) dirlookup(dp *inode, name string) (de *dirent, index int, err error) {
+       fs.atime(dp)
+       for i := range dp.dir {
+               de := &dp.dir[i]
+               if de.name == name {
+                       fs.atime(de.inode)
+                       return de, i, nil
+               }
+       }
+       return nil, 0, ENOENT
+}
+
+// dirlink adds to the directory dp an entry for name pointing at the inode ip.
+// If dp already contains an entry for name, that entry is overwritten.
+func (fs *fsys) dirlink(dp *inode, name string, ip *inode) {
+       fs.mtime(dp)
+       fs.atime(ip)
+       ip.Nlink++
+       for i := range dp.dir {
+               if dp.dir[i].name == name {
+                       dp.dir[i] = dirent{name, ip}
+                       return
+               }
+       }
+       dp.dir = append(dp.dir, dirent{name, ip})
+       dp.dirSize()
+}
+
+func (dp *inode) dirSize() {
+       dp.Size = int64(len(dp.dir)) * (8 + 8 + 2 + 256) // Dirent
+}
+
+// skipelem splits path into the first element and the remainder.
+// the returned first element contains no slashes, and the returned
+// remainder does not begin with a slash.
+func skipelem(path string) (elem, rest string) {
+       for len(path) > 0 && path[0] == '/' {
+               path = path[1:]
+       }
+       if len(path) == 0 {
+               return "", ""
+       }
+       i := 0
+       for i < len(path) && path[i] != '/' {
+               i++
+       }
+       elem, path = path[:i], path[i:]
+       for len(path) > 0 && path[0] == '/' {
+               path = path[1:]
+       }
+       return elem, path
+}
+
+// namei translates a file system path name into an inode.
+// If parent is false, the returned ip corresponds to the given name, and elem is the empty string.
+// If parent is false, the walk stops at the next-to-last element in the name,
+// so that ip is the parent directory and elem is the final element in the path.
+func (fs *fsys) namei(path string, parent bool) (ip *inode, elem string, err error) {
+       // Reject NUL in name.
+       for i := 0; i < len(path); i++ {
+               if path[i] == '\x00' {
+                       return nil, "", EINVAL
+               }
+       }
+
+       // Reject empty name.
+       if path == "" {
+               return nil, "", EINVAL
+       }
+
+       if path[0] == '/' {
+               ip = fs.root
+       } else {
+               ip = fs.cwd
+       }
+
+       for len(path) > 0 && path[len(path)-1] == '/' {
+               path = path[:len(path)-1]
+       }
+
+       for {
+               elem, rest := skipelem(path)
+               if elem == "" {
+                       if parent && ip.Mode&S_IFMT == S_IFDIR {
+                               return ip, ".", nil
+                       }
+                       break
+               }
+               if ip.Mode&S_IFMT != S_IFDIR {
+                       return nil, "", ENOTDIR
+               }
+               if len(elem) >= 256 {
+                       return nil, "", ENAMETOOLONG
+               }
+               if parent && rest == "" {
+                       // Stop one level early.
+                       return ip, elem, nil
+               }
+               de, _, err := fs.dirlookup(ip, elem)
+               if err != nil {
+                       return nil, "", err
+               }
+               ip = de.inode
+               path = rest
+       }
+       if parent {
+               return nil, "", ENOTDIR
+       }
+       return ip, "", nil
+}
+
+// open opens or creates a file with the given name, open mode,
+// and permission mode bits.
+func (fs *fsys) open(name string, openmode int, mode uint32) (fileImpl, error) {
+       dp, elem, err := fs.namei(name, true)
+       if err != nil {
+               return nil, err
+       }
+       var (
+               ip  *inode
+               dev devFile
+       )
+       de, _, err := fs.dirlookup(dp, elem)
+       if err != nil {
+               if openmode&O_CREATE == 0 {
+                       return nil, err
+               }
+               ip = fs.newInode()
+               ip.Mode = mode
+               fs.dirlink(dp, elem, ip)
+               if ip.Mode&S_IFMT == S_IFDIR {
+                       fs.dirlink(ip, ".", ip)
+                       fs.dirlink(ip, "..", dp)
+               }
+       } else {
+               ip = de.inode
+               if openmode&(O_CREATE|O_EXCL) == O_CREATE|O_EXCL {
+                       return nil, EEXIST
+               }
+               if openmode&O_TRUNC != 0 {
+                       if ip.Mode&S_IFMT == S_IFDIR {
+                               return nil, EISDIR
+                       }
+                       ip.data = nil
+               }
+               if ip.Mode&S_IFMT == S_IFCHR {
+                       if ip.Rdev < 0 || ip.Rdev >= int64(len(fs.dev)) || fs.dev[ip.Rdev] == nil {
+                               return nil, ENODEV
+                       }
+                       dev, err = fs.dev[ip.Rdev]()
+                       if err != nil {
+                               return nil, err
+                       }
+               }
+       }
+
+       switch openmode & O_ACCMODE {
+       case O_WRONLY, O_RDWR:
+               if ip.Mode&S_IFMT == S_IFDIR {
+                       return nil, EISDIR
+               }
+       }
+
+       switch ip.Mode & S_IFMT {
+       case S_IFDIR:
+               if openmode&O_ACCMODE != O_RDONLY {
+                       return nil, EISDIR
+               }
+
+       case S_IFREG:
+               // ok
+
+       case S_IFCHR:
+               // handled above
+
+       default:
+               // TODO: some kind of special file
+               return nil, EPERM
+       }
+
+       f := &fsysFile{
+               fsys:     fs,
+               inode:    ip,
+               openmode: openmode,
+               dev:      dev,
+       }
+       if openmode&O_APPEND != 0 {
+               f.offset = ip.Size
+       }
+       return f, nil
+}
+
+// fsysFile methods to implement fileImpl.
+
+func (f *fsysFile) stat(st *Stat_t) error {
+       f.fsys.mu.Lock()
+       defer f.fsys.mu.Unlock()
+       *st = f.inode.Stat_t
+       return nil
+}
+
+func (f *fsysFile) read(b []byte) (int, error) {
+       f.fsys.mu.Lock()
+       defer f.fsys.mu.Unlock()
+       n, err := f.preadLocked(b, f.offset)
+       f.offset += int64(n)
+       return n, err
+}
+
+func ReadDirent(fd int, buf []byte) (int, error) {
+       f, err := fdToFsysFile(fd)
+       if err != nil {
+               return 0, err
+       }
+       f.fsys.mu.Lock()
+       defer f.fsys.mu.Unlock()
+       if f.inode.Mode&S_IFMT != S_IFDIR {
+               return 0, EINVAL
+       }
+       n, err := f.preadLocked(buf, f.offset)
+       f.offset += int64(n)
+       return n, err
+}
+
+func (f *fsysFile) write(b []byte) (int, error) {
+       f.fsys.mu.Lock()
+       defer f.fsys.mu.Unlock()
+       n, err := f.pwriteLocked(b, f.offset)
+       f.offset += int64(n)
+       return n, err
+}
+
+func (f *fsysFile) seek(offset int64, whence int) (int64, error) {
+       f.fsys.mu.Lock()
+       defer f.fsys.mu.Unlock()
+       switch whence {
+       case 1:
+               offset += f.offset
+       case 2:
+               offset += f.inode.Size
+       }
+       if offset < 0 {
+               return 0, EINVAL
+       }
+       if offset > f.inode.Size {
+               return 0, EINVAL
+       }
+       f.offset = offset
+       return offset, nil
+}
+
+func (f *fsysFile) pread(b []byte, offset int64) (int, error) {
+       f.fsys.mu.Lock()
+       defer f.fsys.mu.Unlock()
+       return f.preadLocked(b, offset)
+}
+
+func (f *fsysFile) pwrite(b []byte, offset int64) (int, error) {
+       f.fsys.mu.Lock()
+       defer f.fsys.mu.Unlock()
+       return f.pwriteLocked(b, offset)
+}
+
+func (f *fsysFile) preadLocked(b []byte, offset int64) (int, error) {
+       if f.openmode&O_ACCMODE == O_WRONLY {
+               return 0, EINVAL
+       }
+       if offset < 0 {
+               return 0, EINVAL
+       }
+       if f.dev != nil {
+               f.fsys.atime(f.inode)
+               f.fsys.mu.Unlock()
+               defer f.fsys.mu.Lock()
+               return f.dev.pread(b, offset)
+       }
+       if offset > f.inode.Size {
+               return 0, nil
+       }
+       if int64(len(b)) > f.inode.Size-offset {
+               b = b[:f.inode.Size-offset]
+       }
+
+       if f.inode.Mode&S_IFMT == S_IFDIR {
+               if offset%direntSize != 0 || len(b) != 0 && len(b) < direntSize {
+                       return 0, EINVAL
+               }
+               fs.atime(f.inode)
+               n := 0
+               for len(b) >= direntSize {
+                       src := f.inode.dir[int(offset/direntSize)]
+                       dst := (*Dirent)(unsafe.Pointer(&b[0]))
+                       dst.Ino = int64(src.inode.Ino)
+                       dst.Off = offset
+                       dst.Reclen = direntSize
+                       for i := range dst.Name {
+                               dst.Name[i] = 0
+                       }
+                       copy(dst.Name[:], src.name)
+                       n += direntSize
+                       offset += direntSize
+                       b = b[direntSize:]
+               }
+               return n, nil
+       }
+
+       fs.atime(f.inode)
+       n := copy(b, f.inode.data[offset:])
+       return n, nil
+}
+
+func (f *fsysFile) pwriteLocked(b []byte, offset int64) (int, error) {
+       if f.openmode&O_ACCMODE == O_RDONLY {
+               return 0, EINVAL
+       }
+       if offset < 0 {
+               return 0, EINVAL
+       }
+       if f.dev != nil {
+               f.fsys.atime(f.inode)
+               f.fsys.mu.Unlock()
+               defer f.fsys.mu.Lock()
+               return f.dev.pwrite(b, offset)
+       }
+       if offset > f.inode.Size {
+               return 0, EINVAL
+       }
+       f.fsys.mtime(f.inode)
+       n := copy(f.inode.data[offset:], b)
+       if n < len(b) {
+               f.inode.data = append(f.inode.data, b[n:]...)
+               f.inode.Size = int64(len(f.inode.data))
+       }
+       return len(b), nil
+}
+
+// Standard Unix system calls.
+
+func Open(path string, openmode int, perm uint32) (fd int, err error) {
+       fs.mu.Lock()
+       defer fs.mu.Unlock()
+       f, err := fs.open(path, openmode, perm&0777|S_IFREG)
+       if err != nil {
+               return -1, err
+       }
+       return newFD(f), nil
+}
+
+func Mkdir(path string, perm uint32) error {
+       fs.mu.Lock()
+       defer fs.mu.Unlock()
+       _, err := fs.open(path, O_CREATE|O_EXCL, perm&0777|S_IFDIR)
+       return err
+}
+
+func Getcwd(buf []byte) (n int, err error) {
+       // Force package os to default to the old algorithm using .. and directory reads.
+       return 0, ENOSYS
+}
+
+func Stat(path string, st *Stat_t) error {
+       fs.mu.Lock()
+       defer fs.mu.Unlock()
+       ip, _, err := fs.namei(path, false)
+       if err != nil {
+               return err
+       }
+       *st = ip.Stat_t
+       return nil
+}
+
+func Lstat(path string, st *Stat_t) error {
+       return Stat(path, st)
+}
+
+func unlink(path string, isdir bool) error {
+       fs.mu.Lock()
+       defer fs.mu.Unlock()
+       dp, elem, err := fs.namei(path, true)
+       if err != nil {
+               return err
+       }
+       if elem == "." || elem == ".." {
+               return EINVAL
+       }
+       de, _, err := fs.dirlookup(dp, elem)
+       if err != nil {
+               return err
+       }
+       if isdir {
+               if de.inode.Mode&S_IFMT != S_IFDIR {
+                       return ENOTDIR
+               }
+               if len(de.inode.dir) != 2 {
+                       return ENOTEMPTY
+               }
+       } else {
+               if de.inode.Mode&S_IFMT == S_IFDIR {
+                       return EISDIR
+               }
+       }
+       de.inode.Nlink--
+       *de = dp.dir[len(dp.dir)-1]
+       dp.dir = dp.dir[:len(dp.dir)-1]
+       dp.dirSize()
+       return nil
+}
+
+func Unlink(path string) error {
+       return unlink(path, false)
+}
+
+func Rmdir(path string) error {
+       return unlink(path, true)
+}
+
+func Chmod(path string, mode uint32) error {
+       fs.mu.Lock()
+       defer fs.mu.Unlock()
+       ip, _, err := fs.namei(path, false)
+       if err != nil {
+               return err
+       }
+       ip.Mode = ip.Mode&^0777 | mode&0777
+       return nil
+}
+
+func Fchmod(fd int, mode uint32) error {
+       f, err := fdToFsysFile(fd)
+       if err != nil {
+               return err
+       }
+       f.fsys.mu.Lock()
+       defer f.fsys.mu.Unlock()
+       f.inode.Mode = f.inode.Mode&^0777 | mode&0777
+       return nil
+}
+
+func Chown(path string, uid, gid int) error {
+       fs.mu.Lock()
+       defer fs.mu.Unlock()
+       ip, _, err := fs.namei(path, false)
+       if err != nil {
+               return err
+       }
+       ip.Uid = uint32(uid)
+       ip.Gid = uint32(gid)
+       return nil
+}
+
+func Fchown(fd int, uid, gid int) error {
+       fs.mu.Lock()
+       defer fs.mu.Unlock()
+       f, err := fdToFsysFile(fd)
+       if err != nil {
+               return err
+       }
+       f.fsys.mu.Lock()
+       defer f.fsys.mu.Unlock()
+       f.inode.Uid = uint32(uid)
+       f.inode.Gid = uint32(gid)
+       return nil
+}
+
+func Lchown(path string, uid, gid int) error {
+       return Chown(path, uid, gid)
+}
+
+func UtimesNano(path string, ts []Timespec) error {
+       if len(ts) != 2 {
+               return EINVAL
+       }
+       fs.mu.Lock()
+       defer fs.mu.Unlock()
+       ip, _, err := fs.namei(path, false)
+       if err != nil {
+               return err
+       }
+       ip.Atime = ts[0].Sec
+       ip.AtimeNsec = int64(ts[0].Nsec)
+       ip.Mtime = ts[1].Sec
+       ip.MtimeNsec = int64(ts[1].Nsec)
+       return nil
+}
+
+func Link(path, link string) error {
+       ip, _, err := fs.namei(path, false)
+       if err != nil {
+               return err
+       }
+       dp, elem, err := fs.namei(link, true)
+       if err != nil {
+               return err
+       }
+       if ip.Mode&S_IFMT == S_IFDIR {
+               return EPERM
+       }
+       fs.dirlink(dp, elem, ip)
+       return nil
+}
+
+func Rename(from, to string) error {
+       fdp, felem, err := fs.namei(from, true)
+       if err != nil {
+               return err
+       }
+       fde, _, err := fs.dirlookup(fdp, felem)
+       if err != nil {
+               return err
+       }
+       tdp, telem, err := fs.namei(to, true)
+       if err != nil {
+               return err
+       }
+       fs.dirlink(tdp, telem, fde.inode)
+       fde.inode.Nlink--
+       *fde = fdp.dir[len(fdp.dir)-1]
+       fdp.dir = fdp.dir[:len(fdp.dir)-1]
+       fdp.dirSize()
+       return nil
+}
+
+func (fs *fsys) truncate(ip *inode, length int64) error {
+       if length > 1e9 || ip.Mode&S_IFMT != S_IFREG {
+               return EINVAL
+       }
+       if length < int64(len(ip.data)) {
+               ip.data = ip.data[:length]
+       } else {
+               data := make([]byte, length)
+               copy(data, ip.data)
+               ip.data = data
+       }
+       ip.Size = int64(len(ip.data))
+       return nil
+}
+
+func Truncate(path string, length int64) error {
+       fs.mu.Lock()
+       defer fs.mu.Unlock()
+       ip, _, err := fs.namei(path, false)
+       if err != nil {
+               return err
+       }
+       return fs.truncate(ip, length)
+}
+
+func Ftruncate(fd int, length int64) error {
+       f, err := fdToFsysFile(fd)
+       if err != nil {
+               return err
+       }
+       f.fsys.mu.Lock()
+       defer f.fsys.mu.Unlock()
+       return f.fsys.truncate(f.inode, length)
+}
+
+func Chdir(path string) error {
+       fs.mu.Lock()
+       defer fs.mu.Unlock()
+       ip, _, err := fs.namei(path, false)
+       if err != nil {
+               return err
+       }
+       fs.cwd = ip
+       return nil
+}
+
+func Fchdir(fd int) error {
+       f, err := fdToFsysFile(fd)
+       if err != nil {
+               return err
+       }
+       f.fsys.mu.Lock()
+       defer f.fsys.mu.Unlock()
+       if f.inode.Mode&S_IFMT != S_IFDIR {
+               return ENOTDIR
+       }
+       fs.cwd = f.inode
+       return nil
+}
+
+func Readlink(path string, buf []byte) (n int, err error) {
+       return 0, ENOSYS
+}
+
+func Symlink(path, link string) error {
+       return ENOSYS
+}
+
+func Fsync(fd int) error {
+       return nil
+}
+
+// Special devices.
+
+func mkdev(path string, mode uint32, open func() (devFile, error)) error {
+       fs.mu.Lock()
+       fs.mu.Unlock()
+       f, err := fs.open(path, O_CREATE|O_RDONLY|O_EXCL, S_IFCHR|mode)
+       if err != nil {
+               return err
+       }
+       ip := f.(*fsysFile).inode
+       ip.Rdev = int64(len(fs.dev))
+       fs.dev = append(fs.dev, open)
+       return nil
+}
+
+type nullFile struct{}
+
+func openNull() (devFile, error)                               { return &nullFile{}, nil }
+func (f *nullFile) close() error                               { return nil }
+func (f *nullFile) pread(b []byte, offset int64) (int, error)  { return 0, nil }
+func (f *nullFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
+
+type zeroFile struct{}
+
+func openZero() (devFile, error)                               { return &zeroFile{}, nil }
+func (f *zeroFile) close() error                               { return nil }
+func (f *zeroFile) pwrite(b []byte, offset int64) (int, error) { return len(b), nil }
+
+func (f *zeroFile) pread(b []byte, offset int64) (int, error) {
+       for i := range b {
+               b[i] = 0
+       }
+       return len(b), nil
+}
+
+type randomFile struct {
+       naclFD int
+}
+
+func openRandom() (devFile, error) {
+       fd, err := openNamedService("SecureRandom", O_RDONLY)
+       if err != nil {
+               return nil, err
+       }
+       return &randomFile{naclFD: fd}, nil
+}
+
+func (f *randomFile) close() error {
+       naclClose(f.naclFD)
+       f.naclFD = -1
+       return nil
+}
+
+func (f *randomFile) pread(b []byte, offset int64) (int, error) {
+       return naclRead(f.naclFD, b)
+}
+
+func (f *randomFile) pwrite(b []byte, offset int64) (int, error) {
+       return 0, EPERM
+}
+
+func fdToFsysFile(fd int) (*fsysFile, error) {
+       f, err := fdToFile(fd)
+       if err != nil {
+               return nil, err
+       }
+       impl := f.impl
+       fsysf, ok := impl.(*fsysFile)
+       if !ok {
+               return nil, EINVAL
+       }
+       return fsysf, nil
+}
+
+// create creates a file in the file system with the given name, mode, time, and data.
+// It is meant to be called when initializing the file system image.
+func create(name string, mode uint32, sec int64, data []byte) error {
+       fs.mu.Lock()
+       fs.mu.Unlock()
+       f, err := fs.open(name, O_CREATE|O_EXCL, mode)
+       if err != nil {
+               return err
+       }
+       ip := f.(*fsysFile).inode
+       ip.Atime = sec
+       ip.Mtime = sec
+       ip.Ctime = sec
+       if len(data) > 0 {
+               ip.Size = int64(len(data))
+               ip.data = data
+       }
+       return nil
+}
index 79a3bc889e556578f8deb605a470ec1b367a5e59..1bd6ccb0218e09ddf44e8f122ba147a5c6fd8c51 100755 (executable)
@@ -174,6 +174,18 @@ linux_arm)
        mksysnum="curl -s 'http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/plain/arch/arm/include/uapi/asm/unistd.h' | ./mksysnum_linux.pl"
        mktypes="GOARCH=$GOARCH go tool cgo -godefs"
        ;;
+nacl_386)
+       mkerrors=""
+       mksyscall="./mksyscall.pl -l32 -nacl"
+       mksysnum=""
+       mktypes=""
+       ;;
+nacl_amd64p32)
+       mkerrors=""
+       mksyscall="./mksyscall.pl -nacl"
+       mksysnum=""
+       mktypes=""
+       ;;
 netbsd_386)
        mkerrors="$mkerrors -m32"
        mksyscall="./mksyscall.pl -l32 -netbsd"
index b4ece9a5424d2143acefd66dbb776003e6bfa170..6d35fa6892745ed39c5a2eb2d83a5b3b46edafda 100755 (executable)
@@ -28,6 +28,7 @@ my $plan9 = 0;
 my $openbsd = 0;
 my $netbsd = 0;
 my $dragonfly = 0;
+my $nacl = 0;
 my $arm = 0; # 64-bit value should use (even, odd)-pair
 
 if($ARGV[0] eq "-b32") {
@@ -53,6 +54,10 @@ if($ARGV[0] eq "-dragonfly") {
        $dragonfly = 1;
        shift;
 }
+if($ARGV[0] eq "-nacl") {
+       $nacl = 1;
+       shift;
+}
 if($ARGV[0] eq "-arm") {
        $arm = 1;
        shift;
@@ -95,7 +100,7 @@ while(<>) {
        # Line must be of the form
        #       func Open(path string, mode int, perm int) (fd int, errno error)
        # Split into name, in params, out params.
-       if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(SYS_[A-Z0-9_]+))?$/) {
+       if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$/) {
                print STDERR "$ARGV:$.: malformed //sys declaration\n";
                $errors = 1;
                next;
@@ -219,6 +224,9 @@ while(<>) {
                $sysname = "SYS_$func";
                $sysname =~ s/([a-z])([A-Z])/${1}_$2/g; # turn FooBar into Foo_Bar
                $sysname =~ y/a-z/A-Z/;
+               if($nacl) {
+                       $sysname =~ y/A-Z/a-z/;
+               }
        }
 
        # Actual call.
diff --git a/src/pkg/syscall/srpc_nacl.go b/src/pkg/syscall/srpc_nacl.go
new file mode 100644 (file)
index 0000000..dd07373
--- /dev/null
@@ -0,0 +1,822 @@
+// Copyright 2013 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.
+
+// Native Client SRPC message passing.
+// This code is needed to invoke SecureRandom, the NaCl equivalent of /dev/random.
+
+package syscall
+
+import (
+       "errors"
+       "sync"
+       "unsafe"
+)
+
+// An srpcClient represents the client side of an SRPC connection.
+type srpcClient struct {
+       fd      int // to server
+       r       msgReceiver
+       s       msgSender
+       service map[string]srpcService // services by name
+
+       outMu sync.Mutex // protects writing to connection
+
+       mu      sync.Mutex // protects following fields
+       muxer   bool       // is someone reading and muxing responses
+       pending map[uint32]*srpc
+       idGen   uint32 // generator for request IDs
+}
+
+// An srpcService is a single method that the server offers.
+type srpcService struct {
+       num uint32 // method number
+       fmt string // argument format; see "parsing of RPC messages" below
+}
+
+// An srpc represents a single srpc issued by a client.
+type srpc struct {
+       Ret  []interface{}
+       Done chan *srpc
+       Err  error
+       c    *srpcClient
+       id   uint32
+}
+
+// newClient allocates a new SRPC client using the file descriptor fd.
+func newClient(fd int) (*srpcClient, error) {
+       c := new(srpcClient)
+       c.fd = fd
+       c.r.fd = fd
+       c.s.fd = fd
+       c.service = make(map[string]srpcService)
+       c.pending = make(map[uint32]*srpc)
+
+       // service discovery request
+       m := &msg{
+               isRequest: 1,
+               template:  []interface{}{[]byte(nil)},
+               size:      []int{4000}, // max size to accept for returned byte slice
+       }
+       if err := m.pack(); err != nil {
+               return nil, errors.New("Native Client SRPC service_discovery: preparing request: " + err.Error())
+       }
+       c.s.send(m)
+       m, err := c.r.recv()
+       if err != nil {
+               return nil, err
+       }
+       m.unpack()
+       if m.status != uint32(srpcOK) {
+               return nil, errors.New("Native Client SRPC service_discovery: " + srpcErrno(m.status).Error())
+       }
+       list := m.value[0].([]byte)
+       var n uint32
+       for len(list) > 0 {
+               var line []byte
+               i := byteIndex(list, '\n')
+               if i < 0 {
+                       line, list = list, nil
+               } else {
+                       line, list = list[:i], list[i+1:]
+               }
+               i = byteIndex(line, ':')
+               if i >= 0 {
+                       c.service[string(line)] = srpcService{n, string(line[i+1:])}
+               }
+               n++
+       }
+
+       return c, nil
+}
+
+func byteIndex(b []byte, c byte) int {
+       for i, bi := range b {
+               if bi == c {
+                       return i
+               }
+       }
+       return -1
+}
+
+var yourTurn srpc
+
+func (c *srpcClient) wait(r *srpc) {
+       var rx *srpc
+       for rx = range r.Done {
+               if rx != &yourTurn {
+                       break
+               }
+               c.input()
+       }
+       return
+}
+
+func (c *srpcClient) input() {
+       // read message
+       m, err := c.r.recv()
+       if err != nil {
+               println("Native Client SRPC receive error:", err.Error())
+               return
+       }
+       if m.unpack(); m.status != uint32(srpcOK) {
+               println("Native Client SRPC receive error: invalid message: ", srpcErrno(m.status).Error())
+               return
+       }
+
+       // deliver to intended recipient
+       c.mu.Lock()
+       rpc, ok := c.pending[m.id]
+       if ok {
+               delete(c.pending, m.id)
+       }
+
+       // wake a new muxer if there are more RPCs to read
+       c.muxer = false
+       for _, rpc := range c.pending {
+               c.muxer = true
+               rpc.Done <- &yourTurn
+               break
+       }
+       c.mu.Unlock()
+       if !ok {
+               println("Native Client: unexpected response for ID", m.id)
+               return
+       }
+       rpc.Ret = m.value
+       rpc.Done <- rpc
+}
+
+// Wait blocks until the RPC has finished.
+func (r *srpc) Wait() {
+       r.c.wait(r)
+}
+
+// Start issues an RPC request for method name with the given arguments.
+// The RPC r must not be in use for another pending request.
+// To wait for the RPC to finish, receive from r.Done and then
+// inspect r.Ret and r.Errno.
+func (r *srpc) Start(name string, arg []interface{}) {
+       r.Err = nil
+       r.c.mu.Lock()
+       srv, ok := r.c.service[name]
+       if !ok {
+               r.c.mu.Unlock()
+               r.Err = srpcErrBadRPCNumber
+               r.Done <- r
+               return
+       }
+       r.c.pending[r.id] = r
+       if !r.c.muxer {
+               r.c.muxer = true
+               r.Done <- &yourTurn
+       }
+       r.c.mu.Unlock()
+
+       var m msg
+       m.id = r.id
+       m.isRequest = 1
+       m.rpc = srv.num
+       m.value = arg
+
+       // Fill in the return values and sizes to generate
+       // the right type chars.  We'll take most any size.
+
+       // Skip over input arguments.
+       // We could check them against arg, but the server
+       // will do that anyway.
+       i := 0
+       for srv.fmt[i] != ':' {
+               i++
+       }
+       format := srv.fmt[i+1:]
+
+       // Now the return prototypes.
+       m.template = make([]interface{}, len(format))
+       m.size = make([]int, len(format))
+       for i := 0; i < len(format); i++ {
+               switch format[i] {
+               default:
+                       println("Native Client SRPC: unexpected service type " + string(format[i]))
+                       r.Err = srpcErrBadRPCNumber
+                       r.Done <- r
+                       return
+               case 'b':
+                       m.template[i] = false
+               case 'C':
+                       m.template[i] = []byte(nil)
+                       m.size[i] = 1 << 30
+               case 'd':
+                       m.template[i] = float64(0)
+               case 'D':
+                       m.template[i] = []float64(nil)
+                       m.size[i] = 1 << 30
+               case 'h':
+                       m.template[i] = int(-1)
+               case 'i':
+                       m.template[i] = int32(0)
+               case 'I':
+                       m.template[i] = []int32(nil)
+                       m.size[i] = 1 << 30
+               case 's':
+                       m.template[i] = ""
+                       m.size[i] = 1 << 30
+               }
+       }
+
+       if err := m.pack(); err != nil {
+               r.Err = errors.New("Native Client RPC Start " + name + ": preparing request: " + err.Error())
+               r.Done <- r
+               return
+       }
+
+       r.c.outMu.Lock()
+       r.c.s.send(&m)
+       r.c.outMu.Unlock()
+}
+
+// Call is a convenience wrapper that starts the RPC request,
+// waits for it to finish, and then returns the results.
+// Its implementation is:
+//
+//     r.Start(name, arg)
+//     r.Wait()
+//     return r.Ret, r.Errno
+//
+func (c *srpcClient) Call(name string, arg ...interface{}) (ret []interface{}, err error) {
+       r := c.NewRPC(nil)
+       r.Start(name, arg)
+       r.Wait()
+       return r.Ret, r.Err
+}
+
+// NewRPC creates a new RPC on the client connection.
+func (c *srpcClient) NewRPC(done chan *srpc) *srpc {
+       if done == nil {
+               done = make(chan *srpc, 1)
+       }
+       c.mu.Lock()
+       id := c.idGen
+       c.idGen++
+       c.mu.Unlock()
+       return &srpc{Done: done, c: c, id: id}
+}
+
+// The current protocol number.
+// Kind of useless, since there have been backwards-incompatible changes
+// to the wire protocol that did not update the protocol number.
+// At this point it's really just a sanity check.
+const protocol = 0xc0da0002
+
+// An srpcErrno is an SRPC status code.
+type srpcErrno uint32
+
+const (
+       srpcOK srpcErrno = 256 + iota
+       srpcErrBreak
+       srpcErrMessageTruncated
+       srpcErrNoMemory
+       srpcErrProtocolMismatch
+       srpcErrBadRPCNumber
+       srpcErrBadArgType
+       srpcErrTooFewArgs
+       srpcErrTooManyArgs
+       srpcErrInArgTypeMismatch
+       srpcErrOutArgTypeMismatch
+       srpcErrInternalError
+       srpcErrAppError
+)
+
+var srpcErrstr = [...]string{
+       srpcOK - srpcOK:                    "ok",
+       srpcErrBreak - srpcOK:              "break",
+       srpcErrMessageTruncated - srpcOK:   "message truncated",
+       srpcErrNoMemory - srpcOK:           "out of memory",
+       srpcErrProtocolMismatch - srpcOK:   "protocol mismatch",
+       srpcErrBadRPCNumber - srpcOK:       "invalid RPC method number",
+       srpcErrBadArgType - srpcOK:         "unexpected argument type",
+       srpcErrTooFewArgs - srpcOK:         "too few arguments",
+       srpcErrTooManyArgs - srpcOK:        "too many arguments",
+       srpcErrInArgTypeMismatch - srpcOK:  "input argument type mismatch",
+       srpcErrOutArgTypeMismatch - srpcOK: "output argument type mismatch",
+       srpcErrInternalError - srpcOK:      "internal error",
+       srpcErrAppError - srpcOK:           "application error",
+}
+
+func (e srpcErrno) Error() string {
+       if e < srpcOK || int(e-srpcOK) >= len(srpcErrstr) {
+               return "srpcErrno(" + itoa(int(e)) + ")"
+       }
+       return srpcErrstr[e-srpcOK]
+}
+
+// A msgHdr is the data argument to the imc_recvmsg
+// and imc_sendmsg system calls.
+type msgHdr struct {
+       iov   *iov
+       niov  int32
+       desc  *int32
+       ndesc int32
+       flags uint32
+}
+
+// A single region for I/O.
+type iov struct {
+       base *byte
+       len  int32
+}
+
+const maxMsgSize = 1<<16 - 4*4
+
+// A msgReceiver receives messages from a file descriptor.
+type msgReceiver struct {
+       fd   int
+       data [maxMsgSize]byte
+       desc [8]int32
+       hdr  msgHdr
+       iov  iov
+}
+
+func (r *msgReceiver) recv() (*msg, error) {
+       // Init pointers to buffers where syscall recvmsg can write.
+       r.iov.base = &r.data[0]
+       r.iov.len = int32(len(r.data))
+       r.hdr.iov = &r.iov
+       r.hdr.niov = 1
+       r.hdr.desc = &r.desc[0]
+       r.hdr.ndesc = int32(len(r.desc))
+       n, _, e := Syscall(sys_imc_recvmsg, uintptr(r.fd), uintptr(unsafe.Pointer(&r.hdr)), 0)
+       if e != 0 {
+               println("Native Client imc_recvmsg: ", e.Error())
+               return nil, e
+       }
+
+       // Make a copy of the data so that the next recvmsg doesn't
+       // smash it.  The system call did not update r.iov.len.  Instead it
+       // returned the total byte count as n.
+       m := new(msg)
+       m.data = make([]byte, n)
+       copy(m.data, r.data[0:])
+
+       // Make a copy of the desc too.
+       // The system call *did* update r.hdr.ndesc.
+       if r.hdr.ndesc > 0 {
+               m.desc = make([]int32, r.hdr.ndesc)
+               copy(m.desc, r.desc[:])
+       }
+
+       return m, nil
+}
+
+// A msgSender sends messages on a file descriptor.
+type msgSender struct {
+       fd  int
+       hdr msgHdr
+       iov iov
+}
+
+func (s *msgSender) send(m *msg) error {
+       if len(m.data) > 0 {
+               s.iov.base = &m.data[0]
+       }
+       s.iov.len = int32(len(m.data))
+       s.hdr.iov = &s.iov
+       s.hdr.niov = 1
+       s.hdr.desc = nil
+       s.hdr.ndesc = 0
+       _, _, e := Syscall(sys_imc_sendmsg, uintptr(s.fd), uintptr(unsafe.Pointer(&s.hdr)), 0)
+       if e != 0 {
+               println("Native Client imc_sendmsg: ", e.Error())
+               return e
+       }
+       return nil
+}
+
+// A msg is the Go representation of an SRPC message.
+type msg struct {
+       data []byte  // message data
+       desc []int32 // message file descriptors
+
+       // parsed version of message
+       id        uint32
+       isRequest uint32
+       rpc       uint32
+       status    uint32
+       value     []interface{}
+       template  []interface{}
+       size      []int
+       format    string
+       broken    bool
+}
+
+// reading from a msg
+
+func (m *msg) uint32() uint32 {
+       if m.broken {
+               return 0
+       }
+       if len(m.data) < 4 {
+               m.broken = true
+               return 0
+       }
+       b := m.data[:4]
+       x := uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+       m.data = m.data[4:]
+       return x
+}
+
+func (m *msg) uint64() uint64 {
+       x := uint64(m.uint32()) | uint64(m.uint32())<<32
+       if m.broken {
+               return 0
+       }
+       return x
+}
+
+func (m *msg) bytes(n int) []byte {
+       if m.broken {
+               return nil
+       }
+       if len(m.data) < n {
+               m.broken = true
+               return nil
+       }
+       x := m.data[0:n]
+       m.data = m.data[n:]
+       return x
+}
+
+// writing to a msg
+
+func (m *msg) wuint32(x uint32) {
+       m.data = append(m.data, byte(x), byte(x>>8), byte(x>>16), byte(x>>24))
+}
+
+func (m *msg) wuint64(x uint64) {
+       lo := uint32(x)
+       hi := uint32(x >> 32)
+       m.data = append(m.data, byte(lo), byte(lo>>8), byte(lo>>16), byte(lo>>24), byte(hi), byte(hi>>8), byte(hi>>16), byte(hi>>24))
+}
+
+func (m *msg) wbytes(p []byte) {
+       m.data = append(m.data, p...)
+}
+
+func (m *msg) wstring(s string) {
+       m.data = append(m.data, s...)
+}
+
+// Parsing of RPC messages.
+//
+// Each message begins with
+//     total_size uint32
+//     total_descs uint32
+//     fragment_size uint32
+//     fragment_descs uint32
+//
+// If fragment_size < total_size or fragment_descs < total_descs, the actual
+// message is broken up in multiple messages; follow-up messages omit
+// the "total" fields and begin with the "fragment" fields.
+// We do not support putting fragmented messages back together.
+// To do this we would need to change the message receiver.
+//
+// After that size information, the message header follows:
+//     protocol uint32
+//     requestID uint32
+//     isRequest uint32
+//     rpcNumber uint32
+//     status uint32
+//     numValue uint32
+//     numTemplate uint32
+//
+// After the header come numTemplate fixed-size arguments,
+// numValue fixed-size arguments, and then the variable-sized
+// part of the values. The templates describe the expected results
+// and have no associated variable sized data in the request.
+//
+// Each fixed-size argument has the form:
+//     tag uint32 // really a char, like 'b' or 'C'
+//     pad uint32 // unused
+//     val1 uint32
+//     val2 uint32
+//
+// The tags are:
+//     'b':    bool; val1 == 0 or 1
+//     'C':    []byte; val1 == len, data in variable-sized section
+//     'd':    float64; (val1, val2) is data
+//     'D':    []float64; val1 == len, data in variable-sized section
+//     'h':    int; val1 == file descriptor
+//     'i':    int32; descriptor in next entry in m.desc
+//     'I':    []int; val1 == len, data in variable-sized section
+//     's':    string; val1 == len, data in variable-sized section
+//
+
+func (m *msg) pack() error {
+       m.data = m.data[:0]
+       m.desc = m.desc[:0]
+
+       // sizes, to fill in later
+       m.wuint32(0)
+       m.wuint32(0)
+       m.wuint32(0)
+       m.wuint32(0)
+
+       // message header
+       m.wuint32(protocol)
+       m.wuint32(m.id)
+       m.wuint32(m.isRequest)
+       m.wuint32(m.rpc)
+       m.wuint32(m.status)
+       m.wuint32(uint32(len(m.value)))
+       m.wuint32(uint32(len(m.template)))
+
+       // fixed-size templates
+       for i, x := range m.template {
+               var tag, val1, val2 uint32
+               switch x.(type) {
+               default:
+                       return errors.New("unexpected template type")
+               case bool:
+                       tag = 'b'
+               case []byte:
+                       tag = 'C'
+                       val1 = uint32(m.size[i])
+               case float64:
+                       tag = 'd'
+               case []float64:
+                       tag = 'D'
+                       val1 = uint32(m.size[i])
+               case int:
+                       tag = 'h'
+               case int32:
+                       tag = 'i'
+               case []int32:
+                       tag = 'I'
+                       val1 = uint32(m.size[i])
+               case string:
+                       tag = 's'
+                       val1 = uint32(m.size[i])
+               }
+               m.wuint32(tag)
+               m.wuint32(0)
+               m.wuint32(val1)
+               m.wuint32(val2)
+       }
+
+       // fixed-size values
+       for _, x := range m.value {
+               var tag, val1, val2 uint32
+               switch x := x.(type) {
+               default:
+                       return errors.New("unexpected value type")
+               case bool:
+                       tag = 'b'
+                       if x {
+                               val1 = 1
+                       }
+               case []byte:
+                       tag = 'C'
+                       val1 = uint32(len(x))
+               case float64:
+                       tag = 'd'
+                       v := float64bits(x)
+                       val1 = uint32(v)
+                       val2 = uint32(v >> 32)
+               case []float64:
+                       tag = 'D'
+                       val1 = uint32(len(x))
+               case int32:
+                       tag = 'i'
+                       m.desc = append(m.desc, x)
+               case []int32:
+                       tag = 'I'
+                       val1 = uint32(len(x))
+               case string:
+                       tag = 's'
+                       val1 = uint32(len(x) + 1)
+               }
+               m.wuint32(tag)
+               m.wuint32(0)
+               m.wuint32(val1)
+               m.wuint32(val2)
+       }
+
+       // variable-length data for values
+       for _, x := range m.value {
+               switch x := x.(type) {
+               case []byte:
+                       m.wbytes(x)
+               case []float64:
+                       for _, f := range x {
+                               m.wuint64(float64bits(f))
+                       }
+               case []int32:
+                       for _, j := range x {
+                               m.wuint32(uint32(j))
+                       }
+               case string:
+                       m.wstring(x)
+                       m.wstring("\x00")
+               }
+       }
+
+       // fill in sizes
+       data := m.data
+       m.data = m.data[:0]
+       m.wuint32(uint32(len(data)))
+       m.wuint32(uint32(len(m.desc)))
+       m.wuint32(uint32(len(data)))
+       m.wuint32(uint32(len(m.desc)))
+       m.data = data
+
+       return nil
+}
+
+func (m *msg) unpack() error {
+       totalSize := m.uint32()
+       totalDesc := m.uint32()
+       fragSize := m.uint32()
+       fragDesc := m.uint32()
+       if totalSize != fragSize || totalDesc != fragDesc {
+               return errors.New("Native Client: fragmented RPC messages not supported")
+       }
+       if m.uint32() != protocol {
+               return errors.New("Native Client: RPC protocol mismatch")
+       }
+
+       // message header
+       m.id = m.uint32()
+       m.isRequest = m.uint32()
+       m.rpc = m.uint32()
+       m.status = m.uint32()
+       m.value = make([]interface{}, m.uint32())
+       m.template = make([]interface{}, m.uint32())
+       m.size = make([]int, len(m.template))
+       if m.broken {
+               return errors.New("Native Client: malformed message")
+       }
+
+       // fixed-size templates
+       for i := range m.template {
+               tag := m.uint32()
+               m.uint32() // padding
+               val1 := m.uint32()
+               m.uint32() // val2
+               switch tag {
+               default:
+                       return errors.New("Native Client: unexpected template type " + string(rune(tag)))
+               case 'b':
+                       m.template[i] = false
+               case 'C':
+                       m.template[i] = []byte(nil)
+                       m.size[i] = int(val1)
+               case 'd':
+                       m.template[i] = float64(0)
+               case 'D':
+                       m.template[i] = []float64(nil)
+                       m.size[i] = int(val1)
+               case 'i':
+                       m.template[i] = int32(0)
+               case 'I':
+                       m.template[i] = []int32(nil)
+                       m.size[i] = int(val1)
+               case 'h':
+                       m.template[i] = int(0)
+               case 's':
+                       m.template[i] = ""
+                       m.size[i] = int(val1)
+               }
+       }
+
+       // fixed-size values
+       var (
+               strsize []uint32
+               d       int
+       )
+       for i := range m.value {
+               tag := m.uint32()
+               m.uint32() // padding
+               val1 := m.uint32()
+               val2 := m.uint32()
+               switch tag {
+               default:
+                       return errors.New("Native Client: unexpected value type " + string(rune(tag)))
+               case 'b':
+                       m.value[i] = val1 > 0
+               case 'C':
+                       m.value[i] = []byte(nil)
+                       strsize = append(strsize, val1)
+               case 'd':
+                       m.value[i] = float64frombits(uint64(val1) | uint64(val2)<<32)
+               case 'D':
+                       m.value[i] = make([]float64, val1)
+               case 'i':
+                       m.value[i] = int32(val1)
+               case 'I':
+                       m.value[i] = make([]int32, val1)
+               case 'h':
+                       m.value[i] = int(m.desc[d])
+                       d++
+               case 's':
+                       m.value[i] = ""
+                       strsize = append(strsize, val1)
+               }
+       }
+
+       // variable-sized parts of values
+       for i, x := range m.value {
+               switch x := x.(type) {
+               case []byte:
+                       m.value[i] = m.bytes(int(strsize[0]))
+                       strsize = strsize[1:]
+               case []float64:
+                       for i := range x {
+                               x[i] = float64frombits(m.uint64())
+                       }
+               case []int32:
+                       for i := range x {
+                               x[i] = int32(m.uint32())
+                       }
+               case string:
+                       m.value[i] = string(m.bytes(int(strsize[0])))
+                       strsize = strsize[1:]
+               }
+       }
+
+       if len(m.data) > 0 {
+               return errors.New("Native Client: junk at end of message")
+       }
+       return nil
+}
+
+func float64bits(x float64) uint64 {
+       return *(*uint64)(unsafe.Pointer(&x))
+}
+
+func float64frombits(x uint64) float64 {
+       return *(*float64)(unsafe.Pointer(&x))
+}
+
+// At startup, connect to the name service.
+var nsClient = nsConnect()
+
+func nsConnect() *srpcClient {
+       var ns int32 = -1
+       _, _, errno := Syscall(sys_nameservice, uintptr(unsafe.Pointer(&ns)), 0, 0)
+       if errno != 0 {
+               println("Native Client nameservice:", errno.Error())
+               return nil
+       }
+
+       sock, _, errno := Syscall(sys_imc_connect, uintptr(ns), 0, 0)
+       if errno != 0 {
+               println("Native Client nameservice connect:", errno.Error())
+               return nil
+       }
+
+       c, err := newClient(int(sock))
+       if err != nil {
+               println("Native Client nameservice init:", err.Error())
+               return nil
+       }
+
+       return c
+}
+
+const (
+       nsSuccess               = 0
+       nsNameNotFound          = 1
+       nsDuplicateName         = 2
+       nsInsufficientResources = 3
+       nsPermissionDenied      = 4
+       nsInvalidArgument       = 5
+)
+
+func openNamedService(name string, mode int32) (fd int, err error) {
+       if nsClient == nil {
+               return 0, errors.New("no name service")
+       }
+       ret, err := nsClient.Call("lookup:si:ih", name, int32(mode))
+       if err != nil {
+               return 0, err
+       }
+       status := ret[0].(int32)
+       fd = ret[1].(int)
+       switch status {
+       case nsSuccess:
+               // ok
+       case nsNameNotFound:
+               return -1, ENOENT
+       case nsDuplicateName:
+               return -1, EEXIST
+       case nsInsufficientResources:
+               return -1, EWOULDBLOCK
+       case nsPermissionDenied:
+               return -1, EPERM
+       case nsInvalidArgument:
+               return -1, EINVAL
+       default:
+               return -1, EINVAL
+       }
+       return fd, nil
+}
diff --git a/src/pkg/syscall/syscall_nacl.go b/src/pkg/syscall/syscall_nacl.go
new file mode 100644 (file)
index 0000000..c2788b2
--- /dev/null
@@ -0,0 +1,311 @@
+// Copyright 2013 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 syscall
+
+import (
+       "sync"
+       "unsafe"
+)
+
+//sys  naclClose(fd int) (err error) = sys_close
+//sys  Exit(code int) (err error)
+//sys  naclFstat(fd int, stat *Stat_t) (err error) = sys_fstat
+//sys  naclRead(fd int, b []byte) (n int, err error) = sys_read
+//sys  naclSeek(fd int, off *int64, whence int) (err error) = sys_lseek
+
+const direntSize = 8 + 8 + 2 + 256
+
+// native_client/src/trusted/service_runtime/include/sys/dirent.h
+type Dirent struct {
+       Ino    int64
+       Off    int64
+       Reclen uint16
+       Name   [256]byte
+}
+
+func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string) {
+       origlen := len(buf)
+       count = 0
+       for max != 0 && len(buf) > 0 {
+               dirent := (*Dirent)(unsafe.Pointer(&buf[0]))
+               buf = buf[dirent.Reclen:]
+               if dirent.Ino == 0 { // File absent in directory.
+                       continue
+               }
+               bytes := (*[512 + PathMax]byte)(unsafe.Pointer(&dirent.Name[0]))
+               var name = string(bytes[0:clen(bytes[:])])
+               if name == "." || name == ".." { // Useless names
+                       continue
+               }
+               max--
+               count++
+               names = append(names, name)
+       }
+       return origlen - len(buf), count, names
+}
+
+func clen(n []byte) int {
+       for i := 0; i < len(n); i++ {
+               if n[i] == 0 {
+                       return i
+               }
+       }
+       return len(n)
+}
+
+const PathMax = 256
+
+// An Errno is an unsigned number describing an error condition.
+// It implements the error interface.  The zero Errno is by convention
+// a non-error, so code to convert from Errno to error should use:
+//     err = nil
+//     if errno != 0 {
+//             err = errno
+//     }
+type Errno uintptr
+
+func (e Errno) Error() string {
+       if 0 <= int(e) && int(e) < len(errorstr) {
+               s := errorstr[e]
+               if s != "" {
+                       return s
+               }
+       }
+       return "errno " + itoa(int(e))
+}
+
+func (e Errno) Temporary() bool {
+       return e == EINTR || e == EMFILE || e.Timeout()
+}
+
+func (e Errno) Timeout() bool {
+       return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
+}
+
+// A Signal is a number describing a process signal.
+// It implements the os.Signal interface.
+type Signal int
+
+const (
+       _ Signal = iota
+       SIGCHLD
+       SIGINT
+       SIGKILL
+       SIGTRAP
+       SIGQUIT
+)
+
+func (s Signal) Signal() {}
+
+func (s Signal) String() string {
+       if 0 <= s && int(s) < len(signals) {
+               str := signals[s]
+               if str != "" {
+                       return str
+               }
+       }
+       return "signal " + itoa(int(s))
+}
+
+var signals = [...]string{}
+
+// File system
+
+const (
+       Stdin  = 0
+       Stdout = 1
+       Stderr = 2
+)
+
+// native_client/src/trusted/service_runtime/include/sys/fcntl.h
+const (
+       O_RDONLY  = 0
+       O_WRONLY  = 1
+       O_RDWR    = 2
+       O_ACCMODE = 3
+
+       O_CREAT    = 0100
+       O_CREATE   = O_CREAT // for ken
+       O_TRUNC    = 01000
+       O_APPEND   = 02000
+       O_EXCL     = 0200
+       O_NONBLOCK = 04000
+       O_NDELAY   = O_NONBLOCK
+       O_SYNC     = 010000
+       O_FSYNC    = O_SYNC
+       O_ASYNC    = 020000
+
+       O_CLOEXEC = 0
+
+       FD_CLOEXEC = 1
+)
+
+// native_client/src/trusted/service_runtime/include/sys/fcntl.h
+const (
+       F_DUPFD   = 0
+       F_GETFD   = 1
+       F_SETFD   = 2
+       F_GETFL   = 3
+       F_SETFL   = 4
+       F_GETOWN  = 5
+       F_SETOWN  = 6
+       F_GETLK   = 7
+       F_SETLK   = 8
+       F_SETLKW  = 9
+       F_RGETLK  = 10
+       F_RSETLK  = 11
+       F_CNVT    = 12
+       F_RSETLKW = 13
+
+       F_RDLCK   = 1
+       F_WRLCK   = 2
+       F_UNLCK   = 3
+       F_UNLKSYS = 4
+)
+
+// native_client/src/trusted/service_runtime/include/bits/stat.h
+const (
+       S_IFMT        = 0000370000
+       S_IFSHM_SYSV  = 0000300000
+       S_IFSEMA      = 0000270000
+       S_IFCOND      = 0000260000
+       S_IFMUTEX     = 0000250000
+       S_IFSHM       = 0000240000
+       S_IFBOUNDSOCK = 0000230000
+       S_IFSOCKADDR  = 0000220000
+       S_IFDSOCK     = 0000210000
+
+       S_IFSOCK = 0000140000
+       S_IFLNK  = 0000120000
+       S_IFREG  = 0000100000
+       S_IFBLK  = 0000060000
+       S_IFDIR  = 0000040000
+       S_IFCHR  = 0000020000
+       S_IFIFO  = 0000010000
+
+       S_UNSUP = 0000370000
+
+       S_ISUID = 0004000
+       S_ISGID = 0002000
+       S_ISVTX = 0001000
+
+       S_IREAD  = 0400
+       S_IWRITE = 0200
+       S_IEXEC  = 0100
+
+       S_IRWXU = 0700
+       S_IRUSR = 0400
+       S_IWUSR = 0200
+       S_IXUSR = 0100
+
+       S_IRWXG = 070
+       S_IRGRP = 040
+       S_IWGRP = 020
+       S_IXGRP = 010
+
+       S_IRWXO = 07
+       S_IROTH = 04
+       S_IWOTH = 02
+       S_IXOTH = 01
+)
+
+// native_client/src/trusted/service_runtime/include/sys/stat.h
+// native_client/src/trusted/service_runtime/include/machine/_types.h
+type Stat_t struct {
+       Dev       int64
+       Ino       uint64
+       Mode      uint32
+       Nlink     uint32
+       Uid       uint32
+       Gid       uint32
+       Rdev      int64
+       Size      int64
+       Blksize   int32
+       Blocks    int32
+       Atime     int64
+       AtimeNsec int64
+       Mtime     int64
+       MtimeNsec int64
+       Ctime     int64
+       CtimeNsec int64
+}
+
+// Processes
+// Not supported on NaCl - just enough for package os.
+
+var ForkLock sync.RWMutex
+
+type WaitStatus uint32
+
+func (w WaitStatus) Exited() bool       { return false }
+func (w WaitStatus) ExitStatus() int    { return 0 }
+func (w WaitStatus) Signaled() bool     { return false }
+func (w WaitStatus) Signal() Signal     { return 0 }
+func (w WaitStatus) CoreDump() bool     { return false }
+func (w WaitStatus) Stopped() bool      { return false }
+func (w WaitStatus) Continued() bool    { return false }
+func (w WaitStatus) StopSignal() Signal { return 0 }
+func (w WaitStatus) TrapCause() int     { return 0 }
+
+// XXX made up
+type Rusage struct {
+       Utime Timeval
+       Stime Timeval
+}
+
+// XXX made up
+type ProcAttr struct {
+       Dir   string
+       Env   []string
+       Files []uintptr
+       Sys   *SysProcAttr
+}
+
+type SysProcAttr struct {
+}
+
+// System
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { return 0, 0, ENOSYS }
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)           { return 0, 0, ENOSYS }
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
+       return 0, 0, ENOSYS
+}
+
+func Sysctl(key string) (string, error) {
+       if key == "kern.hostname" {
+               return "naclbox", nil
+       }
+       return "", ENOSYS
+}
+
+// Unimplemented Unix midden heap.
+
+const ImplementsGetwd = false
+
+func Getwd() (wd string, err error)     { return "", ENOSYS }
+func Getegid() int                      { return 1 }
+func Geteuid() int                      { return 1 }
+func Getgid() int                       { return 1 }
+func Getgroups() ([]int, error)         { return []int{1}, nil }
+func Getpagesize() int                  { return 65536 }
+func Getppid() int                      { return 2 }
+func Getpid() int                       { return 3 }
+func Getuid() int                       { return 1 }
+func Kill(pid int, signum Signal) error { return ENOSYS }
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+       return 0, ENOSYS
+}
+func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
+       return 0, 0, ENOSYS
+}
+func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
+       return 0, ENOSYS
+}
+func RouteRIB(facility, param int) ([]byte, error)                { return nil, ENOSYS }
+func ParseRoutingMessage(b []byte) ([]RoutingMessage, error)      { return nil, ENOSYS }
+func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { return nil, ENOSYS }
+func SysctlUint32(name string) (value uint32, err error)          { return 0, ENOSYS }
diff --git a/src/pkg/syscall/syscall_nacl_386.go b/src/pkg/syscall/syscall_nacl_386.go
new file mode 100644 (file)
index 0000000..d12f8e2
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2013 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 syscall
+
+type Timespec struct {
+       Sec  int64
+       Nsec int32
+}
+
+type Timeval struct {
+       Sec  int64
+       Usec int32
+}
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+       ts.Sec = int64(nsec / 1e9)
+       ts.Nsec = int32(nsec % 1e9)
+       return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+       nsec += 999 // round up to microsecond
+       tv.Usec = int32(nsec % 1e9 / 1e3)
+       tv.Sec = int64(nsec / 1e9)
+       return
+}
diff --git a/src/pkg/syscall/syscall_nacl_amd64p32.go b/src/pkg/syscall/syscall_nacl_amd64p32.go
new file mode 100644 (file)
index 0000000..d12f8e2
--- /dev/null
@@ -0,0 +1,32 @@
+// Copyright 2013 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 syscall
+
+type Timespec struct {
+       Sec  int64
+       Nsec int32
+}
+
+type Timeval struct {
+       Sec  int64
+       Usec int32
+}
+
+func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
+
+func NsecToTimespec(nsec int64) (ts Timespec) {
+       ts.Sec = int64(nsec / 1e9)
+       ts.Nsec = int32(nsec % 1e9)
+       return
+}
+
+func TimevalToNsec(tv Timeval) int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1e3 }
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+       nsec += 999 // round up to microsecond
+       tv.Usec = int32(nsec % 1e9 / 1e3)
+       tv.Sec = int64(nsec / 1e9)
+       return
+}
diff --git a/src/pkg/syscall/tables_nacl.go b/src/pkg/syscall/tables_nacl.go
new file mode 100644 (file)
index 0000000..08f4ced
--- /dev/null
@@ -0,0 +1,324 @@
+// Copyright 2013 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 syscall
+
+// TODO: generate with runtime/mknacl.sh, allow override with IRT.
+const (
+       sys_null                 = 1
+       sys_nameservice          = 2
+       sys_dup                  = 8
+       sys_dup2                 = 9
+       sys_open                 = 10
+       sys_close                = 11
+       sys_read                 = 12
+       sys_write                = 13
+       sys_lseek                = 14
+       sys_ioctl                = 15
+       sys_stat                 = 16
+       sys_fstat                = 17
+       sys_chmod                = 18
+       sys_brk                  = 20
+       sys_mmap                 = 21
+       sys_munmap               = 22
+       sys_getdents             = 23
+       sys_mprotect             = 24
+       sys_list_mappings        = 25
+       sys_exit                 = 30
+       sys_getpid               = 31
+       sys_sched_yield          = 32
+       sys_sysconf              = 33
+       sys_gettimeofday         = 40
+       sys_clock                = 41
+       sys_nanosleep            = 42
+       sys_clock_getres         = 43
+       sys_clock_gettime        = 44
+       sys_mkdir                = 45
+       sys_rmdir                = 46
+       sys_chdir                = 47
+       sys_getcwd               = 48
+       sys_unlink               = 49
+       sys_imc_makeboundsock    = 60
+       sys_imc_accept           = 61
+       sys_imc_connect          = 62
+       sys_imc_sendmsg          = 63
+       sys_imc_recvmsg          = 64
+       sys_imc_mem_obj_create   = 65
+       sys_imc_socketpair       = 66
+       sys_mutex_create         = 70
+       sys_mutex_lock           = 71
+       sys_mutex_trylock        = 72
+       sys_mutex_unlock         = 73
+       sys_cond_create          = 74
+       sys_cond_wait            = 75
+       sys_cond_signal          = 76
+       sys_cond_broadcast       = 77
+       sys_cond_timed_wait_abs  = 79
+       sys_thread_create        = 80
+       sys_thread_exit          = 81
+       sys_tls_init             = 82
+       sys_thread_nice          = 83
+       sys_tls_get              = 84
+       sys_second_tls_set       = 85
+       sys_second_tls_get       = 86
+       sys_exception_handler    = 87
+       sys_exception_stack      = 88
+       sys_exception_clear_flag = 89
+       sys_sem_create           = 100
+       sys_sem_wait             = 101
+       sys_sem_post             = 102
+       sys_sem_get_value        = 103
+       sys_dyncode_create       = 104
+       sys_dyncode_modify       = 105
+       sys_dyncode_delete       = 106
+       sys_test_infoleak        = 109
+       sys_test_crash           = 110
+       sys_test_syscall_1       = 111
+       sys_test_syscall_2       = 112
+)
+
+// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
+const (
+       // native_client/src/trusted/service_runtime/include/sys/errno.h
+       // The errors are mainly copied from Linux.
+       EPERM           Errno = 1       /* Operation not permitted */
+       ENOENT          Errno = 2       /* No such file or directory */
+       ESRCH           Errno = 3       /* No such process */
+       EINTR           Errno = 4       /* Interrupted system call */
+       EIO             Errno = 5       /* I/O error */
+       ENXIO           Errno = 6       /* No such device or address */
+       E2BIG           Errno = 7       /* Argument list too long */
+       ENOEXEC         Errno = 8       /* Exec format error */
+       EBADF           Errno = 9       /* Bad file number */
+       ECHILD          Errno = 10      /* No child processes */
+       EAGAIN          Errno = 11      /* Try again */
+       ENOMEM          Errno = 12      /* Out of memory */
+       EACCES          Errno = 13      /* Permission denied */
+       EFAULT          Errno = 14      /* Bad address */
+       EBUSY           Errno = 16      /* Device or resource busy */
+       EEXIST          Errno = 17      /* File exists */
+       EXDEV           Errno = 18      /* Cross-device link */
+       ENODEV          Errno = 19      /* No such device */
+       ENOTDIR         Errno = 20      /* Not a directory */
+       EISDIR          Errno = 21      /* Is a directory */
+       EINVAL          Errno = 22      /* Invalid argument */
+       ENFILE          Errno = 23      /* File table overflow */
+       EMFILE          Errno = 24      /* Too many open files */
+       ENOTTY          Errno = 25      /* Not a typewriter */
+       EFBIG           Errno = 27      /* File too large */
+       ENOSPC          Errno = 28      /* No space left on device */
+       ESPIPE          Errno = 29      /* Illegal seek */
+       EROFS           Errno = 30      /* Read-only file system */
+       EMLINK          Errno = 31      /* Too many links */
+       EPIPE           Errno = 32      /* Broken pipe */
+       ENAMETOOLONG    Errno = 36      /* File name too long */
+       ENOSYS          Errno = 38      /* Function not implemented */
+       EDQUOT          Errno = 122     /* Quota exceeded */
+       EDOM            Errno = 33      /* Math arg out of domain of func */
+       ERANGE          Errno = 34      /* Math result not representable */
+       EDEADLK         Errno = 35      /* Deadlock condition */
+       ENOLCK          Errno = 37      /* No record locks available */
+       ENOTEMPTY       Errno = 39      /* Directory not empty */
+       ELOOP           Errno = 40      /* Too many symbolic links */
+       ENOMSG          Errno = 42      /* No message of desired type */
+       EIDRM           Errno = 43      /* Identifier removed */
+       ECHRNG          Errno = 44      /* Channel number out of range */
+       EL2NSYNC        Errno = 45      /* Level 2 not synchronized */
+       EL3HLT          Errno = 46      /* Level 3 halted */
+       EL3RST          Errno = 47      /* Level 3 reset */
+       ELNRNG          Errno = 48      /* Link number out of range */
+       EUNATCH         Errno = 49      /* Protocol driver not attached */
+       ENOCSI          Errno = 50      /* No CSI structure available */
+       EL2HLT          Errno = 51      /* Level 2 halted */
+       EBADE           Errno = 52      /* Invalid exchange */
+       EBADR           Errno = 53      /* Invalid request descriptor */
+       EXFULL          Errno = 54      /* Exchange full */
+       ENOANO          Errno = 55      /* No anode */
+       EBADRQC         Errno = 56      /* Invalid request code */
+       EBADSLT         Errno = 57      /* Invalid slot */
+       EDEADLOCK       Errno = EDEADLK /* File locking deadlock error */
+       EBFONT          Errno = 59      /* Bad font file fmt */
+       ENOSTR          Errno = 60      /* Device not a stream */
+       ENODATA         Errno = 61      /* No data (for no delay io) */
+       ETIME           Errno = 62      /* Timer expired */
+       ENOSR           Errno = 63      /* Out of streams resources */
+       ENONET          Errno = 64      /* Machine is not on the network */
+       ENOPKG          Errno = 65      /* Package not installed */
+       EREMOTE         Errno = 66      /* The object is remote */
+       ENOLINK         Errno = 67      /* The link has been severed */
+       EADV            Errno = 68      /* Advertise error */
+       ESRMNT          Errno = 69      /* Srmount error */
+       ECOMM           Errno = 70      /* Communication error on send */
+       EPROTO          Errno = 71      /* Protocol error */
+       EMULTIHOP       Errno = 72      /* Multihop attempted */
+       EDOTDOT         Errno = 73      /* Cross mount point (not really error) */
+       EBADMSG         Errno = 74      /* Trying to read unreadable message */
+       EOVERFLOW       Errno = 75      /* Value too large for defined data type */
+       ENOTUNIQ        Errno = 76      /* Given log. name not unique */
+       EBADFD          Errno = 77      /* f.d. invalid for this operation */
+       EREMCHG         Errno = 78      /* Remote address changed */
+       ELIBACC         Errno = 79      /* Can't access a needed shared lib */
+       ELIBBAD         Errno = 80      /* Accessing a corrupted shared lib */
+       ELIBSCN         Errno = 81      /* .lib section in a.out corrupted */
+       ELIBMAX         Errno = 82      /* Attempting to link in too many libs */
+       ELIBEXEC        Errno = 83      /* Attempting to exec a shared library */
+       EILSEQ          Errno = 84
+       EUSERS          Errno = 87
+       ENOTSOCK        Errno = 88  /* Socket operation on non-socket */
+       EDESTADDRREQ    Errno = 89  /* Destination address required */
+       EMSGSIZE        Errno = 90  /* Message too long */
+       EPROTOTYPE      Errno = 91  /* Protocol wrong type for socket */
+       ENOPROTOOPT     Errno = 92  /* Protocol not available */
+       EPROTONOSUPPORT Errno = 93  /* Unknown protocol */
+       ESOCKTNOSUPPORT Errno = 94  /* Socket type not supported */
+       EOPNOTSUPP      Errno = 95  /* Operation not supported on transport endpoint */
+       EPFNOSUPPORT    Errno = 96  /* Protocol family not supported */
+       EAFNOSUPPORT    Errno = 97  /* Address family not supported by protocol family */
+       EADDRINUSE      Errno = 98  /* Address already in use */
+       EADDRNOTAVAIL   Errno = 99  /* Address not available */
+       ENETDOWN        Errno = 100 /* Network interface is not configured */
+       ENETUNREACH     Errno = 101 /* Network is unreachable */
+       ENETRESET       Errno = 102
+       ECONNABORTED    Errno = 103 /* Connection aborted */
+       ECONNRESET      Errno = 104 /* Connection reset by peer */
+       ENOBUFS         Errno = 105 /* No buffer space available */
+       EISCONN         Errno = 106 /* Socket is already connected */
+       ENOTCONN        Errno = 107 /* Socket is not connected */
+       ESHUTDOWN       Errno = 108 /* Can't send after socket shutdown */
+       ETOOMANYREFS    Errno = 109
+       ETIMEDOUT       Errno = 110 /* Connection timed out */
+       ECONNREFUSED    Errno = 111 /* Connection refused */
+       EHOSTDOWN       Errno = 112 /* Host is down */
+       EHOSTUNREACH    Errno = 113 /* Host is unreachable */
+       EALREADY        Errno = 114 /* Socket already connected */
+       EINPROGRESS     Errno = 115 /* Connection already in progress */
+       ESTALE          Errno = 116
+       ENOTSUP         Errno = EOPNOTSUPP /* Not supported */
+       ENOMEDIUM       Errno = 123        /* No medium (in tape drive) */
+       ECANCELED       Errno = 125        /* Operation canceled. */
+       ELBIN           Errno = 2048       /* Inode is remote (not really error) */
+       EFTYPE          Errno = 2049       /* Inappropriate file type or format */
+       ENMFILE         Errno = 2050       /* No more files */
+       EPROCLIM        Errno = 2051
+       ENOSHARE        Errno = 2052   /* No such host or network path */
+       ECASECLASH      Errno = 2053   /* Filename exists with different case */
+       EWOULDBLOCK     Errno = EAGAIN /* Operation would block */
+)
+
+// TODO: Auto-generate some day. (Hard-coded in binaries so not likely to change.)
+var errorstr = [...]string{
+       EPERM:           "Operation not permitted",
+       ENOENT:          "No such file or directory",
+       ESRCH:           "No such process",
+       EINTR:           "Interrupted system call",
+       EIO:             "I/O error",
+       ENXIO:           "No such device or address",
+       E2BIG:           "Argument list too long",
+       ENOEXEC:         "Exec format error",
+       EBADF:           "Bad file number",
+       ECHILD:          "No child processes",
+       EAGAIN:          "Try again",
+       ENOMEM:          "Out of memory",
+       EACCES:          "Permission denied",
+       EFAULT:          "Bad address",
+       EBUSY:           "Device or resource busy",
+       EEXIST:          "File exists",
+       EXDEV:           "Cross-device link",
+       ENODEV:          "No such device",
+       ENOTDIR:         "Not a directory",
+       EISDIR:          "Is a directory",
+       EINVAL:          "Invalid argument",
+       ENFILE:          "File table overflow",
+       EMFILE:          "Too many open files",
+       ENOTTY:          "Not a typewriter",
+       EFBIG:           "File too large",
+       ENOSPC:          "No space left on device",
+       ESPIPE:          "Illegal seek",
+       EROFS:           "Read-only file system",
+       EMLINK:          "Too many links",
+       EPIPE:           "Broken pipe",
+       ENAMETOOLONG:    "File name too long",
+       ENOSYS:          "not implemented on Native Client",
+       EDQUOT:          "Quota exceeded",
+       EDOM:            "Math arg out of domain of func",
+       ERANGE:          "Math result not representable",
+       EDEADLK:         "Deadlock condition",
+       ENOLCK:          "No record locks available",
+       ENOTEMPTY:       "Directory not empty",
+       ELOOP:           "Too many symbolic links",
+       ENOMSG:          "No message of desired type",
+       EIDRM:           "Identifier removed",
+       ECHRNG:          "Channel number out of range",
+       EL2NSYNC:        "Level 2 not synchronized",
+       EL3HLT:          "Level 3 halted",
+       EL3RST:          "Level 3 reset",
+       ELNRNG:          "Link number out of range",
+       EUNATCH:         "Protocol driver not attached",
+       ENOCSI:          "No CSI structure available",
+       EL2HLT:          "Level 2 halted",
+       EBADE:           "Invalid exchange",
+       EBADR:           "Invalid request descriptor",
+       EXFULL:          "Exchange full",
+       ENOANO:          "No anode",
+       EBADRQC:         "Invalid request code",
+       EBADSLT:         "Invalid slot",
+       EBFONT:          "Bad font file fmt",
+       ENOSTR:          "Device not a stream",
+       ENODATA:         "No data (for no delay io)",
+       ETIME:           "Timer expired",
+       ENOSR:           "Out of streams resources",
+       ENONET:          "Machine is not on the network",
+       ENOPKG:          "Package not installed",
+       EREMOTE:         "The object is remote",
+       ENOLINK:         "The link has been severed",
+       EADV:            "Advertise error",
+       ESRMNT:          "Srmount error",
+       ECOMM:           "Communication error on send",
+       EPROTO:          "Protocol error",
+       EMULTIHOP:       "Multihop attempted",
+       EDOTDOT:         "Cross mount point (not really error)",
+       EBADMSG:         "Trying to read unreadable message",
+       EOVERFLOW:       "Value too large for defined data type",
+       ENOTUNIQ:        "Given log. name not unique",
+       EBADFD:          "f.d. invalid for this operation",
+       EREMCHG:         "Remote address changed",
+       ELIBACC:         "Can't access a needed shared lib",
+       ELIBBAD:         "Accessing a corrupted shared lib",
+       ELIBSCN:         ".lib section in a.out corrupted",
+       ELIBMAX:         "Attempting to link in too many libs",
+       ELIBEXEC:        "Attempting to exec a shared library",
+       ENOTSOCK:        "Socket operation on non-socket",
+       EDESTADDRREQ:    "Destination address required",
+       EMSGSIZE:        "Message too long",
+       EPROTOTYPE:      "Protocol wrong type for socket",
+       ENOPROTOOPT:     "Protocol not available",
+       EPROTONOSUPPORT: "Unknown protocol",
+       ESOCKTNOSUPPORT: "Socket type not supported",
+       EOPNOTSUPP:      "Operation not supported on transport endpoint",
+       EPFNOSUPPORT:    "Protocol family not supported",
+       EAFNOSUPPORT:    "Address family not supported by protocol family",
+       EADDRINUSE:      "Address already in use",
+       EADDRNOTAVAIL:   "Address not available",
+       ENETDOWN:        "Network interface is not configured",
+       ENETUNREACH:     "Network is unreachable",
+       ECONNABORTED:    "Connection aborted",
+       ECONNRESET:      "Connection reset by peer",
+       ENOBUFS:         "No buffer space available",
+       EISCONN:         "Socket is already connected",
+       ENOTCONN:        "Socket is not connected",
+       ESHUTDOWN:       "Can't send after socket shutdown",
+       ETIMEDOUT:       "Connection timed out",
+       ECONNREFUSED:    "Connection refused",
+       EHOSTDOWN:       "Host is down",
+       EHOSTUNREACH:    "Host is unreachable",
+       EALREADY:        "Socket already connected",
+       EINPROGRESS:     "Connection already in progress",
+       ENOMEDIUM:       "No medium (in tape drive)",
+       ECANCELED:       "Operation canceled.",
+       ELBIN:           "Inode is remote (not really error)",
+       EFTYPE:          "Inappropriate file type or format",
+       ENMFILE:         "No more files",
+       ENOSHARE:        "No such host or network path",
+       ECASECLASH:      "Filename exists with different case",
+}
diff --git a/src/pkg/syscall/time_nacl_386.s b/src/pkg/syscall/time_nacl_386.s
new file mode 100644 (file)
index 0000000..b5a22d3
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2013 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 "../../cmd/ld/textflag.h"
+
+TEXT Â·startTimer(SB),NOSPLIT,$0
+       JMP time·startTimer(SB)
+
+TEXT Â·stopTimer(SB),NOSPLIT,$0
+       JMP time·stopTimer(SB)
diff --git a/src/pkg/syscall/time_nacl_amd64p32.s b/src/pkg/syscall/time_nacl_amd64p32.s
new file mode 100644 (file)
index 0000000..b5a22d3
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2013 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 "../../cmd/ld/textflag.h"
+
+TEXT Â·startTimer(SB),NOSPLIT,$0
+       JMP time·startTimer(SB)
+
+TEXT Â·stopTimer(SB),NOSPLIT,$0
+       JMP time·stopTimer(SB)
diff --git a/src/pkg/syscall/unzip_nacl.go b/src/pkg/syscall/unzip_nacl.go
new file mode 100644 (file)
index 0000000..5845e44
--- /dev/null
@@ -0,0 +1,685 @@
+// Copyright 2009 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.
+
+// Small in-memory unzip implementation.
+// A simplified copy of the pre-Go 1 compress/flate/inflate.go
+// and a modified copy of the zip reader in package time.
+// (The one in package time does not support decompression; this one does.)
+
+package syscall
+
+const (
+       maxCodeLen = 16    // max length of Huffman code
+       maxHist    = 32768 // max history required
+       maxLit     = 286
+       maxDist    = 32
+       numCodes   = 19 // number of codes in Huffman meta-code
+)
+
+type decompressor struct {
+       in  string // compressed input
+       out []byte // uncompressed output
+       b   uint32 // input bits, at top of b
+       nb  uint
+       err bool // invalid input
+       eof bool // reached EOF
+
+       h1, h2   huffmanDecoder        // decoders for literal/length, distance
+       bits     [maxLit + maxDist]int // lengths defining Huffman codes
+       codebits [numCodes]int
+}
+
+func (f *decompressor) nextBlock() {
+       for f.nb < 1+2 {
+               if f.moreBits(); f.err {
+                       return
+               }
+       }
+       f.eof = f.b&1 == 1
+       f.b >>= 1
+       typ := f.b & 3
+       f.b >>= 2
+       f.nb -= 1 + 2
+       switch typ {
+       case 0:
+               f.dataBlock()
+       case 1:
+               // compressed, fixed Huffman tables
+               f.huffmanBlock(&fixedHuffmanDecoder, nil)
+       case 2:
+               // compressed, dynamic Huffman tables
+               if f.readHuffman(); f.err {
+                       break
+               }
+               f.huffmanBlock(&f.h1, &f.h2)
+       default:
+               // 3 is reserved.
+               f.err = true
+       }
+}
+
+// RFC 1951 section 3.2.7.
+// Compression with dynamic Huffman codes
+
+var codeOrder = [...]int{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
+
+func (f *decompressor) readHuffman() {
+       // HLIT[5], HDIST[5], HCLEN[4].
+       for f.nb < 5+5+4 {
+               if f.moreBits(); f.err {
+                       return
+               }
+       }
+       nlit := int(f.b&0x1F) + 257
+       f.b >>= 5
+       ndist := int(f.b&0x1F) + 1
+       f.b >>= 5
+       nclen := int(f.b&0xF) + 4
+       f.b >>= 4
+       f.nb -= 5 + 5 + 4
+
+       // (HCLEN+4)*3 bits: code lengths in the magic codeOrder order.
+       for i := 0; i < nclen; i++ {
+               for f.nb < 3 {
+                       if f.moreBits(); f.err {
+                               return
+                       }
+               }
+               f.codebits[codeOrder[i]] = int(f.b & 0x7)
+               f.b >>= 3
+               f.nb -= 3
+       }
+       for i := nclen; i < len(codeOrder); i++ {
+               f.codebits[codeOrder[i]] = 0
+       }
+       if !f.h1.init(f.codebits[0:]) {
+               f.err = true
+               return
+       }
+
+       // HLIT + 257 code lengths, HDIST + 1 code lengths,
+       // using the code length Huffman code.
+       for i, n := 0, nlit+ndist; i < n; {
+               x := f.huffSym(&f.h1)
+               if f.err {
+                       return
+               }
+               if x < 16 {
+                       // Actual length.
+                       f.bits[i] = x
+                       i++
+                       continue
+               }
+               // Repeat previous length or zero.
+               var rep int
+               var nb uint
+               var b int
+               switch x {
+               default:
+                       f.err = true
+                       return
+               case 16:
+                       rep = 3
+                       nb = 2
+                       if i == 0 {
+                               f.err = true
+                               return
+                       }
+                       b = f.bits[i-1]
+               case 17:
+                       rep = 3
+                       nb = 3
+                       b = 0
+               case 18:
+                       rep = 11
+                       nb = 7
+                       b = 0
+               }
+               for f.nb < nb {
+                       if f.moreBits(); f.err {
+                               return
+                       }
+               }
+               rep += int(f.b & uint32(1<<nb-1))
+               f.b >>= nb
+               f.nb -= nb
+               if i+rep > n {
+                       f.err = true
+                       return
+               }
+               for j := 0; j < rep; j++ {
+                       f.bits[i] = b
+                       i++
+               }
+       }
+
+       if !f.h1.init(f.bits[0:nlit]) || !f.h2.init(f.bits[nlit:nlit+ndist]) {
+               f.err = true
+               return
+       }
+}
+
+// Decode a single Huffman block from f.
+// hl and hd are the Huffman states for the lit/length values
+// and the distance values, respectively.  If hd == nil, using the
+// fixed distance encoding associated with fixed Huffman blocks.
+func (f *decompressor) huffmanBlock(hl, hd *huffmanDecoder) {
+       for {
+               v := f.huffSym(hl)
+               if f.err {
+                       return
+               }
+               var n uint // number of bits extra
+               var length int
+               switch {
+               case v < 256:
+                       f.out = append(f.out, byte(v))
+                       continue
+               case v == 256:
+                       // Done with huffman block; read next block.
+                       return
+               // otherwise, reference to older data
+               case v < 265:
+                       length = v - (257 - 3)
+                       n = 0
+               case v < 269:
+                       length = v*2 - (265*2 - 11)
+                       n = 1
+               case v < 273:
+                       length = v*4 - (269*4 - 19)
+                       n = 2
+               case v < 277:
+                       length = v*8 - (273*8 - 35)
+                       n = 3
+               case v < 281:
+                       length = v*16 - (277*16 - 67)
+                       n = 4
+               case v < 285:
+                       length = v*32 - (281*32 - 131)
+                       n = 5
+               default:
+                       length = 258
+                       n = 0
+               }
+               if n > 0 {
+                       for f.nb < n {
+                               if f.moreBits(); f.err {
+                                       return
+                               }
+                       }
+                       length += int(f.b & uint32(1<<n-1))
+                       f.b >>= n
+                       f.nb -= n
+               }
+
+               var dist int
+               if hd == nil {
+                       for f.nb < 5 {
+                               if f.moreBits(); f.err {
+                                       return
+                               }
+                       }
+                       dist = int(reverseByte[(f.b&0x1F)<<3])
+                       f.b >>= 5
+                       f.nb -= 5
+               } else {
+                       if dist = f.huffSym(hd); f.err {
+                               return
+                       }
+               }
+
+               switch {
+               case dist < 4:
+                       dist++
+               case dist >= 30:
+                       f.err = true
+                       return
+               default:
+                       nb := uint(dist-2) >> 1
+                       // have 1 bit in bottom of dist, need nb more.
+                       extra := (dist & 1) << nb
+                       for f.nb < nb {
+                               if f.moreBits(); f.err {
+                                       return
+                               }
+                       }
+                       extra |= int(f.b & uint32(1<<nb-1))
+                       f.b >>= nb
+                       f.nb -= nb
+                       dist = 1<<(nb+1) + 1 + extra
+               }
+
+               // Copy [-dist:-dist+length] into output.
+               // Encoding can be prescient, so no check on length.
+               if dist > len(f.out) {
+                       f.err = true
+                       return
+               }
+
+               p := len(f.out) - dist
+               for i := 0; i < length; i++ {
+                       f.out = append(f.out, f.out[p])
+                       p++
+               }
+       }
+}
+
+// Copy a single uncompressed data block from input to output.
+func (f *decompressor) dataBlock() {
+       // Uncompressed.
+       // Discard current half-byte.
+       f.nb = 0
+       f.b = 0
+
+       if len(f.in) < 4 {
+               f.err = true
+               return
+       }
+
+       buf := f.in[:4]
+       f.in = f.in[4:]
+       n := int(buf[0]) | int(buf[1])<<8
+       nn := int(buf[2]) | int(buf[3])<<8
+       if uint16(nn) != uint16(^n) {
+               f.err = true
+               return
+       }
+
+       if len(f.in) < n {
+               f.err = true
+               return
+       }
+       f.out = append(f.out, f.in[:n]...)
+       f.in = f.in[n:]
+}
+
+func (f *decompressor) moreBits() {
+       if len(f.in) == 0 {
+               f.err = true
+               return
+       }
+       c := f.in[0]
+       f.in = f.in[1:]
+       f.b |= uint32(c) << f.nb
+       f.nb += 8
+}
+
+// Read the next Huffman-encoded symbol from f according to h.
+func (f *decompressor) huffSym(h *huffmanDecoder) int {
+       for n := uint(h.min); n <= uint(h.max); n++ {
+               lim := h.limit[n]
+               if lim == -1 {
+                       continue
+               }
+               for f.nb < n {
+                       if f.moreBits(); f.err {
+                               return 0
+                       }
+               }
+               v := int(f.b & uint32(1<<n-1))
+               v <<= 16 - n
+               v = int(reverseByte[v>>8]) | int(reverseByte[v&0xFF])<<8 // reverse bits
+               if v <= lim {
+                       f.b >>= n
+                       f.nb -= n
+                       return h.codes[v-h.base[n]]
+               }
+       }
+       f.err = true
+       return 0
+}
+
+var reverseByte = [256]byte{
+       0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+       0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+       0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+       0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+       0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+       0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+       0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+       0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+       0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+       0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+       0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+       0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+       0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+       0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+       0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+       0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+       0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+       0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+       0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+       0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+       0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+       0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+       0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+       0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+       0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+       0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+       0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+       0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+       0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+       0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+       0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+       0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
+}
+
+// Hard-coded Huffman tables for DEFLATE algorithm.
+// See RFC 1951, section 3.2.6.
+var fixedHuffmanDecoder = huffmanDecoder{
+       7, 9,
+       [maxCodeLen + 1]int{7: 23, 199, 511},
+       [maxCodeLen + 1]int{7: 0, 24, 224},
+       []int{
+               // length 7: 256-279
+               256, 257, 258, 259, 260, 261, 262,
+               263, 264, 265, 266, 267, 268, 269,
+               270, 271, 272, 273, 274, 275, 276,
+               277, 278, 279,
+
+               // length 8: 0-143
+               0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+               12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+               22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+               32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+               42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
+               52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+               62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+               72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
+               82, 83, 84, 85, 86, 87, 88, 89, 90, 91,
+               92, 93, 94, 95, 96, 97, 98, 99, 100,
+               101, 102, 103, 104, 105, 106, 107, 108,
+               109, 110, 111, 112, 113, 114, 115, 116,
+               117, 118, 119, 120, 121, 122, 123, 124,
+               125, 126, 127, 128, 129, 130, 131, 132,
+               133, 134, 135, 136, 137, 138, 139, 140,
+               141, 142, 143,
+
+               // length 8: 280-287
+               280, 281, 282, 283, 284, 285, 286, 287,
+
+               // length 9: 144-255
+               144, 145, 146, 147, 148, 149, 150, 151,
+               152, 153, 154, 155, 156, 157, 158, 159,
+               160, 161, 162, 163, 164, 165, 166, 167,
+               168, 169, 170, 171, 172, 173, 174, 175,
+               176, 177, 178, 179, 180, 181, 182, 183,
+               184, 185, 186, 187, 188, 189, 190, 191,
+               192, 193, 194, 195, 196, 197, 198, 199,
+               200, 201, 202, 203, 204, 205, 206, 207,
+               208, 209, 210, 211, 212, 213, 214, 215,
+               216, 217, 218, 219, 220, 221, 222, 223,
+               224, 225, 226, 227, 228, 229, 230, 231,
+               232, 233, 234, 235, 236, 237, 238, 239,
+               240, 241, 242, 243, 244, 245, 246, 247,
+               248, 249, 250, 251, 252, 253, 254, 255,
+       },
+}
+
+// Huffman decoder is based on
+// J. Brian Connell, ``A Huffman-Shannon-Fano Code,''
+// Proceedings of the IEEE, 61(7) (July 1973), pp 1046-1047.
+type huffmanDecoder struct {
+       // min, max code length
+       min, max int
+
+       // limit[i] = largest code word of length i
+       // Given code v of length n,
+       // need more bits if v > limit[n].
+       limit [maxCodeLen + 1]int
+
+       // base[i] = smallest code word of length i - seq number
+       base [maxCodeLen + 1]int
+
+       // codes[seq number] = output code.
+       // Given code v of length n, value is
+       // codes[v - base[n]].
+       codes []int
+}
+
+// Initialize Huffman decoding tables from array of code lengths.
+func (h *huffmanDecoder) init(bits []int) bool {
+       // Count number of codes of each length,
+       // compute min and max length.
+       var count [maxCodeLen + 1]int
+       var min, max int
+       for _, n := range bits {
+               if n == 0 {
+                       continue
+               }
+               if min == 0 || n < min {
+                       min = n
+               }
+               if n > max {
+                       max = n
+               }
+               count[n]++
+       }
+       if max == 0 {
+               return false
+       }
+
+       h.min = min
+       h.max = max
+
+       // For each code range, compute
+       // nextcode (first code of that length),
+       // limit (last code of that length), and
+       // base (offset from first code to sequence number).
+       code := 0
+       seq := 0
+       var nextcode [maxCodeLen]int
+       for i := min; i <= max; i++ {
+               n := count[i]
+               nextcode[i] = code
+               h.base[i] = code - seq
+               code += n
+               seq += n
+               h.limit[i] = code - 1
+               code <<= 1
+       }
+
+       // Make array mapping sequence numbers to codes.
+       if len(h.codes) < len(bits) {
+               h.codes = make([]int, len(bits))
+       }
+       for i, n := range bits {
+               if n == 0 {
+                       continue
+               }
+               code := nextcode[n]
+               nextcode[n]++
+               seq := code - h.base[n]
+               h.codes[seq] = i
+       }
+       return true
+}
+
+func inflate(in string) (out []byte) {
+       var d decompressor
+       d.in = in
+       for !d.err && !d.eof {
+               d.nextBlock()
+       }
+       if len(d.in) != 0 {
+               println("fs unzip: junk at end of compressed data")
+               return nil
+       }
+       return d.out
+}
+
+// get4 returns the little-endian 32-bit value in b.
+func zget4(b string) int {
+       if len(b) < 4 {
+               return 0
+       }
+       return int(b[0]) | int(b[1])<<8 | int(b[2])<<16 | int(b[3])<<24
+}
+
+// get2 returns the little-endian 16-bit value in b.
+func zget2(b string) int {
+       if len(b) < 2 {
+               return 0
+       }
+       return int(b[0]) | int(b[1])<<8
+}
+
+func unzip(data string) {
+       const (
+               zecheader   = 0x06054b50
+               zcheader    = 0x02014b50
+               ztailsize   = 22
+               zheadersize = 30
+               zheader     = 0x04034b50
+       )
+
+       buf := data[len(data)-ztailsize:]
+       n := zget2(buf[10:])
+       size := zget4(buf[12:])
+       off := zget4(buf[16:])
+
+       hdr := data[off : off+size]
+       for i := 0; i < n; i++ {
+               // zip entry layout:
+               //      0       magic[4]
+               //      4       madevers[1]
+               //      5       madeos[1]
+               //      6       extvers[1]
+               //      7       extos[1]
+               //      8       flags[2]
+               //      10      meth[2]
+               //      12      modtime[2]
+               //      14      moddate[2]
+               //      16      crc[4]
+               //      20      csize[4]
+               //      24      uncsize[4]
+               //      28      namelen[2]
+               //      30      xlen[2]
+               //      32      fclen[2]
+               //      34      disknum[2]
+               //      36      iattr[2]
+               //      38      eattr[4]
+               //      42      off[4]
+               //      46      name[namelen]
+               //      46+namelen+xlen+fclen - next header
+               //
+               if zget4(hdr) != zcheader {
+                       println("fs unzip: bad magic")
+                       break
+               }
+               meth := zget2(hdr[10:])
+               mtime := zget2(hdr[12:])
+               mdate := zget2(hdr[14:])
+               csize := zget4(hdr[20:])
+               size := zget4(hdr[24:])
+               namelen := zget2(hdr[28:])
+               xlen := zget2(hdr[30:])
+               fclen := zget2(hdr[32:])
+               xattr := uint32(zget4(hdr[38:])) >> 16
+               off := zget4(hdr[42:])
+               name := hdr[46 : 46+namelen]
+               hdr = hdr[46+namelen+xlen+fclen:]
+
+               // zip per-file header layout:
+               //      0       magic[4]
+               //      4       extvers[1]
+               //      5       extos[1]
+               //      6       flags[2]
+               //      8       meth[2]
+               //      10      modtime[2]
+               //      12      moddate[2]
+               //      14      crc[4]
+               //      18      csize[4]
+               //      22      uncsize[4]
+               //      26      namelen[2]
+               //      28      xlen[2]
+               //      30      name[namelen]
+               //      30+namelen+xlen - file data
+               //
+               buf := data[off : off+zheadersize+namelen]
+               if zget4(buf) != zheader ||
+                       zget2(buf[8:]) != meth ||
+                       zget2(buf[26:]) != namelen ||
+                       buf[30:30+namelen] != name {
+                       println("fs unzip: inconsistent zip file")
+                       return
+               }
+               xlen = zget2(buf[28:])
+
+               off += zheadersize + namelen + xlen
+
+               var fdata []byte
+               switch meth {
+               case 0:
+                       // buf is uncompressed
+                       buf = data[off : off+size]
+                       fdata = []byte(buf)
+               case 8:
+                       // buf is deflate-compressed
+                       buf = data[off : off+csize]
+                       fdata = inflate(buf)
+                       if len(fdata) != size {
+                               println("fs unzip: inconsistent size in zip file")
+                               return
+                       }
+               }
+
+               if xattr&S_IFMT == 0 {
+                       if xattr&0777 == 0 {
+                               xattr |= 0666
+                       }
+                       if len(name) > 0 && name[len(name)-1] == '/' {
+                               xattr |= S_IFDIR
+                               xattr |= 0111
+                       } else {
+                               xattr |= S_IFREG
+                       }
+               }
+
+               if err := create(name, xattr, zipToTime(mdate, mtime), fdata); err != nil {
+                       print("fs unzip: create ", name, ": ", err.Error(), "\n")
+               }
+       }
+
+       chdirEnv()
+}
+
+func zipToTime(date, time int) int64 {
+       dd := date & 0x1f
+       mm := date >> 5 & 0xf
+       yy := date >> 9 // since 1980
+
+       sec := int64(315532800) // jan 1 1980
+       sec += int64(yy) * 365 * 86400
+       sec += int64(yy) / 4 * 86400
+       if yy%4 > 0 || mm >= 3 {
+               sec += 86400
+       }
+       sec += int64(daysBeforeMonth[mm]) * 86400
+       sec += int64(dd-1) * 86400
+
+       h := time >> 11
+       m := time >> 5 & 0x3F
+       s := time & 0x1f * 2
+       sec += int64(h*3600 + m*60 + s)
+
+       return sec
+}
+
+var daysBeforeMonth = [...]int32{
+       0,
+       0,
+       31,
+       31 + 28,
+       31 + 28 + 31,
+       31 + 28 + 31 + 30,
+       31 + 28 + 31 + 30 + 31,
+       31 + 28 + 31 + 30 + 31 + 30,
+       31 + 28 + 31 + 30 + 31 + 30 + 31,
+       31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
+       31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
+       31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
+       31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
+       31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + 31,
+}
diff --git a/src/pkg/syscall/zsyscall_nacl_386.go b/src/pkg/syscall/zsyscall_nacl_386.go
new file mode 100644 (file)
index 0000000..32eed33
--- /dev/null
@@ -0,0 +1,63 @@
+// mksyscall.pl -l32 -nacl syscall_nacl.go syscall_nacl_386.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclClose(fd int) (err error) {
+       _, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) (err error) {
+       _, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclFstat(fd int, stat *Stat_t) (err error) {
+       _, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclRead(fd int, b []byte) (n int, err error) {
+       var _p0 unsafe.Pointer
+       if len(b) > 0 {
+               _p0 = unsafe.Pointer(&b[0])
+       } else {
+               _p0 = unsafe.Pointer(&_zero)
+       }
+       r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
+       n = int(r0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclSeek(fd int, off *int64, whence int) (err error) {
+       _, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
diff --git a/src/pkg/syscall/zsyscall_nacl_amd64p32.go b/src/pkg/syscall/zsyscall_nacl_amd64p32.go
new file mode 100644 (file)
index 0000000..8bc81fa
--- /dev/null
@@ -0,0 +1,63 @@
+// mksyscall.pl -nacl syscall_nacl.go syscall_nacl_amd64p32.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclClose(fd int) (err error) {
+       _, _, e1 := Syscall(sys_close, uintptr(fd), 0, 0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) (err error) {
+       _, _, e1 := Syscall(sys_exit, uintptr(code), 0, 0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclFstat(fd int, stat *Stat_t) (err error) {
+       _, _, e1 := Syscall(sys_fstat, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclRead(fd int, b []byte) (n int, err error) {
+       var _p0 unsafe.Pointer
+       if len(b) > 0 {
+               _p0 = unsafe.Pointer(&b[0])
+       } else {
+               _p0 = unsafe.Pointer(&_zero)
+       }
+       r0, _, e1 := Syscall(sys_read, uintptr(fd), uintptr(_p0), uintptr(len(b)))
+       n = int(r0)
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func naclSeek(fd int, off *int64, whence int) (err error) {
+       _, _, e1 := Syscall(sys_lseek, uintptr(fd), uintptr(unsafe.Pointer(off)), uintptr(whence))
+       if e1 != 0 {
+               err = e1
+       }
+       return
+}
index 36c214b6b093b99d3df23918807bd654d76eae24..379e13d6a537f7ec87ef818c9881a7212ecdb52d 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 package time
 
index 26159c1aa038f5069e8363ef1f33bb2b87859842..ab7e4612e464d555954eec10ef034745cc577732 100644 (file)
@@ -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 darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
 
 // Parse "zoneinfo" time zone file.
 // This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others.
index 9a4d794ad2fb2a7974aa07ce7f24cfa5b1f53185..c6775c01501ce150a7b9e46f5d7bcb7a5ff5ad13 100644 (file)
@@ -45,6 +45,8 @@ var (
 
        // letter is the build.ArchChar
        letter string
+       
+       goos, goarch string
 
        // dirs are the directories to look for *.go files in.
        // TODO(bradfitz): just use all directories?
@@ -74,6 +76,10 @@ func main() {
                *numParallel = 1
        }
 
+       goos = os.Getenv("GOOS")
+       goarch = os.Getenv("GOARCH")
+       findExecCmd()
+
        ratec = make(chan bool, *numParallel)
        rungatec = make(chan bool, *runoutputLimit)
        var err error
@@ -413,7 +419,7 @@ func (t *test) run() {
                t.err = errors.New("double newline not found")
                return
        }
-       if ok, why := shouldTest(t.src, runtime.GOOS, runtime.GOARCH); !ok {
+       if ok, why := shouldTest(t.src, goos, goarch); !ok {
                t.action = "skip"
                if *showSkips {
                        fmt.Printf("%-20s %-20s: %s\n", t.action, t.goFileName(), why)
@@ -473,8 +479,12 @@ func (t *test) run() {
        check(err)
 
        // A few tests (of things like the environment) require these to be set.
-       os.Setenv("GOOS", runtime.GOOS)
-       os.Setenv("GOARCH", runtime.GOARCH)
+       if os.Getenv("GOOS") == "" {
+               os.Setenv("GOOS", runtime.GOOS)
+       }
+       if os.Getenv("GOARCH") == "" {
+               os.Setenv("GOARCH", runtime.GOARCH)
+       }
 
        useTmp := true
        runcmd := func(args ...string) ([]byte, error) {
@@ -589,7 +599,11 @@ func (t *test) run() {
                                        t.err = err
                                        return
                                }
-                               out, err := runcmd(append([]string{filepath.Join(t.tempDir, "a.exe")}, args...)...)
+                               var cmd []string
+                               cmd = append(cmd, findExecCmd()...)
+                               cmd = append(cmd, filepath.Join(t.tempDir, "a.exe"))
+                               cmd = append(cmd, args...)
+                               out, err := runcmd(cmd...)
                                if err != nil {
                                        t.err = err
                                        return
@@ -671,6 +685,23 @@ func (t *test) run() {
        }
 }
 
+var execCmd []string
+
+func findExecCmd() []string {
+       if execCmd != nil {
+               return execCmd
+       }
+       execCmd = []string{} // avoid work the second time
+       if goos == runtime.GOOS && goarch == runtime.GOARCH {
+               return execCmd
+       }
+       path, err := exec.LookPath(fmt.Sprintf("go_%s_%s_exec", goos, goarch))
+       if err == nil {
+               execCmd = []string{path}
+       }
+       return execCmd
+}      
+
 func (t *test) String() string {
        return filepath.Join(t.dir, t.gofile)
 }