aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r--src/pkg/runtime/arm/asm.s10
-rw-r--r--src/pkg/runtime/cgocall.c3
-rw-r--r--src/pkg/runtime/chan.c44
-rw-r--r--src/pkg/runtime/iface.c33
-rw-r--r--src/pkg/runtime/malloc.goc3
-rw-r--r--src/pkg/runtime/proc.c24
-rw-r--r--src/pkg/runtime/runtime.c1
-rw-r--r--src/pkg/runtime/runtime.h82
-rw-r--r--src/pkg/runtime/stack.h86
9 files changed, 173 insertions, 113 deletions
diff --git a/src/pkg/runtime/arm/asm.s b/src/pkg/runtime/arm/asm.s
index a4e4b32836..93c4d4cd16 100644
--- a/src/pkg/runtime/arm/asm.s
+++ b/src/pkg/runtime/arm/asm.s
@@ -12,10 +12,10 @@ TEXT _rt0_arm(SB),7,$-4
// use R13 instead of SP to avoid linker rewriting the offsets
MOVW 0(R13), R0 // argc
MOVW $4(R13), R1 // argv
- SUB $128, R13 // plenty of scratch
+ SUB $64, R13 // plenty of scratch
AND $~7, R13
- MOVW R0, 120(R13) // save argc, argv away
- MOVW R1, 124(R13)
+ MOVW R0, 60(R13) // save argc, argv away
+ MOVW R1, 64(R13)
// set up m and g registers
// g is R10, m is R9
@@ -34,9 +34,9 @@ TEXT _rt0_arm(SB),7,$-4
BL runtime·check(SB)
// saved argc, argv
- MOVW 120(R13), R0
+ MOVW 60(R13), R0
MOVW R0, 4(R13)
- MOVW 124(R13), R1
+ MOVW 64(R13), R1
MOVW R1, 8(R13)
BL runtime·args(SB)
BL runtime·osinit(SB)
diff --git a/src/pkg/runtime/cgocall.c b/src/pkg/runtime/cgocall.c
index 74e5a30857..741e8f0b8c 100644
--- a/src/pkg/runtime/cgocall.c
+++ b/src/pkg/runtime/cgocall.c
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "stack.h"
#include "cgocall.h"
void *initcgo; /* filled in by dynamic linker when Cgo is available */
@@ -70,7 +71,7 @@ runtime·cgocallback(void (*fn)(void), void *arg, int32 argsize)
runtime·startcgocallback(g1);
sp = g1->sched.sp - argsize;
- if(sp < g1->stackguard - StackGuard + 8) // +8 for return address
+ if(sp < g1->stackguard - StackGuard - StackSystem + 8) // +8 for return address
runtime·throw("g stack overflow in cgocallback");
runtime·mcpy(sp, arg, argsize);
diff --git a/src/pkg/runtime/chan.c b/src/pkg/runtime/chan.c
index 8d3ac2ca4f..28c7d7320a 100644
--- a/src/pkg/runtime/chan.c
+++ b/src/pkg/runtime/chan.c
@@ -495,17 +495,27 @@ runtime·selectnbrecv(byte *v, Hchan *c, bool ok)
runtime·chanrecv(c, v, &ok, nil);
}
+static void newselect(int32, Select**);
+
// newselect(size uint32) (sel *byte);
#pragma textflag 7
void
runtime·newselect(int32 size, ...)
{
- int32 n, o;
+ int32 o;
Select **selp;
- Select *sel;
o = runtime·rnd(sizeof(size), Structrnd);
selp = (Select**)((byte*)&size + o);
+ newselect(size, selp);
+}
+
+static void
+newselect(int32 size, Select **selp)
+{
+ int32 n;
+ Select *sel;
+
n = 0;
if(size > 1)
n = size-1;
@@ -589,21 +599,31 @@ runtime·selectrecv(Select *sel, Hchan *c, ...)
}
-// selectdefaul(sel *byte) (selected bool);
+static void selectdefault(Select**);
+
+// selectdefault(sel *byte) (selected bool);
#pragma textflag 7
void
runtime·selectdefault(Select *sel, ...)
{
+ selectdefault(&sel);
+}
+
+static void
+selectdefault(Select **selp)
+{
+ Select *sel;
int32 i;
Scase *cas;
+ sel = *selp;
i = sel->ncase;
if(i >= sel->tcase)
runtime·throw("selectdefault: too many cases");
sel->ncase = i+1;
cas = runtime·mal(sizeof *cas);
sel->scase[i] = cas;
- cas->pc = runtime·getcallerpc(&sel);
+ cas->pc = runtime·getcallerpc(selp);
cas->chan = nil;
cas->so = runtime·rnd(sizeof(sel), Structrnd);
@@ -662,16 +682,23 @@ runtime·block(void)
runtime·gosched();
}
+static void selectgo(Select**);
+
// selectgo(sel *byte);
//
// overwrites return pc on stack to signal which case of the select
// to run, so cannot appear at the top of a split stack.
-// frame has 6 pointers and 4 int32 so 64 bytes max.
-// that's less than StackGuard-StackSmall, so okay.
#pragma textflag 7
void
runtime·selectgo(Select *sel)
{
+ selectgo(&sel);
+}
+
+static void
+selectgo(Select **selp)
+{
+ Select *sel;
uint32 o, i, j;
Scase *cas, *dfl;
Hchan *c;
@@ -679,6 +706,7 @@ runtime·selectgo(Select *sel)
G *gp;
byte *as;
+ sel = *selp;
if(runtime·gcwaiting)
runtime·gosched();
@@ -889,8 +917,8 @@ retc:
selunlock(sel);
// return to pc corresponding to chosen case
- runtime·setcallerpc(&sel, cas->pc);
- as = (byte*)&sel + cas->so;
+ runtime·setcallerpc(selp, cas->pc);
+ as = (byte*)selp + cas->so;
freesel(sel);
*as = true;
return;
diff --git a/src/pkg/runtime/iface.c b/src/pkg/runtime/iface.c
index 3dec45e2b8..698aead3df 100644
--- a/src/pkg/runtime/iface.c
+++ b/src/pkg/runtime/iface.c
@@ -209,16 +209,25 @@ runtime·convT2E(Type *t, ...)
copyin(t, elem, &ret->data);
}
+static void assertI2Tret(Type *t, Iface i, byte *ret);
+
// func ifaceI2T(typ *byte, iface any) (ret any)
#pragma textflag 7
void
runtime·assertI2T(Type *t, Iface i, ...)
{
- Itab *tab;
byte *ret;
- Eface err;
ret = (byte*)(&i+1);
+ assertI2Tret(t, i, ret);
+}
+
+static void
+assertI2Tret(Type *t, Iface i, byte *ret)
+{
+ Itab *tab;
+ Eface err;
+
tab = i.tab;
if(tab == nil) {
runtime·newTypeAssertionError(nil, nil, t,
@@ -258,15 +267,23 @@ runtime·assertI2T2(Type *t, Iface i, ...)
copyout(t, &i.data, ret);
}
+static void assertE2Tret(Type *t, Eface e, byte *ret);
+
// func ifaceE2T(typ *byte, iface any) (ret any)
#pragma textflag 7
void
runtime·assertE2T(Type *t, Eface e, ...)
{
byte *ret;
- Eface err;
ret = (byte*)(&e+1);
+ assertE2Tret(t, e, ret);
+}
+
+static void
+assertE2Tret(Type *t, Eface e, byte *ret)
+{
+ Eface err;
if(e.type == nil) {
runtime·newTypeAssertionError(nil, nil, t,
@@ -307,7 +324,6 @@ runtime·assertE2T2(Type *t, Eface e, ...)
}
// func convI2E(elem any) (ret any)
-#pragma textflag 7
void
runtime·convI2E(Iface i, Eface ret)
{
@@ -322,7 +338,6 @@ runtime·convI2E(Iface i, Eface ret)
}
// func ifaceI2E(typ *byte, iface any) (ret any)
-#pragma textflag 7
void
runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
{
@@ -343,7 +358,6 @@ runtime·assertI2E(InterfaceType* inter, Iface i, Eface ret)
}
// func ifaceI2E2(typ *byte, iface any) (ret any, ok bool)
-#pragma textflag 7
void
runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
{
@@ -364,7 +378,6 @@ runtime·assertI2E2(InterfaceType* inter, Iface i, Eface ret, bool ok)
}
// func convI2I(typ *byte, elem any) (ret any)
-#pragma textflag 7
void
runtime·convI2I(InterfaceType* inter, Iface i, Iface ret)
{
@@ -399,7 +412,6 @@ runtime·ifaceI2I(InterfaceType *inter, Iface i, Iface *ret)
}
// func ifaceI2I(sigi *byte, iface any) (ret any)
-#pragma textflag 7
void
runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret)
{
@@ -407,7 +419,6 @@ runtime·assertI2I(InterfaceType* inter, Iface i, Iface ret)
}
// func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool)
-#pragma textflag 7
void
runtime·assertI2I2(InterfaceType *inter, Iface i, Iface ret, bool ok)
{
@@ -446,7 +457,6 @@ runtime·ifaceE2I(InterfaceType *inter, Eface e, Iface *ret)
}
// func ifaceE2I(sigi *byte, iface any) (ret any)
-#pragma textflag 7
void
runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
{
@@ -454,7 +464,6 @@ runtime·assertE2I(InterfaceType* inter, Eface e, Iface ret)
}
// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool)
-#pragma textflag 7
void
runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
{
@@ -474,7 +483,6 @@ runtime·assertE2I2(InterfaceType *inter, Eface e, Iface ret, bool ok)
}
// func ifaceE2E(typ *byte, iface any) (ret any)
-#pragma textflag 7
void
runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
{
@@ -494,7 +502,6 @@ runtime·assertE2E(InterfaceType* inter, Eface e, Eface ret)
}
// func ifaceE2E2(iface any) (ret any, ok bool)
-#pragma textflag 7
void
runtime·assertE2E2(InterfaceType* inter, Eface e, Eface ret, bool ok)
{
diff --git a/src/pkg/runtime/malloc.goc b/src/pkg/runtime/malloc.goc
index 745e18ca0d..abbf63b931 100644
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -8,6 +8,7 @@
package runtime
#include "runtime.h"
+#include "stack.h"
#include "malloc.h"
#include "defs.h"
#include "type.h"
@@ -385,7 +386,7 @@ static struct {
} stacks;
enum {
- FixedStack = StackBig + StackExtra
+ FixedStack = StackMin,
};
void*
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index 84cd51700b..1bbca63177 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -7,6 +7,7 @@
#include "defs.h"
#include "malloc.h"
#include "os.h"
+#include "stack.h"
bool runtime·iscgo;
@@ -701,7 +702,7 @@ runtime·oldstack(void)
goid = old.gobuf.g->goid; // fault if g is bad, before gogo
if(old.free != 0)
- runtime·stackfree(g1->stackguard - StackGuard, old.free);
+ runtime·stackfree(g1->stackguard - StackGuard - StackSystem, old.free);
g1->stackbase = old.stackbase;
g1->stackguard = old.stackguard;
@@ -739,14 +740,15 @@ runtime·newstack(void)
// the new Stktop* is necessary to unwind, but
// we don't need to create a new segment.
top = (Stktop*)(m->morebuf.sp - sizeof(*top));
- stk = g1->stackguard - StackGuard;
+ stk = g1->stackguard - StackGuard - StackSystem;
free = 0;
} else {
// allocate new segment.
framesize += argsize;
- if(framesize < StackBig)
- framesize = StackBig;
framesize += StackExtra; // room for more functions, Stktop.
+ if(framesize < StackMin)
+ framesize = StackMin;
+ framesize += StackSystem;
stk = runtime·stackalloc(framesize);
top = (Stktop*)(stk+framesize-sizeof(*top));
free = framesize;
@@ -767,7 +769,7 @@ runtime·newstack(void)
g1->ispanic = false;
g1->stackbase = (byte*)top;
- g1->stackguard = stk + StackGuard;
+ g1->stackguard = stk + StackGuard + StackSystem;
sp = (byte*)top;
if(argsize > 0) {
@@ -798,10 +800,10 @@ runtime·malg(int32 stacksize)
g = runtime·malloc(sizeof(G));
if(stacksize >= 0) {
- stk = runtime·stackalloc(stacksize + StackGuard);
+ stk = runtime·stackalloc(StackSystem + stacksize);
g->stack0 = stk;
- g->stackguard = stk + StackGuard;
- g->stackbase = stk + StackGuard + stacksize - sizeof(Stktop);
+ g->stackguard = stk + StackSystem + StackGuard;
+ g->stackbase = stk + StackSystem + stacksize - sizeof(Stktop);
runtime·memclr(g->stackbase, sizeof(Stktop));
}
return g;
@@ -846,10 +848,10 @@ runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret)
if((newg = gfget()) != nil){
newg->status = Gwaiting;
- if(newg->stackguard - StackGuard != newg->stack0)
+ if(newg->stackguard - StackGuard - StackSystem != newg->stack0)
runtime·throw("invalid stack in newg");
} else {
- newg = runtime·malg(StackBig);
+ newg = runtime·malg(StackMin);
newg->status = Gwaiting;
newg->alllink = runtime·allg;
runtime·allg = newg;
@@ -1099,7 +1101,7 @@ nomatch:
static void
gfput(G *g)
{
- if(g->stackguard - StackGuard != g->stack0)
+ if(g->stackguard - StackGuard - StackSystem != g->stack0)
runtime·throw("invalid stack in gfput");
g->schedlink = runtime·sched.gfree;
runtime·sched.gfree = g;
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index ef2def0f6c..e85bc9daa8 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "stack.h"
enum {
maxround = sizeof(uintptr),
diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h
index a02010013f..ac992a2f1b 100644
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -592,83 +592,17 @@ int32 runtime·chancap(Hchan*);
void runtime·ifaceE2I(struct InterfaceType*, Eface, Iface*);
-/*
- * Stack layout parameters.
- * Known to linkers.
- *
- * The per-goroutine g->stackguard is set to point
- * StackGuard bytes above the bottom of the stack.
- * Each function compares its stack pointer against
- * g->stackguard to check for overflow. To cut one
- * instruction from the check sequence for functions
- * with tiny frames, the stack is allowed to protrude
- * StackSmall bytes below the stack guard. Functions
- * with large frames don't bother with the check and
- * always call morestack. The sequences are
- * (for amd64, others are similar):
- *
- * guard = g->stackguard
- * frame = function's stack frame size
- * argsize = size of function arguments (call + return)
- *
- * stack frame size <= StackSmall:
- * CMPQ guard, SP
- * JHI 3(PC)
- * MOVQ m->morearg, $(argsize << 32)
- * CALL morestack(SB)
- *
- * stack frame size > StackSmall but < StackBig
- * LEAQ (frame-StackSmall)(SP), R0
- * CMPQ guard, R0
- * JHI 3(PC)
- * MOVQ m->morearg, $(argsize << 32)
- * CALL morestack(SB)
- *
- * stack frame size >= StackBig:
- * MOVQ m->morearg, $((argsize << 32) | frame)
- * CALL morestack(SB)
- *
- * The bottom StackGuard - StackSmall bytes are important:
- * there has to be enough room to execute functions that
- * refuse to check for stack overflow, either because they
- * need to be adjacent to the actual caller's frame (deferproc)
- * or because they handle the imminent stack overflow (morestack).
- *
- * For example, deferproc might call malloc, which does one
- * of the above checks (without allocating a full frame),
- * which might trigger a call to morestack. This sequence
- * needs to fit in the bottom section of the stack. On amd64,
- * morestack's frame is 40 bytes, and deferproc's frame is 56 bytes.
- * That fits well within the StackGuard - StackSmall = 128 bytes
- * at the bottom. There may be other sequences lurking or yet to
- * be written that require more stack. Morestack checks to make
- * sure the stack has not completely overflowed and should catch
- * such sequences.
- */
enum
{
+ // StackSystem is a number of additional bytes to add
+ // to each stack below the usual guard area for OS-specific
+ // purposes like signal handling.
+ // TODO(rsc): This is only for Windows. Can't Windows use
+ // a separate exception stack like every other operating system?
#ifdef __WINDOWS__
- // need enough room in guard area for exception handler.
- // use larger stacks to compensate for larger stack guard.
- StackSmall = 256,
- StackGuard = 2048,
- StackBig = 8192,
- StackExtra = StackGuard,
+ StackSystem = 2048,
#else
- // byte offset of stack guard (g->stackguard) above bottom of stack.
- StackGuard = 256,
-
- // checked frames are allowed to protrude below the guard by
- // this many bytes. this saves an instruction in the checking
- // sequence when the stack frame is tiny.
- StackSmall = 128,
-
- // extra space in the frame (beyond the function for which
- // the frame is allocated) is assumed not to be much bigger
- // than this amount. it may not be used efficiently if it is.
- StackBig = 4096,
-
- // extra room over frame size when allocating a stack.
- StackExtra = 1024,
+ StackSystem = 0,
#endif
};
+
diff --git a/src/pkg/runtime/stack.h b/src/pkg/runtime/stack.h
new file mode 100644
index 0000000000..ebf0462b56
--- /dev/null
+++ b/src/pkg/runtime/stack.h
@@ -0,0 +1,86 @@
+// Copyright 2011 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.
+
+/*
+Stack layout parameters.
+Included both by runtime (compiled via 6c) and linkers (compiled via gcc).
+
+The per-goroutine g->stackguard is set to point StackGuard bytes
+above the bottom of the stack. Each function compares its stack
+pointer against g->stackguard to check for overflow. To cut one
+instruction from the check sequence for functions with tiny frames,
+the stack is allowed to protrude StackSmall bytes below the stack
+guard. Functions with large frames don't bother with the check and
+always call morestack. The sequences are (for amd64, others are
+similar):
+
+ guard = g->stackguard
+ frame = function's stack frame size
+ argsize = size of function arguments (call + return)
+
+ stack frame size <= StackSmall:
+ CMPQ guard, SP
+ JHI 3(PC)
+ MOVQ m->morearg, $(argsize << 32)
+ CALL morestack(SB)
+
+ stack frame size > StackSmall but < StackBig
+ LEAQ (frame-StackSmall)(SP), R0
+ CMPQ guard, R0
+ JHI 3(PC)
+ MOVQ m->morearg, $(argsize << 32)
+ CALL morestack(SB)
+
+ stack frame size >= StackBig:
+ MOVQ m->morearg, $((argsize << 32) | frame)
+ CALL morestack(SB)
+
+The bottom StackGuard - StackSmall bytes are important: there has
+to be enough room to execute functions that refuse to check for
+stack overflow, either because they need to be adjacent to the
+actual caller's frame (deferproc) or because they handle the imminent
+stack overflow (morestack).
+
+For example, deferproc might call malloc, which does one of the
+above checks (without allocating a full frame), which might trigger
+a call to morestack. This sequence needs to fit in the bottom
+section of the stack. On amd64, morestack's frame is 40 bytes, and
+deferproc's frame is 56 bytes. That fits well within the
+StackGuard - StackSmall = 128 bytes at the bottom.
+The linkers explore all possible call traces involving non-splitting
+functions to make sure that this limit cannot be violated.
+ */
+
+enum {
+ // The amount of extra stack to allocate beyond the size
+ // needed for the single frame that triggered the split.
+ StackExtra = 1024,
+
+ // The minimum stack segment size to allocate.
+ // If the amount needed for the splitting frame + StackExtra
+ // is less than this number, the stack will have this size instead.
+ StackMin = 4096,
+
+ // Functions that need frames bigger than this call morestack
+ // unconditionally. That is, on entry to a function it is assumed
+ // that the amount of space available in the current stack segment
+ // couldn't possibly be bigger than StackBig. If stack segments
+ // do run with more space than StackBig, the space may not be
+ // used efficiently. As a result, StackBig should not be significantly
+ // smaller than StackMin or StackExtra.
+ StackBig = 4096,
+
+ // The stack guard is a pointer this many bytes above the
+ // bottom of the stack.
+ StackGuard = 256,
+
+ // After a stack split check the SP is allowed to be this
+ // many bytes below the stack guard. This saves an instruction
+ // in the checking sequence for tiny frames.
+ StackSmall = 128,
+
+ // The maximum number of bytes that a chain of NOSPLIT
+ // functions can use.
+ StackLimit = StackGuard - StackSmall,
+};