newproc = nod(ONAME, N, N);
memset(newproc, 0, sizeof(*newproc));
newproc->op = ONAME;
- newproc->sym = pkglookup("_newproc", "sys");
+ newproc->sym = pkglookup("newproc", "sys");
newproc->class = PEXTERN;
newproc->addable = 1;
newproc->ullman = 0;
if(proc) {
nodreg(®, types[TINT64], D_AX);
gins(ALEAQ, f, ®);
- nodreg(®, types[TINT64], D_BX);
+ gins(APUSHQ, ®, N);
nodconst(&con, types[TINT32], argsize(f->type));
- gins(AMOVL, &con, ®);
+ gins(APUSHQ, &con, N);
gins(ACALL, N, newproc);
+ gins(APOPQ, N, ®);
+ gins(APOPQ, N, ®);
return;
}
gins(ACALL, N, f);
Sym *symmorestack;
pmorestack = P;
- symmorestack = lookup("_morestack", 0);
+ symmorestack = lookup("sys·morestack", 0);
if(symmorestack->type == STEXT)
for(p = firstp; p != P; p = p->link) {
if(p->as == ATEXT) {
if(p->from.sym == symmorestack) {
pmorestack = p;
+ p->from.scale |= NOSPLIT;
break;
}
}
}
if(pmorestack == P)
- diag("_morestack not defined");
+ diag("sys·morestack not defined");
curframe = 0;
curbecome = 0;
p = appendp(p);
p->as = AJHI;
p->to.type = D_BRANCH;
- p->to.offset = 3;
+ p->to.offset = 4;
q = p;
p = appendp(p);
p->from.offset = (autoffset+160) & ~7LL;
p->from.offset |= textarg<<32;
+ p = appendp(p);
+ p->as = AMOVQ;
+ p->from.type = D_AX;
+ p->to.type = D_INDIR+D_R14;
+ p->to.offset = 8;
+
p = appendp(p);
p->as = ACALL;
p->to.type = D_BRANCH;
func mapassign1(hmap *map[any]any, key any, val any);
func mapassign2(hmap *map[any]any, key any, val any, pres bool);
+func gosched();
+func goexit();
+
func readfile(string) (string, bool); // read file into string; boolean status
func bytestorune(*byte, int32, int32) (int32, int32); // convert bytes to runes
func stringtorune(string, int32, int32) (int32, int32); // convert bytes to runes
mapassign1
mapassign2
+ // go routines
+ gosched
+ goexit
+
// files
readfile
"type sys._esys_089 (sys._esys_090 sys._esys_091 sys._isys_489)\n"
"var !sys.mapassign2 sys._esys_089\n"
"type sys._esys_095 {}\n"
- "type sys._osys_499 {_esys_496 sys.string _esys_497 sys.bool}\n"
- "type sys._isys_501 {_esys_498 sys.string}\n"
- "type sys._esys_094 (sys._esys_095 sys._osys_499 sys._isys_501)\n"
- "var !sys.readfile sys._esys_094\n"
+ "type sys._esys_096 {}\n"
"type sys._esys_097 {}\n"
- "type sys._osys_510 {_esys_505 sys.int32 _esys_506 sys.int32}\n"
- "type sys._esys_098 *sys.uint8\n"
- "type sys._isys_512 {_esys_507 sys._esys_098 _esys_508 sys.int32 _esys_509 sys.int32}\n"
- "type sys._esys_096 (sys._esys_097 sys._osys_510 sys._isys_512)\n"
- "var !sys.bytestorune sys._esys_096\n"
+ "type sys._esys_094 (sys._esys_095 sys._esys_096 sys._esys_097)\n"
+ "var !sys.gosched sys._esys_094\n"
+ "type sys._esys_099 {}\n"
"type sys._esys_100 {}\n"
- "type sys._osys_523 {_esys_518 sys.int32 _esys_519 sys.int32}\n"
- "type sys._isys_525 {_esys_520 sys.string _esys_521 sys.int32 _esys_522 sys.int32}\n"
- "type sys._esys_099 (sys._esys_100 sys._osys_523 sys._isys_525)\n"
- "var !sys.stringtorune sys._esys_099\n"
- "type sys._esys_102 {}\n"
+ "type sys._esys_101 {}\n"
+ "type sys._esys_098 (sys._esys_099 sys._esys_100 sys._esys_101)\n"
+ "var !sys.goexit sys._esys_098\n"
"type sys._esys_103 {}\n"
- "type sys._isys_532 {_esys_531 sys.int32}\n"
- "type sys._esys_101 (sys._esys_102 sys._esys_103 sys._isys_532)\n"
- "var !sys.exit sys._esys_101\n"
+ "type sys._osys_501 {_esys_498 sys.string _esys_499 sys.bool}\n"
+ "type sys._isys_503 {_esys_500 sys.string}\n"
+ "type sys._esys_102 (sys._esys_103 sys._osys_501 sys._isys_503)\n"
+ "var !sys.readfile sys._esys_102\n"
+ "type sys._esys_105 {}\n"
+ "type sys._osys_512 {_esys_507 sys.int32 _esys_508 sys.int32}\n"
+ "type sys._esys_106 *sys.uint8\n"
+ "type sys._isys_514 {_esys_509 sys._esys_106 _esys_510 sys.int32 _esys_511 sys.int32}\n"
+ "type sys._esys_104 (sys._esys_105 sys._osys_512 sys._isys_514)\n"
+ "var !sys.bytestorune sys._esys_104\n"
+ "type sys._esys_108 {}\n"
+ "type sys._osys_525 {_esys_520 sys.int32 _esys_521 sys.int32}\n"
+ "type sys._isys_527 {_esys_522 sys.string _esys_523 sys.int32 _esys_524 sys.int32}\n"
+ "type sys._esys_107 (sys._esys_108 sys._osys_525 sys._isys_527)\n"
+ "var !sys.stringtorune sys._esys_107\n"
+ "type sys._esys_110 {}\n"
+ "type sys._esys_111 {}\n"
+ "type sys._isys_534 {_esys_533 sys.int32}\n"
+ "type sys._esys_109 (sys._esys_110 sys._esys_111 sys._isys_534)\n"
+ "var !sys.exit sys._esys_109\n"
"))\n"
;
// allocate the per-user and per-mach blocks
- LEAQ peruser<>(SB), R15 // dedicated u. register
- LEAQ permach<>(SB), R14 // dedicated m. register
+ LEAQ m0<>(SB), R14 // dedicated m. register
+ LEAQ g0(SB), R15 // dedicated g. register
+ MOVQ R15, 0(R14) // m has pointer to its g0
- LEAQ (-4096+104+4*8)(SP), AX
- MOVQ AX, 0(R15) // 0(R15) is stack limit (w 104b guard)
-
- MOVL $1024, AX
- MOVL AX, 0(SP)
- CALL mal(SB)
-
- LEAQ 104(AX), BX
- MOVQ BX, 0(R14) // 0(R14) is limit of istack (w 104b guard)
+ // create istack out of the given (operating system) stack
- ADDQ 0(SP), AX
- LEAQ (-4*8)(AX), BX
- MOVQ BX, 8(R14) // 8(R14) is base of istack (w auto*4)
+ LEAQ (-1024+104)(SP), AX
+ MOVQ AX, 0(R15) // 0(R15) is stack limit (w 104b guard)
+ MOVQ SP, 8(R15) // 8(R15) is base
CALL check(SB)
- // process the arguments
-
MOVL 16(SP), AX // copy argc
MOVL AX, 0(SP)
MOVQ 24(SP), AX // copy argv
MOVQ AX, 8(SP)
CALL args(SB)
- CALL main·main(SB)
+ // create a new goroutine to start program
- MOVQ $0, AX
- MOVQ AX, 0(SP) // exit status
- CALL sys·exit(SB)
+ PUSHQ $main·main(SB) // entry
+ PUSHQ $16 // arg size
+ CALL sys·newproc(SB)
+ CALL gom0init(SB)
+ POPQ AX
+ POPQ AX
- CALL notok(SB) // fault
+ CALL notok(SB) // never returns
RET
-//
-// the calling sequence for a routine that
-// needs N bytes stack, A args.
-//
-// N1 = (N+160 > 4096)? N+160: 0
-// A1 = A
-//
-// if N <= 75
-// CMPQ SP, 0(R15)
-// JHI 3(PC)
-// MOVQ $(N1<<0) | (A1<<32)), AX
-// CALL _morestack
-//
-// if N > 75
-// LEAQ (-N-75)(SP), AX
-// CMPQ AX, 0(R15)
-// JHI 3(PC)
-// MOVQ $(N1<<0) | (A1<<32)), AX
-// CALL _morestack
-//
-
-TEXT _morestack(SB), 7, $0
- // save stuff on interrupt stack
-
- MOVQ 8(R14), BX // istack
- MOVQ SP, 8(BX) // old SP
- MOVQ AX, 16(BX) // magic number
- MOVQ 0(R15), AX // old limit
- MOVQ AX, 24(BX)
-
- // switch and set up new limit
-
- MOVQ BX, SP
- MOVQ 0(R14), AX // istack limit
- MOVQ AX, 0(R15)
-
- // allocate a new stack max of request and 4k
-
- MOVL 16(SP), AX // magic number
- CMPL AX, $4096
- JHI 2(PC)
- MOVL $4096, AX
- MOVL AX, 0(SP)
- CALL mal(SB)
-
- // switch to new stack
-
- MOVQ SP, BX // istack
- ADDQ $104, AX // new stack limit
- MOVQ AX, 0(R15)
- ADDQ 0(SP), AX
- LEAQ (-104-4*8)(AX), SP // new SP
- MOVQ 8(R15), AX
- MOVQ AX, 0(SP) // old base
- MOVQ SP, 8(R15) // new base
-
- // copy needed stuff from istack to new stack
-
- MOVQ 16(BX), AX // magic number
- MOVQ AX, 16(SP)
- MOVQ 24(BX), AX // old limit
- MOVQ AX, 24(SP)
- MOVQ 8(BX), AX // old SP
- MOVQ AX, 8(SP)
-
-// are there parameters
-
- MOVL 20(SP), CX // copy count
- CMPL CX, $0
- JEQ easy
-
-// copy in
-
- LEAQ 16(AX), SI
- SUBQ CX, SP
- MOVQ SP, DI
- SHRL $3, CX
- CLD
- REP
- MOVSQ
-
- // call the intended
- CALL 0(AX)
-
-// copy out
-
- MOVQ SP, SI
- MOVQ 8(R15), BX // new base
- MOVQ 8(BX), AX // old SP
- LEAQ 16(AX), DI
- MOVL 20(BX), CX // copy count
- SHRL $3, CX
- CLD
- REP
- MOVSQ
-
- // restore old SP and limit
- MOVQ 8(R15), SP // new base
- MOVQ 24(SP), AX // old limit
- MOVQ AX, 0(R15)
- MOVQ 0(SP), AX
- MOVQ AX, 8(R15) // old base
- MOVQ 8(SP), AX // old SP
- MOVQ AX, SP
-
- // and return to the call behind mine
- ADDQ $8, SP
+TEXT sys·breakpoint(SB),7,$-8
+ BYTE $0xcc
RET
-easy:
- CALL 0(AX)
-
- // restore old SP and limit
- MOVQ 24(SP), AX // old limit
- MOVQ AX, 0(R15)
- MOVQ 0(SP), AX
- MOVQ AX, 8(R15) // old base
- MOVQ 8(SP), AX // old SP
- MOVQ AX, SP
-
- // and return to the call behind mine
- ADDQ $8, SP
+TEXT _morestack(SB), 7, $-8
+ BYTE $0xcc
RET
// marker. must be here; used by traceback() to discover calls to _morestack
TEXT _endmorestack(SB), 7, $-8
RET
-// call a subroutine in a new coroutine
-// argument list is on the stack
-// addr of fn is in AX
-TEXT sys·_newproc(SB), 7, $0
- // save stuff on interrupt stack
-
- MOVQ 8(R14), CX // istack
- MOVQ AX, 0(CX) // fn pointer
- MOVQ BX, 8(CX) // arg size
- MOVQ SP, 16(CX) // old SP
- MOVQ 0(R15), AX // old limit
- MOVQ AX, 24(CX)
-
- // switch and set up new limit
-
- MOVQ CX, SP
- MOVQ 0(R14), AX // istack limit
- MOVQ AX, 0(R15)
-
- CALL _newproc(SB)
-
- // restore old SP and limit
-
- MOVQ 24(SP), AX // old limit
- MOVQ AX, 0(R15)
- MOVQ 16(SP), AX // old SP
- MOVQ AX, SP
+TEXT FLUSH(SB),7,$-8
+ RET
+/*
+ * go-routine
+ */
+TEXT gogo(SB), 7, $0
+ MOVQ 8(SP), AX // gobuf
+ MOVQ 0(AX), SP // restore SP
+ MOVQ 8(AX), AX
+ MOVQ AX, 0(SP) // put PC on the stack
+ MOVL $1, AX // return 1
RET
-TEXT FLUSH(SB),7,$-8
+TEXT gosave(SB), 7, $0
+ MOVQ 8(SP), AX // gobuf
+ MOVQ SP, 0(AX) // save SP
+ MOVQ 0(SP), BX
+ MOVQ BX, 8(AX) // save PC
+ MOVL $0, AX // return 0
RET
-TEXT getu(SB),7,$-8
- MOVQ R15, AX
+TEXT setspgoto(SB), 7, $0
+ MOVQ 8(SP), AX // SP
+ MOVQ 16(SP), BX // fn to call
+ MOVQ 24(SP), CX // fn to return
+ MOVQ AX, SP
+ PUSHQ CX
+ JMP BX
+ POPQ AX
RET
-GLOBL permach<>(SB),$64
-GLOBL peruser<>(SB),$64
+GLOBL m0<>(SB),$64
static int8 spmark[] = "\xa7\xf1\xd9\x2a\x82\xc8\xd8\xfe";
-//typedef struct U U;
-//struct U {
-// uint8* stackguard;
-// uint8* stackbase;
-// uint8* istackguard;
-// uint8* istackbase;
-//};
-
-typedef struct Stktop Stktop;
-struct Stktop {
- uint8* oldbase;
- uint8* oldsp;
- uint8* magic;
- uint8* oldguard;
-};
-
extern void _morestack();
extern void _endmorestack();
#include "runtime.h"
+G g0; // idle goroutine
int32 debug = 0;
-/*BUG: move traceback code to architecture-dependent runtime */
void
sys·panicl(int32 lno)
{
sys·printpc(&lno);
prints("\n");
sp = (uint8*)&lno;
- traceback(sys·getcallerpc(&lno), sp, getu());
+ traceback(sys·getcallerpc(&lno), sp, g);
sys·breakpoint();
sys·exit(2);
}
initsig();
}
-extern register u;
-uint32 a;
+void
+sys·goexit(void)
+{
+//prints("goexit goid=");
+//sys·printint(g->goid);
+//prints("\n");
+ g->status = Gdead;
+ sys·gosched();
+}
void
-_newproc(byte* fn, int32 siz, byte* args)
+sys·newproc(int32 siz, byte* fn, byte* arg0)
{
- a = u;
+ byte *stk, *sp;
+ G *newg;
- prints("_newproc fn=");
- sys·printpointer(fn);
- prints("; siz=");
- sys·printint(siz);
- prints("; args=");
- sys·printpointer(args);
- prints("\n");
- dump(args, 32);
+//prints("newproc siz=");
+//sys·printint(siz);
+//prints(" fn=");
+//sys·printpointer(fn);
+
+ siz = (siz+7) & ~7;
+ if(siz > 1024) {
+ prints("sys·newproc: too many args: ");
+ sys·printint(siz);
+ prints("\n");
+ sys·panicl(123);
+ }
+
+ newg = mal(sizeof(G));
+ stk = mal(4096);
+ newg->stackguard = stk+160;
+
+ sp = stk + 4096 - 4*8;
+ newg->stackbase = sp;
+
+ sp -= siz;
+ mcpy(sp, (byte*)&arg0, siz);
+
+ sp -= 8;
+ *(byte**)sp = (byte*)sys·goexit;
+
+ sp -= 8; // retpc used by gogo
+ newg->sched.SP = sp;
+ newg->sched.PC = fn;
+
+ goidgen++;
+ newg->goid = goidgen;
+
+ newg->status = Grunnable;
+ newg->link = allg;
+ allg = newg;
+
+//prints(" goid=");
+//sys·printint(newg->goid);
+//prints("\n");
+}
+
+G*
+select(void)
+{
+ G *gp, *bestg;
+
+ bestg = nil;
+ for(gp=allg; gp!=nil; gp=gp->link) {
+ if(gp->status != Grunnable)
+ continue;
+ if(bestg == nil || gp->pri < bestg->pri)
+ bestg = gp;
+ }
+ if(bestg != nil)
+ bestg->pri++;
+ return bestg;
+}
+
+void
+gom0init(void)
+{
+ gosave(&m->sched);
+ sys·gosched();
+}
+
+void
+sys·gosched(void)
+{
+ G* gp;
+
+ if(g != m->g0) {
+ if(gosave(&g->sched))
+ return;
+ g = m->g0;
+ gogo(&m->sched);
+ }
+ gp = select();
+ if(gp == nil) {
+// prints("sched: no more work\n");
+ sys·exit(0);
+ }
+
+ m->curg = gp;
+ g = gp;
+ gogo(&gp->sched);
+}
+
+//
+// the calling sequence for a routine that
+// needs N bytes stack, A args.
+//
+// N1 = (N+160 > 4096)? N+160: 0
+// A1 = A
+//
+// if N <= 75
+// CMPQ SP, 0(R15)
+// JHI 4(PC)
+// MOVQ $(N1<<0) | (A1<<32)), AX
+// MOVQ AX, 0(R14)
+// CALL sys·morestack(SB)
+//
+// if N > 75
+// LEAQ (-N-75)(SP), AX
+// CMPQ AX, 0(R15)
+// JHI 4(PC)
+// MOVQ $(N1<<0) | (A1<<32)), AX
+// MOVQ AX, 0(R14)
+// CALL sys·morestack(SB)
+//
+
+int32 debug = 0;
+
+void
+morestack2(void)
+{
+ Stktop *top;
+ uint32 siz2;
+ byte *sp;
+if(debug) prints("morestack2\n");
+
+ top = (Stktop*)m->curg->stackbase;
+
+ m->curg->stackbase = top->oldbase;
+ m->curg->stackguard = top->oldguard;
+ siz2 = (top->magic>>32) & 0xffffLL;
+
+ sp = (byte*)top;
+ if(siz2 > 0) {
+ siz2 = (siz2+7) & ~7;
+ sp -= siz2;
+ mcpy(top->oldsp+16, sp, siz2);
+ }
+
+ m->morestack.SP = top->oldsp+8;
+ m->morestack.PC = (byte*)(*(uint64*)(top->oldsp+8));
+if(debug) prints("morestack2 sp=");
+if(debug) sys·printpointer(m->morestack.SP);
+if(debug) prints(" pc=");
+if(debug) sys·printpointer(m->morestack.PC);
+if(debug) prints("\n");
+ gogo(&m->morestack);
+}
+
+void
+morestack1(void)
+{
+ int32 siz1, siz2;
+ Stktop *top;
+ byte *stk, *sp;
+ void (*fn)(void);
+
+ siz1 = m->morearg & 0xffffffffLL;
+ siz2 = (m->morearg>>32) & 0xffffLL;
+
+if(debug) prints("morestack1 siz1=");
+if(debug) sys·printint(siz1);
+if(debug) prints(" siz2=");
+if(debug) sys·printint(siz2);
+if(debug) prints(" moresp=");
+if(debug) sys·printpointer(m->moresp);
+if(debug) prints("\n");
+
+ if(siz1 < 4096)
+ siz1 = 4096;
+ stk = mal(siz1 + 1024);
+ stk += 512;
+
+ top = (Stktop*)(stk+siz1-sizeof(*top));
+
+ top->oldbase = m->curg->stackbase;
+ top->oldguard = m->curg->stackguard;
+ top->oldsp = m->moresp;
+ top->magic = m->morearg;
+
+ m->curg->stackbase = (byte*)top;
+ m->curg->stackguard = stk + 160;
+
+ sp = (byte*)top;
+
+ if(siz2 > 0) {
+ siz2 = (siz2+7) & ~7;
+ sp -= siz2;
+ mcpy(sp, m->moresp+16, siz2);
+ }
+
+ g = m->curg;
+ fn = (void(*)(void))(*(uint64*)m->moresp);
+if(debug) prints("fn=");
+if(debug) sys·printpointer(fn);
+if(debug) prints("\n");
+ setspgoto(sp, fn, morestack2);
+
+ *(int32*)345 = 123;
+}
+
+void
+sys·morestack(uint64 u)
+{
+ while(g == m->g0) {
+ // very bad news
+ *(int32*)123 = 123;
+ }
+
+ g = m->g0;
+ m->moresp = (byte*)(&u-1);
+ setspgoto(m->sched.SP, morestack1, nil);
+
+ *(int32*)234 = 123;
}
int32 unused;
void (*fun[])(void);
};
+typedef struct Gobuf Gobuf;
+struct Gobuf
+{
+ byte* SP;
+ byte* PC;
+};
typedef struct G G;
struct G
{
byte* stackguard; // must not move
byte* stackbase; // must not move
- G* ufor; // dbl ll of all u
- G* ubak;
- G* runqfor; // dbl ll of runnable
- G* runqbak;
+ Gobuf sched;
+ G* link;
+ int32 status;
+ int32 pri;
+ int32 goid;
};
typedef struct M M;
struct M
{
- byte* istackguard; // must not move
- byte* istackbase; // must not move
+ G* g0; // g0 w interrupt stack - must not move
+ uint64 morearg; // arg to morestack - must not move
+ G* curg; // current running goroutine
+ Gobuf sched;
+ Gobuf morestack;
+ byte* moresp;
+ int32 siz1;
+ int32 siz2;
+};
+typedef struct Stktop Stktop;
+struct Stktop {
+ uint8* oldbase;
+ uint8* oldsp;
+ uint64 magic;
+ uint8* oldguard;
};
extern register G* g; // R15
extern register M* m; // R14
+enum
+{
+ // G status
+ Gidle,
+ Grunnable,
+ Gdead,
+};
+
/*
* global variables
*/
M* allm;
-G* allu;
-G* runq;
+G* allg;
+int32 goidgen;
/*
* defined constants
/*
* common functions and data
*/
-int32 strcmp(byte*, byte*);
-int32 findnull(int8*);
+int32 strcmp(byte*, byte*);
+int32 findnull(int8*);
void dump(byte*, int32);
-int32 runetochar(byte*, int32);
-int32 chartorune(uint32*, byte*);
+int32 runetochar(byte*, int32);
+int32 chartorune(uint32*, byte*);
extern string emptystring;
-extern int32 debug;
+extern int32 debug;
/*
* very low level c-called
*/
+int32 gogo(Gobuf*);
+int32 gosave(Gobuf*);
+void setspgoto(byte*, void(*)(void), void(*)(void));
void FLUSH(void*);
void* getu(void);
void throw(int8*);
void* mal(uint32);
uint32 cmpstring(string, string);
void initsig(void);
-void traceback(uint8 *pc, uint8 *sp, void* up);
+void traceback(uint8 *pc, uint8 *sp, G* gp);
int32 open(byte*, int32);
int32 read(int32, void*, int32);
void close(int32);
/*
* low level go -called
*/
+void sys·goexit(void);
+void sys·gosched(void);
void sys·exit(int32);
void sys·write(int32, void*, int32);
void sys·breakpoint(void);
CALL sighandler(SB)
RET
-TEXT sys·breakpoint(SB),1,$-8
- BYTE $0xcc
- RET
-
TEXT sys·mmap(SB),1,$-8
MOVQ 8(SP), DI // arg 1 addr
MOVL 16(SP), SI // arg 2 len
CALL sighandler(SB)
RET
-TEXT sys·breakpoint(SB),1,$-8
- BYTE $0xcc
- RET
-
TEXT sys·mmap(SB),1,$-8
MOVQ 8(SP), DI
MOVL 16(SP), SI