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
1e1cc4eb
Commit
1e1cc4eb
authored
Jan 27, 2009
by
Ken Thompson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
defer
R=r OCL=23592 CL=23592
parent
4a903e0b
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
141 additions
and
30 deletions
+141
-30
gen.c
src/cmd/6g/gen.c
+55
-16
gg.h
src/cmd/6g/gg.h
+3
-1
go.h
src/cmd/gc/go.h
+2
-1
go.y
src/cmd/gc/go.y
+6
-1
lex.c
src/cmd/gc/lex.c
+2
-2
subr.c
src/cmd/gc/subr.c
+4
-3
walk.c
src/cmd/gc/walk.c
+3
-0
proc.c
src/runtime/proc.c
+36
-1
rt0_amd64.s
src/runtime/rt0_amd64.s
+11
-1
runtime.h
src/runtime/runtime.h
+19
-4
No files found.
src/cmd/6g/gen.c
View file @
1e1cc4eb
...
...
@@ -26,6 +26,22 @@ if(newproc == N) {
newproc
->
ullman
=
1
;
}
if
(
deferproc
==
N
)
{
deferproc
=
nod
(
ONAME
,
N
,
N
);
deferproc
->
sym
=
pkglookup
(
"deferproc"
,
"sys"
);
deferproc
->
class
=
PEXTERN
;
deferproc
->
addable
=
1
;
deferproc
->
ullman
=
1
;
}
if
(
deferreturn
==
N
)
{
deferreturn
=
nod
(
ONAME
,
N
,
N
);
deferreturn
->
sym
=
pkglookup
(
"deferreturn"
,
"sys"
);
deferreturn
->
class
=
PEXTERN
;
deferreturn
->
addable
=
1
;
deferreturn
->
ullman
=
1
;
}
if
(
throwindex
==
N
)
{
throwindex
=
nod
(
ONAME
,
N
,
N
);
throwindex
->
sym
=
pkglookup
(
"throwindex"
,
"sys"
);
...
...
@@ -63,6 +79,7 @@ if(throwreturn == N) {
}
}
hasdefer
=
0
;
walk
(
curfn
);
if
(
nerrors
!=
0
)
goto
ret
;
...
...
@@ -90,6 +107,8 @@ if(throwreturn == N) {
gins
(
ACALL
,
N
,
throwreturn
);
}
if
(
hasdefer
)
gins
(
ACALL
,
N
,
deferreturn
);
pc
->
as
=
ARET
;
// overwrite AEND
pc
->
lineno
=
lineno
;
...
...
@@ -343,7 +362,11 @@ loop:
break
;
case
OPROC
:
cgen_proc
(
n
);
cgen_proc
(
n
,
1
);
break
;
case
ODEFER
:
cgen_proc
(
n
,
2
);
break
;
case
ORETURN
:
...
...
@@ -683,19 +706,26 @@ argsize(Type *t)
/*
* generate:
* call f
* if proc, generate:
* push f
* push argsize
* call newproc
* pop
* pop
* proc=0 normal call
* proc=1 goroutine run in new proc
* proc=2 defer call save away stack
*/
void
ginscall
(
Node
*
f
,
int
proc
)
{
Node
reg
,
con
;
if
(
proc
)
{
switch
(
proc
)
{
default:
fatal
(
"ginscall: bad proc %d"
,
proc
);
break
;
case
0
:
// normal call
gins
(
ACALL
,
N
,
f
);
break
;
case
1
:
// call in new proc (go)
case
2
:
// defered call (defer)
nodreg
(
&
reg
,
types
[
TINT64
],
D_AX
);
if
(
f
->
op
!=
OREGISTER
)
{
gins
(
ALEAQ
,
f
,
&
reg
);
...
...
@@ -704,12 +734,14 @@ ginscall(Node *f, int proc)
gins
(
APUSHQ
,
f
,
N
);
nodconst
(
&
con
,
types
[
TINT32
],
argsize
(
f
->
type
));
gins
(
APUSHQ
,
&
con
,
N
);
gins
(
ACALL
,
N
,
newproc
);
if
(
proc
==
1
)
gins
(
ACALL
,
N
,
newproc
);
else
gins
(
ACALL
,
N
,
deferproc
);
gins
(
APOPQ
,
N
,
&
reg
);
gins
(
APOPQ
,
N
,
&
reg
);
return
;
break
;
}
gins
(
ACALL
,
N
,
f
);
}
/*
...
...
@@ -767,6 +799,9 @@ cgen_callinter(Node *n, Node *res, int proc)
/*
* generate call to non-interface method
* proc=0 normal call
* proc=1 goroutine run in new proc
* proc=2 defer call save away stack
*/
void
cgen_callmeth
(
Node
*
n
,
int
proc
)
...
...
@@ -791,7 +826,9 @@ cgen_callmeth(Node *n, int proc)
/*
* generate function call;
* if proc, run call in new proc.
* proc=0 normal call
* proc=1 goroutine run in new proc
* proc=2 defer call save away stack
*/
void
cgen_call
(
Node
*
n
,
int
proc
)
...
...
@@ -851,22 +888,22 @@ ret:
* generate code to start new proc running call n.
*/
void
cgen_proc
(
Node
*
n
)
cgen_proc
(
Node
*
n
,
int
proc
)
{
switch
(
n
->
left
->
op
)
{
default:
fatal
(
"cgen_proc: unknown call %O"
,
n
->
left
->
op
);
case
OCALLMETH
:
cgen_callmeth
(
n
->
left
,
1
);
cgen_callmeth
(
n
->
left
,
proc
);
break
;
case
OCALLINTER
:
cgen_callinter
(
n
->
left
,
N
,
1
);
cgen_callinter
(
n
->
left
,
N
,
proc
);
break
;
case
OCALL
:
cgen_call
(
n
->
left
,
1
);
cgen_call
(
n
->
left
,
proc
);
break
;
}
...
...
@@ -947,6 +984,8 @@ void
cgen_ret
(
Node
*
n
)
{
gen
(
n
->
left
,
L
);
// copy out args
if
(
hasdefer
)
gins
(
ACALL
,
N
,
deferreturn
);
gins
(
ARET
,
N
,
N
);
}
...
...
src/cmd/6g/gg.h
View file @
1e1cc4eb
...
...
@@ -116,6 +116,8 @@ EXTERN Label* labellist;
EXTERN
Label
*
findlab
(
Sym
*
);
EXTERN
Node
*
curfn
;
EXTERN
Node
*
newproc
;
EXTERN
Node
*
deferproc
;
EXTERN
Node
*
deferreturn
;
EXTERN
Node
*
throwindex
;
EXTERN
Node
*
throwreturn
;
...
...
@@ -151,7 +153,7 @@ void cgen_ret(Node*);
void
cgen_call
(
Node
*
,
int
);
void
cgen_callmeth
(
Node
*
,
int
);
void
cgen_callinter
(
Node
*
,
Node
*
,
int
);
void
cgen_proc
(
Node
*
);
void
cgen_proc
(
Node
*
,
int
);
void
cgen_callret
(
Node
*
,
Node
*
);
void
cgen_div
(
int
,
Node
*
,
Node
*
,
Node
*
);
void
cgen_bmul
(
int
,
Node
*
,
Node
*
,
Node
*
);
...
...
src/cmd/gc/go.h
View file @
1e1cc4eb
...
...
@@ -291,7 +291,7 @@ enum
ODOT
,
ODOTPTR
,
ODOTMETH
,
ODOTINTER
,
ODCLFUNC
,
ODCLFIELD
,
ODCLARG
,
OLIST
,
OCMP
,
OPTR
,
OARRAY
,
ORANGE
,
ORETURN
,
OFOR
,
OIF
,
OSWITCH
,
ORETURN
,
OFOR
,
OIF
,
OSWITCH
,
ODEFER
,
OAS
,
OASOP
,
OCASE
,
OXCASE
,
OFALL
,
OXFALL
,
OGOTO
,
OPROC
,
OMAKE
,
ONEW
,
OEMPTY
,
OSELECT
,
OLEN
,
OCAP
,
OPANIC
,
OPANICN
,
OPRINT
,
OPRINTN
,
OTYPEOF
,
...
...
@@ -498,6 +498,7 @@ EXTERN int32 stksize; // stack size for current frame
EXTERN
int32
initstksize
;
// stack size for init function
EXTERN
ushort
blockgen
;
// max block number
EXTERN
ushort
block
;
// current block number
EXTERN
int
hasdefer
;
// flag that curfn has defer statetment
EXTERN
Node
*
retnil
;
EXTERN
Node
*
fskel
;
...
...
src/cmd/gc/go.y
View file @
1e1cc4eb
...
...
@@ -15,7 +15,7 @@
%
token
<
val
>
LLITERAL
%
token
<
lint
>
LASOP
%
token
<
sym
>
LNAME
LBASETYPE
LATYPE
LPACK
LACONST
%
token
<
sym
>
LPACKAGE
LIMPORT
L
EXPORT
%
token
<
sym
>
LPACKAGE
LIMPORT
L
DEFER
%
token
<
sym
>
LMAP
LCHAN
LINTERFACE
LFUNC
LSTRUCT
%
token
<
sym
>
LCOLAS
LFALL
LRETURN
LDDD
%
token
<
sym
>
LLEN
LCAP
LTYPEOF
LPANIC
LPANICN
LPRINT
LPRINTN
...
...
@@ -504,6 +504,11 @@ semi_stmt:
$$
=
nod
(
OCALL
,
$
2
,
$
4
);
$$
=
nod
(
OPROC
,
$$,
N
);
}
|
LDEFER
pexpr
'('
oexpr_list
')'
{
$$
=
nod
(
OCALL
,
$
2
,
$
4
);
$$
=
nod
(
ODEFER
,
$$,
N
);
}
|
LGOTO
new_name
{
$$
=
nod
(
OGOTO
,
$
2
,
N
);
...
...
src/cmd/gc/lex.c
View file @
1e1cc4eb
...
...
@@ -1056,7 +1056,7 @@ static struct
"continue"
,
LCONTINUE
,
Txxx
,
"default"
,
LDEFAULT
,
Txxx
,
"else"
,
LELSE
,
Txxx
,
"
export"
,
LEXPORT
,
Txxx
,
"
defer"
,
LDEFER
,
Txxx
,
"fallthrough"
,
LFALL
,
Txxx
,
"false"
,
LFALSE
,
Txxx
,
"for"
,
LFOR
,
Txxx
,
...
...
@@ -1275,7 +1275,7 @@ struct
LPRINT
,
"PRINT"
,
LPACKAGE
,
"PACKAGE"
,
LIMPORT
,
"IMPORT"
,
L
EXPORT
,
"EXPORT
"
,
L
DEFER
,
"DEFER
"
,
LPANIC
,
"PANIC"
,
};
...
...
src/cmd/gc/subr.c
View file @
1e1cc4eb
...
...
@@ -641,11 +641,12 @@ opnames[] =
[
ODCLARG
]
=
"DCLARG"
,
[
ODCLFIELD
]
=
"DCLFIELD"
,
[
ODCLFUNC
]
=
"DCLFUNC"
,
[
ODEFER
]
=
"DEFER"
,
[
ODIV
]
=
"DIV"
,
[
ODOT
]
=
"DOT"
,
[
ODOTPTR
]
=
"DOTPTR"
,
[
ODOTMETH
]
=
"DOTMETH"
,
[
ODOTINTER
]
=
"DOTINTER"
,
[
ODOTMETH
]
=
"DOTMETH"
,
[
ODOTPTR
]
=
"DOTPTR"
,
[
ODOT
]
=
"DOT"
,
[
OEMPTY
]
=
"EMPTY"
,
[
OEND
]
=
"END"
,
[
OEQ
]
=
"EQ"
,
...
...
src/cmd/gc/walk.c
View file @
1e1cc4eb
...
...
@@ -145,6 +145,7 @@ loop:
case
OXFALL
:
case
ORETURN
:
case
OPROC
:
case
ODEFER
:
walktype
(
n
,
Etop
);
break
;
}
...
...
@@ -342,6 +343,8 @@ loop:
walkstate
(
n
->
nelse
);
goto
ret
;
case
ODEFER
:
hasdefer
=
1
;
case
OPROC
:
if
(
top
!=
Etop
)
goto
nottop
;
...
...
src/runtime/proc.c
View file @
1e1cc4eb
...
...
@@ -171,7 +171,7 @@ sys·newproc(int32 siz, byte* fn, byte* arg0)
if
((
newg
=
gfget
())
!=
nil
){
newg
->
status
=
Gwaiting
;
}
else
{
}
else
{
newg
=
malg
(
4096
);
newg
->
status
=
Gwaiting
;
newg
->
alllink
=
allg
;
...
...
@@ -204,6 +204,41 @@ sys·newproc(int32 siz, byte* fn, byte* arg0)
//printf(" goid=%d\n", newg->goid);
}
void
sys
·
deferproc
(
int32
siz
,
byte
*
fn
,
byte
*
arg0
)
{
Defer
*
d
;
d
=
mal
(
sizeof
(
*
d
)
+
siz
-
sizeof
(
d
->
args
));
d
->
fn
=
fn
;
d
->
sp
=
(
byte
*
)
&
arg0
;
d
->
siz
=
siz
;
mcpy
(
d
->
args
,
d
->
sp
,
d
->
siz
);
d
->
link
=
g
->
defer
;
g
->
defer
=
d
;
}
void
sys
·
deferreturn
(
int32
arg0
)
{
// warning: jmpdefer knows the frame size
// of this routine. dont change anything
// that might change the frame size
Defer
*
d
;
byte
*
sp
;
d
=
g
->
defer
;
if
(
d
==
nil
)
return
;
sp
=
(
byte
*
)
&
arg0
;
if
(
d
->
sp
!=
sp
)
return
;
mcpy
(
d
->
sp
,
d
->
args
,
d
->
siz
);
g
->
defer
=
d
->
link
;
jmpdefer
(
d
->
fn
);
}
void
tracebackothers
(
G
*
me
)
{
...
...
src/runtime/rt0_amd64.s
View file @
1e1cc4eb
...
...
@@ -120,7 +120,7 @@ TEXT setspgoto(SB), 7, $0
// if(*val == old){
// *val = new;
// return 1;
// }else
// }
else
// return 0;
TEXT cas(SB), 7, $0
MOVQ 8(SP), BX
...
...
@@ -133,3 +133,13 @@ TEXT cas(SB), 7, $0
RET
MOVL $1, AX
RET
// void jmpdefer(byte*);
// 1. pop the caller
// 2. sub 5 bytes from the callers return
// 3. jmp to the argument
TEXT jmpdefer(SB), 7, $0
MOVQ 8(SP), AX // function
ADDQ $(8+56), SP // pop saved PC and callers frame
SUBQ $5, (SP) // reposition his return address
JMP AX // and goto function
src/runtime/runtime.h
View file @
1e1cc4eb
...
...
@@ -52,6 +52,7 @@ typedef struct SigTab SigTab;
typedef
struct
MCache
MCache
;
typedef
struct
Iface
Iface
;
typedef
struct
Itype
Itype
;
typedef
struct
Defer
Defer
;
/*
* per cpu declaration
...
...
@@ -128,6 +129,7 @@ struct G
{
byte
*
stackguard
;
// must not move
byte
*
stackbase
;
// must not move
Defer
*
defer
;
// must not move
byte
*
stack0
;
// first stack segment
Gobuf
sched
;
G
*
alllink
;
// on allg
...
...
@@ -136,8 +138,8 @@ struct G
int32
goid
;
int32
selgen
;
// valid sudog pointer
G
*
schedlink
;
bool
readyonstop
;
M
*
m
;
// for debuggers
bool
readyonstop
;
M
*
m
;
// for debuggers
};
struct
Mem
{
...
...
@@ -151,8 +153,8 @@ struct M
G
*
g0
;
// g0 w interrupt stack - must not move
uint64
morearg
;
// arg to morestack - must not move
uint64
cret
;
// return value from C - must not move
uint64
procid
;
// for debuggers - must not move
G
*
gsignal
;
// signal-handling G - must not move
uint64
procid
;
// for debuggers - must not move
G
*
gsignal
;
// signal-handling G - must not move
G
*
curg
;
// current running goroutine
G
*
lastg
;
// last running goroutine - to emulate fifo
Gobuf
sched
;
...
...
@@ -235,6 +237,18 @@ enum
Amax
};
/*
* defered subroutine calls
*/
struct
Defer
{
int32
siz
;
byte
*
sp
;
byte
*
fn
;
Defer
*
link
;
byte
args
[
8
];
// padded to actual size
};
/*
* external data
*/
...
...
@@ -286,6 +300,7 @@ int32 write(int32, void*, int32);
void
close
(
int32
);
int32
fstat
(
int32
,
void
*
);
bool
cas
(
uint32
*
,
uint32
,
uint32
);
void
jmpdefer
(
byte
*
);
void
exit1
(
int32
);
void
ready
(
G
*
);
byte
*
getenv
(
int8
*
);
...
...
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