Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
G
golang
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
go
golang
Commits
9b1507b0
Commit
9b1507b0
authored
Mar 31, 2010
by
Russ Cox
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
gc: implement panic and recover
R=ken2, r, ken3 CC=golang-dev
https://golang.org/cl/831042
parent
c72f491a
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
239 additions
and
30 deletions
+239
-30
ggen.c
src/cmd/5g/ggen.c
+9
-4
ggen.c
src/cmd/6g/ggen.c
+7
-2
ggen.c
src/cmd/8g/ggen.c
+7
-2
builtin.c.boot
src/cmd/gc/builtin.c.boot
+1
-1
dcl.c
src/cmd/gc/dcl.c
+13
-1
go.h
src/cmd/gc/go.h
+3
-1
init.c
src/cmd/gc/init.c
+1
-1
lex.c
src/cmd/gc/lex.c
+9
-2
runtime.go
src/cmd/gc/runtime.go
+1
-1
subr.c
src/cmd/gc/subr.c
+1
-1
walk.c
src/cmd/gc/walk.c
+2
-1
8db.c
src/libmach/8db.c
+0
-2
proc.c
src/pkg/runtime/proc.c
+165
-1
runtime.c
src/pkg/runtime/runtime.c
+0
-9
runtime.h
src/pkg/runtime/runtime.h
+19
-1
golden.out
test/golden.out
+1
-0
No files found.
src/cmd/5g/ggen.c
View file @
9b1507b0
...
...
@@ -190,7 +190,7 @@ ginscall(Node *f, int proc)
break
;
case
2
:
// defered call (defer)
case
2
:
// defer
r
ed call (defer)
regalloc
(
&
r
,
types
[
tptr
],
N
);
p
=
gins
(
AMOVW
,
N
,
&
r
);
p
->
from
.
type
=
D_OREG
;
...
...
@@ -222,7 +222,7 @@ ginscall(Node *f, int proc)
ginscall
(
deferproc
,
0
);
regalloc
(
&
r
,
types
[
tptr
],
N
);
nodreg
(
&
r
,
types
[
tptr
],
D_R1
);
p
=
gins
(
AMOVW
,
N
,
&
r
);
p
->
from
.
type
=
D_OREG
;
p
->
from
.
reg
=
REGSP
;
...
...
@@ -233,8 +233,13 @@ ginscall(Node *f, int proc)
p
->
to
.
reg
=
REGSP
;
p
->
to
.
offset
=
8
;
p
->
scond
|=
C_WBIT
;
regfree
(
&
r
);
if
(
proc
==
2
)
{
nodconst
(
&
con
,
types
[
TINT32
],
0
);
nodreg
(
&
r
,
types
[
tptr
],
D_R0
);
gins
(
ACMP
,
&
con
,
&
r
);
patch
(
gbranch
(
ABNE
,
T
),
pret
);
}
break
;
}
}
...
...
src/cmd/6g/ggen.c
View file @
9b1507b0
...
...
@@ -142,8 +142,8 @@ ginscall(Node *f, int proc)
break
;
case
1
:
// call in new proc (go)
case
2
:
// defered call (defer)
nodreg
(
&
reg
,
types
[
TINT64
],
D_
A
X
);
case
2
:
// defer
r
ed call (defer)
nodreg
(
&
reg
,
types
[
TINT64
],
D_
C
X
);
gins
(
APUSHQ
,
f
,
N
);
nodconst
(
&
con
,
types
[
TINT32
],
argsize
(
f
->
type
));
gins
(
APUSHQ
,
&
con
,
N
);
...
...
@@ -156,6 +156,11 @@ ginscall(Node *f, int proc)
}
gins
(
APOPQ
,
N
,
&
reg
);
gins
(
APOPQ
,
N
,
&
reg
);
if
(
proc
==
2
)
{
nodreg
(
&
reg
,
types
[
TINT64
],
D_AX
);
gins
(
ATESTQ
,
&
reg
,
&
reg
);
patch
(
gbranch
(
AJNE
,
T
),
pret
);
}
break
;
}
}
...
...
src/cmd/8g/ggen.c
View file @
9b1507b0
...
...
@@ -182,8 +182,8 @@ ginscall(Node *f, int proc)
break
;
case
1
:
// call in new proc (go)
case
2
:
// defered call (defer)
nodreg
(
&
reg
,
types
[
TINT32
],
D_
A
X
);
case
2
:
// defer
r
ed call (defer)
nodreg
(
&
reg
,
types
[
TINT32
],
D_
C
X
);
gins
(
APUSHL
,
f
,
N
);
nodconst
(
&
con
,
types
[
TINT32
],
argsize
(
f
->
type
));
gins
(
APUSHL
,
&
con
,
N
);
...
...
@@ -193,6 +193,11 @@ ginscall(Node *f, int proc)
ginscall
(
deferproc
,
0
);
gins
(
APOPL
,
N
,
&
reg
);
gins
(
APOPL
,
N
,
&
reg
);
if
(
proc
==
2
)
{
nodreg
(
&
reg
,
types
[
TINT64
],
D_AX
);
gins
(
ATESTL
,
&
reg
,
&
reg
);
patch
(
gbranch
(
AJNE
,
T
),
pret
);
}
break
;
}
}
...
...
src/cmd/gc/builtin.c.boot
View file @
9b1507b0
...
...
@@ -5,7 +5,7 @@ char *runtimeimport =
"func \"\".throwreturn ()\n"
"func \"\".throwinit ()\n"
"func \"\".panic (? interface { })\n"
"func \"\".recover () interface { }\n"
"func \"\".recover (
? *int32
) interface { }\n"
"func \"\".printbool (? bool)\n"
"func \"\".printfloat (? float64)\n"
"func \"\".printint (? int64)\n"
...
...
src/cmd/gc/dcl.c
View file @
9b1507b0
...
...
@@ -1276,7 +1276,7 @@ addmethod(Sym *sf, Type *t, int local)
}
void
funccompile
(
Node
*
n
)
funccompile
(
Node
*
n
,
int
isclosure
)
{
stksize
=
BADWIDTH
;
maxarg
=
0
;
...
...
@@ -1289,6 +1289,18 @@ funccompile(Node *n)
// assign parameter offsets
checkwidth
(
n
->
type
);
// record offset to actual frame pointer.
// for closure, have to skip over leading pointers and PC slot.
nodfp
->
xoffset
=
0
;
if
(
isclosure
)
{
NodeList
*
l
;
for
(
l
=
n
->
nname
->
ntype
->
list
;
l
;
l
=
l
->
next
)
{
nodfp
->
xoffset
+=
widthptr
;
if
(
l
->
n
->
left
==
N
)
// found slot for PC
break
;
}
}
if
(
curfn
)
fatal
(
"funccompile %S inside %S"
,
n
->
nname
->
sym
,
curfn
->
nname
->
sym
);
...
...
src/cmd/gc/go.h
View file @
9b1507b0
...
...
@@ -1004,7 +1004,7 @@ NodeList* constiter(NodeList*, Node*, NodeList*);
Node
*
unsafenmagic
(
Node
*
,
NodeList
*
);
void
dclchecks
(
void
);
void
funccompile
(
Node
*
);
void
funccompile
(
Node
*
,
int
);
Node
*
typedcl0
(
Sym
*
);
Node
*
typedcl1
(
Node
*
,
Node
*
,
int
);
...
...
@@ -1169,6 +1169,8 @@ EXTERN Prog* breakpc;
EXTERN
Prog
*
pc
;
EXTERN
Prog
*
firstpc
;
EXTERN
Node
*
nodfp
;
void
allocparams
(
void
);
void
cgen_as
(
Node
*
nl
,
Node
*
nr
);
void
cgen_callmeth
(
Node
*
n
,
int
proc
);
...
...
src/cmd/gc/init.c
View file @
9b1507b0
...
...
@@ -197,5 +197,5 @@ fninit(NodeList *n)
fn
->
nbody
=
r
;
funcbody
(
fn
);
typecheck
(
&
fn
,
Etop
);
funccompile
(
fn
);
funccompile
(
fn
,
0
);
}
src/cmd/gc/lex.c
View file @
9b1507b0
...
...
@@ -138,14 +138,14 @@ main(int argc, char *argv[])
resumecheckwidth
();
for
(
l
=
xtop
;
l
;
l
=
l
->
next
)
if
(
l
->
n
->
op
==
ODCLFUNC
)
funccompile
(
l
->
n
);
funccompile
(
l
->
n
,
0
);
if
(
nerrors
==
0
)
fninit
(
xtop
);
while
(
closures
)
{
l
=
closures
;
closures
=
nil
;
for
(;
l
;
l
=
l
->
next
)
funccompile
(
l
->
n
);
funccompile
(
l
->
n
,
1
);
}
dclchecks
();
...
...
@@ -1443,6 +1443,13 @@ lexfini(void)
*
s
->
def
=
*
nodbool
(
0
);
s
->
def
->
sym
=
s
;
}
nodfp
=
nod
(
ONAME
,
N
,
N
);
nodfp
->
noescape
=
1
;
nodfp
->
type
=
types
[
TINT32
];
nodfp
->
xoffset
=
0
;
nodfp
->
class
=
PPARAM
;
nodfp
->
sym
=
lookup
(
".fp"
);
}
struct
...
...
src/cmd/gc/runtime.go
View file @
9b1507b0
...
...
@@ -16,7 +16,7 @@ func throwreturn()
func
throwinit
()
func
panic
(
interface
{})
func
recover
()
interface
{}
func
recover
(
*
int32
)
interface
{}
func
printbool
(
bool
)
func
printfloat
(
float64
)
...
...
src/cmd/gc/subr.c
View file @
9b1507b0
...
...
@@ -2923,7 +2923,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
funcbody
(
fn
);
typecheck
(
&
fn
,
Etop
);
funccompile
(
fn
);
funccompile
(
fn
,
0
);
}
/*
...
...
src/cmd/gc/walk.c
View file @
9b1507b0
...
...
@@ -391,6 +391,7 @@ walkstmt(Node **np)
case
OPRINTN
:
case
OPANIC
:
case
OEMPTY
:
case
ORECOVER
:
if
(
n
->
typecheck
==
0
)
fatal
(
"missing typecheck"
);
init
=
n
->
ninit
;
...
...
@@ -631,7 +632,7 @@ walkexpr(Node **np, NodeList **init)
goto
ret
;
case
ORECOVER
:
n
=
mkcall
(
"recover"
,
n
->
type
,
init
);
n
=
mkcall
(
"recover"
,
n
->
type
,
init
,
nod
(
OADDR
,
nodfp
,
N
)
);
goto
ret
;
case
OLITERAL
:
...
...
src/libmach/8db.c
View file @
9b1507b0
...
...
@@ -147,8 +147,6 @@ i386trace(Map *map, uvlong pc, uvlong sp, uvlong link, Tracer trace)
// G is
// byte* stackguard
// byte* stackbase (= Stktop*)
// Defer* defer
// Gobuf sched
// TODO(rsc): Need some way to get at the g for other threads.
// Probably need to pass it into the trace function.
g
=
0
;
...
...
src/pkg/runtime/proc.c
View file @
9b1507b0
...
...
@@ -447,6 +447,32 @@ scheduler(void)
lock
(
&
sched
);
if
(
gosave
(
&
m
->
sched
)
!=
0
){
gp
=
m
->
curg
;
if
(
gp
->
status
==
Grecovery
)
{
// switched to scheduler to get stack unwound.
// don't go through the full scheduling logic.
Defer
*
d
;
d
=
gp
->
defer
;
gp
->
defer
=
d
->
link
;
// unwind to the stack frame with d->sp in it.
unwindstack
(
gp
,
d
->
sp
);
if
(
d
->
sp
<
gp
->
stackguard
||
gp
->
stackbase
<
d
->
sp
)
throw
(
"bad stack in recovery"
);
// make the deferproc for this d return again,
// this time returning 1. function will jump to
// standard return epilogue.
// the -2*sizeof(uintptr) makes up for the
// two extra words that are on the stack at
// each call to deferproc.
// (the pc we're returning to does pop pop
// before it tests the return value.)
gp
->
sched
.
sp
=
d
->
sp
-
2
*
sizeof
(
uintptr
);
gp
->
sched
.
pc
=
d
->
pc
;
free
(
d
);
gogo
(
&
gp
->
sched
,
1
);
}
// Jumped here via gosave/gogo, so didn't
// execute lock(&sched) above.
...
...
@@ -719,6 +745,10 @@ newstack(void)
top
->
fp
=
m
->
morefp
;
top
->
args
=
args
;
top
->
free
=
free
;
// copy flag from panic
top
->
panic
=
g1
->
ispanic
;
g1
->
ispanic
=
false
;
g1
->
stackbase
=
(
byte
*
)
top
;
g1
->
stackguard
=
stk
+
StackGuard
;
...
...
@@ -819,7 +849,7 @@ newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
}
#pragma textflag 7
void
uintptr
·
deferproc
(
int32
siz
,
byte
*
fn
,
...)
{
Defer
*
d
;
...
...
@@ -828,10 +858,19 @@ void
d
->
fn
=
fn
;
d
->
sp
=
(
byte
*
)(
&
fn
+
1
);
d
->
siz
=
siz
;
d
->
pc
=
·
getcallerpc
(
&
siz
);
mcpy
(
d
->
args
,
d
->
sp
,
d
->
siz
);
d
->
link
=
g
->
defer
;
g
->
defer
=
d
;
// deferproc returns 0 normally.
// a deferred func that stops a panic
// makes the deferproc return 1.
// the code the compiler generates always
// checks the return value and jumps to the
// end of the function if deferproc returns != 0.
return
0
;
}
#pragma textflag 7
...
...
@@ -888,6 +927,131 @@ unwindstack(G *gp, byte *sp)
}
}
static
void
printpanics
(
Panic
*
p
)
{
if
(
p
->
link
)
{
printpanics
(
p
->
link
);
printf
(
"
\t
"
);
}
printf
(
"panic: "
);
printany
(
p
->
arg
);
if
(
p
->
recovered
)
printf
(
" [recovered]"
);
printf
(
"
\n
"
);
}
void
·
panic
(
Eface
e
)
{
Defer
*
d
;
Panic
*
p
;
p
=
mal
(
sizeof
*
p
);
p
->
arg
=
e
;
p
->
link
=
g
->
panic
;
p
->
stackbase
=
g
->
stackbase
;
g
->
panic
=
p
;
for
(;;)
{
d
=
g
->
defer
;
if
(
d
==
nil
)
break
;
// take defer off list in case of recursive panic
g
->
defer
=
d
->
link
;
g
->
ispanic
=
true
;
// rock for newstack, where reflect.call ends up
reflect
·
call
(
d
->
fn
,
d
->
args
,
d
->
siz
);
if
(
p
->
recovered
)
{
g
->
panic
=
p
->
link
;
free
(
p
);
// put recovering defer back on list
// for scheduler to find.
d
->
link
=
g
->
defer
;
g
->
defer
=
d
;
g
->
status
=
Grecovery
;
gosched
();
throw
(
"recovery failed"
);
// gosched should not return
}
free
(
d
);
}
// ran out of deferred calls - old-school panic now
fd
=
2
;
printpanics
(
g
->
panic
);
panic
(
0
);
}
#pragma textflag 7
/* no split, or else g->stackguard is not the stack for fp */
void
·
recover
(
byte
*
fp
,
Eface
ret
)
{
Stktop
*
top
,
*
oldtop
;
Panic
*
p
;
// Must be a panic going on.
if
((
p
=
g
->
panic
)
==
nil
||
p
->
recovered
)
goto
nomatch
;
// Frame must be at the top of the stack segment,
// because each deferred call starts a new stack
// segment as a side effect of using reflect.call.
// (There has to be some way to remember the
// variable argument frame size, and the segment
// code already takes care of that for us, so we
// reuse it.)
//
// As usual closures complicate things: the fp that
// the closure implementation function claims to have
// is where the explicit arguments start, after the
// implicit pointer arguments and PC slot.
// If we're on the first new segment for a closure,
// then fp == top - top->args is correct, but if
// the closure has its own big argument frame and
// allocated a second segment (see below),
// the fp is slightly above top - top->args.
// That condition can't happen normally though
// (stack pointer go down, not up), so we can accept
// any fp between top and top - top->args as
// indicating the top of the segment.
top
=
(
Stktop
*
)
g
->
stackbase
;
if
(
fp
<
(
byte
*
)
top
-
top
->
args
||
(
byte
*
)
top
<
fp
)
goto
nomatch
;
// The deferred call makes a new segment big enough
// for the argument frame but not necessarily big
// enough for the function's local frame (size unknown
// at the time of the call), so the function might have
// made its own segment immediately. If that's the
// case, back top up to the older one, the one that
// reflect.call would have made for the panic.
//
// The fp comparison here checks that the argument
// frame that was copied during the split (the top->args
// bytes above top->fp) abuts the old top of stack.
// This is a correct test for both closure and non-closure code.
oldtop
=
(
Stktop
*
)
top
->
stackbase
;
if
(
oldtop
!=
nil
&&
top
->
fp
==
(
byte
*
)
oldtop
-
top
->
args
)
top
=
oldtop
;
// Now we have the segment that was created to
// run this call. It must have been marked as a panic segment.
if
(
!
top
->
panic
)
goto
nomatch
;
// Okay, this is the top frame of a deferred call
// in response to a panic. It can see the panic argument.
p
->
recovered
=
1
;
ret
=
p
->
arg
;
FLUSH
(
&
ret
);
return
;
nomatch
:
ret
.
type
=
nil
;
ret
.
data
=
nil
;
FLUSH
(
&
ret
);
}
// Put on gfree list. Sched must be locked.
static
void
gfput
(
G
*
g
)
...
...
src/pkg/runtime/runtime.c
View file @
9b1507b0
...
...
@@ -41,15 +41,6 @@ panic(int32 unused)
exit
(
2
);
}
void
·
panic
(
Eface
e
)
{
fd
=
2
;
printf
(
"panic: "
);
printany
(
e
);
panic
(
0
);
}
void
·
throwindex
(
void
)
{
...
...
src/pkg/runtime/runtime.h
View file @
9b1507b0
...
...
@@ -62,6 +62,7 @@ typedef struct Itab Itab;
typedef
struct
Eface
Eface
;
typedef
struct
Type
Type
;
typedef
struct
Defer
Defer
;
typedef
struct
Panic
Panic
;
typedef
struct
hash
Hmap
;
typedef
struct
Hchan
Hchan
;
typedef
struct
Complex64
Complex64
;
...
...
@@ -98,6 +99,7 @@ enum
Gwaiting
,
Gmoribund
,
Gdead
,
Grecovery
,
};
enum
{
...
...
@@ -176,7 +178,8 @@ struct G
byte
*
stackguard
;
// cannot move - also known to linker, libmach, libcgo
byte
*
stackbase
;
// cannot move - also known to libmach, libcgo
Defer
*
defer
;
Gobuf
sched
;
// cannot move - also known to libmach
Panic
*
panic
;
Gobuf
sched
;
byte
*
stack0
;
byte
*
entry
;
// initial function
G
*
alllink
;
// on allg
...
...
@@ -186,6 +189,7 @@ struct G
uint32
selgen
;
// valid sudog pointer
G
*
schedlink
;
bool
readyonstop
;
bool
ispanic
;
M
*
m
;
// for debuggers, but offset not hard-coded
M
*
lockedm
;
void
(
*
cgofn
)(
void
*
);
// for cgo/ffi
...
...
@@ -240,6 +244,7 @@ struct Stktop
// function call, which uses an off-stack argument frame.
uint8
*
fp
;
bool
free
;
// call stackfree for this frame?
bool
panic
;
// is this frame the top of a panic?
};
struct
Alg
{
...
...
@@ -311,11 +316,23 @@ struct Defer
{
int32
siz
;
byte
*
sp
;
byte
*
pc
;
byte
*
fn
;
Defer
*
link
;
byte
args
[
8
];
// padded to actual size
};
/*
* panics
*/
struct
Panic
{
Eface
arg
;
// argument to panic
byte
*
stackbase
;
// g->stackbase in panic
Panic
*
link
;
// link to earlier panic
bool
recovered
;
// whether this panic is over
};
/*
* external data
*/
...
...
@@ -400,6 +417,7 @@ void* malloc(uintptr size);
void
free
(
void
*
v
);
void
addfinalizer
(
void
*
,
void
(
*
fn
)(
void
*
),
int32
);
void
walkfintab
(
void
(
*
fn
)(
void
*
));
void
runpanic
(
Panic
*
);
void
exit
(
int32
);
void
breakpoint
(
void
);
...
...
test/golden.out
View file @
9b1507b0
...
...
@@ -190,5 +190,6 @@ bar
bal
bal
panic: barCount != 1
panic PC=xxx
BUG
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment