]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: closures, defer bug fix for Native Client
authorRuss Cox <rsc@golang.org>
Fri, 23 Apr 2010 00:52:22 +0000 (17:52 -0700)
committerRuss Cox <rsc@golang.org>
Fri, 23 Apr 2010 00:52:22 +0000 (17:52 -0700)
Enable package tests for Native Client build.

R=r
CC=golang-dev
https://golang.org/cl/957042

36 files changed:
misc/nacl/naclrun [new file with mode: 0755]
src/all-nacl.bash
src/cmd/8g/ggen.c
src/cmd/8l/asm.c
src/cmd/8l/l.h
src/cmd/8l/obj.c
src/cmd/8l/span.c
src/cmd/gotest/gotest
src/pkg/Makefile
src/pkg/os/stat_nacl.go
src/pkg/runtime/Makefile
src/pkg/runtime/malloc.h
src/pkg/runtime/mgc0.c
src/pkg/runtime/nacl/386/closure.c [new file with mode: 0644]
src/pkg/runtime/nacl/386/sys.s
src/pkg/runtime/nacl/thread.c
src/pkg/syscall/syscall_nacl.go
test/env.go
test/fixedbugs/bug243.go
test/nacl-pass.txt [deleted file]
test/nilptr/arrayindex.go
test/nilptr/arrayindex1.go
test/nilptr/arraytoslice.go
test/nilptr/arraytoslice1.go
test/nilptr/arraytoslice2.go
test/nilptr/slicearray.go
test/nilptr/structfield.go
test/nilptr/structfield1.go
test/nilptr/structfield2.go
test/nilptr/structfieldaddr.go
test/nul1.go
test/recover3.go
test/run
test/run-nacl [deleted file]
test/sigchld.go
test/stack.go

diff --git a/misc/nacl/naclrun b/misc/nacl/naclrun
new file mode 100755 (executable)
index 0000000..1cdcf87
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/sh
+# 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.
+
+# Run nacl binary in debug mode (allow file access)
+# and then grep away the chatter.
+# See ../../src/pkg/exp/nacl/README for more on
+# how to configure NaCl.
+
+nacl -d "$@" >/tmp/nacl.out.$$ 2>&1
+status=$?
+egrep -v 'DEBUG MODE ENABLED|^\[[0-9]+,' /tmp/nacl.out.$$
+rm -f /tmp/nacl.out.$$
+exit $status
index 23107d25e34e2a33cc6b22ed9414fe5a54898de5..817b911c07725629ecf931fd97e860b4a9f57c06 100755 (executable)
@@ -7,6 +7,7 @@
 
 export GOARCH=386
 export GOOS=nacl
+export GORUN="$GOROOT/misc/nacl/naclrun"
 
 set -e
 bash make.bash
@@ -17,6 +18,11 @@ xcd() {
        builtin cd $1
 }
 
+(xcd pkg
+make install
+make test
+) || exit $?
+
 (xcd pkg/exp/nacl/srpc
 make clean
 make install
@@ -38,5 +44,5 @@ make
 ) || exit $?
 
 (xcd ../test
-./run-nacl
+./run
 ) || exit $?
index c1cad74bee18defb4c6dbfa27d0155e3b808244c..110446a0d772217ee2d235c5549f51030b533425 100644 (file)
@@ -8,6 +8,7 @@
 #include "opt.h"
 
 static Prog *pret;
+static Node *naclnop;
 
 void
 compile(Node *fn)
@@ -23,6 +24,7 @@ compile(Node *fn)
                newproc = sysfunc("newproc");
                deferproc = sysfunc("deferproc");
                deferreturn = sysfunc("deferreturn");
+               naclnop = sysfunc("naclnop");
                panicindex = sysfunc("panicindex");
                panicslice = sysfunc("panicslice");
                throwreturn = sysfunc("throwreturn");
@@ -95,8 +97,16 @@ compile(Node *fn)
        gclean();
        if(nerrors != 0)
                goto ret;
-       if(hasdefer)
+       if(hasdefer) {
+               // On Native client, insert call to no-op function
+               // to force alignment immediately before call to deferreturn,
+               // so that when jmpdefer subtracts 5 from the second CALL's
+               // return address and then the return masks off the low bits,
+               // we'll back up to the NOPs immediately after the dummy CALL.
+               if(strcmp(getgoos(), "nacl") == 0)
+                       ginscall(naclnop, 0);
                ginscall(deferreturn, 0);
+       }
        pc->as = ARET;  // overwrite AEND
        pc->lineno = lineno;
 
index 4e8c0560d9b1e16ae01708ac05c7ff9b776e102a..0fca6fa0f87f65688ea8fd358796d27f0f68a9ee 100644 (file)
@@ -226,8 +226,11 @@ addsize(Sym *s, Sym *t)
 vlong
 datoff(vlong addr)
 {
-       if(addr >= INITDAT)
+       if(addr >= INITDAT) {
+               if(HEADTYPE == 8)
+                       return addr - INITDAT + rnd(HEADR+textsize, 4096);
                return addr - INITDAT + rnd(HEADR+textsize, INITRND);
+       }
        diag("datoff %#llx", addr);
        return 0;
 }
@@ -548,6 +551,14 @@ asmb(void)
                }
                cflush();
                break;
+       case 8:
+               // Native Client only needs to round
+               // text segment file address to 4096 bytes,
+               // but text segment memory address rounds
+               // to INITRND (65536).
+               v = rnd(HEADR+textsize, 4096);
+               seek(cout, v, 0);
+               break;
        Elfseek:
        case 10:
                v = rnd(HEADR+textsize, INITRND);
@@ -829,15 +840,25 @@ asmb(void)
                ph = newElfPhdr();
                ph->type = PT_LOAD;
                ph->flags = PF_X+PF_R;
-               ph->vaddr = va - fo;
-               ph->paddr = va - fo;
-               ph->off = 0;
-               ph->filesz = w + fo;
-               ph->memsz = w + fo;
+               if(HEADTYPE != 8) {     // Include header, but not on Native Client.
+                       va -= fo;
+                       w += fo;
+                       fo = 0;
+               }
+               ph->vaddr = va;
+               ph->paddr = va;
+               ph->off = fo;
+               ph->filesz = w;
+               ph->memsz = INITDAT - va;
                ph->align = INITRND;
 
-               fo = rnd(fo+w, INITRND);
-               va = rnd(va+w, INITRND);
+               // NaCl text segment file address rounds to 4096;
+               // only memory address rounds to INITRND.
+               if(HEADTYPE == 8)
+                       fo = rnd(fo+w, 4096);
+               else
+                       fo = rnd(fo+w, INITRND);
+               va = INITDAT;
                w = datsize;
 
                ph = newElfPhdr();
@@ -941,7 +962,7 @@ asmb(void)
                ph->flags = PF_W+PF_R;
                ph->align = 4;
 
-               fo = ELFRESERVE;
+               fo = HEADR;
                va = startva + fo;
                w = textsize;
 
@@ -953,7 +974,12 @@ asmb(void)
                sh->size = w;
                sh->addralign = 4;
 
-               fo = rnd(fo+w, INITRND);
+               // NaCl text segment file address rounds to 4096;
+               // only memory address rounds to INITRND.
+               if(HEADTYPE == 8)
+                       fo = rnd(fo+w, 4096);
+               else
+                       fo = rnd(fo+w, INITRND);
                va = rnd(va+w, INITRND);
                w = datsize;
 
@@ -1013,7 +1039,7 @@ asmb(void)
                switch(HEADTYPE) {
                case 8:
                        eh->ident[EI_OSABI] = ELFOSABI_NACL;
-                       eh->ident[EI_ABIVERSION] = 6;
+                       eh->ident[EI_ABIVERSION] = 7;
                        eh->flags = 0x200000;   // aligned mod 32
                        break;
                case 9:
index 8f02bdefda0a614fa2e01e5c0ca0993d5d9ab865..5b0f307233eb826447cbca42fc8d9532c9ec30f7 100644 (file)
@@ -302,6 +302,7 @@ EXTERN      Sym*    symlist;
 EXTERN int32   symsize;
 EXTERN Prog*   textp;
 EXTERN int32   textsize;
+EXTERN int32   textpad;
 EXTERN int     version;
 EXTERN Prog    zprg;
 EXTERN int     dtype;
index cd7984d7158264e11252f4fc44a53ba8cbf0e2c0..82f4e47b7c0dd81392513cf4f51d3d02375566a3 100644 (file)
@@ -280,7 +280,12 @@ main(int argc, char *argv[])
                if(INITDAT == -1)
                        INITDAT = 0;
                if(INITRND == -1)
-                       INITRND = 4096;
+                       INITRND = 65536;
+               
+               // 512 kB of address space for closures.
+               // (Doesn't take any space in the binary file.)
+               // Closures are 64 bytes each, so this is 8,192 closures.
+               textpad = 512*1024;
                break;
        case 10: /* PE executable */
                peinit();
index f649777ec39b60c74377b35740660613bdff105e..0245d72b9bf0504d7ddd8d3f696d4a20efb795bd 100644 (file)
@@ -108,7 +108,7 @@ start:
        }while(again);
 
        if(INITRND) {
-               INITDAT = rnd(c, INITRND);
+               INITDAT = rnd(c+textpad, INITRND);
                if(INITDAT != idat) {
                        idat = INITDAT;
                        goto start;
index 3fca81b6a575e145ce7b2303643167f435e3c7c9..0a0aafc3440622de762feee05e7b64e74d469f4c 100755 (executable)
@@ -29,11 +29,7 @@ if [ -z "$O" ]; then
        exit 2
 fi
 
-E=""
-case "$GOOS" in
-nacl)
-       E="nacl"
-esac
+E="$GORUN"
 
 # TODO(kaib): proper emulator strategy
 case x"$GOARCH" in
index 4057ed97d183d5dbff562be0599fdc41bca2ac3f..a9c400a9ceef896ab1a2d973addd5dc6b7ed0e53 100644 (file)
@@ -150,6 +150,25 @@ TEST=\
 BENCH=\
        $(filter-out $(NOBENCH),$(TEST))
 
+# Disable tests that NaCl cannot run yet.
+ifeq ($(GOOS),nacl)
+NOTEST+=archive/tar  # no pipe
+NOTEST+=debug/dwarf  # no pread
+NOTEST+=debug/macho  # no pread
+NOTEST+=debug/elf    # no pread
+NOTEST+=exec         # no pipe
+NOTEST+=http         # no network
+NOTEST+=log          # no runtime.Caller
+NOTEST+=net          # no network
+NOTEST+=os           # many things unimplemented
+NOTEST+=os/signal    # no signals
+NOTEST+=path         # tree walking does not work
+NOTEST+=rpc          # no network
+NOTEST+=syslog       # no network
+NOTEST+=time         # no syscall.Kill, syscall.SIGCHLD for sleep tests
+NOTEST+=websocket    # no network
+endif
+
 clean.dirs: $(addsuffix .clean, $(DIRS))
 install.dirs: $(addsuffix .install, $(DIRS))
 nuke.dirs: $(addsuffix .nuke, $(DIRS))
index be693e81478c90b694e270a91628cfb3ab611251..a44d0b0b6ec66f91673c71afb0af4249402a8e54 100644 (file)
@@ -15,15 +15,15 @@ func fileInfoFromStat(name string, fi *FileInfo, lstat, stat *syscall.Stat_t) *F
        fi.Ino = uint64(stat.Ino)
        fi.Nlink = uint64(stat.Nlink)
        fi.Mode = stat.Mode
-       fi.Uid = stat.Uid
-       fi.Gid = stat.Gid
+       fi.Uid = int(stat.Uid)
+       fi.Gid = int(stat.Gid)
        fi.Rdev = uint64(stat.Rdev)
-       fi.Size = uint64(stat.Size)
-       fi.Blksize = uint64(stat.Blksize)
-       fi.Blocks = uint64(stat.Blocks)
-       fi.Atime_ns = uint64(stat.Atime) * 1e9
-       fi.Mtime_ns = uint64(stat.Mtime) * 1e9
-       fi.Ctime_ns = uint64(stat.Ctime) * 1e9
+       fi.Size = int64(stat.Size)
+       fi.Blksize = int64(stat.Blksize)
+       fi.Blocks = int64(stat.Blocks)
+       fi.Atime_ns = int64(stat.Atime) * 1e9
+       fi.Mtime_ns = int64(stat.Mtime) * 1e9
+       fi.Ctime_ns = int64(stat.Ctime) * 1e9
        for i := len(name) - 1; i >= 0; i-- {
                if name[i] == '/' {
                        name = name[i+1:]
index f7da0251e55d782f09c4272e785b2efce3a476f3..6b3ab21e35422c9d0374721e035e10a3b266d854 100644 (file)
@@ -154,8 +154,12 @@ runtime.acid.$(GOARCH): runtime.h proc.c
 
 # 386 traceback is really amd64 traceback
 ifeq ($(GOARCH),386)
-
 traceback.$O:  amd64/traceback.c
        $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
+endif
 
+# NaCl closure is special.
+ifeq ($(GOOS),nacl)
+closure.$O: nacl/$(GOARCH)/closure.c
+       $(QUOTED_GOBIN)/$(CC) $(CFLAGS) $<
 endif
index 8b733b6a4af80eccf4227a65258849b30eb765a2..473e8a836fdd680f9f29a0067ce9760e8f687f70 100644 (file)
@@ -324,6 +324,10 @@ struct MHeap
        // range of addresses we might see in the heap
        byte *min;
        byte *max;
+       
+       // range of addresses we might see in a Native Client closure
+       byte *closure_min;
+       byte *closure_max;
 
        // central free lists for small size classes.
        // the union makes sure that the MCentrals are
index f78dabf88b1231c1afdba223de1bf284c19eaa99..2324eff29014842a11a832fd5bf0e1cfc11bfbfc 100644 (file)
@@ -56,18 +56,36 @@ scanblock(int32 depth, byte *b, int64 n)
        n /= PtrSize;
        for(i=0; i<n; i++) {
                obj = vp[i];
-               if(obj == nil || (byte*)obj < mheap.min || (byte*)obj >= mheap.max)
+               if(obj == nil)
                        continue;
-               if(mlookup(obj, &obj, &size, nil, &refp)) {
-                       ref = *refp;
-                       switch(ref & ~RefFlags) {
-                       case RefNone:
-                               if(Debug > 1)
-                                       printf("%d found at %p: ", depth, &vp[i]);
-                               *refp = RefSome | (ref & RefFlags);
-                               if(!(ref & RefNoPointers))
-                                       scanblock(depth+1, obj, size);
-                               break;
+               if(mheap.closure_min != nil && mheap.closure_min <= (byte*)obj && (byte*)obj < mheap.closure_max) {
+                       if((((uintptr)obj) & 63) != 0)
+                               continue;
+
+                       // Looks like a Native Client closure.
+                       // Actual pointer is pointed at by address in first instruction.
+                       // Embedded pointer starts at byte 2.
+                       // If it is f4f4f4f4 then that space hasn't been
+                       // used for a closure yet (f4 is the HLT instruction).
+                       // See nacl/386/closure.c for more.
+                       void **pp;
+                       pp = *(void***)((byte*)obj+2);
+                       if(pp == (void**)0xf4f4f4f4)    // HLT... - not a closure after all
+                               continue;
+                       obj = *pp;
+               }
+               if(mheap.min <= (byte*)obj && (byte*)obj < mheap.max) {
+                       if(mlookup(obj, &obj, &size, nil, &refp)) {
+                               ref = *refp;
+                               switch(ref & ~RefFlags) {
+                               case RefNone:
+                                       if(Debug > 1)
+                                               printf("%d found at %p: ", depth, &vp[i]);
+                                       *refp = RefSome | (ref & RefFlags);
+                                       if(!(ref & RefNoPointers))
+                                               scanblock(depth+1, obj, size);
+                                       break;
+                               }
                        }
                }
        }
@@ -310,8 +328,8 @@ gc(int32 force)
                if(fing == nil)
                        fing = newproc1((byte*)runfinq, nil, 0, 0);
                else if(fingwait) {
-                       ready(fing);
                        fingwait = 0;
+                       ready(fing);
                }
        }
        m->locks--;
@@ -359,6 +377,7 @@ runfinq(void)
                        f->fn = nil;
                        f->arg = nil;
                        f->next = nil;
+                       free(f);
                }
                gc(1);  // trigger another gc to clean up the finalized objects, if possible
        }
diff --git a/src/pkg/runtime/nacl/386/closure.c b/src/pkg/runtime/nacl/386/closure.c
new file mode 100644 (file)
index 0000000..6a27d6e
--- /dev/null
@@ -0,0 +1,247 @@
+// 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.
+
+/*
+ * Closure implementation for Native Client.
+ * Native Client imposes some interesting restrictions.
+ *
+ * First, we can only add new code to the code segment
+ * through a special system call, and we have to pick the
+ * maximum amount of code we're going to add that way
+ * at link time (8l reserves 512 kB for us).
+ *
+ * Second, once we've added the code we can't ever
+ * change it or delete it.  If we want to garbage collect
+ * the memory and then reuse it for another closure,
+ * we have to do so without editing the code.
+ *
+ * To address both of these, we fill the code segment pieces
+ * with very stylized closures.  Each has the form given below
+ * in the comments on the closasm array, with ** replaced by
+ * a pointer to a single word of memory.  The garbage collector
+ * treats a pointer to such a closure as equivalent to the value
+ * held in **.  This tiled run of closures is called the closure array.
+ *
+ * The ptr points at a ClosureData structure, defined below,
+ * which gives the function, arguments, and size for the
+ * closuretramp function.  The ClosureData structure has
+ * in it a pointer to a ClosureFreeList structure holding the index
+ * of the closure in the closure array (but not a pointer to it). 
+ * That structure has a finalizer: when the garbage collector
+ * notices that the ClosureFreeList structure is not referenced
+ * anymore, that means the closure is not referenced, so it
+ * can be reused.  To do that, the ClosureFreeList entry is put
+ * onto an actual free list.
+ */
+#include "runtime.h"
+#include "malloc.h"
+
+// NaCl system call to copy data into text segment.
+extern int32 dyncode_copy(void*, void*, int32);
+
+enum{
+       // Allocate chunks of 4096 bytes worth of closures:
+       // at 64 bytes each, that's 64 closures.
+       ClosureChunk = 4096,
+       ClosureSize = 64,
+};
+
+typedef struct ClosureFreeList ClosureFreeList;
+struct ClosureFreeList
+{
+       ClosureFreeList *next;
+       int32 index;    // into closure array
+};
+
+// Known to closasm
+typedef struct ClosureData ClosureData;
+struct ClosureData
+{
+       ClosureFreeList *free;
+       byte *fn;
+       int32 siz;
+       // then args
+};
+
+// List of the closure data pointer blocks we've allocated
+// and hard-coded in the closure text segments.
+// The list keeps the pointer blocks from getting collected.
+typedef struct ClosureDataList ClosureDataList;
+struct ClosureDataList
+{
+       ClosureData **block;
+       ClosureDataList *next;
+};
+
+static struct {
+       Lock;
+       byte *code;
+       byte *ecode;
+       ClosureFreeList *free;
+       ClosureDataList *datalist;
+       byte buf[ClosureChunk];
+} clos;
+
+static byte closasm[64] = {
+       0x8b, 0x1d, 0, 0, 0, 0, // MOVL **, BX
+       0x8b, 0x4b, 8,          // MOVL 8(BX), CX
+       0x8d, 0x73, 12,         // LEAL 12(BX), SI
+       0x29, 0xcc,             // SUBL CX, SP
+       0x89, 0xe7,             // MOVL SP, DI
+       0xc1, 0xe9, 2,          // SHRL $2, CX
+       0xf3, 0xa5,             // REP MOVSL
+       0x8b, 0x5b, 4,          // MOVL 4(BX), BX
+       0x90, 0x90, 0x90,       // NOP...
+       0x83, 0xe3, ~31,        // ANDL $~31, BX
+       0xff, 0xd3,             // CALL *BX
+       // --- 32-byte boundary
+       0x8b, 0x1d, 0, 0, 0, 0, // MOVL **, BX
+       0x03, 0x63, 8,          // ADDL 8(BX), SP
+       0x5b,                   // POPL BX
+       0x83, 0xe3, ~31,        // ANDL $~31, BX
+       0xff, 0xe3,             // JMP *BX
+       0xf4,                   // HLT...
+       0xf4, 0xf4, 0xf4, 0xf4,
+       0xf4, 0xf4, 0xf4, 0xf4,
+       0xf4, 0xf4, 0xf4, 0xf4,
+       0xf4, 0xf4, 0xf4, 0xf4,
+       // --- 32-byte boundary
+};
+
+// Returns immediate pointer from closure code block.
+// Triple pointer:
+//     p is the instruction stream
+//     p+2 is the location of the immediate value
+//     *(p+2) is the immediate value, a word in the pointer block
+//             permanently associated with this closure.
+//     **(p+2) is the ClosureData* pointer temporarily associated
+//             with this closure.
+//
+#define codeptr(p) *(ClosureData***)((byte*)(p)+2)
+
+void
+finclosure(void *v)
+{
+       byte *p;
+       ClosureFreeList *f;
+
+       f = v;
+       p = clos.code + f->index*ClosureSize;
+       *codeptr(p) = nil;
+
+       lock(&clos);
+       f->next = clos.free;
+       clos.free = f;
+       unlock(&clos);
+}
+
+#pragma textflag 7
+// func closure(siz int32,
+//     fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
+//     arg0, arg1, arg2 *ptr) (func(xxx) yyy)
+void
+·closure(int32 siz, byte *fn, byte *arg0)
+{
+       byte *p, **ret;
+       int32 e, i, n, off;
+       extern byte data[], etext[];
+       ClosureData *d, **block;
+       ClosureDataList *l;
+       ClosureFreeList *f;
+
+       if(siz < 0 || siz%4 != 0)
+               throw("bad closure size");
+
+       ret = (byte**)((byte*)&arg0 + siz);
+
+       if(siz > 100) {
+               // TODO(rsc): implement stack growth preamble?
+               throw("closure too big");
+       }
+
+       lock(&clos);
+       if(clos.free == nil) {
+               // Allocate more closures.
+               if(clos.code == nil) {
+                       // First time: find closure space, between end of text
+                       // segment and beginning of data.
+                       clos.code = (byte*)(((uintptr)etext + 65535) & ~65535);
+                       clos.ecode = clos.code;
+                       mheap.closure_min = clos.code;
+                       mheap.closure_max = data;
+               }
+               if(clos.ecode+ClosureChunk > data) {
+                       // Last ditch effort: garbage collect and hope.
+                       unlock(&clos);
+                       gc(1);
+                       lock(&clos);
+                       if(clos.free != nil)
+                               goto alloc;
+                       throw("ran out of room for closures in text segment");
+               }
+
+               n = ClosureChunk/ClosureSize;
+               
+               // Allocate the pointer block as opaque to the
+               // garbage collector.  Finalizers will clean up.
+               block = mallocgc(n*sizeof block[0], RefNoPointers, 1, 1);
+
+               // Pointers into the pointer block are getting added
+               // to the text segment; keep a pointer here in the data
+               // segment so that the garbage collector doesn't free
+               // the block itself.
+               l = mal(sizeof *l);
+               l->block = block;
+               l->next = clos.datalist;
+               clos.datalist = l;
+
+               p = clos.buf;
+               off = (clos.ecode - clos.code)/ClosureSize;
+               for(i=0; i<n; i++) {
+                       f = mal(sizeof *f);
+                       f->index = off++;
+                       f->next = clos.free;
+                       clos.free = f;
+
+                       // There are two hard-coded immediate values in
+                       // the assembly that need to be pp+i, one 2 bytes in
+                       // and one 2 bytes after the 32-byte boundary.
+                       mcpy(p, closasm, ClosureSize);
+                       *(ClosureData***)(p+2) = block+i;
+                       *(ClosureData***)(p+32+2) = block+i;
+                       p += ClosureSize;
+               }
+
+               if(p != clos.buf+sizeof clos.buf)
+                       throw("bad buf math in closure");
+
+               e = dyncode_copy(clos.ecode, clos.buf, ClosureChunk);
+               if(e != 0) {
+                       fd = 2;
+                       printf("dyncode_copy: error %d\n", e);
+                       throw("dyncode_copy");
+               }
+               clos.ecode += ClosureChunk;
+       }
+
+alloc:
+       // Grab a free closure and save the data pointer in its indirect pointer.
+       f = clos.free;
+       clos.free = f->next;
+       f->next = nil;
+       p = clos.code + f->index*ClosureSize;
+
+       d = mal(sizeof(*d)+siz);
+       d->free = f;
+       d->fn = fn;
+       d->siz = siz;
+       mcpy((byte*)(d+1), (byte*)&arg0, siz);
+       *codeptr(p) = d;
+       addfinalizer(f, finclosure, 0);
+       unlock(&clos);
+
+       *ret = p;
+}
+
+
index 356d85eff00b55518cdcf5362838e83759140156..e855351b92739627ea47f8093c33bec581a2c2d6 100644 (file)
@@ -20,6 +20,8 @@
 #define SYS_mutex_lock  71
 #define SYS_mutex_unlock 73
 #define SYS_gettimeofday 40
+#define SYS_dyncode_copy 104
+
 
 #define SYSCALL(x)     $(0x10000+SYS_/**/x * 32)
 
@@ -55,6 +57,15 @@ TEXT mutex_unlock(SB),7,$0
 TEXT thread_create(SB),7,$0
        JMP     SYSCALL(thread_create)
 
+TEXT dyncode_copy(SB),7,$0
+       JMP     SYSCALL(dyncode_copy)
+
+// For Native Client: a simple no-op function.
+// Inserting a call to this no-op is a simple way
+// to trigger an alignment.
+TEXT ·naclnop(SB),7,$0
+       RET
+
 TEXT ·mmap(SB),7,$24
        MOVL    a1+0(FP), BX
        MOVL    a2+4(FP), CX    // round up to 64 kB boundary; silences nacl warning
index 4112eaa993cece39e0831d8874a93ba6a26da67c..392be870ff4e18720a43fca44411b27deaba95dd 100644 (file)
@@ -88,7 +88,7 @@ unlock(Lock *l)
 }
 
 void
-destroylock(Lock *l)
+destroylock(Lock*)
 {
 }
 
index 6a5d9c2d6900124129f042a7d371b9d9f4cb48a6..7b40a22ad05a3e7d4f2bf7e8154cd3d865be5eec 100644 (file)
@@ -131,7 +131,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
 func Mkdir(path string, mode int) (errno int) { return ENACL }
 
 func Lstat(path string, stat *Stat_t) (errno int) {
-       return ENACL
+       return Stat(path, stat)
 }
 
 func Chdir(path string) (errno int) { return ENACL }
index 2cf9ddf381373f74ce8f3542a23b7665d80e8583..b12a72973b49e05c4b944a1aeb3966439c742801 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # NaCl runner does not expose environment
 // $G $F.go && $L $F.$A && ./$A.out
 
 // Copyright 2009 The Go Authors. All rights reserved.
index 01112dae73a30e1d5a45d846c4279514349adc65..837b91035f704915152758aac61c6c90863b3324 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # no network
 // $G $D/$F.go && $L $F.$A && ./$A.out
 
 // Copyright 2010 The Go Authors.  All rights reserved.
diff --git a/test/nacl-pass.txt b/test/nacl-pass.txt
deleted file mode 100644 (file)
index 91a9cc8..0000000
+++ /dev/null
@@ -1,355 +0,0 @@
-./64bit.go
-./args.go
-./assign.go
-./bigalg.go
-./blank.go
-./blank1.go
-./chancap.go
-./char_lit.go
-./closedchan.go
-./cmp1.go
-./complit.go
-./compos.go
-./const.go
-./const1.go
-./const2.go
-./const3.go
-./convert.go
-./convert3.go
-./convlit.go
-./convlit1.go
-./copy.go
-./ddd1.go
-./ddd2.go
-./ddd3.go
-./decl.go
-./declbad.go
-./defer.go
-./empty.go
-./escape.go
-./escape1.go
-./float_lit.go
-./floatcmp.go
-./for.go
-./func.go
-./func1.go
-./func2.go
-./func3.go
-./func4.go
-./gc.go
-./gc1.go
-./hashmap.go
-./hilbert.go
-./if.go
-./if1.go
-./import.go
-./import1.go
-./import2.go
-./import3.go
-./indirect.go
-./indirect1.go
-./initcomma.go
-./initialize.go
-./initializerr.go
-./initsyscall.go
-./int_lit.go
-./intcvt.go
-./iota.go
-./literal.go
-./map.go
-./method.go
-./method1.go
-./method2.go
-./method3.go
-./named.go
-./named1.go
-./nil.go
-./parentype.go
-./range.go
-./rename.go
-./rename1.go
-./runtime.go
-./sieve.go
-./simassign.go
-./string_lit.go
-./stringrange.go
-./switch.go
-./switch1.go
-./test0.go
-./typeswitch.go
-./typeswitch1.go
-./typeswitch2.go
-./utf.go
-./varinit.go
-./vectors.go
-ken/array.go
-ken/chan.go
-ken/chan1.go
-ken/complit.go
-ken/divconst.go
-ken/divmod.go
-ken/embed.go
-ken/for.go
-ken/interbasic.go
-ken/interfun.go
-ken/mfunc.go
-ken/modconst.go
-ken/ptrfun.go
-ken/ptrvar.go
-ken/range.go
-ken/robfor.go
-ken/robfunc.go
-ken/robif.go
-ken/shift.go
-ken/simparray.go
-ken/simpbool.go
-ken/simpconv.go
-ken/simpfun.go
-ken/simpvar.go
-ken/slicearray.go
-ken/sliceslice.go
-ken/strvar.go
-chan/fifo.go
-chan/perm.go
-chan/select.go
-chan/sieve.go
-interface/bigdata.go
-interface/convert.go
-interface/convert1.go
-interface/convert2.go
-interface/embed.go
-interface/embed0.go
-interface/embed1.go
-interface/explicit.go
-interface/fake.go
-interface/pointer.go
-interface/receiver.go
-interface/receiver1.go
-interface/recursive.go
-interface/struct.go
-syntax/forvar.go
-syntax/import.go
-syntax/interface.go
-syntax/semi1.go
-syntax/semi2.go
-syntax/semi3.go
-syntax/semi4.go
-syntax/semi5.go
-syntax/semi6.go
-syntax/semi7.go
-syntax/slice.go
-fixedbugs/bug000.go
-fixedbugs/bug001.go
-fixedbugs/bug002.go
-fixedbugs/bug003.go
-fixedbugs/bug004.go
-fixedbugs/bug005.go
-fixedbugs/bug006.go
-fixedbugs/bug007.go
-fixedbugs/bug008.go
-fixedbugs/bug009.go
-fixedbugs/bug010.go
-fixedbugs/bug011.go
-fixedbugs/bug012.go
-fixedbugs/bug013.go
-fixedbugs/bug014.go
-fixedbugs/bug015.go
-fixedbugs/bug017.go
-fixedbugs/bug020.go
-fixedbugs/bug021.go
-fixedbugs/bug022.go
-fixedbugs/bug023.go
-fixedbugs/bug024.go
-fixedbugs/bug026.go
-fixedbugs/bug028.go
-fixedbugs/bug030.go
-fixedbugs/bug031.go
-fixedbugs/bug035.go
-fixedbugs/bug036.go
-fixedbugs/bug037.go
-fixedbugs/bug038.go
-fixedbugs/bug039.go
-fixedbugs/bug040.go
-fixedbugs/bug045.go
-fixedbugs/bug046.go
-fixedbugs/bug047.go
-fixedbugs/bug048.go
-fixedbugs/bug049.go
-fixedbugs/bug050.go
-fixedbugs/bug051.go
-fixedbugs/bug052.go
-fixedbugs/bug053.go
-fixedbugs/bug054.go
-fixedbugs/bug055.go
-fixedbugs/bug056.go
-fixedbugs/bug057.go
-fixedbugs/bug058.go
-fixedbugs/bug059.go
-fixedbugs/bug060.go
-fixedbugs/bug061.go
-fixedbugs/bug062.go
-fixedbugs/bug063.go
-fixedbugs/bug064.go
-fixedbugs/bug065.go
-fixedbugs/bug066.go
-fixedbugs/bug068.go
-fixedbugs/bug069.go
-fixedbugs/bug071.go
-fixedbugs/bug072.go
-fixedbugs/bug073.go
-fixedbugs/bug074.go
-fixedbugs/bug075.go
-fixedbugs/bug076.go
-fixedbugs/bug077.go
-fixedbugs/bug078.go
-fixedbugs/bug080.go
-fixedbugs/bug082.go
-fixedbugs/bug083.go
-fixedbugs/bug084.go
-fixedbugs/bug085.go
-fixedbugs/bug086.go
-fixedbugs/bug087.go
-fixedbugs/bug088.go
-fixedbugs/bug089.go
-fixedbugs/bug090.go
-fixedbugs/bug091.go
-fixedbugs/bug092.go
-fixedbugs/bug094.go
-fixedbugs/bug096.go
-fixedbugs/bug097.go
-fixedbugs/bug098.go
-fixedbugs/bug099.go
-fixedbugs/bug101.go
-fixedbugs/bug102.go
-fixedbugs/bug103.go
-fixedbugs/bug104.go
-fixedbugs/bug106.go
-fixedbugs/bug107.go
-fixedbugs/bug108.go
-fixedbugs/bug109.go
-fixedbugs/bug110.go
-fixedbugs/bug111.go
-fixedbugs/bug112.go
-fixedbugs/bug114.go
-fixedbugs/bug115.go
-fixedbugs/bug116.go
-fixedbugs/bug117.go
-fixedbugs/bug118.go
-fixedbugs/bug119.go
-fixedbugs/bug120.go
-fixedbugs/bug121.go
-fixedbugs/bug122.go
-fixedbugs/bug123.go
-fixedbugs/bug126.go
-fixedbugs/bug127.go
-fixedbugs/bug128.go
-fixedbugs/bug129.go
-fixedbugs/bug130.go
-fixedbugs/bug131.go
-fixedbugs/bug132.go
-fixedbugs/bug133.go
-fixedbugs/bug135.go
-fixedbugs/bug136.go
-fixedbugs/bug137.go
-fixedbugs/bug139.go
-fixedbugs/bug140.go
-fixedbugs/bug141.go
-fixedbugs/bug142.go
-fixedbugs/bug143.go
-fixedbugs/bug144.go
-fixedbugs/bug145.go
-fixedbugs/bug146.go
-fixedbugs/bug149.go
-fixedbugs/bug150.go
-fixedbugs/bug151.go
-fixedbugs/bug152.go
-fixedbugs/bug153.go
-fixedbugs/bug154.go
-fixedbugs/bug155.go
-fixedbugs/bug156.go
-fixedbugs/bug157.go
-fixedbugs/bug158.go
-fixedbugs/bug160.go
-fixedbugs/bug161.go
-fixedbugs/bug163.go
-fixedbugs/bug164.go
-fixedbugs/bug165.go
-fixedbugs/bug167.go
-fixedbugs/bug168.go
-fixedbugs/bug169.go
-fixedbugs/bug170.go
-fixedbugs/bug171.go
-fixedbugs/bug172.go
-fixedbugs/bug173.go
-fixedbugs/bug174.go
-fixedbugs/bug175.go
-fixedbugs/bug176.go
-fixedbugs/bug177.go
-fixedbugs/bug178.go
-fixedbugs/bug179.go
-fixedbugs/bug180.go
-fixedbugs/bug181.go
-fixedbugs/bug182.go
-fixedbugs/bug183.go
-fixedbugs/bug184.go
-fixedbugs/bug185.go
-fixedbugs/bug186.go
-fixedbugs/bug187.go
-fixedbugs/bug188.go
-fixedbugs/bug189.go
-fixedbugs/bug190.go
-fixedbugs/bug191.go
-fixedbugs/bug192.go
-fixedbugs/bug193.go
-fixedbugs/bug194.go
-fixedbugs/bug195.go
-fixedbugs/bug196.go
-fixedbugs/bug197.go
-fixedbugs/bug198.go
-fixedbugs/bug199.go
-fixedbugs/bug200.go
-fixedbugs/bug201.go
-fixedbugs/bug202.go
-fixedbugs/bug203.go
-fixedbugs/bug204.go
-fixedbugs/bug205.go
-fixedbugs/bug206.go
-fixedbugs/bug207.go
-fixedbugs/bug208.go
-fixedbugs/bug209.go
-fixedbugs/bug211.go
-fixedbugs/bug212.go
-fixedbugs/bug213.go
-fixedbugs/bug214.go
-fixedbugs/bug215.go
-fixedbugs/bug216.go
-fixedbugs/bug217.go
-fixedbugs/bug218.go
-fixedbugs/bug219.go
-fixedbugs/bug220.go
-fixedbugs/bug221.go
-fixedbugs/bug222.go
-fixedbugs/bug223.go
-fixedbugs/bug224.go
-fixedbugs/bug225.go
-fixedbugs/bug226.go
-fixedbugs/bug227.go
-fixedbugs/bug228.go
-fixedbugs/bug229.go
-fixedbugs/bug230.go
-fixedbugs/bug231.go
-fixedbugs/bug232.go
-fixedbugs/bug233.go
-fixedbugs/bug234.go
-fixedbugs/bug235.go
-fixedbugs/bug236.go
-fixedbugs/bug237.go
-fixedbugs/bug238.go
-fixedbugs/bug239.go
-fixedbugs/bug240.go
-fixedbugs/bug241.go
-fixedbugs/bug244.go
-fixedbugs/bug245.go
-fixedbugs/bug247.go
-fixedbugs/bug248.go
-fixedbugs/bug249.go
index c42dedee8144d8814b9a3742fa240aed7e621bce..1767acc275e640471287f74c378140f446f7d849 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
 // $G $D/$F.go && $L $F.$A &&
 //     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
 
index 59126f82d5eb605d5fe0c2cceed28a009d9f80b2..c16cac4053e96fa50d44c7ab687585104b6dd6bb 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
 // $G $D/$F.go && $L $F.$A &&
 //     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
 
index 4864d6855270ef46cf0eac0a8929b0a82d786695..65b2f8a765e7783ee341869e0597a7bd65c2badc 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
 // $G $D/$F.go && $L $F.$A &&
 //     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
 
index 1a479dcdb2b8a4dbf067cbb5ddeabce5dc856618..b5240a803a9f963536a345055c04ed2dca4e0c31 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
 // $G $D/$F.go && $L $F.$A &&
 //     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
 
index 0990b899ddab875d2bd94342de52b9106a3b3e35..38e1a5cb2821034eec45d225b73d9550b0ff376d 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
 // $G $D/$F.go && $L $F.$A &&
 //     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
 
index 7a156b5e64c609c0fd877f98da4ae03292627785..5f88010df849d1f1c99c2b8c592a01230e588a71 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
 // $G $D/$F.go && $L $F.$A &&
 //     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
 
index 22db500d7d1561094f42f118db6a0abaed3d2aa4..9f70ecc70f7d48e4fb815171e78d3f9166cd8a3b 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
 // $G $D/$F.go && $L $F.$A &&
 //     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
 
index 520136805fb6f60d47a4ed484c6be58e402fd457..1a120890a0717cba477936f144dbb992a50072a6 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
 // $G $D/$F.go && $L $F.$A &&
 //     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
 
index a0a552c933394dd37e31a9c3aff73bc211b79e26..25ea8f665c36b55de4cb3e2db17308960f111b02 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
 // $G $D/$F.go && $L $F.$A &&
 //     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
 
index 32e9f79315a83597f22943013db3441f59fe6fca..b5d370ca8b88b9986c944a77b4ebaf415edace41 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # do not bother on NaCl
 // $G $D/$F.go && $L $F.$A &&
 //     ((! sh -c ./$A.out) >/dev/null 2>&1 || echo BUG: should fail)
 
index 026d397544a02319a097956fdbfd9b90723e9ba5..5e459633124c1476a59793a6d2279a999d776336 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # NaCl runner elides NUL in output
 // $G $D/$F.go && $L $F.$A && ./$A.out >tmp.go &&
 // errchk $G -e tmp.go
 // rm -f tmp.go
index f719b0ced1a5c6bc004928c4ff38025e9685c3a3..b982ec8fa5431332c138f67b063366b07cb79acc 100644 (file)
@@ -1,3 +1,4 @@
+// [ $GOOS != nacl ] || exit 0  # NaCl cannot recover from signals
 // $G $D/$F.go && $L $F.$A && ./$A.out
 
 // Copyright 2010 The Go Authors.  All rights reserved.
index 78014c867f6222f43e6e96203bd14188afbbdcb7..b3f54f12f24cdf2d1c5f9bcc10e92781700a13e1 100755 (executable)
--- a/test/run
+++ b/test/run
@@ -22,7 +22,7 @@ esac
 
 case X"$GOOS" in
 Xnacl)
-       export E="nacl"
+       export E=${GORUN:-$GOROOT/misc/nacl/naclrun}
 esac
 
 export G=${A}g
diff --git a/test/run-nacl b/test/run-nacl
deleted file mode 100755 (executable)
index 2f5b7ba..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#!/bin/sh
-# 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.
-
-case X"$GOARCH" in
-X386)
-       # After downloading the Native Client binary distribution,
-       # copy build/native_client/scons-out/opt-*/obj/src/trusted/service_runtime/sel_ldr
-       # into your path as "nacl".  You might need to wrap it to get rid of the
-       # 'Exit syscall handler' print.  To do that, install the binary as nacl.bin and
-       # make this script nacl: 
-       #       #!/bin/sh
-       #       nacl.bin "$@" 2>&1 | grep -v 'Exit syscall handler: 0'
-       #       exit 0
-       export A=8
-       export E=nacl
-       ;;
-*)
-       echo 1>&2 run: unsupported '$GOARCH'
-       exit 1
-esac
-
-export G=${A}g
-export L=${A}l
-export GOTRACEBACK=0
-
-failed=0
-
-export PATH=/bin:/usr/bin:/usr/local/bin:${GOBIN:-$HOME/bin}:$HOME/bin:$(pwd)
-
-RUNFILE=/tmp/gorun-$$-$USER
-TMP1FILE=/tmp/gotest1-$$-$USER
-TMP2FILE=/tmp/gotest2-$$-$USER
-
-# don't run the machine out of memory: limit individual processes to 4GB.
-# on thresher, 3GB suffices to run the tests; with 2GB, peano fails.
-ulimit -v 4000000
-
-for i in $(cat nacl-pass.txt)
-do
-       export F=$(basename $i .go)
-       dir=$(dirname $i)
-       export D=$dir
-       sed '/^\/\//!q; s|//||g; s|./\$A.out|$E &|' $i >$RUNFILE
-       if ! sh $RUNFILE >$TMP1FILE 2>$TMP2FILE
-       then
-               echo
-               echo "===========" $i
-               cat $TMP1FILE
-               cat $TMP2FILE
-               echo >&2 fail: $i
-       elif test -s $TMP1FILE || test -s $TMP2FILE
-       then
-               echo
-               echo "===========" $i
-               cat $TMP1FILE
-               cat $TMP2FILE
-       elif [ $dir = "bugs" ]
-       then
-               echo $i succeeded with no output.
-       fi
-done | # clean up some stack noise
-       egrep -v '^(r[0-9a-z]+|[cfg]s)  +0x'  |
-       sed '/tmp.*Bus error/s/.*Bus/Bus/; /tmp.*Trace.BPT/s/.*Trace/Trace/
-               s!'$RUNFILE'!$RUNFILE!g
-               s/ PC=0x[0-9a-f]*/ PC=xxx/
-               s/^pc: 0x[0-9a-f]*/pc: xxx/
-               /^Trace\/breakpoint trap/d
-               /^Trace\/BPT trap/d
-               /RUNFILE/ s/line 1: *[0-9][0-9]* /line 1: PID /
-               /^\$RUNFILE: line 1: PID Trace\/breakpoint trap/d
-               /^qemu: uncaught target signal 11 (Segmentation fault) - exiting/d' > run.out
-
-case $failed in
-0)
-       echo PASS
-       ;;
-1)
-       echo FAIL
-esac
-rm  -f $RUNFILE $TMP1FILE $TMP2FILE *.$A $A.out
-
-exit $failed
index 5b95314df643ddad02269b9b686e05eefc692c0e..3887e2d024c693f2ac75be2089cfcdb109a77d85 100644 (file)
@@ -1,3 +1,4 @@
+// if [ $GOOS == nacl ]; then echo survived SIGCHLD; exit 0; fi  # NaCl has no signals.
 // $G $D/$F.go && $L $F.$A && ./$A.out
 
 // Copyright 2009 The Go Authors. All rights reserved.
index 168830f70ae34662eb54a5b61402142797dce047..816b555a4c8849618a26ad9498fead3878c52d6b 100644 (file)
@@ -68,5 +68,5 @@ func main() {
        for i := 0; i < len(t); i++ {
                t[i] = 1
        }
-       recur(10000)
+       recur(8000)
 }