add channel send type check (thanks austin).
fix type mismatch message.
R=r
DELTA=241 (225 added, 5 deleted, 11 changed)
OCL=31370
CL=31375
}
}
+// Difficult test for function call because of
+// implicit padding between arguments.
+func dummy(b byte, c int, d byte) (i byte, j int, k byte){
+ return b, c, d;
+}
+
+func TestFunc(t *testing.T) {
+ ret := NewValue(dummy).(*FuncValue).Call([]Value{NewValue(byte(10)), NewValue(20), NewValue(byte(30))});
+ if len(ret) != 3 {
+ t.Fatalf("Call returned %d values, want 3", len(ret));
+ }
+
+ i := ret[0].(*Uint8Value).Get();
+ j := ret[1].(*IntValue).Get();
+ k := ret[2].(*Uint8Value).Get();
+ if i != 10 || j != 20 || k != 30 {
+ t.Errorf("Call returned %d, %d, %d; want 10, 20, 30", i, j, k);
+ }
+}
Elem() Type;
}
+// Typeof returns the reflection Type of the value in the interface{}.
+func Typeof(i interface{}) Type {
+ return toType(unsafe.Typeof(i));
+}
+
// TODO: This will have to go away when
// the new gc goes in.
-func memmove(dst, src, n uintptr) {
+func memmove(adst, asrc addr, n uintptr) {
var p uintptr; // dummy for sizeof
const ptrsize = uintptr(unsafe.Sizeof(p));
+ dst := uintptr(adst);
+ src := uintptr(asrc);
switch {
case src < dst && src+n > dst:
// byte copy backward
func typesMustMatch(t1, t2 reflect.Type) {
if t1 != t2 {
- panicln("type mismatch:", t1, "!=", t2);
+ panicln("type mismatch:", t1.String(), "!=", t2.String());
}
}
if xn := src.Len(); n > xn {
n = xn;
}
- memmove(uintptr(dst.addr()), uintptr(src.addr()), uintptr(n) * de.Size());
+ memmove(dst.addr(), src.addr(), uintptr(n) * de.Size());
return n;
}
if t.Dir() & SendDir == 0{
panic("send on recv-only channel");
}
+ typesMustMatch(t.Elem(), x.Type());
ch := *(**byte)(v.addr);
chansend(ch, (*byte)(x.getAddr()), b);
}
*(*uintptr)(v.addr) = *(*uintptr)(x.addr);
}
+// implemented in ../pkg/runtime/*/asm.s
+func call(fn, arg *byte, n uint32)
+
+type tiny struct { b byte }
+
// Call calls the function v with input parameters in.
// It returns the function's output parameters as Values.
func (v *FuncValue) Call(in []Value) []Value {
- panic("unimplemented: function Call");
-}
+ var structAlign = Typeof((*tiny)(nil)).(*PtrType).Elem().Size();
+
+ t := v.Type().(*FuncType);
+ if len(in) != t.NumIn() {
+ panic("FuncValue: wrong argument count");
+ }
+ nout := t.NumOut();
+
+ // Compute arg size & allocate.
+ // This computation is 6g/8g-dependent
+ // and probably wrong for gccgo, but so
+ // is most of this function.
+ size := uintptr(0);
+ for i, v := range in {
+ tv := v.Type();
+ typesMustMatch(t.In(i), tv);
+ a := uintptr(tv.Align());
+ size = (size + a - 1) &^ (a - 1);
+ size += tv.Size();
+ }
+ size = (size + structAlign - 1) &^ (structAlign - 1);
+ for i := 0; i < nout; i++ {
+ tv := t.Out(i);
+ a := uintptr(tv.Align());
+ size = (size + a - 1) &^ (a - 1);
+ size += tv.Size();
+ }
+
+ // size must be > 0 in order for &args[0] to be valid.
+ // the argument copying is going to round it up to
+ // a multiple of 8 anyway, so make it 8 to begin with.
+ if size < 8 {
+ size = 8;
+ }
+ args := make([]byte, size);
+ ptr := uintptr(unsafe.Pointer(&args[0]));
+
+ // Copy into args.
+ //
+ // TODO(rsc): revisit when reference counting happens.
+ // This one may be fine. The values are holding up the
+ // references for us, so maybe this can be treated
+ // like any stack-to-stack copy.
+ off := uintptr(0);
+ for i, v := range in {
+ tv := v.Type();
+ a := uintptr(tv.Align());
+ off = (off + a - 1) &^ (a - 1);
+ n := tv.Size();
+ memmove(addr(ptr+off), v.getAddr(), n);
+ off += n;
+ }
+ off = (off + structAlign - 1) &^ (structAlign - 1);
+
+ // Call
+ call(*(**byte)(v.addr), (*byte)(addr(ptr)), uint32(size));
+
+ // Copy return values out of args.
+ //
+ // TODO(rsc): revisit like above.
+ ret := make([]Value, nout);
+ for i := 0; i < nout; i++ {
+ tv := t.Out(i);
+ a := uintptr(tv.Align());
+ off = (off + a - 1) &^ (a - 1);
+ v := MakeZero(tv);
+ n := tv.Size();
+ memmove(v.getAddr(), addr(ptr+off), n);
+ ret[i] = v;
+ off += n;
+ }
+ return ret;
+}
/*
* interface
panic(cannotSet);
}
typesMustMatch(v.typ, x.typ);
- memmove(uintptr(v.addr), uintptr(x.addr), v.typ.Size());
+ memmove(v.addr, x.addr, v.typ.Size());
}
// Field returns the i'th field of the struct.
* constructors
*/
-// Typeof returns the reflection Type of the value in the interface{}.
-func Typeof(i interface{}) Type {
- return toType(unsafe.Typeof(i));
-}
-
// NewValue returns a new Value initialized to the concrete value
// stored in the interface i. NewValue(nil) returns nil.
func NewValue(i interface{}) Value {
data := make([]uint8, size);
return newValue(typ, addr(&data[0]), true);
}
+
MOVL DI, (m_morebuf+gobuf_pc)(BX)
LEAL 8(SP), CX // f's caller's SP
MOVL CX, (m_morebuf+gobuf_sp)(BX)
+ MOVL CX, (m_morefp)(BX)
MOVL g, SI
MOVL SI, (m_morebuf+gobuf_g)(BX)
MOVL $0, 0x1003 // crash if newstack returns
RET
+// Called from reflection library. 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 reflect·call(SB), 7, $0
+ MOVL m, 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 4(SP), AX // our caller's SP
+ MOVL AX, (m_morebuf+gobuf_sp)(BX)
+ MOVL g, AX
+ MOVL AX, (m_morebuf+gobuf_g)(BX)
+
+ // Set up morestack arguments to call f on a new stack.
+ // We set f's frame size to zero, meaning
+ // allocate a standard sized stack segment.
+ // If it turns out that f needs a larger frame than this,
+ // f's usual stack growth prolog will allocate
+ // a new segment (and recopy the arguments).
+ MOVL 4(SP), AX // fn
+ MOVL 8(SP), DX // arg frame
+ MOVL 12(SP), CX // arg size
+
+ MOVL AX, m_morepc(BX) // f's PC
+ MOVL DX, m_morefp(BX) // argument frame pointer
+ MOVL CX, m_moreargs(BX) // f's argument size
+ MOVL $0, m_moreframe(BX) // f's frame size
+
+ // Call newstack on m's scheduling stack.
+ MOVL m_g0(BX), BP
+ MOVL BP, g
+ MOVL (m_sched+gobuf_sp)(BX), SP
+ CALL newstack(SB)
+ MOVL $0, 0x1103 // crash if newstack returns
+ RET
+
+
// Return point when leaving stack.
TEXT sys·lessstack(SB), 7, $0
// Save return value in m->cret
MOVQ AX, (m_morebuf+gobuf_pc)(m)
LEAQ 16(SP), AX // f's caller's SP
MOVQ AX, (m_morebuf+gobuf_sp)(m)
+ MOVQ AX, (m_morefp)(m)
MOVQ g, (m_morebuf+gobuf_g)(m)
// Set m->morepc to f's PC.
MOVQ $0, 0x1003 // crash if newstack returns
RET
+// Called from reflection library. 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 reflect·call(SB), 7, $0
+ // 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)(m)
+ LEAQ 8(SP), AX // our caller's SP
+ MOVQ AX, (m_morebuf+gobuf_sp)(m)
+ MOVQ g, (m_morebuf+gobuf_g)(m)
+
+ // Set up morestack arguments to call f on a new stack.
+ // We set f's frame size to zero, meaning
+ // allocate a standard sized stack segment.
+ // If it turns out that f needs a larger frame than this,
+ // f's usual stack growth prolog will allocate
+ // a new segment (and recopy the arguments).
+ MOVQ 8(SP), AX // fn
+ MOVQ 16(SP), BX // arg frame
+ MOVL 24(SP), CX // arg size
+
+ MOVQ AX, m_morepc(m) // f's PC
+ MOVQ BX, m_morefp(m) // argument frame pointer
+ MOVL CX, m_moreargs(m) // f's argument size
+ MOVL $0, m_moreframe(m) // f's frame size
+
+ // Call newstack on m's scheduling stack.
+ MOVQ m_g0(m), g
+ MOVQ (m_sched+gobuf_sp)(m), SP
+ CALL newstack(SB)
+ MOVQ $0, 0x1103 // crash if newstack returns
+ RET
+
// Return point when leaving stack.
TEXT sys·lessstack(SB), 7, $0
// Save return value in m->cret
// Set m->morebuf to f's caller.
MOVW R3, (m_morebuf+gobuf_pc)(m) // f's caller's PC
MOVW SP, (m_morebuf+gobuf_sp)(m) // f's caller's SP
+ MOVW SP, m_morefp(m) // f's caller's SP
MOVW g, (m_morebuf+gobuf_g)(m)
MOVW R0, (m_morebuf+gobuf_r0)(m)
MOVW (m_sched+gobuf_sp)(m), SP
B newstack(SB)
+// Called from reflection library. 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 reflect·call(SB), 7, $-4
+ // Save our caller's state as the PC and SP to
+ // restore when returning from f.
+ MOVW LR, (m_morebuf+gobuf_pc)(m) // our caller's PC
+ MOVW SP, (m_morebuf+gobuf_sp)(m) // our caller's SP
+ MOVW R0, (m_morebuf+gobuf_r0)(m)
+ MOVQ g, (m_morebuf+gobuf_g)(m)
+
+ // Set up morestack arguments to call f on a new stack.
+ // We set f's frame size to zero, meaning
+ // allocate a standard sized stack segment.
+ // If it turns out that f needs a larger frame than this,
+ // 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_morepc(m) // f's PC
+ MOVW R1, m_morefp(m) // argument frame pointer
+ MOVW R2, m_moreargs(m) // f's argument size
+ MOVW $0, R3
+ MOVW R3, m_moreframe(m) // f's frame size
+
+ // Call newstack on m's scheduling stack.
+ MOVW m_g0(m), g
+ MOVW (m_sched+gobuf_sp)(m), SP
+ B newstack(SB)
+
// Return point when leaving stack.
// using frame size $-4 means do not save LR on stack.
TEXT sys·lessstack(SB), 7, $-4
args = old.args;
if(args > 0) {
sp -= args;
- mcpy(top->gobuf.sp, sp, args);
+ mcpy(top->fp, sp, args);
}
stackfree((byte*)g1->stackguard - StackGuard);
frame = m->moreframe;
args = m->moreargs;
-
+
// Round up to align things nicely.
// This is sufficient for both 32- and 64-bit machines.
args = (args+7) & ~7;
frame += 1024; // for more functions, Stktop.
stk = stackalloc(frame);
-//printf("newstack frame=%d args=%d morepc=%p gobuf=%p, %p newstk=%p\n", frame, args, m->morepc, g->sched.pc, g->sched.sp, stk);
+//printf("newstack frame=%d args=%d morepc=%p morefp=%p gobuf=%p, %p newstk=%p\n", frame, args, m->morepc, m->morefp, g->sched.pc, g->sched.sp, stk);
g1 = m->curg;
top = (Stktop*)(stk+frame-sizeof(*top));
top->stackbase = g1->stackbase;
top->stackguard = g1->stackguard;
top->gobuf = m->morebuf;
+ top->fp = m->morefp;
top->args = args;
g1->stackbase = (byte*)top;
sp = (byte*)top;
if(args > 0) {
sp -= args;
- mcpy(sp, top->gobuf.sp, args);
+ mcpy(sp, m->morefp, args);
}
// Continue as if lessstack had just called m->morepc
// The offsets of these fields are known to (hard-coded in) libmach.
G* g0; // goroutine with scheduling stack
void (*morepc)(void);
+ void* morefp; // frame pointer for more stack
Gobuf morebuf; // gobuf arg to morestack
// Fields not known to debuggers.
uint8* stackbase;
Gobuf gobuf;
uint32 args;
+
+ // Frame pointer: where args start in old frame.
+ // fp == gobuf.sp except in the case of a reflected
+ // function call, which uses an off-stack argument frame.
+ uint8* fp;
};
struct Alg
{