mirror of
https://github.com/golang/go
synced 2024-11-24 17:00:01 -07:00
gc: implement defer print/println/panic/panicln
Fixes #219. R=ken2, r CC=golang-dev https://golang.org/cl/194097
This commit is contained in:
parent
22a4952bd2
commit
a186b77b03
@ -1,6 +1,6 @@
|
||||
char *runtimeimport =
|
||||
"package runtime\n"
|
||||
"func \"\".mal (? int32) (? *any)\n"
|
||||
"func \"\".mal (? int32) *any\n"
|
||||
"func \"\".throwindex ()\n"
|
||||
"func \"\".throwreturn ()\n"
|
||||
"func \"\".throwinit ()\n"
|
||||
@ -16,17 +16,18 @@ char *runtimeimport =
|
||||
"func \"\".printslice (? any)\n"
|
||||
"func \"\".printnl ()\n"
|
||||
"func \"\".printsp ()\n"
|
||||
"func \"\".catstring (? string, ? string) (? string)\n"
|
||||
"func \"\".cmpstring (? string, ? string) (? int)\n"
|
||||
"func \"\".slicestring (? string, ? int, ? int) (? string)\n"
|
||||
"func \"\".slicestring1 (? string, ? int) (? string)\n"
|
||||
"func \"\".indexstring (? string, ? int) (? uint8)\n"
|
||||
"func \"\".intstring (? int64) (? string)\n"
|
||||
"func \"\".slicebytetostring (? []uint8) (? string)\n"
|
||||
"func \"\".sliceinttostring (? []int) (? string)\n"
|
||||
"func \"\".stringiter (? string, ? int) (? int)\n"
|
||||
"func \"\".printf ()\n"
|
||||
"func \"\".catstring (? string, ? string) string\n"
|
||||
"func \"\".cmpstring (? string, ? string) int\n"
|
||||
"func \"\".slicestring (? string, ? int, ? int) string\n"
|
||||
"func \"\".slicestring1 (? string, ? int) string\n"
|
||||
"func \"\".indexstring (? string, ? int) uint8\n"
|
||||
"func \"\".intstring (? int64) string\n"
|
||||
"func \"\".slicebytetostring (? []uint8) string\n"
|
||||
"func \"\".sliceinttostring (? []int) string\n"
|
||||
"func \"\".stringiter (? string, ? int) int\n"
|
||||
"func \"\".stringiter2 (? string, ? int) (retk int, retv int)\n"
|
||||
"func \"\".slicecopy (to any, fr any, wid uint32) (? int)\n"
|
||||
"func \"\".slicecopy (to any, fr any, wid uint32) int\n"
|
||||
"func \"\".ifaceI2E (iface any) (ret any)\n"
|
||||
"func \"\".ifaceE2I (typ *uint8, iface any) (ret any)\n"
|
||||
"func \"\".ifaceT2E (typ *uint8, elem any) (ret any)\n"
|
||||
@ -58,7 +59,7 @@ char *runtimeimport =
|
||||
"func \"\".chansend1 (hchan chan<- any, elem any)\n"
|
||||
"func \"\".chansend2 (hchan chan<- any, elem any) (pres bool)\n"
|
||||
"func \"\".closechan (hchan any)\n"
|
||||
"func \"\".closedchan (hchan any) (? bool)\n"
|
||||
"func \"\".closedchan (hchan any) bool\n"
|
||||
"func \"\".newselect (size int) (sel *uint8)\n"
|
||||
"func \"\".selectsend (sel *uint8, hchan chan<- any, elem any) (selected bool)\n"
|
||||
"func \"\".selectrecv (sel *uint8, hchan <-chan any, elem *any) (selected bool)\n"
|
||||
@ -69,24 +70,24 @@ char *runtimeimport =
|
||||
"func \"\".sliceslice (old []any, lb int, hb int, width int) (ary []any)\n"
|
||||
"func \"\".slicearray (old *any, nel int, lb int, hb int, width int) (ary []any)\n"
|
||||
"func \"\".closure ()\n"
|
||||
"func \"\".int64div (? int64, ? int64) (? int64)\n"
|
||||
"func \"\".uint64div (? uint64, ? uint64) (? uint64)\n"
|
||||
"func \"\".int64mod (? int64, ? int64) (? int64)\n"
|
||||
"func \"\".uint64mod (? uint64, ? uint64) (? uint64)\n"
|
||||
"func \"\".float64toint64 (? float64) (? int64)\n"
|
||||
"func \"\".int64tofloat64 (? int64) (? float64)\n"
|
||||
"func \"\".int64div (? int64, ? int64) int64\n"
|
||||
"func \"\".uint64div (? uint64, ? uint64) uint64\n"
|
||||
"func \"\".int64mod (? int64, ? int64) int64\n"
|
||||
"func \"\".uint64mod (? uint64, ? uint64) uint64\n"
|
||||
"func \"\".float64toint64 (? float64) int64\n"
|
||||
"func \"\".int64tofloat64 (? int64) float64\n"
|
||||
"\n"
|
||||
"$$\n";
|
||||
char *unsafeimport =
|
||||
"package unsafe\n"
|
||||
"type \"\".Pointer *any\n"
|
||||
"func \"\".Offsetof (? any) (? int)\n"
|
||||
"func \"\".Sizeof (? any) (? int)\n"
|
||||
"func \"\".Alignof (? any) (? int)\n"
|
||||
"func \"\".Offsetof (? any) int\n"
|
||||
"func \"\".Sizeof (? any) int\n"
|
||||
"func \"\".Alignof (? any) int\n"
|
||||
"func \"\".Typeof (i interface { }) (typ interface { })\n"
|
||||
"func \"\".Reflect (i interface { }) (typ interface { }, addr \"\".Pointer)\n"
|
||||
"func \"\".Unreflect (typ interface { }, addr \"\".Pointer) (ret interface { })\n"
|
||||
"func \"\".New (typ interface { }) (? \"\".Pointer)\n"
|
||||
"func \"\".NewArray (typ interface { }, n int) (? \"\".Pointer)\n"
|
||||
"func \"\".New (typ interface { }) \"\".Pointer\n"
|
||||
"func \"\".NewArray (typ interface { }, n int) \"\".Pointer\n"
|
||||
"\n"
|
||||
"$$\n";
|
||||
|
@ -27,6 +27,7 @@ func printeface(any)
|
||||
func printslice(any)
|
||||
func printnl()
|
||||
func printsp()
|
||||
func printf()
|
||||
|
||||
func catstring(string, string) string
|
||||
func cmpstring(string, string) int
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
#include "go.h"
|
||||
|
||||
static Node* walkprint(Node*, NodeList**);
|
||||
static Node* walkprint(Node*, NodeList**, int);
|
||||
static Node* conv(Node*, Type*);
|
||||
static Node* mapfn(char*, Type*);
|
||||
static Node* makenewvar(Type*, NodeList**, Node**);
|
||||
@ -355,7 +355,18 @@ walkstmt(Node **np)
|
||||
|
||||
case ODEFER:
|
||||
hasdefer = 1;
|
||||
walkexpr(&n->left, &n->ninit);
|
||||
switch(n->left->op) {
|
||||
case OPRINT:
|
||||
case OPRINTN:
|
||||
case OPANIC:
|
||||
case OPANICN:
|
||||
walkexprlist(n->left->list, &n->ninit);
|
||||
n->left = walkprint(n->left, &n->ninit, 1);
|
||||
break;
|
||||
default:
|
||||
walkexpr(&n->left, &n->ninit);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case OFOR:
|
||||
@ -539,7 +550,7 @@ walkexpr(Node **np, NodeList **init)
|
||||
case OPANIC:
|
||||
case OPANICN:
|
||||
walkexprlist(n->list, init);
|
||||
n = walkprint(n, init);
|
||||
n = walkprint(n, init, 0);
|
||||
goto ret;
|
||||
|
||||
case OLITERAL:
|
||||
@ -1510,7 +1521,7 @@ ret:
|
||||
|
||||
// generate code for print
|
||||
static Node*
|
||||
walkprint(Node *nn, NodeList **init)
|
||||
walkprint(Node *nn, NodeList **init, int defer)
|
||||
{
|
||||
Node *r;
|
||||
Node *n;
|
||||
@ -1518,16 +1529,32 @@ walkprint(Node *nn, NodeList **init)
|
||||
Node *on;
|
||||
Type *t;
|
||||
int notfirst, et, op;
|
||||
NodeList *calls;
|
||||
NodeList *calls, *intypes, *args;
|
||||
Fmt fmt;
|
||||
|
||||
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)
|
||||
calls = list(calls, mkcall("printsp", T, init));
|
||||
if(notfirst) {
|
||||
if(defer)
|
||||
fmtprint(&fmt, " ");
|
||||
else
|
||||
calls = list(calls, mkcall("printsp", T, init));
|
||||
}
|
||||
notfirst = op == OPRINTN || op == OPANICN;
|
||||
|
||||
n = l->n;
|
||||
@ -1548,62 +1575,121 @@ walkprint(Node *nn, NodeList **init)
|
||||
if(n->type == T || n->type->etype == TFORW)
|
||||
continue;
|
||||
|
||||
t = n->type;
|
||||
et = n->type->etype;
|
||||
if(isinter(n->type)) {
|
||||
if(isnilinter(n->type))
|
||||
on = syslook("printeface", 1);
|
||||
else
|
||||
on = syslook("printiface", 1);
|
||||
argtype(on, n->type); // any-1
|
||||
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
|
||||
}
|
||||
} else if(isptr[et] || et == TCHAN || et == TMAP || et == TFUNC) {
|
||||
on = syslook("printpointer", 1);
|
||||
argtype(on, n->type); // any-1
|
||||
if(defer) {
|
||||
fmtprint(&fmt, "%%p");
|
||||
} else {
|
||||
on = syslook("printpointer", 1);
|
||||
argtype(on, n->type); // any-1
|
||||
}
|
||||
} else if(isslice(n->type)) {
|
||||
on = syslook("printslice", 1);
|
||||
argtype(on, n->type); // any-1
|
||||
if(defer) {
|
||||
fmtprint(&fmt, "%%a");
|
||||
} else {
|
||||
on = syslook("printslice", 1);
|
||||
argtype(on, n->type); // any-1
|
||||
}
|
||||
} else if(isint[et]) {
|
||||
if(et == TUINT64)
|
||||
on = syslook("printuint", 0);
|
||||
else
|
||||
on = syslook("printint", 0);
|
||||
if(defer) {
|
||||
if(et == TUINT64)
|
||||
fmtprint(&fmt, "%%U");
|
||||
else {
|
||||
fmtprint(&fmt, "%%D");
|
||||
t = types[TINT64];
|
||||
}
|
||||
} else {
|
||||
if(et == TUINT64)
|
||||
on = syslook("printuint", 0);
|
||||
else
|
||||
on = syslook("printint", 0);
|
||||
}
|
||||
} else if(isfloat[et]) {
|
||||
on = syslook("printfloat", 0);
|
||||
if(defer) {
|
||||
fmtprint(&fmt, "%%f");
|
||||
t = types[TFLOAT64];
|
||||
} else
|
||||
on = syslook("printfloat", 0);
|
||||
} else if(et == TBOOL) {
|
||||
on = syslook("printbool", 0);
|
||||
if(defer)
|
||||
fmtprint(&fmt, "%%t");
|
||||
else
|
||||
on = syslook("printbool", 0);
|
||||
} else if(et == TSTRING) {
|
||||
on = syslook("printstring", 0);
|
||||
if(defer)
|
||||
fmtprint(&fmt, "%%S");
|
||||
else
|
||||
on = syslook("printstring", 0);
|
||||
} else {
|
||||
badtype(OPRINT, n->type, T);
|
||||
continue;
|
||||
}
|
||||
|
||||
t = *getinarg(on->type);
|
||||
if(t != nil)
|
||||
t = t->type;
|
||||
if(t != nil)
|
||||
t = t->type;
|
||||
if(!defer) {
|
||||
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;
|
||||
}
|
||||
r = nod(OCALL, on, N);
|
||||
r->list = list1(n);
|
||||
calls = list(calls, r);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
if(op == OPRINTN)
|
||||
calls = list(calls, mkcall("printnl", T, nil));
|
||||
typechecklist(calls, Etop);
|
||||
walkexprlist(calls, init);
|
||||
if(defer) {
|
||||
if(op == OPRINTN)
|
||||
fmtprint(&fmt, "\n");
|
||||
if(op == OPANIC || op == OPANICN)
|
||||
fmtprint(&fmt, "%%!");
|
||||
on = syslook("printf", 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 == OPANIC || op == OPANICN)
|
||||
r = mkcall("panicl", T, nil);
|
||||
else
|
||||
r = nod(OEMPTY, N, N);
|
||||
typecheck(&r, Etop);
|
||||
walkexpr(&r, init);
|
||||
r->ninit = calls;
|
||||
if(op == OPANIC || op == OPANICN)
|
||||
r = mkcall("panicl", T, nil);
|
||||
else
|
||||
r = nod(OEMPTY, N, N);
|
||||
typecheck(&r, Etop);
|
||||
walkexpr(&r, init);
|
||||
r->ninit = calls;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
//static Lock debuglock;
|
||||
|
||||
static void vprintf(int8*, byte*);
|
||||
|
||||
void
|
||||
dump(byte *p, int32 n)
|
||||
{
|
||||
@ -29,18 +31,35 @@ prints(int8 *s)
|
||||
write(fd, s, findnull((byte*)s));
|
||||
}
|
||||
|
||||
// Very simple printf. Only for debugging prints.
|
||||
// Do not add to this without checking with Rob.
|
||||
#pragma textflag 7
|
||||
void
|
||||
printf(int8 *s, ...)
|
||||
{
|
||||
byte *arg;
|
||||
|
||||
arg = (byte*)(&s+1);
|
||||
vprintf(s, arg);
|
||||
}
|
||||
|
||||
static byte*
|
||||
vrnd(byte *p, int32 x)
|
||||
{
|
||||
if((uint32)(uintptr)p&(x-1))
|
||||
p += x - ((uint32)(uintptr)p&(x-1));
|
||||
return p;
|
||||
}
|
||||
|
||||
// Very simple printf. Only for debugging prints.
|
||||
// Do not add to this without checking with Rob.
|
||||
static void
|
||||
vprintf(int8 *s, byte *arg)
|
||||
{
|
||||
int8 *p, *lp;
|
||||
byte *arg, *narg;
|
||||
byte *narg;
|
||||
|
||||
// lock(&debuglock);
|
||||
|
||||
lp = p = s;
|
||||
arg = (byte*)(&s+1);
|
||||
for(; *p; p++) {
|
||||
if(*p != '%')
|
||||
continue;
|
||||
@ -49,40 +68,58 @@ printf(int8 *s, ...)
|
||||
p++;
|
||||
narg = nil;
|
||||
switch(*p) {
|
||||
case 't':
|
||||
narg = arg + 1;
|
||||
break;
|
||||
case 'd': // 32-bit
|
||||
case 'x':
|
||||
arg = vrnd(arg, 4);
|
||||
narg = arg + 4;
|
||||
break;
|
||||
case 'D': // 64-bit
|
||||
case 'U':
|
||||
case 'X':
|
||||
if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4)
|
||||
arg += 4;
|
||||
case 'f':
|
||||
arg = vrnd(arg, sizeof(uintptr));
|
||||
narg = arg + 8;
|
||||
break;
|
||||
case 'p': // pointer-sized
|
||||
case 's':
|
||||
if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4)
|
||||
arg += 4;
|
||||
arg = vrnd(arg, sizeof(uintptr));
|
||||
narg = arg + sizeof(uintptr);
|
||||
break;
|
||||
case 'S': // pointer-aligned but bigger
|
||||
if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4)
|
||||
arg += 4;
|
||||
arg = vrnd(arg, sizeof(uintptr));
|
||||
narg = arg + sizeof(String);
|
||||
break;
|
||||
case 'a': // pointer-aligned but bigger
|
||||
arg = vrnd(arg, sizeof(uintptr));
|
||||
narg = arg + sizeof(Slice);
|
||||
break;
|
||||
case 'i': // pointer-aligned but bigger
|
||||
case 'e':
|
||||
arg = vrnd(arg, sizeof(uintptr));
|
||||
narg = arg + sizeof(Eface);
|
||||
break;
|
||||
}
|
||||
switch(*p) {
|
||||
case 'a':
|
||||
·printslice(*(Slice*)arg);
|
||||
break;
|
||||
case 'd':
|
||||
·printint(*(int32*)arg);
|
||||
break;
|
||||
case 'D':
|
||||
·printint(*(int64*)arg);
|
||||
break;
|
||||
case 'x':
|
||||
·printhex(*(uint32*)arg);
|
||||
case 'e':
|
||||
·printeface(*(Eface*)arg);
|
||||
break;
|
||||
case 'X':
|
||||
·printhex(*(uint64*)arg);
|
||||
case 'f':
|
||||
·printfloat(*(float64*)arg);
|
||||
break;
|
||||
case 'i':
|
||||
·printiface(*(Iface*)arg);
|
||||
break;
|
||||
case 'p':
|
||||
·printpointer(*(void**)arg);
|
||||
@ -93,6 +130,20 @@ printf(int8 *s, ...)
|
||||
case 'S':
|
||||
·printstring(*(String*)arg);
|
||||
break;
|
||||
case 't':
|
||||
·printbool(*(bool*)arg);
|
||||
break;
|
||||
case 'U':
|
||||
·printuint(*(uint64*)arg);
|
||||
break;
|
||||
case 'x':
|
||||
·printhex(*(uint32*)arg);
|
||||
break;
|
||||
case 'X':
|
||||
·printhex(*(uint64*)arg);
|
||||
break;
|
||||
case '!':
|
||||
·panicl(-1);
|
||||
}
|
||||
arg = narg;
|
||||
lp = p+1;
|
||||
@ -103,6 +154,14 @@ printf(int8 *s, ...)
|
||||
// unlock(&debuglock);
|
||||
}
|
||||
|
||||
void
|
||||
·printf(String s, ...)
|
||||
{
|
||||
// Can assume s has terminating NUL because only
|
||||
// the Go compiler generates calls to ·printf, using
|
||||
// string constants, and all the string constants have NULs.
|
||||
vprintf((int8*)s.str, (byte*)(&s+1));
|
||||
}
|
||||
|
||||
void
|
||||
·printpc(void *p)
|
||||
|
@ -487,6 +487,7 @@ void runtime_printpointer(void*);
|
||||
void runtime_printuint(uint64);
|
||||
void runtime_printhex(uint64);
|
||||
void runtime_printslice(Slice);
|
||||
void ·panicl(int32);
|
||||
|
||||
/*
|
||||
* wrapped for go users
|
||||
|
14
test/deferprint.go
Normal file
14
test/deferprint.go
Normal file
@ -0,0 +1,14 @@
|
||||
// $G $D/$F.go && $L $F.$A && ./$A.out
|
||||
|
||||
// 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.
|
||||
|
||||
package main
|
||||
|
||||
func main() {
|
||||
defer println(42, true, false, true, 1.5, "world", (chan int)(nil), []int(nil), (map[string]int)(nil), (func())(nil), byte(255))
|
||||
defer println(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
|
||||
// defer panic("dead")
|
||||
defer print("printing: ")
|
||||
}
|
@ -25,6 +25,10 @@ throw: interface hash
|
||||
|
||||
panic PC=xxx
|
||||
|
||||
=========== ./deferprint.go
|
||||
printing: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
||||
42 true false true +1.500000e+000 world 0x0 [0/0]0x0 0x0 0x0 255
|
||||
|
||||
=========== ./helloworld.go
|
||||
hello, world
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user