]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.power64] all: merge default (dd5014ed9b01) into dev.power64
authorRuss Cox <rsc@golang.org>
Wed, 29 Oct 2014 15:45:01 +0000 (11:45 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 29 Oct 2014 15:45:01 +0000 (11:45 -0400)
Still passes on amd64.

LGTM=austin
R=austin
CC=golang-codereviews
https://golang.org/cl/165110043

1  2 
src/cmd/gc/walk.c
src/runtime/asm_386.s
src/runtime/asm_amd64.s
src/runtime/asm_arm.s
src/runtime/mgc0.c
src/runtime/proc.c
src/runtime/runtime.c
src/runtime/sys_nacl_amd64p32.s

diff --combined src/cmd/gc/walk.c
index eaa044055280862be7e4234eb8ca7060cee53cef,ff9b362083e7892bc920bc02fd142719a618cf52..d4d0f449c3e751e489f58bd5cfdb05ace459f8c3
@@@ -7,7 -7,7 +7,7 @@@
  #include      "go.h"
  #include      "../ld/textflag.h"
  
- static        Node*   walkprint(Node*, NodeList**, int);
+ static        Node*   walkprint(Node*, NodeList**);
  static        Node*   writebarrierfn(char*, Type*, Type*);
  static        Node*   applywritebarrier(Node*, NodeList**);
  static        Node*   mapfn(char*, Type*);
@@@ -32,6 -32,7 +32,7 @@@ static        void    walkmul(Node**, NodeList**)
  static        void    walkdiv(Node**, NodeList**);
  static        int     bounded(Node*, int64);
  static        Mpint   mpzero;
+ static        void    walkprintfunc(Node**, NodeList**);
  
  void
  walk(Node *fn)
@@@ -226,8 -227,7 +227,7 @@@ walkstmt(Node **np
                switch(n->left->op) {
                case OPRINT:
                case OPRINTN:
-                       walkexprlist(n->left->list, &n->ninit);
-                       n->left = walkprint(n->left, &n->ninit, 1);
+                       walkprintfunc(&n->left, &n->ninit);
                        break;
                case OCOPY:
                        n->left = copyany(n->left, &n->ninit, 1);
                switch(n->left->op) {
                case OPRINT:
                case OPRINTN:
-                       walkexprlist(n->left->list, &n->ninit);
-                       n->left = walkprint(n->left, &n->ninit, 1);
+                       walkprintfunc(&n->left, &n->ninit);
                        break;
                case OCOPY:
                        n->left = copyany(n->left, &n->ninit, 1);
@@@ -543,7 -542,7 +542,7 @@@ walkexpr(Node **np, NodeList **init
        case OPRINT:
        case OPRINTN:
                walkexprlist(n->list, init);
-               n = walkprint(n, init, 0);
+               n = walkprint(n, init);
                goto ret;
  
        case OPANIC:
@@@ -1757,7 -1756,7 +1756,7 @@@ ret
  
  // generate code for print
  static Node*
- walkprint(Node *nn, NodeList **init, int defer)
+ walkprint(Node *nn, NodeList **init)
  {
        Node *r;
        Node *n;
        Node *on;
        Type *t;
        int notfirst, et, op;
-       NodeList *calls, *intypes, *args;
-       Fmt fmt;
+       NodeList *calls;
  
        on = nil;
        op = nn->op;
        all = nn->list;
        calls = nil;
        notfirst = 0;
-       intypes = nil;
-       args = nil;
-       memset(&fmt, 0, sizeof fmt);
-       if(defer) {
-               // defer print turns into defer printf with format string
-               fmtstrinit(&fmt);
-               intypes = list(intypes, nod(ODCLFIELD, N, typenod(types[TSTRING])));
-               args = list1(nod(OXXX, N, N));
-       }
  
        for(l=all; l; l=l->next) {
                if(notfirst) {
-                       if(defer)
-                               fmtprint(&fmt, " ");
-                       else
-                               calls = list(calls, mkcall("printsp", T, init));
+                       calls = list(calls, mkcall("printsp", T, init));
                }
                notfirst = op == OPRINTN;
  
                t = n->type;
                et = n->type->etype;
                if(isinter(n->type)) {
-                       if(defer) {
-                               if(isnilinter(n->type))
-                                       fmtprint(&fmt, "%%e");
-                               else
-                                       fmtprint(&fmt, "%%i");
-                       } else {
-                               if(isnilinter(n->type))
-                                       on = syslook("printeface", 1);
-                               else
-                                       on = syslook("printiface", 1);
-                               argtype(on, n->type);           // any-1
-                       }
+                       if(isnilinter(n->type))
+                               on = syslook("printeface", 1);
+                       else
+                               on = syslook("printiface", 1);
+                       argtype(on, n->type);           // any-1
                } else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR) {
-                       if(defer) {
-                               fmtprint(&fmt, "%%p");
-                       } else {
-                               on = syslook("printpointer", 1);
-                               argtype(on, n->type);   // any-1
-                       }
+                       on = syslook("printpointer", 1);
+                       argtype(on, n->type);   // any-1
                } else if(isslice(n->type)) {
-                       if(defer) {
-                               fmtprint(&fmt, "%%a");
-                       } else {
-                               on = syslook("printslice", 1);
-                               argtype(on, n->type);   // any-1
-                       }
+                       on = syslook("printslice", 1);
+                       argtype(on, n->type);   // any-1
                } else if(isint[et]) {
-                       if(defer) {
-                               if(et == TUINT64)
-                                       fmtprint(&fmt, "%%U");
-                               else {
-                                       fmtprint(&fmt, "%%D");
-                                       t = types[TINT64];
-                               }
-                       } else {
-                               if(et == TUINT64) {
-                                       if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0)
-                                               on = syslook("printhex", 0);
-                                       else
-                                               on = syslook("printuint", 0);
-                               } else
-                                       on = syslook("printint", 0);
-                       }
-               } else if(isfloat[et]) {
-                       if(defer) {
-                               fmtprint(&fmt, "%%f");
-                               t = types[TFLOAT64];
+                       if(et == TUINT64) {
+                               if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0)
+                                       on = syslook("printhex", 0);
+                               else
+                                       on = syslook("printuint", 0);
                        } else
-                               on = syslook("printfloat", 0);
+                               on = syslook("printint", 0);
+               } else if(isfloat[et]) {
+                       on = syslook("printfloat", 0);
                } else if(iscomplex[et]) {
-                       if(defer) {
-                               fmtprint(&fmt, "%%C");
-                               t = types[TCOMPLEX128];
-                       } else
-                               on = syslook("printcomplex", 0);
+                       on = syslook("printcomplex", 0);
                } else if(et == TBOOL) {
-                       if(defer)
-                               fmtprint(&fmt, "%%t");
-                       else
-                               on = syslook("printbool", 0);
+                       on = syslook("printbool", 0);
                } else if(et == TSTRING) {
-                       if(defer)
-                               fmtprint(&fmt, "%%S");
-                       else
-                               on = syslook("printstring", 0);
+                       on = syslook("printstring", 0);
                } else {
                        badtype(OPRINT, n->type, T);
                        continue;
                }
  
-               if(!defer) {
-                       t = *getinarg(on->type);
-                       if(t != nil)
-                               t = t->type;
-                       if(t != nil)
-                               t = t->type;
-               }
+               t = *getinarg(on->type);
+               if(t != nil)
+                       t = t->type;
+               if(t != nil)
+                       t = t->type;
  
                if(!eqtype(t, n->type)) {
                        n = nod(OCONV, n, N);
                        n->type = t;
                }
  
-               if(defer) {
-                       intypes = list(intypes, nod(ODCLFIELD, N, typenod(t)));
-                       args = list(args, n);
-               } else {
-                       r = nod(OCALL, on, N);
-                       r->list = list1(n);
-                       calls = list(calls, r);
-               }
+               r = nod(OCALL, on, N);
+               r->list = list1(n);
+               calls = list(calls, r);
        }
  
-       if(defer) {
-               if(op == OPRINTN)
-                       fmtprint(&fmt, "\n");
-               on = syslook("goprintf", 1);
-               on->type = functype(nil, intypes, nil);
-               args->n = nod(OLITERAL, N, N);
-               args->n->val.ctype = CTSTR;
-               args->n->val.u.sval = strlit(fmtstrflush(&fmt));
-               r = nod(OCALL, on, N);
-               r->list = args;
-               typecheck(&r, Etop);
-               walkexpr(&r, init);
-       } else {
-               if(op == OPRINTN)
-                       calls = list(calls, mkcall("printnl", T, nil));
-               typechecklist(calls, Etop);
-               walkexprlist(calls, init);
+       if(op == OPRINTN)
+               calls = list(calls, mkcall("printnl", T, nil));
+       typechecklist(calls, Etop);
+       walkexprlist(calls, init);
  
-               r = nod(OEMPTY, N, N);
-               typecheck(&r, Etop);
-               walkexpr(&r, init);
-               r->ninit = calls;
-       }
+       r = nod(OEMPTY, N, N);
+       typecheck(&r, Etop);
+       walkexpr(&r, init);
+       r->ninit = calls;
        return r;
  }
  
@@@ -3229,7 -3155,7 +3155,7 @@@ countfield(Type *t
  static void
  walkcompare(Node **np, NodeList **init)
  {
-       Node *n, *l, *r, *call, *a, *li, *ri, *expr;
+       Node *n, *l, *r, *call, *a, *li, *ri, *expr, *cmpl, *cmpr;
        int andor, i;
        Type *t, *t1;
        
                break;
        }
        
-       if(!islvalue(n->left) || !islvalue(n->right)) {
-               fatal("arguments of comparison must be lvalues");
+       cmpl = n->left;
+       while(cmpl != N && cmpl->op == OCONVNOP)
+               cmpl = cmpl->left;
+       cmpr = n->right;
+       while(cmpr != N && cmpr->op == OCONVNOP)
+               cmpr = cmpr->left;
+       
+       if(!islvalue(cmpl) || !islvalue(cmpr)) {
+               fatal("arguments of comparison must be lvalues - %N %N", cmpl, cmpr);
        }
  
        l = temp(ptrto(t));
-       a = nod(OAS, l, nod(OADDR, n->left, N));
+       a = nod(OAS, l, nod(OADDR, cmpl, N));
        a->right->etype = 1;  // addr does not escape
        typecheck(&a, Etop);
        *init = list(*init, a);
  
        r = temp(ptrto(t));
-       a = nod(OAS, r, nod(OADDR, n->right, N));
+       a = nod(OAS, r, nod(OADDR, cmpr, N));
        a->right->etype = 1;  // addr does not escape
        typecheck(&a, Etop);
        *init = list(*init, a);
@@@ -3368,9 -3301,6 +3301,9 @@@ walkrotate(Node **np
        int w, sl, sr, s;
        Node *l, *r;
        Node *n;
 +
 +      if(thechar == '9')
 +              return;
        
        n = *np;
  
@@@ -3496,10 -3426,6 +3429,10 @@@ walkdiv(Node **np, NodeList **init
        Type *twide;
        Magic m;
  
 +      // TODO(minux)
 +      if(thechar == '9')
 +              return;
 +
        n = *np;
        if(n->right->op != OLITERAL)
                return;
@@@ -3941,3 -3867,71 +3874,71 @@@ candiscard(Node *n
        
        return 1;
  }
+ // rewrite
+ //    print(x, y, z)
+ // into
+ //    func(a1, a2, a3) {
+ //            print(a1, a2, a3)
+ //    }(x, y, z)
+ // and same for println.
+ static void
+ walkprintfunc(Node **np, NodeList **init)
+ {
+       Node *n;
+       Node *a, *fn, *t, *oldfn;
+       NodeList *l, *printargs;
+       int num;
+       char buf[100];
+       static int prgen;
+       
+       n = *np;
+       if(n->ninit != nil) {
+               walkstmtlist(n->ninit);
+               *init = concat(*init, n->ninit);
+               n->ninit = nil;
+       }
+       t = nod(OTFUNC, N, N);
+       num = 0;
+       printargs = nil;
+       for(l=n->list; l != nil; l=l->next) {
+               snprint(buf, sizeof buf, "a%d", num++);
+               a = nod(ODCLFIELD, newname(lookup(buf)), typenod(l->n->type));
+               t->list = list(t->list, a);
+               printargs = list(printargs, a->left);
+       }
+       fn = nod(ODCLFUNC, N, N);
+       snprint(buf, sizeof buf, "print·%d", ++prgen);
+       fn->nname = newname(lookup(buf));
+       fn->nname->defn = fn;
+       fn->nname->ntype = t;
+       declare(fn->nname, PFUNC);
+       oldfn = curfn;
+       curfn = nil;
+       funchdr(fn);
+       
+       a = nod(n->op, N, N);
+       a->list = printargs;
+       typecheck(&a, Etop);
+       walkstmt(&a);
+       
+       fn->nbody = list1(a);
+       funcbody(fn);
+       
+       typecheck(&fn, Etop);
+       typechecklist(fn->nbody, Etop);
+       xtop = list(xtop, fn);
+       curfn = oldfn;
+       a = nod(OCALL, N, N);
+       a->left = fn->nname;
+       a->list = n->list;
+       typecheck(&a, Etop);
+       walkexpr(&a, init);
+       *np = a;
+ }
diff --combined src/runtime/asm_386.s
index d0b3969bda9dc05c9c0421a290bb749b1445b6f9,0d46a9eff78035a6fca583a0f4b6800c32cabcde..2d102b27358b618c46ed3a320d61587313234eb2
@@@ -486,11 -486,11 +486,11 @@@ TEXT runtime·cas64(SB), NOSPLIT, $0-2
        MOVL    new_hi+16(FP), CX
        LOCK
        CMPXCHG8B       0(BP)
 -      JNZ     cas64_fail
 +      JNZ     fail
        MOVL    $1, AX
        MOVB    AX, ret+20(FP)
        RET
 -cas64_fail:
 +fail:
        MOVL    $0, AX
        MOVB    AX, ret+20(FP)
        RET
@@@ -732,6 -732,20 +732,20 @@@ needm
        MOVL    g(CX), BP
        MOVL    g_m(BP), BP
  
+       // Set m->sched.sp = SP, so that if a panic happens
+       // during the function we are about to execute, it will
+       // have a valid SP to run on the g0 stack.
+       // The next few lines (after the havem label)
+       // will save this SP onto the stack and then write
+       // the same SP back to m->sched.sp. That seems redundant,
+       // but if an unrecovered panic happens, unwindm will
+       // restore the g->sched.sp from the stack location
+       // and then onM will try to use it. If we don't set it here,
+       // that restored SP will be uninitialized (typically 0) and
+       // will not be usable.
+       MOVL    m_g0(BP), SI
+       MOVL    SP, (g_sched+gobuf_sp)(SI)
  havem:
        // Now there's a valid m, and we're running on its m->g0.
        // Save current m->g0->sched.sp on stack and then set it to SP.
@@@ -1342,29 -1356,29 +1356,29 @@@ TEXT strings·IndexByte(SB),NOSPLIT,$
  //   AX = 1/0/-1
  TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
        CMPL    SI, DI
 -      JEQ     cmp_allsame
 +      JEQ     allsame
        CMPL    BX, DX
        MOVL    DX, BP
        CMOVLLT BX, BP // BP = min(alen, blen)
        CMPL    BP, $4
 -      JB      cmp_small
 +      JB      small
        TESTL   $0x4000000, runtime·cpuid_edx(SB) // check for sse2
 -      JE      cmp_mediumloop
 -cmp_largeloop:
 +      JE      mediumloop
 +largeloop:
        CMPL    BP, $16
 -      JB      cmp_mediumloop
 +      JB      mediumloop
        MOVOU   (SI), X0
        MOVOU   (DI), X1
        PCMPEQB X0, X1
        PMOVMSKB X1, AX
        XORL    $0xffff, AX     // convert EQ to NE
 -      JNE     cmp_diff16      // branch if at least one byte is not equal
 +      JNE     diff16  // branch if at least one byte is not equal
        ADDL    $16, SI
        ADDL    $16, DI
        SUBL    $16, BP
 -      JMP     cmp_largeloop
 +      JMP     largeloop
  
 -cmp_diff16:
 +diff16:
        BSFL    AX, BX  // index of first byte that differs
        XORL    AX, AX
        MOVB    (SI)(BX*1), CX
        LEAL    -1(AX*2), AX    // convert 1/0 to +1/-1
        RET
  
 -cmp_mediumloop:
 +mediumloop:
        CMPL    BP, $4
 -      JBE     cmp_0through4
 +      JBE     _0through4
        MOVL    (SI), AX
        MOVL    (DI), CX
        CMPL    AX, CX
 -      JNE     cmp_diff4
 +      JNE     diff4
        ADDL    $4, SI
        ADDL    $4, DI
        SUBL    $4, BP
 -      JMP     cmp_mediumloop
 +      JMP     mediumloop
  
 -cmp_0through4:
 +_0through4:
        MOVL    -4(SI)(BP*1), AX
        MOVL    -4(DI)(BP*1), CX
        CMPL    AX, CX
 -      JEQ     cmp_allsame
 +      JEQ     allsame
  
 -cmp_diff4:
 +diff4:
        BSWAPL  AX      // reverse order of bytes
        BSWAPL  CX
        XORL    AX, CX  // find bit differences
        RET
  
        // 0-3 bytes in common
 -cmp_small:
 +small:
        LEAL    (BP*8), CX
        NEGL    CX
 -      JEQ     cmp_allsame
 +      JEQ     allsame
  
        // load si
        CMPB    SI, $0xfc
 -      JA      cmp_si_high
 +      JA      si_high
        MOVL    (SI), SI
 -      JMP     cmp_si_finish
 -cmp_si_high:
 +      JMP     si_finish
 +si_high:
        MOVL    -4(SI)(BP*1), SI
        SHRL    CX, SI
 -cmp_si_finish:
 +si_finish:
        SHLL    CX, SI
  
        // same for di
        CMPB    DI, $0xfc
 -      JA      cmp_di_high
 +      JA      di_high
        MOVL    (DI), DI
 -      JMP     cmp_di_finish
 -cmp_di_high:
 +      JMP     di_finish
 +di_high:
        MOVL    -4(DI)(BP*1), DI
        SHRL    CX, DI
 -cmp_di_finish:
 +di_finish:
        SHLL    CX, DI
  
        BSWAPL  SI      // reverse order of bytes
        BSWAPL  DI
        XORL    SI, DI  // find bit differences
 -      JEQ     cmp_allsame
 +      JEQ     allsame
        BSRL    DI, CX  // index of highest bit difference
        SHRL    CX, SI  // move a's bit to bottom
        ANDL    $1, SI  // mask bit
  
        // all the bytes in common are the same, so we just need
        // to compare the lengths.
 -cmp_allsame:
 +allsame:
        XORL    AX, AX
        XORL    CX, CX
        CMPL    BX, DX
diff --combined src/runtime/asm_amd64.s
index 7a0fdfa73a2bbe593fccfad34d9c009fd41232d5,a9b082beb82a66f28d9e808166f66e334415de3e..ac9c58cf3e2cce8e23304fdd418f88af7aea9eab
@@@ -461,11 -461,11 +461,11 @@@ TEXT runtime·cas64(SB), NOSPLIT, $0-2
        MOVQ    new+16(FP), CX
        LOCK
        CMPXCHGQ        CX, 0(BX)
 -      JNZ     cas64_fail
 +      JNZ     fail
        MOVL    $1, AX
        MOVB    AX, ret+24(FP)
        RET
 -cas64_fail:
 +fail:
        MOVL    $0, AX
        MOVB    AX, ret+24(FP)
        RET
@@@ -717,6 -717,20 +717,20 @@@ needm
        get_tls(CX)
        MOVQ    g(CX), BP
        MOVQ    g_m(BP), BP
+       
+       // Set m->sched.sp = SP, so that if a panic happens
+       // during the function we are about to execute, it will
+       // have a valid SP to run on the g0 stack.
+       // The next few lines (after the havem label)
+       // will save this SP onto the stack and then write
+       // the same SP back to m->sched.sp. That seems redundant,
+       // but if an unrecovered panic happens, unwindm will
+       // restore the g->sched.sp from the stack location
+       // and then onM will try to use it. If we don't set it here,
+       // that restored SP will be uninitialized (typically 0) and
+       // will not be usable.
+       MOVQ    m_g0(BP), SI
+       MOVQ    SP, (g_sched+gobuf_sp)(SI)
  
  havem:
        // Now there's a valid m, and we're running on its m->g0.
@@@ -876,24 -890,24 +890,24 @@@ TEXT runtime·aeshashbody(SB),NOSPLIT,$
        MOVO    runtime·aeskeysched+0(SB), X2
        MOVO    runtime·aeskeysched+16(SB), X3
        CMPQ    CX, $16
 -      JB      aessmall
 -aesloop:
 +      JB      small
 +loop:
        CMPQ    CX, $16
 -      JBE     aesloopend
 +      JBE     loopend
        MOVOU   (AX), X1
        AESENC  X2, X0
        AESENC  X1, X0
        SUBQ    $16, CX
        ADDQ    $16, AX
 -      JMP     aesloop
 +      JMP     loop
  // 1-16 bytes remaining
 -aesloopend:
 +loopend:
        // This load may overlap with the previous load above.
        // We'll hash some bytes twice, but that's ok.
        MOVOU   -16(AX)(CX*1), X1
        JMP     partial
  // 0-15 bytes
 -aessmall:
 +small:
        TESTQ   CX, CX
        JE      finalize        // 0 bytes
  
@@@ -1036,18 -1050,18 +1050,18 @@@ TEXT runtime·eqstring(SB),NOSPLIT,$0-3
        MOVQ    s1len+8(FP), AX
        MOVQ    s2len+24(FP), BX
        CMPQ    AX, BX
 -      JNE     different
 +      JNE     noteq
        MOVQ    s1str+0(FP), SI
        MOVQ    s2str+16(FP), DI
        CMPQ    SI, DI
 -      JEQ     same
 +      JEQ     eq
        CALL    runtime·memeqbody(SB)
        MOVB    AX, v+32(FP)
        RET
 -same:
 +eq:
        MOVB    $1, v+32(FP)
        RET
 -different:
 +noteq:
        MOVB    $0, v+32(FP)
        RET
  
@@@ -1170,29 -1184,29 +1184,29 @@@ TEXT runtime·cmpbytes(SB),NOSPLIT,$0-5
  //   AX = 1/0/-1
  TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
        CMPQ    SI, DI
 -      JEQ     cmp_allsame
 +      JEQ     allsame
        CMPQ    BX, DX
        MOVQ    DX, BP
        CMOVQLT BX, BP // BP = min(alen, blen) = # of bytes to compare
        CMPQ    BP, $8
 -      JB      cmp_small
 +      JB      small
  
 -cmp_loop:
 +loop:
        CMPQ    BP, $16
 -      JBE     cmp_0through16
 +      JBE     _0through16
        MOVOU   (SI), X0
        MOVOU   (DI), X1
        PCMPEQB X0, X1
        PMOVMSKB X1, AX
        XORQ    $0xffff, AX     // convert EQ to NE
 -      JNE     cmp_diff16      // branch if at least one byte is not equal
 +      JNE     diff16  // branch if at least one byte is not equal
        ADDQ    $16, SI
        ADDQ    $16, DI
        SUBQ    $16, BP
 -      JMP     cmp_loop
 +      JMP     loop
        
        // AX = bit mask of differences
 -cmp_diff16:
 +diff16:
        BSFQ    AX, BX  // index of first byte that differs
        XORQ    AX, AX
        MOVB    (SI)(BX*1), CX
        RET
  
        // 0 through 16 bytes left, alen>=8, blen>=8
 -cmp_0through16:
 +_0through16:
        CMPQ    BP, $8
 -      JBE     cmp_0through8
 +      JBE     _0through8
        MOVQ    (SI), AX
        MOVQ    (DI), CX
        CMPQ    AX, CX
 -      JNE     cmp_diff8
 -cmp_0through8:
 +      JNE     diff8
 +_0through8:
        MOVQ    -8(SI)(BP*1), AX
        MOVQ    -8(DI)(BP*1), CX
        CMPQ    AX, CX
 -      JEQ     cmp_allsame
 +      JEQ     allsame
  
        // AX and CX contain parts of a and b that differ.
 -cmp_diff8:
 +diff8:
        BSWAPQ  AX      // reverse order of bytes
        BSWAPQ  CX
        XORQ    AX, CX
        RET
  
        // 0-7 bytes in common
 -cmp_small:
 +small:
        LEAQ    (BP*8), CX      // bytes left -> bits left
        NEGQ    CX              //  - bits lift (== 64 - bits left mod 64)
 -      JEQ     cmp_allsame
 +      JEQ     allsame
  
        // load bytes of a into high bytes of AX
        CMPB    SI, $0xf8
 -      JA      cmp_si_high
 +      JA      si_high
        MOVQ    (SI), SI
 -      JMP     cmp_si_finish
 -cmp_si_high:
 +      JMP     si_finish
 +si_high:
        MOVQ    -8(SI)(BP*1), SI
        SHRQ    CX, SI
 -cmp_si_finish:
 +si_finish:
        SHLQ    CX, SI
  
        // load bytes of b in to high bytes of BX
        CMPB    DI, $0xf8
 -      JA      cmp_di_high
 +      JA      di_high
        MOVQ    (DI), DI
 -      JMP     cmp_di_finish
 -cmp_di_high:
 +      JMP     di_finish
 +di_high:
        MOVQ    -8(DI)(BP*1), DI
        SHRQ    CX, DI
 -cmp_di_finish:
 +di_finish:
        SHLQ    CX, DI
  
        BSWAPQ  SI      // reverse order of bytes
        BSWAPQ  DI
        XORQ    SI, DI  // find bit differences
 -      JEQ     cmp_allsame
 +      JEQ     allsame
        BSRQ    DI, CX  // index of highest bit difference
        SHRQ    CX, SI  // move a's bit to bottom
        ANDQ    $1, SI  // mask bit
        LEAQ    -1(SI*2), AX // 1/0 => +1/-1
        RET
  
 -cmp_allsame:
 +allsame:
        XORQ    AX, AX
        XORQ    CX, CX
        CMPQ    BX, DX
@@@ -1299,7 -1313,7 +1313,7 @@@ TEXT runtime·indexbytebody(SB),NOSPLIT
        MOVQ SI, DI
  
        CMPQ BX, $16
 -      JLT indexbyte_small
 +      JLT small
  
        // round up to first 16-byte boundary
        TESTQ $15, SI
@@@ -1357,7 -1371,7 +1371,7 @@@ failure
        RET
  
  // handle for lengths < 16
 -indexbyte_small:
 +small:
        MOVQ BX, CX
        REPN; SCASB
        JZ success
diff --combined src/runtime/asm_arm.s
index 8942b11acb1025d13eae253e3a51cf7ae41f00c5,e94b4c1ff61560f3424b45ff0dc9c758980e1dae..9a58fdc51e25a1d4e9853c6d0a47f68fd6933cd1
@@@ -492,7 -492,7 +492,7 @@@ TEXT asmcgocall<>(SB),NOSPLIT,$0-
        MOVW    g_m(g), R8
        MOVW    m_g0(R8), R3
        CMP     R3, g
 -      BEQ     asmcgocall_g0
 +      BEQ     g0
        BL      gosave<>(SB)
        MOVW    R0, R5
        MOVW    R3, R0
        MOVW    (g_sched+gobuf_sp)(g), R13
  
        // Now on a scheduling stack (a pthread-created stack).
 -asmcgocall_g0:
 +g0:
        SUB     $24, R13
        BIC     $0x7, R13       // alignment for gcc ABI
        MOVW    R4, 20(R13) // save old g
@@@ -556,6 -556,21 +556,21 @@@ TEXT     ·cgocallback_gofunc(SB),NOSPLIT,$
        MOVW    $runtime·needm(SB), R0
        BL      (R0)
  
+       // Set m->sched.sp = SP, so that if a panic happens
+       // during the function we are about to execute, it will
+       // have a valid SP to run on the g0 stack.
+       // The next few lines (after the havem label)
+       // will save this SP onto the stack and then write
+       // the same SP back to m->sched.sp. That seems redundant,
+       // but if an unrecovered panic happens, unwindm will
+       // restore the g->sched.sp from the stack location
+       // and then onM will try to use it. If we don't set it here,
+       // that restored SP will be uninitialized (typically 0) and
+       // will not be usable.
+       MOVW    g_m(g), R8
+       MOVW    m_g0(R8), R3
+       MOVW    R13, (g_sched+gobuf_sp)(R3)
  havem:
        MOVW    g_m(g), R8
        MOVW    R8, savedm-4(SP)
@@@ -736,13 -751,13 +751,13 @@@ TEXT runtime·memeq(SB),NOSPLIT,$-4-1
        ADD     R1, R3, R6
        MOVW    $1, R0
        MOVB    R0, ret+12(FP)
 -_next2:
 +loop:
        CMP     R1, R6
        RET.EQ
        MOVBU.P 1(R1), R4
        MOVBU.P 1(R2), R5
        CMP     R4, R5
 -      BEQ     _next2
 +      BEQ     loop
  
        MOVW    $0, R0
        MOVB    R0, ret+12(FP)
@@@ -765,13 -780,13 +780,13 @@@ TEXT runtime·eqstring(SB),NOSPLIT,$-4-
        CMP     R2, R3
        RET.EQ
        ADD     R2, R0, R6
 -_eqnext:
 +loop:
        CMP     R2, R6
        RET.EQ
        MOVBU.P 1(R2), R4
        MOVBU.P 1(R3), R5
        CMP     R4, R5
 -      BEQ     _eqnext
 +      BEQ     loop
        MOVB    R7, v+16(FP)
        RET
  
@@@ -786,26 -801,26 +801,26 @@@ TEXT bytes·Equal(SB),NOSPLIT,$
        MOVW    b_len+16(FP), R3
        
        CMP     R1, R3          // unequal lengths are not equal
 -      B.NE    _notequal
 +      B.NE    notequal
  
        MOVW    a+0(FP), R0
        MOVW    b+12(FP), R2
        ADD     R0, R1          // end
  
 -_byteseq_next:
 +loop:
        CMP     R0, R1
 -      B.EQ    _equal          // reached the end
 +      B.EQ    equal           // reached the end
        MOVBU.P 1(R0), R4
        MOVBU.P 1(R2), R5
        CMP     R4, R5
 -      B.EQ    _byteseq_next
 +      B.EQ    loop
  
 -_notequal:
 +notequal:
        MOVW    $0, R0
        MOVBU   R0, ret+24(FP)
        RET
  
 -_equal:
 +equal:
        MOVW    $1, R0
        MOVBU   R0, ret+24(FP)
        RET
diff --combined src/runtime/mgc0.c
index 02f7eba1202c8f2474450f0154d10e753d35349c,1b41bf9a79419627c791092102922c05e737f57b..e5b6870c668d8a5887d9924a928aee7277a2b05c
@@@ -65,7 -65,7 +65,7 @@@
  enum {
        Debug           = 0,
        DebugPtrs       = 0, // if 1, print trace of every pointer load during GC
 -      ConcurrentSweep = 1,
 +      ConcurrentSweep = 0,
  
        WorkbufSize     = 4*1024,
        FinBlockSize    = 4*1024,
@@@ -330,7 -330,7 +330,7 @@@ scanblock(byte *b, uintptr n, byte *ptr
                        if(obj == nil)
                                continue;
                        if(obj < arena_start || obj >= arena_used) {
-                               if((uintptr)obj < PhysPageSize) {
+                               if((uintptr)obj < PhysPageSize && runtime·invalidptr) {
                                        s = nil;
                                        goto badobj;
                                }
                                        else
                                                runtime·printf(" span=%p-%p-%p state=%d\n", (uintptr)s->start<<PageShift, s->limit, (uintptr)(s->start+s->npages)<<PageShift, s->state);
                                        if(ptrmask != nil)
-                                               runtime·throw("bad pointer");
+                                               runtime·throw("invalid heap pointer");
                                        // Add to badblock list, which will cause the garbage collection
                                        // to keep repeating until it has traced the chain of pointers
                                        // leading to obj all the way back to a root.
@@@ -1459,6 -1459,7 +1459,7 @@@ gc(struct gc_args *args
        t4 = runtime·nanotime();
        runtime·atomicstore64(&mstats.last_gc, runtime·unixnanotime());  // must be Unix time to make sense to user
        mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t4 - t0;
+       mstats.pause_end[mstats.numgc%nelem(mstats.pause_end)] = t4;
        mstats.pause_total_ns += t4 - t0;
        mstats.numgc++;
        if(mstats.debuggc)
@@@ -1572,7 -1573,7 +1573,7 @@@ readgcstats_m(void
  {
        Slice *pauses;  
        uint64 *p;
-       uint32 i, n;
+       uint32 i, j, n;
        
        pauses = g->m->ptrarg[0];
        g->m->ptrarg[0] = nil;
        if(pauses->cap < nelem(mstats.pause_ns)+3)
                runtime·throw("runtime: short slice passed to readGCStats");
  
-       // Pass back: pauses, last gc (absolute time), number of gc, total pause ns.
+       // Pass back: pauses, pause ends, last gc (absolute time), number of gc, total pause ns.
        p = (uint64*)pauses->array;
        runtime·lock(&runtime·mheap.lock);
        n = mstats.numgc;
        if(n > nelem(mstats.pause_ns))
                n = nelem(mstats.pause_ns);
-       
        // The pause buffer is circular. The most recent pause is at
        // pause_ns[(numgc-1)%nelem(pause_ns)], and then backward
        // from there to go back farther in time. We deliver the times
        // most recent first (in p[0]).
-       for(i=0; i<n; i++)
-               p[i] = mstats.pause_ns[(mstats.numgc-1-i)%nelem(mstats.pause_ns)];
+       for(i=0; i<n; i++) {
+               j = (mstats.numgc-1-i)%nelem(mstats.pause_ns);
+               p[i] = mstats.pause_ns[j];
+               p[n+i] = mstats.pause_end[j];
+       }
  
-       p[n] = mstats.last_gc;
-       p[n+1] = mstats.numgc;
-       p[n+2] = mstats.pause_total_ns; 
+       p[n+n] = mstats.last_gc;
+       p[n+n+1] = mstats.numgc;
+       p[n+n+2] = mstats.pause_total_ns;       
        runtime·unlock(&runtime·mheap.lock);
-       pauses->len = n+3;
+       pauses->len = n+n+3;
  }
  
  void
@@@ -1779,7 -1784,7 +1784,7 @@@ runtime·unrollgcprog_m(void
        Type *typ;
        byte *mask, *prog;
        uintptr pos;
 -      uint32 x;
 +      uintptr x;
  
        typ = g->m->ptrarg[0];
        g->m->ptrarg[0] = nil;
                        prog = (byte*)typ->gc[1];
                        unrollgcprog1(mask, prog, &pos, false, true);
                }
 +              
                // atomic way to say mask[0] = 1
 -              x = ((uint32*)mask)[0];
 -              runtime·atomicstore((uint32*)mask, x|1);
 +              x = *(uintptr*)mask;
 +              ((byte*)&x)[0] = 1;
 +              runtime·atomicstorep((void**)mask, (void*)x);
        }
        runtime·unlock(&lock);
  }
diff --combined src/runtime/proc.c
index 11af6a1eaa8fbbf2b58b13a099fb4020979b1d1a,52f7ef3a5bfbca96f63904fab25e35e4e3d62207..31c62d43f5798499bcf3d55f622600dd58bc25c9
@@@ -2124,7 -2124,7 +2124,7 @@@ runtime·newproc(int32 siz, FuncVal* fn
        byte *argp;
        void (*mfn)(void);
  
 -      if(thechar == '5')
 +      if(thechar == '5' || thechar == '9')
                argp = (byte*)(&fn+2);  // skip caller's saved LR
        else
                argp = (byte*)(&fn+1);
@@@ -2184,7 -2184,7 +2184,7 @@@ runtime·newproc1(FuncVal *fn, byte *ar
        sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame
        sp -= siz;
        runtime·memmove(sp, argp, narg);
 -      if(thechar == '5') {
 +      if(thechar == '5' || thechar == '9') {
                // caller's LR
                sp -= sizeof(void*);
                *(void**)sp = nil;
@@@ -2758,6 -2758,8 +2758,8 @@@ static voi
  checkdead(void)
  {
        G *gp;
+       P *p;
+       M *mp;
        int32 run, grunning, s;
        uintptr i;
  
        runtime·unlock(&runtime·allglock);
        if(grunning == 0)  // possible if main goroutine calls runtime·Goexit()
                runtime·throw("no goroutines (main called runtime.Goexit) - deadlock!");
+       // Maybe jump time forward for playground.
+       if((gp = runtime·timejump()) != nil) {
+               runtime·casgstatus(gp, Gwaiting, Grunnable);
+               globrunqput(gp);
+               p = pidleget();
+               if(p == nil)
+                       runtime·throw("checkdead: no p for timer");
+               mp = mget();
+               if(mp == nil)
+                       newm(nil, p);
+               else {
+                       mp->nextp = p;
+                       runtime·notewakeup(&mp->park);
+               }
+               return;
+       }
        g->m->throwing = -1;  // do not dump full stacks
        runtime·throw("all goroutines are asleep - deadlock!");
  }
diff --combined src/runtime/runtime.c
index d984983ce22c553a24ca0f76174b929537a2770c,c823691ec5a178ca27f1ef5f2d60cdede2be83a1..f19f8e4be3c397aab8da7923d47ea56ef324cbad
@@@ -185,7 -185,6 +185,7 @@@ runtime·check(void
        float64 j, j1;
        byte *k, *k1;
        uint16* l;
 +      byte m[4];
        struct x1 {
                byte x;
        };
        if(k != k1)
                runtime·throw("casp3");
  
 +      m[0] = m[1] = m[2] = m[3] = 0x1;
 +      runtime·atomicor8(&m[1], 0xf0);
 +      if (m[0] != 0x1 || m[1] != 0xf1 || m[2] != 0x1 || m[3] != 0x1)
 +              runtime·throw("atomicor8");
 +
        *(uint64*)&j = ~0ULL;
        if(j == j)
                runtime·throw("float64nan");
@@@ -282,9 -276,13 +282,13 @@@ struct DbgVa
        int32*  value;
  };
  
+ // Do we report invalid pointers found during stack or heap scans?
+ int32 runtime·invalidptr = 1;
  #pragma dataflag NOPTR /* dbgvar has no heap pointers */
  static DbgVar dbgvar[] = {
        {"allocfreetrace", &runtime·debug.allocfreetrace},
+       {"invalidptr", &runtime·invalidptr},
        {"efence", &runtime·debug.efence},
        {"gctrace", &runtime·debug.gctrace},
        {"gcdead", &runtime·debug.gcdead},
index 06a0dc5dd72e27c4abee454edab9a8f981396776,4eb4aacdd58cad0dd2d3b02b6b60d75292ee0b35..9cfbef6efaf41baef9c5e1ebf43ef06729421e11
@@@ -60,7 -60,7 +60,7 @@@ TEXT syscall·naclWrite(SB), NOSPLIT, $
  TEXT runtime·write(SB),NOSPLIT,$16-20
        // If using fake time and writing to stdout or stderr,
        // emit playback header before actual data.
-       MOVQ runtime·timens(SB), AX
+       MOVQ runtime·faketime(SB), AX
        CMPQ AX, $0
        JEQ write
        MOVL fd+0(FP), DI
@@@ -242,7 -242,7 +242,7 @@@ TEXT runtime·mmap(SB),NOSPLIT,$
        RET
  
  TEXT time·now(SB),NOSPLIT,$16
-       MOVQ runtime·timens(SB), AX
+       MOVQ runtime·faketime(SB), AX
        CMPQ AX, $0
        JEQ realtime
        MOVQ $0, DX
@@@ -277,7 -277,7 +277,7 @@@ TEXT runtime·nacl_clock_gettime(SB),NO
        RET
  
  TEXT runtime·nanotime(SB),NOSPLIT,$16
-       MOVQ runtime·timens(SB), AX
+       MOVQ runtime·faketime(SB), AX
        CMPQ AX, $0
        JEQ 3(PC)
        MOVQ    AX, ret+0(FP)
@@@ -338,6 -338,7 +338,6 @@@ TEXT runtime·sigtramp(SB),NOSPLIT,$8
        MOVL    20(SP), BX
        MOVL    BX, g(CX)
  
 -sigtramp_ret:
        // Enable exceptions again.
        NACL_SYSCALL(SYS_exception_clear_flag)