n := 0
name := []string{
"test.goCallback",
+ "runtime.call16",
"runtime.cgocallbackg1",
"runtime.cgocallbackg",
"runtime.cgocallback_gofunc",
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build ignore
+// This test depends on running C code on Go stacks. Not allowed anymore.
+
// Demo of deferred C function with untrue prototype
// breaking stack copying. See golang.org/issue/7695.
aggr = "seh";
else if(streq(fields.p[1], "Alg"))
aggr = "alg";
+ else if(streq(fields.p[1], "Panic"))
+ aggr = "panic";
}
if(hasprefix(lines.p[i], "}"))
aggr = nil;
}
// Call.
- call(fn, args, uint32(frametype.size), uint32(retOffset))
+ call(fn, args, uint32(frametype.size), uint32(retOffset), nil)
// For testing; see TestCallMethodJump.
if callGC {
memmove(unsafe.Pointer(uintptr(args)+ptrSize), frame, argSize-ptrSize)
// Call.
- call(fn, args, uint32(frametype.size), uint32(retOffset))
+ call(fn, args, uint32(frametype.size), uint32(retOffset), nil)
// Copy return values. On amd64p32, the beginning of return values
// is 64-bit aligned, so the caller's frame layout (which doesn't have
func mapiternext(it unsafe.Pointer)
func maplen(m unsafe.Pointer) int
-func call(fn, arg unsafe.Pointer, n uint32, retoffset uint32)
+// panicpos is for use by runtime and should be nil in all calls in this package
+func call(fn, arg unsafe.Pointer, n uint32, retoffset uint32, panicpos unsafe.Pointer)
+
func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer)
// Dummy annotation marking that the value x escapes,
JNE 2(PC)
INT $3
+ // Cannot grow signal stack.
+ MOVL m_gsignal(BX), SI
+ CMPL g(CX), SI
+ JNE 2(PC)
+ INT $3
+
// frame size in DI
// arg size in AX
// Save in m.
MOVL $0, DX
JMP runtime·morestack(SB)
-// Called from panic. Mimics morestack,
-// reuses stack growth code to create a frame
-// with the desired args running the desired function.
-//
-// func call(fn *byte, arg *byte, argsize uint32).
-TEXT runtime·newstackcall(SB), NOSPLIT, $0-12
- get_tls(CX)
- MOVL g(CX), BX
- MOVL g_m(BX), BX
-
- // Save our caller's state as the PC and SP to
- // restore when returning from f.
- MOVL 0(SP), AX // our caller's PC
- MOVL AX, (m_morebuf+gobuf_pc)(BX)
- LEAL fv+0(FP), AX // our caller's SP
- MOVL AX, (m_morebuf+gobuf_sp)(BX)
- MOVL g(CX), AX
- MOVL AX, (m_morebuf+gobuf_g)(BX)
-
- // Save our own state as the PC and SP to restore
- // if this goroutine needs to be restarted.
- MOVL $runtime·newstackcall(SB), (g_sched+gobuf_pc)(AX)
- MOVL SP, (g_sched+gobuf_sp)(AX)
-
- // Set up morestack arguments to call f on a new stack.
- // We set f's frame size to 1, as a hint to newstack
- // that this is a call from runtime·newstackcall.
- // If it turns out that f needs a larger frame than
- // the default stack, f's usual stack growth prolog will
- // allocate a new segment (and recopy the arguments).
- MOVL fv+0(FP), AX // fn
- MOVL addr+4(FP), DX // arg frame
- MOVL size+8(FP), CX // arg size
-
- MOVL AX, m_cret(BX) // f's PC
- MOVL DX, m_moreargp(BX) // f's argument pointer
- MOVL CX, m_moreargsize(BX) // f's argument size
- MOVL $1, m_moreframesize(BX) // f's frame size
-
- // Call newstack on m->g0's stack.
- MOVL m_g0(BX), BP
- get_tls(CX)
- MOVL BP, g(CX)
- MOVL (g_sched+gobuf_sp)(BP), SP
- CALL runtime·newstack(SB)
- MOVL $0, 0x1103 // crash if newstack returns
- RET
-
// reflect·call: call a function with the given argument list
-// func call(f *FuncVal, arg *byte, argsize uint32).
+// func call(f *FuncVal, arg *byte, argsize, retoffset uint32, p *Panic).
// we don't have variable-sized frames, so we use a small number
// of constant-sized-frame functions to encode a few bits of size in the pc.
// Caution: ugly multiline assembly macros in your future!
#define DISPATCH(NAME,MAXSIZE) \
CMPL CX, $MAXSIZE; \
JA 3(PC); \
- MOVL $NAME(SB), AX; \
+ MOVL $NAME(SB), AX; \
JMP AX
// Note: can't just "JMP NAME(SB)" - bad inlining results.
-TEXT reflect·call(SB), NOSPLIT, $0-16
+TEXT reflect·call(SB), NOSPLIT, $0-20
MOVL argsize+8(FP), CX
DISPATCH(runtime·call16, 16)
DISPATCH(runtime·call32, 32)
MOVL $runtime·badreflectcall(SB), AX
JMP AX
-// Argument map for the callXX frames. Each has one
-// stack map (for the single call) with 3 arguments.
+// Argument map for the callXX frames. Each has one stack map.
DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gcargs_reflectcall<>+0x04(SB)/4, $6 // 3 args
-DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
+DATA gcargs_reflectcall<>+0x04(SB)/4, $10 // 5 words
+DATA gcargs_reflectcall<>+0x08(SB)/1, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4)+(const_BitsScalar<<6))
+DATA gcargs_reflectcall<>+0x09(SB)/1, $(const_BitsPointer)
GLOBL gcargs_reflectcall<>(SB),RODATA,$12
// callXX frames have no locals
GLOBL gclocals_reflectcall<>(SB),RODATA,$8
#define CALLFN(NAME,MAXSIZE) \
-TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \
+TEXT NAME(SB), WRAPPER, $MAXSIZE-20; \
FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
/* copy arguments to stack */ \
MOVL argsize+8(FP), CX; \
MOVL SP, DI; \
REP;MOVSB; \
+ /* initialize panic argp */ \
+ MOVL panic+16(FP), CX; \
+ CMPL CX, $0; \
+ JEQ 3(PC); \
+ LEAL (MAXSIZE+4)(SP), BX; \
+ MOVL BX, panic_argp(CX); \
/* call function */ \
MOVL f+0(FP), DX; \
MOVL (DX), AX; \
PCDATA $PCDATA_StackMapIndex, $0; \
CALL AX; \
+ /* clear panic argp */ \
+ MOVL panic+16(FP), CX; \
+ CMPL CX, $0; \
+ JEQ 2(PC); \
+ MOVL $0, panic_argp(CX); \
/* copy return values back */ \
MOVL argptr+4(FP), DI; \
MOVL argsize+8(FP), CX; \
JNE 2(PC)
INT $3
+ // Cannot grow signal stack (m->gsignal).
+ MOVQ m_gsignal(BX), SI
+ CMPQ g(CX), SI
+ JNE 2(PC)
+ INT $3
+
// Called from f.
// Set m->morebuf to f's caller.
MOVQ 8(SP), AX // f's caller's PC
MOVQ $0, 0x1003 // crash if newstack returns
RET
-// Called from panic. Mimics morestack,
-// reuses stack growth code to create a frame
-// with the desired args running the desired function.
-//
-// func call(fn *byte, arg *byte, argsize uint32).
-TEXT runtime·newstackcall(SB), NOSPLIT, $0-20
- get_tls(CX)
- MOVQ g(CX), BX
- MOVQ g_m(BX), BX
-
- // Save our caller's state as the PC and SP to
- // restore when returning from f.
- MOVQ 0(SP), AX // our caller's PC
- MOVQ AX, (m_morebuf+gobuf_pc)(BX)
- LEAQ fv+0(FP), AX // our caller's SP
- MOVQ AX, (m_morebuf+gobuf_sp)(BX)
- MOVQ g(CX), AX
- MOVQ AX, (m_morebuf+gobuf_g)(BX)
-
- // Save our own state as the PC and SP to restore
- // if this goroutine needs to be restarted.
- MOVQ $runtime·newstackcall(SB), BP
- MOVQ BP, (g_sched+gobuf_pc)(AX)
- MOVQ SP, (g_sched+gobuf_sp)(AX)
-
- // Set up morestack arguments to call f on a new stack.
- // We set f's frame size to 1, as a hint to newstack
- // that this is a call from runtime·newstackcall.
- // If it turns out that f needs a larger frame than
- // the default stack, f's usual stack growth prolog will
- // allocate a new segment (and recopy the arguments).
- MOVQ fv+0(FP), AX // fn
- MOVQ addr+8(FP), DX // arg frame
- MOVL size+16(FP), CX // arg size
-
- MOVQ AX, m_cret(BX) // f's PC
- MOVQ DX, m_moreargp(BX) // argument frame pointer
- MOVL CX, m_moreargsize(BX) // f's argument size
- MOVL $1, m_moreframesize(BX) // f's frame size
-
- // Call newstack on m->g0's stack.
- MOVQ m_g0(BX), BP
- get_tls(CX)
- MOVQ BP, g(CX)
- MOVQ (g_sched+gobuf_sp)(BP), SP
- CALL runtime·newstack(SB)
- MOVQ $0, 0x1103 // crash if newstack returns
- RET
-
// reflect·call: call a function with the given argument list
-// func call(f *FuncVal, arg *byte, argsize uint32).
+// func call(f *FuncVal, arg *byte, argsize, retoffset uint32, p *Panic).
// we don't have variable-sized frames, so we use a small number
// of constant-sized-frame functions to encode a few bits of size in the pc.
// Caution: ugly multiline assembly macros in your future!
JMP AX
// Note: can't just "JMP NAME(SB)" - bad inlining results.
-TEXT reflect·call(SB), NOSPLIT, $0-24
+TEXT reflect·call(SB), NOSPLIT, $0-32
MOVLQZX argsize+16(FP), CX
DISPATCH(runtime·call16, 16)
DISPATCH(runtime·call32, 32)
MOVQ $runtime·badreflectcall(SB), AX
JMP AX
-// Argument map for the callXX frames. Each has one
-// stack map (for the single call) with 3 arguments.
+// Argument map for the callXX frames. Each has one stack map.
DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gcargs_reflectcall<>+0x04(SB)/4, $6 // 3 args
-DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
+DATA gcargs_reflectcall<>+0x04(SB)/4, $8 // 4 words
+DATA gcargs_reflectcall<>+0x08(SB)/1, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4)+(const_BitsPointer<<6))
GLOBL gcargs_reflectcall<>(SB),RODATA,$12
// callXX frames have no locals
DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals
GLOBL gclocals_reflectcall<>(SB),RODATA,$8
+// CALLFN is marked as a WRAPPER so that a deferred reflect.call func will
+// see the right answer for recover. However, CALLFN is also how we start
+// the panic in the first place. We record the panic argp if this is the start of
+// a panic. Since the wrapper adjustment has already happened, though
+// (in the implicit prologue), we have to write not SP but MAXSIZE+8+SP into
+// p.argp. The MAXSIZE+8 will counter the MAXSIZE+8 the wrapper prologue
+// added to g->panicwrap.
+
#define CALLFN(NAME,MAXSIZE) \
-TEXT NAME(SB), WRAPPER, $MAXSIZE-24; \
+TEXT NAME(SB), WRAPPER, $MAXSIZE-32; \
FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
/* copy arguments to stack */ \
MOVLQZX argsize+16(FP), CX; \
MOVQ SP, DI; \
REP;MOVSB; \
+ /* initialize panic argp */ \
+ MOVQ panic+24(FP), CX; \
+ CMPQ CX, $0; \
+ JEQ 3(PC); \
+ LEAQ (MAXSIZE+8)(SP), BX; \
+ MOVQ BX, panic_argp(CX); \
/* call function */ \
MOVQ f+0(FP), DX; \
PCDATA $PCDATA_StackMapIndex, $0; \
CALL (DX); \
+ /* clear panic argp */ \
+ MOVQ panic+24(FP), CX; \
+ CMPQ CX, $0; \
+ JEQ 2(PC); \
+ MOVQ $0, panic_argp(CX); \
/* copy return values back */ \
MOVQ argptr+8(FP), DI; \
MOVLQZX argsize+16(FP), CX; \
JNE 2(PC)
MOVL 0, AX
+ // Cannot grow signal stack (m->gsignal).
+ MOVL m_gsignal(BX), SI
+ CMPL g(CX), SI
+ JNE 2(PC)
+ MOVL 0, AX
+
// Called from f.
// Set m->morebuf to f's caller.
MOVL 8(SP), AX // f's caller's PC
MOVL $0, 0x1003 // crash if newstack returns
RET
-// Called from panic. Mimics morestack,
-// reuses stack growth code to create a frame
-// with the desired args running the desired function.
-//
-// func call(fn *byte, arg *byte, argsize uint32).
-TEXT runtime·newstackcall(SB), NOSPLIT, $0-12
- get_tls(CX)
- MOVL g(CX), BX
- MOVL g_m(BX), BX
-
- // Save our caller's state as the PC and SP to
- // restore when returning from f.
- MOVL 0(SP), AX // our caller's PC
- MOVL AX, (m_morebuf+gobuf_pc)(BX)
- LEAL fv+0(FP), AX // our caller's SP
- MOVL AX, (m_morebuf+gobuf_sp)(BX)
- MOVL g(CX), AX
- MOVL AX, (m_morebuf+gobuf_g)(BX)
-
- // Save our own state as the PC and SP to restore
- // if this goroutine needs to be restarted.
- MOVL $runtime·newstackcall(SB), DI
- MOVL DI, (g_sched+gobuf_pc)(AX)
- MOVL SP, (g_sched+gobuf_sp)(AX)
-
- // Set up morestack arguments to call f on a new stack.
- // We set f's frame size to 1, as a hint to newstack
- // that this is a call from runtime·newstackcall.
- // If it turns out that f needs a larger frame than
- // the default stack, f's usual stack growth prolog will
- // allocate a new segment (and recopy the arguments).
- MOVL fv+0(FP), AX // fn
- MOVL addr+4(FP), DX // arg frame
- MOVL size+8(FP), CX // arg size
-
- MOVQ AX, m_cret(BX) // f's PC
- MOVL DX, m_moreargp(BX) // argument frame pointer
- MOVL CX, m_moreargsize(BX) // f's argument size
- MOVL $1, m_moreframesize(BX) // f's frame size
-
- // Call newstack on m->g0's stack.
- MOVL m_g0(BX), BX
- get_tls(CX)
- MOVL BX, g(CX)
- MOVL (g_sched+gobuf_sp)(BX), SP
- CALL runtime·newstack(SB)
- MOVL $0, 0x1103 // crash if newstack returns
- RET
-
// reflect·call: call a function with the given argument list
-// func call(f *FuncVal, arg *byte, argsize uint32).
+// func call(f *FuncVal, arg *byte, argsize, retoffset uint32, p *Panic).
// we don't have variable-sized frames, so we use a small number
// of constant-sized-frame functions to encode a few bits of size in the pc.
// Caution: ugly multiline assembly macros in your future!
MOVL $runtime·badreflectcall(SB), AX
JMP AX
+// Argument map for the callXX frames. Each has one stack map.
+DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gcargs_reflectcall<>+0x04(SB)/4, $10 // 5 words
+DATA gcargs_reflectcall<>+0x08(SB)/1, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4)+(const_BitsScalar<<6))
+DATA gcargs_reflectcall<>+0x09(SB)/1, $(const_BitsPointer)
+GLOBL gcargs_reflectcall<>(SB),RODATA,$12
+
+// callXX frames have no locals
+DATA gclocals_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
+DATA gclocals_reflectcall<>+0x04(SB)/4, $0 // 0 locals
+GLOBL gclocals_reflectcall<>(SB),RODATA,$8
+
#define CALLFN(NAME,MAXSIZE) \
-TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \
+TEXT NAME(SB), WRAPPER, $MAXSIZE-20; \
+ FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
+ FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
/* copy arguments to stack */ \
MOVL argptr+4(FP), SI; \
MOVL argsize+8(FP), CX; \
MOVL SP, DI; \
REP;MOVSB; \
+ /* initialize panic argp */ \
+ MOVL panic+16(FP), CX; \
+ CMPL CX, $0; \
+ JEQ 3(PC); \
+ LEAL (MAXSIZE+8)(SP), BX; \
+ MOVL BX, panic_argp(CX); \
/* call function */ \
MOVL f+0(FP), DX; \
MOVL (DX), AX; \
CALL AX; \
+ /* clear panic argp */ \
+ MOVL panic+16(FP), CX; \
+ CMPL CX, $0; \
+ JEQ 2(PC); \
+ MOVL $0, panic_argp(CX); \
/* copy return values back */ \
MOVL argptr+4(FP), DI; \
MOVL argsize+8(FP), CX; \
CMP g, R4
BL.EQ runtime·abort(SB)
+ // Cannot grow signal stack (m->gsignal).
+ MOVW m_gsignal(R8), R4
+ CMP g, R4
+ BL.EQ runtime·abort(SB)
+
MOVW R1, m_moreframesize(R8)
MOVW R2, m_moreargsize(R8)
MOVW $0, R7
B runtime·morestack(SB)
-// Called from panic. Mimics morestack,
-// reuses stack growth code to create a frame
-// with the desired args running the desired function.
-//
-// func call(fn *byte, arg *byte, argsize uint32).
-TEXT runtime·newstackcall(SB),NOSPLIT,$-4-12
- // Save our caller's state as the PC and SP to
- // restore when returning from f.
- MOVW g_m(g), R8
- MOVW LR, (m_morebuf+gobuf_pc)(R8) // our caller's PC
- MOVW SP, (m_morebuf+gobuf_sp)(R8) // our caller's SP
- MOVW g, (m_morebuf+gobuf_g)(R8)
-
- // Save our own state as the PC and SP to restore
- // if this goroutine needs to be restarted.
- MOVW $runtime·newstackcall(SB), R11
- MOVW R11, (g_sched+gobuf_pc)(g)
- MOVW LR, (g_sched+gobuf_lr)(g)
- MOVW SP, (g_sched+gobuf_sp)(g)
-
- // Set up morestack arguments to call f on a new stack.
- // We set f's frame size to 1, as a hint to newstack
- // that this is a call from runtime·newstackcall.
- // If it turns out that f needs a larger frame than
- // the default stack, f's usual stack growth prolog will
- // allocate a new segment (and recopy the arguments).
- MOVW 4(SP), R0 // fn
- MOVW 8(SP), R1 // arg frame
- MOVW 12(SP), R2 // arg size
-
- MOVW R0, m_cret(R8) // f's PC
- MOVW R1, m_moreargp(R8) // f's argument pointer
- MOVW R2, m_moreargsize(R8) // f's argument size
- MOVW $1, R3
- MOVW R3, m_moreframesize(R8) // f's frame size
-
- // Call newstack on m->g0's stack.
- MOVW m_g0(R8), g
- MOVW (g_sched+gobuf_sp)(g), SP
- B runtime·newstack(SB)
-
// reflect·call: call a function with the given argument list
-// func call(f *FuncVal, arg *byte, argsize uint32).
+// func call(f *FuncVal, arg *byte, argsize, retoffset uint32, p *Panic).
// we don't have variable-sized frames, so we use a small number
// of constant-sized-frame functions to encode a few bits of size in the pc.
// Caution: ugly multiline assembly macros in your future!
#define DISPATCH(NAME,MAXSIZE) \
CMP $MAXSIZE, R0; \
B.HI 3(PC); \
- MOVW $NAME(SB), R1; \
+ MOVW $NAME(SB), R1; \
B (R1)
-TEXT reflect·call(SB),NOSPLIT,$-4-16
+TEXT reflect·call(SB),NOSPLIT,$-4-20
MOVW argsize+8(FP), R0
DISPATCH(runtime·call16, 16)
DISPATCH(runtime·call32, 32)
MOVW $runtime·badreflectcall(SB), R1
B (R1)
-// Argument map for the callXX frames. Each has one
-// stack map (for the single call) with 3 arguments.
+// Argument map for the callXX frames. Each has one stack map.
DATA gcargs_reflectcall<>+0x00(SB)/4, $1 // 1 stackmap
-DATA gcargs_reflectcall<>+0x04(SB)/4, $6 // 3 args
-DATA gcargs_reflectcall<>+0x08(SB)/4, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4))
+DATA gcargs_reflectcall<>+0x04(SB)/4, $10 // 5 words
+DATA gcargs_reflectcall<>+0x08(SB)/1, $(const_BitsPointer+(const_BitsPointer<<2)+(const_BitsScalar<<4)+(const_BitsScalar<<6))
+DATA gcargs_reflectcall<>+0x09(SB)/1, $(const_BitsPointer)
GLOBL gcargs_reflectcall<>(SB),RODATA,$12
// callXX frames have no locals
GLOBL gclocals_reflectcall<>(SB),RODATA,$8
#define CALLFN(NAME,MAXSIZE) \
-TEXT NAME(SB), WRAPPER, $MAXSIZE-16; \
+TEXT NAME(SB), WRAPPER, $MAXSIZE-20; \
FUNCDATA $FUNCDATA_ArgsPointerMaps,gcargs_reflectcall<>(SB); \
FUNCDATA $FUNCDATA_LocalsPointerMaps,gclocals_reflectcall<>(SB);\
/* copy arguments to stack */ \
MOVBU.P R5, 1(R1); \
SUB $1, R2, R2; \
B -5(PC); \
+ /* initialize panic argp */ \
+ MOVW panic+16(FP), R4; \
+ CMP $0, R4; \
+ B.EQ 3(PC); \
+ ADD $(4+MAXSIZE+4), R13, R5; \
+ MOVW R5, panic_argp(R4); \
/* call function */ \
MOVW f+0(FP), R7; \
MOVW (R7), R0; \
PCDATA $PCDATA_StackMapIndex, $0; \
BL (R0); \
+ /* clear panic argp */ \
+ MOVW panic+16(FP), R4; \
+ CMP $0, R4; \
+ B.EQ 3(PC); \
+ MOVW $0, R5; \
+ MOVW R5, panic_argp(R4); \
/* copy return values back */ \
MOVW argptr+4(FP), R0; \
MOVW argsize+8(FP), R2; \
}
// Invoke callback.
- newstackcall(cb.fn, cb.arg, uint32(cb.argsize))
+ reflectcall(unsafe.Pointer(cb.fn), unsafe.Pointer(cb.arg), uint32(cb.argsize), 0, nil)
if raceenabled {
racereleasemerge(unsafe.Pointer(&racecgosync))
default:
gothrow("bad kind in runfinq")
}
- reflectcall(unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz))
+ reflectcall(unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz), nil)
// drop finalizer queue references to finalized object
f.fn = nil
for gp._defer != nil {
d := gp._defer
gp._defer = d.link
- reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz))
+ reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz), nil)
freedefer(d)
// Note: we ignore recovers here because Goexit isn't a panic
}
dabort.link = gp._defer
gp._defer = (*_defer)(noescape(unsafe.Pointer(&dabort)))
p._defer = d
+ p.outerwrap = gp.panicwrap
- newstackcall(d.fn, unsafe.Pointer(&d.args), uint32(d.siz))
+ // TODO(rsc): I am pretty sure the panicwrap manipulation here is not correct.
+ // It is close enough to pass all the tests we have, but I think it needs to be
+ // restored during recovery too. I will write better tests and fix it in a separate CL.
- // Newstackcall did not panic. Remove dabort.
+ gp.panicwrap = 0
+ reflectcall(unsafe.Pointer(d.fn), unsafe.Pointer(&d.args), uint32(d.siz), uint32(d.siz), (*_panic)(noescape(unsafe.Pointer(&p))))
+ gp.panicwrap = p.outerwrap
+
+ // reflectcall did not panic. Remove dabort.
if gp._defer != &dabort {
gothrow("bad defer entry in panic")
}
// while they are active on the stack. The linker emits adjustments of
// g.panicwrap in the prologue and epilogue of functions marked as wrappers.
gp := getg()
- top := (*stktop)(unsafe.Pointer(gp.stackbase))
p := gp._panic
- if p != nil && !p.recovered && top._panic && argp == gp.stackbase-uintptr(top.argsize+gp.panicwrap) {
+ // if p != nil {
+ // println("recover?", p, p.recovered, hex(argp), hex(p.argp), uintptr(gp.panicwrap), p != nil && !p.recovered && argp == p.argp-uintptr(gp.panicwrap))
+ // }
+ if p != nil && !p.recovered && argp == p.argp-uintptr(gp.panicwrap) {
p.recovered = true
return p.arg
}
uint32 panicwrap;
uint8* argp; // pointer to arguments in old frame
- bool panic; // is this frame the top of a panic?
};
struct SigTab
{
Eface arg; // argument to panic
Panic* link; // link to earlier panic
Defer* defer; // current executing defer
+ uintptr argp; // pointer to arguments of deferred call, for recover
+ uint32 outerwrap; // outer gp->panicwrap
bool recovered; // whether this panic is over
bool aborted; // the panic was aborted
};
/*
* runtime go-called
*/
-void runtime·newstackcall(FuncVal*, byte*, uint32);
-void reflect·call(FuncVal*, byte*, uint32, uint32);
void runtime·gopanic(Eface);
void runtime·panicindex(void);
void runtime·panicslice(void);
StackFaultOnFree = 0, // old stacks are mapped noaccess to detect use after free
StackCache = 1,
+
+ StackCopyAlways = 1, // expect to be able to copy stacks 100% of the time
};
// Global pool of spans that have free stacks.
int64 goid;
int32 oldstatus;
+ if(StackCopyAlways)
+ runtime·throw("unexpected call to oldstack");
+
gp = g->m->curg;
top = (Stktop*)gp->stackbase;
if(top == nil)
stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
if(stackmap == nil) {
cinfo->frames = -1;
- if(StackDebug >= 1)
- runtime·printf("copystack: no locals info for %s\n", runtime·funcname(f));
+ if(StackDebug >= 1 || StackCopyAlways)
+ runtime·printf("runtime: copystack: no locals info for %s\n", runtime·funcname(f));
return false;
}
if(stackmap->n <= 0) {
cinfo->frames = -1;
- if(StackDebug >= 1)
- runtime·printf("copystack: locals size info only for %s\n", runtime·funcname(f));
+ if(StackDebug >= 1 || StackCopyAlways)
+ runtime·printf("runtime: copystack: locals size info only for %s\n", runtime·funcname(f));
return false;
}
}
stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
if(stackmap == nil) {
cinfo->frames = -1;
- if(StackDebug >= 1)
- runtime·printf("copystack: no arg info for %s\n", runtime·funcname(f));
+ if(StackDebug >= 1 || StackCopyAlways)
+ runtime·printf("runtime: copystack: no arg info for %s\n", runtime·funcname(f));
return false;
}
}
continue;
f = runtime·findfunc((uintptr)fn->fn);
if(f == nil) {
- if(StackDebug >= 1)
- runtime·printf("copystack: no func for deferred pc %p\n", fn->fn);
+ if(StackDebug >= 1 || StackCopyAlways)
+ runtime·printf("runtime: copystack: no func for deferred pc %p\n", fn->fn);
return -1;
}
// C (particularly, cgo) lies to us. See issue 7695.
stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
if(stackmap == nil || stackmap->n <= 0) {
- if(StackDebug >= 1)
- runtime·printf("copystack: no arg info for deferred %s\n", runtime·funcname(f));
+ if(StackDebug >= 1 || StackCopyAlways)
+ runtime·printf("runtime: copystack: no arg info for deferred %s\n", runtime·funcname(f));
return -1;
}
stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
if(stackmap == nil || stackmap->n <= 0) {
- if(StackDebug >= 1)
- runtime·printf("copystack: no local info for deferred %s\n", runtime·funcname(f));
+ if(StackDebug >= 1 || StackCopyAlways)
+ runtime·printf("runtime: copystack: no local info for deferred %s\n", runtime·funcname(f));
return -1;
}
static void
adjustpanics(G *gp, AdjustInfo *adjinfo)
{
- Panic *p;
+ Panic *p, **l;
// only the topmost panic is on the current stack
- p = gp->panic;
- if(p == nil)
- return;
- if(p->link != nil) {
- // only the topmost panic can be on the current stack
- // (because panic runs defers on a new stack)
- if(adjinfo->oldstk <= (byte*)p->link && (byte*)p->link < adjinfo->oldbase)
- runtime·throw("two panics on one stack");
+ for(l = &gp->panic; (p = *l) != nil; ) {
+ if(adjinfo->oldstk <= (byte*)p && (byte*)p < adjinfo->oldbase)
+ *l = (Panic*)((byte*)p + adjinfo->delta);
+ l = &p->link;
+
+ if(adjinfo->oldstk <= (byte*)p->argp && (byte*)p->argp < adjinfo->oldbase)
+ p->argp += adjinfo->delta;
}
- if(adjinfo->oldstk <= (byte*)p && (byte*)p < adjinfo->oldbase)
- gp->panic = (Panic*)((byte*)p + adjinfo->delta);
}
static void
return 1 << s;
}
-// Called from runtime·newstackcall or from runtime·morestack when a new
-// stack segment is needed. Allocate a new stack big enough for
-// m->moreframesize bytes, copy m->moreargsize bytes to the new frame,
-// and then act as though runtime·lessstack called the function at
-// m->morepc.
+// Called from runtime·morestack when a new stack segment is needed.
+// Allocate a new stack big enough for m->moreframesize bytes,
+// copy m->moreargsize bytes to the new frame,
+// and then act as though runtime·lessstack called the function at m->morepc.
//
// g->atomicstatus will be Grunning, Gsyscall or Gscanrunning, Gscansyscall upon entry.
// If the GC is trying to stop this g then it will set preemptscan to true.
runtime·newstack(void)
{
int32 framesize, argsize, oldstatus, oldsize, newsize, nframes;
- Stktop *top, *oldtop;
+ Stktop *top;
byte *stk, *oldstk, *oldbase;
uintptr sp;
uintptr *src, *dst, *dstend;
G *gp;
Gobuf label, morebuf;
void *moreargp;
- bool newstackcall;
if(g->m->forkstackguard)
runtime·throw("split stack after fork");
runtime·printf("runtime: newstack called from g=%p\n"
"\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n",
g->m->morebuf.g, g->m, g->m->curg, g->m->g0, g->m->gsignal);
+ morebuf = g->m->morebuf;
+ runtime·traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g);
runtime·throw("runtime: wrong goroutine in newstack");
}
if(g->throwsplit)
runtime·casgstatus(gp, oldstatus, Gwaiting); // oldstatus is not in a Gscan status
gp->waitreason = runtime·gostringnocopy((byte*)"stack growth");
- newstackcall = framesize==1;
- if(newstackcall)
- framesize = 0;
- // For newstackcall the context already points to beginning of runtime·newstackcall.
- if(!newstackcall)
- runtime·rewindmorestack(&gp->sched);
+ runtime·rewindmorestack(&gp->sched);
if(gp->stackbase == 0)
runtime·throw("nil stackbase");
// end of C code to trigger a copy as soon as C code exits. That way, we'll
// have stack available if we get this deep again.
}
+
+ if(StackCopyAlways)
+ runtime·throw("split stack not allowed");
// allocate new segment.
framesize += argsize;
top->argp = moreargp;
top->argsize = argsize;
- // copy flag from panic
- top->panic = gp->ispanic;
- gp->ispanic = false;
-
- // if this isn't a panic, maybe we're splitting the stack for a panic.
- // if we're splitting in the top frame, propagate the panic flag
- // forward so that recover will know we're in a panic.
- oldtop = (Stktop*)top->stackbase;
- if(oldtop != nil && oldtop->panic && top->argp == (byte*)oldtop - oldtop->argsize - gp->panicwrap)
- top->panic = true;
-
top->panicwrap = gp->panicwrap;
gp->panicwrap = 0;
while(dst < dstend)
*dst++ = *src++;
}
+
if(thechar == '5') {
// caller would have saved its LR below args.
sp -= sizeof(void*);
label.sp = sp;
label.pc = (uintptr)runtime·lessstack;
label.g = g->m->curg;
- if(newstackcall)
- runtime·gostartcallfn(&label, (FuncVal*)g->m->cret);
- else {
- runtime·gostartcall(&label, (void(*)(void))gp->sched.pc, gp->sched.ctxt);
- gp->sched.ctxt = nil;
- }
+ runtime·gostartcall(&label, (void(*)(void))gp->sched.pc, gp->sched.ctxt);
+ gp->sched.ctxt = nil;
runtime·casgstatus(gp, Gwaiting, oldstatus); // oldstatus is Grunning or Gsyscall
runtime·gogo(&label);
func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
func munmap(addr unsafe.Pointer, n uintptr)
func madvise(addr unsafe.Pointer, n uintptr, flags int32)
-func newstackcall(fv *funcval, addr unsafe.Pointer, size uint32)
-func reflectcall(fn, arg unsafe.Pointer, n uint32, retoffset uint32)
+func reflectcall(fn, arg unsafe.Pointer, n uint32, retoffset uint32, p *_panic)
func osyield()
func procyield(cycles uint32)
func cgocallback_gofunc(fv *funcval, frame unsafe.Pointer, framesize uintptr)
}
func f1() {
- // The 4 here and below depends on the number of internal runtime frames
+ // The 5 here and below depends on the number of internal runtime frames
// that sit between a deferred function called during panic and
// the original frame. If that changes, this test will start failing and
// the number here will need to be updated.
- defer checkLine(4)
+ defer checkLine(5)
var t *T
var c io.Closer = t
c.Close()
}
func f2() {
- defer checkLine(4)
+ defer checkLine(5)
var t T
var c io.Closer = t
c.Close()
}
func g() {
- _, file, line, _ := runtime.Caller(2)
+ _, file, line, _ := runtime.Caller(3)
if !strings.HasSuffix(file, "issue5856.go") || line != 28 {
fmt.Printf("BUG: defer called from %s:%d, want issue5856.go:28\n", file, line)
os.Exit(1)