]> Cypherpunks repositories - gostls13.git/commitdiff
gc: add panic and recover (still unimplemented in runtime)
authorRuss Cox <rsc@golang.org>
Tue, 30 Mar 2010 17:53:16 +0000 (10:53 -0700)
committerRuss Cox <rsc@golang.org>
Tue, 30 Mar 2010 17:53:16 +0000 (10:53 -0700)
main semantic change is to enforce single argument to panic.

runtime: change to 1-argument panic.
use String method on argument if it has one.

R=ken2, r
CC=golang-dev
https://golang.org/cl/812043

13 files changed:
src/cmd/gc/align.c
src/cmd/gc/builtin.c.boot
src/cmd/gc/go.h
src/cmd/gc/lex.c
src/cmd/gc/runtime.go
src/cmd/gc/typecheck.c
src/cmd/gc/walk.c
src/pkg/runtime/386/asm.s
src/pkg/runtime/amd64/asm.s
src/pkg/runtime/arm/asm.s
src/pkg/runtime/print.c
src/pkg/runtime/runtime.c
src/pkg/runtime/runtime.h

index 278540a249a87c4ea3d537a4d994e5f2e9951f68..6d9083bc3299e595c8a394310a8b8e5e1ca1923a 100644 (file)
@@ -542,6 +542,7 @@ typeinit(void)
        /* types used in front end */
        // types[TNIL] got set early in lexinit
        types[TIDEAL] = typ(TIDEAL);
+       types[TINTER] = typ(TINTER);
 
        /* simple aliases */
        simtype[TMAP] = tptr;
index bc39ed65a16cf8a0e40bd3af06360874ff79cf67..b74e7f5e50d17ab66c848663c26bfe511926c6e0 100644 (file)
@@ -4,7 +4,8 @@ char *runtimeimport =
        "func \"\".throwindex ()\n"
        "func \"\".throwreturn ()\n"
        "func \"\".throwinit ()\n"
-       "func \"\".panicl ()\n"
+       "func \"\".panic (? interface { })\n"
+       "func \"\".recover () interface { }\n"
        "func \"\".printbool (? bool)\n"
        "func \"\".printfloat (? float64)\n"
        "func \"\".printint (? int64)\n"
index 9de2361194fbfcbf3dd9092a92c5250dbd0fa92d..7ae5d99287de9a9929f8f5d5dba9a649be49fad6 100644 (file)
@@ -379,6 +379,7 @@ enum
        OPANIC, OPRINT, OPRINTN,
        OSEND, OSENDNB,
        OSLICE, OSLICEARR, OSLICESTR,
+       ORECOVER,
        ORECV,
        ORUNESTR,
        OSELRECV,
index 225a9027797aced5f50191f4cb386530aae9abb0..bde1367da039b33ca1685b5308313c7702805e01 100644 (file)
@@ -1309,6 +1309,7 @@ static    struct
        "print",        LNAME,          Txxx,           OPRINT,
        "println",      LNAME,          Txxx,           OPRINTN,
        "real",         LNAME,          Txxx,           OREAL,
+       "recover",      LNAME,          Txxx,           ORECOVER,
 
        "notwithstanding",              LIGNORE,        Txxx,           OXXX,
        "thetruthofthematter",          LIGNORE,        Txxx,           OXXX,
index e5930790d4b9fc8e703884fef88afbf37c1ebdfb..0103c53d9f8dc37e9c88637ae563fa93f04ed4b8 100644 (file)
@@ -14,7 +14,9 @@ func mal(int32) *any
 func throwindex()
 func throwreturn()
 func throwinit()
-func panicl()
+
+func panic(interface{})
+func recover() interface{}
 
 func printbool(bool)
 func printfloat(float64)
index c219ad8c53cd44c4efcf41432030d0ac20ccb6ff..65c2384778f2e2c19e10b89d73d7b40ed377c55e 100644 (file)
@@ -1012,13 +1012,31 @@ reswitch:
                n->type = ptrto(t);
                goto ret;
 
-       case OPANIC:
        case OPRINT:
        case OPRINTN:
                ok |= Etop;
                typechecklist(n->list, Erv);
                goto ret;
 
+       case OPANIC:
+               ok |= Etop;
+               if(onearg(n) < 0)
+                       goto error;
+               typecheck(&n->left, Erv);
+               defaultlit(&n->left, types[TINTER]);
+               if(n->left->type == T)
+                       goto error;
+               goto ret;
+       
+       case ORECOVER:
+               ok |= Erv|Etop;
+               if(n->list != nil) {
+                       yyerror("too many arguments to recover");
+                       goto error;
+               }
+               n->type = types[TINTER];
+               goto ret;
+
        case OCLOSURE:
                ok |= Erv;
                typecheckclosure(n);
index b64d58e7fee68a527c2fb57e3023277d28ccc87e..1d5db4c045d9cea456083fe00fec83cf9ed88f4d 100644 (file)
@@ -425,7 +425,6 @@ walkstmt(Node **np)
                switch(n->left->op) {
                case OPRINT:
                case OPRINTN:
-               case OPANIC:
                        walkexprlist(n->left->list, &n->ninit);
                        n->left = walkprint(n->left, &n->ninit, 1);
                        break;
@@ -623,11 +622,18 @@ walkexpr(Node **np, NodeList **init)
 
        case OPRINT:
        case OPRINTN:
-       case OPANIC:
                walkexprlist(n->list, init);
                n = walkprint(n, init, 0);
                goto ret;
 
+       case OPANIC:
+               n = mkcall("panic", T, init, n->left);
+               goto ret;
+
+       case ORECOVER:
+               n = mkcall("recover", n->type, init);
+               goto ret;
+
        case OLITERAL:
                n->addable = 1;
                goto ret;
index c6c8b4a85bebdbc868863c0c8278d54378cee1ed..e2eca81a88431968cf7e110e390534ac261a5d34 100644 (file)
@@ -360,15 +360,28 @@ TEXT      runcgo(SB),7,$16
 // check that SP is in range [g->stackbase, g->stackguard)
 TEXT stackcheck(SB), 7, $0
        get_tls(CX)
-       MOVL g(CX), AX
-       CMPL g_stackbase(AX), SP
-       JHI 2(PC)
-       INT $3
-       CMPL SP, g_stackguard(AX)
-       JHI 2(PC)
-       INT $3
+       MOVL    g(CX), AX
+       CMPL    g_stackbase(AX), SP
+       JHI     2(PC)
+       INT     $3
+       CMPL    SP, g_stackguard(AX)
+       JHI     2(PC)
+       INT     $3
        RET
 
+// callString(f, arg, out)
+// call Go f(arg), which returns a string, and store in out
+TEXT callString(SB), 7, $24
+       MOVL    arg+4(FP), BX
+       MOVL    f+0(FP), CX
+       MOVL    BX, 0(SP)
+       CALL    *CX
+       MOVL    out+8(FP), DI
+       LEAL    4(SP), SI
+       MOVSL
+       MOVSL
+       MOVSL
+       RET
 
 GLOBL m0(SB), $1024
 GLOBL g0(SB), $1024
index c8466318c1181b5a28057f6626b569bda7ad6efa..fb32be05f9d722ec76af2efcc5b9c35e43493023 100644 (file)
@@ -303,11 +303,24 @@ TEXT runcgo(SB),7,$32
 
 // check that SP is in range [g->stackbase, g->stackguard)
 TEXT stackcheck(SB), 7, $0
-       CMPQ g_stackbase(g), SP
-       JHI 2(PC)
-       INT $3
-       CMPQ SP, g_stackguard(g)
-       JHI 2(PC)
-       INT $3
+       CMPQ    g_stackbase(g), SP
+       JHI     2(PC)
+       INT     $3
+       CMPQ    SP, g_stackguard(g)
+       JHI     2(PC)
+       INT     $3
+       RET
+
+// callString(f, arg, out)
+// call Go f(arg), which returns a string, and store in out
+TEXT callString(SB), 7, $24
+       MOVQ    arg+8(FP), BX
+       MOVQ    f+0(FP), CX
+       MOVQ    BX, 0(SP)
+       CALL    *CX
+       MOVQ    out+16(FP), DI
+       LEAQ    8(SP), SI
+       MOVSQ
+       MOVSQ
        RET
 
index 19fa1cc2e3343b98fc34a92b32a09a1d8d3ffb99..6be266734d19283c39b68177585884241734f558 100644 (file)
@@ -264,3 +264,18 @@ TEXT abort(SB),7,$0
        MOVW    $0, R0
        MOVW    (R0), R1
 
+// callString(f, arg, out)
+// call Go f(arg), which returns a string, and store in out
+TEXT callString(SB), 7, $24
+       MOVW    arg+4(FP), R1
+       MOVW    f+0(FP), R0
+       MOVW    R1, 0(SP)
+       BL      R0
+       MOVW    4(SP), R1
+       MOVW    8(SP), R2
+       MOVW    12(SP), R3
+       MOVW    out+8(FP), R0
+       MOVW    R1, 0(R0)
+       MOVW    R2, 4(R0)
+       MOVW    R3, 8(R0)
+       RET
index 26b3de785cdd3146ddbe0ae83ad463e1c261494e..5e4f2f59561861ffac8be5c321b2668fda7d5214 100644 (file)
@@ -3,6 +3,7 @@
 // license that can be found in the LICENSE file.
 
 #include "runtime.h"
+#include "type.h"
 
 //static Lock debuglock;
 
@@ -150,7 +151,7 @@ vprintf(int8 *s, byte *arg)
                        ·printhex(*(uint64*)arg);
                        break;
                case '!':
-                       ·panicl(-1);
+                       panic(-1);
                }
                arg = narg;
                lp = p+1;
@@ -347,3 +348,68 @@ void
 {
        write(fd, "\n", 1);
 }
+
+// print an empty interface, for use by panic.
+// this could be arbitrarily complex in general,
+// so we pick off only a few important cases:
+// int, string, and values with a String() string method.
+void
+printany(Eface e)
+{
+       int32 i;
+       FuncType *ft;
+       Method *m;
+       String s;
+       Type *rt;
+       UncommonType *x;
+
+       if(e.type == nil) {
+               write(fd, "nil", 3);
+               return;
+       }
+
+       if((x=e.type->x) != nil) {
+               for(i=0; i<x->mhdr.len; i++) {
+                       // Look for String() string method.
+                       m = &x->m[i];
+                       if(m->name->len == 6 &&
+                          mcmp(m->name->str, (byte*)"String", 6) == 0 &&
+                          // Found String; check method signature for func() string.
+                          m->mtyp->kind == KindFunc &&
+                          (ft = (FuncType*)m->mtyp)->in.len == 0 &&
+                          ft->out.len == 1 &&
+                          // Found single output.  Is it string?
+                          // Only base types have name != nil but pkgPath == nil.
+                          (rt = *(Type**)ft->out.array)->kind == KindString &&
+                          rt->x != nil &&
+                          rt->x->name != nil && rt->x->pkgPath == nil) {
+                               // Found the method!
+                               // Have to use assembly to call it
+                               // and save the return value.
+                               callString(m->ifn, e.data, &s);
+                               ·printstring(s);
+                               return;
+                       }
+               }
+       }
+
+       switch(e.type->kind & ~KindNoPointers) {
+       case KindInt:
+               mcpy((byte*)&i, (byte*)&e.data, sizeof(i));
+               ·printint(i);
+               break;
+
+       case KindString:
+               ·printstring(*(String*)e.data);
+               break;
+
+       default:
+               // Could print the other numeric types,
+               // but that's overkill: good panics have
+               // a string method anyway.
+               ·printstring(*e.type->string);
+               write(fd, "(???)", 5);
+               break;
+       }
+
+}
index aa6d82506ee18244eeade1af3fa1f906448d0a4d..c6655d9ec04054fb6c2fb5d26c89b21457b2f09e 100644 (file)
@@ -20,7 +20,7 @@ gotraceback(void)
 }
 
 void
-·panicl(int32 lno)
+panic(int32 unused)
 {
        uint8 *sp;
 
@@ -31,16 +31,25 @@ void
        }
        panicking++;
 
-       printf("\npanic PC=%X\n", (uint64)(uintptr)&lno);
-       sp = (uint8*)&lno;
+       printf("\npanic PC=%X\n", (uint64)(uintptr)&unused);
+       sp = (uint8*)&unused;
        if(gotraceback()){
-               traceback(·getcallerpc(&lno), sp, g);
+               traceback(·getcallerpc(&unused), sp, g);
                tracebackothers(g);
        }
        breakpoint();  // so we can grab it in a debugger
        exit(2);
 }
 
+void
+·panic(Eface e)
+{
+       fd = 2;
+       printf("panic: ");
+       printany(e);
+       panic(0);
+}
+
 void
 ·throwindex(void)
 {
@@ -70,7 +79,7 @@ throw(int8 *s)
 {
        fd = 2;
        printf("throw: %s\n", s);
-       ·panicl(-1);
+       panic(-1);
        *(int32*)0 = 0; // not reached
        exit(1);        // even more not reached
 }
index 2671a0592490ef1a5f97135048a9fa8616c4ab63..a0c0dd7a18ec7b2d6f428384d3e88a493e16ab2d 100644 (file)
@@ -344,6 +344,7 @@ int32       charntorune(int32*, uint8*, int32);
 /*
  * very low level c-called
  */
+void   callString(void(*fn)(void), void *arg, String *out);
 void   gogo(Gobuf*, uintptr);
 void   gogocall(Gobuf*, void(*)(void));
 uintptr        gosave(Gobuf*);
@@ -354,6 +355,7 @@ void*       getu(void);
 void   throw(int8*);
 uint32 rnd(uint32, uint32);
 void   prints(int8*);
+void   printany(Eface);
 void   printf(int8*, ...);
 byte*  mchr(byte*, byte, byte*);
 void   mcpy(byte*, byte*, uint32);
@@ -510,7 +512,7 @@ void        runtime_printuint(uint64);
 void   runtime_printhex(uint64);
 void   runtime_printslice(Slice);
 void   runtime_printcomplex(Complex128);
-void   ·panicl(int32);
+void   panic(int32);
 void   reflect·call(byte*, byte*, uint32);
 
 /*